cranky-coder08 commited on
Commit
ac2f8e9
·
verified ·
1 Parent(s): 2902979

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +4 -0
  2. phivenv/Lib/site-packages/numpy/random/_bounded_integers.cp39-win_amd64.pyd +3 -0
  3. phivenv/Lib/site-packages/numpy/random/_common.cp39-win_amd64.pyd +3 -0
  4. phivenv/Lib/site-packages/numpy/random/_generator.cp39-win_amd64.pyd +3 -0
  5. phivenv/Lib/site-packages/numpy/random/lib/npyrandom.lib +3 -0
  6. phivenv/Lib/site-packages/sympy/logic/__pycache__/__init__.cpython-39.pyc +0 -0
  7. phivenv/Lib/site-packages/sympy/logic/__pycache__/inference.cpython-39.pyc +0 -0
  8. phivenv/Lib/site-packages/sympy/logic/algorithms/__init__.py +0 -0
  9. phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/__init__.cpython-39.pyc +0 -0
  10. phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/dpll.cpython-39.pyc +0 -0
  11. phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/dpll2.cpython-39.pyc +0 -0
  12. phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/lra_theory.cpython-39.pyc +0 -0
  13. phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/minisat22_wrapper.cpython-39.pyc +0 -0
  14. phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/pycosat_wrapper.cpython-39.pyc +0 -0
  15. phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/z3_wrapper.cpython-39.pyc +0 -0
  16. phivenv/Lib/site-packages/sympy/logic/algorithms/dpll2.py +688 -0
  17. phivenv/Lib/site-packages/sympy/logic/algorithms/lra_theory.py +912 -0
  18. phivenv/Lib/site-packages/sympy/logic/algorithms/minisat22_wrapper.py +46 -0
  19. phivenv/Lib/site-packages/sympy/logic/algorithms/pycosat_wrapper.py +41 -0
  20. phivenv/Lib/site-packages/sympy/logic/algorithms/z3_wrapper.py +115 -0
  21. phivenv/Lib/site-packages/sympy/logic/tests/__init__.py +0 -0
  22. phivenv/Lib/site-packages/sympy/logic/tests/__pycache__/__init__.cpython-39.pyc +0 -0
  23. phivenv/Lib/site-packages/sympy/logic/tests/__pycache__/test_boolalg.cpython-39.pyc +0 -0
  24. phivenv/Lib/site-packages/sympy/logic/tests/__pycache__/test_dimacs.cpython-39.pyc +0 -0
  25. phivenv/Lib/site-packages/sympy/logic/tests/__pycache__/test_inference.cpython-39.pyc +0 -0
  26. phivenv/Lib/site-packages/sympy/logic/tests/__pycache__/test_lra_theory.cpython-39.pyc +0 -0
  27. phivenv/Lib/site-packages/sympy/logic/tests/test_boolalg.py +1367 -0
  28. phivenv/Lib/site-packages/sympy/logic/tests/test_dimacs.py +234 -0
  29. phivenv/Lib/site-packages/sympy/logic/tests/test_inference.py +396 -0
  30. phivenv/Lib/site-packages/sympy/logic/tests/test_lra_theory.py +440 -0
  31. phivenv/Lib/site-packages/sympy/logic/utilities/__init__.py +3 -0
  32. phivenv/Lib/site-packages/sympy/logic/utilities/__pycache__/__init__.cpython-39.pyc +0 -0
  33. phivenv/Lib/site-packages/sympy/logic/utilities/__pycache__/dimacs.cpython-39.pyc +0 -0
  34. phivenv/Lib/site-packages/sympy/logic/utilities/dimacs.py +69 -0
  35. phivenv/Lib/site-packages/sympy/matrices/__init__.py +72 -0
  36. phivenv/Lib/site-packages/sympy/matrices/__pycache__/__init__.cpython-39.pyc +0 -0
  37. phivenv/Lib/site-packages/sympy/matrices/__pycache__/decompositions.cpython-39.pyc +0 -0
  38. phivenv/Lib/site-packages/sympy/matrices/__pycache__/dense.cpython-39.pyc +0 -0
  39. phivenv/Lib/site-packages/sympy/matrices/__pycache__/determinant.cpython-39.pyc +0 -0
  40. phivenv/Lib/site-packages/sympy/matrices/__pycache__/eigen.cpython-39.pyc +0 -0
  41. phivenv/Lib/site-packages/sympy/matrices/__pycache__/exceptions.cpython-39.pyc +0 -0
  42. phivenv/Lib/site-packages/sympy/matrices/__pycache__/graph.cpython-39.pyc +0 -0
  43. phivenv/Lib/site-packages/sympy/matrices/__pycache__/immutable.cpython-39.pyc +0 -0
  44. phivenv/Lib/site-packages/sympy/matrices/__pycache__/inverse.cpython-39.pyc +0 -0
  45. phivenv/Lib/site-packages/sympy/matrices/__pycache__/kind.cpython-39.pyc +0 -0
  46. phivenv/Lib/site-packages/sympy/matrices/__pycache__/matrices.cpython-39.pyc +0 -0
  47. phivenv/Lib/site-packages/sympy/matrices/__pycache__/normalforms.cpython-39.pyc +0 -0
  48. phivenv/Lib/site-packages/sympy/matrices/__pycache__/reductions.cpython-39.pyc +0 -0
  49. phivenv/Lib/site-packages/sympy/matrices/__pycache__/repmatrix.cpython-39.pyc +0 -0
  50. phivenv/Lib/site-packages/sympy/matrices/__pycache__/solvers.cpython-39.pyc +0 -0
.gitattributes CHANGED
@@ -33,3 +33,7 @@ phivenv/Lib/site-packages/numpy/ma/tests/__pycache__/test_core.cpython-39.pyc fi
33
  phivenv/Lib/site-packages/numpy/ma/__pycache__/core.cpython-39.pyc filter=lfs diff=lfs merge=lfs -text
34
  phivenv/Lib/site-packages/numpy/random/bit_generator.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
35
  phivenv/Lib/site-packages/numpy/random/mtrand.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
33
  phivenv/Lib/site-packages/numpy/ma/__pycache__/core.cpython-39.pyc filter=lfs diff=lfs merge=lfs -text
34
  phivenv/Lib/site-packages/numpy/random/bit_generator.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
35
  phivenv/Lib/site-packages/numpy/random/mtrand.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
36
+ phivenv/Lib/site-packages/numpy/random/_common.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
37
+ phivenv/Lib/site-packages/numpy/random/_bounded_integers.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
38
+ phivenv/Lib/site-packages/numpy/random/lib/npyrandom.lib filter=lfs diff=lfs merge=lfs -text
39
+ phivenv/Lib/site-packages/numpy/random/_generator.cp39-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
phivenv/Lib/site-packages/numpy/random/_bounded_integers.cp39-win_amd64.pyd ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5e38cea16c127bbfb7291b60468e9500f45bbdc6b63f83d3240109d02fd00e44
3
+ size 252928
phivenv/Lib/site-packages/numpy/random/_common.cp39-win_amd64.pyd ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a4eceb8cd34b3ecf695c4252df85452c31f3e4e0a2cb43cfc62f70f21e35d46c
3
+ size 176640
phivenv/Lib/site-packages/numpy/random/_generator.cp39-win_amd64.pyd ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0831522b7e15b6b0888586a5bb296d093c4f771b314ec812caa261f96189d464
3
+ size 754688
phivenv/Lib/site-packages/numpy/random/lib/npyrandom.lib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6046451e469e3f9257f302b8a7b90e1fe9c20b4635113e0ab4497da3e36dc71f
3
+ size 147796
phivenv/Lib/site-packages/sympy/logic/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (666 Bytes). View file
 
