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:

>>> from concepts import Definition, Context

>>> d = Definition()

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

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

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

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

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

>>> print(Context(*d))  
<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:

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

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

>>> u = c.definition() | h.definition()

>>> print(u)
           |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    |

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

>>> print(u)
           |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    |

>>> Context(*u).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'

c = 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))

c_ = concepts.Context(objects, properties, bools)
assert c_ == c

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).