xflr6 / concepts

Formal Concept Analysis with Python

Home Page:https://concepts.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Access to concepts themselves

Aluriak opened this issue · comments

It seems that currently, context's concepts are accessible only through the lattice representation, through the (implicitly protected) attribute _concepts.

Accessing the Concept instances is necessary for various reasons, including the mapping of a concept with its node in the lattice representation.

Hack: use _concepts even if it's not public API.

Not sure if there is a terminological problem: the concept instances are also the nodes of their lattice object.

You can just iterate over the lattice to walk all concepts:

def __iter__(self):
return iter(self._concepts)

In principle you can also directly iterate over .lattice (note that the main feature of this library is to produce the full lattice graph for you):

In [1]: import concepts
   ...: ctx = concepts.Context.fromstring('''
   ...:             |human|knight|king |mysterious|
   ...: King Arthur|  X  |  X   |  X  |          |
   ...: Sir Robin  |  X  |  X   |     |          |
   ...: holy grail |     |      |     |     X    |
   ...: ''')
   ...: [c.extent for c in ctx.lattice]
Out[1]: 
[(),
 ('King Arthur',),
 ('holy grail',),
 ('King Arthur', 'Sir Robin'),
 ('King Arthur', 'Sir Robin', 'holy grail')]

Oh, i didn't see that.

Thank you for answering, and so quickly.

Maybe you should consider adding a concepts property, in order to make things even more clear. I love explicit accessors like that, so probably it's affecting my judgement.

Understand. IMO using the native APIs is more pythonic. I think Lattice should implement a set-like interface. So I consider to add a .__contains__()-method that should be simple to implement (once decided on the concrete semantics for the edge cases :) ).

Btw, you could in principle go deeper:

import concepts
ctx = concepts.Context.fromstring('''
              |human|knight|king |mysterious|
   King Arthur|  X  |  X   |  X  |          |
   Sir Robin  |  X  |  X   |     |          |
   holy grail |     |      |     |     X    |
 ''')
list(ctx._lattice())
Out[1]: 
[(Extent('000'), Intent('1111'), [Extent('100'), Extent('001')], []),
 (Extent('100'), Intent('1110'), [Extent('110')], [Extent('000')]),
 (Extent('001'), Intent('0001'), [Extent('111')], [Extent('000')]),
 (Extent('110'), Intent('1100'), [Extent('111')], [Extent('100')]),
 (Extent('111'), Intent('0000'), [], [Extent('001'), Extent('110')])]

These items should contain in principle contain all information about a concept and its lattice position:

[(set(e.members()),
  set(i.members()),
 [set(u.members()) for u in upper],
 [set(l.members()) for l in lower])
 for e, i, upper, lower, in ctx._lattice()]
Out[2]: 
[(set(),
  {'human', 'king', 'knight', 'mysterious'},
  [{'King Arthur'}, {'holy grail'}],
  []),
 ({'King Arthur'},
  {'human', 'king', 'knight'},
  [{'King Arthur', 'Sir Robin'}],
  [set()]),
 ({'holy grail'},
  {'mysterious'},
  [{'King Arthur', 'Sir Robin', 'holy grail'}],
  [set()]),
 ({'King Arthur', 'Sir Robin'},
  {'human', 'knight'},
  [{'King Arthur', 'Sir Robin', 'holy grail'}],
  [{'King Arthur'}]),
 ({'King Arthur', 'Sir Robin', 'holy grail'},
  set(),
  [],
  [{'holy grail'}, {'King Arthur', 'Sir Robin'}])]