phivenv/Lib/site-packages/sympy/logic/__pycache__/inference.cpython-39.pyc ADDED
Binary file (9.19 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/algorithms/__init__.py ADDED
File without changes
phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (166 Bytes). View file
 
phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/dpll.cpython-39.pyc ADDED
Binary file (7.96 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/dpll2.cpython-39.pyc ADDED
Binary file (18 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/lra_theory.cpython-39.pyc ADDED
Binary file (29.5 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/minisat22_wrapper.cpython-39.pyc ADDED
Binary file (1.94 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/pycosat_wrapper.cpython-39.pyc ADDED
Binary file (1.41 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/algorithms/__pycache__/z3_wrapper.cpython-39.pyc ADDED
Binary file (4.15 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/algorithms/dpll2.py ADDED
@@ -0,0 +1,688 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of DPLL algorithm
2
+
3
+ Features:
4
+ - Clause learning
5
+ - Watch literal scheme
6
+ - VSIDS heuristic
7
+
8
+ References:
9
+ - https://en.wikipedia.org/wiki/DPLL_algorithm
10
+ """
11
+
12
+ from collections import defaultdict
13
+ from heapq import heappush, heappop
14
+
15
+ from sympy.core.sorting import ordered
16
+ from sympy.assumptions.cnf import EncodedCNF
17
+
18
+ from sympy.logic.algorithms.lra_theory import LRASolver
19
+
20
+
21
+ def dpll_satisfiable(expr, all_models=False, use_lra_theory=False):
22
+ """
23
+ Check satisfiability of a propositional sentence.
24
+ It returns a model rather than True when it succeeds.
25
+ Returns a generator of all models if all_models is True.
26
+
27
+ Examples
28
+ ========
29
+
30
+ >>> from sympy.abc import A, B
31
+ >>> from sympy.logic.algorithms.dpll2 import dpll_satisfiable
32
+ >>> dpll_satisfiable(A & ~B)
33
+ {A: True, B: False}
34
+ >>> dpll_satisfiable(A & ~A)
35
+ False
36
+
37
+ """
38
+ if not isinstance(expr, EncodedCNF):
39
+ exprs = EncodedCNF()
40
+ exprs.add_prop(expr)
41
+ expr = exprs
42
+
43
+ # Return UNSAT when False (encoded as 0) is present in the CNF
44
+ if {0} in expr.data:
45
+ if all_models:
46
+ return (f for f in [False])
47
+ return False
48
+
49
+ if use_lra_theory:
50
+ lra, immediate_conflicts = LRASolver.from_encoded_cnf(expr)
51
+ else:
52
+ lra = None
53
+ immediate_conflicts = []
54
+ solver = SATSolver(expr.data + immediate_conflicts, expr.variables, set(), expr.symbols, lra_theory=lra)
55
+ models = solver._find_model()
56
+
57
+ if all_models:
58
+ return _all_models(models)
59
+
60
+ try:
61
+ return next(models)
62
+ except StopIteration:
63
+ return False
64
+
65
+ # Uncomment to confirm the solution is valid (hitting set for the clauses)
66
+ #else:
67
+ #for cls in clauses_int_repr:
68
+ #assert solver.var_settings.intersection(cls)
69
+
70
+
71
+ def _all_models(models):
72
+ satisfiable = False
73
+ try:
74
+ while True:
75
+ yield next(models)
76
+ satisfiable = True
77
+ except StopIteration:
78
+ if not satisfiable:
79
+ yield False
80
+
81
+
82
+ class SATSolver:
83
+ """
84
+ Class for representing a SAT solver capable of
85
+ finding a model to a boolean theory in conjunctive
86
+ normal form.
87
+ """
88
+
89
+ def __init__(self, clauses, variables, var_settings, symbols=None,
90
+ heuristic='vsids', clause_learning='none', INTERVAL=500,
91
+ lra_theory = None):
92
+
93
+ self.var_settings = var_settings
94
+ self.heuristic = heuristic
95
+ self.is_unsatisfied = False
96
+ self._unit_prop_queue = []
97
+ self.update_functions = []
98
+ self.INTERVAL = INTERVAL
99
+
100
+ if symbols is None:
101
+ self.symbols = list(ordered(variables))
102
+ else:
103
+ self.symbols = symbols
104
+
105
+ self._initialize_variables(variables)
106
+ self._initialize_clauses(clauses)
107
+
108
+ if 'vsids' == heuristic:
109
+ self._vsids_init()
110
+ self.heur_calculate = self._vsids_calculate
111
+ self.heur_lit_assigned = self._vsids_lit_assigned
112
+ self.heur_lit_unset = self._vsids_lit_unset
113
+ self.heur_clause_added = self._vsids_clause_added
114
+
115
+ # Note: Uncomment this if/when clause learning is enabled
116
+ #self.update_functions.append(self._vsids_decay)
117
+
118
+ else:
119
+ raise NotImplementedError
120
+
121
+ if 'simple' == clause_learning:
122
+ self.add_learned_clause = self._simple_add_learned_clause
123
+ self.compute_conflict = self._simple_compute_conflict
124
+ self.update_functions.append(self._simple_clean_clauses)
125
+ elif 'none' == clause_learning:
126
+ self.add_learned_clause = lambda x: None
127
+ self.compute_conflict = lambda: None
128
+ else:
129
+ raise NotImplementedError
130
+
131
+ # Create the base level
132
+ self.levels = [Level(0)]
133
+ self._current_level.varsettings = var_settings
134
+
135
+ # Keep stats
136
+ self.num_decisions = 0
137
+ self.num_learned_clauses = 0
138
+ self.original_num_clauses = len(self.clauses)
139
+
140
+ self.lra = lra_theory
141
+
142
+ def _initialize_variables(self, variables):
143
+ """Set up the variable data structures needed."""
144
+ self.sentinels = defaultdict(set)
145
+ self.occurrence_count = defaultdict(int)
146
+ self.variable_set = [False] * (len(variables) + 1)
147
+
148
+ def _initialize_clauses(self, clauses):
149
+ """Set up the clause data structures needed.
150
+
151
+ For each clause, the following changes are made:
152
+ - Unit clauses are queued for propagation right away.
153
+ - Non-unit clauses have their first and last literals set as sentinels.
154
+ - The number of clauses a literal appears in is computed.
155
+ """
156
+ self.clauses = [list(clause) for clause in clauses]
157
+
158
+ for i, clause in enumerate(self.clauses):
159
+
160
+ # Handle the unit clauses
161
+ if 1 == len(clause):
162
+ self._unit_prop_queue.append(clause[0])
163
+ continue
164
+
165
+ self.sentinels[clause[0]].add(i)
166
+ self.sentinels[clause[-1]].add(i)
167
+
168
+ for lit in clause:
169
+ self.occurrence_count[lit] += 1
170
+
171
+ def _find_model(self):
172
+ """
173
+ Main DPLL loop. Returns a generator of models.
174
+
175
+ Variables are chosen successively, and assigned to be either
176
+ True or False. If a solution is not found with this setting,
177
+ the opposite is chosen and the search continues. The solver
178
+ halts when every variable has a setting.
179
+
180
+ Examples
181
+ ========
182
+
183
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
184
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
185
+ ... {3, -2}], {1, 2, 3}, set())
186
+ >>> list(l._find_model())
187
+ [{1: True, 2: False, 3: False}, {1: True, 2: True, 3: True}]
188
+
189
+ >>> from sympy.abc import A, B, C
190
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
191
+ ... {3, -2}], {1, 2, 3}, set(), [A, B, C])
192
+ >>> list(l._find_model())
193
+ [{A: True, B: False, C: False}, {A: True, B: True, C: True}]
194
+
195
+ """
196
+
197
+ # We use this variable to keep track of if we should flip a
198
+ # variable setting in successive rounds
199
+ flip_var = False
200
+
201
+ # Check if unit prop says the theory is unsat right off the bat
202
+ self._simplify()
203
+ if self.is_unsatisfied:
204
+ return
205
+
206
+ # While the theory still has clauses remaining
207
+ while True:
208
+ # Perform cleanup / fixup at regular intervals
209
+ if self.num_decisions % self.INTERVAL == 0:
210
+ for func in self.update_functions:
211
+ func()
212
+
213
+ if flip_var:
214
+ # We have just backtracked and we are trying to opposite literal
215
+ flip_var = False
216
+ lit = self._current_level.decision
217
+
218
+ else:
219
+ # Pick a literal to set
220
+ lit = self.heur_calculate()
221
+ self.num_decisions += 1
222
+
223
+ # Stopping condition for a satisfying theory
224
+ if 0 == lit:
225
+
226
+ # check if assignment satisfies lra theory
227
+ if self.lra:
228
+ for enc_var in self.var_settings:
229
+ res = self.lra.assert_lit(enc_var)
230
+ if res is not None:
231
+ break
232
+ res = self.lra.check()
233
+ self.lra.reset_bounds()
234
+ else:
235
+ res = None
236
+ if res is None or res[0]:
237
+ yield {self.symbols[abs(lit) - 1]:
238
+ lit > 0 for lit in self.var_settings}
239
+ else:
240
+ self._simple_add_learned_clause(res[1])
241
+
242
+ # backtrack until we unassign one of the literals causing the conflict
243
+ while not any(-lit in res[1] for lit in self._current_level.var_settings):
244
+ self._undo()
245
+
246
+ while self._current_level.flipped:
247
+ self._undo()
248
+ if len(self.levels) == 1:
249
+ return
250
+ flip_lit = -self._current_level.decision
251
+ self._undo()
252
+ self.levels.append(Level(flip_lit, flipped=True))
253
+ flip_var = True
254
+ continue
255
+
256
+ # Start the new decision level
257
+ self.levels.append(Level(lit))
258
+
259
+ # Assign the literal, updating the clauses it satisfies
260
+ self._assign_literal(lit)
261
+
262
+ # _simplify the theory
263
+ self._simplify()
264
+
265
+ # Check if we've made the theory unsat
266
+ if self.is_unsatisfied:
267
+
268
+ self.is_unsatisfied = False
269
+
270
+ # We unroll all of the decisions until we can flip a literal
271
+ while self._current_level.flipped:
272
+ self._undo()
273
+
274
+ # If we've unrolled all the way, the theory is unsat
275
+ if 1 == len(self.levels):
276
+ return
277
+
278
+ # Detect and add a learned clause
279
+ self.add_learned_clause(self.compute_conflict())
280
+
281
+ # Try the opposite setting of the most recent decision
282
+ flip_lit = -self._current_level.decision
283
+ self._undo()
284
+ self.levels.append(Level(flip_lit, flipped=True))
285
+ flip_var = True
286
+
287
+ ########################
288
+ # Helper Methods #
289
+ ########################
290
+ @property
291
+ def _current_level(self):
292
+ """The current decision level data structure
293
+
294
+ Examples
295
+ ========
296
+
297
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
298
+ >>> l = SATSolver([{1}, {2}], {1, 2}, set())
299
+ >>> next(l._find_model())
300
+ {1: True, 2: True}
301
+ >>> l._current_level.decision
302
+ 0
303
+ >>> l._current_level.flipped
304
+ False
305
+ >>> l._current_level.var_settings
306
+ {1, 2}
307
+
308
+ """
309
+ return self.levels[-1]
310
+
311
+ def _clause_sat(self, cls):
312
+ """Check if a clause is satisfied by the current variable setting.
313
+
314
+ Examples
315
+ ========
316
+
317
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
318
+ >>> l = SATSolver([{1}, {-1}], {1}, set())
319
+ >>> try:
320
+ ... next(l._find_model())
321
+ ... except StopIteration:
322
+ ... pass
323
+ >>> l._clause_sat(0)
324
+ False
325
+ >>> l._clause_sat(1)
326
+ True
327
+
328
+ """
329
+ for lit in self.clauses[cls]:
330
+ if lit in self.var_settings:
331
+ return True
332
+ return False
333
+
334
+ def _is_sentinel(self, lit, cls):
335
+ """Check if a literal is a sentinel of a given clause.
336
+
337
+ Examples
338
+ ========
339
+
340
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
341
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
342
+ ... {3, -2}], {1, 2, 3}, set())
343
+ >>> next(l._find_model())
344
+ {1: True, 2: False, 3: False}
345
+ >>> l._is_sentinel(2, 3)
346
+ True
347
+ >>> l._is_sentinel(-3, 1)
348
+ False
349
+
350
+ """
351
+ return cls in self.sentinels[lit]
352
+
353
+ def _assign_literal(self, lit):
354
+ """Make a literal assignment.
355
+
356
+ The literal assignment must be recorded as part of the current
357
+ decision level. Additionally, if the literal is marked as a
358
+ sentinel of any clause, then a new sentinel must be chosen. If
359
+ this is not possible, then unit propagation is triggered and
360
+ another literal is added to the queue to be set in the future.
361
+
362
+ Examples
363
+ ========
364
+
365
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
366
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
367
+ ... {3, -2}], {1, 2, 3}, set())
368
+ >>> next(l._find_model())
369
+ {1: True, 2: False, 3: False}
370
+ >>> l.var_settings
371
+ {-3, -2, 1}
372
+
373
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
374
+ ... {3, -2}], {1, 2, 3}, set())
375
+ >>> l._assign_literal(-1)
376
+ >>> try:
377
+ ... next(l._find_model())
378
+ ... except StopIteration:
379
+ ... pass
380
+ >>> l.var_settings
381
+ {-1}
382
+
383
+ """
384
+ self.var_settings.add(lit)
385
+ self._current_level.var_settings.add(lit)
386
+ self.variable_set[abs(lit)] = True
387
+ self.heur_lit_assigned(lit)
388
+
389
+ sentinel_list = list(self.sentinels[-lit])
390
+
391
+ for cls in sentinel_list:
392
+ if not self._clause_sat(cls):
393
+ other_sentinel = None
394
+ for newlit in self.clauses[cls]:
395
+ if newlit != -lit:
396
+ if self._is_sentinel(newlit, cls):
397
+ other_sentinel = newlit
398
+ elif not self.variable_set[abs(newlit)]:
399
+ self.sentinels[-lit].remove(cls)
400
+ self.sentinels[newlit].add(cls)
401
+ other_sentinel = None
402
+ break
403
+
404
+ # Check if no sentinel update exists
405
+ if other_sentinel:
406
+ self._unit_prop_queue.append(other_sentinel)
407
+
408
+ def _undo(self):
409
+ """
410
+ _undo the changes of the most recent decision level.
411
+
412
+ Examples
413
+ ========
414
+
415
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
416
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
417
+ ... {3, -2}], {1, 2, 3}, set())
418
+ >>> next(l._find_model())
419
+ {1: True, 2: False, 3: False}
420
+ >>> level = l._current_level
421
+ >>> level.decision, level.var_settings, level.flipped
422
+ (-3, {-3, -2}, False)
423
+ >>> l._undo()
424
+ >>> level = l._current_level
425
+ >>> level.decision, level.var_settings, level.flipped
426
+ (0, {1}, False)
427
+
428
+ """
429
+ # Undo the variable settings
430
+ for lit in self._current_level.var_settings:
431
+ self.var_settings.remove(lit)
432
+ self.heur_lit_unset(lit)
433
+ self.variable_set[abs(lit)] = False
434
+
435
+ # Pop the level off the stack
436
+ self.levels.pop()
437
+
438
+ #########################
439
+ # Propagation #
440
+ #########################
441
+ """
442
+ Propagation methods should attempt to soundly simplify the boolean
443
+ theory, and return True if any simplification occurred and False
444
+ otherwise.
445
+ """
446
+ def _simplify(self):
447
+ """Iterate over the various forms of propagation to simplify the theory.
448
+
449
+ Examples
450
+ ========
451
+
452
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
453
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
454
+ ... {3, -2}], {1, 2, 3}, set())
455
+ >>> l.variable_set
456
+ [False, False, False, False]
457
+ >>> l.sentinels
458
+ {-3: {0, 2}, -2: {3, 4}, 2: {0, 3}, 3: {2, 4}}
459
+
460
+ >>> l._simplify()
461
+
462
+ >>> l.variable_set
463
+ [False, True, False, False]
464
+ >>> l.sentinels
465
+ {-3: {0, 2}, -2: {3, 4}, -1: set(), 2: {0, 3},
466
+ ...3: {2, 4}}
467
+
468
+ """
469
+ changed = True
470
+ while changed:
471
+ changed = False
472
+ changed |= self._unit_prop()
473
+ changed |= self._pure_literal()
474
+
475
+ def _unit_prop(self):
476
+ """Perform unit propagation on the current theory."""
477
+ result = len(self._unit_prop_queue) > 0
478
+ while self._unit_prop_queue:
479
+ next_lit = self._unit_prop_queue.pop()
480
+ if -next_lit in self.var_settings:
481
+ self.is_unsatisfied = True
482
+ self._unit_prop_queue = []
483
+ return False
484
+ else:
485
+ self._assign_literal(next_lit)
486
+
487
+ return result
488
+
489
+ def _pure_literal(self):
490
+ """Look for pure literals and assign them when found."""
491
+ return False
492
+
493
+ #########################
494
+ # Heuristics #
495
+ #########################
496
+ def _vsids_init(self):
497
+ """Initialize the data structures needed for the VSIDS heuristic."""
498
+ self.lit_heap = []
499
+ self.lit_scores = {}
500
+
501
+ for var in range(1, len(self.variable_set)):
502
+ self.lit_scores[var] = float(-self.occurrence_count[var])
503
+ self.lit_scores[-var] = float(-self.occurrence_count[-var])
504
+ heappush(self.lit_heap, (self.lit_scores[var], var))
505
+ heappush(self.lit_heap, (self.lit_scores[-var], -var))
506
+
507
+ def _vsids_decay(self):
508
+ """Decay the VSIDS scores for every literal.
509
+
510
+ Examples
511
+ ========
512
+
513
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
514
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
515
+ ... {3, -2}], {1, 2, 3}, set())
516
+
517
+ >>> l.lit_scores
518
+ {-3: -2.0, -2: -2.0, -1: 0.0, 1: 0.0, 2: -2.0, 3: -2.0}
519
+
520
+ >>> l._vsids_decay()
521
+
522
+ >>> l.lit_scores
523
+ {-3: -1.0, -2: -1.0, -1: 0.0, 1: 0.0, 2: -1.0, 3: -1.0}
524
+
525
+ """
526
+ # We divide every literal score by 2 for a decay factor
527
+ # Note: This doesn't change the heap property
528
+ for lit in self.lit_scores.keys():
529
+ self.lit_scores[lit] /= 2.0
530
+
531
+ def _vsids_calculate(self):
532
+ """
533
+ VSIDS Heuristic Calculation
534
+
535
+ Examples
536
+ ========
537
+
538
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
539
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
540
+ ... {3, -2}], {1, 2, 3}, set())
541
+
542
+ >>> l.lit_heap
543
+ [(-2.0, -3), (-2.0, 2), (-2.0, -2), (0.0, 1), (-2.0, 3), (0.0, -1)]
544
+
545
+ >>> l._vsids_calculate()
546
+ -3
547
+
548
+ >>> l.lit_heap
549
+ [(-2.0, -2), (-2.0, 2), (0.0, -1), (0.0, 1), (-2.0, 3)]
550
+
551
+ """
552
+ if len(self.lit_heap) == 0:
553
+ return 0
554
+
555
+ # Clean out the front of the heap as long the variables are set
556
+ while self.variable_set[abs(self.lit_heap[0][1])]:
557
+ heappop(self.lit_heap)
558
+ if len(self.lit_heap) == 0:
559
+ return 0
560
+
561
+ return heappop(self.lit_heap)[1]
562
+
563
+ def _vsids_lit_assigned(self, lit):
564
+ """Handle the assignment of a literal for the VSIDS heuristic."""
565
+ pass
566
+
567
+ def _vsids_lit_unset(self, lit):
568
+ """Handle the unsetting of a literal for the VSIDS heuristic.
569
+
570
+ Examples
571
+ ========
572
+
573
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
574
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
575
+ ... {3, -2}], {1, 2, 3}, set())
576
+ >>> l.lit_heap
577
+ [(-2.0, -3), (-2.0, 2), (-2.0, -2), (0.0, 1), (-2.0, 3), (0.0, -1)]
578
+
579
+ >>> l._vsids_lit_unset(2)
580
+
581
+ >>> l.lit_heap
582
+ [(-2.0, -3), (-2.0, -2), (-2.0, -2), (-2.0, 2), (-2.0, 3), (0.0, -1),
583
+ ...(-2.0, 2), (0.0, 1)]
584
+
585
+ """
586
+ var = abs(lit)
587
+ heappush(self.lit_heap, (self.lit_scores[var], var))
588
+ heappush(self.lit_heap, (self.lit_scores[-var], -var))
589
+
590
+ def _vsids_clause_added(self, cls):
591
+ """Handle the addition of a new clause for the VSIDS heuristic.
592
+
593
+ Examples
594
+ ========
595
+
596
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
597
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
598
+ ... {3, -2}], {1, 2, 3}, set())
599
+
600
+ >>> l.num_learned_clauses
601
+ 0
602
+ >>> l.lit_scores
603
+ {-3: -2.0, -2: -2.0, -1: 0.0, 1: 0.0, 2: -2.0, 3: -2.0}
604
+
605
+ >>> l._vsids_clause_added({2, -3})
606
+
607
+ >>> l.num_learned_clauses
608
+ 1
609
+ >>> l.lit_scores
610
+ {-3: -1.0, -2: -2.0, -1: 0.0, 1: 0.0, 2: -1.0, 3: -2.0}
611
+
612
+ """
613
+ self.num_learned_clauses += 1
614
+ for lit in cls:
615
+ self.lit_scores[lit] += 1
616
+
617
+ ########################
618
+ # Clause Learning #
619
+ ########################
620
+ def _simple_add_learned_clause(self, cls):
621
+ """Add a new clause to the theory.
622
+
623
+ Examples
624
+ ========
625
+
626
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
627
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
628
+ ... {3, -2}], {1, 2, 3}, set())
629
+
630
+ >>> l.num_learned_clauses
631
+ 0
632
+ >>> l.clauses
633
+ [[2, -3], [1], [3, -3], [2, -2], [3, -2]]
634
+ >>> l.sentinels
635
+ {-3: {0, 2}, -2: {3, 4}, 2: {0, 3}, 3: {2, 4}}
636
+
637
+ >>> l._simple_add_learned_clause([3])
638
+
639
+ >>> l.clauses
640
+ [[2, -3], [1], [3, -3], [2, -2], [3, -2], [3]]
641
+ >>> l.sentinels
642
+ {-3: {0, 2}, -2: {3, 4}, 2: {0, 3}, 3: {2, 4, 5}}
643
+
644
+ """
645
+ cls_num = len(self.clauses)
646
+ self.clauses.append(cls)
647
+
648
+ for lit in cls:
649
+ self.occurrence_count[lit] += 1
650
+
651
+ self.sentinels[cls[0]].add(cls_num)
652
+ self.sentinels[cls[-1]].add(cls_num)
653
+
654
+ self.heur_clause_added(cls)
655
+
656
+ def _simple_compute_conflict(self):
657
+ """ Build a clause representing the fact that at least one decision made
658
+ so far is wrong.
659
+
660
+ Examples
661
+ ========
662
+
663
+ >>> from sympy.logic.algorithms.dpll2 import SATSolver
664
+ >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2},
665
+ ... {3, -2}], {1, 2, 3}, set())
666
+ >>> next(l._find_model())
667
+ {1: True, 2: False, 3: False}
668
+ >>> l._simple_compute_conflict()
669
+ [3]
670
+
671
+ """
672
+ return [-(level.decision) for level in self.levels[1:]]
673
+
674
+ def _simple_clean_clauses(self):
675
+ """Clean up learned clauses."""
676
+ pass
677
+
678
+
679
+ class Level:
680
+ """
681
+ Represents a single level in the DPLL algorithm, and contains
682
+ enough information for a sound backtracking procedure.
683
+ """
684
+
685
+ def __init__(self, decision, flipped=False):
686
+ self.decision = decision
687
+ self.var_settings = set()
688
+ self.flipped = flipped
phivenv/Lib/site-packages/sympy/logic/algorithms/lra_theory.py ADDED
@@ -0,0 +1,912 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implements "A Fast Linear-Arithmetic Solver for DPLL(T)"
2
+
3
+ The LRASolver class defined in this file can be used
4
+ in conjunction with a SAT solver to check the
5
+ satisfiability of formulas involving inequalities.
6
+
7
+ Here's an example of how that would work:
8
+
9
+ Suppose you want to check the satisfiability of
10
+ the following formula:
11
+
12
+ >>> from sympy.core.relational import Eq
13
+ >>> from sympy.abc import x, y
14
+ >>> f = ((x > 0) | (x < 0)) & (Eq(x, 0) | Eq(y, 1)) & (~Eq(y, 1) | Eq(1, 2))
15
+
16
+ First a preprocessing step should be done on f. During preprocessing,
17
+ f should be checked for any predicates such as `Q.prime` that can't be
18
+ handled. Also unequality like `~Eq(y, 1)` should be split.
19
+
20
+ I should mention that the paper says to split both equalities and
21
+ unequality, but this implementation only requires that unequality
22
+ be split.
23
+
24
+ >>> f = ((x > 0) | (x < 0)) & (Eq(x, 0) | Eq(y, 1)) & ((y < 1) | (y > 1) | Eq(1, 2))
25
+
26
+ Then an LRASolver instance needs to be initialized with this formula.
27
+
28
+ >>> from sympy.assumptions.cnf import CNF, EncodedCNF
29
+ >>> from sympy.assumptions.ask import Q
30
+ >>> from sympy.logic.algorithms.lra_theory import LRASolver
31
+ >>> cnf = CNF.from_prop(f)
32
+ >>> enc = EncodedCNF()
33
+ >>> enc.add_from_cnf(cnf)
34
+ >>> lra, conflicts = LRASolver.from_encoded_cnf(enc)
35
+
36
+ Any immediate one-lital conflicts clauses will be detected here.
37
+ In this example, `~Eq(1, 2)` is one such conflict clause. We'll
38
+ want to add it to `f` so that the SAT solver is forced to
39
+ assign Eq(1, 2) to False.
40
+
41
+ >>> f = f & ~Eq(1, 2)
42
+
43
+ Now that the one-literal conflict clauses have been added
44
+ and an lra object has been initialized, we can pass `f`
45
+ to a SAT solver. The SAT solver will give us a satisfying
46
+ assignment such as:
47
+
48
+ (1 = 2): False
49
+ (y = 1): True
50
+ (y < 1): True
51
+ (y > 1): True
52
+ (x = 0): True
53
+ (x < 0): True
54
+ (x > 0): True
55
+
56
+ Next you would pass this assignment to the LRASolver
57
+ which will be able to determine that this particular
58
+ assignment is satisfiable or not.
59
+
60
+ Note that since EncodedCNF is inherently non-deterministic,
61
+ the int each predicate is encoded as is not consistent. As a
62
+ result, the code below likely does not reflect the assignment
63
+ given above.
64
+
65
+ >>> lra.assert_lit(-1) #doctest: +SKIP
66
+ >>> lra.assert_lit(2) #doctest: +SKIP
67
+ >>> lra.assert_lit(3) #doctest: +SKIP
68
+ >>> lra.assert_lit(4) #doctest: +SKIP
69
+ >>> lra.assert_lit(5) #doctest: +SKIP
70
+ >>> lra.assert_lit(6) #doctest: +SKIP
71
+ >>> lra.assert_lit(7) #doctest: +SKIP
72
+ >>> is_sat, conflict_or_assignment = lra.check()
73
+
74
+ As the particular assignment suggested is not satisfiable,
75
+ the LRASolver will return unsat and a conflict clause when
76
+ given that assignment. The conflict clause will always be
77
+ minimal, but there can be multiple minimal conflict clauses.
78
+ One possible conflict clause could be `~(x < 0) | ~(x > 0)`.
79
+
80
+ We would then add whatever conflict clause is given to
81
+ `f` to prevent the SAT solver from coming up with an
82
+ assignment with the same conflicting literals. In this case,
83
+ the conflict clause `~(x < 0) | ~(x > 0)` would prevent
84
+ any assignment where both (x < 0) and (x > 0) were both
85
+ true.
86
+
87
+ The SAT solver would then find another assignment
88
+ and we would check that assignment with the LRASolver
89
+ and so on. Eventually either a satisfying assignment
90
+ that the SAT solver and LRASolver agreed on would be found
91
+ or enough conflict clauses would be added so that the
92
+ boolean formula was unsatisfiable.
93
+
94
+
95
+ This implementation is based on [1]_, which includes a
96
+ detailed explanation of the algorithm and pseudocode
97
+ for the most important functions.
98
+
99
+ [1]_ also explains how backtracking and theory propagation
100
+ could be implemented to speed up the current implementation,
101
+ but these are not currently implemented.
102
+
103
+ TODO:
104
+ - Handle non-rational real numbers
105
+ - Handle positive and negative infinity
106
+ - Implement backtracking and theory proposition
107
+ - Simplify matrix by removing unused variables using Gaussian elimination
108
+
109
+ References
110
+ ==========
111
+
112
+ .. [1] Dutertre, B., de Moura, L.:
113
+ A Fast Linear-Arithmetic Solver for DPLL(T)
114
+ https://link.springer.com/chapter/10.1007/11817963_11
115
+ """
116
+ from sympy.solvers.solveset import linear_eq_to_matrix
117
+ from sympy.matrices.dense import eye
118
+ from sympy.assumptions import Predicate
119
+ from sympy.assumptions.assume import AppliedPredicate
120
+ from sympy.assumptions.ask import Q
121
+ from sympy.core import Dummy
122
+ from sympy.core.mul import Mul
123
+ from sympy.core.add import Add
124
+ from sympy.core.relational import Eq, Ne
125
+ from sympy.core.sympify import sympify
126
+ from sympy.core.singleton import S
127
+ from sympy.core.numbers import Rational, oo
128
+ from sympy.matrices.dense import Matrix
129
+
130
+ class UnhandledInput(Exception):
131
+ """
132
+ Raised while creating an LRASolver if non-linearity
133
+ or non-rational numbers are present.
134
+ """
135
+
136
+ # predicates that LRASolver understands and makes use of
137
+ ALLOWED_PRED = {Q.eq, Q.gt, Q.lt, Q.le, Q.ge}
138
+
139
+ # if true ~Q.gt(x, y) implies Q.le(x, y)
140
+ HANDLE_NEGATION = True
141
+
142
+ class LRASolver():
143
+ """
144
+ Linear Arithmetic Solver for DPLL(T) implemented with an algorithm based on
145
+ the Dual Simplex method. Uses Bland's pivoting rule to avoid cycling.
146
+
147
+ References
148
+ ==========
149
+
150
+ .. [1] Dutertre, B., de Moura, L.:
151
+ A Fast Linear-Arithmetic Solver for DPLL(T)
152
+ https://link.springer.com/chapter/10.1007/11817963_11
153
+ """
154
+
155
+ def __init__(self, A, slack_variables, nonslack_variables, enc_to_boundary, s_subs, testing_mode):
156
+ """
157
+ Use the "from_encoded_cnf" method to create a new LRASolver.
158
+ """
159
+ self.run_checks = testing_mode
160
+ self.s_subs = s_subs # used only for test_lra_theory.test_random_problems
161
+
162
+ if any(not isinstance(a, Rational) for a in A):
163
+ raise UnhandledInput("Non-rational numbers are not handled")
164
+ if any(not isinstance(b.bound, Rational) for b in enc_to_boundary.values()):
165
+ raise UnhandledInput("Non-rational numbers are not handled")
166
+ m, n = len(slack_variables), len(slack_variables)+len(nonslack_variables)
167
+ if m != 0:
168
+ assert A.shape == (m, n)
169
+ if self.run_checks:
170
+ assert A[:, n-m:] == -eye(m)
171
+
172
+ self.enc_to_boundary = enc_to_boundary # mapping of int to Boundary objects
173
+ self.boundary_to_enc = {value: key for key, value in enc_to_boundary.items()}
174
+ self.A = A
175
+ self.slack = slack_variables
176
+ self.nonslack = nonslack_variables
177
+ self.all_var = nonslack_variables + slack_variables
178
+
179
+ self.slack_set = set(slack_variables)
180
+
181
+ self.is_sat = True # While True, all constraints asserted so far are satisfiable
182
+ self.result = None # always one of: (True, assignment), (False, conflict clause), None
183
+
184
+ @staticmethod
185
+ def from_encoded_cnf(encoded_cnf, testing_mode=False):
186
+ """
187
+ Creates an LRASolver from an EncodedCNF object
188
+ and a list of conflict clauses for propositions
189
+ that can be simplified to True or False.
190
+
191
+ Parameters
192
+ ==========
193
+
194
+ encoded_cnf : EncodedCNF
195
+
196
+ testing_mode : bool
197
+ Setting testing_mode to True enables some slow assert statements
198
+ and sorting to reduce nonterministic behavior.
199
+
200
+ Returns
201
+ =======
202
+
203
+ (lra, conflicts)
204
+
205
+ lra : LRASolver
206
+
207
+ conflicts : list
208
+ Contains a one-literal conflict clause for each proposition
209
+ that can be simplified to True or False.
210
+
211
+ Example
212
+ =======
213
+
214
+ >>> from sympy.core.relational import Eq
215
+ >>> from sympy.assumptions.cnf import CNF, EncodedCNF
216
+ >>> from sympy.assumptions.ask import Q
217
+ >>> from sympy.logic.algorithms.lra_theory import LRASolver
218
+ >>> from sympy.abc import x, y, z
219
+ >>> phi = (x >= 0) & ((x + y <= 2) | (x + 2 * y - z >= 6))
220
+ >>> phi = phi & (Eq(x + y, 2) | (x + 2 * y - z > 4))
221
+ >>> phi = phi & Q.gt(2, 1)
222
+ >>> cnf = CNF.from_prop(phi)
223
+ >>> enc = EncodedCNF()
224
+ >>> enc.from_cnf(cnf)
225
+ >>> lra, conflicts = LRASolver.from_encoded_cnf(enc, testing_mode=True)
226
+ >>> lra #doctest: +SKIP
227
+ <sympy.logic.algorithms.lra_theory.LRASolver object at 0x7fdcb0e15b70>
228
+ >>> conflicts #doctest: +SKIP
229
+ [[4]]
230
+ """
231
+ # This function has three main jobs:
232
+ # - raise errors if the input formula is not handled
233
+ # - preprocesses the formula into a matrix and single variable constraints
234
+ # - create one-literal conflict clauses from predicates that are always True
235
+ # or always False such as Q.gt(3, 2)
236
+ #
237
+ # See the preprocessing section of "A Fast Linear-Arithmetic Solver for DPLL(T)"
238
+ # for an explanation of how the formula is converted into a matrix
239
+ # and a set of single variable constraints.
240
+
241
+ encoding = {} # maps int to boundary
242
+ A = []
243
+
244
+ basic = []
245
+ s_count = 0
246
+ s_subs = {}
247
+ nonbasic = []
248
+
249
+ if testing_mode:
250
+ # sort to reduce nondeterminism
251
+ encoded_cnf_items = sorted(encoded_cnf.encoding.items(), key=lambda x: str(x))
252
+ else:
253
+ encoded_cnf_items = encoded_cnf.encoding.items()
254
+
255
+ empty_var = Dummy()
256
+ var_to_lra_var = {}
257
+ conflicts = []
258
+
259
+ for prop, enc in encoded_cnf_items:
260
+ if isinstance(prop, Predicate):
261
+ prop = prop(empty_var)
262
+ if not isinstance(prop, AppliedPredicate):
263
+ if prop == True:
264
+ conflicts.append([enc])
265
+ continue
266
+ if prop == False:
267
+ conflicts.append([-enc])
268
+ continue
269
+
270
+ raise ValueError(f"Unhandled Predicate: {prop}")
271
+
272
+ assert prop.function in ALLOWED_PRED
273
+ if prop.lhs == S.NaN or prop.rhs == S.NaN:
274
+ raise ValueError(f"{prop} contains nan")
275
+ if prop.lhs.is_imaginary or prop.rhs.is_imaginary:
276
+ raise UnhandledInput(f"{prop} contains an imaginary component")
277
+ if prop.lhs == oo or prop.rhs == oo:
278
+ raise UnhandledInput(f"{prop} contains infinity")
279
+
280
+ prop = _eval_binrel(prop) # simplify variable-less quantities to True / False if possible
281
+ if prop == True:
282
+ conflicts.append([enc])
283
+ continue
284
+ elif prop == False:
285
+ conflicts.append([-enc])
286
+ continue
287
+ elif prop is None:
288
+ raise UnhandledInput(f"{prop} could not be simplified")
289
+
290
+ expr = prop.lhs - prop.rhs
291
+ if prop.function in [Q.ge, Q.gt]:
292
+ expr = -expr
293
+
294
+ # expr should be less than (or equal to) 0
295
+ # otherwise prop is False
296
+ if prop.function in [Q.le, Q.ge]:
297
+ bool = (expr <= 0)
298
+ elif prop.function in [Q.lt, Q.gt]:
299
+ bool = (expr < 0)
300
+ else:
301
+ assert prop.function == Q.eq
302
+ bool = Eq(expr, 0)
303
+
304
+ if bool == True:
305
+ conflicts.append([enc])
306
+ continue
307
+ elif bool == False:
308
+ conflicts.append([-enc])
309
+ continue
310
+
311
+
312
+ vars, const = _sep_const_terms(expr) # example: (2x + 3y + 2) --> (2x + 3y), (2)
313
+ vars, var_coeff = _sep_const_coeff(vars) # examples: (2x) --> (x, 2); (2x + 3y) --> (2x + 3y), (1)
314
+ const = const / var_coeff
315
+
316
+ terms = _list_terms(vars) # example: (2x + 3y) --> [2x, 3y]
317
+ for term in terms:
318
+ term, _ = _sep_const_coeff(term)
319
+ assert len(term.free_symbols) > 0
320
+ if term not in var_to_lra_var:
321
+ var_to_lra_var[term] = LRAVariable(term)
322
+ nonbasic.append(term)
323
+
324
+ if len(terms) > 1:
325
+ if vars not in s_subs:
326
+ s_count += 1
327
+ d = Dummy(f"s{s_count}")
328
+ var_to_lra_var[d] = LRAVariable(d)
329
+ basic.append(d)
330
+ s_subs[vars] = d
331
+ A.append(vars - d)
332
+ var = s_subs[vars]
333
+ else:
334
+ var = terms[0]
335
+
336
+ assert var_coeff != 0
337
+
338
+ equality = prop.function == Q.eq
339
+ upper = var_coeff > 0 if not equality else None
340
+ strict = prop.function in [Q.gt, Q.lt]
341
+ b = Boundary(var_to_lra_var[var], -const, upper, equality, strict)
342
+ encoding[enc] = b
343
+
344
+ fs = [v.free_symbols for v in nonbasic + basic]
345
+ assert all(len(syms) > 0 for syms in fs)
346
+ fs_count = sum(len(syms) for syms in fs)
347
+ if len(fs) > 0 and len(set.union(*fs)) < fs_count:
348
+ raise UnhandledInput("Nonlinearity is not handled")
349
+
350
+ A, _ = linear_eq_to_matrix(A, nonbasic + basic)
351
+ nonbasic = [var_to_lra_var[nb] for nb in nonbasic]
352
+ basic = [var_to_lra_var[b] for b in basic]
353
+ for idx, var in enumerate(nonbasic + basic):
354
+ var.col_idx = idx
355
+
356
+ return LRASolver(A, basic, nonbasic, encoding, s_subs, testing_mode), conflicts
357
+
358
+ def reset_bounds(self):
359
+ """
360
+ Resets the state of the LRASolver to before
361
+ anything was asserted.
362
+ """
363
+ self.result = None
364
+ for var in self.all_var:
365
+ var.lower = LRARational(-float("inf"), 0)
366
+ var.lower_from_eq = False
367
+ var.lower_from_neg = False
368
+ var.upper = LRARational(float("inf"), 0)
369
+ var.upper_from_eq= False
370
+ var.lower_from_neg = False
371
+ var.assign = LRARational(0, 0)
372
+
373
+ def assert_lit(self, enc_constraint):
374
+ """
375
+ Assert a literal representing a constraint
376
+ and update the internal state accordingly.
377
+
378
+ Note that due to peculiarities of this implementation
379
+ asserting ~(x > 0) will assert (x <= 0) but asserting
380
+ ~Eq(x, 0) will not do anything.
381
+
382
+ Parameters
383
+ ==========
384
+
385
+ enc_constraint : int
386
+ A mapping of encodings to constraints
387
+ can be found in `self.enc_to_boundary`.
388
+
389
+ Returns
390
+ =======
391
+
392
+ None or (False, explanation)
393
+
394
+ explanation : set of ints
395
+ A conflict clause that "explains" why
396
+ the literals asserted so far are unsatisfiable.
397
+ """
398
+ if abs(enc_constraint) not in self.enc_to_boundary:
399
+ return None
400
+
401
+ if not HANDLE_NEGATION and enc_constraint < 0:
402
+ return None
403
+
404
+ boundary = self.enc_to_boundary[abs(enc_constraint)]
405
+ sym, c, negated = boundary.var, boundary.bound, enc_constraint < 0
406
+
407
+ if boundary.equality and negated:
408
+ return None # negated equality is not handled and should only appear in conflict clauses
409
+
410
+ upper = boundary.upper != negated
411
+ if boundary.strict != negated:
412
+ delta = -1 if upper else 1
413
+ c = LRARational(c, delta)
414
+ else:
415
+ c = LRARational(c, 0)
416
+
417
+ if boundary.equality:
418
+ res1 = self._assert_lower(sym, c, from_equality=True, from_neg=negated)
419
+ if res1 and res1[0] == False:
420
+ res = res1
421
+ else:
422
+ res2 = self._assert_upper(sym, c, from_equality=True, from_neg=negated)
423
+ res = res2
424
+ elif upper:
425
+ res = self._assert_upper(sym, c, from_neg=negated)
426
+ else:
427
+ res = self._assert_lower(sym, c, from_neg=negated)
428
+
429
+ if self.is_sat and sym not in self.slack_set:
430
+ self.is_sat = res is None
431
+ else:
432
+ self.is_sat = False
433
+
434
+ return res
435
+
436
+ def _assert_upper(self, xi, ci, from_equality=False, from_neg=False):
437
+ """
438
+ Adjusts the upper bound on variable xi if the new upper bound is
439
+ more limiting. The assignment of variable xi is adjusted to be
440
+ within the new bound if needed.
441
+
442
+ Also calls `self._update` to update the assignment for slack variables
443
+ to keep all equalities satisfied.
444
+ """
445
+ if self.result:
446
+ assert self.result[0] != False
447
+ self.result = None
448
+ if ci >= xi.upper:
449
+ return None
450
+ if ci < xi.lower:
451
+ assert (xi.lower[1] >= 0) is True
452
+ assert (ci[1] <= 0) is True
453
+
454
+ lit1, neg1 = Boundary.from_lower(xi)
455
+
456
+ lit2 = Boundary(var=xi, const=ci[0], strict=ci[1] != 0, upper=True, equality=from_equality)
457
+ if from_neg:
458
+ lit2 = lit2.get_negated()
459
+ neg2 = -1 if from_neg else 1
460
+
461
+ conflict = [-neg1*self.boundary_to_enc[lit1], -neg2*self.boundary_to_enc[lit2]]
462
+ self.result = False, conflict
463
+ return self.result
464
+ xi.upper = ci
465
+ xi.upper_from_eq = from_equality
466
+ xi.upper_from_neg = from_neg
467
+ if xi in self.nonslack and xi.assign > ci:
468
+ self._update(xi, ci)
469
+
470
+ if self.run_checks and all(v.assign[0] != float("inf") and v.assign[0] != -float("inf")
471
+ for v in self.all_var):
472
+ M = self.A
473
+ X = Matrix([v.assign[0] for v in self.all_var])
474
+ assert all(abs(val) < 10 ** (-10) for val in M * X)
475
+
476
+ return None
477
+
478
+ def _assert_lower(self, xi, ci, from_equality=False, from_neg=False):
479
+ """
480
+ Adjusts the lower bound on variable xi if the new lower bound is
481
+ more limiting. The assignment of variable xi is adjusted to be
482
+ within the new bound if needed.
483
+
484
+ Also calls `self._update` to update the assignment for slack variables
485
+ to keep all equalities satisfied.
486
+ """
487
+ if self.result:
488
+ assert self.result[0] != False
489
+ self.result = None
490
+ if ci <= xi.lower:
491
+ return None
492
+ if ci > xi.upper:
493
+ assert (xi.upper[1] <= 0) is True
494
+ assert (ci[1] >= 0) is True
495
+
496
+ lit1, neg1 = Boundary.from_upper(xi)
497
+
498
+ lit2 = Boundary(var=xi, const=ci[0], strict=ci[1] != 0, upper=False, equality=from_equality)
499
+ if from_neg:
500
+ lit2 = lit2.get_negated()
501
+ neg2 = -1 if from_neg else 1
502
+
503
+ conflict = [-neg1*self.boundary_to_enc[lit1],-neg2*self.boundary_to_enc[lit2]]
504
+ self.result = False, conflict
505
+ return self.result
506
+ xi.lower = ci
507
+ xi.lower_from_eq = from_equality
508
+ xi.lower_from_neg = from_neg
509
+ if xi in self.nonslack and xi.assign < ci:
510
+ self._update(xi, ci)
511
+
512
+ if self.run_checks and all(v.assign[0] != float("inf") and v.assign[0] != -float("inf")
513
+ for v in self.all_var):
514
+ M = self.A
515
+ X = Matrix([v.assign[0] for v in self.all_var])
516
+ assert all(abs(val) < 10 ** (-10) for val in M * X)
517
+
518
+ return None
519
+
520
+ def _update(self, xi, v):
521
+ """
522
+ Updates all slack variables that have equations that contain
523
+ variable xi so that they stay satisfied given xi is equal to v.
524
+ """
525
+ i = xi.col_idx
526
+ for j, b in enumerate(self.slack):
527
+ aji = self.A[j, i]
528
+ b.assign = b.assign + (v - xi.assign)*aji
529
+ xi.assign = v
530
+
531
+ def check(self):
532
+ """
533
+ Searches for an assignment that satisfies all constraints
534
+ or determines that no such assignment exists and gives
535
+ a minimal conflict clause that "explains" why the
536
+ constraints are unsatisfiable.
537
+
538
+ Returns
539
+ =======
540
+
541
+ (True, assignment) or (False, explanation)
542
+
543
+ assignment : dict of LRAVariables to values
544
+ Assigned values are tuples that represent a rational number
545
+ plus some infinatesimal delta.
546
+
547
+ explanation : set of ints
548
+ """
549
+ if self.is_sat:
550
+ return True, {var: var.assign for var in self.all_var}
551
+ if self.result:
552
+ return self.result
553
+
554
+ from sympy.matrices.dense import Matrix
555
+ M = self.A.copy()
556
+ basic = {s: i for i, s in enumerate(self.slack)} # contains the row index associated with each basic variable
557
+ nonbasic = set(self.nonslack)
558
+ while True:
559
+ if self.run_checks:
560
+ # nonbasic variables must always be within bounds
561
+ assert all(((nb.assign >= nb.lower) == True) and ((nb.assign <= nb.upper) == True) for nb in nonbasic)
562
+
563
+ # assignments for x must always satisfy Ax = 0
564
+ # probably have to turn this off when dealing with strict ineq
565
+ if all(v.assign[0] != float("inf") and v.assign[0] != -float("inf")
566
+ for v in self.all_var):
567
+ X = Matrix([v.assign[0] for v in self.all_var])
568
+ assert all(abs(val) < 10**(-10) for val in M*X)
569
+
570
+ # check upper and lower match this format:
571
+ # x <= rat + delta iff x < rat
572
+ # x >= rat - delta iff x > rat
573
+ # this wouldn't make sense:
574
+ # x <= rat - delta
575
+ # x >= rat + delta
576
+ assert all(x.upper[1] <= 0 for x in self.all_var)
577
+ assert all(x.lower[1] >= 0 for x in self.all_var)
578
+
579
+ cand = [b for b in basic if b.assign < b.lower or b.assign > b.upper]
580
+
581
+ if len(cand) == 0:
582
+ return True, {var: var.assign for var in self.all_var}
583
+
584
+ xi = min(cand, key=lambda v: v.col_idx) # Bland's rule
585
+ i = basic[xi]
586
+
587
+ if xi.assign < xi.lower:
588
+ cand = [nb for nb in nonbasic
589
+ if (M[i, nb.col_idx] > 0 and nb.assign < nb.upper)
590
+ or (M[i, nb.col_idx] < 0 and nb.assign > nb.lower)]
591
+ if len(cand) == 0:
592
+ N_plus = [nb for nb in nonbasic if M[i, nb.col_idx] > 0]
593
+ N_minus = [nb for nb in nonbasic if M[i, nb.col_idx] < 0]
594
+
595
+ conflict = []
596
+ conflict += [Boundary.from_upper(nb) for nb in N_plus]
597
+ conflict += [Boundary.from_lower(nb) for nb in N_minus]
598
+ conflict.append(Boundary.from_lower(xi))
599
+ conflict = [-neg*self.boundary_to_enc[c] for c, neg in conflict]
600
+ return False, conflict
601
+ xj = min(cand, key=str)
602
+ M = self._pivot_and_update(M, basic, nonbasic, xi, xj, xi.lower)
603
+
604
+ if xi.assign > xi.upper:
605
+ cand = [nb for nb in nonbasic
606
+ if (M[i, nb.col_idx] < 0 and nb.assign < nb.upper)
607
+ or (M[i, nb.col_idx] > 0 and nb.assign > nb.lower)]
608
+
609
+ if len(cand) == 0:
610
+ N_plus = [nb for nb in nonbasic if M[i, nb.col_idx] > 0]
611
+ N_minus = [nb for nb in nonbasic if M[i, nb.col_idx] < 0]
612
+
613
+ conflict = []
614
+ conflict += [Boundary.from_upper(nb) for nb in N_minus]
615
+ conflict += [Boundary.from_lower(nb) for nb in N_plus]
616
+ conflict.append(Boundary.from_upper(xi))
617
+
618
+ conflict = [-neg*self.boundary_to_enc[c] for c, neg in conflict]
619
+ return False, conflict
620
+ xj = min(cand, key=lambda v: v.col_idx)
621
+ M = self._pivot_and_update(M, basic, nonbasic, xi, xj, xi.upper)
622
+
623
+ def _pivot_and_update(self, M, basic, nonbasic, xi, xj, v):
624
+ """
625
+ Pivots basic variable xi with nonbasic variable xj,
626
+ and sets value of xi to v and adjusts the values of all basic variables
627
+ to keep equations satisfied.
628
+ """
629
+ i, j = basic[xi], xj.col_idx
630
+ assert M[i, j] != 0
631
+ theta = (v - xi.assign)*(1/M[i, j])
632
+ xi.assign = v
633
+ xj.assign = xj.assign + theta
634
+ for xk in basic:
635
+ if xk != xi:
636
+ k = basic[xk]
637
+ akj = M[k, j]
638
+ xk.assign = xk.assign + theta*akj
639
+ # pivot
640
+ basic[xj] = basic[xi]
641
+ del basic[xi]
642
+ nonbasic.add(xi)
643
+ nonbasic.remove(xj)
644
+ return self._pivot(M, i, j)
645
+
646
+ @staticmethod
647
+ def _pivot(M, i, j):
648
+ """
649
+ Performs a pivot operation about entry i, j of M by performing
650
+ a series of row operations on a copy of M and returning the result.
651
+ The original M is left unmodified.
652
+
653
+ Conceptually, M represents a system of equations and pivoting
654
+ can be thought of as rearranging equation i to be in terms of
655
+ variable j and then substituting in the rest of the equations
656
+ to get rid of other occurances of variable j.
657
+
658
+ Example
659
+ =======
660
+
661
+ >>> from sympy.matrices.dense import Matrix
662
+ >>> from sympy.logic.algorithms.lra_theory import LRASolver
663
+ >>> from sympy import var
664
+ >>> Matrix(3, 3, var('a:i'))
665
+ Matrix([
666
+ [a, b, c],
667
+ [d, e, f],
668
+ [g, h, i]])
669
+
670
+ This matrix is equivalent to:
671
+ 0 = a*x + b*y + c*z
672
+ 0 = d*x + e*y + f*z
673
+ 0 = g*x + h*y + i*z
674
+
675
+ >>> LRASolver._pivot(_, 1, 0)
676
+ Matrix([
677
+ [ 0, -a*e/d + b, -a*f/d + c],
678
+ [-1, -e/d, -f/d],
679
+ [ 0, h - e*g/d, i - f*g/d]])
680
+
681
+ We rearrange equation 1 in terms of variable 0 (x)
682
+ and substitute to remove x from the other equations.
683
+
684
+ 0 = 0 + (-a*e/d + b)*y + (-a*f/d + c)*z
685
+ 0 = -x + (-e/d)*y + (-f/d)*z
686
+ 0 = 0 + (h - e*g/d)*y + (i - f*g/d)*z
687
+ """
688
+ _, _, Mij = M[i, :], M[:, j], M[i, j]
689
+ if Mij == 0:
690
+ raise ZeroDivisionError("Tried to pivot about zero-valued entry.")
691
+ A = M.copy()
692
+ A[i, :] = -A[i, :]/Mij
693
+ for row in range(M.shape[0]):
694
+ if row != i:
695
+ A[row, :] = A[row, :] + A[row, j] * A[i, :]
696
+
697
+ return A
698
+
699
+
700
+ def _sep_const_coeff(expr):
701
+ """
702
+ Example
703
+ =======
704
+
705
+ >>> from sympy.logic.algorithms.lra_theory import _sep_const_coeff
706
+ >>> from sympy.abc import x, y
707
+ >>> _sep_const_coeff(2*x)
708
+ (x, 2)
709
+ >>> _sep_const_coeff(2*x + 3*y)
710
+ (2*x + 3*y, 1)
711
+ """
712
+ if isinstance(expr, Add):
713
+ return expr, sympify(1)
714
+
715
+ if isinstance(expr, Mul):
716
+ coeffs = expr.args
717
+ else:
718
+ coeffs = [expr]
719
+
720
+ var, const = [], []
721
+ for c in coeffs:
722
+ c = sympify(c)
723
+ if len(c.free_symbols)==0:
724
+ const.append(c)
725
+ else:
726
+ var.append(c)
727
+ return Mul(*var), Mul(*const)
728
+
729
+
730
+ def _list_terms(expr):
731
+ if not isinstance(expr, Add):
732
+ return [expr]
733
+
734
+ return expr.args
735
+
736
+
737
+ def _sep_const_terms(expr):
738
+ """
739
+ Example
740
+ =======
741
+
742
+ >>> from sympy.logic.algorithms.lra_theory import _sep_const_terms
743
+ >>> from sympy.abc import x, y
744
+ >>> _sep_const_terms(2*x + 3*y + 2)
745
+ (2*x + 3*y, 2)
746
+ """
747
+ if isinstance(expr, Add):
748
+ terms = expr.args
749
+ else:
750
+ terms = [expr]
751
+
752
+ var, const = [], []
753
+ for t in terms:
754
+ if len(t.free_symbols) == 0:
755
+ const.append(t)
756
+ else:
757
+ var.append(t)
758
+ return sum(var), sum(const)
759
+
760
+
761
+ def _eval_binrel(binrel):
762
+ """
763
+ Simplify binary relation to True / False if possible.
764
+ """
765
+ if not (len(binrel.lhs.free_symbols) == 0 and len(binrel.rhs.free_symbols) == 0):
766
+ return binrel
767
+ if binrel.function == Q.lt:
768
+ res = binrel.lhs < binrel.rhs
769
+ elif binrel.function == Q.gt:
770
+ res = binrel.lhs > binrel.rhs
771
+ elif binrel.function == Q.le:
772
+ res = binrel.lhs <= binrel.rhs
773
+ elif binrel.function == Q.ge:
774
+ res = binrel.lhs >= binrel.rhs
775
+ elif binrel.function == Q.eq:
776
+ res = Eq(binrel.lhs, binrel.rhs)
777
+ elif binrel.function == Q.ne:
778
+ res = Ne(binrel.lhs, binrel.rhs)
779
+
780
+ if res == True or res == False:
781
+ return res
782
+ else:
783
+ return None
784
+
785
+
786
+ class Boundary:
787
+ """
788
+ Represents an upper or lower bound or an equality between a symbol
789
+ and some constant.
790
+ """
791
+ def __init__(self, var, const, upper, equality, strict=None):
792
+ if not equality in [True, False]:
793
+ assert equality in [True, False]
794
+
795
+
796
+ self.var = var
797
+ if isinstance(const, tuple):
798
+ s = const[1] != 0
799
+ if strict:
800
+ assert s == strict
801
+ self.bound = const[0]
802
+ self.strict = s
803
+ else:
804
+ self.bound = const
805
+ self.strict = strict
806
+ self.upper = upper if not equality else None
807
+ self.equality = equality
808
+ self.strict = strict
809
+ assert self.strict is not None
810
+
811
+ @staticmethod
812
+ def from_upper(var):
813
+ neg = -1 if var.upper_from_neg else 1
814
+ b = Boundary(var, var.upper[0], True, var.upper_from_eq, var.upper[1] != 0)
815
+ if neg < 0:
816
+ b = b.get_negated()
817
+ return b, neg
818
+
819
+ @staticmethod
820
+ def from_lower(var):
821
+ neg = -1 if var.lower_from_neg else 1
822
+ b = Boundary(var, var.lower[0], False, var.lower_from_eq, var.lower[1] != 0)
823
+ if neg < 0:
824
+ b = b.get_negated()
825
+ return b, neg
826
+
827
+ def get_negated(self):
828
+ return Boundary(self.var, self.bound, not self.upper, self.equality, not self.strict)
829
+
830
+ def get_inequality(self):
831
+ if self.equality:
832
+ return Eq(self.var.var, self.bound)
833
+ elif self.upper and self.strict:
834
+ return self.var.var < self.bound
835
+ elif not self.upper and self.strict:
836
+ return self.var.var > self.bound
837
+ elif self.upper:
838
+ return self.var.var <= self.bound
839
+ else:
840
+ return self.var.var >= self.bound
841
+
842
+ def __repr__(self):
843
+ return repr("Boundary(" + repr(self.get_inequality()) + ")")
844
+
845
+ def __eq__(self, other):
846
+ other = (other.var, other.bound, other.strict, other.upper, other.equality)
847
+ return (self.var, self.bound, self.strict, self.upper, self.equality) == other
848
+
849
+ def __hash__(self):
850
+ return hash((self.var, self.bound, self.strict, self.upper, self.equality))
851
+
852
+
853
+ class LRARational():
854
+ """
855
+ Represents a rational plus or minus some amount
856
+ of arbitrary small deltas.
857
+ """
858
+ def __init__(self, rational, delta):
859
+ self.value = (rational, delta)
860
+
861
+ def __lt__(self, other):
862
+ return self.value < other.value
863
+
864
+ def __le__(self, other):
865
+ return self.value <= other.value
866
+
867
+ def __eq__(self, other):
868
+ return self.value == other.value
869
+
870
+ def __add__(self, other):
871
+ return LRARational(self.value[0] + other.value[0], self.value[1] + other.value[1])
872
+
873
+ def __sub__(self, other):
874
+ return LRARational(self.value[0] - other.value[0], self.value[1] - other.value[1])
875
+
876
+ def __mul__(self, other):
877
+ assert not isinstance(other, LRARational)
878
+ return LRARational(self.value[0] * other, self.value[1] * other)
879
+
880
+ def __getitem__(self, index):
881
+ return self.value[index]
882
+
883
+ def __repr__(self):
884
+ return repr(self.value)
885
+
886
+
887
+ class LRAVariable():
888
+ """
889
+ Object to keep track of upper and lower bounds
890
+ on `self.var`.
891
+ """
892
+ def __init__(self, var):
893
+ self.upper = LRARational(float("inf"), 0)
894
+ self.upper_from_eq = False
895
+ self.upper_from_neg = False
896
+ self.lower = LRARational(-float("inf"), 0)
897
+ self.lower_from_eq = False
898
+ self.lower_from_neg = False
899
+ self.assign = LRARational(0,0)
900
+ self.var = var
901
+ self.col_idx = None
902
+
903
+ def __repr__(self):
904
+ return repr(self.var)
905
+
906
+ def __eq__(self, other):
907
+ if not isinstance(other, LRAVariable):
908
+ return False
909
+ return other.var == self.var
910
+
911
+ def __hash__(self):
912
+ return hash(self.var)
phivenv/Lib/site-packages/sympy/logic/algorithms/minisat22_wrapper.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions.cnf import EncodedCNF
2
+
3
+ def minisat22_satisfiable(expr, all_models=False, minimal=False):
4
+
5
+ if not isinstance(expr, EncodedCNF):
6
+ exprs = EncodedCNF()
7
+ exprs.add_prop(expr)
8
+ expr = exprs
9
+
10
+ from pysat.solvers import Minisat22
11
+
12
+ # Return UNSAT when False (encoded as 0) is present in the CNF
13
+ if {0} in expr.data:
14
+ if all_models:
15
+ return (f for f in [False])
16
+ return False
17
+
18
+ r = Minisat22(expr.data)
19
+
20
+ if minimal:
21
+ r.set_phases([-(i+1) for i in range(r.nof_vars())])
22
+
23
+ if not r.solve():
24
+ return False
25
+
26
+ if not all_models:
27
+ return {expr.symbols[abs(lit) - 1]: lit > 0 for lit in r.get_model()}
28
+
29
+ else:
30
+ # Make solutions SymPy compatible by creating a generator
31
+ def _gen(results):
32
+ satisfiable = False
33
+ while results.solve():
34
+ sol = results.get_model()
35
+ yield {expr.symbols[abs(lit) - 1]: lit > 0 for lit in sol}
36
+ if minimal:
37
+ results.add_clause([-i for i in sol if i>0])
38
+ else:
39
+ results.add_clause([-i for i in sol])
40
+ satisfiable = True
41
+ if not satisfiable:
42
+ yield False
43
+ raise StopIteration
44
+
45
+
46
+ return _gen(r)
phivenv/Lib/site-packages/sympy/logic/algorithms/pycosat_wrapper.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions.cnf import EncodedCNF
2
+
3
+
4
+ def pycosat_satisfiable(expr, all_models=False):
5
+ import pycosat
6
+ if not isinstance(expr, EncodedCNF):
7
+ exprs = EncodedCNF()
8
+ exprs.add_prop(expr)
9
+ expr = exprs
10
+
11
+ # Return UNSAT when False (encoded as 0) is present in the CNF
12
+ if {0} in expr.data:
13
+ if all_models:
14
+ return (f for f in [False])
15
+ return False
16
+
17
+ if not all_models:
18
+ r = pycosat.solve(expr.data)
19
+ result = (r != "UNSAT")
20
+ if not result:
21
+ return result
22
+ return {expr.symbols[abs(lit) - 1]: lit > 0 for lit in r}
23
+ else:
24
+ r = pycosat.itersolve(expr.data)
25
+ result = (r != "UNSAT")
26
+ if not result:
27
+ return result
28
+
29
+ # Make solutions SymPy compatible by creating a generator
30
+ def _gen(results):
31
+ satisfiable = False
32
+ try:
33
+ while True:
34
+ sol = next(results)
35
+ yield {expr.symbols[abs(lit) - 1]: lit > 0 for lit in sol}
36
+ satisfiable = True
37
+ except StopIteration:
38
+ if not satisfiable:
39
+ yield False
40
+
41
+ return _gen(r)
phivenv/Lib/site-packages/sympy/logic/algorithms/z3_wrapper.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.printing.smtlib import smtlib_code
2
+ from sympy.assumptions.assume import AppliedPredicate
3
+ from sympy.assumptions.cnf import EncodedCNF
4
+ from sympy.assumptions.ask import Q
5
+
6
+ from sympy.core import Add, Mul
7
+ from sympy.core.relational import Equality, LessThan, GreaterThan, StrictLessThan, StrictGreaterThan
8
+ from sympy.functions.elementary.complexes import Abs
9
+ from sympy.functions.elementary.exponential import Pow
10
+ from sympy.functions.elementary.miscellaneous import Min, Max
11
+ from sympy.logic.boolalg import And, Or, Xor, Implies
12
+ from sympy.logic.boolalg import Not, ITE
13
+ from sympy.assumptions.relation.equality import StrictGreaterThanPredicate, StrictLessThanPredicate, GreaterThanPredicate, LessThanPredicate, EqualityPredicate
14
+ from sympy.external import import_module
15
+
16
+ def z3_satisfiable(expr, all_models=False):
17
+ if not isinstance(expr, EncodedCNF):
18
+ exprs = EncodedCNF()
19
+ exprs.add_prop(expr)
20
+ expr = exprs
21
+
22
+ z3 = import_module("z3")
23
+ if z3 is None:
24
+ raise ImportError("z3 is not installed")
25
+
26
+ s = encoded_cnf_to_z3_solver(expr, z3)
27
+
28
+ res = str(s.check())
29
+ if res == "unsat":
30
+ return False
31
+ elif res == "sat":
32
+ return z3_model_to_sympy_model(s.model(), expr)
33
+ else:
34
+ return None
35
+
36
+
37
+ def z3_model_to_sympy_model(z3_model, enc_cnf):
38
+ rev_enc = {value : key for key, value in enc_cnf.encoding.items()}
39
+ return {rev_enc[int(var.name()[1:])] : bool(z3_model[var]) for var in z3_model}
40
+
41
+
42
+ def clause_to_assertion(clause):
43
+ clause_strings = [f"d{abs(lit)}" if lit > 0 else f"(not d{abs(lit)})" for lit in clause]
44
+ return "(assert (or " + " ".join(clause_strings) + "))"
45
+
46
+
47
+ def encoded_cnf_to_z3_solver(enc_cnf, z3):
48
+ def dummify_bool(pred):
49
+ return False
50
+ assert isinstance(pred, AppliedPredicate)
51
+
52
+ if pred.function in [Q.positive, Q.negative, Q.zero]:
53
+ return pred
54
+ else:
55
+ return False
56
+
57
+ s = z3.Solver()
58
+
59
+ declarations = [f"(declare-const d{var} Bool)" for var in enc_cnf.variables]
60
+ assertions = [clause_to_assertion(clause) for clause in enc_cnf.data]
61
+
62
+ symbols = set()
63
+ for pred, enc in enc_cnf.encoding.items():
64
+ if not isinstance(pred, AppliedPredicate):
65
+ continue
66
+ if pred.function not in (Q.gt, Q.lt, Q.ge, Q.le, Q.ne, Q.eq, Q.positive, Q.negative, Q.extended_negative, Q.extended_positive, Q.zero, Q.nonzero, Q.nonnegative, Q.nonpositive, Q.extended_nonzero, Q.extended_nonnegative, Q.extended_nonpositive):
67
+ continue
68
+
69
+ pred_str = smtlib_code(pred, auto_declare=False, auto_assert=False, known_functions=known_functions)
70
+
71
+ symbols |= pred.free_symbols
72
+ pred = pred_str
73
+ clause = f"(implies d{enc} {pred})"
74
+ assertion = "(assert " + clause + ")"
75
+ assertions.append(assertion)
76
+
77
+ for sym in symbols:
78
+ declarations.append(f"(declare-const {sym} Real)")
79
+
80
+ declarations = "\n".join(declarations)
81
+ assertions = "\n".join(assertions)
82
+ s.from_string(declarations)
83
+ s.from_string(assertions)
84
+
85
+ return s
86
+
87
+
88
+ known_functions = {
89
+ Add: '+',
90
+ Mul: '*',
91
+
92
+ Equality: '=',
93
+ LessThan: '<=',
94
+ GreaterThan: '>=',
95
+ StrictLessThan: '<',
96
+ StrictGreaterThan: '>',
97
+
98
+ EqualityPredicate(): '=',
99
+ LessThanPredicate(): '<=',
100
+ GreaterThanPredicate(): '>=',
101
+ StrictLessThanPredicate(): '<',
102
+ StrictGreaterThanPredicate(): '>',
103
+
104
+ Abs: 'abs',
105
+ Min: 'min',
106
+ Max: 'max',
107
+ Pow: '^',
108
+
109
+ And: 'and',
110
+ Or: 'or',
111
+ Xor: 'xor',
112
+ Not: 'not',
113
+ ITE: 'ite',
114
+ Implies: '=>',
115
+ }
phivenv/Lib/site-packages/sympy/logic/tests/__init__.py ADDED
File without changes
phivenv/Lib/site-packages/sympy/logic/tests/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (161 Bytes). View file
 
