Opened 12 months ago

Last modified 3 months ago

#31911 needs_work enhancement

Boolean symbolic expressions

Reported by: mkoeppe Owned by:
Priority: major Milestone: sage-9.7
Component: symbolics Keywords:
Cc: charpent, nbruin, egourgoulhon, chapoton, gh-spaghettisalat, 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:

Status badges

Description (last modified by mkoeppe)

As proposed in https://groups.google.com/g/sage-devel/c/U_WGbYG2zOE/m/yq-EDEXDAgAJ

We add symbolic functions and_symbolic, or_symbolic, not_symbolic; the first two are also accessible by repurposing the operators bitwise-and & and bitwise-or |.

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 mkoeppe

  • Branch set to u/mkoeppe/boolean_symbolic_expressions

comment:2 follow-up: Changed 12 months ago by mkoeppe

  • Commit set to 863c636f52e73c08b3730a99ce7345cb694544da

Here's an attempt


New commits:

863c636sage.functions.boolean.AndSymbolic: New

comment:3 Changed 12 months ago by mkoeppe

  • Cc egourgoulhon added
  • Description modified (diff)

comment:4 in reply to: ↑ 2 Changed 12 months ago by charpent

Replying to mkoeppe:

Here's an attempt


New commits:

863c636sage.functions.boolean.AndSymbolic: New

I'll test that tomorrow. A couple remarks :

  • eval can be farmed out to sympy's And (one of the goals of this addition being the ability to use Sympy's Piecewise expressions of integrals and ODE solutions, often involving logical expressions...). I was originally aiming at wrapping Sympy'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) simplifyable (other Expression 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 and Sympy should be trivial (give the names in a conversions argument). I don't know (yet) what is offered by giac and fricas, but maintaining universal translatability seems highly desirable...

HTH,

comment:5 in reply to: ↑ description Changed 12 months ago by egourgoulhon

Replying to mkoeppe:

One application is for the restrictions of a Chart.

May I ask which application?

comment:6 follow-up: Changed 12 months ago by mkoeppe

Right now, chart restrictions have an ad-hoc 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 egourgoulhon

Replying to mkoeppe:

Right now, chart restrictions have an ad-hoc 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 mkoeppe

  • Milestone changed from sage-9.4 to sage-9.5

comment:9 Changed 9 months ago by mkoeppe

  • Cc chapoton added

