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.
Files changed (83) hide show
  1. passagemath_standard_no_symbolics/__init__.py +1 -0
  2. passagemath_standard_no_symbolics-10.6.45.data/scripts/sage-grep +5 -0
  3. passagemath_standard_no_symbolics-10.6.45.data/scripts/sage-grepdoc +5 -0
  4. passagemath_standard_no_symbolics-10.6.45.data/scripts/sage-list-packages +103 -0
  5. passagemath_standard_no_symbolics-10.6.45.dist-info/METADATA +150 -0
  6. passagemath_standard_no_symbolics-10.6.45.dist-info/RECORD +83 -0
  7. passagemath_standard_no_symbolics-10.6.45.dist-info/WHEEL +6 -0
  8. passagemath_standard_no_symbolics-10.6.45.dist-info/top_level.txt +2 -0
  9. sage/all.py +207 -0
  10. sage/all_cmdline.py +36 -0
  11. sage/cli/__init__.py +61 -0
  12. sage/cli/__main__.py +5 -0
  13. sage/cli/eval_cmd.py +45 -0
  14. sage/cli/eval_cmd_test.py +25 -0
  15. sage/cli/interactive_shell_cmd.py +28 -0
  16. sage/cli/notebook_cmd.py +51 -0
  17. sage/cli/notebook_cmd_test.py +39 -0
  18. sage/cli/options.py +26 -0
  19. sage/cli/run_file_cmd.py +50 -0
  20. sage/cli/version_cmd.py +26 -0
  21. sage/databases/all.py +83 -0
  22. sage/databases/cubic_hecke_db.py +1527 -0
  23. sage/dynamics/all.py +31 -0
  24. sage/dynamics/surface_dynamics_deprecation.py +32 -0
  25. sage/ext_data/kenzo/CP2.txt +45 -0
  26. sage/ext_data/kenzo/CP3.txt +349 -0
  27. sage/ext_data/kenzo/CP4.txt +4774 -0
  28. sage/ext_data/kenzo/README.txt +49 -0
  29. sage/ext_data/kenzo/S4.txt +20 -0
  30. sage/ext_data/mwrank/PRIMES +1 -0
  31. sage/ext_data/nbconvert/postprocess.py +48 -0
  32. sage/ext_data/nbconvert/rst_sage.tpl +99 -0
  33. sage/ext_data/nodoctest +0 -0
  34. sage/ext_data/notebook-ipython/kernel.json.in +11 -0
  35. sage/ext_data/notebook-ipython/logo-64x64.png +0 -0
  36. sage/ext_data/notebook-ipython/logo.svg +352 -0
  37. sage/ext_data/valgrind/pyalloc.supp +58 -0
  38. sage/ext_data/valgrind/sage-additional.supp +417 -0
  39. sage/ext_data/valgrind/sage.supp +43 -0
  40. sage/ext_data/valgrind/valgrind-python.supp +480 -0
  41. sage/geometry/all.py +12 -0
  42. sage/groups/matrix_gps/pickling_overrides.py +110 -0
  43. sage/homology/tests.py +66 -0
  44. sage/interacts/algebra.py +20 -0
  45. sage/interacts/all.py +25 -0
  46. sage/interacts/calculus.py +24 -0
  47. sage/interacts/fractals.py +18 -0
  48. sage/interacts/geometry.py +19 -0
  49. sage/interacts/library.py +1950 -0
  50. sage/interacts/library_cython.cpython-313-darwin.so +0 -0
  51. sage/interacts/statistics.py +19 -0
  52. sage/interfaces/axiom.py +1002 -0
  53. sage/interfaces/kash.py +834 -0
  54. sage/interfaces/lie.py +950 -0
  55. sage/interfaces/matlab.py +413 -0
  56. sage/interfaces/mupad.py +686 -0
  57. sage/interfaces/octave.py +858 -0
  58. sage/interfaces/phc.py +943 -0
  59. sage/interfaces/psage.py +189 -0
  60. sage/interfaces/qsieve.py +4 -0
  61. sage/interfaces/r.py +2096 -0
  62. sage/interfaces/read_data.py +46 -0
  63. sage/interfaces/scilab.py +576 -0
  64. sage/interfaces/tests.py +81 -0
  65. sage/libs/all.py +11 -0
  66. sage/libs/cremona/__init__.py +0 -0
  67. sage/libs/mwrank/__init__.py +0 -0
  68. sage/logic/all.py +3 -0
  69. sage/logic/booleval.py +160 -0
  70. sage/logic/boolformula.py +1490 -0
  71. sage/logic/logic.py +856 -0
  72. sage/logic/logicparser.py +696 -0
  73. sage/logic/logictable.py +272 -0
  74. sage/logic/propcalc.py +311 -0
  75. sage/misc/all.py +28 -0
  76. sage/misc/lazy_attribute.pyi +11 -0
  77. sage/rings/all.py +48 -0
  78. sage/rings/commutative_algebra.py +38 -0
  79. sage/rings/finite_rings/all.py +21 -0
  80. sage/rings/numbers_abc.py +58 -0
  81. sage/rings/polynomial/all.py +22 -0
  82. sage/rings/polynomial/convolution.py +421 -0
  83. sage/symbolic/all__sagemath_standard_no_symbolics.py +0 -0
