-
Notifications
You must be signed in to change notification settings - Fork 0
/
bool.py
412 lines (299 loc) · 11 KB
/
bool.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
from dispatcher import (
_AND,
_OR,
dispatch_and,
dispatch_or,
)
class Expression:
def __and__(self, other):
return self.AND(other)
def __or__(self, other):
return self.OR(other)
def __invert__(self):
return self.NOT()
def AND(self, other):
if other.LOOSENS(self):
return self
if other.RESTRICTS(self):
return other
return dispatch_and(self, other)
def OR(self, other):
if other.RESTRICTS(self):
return self
if other.LOOSENS(self):
return other
return dispatch_or(self, other)
def IS_TRUE(self):
return False
def IS_FALSE(self):
return False
def LOOSENS(self, other):
return other.RESTRICTS(self)
class TrueVal(Expression):
def __str__(self):
return "T"
def NOT(self):
return FALSE
def IS_TRUE(self):
return True
def RESTRICTS(self, other):
return other.IS_TRUE()
def eval(self, _):
return True
class FalseVal(Expression):
def __str__(self):
return "F"
def NOT(self):
return TRUE
def IS_FALSE(self):
return True
def RESTRICTS(self, other):
return True
def eval(self, _):
return False
class SignedVar(Expression):
def __init__(self, name, sign):
self.name = name
self.sign = sign
def __str__(self):
return self.name if self.sign else "~" + self.name
def EQ(self, other):
return self.name == other.name and self.sign == other.sign
def NOT(self):
return SignedVar(self.name, not self.sign)
def RESTRICTS(self, other):
if other.IS_TRUE():
return True
if other.IS_FALSE():
return False
if type(other) == SignedVar:
return self.EQ(other)
if type(other) == OrClause:
return any(sv.EQ(self) for sv in other.signed_vars)
if type(other) == AndClause:
return all(sv.EQ(self) for sv in other.signed_vars)
if type(other) == Disjunction:
return any(self.RESTRICTS(clause) for clause in other.clauses)
if type(other) == Conjunction:
return all(self.RESTRICTS(clause) for clause in other.clauses)
assert False
def eval(self, tvars):
var_value = self.name in tvars
if self.sign:
return var_value
else:
return not var_value
class Clause(Expression):
def __init__(self, signed_vars):
for sv in signed_vars:
assert type(sv) == SignedVar
self.signed_vars = signed_vars
names = {sv.name for sv in signed_vars if sv.sign}
negated_names = {sv.name for sv in signed_vars if not sv.sign}
assert not (names & negated_names)
self.names = names
self.negated_names = negated_names
def stringified_vars(self):
signed_vars = sorted(list(self.signed_vars), key=lambda sv: sv.name)
return [str(sv) for sv in signed_vars]
def key(self):
var_names = {sv.name for sv in self.signed_vars}
return sorted(var_names)
@staticmethod
def make_signed_vars(names, negated_names):
return [SignedVar(name, True) for name in names] + [
SignedVar(name, False) for name in negated_names
]
class OrClause(Clause):
def __str__(self):
return "|".join(self.stringified_vars())
def NOT(self):
return AndClause.make(self.negated_names, self.names)
def RESTRICTS(self, other):
if other.IS_TRUE():
return True
if other.IS_FALSE():
return False
if type(other) == SignedVar:
return all(sv.EQ(other) for sv in self.signed_vars)
if type(other) == AndClause:
return all(self.RESTRICTS(sv) for sv in other.signed_vars)
if type(other) == OrClause:
return all(sv.RESTRICTS(other) for sv in self.signed_vars)
if type(other) == Disjunction:
return any(self.RESTRICTS(clause) for clause in other.clauses)
if type(other) == Conjunction:
return all(self.RESTRICTS(clause) for clause in other.clauses)
def eval(self, tvars):
return any(sv.eval(tvars) for sv in self.signed_vars)
@staticmethod
def make(names, negated_names):
signed_vars = Clause.make_signed_vars(names, negated_names)
return OrClause(signed_vars)
class AndClause(Clause):
def __str__(self):
return "&".join(self.stringified_vars())
def NOT(self):
return OrClause.make(self.negated_names, self.names)
def RESTRICTS(self, other):
if other.IS_TRUE():
return True
if other.IS_FALSE():
return False
if type(other) == SignedVar:
return any(sv.EQ(other) for sv in self.signed_vars)
if type(other) == AndClause:
return all(self.RESTRICTS(sv) for sv in other.signed_vars)
if type(other) == OrClause:
return any(sv.RESTRICTS(other) for sv in self.signed_vars)
if type(other) == Disjunction:
return any(self.RESTRICTS(clause) for clause in other.clauses)
if type(other) == Conjunction:
return all(self.RESTRICTS(clause) for clause in other.clauses)
def eval(self, tvars):
return all(sv.eval(tvars) for sv in self.signed_vars)
@staticmethod
def make(names, negated_names):
signed_vars = Clause.make_signed_vars(names, negated_names)
return AndClause(signed_vars)
class Junction(Expression):
def stringified_clauses(self):
clauses = sorted(self.clauses, key=lambda clause: clause.key())
return [f"({clause})" for clause in clauses]
class Disjunction(Junction):
def __init__(self, clauses):
assert all(type(clause) == AndClause for clause in clauses)
self.clauses = clauses
def __str__(self):
return "|".join(self.stringified_clauses())
def NOT(self):
return Conjunction([clause.NOT() for clause in self.clauses])
def RESTRICTS(self, other):
return all(clause.RESTRICTS(other) for clause in self.clauses)
def eval(self, tvars):
return any(clause.eval(tvars) for clause in self.clauses)
class Conjunction(Junction):
def __init__(self, clauses):
assert all(type(clause) == OrClause for clause in clauses)
self.clauses = clauses
def __str__(self):
return "&".join(self.stringified_clauses())
def NOT(self):
return Disjunction([clause.NOT() for clause in self.clauses])
def RESTRICTS(self, other):
if type(other) == Conjunction:
return all(self.RESTRICTS(clause) for clause in other.clauses)
return any(clause.RESTRICTS(other) for clause in self.clauses)
def eval(self, tvars):
return all(clause.eval(tvars) for clause in self.clauses)
TRUE = TrueVal()
FALSE = FalseVal()
def SYMBOL(name):
return SignedVar(name, True)
def eliminate_terms(exprs, predicate):
reject_tups = set()
for i in range(len(exprs)):
for j in range(len(exprs)):
if i != j and (j, i) not in reject_tups:
if predicate(exprs[i], exprs[j]):
reject_tups.add((i, j))
rejects = {i for i, j in reject_tups}
return [exprs[i] for i in range(len(exprs)) if i not in rejects]
def eliminate_resticting_terms(exprs):
return eliminate_terms(exprs, lambda x, y: x.RESTRICTS(y))
def eliminate_loosening_terms(exprs):
return eliminate_terms(exprs, lambda x, y: x.LOOSENS(y))
def and_expression(exprs):
exprs = eliminate_loosening_terms(exprs)
if len(exprs) == 1:
return exprs[0]
if all(type(expr) == SignedVar for expr in exprs):
return AndClause(exprs)
return Conjunction(exprs)
def or_expression(exprs):
exprs = eliminate_resticting_terms(exprs)
if len(exprs) == 1:
return exprs[0]
if all(type(expr) == SignedVar for expr in exprs):
return OrClause(exprs)
return Disjunction(exprs)
@_AND(TrueVal, Expression)
def TrueVal_AND_Expression(_, x):
return x
@_AND(FalseVal, Expression)
def FalseVal_AND_Expression(_, x):
return FALSE
@_OR(TrueVal, Expression)
def TrueVal_OR_Expression(_, x):
return TRUE
@_OR(FalseVal, Expression)
def FalseVal_OR_Expression(_, x):
return x
@_AND(SignedVar, SignedVar)
def SignedVar_AND_SignedVar(x, y):
if x.name == y.name:
return x if x.sign == y.sign else FALSE
return AndClause([x, y])
@_OR(SignedVar, SignedVar)
def SignedVar_OR_SignedVar(x, y):
if x.name == y.name:
return x if x.sign == y.sign else TRUE
return OrClause([x, y])
@_AND(AndClause, AndClause)
def AndClause_AND_AndClause(x, y):
names = x.names | y.names
negated_names = x.negated_names | y.negated_names
if names & negated_names:
return FALSE
return AndClause.make(names, negated_names)
@_OR(OrClause, OrClause)
def OrClause_OR_OrClause(x, y):
names = x.names | y.names
negated_names = x.negated_names | y.negated_names
if names & negated_names:
return TRUE
return OrClause.make(names, negated_names)
@_AND(AndClause, OrClause)
def AndClause_AND_OrClause(x, y):
exprs = [x.AND(sv) for sv in y.signed_vars]
return or_expression(exprs)
@_OR(AndClause, OrClause)
def AndClause_OR_OrClause(x, y):
exprs = [y.OR(sv) for sv in x.signed_vars]
return and_expression(exprs)
@_OR(AndClause, SignedVar)
def AndClause_OR_SignedVar(clause, signed_var):
exprs = [sv.OR(signed_var) for sv in clause.signed_vars]
return and_expression(exprs)
@_OR(AndClause, AndClause)
def AndClause_OR_AndClause(x, y):
exprs = [sv_x.OR(sv_y) for sv_x in x.signed_vars for sv_y in y.signed_vars]
return and_expression(exprs)
@_AND(OrClause, SignedVar)
def OrClause_AND_SignedVar(clause, signed_var):
exprs = [sv.AND(signed_var) for sv in clause.signed_vars]
return or_expression(exprs)
@_AND(OrClause, OrClause)
def OrClause_AND_OrClause(x, y):
exprs = [sv_x.AND(sv_y) for sv_x in x.signed_vars for sv_y in y.signed_vars]
return or_expression(exprs)
@_OR(OrClause, SignedVar)
def OrClause_OR_SignedVar(clause, signed_var):
return OrClause_OR_OrClause(clause, OrClause([signed_var]))
@_AND(AndClause, SignedVar)
def AndClause_AND_SignedVar(clause, signed_var):
return AndClause_AND_AndClause(clause, AndClause([signed_var]))
@_AND(Disjunction, SignedVar)
def Disjunction_AND_SignedVar(conjunction, signed_var):
exprs = [clause.AND(signed_var) for clause in conjunction.clauses]
return or_expression(exprs)
@_OR(Disjunction, SignedVar)
def Disjunction_OR_SignedVar(conjunction, signed_var):
return or_expression(conjunction.clauses + [AndClause([signed_var])])
@_AND(Conjunction, SignedVar)
def Conjunction_AND_SignedVar(conjunction, signed_var):
return and_expression(conjunction.clauses + [OrClause([signed_var])])
@_OR(Conjunction, SignedVar)
def Conjunction_OR_SignedVar(conjunction, signed_var):
exprs = [clause.OR(signed_var) for clause in conjunction.clauses]
return and_expression(exprs)