Ask Your Question
1

Using matrix() inside a user function prevents argument evaluation

asked 2021-04-03 00:06:58 +0100

chris233 gravatar image

This function:

f(x) = x*matrix([[5]])

Will produce this result:

In: f(3)
Out: [5*x]

I would expect the result to be the same as this:

In: 3*matrix([[5]])
Out: [15]

What am I missing? How come the argument supplied ('x') isn't being evaluated inside the function?

Thank you

edit retag flag offensive close merge delete

2 Answers

Sort by » oldest newest most voted
2

answered 2021-04-03 06:19:30 +0100

dsejas gravatar image

Hello, @chris233! I had the same problem some time ago. Check this related questions:

  1. https://ask.sagemath.org/question/476... (my related question, with an excellent answer by @rburing, with a list of additional cases where this particular syntax for function definition fails.)
  2. https://ask.sagemath.org/question/104... (this one has an excellent to-the-point explanation of this problem by @nbruin; this should answer your doubt.)

The only way around this problem (as far as I know) is to use pure Python syntax for function definition (In this case, "function" in the sense of computer pŕogramming, as a synonym of "subroutine", not "function" in the mathematical sense):

def f(x):
    return x * matrix([[5]])

(In my humble opinion, this is very unfortunate because mathematical function definition, like the one you intended, is a very convenient feature.)

I hope this helps!

edit flag offensive delete link more
0

answered 2021-04-04 14:17:18 +0100

Emmanuel Charpentier gravatar image

updated 2021-04-04 14:37:28 +0100

You can still create a symbolic function via the function function... :

f=function("f", eval_func=lambda self,*args:args[0]*matrix[[5]])

(or possibly

f=function("f", evalf_func=lambda self,*args:[u*matrix[[5]] for u in args])

depending of the semantics you wish to have for non-scalar arguments...)

The point is that f can now appear in symbolic expressions, where its argument is symbolic. This allows its use in other symbolic expressions. Contrast :

sage: fs=function("fs", evalf_func=lambda self, *args: len(divisors(args[0])))
sage: gs(x)=fs(x)^2
sage: gs
x |--> fs(x)^2
sage: fs
fs

where fs is treated as some "primitive" functoin, with :

sage: def fp(x): return len(divisors(x))
sage: gp(x)=fp(x)^2
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/usr/local/sage-9/local/lib/python3.9/site-packages/sage/arith/misc.py in divisors(n)
   1484     try:
-> 1485         m = n.divisors
   1486     except AttributeError:

/usr/local/sage-9/local/lib/python3.9/site-packages/sage/structure/element.pyx in sage.structure.element.Element.__getattr__ (build/cythonized/sage/structure/element.c:4708)()
    492         """
--> 493         return self.getattr_from_category(name)
    494 

/usr/local/sage-9/local/lib/python3.9/site-packages/sage/structure/element.pyx in sage.structure.element.Element.getattr_from_category (build/cythonized/sage/structure/element.c:4820)()
    505             cls = P._abstract_element_class
--> 506         return getattr_from_other_class(self, cls, name)
    507 

/usr/local/sage-9/local/lib/python3.9/site-packages/sage/cpython/getattr.pyx in sage.cpython.getattr.getattr_from_other_class (build/cythonized/sage/cpython/getattr.c:2618)()
    371         dummy_error_message.name = name
--> 372         raise AttributeError(dummy_error_message)
    373     attribute = <object>attr

AttributeError: 'sage.symbolic.expression.Expression' object has no attribute 'divisors'

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-90-05136176d065> in <module>
----> 1 __tmp__=var("x"); gp = symbolic_expression(fp(x)**Integer(2)).function(x)

<ipython-input-87-c759a1d7e016> in fp(x)
----> 1 def fp(x): return len(divisors(x))

/usr/local/sage-9/local/lib/python3.9/site-packages/sage/arith/misc.py in divisors(n)
   1492             one = parent(n)(1)
   1493             output = [one]
-> 1494             for p, e in f:
   1495                 prev = output[:]
   1496                 pn = one

TypeError: 'sage.symbolic.expression.Expression' object is not iterable

where the expression serving as "function body" is somehow evaluated during the creation of the symbolic expression ; this entails trying to evaluate divisors(x), which fails, since divisors is not a symbolic function...

Note that fs has a, evalf_func method, but not an eval_func method : this ensures that fs(x) will remain unevaluated, whereas fs(12) will be (numerically) evaluated (and return 12). Type function? for more details (quite important here...).

HTH,

edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2021-04-03 00:06:09 +0100

Seen: 255 times

Last updated: Apr 04 '21