@@ -0,0 +1,1490 @@
1
+ r"""
2
+ Boolean Formulas
3
+
4
+ Formulas consist of the operators ``&``, ``|``, ``~``, ``^``, ``->``, ``<->``,
5
+ corresponding to ``and``, ``or``, ``not``, ``xor``, ``if...then``, ``if and
6
+ only if``. Operators can be applied to variables that consist of a leading
7
+ letter and trailing underscores and alphanumerics. Parentheses may be used
8
+ to explicitly show order of operation.
9
+
10
+ EXAMPLES:
11
+
12
+ Create boolean formulas and combine them with
13
+ :meth:`~sage.logic.boolformula.BooleanFormula.ifthen()` method::
14
+
15
+ sage: import sage.logic.propcalc as propcalc
16
+ sage: f = propcalc.formula("a&((b|c)^a->c)<->b")
17
+ sage: g = propcalc.formula("boolean<->algebra")
18
+ sage: (f&~g).ifthen(f)
19
+ ((a&((b|c)^a->c)<->b)&(~(boolean<->algebra)))->(a&((b|c)^a->c)<->b)
20
+
21
+ We can create a truth table from a formula::
22
+
23
+ sage: f.truthtable()
24
+ a b c value
25
+ False False False True
26
+ False False True True
27
+ False True False False
28
+ False True True False
29
+ True False False True
30
+ True False True False
31
+ True True False True
32
+ True True True True
33
+ sage: f.truthtable(end=3)
34
+ a b c value
35
+ False False False True
36
+ False False True True
37
+ False True False False
38
+ sage: f.truthtable(start=4)
39
+ a b c value
40
+ True False False True
41
+ True False True False
42
+ True True False True
43
+ True True True True
44
+ sage: propcalc.formula("a").truthtable()
45
+ a value
46
+ False False
47
+ True True
48
+
49
+ Now we can evaluate the formula for a given set of inputs::
50
+
51
+ sage: f.evaluate({'a':True, 'b':False, 'c':True})
52
+ False
53
+ sage: f.evaluate({'a':False, 'b':False, 'c':True})
54
+ True
55
+
56
+ And we can convert a boolean formula to conjunctive normal form::
57
+
58
+ sage: f.convert_cnf_table()
59
+ sage: f
60
+ (a|~b|c)&(a|~b|~c)&(~a|b|~c)
61
+ sage: f.convert_cnf_recur()
62
+ sage: f
63
+ (a|~b|c)&(a|~b|~c)&(~a|b|~c)
64
+
65
+ Or determine if an expression is satisfiable, a contradiction, or a tautology::
66
+
67
+ sage: f = propcalc.formula("a|b")
68
+ sage: f.is_satisfiable()
69
+ True
70
+ sage: f = f & ~f
71
+ sage: f.is_satisfiable()
72
+ False
73
+ sage: f.is_contradiction()
74
+ True
75
+ sage: f = f | ~f
76
+ sage: f.is_tautology()
77
+ True
78
+
79
+ The equality operator compares semantic equivalence::
80
+
81
+ sage: f = propcalc.formula("(a|b)&c")
82
+ sage: g = propcalc.formula("c&(b|a)")
83
+ sage: f == g
84
+ True
85
+ sage: g = propcalc.formula("a|b&c")
86
+ sage: f == g
87
+ False
88
+
89
+ It is an error to create a formula with bad syntax::
90
+
91
+ sage: propcalc.formula("")
92
+ Traceback (most recent call last):
93
+ ...
94
+ SyntaxError: malformed statement
95
+ sage: propcalc.formula("a&b~(c|(d)")
96
+ Traceback (most recent call last):
97
+ ...
98
+ SyntaxError: malformed statement
99
+ sage: propcalc.formula("a&&b")
100
+ Traceback (most recent call last):
101
+ ...
102
+ SyntaxError: malformed statement
103
+ sage: propcalc.formula("a&b a")
104
+ Traceback (most recent call last):
105
+ ...
106
+ SyntaxError: malformed statement
107
+
108
+ It is also an error to not abide by the naming conventions::
109
+
110
+ sage: propcalc.formula("~a&9b")
111
+ Traceback (most recent call last):
112
+ ...
113
+ NameError: invalid variable name 9b: identifiers must begin with a letter and contain only alphanumerics and underscores
114
+
115
+ AUTHORS:
116
+
117
+ - Chris Gorecki (2006): initial version
118
+
119
+ - Paul Scurek (2013-08-03): added polish_notation, full_tree,
120
+ updated docstring formatting
121
+
122
+ - Paul Scurek (2013-08-08): added
123
+ :meth:`~sage.logic.boolformula.BooleanFormula.implies()`
124
+ """
125
+ # *****************************************************************************
126
+ # Copyright (C) 2006 William Stein <wstein.gmail.com>
127
+ # Copyright (C) 2006 Chris Gorecki <chris.k.gorecki@gmail.com>
128
+ # Copyright (C) 2013 Paul Scurek <scurek86@gmail.com>
129
+ #
130
+ # Distributed under the terms of the GNU General Public License (GPL)
131
+ # as published by the Free Software Foundation; either version 2 of
132
+ # the License, or (at your option) any later version.
133
+ # https://www.gnu.org/licenses/
134
+ # *****************************************************************************
135
+
136
+ from . import booleval
137
+ from . import logictable
138
+ from . import logicparser
139
+ # import boolopt
140
+ from sage.misc.flatten import flatten
141
+
142
+ latex_operators = [('&', '\\wedge '),
143
+ ('|', '\\vee '),
144
+ ('~', '\\neg '),
145
+ ('^', '\\oplus '),
146
+ ('<->', '\\leftrightarrow '),
147
+ ('->', '\\rightarrow ')]
148
+
149
+
150
+ class BooleanFormula:
151
+ """
152
+ Boolean formulas.
153
+
154
+ INPUT:
155
+
156
+ - ``self`` -- calling object
157
+
158
+ - ``exp`` -- string; this contains the boolean expression
159
+ to be manipulated
160
+
161
+ - ``tree`` -- list; this contains the parse tree of the expression
162
+
163
+ - ``vo`` -- list; this contains the variables in the expression, in the
164
+ order that they appear; each variable only occurs once in the list
165
+ """
166
+ __expression = ""
167
+ __tree = []
168
+ __vars_order = []
169
+
170
+ def __init__(self, exp, tree, vo):
171
+ r"""
172
+ Initialize the data fields.
173
+
174
+ EXAMPLES:
175
+
176
+ This example illustrates the creation of a statement::
177
+
178
+ sage: import sage.logic.propcalc as propcalc
179
+ sage: s = propcalc.formula("a&b|~(c|a)")
180
+ sage: s
181
+ a&b|~(c|a)
182
+ """
183
+ self.__expression = exp.replace(' ', '')
184
+ self.__tree = tree
185
+ self.__vars_order = vo
186
+
187
+ def __repr__(self):
188
+ r"""
189
+ Return a string representation of this statement.
190
+
191
+ EXAMPLES::
192
+
193
+ sage: import sage.logic.propcalc as propcalc
194
+ sage: propcalc.formula("man->monkey&human")
195
+ man->monkey&human
196
+ """
197
+ return self.__expression
198
+
199
+ def _latex_(self):
200
+ r"""
201
+ Return a LaTeX representation of this statement.
202
+
203
+ OUTPUT: string containing the latex code for the statement
204
+
205
+ EXAMPLES::
206
+
207
+ sage: import sage.logic.propcalc as propcalc
208
+ sage: s = propcalc.formula("man->monkey&human")
209
+ sage: latex(s)
210
+ man\rightarrow monkey\wedge human
211
+
212
+ sage: f = propcalc.formula("a & ((~b | c) ^ a -> c) <-> ~b")
213
+ sage: latex(f)
214
+ a\wedge ((\neg b\vee c)\oplus a\rightarrow c)\leftrightarrow \neg b
215
+ """
216
+ latex_expression = self.__expression
217
+ for old, new in latex_operators:
218
+ latex_expression = latex_expression.replace(old, new)
219
+ return latex_expression
220
+
221
+ def polish_notation(self):
222
+ r"""
223
+ Convert the calling boolean formula into polish notation.
224
+
225
+ OUTPUT: string representation of the formula in polish notation
226
+
227
+ EXAMPLES:
228
+
229
+ This example illustrates converting a formula to polish notation::
230
+
231
+ sage: import sage.logic.propcalc as propcalc
232
+ sage: f = propcalc.formula("~~a|(c->b)")
233
+ sage: f.polish_notation()
234
+ '|~~a->cb'
235
+
236
+ sage: g = propcalc.formula("(a|~b)->c")
237
+ sage: g.polish_notation()
238
+ '->|a~bc'
239
+
240
+ AUTHORS:
241
+
242
+ - Paul Scurek (2013-08-03)
243
+ """
244
+ return ''.join(flatten(logicparser.polish_parse(repr(self))))
245
+
246
+ def tree(self):
247
+ r"""
248
+ Return the parse tree of this boolean expression.
249
+
250
+ OUTPUT: the parse tree as a nested list
251
+
252
+ EXAMPLES:
253
+
254
+ This example illustrates how to find the parse tree of a boolean
255
+ formula::
256
+
257
+ sage: import sage.logic.propcalc as propcalc
258
+ sage: s = propcalc.formula("man -> monkey & human")
259
+ sage: s.tree()
260
+ ['->', 'man', ['&', 'monkey', 'human']]
261
+
262
+ ::
263
+
264
+ sage: f = propcalc.formula("a & ((~b | c) ^ a -> c) <-> ~b")
265
+ sage: f.tree()
266
+ ['<->',
267
+ ['&', 'a', ['->', ['^', ['|', ['~', 'b', None], 'c'], 'a'], 'c']],
268
+ ['~', 'b', None]]
269
+
270
+ .. NOTE::
271
+
272
+ This function is used by other functions in the logic module
273
+ that perform semantic operations on a boolean formula.
274
+ """
275
+ return self.__tree
276
+
277
+ def full_tree(self):
278
+ r"""
279
+ Return a full syntax parse tree of the calling formula.
280
+
281
+ OUTPUT: the full syntax parse tree as a nested list
282
+
283
+ EXAMPLES:
284
+
285
+ This example shows how to find the full syntax parse tree
286
+ of a formula::
287
+
288
+ sage: import sage.logic.propcalc as propcalc
289
+ sage: s = propcalc.formula("a->(b&c)")
290
+ sage: s.full_tree()
291
+ ['->', 'a', ['&', 'b', 'c']]
292
+
293
+ sage: t = propcalc.formula("a & ((~b | c) ^ a -> c) <-> ~b")
294
+ sage: t.full_tree()
295
+ ['<->', ['&', 'a', ['->', ['^', ['|', ['~', 'b'], 'c'], 'a'], 'c']], ['~', 'b']]
296
+
297
+ sage: f = propcalc.formula("~~(a&~b)")
298
+ sage: f.full_tree()
299
+ ['~', ['~', ['&', 'a', ['~', 'b']]]]
300
+
301
+ .. NOTE::
302
+
303
+ This function is used by other functions in the logic module
304
+ that perform syntactic operations on a boolean formula.
305
+
306
+ AUTHORS:
307
+
308
+ - Paul Scurek (2013-08-03)
309
+ """
310
+ return logicparser.polish_parse(repr(self))
311
+
312
+ def __or__(self, other):
313
+ r"""
314
+ Overload the ``|`` operator to 'or' two statements together.
315
+
316
+ INPUT:
317
+
318
+ - ``other`` -- boolean formula; this is the statement
319
+ on the right side of the operator
320
+
321
+ OUTPUT:
322
+
323
+ A boolean formula of the form ``self | other``.
324
+
325
+ EXAMPLES:
326
+
327
+ This example illustrates combining two formulas with ``|``::
328
+
329
+ sage: import sage.logic.propcalc as propcalc
330
+ sage: s = propcalc.formula("a&b")
331
+ sage: f = propcalc.formula("c^d")
332
+ sage: s | f
333
+ (a&b)|(c^d)
334
+ """
335
+ return self.add_statement(other, '|')
336
+
337
+ def __and__(self, other):
338
+ r"""
339
+ Overload the ``&`` operator to 'and' two statements together.
340
+
341
+ INPUT:
342
+
343
+ - ``other`` -- boolean formula; this is the formula on
344
+ the right side of the operator
345
+
346
+ OUTPUT: a boolean formula of the form ``self & other``
347
+
348
+ EXAMPLES:
349
+
350
+ This example shows how to combine two formulas with ``&``::
351
+
352
+ sage: import sage.logic.propcalc as propcalc
353
+ sage: s = propcalc.formula("a&b")
354
+ sage: f = propcalc.formula("c^d")
355
+ sage: s & f
356
+ (a&b)&(c^d)
357
+ """
358
+ return self.add_statement(other, '&')
359
+
360
+ def __xor__(self, other):
361
+ r"""
362
+ Overload the ``^`` operator to 'xor' two statements together.
363
+
364
+ INPUT:
365
+
366
+ - ``other`` -- boolean formula; this is the formula on
367
+ the right side of the operator
368
+
369
+ OUTPUT: a boolean formula of the form ``self ^ other``
370
+
371
+ EXAMPLES:
372
+
373
+ This example illustrates how to combine two formulas with ``^``::
374
+
375
+ sage: import sage.logic.propcalc as propcalc
376
+ sage: s = propcalc.formula("a&b")
377
+ sage: f = propcalc.formula("c^d")
378
+ sage: s ^ f
379
+ (a&b)^(c^d)
380
+ """
381
+ return self.add_statement(other, '^')
382
+
383
+ def __pow__(self, other):
384
+ r"""
385
+ Overload the ``^`` operator to 'xor' two statements together.
386
+
387
+ INPUT:
388
+
389
+ - ``other`` -- boolean formula; this is the formula on
390
+ the right side of the operator
391
+
392
+ OUTPUT: a boolean formula of the form ``self ^ other``
393
+
394
+ EXAMPLES:
395
+
396
+ This example shows how to combine two formulas with ``^``::
397
+
398
+ sage: import sage.logic.propcalc as propcalc
399
+ sage: s = propcalc.formula("a&b")
400
+ sage: f = propcalc.formula("c^d")
401
+ sage: s ^ f
402
+ (a&b)^(c^d)
403
+
404
+ .. TODO::
405
+
406
+ This function seems to be identical to ``__xor__``.
407
+ Thus, this function should be replaced with ``__xor__`` everywhere
408
+ that it appears in the logic module. Then it can be deleted
409
+ altogether.
410
+ """
411
+ return self.add_statement(other, '^')
412
+
413
+ def __invert__(self):
414
+ r"""
415
+ Overload the ``~`` operator to 'not' a statement.
416
+
417
+ OUTPUT: a boolean formula of the form ``~self``
418
+
419
+ EXAMPLES:
420
+
421
+ This example shows how to negate a boolean formula::
422
+
423
+ sage: import sage.logic.propcalc as propcalc
424
+ sage: s = propcalc.formula("a&b")
425
+ sage: ~s
426
+ ~(a&b)
427
+ """
428
+ exp = '~(' + self.__expression + ')'
429
+ parse_tree, vars_order = logicparser.parse(exp)
430
+ return BooleanFormula(exp, parse_tree, vars_order)
431
+
432
+ def ifthen(self, other):
433
+ r"""
434
+ Combine two formulas with the ``->`` operator.
435
+
436
+ INPUT:
437
+
438
+ - ``other`` -- boolean formula; this is the formula
439
+ on the right side of the operator
440
+
441
+ OUTPUT:
442
+
443
+ A boolean formula of the form ``self -> other``.
444
+
445
+ EXAMPLES:
446
+
447
+ This example illustrates how to combine two formulas with '->'::
448
+
449
+ sage: import sage.logic.propcalc as propcalc
450
+ sage: s = propcalc.formula("a&b")
451
+ sage: f = propcalc.formula("c^d")
452
+ sage: s.ifthen(f)
453
+ (a&b)->(c^d)
454
+ """
455
+ return self.add_statement(other, '->')
456
+
457
+ def iff(self, other):
458
+ r"""
459
+ Combine two formulas with the ``<->`` operator.
460
+
461
+ INPUT:
462
+
463
+ - ``other`` -- boolean formula; this is the formula
464
+ on the right side of the operator
465
+
466
+ OUTPUT:
467
+
468
+ A boolean formula of the form ``self <-> other``.
469
+
470
+ EXAMPLES:
471
+
472
+ This example illustrates how to combine two formulas with '<->'::
473
+
474
+ sage: import sage.logic.propcalc as propcalc
475
+ sage: s = propcalc.formula("a&b")
476
+ sage: f = propcalc.formula("c^d")
477
+ sage: s.iff(f)
478
+ (a&b)<->(c^d)
479
+ """
480
+ return self.add_statement(other, '<->')
481
+
482
+ def __eq__(self, other):
483
+ r"""
484
+ Overload the ``==`` operator to determine logical equivalence.
485
+
486
+ INPUT:
487
+
488
+ - ``other`` -- boolean formula; this is the formula
489
+ on the right side of the comparator
490
+
491
+ OUTPUT: a boolean value to be determined as follows:
492
+
493
+ - ``True`` if ``self`` and ``other`` are logically equivalent
494
+
495
+ - ``False`` if ``self`` and ``other`` are not logically equivalent
496
+
497
+ EXAMPLES:
498
+
499
+ This example shows how to determine logical equivalence::
500
+
501
+ sage: import sage.logic.propcalc as propcalc
502
+ sage: f = propcalc.formula("(a|b)&c")
503
+ sage: g = propcalc.formula("c&(b|a)")
504
+ sage: f == g
505
+ True
506
+
507
+ ::
508
+
509
+ sage: g = propcalc.formula("a|b&c")
510
+ sage: f == g
511
+ False
512
+ """
513
+ return self.equivalent(other)
514
+
515
+ def truthtable(self, start=0, end=-1):
516
+ r"""
517
+ Return a truth table for the calling formula.
518
+
519
+ INPUT:
520
+
521
+ - ``start`` -- (default: 0) an integer; this is the first
522
+ row of the truth table to be created
523
+
524
+ - ``end`` -- (default: -1) an integer; this is the last
525
+ row of the truth table to be created
526
+
527
+ OUTPUT: the truth table as a 2-D array
528
+
529
+ EXAMPLES:
530
+
531
+ This example illustrates the creation of a truth table::
532
+
533
+ sage: import sage.logic.propcalc as propcalc
534
+ sage: s = propcalc.formula("a&b|~(c|a)")
535
+ sage: s.truthtable()
536
+ a b c value
537
+ False False False True
538
+ False False True False
539
+ False True False True
540
+ False True True False
541
+ True False False False
542
+ True False True False
543
+ True True False True
544
+ True True True True
545
+
546
+ We can now create a truthtable of rows 1 to 4, inclusive::
547
+
548
+ sage: s.truthtable(1, 5)
549
+ a b c value
550
+ False False True False
551
+ False True False True
552
+ False True True False
553
+ True False False False
554
+
555
+ .. NOTE::
556
+
557
+ Each row of the table corresponds to a binary number, with
558
+ each variable associated to a column of the number, and taking on
559
+ a true value if that column has a value of 1. Please see the
560
+ logictable module for details. The function returns a table that
561
+ start inclusive and end exclusive so ``truthtable(0, 2)`` will
562
+ include row 0, but not row 2.
563
+
564
+ When sent with no start or end parameters, this is an
565
+ exponential time function requiring `O(2^n)` time, where
566
+ `n` is the number of variables in the expression.
567
+ """
568
+ maximum = 2 ** len(self.__vars_order)
569
+ if end < 0:
570
+ end = maximum
571
+ end = min(end, maximum)
572
+ start = max(start, 0)
573
+ start = min(start, maximum)
574
+ keys, table = [], []
575
+ vars = {}
576
+ for var in self.__vars_order:
577
+ vars[var] = False
578
+ keys.insert(0, var)
579
+ keys = list(keys)
580
+ for i in range(start, end):
581
+ j = 0
582
+ row = []
583
+ for key in keys:
584
+ bit = self.get_bit(i, j)
585
+ vars[key] = bit
586
+ j += 1
587
+ row.insert(0, bit)
588
+ row.append(booleval.eval_formula(self.__tree, vars))
589
+ table.append(row)
590
+ keys.reverse()
591
+ table = logictable.Truthtable(table, keys)
592
+ return table
593
+
594
+ def evaluate(self, var_values):
595
+ r"""
596
+ Evaluate a formula for the given input values.
597
+
598
+ INPUT:
599
+
600
+ - ``var_values`` -- dictionary; this contains the
601
+ pairs of variables and their boolean values
602
+
603
+ OUTPUT: the result of the evaluation as a boolean
604
+
605
+ EXAMPLES:
606
+
607
+ This example illustrates the evaluation of a boolean formula::
608
+
609
+ sage: import sage.logic.propcalc as propcalc
610
+ sage: f = propcalc.formula("a&b|c")
611
+ sage: f.evaluate({'a':False, 'b':False, 'c':True})
612
+ True
613
+ sage: f.evaluate({'a':True, 'b':False, 'c':False})
614
+ False
615
+ """
616
+ return booleval.eval_formula(self.__tree, var_values)
617
+
618
+ def is_satisfiable(self):
619
+ r"""
620
+ Determine if the formula is ``True`` for some assignment of values.
621
+
622
+ OUTPUT: a boolean value to be determined as follows:
623
+
624
+ - ``True`` if there is an assignment of values that makes the
625
+ formula ``True``.
626
+
627
+ - ``False`` if the formula cannot be made ``True`` by any assignment
628
+ of values.
629
+
630
+ EXAMPLES:
631
+
632
+ This example illustrates how to check a formula for satisfiability::
633
+
634
+ sage: import sage.logic.propcalc as propcalc
635
+ sage: f = propcalc.formula("a|b")
636
+ sage: f.is_satisfiable()
637
+ True
638
+
639
+ sage: g = f & (~f)
640
+ sage: g.is_satisfiable()
641
+ False
642
+ """
643
+ table = self.truthtable().get_table_list()
644
+ return any(row[-1] is True for row in table[1:])
645
+
646
+ def is_tautology(self):
647
+ r"""
648
+ Determine if the formula is always ``True``.
649
+
650
+ OUTPUT: a boolean value to be determined as follows:
651
+
652
+ - ``True`` if the formula is a tautology.
653
+
654
+ - ``False`` if the formula is not a tautology.
655
+
656
+ EXAMPLES:
657
+
658
+ This example illustrates how to check if a formula is a tautology::
659
+
660
+ sage: import sage.logic.propcalc as propcalc
661
+ sage: f = propcalc.formula("a|~a")
662
+ sage: f.is_tautology()
663
+ True
664
+
665
+ sage: f = propcalc.formula("a&~a")
666
+ sage: f.is_tautology()
667
+ False
668
+
669
+ sage: f = propcalc.formula("a&b")
670
+ sage: f.is_tautology()
671
+ False
672
+ """
673
+ return not (~self).is_satisfiable()
674
+
675
+ def is_contradiction(self):
676
+ r"""
677
+ Determine if the formula is always ``False``.
678
+
679
+ OUTPUT: a boolean value to be determined as follows:
680
+
681
+ - ``True`` if the formula is a contradiction.
682
+
683
+ - ``False`` if the formula is not a contradiction.
684
+
685
+ EXAMPLES:
686
+
687
+ This example illustrates how to check if a formula is a contradiction.
688
+
689
+ ::
690
+
691
+ sage: import sage.logic.propcalc as propcalc
692
+ sage: f = propcalc.formula("a&~a")
693
+ sage: f.is_contradiction()
694
+ True
695
+
696
+ sage: f = propcalc.formula("a|~a")
697
+ sage: f.is_contradiction()
698
+ False
699
+
700
+ sage: f = propcalc.formula("a|b")
701
+ sage: f.is_contradiction()
702
+ False
703
+ """
704
+ return not self.is_satisfiable()
705
+
706
+ def is_consequence(self, *hypotheses):
707
+ r"""
708
+ Determine if ``self`` (the desired conclusion) is a logical consequence of the
709
+ hypotheses. The function call ``is_consequence(conclusion, *hypotheses)`` is a
710
+ synonym for ``conclusion.is_consequence(*hypotheses)``.
711
+
712
+ INPUT:
713
+
714
+ - ``*hypotheses`` -- instances of :class:`BooleanFormula`
715
+
716
+ OUTPUT: a boolean value to be determined as follows:
717
+
718
+ - ``True`` -- if ``self`` (the desired conclusion) is a logical consequence
719
+ of the set of hypotheses
720
+
721
+ - ``False`` -- if ``self`` (the desired conclusion) is not a logical consequence
722
+ of the set of hypotheses
723
+
724
+ EXAMPLES::
725
+
726
+ sage: from sage.logic.propcalc import formula
727
+ sage: formula("a | b").is_consequence(formula("b"))
728
+ True
729
+ sage: formula("a & b").is_consequence(formula("b"))
730
+ False
731
+ sage: formula("b").is_consequence(formula("a"), formula("a -> b"))
732
+ True
733
+ sage: formula("b -> a").is_consequence(formula("a -> b"))
734
+ False
735
+ sage: formula("~b -> ~a").is_consequence(formula("a -> b"))
736
+ True
737
+
738
+ ::
739
+
740
+ sage: f, g, h = propcalc.get_formulas("a & ~b", "c -> b", "c | e")
741
+ sage: propcalc.formula("a & e").is_consequence(f, g, h)
742
+ True
743
+ sage: i = propcalc.formula("a & ~e")
744
+ sage: i.is_consequence(f, g, h)
745
+ False
746
+ sage: from sage.logic.boolformula import is_consequence
747
+ sage: is_consequence(i, f, g, h)
748
+ False
749
+ sage: is_consequence(propcalc.formula("((p <-> q) & r) -> ~c"), f, g, h)
750
+ True
751
+
752
+ Only a tautology is a logical consequence of an empty set of formulas::
753
+
754
+ sage: propcalc.formula("a | ~a").is_consequence()
755
+ True
756
+ sage: propcalc.formula("a | b").is_consequence()
757
+ False
758
+
759
+ TESTS:
760
+
761
+ Arguments must be instances of :class:`BooleanFormula` (not strings, for example)::
762
+
763
+ sage: propcalc.formula("a | b").is_consequence("a | b")
764
+ Traceback (most recent call last):
765
+ ...
766
+ TypeError: is_consequence only takes instances of BooleanFormula() class as input
767
+
768
+ AUTHORS:
769
+
770
+ - Paul Scurek (2013-08-12)
771
+ """
772
+ # make sure every argument is an instance of :class:`BooleanFormula`
773
+ for formula in (self,) + hypotheses:
774
+ if not isinstance(formula, BooleanFormula):
775
+ raise TypeError("is_consequence only takes instances of BooleanFormula() class as input")
776
+
777
+ if not hypotheses:
778
+ # if there are no hypotheses, then we just want to know whether self is a tautology
779
+ return self.is_tautology()
780
+ else:
781
+ # conjoin all of the hypotheses into a single Boolean formula
782
+ conjunction = hypotheses[0]
783
+ for hypothesis in hypotheses[1:]:
784
+ conjunction = conjunction & hypothesis
785
+
786
+ return conjunction.implies(self)
787
+
788
+ def implies(self, other):
789
+ r"""
790
+ Determine if calling formula implies other formula.
791
+
792
+ INPUT:
793
+
794
+ - ``self`` -- calling object
795
+
796
+ - ``other`` -- instance of :class:`BooleanFormula`
797
+
798
+ OUTPUT: a boolean value to be determined as follows:
799
+
800
+ - ``True`` -- if ``self`` implies ``other``
801
+
802
+ - ``False`` -- if ``self does not imply ``other``
803
+
804
+ EXAMPLES:
805
+
806
+ This example illustrates determining if one formula implies another::
807
+
808
+ sage: import sage.logic.propcalc as propcalc
809
+ sage: f = propcalc.formula("a<->b")
810
+ sage: g = propcalc.formula("b->a")
811
+ sage: f.implies(g)
812
+ True
813
+
814
+ ::
815
+
816
+ sage: h = propcalc.formula("a->(a|~b)")
817
+ sage: i = propcalc.formula("a")
818
+ sage: h.implies(i)
819
+ False
820
+
821
+ AUTHORS:
822
+
823
+ - Paul Scurek (2013-08-08)
824
+ """
825
+ # input validation
826
+ if not isinstance(other, BooleanFormula):
827
+ raise TypeError("implies() takes an instance of the BooleanFormula() class as input")
828
+
829
+ conditional = self.ifthen(other)
830
+ return (conditional).is_tautology()
831
+
832
+ def equivalent(self, other):
833
+ r"""
834
+ Determine if two formulas are semantically equivalent.
835
+
836
+ INPUT:
837
+
838
+ - ``self`` -- calling object
839
+
840
+ - ``other`` -- instance of BooleanFormula class
841
+
842
+ OUTPUT: a boolean value to be determined as follows:
843
+
844
+ ``True`` -- if the two formulas are logically equivalent
845
+
846
+ ``False`` -- if the two formulas are not logically equivalent
847
+
848
+ EXAMPLES:
849
+
850
+ This example shows how to check for logical equivalence::
851
+
852
+ sage: import sage.logic.propcalc as propcalc
853
+ sage: f = propcalc.formula("(a|b)&c")
854
+ sage: g = propcalc.formula("c&(a|b)")
855
+ sage: f.equivalent(g)
856
+ True
857
+
858
+ sage: g = propcalc.formula("a|b&c")
859
+ sage: f.equivalent(g)
860
+ False
861
+ """
862
+ return self.iff(other).is_tautology()
863
+
864
+ def convert_cnf_table(self):
865
+ r"""
866
+ Convert boolean formula to conjunctive normal form.
867
+
868
+ OUTPUT: an instance of :class:`BooleanFormula` in conjunctive normal form
869
+
870
+ EXAMPLES:
871
+
872
+ This example illustrates how to convert a formula to cnf::
873
+
874
+ sage: import sage.logic.propcalc as propcalc
875
+ sage: s = propcalc.formula("a ^ b <-> c")
876
+ sage: s.convert_cnf()
877
+ sage: s
878
+ (a|b|~c)&(a|~b|c)&(~a|b|c)&(~a|~b|~c)
879
+
880
+ We now show that :meth:`convert_cnf` and :meth:`convert_cnf_table`
881
+ are aliases::
882
+
883
+ sage: t = propcalc.formula("a ^ b <-> c")
884
+ sage: t.convert_cnf_table(); t
885
+ (a|b|~c)&(a|~b|c)&(~a|b|c)&(~a|~b|~c)
886
+ sage: t == s
887
+ True
888
+
889
+ .. NOTE::
890
+
891
+ This method creates the cnf parse tree by examining the logic
892
+ table of the formula. Creating the table requires `O(2^n)` time
893
+ where `n` is the number of variables in the formula.
894
+ """
895
+ str = ''
896
+ t = self.truthtable()
897
+ table = t.get_table_list()
898
+ vars = table[0]
899
+ for row in table[1:]:
900
+ if row[-1] is False:
901
+ str += '('
902
+ for i in range(len(row) - 1):
903
+ if row[i] is True:
904
+ str += '~'
905
+ str += vars[i]
906
+ str += '|'
907
+ str = str[:-1] + ')&'
908
+ self.__expression = str[:-1]
909
+ # in case of tautology
910
+ if len(self.__expression) == 0:
911
+ self.__expression = '(' + self.__vars_order[0] + '|~' + self.__vars_order[0] + ')'
912
+ self.__tree, self.__vars_order = logicparser.parse(self.__expression)
913
+
914
+ convert_cnf = convert_cnf_table
915
+
916
+ def convert_cnf_recur(self):
917
+ r"""
918
+ Convert boolean formula to conjunctive normal form.
919
+
920
+ OUTPUT: an instance of :class:`BooleanFormula` in conjunctive normal form
921
+
922
+ EXAMPLES:
923
+
924
+ This example hows how to convert a formula to conjunctive normal form::
925
+
926
+ sage: import sage.logic.propcalc as propcalc
927
+ sage: s = propcalc.formula("a^b<->c")
928
+ sage: s.convert_cnf_recur()
929
+ sage: s
930
+ (~a|a|c)&(~b|a|c)&(~a|b|c)&(~b|b|c)&(~c|a|b)&(~c|~a|~b)
931
+
932
+ .. NOTE::
933
+
934
+ This function works by applying a set of rules that are
935
+ guaranteed to convert the formula. Worst case the converted
936
+ expression has an `O(2^n)` increase in size (and time as well), but
937
+ if the formula is already in CNF (or close to) it is only `O(n)`.
938
+
939
+ This function can require an exponential blow up in space from the
940
+ original expression. This in turn can require large amounts of
941
+ time. Unless a formula is already in (or close to) being in cnf
942
+ :meth:`convert_cnf()` is typically preferred, but results can vary.
943
+ """
944
+ self.__tree = logicparser.apply_func(self.__tree, self.reduce_op)
945
+ self.__tree = logicparser.apply_func(self.__tree, self.dist_not)
946
+ self.__tree = logicparser.apply_func(self.__tree, self.dist_ors)
947
+ self.convert_expression()
948
+
949
+ def satformat(self):
950
+ r"""
951
+ Return the satformat representation of a boolean formula.
952
+
953
+ OUTPUT: the satformat of the formula as a string
954
+
955
+ EXAMPLES:
956
+
957
+ This example illustrates how to find the satformat of a formula::
958
+
959
+ sage: import sage.logic.propcalc as propcalc
960
+ sage: f = propcalc.formula("a&((b|c)^a->c)<->b")
961
+ sage: f.convert_cnf()
962
+ sage: f
963
+ (a|~b|c)&(a|~b|~c)&(~a|b|~c)
964
+ sage: f.satformat()
965
+ 'p cnf 3 0\n1 -2 3 0 1 -2 -3 \n0 -1 2 -3'
966
+
967
+ .. NOTE::
968
+
969
+ See www.cs.ubc.ca/~hoos/SATLIB/Benchmarks/SAT/satformat.ps for a
970
+ description of satformat.
971
+
972
+ If the instance of boolean formula has not been converted to
973
+ CNF form by a call to :meth:`convert_cnf()` or
974
+ :meth:`convert_cnf_recur()`, then :meth:`satformat()` will call
975
+ :meth:`convert_cnf()`. Please see the notes for
976
+ :meth:`convert_cnf()` and :meth:`convert_cnf_recur()` for
977
+ performance issues.
978
+ """
979
+ self.convert_cnf_table()
980
+ s = ''
981
+ vars_num = {}
982
+ i = 0
983
+ clauses = 0
984
+ for e in self.__vars_order:
985
+ vars_num[e] = str(i + 1)
986
+ i += 1
987
+ i = 0
988
+ w = 1
989
+ while i < len(self.__expression):
990
+ c = self.__expression[i]
991
+ if c == ')':
992
+ clauses += 1
993
+ if c in '()|':
994
+ i += 1
995
+ continue
996
+ if c == '~':
997
+ s += '-'
998
+ elif c == '&':
999
+ s += '0 '
1000
+ else:
1001
+ varname = ''
1002
+ if self.__expression[i] not in '|) ':
1003
+ varname += self.__expression[i]
1004
+ i += 1
1005
+ s += vars_num[varname] + ' '
1006
+ if len(s) >= (w * 15) and s[-1] != '-':
1007
+ s += '\n'
1008
+ w += 1
1009
+ i += 1
1010
+ s = 'p cnf ' + str(len(self.__vars_order)) + ' ' + str(clauses) + '\n' + s
1011
+ return s[:-1]
1012
+
1013
+ # def simplify(self):
1014
+ # r"""
1015
+ # This function uses the propcalc package to simplify an expression to
1016
+ # its minimal form.
1017
+ #
1018
+ # OUTPUT: a simplified expression
1019
+ #
1020
+ # EXAMPLES::
1021
+
1022
+ # sage: import sage.logic.propcalc as propcalc
1023
+ # sage: f = propcalc.formula("a&((b|c)^a->c)<->b")
1024
+ # sage: f.truthtable()
1025
+ # a b c value
1026
+ # False False False True
1027
+ # False False True True
1028
+ # False True False False
1029
+ # False True True False
1030
+ # True False False True
1031
+ # True False True False
1032
+ # True True False True
1033
+ # True True True True
1034
+ # sage: f.simplify()
1035
+ # (~a&~b)|(a&~b&~c)|(a&b)
1036
+ # sage: f.truthtable()
1037
+ # a b c value
1038
+ # False False False True
1039
+ # False False True True
1040
+ # False True False False
1041
+ # False True True False
1042
+ # True False False True
1043
+ # True False True False
1044
+ # True True False True
1045
+ # True True True True
1046
+ #
1047
+ # .. NOTE::
1048
+ #
1049
+ # If the instance of boolean formula has not been converted to
1050
+ # cnf form by a call to convert_cnf() or convert_cnf_recur()
1051
+ # satformat() will call convert_cnf(). Please see the notes for
1052
+ # convert_cnf() and convert_cnf_recur() for performance issues.
1053
+ # """
1054
+ # exp = ''
1055
+ # self.__tree = logicparser.apply_func(self.__tree, self.reduce_op)
1056
+ # plf = logicparser.apply_func(self.__tree, self.convert_opt)
1057
+ # wff = boolopt.PLFtoWFF()(plf) # convert to positive-normal form
1058
+ # wtd = boolopt.WFFtoDNF()
1059
+ # dnf = wtd(wff)
1060
+ # dnf = wtd.clean(dnf)
1061
+ # if dnf == [] or dnf == [[]]:
1062
+ # exp = self.__vars_order[0] + '&~' + self.__vars_order[0] + ' '
1063
+ # opt = boolopt.optimize(dnf)
1064
+ # if exp == '' and (opt == [] or opt == [[]]):
1065
+ # exp = self.__vars_order[0] + '|~' + self.__vars_order[0] + ' '
1066
+ # if exp == '':
1067
+ # for con in opt:
1068
+ # s = '('
1069
+ # for prop in con:
1070
+ # if prop[0] == 'notprop':
1071
+ # s += '~'
1072
+ # s += prop[1] + '&'
1073
+ # exp += s[:-1] + ')|'
1074
+ # self.__expression = exp[:-1]
1075
+ # self.__tree, self.__vars_order = logicparser.parse(self.__expression)
1076
+ # return BooleanFormula(self.__expression, self.__tree, self.__vars_order)
1077
+
1078
+ def convert_opt(self, tree):
1079
+ r"""
1080
+ Convert a parse tree to the tuple form used by :meth:`bool_opt()`.
1081
+
1082
+ INPUT:
1083
+
1084
+ - ``tree`` -- list; this is a branch of a
1085
+ parse tree and can only contain the '&', '|'
1086
+ and '~' operators along with variables
1087
+
1088
+ OUTPUT: a 3-tuple
1089
+
1090
+ EXAMPLES:
1091
+
1092
+ This example illustrates the conversion of a formula into its
1093
+ corresponding tuple::
1094
+
1095
+ sage: import sage.logic.propcalc as propcalc, sage.logic.logicparser as logicparser
1096
+ sage: s = propcalc.formula("a&(b|~c)")
1097
+ sage: tree = ['&', 'a', ['|', 'b', ['~', 'c', None]]]
1098
+ sage: logicparser.apply_func(tree, s.convert_opt)
1099
+ ('and', ('prop', 'a'), ('or', ('prop', 'b'), ('not', ('prop', 'c'))))
1100
+
1101
+ .. NOTE::
1102
+
1103
+ This function only works on one branch of the parse tree. To
1104
+ apply the function to every branch of a parse tree, pass the
1105
+ function as an argument in
1106
+ :func:`~sage.logic.logicparser.apply_func()` in
1107
+ :mod:`~sage.logic.logicparser`.
1108
+ """
1109
+ if not isinstance(tree[1], tuple) and tree[1] is not None:
1110
+ lval = ('prop', tree[1])
1111
+ else:
1112
+ lval = tree[1]
1113
+ if not isinstance(tree[2], tuple) and tree[2] is not None:
1114
+ rval = ('prop', tree[2])
1115
+ else:
1116
+ rval = tree[2]
1117
+ if tree[0] == '~':
1118
+ return ('not', lval)
1119
+ if tree[0] == '&':
1120
+ op = 'and'
1121
+ if tree[0] == '|':
1122
+ op = 'or'
1123
+ return (op, lval, rval)
1124
+
1125
+ def add_statement(self, other, op):
1126
+ r"""
1127
+ Combine two formulas with the given operator.
1128
+
1129
+ INPUT:
1130
+
1131
+ - ``other`` -- instance of :class:`BooleanFormula`; this
1132
+ is the formula on the right of the operator
1133
+
1134
+ - ``op`` -- string; this is the operator used to
1135
+ combine the two formulas
1136
+
1137
+ OUTPUT: the result as an instance of :class:`BooleanFormula`
1138
+
1139
+ EXAMPLES:
1140
+
1141
+ This example shows how to create a new formula from two others::
1142
+
1143
+ sage: import sage.logic.propcalc as propcalc
1144
+ sage: s = propcalc.formula("a&b")
1145
+ sage: f = propcalc.formula("c^d")
1146
+ sage: s.add_statement(f, '|')
1147
+ (a&b)|(c^d)
1148
+
1149
+ sage: s.add_statement(f, '->')
1150
+ (a&b)->(c^d)
1151
+ """
1152
+ exp = '(' + self.__expression + ')' + op + '(' + other.__expression + ')'
1153
+ parse_tree, vars_order = logicparser.parse(exp)
1154
+ return BooleanFormula(exp, parse_tree, vars_order)
1155
+
1156
+ def get_bit(self, x, c):
1157
+ r"""
1158
+ Determine if bit ``c`` of the number ``x`` is 1.
1159
+
1160
+ INPUT:
1161
+
1162
+ - ``x`` -- integer; this is the number from
1163
+ which to take the bit
1164
+
1165
+ - ``c`` -- integer; this is the but number to
1166
+ be taken, where 0 is the low order bit
1167
+
1168
+ OUTPUT: a boolean to be determined as follows:
1169
+
1170
+ - ``True`` if bit ``c`` of ``x`` is 1.
1171
+
1172
+ - ``False`` if bit c of x is not 1.
1173
+
1174
+ EXAMPLES:
1175
+
1176
+ This example illustrates the use of :meth:`get_bit`::
1177
+
1178
+ sage: import sage.logic.propcalc as propcalc
1179
+ sage: s = propcalc.formula("a&b")
1180
+ sage: s.get_bit(2, 1)
1181
+ True
1182
+ sage: s.get_bit(8, 0)
1183
+ False
1184
+
1185
+ It is not an error to have a bit out of range::
1186
+
1187
+ sage: s.get_bit(64, 7)
1188
+ False
1189
+
1190
+ Nor is it an error to use a negative number::
1191
+
1192
+ sage: s.get_bit(-1, 3)
1193
+ False
1194
+ sage: s.get_bit(64, -1)
1195
+ True
1196
+ sage: s.get_bit(64, -2)
1197
+ False
1198
+
1199
+ .. NOTE::
1200
+
1201
+ The 0 bit is the low order bit. Errors should be handled
1202
+ gracefully by a return of ``False``, and negative numbers ``x``
1203
+ always return ``False`` while a negative ``c`` will index from the
1204
+ high order bit.
1205
+ """
1206
+ bits = []
1207
+ while x > 0:
1208
+ b = bool(x % 2)
1209
+ x = x // 2
1210
+ bits.append(b)
1211
+ if c > len(bits) - 1:
1212
+ return False
1213
+ else:
1214
+ return bits[c]
1215
+
1216
+ def reduce_op(self, tree):
1217
+ r"""
1218
+ Convert if-and-only-if, if-then, and xor operations to operations
1219
+ only involving and/or operations.
1220
+
1221
+ INPUT:
1222
+
1223
+ - ``tree`` -- list; this represents a branch
1224
+ of a parse tree
1225
+
1226
+ OUTPUT:
1227
+
1228
+ A new list with no '^', '->', or '<->' as first element of list.
1229
+
1230
+ EXAMPLES:
1231
+
1232
+ This example illustrates the use of :meth:`reduce_op` with
1233
+ :func:`apply_func`::
1234
+
1235
+ sage: import sage.logic.propcalc as propcalc, sage.logic.logicparser as logicparser
1236
+ sage: s = propcalc.formula("a->b^c")
1237
+ sage: tree = ['->', 'a', ['^', 'b', 'c']]
1238
+ sage: logicparser.apply_func(tree, s.reduce_op)
1239
+ ['|', ['~', 'a', None], ['&', ['|', 'b', 'c'], ['~', ['&', 'b', 'c'], None]]]
1240
+
1241
+ .. NOTE::
1242
+
1243
+ This function only operates on a single branch of a parse tree.
1244
+ To apply the function to an entire parse tree, pass the function
1245
+ as an argument to :func:`~sage.logic.logicparser.apply_func()`
1246
+ in :mod:`~sage.logic.logicparser`.
1247
+ """
1248
+ if tree[0] == '<->':
1249
+ # parse tree for (~tree[1]|tree[2])&(~tree[2]|tree[1])
1250
+ new_tree = ['&', ['|', ['~', tree[1], None], tree[2]],
1251
+ ['|', ['~', tree[2], None], tree[1]]]
1252
+ elif tree[0] == '^':
1253
+ # parse tree for (tree[1]|tree[2])&~(tree[1]&tree[2])
1254
+ new_tree = ['&', ['|', tree[1], tree[2]],
1255
+ ['~', ['&', tree[1], tree[2]], None]]
1256
+ elif tree[0] == '->':
1257
+ # parse tree for ~tree[1]|tree[2]
1258
+ new_tree = ['|', ['~', tree[1], None], tree[2]]
1259
+ else:
1260
+ new_tree = tree
1261
+ return new_tree
1262
+
1263
+ def dist_not(self, tree):
1264
+ r"""
1265
+ Distribute '~' operators over '&' and '|' operators.
1266
+
1267
+ INPUT:
1268
+
1269
+ - ``tree`` a list; this represents a branch
1270
+ of a parse tree
1271
+
1272
+ OUTPUT: a new list
1273
+
1274
+ EXAMPLES:
1275
+
1276
+ This example illustrates the distribution of '~' over '&'::
1277
+
1278
+ sage: import sage.logic.propcalc as propcalc, sage.logic.logicparser as logicparser
1279
+ sage: s = propcalc.formula("~(a&b)")
1280
+ sage: tree = ['~', ['&', 'a', 'b'], None]
1281
+ sage: logicparser.apply_func(tree, s.dist_not) #long time
1282
+ ['|', ['~', 'a', None], ['~', 'b', None]]
1283
+
1284
+ .. NOTE::
1285
+
1286
+ This function only operates on a single branch of a parse tree.
1287
+ To apply the function to an entire parse tree, pass the function
1288
+ as an argument to :func:`~sage.logic.logicparser.apply_func()`
1289
+ in :mod:`~sage.logic.logicparser`.
1290
+ """
1291
+ if tree[0] == '~' and isinstance(tree[1], list):
1292
+ op = tree[1][0]
1293
+ if op != '~':
1294
+ op = '|' if op == '&' else '&'
1295
+ new_tree = [op, ['~', tree[1][1], None], ['~', tree[1][2], None]]
1296
+ return logicparser.apply_func(new_tree, self.dist_not)
1297
+ else:
1298
+ # cancel double negative
1299
+ return tree[1][1]
1300
+ else:
1301
+ return tree
1302
+
1303
+ def dist_ors(self, tree):
1304
+ r"""
1305
+ Distribute '|' over '&'.
1306
+
1307
+ INPUT:
1308
+
1309
+ - ``tree`` -- list; this represents a branch of
1310
+ a parse tree
1311
+
1312
+ OUTPUT: a new list
1313
+
1314
+ EXAMPLES:
1315
+
1316
+ This example illustrates the distribution of '|' over '&'::
1317
+
1318
+ sage: import sage.logic.propcalc as propcalc, sage.logic.logicparser as logicparser
1319
+ sage: s = propcalc.formula("(a&b)|(a&c)")
1320
+ sage: tree = ['|', ['&', 'a', 'b'], ['&', 'a', 'c']]
1321
+ sage: logicparser.apply_func(tree, s.dist_ors) #long time
1322
+ ['&', ['&', ['|', 'a', 'a'], ['|', 'b', 'a']], ['&', ['|', 'a', 'c'], ['|', 'b', 'c']]]
1323
+
1324
+ .. NOTE::
1325
+
1326
+ This function only operates on a single branch of a parse tree.
1327
+ To apply the function to an entire parse tree, pass the function
1328
+ as an argument to :func:`~sage.logic.logicparser.apply_func()`
1329
+ in :mod:`~sage.logic.logicparser`.
1330
+ """
1331
+ if tree[0] == '|' and isinstance(tree[2], list) and tree[2][0] == '&':
1332
+ new_tree = ['&', ['|', tree[1], tree[2][1]],
1333
+ ['|', tree[1], tree[2][2]]]
1334
+ return logicparser.apply_func(new_tree, self.dist_ors)
1335
+ if tree[0] == '|' and isinstance(tree[1], list) and tree[1][0] == '&':
1336
+ new_tree = ['&', ['|', tree[1][1], tree[2]],
1337
+ ['|', tree[1][2], tree[2]]]
1338
+ return logicparser.apply_func(new_tree, self.dist_ors)
1339
+ return tree
1340
+
1341
+ def to_infix(self, tree):
1342
+ r"""
1343
+ Convert a parse tree from prefix to infix form.
1344
+
1345
+ INPUT:
1346
+
1347
+ - ``tree`` -- list; this represents a branch
1348
+ of a parse tree
1349
+
1350
+ OUTPUT: a new list
1351
+
1352
+ EXAMPLES:
1353
+
1354
+ This example shows how to convert a parse tree from prefix to
1355
+ infix form::
1356
+
1357
+ sage: import sage.logic.propcalc as propcalc, sage.logic.logicparser as logicparser
1358
+ sage: s = propcalc.formula("(a&b)|(a&c)")
1359
+ sage: tree = ['|', ['&', 'a', 'b'], ['&', 'a', 'c']]
1360
+ sage: logicparser.apply_func(tree, s.to_infix)
1361
+ [['a', '&', 'b'], '|', ['a', '&', 'c']]
1362
+
1363
+ .. NOTE::
1364
+
1365
+ This function only operates on a single branch of a parse tree.
1366
+ To apply the function to an entire parse tree, pass the function
1367
+ as an argument to :func:`~sage.logic.logicparser.apply_func()`
1368
+ in :mod:`~sage.logic.logicparser`.
1369
+ """
1370
+ if tree[0] != '~':
1371
+ return [tree[1], tree[0], tree[2]]
1372
+ return tree
1373
+
1374
+ def convert_expression(self):
1375
+ r"""
1376
+ Convert the string representation of a formula to conjunctive
1377
+ normal form.
1378
+
1379
+ EXAMPLES::
1380
+
1381
+ sage: import sage.logic.propcalc as propcalc
1382
+ sage: s = propcalc.formula("a^b<->c")
1383
+ sage: s.convert_expression(); s
1384
+ a^b<->c
1385
+ """
1386
+ ttree = self.__tree[:]
1387
+ ttree = logicparser.apply_func(ttree, self.to_infix)
1388
+ self.__expression = ''
1389
+ str_tree = str(ttree)
1390
+ open_flag = False
1391
+ i = 0
1392
+ for c in str_tree:
1393
+ if i < len(str_tree) - 1:
1394
+ op = self.get_next_op(str_tree[i:])
1395
+ if op == '|' and not open_flag:
1396
+ self.__expression += '('
1397
+ open_flag = True
1398
+ if i < len(str_tree) - 2 and str_tree[i + 1] == '&' and open_flag:
1399
+ open_flag = False
1400
+ self.__expression += ')'
1401
+ if str_tree[i:i + 4] == 'None':
1402
+ i += 4
1403
+ if i < len(str_tree) and str_tree[i] not in ' \',[]':
1404
+ self.__expression += str_tree[i]
1405
+ i += 1
1406
+ if open_flag is True:
1407
+ self.__expression += ')'
1408
+
1409
+ def get_next_op(self, str):
1410
+ r"""
1411
+ Return the next operator in a string.
1412
+
1413
+ INPUT:
1414
+
1415
+ - ``str`` -- string; this contains a logical
1416
+ expression
1417
+
1418
+ OUTPUT: the next operator as a string
1419
+
1420
+ EXAMPLES:
1421
+
1422
+ This example illustrates how to find the next operator in a formula::
1423
+
1424
+ sage: import sage.logic.propcalc as propcalc
1425
+ sage: s = propcalc.formula("f&p")
1426
+ sage: s.get_next_op("abra|cadabra")
1427
+ '|'
1428
+
1429
+ .. NOTE::
1430
+
1431
+ The parameter ``str`` is not necessarily the string
1432
+ representation of the calling object.
1433
+ """
1434
+ i = 0
1435
+ while i < len(str) - 1 and str[i] != '&' and str[i] != '|':
1436
+ i += 1
1437
+ return str[i]
1438
+
1439
+ def length(self):
1440
+ r"""
1441
+ Return the length of ``self``.
1442
+
1443
+ OUTPUT:
1444
+
1445
+ The length of the Boolean formula. This is the number of operators plus
1446
+ the number of variables (counting multiplicity). Parentheses are ignored.
1447
+
1448
+ EXAMPLES::
1449
+
1450
+ sage: import sage.logic.propcalc as propcalc
1451
+ sage: s = propcalc.formula("a")
1452
+ sage: s.length()
1453
+ 1
1454
+ sage: s = propcalc.formula("(a)")
1455
+ sage: s.length()
1456
+ 1
1457
+ sage: s = propcalc.formula("~a")
1458
+ sage: s.length()
1459
+ 2
1460
+ sage: s = propcalc.formula("a -> b")
1461
+ sage: s.length()
1462
+ 3
1463
+ sage: s = propcalc.formula("alpha -> beta")
1464
+ sage: s.length()
1465
+ 3
1466
+ sage: s = propcalc.formula("a -> a")
1467
+ sage: s.length()
1468
+ 3
1469
+ sage: s = propcalc.formula("~(a -> b)")
1470
+ sage: s.length()
1471
+ 4
1472
+ sage: s = propcalc.formula("((a&b)|(a&c))->~d")
1473
+ sage: s.length()
1474
+ 10
1475
+
1476
+ TESTS::
1477
+
1478
+ sage: s = propcalc.formula("(((alpha) -> ((beta))))")
1479
+ sage: s.length()
1480
+ 3
1481
+ """
1482
+ return len(flatten(self.full_tree()))
1483
+
1484
+ # For backward compatibility, we allow `self.length()` to be called as
1485
+ # `len(self)`, but this may be deprecated in the future (see :issue:`32148`):
1486
+ __len__ = length
1487
+
1488
+
1489
+ # allow is_consequence to be called as a function (not only as a method of BooleanFormula)
1490
+ is_consequence = BooleanFormula.is_consequence