[ Context: implementing a root_sum
function analogous to Sympy's RootSum
and Maxima's similar function, whose name currently escapes me... A similar functionality exist also in Fricas, and can be met within its results.. ]
Sympy has a function Lambda
, that creates a Sympy Function
from a (tuple of) formal argumen(s) and a (Sympy) expression. I want to create a similar function in Sage. Such a function should:
accept a
hold
parameter (and therefore stay unevaluatd if necessaryaccept two-ways conversions (in Sympy at first, but similar cases can be made for Mathematica and Fricas)
return either a
lambda
Python anonymous function or a Sage symbolic function.
Creating such a function is relatively easy : function
(or its related sage.symbolic.function_factory.function
) can almost do the necessary setup:
# Eval the rgument and return the correct symbolic function:
def eval_symbolic_lambda(self, args, body):
from sympy.core.compatibility import iterable
if not iterable(args): args=[args]
sargs=tuple([u._sage_() for u in args])
vargs=tuple([u._sage_() for u in body._sage_().variables()])
vargs=tuple(set(vargs)-set(vargs))
for w in sargs:
exec("{}=SR.var('{}')".format(repr(w),repr(w)))
for w in vargs:
exec("{}=SR.var('{}')".format(repr(w),repr(w)))
return eval(preparse(repr(body._sage_()))).function(*sargs)
# The symbolic functuin itself
symbolic_lambda=sage.symbolic.function_factory.function("symbolic_lambda",
nargs=2,
conversions=dict(sympy="Lambda"),
eval_func=eval_symbolic_lambda)
The evaluation function does its job of building the relevant symbolic function :
sage: foo=eval_symbolic_lambda(None, x,x^2+1);foo
x |--> x^2 + 1
sage: foo(3)
10
sage: foo.parent()
Callable function ring with argument x
sage: type(foo)
<class 'sage.symbolic.expression.Expression'>
The symbolic function can be held:
sage: gee=symbolic_lambda(x, x^2-1, hold=True); gee
symbolic_lambda(x, x^2 - 1)
It can also (correctly) be translated to Sympy:
sage: gee._sympy_()
Lambda(x, x**2 - 1)
sage: type(gee._sympy_())
<class 'sympy.core.function.Lambda'>
But trying to use it with evaluation fails: the result of eval_symbolic_lambda
, which is a symbolic function, cannot be coerced to a symbolic expression :
sage: symbolic_lambda(x, x^2-1)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/pynac/pynac.pyx in sage.libs.pynac.pynac.pyExpression_to_ex (build/cythonized/sage/libs/pynac/pynac.cpp:5373)()
182 try:
--> 183 t = ring.SR.coerce(res)
184 except TypeError as err:
/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/parent.pyx in sage.structure.parent.Parent.coerce (build/cythonized/sage/structure/parent.c:10562)()
1113
-> 1114 cpdef coerce(self, x):
1115 """
/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/parent.pyx in sage.structure.parent.Parent.coerce (build/cythonized/sage/structure/parent.c:10491)()
1143 _record_exception()
-> 1144 raise TypeError(_LazyString(_lazy_format, ("no canonical coercion from %s to %s", parent(x), self), {}))
1145 else:
TypeError: no canonical coercion from Callable function ring with argument x to Symbolic Ring
During handling of the above exception, another exception occurred:
TypeError Traceback (most recent call last)
<ipython-input-73-c250078eff24> in <module>()
----> 1 symbolic_lambda(x, x**Integer(2)-Integer(1))
/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/function.pyx in sage.symbolic.function.Function.__call__ (build/cythonized/sage/symbolic/function.cpp:7039)()
600 (<Expression>args[0])._gobj, hold)
601 elif self._nargs == 2:
--> 602 res = g_function_eval2(self._serial, (<Expression>args[0])._gobj,
603 (<Expression>args[1])._gobj, hold)
604 elif self._nargs == 3:
/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/pynac/pynac.pyx in sage.libs.pynac.pynac.pyExpression_to_ex (build/cythonized/sage/libs/pynac/pynac.cpp:5425)()
183 t = ring.SR.coerce(res)
184 except TypeError as err:
--> 185 raise TypeError("function did not return a symbolic expression or an element that can be coerced into a symbolic expression")
186 return (<Expression>t)._gobj
187
TypeError: function did not return a symbolic expression or an element that can be coerced into a symbolic expression
Furthermore, at least in this use in "interactive mode", the mechanism allowing this function to be used for retro-converting a Sympy object to sage doesn't work:
sage: bar=sympy.Lambda(*[sympy.sympify(u) for u in (x, x^2-1)]);bar
Lambda(x, x**2 - 1)
sage: bar._sage_()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-102-5b91e5ff707e> in <module>()
----> 1 bar._sage_()
AttributeError: 'Lambda' object has no attribute '_sage_'
Any suggestion to solve those two problems ?