Opened 12 months ago
Last modified 3 months ago
#31911 needs_work enhancement
Boolean symbolic expressions
Reported by:  mkoeppe  Owned by:  

Priority:  major  Milestone:  sage9.7 
Component:  symbolics  Keywords:  
Cc:  charpent, nbruin, egourgoulhon, chapoton, ghspaghettisalat, kcrisman  Merged in:  
Authors:  Matthias Koeppe  Reviewers:  
Report Upstream:  N/A  Work issues:  Parser: Use a make_... function instead of importing and_symbolic... 
Branch:  u/mkoeppe/boolean_symbolic_expressions (Commits, GitHub, GitLab)  Commit:  e9eac61a362a738322cbade296356c7d30b1bd7c 
Dependencies:  #32383  Stopgaps: 
Description (last modified by )
As proposed in https://groups.google.com/g/sagedevel/c/U_WGbYG2zOE/m/yqEDEXDAgAJ
We add symbolic functions and_symbolic
, or_symbolic
, not_symbolic
; the first two are also accessible by repurposing the operators bitwiseand &
and bitwiseor 
.
By extending the expression parser to also handle &
(equivalently, infix and
), 
(equivalently, infix or
), and ~
(equivalently, prefix not
), these constructions can also be obtained as a conversion from maxima
and giac
expression strings.
One application is for the coordinate restrictions of a Chart
.
Change History (92)
comment:1 Changed 12 months ago by
 Branch set to u/mkoeppe/boolean_symbolic_expressions
comment:2 followup: ↓ 4 Changed 12 months ago by
 Commit set to 863c636f52e73c08b3730a99ce7345cb694544da
comment:3 Changed 12 months ago by
 Cc egourgoulhon added
 Description modified (diff)
comment:4 in reply to: ↑ 2 Changed 12 months ago by
Replying to mkoeppe:
Here's an attempt
New commits:
863c636 sage.functions.boolean.AndSymbolic: New
I'll test that tomorrow. A couple remarks :
eval
can be farmed out tosympy
'sAnd
(one of the goals of this addition being the ability to useSympy
'sPiecewise
expressions of integrals and ODE solutions, often involving logical expressions...). I was originally aiming at wrappingSympy
's logical functions, but got stopped by :
 The showstopper problem I haven't been able to solve yet is translation to Maxima and backtranslation.
This is utterly necessary if you want to keep logical symbolic expressions (or symbolic expressions involving logical parts, as in
case
calls)simplify
able (otherExpression
methods are also farmed out to Maxima...).
OTOH,
maxima_calculus
should be easier, since this interface works "naturally" with the Lisp function tree representing Maxima expressions.
 Translation to
Mathematica
andSympy
should be trivial (give the names in aconversions
argument). I don't know (yet) what is offered bygiac
andfricas
, but maintaining universal translatability seems highly desirable...
HTH,
comment:5 in reply to: ↑ description Changed 12 months ago by
Replying to mkoeppe:
One application is for the restrictions of a
Chart
.
May I ask which application?
comment:6 followup: ↓ 7 Changed 12 months ago by
Right now, chart restrictions have an adhoc representation as nested lists and tuples of symbolic relation expressions; this could be replaced by the corresponding boolean expressions (instances of AndSymbolic
, OrSymbolic
)
comment:7 in reply to: ↑ 6 Changed 12 months ago by
Replying to mkoeppe:
Right now, chart restrictions have an adhoc representation as nested lists and tuples of symbolic relation expressions; this could be replaced by the corresponding boolean expressions (instances of
AndSymbolic
,OrSymbolic
)
Ah yes, this would be nice! Thanks for your answer.
comment:8 Changed 10 months ago by
 Milestone changed from sage9.4 to sage9.5
comment:9 Changed 9 months ago by
 Cc chapoton added
comment:10 followup: ↓ 67 Changed 9 months ago by
 Cc ghspaghettisalat added