comment:10 follow-up: Changed 9 months ago by mkoeppe

  • Cc gh-spaghettisalat 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): 
    3131
    3232        """
    3333        BuiltinFunction.__init__(self, 'and_symbolic', nargs=0,
    34                                  conversions=dict(sympy='And'))
     34                                 conversions=dict(sympy='And',
     35                                                  maxima='andsymbolic'))
    3536
    3637    def _eval_(self, *args):
    3738
  • 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 
    113113ecl_eval("(remprop 'mfactorial 'grind)") # don't use ! for factorials (#11539)
    114114ecl_eval("(setf $errormsg nil)")
    115115
     116ecl_eval("(defmfun $andsymbolic (&rest args) (simplify (cons '(mand) args)))")
     117
     118
    116119# the following is a direct adaptation of the definition of "retrieve"
    117120# in the Maxima file macsys.lisp. This routine is normally responsible
    118121# for displaying a question and returning the answer. We change it to
    sage_op_dict = { 
    12131216    sage.symbolic.expression.operator.neg : "MMINUS",
    12141217    sage.symbolic.expression.operator.pow : "MEXPT",
    12151218    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 git

  • Commit changed from 863c636f52e73c08b3730a99ce7345cb694544da to 106cc8f48bcc935a52940bebc377e47d5e2d6e79

Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:

106cc8fsage.functions.boolean.AndSymbolic: New

comment:12 Changed 9 months ago by git

  • Commit changed from 106cc8f48bcc935a52940bebc377e47d5e2d6e79 to 859a969b52cf76040d1822324a00db57998bd273

Branch pushed to git repo; I updated commit sha1. New commits:

859a969RealSet: Handle symbolic 'and' input

comment:13 Changed 9 months ago by git

  • Commit changed from 859a969b52cf76040d1822324a00db57998bd273 to 0dca44278264774fa8c3449e1cf3565811446310

Branch pushed to git repo; I updated commit sha1. New commits:

0dca442ConditionSet: flattens symbolic 'and's

comment:14 Changed 9 months ago by git

  • Commit changed from 0dca44278264774fa8c3449e1cf3565811446310 to 2866ee7df268dd0068c752896aecfe3abfee7685

Branch pushed to git repo; I updated commit sha1. New commits:

9427892Parser.p_atom: Accept parenthesized equations
a222684Tokenizer: Tokenize infix '&' or 'and' as '&'
1741468fixup atom
2866ee7Parser.p_eqn: Accept chains of equations

comment:15 Changed 9 months ago by git

  • Commit changed from 2866ee7df268dd0068c752896aecfe3abfee7685 to fb3f9d0fefe0f91ae9a3f3018bd596cb8f169b61

Branch pushed to git repo; I updated commit sha1. New commits:

b8f5bf1Parser.p_eqn: Handle logical and
fb3f9d0AndSymbolic._eval_: Weaken simplifications to not trigger equality test

comment:16 Changed 9 months ago by mkoeppe

  • Authors set to Matthias Koeppe

comment:17 Changed 9 months ago by git

  • Commit changed from fb3f9d0fefe0f91ae9a3f3018bd596cb8f169b61 to 6b9adbfaeba46ec430cf004af4fb1843109ce27d

Branch pushed to git repo; I updated commit sha1. New commits:

9300284sage.functions.boolean.or_symbolic: New
e2c4470src/sage/misc/parser.pyx: Handle '|', 'or'
6b9adbfsrc/sage/interfaces/sympy.py: Fixup _sympysage_and, add _sympysage_or

comment:18 Changed 9 months ago by git

  • Commit changed from 6b9adbfaeba46ec430cf004af4fb1843109ce27d to 8e10ed36645fff93cccc870160bf65f87fc45ea4

Branch pushed to git repo; I updated commit sha1. New commits:

8e10ed3AndSymbolic, OrSymbolic: Use new function _trivial_bool for simplification

comment:19 Changed 9 months ago by mkoeppe

  • Status changed from new to needs_review

comment:20 follow-up: Changed 9 months ago by egourgoulhon

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 mkoeppe

  • Dependencies set to #32315

comment:22 Changed 9 months ago by git

  • Commit changed from 8e10ed36645fff93cccc870160bf65f87fc45ea4 to 061102665f740cf693e900273fb143b0213b19ca

Branch pushed to git repo; I updated commit sha1. New commits:

0611026Expression.__and__, __or__: New

comment:23 in reply to: ↑ 20 Changed 9 months ago by mkoeppe

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 git

  • Commit changed from 061102665f740cf693e900273fb143b0213b19ca to a839cdfe1b728a885d8b239871056296fe6a89e5

Branch pushed to git repo; I updated commit sha1. New commits:

a839cdfAndSymbolic, OrSymbolic: Flatten nested calls

comment:25 follow-ups: Changed 9 months ago by charpent

  • 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) <ipython-input-2-67fb44f33113> 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:

a839cdfAndSymbolic, OrSymbolic: Flatten nested calls

comment:26 in reply to: ↑ 25 Changed 9 months ago by mkoeppe

Replying to charpent:

This is work in progress, no ?

Yes; setting it to "needs review" allows the patchbot to run

comment:27 follow-up: Changed 9 months ago by mkoeppe

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 mkoeppe

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 mkoeppe

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 mkoeppe

  • Status changed from needs_work to needs_info

comment:31 in reply to: ↑ 27 Changed 9 months ago by charpent

Replying to mkoeppe:

and_symbolic is not a global binding -- you need to import it to use it, or the NameError 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...

Last edited 9 months ago by charpent (previous) (diff)

comment:32 Changed 9 months ago by mkoeppe

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 mkoeppe

(see src/sage/functions/all.py)

comment:34 follow-up: Changed 9 months ago by mkoeppe

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 git

  • Commit changed from a839cdfe1b728a885d8b239871056296fe6a89e5 to 5505b38ae5d27d13c5ed55310324f85980b00cfd

Branch pushed to git repo; I updated commit sha1. New commits:

0a26b5dParser.p_eqn: Update doctest output for nested and_symbolic
5505b38Tokenizer: Tokenize 'not' and '~' as '~'

comment:36 in reply to: ↑ 34 ; follow-ups: Changed 9 months ago by charpent

Replying to mkoeppe:

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'.)

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:

0a26b5dParser.p_eqn: Update doctest output for nested and_symbolic
5505b38Tokenizer: Tokenize 'not' and '~' as '~'

comment:37 Changed 9 months ago by git

  • Commit changed from 5505b38ae5d27d13c5ed55310324f85980b00cfd to bb06156d7ab3dadc832c3ee5296fe18c09da7784

Branch pushed to git repo; I updated commit sha1. New commits:

bb06156src/doc/en/reference/functions/index.rst: Add sage/functions/boolean

comment:38 in reply to: ↑ 36 ; follow-up: Changed 9 months ago by mkoeppe

Replying to charpent:

Replying to mkoeppe:

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'. [...]

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 mkoeppe

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 ; follow-up: Changed 9 months ago by charpent

Replying to mkoeppe:

Replying to charpent:

Replying to mkoeppe:

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'. [...]

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 mkoeppe

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 mkoeppe

  • Work issues set to Parser: Use a make_... function instead of importing and_symbolic...

comment:43 Changed 9 months ago by charpent

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 ill-translated
  • the operator's translation should be & (or a call to symbolic_and or And).

comment:44 Changed 9 months ago by mkoeppe

Yes, see comment:10 -- I have not figured out maxima conversion -- hoping for help from the experts

comment:45 follow-ups: Changed 9 months ago by mkoeppe

sage: maxima("(a>0) and (b<0)")                                                 
a>0andb<0

Didn't you fix the whitespace-eating behavior some time recently?

comment:46 Changed 9 months ago by mkoeppe

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 mkoeppe

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 mkoeppe

Actually, this is just implicit multiplication 0*fffffif, which gets simplified to 0.

comment:49 in reply to: ↑ 45 Changed 9 months ago by mkoeppe

Replying to mkoeppe:

sage: maxima("(a>0) and (b<0)")                                                 
a>0andb<0

Didn't you fix the whitespace-eating behavior some time recently?

I see, that's #31796, which appears to be stuck

comment:50 Changed 9 months ago by mkoeppe

  • Dependencies changed from #32315 to #32315, #31796

comment:51 in reply to: ↑ 45 Changed 9 months ago by charpent

Replying to mkoeppe:

sage: maxima("(a>0) and (b<0)")                                                 
a>0andb<0

Didn't you fix the whitespace-eating 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 git

  • Commit changed from bb06156d7ab3dadc832c3ee5296fe18c09da7784 to 644d831acb4a016f4e1c803319009bd54c92eb62

Branch pushed to git repo; I updated commit sha1. New commits:

b5e4168Trac #32315: support iteration and enumerated sets
e0a8145Merge #32315
767e89aTicket #31796 : make maxima output parseable.
d7abbe6MaximaAbstract._commands: Remove whitespace in apropos output before breaking it apart
644d831Merge #31796

comment:53 follow-up: Changed 9 months ago by 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)

comment:54 Changed 9 months ago by mkoeppe

  • 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 charpent

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.

Last edited 9 months ago by charpent (previous) (diff)

comment:56 follow-up: Changed 9 months ago by mkoeppe

Could you elaborate on is? What collides with what?

comment:57 Changed 9 months ago by mkoeppe

  • Dependencies changed from #32315, #31796 to #32315, #31796, #32379

comment:58 Changed 9 months ago by git

  • Commit changed from 644d831acb4a016f4e1c803319009bd54c92eb62 to 4aec1e8c7348069bef9cd739dc687b3d436644ca

Branch pushed to git repo; I updated commit sha1. New commits:

f1e2fe0NotSymbolic, not_symbolic: New
f492321src/sage/symbolic/expression_conversions.py: Make a docstring raw
4aec1e8Merge #32379

comment:59 Changed 9 months ago by git

  • Commit changed from 4aec1e8c7348069bef9cd739dc687b3d436644ca to 218b2d66ad5b01b82660493e5c28cd8ebf461a6e

Branch pushed to git repo; I updated commit sha1. New commits:

175e523src/sage/functions/boolean.py: Remove unused imports
218b2d6and_symbolic, or_symbolic, not_symbolic: Add global bindings

comment:60 Changed 9 months ago by mkoeppe

  • Description modified (diff)

comment:61 in reply to: ↑ 56 Changed 9 months ago by charpent

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 "<ipython-input-6-e177b9fc4016>", line 1
    maxima.is(x>Integer(0))
           ^
SyntaxError: invalid syntax

sage: maxima_calculus.is(x>0)
  File "<ipython-input-7-dea1cf49bee0>", line 1
    maxima_calculus.is(x>Integer(0))
                    ^
SyntaxError: invalid syntax

comment:62 Changed 9 months ago by mkoeppe

A simple workaround for this is:

sage: getattr(maxima, 'is')(x>0)                                                                                         
unknown

comment:63 Changed 9 months ago by git

  • Commit changed from 218b2d66ad5b01b82660493e5c28cd8ebf461a6e to 4094035d7a689dfdbaa65a442ca9f20ff0f56a3c

Branch pushed to git repo; I updated commit sha1. New commits:

4094035src/sage/interfaces/sympy.py: Handle Not

comment:64 Changed 9 months ago by git

  • Commit changed from 4094035d7a689dfdbaa65a442ca9f20ff0f56a3c to a9302a658e75a30fe3fad4a7b7e0a45a13482857

Branch pushed to git repo; I updated commit sha1. New commits:

a9302a6NotSymbolic: Add sympy test

comment:65 Changed 9 months ago by git

  • Commit changed from a9302a658e75a30fe3fad4a7b7e0a45a13482857 to d202804d9d82054c2317b58709d65a76de13d26d

Branch pushed to git repo; I updated commit sha1. New commits:

d202804src/sage/functions/boolean.py: Add conversions to giac

comment:66 Changed 9 months ago by git

  • Commit changed from d202804d9d82054c2317b58709d65a76de13d26d to 700e84b41043070deb4f5a9b7e77a391665fcce0

Branch pushed to git repo; I updated commit sha1. New commits:

700e84bsrc/sage/functions/boolean.py: Add conversions to maxima

comment:67 in reply to: ↑ 10 Changed 9 months ago by mkoeppe

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 git

  • Commit changed from 700e84b41043070deb4f5a9b7e77a391665fcce0 to 392926c7577b0cbeb739fbe0eae5763dd1f9656d

Branch pushed to git repo; I updated commit sha1. New commits:

392926cParser.p_eqn: Handle 'not', '~'

comment:69 follow-up: Changed 9 months ago by charpent

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))
Last edited 9 months ago by charpent (previous) (diff)

comment:70 follow-up: Changed 9 months ago by mkoeppe

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?

Last edited 9 months ago by mkoeppe (previous) (diff)

comment:71 in reply to: ↑ 69 Changed 9 months ago by mkoeppe

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 ; follow-up: Changed 9 months ago by 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

comment:73 follow-up: Changed 9 months ago by mkoeppe

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 charpent

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 charpent

Replying to mkoeppe:

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)

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 follow-up: Changed 9 months ago by 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 using equal, notequal): Expression._maxima_init_assume_ and test_relation_maxima.

comment:77 Changed 9 months ago by mkoeppe

See the early tickets #1163, #2218

comment:78 Changed 9 months ago by mkoeppe

  • Cc kcrisman added

comment:79 in reply to: ↑ 76 Changed 9 months ago by charpent

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 using equal, notequal): Expression._maxima_init_assume_ and test_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 mkoeppe

  • 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 charpent

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 mkoeppe

Sympy translation already works, in both directions.

comment:83 Changed 9 months ago by mkoeppe

And there is no remaining issue with "syntax".

comment:84 Changed 9 months ago by mkoeppe

  • Dependencies changed from #32315, #31796, #32379, #32383 to #32315, #31796, #32383

comment:85 Changed 9 months ago by git

  • Commit changed from 392926c7577b0cbeb739fbe0eae5763dd1f9656d to 0069e9c27af7060d531613a5562df4a8bddac3f4

Branch pushed to git repo; I updated commit sha1. New commits:

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

comment:86 Changed 9 months ago by mkoeppe

  • 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 a make_... function instead of importing and_symbolic and hardcoding its use - so that the other uses of Parser are not affected
  • Add more documentation and tests
  • possibly create a direct conversion from bool to SR so that we get to see False/True, not 0/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 mkoeppe

  • Description modified (diff)

comment:88 Changed 5 months ago by mkoeppe

  • Milestone changed from sage-9.5 to sage-9.6

comment:89 Changed 4 months ago by mkoeppe

  • Dependencies changed from #32315, #31796, #32383 to #32383

comment:90 Changed 4 months ago by git

  • Commit changed from 0069e9c27af7060d531613a5562df4a8bddac3f4 to e9eac61a362a738322cbade296356c7d30b1bd7c

Branch pushed to git repo; I updated commit sha1. This was a forced push. Last 10 new commits:

e385497src/doc/en/reference/functions/index.rst: Add sage/functions/boolean
8cdd2cbNotSymbolic, not_symbolic: New
71341c4src/sage/functions/boolean.py: Remove unused imports
1699ec8and_symbolic, or_symbolic, not_symbolic: Add global bindings
408bd37src/sage/interfaces/sympy.py: Handle Not
b4c6fb6NotSymbolic: Add sympy test
bf418fbsrc/sage/functions/boolean.py: Add conversions to giac
833ba8csrc/sage/functions/boolean.py: Add conversions to maxima
d10ade0Parser.p_eqn: Handle 'not', '~'
e9eac61Expression.__and__, __or__: Coerce to common parent or return NotImplemented; fixes @infix_operator doctest

comment:91 Changed 4 months ago by mkoeppe

Rebased.

comment:92 Changed 3 months ago by mkoeppe

  • Milestone changed from sage-9.6 to sage-9.7
Note: See TracTickets for help on using tickets.