Advanced Usage

Modification

Context objects are immutable. However, iterative assembling, modification, and combination of contexts is supported by using Definition objects. They can be edited and then given to Context to construct a new context object:

>>> import concepts

>>> definition = concepts.Definition()

>>> definition.add_object('man', ['male'])
>>> definition.add_object('woman', ['female'])

>>> definition
<Definition(['man', 'woman'], ['male', 'female'], [(True, False), (False, True)])>

>>> definition.add_property('adult', ['man', 'woman'])
>>> definition.add_property('child', ['boy', 'girl'])

>>> print(definition)
     |male|female|adult|child|
man  |X   |      |X    |     |
woman|    |X     |X    |     |
boy  |    |      |     |X    |
girl |    |      |     |X    |

>>> definition['boy', 'male'] = True
>>> definition.add_object('girl', ['female'])

>>> print(concepts.Context(*definition))  
<Context object mapping 4 objects to 4 properties [65aa9782] at 0x...>
         |male|female|adult|child|
    man  |X   |      |X    |     |
    woman|    |X     |X    |     |
    boy  |X   |      |     |X    |
    girl |    |X     |     |X    |

Use definitions to combine two contexts, fill out the missing cells, and create the resulting context:

>>> context = concepts.Context.fromstring('''
...            |human|knight|king |mysterious|
... King Arthur|  X  |  X   |  X  |          |
... Sir Robin  |  X  |  X   |     |          |
... holy grail |     |      |     |     X    |
... ''')

>>> human = concepts.Context.fromstring('''
...      |male|female|adult|child|
... man  |  X |      |  X  |     |
... woman|    |   X  |  X  |     |
... boy  |  X |      |     |  X  |
... girl |    |   X  |     |  X  |
... ''')

>>> union = context.definition() | human.definition()

>>> print(union)
           |human|knight|king|mysterious|male|female|adult|child|
King Arthur|X    |X     |X   |          |    |      |     |     |
Sir Robin  |X    |X     |    |          |    |      |     |     |
holy grail |     |      |    |X         |    |      |     |     |
man        |     |      |    |          |X   |      |X    |     |
woman      |     |      |    |          |    |X     |X    |     |
boy        |     |      |    |          |X   |      |     |X    |
girl       |     |      |    |          |    |X     |     |X    |

>>> union.add_property('human', ['man', 'woman', 'boy', 'girl'])
>>> union.add_object('King Arthur', ['male', 'adult'])
>>> union.add_object('Sir Robin', ['male', 'adult'])

>>> print(union)
           |human|knight|king|mysterious|male|female|adult|child|
King Arthur|X    |X     |X   |          |X   |      |X    |     |
Sir Robin  |X    |X     |    |          |X   |      |X    |     |
holy grail |     |      |    |X         |    |      |     |     |
man        |X    |      |    |          |X   |      |X    |     |
woman      |X    |      |    |          |    |X     |X    |     |
boy        |X    |      |    |          |X   |      |     |X    |
girl       |X    |      |    |          |    |X     |     |X    |

>>> concepts.Context(*union).lattice  
<Lattice object of 5 atoms 14 concepts 2 coatoms at 0x...>
_images/union.svg

Context from pandas.DataFrame

import concepts
import pandas as pd

CONTEXT = 'examples/relations.csv'

context = concepts.load_csv(CONTEXT)

df = pd.read_csv(CONTEXT, index_col='name')
objects = df.index.tolist()
properties = list(df)
bools = list(df.fillna(False).astype(bool).itertuples(index=False, name=None))

context_ = concepts.Context(objects, properties, bools)
assert context_ == context

Custom serialization format

For the Context from concepts.EXAMPLE:

EXAMPLE = '''\
   |+1|-1|+2|-2|+3|-3|+sg|+pl|-sg|-pl|
1sg| X|  |  | X|  | X|  X|   |   |  X|
1pl| X|  |  | X|  | X|   |  X|  X|   |
2sg|  | X| X|  |  | X|  X|   |   |  X|
2pl|  | X| X|  |  | X|   |  X|  X|   |
3sg|  | X|  | X| X|  |  X|   |   |  X|
3pl|  | X|  | X| X|  |   |  X|  X|   |
'''

The serialization as Python dict (including its lattice structure) looks like this:

SERIALIZED = {
    'objects': (
        '1sg', '1pl', '2sg', '2pl', '3sg', '3pl',
    ),
    'properties': (
        '+1', '-1', '+2', '-2', '+3', '-3', '+sg', '+pl', '-sg', '-pl',
    ),
    'context': [
        (0, 3, 5, 6, 9),
        (0, 3, 5, 7, 8),
        (1, 2, 5, 6, 9),
        (1, 2, 5, 7, 8),
        (1, 3, 4, 6, 9),
        (1, 3, 4, 7, 8),
    ],
    'lattice': [
        ((), (0, 1, 2, 3, 4, 5, 6, 7, 8, 9), (1, 2, 3, 4, 5, 6), ()),
        ((0,), (0, 3, 5, 6, 9), (7, 8, 9), (0,)),
        ((1,), (0, 3, 5, 7, 8), (7, 10, 11), (0,)),
        ((2,), (1, 2, 5, 6, 9), (8, 12, 13), (0,)),
        ((3,), (1, 2, 5, 7, 8), (10, 12, 14), (0,)),
        ((4,), (1, 3, 4, 6, 9), (9, 13, 15), (0,)),
        ((5,), (1, 3, 4, 7, 8), (11, 14, 15), (0,)),
        ((0, 1), (0, 3, 5), (18, 19), (1, 2)),
        ((0, 2), (5, 6, 9), (16, 18), (1, 3)),
        ((0, 4), (3, 6, 9), (16, 19), (1, 5)),
        ((1, 3), (5, 7, 8), (17, 18), (2, 4)),
        ((1, 5), (3, 7, 8), (17, 19), (2, 6)),
        ((2, 3), (1, 2, 5), (18, 20), (3, 4)),
        ((2, 4), (1, 6, 9), (16, 20), (3, 5)),
        ((3, 5), (1, 7, 8), (17, 20), (4, 6)),
        ((4, 5), (1, 3, 4), (19, 20), (5, 6)),
        ((0, 2, 4), (6, 9), (21,), (8, 9, 13)),
        ((1, 3, 5), (7, 8), (21,), (10, 11, 14)),
        ((0, 1, 2, 3), (5,), (21,), (7, 8, 10, 12)),
        ((0, 1, 4, 5), (3,), (21,), (7, 9, 11, 15)),
        ((2, 3, 4, 5), (1,), (21,), (12, 13, 14, 15)),
        ((0, 1, 2, 3, 4, 5), (), (), (18, 19, 20, 16, 17)),
    ],
}

Any extra keys are ignored when loading.

Note that the 'context' list items are (by-index) references to 'properties' (intents). The 'lattice' list items are 4-tuples where the first elements are references to 'objects' (extents), the second elements are references to 'properties' (intents), and the last two are references to the 'lattice' list itself (upper and lower neighbors, a.k.a. cover sets). All references are zero-based index references into their target sequence.