A database of categories
リビジョン | 20425dba992f751cf23c32030deb7685fc6bb85b (tree) |
---|---|
日時 | 2023-12-29 13:32:25 |
作者 | Corbin <cds@corb...> |
コミッター | Corbin |
And this too.
@@ -0,0 +1,103 @@ | ||
1 | +from collections import deque | |
2 | +from itertools import combinations | |
3 | +import operator | |
4 | +import random | |
5 | + | |
6 | +def randDim(): return random.choice(list(range(2, 8))) | |
7 | + | |
8 | +def discreteness(r, c): | |
9 | + p = 2 ** c - r | |
10 | + q = 2 ** r - c | |
11 | + return (p - q) / (p + q) | |
12 | + | |
13 | +def randomSpace(): | |
14 | + r = randDim() | |
15 | + c = randDim() | |
16 | + return tuple(tuple(random.choice([False, True]) for _ in range(c)) | |
17 | + for _ in range(r)) | |
18 | + | |
19 | +def transpose(s): return tuple(map(tuple, zip(*s))) | |
20 | + | |
21 | +def addRow(s, v): return s + (tuple(v for _ in range(len(s[0]))),) | |
22 | +def addZeroRow(s): return addRow(s, False) | |
23 | +def addZeroColumn(s): return transpose(addZeroRow(transpose(s))) | |
24 | +def addOneColumn(s): return transpose(addRow(transpose(s), True)) | |
25 | + | |
26 | +def dims(s): return len(s), len(s[0]) | |
27 | + | |
28 | +def collapse(s): | |
29 | + done = False | |
30 | + while not done: | |
31 | + t = tuple(set(s)) | |
32 | + u = transpose(tuple(set(transpose(t)))) | |
33 | + done = dims(s) == dims(t) == dims(u) | |
34 | + s = u | |
35 | + return s | |
36 | + | |
37 | +def closeOverOps(s, *ops): | |
38 | + # NB: closure over rows only! | |
39 | + d = deque(s) | |
40 | + rs = set(s) | |
41 | + while d: | |
42 | + r = d.pop() | |
43 | + closure = set(op(r, x) for x in rs for op in ops) - rs | |
44 | + rs |= closure | |
45 | + d.extendleft(closure) | |
46 | + return tuple(rs) | |
47 | + | |
48 | +def makeOp(f): | |
49 | + return lambda r1, r2: tuple(f(x, y) for x, y in zip(r1, r2)) | |
50 | + | |
51 | +union = makeOp(operator.or_) | |
52 | +intersection = makeOp(operator.and_) | |
53 | +xor = makeOp(operator.xor) | |
54 | + | |
55 | +def topSpace(s): | |
56 | + # Closure over empty intersections is equivalent to an all-ones column. | |
57 | + s = addOneColumn(s) | |
58 | + return collapse(transpose(closeOverOps(transpose(s), union, intersection))) | |
59 | + | |
60 | +def unionPoset(s): | |
61 | + p = set((i, j) for ((i, x), (j, y)) in combinations(enumerate(s), 2) | |
62 | + if all(map(operator.le, x, y))) | |
63 | + p |= set((j, i) for ((i, x), (j, y)) in combinations(enumerate(s), 2) | |
64 | + if all(map(operator.ge, x, y))) | |
65 | + return p | |
66 | + | |
67 | +def assigns(w): | |
68 | + for i in range(2 ** w): | |
69 | + yield tuple(bool((i >> k) & 1) for k in reversed(range(w))) | |
70 | + | |
71 | +def implies(p, q): return (not p) or q | |
72 | + | |
73 | +def antichains(p, w): | |
74 | + # NB: #P-complete! See https://cs.stackexchange.com/a/83954/131656 | |
75 | + for r in assigns(w): | |
76 | + if all(implies(r[s], r[d]) for (s, d) in p): yield r | |
77 | + | |
78 | +def semilat(s): | |
79 | + s = addZeroColumn(s) | |
80 | + s = closeOverOps(s, union) | |
81 | + s = collapse(s) | |
82 | + p = unionPoset(s) | |
83 | + s += tuple(antichains(p, len(s))) | |
84 | + return collapse(s) | |
85 | + | |
86 | +def distlat(s): | |
87 | + s = addOneColumn(addZeroColumn(s)) | |
88 | + return collapse(closeOverOps(s, union, intersection)) | |
89 | + | |
90 | +def complat(s): | |
91 | + s = closeOverOps(transpose(addOneColumn(s)), intersection) | |
92 | + s = closeOverOps(transpose(addOneColumn(s)), intersection) | |
93 | + return collapse(s) | |
94 | + | |
95 | +def vectorSpace(s): | |
96 | + s = closeOverOps(transpose(s), xor) | |
97 | + s = closeOverOps(transpose(s), xor) | |
98 | + s = addZeroColumn(addZeroRow(s)) | |
99 | + return collapse(s) | |
100 | + | |
101 | +def findRange(ss): | |
102 | + r = set(discreteness(*dims(s)) for s in ss) | |
103 | + return min(r), max(r) |