passagemath-standard-no-symbolics 10.6.45__cp313-cp313-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.
- passagemath_standard_no_symbolics/__init__.py +1 -0
- passagemath_standard_no_symbolics-10.6.45.data/scripts/sage-grep +5 -0
- passagemath_standard_no_symbolics-10.6.45.data/scripts/sage-grepdoc +5 -0
- passagemath_standard_no_symbolics-10.6.45.data/scripts/sage-list-packages +103 -0
- passagemath_standard_no_symbolics-10.6.45.dist-info/METADATA +150 -0
- passagemath_standard_no_symbolics-10.6.45.dist-info/RECORD +83 -0
- passagemath_standard_no_symbolics-10.6.45.dist-info/WHEEL +6 -0
- passagemath_standard_no_symbolics-10.6.45.dist-info/top_level.txt +2 -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-313-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
|
@@ -0,0 +1,696 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
Module that creates and modifies parse trees of well formed boolean formulas.
|
|
3
|
+
|
|
4
|
+
A parse tree of a boolean formula is a nested list, where each branch is either
|
|
5
|
+
a single variable, or a formula composed of either two variables and a binary
|
|
6
|
+
operator or one variable and a unary operator. The function parse produces
|
|
7
|
+
a parse tree that is simplified for the purposes of more efficient truth value
|
|
8
|
+
evaluation. The function :func:`~sage.logic.logicparser.polish_parse()`
|
|
9
|
+
produces the full parse tree of a boolean formula which is used in functions
|
|
10
|
+
related to proof and inference. That is,
|
|
11
|
+
:func:`~sage.logic.logicparser.parse()` is meant to be used with functions
|
|
12
|
+
in the logic module that perform semantic operations on a boolean formula,
|
|
13
|
+
and :func:`~sage.logic.logicparser.polish_parse()` is to be used with
|
|
14
|
+
functions that perform syntactic operations on a boolean formula.
|
|
15
|
+
|
|
16
|
+
AUTHORS:
|
|
17
|
+
|
|
18
|
+
- Chris Gorecki (2007): initial version
|
|
19
|
+
|
|
20
|
+
- Paul Scurek (2013-08-01): added polish_parse, cleaned up python code,
|
|
21
|
+
updated docstring formatting
|
|
22
|
+
|
|
23
|
+
- Paul Scurek (2013-08-06): added
|
|
24
|
+
:func:`~sage.logic.logicparser.recover_formula()`,
|
|
25
|
+
:func:`~sage.logic.logicparser.recover_formula_internal()`,
|
|
26
|
+
:func:`~sage.logic.logicparser.prefix_to_infix()`,
|
|
27
|
+
:func:`~sage.logic.logicparser.to_infix_internal()`
|
|
28
|
+
|
|
29
|
+
- Paul Scurek (2013-08-08): added get_trees, error handling in polish_parse,
|
|
30
|
+
recover_formula_internal, and tree_parse
|
|
31
|
+
|
|
32
|
+
EXAMPLES:
|
|
33
|
+
|
|
34
|
+
Find the parse tree and variables of a string representation of a boolean
|
|
35
|
+
formula::
|
|
36
|
+
|
|
37
|
+
sage: import sage.logic.logicparser as logicparser
|
|
38
|
+
sage: s = 'a|b&c'
|
|
39
|
+
sage: t = logicparser.parse(s)
|
|
40
|
+
sage: t
|
|
41
|
+
(['|', 'a', ['&', 'b', 'c']], ['a', 'b', 'c'])
|
|
42
|
+
|
|
43
|
+
Find the full syntax parse tree of a string representation of a boolean
|
|
44
|
+
formula::
|
|
45
|
+
|
|
46
|
+
sage: import sage.logic.logicparser as logicparser
|
|
47
|
+
sage: s = '(a&b)->~~c'
|
|
48
|
+
sage: logicparser.polish_parse(s)
|
|
49
|
+
['->', ['&', 'a', 'b'], ['~', ['~', 'c']]]
|
|
50
|
+
|
|
51
|
+
Find the tokens and distinct variables of a boolean formula::
|
|
52
|
+
|
|
53
|
+
sage: import sage.logic.logicparser as logicparser
|
|
54
|
+
sage: s = '~(a|~b)<->(c->c)'
|
|
55
|
+
sage: logicparser.tokenize(s)
|
|
56
|
+
(['(', '~', '(', 'a', '|', '~', 'b', ')', '<->', '(', 'c', '->', 'c', ')', ')'], ['a', 'b', 'c'])
|
|
57
|
+
|
|
58
|
+
Find the parse tree of a boolean formula from a list of the formula's tokens::
|
|
59
|
+
|
|
60
|
+
sage: import sage.logic.logicparser as logicparser
|
|
61
|
+
sage: t = ['(', 'a', '->', '~', 'c', ')']
|
|
62
|
+
sage: logicparser.tree_parse(t)
|
|
63
|
+
['->', 'a', ['~', 'c', None]]
|
|
64
|
+
sage: r = ['(', '~', '~', 'a', '|', 'b', ')']
|
|
65
|
+
sage: logicparser.tree_parse(r)
|
|
66
|
+
['|', 'a', 'b']
|
|
67
|
+
|
|
68
|
+
Find the full syntax parse tree of a boolean formula from a list of tokens::
|
|
69
|
+
|
|
70
|
+
sage: import sage.logic.logicparser as logicparser
|
|
71
|
+
sage: t = ['(', 'a', '->', '~', 'c', ')']
|
|
72
|
+
sage: logicparser.tree_parse(t, polish = True)
|
|
73
|
+
['->', 'a', ['~', 'c']]
|
|
74
|
+
sage: r = ['(', '~', '~', 'a', '|', 'b', ')']
|
|
75
|
+
sage: logicparser.tree_parse(r, polish = True)
|
|
76
|
+
['|', ['~', ['~', 'a']], 'b']
|
|
77
|
+
"""
|
|
78
|
+
# ****************************************************************************
|
|
79
|
+
# Copyright (C) 2007 Chris Gorecki <chris.k.gorecki@gmail.com>
|
|
80
|
+
# Copyright (C) 2013 Paul Scurek <scurek86@gmail.com>
|
|
81
|
+
#
|
|
82
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
83
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
84
|
+
# the License, or (at your option) any later version.
|
|
85
|
+
# https://www.gnu.org/licenses/
|
|
86
|
+
# ****************************************************************************
|
|
87
|
+
|
|
88
|
+
import string
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
__symbols = '()&|~<->^'
|
|
92
|
+
__op_list = ['~', '&', '|', '^', '->', '<->']
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def parse(s):
|
|
96
|
+
r"""
|
|
97
|
+
Return a parse tree from a boolean formula ``s``.
|
|
98
|
+
|
|
99
|
+
INPUT:
|
|
100
|
+
|
|
101
|
+
- ``s`` -- string containing a boolean formula
|
|
102
|
+
|
|
103
|
+
OUTPUT:
|
|
104
|
+
|
|
105
|
+
A list containing the parse tree and a list containing the
|
|
106
|
+
variables in a boolean formula in this order:
|
|
107
|
+
|
|
108
|
+
1. the list containing the parse tree
|
|
109
|
+
2. the list containing the variables
|
|
110
|
+
|
|
111
|
+
EXAMPLES:
|
|
112
|
+
|
|
113
|
+
This example illustrates how to produce the parse tree of a boolean
|
|
114
|
+
formula ``s``::
|
|
115
|
+
|
|
116
|
+
sage: import sage.logic.logicparser as logicparser
|
|
117
|
+
sage: s = 'a|b&c'
|
|
118
|
+
sage: t = logicparser.parse(s)
|
|
119
|
+
sage: t
|
|
120
|
+
(['|', 'a', ['&', 'b', 'c']], ['a', 'b', 'c'])
|
|
121
|
+
"""
|
|
122
|
+
toks, vars_order = tokenize(s)
|
|
123
|
+
tree = tree_parse(toks)
|
|
124
|
+
# special case of tree == single variable
|
|
125
|
+
if isinstance(tree, str):
|
|
126
|
+
return ['&', tree, tree], vars_order
|
|
127
|
+
return tree, vars_order
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def polish_parse(s):
|
|
131
|
+
r"""
|
|
132
|
+
Return the full syntax parse tree from a boolean formula ``s``.
|
|
133
|
+
|
|
134
|
+
INPUT:
|
|
135
|
+
|
|
136
|
+
- ``s`` -- string containing a boolean expression
|
|
137
|
+
|
|
138
|
+
OUTPUT: the full syntax parse tree as a nested list
|
|
139
|
+
|
|
140
|
+
EXAMPLES:
|
|
141
|
+
|
|
142
|
+
This example illustrates how to find the full syntax parse tree
|
|
143
|
+
of a boolean formula::
|
|
144
|
+
|
|
145
|
+
sage: import sage.logic.logicparser as logicparser
|
|
146
|
+
sage: s = 'a|~~b'
|
|
147
|
+
sage: t = logicparser.polish_parse(s)
|
|
148
|
+
sage: t
|
|
149
|
+
['|', 'a', ['~', ['~', 'b']]]
|
|
150
|
+
|
|
151
|
+
AUTHORS:
|
|
152
|
+
|
|
153
|
+
- Paul Scurek (2013-08-03)
|
|
154
|
+
"""
|
|
155
|
+
if (s.count('(') != s.count(')')) or not s:
|
|
156
|
+
raise SyntaxError("malformed statement")
|
|
157
|
+
|
|
158
|
+
toks, vars_order = tokenize(s)
|
|
159
|
+
tree = tree_parse(toks, polish=True)
|
|
160
|
+
# special case where the formula s is a single variable
|
|
161
|
+
if isinstance(tree, str):
|
|
162
|
+
return vars_order
|
|
163
|
+
return tree
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def get_trees(*statements):
|
|
167
|
+
r"""
|
|
168
|
+
Return the full syntax parse trees of the statements.
|
|
169
|
+
|
|
170
|
+
INPUT:
|
|
171
|
+
|
|
172
|
+
- ``*statements`` -- strings or :class:`BooleanFormula` instances
|
|
173
|
+
|
|
174
|
+
OUTPUT: the parse trees in a list
|
|
175
|
+
|
|
176
|
+
EXAMPLES:
|
|
177
|
+
|
|
178
|
+
This example illustrates finding the parse trees of multiple formulas.
|
|
179
|
+
|
|
180
|
+
::
|
|
181
|
+
|
|
182
|
+
sage: import sage.logic.propcalc as propcalc
|
|
183
|
+
sage: import sage.logic.logicparser as logicparser
|
|
184
|
+
sage: f = propcalc.formula("((a|b)&~~c)")
|
|
185
|
+
sage: g = "a<->(~(c))"
|
|
186
|
+
sage: h = "~b"
|
|
187
|
+
sage: logicparser.get_trees(f, g, h)
|
|
188
|
+
[['&', ['|', 'a', 'b'], ['~', ['~', 'c']]],
|
|
189
|
+
['<->', 'a', ['~', 'c']],
|
|
190
|
+
['~', 'b']]
|
|
191
|
+
|
|
192
|
+
::
|
|
193
|
+
|
|
194
|
+
sage: i = "(~q->p)"
|
|
195
|
+
sage: j = propcalc.formula("a")
|
|
196
|
+
sage: logicparser.get_trees(i, j)
|
|
197
|
+
[['->', ['~', 'q'], 'p'], ['a']]
|
|
198
|
+
|
|
199
|
+
::
|
|
200
|
+
|
|
201
|
+
sage: k = "p"
|
|
202
|
+
sage: logicparser.get_trees(k)
|
|
203
|
+
[['p']]
|
|
204
|
+
|
|
205
|
+
AUTHORS:
|
|
206
|
+
|
|
207
|
+
- Paul Scurek (2013-08-06)
|
|
208
|
+
"""
|
|
209
|
+
trees = []
|
|
210
|
+
from . import boolformula
|
|
211
|
+
for statement in statements:
|
|
212
|
+
if not isinstance(statement, boolformula.BooleanFormula):
|
|
213
|
+
try:
|
|
214
|
+
trees.append(polish_parse(statement))
|
|
215
|
+
except (NameError, SyntaxError):
|
|
216
|
+
raise SyntaxError("malformed statement")
|
|
217
|
+
else:
|
|
218
|
+
trees.append(statement.full_tree())
|
|
219
|
+
return trees
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def recover_formula(prefix_tree):
|
|
223
|
+
r"""
|
|
224
|
+
Recover the formula from a parse tree in prefix form.
|
|
225
|
+
|
|
226
|
+
INPUT:
|
|
227
|
+
|
|
228
|
+
- ``prefix_tree`` -- list; this is a full syntax parse
|
|
229
|
+
tree in prefix form
|
|
230
|
+
|
|
231
|
+
OUTPUT: the formula as a string
|
|
232
|
+
|
|
233
|
+
EXAMPLES:
|
|
234
|
+
|
|
235
|
+
This example illustrates the recovery of a formula from a parse tree::
|
|
236
|
+
|
|
237
|
+
sage: import sage.logic.propcalc as propcalc
|
|
238
|
+
sage: import sage.logic.logicparser as logicparser
|
|
239
|
+
sage: t = ['->', ['&', 'a', ['~', ['~', 'c']]], ['~', ['|', ['~', 'c'], 'd']]]
|
|
240
|
+
sage: logicparser.recover_formula(t)
|
|
241
|
+
'(a&~~c)->~(~c|d)'
|
|
242
|
+
|
|
243
|
+
sage: f = propcalc.formula("a&(~~c|d)")
|
|
244
|
+
sage: logicparser.recover_formula(f.full_tree())
|
|
245
|
+
'a&(~~c|d)'
|
|
246
|
+
|
|
247
|
+
sage: r = ['~', 'a']
|
|
248
|
+
sage: logicparser.recover_formula(r)
|
|
249
|
+
'~a'
|
|
250
|
+
|
|
251
|
+
sage: s = ['d']
|
|
252
|
+
sage: logicparser.recover_formula(s)
|
|
253
|
+
'd'
|
|
254
|
+
|
|
255
|
+
.. NOTE::
|
|
256
|
+
|
|
257
|
+
The function :func:`~sage.logic.logicparser.polish_parse()` may be
|
|
258
|
+
passed as an argument, but :func:`~sage.logic.logicparser.tree_parse()`
|
|
259
|
+
may not unless the parameter ``polish`` is set to ``True``.
|
|
260
|
+
|
|
261
|
+
AUTHORS:
|
|
262
|
+
|
|
263
|
+
- Paul Scurek (2013-08-06)
|
|
264
|
+
"""
|
|
265
|
+
formula = ''
|
|
266
|
+
if not isinstance(prefix_tree, list):
|
|
267
|
+
raise TypeError("the input must be a parse tree as a list")
|
|
268
|
+
|
|
269
|
+
formula = apply_func(prefix_tree, recover_formula_internal)
|
|
270
|
+
if prefix_tree[0] == '~' or len(prefix_tree) == 1:
|
|
271
|
+
return formula
|
|
272
|
+
return formula[1:-1]
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def recover_formula_internal(prefix_tree):
|
|
276
|
+
r"""
|
|
277
|
+
Recover the formula from a parse tree in prefix form.
|
|
278
|
+
|
|
279
|
+
INPUT:
|
|
280
|
+
|
|
281
|
+
- ``prefix_tree`` -- list; this is a simple tree
|
|
282
|
+
with at most one operator in prefix form
|
|
283
|
+
|
|
284
|
+
OUTPUT: the formula as a string
|
|
285
|
+
|
|
286
|
+
EXAMPLES:
|
|
287
|
+
|
|
288
|
+
This example illustrates recovering the formula from a parse tree::
|
|
289
|
+
|
|
290
|
+
sage: import sage.logic.logicparser as logicparser
|
|
291
|
+
sage: import sage.logic.propcalc as propcalc
|
|
292
|
+
sage: t = ['->', 'a', 'b']
|
|
293
|
+
sage: logicparser.recover_formula_internal(t)
|
|
294
|
+
'(a->b)'
|
|
295
|
+
|
|
296
|
+
sage: r = ['~', 'c']
|
|
297
|
+
sage: logicparser.recover_formula_internal(r)
|
|
298
|
+
'~c'
|
|
299
|
+
|
|
300
|
+
sage: s = ['d']
|
|
301
|
+
sage: logicparser.recover_formula_internal(s)
|
|
302
|
+
'd'
|
|
303
|
+
|
|
304
|
+
We can pass :func:`~sage.logic.logicparser.recover_formula_internal()`
|
|
305
|
+
as an argument in :func:`~sage.logic.logicparser.apply_func()`::
|
|
306
|
+
|
|
307
|
+
sage: f = propcalc.formula("~(d|c)<->(a&~~~c)")
|
|
308
|
+
sage: logicparser.apply_func(f.full_tree(), logicparser.recover_formula_internal)
|
|
309
|
+
'(~(d|c)<->(a&~~~c))'
|
|
310
|
+
|
|
311
|
+
.. NOTE::
|
|
312
|
+
|
|
313
|
+
This function is for internal use by :mod:`~sage.logic.logicparser`.
|
|
314
|
+
The function recovers the formula of a simple parse tree in prefix
|
|
315
|
+
form. A simple parse tree contains at most one operator.
|
|
316
|
+
|
|
317
|
+
The function :func:`~sage.logic.logicparser.polish_parse()` may be
|
|
318
|
+
passed as an argument, but :func:`~sage.logic.logicparser.tree_parse()`
|
|
319
|
+
may not unless the parameter ``polish`` is set to ``True``.
|
|
320
|
+
|
|
321
|
+
AUTHORS:
|
|
322
|
+
|
|
323
|
+
- Paul Scurek (2013-08-06)
|
|
324
|
+
"""
|
|
325
|
+
from .propcalc import formula as propcalc_formula
|
|
326
|
+
if len(prefix_tree) == 3:
|
|
327
|
+
bool_formula = '(' + prefix_tree[1] + prefix_tree[0] + prefix_tree[2] + ')'
|
|
328
|
+
else:
|
|
329
|
+
bool_formula = ''.join(prefix_tree)
|
|
330
|
+
|
|
331
|
+
try:
|
|
332
|
+
bool_formula = propcalc_formula(bool_formula)
|
|
333
|
+
except (SyntaxError, NameError):
|
|
334
|
+
raise SyntaxError
|
|
335
|
+
|
|
336
|
+
return repr(bool_formula)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def prefix_to_infix(prefix_tree):
|
|
340
|
+
r"""
|
|
341
|
+
Convert a parse tree from prefix form to infix form.
|
|
342
|
+
|
|
343
|
+
INPUT:
|
|
344
|
+
|
|
345
|
+
- ``prefix_tree`` -- list; this is a full syntax parse
|
|
346
|
+
tree in prefix form
|
|
347
|
+
|
|
348
|
+
OUTPUT: list containing the tree in infix form
|
|
349
|
+
|
|
350
|
+
EXAMPLES:
|
|
351
|
+
|
|
352
|
+
This example illustrates converting a prefix tree to an infix tree::
|
|
353
|
+
|
|
354
|
+
sage: import sage.logic.logicparser as logicparser
|
|
355
|
+
sage: import sage.logic.propcalc as propcalc
|
|
356
|
+
sage: t = ['|', ['~', 'a'], ['&', 'b', 'c']]
|
|
357
|
+
sage: logicparser.prefix_to_infix(t)
|
|
358
|
+
[['~', 'a'], '|', ['b', '&', 'c']]
|
|
359
|
+
|
|
360
|
+
::
|
|
361
|
+
|
|
362
|
+
sage: f = propcalc.formula("(a&~b)<->~~~(c|d)")
|
|
363
|
+
sage: logicparser.prefix_to_infix(f.full_tree())
|
|
364
|
+
[['a', '&', ['~', 'b']], '<->', ['~', ['~', ['~', ['c', '|', 'd']]]]]
|
|
365
|
+
|
|
366
|
+
.. NOTE::
|
|
367
|
+
|
|
368
|
+
The function :func:`~sage.logic.logicparser.polish_parse()` may be
|
|
369
|
+
passed as an argument, but :func:`~sage.logic.logicparser.tree_parse()`
|
|
370
|
+
may not unless the parameter ``polish`` is set to ``True``.
|
|
371
|
+
|
|
372
|
+
AUTHORS:
|
|
373
|
+
|
|
374
|
+
- Paul Scurek (2013-08-06)
|
|
375
|
+
"""
|
|
376
|
+
if not isinstance(prefix_tree, list):
|
|
377
|
+
raise TypeError("the input must be a parse tree as a list")
|
|
378
|
+
return apply_func(prefix_tree, to_infix_internal)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def to_infix_internal(prefix_tree):
|
|
382
|
+
r"""
|
|
383
|
+
Convert a simple parse tree from prefix form to infix form.
|
|
384
|
+
|
|
385
|
+
INPUT:
|
|
386
|
+
|
|
387
|
+
- ``prefix_tree`` -- list; this is a simple parse tree
|
|
388
|
+
in prefix form with at most one operator
|
|
389
|
+
|
|
390
|
+
OUTPUT: the tree in infix form as a list
|
|
391
|
+
|
|
392
|
+
EXAMPLES:
|
|
393
|
+
|
|
394
|
+
This example illustrates converting a simple tree from prefix
|
|
395
|
+
to infix form::
|
|
396
|
+
|
|
397
|
+
sage: import sage.logic.logicparser as logicparser
|
|
398
|
+
sage: import sage.logic.propcalc as propcalc
|
|
399
|
+
sage: t = ['|', 'a', 'b']
|
|
400
|
+
sage: logicparser.to_infix_internal(t)
|
|
401
|
+
['a', '|', 'b']
|
|
402
|
+
|
|
403
|
+
We can pass :func:`~sage.logic.logicparser.to_infix_internal()` as an
|
|
404
|
+
argument in :func:`~sage.logic.logicparser.apply_func()`::
|
|
405
|
+
|
|
406
|
+
sage: f = propcalc.formula("(a&~b)<->~~~(c|d)")
|
|
407
|
+
sage: logicparser.apply_func(f.full_tree(), logicparser.to_infix_internal)
|
|
408
|
+
[['a', '&', ['~', 'b']], '<->', ['~', ['~', ['~', ['c', '|', 'd']]]]]
|
|
409
|
+
|
|
410
|
+
.. NOTE::
|
|
411
|
+
|
|
412
|
+
This function is for internal use by :mod:`~sage.logic.logicparser`.
|
|
413
|
+
It converts a simple parse tree from prefix form to infix form. A
|
|
414
|
+
simple parse tree contains at most one operator.
|
|
415
|
+
|
|
416
|
+
The function :func:`polish_parse` may be passed as an argument,
|
|
417
|
+
but :func:`~sage.logic.logicparser.tree_parse()` may not unless the
|
|
418
|
+
parameter ``polish`` is set to ``True``.
|
|
419
|
+
|
|
420
|
+
AUTHORS:
|
|
421
|
+
|
|
422
|
+
- Paul Scurek (2013-08-06)
|
|
423
|
+
"""
|
|
424
|
+
if prefix_tree[0] != '~' and len(prefix_tree) == 3:
|
|
425
|
+
return [prefix_tree[1], prefix_tree[0], prefix_tree[2]]
|
|
426
|
+
return prefix_tree
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def tokenize(s):
|
|
430
|
+
r"""
|
|
431
|
+
Return the tokens and the distinct variables appearing in a boolean
|
|
432
|
+
formula ``s``.
|
|
433
|
+
|
|
434
|
+
INPUT:
|
|
435
|
+
|
|
436
|
+
- ``s`` -- string representation of a boolean formula
|
|
437
|
+
|
|
438
|
+
OUTPUT:
|
|
439
|
+
|
|
440
|
+
The tokens and variables as an ordered pair of lists in the following
|
|
441
|
+
order:
|
|
442
|
+
|
|
443
|
+
1. A list containing the tokens of ``s``, in the order they appear in ``s``
|
|
444
|
+
2. A list containing the distinct variables in ``s``, in the order
|
|
445
|
+
they appear in ``s``
|
|
446
|
+
|
|
447
|
+
EXAMPLES:
|
|
448
|
+
|
|
449
|
+
This example illustrates how to tokenize a string representation of a
|
|
450
|
+
boolean formula::
|
|
451
|
+
|
|
452
|
+
sage: import sage.logic.logicparser as logicparser
|
|
453
|
+
sage: s = 'a|b&c'
|
|
454
|
+
sage: t = logicparser.tokenize(s)
|
|
455
|
+
sage: t
|
|
456
|
+
(['(', 'a', '|', 'b', '&', 'c', ')'], ['a', 'b', 'c'])
|
|
457
|
+
"""
|
|
458
|
+
i = 0
|
|
459
|
+
toks = ['(']
|
|
460
|
+
vars_order = []
|
|
461
|
+
|
|
462
|
+
while i < len(s):
|
|
463
|
+
tok = ""
|
|
464
|
+
skip = valid = 1
|
|
465
|
+
if s[i] in '()~&|^':
|
|
466
|
+
tok = s[i]
|
|
467
|
+
elif s[i:i + 2] == '->':
|
|
468
|
+
tok = '->'
|
|
469
|
+
skip = 2
|
|
470
|
+
elif s[i:i + 3] == '<->':
|
|
471
|
+
tok = '<->'
|
|
472
|
+
skip = 3
|
|
473
|
+
# check to see if '-', '<' or '>' are used incorrectly
|
|
474
|
+
elif s[i] in '<->':
|
|
475
|
+
raise SyntaxError("'{}' can only be used as part of the operators '<->' or '->'.".format(s[i]))
|
|
476
|
+
|
|
477
|
+
if len(tok) > 0:
|
|
478
|
+
toks.append(tok)
|
|
479
|
+
i += skip
|
|
480
|
+
continue
|
|
481
|
+
|
|
482
|
+
# token is a variable name
|
|
483
|
+
if s[i] == ' ':
|
|
484
|
+
i += 1
|
|
485
|
+
continue
|
|
486
|
+
|
|
487
|
+
while i < len(s) and s[i] not in __symbols and s[i] != ' ':
|
|
488
|
+
tok += s[i]
|
|
489
|
+
i += 1
|
|
490
|
+
|
|
491
|
+
if len(tok) > 0:
|
|
492
|
+
if tok[0] not in string.ascii_letters:
|
|
493
|
+
valid = 0
|
|
494
|
+
for c in tok:
|
|
495
|
+
if c not in string.ascii_letters and c not in string.digits and c != '_':
|
|
496
|
+
valid = 0
|
|
497
|
+
|
|
498
|
+
if valid == 1:
|
|
499
|
+
toks.append(tok)
|
|
500
|
+
if tok not in vars_order:
|
|
501
|
+
vars_order.append(tok)
|
|
502
|
+
else:
|
|
503
|
+
msg = "invalid variable name " + tok
|
|
504
|
+
msg += ": identifiers must begin with a letter and contain only "
|
|
505
|
+
msg += "alphanumerics and underscores"
|
|
506
|
+
raise NameError(msg)
|
|
507
|
+
|
|
508
|
+
toks.append(')')
|
|
509
|
+
return toks, vars_order
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def tree_parse(toks, polish=False):
|
|
513
|
+
r"""
|
|
514
|
+
Return a parse tree from the tokens in ``toks``.
|
|
515
|
+
|
|
516
|
+
INPUT:
|
|
517
|
+
|
|
518
|
+
- ``toks`` -- list of tokens from a boolean formula
|
|
519
|
+
|
|
520
|
+
- ``polish`` -- boolean (default: ``False``); when ``True``,
|
|
521
|
+
:func:`~sage.logic.logicparser.tree_parse()` will return
|
|
522
|
+
the full syntax parse tree
|
|
523
|
+
|
|
524
|
+
OUTPUT:
|
|
525
|
+
|
|
526
|
+
A parse tree in the form of a nested list that depends on ``polish``
|
|
527
|
+
as follows:
|
|
528
|
+
|
|
529
|
+
- If ``False``, then return a simplified parse tree.
|
|
530
|
+
|
|
531
|
+
- If ``True``, then return the full syntax parse tree.
|
|
532
|
+
|
|
533
|
+
EXAMPLES:
|
|
534
|
+
|
|
535
|
+
This example illustrates the use of
|
|
536
|
+
:func:`~sage.logic.logicparser.tree_parse()` when ``polish`` is ``False``::
|
|
537
|
+
|
|
538
|
+
sage: import sage.logic.logicparser as logicparser
|
|
539
|
+
sage: t = ['(', 'a', '|', 'b', '&', 'c', ')']
|
|
540
|
+
sage: logicparser.tree_parse(t)
|
|
541
|
+
['|', 'a', ['&', 'b', 'c']]
|
|
542
|
+
|
|
543
|
+
We now demonstrate the use of :func:`~sage.logic.logicparser.tree_parse()`
|
|
544
|
+
when ``polish`` is ``True``::
|
|
545
|
+
|
|
546
|
+
sage: t = ['(', 'a', '->', '~', '~', 'b', ')']
|
|
547
|
+
sage: logicparser.tree_parse(t)
|
|
548
|
+
['->', 'a', 'b']
|
|
549
|
+
sage: t = ['(', 'a', '->', '~', '~', 'b', ')']
|
|
550
|
+
sage: logicparser.tree_parse(t, polish = True)
|
|
551
|
+
['->', 'a', ['~', ['~', 'b']]]
|
|
552
|
+
"""
|
|
553
|
+
if toks[1] in ['|', '&', '->', '<->', '^']:
|
|
554
|
+
raise SyntaxError
|
|
555
|
+
|
|
556
|
+
stack = []
|
|
557
|
+
for tok in toks:
|
|
558
|
+
stack.append(tok)
|
|
559
|
+
if tok == ')':
|
|
560
|
+
lrtoks = []
|
|
561
|
+
while tok != '(':
|
|
562
|
+
tok = stack.pop()
|
|
563
|
+
lrtoks.insert(0, tok)
|
|
564
|
+
branch = parse_ltor(lrtoks[1:-1], polish=polish)
|
|
565
|
+
stack.append(branch)
|
|
566
|
+
return stack[0]
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
def parse_ltor(toks, n=0, polish=False):
|
|
570
|
+
r"""
|
|
571
|
+
Return a parse tree from ``toks``, where each token in ``toks`` is atomic.
|
|
572
|
+
|
|
573
|
+
INPUT:
|
|
574
|
+
|
|
575
|
+
- ``toks`` -- list of tokens; each token is atomic
|
|
576
|
+
|
|
577
|
+
- ``n`` -- integer (default: 0) representing which order of
|
|
578
|
+
operations are occurring
|
|
579
|
+
|
|
580
|
+
- ``polish`` -- boolean (default: ``False``); when ``True``, double
|
|
581
|
+
negations are not cancelled and negated statements are turned into
|
|
582
|
+
list of length two
|
|
583
|
+
|
|
584
|
+
OUTPUT: the parse tree as a nested list that depends on ``polish`` as follows:
|
|
585
|
+
|
|
586
|
+
- If ``False``, then return a simplified parse tree.
|
|
587
|
+
|
|
588
|
+
- If ``True``, then return the full syntax parse tree.
|
|
589
|
+
|
|
590
|
+
EXAMPLES:
|
|
591
|
+
|
|
592
|
+
This example illustrates the use of
|
|
593
|
+
:func:`~sage.logic.logicparser.parse_ltor()` when ``polish`` is ``False``::
|
|
594
|
+
|
|
595
|
+
sage: import sage.logic.logicparser as logicparser
|
|
596
|
+
sage: t = ['a', '|', 'b', '&', 'c']
|
|
597
|
+
sage: logicparser.parse_ltor(t)
|
|
598
|
+
['|', 'a', ['&', 'b', 'c']]
|
|
599
|
+
|
|
600
|
+
::
|
|
601
|
+
|
|
602
|
+
sage: import sage.logic.logicparser as logicparser
|
|
603
|
+
sage: t = ['a', '->', '~', '~', 'b']
|
|
604
|
+
sage: logicparser.parse_ltor(t)
|
|
605
|
+
['->', 'a', 'b']
|
|
606
|
+
|
|
607
|
+
We now repeat the previous example, but with ``polish`` being ``True``::
|
|
608
|
+
|
|
609
|
+
sage: import sage.logic.logicparser as logicparser
|
|
610
|
+
sage: t = ['a', '->', '~', '~', 'b']
|
|
611
|
+
sage: logicparser.parse_ltor(t, polish = True)
|
|
612
|
+
['->', 'a', ['~', ['~', 'b']]]
|
|
613
|
+
"""
|
|
614
|
+
i = 0
|
|
615
|
+
for tok in toks:
|
|
616
|
+
if tok == __op_list[n]:
|
|
617
|
+
if tok == '~':
|
|
618
|
+
if not polish:
|
|
619
|
+
# cancel double negations
|
|
620
|
+
if toks[i] == '~' and toks[i + 1] == '~':
|
|
621
|
+
del toks[i]
|
|
622
|
+
del toks[i]
|
|
623
|
+
return parse_ltor(toks, n)
|
|
624
|
+
args = [toks[i], toks[i + 1], None]
|
|
625
|
+
toks[i] = args
|
|
626
|
+
del toks[i + 1]
|
|
627
|
+
return parse_ltor(toks, n)
|
|
628
|
+
# This executes when creating the full syntax parse tree
|
|
629
|
+
else:
|
|
630
|
+
j = i
|
|
631
|
+
while toks[j] == '~':
|
|
632
|
+
j += 1
|
|
633
|
+
while j > i:
|
|
634
|
+
args = [toks[j - 1], toks[j]]
|
|
635
|
+
toks[j - 1] = args
|
|
636
|
+
del toks[j]
|
|
637
|
+
j -= 1
|
|
638
|
+
return parse_ltor(toks, n=n, polish=polish)
|
|
639
|
+
else:
|
|
640
|
+
args = [toks[i - 1], toks[i], toks[i + 1]]
|
|
641
|
+
toks[i - 1] = [args[1], args[0], args[2]]
|
|
642
|
+
del toks[i]
|
|
643
|
+
del toks[i]
|
|
644
|
+
return parse_ltor(toks, n)
|
|
645
|
+
i += 1
|
|
646
|
+
if n + 1 < len(__op_list):
|
|
647
|
+
return parse_ltor(toks, n + 1)
|
|
648
|
+
if len(toks) > 1:
|
|
649
|
+
raise SyntaxError
|
|
650
|
+
return toks[0]
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
def apply_func(tree, func):
|
|
654
|
+
r"""
|
|
655
|
+
Apply ``func`` to each node of ``tree``, and return a new parse tree.
|
|
656
|
+
|
|
657
|
+
INPUT:
|
|
658
|
+
|
|
659
|
+
- ``tree`` -- a parse tree of a boolean formula
|
|
660
|
+
|
|
661
|
+
- ``func`` -- a function to be applied to each node of tree; this may
|
|
662
|
+
be a function that comes from elsewhere in the logic module
|
|
663
|
+
|
|
664
|
+
OUTPUT: the new parse tree in the form of a nested list
|
|
665
|
+
|
|
666
|
+
EXAMPLES:
|
|
667
|
+
|
|
668
|
+
This example uses :func:`~sage.logic.logicparser.apply_func()` where
|
|
669
|
+
``func`` switches two entries of tree::
|
|
670
|
+
|
|
671
|
+
sage: import sage.logic.logicparser as logicparser
|
|
672
|
+
sage: t = ['|', ['&', 'a', 'b'], ['&', 'a', 'c']]
|
|
673
|
+
sage: f = lambda t: [t[0], t[2], t[1]]
|
|
674
|
+
sage: logicparser.apply_func(t, f)
|
|
675
|
+
['|', ['&', 'c', 'a'], ['&', 'b', 'a']]
|
|
676
|
+
"""
|
|
677
|
+
# used when full syntax parse tree is passed as argument
|
|
678
|
+
if len(tree) == 1:
|
|
679
|
+
return func(tree)
|
|
680
|
+
# used when full syntax parse tree is passed as argument
|
|
681
|
+
elif len(tree) == 2:
|
|
682
|
+
rval = apply_func(tree[1], func)
|
|
683
|
+
return func([tree[0], rval])
|
|
684
|
+
elif isinstance(tree[1], list) and isinstance(tree[2], list):
|
|
685
|
+
lval = apply_func(tree[1], func)
|
|
686
|
+
rval = apply_func(tree[2], func)
|
|
687
|
+
elif isinstance(tree[1], list):
|
|
688
|
+
lval = apply_func(tree[1], func)
|
|
689
|
+
rval = tree[2]
|
|
690
|
+
elif isinstance(tree[2], list):
|
|
691
|
+
lval = tree[1]
|
|
692
|
+
rval = apply_func(tree[2], func)
|
|
693
|
+
else:
|
|
694
|
+
lval = tree[1]
|
|
695
|
+
rval = tree[2]
|
|
696
|
+
return func([tree[0], lval, rval])
|