Skip to content

Instantly share code, notes, and snippets.

@xflr6
Last active June 4, 2022 14:00
Show Gist options
  • Save xflr6/7b9f4a6e8f537aa0d647 to your computer and use it in GitHub Desktop.
Save xflr6/7b9f4a6e8f537aa0d647 to your computer and use it in GitHub Desktop.
Brute force FCA concepts by trying all combinations with NumPy
"""Generate concepts by trying all combinations with NumPy."""
from collections.abc import Iterator, Sequence
import itertools
import numpy as np
OBJECTS = ('1s', '1de', '1pe', '1di', '1pi',
'2s', '2d', '2p',
'3s.m', '3s.f', '3s.n',
'3d.m', '3d.f', '3d.n',
'3p.m', '3p.f', '3p.n')
PROPERTIES = ('+1', '-1', '+2', '-2', '+3', '-3',
'+sg', '+du', '+pl', '-sg', '-du', '-pl',
'+masc', '+fem', '+neut', '-masc', '-fem', '-neut')
BOOLS = [(1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0),
(1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0),
(1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0),
(1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0),
(0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0),
(0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0),
(0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1),
(0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1),
(0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0),
(0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1),
(0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1),
(0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0),
(0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1),
(0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1),
(0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0)]
def concepts(objects: Sequence[str],
properties: Sequence[str],
bools: Sequence[Sequence[int]]
) -> Iterator[tuple[Sequence[str], Sequence[str]]]:
"""Yield all (extent, intent) pairs in shortlex order."""
X = np.array(bools, dtype=bool)
Y = X.transpose().copy()
indexes = range(len(objects))
for r in range(len(objects) + 1):
for idx in itertools.combinations(indexes, r):
P = X.take(idx, axis=0)
prime = np.logical_and.reduce(P)
O = Y.compress(prime, axis=0)
double = np.logical_and.reduce(O)
if np.count_nonzero(double) == r:
intent = tuple(np.compress(prime, properties))
extent = tuple(np.compress(double, objects))
yield extent, intent
for extent, intent in concepts(OBJECTS, PROPERTIES, BOOLS):
print(f"{{{', '.join(extent)}}} <-> [{' '.join(intent)}]")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment