passagemath-standard-no-symbolics 10.6.31rc3__cp314-cp314-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-standard-no-symbolics might be problematic. Click here for more details.
- passagemath_standard_no_symbolics-10.6.31rc3.data/scripts/sage-grep +5 -0
- passagemath_standard_no_symbolics-10.6.31rc3.data/scripts/sage-grepdoc +5 -0
- passagemath_standard_no_symbolics-10.6.31rc3.data/scripts/sage-list-packages +103 -0
- passagemath_standard_no_symbolics-10.6.31rc3.dist-info/METADATA +151 -0
- passagemath_standard_no_symbolics-10.6.31rc3.dist-info/RECORD +82 -0
- passagemath_standard_no_symbolics-10.6.31rc3.dist-info/WHEEL +6 -0
- passagemath_standard_no_symbolics-10.6.31rc3.dist-info/top_level.txt +1 -0
- sage/all.py +207 -0
- sage/all_cmdline.py +36 -0
- sage/cli/__init__.py +61 -0
- sage/cli/__main__.py +5 -0
- sage/cli/eval_cmd.py +45 -0
- sage/cli/eval_cmd_test.py +25 -0
- sage/cli/interactive_shell_cmd.py +28 -0
- sage/cli/notebook_cmd.py +51 -0
- sage/cli/notebook_cmd_test.py +39 -0
- sage/cli/options.py +26 -0
- sage/cli/run_file_cmd.py +50 -0
- sage/cli/version_cmd.py +26 -0
- sage/databases/all.py +83 -0
- sage/databases/cubic_hecke_db.py +1527 -0
- sage/dynamics/all.py +31 -0
- sage/dynamics/surface_dynamics_deprecation.py +32 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/ext_data/mwrank/PRIMES +1 -0
- sage/ext_data/nbconvert/postprocess.py +48 -0
- sage/ext_data/nbconvert/rst_sage.tpl +99 -0
- sage/ext_data/nodoctest +0 -0
- sage/ext_data/notebook-ipython/kernel.json.in +11 -0
- sage/ext_data/notebook-ipython/logo-64x64.png +0 -0
- sage/ext_data/notebook-ipython/logo.svg +352 -0
- sage/ext_data/valgrind/pyalloc.supp +58 -0
- sage/ext_data/valgrind/sage-additional.supp +417 -0
- sage/ext_data/valgrind/sage.supp +43 -0
- sage/ext_data/valgrind/valgrind-python.supp +480 -0
- sage/geometry/all.py +12 -0
- sage/groups/matrix_gps/pickling_overrides.py +110 -0
- sage/homology/tests.py +66 -0
- sage/interacts/algebra.py +20 -0
- sage/interacts/all.py +25 -0
- sage/interacts/calculus.py +24 -0
- sage/interacts/fractals.py +18 -0
- sage/interacts/geometry.py +19 -0
- sage/interacts/library.py +1950 -0
- sage/interacts/library_cython.cpython-314-darwin.so +0 -0
- sage/interacts/statistics.py +19 -0
- sage/interfaces/axiom.py +1002 -0
- sage/interfaces/kash.py +834 -0
- sage/interfaces/lie.py +950 -0
- sage/interfaces/matlab.py +413 -0
- sage/interfaces/mupad.py +686 -0
- sage/interfaces/octave.py +858 -0
- sage/interfaces/phc.py +943 -0
- sage/interfaces/psage.py +189 -0
- sage/interfaces/qsieve.py +4 -0
- sage/interfaces/r.py +2096 -0
- sage/interfaces/read_data.py +46 -0
- sage/interfaces/scilab.py +576 -0
- sage/interfaces/tests.py +81 -0
- sage/libs/all.py +11 -0
- sage/libs/cremona/__init__.py +0 -0
- sage/libs/mwrank/__init__.py +0 -0
- sage/logic/all.py +3 -0
- sage/logic/booleval.py +160 -0
- sage/logic/boolformula.py +1490 -0
- sage/logic/logic.py +856 -0
- sage/logic/logicparser.py +696 -0
- sage/logic/logictable.py +272 -0
- sage/logic/propcalc.py +311 -0
- sage/misc/all.py +28 -0
- sage/misc/lazy_attribute.pyi +11 -0
- sage/rings/all.py +48 -0
- sage/rings/commutative_algebra.py +38 -0
- sage/rings/finite_rings/all.py +21 -0
- sage/rings/numbers_abc.py +58 -0
- sage/rings/polynomial/all.py +22 -0
- sage/rings/polynomial/convolution.py +421 -0
- sage/symbolic/all__sagemath_standard_no_symbolics.py +0 -0
sage/logic/logic.py
ADDED
|
@@ -0,0 +1,856 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
Symbolic Logic Expressions
|
|
3
|
+
|
|
4
|
+
An expression is created from a string that consists of the
|
|
5
|
+
operators ``!``, ``&``, ``|``, ``->``, ``<->``, which correspond to the
|
|
6
|
+
logical functions not, and, or, if then, if and only if, respectively.
|
|
7
|
+
Variable names must start with a letter and contain only
|
|
8
|
+
alpha-numerics and the underscore character.
|
|
9
|
+
|
|
10
|
+
AUTHORS:
|
|
11
|
+
|
|
12
|
+
- Chris Gorecki (2007): initial version
|
|
13
|
+
|
|
14
|
+
- William Stein (2007-08-31): integration into Sage 2.8.4
|
|
15
|
+
|
|
16
|
+
- Paul Scurek (2013-08-03): updated docstring formatting
|
|
17
|
+
"""
|
|
18
|
+
# ****************************************************************************
|
|
19
|
+
# Copyright (C) 2007 Chris Gorecki <chris.k.gorecki@gmail.com>
|
|
20
|
+
# Copyright (C) 2007 William Stein <wstein@gmail.com>
|
|
21
|
+
# Copyright (C) 2013 Paul Scurek <scurek86@gmail.com>
|
|
22
|
+
#
|
|
23
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
24
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
25
|
+
# the License, or (at your option) any later version.
|
|
26
|
+
# https://www.gnu.org/licenses/
|
|
27
|
+
# ****************************************************************************
|
|
28
|
+
|
|
29
|
+
import string
|
|
30
|
+
|
|
31
|
+
# constants
|
|
32
|
+
tok_list = ['OPAREN', 'CPAREN', 'AND', 'OR', 'NOT', 'IFTHEN', 'IFF']
|
|
33
|
+
bin_list = ['AND', 'OR', 'IFTHEN', 'IFF']
|
|
34
|
+
operators = '()&|!<->'
|
|
35
|
+
# variables
|
|
36
|
+
vars = {}
|
|
37
|
+
vars_order = []
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class SymbolicLogic:
|
|
41
|
+
"""
|
|
42
|
+
EXAMPLES:
|
|
43
|
+
|
|
44
|
+
This example illustrates how to create a boolean formula and print
|
|
45
|
+
its table::
|
|
46
|
+
|
|
47
|
+
sage: log = SymbolicLogic()
|
|
48
|
+
sage: s = log.statement("a&b|!(c|a)")
|
|
49
|
+
sage: t = log.truthtable(s)
|
|
50
|
+
sage: log.print_table(t)
|
|
51
|
+
a | b | c | value |
|
|
52
|
+
--------------------------------
|
|
53
|
+
False | False | False | True |
|
|
54
|
+
False | False | True | False |
|
|
55
|
+
False | True | False | True |
|
|
56
|
+
False | True | True | False |
|
|
57
|
+
True | False | False | False |
|
|
58
|
+
True | False | True | False |
|
|
59
|
+
True | True | False | True |
|
|
60
|
+
True | True | True | True |
|
|
61
|
+
"""
|
|
62
|
+
def statement(self, s):
|
|
63
|
+
r"""
|
|
64
|
+
Return a token list to be used by other functions in the class.
|
|
65
|
+
|
|
66
|
+
INPUT:
|
|
67
|
+
|
|
68
|
+
- ``s`` -- string containing the logic expression to be manipulated
|
|
69
|
+
|
|
70
|
+
- ``global vars`` -- dictionary with variable names as keys and the
|
|
71
|
+
variables' current boolean values as dictionary values
|
|
72
|
+
|
|
73
|
+
- ``global vars_order`` -- list of the variables in the order
|
|
74
|
+
that they are found
|
|
75
|
+
|
|
76
|
+
OUTPUT: list of length three containing the following in this order:
|
|
77
|
+
|
|
78
|
+
1. a list of tokens
|
|
79
|
+
2. a dictionary of variable/value pairs
|
|
80
|
+
3. a list of the variables in the order they were found
|
|
81
|
+
|
|
82
|
+
EXAMPLES:
|
|
83
|
+
|
|
84
|
+
This example illustrates the creation of a statement::
|
|
85
|
+
|
|
86
|
+
sage: log = SymbolicLogic()
|
|
87
|
+
sage: s = log.statement("a&b|!(c|a)")
|
|
88
|
+
sage: s2 = log.statement("!((!(a&b)))")
|
|
89
|
+
|
|
90
|
+
It is an error to use invalid variable names::
|
|
91
|
+
|
|
92
|
+
sage: s = log.statement("3fe & @q")
|
|
93
|
+
Invalid variable name: 3fe
|
|
94
|
+
Invalid variable name: @q
|
|
95
|
+
|
|
96
|
+
It is also an error to use invalid syntax::
|
|
97
|
+
|
|
98
|
+
sage: s = log.statement("a&&b")
|
|
99
|
+
Malformed Statement
|
|
100
|
+
sage: s = log.statement("a&((b)")
|
|
101
|
+
Malformed Statement
|
|
102
|
+
"""
|
|
103
|
+
global vars, vars_order
|
|
104
|
+
toks, vars, vars_order = ['OPAREN'], {}, []
|
|
105
|
+
tokenize(s, toks)
|
|
106
|
+
statement = [toks, vars, vars_order]
|
|
107
|
+
try: # verify the syntax
|
|
108
|
+
eval(toks)
|
|
109
|
+
except (KeyError, RuntimeError):
|
|
110
|
+
print('Malformed Statement')
|
|
111
|
+
return []
|
|
112
|
+
return statement
|
|
113
|
+
|
|
114
|
+
def truthtable(self, statement, start=0, end=-1):
|
|
115
|
+
r"""
|
|
116
|
+
Return a truth table.
|
|
117
|
+
|
|
118
|
+
INPUT:
|
|
119
|
+
|
|
120
|
+
- ``statement`` -- list; it contains the tokens and the two global
|
|
121
|
+
variables vars and vars_order
|
|
122
|
+
|
|
123
|
+
- ``start`` -- integer (default: 0); this represents the row of
|
|
124
|
+
the truth table from which to start
|
|
125
|
+
|
|
126
|
+
- ``end`` -- integer (default: -1); this represents the last row
|
|
127
|
+
of the truth table to be created
|
|
128
|
+
|
|
129
|
+
OUTPUT:
|
|
130
|
+
|
|
131
|
+
The truth table as a 2d array with the creating formula tacked
|
|
132
|
+
to the front.
|
|
133
|
+
|
|
134
|
+
EXAMPLES:
|
|
135
|
+
|
|
136
|
+
This example illustrates the creation of a statement::
|
|
137
|
+
|
|
138
|
+
sage: log = SymbolicLogic()
|
|
139
|
+
sage: s = log.statement("a&b|!(c|a)")
|
|
140
|
+
sage: t = log.truthtable(s) #creates the whole truth table
|
|
141
|
+
|
|
142
|
+
We can now create truthtable of rows 1 to 5::
|
|
143
|
+
|
|
144
|
+
sage: s2 = log.truthtable(s, 1, 5); s2
|
|
145
|
+
[[['OPAREN',
|
|
146
|
+
'a',
|
|
147
|
+
'AND',
|
|
148
|
+
'b',
|
|
149
|
+
'OR',
|
|
150
|
+
'NOT',
|
|
151
|
+
'OPAREN',
|
|
152
|
+
'c',
|
|
153
|
+
'OR',
|
|
154
|
+
'a',
|
|
155
|
+
'CPAREN',
|
|
156
|
+
'CPAREN'],
|
|
157
|
+
{'a': 'True', 'b': 'False', 'c': 'False'},
|
|
158
|
+
['a', 'b', 'c']],
|
|
159
|
+
['False', 'False', 'True', 'False'],
|
|
160
|
+
['False', 'True', 'False', 'True'],
|
|
161
|
+
['False', 'True', 'True', 'False'],
|
|
162
|
+
['True', 'False', 'False', 'False']]
|
|
163
|
+
|
|
164
|
+
.. NOTE::
|
|
165
|
+
|
|
166
|
+
When sent with no start or end parameters this is an
|
|
167
|
+
exponential time function requiring `O(2^n)` time, where
|
|
168
|
+
`n` is the number of variables in the logic expression
|
|
169
|
+
|
|
170
|
+
TESTS:
|
|
171
|
+
|
|
172
|
+
Verify that :issue:`32676` is fixed::
|
|
173
|
+
|
|
174
|
+
sage: s = log.statement("a&b|!(c|a)")
|
|
175
|
+
sage: copy_s2 = copy(s[2])
|
|
176
|
+
sage: t = log.truthtable(s)
|
|
177
|
+
sage: s[2] == copy_s2
|
|
178
|
+
True
|
|
179
|
+
"""
|
|
180
|
+
global vars, vars_order
|
|
181
|
+
toks, vars, vars_order = statement
|
|
182
|
+
if end == -1:
|
|
183
|
+
end = 2 ** len(vars)
|
|
184
|
+
table = [statement]
|
|
185
|
+
keys = vars_order
|
|
186
|
+
for i in range(start, end):
|
|
187
|
+
j = 0
|
|
188
|
+
row = []
|
|
189
|
+
for key in reversed(keys):
|
|
190
|
+
bit = get_bit(i, j)
|
|
191
|
+
vars[key] = bit
|
|
192
|
+
j += 1
|
|
193
|
+
row.insert(0, bit)
|
|
194
|
+
row.append(eval(toks))
|
|
195
|
+
table.append(row)
|
|
196
|
+
return table
|
|
197
|
+
|
|
198
|
+
def print_table(self, table):
|
|
199
|
+
r"""
|
|
200
|
+
Return a truthtable corresponding to the given statement.
|
|
201
|
+
|
|
202
|
+
INPUT:
|
|
203
|
+
|
|
204
|
+
- ``table`` -- object created by :meth:`truthtable()` method; it
|
|
205
|
+
contains the variable values and the evaluation of the statement
|
|
206
|
+
|
|
207
|
+
OUTPUT: a formatted version of the truth table
|
|
208
|
+
|
|
209
|
+
EXAMPLES:
|
|
210
|
+
|
|
211
|
+
This example illustrates the creation of a statement and
|
|
212
|
+
its truth table::
|
|
213
|
+
|
|
214
|
+
sage: log = SymbolicLogic()
|
|
215
|
+
sage: s = log.statement("a&b|!(c|a)")
|
|
216
|
+
sage: t = log.truthtable(s) #creates the whole truth table
|
|
217
|
+
sage: log.print_table(t)
|
|
218
|
+
a | b | c | value |
|
|
219
|
+
--------------------------------
|
|
220
|
+
False | False | False | True |
|
|
221
|
+
False | False | True | False |
|
|
222
|
+
False | True | False | True |
|
|
223
|
+
False | True | True | False |
|
|
224
|
+
True | False | False | False |
|
|
225
|
+
True | False | True | False |
|
|
226
|
+
True | True | False | True |
|
|
227
|
+
True | True | True | True |
|
|
228
|
+
|
|
229
|
+
We can also print a shortened table::
|
|
230
|
+
|
|
231
|
+
sage: t = log.truthtable(s, 1, 5)
|
|
232
|
+
sage: log.print_table(t)
|
|
233
|
+
a | b | c | value |
|
|
234
|
+
--------------------------------
|
|
235
|
+
False | False | True | False |
|
|
236
|
+
False | True | False | True |
|
|
237
|
+
False | True | True | False |
|
|
238
|
+
True | False | False | False |
|
|
239
|
+
|
|
240
|
+
TESTS:
|
|
241
|
+
|
|
242
|
+
Verify that :issue:`32676` is fixed::
|
|
243
|
+
|
|
244
|
+
sage: table = log.truthtable(log.statement("A->B"))
|
|
245
|
+
sage: table_copy = table.copy()
|
|
246
|
+
sage: log.print_table(table)
|
|
247
|
+
...
|
|
248
|
+
sage: table_copy == table
|
|
249
|
+
True
|
|
250
|
+
"""
|
|
251
|
+
statement = table[0]
|
|
252
|
+
table = table[1:]
|
|
253
|
+
vars_order = statement[2].copy()
|
|
254
|
+
vars_len = []
|
|
255
|
+
line = s = ""
|
|
256
|
+
vars_order.append('value')
|
|
257
|
+
for var in vars_order:
|
|
258
|
+
vars_len.append(len(var))
|
|
259
|
+
s = var + ' '
|
|
260
|
+
while len(s) < len('False '):
|
|
261
|
+
s += ' '
|
|
262
|
+
s += '| '
|
|
263
|
+
line += s
|
|
264
|
+
print(line)
|
|
265
|
+
print(len(line) * '-')
|
|
266
|
+
for row in table:
|
|
267
|
+
line = s = ""
|
|
268
|
+
i = 0
|
|
269
|
+
for e in row:
|
|
270
|
+
j = 2 if e == 'True' else 1
|
|
271
|
+
s = e + ' ' * j
|
|
272
|
+
if i < len(vars_len):
|
|
273
|
+
while len(s) <= vars_len[i]:
|
|
274
|
+
s += ' '
|
|
275
|
+
s += '| '
|
|
276
|
+
line += s
|
|
277
|
+
i += 1
|
|
278
|
+
print(line)
|
|
279
|
+
print("")
|
|
280
|
+
|
|
281
|
+
def combine(self, statement1, statement2):
|
|
282
|
+
r"""
|
|
283
|
+
Return a new statement which contains the
|
|
284
|
+
two statements or'd together.
|
|
285
|
+
|
|
286
|
+
INPUT:
|
|
287
|
+
|
|
288
|
+
- ``statement1`` -- the first statement
|
|
289
|
+
- ``statement2`` -- the second statement
|
|
290
|
+
|
|
291
|
+
OUTPUT: a new statement which or'd the given statements together
|
|
292
|
+
|
|
293
|
+
EXAMPLES::
|
|
294
|
+
|
|
295
|
+
sage: log = SymbolicLogic()
|
|
296
|
+
sage: s1 = log.statement("(a&b)")
|
|
297
|
+
sage: s2 = log.statement("b")
|
|
298
|
+
sage: log.combine(s1,s2)
|
|
299
|
+
[['OPAREN',
|
|
300
|
+
'OPAREN',
|
|
301
|
+
'OPAREN',
|
|
302
|
+
'a',
|
|
303
|
+
'AND',
|
|
304
|
+
'b',
|
|
305
|
+
'CPAREN',
|
|
306
|
+
'CPAREN',
|
|
307
|
+
'OR',
|
|
308
|
+
'OPAREN',
|
|
309
|
+
'b',
|
|
310
|
+
'CPAREN',
|
|
311
|
+
'CPAREN'],
|
|
312
|
+
{'a': 'False', 'b': 'False'},
|
|
313
|
+
['a', 'b', 'b']]
|
|
314
|
+
"""
|
|
315
|
+
toks = ['OPAREN'] + statement1[0] + ['OR'] + statement2[0] + ['CPAREN']
|
|
316
|
+
variables = dict(statement1[1])
|
|
317
|
+
variables.update(statement2[1])
|
|
318
|
+
var_order = statement1[2] + statement2[2]
|
|
319
|
+
return [toks, variables, var_order]
|
|
320
|
+
|
|
321
|
+
# TODO: implement the simplify function which calls
|
|
322
|
+
# a c++ implementation of the ESPRESSO algorithm
|
|
323
|
+
# to simplify the truthtable: probably Minilog
|
|
324
|
+
def simplify(self, table):
|
|
325
|
+
"""
|
|
326
|
+
Call a C++ implementation of the ESPRESSO algorithm to simplify the
|
|
327
|
+
given truth table.
|
|
328
|
+
|
|
329
|
+
.. TODO::
|
|
330
|
+
|
|
331
|
+
Implement this method.
|
|
332
|
+
|
|
333
|
+
EXAMPLES::
|
|
334
|
+
|
|
335
|
+
sage: log = SymbolicLogic()
|
|
336
|
+
sage: s = log.statement("a&b|!(c|a)")
|
|
337
|
+
sage: t = log.truthtable(s)
|
|
338
|
+
sage: log.simplify(t)
|
|
339
|
+
Traceback (most recent call last):
|
|
340
|
+
...
|
|
341
|
+
NotImplementedError
|
|
342
|
+
"""
|
|
343
|
+
raise NotImplementedError
|
|
344
|
+
|
|
345
|
+
def prove(self, statement):
|
|
346
|
+
"""
|
|
347
|
+
A function to test to see if the statement is a tautology or
|
|
348
|
+
contradiction by calling a C++ library.
|
|
349
|
+
|
|
350
|
+
.. TODO::
|
|
351
|
+
|
|
352
|
+
Implement this method.
|
|
353
|
+
|
|
354
|
+
EXAMPLES::
|
|
355
|
+
|
|
356
|
+
sage: log = SymbolicLogic()
|
|
357
|
+
sage: s = log.statement("a&b|!(c|a)")
|
|
358
|
+
sage: log.prove(s)
|
|
359
|
+
Traceback (most recent call last):
|
|
360
|
+
...
|
|
361
|
+
NotImplementedError
|
|
362
|
+
"""
|
|
363
|
+
raise NotImplementedError
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def get_bit(x, c):
|
|
367
|
+
r"""
|
|
368
|
+
Determine if bit ``c`` of the number ``x`` is 1.
|
|
369
|
+
|
|
370
|
+
INPUT:
|
|
371
|
+
|
|
372
|
+
- ``x`` -- integer; this is the number from which to take the bit
|
|
373
|
+
|
|
374
|
+
- ``c`` -- integer; this is the bit number to be taken
|
|
375
|
+
|
|
376
|
+
OUTPUT: a boolean value to be determined as follows:
|
|
377
|
+
|
|
378
|
+
- ``True`` if bit ``c`` of ``x`` is 1.
|
|
379
|
+
|
|
380
|
+
- ``False`` if bit ``c`` of ``x`` is not 1.
|
|
381
|
+
|
|
382
|
+
.. NOTE::
|
|
383
|
+
|
|
384
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
385
|
+
|
|
386
|
+
EXAMPLES::
|
|
387
|
+
|
|
388
|
+
sage: from sage.logic.logic import get_bit
|
|
389
|
+
sage: get_bit(int(2), int(1))
|
|
390
|
+
'True'
|
|
391
|
+
sage: get_bit(int(8), int(0))
|
|
392
|
+
'False'
|
|
393
|
+
"""
|
|
394
|
+
bits = []
|
|
395
|
+
while x > 0:
|
|
396
|
+
b = 'False' if x % 2 == 0 else 'True'
|
|
397
|
+
x = x // 2
|
|
398
|
+
bits.append(b)
|
|
399
|
+
if c > len(bits) - 1:
|
|
400
|
+
return 'False'
|
|
401
|
+
else:
|
|
402
|
+
return bits[c]
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
def eval(toks):
|
|
406
|
+
r"""
|
|
407
|
+
Evaluate the expression contained in ``toks``.
|
|
408
|
+
|
|
409
|
+
INPUT:
|
|
410
|
+
|
|
411
|
+
- ``toks`` -- list of tokens; this represents a boolean expression
|
|
412
|
+
|
|
413
|
+
OUTPUT: a boolean value to be determined as follows:
|
|
414
|
+
|
|
415
|
+
- ``True`` if expression evaluates to ``True``.
|
|
416
|
+
|
|
417
|
+
- ``False`` if expression evaluates to ``False``.
|
|
418
|
+
|
|
419
|
+
.. NOTE::
|
|
420
|
+
|
|
421
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
422
|
+
The evaluations rely on setting the values of the variables in the
|
|
423
|
+
global dictionary vars.
|
|
424
|
+
|
|
425
|
+
TESTS::
|
|
426
|
+
|
|
427
|
+
sage: log = SymbolicLogic()
|
|
428
|
+
sage: s = log.statement("a&b|!(c|a)")
|
|
429
|
+
sage: sage.logic.logic.eval(s[0])
|
|
430
|
+
'True'
|
|
431
|
+
"""
|
|
432
|
+
stack = []
|
|
433
|
+
for tok in toks:
|
|
434
|
+
stack.append(tok)
|
|
435
|
+
if tok == 'CPAREN':
|
|
436
|
+
lrtoks = []
|
|
437
|
+
while tok != 'OPAREN':
|
|
438
|
+
tok = stack.pop()
|
|
439
|
+
lrtoks.insert(0, tok)
|
|
440
|
+
stack.append(eval_ltor_toks(lrtoks[1:-1]))
|
|
441
|
+
if len(stack) > 1:
|
|
442
|
+
raise RuntimeError
|
|
443
|
+
return stack[0]
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def eval_ltor_toks(lrtoks):
|
|
447
|
+
r"""
|
|
448
|
+
Evaluates the expression contained in ``lrtoks``.
|
|
449
|
+
|
|
450
|
+
INPUT:
|
|
451
|
+
|
|
452
|
+
- ``lrtoks`` -- list of tokens; this represents a part of a boolean
|
|
453
|
+
formula that contains no inner parentheses
|
|
454
|
+
|
|
455
|
+
OUTPUT: a boolean value to be determined as follows:
|
|
456
|
+
|
|
457
|
+
- ``True`` if expression evaluates to ``True``.
|
|
458
|
+
|
|
459
|
+
- ``False`` if expression evaluates to ``False``.
|
|
460
|
+
|
|
461
|
+
.. NOTE::
|
|
462
|
+
|
|
463
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
464
|
+
The evaluations rely on setting the values of the variables in the
|
|
465
|
+
global dictionary vars.
|
|
466
|
+
|
|
467
|
+
TESTS::
|
|
468
|
+
|
|
469
|
+
sage: log = SymbolicLogic()
|
|
470
|
+
sage: s = log.statement("a&b|!c")
|
|
471
|
+
sage: ltor = s[0][1:-1]; ltor
|
|
472
|
+
['a', 'AND', 'b', 'OR', 'NOT', 'c']
|
|
473
|
+
sage: sage.logic.logic.eval_ltor_toks(ltor)
|
|
474
|
+
'True'
|
|
475
|
+
"""
|
|
476
|
+
reduce_monos(lrtoks) # monotonic ! operators go first
|
|
477
|
+
reduce_bins(lrtoks) # then the binary operators
|
|
478
|
+
if len(lrtoks) > 1:
|
|
479
|
+
raise RuntimeError
|
|
480
|
+
return lrtoks[0]
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def reduce_bins(lrtoks):
|
|
484
|
+
r"""
|
|
485
|
+
Evaluate ``lrtoks`` to a single boolean value.
|
|
486
|
+
|
|
487
|
+
INPUT:
|
|
488
|
+
|
|
489
|
+
- ``lrtoks`` -- list of tokens; this represents a part of a boolean
|
|
490
|
+
formula that contains no inner parentheses or monotonic operators
|
|
491
|
+
|
|
492
|
+
OUTPUT:
|
|
493
|
+
|
|
494
|
+
``None``; the pointer to lrtoks is now a list containing
|
|
495
|
+
``True`` or ``False``.
|
|
496
|
+
|
|
497
|
+
.. NOTE::
|
|
498
|
+
|
|
499
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
500
|
+
|
|
501
|
+
TESTS::
|
|
502
|
+
|
|
503
|
+
sage: log = SymbolicLogic()
|
|
504
|
+
sage: s = log.statement("a&b|c")
|
|
505
|
+
sage: lrtoks = s[0][1:-1]; lrtoks
|
|
506
|
+
['a', 'AND', 'b', 'OR', 'c']
|
|
507
|
+
sage: sage.logic.logic.reduce_bins(lrtoks); lrtoks
|
|
508
|
+
['False']
|
|
509
|
+
"""
|
|
510
|
+
i = 0
|
|
511
|
+
while i < len(lrtoks):
|
|
512
|
+
if lrtoks[i] in bin_list:
|
|
513
|
+
args = [lrtoks[i - 1], lrtoks[i], lrtoks[i + 1]]
|
|
514
|
+
lrtoks[i - 1] = eval_bin_op(args)
|
|
515
|
+
del lrtoks[i]
|
|
516
|
+
del lrtoks[i]
|
|
517
|
+
reduce_bins(lrtoks)
|
|
518
|
+
i += 1
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
def reduce_monos(lrtoks):
|
|
522
|
+
r"""
|
|
523
|
+
Replace monotonic operator/variable pairs with a boolean value.
|
|
524
|
+
|
|
525
|
+
INPUT:
|
|
526
|
+
|
|
527
|
+
- ``lrtoks`` -- list of tokens; this represents a part of a boolean
|
|
528
|
+
expression that contains now inner parentheses
|
|
529
|
+
|
|
530
|
+
OUTPUT:
|
|
531
|
+
|
|
532
|
+
``None``; the pointer to ``lrtoks`` is now a list containing
|
|
533
|
+
monotonic operators.
|
|
534
|
+
|
|
535
|
+
.. NOTE::
|
|
536
|
+
|
|
537
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
538
|
+
|
|
539
|
+
TESTS::
|
|
540
|
+
|
|
541
|
+
sage: log = SymbolicLogic()
|
|
542
|
+
sage: s = log.statement("!a&!b")
|
|
543
|
+
sage: lrtoks = s[0][1:-1]; lrtoks
|
|
544
|
+
['NOT', 'a', 'AND', 'NOT', 'b']
|
|
545
|
+
sage: sage.logic.logic.reduce_monos(lrtoks); lrtoks
|
|
546
|
+
['True', 'AND', 'True']
|
|
547
|
+
"""
|
|
548
|
+
i = 0
|
|
549
|
+
while i < len(lrtoks):
|
|
550
|
+
if lrtoks[i] == 'NOT':
|
|
551
|
+
args = [lrtoks[i], lrtoks[i + 1]]
|
|
552
|
+
lrtoks[i] = eval_mon_op(args)
|
|
553
|
+
del lrtoks[i + 1]
|
|
554
|
+
i += 1
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def eval_mon_op(args):
|
|
558
|
+
r"""
|
|
559
|
+
Return a boolean value based on the truth table of the operator
|
|
560
|
+
in ``args``.
|
|
561
|
+
|
|
562
|
+
INPUT:
|
|
563
|
+
|
|
564
|
+
- ``args`` -- list of length 2; this contains the token 'NOT' and
|
|
565
|
+
then a variable name
|
|
566
|
+
|
|
567
|
+
OUTPUT: a boolean value to be determined as follows:
|
|
568
|
+
|
|
569
|
+
- ``True`` if the variable in ``args`` is ``False``.
|
|
570
|
+
|
|
571
|
+
- ``False`` if the variable in ``args`` is ``True``.
|
|
572
|
+
|
|
573
|
+
.. NOTE::
|
|
574
|
+
|
|
575
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
576
|
+
|
|
577
|
+
TESTS::
|
|
578
|
+
|
|
579
|
+
sage: log = SymbolicLogic()
|
|
580
|
+
sage: s = log.statement("!(a&b)|!a"); s
|
|
581
|
+
[['OPAREN', 'NOT', 'OPAREN', 'a', 'AND', 'b', 'CPAREN', 'OR',
|
|
582
|
+
'NOT', 'a', 'CPAREN'],
|
|
583
|
+
{'a': 'False', 'b': 'False'},
|
|
584
|
+
['a', 'b']]
|
|
585
|
+
sage: sage.logic.logic.eval_mon_op(['NOT', 'a'])
|
|
586
|
+
'True'
|
|
587
|
+
"""
|
|
588
|
+
val = vars[args[1]] if args[1] != 'True' and args[1] != 'False' else args[1]
|
|
589
|
+
|
|
590
|
+
return 'False' if val == 'True' else 'True'
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def eval_bin_op(args):
|
|
594
|
+
r"""
|
|
595
|
+
Return a boolean value based on the truth table of the operator
|
|
596
|
+
in ``args``.
|
|
597
|
+
|
|
598
|
+
INPUT:
|
|
599
|
+
|
|
600
|
+
- ``args`` -- list of length 3; this contains a variable name,
|
|
601
|
+
then a binary operator, and then a variable name, in that order
|
|
602
|
+
|
|
603
|
+
OUTPUT:
|
|
604
|
+
|
|
605
|
+
A boolean value; this is the evaluation of the operator based on the
|
|
606
|
+
truth values of the variables.
|
|
607
|
+
|
|
608
|
+
.. NOTE::
|
|
609
|
+
|
|
610
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
611
|
+
|
|
612
|
+
TESTS::
|
|
613
|
+
|
|
614
|
+
sage: log = SymbolicLogic()
|
|
615
|
+
sage: s = log.statement("!(a&b)"); s
|
|
616
|
+
[['OPAREN', 'NOT', 'OPAREN', 'a', 'AND', 'b', 'CPAREN', 'CPAREN'],
|
|
617
|
+
{'a': 'False', 'b': 'False'},
|
|
618
|
+
['a', 'b']]
|
|
619
|
+
sage: sage.logic.logic.eval_bin_op(['a', 'AND', 'b'])
|
|
620
|
+
'False'
|
|
621
|
+
"""
|
|
622
|
+
if args[0] == 'False':
|
|
623
|
+
lval = 'False'
|
|
624
|
+
elif args[0] == 'True':
|
|
625
|
+
lval = 'True'
|
|
626
|
+
else:
|
|
627
|
+
lval = vars[args[0]]
|
|
628
|
+
|
|
629
|
+
if args[2] == 'False':
|
|
630
|
+
rval = 'False'
|
|
631
|
+
elif args[2] == 'True':
|
|
632
|
+
rval = 'True'
|
|
633
|
+
else:
|
|
634
|
+
rval = vars[args[2]]
|
|
635
|
+
|
|
636
|
+
if args[1] == 'AND':
|
|
637
|
+
return eval_and_op(lval, rval)
|
|
638
|
+
elif args[1] == 'OR':
|
|
639
|
+
return eval_or_op(lval, rval)
|
|
640
|
+
elif args[1] == 'IFTHEN':
|
|
641
|
+
return eval_ifthen_op(lval, rval)
|
|
642
|
+
elif args[1] == 'IFF':
|
|
643
|
+
return eval_iff_op(lval, rval)
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
def eval_and_op(lval, rval):
|
|
647
|
+
r"""
|
|
648
|
+
Apply the 'and' operator to ``lval`` and ``rval``.
|
|
649
|
+
|
|
650
|
+
INPUT:
|
|
651
|
+
|
|
652
|
+
- ``lval`` -- string; this represents the value of the variable
|
|
653
|
+
appearing to the left of the 'and' operator
|
|
654
|
+
|
|
655
|
+
- ``rval`` -- string; this represents the value of the variable
|
|
656
|
+
appearing to the right of the 'and' operator
|
|
657
|
+
|
|
658
|
+
OUTPUT: the result of applying 'and' to ``lval`` and ``rval`` as a string
|
|
659
|
+
|
|
660
|
+
.. NOTE::
|
|
661
|
+
|
|
662
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
663
|
+
|
|
664
|
+
TESTS::
|
|
665
|
+
|
|
666
|
+
sage: sage.logic.logic.eval_and_op('False', 'False')
|
|
667
|
+
'False'
|
|
668
|
+
sage: sage.logic.logic.eval_and_op('False', 'True')
|
|
669
|
+
'False'
|
|
670
|
+
sage: sage.logic.logic.eval_and_op('True', 'False')
|
|
671
|
+
'False'
|
|
672
|
+
sage: sage.logic.logic.eval_and_op('True', 'True')
|
|
673
|
+
'True'
|
|
674
|
+
"""
|
|
675
|
+
return 'True' if (lval == 'True' == rval) else 'False'
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def eval_or_op(lval, rval):
|
|
679
|
+
r"""
|
|
680
|
+
Apply the 'or' operator to ``lval`` and ``rval``.
|
|
681
|
+
|
|
682
|
+
INPUT:
|
|
683
|
+
|
|
684
|
+
- ``lval`` -- string; this represents the value of the variable
|
|
685
|
+
appearing to the left of the 'or' operator
|
|
686
|
+
|
|
687
|
+
- ``rval`` -- string; this represents the value of the variable
|
|
688
|
+
appearing to the right of the 'or' operator
|
|
689
|
+
|
|
690
|
+
OUTPUT: string representing the result of applying 'or' to ``lval`` and ``rval``
|
|
691
|
+
|
|
692
|
+
.. NOTE::
|
|
693
|
+
|
|
694
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
695
|
+
|
|
696
|
+
TESTS::
|
|
697
|
+
|
|
698
|
+
sage: sage.logic.logic.eval_or_op('False', 'False')
|
|
699
|
+
'False'
|
|
700
|
+
sage: sage.logic.logic.eval_or_op('False', 'True')
|
|
701
|
+
'True'
|
|
702
|
+
sage: sage.logic.logic.eval_or_op('True', 'False')
|
|
703
|
+
'True'
|
|
704
|
+
sage: sage.logic.logic.eval_or_op('True', 'True')
|
|
705
|
+
'True'
|
|
706
|
+
"""
|
|
707
|
+
return 'True' if (lval == 'True' or rval == 'True') else 'False'
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def eval_ifthen_op(lval, rval):
|
|
711
|
+
r"""
|
|
712
|
+
Apply the 'if then' operator to ``lval`` and ``rval``.
|
|
713
|
+
|
|
714
|
+
INPUT:
|
|
715
|
+
|
|
716
|
+
- ``lval`` -- string; this represents the value of the variable
|
|
717
|
+
appearing to the left of the 'if then' operator
|
|
718
|
+
|
|
719
|
+
- ``rval`` -- string; this represents the value of the variable
|
|
720
|
+
appearing to the right of the 'if then' operator
|
|
721
|
+
|
|
722
|
+
OUTPUT:
|
|
723
|
+
|
|
724
|
+
A string representing the result of applying 'if then' to
|
|
725
|
+
``lval`` and ``rval``.
|
|
726
|
+
|
|
727
|
+
.. NOTE::
|
|
728
|
+
|
|
729
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
730
|
+
|
|
731
|
+
TESTS::
|
|
732
|
+
|
|
733
|
+
sage: sage.logic.logic.eval_ifthen_op('False', 'False')
|
|
734
|
+
'True'
|
|
735
|
+
sage: sage.logic.logic.eval_ifthen_op('False', 'True')
|
|
736
|
+
'True'
|
|
737
|
+
sage: sage.logic.logic.eval_ifthen_op('True', 'False')
|
|
738
|
+
'False'
|
|
739
|
+
sage: sage.logic.logic.eval_ifthen_op('True', 'True')
|
|
740
|
+
'True'
|
|
741
|
+
"""
|
|
742
|
+
return 'False' if (lval == 'True' and rval == 'False') else 'True'
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
def eval_iff_op(lval, rval):
|
|
746
|
+
r"""
|
|
747
|
+
Apply the 'if and only if' operator to ``lval`` and ``rval``.
|
|
748
|
+
|
|
749
|
+
INPUT:
|
|
750
|
+
|
|
751
|
+
- ``lval`` -- string; this represents the value of the variable
|
|
752
|
+
appearing to the left of the 'if and only if' operator
|
|
753
|
+
|
|
754
|
+
- ``rval`` -- string; this represents the value of the variable
|
|
755
|
+
appearing to the right of the 'if and only if' operator
|
|
756
|
+
|
|
757
|
+
OUTPUT:
|
|
758
|
+
|
|
759
|
+
A string representing the result of applying 'if and only if'
|
|
760
|
+
to ``lval`` and ``rval``.
|
|
761
|
+
|
|
762
|
+
.. NOTE::
|
|
763
|
+
|
|
764
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
765
|
+
|
|
766
|
+
TESTS::
|
|
767
|
+
|
|
768
|
+
sage: sage.logic.logic.eval_iff_op('False', 'False')
|
|
769
|
+
'True'
|
|
770
|
+
sage: sage.logic.logic.eval_iff_op('False', 'True')
|
|
771
|
+
'False'
|
|
772
|
+
sage: sage.logic.logic.eval_iff_op('True', 'False')
|
|
773
|
+
'False'
|
|
774
|
+
sage: sage.logic.logic.eval_iff_op('True', 'True')
|
|
775
|
+
'True'
|
|
776
|
+
"""
|
|
777
|
+
return 'True' if (lval == rval) else 'False'
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
def tokenize(s, toks):
|
|
781
|
+
r"""
|
|
782
|
+
Tokenize ``s`` and place the tokens of ``s`` in ``toks``.
|
|
783
|
+
|
|
784
|
+
INPUT:
|
|
785
|
+
|
|
786
|
+
- ``s`` -- string; this contains a boolean expression
|
|
787
|
+
|
|
788
|
+
- ``toks`` -- list; this will be populated with the tokens of ``s``
|
|
789
|
+
|
|
790
|
+
OUTPUT: none; the tokens of ``s`` are placed in ``toks``
|
|
791
|
+
|
|
792
|
+
.. NOTE::
|
|
793
|
+
|
|
794
|
+
This function is for internal use by the :class:`SymbolicLogic` class.
|
|
795
|
+
|
|
796
|
+
EXAMPLES::
|
|
797
|
+
|
|
798
|
+
sage: from sage.logic.logic import tokenize
|
|
799
|
+
sage: toks = []
|
|
800
|
+
sage: tokenize("(a&b)|c", toks)
|
|
801
|
+
sage: toks
|
|
802
|
+
['OPAREN', 'a', 'AND', 'b', 'CPAREN', 'OR', 'c', 'CPAREN']
|
|
803
|
+
"""
|
|
804
|
+
i = 0
|
|
805
|
+
while i < len(s):
|
|
806
|
+
tok = ""
|
|
807
|
+
skip = valid = 1
|
|
808
|
+
if s[i] == '(':
|
|
809
|
+
tok = tok_list[0]
|
|
810
|
+
elif s[i] == ')':
|
|
811
|
+
tok = tok_list[1]
|
|
812
|
+
elif s[i] == '&':
|
|
813
|
+
tok = tok_list[2]
|
|
814
|
+
elif s[i] == '|':
|
|
815
|
+
tok = tok_list[3]
|
|
816
|
+
elif s[i] == '!':
|
|
817
|
+
tok = tok_list[4]
|
|
818
|
+
elif s[i:i + 2] == '->':
|
|
819
|
+
tok = tok_list[5]
|
|
820
|
+
skip = 2
|
|
821
|
+
elif s[i:i + 3] == '<->':
|
|
822
|
+
tok = tok_list[6]
|
|
823
|
+
skip = 3
|
|
824
|
+
|
|
825
|
+
if tok:
|
|
826
|
+
toks.append(tok)
|
|
827
|
+
i += skip
|
|
828
|
+
continue
|
|
829
|
+
else:
|
|
830
|
+
# token is a variable name
|
|
831
|
+
if s[i] == ' ':
|
|
832
|
+
i += 1
|
|
833
|
+
continue
|
|
834
|
+
|
|
835
|
+
while i < len(s) and s[i] not in operators and s[i] != ' ':
|
|
836
|
+
tok += s[i]
|
|
837
|
+
i += 1
|
|
838
|
+
|
|
839
|
+
if tok:
|
|
840
|
+
if tok[0] not in string.ascii_letters:
|
|
841
|
+
valid = 0
|
|
842
|
+
for c in tok:
|
|
843
|
+
if not (c in string.ascii_letters
|
|
844
|
+
or c in string.digits or c == '_'):
|
|
845
|
+
valid = 0
|
|
846
|
+
|
|
847
|
+
if valid == 1:
|
|
848
|
+
toks.append(tok)
|
|
849
|
+
vars[tok] = 'False'
|
|
850
|
+
if tok not in vars_order:
|
|
851
|
+
vars_order.append(tok)
|
|
852
|
+
else:
|
|
853
|
+
print('Invalid variable name: ', tok)
|
|
854
|
+
toks = []
|
|
855
|
+
|
|
856
|
+
toks.append('CPAREN')
|