phivenv/Lib/site-packages/sympy/logic/tests/__pycache__/test_boolalg.cpython-39.pyc ADDED
Binary file (49.7 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/tests/__pycache__/test_dimacs.cpython-39.pyc ADDED
Binary file (4.48 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/tests/__pycache__/test_inference.cpython-39.pyc ADDED
Binary file (15.5 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/tests/__pycache__/test_lra_theory.cpython-39.pyc ADDED
Binary file (14.9 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/tests/test_boolalg.py ADDED
@@ -0,0 +1,1367 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.assumptions.ask import Q
2
+ from sympy.assumptions.refine import refine
3
+ from sympy.core.numbers import oo
4
+ from sympy.core.relational import Equality, Eq, Ne
5
+ from sympy.core.singleton import S
6
+ from sympy.core.symbol import (Dummy, symbols)
7
+ from sympy.functions import Piecewise
8
+ from sympy.functions.elementary.trigonometric import cos, sin
9
+ from sympy.sets.sets import Interval, Union
10
+ from sympy.sets.contains import Contains
11
+ from sympy.simplify.simplify import simplify
12
+ from sympy.logic.boolalg import (
13
+ And, Boolean, Equivalent, ITE, Implies, Nand, Nor, Not, Or,
14
+ POSform, SOPform, Xor, Xnor, conjuncts, disjuncts,
15
+ distribute_or_over_and, distribute_and_over_or,
16
+ eliminate_implications, is_nnf, is_cnf, is_dnf, simplify_logic,
17
+ to_nnf, to_cnf, to_dnf, to_int_repr, bool_map, true, false,
18
+ BooleanAtom, is_literal, term_to_integer,
19
+ truth_table, as_Boolean, to_anf, is_anf, distribute_xor_over_and,
20
+ anf_coeffs, ANFform, bool_minterm, bool_maxterm, bool_monomial,
21
+ _check_pair, _convert_to_varsSOP, _convert_to_varsPOS, Exclusive,
22
+ gateinputcount)
23
+ from sympy.assumptions.cnf import CNF
24
+
25
+ from sympy.testing.pytest import raises, XFAIL, slow
26
+
27
+ from itertools import combinations, permutations, product
28
+
29
+ A, B, C, D = symbols('A:D')
30
+ a, b, c, d, e, w, x, y, z = symbols('a:e w:z')
31
+
32
+
33
+ def test_overloading():
34
+ """Test that |, & are overloaded as expected"""
35
+
36
+ assert A & B == And(A, B)
37
+ assert A | B == Or(A, B)
38
+ assert (A & B) | C == Or(And(A, B), C)
39
+ assert A >> B == Implies(A, B)
40
+ assert A << B == Implies(B, A)
41
+ assert ~A == Not(A)
42
+ assert A ^ B == Xor(A, B)
43
+
44
+
45
+ def test_And():
46
+ assert And() is true
47
+ assert And(A) == A
48
+ assert And(True) is true
49
+ assert And(False) is false
50
+ assert And(True, True) is true
51
+ assert And(True, False) is false
52
+ assert And(False, False) is false
53
+ assert And(True, A) == A
54
+ assert And(False, A) is false
55
+ assert And(True, True, True) is true
56
+ assert And(True, True, A) == A
57
+ assert And(True, False, A) is false
58
+ assert And(1, A) == A
59
+ raises(TypeError, lambda: And(2, A))
60
+ assert And(A < 1, A >= 1) is false
61
+ e = A > 1
62
+ assert And(e, e.canonical) == e.canonical
63
+ g, l, ge, le = A > B, B < A, A >= B, B <= A
64
+ assert And(g, l, ge, le) == And(ge, g)
65
+ assert {And(*i) for i in permutations((l, g, le, ge))} == {And(ge, g)}
66
+ assert And(And(Eq(a, 0), Eq(b, 0)), And(Ne(a, 0), Eq(c, 0))) is false
67
+
68
+
69
+ def test_Or():
70
+ assert Or() is false
71
+ assert Or(A) == A
72
+ assert Or(True) is true
73
+ assert Or(False) is false
74
+ assert Or(True, True) is true
75
+ assert Or(True, False) is true
76
+ assert Or(False, False) is false
77
+ assert Or(True, A) is true
78
+ assert Or(False, A) == A
79
+ assert Or(True, False, False) is true
80
+ assert Or(True, False, A) is true
81
+ assert Or(False, False, A) == A
82
+ assert Or(1, A) is true
83
+ raises(TypeError, lambda: Or(2, A))
84
+ assert Or(A < 1, A >= 1) is true
85
+ e = A > 1
86
+ assert Or(e, e.canonical) == e
87
+ g, l, ge, le = A > B, B < A, A >= B, B <= A
88
+ assert Or(g, l, ge, le) == Or(g, ge)
89
+
90
+
91
+ def test_Xor():
92
+ assert Xor() is false
93
+ assert Xor(A) == A
94
+ assert Xor(A, A) is false
95
+ assert Xor(True, A, A) is true
96
+ assert Xor(A, A, A, A, A) == A
97
+ assert Xor(True, False, False, A, B) == ~Xor(A, B)
98
+ assert Xor(True) is true
99
+ assert Xor(False) is false
100
+ assert Xor(True, True) is false
101
+ assert Xor(True, False) is true
102
+ assert Xor(False, False) is false
103
+ assert Xor(True, A) == ~A
104
+ assert Xor(False, A) == A
105
+ assert Xor(True, False, False) is true
106
+ assert Xor(True, False, A) == ~A
107
+ assert Xor(False, False, A) == A
108
+ assert isinstance(Xor(A, B), Xor)
109
+ assert Xor(A, B, Xor(C, D)) == Xor(A, B, C, D)
110
+ assert Xor(A, B, Xor(B, C)) == Xor(A, C)
111
+ assert Xor(A < 1, A >= 1, B) == Xor(0, 1, B) == Xor(1, 0, B)
112
+ e = A > 1
113
+ assert Xor(e, e.canonical) == Xor(0, 0) == Xor(1, 1)
114
+
115
+
116
+ def test_rewrite_as_And():
117
+ expr = x ^ y
118
+ assert expr.rewrite(And) == (x | y) & (~x | ~y)
119
+
120
+
121
+ def test_rewrite_as_Or():
122
+ expr = x ^ y
123
+ assert expr.rewrite(Or) == (x & ~y) | (y & ~x)
124
+
125
+
126
+ def test_rewrite_as_Nand():
127
+ expr = (y & z) | (z & ~w)
128
+ assert expr.rewrite(Nand) == ~(~(y & z) & ~(z & ~w))
129
+
130
+
131
+ def test_rewrite_as_Nor():
132
+ expr = z & (y | ~w)
133
+ assert expr.rewrite(Nor) == ~(~z | ~(y | ~w))
134
+
135
+
136
+ def test_Not():
137
+ raises(TypeError, lambda: Not(True, False))
138
+ assert Not(True) is false
139
+ assert Not(False) is true
140
+ assert Not(0) is true
141
+ assert Not(1) is false
142
+ assert Not(2) is false
143
+
144
+
145
+ def test_Nand():
146
+ assert Nand() is false
147
+ assert Nand(A) == ~A
148
+ assert Nand(True) is false
149
+ assert Nand(False) is true
150
+ assert Nand(True, True) is false
151
+ assert Nand(True, False) is true
152
+ assert Nand(False, False) is true
153
+ assert Nand(True, A) == ~A
154
+ assert Nand(False, A) is true
155
+ assert Nand(True, True, True) is false
156
+ assert Nand(True, True, A) == ~A
157
+ assert Nand(True, False, A) is true
158
+
159
+
160
+ def test_Nor():
161
+ assert Nor() is true
162
+ assert Nor(A) == ~A
163
+ assert Nor(True) is false
164
+ assert Nor(False) is true
165
+ assert Nor(True, True) is false
166
+ assert Nor(True, False) is false
167
+ assert Nor(False, False) is true
168
+ assert Nor(True, A) is false
169
+ assert Nor(False, A) == ~A
170
+ assert Nor(True, True, True) is false
171
+ assert Nor(True, True, A) is false
172
+ assert Nor(True, False, A) is false
173
+
174
+
175
+ def test_Xnor():
176
+ assert Xnor() is true
177
+ assert Xnor(A) == ~A
178
+ assert Xnor(A, A) is true
179
+ assert Xnor(True, A, A) is false
180
+ assert Xnor(A, A, A, A, A) == ~A
181
+ assert Xnor(True) is false
182
+ assert Xnor(False) is true
183
+ assert Xnor(True, True) is true
184
+ assert Xnor(True, False) is false
185
+ assert Xnor(False, False) is true
186
+ assert Xnor(True, A) == A
187
+ assert Xnor(False, A) == ~A
188
+ assert Xnor(True, False, False) is false
189
+ assert Xnor(True, False, A) == A
190
+ assert Xnor(False, False, A) == ~A
191
+
192
+
193
+ def test_Implies():
194
+ raises(ValueError, lambda: Implies(A, B, C))
195
+ assert Implies(True, True) is true
196
+ assert Implies(True, False) is false
197
+ assert Implies(False, True) is true
198
+ assert Implies(False, False) is true
199
+ assert Implies(0, A) is true
200
+ assert Implies(1, 1) is true
201
+ assert Implies(1, 0) is false
202
+ assert A >> B == B << A
203
+ assert (A < 1) >> (A >= 1) == (A >= 1)
204
+ assert (A < 1) >> (S.One > A) is true
205
+ assert A >> A is true
206
+
207
+
208
+ def test_Equivalent():
209
+ assert Equivalent(A, B) == Equivalent(B, A) == Equivalent(A, B, A)
210
+ assert Equivalent() is true
211
+ assert Equivalent(A, A) == Equivalent(A) is true
212
+ assert Equivalent(True, True) == Equivalent(False, False) is true
213
+ assert Equivalent(True, False) == Equivalent(False, True) is false
214
+ assert Equivalent(A, True) == A
215
+ assert Equivalent(A, False) == Not(A)
216
+ assert Equivalent(A, B, True) == A & B
217
+ assert Equivalent(A, B, False) == ~A & ~B
218
+ assert Equivalent(1, A) == A
219
+ assert Equivalent(0, A) == Not(A)
220
+ assert Equivalent(A, Equivalent(B, C)) != Equivalent(Equivalent(A, B), C)
221
+ assert Equivalent(A < 1, A >= 1) is false
222
+ assert Equivalent(A < 1, A >= 1, 0) is false
223
+ assert Equivalent(A < 1, A >= 1, 1) is false
224
+ assert Equivalent(A < 1, S.One > A) == Equivalent(1, 1) == Equivalent(0, 0)
225
+ assert Equivalent(Equality(A, B), Equality(B, A)) is true
226
+
227
+
228
+ def test_Exclusive():
229
+ assert Exclusive(False, False, False) is true
230
+ assert Exclusive(True, False, False) is true
231
+ assert Exclusive(True, True, False) is false
232
+ assert Exclusive(True, True, True) is false
233
+
234
+
235
+ def test_equals():
236
+ assert Not(Or(A, B)).equals(And(Not(A), Not(B))) is True
237
+ assert Equivalent(A, B).equals((A >> B) & (B >> A)) is True
238
+ assert ((A | ~B) & (~A | B)).equals((~A & ~B) | (A & B)) is True
239
+ assert (A >> B).equals(~A >> ~B) is False
240
+ assert (A >> (B >> A)).equals(A >> (C >> A)) is False
241
+ raises(NotImplementedError, lambda: (A & B).equals(A > B))
242
+
243
+
244
+ def test_simplification_boolalg():
245
+ """
246
+ Test working of simplification methods.
247
+ """
248
+ set1 = [[0, 0, 1], [0, 1, 1], [1, 0, 0], [1, 1, 0]]
249
+ set2 = [[0, 0, 0], [0, 1, 0], [1, 0, 1], [1, 1, 1]]
250
+ assert SOPform([x, y, z], set1) == Or(And(Not(x), z), And(Not(z), x))
251
+ assert Not(SOPform([x, y, z], set2)) == \
252
+ Not(Or(And(Not(x), Not(z)), And(x, z)))
253
+ assert POSform([x, y, z], set1 + set2) is true
254
+ assert SOPform([x, y, z], set1 + set2) is true
255
+ assert SOPform([Dummy(), Dummy(), Dummy()], set1 + set2) is true
256
+
257
+ minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 0, 1, 1],
258
+ [1, 1, 1, 1]]
259
+ dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]]
260
+ assert (
261
+ SOPform([w, x, y, z], minterms, dontcares) ==
262
+ Or(And(y, z), And(Not(w), Not(x))))
263
+ assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
264
+
265
+ minterms = [1, 3, 7, 11, 15]
266
+ dontcares = [0, 2, 5]
267
+ assert (
268
+ SOPform([w, x, y, z], minterms, dontcares) ==
269
+ Or(And(y, z), And(Not(w), Not(x))))
270
+ assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
271
+
272
+ minterms = [1, [0, 0, 1, 1], 7, [1, 0, 1, 1],
273
+ [1, 1, 1, 1]]
274
+ dontcares = [0, [0, 0, 1, 0], 5]
275
+ assert (
276
+ SOPform([w, x, y, z], minterms, dontcares) ==
277
+ Or(And(y, z), And(Not(w), Not(x))))
278
+ assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
279
+
280
+ minterms = [1, {y: 1, z: 1}]
281
+ dontcares = [0, [0, 0, 1, 0], 5]
282
+ assert (
283
+ SOPform([w, x, y, z], minterms, dontcares) ==
284
+ Or(And(y, z), And(Not(w), Not(x))))
285
+ assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
286
+
287
+ minterms = [{y: 1, z: 1}, 1]
288
+ dontcares = [[0, 0, 0, 0]]
289
+
290
+ minterms = [[0, 0, 0]]
291
+ raises(ValueError, lambda: SOPform([w, x, y, z], minterms))
292
+ raises(ValueError, lambda: POSform([w, x, y, z], minterms))
293
+
294
+ raises(TypeError, lambda: POSform([w, x, y, z], ["abcdefg"]))
295
+
296
+ # test simplification
297
+ ans = And(A, Or(B, C))
298
+ assert simplify_logic(A & (B | C)) == ans
299
+ assert simplify_logic((A & B) | (A & C)) == ans
300
+ assert simplify_logic(Implies(A, B)) == Or(Not(A), B)
301
+ assert simplify_logic(Equivalent(A, B)) == \
302
+ Or(And(A, B), And(Not(A), Not(B)))
303
+ assert simplify_logic(And(Equality(A, 2), C)) == And(Equality(A, 2), C)
304
+ assert simplify_logic(And(Equality(A, 2), A)) == And(Equality(A, 2), A)
305
+ assert simplify_logic(And(Equality(A, B), C)) == And(Equality(A, B), C)
306
+ assert simplify_logic(Or(And(Equality(A, 3), B), And(Equality(A, 3), C))) \
307
+ == And(Equality(A, 3), Or(B, C))
308
+ b = (~x & ~y & ~z) | (~x & ~y & z)
309
+ e = And(A, b)
310
+ assert simplify_logic(e) == A & ~x & ~y
311
+ raises(ValueError, lambda: simplify_logic(A & (B | C), form='blabla'))
312
+ assert simplify(Or(x <= y, And(x < y, z))) == (x <= y)
313
+ assert simplify(Or(x <= y, And(y > x, z))) == (x <= y)
314
+ assert simplify(Or(x >= y, And(y < x, z))) == (x >= y)
315
+
316
+ # Check that expressions with nine variables or more are not simplified
317
+ # (without the force-flag)
318
+ a, b, c, d, e, f, g, h, j = symbols('a b c d e f g h j')
319
+ expr = a & b & c & d & e & f & g & h & j | \
320
+ a & b & c & d & e & f & g & h & ~j
321
+ # This expression can be simplified to get rid of the j variables
322
+ assert simplify_logic(expr) == expr
323
+
324
+ # Test dontcare
325
+ assert simplify_logic((a & b) | c | d, dontcare=(a & b)) == c | d
326
+
327
+ # check input
328
+ ans = SOPform([x, y], [[1, 0]])
329
+ assert SOPform([x, y], [[1, 0]]) == ans
330
+ assert POSform([x, y], [[1, 0]]) == ans
331
+
332
+ raises(ValueError, lambda: SOPform([x], [[1]], [[1]]))
333
+ assert SOPform([x], [[1]], [[0]]) is true
334
+ assert SOPform([x], [[0]], [[1]]) is true
335
+ assert SOPform([x], [], []) is false
336
+
337
+ raises(ValueError, lambda: POSform([x], [[1]], [[1]]))
338
+ assert POSform([x], [[1]], [[0]]) is true
339
+ assert POSform([x], [[0]], [[1]]) is true
340
+ assert POSform([x], [], []) is false
341
+
342
+ # check working of simplify
343
+ assert simplify((A & B) | (A & C)) == And(A, Or(B, C))
344
+ assert simplify(And(x, Not(x))) == False
345
+ assert simplify(Or(x, Not(x))) == True
346
+ assert simplify(And(Eq(x, 0), Eq(x, y))) == And(Eq(x, 0), Eq(y, 0))
347
+ assert And(Eq(x - 1, 0), Eq(x, y)).simplify() == And(Eq(x, 1), Eq(y, 1))
348
+ assert And(Ne(x - 1, 0), Ne(x, y)).simplify() == And(Ne(x, 1), Ne(x, y))
349
+ assert And(Eq(x - 1, 0), Ne(x, y)).simplify() == And(Eq(x, 1), Ne(y, 1))
350
+ assert And(Eq(x - 1, 0), Eq(x, z + y), Eq(y + x, 0)).simplify(
351
+ ) == And(Eq(x, 1), Eq(y, -1), Eq(z, 2))
352
+ assert And(Eq(x - 1, 0), Eq(x + 2, 3)).simplify() == Eq(x, 1)
353
+ assert And(Ne(x - 1, 0), Ne(x + 2, 3)).simplify() == Ne(x, 1)
354
+ assert And(Eq(x - 1, 0), Eq(x + 2, 2)).simplify() == False
355
+ assert And(Ne(x - 1, 0), Ne(x + 2, 2)).simplify(
356
+ ) == And(Ne(x, 1), Ne(x, 0))
357
+ assert simplify(Xor(x, ~x)) == True
358
+
359
+
360
+ def test_bool_map():
361
+ """
362
+ Test working of bool_map function.
363
+ """
364
+
365
+ minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 0, 1, 1],
366
+ [1, 1, 1, 1]]
367
+ assert bool_map(Not(Not(a)), a) == (a, {a: a})
368
+ assert bool_map(SOPform([w, x, y, z], minterms),
369
+ POSform([w, x, y, z], minterms)) == \
370
+ (And(Or(Not(w), y), Or(Not(x), y), z), {x: x, w: w, z: z, y: y})
371
+ assert bool_map(SOPform([x, z, y], [[1, 0, 1]]),
372
+ SOPform([a, b, c], [[1, 0, 1]])) != False
373
+ function1 = SOPform([x, z, y], [[1, 0, 1], [0, 0, 1]])
374
+ function2 = SOPform([a, b, c], [[1, 0, 1], [1, 0, 0]])
375
+ assert bool_map(function1, function2) == \
376
+ (function1, {y: a, z: b})
377
+ assert bool_map(Xor(x, y), ~Xor(x, y)) == False
378
+ assert bool_map(And(x, y), Or(x, y)) is None
379
+ assert bool_map(And(x, y), And(x, y, z)) is None
380
+ # issue 16179
381
+ assert bool_map(Xor(x, y, z), ~Xor(x, y, z)) == False
382
+ assert bool_map(Xor(a, x, y, z), ~Xor(a, x, y, z)) == False
383
+
384
+
385
+ def test_bool_symbol():
386
+ """Test that mixing symbols with boolean values
387
+ works as expected"""
388
+
389
+ assert And(A, True) == A
390
+ assert And(A, True, True) == A
391
+ assert And(A, False) is false
392
+ assert And(A, True, False) is false
393
+ assert Or(A, True) is true
394
+ assert Or(A, False) == A
395
+
396
+
397
+ def test_is_boolean():
398
+ assert isinstance(True, Boolean) is False
399
+ assert isinstance(true, Boolean) is True
400
+ assert 1 == True
401
+ assert 1 != true
402
+ assert (1 == true) is False
403
+ assert 0 == False
404
+ assert 0 != false
405
+ assert (0 == false) is False
406
+ assert true.is_Boolean is True
407
+ assert (A & B).is_Boolean
408
+ assert (A | B).is_Boolean
409
+ assert (~A).is_Boolean
410
+ assert (A ^ B).is_Boolean
411
+ assert A.is_Boolean != isinstance(A, Boolean)
412
+ assert isinstance(A, Boolean)
413
+
414
+
415
+ def test_subs():
416
+ assert (A & B).subs(A, True) == B
417
+ assert (A & B).subs(A, False) is false
418
+ assert (A & B).subs(B, True) == A
419
+ assert (A & B).subs(B, False) is false
420
+ assert (A & B).subs({A: True, B: True}) is true
421
+ assert (A | B).subs(A, True) is true
422
+ assert (A | B).subs(A, False) == B
423
+ assert (A | B).subs(B, True) is true
424
+ assert (A | B).subs(B, False) == A
425
+ assert (A | B).subs({A: True, B: True}) is true
426
+
427
+
428
+ """
429
+ we test for axioms of boolean algebra
430
+ see https://en.wikipedia.org/wiki/Boolean_algebra_(structure)
431
+ """
432
+
433
+
434
+ def test_commutative():
435
+ """Test for commutativity of And and Or"""
436
+ A, B = map(Boolean, symbols('A,B'))
437
+
438
+ assert A & B == B & A
439
+ assert A | B == B | A
440
+
441
+
442
+ def test_and_associativity():
443
+ """Test for associativity of And"""
444
+
445
+ assert (A & B) & C == A & (B & C)
446
+
447
+
448
+ def test_or_assicativity():
449
+ assert ((A | B) | C) == (A | (B | C))
450
+
451
+
452
+ def test_double_negation():
453
+ a = Boolean()
454
+ assert ~(~a) == a
455
+
456
+
457
+ # test methods
458
+
459
+ def test_eliminate_implications():
460
+ assert eliminate_implications(Implies(A, B, evaluate=False)) == (~A) | B
461
+ assert eliminate_implications(
462
+ A >> (C >> Not(B))) == Or(Or(Not(B), Not(C)), Not(A))
463
+ assert eliminate_implications(Equivalent(A, B, C, D)) == \
464
+ (~A | B) & (~B | C) & (~C | D) & (~D | A)
465
+
466
+
467
+ def test_conjuncts():
468
+ assert conjuncts(A & B & C) == {A, B, C}
469
+ assert conjuncts((A | B) & C) == {A | B, C}
470
+ assert conjuncts(A) == {A}
471
+ assert conjuncts(True) == {True}
472
+ assert conjuncts(False) == {False}
473
+
474
+
475
+ def test_disjuncts():
476
+ assert disjuncts(A | B | C) == {A, B, C}
477
+ assert disjuncts((A | B) & C) == {(A | B) & C}
478
+ assert disjuncts(A) == {A}
479
+ assert disjuncts(True) == {True}
480
+ assert disjuncts(False) == {False}
481
+
482
+
483
+ def test_distribute():
484
+ assert distribute_and_over_or(Or(And(A, B), C)) == And(Or(A, C), Or(B, C))
485
+ assert distribute_or_over_and(And(A, Or(B, C))) == Or(And(A, B), And(A, C))
486
+ assert distribute_xor_over_and(And(A, Xor(B, C))) == Xor(And(A, B), And(A, C))
487
+
488
+
489
+ def test_to_anf():
490
+ x, y, z = symbols('x,y,z')
491
+ assert to_anf(And(x, y)) == And(x, y)
492
+ assert to_anf(Or(x, y)) == Xor(x, y, And(x, y))
493
+ assert to_anf(Or(Implies(x, y), And(x, y), y)) == \
494
+ Xor(x, True, x & y, remove_true=False)
495
+ assert to_anf(Or(Nand(x, y), Nor(x, y), Xnor(x, y), Implies(x, y))) == True
496
+ assert to_anf(Or(x, Not(y), Nor(x, z), And(x, y), Nand(y, z))) == \
497
+ Xor(True, And(y, z), And(x, y, z), remove_true=False)
498
+ assert to_anf(Xor(x, y)) == Xor(x, y)
499
+ assert to_anf(Not(x)) == Xor(x, True, remove_true=False)
500
+ assert to_anf(Nand(x, y)) == Xor(True, And(x, y), remove_true=False)
501
+ assert to_anf(Nor(x, y)) == Xor(x, y, True, And(x, y), remove_true=False)
502
+ assert to_anf(Implies(x, y)) == Xor(x, True, And(x, y), remove_true=False)
503
+ assert to_anf(Equivalent(x, y)) == Xor(x, y, True, remove_true=False)
504
+ assert to_anf(Nand(x | y, x >> y), deep=False) == \
505
+ Xor(True, And(Or(x, y), Implies(x, y)), remove_true=False)
506
+ assert to_anf(Nor(x ^ y, x & y), deep=False) == \
507
+ Xor(True, Or(Xor(x, y), And(x, y)), remove_true=False)
508
+ # issue 25218
509
+ assert to_anf(x ^ ~(x ^ y ^ ~y)) == False
510
+
511
+
512
+ def test_to_nnf():
513
+ assert to_nnf(true) is true
514
+ assert to_nnf(false) is false
515
+ assert to_nnf(A) == A
516
+ assert to_nnf(A | ~A | B) is true
517
+ assert to_nnf(A & ~A & B) is false
518
+ assert to_nnf(A >> B) == ~A | B
519
+ assert to_nnf(Equivalent(A, B, C)) == (~A | B) & (~B | C) & (~C | A)
520
+ assert to_nnf(A ^ B ^ C) == \
521
+ (A | B | C) & (~A | ~B | C) & (A | ~B | ~C) & (~A | B | ~C)
522
+ assert to_nnf(ITE(A, B, C)) == (~A | B) & (A | C)
523
+ assert to_nnf(Not(A | B | C)) == ~A & ~B & ~C
524
+ assert to_nnf(Not(A & B & C)) == ~A | ~B | ~C
525
+ assert to_nnf(Not(A >> B)) == A & ~B
526
+ assert to_nnf(Not(Equivalent(A, B, C))) == And(Or(A, B, C), Or(~A, ~B, ~C))
527
+ assert to_nnf(Not(A ^ B ^ C)) == \
528
+ (~A | B | C) & (A | ~B | C) & (A | B | ~C) & (~A | ~B | ~C)
529
+ assert to_nnf(Not(ITE(A, B, C))) == (~A | ~B) & (A | ~C)
530
+ assert to_nnf((A >> B) ^ (B >> A)) == (A & ~B) | (~A & B)
531
+ assert to_nnf((A >> B) ^ (B >> A), False) == \
532
+ (~A | ~B | A | B) & ((A & ~B) | (~A & B))
533
+ assert ITE(A, 1, 0).to_nnf() == A
534
+ assert ITE(A, 0, 1).to_nnf() == ~A
535
+ # although ITE can hold non-Boolean, it will complain if
536
+ # an attempt is made to convert the ITE to Boolean nnf
537
+ raises(TypeError, lambda: ITE(A < 1, [1], B).to_nnf())
538
+
539
+
540
+ def test_to_cnf():
541
+ assert to_cnf(~(B | C)) == And(Not(B), Not(C))
542
+ assert to_cnf((A & B) | C) == And(Or(A, C), Or(B, C))
543
+ assert to_cnf(A >> B) == (~A) | B
544
+ assert to_cnf(A >> (B & C)) == (~A | B) & (~A | C)
545
+ assert to_cnf(A & (B | C) | ~A & (B | C), True) == B | C
546
+ assert to_cnf(A & B) == And(A, B)
547
+
548
+ assert to_cnf(Equivalent(A, B)) == And(Or(A, Not(B)), Or(B, Not(A)))
549
+ assert to_cnf(Equivalent(A, B & C)) == \
550
+ (~A | B) & (~A | C) & (~B | ~C | A)
551
+ assert to_cnf(Equivalent(A, B | C), True) == \
552
+ And(Or(Not(B), A), Or(Not(C), A), Or(B, C, Not(A)))
553
+ assert to_cnf(A + 1) == A + 1
554
+
555
+
556
+ def test_issue_18904():
557
+ x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 = symbols('x1:16')
558
+ eq = ((x1 & x2 & x3 & x4 & x5 & x6 & x7 & x8 & x9) |
559
+ (x1 & x2 & x3 & x4 & x5 & x6 & x7 & x10 & x9) |
560
+ (x1 & x11 & x3 & x12 & x5 & x13 & x14 & x15 & x9))
561
+ assert is_cnf(to_cnf(eq))
562
+ raises(ValueError, lambda: to_cnf(eq, simplify=True))
563
+ for f, t in zip((And, Or), (to_cnf, to_dnf)):
564
+ eq = f(x1, x2, x3, x4, x5, x6, x7, x8, x9)
565
+ raises(ValueError, lambda: to_cnf(eq, simplify=True))
566
+ assert t(eq, simplify=True, force=True) == eq
567
+
568
+
569
+ def test_issue_9949():
570
+ assert is_cnf(to_cnf((b > -5) | (a > 2) & (a < 4)))
571
+
572
+
573
+ def test_to_CNF():
574
+ assert CNF.CNF_to_cnf(CNF.to_CNF(~(B | C))) == to_cnf(~(B | C))
575
+ assert CNF.CNF_to_cnf(CNF.to_CNF((A & B) | C)) == to_cnf((A & B) | C)
576
+ assert CNF.CNF_to_cnf(CNF.to_CNF(A >> B)) == to_cnf(A >> B)
577
+ assert CNF.CNF_to_cnf(CNF.to_CNF(A >> (B & C))) == to_cnf(A >> (B & C))
578
+ assert CNF.CNF_to_cnf(CNF.to_CNF(A & (B | C) | ~A & (B | C))) == to_cnf(A & (B | C) | ~A & (B | C))
579
+ assert CNF.CNF_to_cnf(CNF.to_CNF(A & B)) == to_cnf(A & B)
580
+
581
+
582
+ def test_to_dnf():
583
+ assert to_dnf(~(B | C)) == And(Not(B), Not(C))
584
+ assert to_dnf(A & (B | C)) == Or(And(A, B), And(A, C))
585
+ assert to_dnf(A >> B) == (~A) | B
586
+ assert to_dnf(A >> (B & C)) == (~A) | (B & C)
587
+ assert to_dnf(A | B) == A | B
588
+
589
+ assert to_dnf(Equivalent(A, B), True) == \
590
+ Or(And(A, B), And(Not(A), Not(B)))
591
+ assert to_dnf(Equivalent(A, B & C), True) == \
592
+ Or(And(A, B, C), And(Not(A), Not(B)), And(Not(A), Not(C)))
593
+ assert to_dnf(A + 1) == A + 1
594
+
595
+
596
+ def test_to_int_repr():
597
+ x, y, z = map(Boolean, symbols('x,y,z'))
598
+
599
+ def sorted_recursive(arg):
600
+ try:
601
+ return sorted(sorted_recursive(x) for x in arg)
602
+ except TypeError: # arg is not a sequence
603
+ return arg
604
+
605
+ assert sorted_recursive(to_int_repr([x | y, z | x], [x, y, z])) == \
606
+ sorted_recursive([[1, 2], [1, 3]])
607
+ assert sorted_recursive(to_int_repr([x | y, z | ~x], [x, y, z])) == \
608
+ sorted_recursive([[1, 2], [3, -1]])
609
+
610
+
611
+ def test_is_anf():
612
+ x, y = symbols('x,y')
613
+ assert is_anf(true) is True
614
+ assert is_anf(false) is True
615
+ assert is_anf(x) is True
616
+ assert is_anf(And(x, y)) is True
617
+ assert is_anf(Xor(x, y, And(x, y))) is True
618
+ assert is_anf(Xor(x, y, Or(x, y))) is False
619
+ assert is_anf(Xor(Not(x), y)) is False
620
+
621
+
622
+ def test_is_nnf():
623
+ assert is_nnf(true) is True
624
+ assert is_nnf(A) is True
625
+ assert is_nnf(~A) is True
626
+ assert is_nnf(A & B) is True
627
+ assert is_nnf((A & B) | (~A & A) | (~B & B) | (~A & ~B), False) is True
628
+ assert is_nnf((A | B) & (~A | ~B)) is True
629
+ assert is_nnf(Not(Or(A, B))) is False
630
+ assert is_nnf(A ^ B) is False
631
+ assert is_nnf((A & B) | (~A & A) | (~B & B) | (~A & ~B), True) is False
632
+
633
+
634
+ def test_is_cnf():
635
+ assert is_cnf(x) is True
636
+ assert is_cnf(x | y | z) is True
637
+ assert is_cnf(x & y & z) is True
638
+ assert is_cnf((x | y) & z) is True
639
+ assert is_cnf((x & y) | z) is False
640
+ assert is_cnf(~(x & y) | z) is False
641
+
642
+
643
+ def test_is_dnf():
644
+ assert is_dnf(x) is True
645
+ assert is_dnf(x | y | z) is True
646
+ assert is_dnf(x & y & z) is True
647
+ assert is_dnf((x & y) | z) is True
648
+ assert is_dnf((x | y) & z) is False
649
+ assert is_dnf(~(x | y) & z) is False
650
+
651
+
652
+ def test_ITE():
653
+ A, B, C = symbols('A:C')
654
+ assert ITE(True, False, True) is false
655
+ assert ITE(True, True, False) is true
656
+ assert ITE(False, True, False) is false
657
+ assert ITE(False, False, True) is true
658
+ assert isinstance(ITE(A, B, C), ITE)
659
+
660
+ A = True
661
+ assert ITE(A, B, C) == B
662
+ A = False
663
+ assert ITE(A, B, C) == C
664
+ B = True
665
+ assert ITE(And(A, B), B, C) == C
666
+ assert ITE(Or(A, False), And(B, True), False) is false
667
+ assert ITE(x, A, B) == Not(x)
668
+ assert ITE(x, B, A) == x
669
+ assert ITE(1, x, y) == x
670
+ assert ITE(0, x, y) == y
671
+ raises(TypeError, lambda: ITE(2, x, y))
672
+ raises(TypeError, lambda: ITE(1, [], y))
673
+ raises(TypeError, lambda: ITE(1, (), y))
674
+ raises(TypeError, lambda: ITE(1, y, []))
675
+ assert ITE(1, 1, 1) is S.true
676
+ assert isinstance(ITE(1, 1, 1, evaluate=False), ITE)
677
+
678
+ assert ITE(Eq(x, True), y, x) == ITE(x, y, x)
679
+ assert ITE(Eq(x, False), y, x) == ITE(~x, y, x)
680
+ assert ITE(Ne(x, True), y, x) == ITE(~x, y, x)
681
+ assert ITE(Ne(x, False), y, x) == ITE(x, y, x)
682
+ assert ITE(Eq(S.true, x), y, x) == ITE(x, y, x)
683
+ assert ITE(Eq(S.false, x), y, x) == ITE(~x, y, x)
684
+ assert ITE(Ne(S.true, x), y, x) == ITE(~x, y, x)
685
+ assert ITE(Ne(S.false, x), y, x) == ITE(x, y, x)
686
+ # 0 and 1 in the context are not treated as True/False
687
+ # so the equality must always be False since dissimilar
688
+ # objects cannot be equal
689
+ assert ITE(Eq(x, 0), y, x) == x
690
+ assert ITE(Eq(x, 1), y, x) == x
691
+ assert ITE(Ne(x, 0), y, x) == y
692
+ assert ITE(Ne(x, 1), y, x) == y
693
+ assert ITE(Eq(x, 0), y, z).subs(x, 0) == y
694
+ assert ITE(Eq(x, 0), y, z).subs(x, 1) == z
695
+ raises(ValueError, lambda: ITE(x > 1, y, x, z))
696
+
697
+
698
+ def test_is_literal():
699
+ assert is_literal(True) is True
700
+ assert is_literal(False) is True
701
+ assert is_literal(A) is True
702
+ assert is_literal(~A) is True
703
+ assert is_literal(Or(A, B)) is False
704
+ assert is_literal(Q.zero(A)) is True
705
+ assert is_literal(Not(Q.zero(A))) is True
706
+ assert is_literal(Or(A, B)) is False
707
+ assert is_literal(And(Q.zero(A), Q.zero(B))) is False
708
+ assert is_literal(x < 3)
709
+ assert not is_literal(x + y < 3)
710
+
711
+
712
+ def test_operators():
713
+ # Mostly test __and__, __rand__, and so on
714
+ assert True & A == A & True == A
715
+ assert False & A == A & False == False
716
+ assert A & B == And(A, B)
717
+ assert True | A == A | True == True
718
+ assert False | A == A | False == A
719
+ assert A | B == Or(A, B)
720
+ assert ~A == Not(A)
721
+ assert True >> A == A << True == A
722
+ assert False >> A == A << False == True
723
+ assert A >> True == True << A == True
724
+ assert A >> False == False << A == ~A
725
+ assert A >> B == B << A == Implies(A, B)
726
+ assert True ^ A == A ^ True == ~A
727
+ assert False ^ A == A ^ False == A
728
+ assert A ^ B == Xor(A, B)
729
+
730
+
731
+ def test_true_false():
732
+ assert true is S.true
733
+ assert false is S.false
734
+ assert true is not True
735
+ assert false is not False
736
+ assert true
737
+ assert not false
738
+ assert true == True
739
+ assert false == False
740
+ assert not (true == False)
741
+ assert not (false == True)
742
+ assert not (true == false)
743
+
744
+ assert hash(true) == hash(True)
745
+ assert hash(false) == hash(False)
746
+ assert len({true, True}) == len({false, False}) == 1
747
+
748
+ assert isinstance(true, BooleanAtom)
749
+ assert isinstance(false, BooleanAtom)
750
+ # We don't want to subclass from bool, because bool subclasses from
751
+ # int. But operators like &, |, ^, <<, >>, and ~ act differently on 0 and
752
+ # 1 then we want them to on true and false. See the docstrings of the
753
+ # various And, Or, etc. functions for examples.
754
+ assert not isinstance(true, bool)
755
+ assert not isinstance(false, bool)
756
+
757
+ # Note: using 'is' comparison is important here. We want these to return
758
+ # true and false, not True and False
759
+
760
+ assert Not(true) is false
761
+ assert Not(True) is false
762
+ assert Not(false) is true
763
+ assert Not(False) is true
764
+ assert ~true is false
765
+ assert ~false is true
766
+
767
+ for T, F in product((True, true), (False, false)):
768
+ assert And(T, F) is false
769
+ assert And(F, T) is false
770
+ assert And(F, F) is false
771
+ assert And(T, T) is true
772
+ assert And(T, x) == x
773
+ assert And(F, x) is false
774
+ if not (T is True and F is False):
775
+ assert T & F is false
776
+ assert F & T is false
777
+ if F is not False:
778
+ assert F & F is false
779
+ if T is not True:
780
+ assert T & T is true
781
+
782
+ assert Or(T, F) is true
783
+ assert Or(F, T) is true
784
+ assert Or(F, F) is false
785
+ assert Or(T, T) is true
786
+ assert Or(T, x) is true
787
+ assert Or(F, x) == x
788
+ if not (T is True and F is False):
789
+ assert T | F is true
790
+ assert F | T is true
791
+ if F is not False:
792
+ assert F | F is false
793
+ if T is not True:
794
+ assert T | T is true
795
+
796
+ assert Xor(T, F) is true
797
+ assert Xor(F, T) is true
798
+ assert Xor(F, F) is false
799
+ assert Xor(T, T) is false
800
+ assert Xor(T, x) == ~x
801
+ assert Xor(F, x) == x
802
+ if not (T is True and F is False):
803
+ assert T ^ F is true
804
+ assert F ^ T is true
805
+ if F is not False:
806
+ assert F ^ F is false
807
+ if T is not True:
808
+ assert T ^ T is false
809
+
810
+ assert Nand(T, F) is true
811
+ assert Nand(F, T) is true
812
+ assert Nand(F, F) is true
813
+ assert Nand(T, T) is false
814
+ assert Nand(T, x) == ~x
815
+ assert Nand(F, x) is true
816
+
817
+ assert Nor(T, F) is false
818
+ assert Nor(F, T) is false
819
+ assert Nor(F, F) is true
820
+ assert Nor(T, T) is false
821
+ assert Nor(T, x) is false
822
+ assert Nor(F, x) == ~x
823
+
824
+ assert Implies(T, F) is false
825
+ assert Implies(F, T) is true
826
+ assert Implies(F, F) is true
827
+ assert Implies(T, T) is true
828
+ assert Implies(T, x) == x
829
+ assert Implies(F, x) is true
830
+ assert Implies(x, T) is true
831
+ assert Implies(x, F) == ~x
832
+ if not (T is True and F is False):
833
+ assert T >> F is false
834
+ assert F << T is false
835
+ assert F >> T is true
836
+ assert T << F is true
837
+ if F is not False:
838
+ assert F >> F is true
839
+ assert F << F is true
840
+ if T is not True:
841
+ assert T >> T is true
842
+ assert T << T is true
843
+
844
+ assert Equivalent(T, F) is false
845
+ assert Equivalent(F, T) is false
846
+ assert Equivalent(F, F) is true
847
+ assert Equivalent(T, T) is true
848
+ assert Equivalent(T, x) == x
849
+ assert Equivalent(F, x) == ~x
850
+ assert Equivalent(x, T) == x
851
+ assert Equivalent(x, F) == ~x
852
+
853
+ assert ITE(T, T, T) is true
854
+ assert ITE(T, T, F) is true
855
+ assert ITE(T, F, T) is false
856
+ assert ITE(T, F, F) is false
857
+ assert ITE(F, T, T) is true
858
+ assert ITE(F, T, F) is false
859
+ assert ITE(F, F, T) is true
860
+ assert ITE(F, F, F) is false
861
+
862
+ assert all(i.simplify(1, 2) is i for i in (S.true, S.false))
863
+
864
+
865
+ def test_bool_as_set():
866
+ assert ITE(y <= 0, False, y >= 1).as_set() == Interval(1, oo)
867
+ assert And(x <= 2, x >= -2).as_set() == Interval(-2, 2)
868
+ assert Or(x >= 2, x <= -2).as_set() == Interval(-oo, -2) + Interval(2, oo)
869
+ assert Not(x > 2).as_set() == Interval(-oo, 2)
870
+ # issue 10240
871
+ assert Not(And(x > 2, x < 3)).as_set() == \
872
+ Union(Interval(-oo, 2), Interval(3, oo))
873
+ assert true.as_set() == S.UniversalSet
874
+ assert false.as_set() is S.EmptySet
875
+ assert x.as_set() == S.UniversalSet
876
+ assert And(Or(x < 1, x > 3), x < 2).as_set() == Interval.open(-oo, 1)
877
+ assert And(x < 1, sin(x) < 3).as_set() == (x < 1).as_set()
878
+ raises(NotImplementedError, lambda: (sin(x) < 1).as_set())
879
+ # watch for object morph in as_set
880
+ assert Eq(-1, cos(2 * x) ** 2 / sin(2 * x) ** 2).as_set() is S.EmptySet
881
+
882
+
883
+ @XFAIL
884
+ def test_multivariate_bool_as_set():
885
+ x, y = symbols('x,y')
886
+
887
+ assert And(x >= 0, y >= 0).as_set() == Interval(0, oo) * Interval(0, oo)
888
+ assert Or(x >= 0, y >= 0).as_set() == S.Reals * S.Reals - \
889
+ Interval(-oo, 0, True, True) * Interval(-oo, 0, True, True)
890
+
891
+
892
+ def test_all_or_nothing():
893
+ x = symbols('x', extended_real=True)
894
+ args = x >= -oo, x <= oo
895
+ v = And(*args)
896
+ if v.func is And:
897
+ assert len(v.args) == len(args) - args.count(S.true)
898
+ else:
899
+ assert v == True
900
+ v = Or(*args)
901
+ if v.func is Or:
902
+ assert len(v.args) == 2
903
+ else:
904
+ assert v == True
905
+
906
+
907
+ def test_canonical_atoms():
908
+ assert true.canonical == true
909
+ assert false.canonical == false
910
+
911
+
912
+ def test_negated_atoms():
913
+ assert true.negated == false
914
+ assert false.negated == true
915
+
916
+
917
+ def test_issue_8777():
918
+ assert And(x > 2, x < oo).as_set() == Interval(2, oo, left_open=True)
919
+ assert And(x >= 1, x < oo).as_set() == Interval(1, oo)
920
+ assert (x < oo).as_set() == Interval(-oo, oo)
921
+ assert (x > -oo).as_set() == Interval(-oo, oo)
922
+
923
+
924
+ def test_issue_8975():
925
+ assert Or(And(-oo < x, x <= -2), And(2 <= x, x < oo)).as_set() == \
926
+ Interval(-oo, -2) + Interval(2, oo)
927
+
928
+
929
+ def test_term_to_integer():
930
+ assert term_to_integer([1, 0, 1, 0, 0, 1, 0]) == 82
931
+ assert term_to_integer('0010101000111001') == 10809
932
+
933
+
934
+ def test_issue_21971():
935
+ a, b, c, d = symbols('a b c d')
936
+ f = a & b & c | a & c
937
+ assert f.subs(a & c, d) == b & d | d
938
+ assert f.subs(a & b & c, d) == a & c | d
939
+
940
+ f = (a | b | c) & (a | c)
941
+ assert f.subs(a | c, d) == (b | d) & d
942
+ assert f.subs(a | b | c, d) == (a | c) & d
943
+
944
+ f = (a ^ b ^ c) & (a ^ c)
945
+ assert f.subs(a ^ c, d) == (b ^ d) & d
946
+ assert f.subs(a ^ b ^ c, d) == (a ^ c) & d
947
+
948
+
949
+ def test_truth_table():
950
+ assert list(truth_table(And(x, y), [x, y], input=False)) == \
951
+ [False, False, False, True]
952
+ assert list(truth_table(x | y, [x, y], input=False)) == \
953
+ [False, True, True, True]
954
+ assert list(truth_table(x >> y, [x, y], input=False)) == \
955
+ [True, True, False, True]
956
+ assert list(truth_table(And(x, y), [x, y])) == \
957
+ [([0, 0], False), ([0, 1], False), ([1, 0], False), ([1, 1], True)]
958
+
959
+
960
+ def test_issue_8571():
961
+ for t in (S.true, S.false):
962
+ raises(TypeError, lambda: +t)
963
+ raises(TypeError, lambda: -t)
964
+ raises(TypeError, lambda: abs(t))
965
+ # use int(bool(t)) to get 0 or 1
966
+ raises(TypeError, lambda: int(t))
967
+
968
+ for o in [S.Zero, S.One, x]:
969
+ for _ in range(2):
970
+ raises(TypeError, lambda: o + t)
971
+ raises(TypeError, lambda: o - t)
972
+ raises(TypeError, lambda: o % t)
973
+ raises(TypeError, lambda: o * t)
974
+ raises(TypeError, lambda: o / t)
975
+ raises(TypeError, lambda: o ** t)
976
+ o, t = t, o # do again in reversed order
977
+
978
+
979
+ def test_expand_relational():
980
+ n = symbols('n', negative=True)
981
+ p, q = symbols('p q', positive=True)
982
+ r = ((n + q * (-n / q + 1)) / (q * (-n / q + 1)) < 0)
983
+ assert r is not S.false
984
+ assert r.expand() is S.false
985
+ assert (q > 0).expand() is S.true
986
+
987
+
988
+ def test_issue_12717():
989
+ assert S.true.is_Atom == True
990
+ assert S.false.is_Atom == True
991
+
992
+
993
+ def test_as_Boolean():
994
+ nz = symbols('nz', nonzero=True)
995
+ assert all(as_Boolean(i) is S.true for i in (True, S.true, 1, nz))
996
+ z = symbols('z', zero=True)
997
+ assert all(as_Boolean(i) is S.false for i in (False, S.false, 0, z))
998
+ assert all(as_Boolean(i) == i for i in (x, x < 0))
999
+ for i in (2, S(2), x + 1, []):
1000
+ raises(TypeError, lambda: as_Boolean(i))
1001
+
1002
+
1003
+ def test_binary_symbols():
1004
+ assert ITE(x < 1, y, z).binary_symbols == {y, z}
1005
+ for f in (Eq, Ne):
1006
+ assert f(x, 1).binary_symbols == set()
1007
+ assert f(x, True).binary_symbols == {x}
1008
+ assert f(x, False).binary_symbols == {x}
1009
+ assert S.true.binary_symbols == set()
1010
+ assert S.false.binary_symbols == set()
1011
+ assert x.binary_symbols == {x}
1012
+ assert And(x, Eq(y, False), Eq(z, 1)).binary_symbols == {x, y}
1013
+ assert Q.prime(x).binary_symbols == set()
1014
+ assert Q.lt(x, 1).binary_symbols == set()
1015
+ assert Q.is_true(x).binary_symbols == {x}
1016
+ assert Q.eq(x, True).binary_symbols == {x}
1017
+ assert Q.prime(x).binary_symbols == set()
1018
+
1019
+
1020
+ def test_BooleanFunction_diff():
1021
+ assert And(x, y).diff(x) == Piecewise((0, Eq(y, False)), (1, True))
1022
+
1023
+
1024
+ def test_issue_14700():
1025
+ A, B, C, D, E, F, G, H = symbols('A B C D E F G H')
1026
+ q = ((B & D & H & ~F) | (B & H & ~C & ~D) | (B & H & ~C & ~F) |
1027
+ (B & H & ~D & ~G) | (B & H & ~F & ~G) | (C & G & ~B & ~D) |
1028
+ (C & G & ~D & ~H) | (C & G & ~F & ~H) | (D & F & H & ~B) |
1029
+ (D & F & ~G & ~H) | (B & D & F & ~C & ~H) | (D & E & F & ~B & ~C) |
1030
+ (D & F & ~A & ~B & ~C) | (D & F & ~A & ~C & ~H) |
1031
+ (A & B & D & F & ~E & ~H))
1032
+ soldnf = ((B & D & H & ~F) | (D & F & H & ~B) | (B & H & ~C & ~D) |
1033
+ (B & H & ~D & ~G) | (C & G & ~B & ~D) | (C & G & ~D & ~H) |
1034
+ (C & G & ~F & ~H) | (D & F & ~G & ~H) | (D & E & F & ~C & ~H) |
1035
+ (D & F & ~A & ~C & ~H) | (A & B & D & F & ~E & ~H))
1036
+ solcnf = ((B | C | D) & (B | D | G) & (C | D | H) & (C | F | H) &
1037
+ (D | G | H) & (F | G | H) & (B | F | ~D | ~H) &
1038
+ (~B | ~D | ~F | ~H) & (D | ~B | ~C | ~G | ~H) &
1039
+ (A | H | ~C | ~D | ~F | ~G) & (H | ~C | ~D | ~E | ~F | ~G) &
1040
+ (B | E | H | ~A | ~D | ~F | ~G))
1041
+ assert simplify_logic(q, "dnf") == soldnf
1042
+ assert simplify_logic(q, "cnf") == solcnf
1043
+
1044
+ minterms = [[0, 1, 0, 0], [0, 1, 0, 1], [0, 1, 1, 0], [0, 1, 1, 1],
1045
+ [0, 0, 1, 1], [1, 0, 1, 1]]
1046
+ dontcares = [[1, 0, 0, 0], [1, 0, 0, 1], [1, 1, 0, 0], [1, 1, 0, 1]]
1047
+ assert SOPform([w, x, y, z], minterms) == (x & ~w) | (y & z & ~x)
1048
+ # Should not be more complicated with don't cares
1049
+ assert SOPform([w, x, y, z], minterms, dontcares) == \
1050
+ (x & ~w) | (y & z & ~x)
1051
+
1052
+
1053
+ def test_issue_25115():
1054
+ cond = Contains(x, S.Integers)
1055
+ # Previously this raised an exception:
1056
+ assert simplify_logic(cond) == cond
1057
+
1058
+
1059
+ def test_relational_simplification():
1060
+ w, x, y, z = symbols('w x y z', real=True)
1061
+ d, e = symbols('d e', real=False)
1062
+ # Test all combinations or sign and order
1063
+ assert Or(x >= y, x < y).simplify() == S.true
1064
+ assert Or(x >= y, y > x).simplify() == S.true
1065
+ assert Or(x >= y, -x > -y).simplify() == S.true
1066
+ assert Or(x >= y, -y < -x).simplify() == S.true
1067
+ assert Or(-x <= -y, x < y).simplify() == S.true
1068
+ assert Or(-x <= -y, -x > -y).simplify() == S.true
1069
+ assert Or(-x <= -y, y > x).simplify() == S.true
1070
+ assert Or(-x <= -y, -y < -x).simplify() == S.true
1071
+ assert Or(y <= x, x < y).simplify() == S.true
1072
+ assert Or(y <= x, y > x).simplify() == S.true
1073
+ assert Or(y <= x, -x > -y).simplify() == S.true
1074
+ assert Or(y <= x, -y < -x).simplify() == S.true
1075
+ assert Or(-y >= -x, x < y).simplify() == S.true
1076
+ assert Or(-y >= -x, y > x).simplify() == S.true
1077
+ assert Or(-y >= -x, -x > -y).simplify() == S.true
1078
+ assert Or(-y >= -x, -y < -x).simplify() == S.true
1079
+
1080
+ assert Or(x < y, x >= y).simplify() == S.true
1081
+ assert Or(y > x, x >= y).simplify() == S.true
1082
+ assert Or(-x > -y, x >= y).simplify() == S.true
1083
+ assert Or(-y < -x, x >= y).simplify() == S.true
1084
+ assert Or(x < y, -x <= -y).simplify() == S.true
1085
+ assert Or(-x > -y, -x <= -y).simplify() == S.true
1086
+ assert Or(y > x, -x <= -y).simplify() == S.true
1087
+ assert Or(-y < -x, -x <= -y).simplify() == S.true
1088
+ assert Or(x < y, y <= x).simplify() == S.true
1089
+ assert Or(y > x, y <= x).simplify() == S.true
1090
+ assert Or(-x > -y, y <= x).simplify() == S.true
1091
+ assert Or(-y < -x, y <= x).simplify() == S.true
1092
+ assert Or(x < y, -y >= -x).simplify() == S.true
1093
+ assert Or(y > x, -y >= -x).simplify() == S.true
1094
+ assert Or(-x > -y, -y >= -x).simplify() == S.true
1095
+ assert Or(-y < -x, -y >= -x).simplify() == S.true
1096
+
1097
+ # Some other tests
1098
+ assert Or(x >= y, w < z, x <= y).simplify() == S.true
1099
+ assert And(x >= y, x < y).simplify() == S.false
1100
+ assert Or(x >= y, Eq(y, x)).simplify() == (x >= y)
1101
+ assert And(x >= y, Eq(y, x)).simplify() == Eq(x, y)
1102
+ assert And(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y).simplify() == \
1103
+ (Eq(x, y) & (x >= 1) & (y >= 5) & (y > z))
1104
+ assert Or(Eq(x, y), x >= y, w < y, z < y).simplify() == \
1105
+ (x >= y) | (y > z) | (w < y)
1106
+ assert And(Eq(x, y), x >= y, w < y, y >= z, z < y).simplify() == \
1107
+ Eq(x, y) & (y > z) & (w < y)
1108
+ # assert And(Eq(x, y), x >= y, w < y, y >= z, z < y).simplify(relational_minmax=True) == \
1109
+ # And(Eq(x, y), y > Max(w, z))
1110
+ # assert Or(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y).simplify(relational_minmax=True) == \
1111
+ # (Eq(x, y) | (x >= 1) | (y > Min(2, z)))
1112
+ assert And(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y).simplify() == \
1113
+ (Eq(x, y) & (x >= 1) & (y >= 5) & (y > z))
1114
+ assert (Eq(x, y) & Eq(d, e) & (x >= y) & (d >= e)).simplify() == \
1115
+ (Eq(x, y) & Eq(d, e) & (d >= e))
1116
+ assert And(Eq(x, y), Eq(x, -y)).simplify() == And(Eq(x, 0), Eq(y, 0))
1117
+ assert Xor(x >= y, x <= y).simplify() == Ne(x, y)
1118
+ assert And(x > 1, x < -1, Eq(x, y)).simplify() == S.false
1119
+ # From #16690
1120
+ assert And(x >= y, Eq(y, 0)).simplify() == And(x >= 0, Eq(y, 0))
1121
+ assert Or(Ne(x, 1), Ne(x, 2)).simplify() == S.true
1122
+ assert And(Eq(x, 1), Ne(2, x)).simplify() == Eq(x, 1)
1123
+ assert Or(Eq(x, 1), Ne(2, x)).simplify() == Ne(x, 2)
1124
+
1125
+
1126
+ def test_issue_8373():
1127
+ x = symbols('x', real=True)
1128
+ assert Or(x < 1, x > -1).simplify() == S.true
1129
+ assert Or(x < 1, x >= 1).simplify() == S.true
1130
+ assert And(x < 1, x >= 1).simplify() == S.false
1131
+ assert Or(x <= 1, x >= 1).simplify() == S.true
1132
+
1133
+
1134
+ def test_issue_7950():
1135
+ x = symbols('x', real=True)
1136
+ assert And(Eq(x, 1), Eq(x, 2)).simplify() == S.false
1137
+
1138
+
1139
+ @slow
1140
+ def test_relational_simplification_numerically():
1141
+ def test_simplification_numerically_function(original, simplified):
1142
+ symb = original.free_symbols
1143
+ n = len(symb)
1144
+ valuelist = list(set(combinations(list(range(-(n - 1), n)) * n, n)))
1145
+ for values in valuelist:
1146
+ sublist = dict(zip(symb, values))
1147
+ originalvalue = original.subs(sublist)
1148
+ simplifiedvalue = simplified.subs(sublist)
1149
+ assert originalvalue == simplifiedvalue, "Original: {}\nand" \
1150
+ " simplified: {}\ndo not evaluate to the same value for {}" \
1151
+ "".format(original, simplified, sublist)
1152
+
1153
+ w, x, y, z = symbols('w x y z', real=True)
1154
+ d, e = symbols('d e', real=False)
1155
+
1156
+ expressions = (And(Eq(x, y), x >= y, w < y, y >= z, z < y),
1157
+ And(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y),
1158
+ Or(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y),
1159
+ And(x >= y, Eq(y, x)),
1160
+ Or(And(Eq(x, y), x >= y, w < y, Or(y >= z, z < y)),
1161
+ And(Eq(x, y), x >= 1, 2 < y, y >= -1, z < y)),
1162
+ (Eq(x, y) & Eq(d, e) & (x >= y) & (d >= e)),
1163
+ )
1164
+
1165
+ for expression in expressions:
1166
+ test_simplification_numerically_function(expression,
1167
+ expression.simplify())
1168
+
1169
+
1170
+ def test_relational_simplification_patterns_numerically():
1171
+ from sympy.core import Wild
1172
+ from sympy.logic.boolalg import _simplify_patterns_and, \
1173
+ _simplify_patterns_or, _simplify_patterns_xor
1174
+ a = Wild('a')
1175
+ b = Wild('b')
1176
+ c = Wild('c')
1177
+ symb = [a, b, c]
1178
+ patternlists = [[And, _simplify_patterns_and()],
1179
+ [Or, _simplify_patterns_or()],
1180
+ [Xor, _simplify_patterns_xor()]]
1181
+ valuelist = list(set(combinations(list(range(-2, 3)) * 3, 3)))
1182
+ # Skip combinations of +/-2 and 0, except for all 0
1183
+ valuelist = [v for v in valuelist if any(w % 2 for w in v) or not any(v)]
1184
+ for func, patternlist in patternlists:
1185
+ for pattern in patternlist:
1186
+ original = func(*pattern[0].args)
1187
+ simplified = pattern[1]
1188
+ for values in valuelist:
1189
+ sublist = dict(zip(symb, values))
1190
+ originalvalue = original.xreplace(sublist)
1191
+ simplifiedvalue = simplified.xreplace(sublist)
1192
+ assert originalvalue == simplifiedvalue, "Original: {}\nand" \
1193
+ " simplified: {}\ndo not evaluate to the same value for" \
1194
+ "{}".format(pattern[0], simplified, sublist)
1195
+
1196
+
1197
+ def test_issue_16803():
1198
+ n = symbols('n')
1199
+ # No simplification done, but should not raise an exception
1200
+ assert ((n > 3) | (n < 0) | ((n > 0) & (n < 3))).simplify() == \
1201
+ (n > 3) | (n < 0) | ((n > 0) & (n < 3))
1202
+
1203
+
1204
+ def test_issue_17530():
1205
+ r = {x: oo, y: oo}
1206
+ assert Or(x + y > 0, x - y < 0).subs(r)
1207
+ assert not And(x + y < 0, x - y < 0).subs(r)
1208
+ raises(TypeError, lambda: Or(x + y < 0, x - y < 0).subs(r))
1209
+ raises(TypeError, lambda: And(x + y > 0, x - y < 0).subs(r))
1210
+ raises(TypeError, lambda: And(x + y > 0, x - y < 0).subs(r))
1211
+
1212
+
1213
+ def test_anf_coeffs():
1214
+ assert anf_coeffs([1, 0]) == [1, 1]
1215
+ assert anf_coeffs([0, 0, 0, 1]) == [0, 0, 0, 1]
1216
+ assert anf_coeffs([0, 1, 1, 1]) == [0, 1, 1, 1]
1217
+ assert anf_coeffs([1, 1, 1, 0]) == [1, 0, 0, 1]
1218
+ assert anf_coeffs([1, 0, 0, 0]) == [1, 1, 1, 1]
1219
+ assert anf_coeffs([1, 0, 0, 1]) == [1, 1, 1, 0]
1220
+ assert anf_coeffs([1, 1, 0, 1]) == [1, 0, 1, 1]
1221
+
1222
+
1223
+ def test_ANFform():
1224
+ x, y = symbols('x,y')
1225
+ assert ANFform([x], [1, 1]) == True
1226
+ assert ANFform([x], [0, 0]) == False
1227
+ assert ANFform([x], [1, 0]) == Xor(x, True, remove_true=False)
1228
+ assert ANFform([x, y], [1, 1, 1, 0]) == \
1229
+ Xor(True, And(x, y), remove_true=False)
1230
+
1231
+
1232
+ def test_bool_minterm():
1233
+ x, y = symbols('x,y')
1234
+ assert bool_minterm(3, [x, y]) == And(x, y)
1235
+ assert bool_minterm([1, 0], [x, y]) == And(Not(y), x)
1236
+
1237
+
1238
+ def test_bool_maxterm():
1239
+ x, y = symbols('x,y')
1240
+ assert bool_maxterm(2, [x, y]) == Or(Not(x), y)
1241
+ assert bool_maxterm([0, 1], [x, y]) == Or(Not(y), x)
1242
+
1243
+
1244
+ def test_bool_monomial():
1245
+ x, y = symbols('x,y')
1246
+ assert bool_monomial(1, [x, y]) == y
1247
+ assert bool_monomial([1, 1], [x, y]) == And(x, y)
1248
+
1249
+
1250
+ def test_check_pair():
1251
+ assert _check_pair([0, 1, 0], [0, 1, 1]) == 2
1252
+ assert _check_pair([0, 1, 0], [1, 1, 1]) == -1
1253
+
1254
+
1255
+ def test_issue_19114():
1256
+ expr = (B & C) | (A & ~C) | (~A & ~B)
1257
+ # Expression is minimal, but there are multiple minimal forms possible
1258
+ res1 = (A & B) | (C & ~A) | (~B & ~C)
1259
+ result = to_dnf(expr, simplify=True)
1260
+ assert result in (expr, res1)
1261
+
1262
+
1263
+ def test_issue_20870():
1264
+ result = SOPform([a, b, c, d], [1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 14, 15])
1265
+ expected = ((d & ~b) | (a & b & c) | (a & ~c & ~d) |
1266
+ (b & ~a & ~c) | (c & ~a & ~d))
1267
+ assert result == expected
1268
+
1269
+
1270
+ def test_convert_to_varsSOP():
1271
+ assert _convert_to_varsSOP([0, 1, 0], [x, y, z]) == And(Not(x), y, Not(z))
1272
+ assert _convert_to_varsSOP([3, 1, 0], [x, y, z]) == And(y, Not(z))
1273
+
1274
+
1275
+ def test_convert_to_varsPOS():
1276
+ assert _convert_to_varsPOS([0, 1, 0], [x, y, z]) == Or(x, Not(y), z)
1277
+ assert _convert_to_varsPOS([3, 1, 0], [x, y, z]) == Or(Not(y), z)
1278
+
1279
+
1280
+ def test_gateinputcount():
1281
+ a, b, c, d, e = symbols('a:e')
1282
+ assert gateinputcount(And(a, b)) == 2
1283
+ assert gateinputcount(a | b & c & d ^ (e | a)) == 9
1284
+ assert gateinputcount(And(a, True)) == 0
1285
+ raises(TypeError, lambda: gateinputcount(a * b))
1286
+
1287
+
1288
+ def test_refine():
1289
+ # relational
1290
+ assert not refine(x < 0, ~(x < 0))
1291
+ assert refine(x < 0, (x < 0))
1292
+ assert refine(x < 0, (0 > x)) is S.true
1293
+ assert refine(x < 0, (y < 0)) == (x < 0)
1294
+ assert not refine(x <= 0, ~(x <= 0))
1295
+ assert refine(x <= 0, (x <= 0))
1296
+ assert refine(x <= 0, (0 >= x)) is S.true
1297
+ assert refine(x <= 0, (y <= 0)) == (x <= 0)
1298
+ assert not refine(x > 0, ~(x > 0))
1299
+ assert refine(x > 0, (x > 0))
1300
+ assert refine(x > 0, (0 < x)) is S.true
1301
+ assert refine(x > 0, (y > 0)) == (x > 0)
1302
+ assert not refine(x >= 0, ~(x >= 0))
1303
+ assert refine(x >= 0, (x >= 0))
1304
+ assert refine(x >= 0, (0 <= x)) is S.true
1305
+ assert refine(x >= 0, (y >= 0)) == (x >= 0)
1306
+ assert not refine(Eq(x, 0), ~(Eq(x, 0)))
1307
+ assert refine(Eq(x, 0), (Eq(x, 0)))
1308
+ assert refine(Eq(x, 0), (Eq(0, x))) is S.true
1309
+ assert refine(Eq(x, 0), (Eq(y, 0))) == Eq(x, 0)
1310
+ assert not refine(Ne(x, 0), ~(Ne(x, 0)))
1311
+ assert refine(Ne(x, 0), (Ne(0, x))) is S.true
1312
+ assert refine(Ne(x, 0), (Ne(x, 0)))
1313
+ assert refine(Ne(x, 0), (Ne(y, 0))) == (Ne(x, 0))
1314
+
1315
+ # boolean functions
1316
+ assert refine(And(x > 0, y > 0), (x > 0)) == (y > 0)
1317
+ assert refine(And(x > 0, y > 0), (x > 0) & (y > 0)) is S.true
1318
+
1319
+ # predicates
1320
+ assert refine(Q.positive(x), Q.positive(x)) is S.true
1321
+ assert refine(Q.positive(x), Q.negative(x)) is S.false
1322
+ assert refine(Q.positive(x), Q.real(x)) == Q.positive(x)
1323
+
1324
+
1325
+ def test_relational_threeterm_simplification_patterns_numerically():
1326
+ from sympy.core import Wild
1327
+ from sympy.logic.boolalg import _simplify_patterns_and3
1328
+ a = Wild('a')
1329
+ b = Wild('b')
1330
+ c = Wild('c')
1331
+ symb = [a, b, c]
1332
+ patternlists = [[And, _simplify_patterns_and3()]]
1333
+ valuelist = list(set(combinations(list(range(-2, 3)) * 3, 3)))
1334
+ # Skip combinations of +/-2 and 0, except for all 0
1335
+ valuelist = [v for v in valuelist if any(w % 2 for w in v) or not any(v)]
1336
+ for func, patternlist in patternlists:
1337
+ for pattern in patternlist:
1338
+ original = func(*pattern[0].args)
1339
+ simplified = pattern[1]
1340
+ for values in valuelist:
1341
+ sublist = dict(zip(symb, values))
1342
+ originalvalue = original.xreplace(sublist)
1343
+ simplifiedvalue = simplified.xreplace(sublist)
1344
+ assert originalvalue == simplifiedvalue, "Original: {}\nand" \
1345
+ " simplified: {}\ndo not evaluate to the same value for" \
1346
+ "{}".format(pattern[0], simplified, sublist)
1347
+
1348
+
1349
+ def test_issue_25451():
1350
+ x = Or(And(a, c), Eq(a, b))
1351
+ assert isinstance(x, Or)
1352
+ assert set(x.args) == {And(a, c), Eq(a, b)}
1353
+
1354
+
1355
+ def test_issue_26985():
1356
+ a, b, c, d = symbols('a b c d')
1357
+
1358
+ # Expression before applying to_anf
1359
+ x = Xor(c, And(a, b), And(a, c))
1360
+ y = Xor(a, b, And(a, c))
1361
+
1362
+ # Applying to_anf
1363
+ result = Xor(Xor(d, And(x, y)), And(x, y))
1364
+ result_anf = to_anf(Xor(to_anf(Xor(d, And(x, y))), And(x, y)))
1365
+
1366
+ assert result_anf == d
1367
+ assert result == d
phivenv/Lib/site-packages/sympy/logic/tests/test_dimacs.py ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Various tests on satisfiability using dimacs cnf file syntax
2
+ You can find lots of cnf files in
3
+ ftp://dimacs.rutgers.edu/pub/challenge/satisfiability/benchmarks/cnf/
4
+ """
5
+
6
+ from sympy.logic.utilities.dimacs import load
7
+ from sympy.logic.algorithms.dpll import dpll_satisfiable
8
+
9
+
10
+ def test_f1():
11
+ assert bool(dpll_satisfiable(load(f1)))
12
+
13
+
14
+ def test_f2():
15
+ assert bool(dpll_satisfiable(load(f2)))
16
+
17
+
18
+ def test_f3():
19
+ assert bool(dpll_satisfiable(load(f3)))
20
+
21
+
22
+ def test_f4():
23
+ assert not bool(dpll_satisfiable(load(f4)))
24
+
25
+
26
+ def test_f5():
27
+ assert bool(dpll_satisfiable(load(f5)))
28
+
29
+ f1 = """c simple example
30
+ c Resolution: SATISFIABLE
31
+ c
32
+ p cnf 3 2
33
+ 1 -3 0
34
+ 2 3 -1 0
35
+ """
36
+
37
+
38
+ f2 = """c an example from Quinn's text, 16 variables and 18 clauses.
39
+ c Resolution: SATISFIABLE
40
+ c
41
+ p cnf 16 18
42
+ 1 2 0
43
+ -2 -4 0
44
+ 3 4 0
45
+ -4 -5 0
46
+ 5 -6 0
47
+ 6 -7 0
48
+ 6 7 0
49
+ 7 -16 0
50
+ 8 -9 0
51
+ -8 -14 0
52
+ 9 10 0
53
+ 9 -10 0
54
+ -10 -11 0
55
+ 10 12 0
56
+ 11 12 0
57
+ 13 14 0
58
+ 14 -15 0
59
+ 15 16 0
60
+ """
61
+
62
+ f3 = """c
63
+ p cnf 6 9
64
+ -1 0
65
+ -3 0
66
+ 2 -1 0
67
+ 2 -4 0
68
+ 5 -4 0
69
+ -1 -3 0
70
+ -4 -6 0
71
+ 1 3 -2 0
72
+ 4 6 -2 -5 0
73
+ """
74
+
75
+ f4 = """c
76
+ c file: hole6.cnf [http://people.sc.fsu.edu/~jburkardt/data/cnf/hole6.cnf]
77
+ c
78
+ c SOURCE: John Hooker (jh38+@andrew.cmu.edu)
79
+ c
80
+ c DESCRIPTION: Pigeon hole problem of placing n (for file 'holen.cnf') pigeons
81
+ c in n+1 holes without placing 2 pigeons in the same hole
82
+ c
83
+ c NOTE: Part of the collection at the Forschungsinstitut fuer
84
+ c anwendungsorientierte Wissensverarbeitung in Ulm Germany.
85
+ c
86
+ c NOTE: Not satisfiable
87
+ c
88
+ p cnf 42 133
89
+ -1 -7 0
90
+ -1 -13 0
91
+ -1 -19 0
92
+ -1 -25 0
93
+ -1 -31 0
94
+ -1 -37 0
95
+ -7 -13 0
96
+ -7 -19 0
97
+ -7 -25 0
98
+ -7 -31 0
99
+ -7 -37 0
100
+ -13 -19 0
101
+ -13 -25 0
102
+ -13 -31 0
103
+ -13 -37 0
104
+ -19 -25 0
105
+ -19 -31 0
106
+ -19 -37 0
107
+ -25 -31 0
108
+ -25 -37 0
109
+ -31 -37 0
110
+ -2 -8 0
111
+ -2 -14 0
112
+ -2 -20 0
113
+ -2 -26 0
114
+ -2 -32 0
115
+ -2 -38 0
116
+ -8 -14 0
117
+ -8 -20 0
118
+ -8 -26 0
119
+ -8 -32 0
120
+ -8 -38 0
121
+ -14 -20 0
122
+ -14 -26 0
123
+ -14 -32 0
124
+ -14 -38 0
125
+ -20 -26 0
126
+ -20 -32 0
127
+ -20 -38 0
128
+ -26 -32 0
129
+ -26 -38 0
130
+ -32 -38 0
131
+ -3 -9 0
132
+ -3 -15 0
133
+ -3 -21 0
134
+ -3 -27 0
135
+ -3 -33 0
136
+ -3 -39 0
137
+ -9 -15 0
138
+ -9 -21 0
139
+ -9 -27 0
140
+ -9 -33 0
141
+ -9 -39 0
142
+ -15 -21 0
143
+ -15 -27 0
144
+ -15 -33 0
145
+ -15 -39 0
146
+ -21 -27 0
147
+ -21 -33 0
148
+ -21 -39 0
149
+ -27 -33 0
150
+ -27 -39 0
151
+ -33 -39 0
152
+ -4 -10 0
153
+ -4 -16 0
154
+ -4 -22 0
155
+ -4 -28 0
156
+ -4 -34 0
157
+ -4 -40 0
158
+ -10 -16 0
159
+ -10 -22 0
160
+ -10 -28 0
161
+ -10 -34 0
162
+ -10 -40 0
163
+ -16 -22 0
164
+ -16 -28 0
165
+ -16 -34 0
166
+ -16 -40 0
167
+ -22 -28 0
168
+ -22 -34 0
169
+ -22 -40 0
170
+ -28 -34 0
171
+ -28 -40 0
172
+ -34 -40 0
173
+ -5 -11 0
174
+ -5 -17 0
175
+ -5 -23 0
176
+ -5 -29 0
177
+ -5 -35 0
178
+ -5 -41 0
179
+ -11 -17 0
180
+ -11 -23 0
181
+ -11 -29 0
182
+ -11 -35 0
183
+ -11 -41 0
184
+ -17 -23 0
185
+ -17 -29 0
186
+ -17 -35 0
187
+ -17 -41 0
188
+ -23 -29 0
189
+ -23 -35 0
190
+ -23 -41 0
191
+ -29 -35 0
192
+ -29 -41 0
193
+ -35 -41 0
194
+ -6 -12 0
195
+ -6 -18 0
196
+ -6 -24 0
197
+ -6 -30 0
198
+ -6 -36 0
199
+ -6 -42 0
200
+ -12 -18 0
201
+ -12 -24 0
202
+ -12 -30 0
203
+ -12 -36 0
204
+ -12 -42 0
205
+ -18 -24 0
206
+ -18 -30 0
207
+ -18 -36 0
208
+ -18 -42 0
209
+ -24 -30 0
210
+ -24 -36 0
211
+ -24 -42 0
212
+ -30 -36 0
213
+ -30 -42 0
214
+ -36 -42 0
215
+ 6 5 4 3 2 1 0
216
+ 12 11 10 9 8 7 0
217
+ 18 17 16 15 14 13 0
218
+ 24 23 22 21 20 19 0
219
+ 30 29 28 27 26 25 0
220
+ 36 35 34 33 32 31 0
221
+ 42 41 40 39 38 37 0
222
+ """
223
+
224
+ f5 = """c simple example requiring variable selection
225
+ c
226
+ c NOTE: Satisfiable
227
+ c
228
+ p cnf 5 5
229
+ 1 2 3 0
230
+ 1 -2 3 0
231
+ 4 5 -3 0
232
+ 1 -4 -3 0
233
+ -1 -5 0
234
+ """
phivenv/Lib/site-packages/sympy/logic/tests/test_inference.py ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """For more tests on satisfiability, see test_dimacs"""
2
+
3
+ from sympy.assumptions.ask import Q
4
+ from sympy.core.symbol import symbols
5
+ from sympy.core.relational import Unequality
6
+ from sympy.logic.boolalg import And, Or, Implies, Equivalent, true, false
7
+ from sympy.logic.inference import literal_symbol, \
8
+ pl_true, satisfiable, valid, entails, PropKB
9
+ from sympy.logic.algorithms.dpll import dpll, dpll_satisfiable, \
10
+ find_pure_symbol, find_unit_clause, unit_propagate, \
11
+ find_pure_symbol_int_repr, find_unit_clause_int_repr, \
12
+ unit_propagate_int_repr
13
+ from sympy.logic.algorithms.dpll2 import dpll_satisfiable as dpll2_satisfiable
14
+
15
+ from sympy.logic.algorithms.z3_wrapper import z3_satisfiable
16
+ from sympy.assumptions.cnf import CNF, EncodedCNF
17
+ from sympy.logic.tests.test_lra_theory import make_random_problem
18
+ from sympy.core.random import randint
19
+
20
+ from sympy.testing.pytest import raises, skip
21
+ from sympy.external import import_module
22
+
23
+
24
+ def test_literal():
25
+ A, B = symbols('A,B')
26
+ assert literal_symbol(True) is True
27
+ assert literal_symbol(False) is False
28
+ assert literal_symbol(A) is A
29
+ assert literal_symbol(~A) is A
30
+
31
+
32
+ def test_find_pure_symbol():
33
+ A, B, C = symbols('A,B,C')
34
+ assert find_pure_symbol([A], [A]) == (A, True)
35
+ assert find_pure_symbol([A, B], [~A | B, ~B | A]) == (None, None)
36
+ assert find_pure_symbol([A, B, C], [ A | ~B, ~B | ~C, C | A]) == (A, True)
37
+ assert find_pure_symbol([A, B, C], [~A | B, B | ~C, C | A]) == (B, True)
38
+ assert find_pure_symbol([A, B, C], [~A | ~B, ~B | ~C, C | A]) == (B, False)
39
+ assert find_pure_symbol(
40
+ [A, B, C], [~A | B, ~B | ~C, C | A]) == (None, None)
41
+
42
+
43
+ def test_find_pure_symbol_int_repr():
44
+ assert find_pure_symbol_int_repr([1], [{1}]) == (1, True)
45
+ assert find_pure_symbol_int_repr([1, 2],
46
+ [{-1, 2}, {-2, 1}]) == (None, None)
47
+ assert find_pure_symbol_int_repr([1, 2, 3],
48
+ [{1, -2}, {-2, -3}, {3, 1}]) == (1, True)
49
+ assert find_pure_symbol_int_repr([1, 2, 3],
50
+ [{-1, 2}, {2, -3}, {3, 1}]) == (2, True)
51
+ assert find_pure_symbol_int_repr([1, 2, 3],
52
+ [{-1, -2}, {-2, -3}, {3, 1}]) == (2, False)
53
+ assert find_pure_symbol_int_repr([1, 2, 3],
54
+ [{-1, 2}, {-2, -3}, {3, 1}]) == (None, None)
55
+
56
+
57
+ def test_unit_clause():
58
+ A, B, C = symbols('A,B,C')
59
+ assert find_unit_clause([A], {}) == (A, True)
60
+ assert find_unit_clause([A, ~A], {}) == (A, True) # Wrong ??
61
+ assert find_unit_clause([A | B], {A: True}) == (B, True)
62
+ assert find_unit_clause([A | B], {B: True}) == (A, True)
63
+ assert find_unit_clause(
64
+ [A | B | C, B | ~C, A | ~B], {A: True}) == (B, False)
65
+ assert find_unit_clause([A | B | C, B | ~C, A | B], {A: True}) == (B, True)
66
+ assert find_unit_clause([A | B | C, B | ~C, A ], {}) == (A, True)
67
+
68
+
69
+ def test_unit_clause_int_repr():
70
+ assert find_unit_clause_int_repr(map(set, [[1]]), {}) == (1, True)
71
+ assert find_unit_clause_int_repr(map(set, [[1], [-1]]), {}) == (1, True)
72
+ assert find_unit_clause_int_repr([{1, 2}], {1: True}) == (2, True)
73
+ assert find_unit_clause_int_repr([{1, 2}], {2: True}) == (1, True)
74
+ assert find_unit_clause_int_repr(map(set,
75
+ [[1, 2, 3], [2, -3], [1, -2]]), {1: True}) == (2, False)
76
+ assert find_unit_clause_int_repr(map(set,
77
+ [[1, 2, 3], [3, -3], [1, 2]]), {1: True}) == (2, True)
78
+
79
+ A, B, C = symbols('A,B,C')
80
+ assert find_unit_clause([A | B | C, B | ~C, A ], {}) == (A, True)
81
+
82
+
83
+ def test_unit_propagate():
84
+ A, B, C = symbols('A,B,C')
85
+ assert unit_propagate([A | B], A) == []
86
+ assert unit_propagate([A | B, ~A | C, ~C | B, A], A) == [C, ~C | B, A]
87
+
88
+
89
+ def test_unit_propagate_int_repr():
90
+ assert unit_propagate_int_repr([{1, 2}], 1) == []
91
+ assert unit_propagate_int_repr(map(set,
92
+ [[1, 2], [-1, 3], [-3, 2], [1]]), 1) == [{3}, {-3, 2}]
93
+
94
+
95
+ def test_dpll():
96
+ """This is also tested in test_dimacs"""
97
+ A, B, C = symbols('A,B,C')
98
+ assert dpll([A | B], [A, B], {A: True, B: True}) == {A: True, B: True}
99
+
100
+
101
+ def test_dpll_satisfiable():
102
+ A, B, C = symbols('A,B,C')
103
+ assert dpll_satisfiable( A & ~A ) is False
104
+ assert dpll_satisfiable( A & ~B ) == {A: True, B: False}
105
+ assert dpll_satisfiable(
106
+ A | B ) in ({A: True}, {B: True}, {A: True, B: True})
107
+ assert dpll_satisfiable(
108
+ (~A | B) & (~B | A) ) in ({A: True, B: True}, {A: False, B: False})
109
+ assert dpll_satisfiable( (A | B) & (~B | C) ) in ({A: True, B: False},
110
+ {A: True, C: True}, {B: True, C: True})
111
+ assert dpll_satisfiable( A & B & C ) == {A: True, B: True, C: True}
112
+ assert dpll_satisfiable( (A | B) & (A >> B) ) == {B: True}
113
+ assert dpll_satisfiable( Equivalent(A, B) & A ) == {A: True, B: True}
114
+ assert dpll_satisfiable( Equivalent(A, B) & ~A ) == {A: False, B: False}
115
+
116
+
117
+ def test_dpll2_satisfiable():
118
+ A, B, C = symbols('A,B,C')
119
+ assert dpll2_satisfiable( A & ~A ) is False
120
+ assert dpll2_satisfiable( A & ~B ) == {A: True, B: False}
121
+ assert dpll2_satisfiable(
122
+ A | B ) in ({A: True}, {B: True}, {A: True, B: True})
123
+ assert dpll2_satisfiable(
124
+ (~A | B) & (~B | A) ) in ({A: True, B: True}, {A: False, B: False})
125
+ assert dpll2_satisfiable( (A | B) & (~B | C) ) in ({A: True, B: False, C: True},
126
+ {A: True, B: True, C: True})
127
+ assert dpll2_satisfiable( A & B & C ) == {A: True, B: True, C: True}
128
+ assert dpll2_satisfiable( (A | B) & (A >> B) ) in ({B: True, A: False},
129
+ {B: True, A: True})
130
+ assert dpll2_satisfiable( Equivalent(A, B) & A ) == {A: True, B: True}
131
+ assert dpll2_satisfiable( Equivalent(A, B) & ~A ) == {A: False, B: False}
132
+
133
+
134
+ def test_minisat22_satisfiable():
135
+ A, B, C = symbols('A,B,C')
136
+ minisat22_satisfiable = lambda expr: satisfiable(expr, algorithm="minisat22")
137
+ assert minisat22_satisfiable( A & ~A ) is False
138
+ assert minisat22_satisfiable( A & ~B ) == {A: True, B: False}
139
+ assert minisat22_satisfiable(
140
+ A | B ) in ({A: True}, {B: False}, {A: False, B: True}, {A: True, B: True}, {A: True, B: False})
141
+ assert minisat22_satisfiable(
142
+ (~A | B) & (~B | A) ) in ({A: True, B: True}, {A: False, B: False})
143
+ assert minisat22_satisfiable( (A | B) & (~B | C) ) in ({A: True, B: False, C: True},
144
+ {A: True, B: True, C: True}, {A: False, B: True, C: True}, {A: True, B: False, C: False})
145
+ assert minisat22_satisfiable( A & B & C ) == {A: True, B: True, C: True}
146
+ assert minisat22_satisfiable( (A | B) & (A >> B) ) in ({B: True, A: False},
147
+ {B: True, A: True})
148
+ assert minisat22_satisfiable( Equivalent(A, B) & A ) == {A: True, B: True}
149
+ assert minisat22_satisfiable( Equivalent(A, B) & ~A ) == {A: False, B: False}
150
+
151
+ def test_minisat22_minimal_satisfiable():
152
+ A, B, C = symbols('A,B,C')
153
+ minisat22_satisfiable = lambda expr, minimal=True: satisfiable(expr, algorithm="minisat22", minimal=True)
154
+ assert minisat22_satisfiable( A & ~A ) is False
155
+ assert minisat22_satisfiable( A & ~B ) == {A: True, B: False}
156
+ assert minisat22_satisfiable(
157
+ A | B ) in ({A: True}, {B: False}, {A: False, B: True}, {A: True, B: True}, {A: True, B: False})
158
+ assert minisat22_satisfiable(
159
+ (~A | B) & (~B | A) ) in ({A: True, B: True}, {A: False, B: False})
160
+ assert minisat22_satisfiable( (A | B) & (~B | C) ) in ({A: True, B: False, C: True},
161
+ {A: True, B: True, C: True}, {A: False, B: True, C: True}, {A: True, B: False, C: False})
162
+ assert minisat22_satisfiable( A & B & C ) == {A: True, B: True, C: True}
163
+ assert minisat22_satisfiable( (A | B) & (A >> B) ) in ({B: True, A: False},
164
+ {B: True, A: True})
165
+ assert minisat22_satisfiable( Equivalent(A, B) & A ) == {A: True, B: True}
166
+ assert minisat22_satisfiable( Equivalent(A, B) & ~A ) == {A: False, B: False}
167
+ g = satisfiable((A | B | C),algorithm="minisat22",minimal=True,all_models=True)
168
+ sol = next(g)
169
+ first_solution = {key for key, value in sol.items() if value}
170
+ sol=next(g)
171
+ second_solution = {key for key, value in sol.items() if value}
172
+ sol=next(g)
173
+ third_solution = {key for key, value in sol.items() if value}
174
+ assert not first_solution <= second_solution
175
+ assert not second_solution <= third_solution
176
+ assert not first_solution <= third_solution
177
+
178
+ def test_satisfiable():
179
+ A, B, C = symbols('A,B,C')
180
+ assert satisfiable(A & (A >> B) & ~B) is False
181
+
182
+
183
+ def test_valid():
184
+ A, B, C = symbols('A,B,C')
185
+ assert valid(A >> (B >> A)) is True
186
+ assert valid((A >> (B >> C)) >> ((A >> B) >> (A >> C))) is True
187
+ assert valid((~B >> ~A) >> (A >> B)) is True
188
+ assert valid(A | B | C) is False
189
+ assert valid(A >> B) is False
190
+
191
+
192
+ def test_pl_true():
193
+ A, B, C = symbols('A,B,C')
194
+ assert pl_true(True) is True
195
+ assert pl_true( A & B, {A: True, B: True}) is True
196
+ assert pl_true( A | B, {A: True}) is True
197
+ assert pl_true( A | B, {B: True}) is True
198
+ assert pl_true( A | B, {A: None, B: True}) is True
199
+ assert pl_true( A >> B, {A: False}) is True
200
+ assert pl_true( A | B | ~C, {A: False, B: True, C: True}) is True
201
+ assert pl_true(Equivalent(A, B), {A: False, B: False}) is True
202
+
203
+ # test for false
204
+ assert pl_true(False) is False
205
+ assert pl_true( A & B, {A: False, B: False}) is False
206
+ assert pl_true( A & B, {A: False}) is False
207
+ assert pl_true( A & B, {B: False}) is False
208
+ assert pl_true( A | B, {A: False, B: False}) is False
209
+
210
+ #test for None
211
+ assert pl_true(B, {B: None}) is None
212
+ assert pl_true( A & B, {A: True, B: None}) is None
213
+ assert pl_true( A >> B, {A: True, B: None}) is None
214
+ assert pl_true(Equivalent(A, B), {A: None}) is None
215
+ assert pl_true(Equivalent(A, B), {A: True, B: None}) is None
216
+
217
+ # Test for deep
218
+ assert pl_true(A | B, {A: False}, deep=True) is None
219
+ assert pl_true(~A & ~B, {A: False}, deep=True) is None
220
+ assert pl_true(A | B, {A: False, B: False}, deep=True) is False
221
+ assert pl_true(A & B & (~A | ~B), {A: True}, deep=True) is False
222
+ assert pl_true((C >> A) >> (B >> A), {C: True}, deep=True) is True
223
+
224
+
225
+ def test_pl_true_wrong_input():
226
+ from sympy.core.numbers import pi
227
+ raises(ValueError, lambda: pl_true('John Cleese'))
228
+ raises(ValueError, lambda: pl_true(42 + pi + pi ** 2))
229
+ raises(ValueError, lambda: pl_true(42))
230
+
231
+
232
+ def test_entails():
233
+ A, B, C = symbols('A, B, C')
234
+ assert entails(A, [A >> B, ~B]) is False
235
+ assert entails(B, [Equivalent(A, B), A]) is True
236
+ assert entails((A >> B) >> (~A >> ~B)) is False
237
+ assert entails((A >> B) >> (~B >> ~A)) is True
238
+
239
+
240
+ def test_PropKB():
241
+ A, B, C = symbols('A,B,C')
242
+ kb = PropKB()
243
+ assert kb.ask(A >> B) is False
244
+ assert kb.ask(A >> (B >> A)) is True
245
+ kb.tell(A >> B)
246
+ kb.tell(B >> C)
247
+ assert kb.ask(A) is False
248
+ assert kb.ask(B) is False
249
+ assert kb.ask(C) is False
250
+ assert kb.ask(~A) is False
251
+ assert kb.ask(~B) is False
252
+ assert kb.ask(~C) is False
253
+ assert kb.ask(A >> C) is True
254
+ kb.tell(A)
255
+ assert kb.ask(A) is True
256
+ assert kb.ask(B) is True
257
+ assert kb.ask(C) is True
258
+ assert kb.ask(~C) is False
259
+ kb.retract(A)
260
+ assert kb.ask(C) is False
261
+
262
+
263
+ def test_propKB_tolerant():
264
+ """"tolerant to bad input"""
265
+ kb = PropKB()
266
+ A, B, C = symbols('A,B,C')
267
+ assert kb.ask(B) is False
268
+
269
+ def test_satisfiable_non_symbols():
270
+ x, y = symbols('x y')
271
+ assumptions = Q.zero(x*y)
272
+ facts = Implies(Q.zero(x*y), Q.zero(x) | Q.zero(y))
273
+ query = ~Q.zero(x) & ~Q.zero(y)
274
+ refutations = [
275
+ {Q.zero(x): True, Q.zero(x*y): True},
276
+ {Q.zero(y): True, Q.zero(x*y): True},
277
+ {Q.zero(x): True, Q.zero(y): True, Q.zero(x*y): True},
278
+ {Q.zero(x): True, Q.zero(y): False, Q.zero(x*y): True},
279
+ {Q.zero(x): False, Q.zero(y): True, Q.zero(x*y): True}]
280
+ assert not satisfiable(And(assumptions, facts, query), algorithm='dpll')
281
+ assert satisfiable(And(assumptions, facts, ~query), algorithm='dpll') in refutations
282
+ assert not satisfiable(And(assumptions, facts, query), algorithm='dpll2')
283
+ assert satisfiable(And(assumptions, facts, ~query), algorithm='dpll2') in refutations
284
+
285
+ def test_satisfiable_bool():
286
+ from sympy.core.singleton import S
287
+ assert satisfiable(true) == {true: true}
288
+ assert satisfiable(S.true) == {true: true}
289
+ assert satisfiable(false) is False
290
+ assert satisfiable(S.false) is False
291
+
292
+
293
+ def test_satisfiable_all_models():
294
+ from sympy.abc import A, B
295
+ assert next(satisfiable(False, all_models=True)) is False
296
+ assert list(satisfiable((A >> ~A) & A, all_models=True)) == [False]
297
+ assert list(satisfiable(True, all_models=True)) == [{true: true}]
298
+
299
+ models = [{A: True, B: False}, {A: False, B: True}]
300
+ result = satisfiable(A ^ B, all_models=True)
301
+ models.remove(next(result))
302
+ models.remove(next(result))
303
+ raises(StopIteration, lambda: next(result))
304
+ assert not models
305
+
306
+ assert list(satisfiable(Equivalent(A, B), all_models=True)) == \
307
+ [{A: False, B: False}, {A: True, B: True}]
308
+
309
+ models = [{A: False, B: False}, {A: False, B: True}, {A: True, B: True}]
310
+ for model in satisfiable(A >> B, all_models=True):
311
+ models.remove(model)
312
+ assert not models
313
+
314
+ # This is a santiy test to check that only the required number
315
+ # of solutions are generated. The expr below has 2**100 - 1 models
316
+ # which would time out the test if all are generated at once.
317
+ from sympy.utilities.iterables import numbered_symbols
318
+ from sympy.logic.boolalg import Or
319
+ sym = numbered_symbols()
320
+ X = [next(sym) for i in range(100)]
321
+ result = satisfiable(Or(*X), all_models=True)
322
+ for i in range(10):
323
+ assert next(result)
324
+
325
+
326
+ def test_z3():
327
+ z3 = import_module("z3")
328
+
329
+ if not z3:
330
+ skip("z3 not installed.")
331
+ A, B, C = symbols('A,B,C')
332
+ x, y, z = symbols('x,y,z')
333
+ assert z3_satisfiable((x >= 2) & (x < 1)) is False
334
+ assert z3_satisfiable( A & ~A ) is False
335
+
336
+ model = z3_satisfiable(A & (~A | B | C))
337
+ assert bool(model) is True
338
+ assert model[A] is True
339
+
340
+ # test nonlinear function
341
+ assert z3_satisfiable((x ** 2 >= 2) & (x < 1) & (x > -1)) is False
342
+
343
+
344
+ def test_z3_vs_lra_dpll2():
345
+ z3 = import_module("z3")
346
+ if z3 is None:
347
+ skip("z3 not installed.")
348
+
349
+ def boolean_formula_to_encoded_cnf(bf):
350
+ cnf = CNF.from_prop(bf)
351
+ enc = EncodedCNF()
352
+ enc.from_cnf(cnf)
353
+ return enc
354
+
355
+ def make_random_cnf(num_clauses=5, num_constraints=10, num_var=2):
356
+ assert num_clauses <= num_constraints
357
+ constraints = make_random_problem(num_variables=num_var, num_constraints=num_constraints, rational=False)
358
+ clauses = [[cons] for cons in constraints[:num_clauses]]
359
+ for cons in constraints[num_clauses:]:
360
+ if isinstance(cons, Unequality):
361
+ cons = ~cons
362
+ i = randint(0, num_clauses-1)
363
+ clauses[i].append(cons)
364
+
365
+ clauses = [Or(*clause) for clause in clauses]
366
+ cnf = And(*clauses)
367
+ return boolean_formula_to_encoded_cnf(cnf)
368
+
369
+ lra_dpll2_satisfiable = lambda x: dpll2_satisfiable(x, use_lra_theory=True)
370
+
371
+ for _ in range(50):
372
+ cnf = make_random_cnf(num_clauses=10, num_constraints=15, num_var=2)
373
+
374
+ try:
375
+ z3_sat = z3_satisfiable(cnf)
376
+ except z3.z3types.Z3Exception:
377
+ continue
378
+
379
+ lra_dpll2_sat = lra_dpll2_satisfiable(cnf) is not False
380
+
381
+ assert z3_sat == lra_dpll2_sat
382
+
383
+ def test_issue_27733():
384
+ x, y = symbols('x,y')
385
+ clauses = [[1, -3, -2], [5, 7, -8, -6, -4], [-10, -9, 10, 11, -4], [-12, 13, 14], [-10, 9, -6, 11, -4],
386
+ [16, -15, 18, -19, -17], [11, -6, 10, -9], [9, 11, -10, -9], [2, -3, -1], [-13, 12], [-15, 3, -17],
387
+ [-16, -15, 19, -17], [-6, -9, 10, 11, -4], [20, -1, -2], [-23, -22, -21], [10, 11, -10, -9],
388
+ [9, 11, -4, -10], [24, -6, -4], [-14, 12], [-10, -9, 9, -6, 11], [25, -27, -26], [-15, 19, -18, -17],
389
+ [5, 8, -7, -6, -4], [-30, -29, 28], [12], [14]]
390
+
391
+ encoding = {Q.gt(y, i): i for i in range(1, 31) if i != 11 and i != 12}
392
+ encoding[Q.gt(x, 0)] = 11
393
+ encoding[Q.lt(x, 0)] = 12
394
+
395
+ cnf = EncodedCNF(clauses, encoding)
396
+ assert satisfiable(cnf, use_lra_theory=True) is False
phivenv/Lib/site-packages/sympy/logic/tests/test_lra_theory.py ADDED
@@ -0,0 +1,440 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.numbers import Rational, I, oo
2
+ from sympy.core.relational import Eq
3
+ from sympy.core.symbol import symbols
4
+ from sympy.core.singleton import S
5
+ from sympy.matrices.dense import Matrix
6
+ from sympy.matrices.dense import randMatrix
7
+ from sympy.assumptions.ask import Q
8
+ from sympy.logic.boolalg import And
9
+ from sympy.abc import x, y, z
10
+ from sympy.assumptions.cnf import CNF, EncodedCNF
11
+ from sympy.functions.elementary.trigonometric import cos
12
+ from sympy.external import import_module
13
+
14
+ from sympy.logic.algorithms.lra_theory import LRASolver, UnhandledInput, LRARational, HANDLE_NEGATION
15
+ from sympy.core.random import random, choice, randint
16
+ from sympy.core.sympify import sympify
17
+ from sympy.ntheory.generate import randprime
18
+ from sympy.core.relational import StrictLessThan, StrictGreaterThan
19
+ import itertools
20
+
21
+ from sympy.testing.pytest import raises, XFAIL, skip
22
+
23
+ def make_random_problem(num_variables=2, num_constraints=2, sparsity=.1, rational=True,
24
+ disable_strict = False, disable_nonstrict=False, disable_equality=False):
25
+ def rand(sparsity=sparsity):
26
+ if random() < sparsity:
27
+ return sympify(0)
28
+ if rational:
29
+ int1, int2 = [randprime(0, 50) for _ in range(2)]
30
+ return Rational(int1, int2) * choice([-1, 1])
31
+ else:
32
+ return randint(1, 10) * choice([-1, 1])
33
+
34
+ variables = symbols('x1:%s' % (num_variables + 1))
35
+ constraints = []
36
+ for _ in range(num_constraints):
37
+ lhs, rhs = sum(rand() * x for x in variables), rand(sparsity=0) # sparsity=0 bc of bug with smtlib_code
38
+ options = []
39
+ if not disable_equality:
40
+ options += [Eq(lhs, rhs)]
41
+ if not disable_nonstrict:
42
+ options += [lhs <= rhs, lhs >= rhs]
43
+ if not disable_strict:
44
+ options += [lhs < rhs, lhs > rhs]
45
+
46
+ constraints.append(choice(options))
47
+
48
+ return constraints
49
+
50
+ def check_if_satisfiable_with_z3(constraints):
51
+ from sympy.external.importtools import import_module
52
+ from sympy.printing.smtlib import smtlib_code
53
+ from sympy.logic.boolalg import And
54
+ boolean_formula = And(*constraints)
55
+ z3 = import_module("z3")
56
+ if z3:
57
+ smtlib_string = smtlib_code(boolean_formula)
58
+ s = z3.Solver()
59
+ s.from_string(smtlib_string)
60
+ res = str(s.check())
61
+ if res == 'sat':
62
+ return True
63
+ elif res == 'unsat':
64
+ return False
65
+ else:
66
+ raise ValueError(f"z3 was not able to check the satisfiability of {boolean_formula}")
67
+
68
+ def find_rational_assignment(constr, assignment, iter=20):
69
+ eps = sympify(1)
70
+
71
+ for _ in range(iter):
72
+ assign = {key: val[0] + val[1]*eps for key, val in assignment.items()}
73
+ try:
74
+ for cons in constr:
75
+ assert cons.subs(assign) == True
76
+ return assign
77
+ except AssertionError:
78
+ eps = eps/2
79
+
80
+ return None
81
+
82
+ def boolean_formula_to_encoded_cnf(bf):
83
+ cnf = CNF.from_prop(bf)
84
+ enc = EncodedCNF()
85
+ enc.from_cnf(cnf)
86
+ return enc
87
+
88
+
89
+ def test_from_encoded_cnf():
90
+ s1, s2 = symbols("s1 s2")
91
+
92
+ # Test preprocessing
93
+ # Example is from section 3 of paper.
94
+ phi = (x >= 0) & ((x + y <= 2) | (x + 2 * y - z >= 6)) & (Eq(x + y, 2) | (x + 2 * y - z > 4))
95
+ enc = boolean_formula_to_encoded_cnf(phi)
96
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
97
+ assert lra.A.shape == (2, 5)
98
+ assert str(lra.slack) == '[_s1, _s2]'
99
+ assert str(lra.nonslack) == '[x, y, z]'
100
+ assert lra.A == Matrix([[ 1, 1, 0, -1, 0],
101
+ [-1, -2, 1, 0, -1]])
102
+ assert {(str(b.var), b.bound, b.upper, b.equality, b.strict) for b in lra.enc_to_boundary.values()} == {('_s1', 2, None, True, False),
103
+ ('_s1', 2, True, False, False),
104
+ ('_s2', -4, True, False, True),
105
+ ('_s2', -6, True, False, False),
106
+ ('x', 0, False, False, False)}
107
+
108
+
109
+ def test_problem():
110
+ from sympy.logic.algorithms.lra_theory import LRASolver
111
+ from sympy.assumptions.cnf import CNF, EncodedCNF
112
+ cons = [-2 * x - 2 * y >= 7, -9 * y >= 7, -6 * y >= 5]
113
+ cnf = CNF().from_prop(And(*cons))
114
+ enc = EncodedCNF()
115
+ enc.from_cnf(cnf)
116
+ lra, _ = LRASolver.from_encoded_cnf(enc)
117
+ lra.assert_lit(1)
118
+ lra.assert_lit(2)
119
+ lra.assert_lit(3)
120
+ is_sat, assignment = lra.check()
121
+ assert is_sat is True
122
+
123
+
124
+ def test_random_problems():
125
+ z3 = import_module("z3")
126
+ if z3 is None:
127
+ skip("z3 is not installed")
128
+
129
+ special_cases = []; x1, x2, x3 = symbols("x1 x2 x3")
130
+ special_cases.append([x1 - 3 * x2 <= -5, 6 * x1 + 4 * x2 <= 0, -7 * x1 + 3 * x2 <= 3])
131
+ special_cases.append([-3 * x1 >= 3, Eq(4 * x1, -1)])
132
+ special_cases.append([-4 * x1 < 4, 6 * x1 <= -6])
133
+ special_cases.append([-3 * x2 >= 7, 6 * x1 <= -5, -3 * x2 <= -4])
134
+ special_cases.append([x + y >= 2, x + y <= 1])
135
+ special_cases.append([x >= 0, x + y <= 2, x + 2 * y - z >= 6]) # from paper example
136
+ special_cases.append([-2 * x1 - 2 * x2 >= 7, -9 * x1 >= 7, -6 * x1 >= 5])
137
+ special_cases.append([2 * x1 > -3, -9 * x1 < -6, 9 * x1 <= 6])
138
+ special_cases.append([-2*x1 < -4, 9*x1 > -9])
139
+ special_cases.append([-6*x1 >= -1, -8*x1 + x2 >= 5, -8*x1 + 7*x2 < 4, x1 > 7])
140
+ special_cases.append([Eq(x1, 2), Eq(5*x1, -2), Eq(-7*x2, -6), Eq(9*x1 + 10*x2, 9)])
141
+ special_cases.append([Eq(3*x1, 6), Eq(x1 - 8*x2, -9), Eq(-7*x1 + 5*x2, 3), Eq(3*x2, 7)])
142
+ special_cases.append([-4*x1 < 4, 6*x1 <= -6])
143
+ special_cases.append([-3*x1 + 8*x2 >= -8, -10*x2 > 9, 8*x1 - 4*x2 < 8, 10*x1 - 9*x2 >= -9])
144
+ special_cases.append([x1 + 5*x2 >= -6, 9*x1 - 3*x2 >= -9, 6*x1 + 6*x2 < -10, -3*x1 + 3*x2 < -7])
145
+ special_cases.append([-9*x1 < 7, -5*x1 - 7*x2 < -1, 3*x1 + 7*x2 > 1, -6*x1 - 6*x2 > 9])
146
+ special_cases.append([9*x1 - 6*x2 >= -7, 9*x1 + 4*x2 < -8, -7*x2 <= 1, 10*x2 <= -7])
147
+
148
+ feasible_count = 0
149
+ for i in range(50):
150
+ if i % 8 == 0:
151
+ constraints = make_random_problem(num_variables=1, num_constraints=2, rational=False)
152
+ elif i % 8 == 1:
153
+ constraints = make_random_problem(num_variables=2, num_constraints=4, rational=False, disable_equality=True,
154
+ disable_nonstrict=True)
155
+ elif i % 8 == 2:
156
+ constraints = make_random_problem(num_variables=2, num_constraints=4, rational=False, disable_strict=True)
157
+ elif i % 8 == 3:
158
+ constraints = make_random_problem(num_variables=3, num_constraints=12, rational=False)
159
+ else:
160
+ constraints = make_random_problem(num_variables=3, num_constraints=6, rational=False)
161
+
162
+ if i < len(special_cases):
163
+ constraints = special_cases[i]
164
+
165
+ if False in constraints or True in constraints:
166
+ continue
167
+
168
+ phi = And(*constraints)
169
+ if phi == False:
170
+ continue
171
+ cnf = CNF.from_prop(phi); enc = EncodedCNF()
172
+ enc.from_cnf(cnf)
173
+ assert all(0 not in clause for clause in enc.data)
174
+
175
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
176
+ s_subs = lra.s_subs
177
+
178
+ lra.run_checks = True
179
+ s_subs_rev = {value: key for key, value in s_subs.items()}
180
+ lits = {lit for clause in enc.data for lit in clause}
181
+
182
+ bounds = [(lra.enc_to_boundary[l], l) for l in lits if l in lra.enc_to_boundary]
183
+ bounds = sorted(bounds, key=lambda x: (str(x[0].var), x[0].bound, str(x[0].upper))) # to remove nondeterminism
184
+
185
+ for b, l in bounds:
186
+ if lra.result and lra.result[0] == False:
187
+ break
188
+ lra.assert_lit(l)
189
+
190
+ feasible = lra.check()
191
+
192
+ if feasible[0] == True:
193
+ feasible_count += 1
194
+ assert check_if_satisfiable_with_z3(constraints) is True
195
+ cons_funcs = [cons.func for cons in constraints]
196
+ assignment = feasible[1]
197
+ assignment = {key.var : value for key, value in assignment.items()}
198
+ if not (StrictLessThan in cons_funcs or StrictGreaterThan in cons_funcs):
199
+ assignment = {key: value[0] for key, value in assignment.items()}
200
+ for cons in constraints:
201
+ assert cons.subs(assignment) == True
202
+
203
+ else:
204
+ rat_assignment = find_rational_assignment(constraints, assignment)
205
+ assert rat_assignment is not None
206
+ else:
207
+ assert check_if_satisfiable_with_z3(constraints) is False
208
+
209
+ conflict = feasible[1]
210
+ assert len(conflict) >= 2
211
+ conflict = {lra.enc_to_boundary[-l].get_inequality() for l in conflict}
212
+ conflict = {clause.subs(s_subs_rev) for clause in conflict}
213
+ assert check_if_satisfiable_with_z3(conflict) is False
214
+
215
+ # check that conflict clause is probably minimal
216
+ for subset in itertools.combinations(conflict, len(conflict)-1):
217
+ assert check_if_satisfiable_with_z3(subset) is True
218
+
219
+
220
+ @XFAIL
221
+ def test_pos_neg_zero():
222
+ bf = Q.positive(x) & Q.negative(x) & Q.zero(y)
223
+ enc = boolean_formula_to_encoded_cnf(bf)
224
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
225
+ for lit in enc.encoding.values():
226
+ if lra.assert_lit(lit) is not None:
227
+ break
228
+ assert len(lra.enc_to_boundary) == 3
229
+ assert lra.check()[0] == False
230
+
231
+ bf = Q.positive(x) & Q.lt(x, -1)
232
+ enc = boolean_formula_to_encoded_cnf(bf)
233
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
234
+ for lit in enc.encoding.values():
235
+ if lra.assert_lit(lit) is not None:
236
+ break
237
+ assert len(lra.enc_to_boundary) == 2
238
+ assert lra.check()[0] == False
239
+
240
+ bf = Q.positive(x) & Q.zero(x)
241
+ enc = boolean_formula_to_encoded_cnf(bf)
242
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
243
+ for lit in enc.encoding.values():
244
+ if lra.assert_lit(lit) is not None:
245
+ break
246
+ assert len(lra.enc_to_boundary) == 2
247
+ assert lra.check()[0] == False
248
+
249
+ bf = Q.positive(x) & Q.zero(y)
250
+ enc = boolean_formula_to_encoded_cnf(bf)
251
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
252
+ for lit in enc.encoding.values():
253
+ if lra.assert_lit(lit) is not None:
254
+ break
255
+ assert len(lra.enc_to_boundary) == 2
256
+ assert lra.check()[0] == True
257
+
258
+
259
+ @XFAIL
260
+ def test_pos_neg_infinite():
261
+ bf = Q.positive_infinite(x) & Q.lt(x, 10000000) & Q.positive_infinite(y)
262
+ enc = boolean_formula_to_encoded_cnf(bf)
263
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
264
+ for lit in enc.encoding.values():
265
+ if lra.assert_lit(lit) is not None:
266
+ break
267
+ assert len(lra.enc_to_boundary) == 3
268
+ assert lra.check()[0] == False
269
+
270
+ bf = Q.positive_infinite(x) & Q.gt(x, 10000000) & Q.positive_infinite(y)
271
+ enc = boolean_formula_to_encoded_cnf(bf)
272
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
273
+ for lit in enc.encoding.values():
274
+ if lra.assert_lit(lit) is not None:
275
+ break
276
+ assert len(lra.enc_to_boundary) == 3
277
+ assert lra.check()[0] == True
278
+
279
+ bf = Q.positive_infinite(x) & Q.negative_infinite(x)
280
+ enc = boolean_formula_to_encoded_cnf(bf)
281
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
282
+ for lit in enc.encoding.values():
283
+ if lra.assert_lit(lit) is not None:
284
+ break
285
+ assert len(lra.enc_to_boundary) == 2
286
+ assert lra.check()[0] == False
287
+
288
+
289
+ def test_binrel_evaluation():
290
+ bf = Q.gt(3, 2)
291
+ enc = boolean_formula_to_encoded_cnf(bf)
292
+ lra, conflicts = LRASolver.from_encoded_cnf(enc, testing_mode=True)
293
+ assert len(lra.enc_to_boundary) == 0
294
+ assert conflicts == [[1]]
295
+
296
+ bf = Q.lt(3, 2)
297
+ enc = boolean_formula_to_encoded_cnf(bf)
298
+ lra, conflicts = LRASolver.from_encoded_cnf(enc, testing_mode=True)
299
+ assert len(lra.enc_to_boundary) == 0
300
+ assert conflicts == [[-1]]
301
+
302
+
303
+ def test_negation():
304
+ assert HANDLE_NEGATION is True
305
+ bf = Q.gt(x, 1) & ~Q.gt(x, 0)
306
+ enc = boolean_formula_to_encoded_cnf(bf)
307
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
308
+ for clause in enc.data:
309
+ for lit in clause:
310
+ lra.assert_lit(lit)
311
+ assert len(lra.enc_to_boundary) == 2
312
+ assert lra.check()[0] == False
313
+ assert sorted(lra.check()[1]) in [[-1, 2], [-2, 1]]
314
+
315
+ bf = ~Q.gt(x, 1) & ~Q.lt(x, 0)
316
+ enc = boolean_formula_to_encoded_cnf(bf)
317
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
318
+ for clause in enc.data:
319
+ for lit in clause:
320
+ lra.assert_lit(lit)
321
+ assert len(lra.enc_to_boundary) == 2
322
+ assert lra.check()[0] == True
323
+
324
+ bf = ~Q.gt(x, 0) & ~Q.lt(x, 1)
325
+ enc = boolean_formula_to_encoded_cnf(bf)
326
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
327
+ for clause in enc.data:
328
+ for lit in clause:
329
+ lra.assert_lit(lit)
330
+ assert len(lra.enc_to_boundary) == 2
331
+ assert lra.check()[0] == False
332
+
333
+ bf = ~Q.gt(x, 0) & ~Q.le(x, 0)
334
+ enc = boolean_formula_to_encoded_cnf(bf)
335
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
336
+ for clause in enc.data:
337
+ for lit in clause:
338
+ lra.assert_lit(lit)
339
+ assert len(lra.enc_to_boundary) == 2
340
+ assert lra.check()[0] == False
341
+
342
+ bf = ~Q.le(x+y, 2) & ~Q.ge(x-y, 2) & ~Q.ge(y, 0)
343
+ enc = boolean_formula_to_encoded_cnf(bf)
344
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
345
+ for clause in enc.data:
346
+ for lit in clause:
347
+ lra.assert_lit(lit)
348
+ assert len(lra.enc_to_boundary) == 3
349
+ assert lra.check()[0] == False
350
+ assert len(lra.check()[1]) == 3
351
+ assert all(i > 0 for i in lra.check()[1])
352
+
353
+
354
+ def test_unhandled_input():
355
+ nan = S.NaN
356
+ bf = Q.gt(3, nan) & Q.gt(x, nan)
357
+ enc = boolean_formula_to_encoded_cnf(bf)
358
+ raises(ValueError, lambda: LRASolver.from_encoded_cnf(enc, testing_mode=True))
359
+
360
+ bf = Q.gt(3, I) & Q.gt(x, I)
361
+ enc = boolean_formula_to_encoded_cnf(bf)
362
+ raises(UnhandledInput, lambda: LRASolver.from_encoded_cnf(enc, testing_mode=True))
363
+
364
+ bf = Q.gt(3, float("inf")) & Q.gt(x, float("inf"))
365
+ enc = boolean_formula_to_encoded_cnf(bf)
366
+ raises(UnhandledInput, lambda: LRASolver.from_encoded_cnf(enc, testing_mode=True))
367
+
368
+ bf = Q.gt(3, oo) & Q.gt(x, oo)
369
+ enc = boolean_formula_to_encoded_cnf(bf)
370
+ raises(UnhandledInput, lambda: LRASolver.from_encoded_cnf(enc, testing_mode=True))
371
+
372
+ # test non-linearity
373
+ bf = Q.gt(x**2 + x, 2)
374
+ enc = boolean_formula_to_encoded_cnf(bf)
375
+ raises(UnhandledInput, lambda: LRASolver.from_encoded_cnf(enc, testing_mode=True))
376
+
377
+ bf = Q.gt(cos(x) + x, 2)
378
+ enc = boolean_formula_to_encoded_cnf(bf)
379
+ raises(UnhandledInput, lambda: LRASolver.from_encoded_cnf(enc, testing_mode=True))
380
+
381
+ @XFAIL
382
+ def test_infinite_strict_inequalities():
383
+ # Extensive testing of the interaction between strict inequalities
384
+ # and constraints containing infinity is needed because
385
+ # the paper's rule for strict inequalities don't work when
386
+ # infinite numbers are allowed. Using the paper's rules you
387
+ # can end up with situations where oo + delta > oo is considered
388
+ # True when oo + delta should be equal to oo.
389
+ # See https://math.stackexchange.com/questions/4757069/can-this-method-of-converting-strict-inequalities-to-equisatisfiable-nonstrict-i
390
+ bf = (-x - y >= -float("inf")) & (x > 0) & (y >= float("inf"))
391
+ enc = boolean_formula_to_encoded_cnf(bf)
392
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
393
+ for lit in sorted(enc.encoding.values()):
394
+ if lra.assert_lit(lit) is not None:
395
+ break
396
+ assert len(lra.enc_to_boundary) == 3
397
+ assert lra.check()[0] == True
398
+
399
+
400
+ def test_pivot():
401
+ for _ in range(10):
402
+ m = randMatrix(5)
403
+ rref = m.rref()
404
+ for _ in range(5):
405
+ i, j = randint(0, 4), randint(0, 4)
406
+ if m[i, j] != 0:
407
+ assert LRASolver._pivot(m, i, j).rref() == rref
408
+
409
+
410
+ def test_reset_bounds():
411
+ bf = Q.ge(x, 1) & Q.lt(x, 1)
412
+ enc = boolean_formula_to_encoded_cnf(bf)
413
+ lra, _ = LRASolver.from_encoded_cnf(enc, testing_mode=True)
414
+ for clause in enc.data:
415
+ for lit in clause:
416
+ lra.assert_lit(lit)
417
+ assert len(lra.enc_to_boundary) == 2
418
+ assert lra.check()[0] == False
419
+
420
+ lra.reset_bounds()
421
+ assert lra.check()[0] == True
422
+ for var in lra.all_var:
423
+ assert var.upper == LRARational(float("inf"), 0)
424
+ assert var.upper_from_eq == False
425
+ assert var.upper_from_neg == False
426
+ assert var.lower == LRARational(-float("inf"), 0)
427
+ assert var.lower_from_eq == False
428
+ assert var.lower_from_neg == False
429
+ assert var.assign == LRARational(0, 0)
430
+ assert var.var is not None
431
+ assert var.col_idx is not None
432
+
433
+
434
+ def test_empty_cnf():
435
+ cnf = CNF()
436
+ enc = EncodedCNF()
437
+ enc.from_cnf(cnf)
438
+ lra, conflict = LRASolver.from_encoded_cnf(enc)
439
+ assert len(conflict) == 0
440
+ assert lra.check() == (True, {})
phivenv/Lib/site-packages/sympy/logic/utilities/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .dimacs import load_file
2
+
3
+ __all__ = ['load_file']
phivenv/Lib/site-packages/sympy/logic/utilities/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (227 Bytes). View file
 
phivenv/Lib/site-packages/sympy/logic/utilities/__pycache__/dimacs.cpython-39.pyc ADDED
Binary file (1.49 kB). View file
 
phivenv/Lib/site-packages/sympy/logic/utilities/dimacs.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """For reading in DIMACS file format
2
+
3
+ www.cs.ubc.ca/~hoos/SATLIB/Benchmarks/SAT/satformat.ps
4
+
5
+ """
6
+
7
+ from sympy.core import Symbol
8
+ from sympy.logic.boolalg import And, Or
9
+ import re
10
+ from pathlib import Path
11
+
12
+
13
+ def load(s):
14
+ """Loads a boolean expression from a string.
15
+
16
+ Examples
17
+ ========
18
+
19
+ >>> from sympy.logic.utilities.dimacs import load
20
+ >>> load('1')
21
+ cnf_1
22
+ >>> load('1 2')
23
+ cnf_1 | cnf_2
24
+ >>> load('1 \\n 2')
25
+ cnf_1 & cnf_2
26
+ >>> load('1 2 \\n 3')
27
+ cnf_3 & (cnf_1 | cnf_2)
28
+ """
29
+ clauses = []
30
+
31
+ lines = s.split('\n')
32
+
33
+ pComment = re.compile(r'c.*')
34
+ pStats = re.compile(r'p\s*cnf\s*(\d*)\s*(\d*)')
35
+
36
+ while len(lines) > 0:
37
+ line = lines.pop(0)
38
+
39
+ # Only deal with lines that aren't comments
40
+ if not pComment.match(line):
41
+ m = pStats.match(line)
42
+
43
+ if not m:
44
+ nums = line.rstrip('\n').split(' ')
45
+ list = []
46
+ for lit in nums:
47
+ if lit != '':
48
+ if int(lit) == 0:
49
+ continue
50
+ num = abs(int(lit))
51
+ sign = True
52
+ if int(lit) < 0:
53
+ sign = False
54
+
55
+ if sign:
56
+ list.append(Symbol("cnf_%s" % num))
57
+ else:
58
+ list.append(~Symbol("cnf_%s" % num))
59
+
60
+ if len(list) > 0:
61
+ clauses.append(Or(*list))
62
+
63
+ return And(*clauses)
64
+
65
+
66
+ def load_file(location):
67
+ """Loads a boolean expression from a file."""
68
+ s = Path(location).read_text()
69
+ return load(s)
phivenv/Lib/site-packages/sympy/matrices/__init__.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """A module that handles matrices.
2
+
3
+ Includes functions for fast creating matrices like zero, one/eye, random
4
+ matrix, etc.
5
+ """
6
+ from .exceptions import ShapeError, NonSquareMatrixError
7
+ from .kind import MatrixKind
8
+ from .dense import (
9
+ GramSchmidt, casoratian, diag, eye, hessian, jordan_cell,
10
+ list2numpy, matrix2numpy, matrix_multiply_elementwise, ones,
11
+ randMatrix, rot_axis1, rot_axis2, rot_axis3, rot_ccw_axis1,
12
+ rot_ccw_axis2, rot_ccw_axis3, rot_givens,
13
+ symarray, wronskian, zeros)
14
+ from .dense import MutableDenseMatrix
15
+ from .matrixbase import DeferredVector, MatrixBase
16
+
17
+ MutableMatrix = MutableDenseMatrix
18
+ Matrix = MutableMatrix
19
+
20
+ from .sparse import MutableSparseMatrix
21
+ from .sparsetools import banded
22
+ from .immutable import ImmutableDenseMatrix, ImmutableSparseMatrix
23
+
24
+ ImmutableMatrix = ImmutableDenseMatrix
25
+ SparseMatrix = MutableSparseMatrix
26
+
27
+ from .expressions import (
28
+ MatrixSlice, BlockDiagMatrix, BlockMatrix, FunctionMatrix, Identity,
29
+ Inverse, MatAdd, MatMul, MatPow, MatrixExpr, MatrixSymbol, Trace,
30
+ Transpose, ZeroMatrix, OneMatrix, blockcut, block_collapse, matrix_symbols, Adjoint,
31
+ hadamard_product, HadamardProduct, HadamardPower, Determinant, det,
32
+ diagonalize_vector, DiagMatrix, DiagonalMatrix, DiagonalOf, trace,
33
+ DotProduct, kronecker_product, KroneckerProduct,
34
+ PermutationMatrix, MatrixPermute, MatrixSet, Permanent, per)
35
+
36
+ from .utilities import dotprodsimp
37
+
38
+ __all__ = [
39
+ 'ShapeError', 'NonSquareMatrixError', 'MatrixKind',
40
+
41
+ 'GramSchmidt', 'casoratian', 'diag', 'eye', 'hessian', 'jordan_cell',
42
+ 'list2numpy', 'matrix2numpy', 'matrix_multiply_elementwise', 'ones',
43
+ 'randMatrix', 'rot_axis1', 'rot_axis2', 'rot_axis3', 'symarray',
44
+ 'wronskian', 'zeros', 'rot_ccw_axis1', 'rot_ccw_axis2', 'rot_ccw_axis3',
45
+ 'rot_givens',
46
+
47
+ 'MutableDenseMatrix',
48
+
49
+ 'DeferredVector', 'MatrixBase',
50
+
51
+ 'Matrix', 'MutableMatrix',
52
+
53
+ 'MutableSparseMatrix',
54
+
55
+ 'banded',
56
+
57
+ 'ImmutableDenseMatrix', 'ImmutableSparseMatrix',
58
+
59
+ 'ImmutableMatrix', 'SparseMatrix',
60
+
61
+ 'MatrixSlice', 'BlockDiagMatrix', 'BlockMatrix', 'FunctionMatrix',
62
+ 'Identity', 'Inverse', 'MatAdd', 'MatMul', 'MatPow', 'MatrixExpr',
63
+ 'MatrixSymbol', 'Trace', 'Transpose', 'ZeroMatrix', 'OneMatrix',
64
+ 'blockcut', 'block_collapse', 'matrix_symbols', 'Adjoint',
65
+ 'hadamard_product', 'HadamardProduct', 'HadamardPower', 'Determinant',
66
+ 'det', 'diagonalize_vector', 'DiagMatrix', 'DiagonalMatrix',
67
+ 'DiagonalOf', 'trace', 'DotProduct', 'kronecker_product',
68
+ 'KroneckerProduct', 'PermutationMatrix', 'MatrixPermute', 'MatrixSet',
69
+ 'Permanent', 'per',
70
+
71
+ 'dotprodsimp',
72
+ ]
phivenv/Lib/site-packages/sympy/matrices/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (2.49 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/decompositions.cpython-39.pyc ADDED
Binary file (41.3 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/dense.cpython-39.pyc ADDED
Binary file (31.4 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/determinant.cpython-39.pyc ADDED
Binary file (27.5 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/eigen.cpython-39.pyc ADDED
Binary file (36.9 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/exceptions.cpython-39.pyc ADDED
Binary file (1.13 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/graph.cpython-39.pyc ADDED
Binary file (9.09 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/immutable.cpython-39.pyc ADDED
Binary file (6.41 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/inverse.cpython-39.pyc ADDED
Binary file (12 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/kind.cpython-39.pyc ADDED
Binary file (2.95 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/matrices.cpython-39.pyc ADDED
Binary file (24.4 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/normalforms.cpython-39.pyc ADDED
Binary file (5.21 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/reductions.cpython-39.pyc ADDED
Binary file (10.9 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/repmatrix.cpython-39.pyc ADDED
Binary file (29.1 kB). View file
 
phivenv/Lib/site-packages/sympy/matrices/__pycache__/solvers.cpython-39.pyc ADDED
Binary file (24 kB). View file