For converting to maxima, some help would be welcome. My last failed attempt looked like this:

src/sage/functions/boolean.py
diff git a/src/sage/functions/boolean.py b/src/sage/functions/boolean.py index 58089dce81..d32acca761 100644
a b class AndSymbolic(BuiltinFunction): 31 31 32 32 """ 33 33 BuiltinFunction.__init__(self, 'and_symbolic', nargs=0, 34 conversions=dict(sympy='And')) 34 conversions=dict(sympy='And', 35 maxima='andsymbolic')) 35 36 36 37 def _eval_(self, *args): 37 38 
src/sage/interfaces/maxima_lib.py
diff git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index 40367c5242..2f6ab545f8 100644
a b ecl_eval('(defun principal nil (cond ($noprincipal (diverg)) ((not pcprntd) (mer 113 113 ecl_eval("(remprop 'mfactorial 'grind)") # don't use ! for factorials (#11539) 114 114 ecl_eval("(setf $errormsg nil)") 115 115 116 ecl_eval("(defmfun $andsymbolic (&rest args) (simplify (cons '(mand) args)))") 117 118 116 119 # the following is a direct adaptation of the definition of "retrieve" 117 120 # in the Maxima file macsys.lisp. This routine is normally responsible 118 121 # for displaying a question and returning the answer. We change it to … … sage_op_dict = { 1213 1216 sage.symbolic.expression.operator.neg : "MMINUS", 1214 1217 sage.symbolic.expression.operator.pow : "MEXPT", 1215 1218 sage.symbolic.expression.operator.or_ : "MOR", 1216 sage.symbolic.expression.operator.and_ : "MAND",1219 #sage.symbolic.expression.operator.and_ : "MAND",
comment:11 Changed 9 months ago by
 Commit changed from 863c636f52e73c08b3730a99ce7345cb694544da to 106cc8f48bcc935a52940bebc377e47d5e2d6e79
Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:
106cc8f  sage.functions.boolean.AndSymbolic: New

comment:12 Changed 9 months ago by
 Commit changed from 106cc8f48bcc935a52940bebc377e47d5e2d6e79 to 859a969b52cf76040d1822324a00db57998bd273
Branch pushed to git repo; I updated commit sha1. New commits:
859a969  RealSet: Handle symbolic 'and' input

comment:13 Changed 9 months ago by
 Commit changed from 859a969b52cf76040d1822324a00db57998bd273 to 0dca44278264774fa8c3449e1cf3565811446310
Branch pushed to git repo; I updated commit sha1. New commits:
0dca442  ConditionSet: flattens symbolic 'and's

comment:14 Changed 9 months ago by
 Commit changed from 0dca44278264774fa8c3449e1cf3565811446310 to 2866ee7df268dd0068c752896aecfe3abfee7685
comment:15 Changed 9 months ago by
 Commit changed from 2866ee7df268dd0068c752896aecfe3abfee7685 to fb3f9d0fefe0f91ae9a3f3018bd596cb8f169b61
comment:16 Changed 9 months ago by
comment:17 Changed 9 months ago by
 Commit changed from fb3f9d0fefe0f91ae9a3f3018bd596cb8f169b61 to 6b9adbfaeba46ec430cf004af4fb1843109ce27d
comment:18 Changed 9 months ago by
 Commit changed from 6b9adbfaeba46ec430cf004af4fb1843109ce27d to 8e10ed36645fff93cccc870160bf65f87fc45ea4
Branch pushed to git repo; I updated commit sha1. New commits:
8e10ed3  AndSymbolic, OrSymbolic: Use new function _trivial_bool for simplification

comment:19 Changed 9 months ago by
 Status changed from new to needs_review
comment:20 followup: ↓ 23 Changed 9 months ago by
Thank you for implementing this!
It seems that there is no entry for the new symbolic boolean operators in the reference manual. There should probably be more examples of use. A few naive trials:
sage: var('x y') (x, y) sage: s = x>0 & y<0 TypeError: unsupported operand type(s) for &: 'sage.symbolic.expression.Expression' and 'sage.symbolic.expression.Expression'
sage: from sage.functions.boolean import and_symbolic sage: s = and_symbolic(x>0, y<0) sage: bool(s.subs({x: 1, y: 2})) TypeError: unable to make sense of Maxima expression 'and_symbolic(1>0,2<0)' in Sage
comment:21 Changed 9 months ago by
 Dependencies set to #32315
comment:22 Changed 9 months ago by
 Commit changed from 8e10ed36645fff93cccc870160bf65f87fc45ea4 to 061102665f740cf693e900273fb143b0213b19ca
Branch pushed to git repo; I updated commit sha1. New commits:
0611026  Expression.__and__, __or__: New

comment:23 in reply to: ↑ 20 Changed 9 months ago by
Replying to egourgoulhon:
sage: var('x y') (x, y) sage: s = x>0 & y<0 TypeError: unsupported operand type(s) for &: 'sage.symbolic.expression.Expression' and 'sage.symbolic.expression.Expression'
The &
operator is now implemented  note that due to Python operator precedence, the operands need to be put in parentheses:
sage: var('x y') (x, y) sage: (x>0) & (y<0) and_symbolic(x > 0, y < 0)
comment:24 Changed 9 months ago by
 Commit changed from 061102665f740cf693e900273fb143b0213b19ca to a839cdfe1b728a885d8b239871056296fe6a89e5
Branch pushed to git repo; I updated commit sha1. New commits:
a839cdf  AndSymbolic, OrSymbolic: Flatten nested calls

comment:25 followups: ↓ 26 ↓ 28 Changed 9 months ago by
 Status changed from needs_review to needs_work
This is work in progress, no ?
 A
symbolic_not
is necessary. It might implement De Morgan's equalities (or this could be delegated to.expand
and.factor
, or, alternatively delegated to the logical functions).
 These functions currently do nothing :
{{{sage: var("a, b") (a, b) sage: and_symbolic((a>0), (b<0))
NameError? Traceback (most recent call last) <ipythoninput267fb44f33113> in <module>
NameError?: name 'and_symbolic' is not defined sage: (a>0) & (b<0) and_symbolic(a > 0, b < 0) sage: ((a>0) & (b<0)).subs(a==3) and_symbolic(3 > 0, b < 0) }}}
Compare :
sage: ((a>0) & (b<0)).subs(a==3)._sympy_().simplify()._sage_() b < 0 sage: sympy.Not(sympy.And(a._sympy_(), b._sympy_())) ~(a & b) sage: sympy.Not(sympy.And(a._sympy_(), b._sympy_())).simplify() ~a  ~b
==> needs_work
New commits:
a839cdf  AndSymbolic, OrSymbolic: Flatten nested calls

comment:26 in reply to: ↑ 25 Changed 9 months ago by
Replying to charpent:
This is work in progress, no ?
Yes; setting it to "needs review" allows the patchbot to run
comment:27 followup: ↓ 31 Changed 9 months ago by
and_symbolic
is not a global binding  you need to import it to use it, or the NameError
shows up. See doctests
comment:28 in reply to: ↑ 25 Changed 9 months ago by
Replying to charpent:
 A
symbolic_not
is necessary.
Yes, good point; any help with implementing it is welcome...
comment:29 Changed 9 months ago by
Do we want and_symbolic
, or_symbolic
, not_symbolic
as global bindings?
(The names are modeled after the existing min_symbolic
, max_symbolic
.)
In particular, for not_symbolic
, we cannot rely on an operator to make it available: Sage already repurposes the bitwise inversion operator ~
for multiplicative inversion.
comment:30 Changed 9 months ago by
 Status changed from needs_work to needs_info
comment:31 in reply to: ↑ 27 Changed 9 months ago by
Replying to mkoeppe:
and_symbolic
is not a global binding  you need to import it to use it, or theNameError
shows up. See doctests
and_symbolic
is a tad heavy to be exported. However, global And
, Or
and Not
would be welcome...
BTW, that's how they are known in Sympy...
comment:32 Changed 9 months ago by
But capitalized And, Or, Not seem out of line with our naming scheme for symbolic functions  they are all lowercase if I'm not mistaken.
comment:33 Changed 9 months ago by
(see src/sage/functions/all.py
)
comment:34 followup: ↓ 36 Changed 9 months ago by
For extending sage.misc.parser
, I would follow sage.logic.logicparser
(even though I am not sure of its relevance), which uses ~
for logical 'not'. (It also uses >
and <>
for implication/equivalence; and (incompatible with the expression parser) ^
for logical 'xor'.)
comment:35 Changed 9 months ago by
 Commit changed from a839cdfe1b728a885d8b239871056296fe6a89e5 to 5505b38ae5d27d13c5ed55310324f85980b00cfd
comment:36 in reply to: ↑ 34 ; followups: ↓ 38 ↓ 39 Changed 9 months ago by
Replying to mkoeppe:
For extending
sage.misc.parser
, I would followsage.logic.logicparser
(even though I am not sure of its relevance), which uses~
for logical 'not'. (It also uses>
and<>
for implication/equivalence; and (incompatible with the expression parser)^
for logical 'xor'.)
This would entail conditioning the interpretation of ~
to the type of its arguments, which is fishy : ~(x>0)
is indubitably a logical expression, but ~(x>0).subs(x==0)
could be understood as ~True}}}, which is ... 2 (!).
Not
can be unambiguous, and nine characters lighter than "symbolic_not" ; furthermore, "our naming scheme for symbolic functions" is a scheme, not Gospel...
New commits:
0a26b5d  Parser.p_eqn: Update doctest output for nested and_symbolic

5505b38  Tokenizer: Tokenize 'not' and '~' as '~'

comment:37 Changed 9 months ago by
 Commit changed from 5505b38ae5d27d13c5ed55310324f85980b00cfd to bb06156d7ab3dadc832c3ee5296fe18c09da7784
Branch pushed to git repo; I updated commit sha1. New commits:
bb06156  src/doc/en/reference/functions/index.rst: Add sage/functions/boolean

comment:38 in reply to: ↑ 36 ; followup: ↓ 40 Changed 9 months ago by
Replying to charpent:
Replying to mkoeppe:
For extending
sage.misc.parser
, I would followsage.logic.logicparser
(even though I am not sure of its relevance), which uses~
for logical 'not'. [...]This would entail conditioning the interpretation of
~
[...]
Note, this is just for the expression parser, not for Python semantics.
As I said in comment:29, we cannot use Python operators to make the operation available. We agree here.
comment:39 in reply to: ↑ 36 Changed 9 months ago by
Replying to charpent:
Not
can be unambiguous, and nine characters lighter than "symbolic_not" ;
It would be not_symbolic
, which is discoverable by typing not<TAB>
and autocompletes from not_<TAB>
, so I don't think the length is a significant burden.
comment:40 in reply to: ↑ 38 ; followup: ↓ 41 Changed 9 months ago by
Replying to mkoeppe:
Replying to charpent:
Replying to mkoeppe:
For extending
sage.misc.parser
, I would followsage.logic.logicparser
(even though I am not sure of its relevance), which uses~
for logical 'not'. [...]This would entail conditioning the interpretation of
~
[...]Note, this is just for the expression parser, not for Python semantics.
As I said in comment:29, we cannot use Python operators to make the operation available. We agree here.
Possible alternatives :
 forget operators, and limit this functionality to logic functions.
 Borrow inspiration from R and create
&&
,
and possibly~~
operators (analogous to our representation of bit XOR as^^
).
IMHO, a functional representatin is the most useful...
comment:41 in reply to: ↑ 40 Changed 9 months ago by
Replying to charpent:
create
&&
,
and possibly~~
operators (analogous to our representation of bit XOR as^^
).
You mean in the preparser? I'll not touch that.
In just Python, creating new operators such as &&
is not possible.
comment:42 Changed 9 months ago by
 Work issues set to Parser: Use a make_... function instead of importing and_symbolic...
comment:43 Changed 9 months ago by
Something is fishhy in the maxima>Sage conversion :
sage: maxima("(a>0) and (b<0)") a>0andb<0 sage: maxima("(a>0) and (b<0)")._sage_() and_symbolic(a > 0, 0 < 0)
 The second clause is illtranslated
 the operator's translation should be
&
(or a call tosymbolic_and
orAnd
).
comment:44 Changed 9 months ago by
Yes, see comment:10  I have not figured out maxima conversion  hoping for help from the experts
comment:45 followups: ↓ 49 ↓ 51 Changed 9 months ago by
sage: maxima("(a>0) and (b<0)") a>0andb<0
Didn't you fix the whitespaceeating behavior some time recently?
comment:46 Changed 9 months ago by
Note
sage: sage.calculus.calculus.symbolic_expression_from_string("a>0andb<0", accept_sequence=True) and_symbolic(a > 0, 0 < 0) sage: sage.calculus.calculus.symbolic_expression_from_string("a>0and b<0", accept_sequence=True) and_symbolic(a > 0, b < 0) sage: sage.calculus.calculus.symbolic_expression_from_string("0andb", accept_sequence=True) 0
comment:47 Changed 9 months ago by
Our expression parser has poor error checking and silently ignores unexpected trailing tokens in some situations:
sage: sage.calculus.calculus.symbolic_expression_from_string("0fffffif", accept_sequence=True) 0
comment:48 Changed 9 months ago by
Actually, this is just implicit multiplication 0*fffffif
, which gets simplified to 0.
comment:49 in reply to: ↑ 45 Changed 9 months ago by
comment:50 Changed 9 months ago by
 Dependencies changed from #32315 to #32315, #31796
comment:51 in reply to: ↑ 45 Changed 9 months ago by
Replying to mkoeppe:
sage: maxima("(a>0) and (b<0)") a>0andb<0Didn't you fix the whitespaceeating behavior some time recently?
I tried. But this patch entailed other bugs, which I hanven't yet understood == back to the old drawing board...
comment:52 Changed 9 months ago by
 Commit changed from bb06156d7ab3dadc832c3ee5296fe18c09da7784 to 644d831acb4a016f4e1c803319009bd54c92eb62
Branch pushed to git repo; I updated commit sha1. New commits:
b5e4168  Trac #32315: support iteration and enumerated sets

e0a8145  Merge #32315

767e89a  Ticket #31796 : make maxima output parseable.

d7abbe6  MaximaAbstract._commands: Remove whitespace in apropos output before breaking it apart

644d831  Merge #31796

comment:53 followup: ↓ 55 Changed 9 months ago by
Now, with the repaired #31796 merged, the problem is fixed:
sage: maxima("(a>0) and (b<0)") a > 0 and b < 0 sage: maxima("(a>0) and (b<0)")._sage_() and_symbolic(a > 0, b < 0)
comment:54 Changed 9 months ago by
 Status changed from needs_info to needs_review
I'm setting this again to needs_review
so that the patchbot runs; obviously more work is needed.
comment:55 in reply to: ↑ 53 Changed 9 months ago by
Replying to mkoeppe:
Now, with the repaired #31796 merged, the problem is fixed:
sage: maxima("(a>0) and (b<0)") a > 0 and b < 0 sage: maxima("(a>0) and (b<0)")._sage_() and_symbolic(a > 0, b < 0)
Thanks a lot ; I was searching in that direction, but missed the target you reached masterfully. Kudos !
BTW : "something" translating Maxima's is
would be as useful as a translation of Maxima's and
, or
and not
, necessary for the present ticket :
(%i3) is(a>2); (%o3) unknown (%i4) is(subst([a=3],a>2)); (%o4) true
Not coincidentally, it has the same Sage syntax collision problem...
Shouldn't it be added to this ticket ? Alternatively, we could create a new ticket for this and and depend on it.
comment:56 followup: ↓ 61 Changed 9 months ago by
Could you elaborate on is
? What collides with what?
comment:57 Changed 9 months ago by
 Dependencies changed from #32315, #31796 to #32315, #31796, #32379
comment:58 Changed 9 months ago by
 Commit changed from 644d831acb4a016f4e1c803319009bd54c92eb62 to 4aec1e8c7348069bef9cd739dc687b3d436644ca
comment:59 Changed 9 months ago by
 Commit changed from 4aec1e8c7348069bef9cd739dc687b3d436644ca to 218b2d66ad5b01b82660493e5c28cd8ebf461a6e
comment:60 Changed 9 months ago by
 Description modified (diff)
comment:61 in reply to: ↑ 56 Changed 9 months ago by
Replying to mkoeppe:
Could you elaborate on
is
? What collides with what?
is
is a Sage operator, roughly equivalent to Lisp's eq
:
sage: x.parent() is SR True
Therefore, the Maxima's is
can't be translated by the mechanism used for Maxima's functions :
sage: maxima.is(x>0) File "<ipythoninput6e177b9fc4016>", line 1 maxima.is(x>Integer(0)) ^ SyntaxError: invalid syntax sage: maxima_calculus.is(x>0) File "<ipythoninput7dea1cf49bee0>", line 1 maxima_calculus.is(x>Integer(0)) ^ SyntaxError: invalid syntax
comment:62 Changed 9 months ago by
A simple workaround for this is:
sage: getattr(maxima, 'is')(x>0) unknown
comment:63 Changed 9 months ago by
 Commit changed from 218b2d66ad5b01b82660493e5c28cd8ebf461a6e to 4094035d7a689dfdbaa65a442ca9f20ff0f56a3c
Branch pushed to git repo; I updated commit sha1. New commits:
4094035  src/sage/interfaces/sympy.py: Handle Not

comment:64 Changed 9 months ago by
 Commit changed from 4094035d7a689dfdbaa65a442ca9f20ff0f56a3c to a9302a658e75a30fe3fad4a7b7e0a45a13482857
Branch pushed to git repo; I updated commit sha1. New commits:
a9302a6  NotSymbolic: Add sympy test

comment:65 Changed 9 months ago by
 Commit changed from a9302a658e75a30fe3fad4a7b7e0a45a13482857 to d202804d9d82054c2317b58709d65a76de13d26d
Branch pushed to git repo; I updated commit sha1. New commits:
d202804  src/sage/functions/boolean.py: Add conversions to giac

comment:66 Changed 9 months ago by
 Commit changed from d202804d9d82054c2317b58709d65a76de13d26d to 700e84b41043070deb4f5a9b7e77a391665fcce0
Branch pushed to git repo; I updated commit sha1. New commits:
700e84b  src/sage/functions/boolean.py: Add conversions to maxima

comment:67 in reply to: ↑ 10 Changed 9 months ago by
Replying to mkoeppe:
For converting to maxima, some help would be welcome.
I think I figured a solution
comment:68 Changed 9 months ago by
 Commit changed from 700e84b41043070deb4f5a9b7e77a391665fcce0 to 392926c7577b0cbeb739fbe0eae5763dd1f9656d
Branch pushed to git repo; I updated commit sha1. New commits:
392926c  Parser.p_eqn: Handle 'not', '~'

comment:69 followup: ↓ 71 Changed 9 months ago by
Still problematic :
sage: not_symbolic((a>0) & ((b<0)  (x!=0))).simplify() a <= 0
Worse :
sage: ((a>0)  (x!=0)).simplify() 1
BTW :
sage: ~((a>0) & ((b<0)  (x!=0))) 1/and_symbolic(a > 0, or_symbolic(b < 0, x != 0))
comment:70 followup: ↓ 72 Changed 9 months ago by
Indeed:
sage: var('a,b') (a, b) sage: ((a>0)  (x!=0)).simplify() 1 sage: ((a>0)  (x!=0))._maxima_() true sage: ((a>0)  (x!=0)) or_symbolic(a > 0, x != 0) sage: f = ((a>0)  (x!=0)) sage: f._maxima_init_() '(_SAGE_VAR_a > 0) or (_SAGE_VAR_x # 0)' sage: maxima(_) true sage: (x!=0)._maxima_() _SAGE_VAR_x # 0 sage: (a>0)._maxima_() _SAGE_VAR_a > 0 sage: maxima('(a>0) or (x # 0)') true
Is this a maxima bug?
comment:71 in reply to: ↑ 69 Changed 9 months ago by
Replying to charpent:
BTW :
sage: ~((a>0) & ((b<0)  (x!=0))) 1/and_symbolic(a > 0, or_symbolic(b < 0, x != 0))
Yes, this is as discussed in comment:29, comment:38.
comment:72 in reply to: ↑ 70 ; followup: ↓ 74 Changed 9 months ago by
Replying to mkoeppe:
Is this a maxima bug?
Minimal example in plain maxima 5.45.0:
(%i8) (x#0); (%o8) x # 0 (%i9) (x#0) or (x#0); (%o9) true
comment:73 followup: ↓ 75 Changed 9 months ago by
I think our translation of Python's ==
and !=
to =
and #
on the Maxima side is wrong, and we should use equal
and notequal
instead  see https://maxima.sourceforge.io/docs/manual/maxima_169.html (Special operator: if)
comment:74 in reply to: ↑ 72 Changed 9 months ago by
Replying to mkoeppe:
Replying to mkoeppe:
Is this a maxima bug?
Minimal example in plain maxima 5.45.0:
(%i8) (x#0); (%o8) x # 0 (%i9) (x#0) or (x#0); (%o9) true
Did you (or do you plan to) report it in Maxima's bug report system ?
BTW : Sympy's logical functions seem exempt from this bug :
sage: foo = x!=0 sage: sympy.And(*map(lambda u:u._sympy_(), (foo, foo)))._sage_() x != 0 sage: sympy.Or(*map(lambda u:u._sympy_(), (foo, foo)))._sage_() x != 0 sage: sympy.Not(foo._sympy_())._sage_() x == 0
Wrapping Sympy's functions may be a quick way out (that was my initial plan...).
comment:75 in reply to: ↑ 73 Changed 9 months ago by
Replying to mkoeppe:
I think our translation of Python's
==
and!=
to=
and#
on the Maxima side is wrong, and we should useequal
andnotequal
instead  see https://maxima.sourceforge.io/docs/manual/maxima_169.html (Special operator: if)
Doesn't seem to be a question of precedence :
(%i9) x#0 or x#0; (%o9) true (%i10) (x#0) or (x#0); (%o10) true
comment:76 followup: ↓ 79 Changed 9 months ago by
No, I no longer think this is a Maxima bug.
I think it is a bug in our interface sage.interfaces.maxima_abstract
. There are already two places that work around it (by using equal
, notequal
): Expression._maxima_init_assume_
and test_relation_maxima
.
comment:77 Changed 9 months ago by
comment:78 Changed 9 months ago by
 Cc kcrisman added
comment:79 in reply to: ↑ 76 Changed 9 months ago by
Replying to mkoeppe:
No, I no longer think this is a Maxima bug.
I think it is a bug in our interface
sage.interfaces.maxima_abstract
. There are already two places that work around it (by usingequal
,notequal
):Expression._maxima_init_assume_
andtest_relation_maxima
.
Indeed, the documentation is quite clear : =
and #
: syntactic (in)equality (i. e. isomorphic structures) ; equal
and unequal
: value (= structural) (in)equality.
This might be a heavy change. Separate ticket, separately tested ?
comment:80 Changed 9 months ago by
 Dependencies changed from #32315, #31796, #32379 to #32315, #31796, #32379, #32383
Yes, I agree. There is a big potential for breakage. I've opened #32383 for it.
comment:81 Changed 9 months ago by
A possible plan B (independent of the Maxima snag) is to wrap Sympy's symbolic functions And
, Or
and Not
, possibly leaving the logical operators to a later ticket. This is easy, the only problem being Maxima (1+back)translation, which you have solved.
Wrapping a Python method (imptementation of these functions in Sympy) shouldn't be as heavy as invoking a function in another interpreter : we stay in Python.
This is new functionality, after all : we don't (yet) have to worry about backwards compatibility. Introducing it with limited syntax (possibly extended later) isn't a drawback to anybody.
Thoughts ?
comment:82 Changed 9 months ago by
Sympy translation already works, in both directions.
comment:83 Changed 9 months ago by
And there is no remaining issue with "syntax".
comment:84 Changed 9 months ago by
 Dependencies changed from #32315, #31796, #32379, #32383 to #32315, #31796, #32383
comment:85 Changed 9 months ago by
 Commit changed from 392926c7577b0cbeb739fbe0eae5763dd1f9656d to 0069e9c27af7060d531613a5562df4a8bddac3f4
Branch pushed to git repo; I updated commit sha1. New commits:
0069e9c  Expression.__and__, __or__: Coerce to common parent or return NotImplemented; fixes @infix_operator doctest

comment:86 Changed 9 months ago by
 Status changed from needs_review to needs_work
This passes tests but will need more work:
 without #32383, roundtripping through maxima is not safe
Parser
: Use amake_...
function instead of importingand_symbolic
and hardcoding its use  so that the other uses ofParser
are not affected Add more documentation and tests
 possibly create a direct conversion from
bool
toSR
so that we get to seeFalse
/True
, not0
/1
 various places, for example the
solve
method and global function, should be generalized so that they deal with (at least some) boolean symbolic expressions
comment:87 Changed 9 months ago by
 Description modified (diff)
comment:88 Changed 5 months ago by
 Milestone changed from sage9.5 to sage9.6
comment:89 Changed 4 months ago by
 Dependencies changed from #32315, #31796, #32383 to #32383
comment:90 Changed 4 months ago by
 Commit changed from 0069e9c27af7060d531613a5562df4a8bddac3f4 to e9eac61a362a738322cbade296356c7d30b1bd7c
Branch pushed to git repo; I updated commit sha1. This was a forced push. Last 10 new commits:
e385497  src/doc/en/reference/functions/index.rst: Add sage/functions/boolean

8cdd2cb  NotSymbolic, not_symbolic: New

71341c4  src/sage/functions/boolean.py: Remove unused imports

1699ec8  and_symbolic, or_symbolic, not_symbolic: Add global bindings

408bd37  src/sage/interfaces/sympy.py: Handle Not

b4c6fb6  NotSymbolic: Add sympy test

bf418fb  src/sage/functions/boolean.py: Add conversions to giac

833ba8c  src/sage/functions/boolean.py: Add conversions to maxima

d10ade0  Parser.p_eqn: Handle 'not', '~'

e9eac61  Expression.__and__, __or__: Coerce to common parent or return NotImplemented; fixes @infix_operator doctest

comment:91 Changed 4 months ago by
Rebased.
comment:92 Changed 3 months ago by
 Milestone changed from sage9.6 to sage9.7
Here's an attempt
New commits:
sage.functions.boolean.AndSymbolic: New