Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Hello, @Emmanuel Charpentier! I tried various approaches to your code, added print() commands to every line in order to see what is happening internally, studied the code for function, which lead me to FunctionFactory, which lead me to SymbolicFunction, which lead me too your code again, etc., etc., etc. It took me hours, but I couldn't resist the challenge. It bugs me that I couldn't solve your problem. However, in the end, I do believe that I could find an explanation for why you don't get boolean results. Here is my theory: If you make

print(type(And(x>2, 4>3, y<5)))

you will get <class 'sage.symbolic.expression.Expression'>, which makes sense if you think about it, because you are creating a new symbolic function. Anyway, it seems that booleans cannot be coerced to Expressions without being converted to Integers first. For example,

Expression(SR, True)

will return 1, and the similar applies to False and 0.

My appreciation is that this mechanism you use should allow the construction of boolean functions like your And, so I think this should be classified as a bug (?), but I am going beyond my attributions here.

Perhaps a solution to your problem could be make a wrapper function for the wrapper symbolic function. Another solution I can think of is to go low level and try to use something more elementary than function(), e.g., function_factory or perhaps even inherit from BuiltinFunction.

If I make some progress, I'll let you know.

I hope this helps!

Hello, @Emmanuel Charpentier! I tried various approaches to your code, added print() commands to every line in order to see what is happening internally, studied the code for function, which lead me to FunctionFactory, which lead me to SymbolicFunction, which lead me too your code again, etc., etc., etc. It took me hours, but I couldn't resist the challenge. It bugs me that I couldn't solve your problem. However, in the end, I do believe that I could find an explanation for why you don't get boolean results. Here is my theory: If you make

print(type(And(x>2, 4>3, y<5)))

you will get <class 'sage.symbolic.expression.Expression'>, which makes sense if you think about it, because you are creating a new symbolic function. Anyway, it seems that booleans cannot be coerced to Expressions without being converted to Integers first. For example,

Expression(SR, True)

will return 1, and the similar applies to False and 0.

My appreciation is that this mechanism you use should allow the construction of boolean functions like your And, so I think this should be classified as a bug (?), but I am going beyond my attributions here.

Perhaps a solution to your problem could be make a wrapper function for the wrapper symbolic function. Another solution I can think of is to go low level and try to use something more elementary than function(), e.g., function_factory or perhaps even inherit from BuiltinFunction.

If I make some progress, I'll let you know.

I hope this helps!

EDIT 1: Hello, @Emmanuel Charpentier! Sorry to ping you twice with this question, but, as I promised, I am letting you know that I made some progress in this matter, although it is very anticlimactic.

I've been studying the source code for function(), SymbolicFunction, BuiltinFunction, function_factory and Function. I have tried various approaches at various levels, and nothing worked. I believe the problem is in the class Function, from which the others mentioned inherit. It has a method called __call__, which takes care of the evaluation (you can find it at sage.symbolic.function.pyx; in Sage 9.2, it is at line 436). Unfortunately, this method coerces the arguments to the Symbolic Ring SR, which, as indicated in my text above, converts True and False to 1 and 0, respectively.

You will observe that this method has the arguments coerce and hold. This hold seems to be the same as the one you used in your code, so my best guess is that this method takes care of the low level evaluation of the function (And in your case). You will see the following lines in that method:

if coerce:
        try:
            args = [SR.coerce(a) for a in args]
        ...

This seems to what is causing the True-->1 and False-->0 conversion. Unfortunately, setting coerce to False wrecks havoc in the computation, so I have no idea how to solve this.

As I told you, I am just guessing that this __call__ method is indeed the one taking care of the low level evaluation; however, at the very least, it is correct that the true problem is that your code is somehow coercing to the Symbolic Ring.

I only see two solutions: (1) Somehow modify the Function class so that it doesn't coerce boolean arguments, or (2) define your own class BoolFunction that mimics Function (which should inherit from SageObject) or SymbolicFunction (which should inherit from Function), but uses a different evaluation method for boolean arguments. (Perhaps this requires to open a ticket?)

Sorry for not bringing a definitive solution to your problem!