Ask Your Question
2

Delayed evaluation (equivalent to := in Mathematica)?

asked 2022-06-22 12:04:28 +0100

cav24 gravatar image

In Sage, is there a way to define a function such that the expressions used are evaluated only when the function is called with specific values replacing its arguments? (In Mathematica, this is done by defining f(x_) : = some function(x).)

As an example, here is some otherwise useless code which is intended to give back a plot of x^r for arbitrary integer r.

myplot(r) = lambda r: plot(x^r,(x,-1,1))

Executing this line causes the errors copied below, which are identical to those produced if I simply execute plot(x^r,(x,-1,1)) by itself. So my interpretation is that Sage is immediately trying to evaluate the RHS of the function I'm defining. In Mathematica, this evaluation can be delayed using the ":=" syntax, so that if I then call "my plot(3)" it would go and evaluate plot(x^3,(x,-1,1)) which of course would produce the desired result. So, again, my question is whether there is something analogous in Sage?

(And yes, I have heard that Sage is short for "Sage is not Mathematica". But it's so great! Sage I mean.)

Thanks!

 ---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/ext/fast_callable.pyx in sage.ext.fast_callable.ExpressionTreeBuilder.var (build/cythonized/sage/ext/fast_callable.c:6657)()
    688         try:
--> 689             ind = self._vars.index(var_name)
    690         except ValueError:

ValueError: 'x' is not in list

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
/var/folders/mt/4xjm_x515mxdjkm49zmplt240000gq/T/ipykernel_91376/380259859.py in <module>
----> 1 __tmp__=var("r"); myplot = symbolic_expression(lambda r: plot(x**r,(x,-Integer(1),Integer(1)))).function(r)

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/calculus/all.py in symbolic_expression(x)
    223                    for param in s.parameters.values()):
    224                 vars = [SR.var(name) for name in s.parameters.keys()]
--> 225                 result = x(*vars)
    226                 if isinstance(result, (tuple, list)):
    227                     return vector(SR, result).function(*vars)

/var/folders/mt/4xjm_x515mxdjkm49zmplt240000gq/T/ipykernel_91376/380259859.py in <lambda>(r)
----> 1 __tmp__=var("r"); myplot = symbolic_expression(lambda r: plot(x**r,(x,-Integer(1),Integer(1)))).function(r)

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/misc/decorators.py in wrapper(*args, **kwds)
    489                 options['__original_opts'] = kwds
    490             options.update(kwds)
--> 491             return func(*args, **options)
    492 
    493         #Add the options specified by @options to the signature of the wrapped

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/plot/plot.py in plot(funcs, *args, **kwds)
   1981 
   1982     if hasattr(funcs, 'plot'):
-> 1983         G = funcs.plot(*args, **original_opts)
   1984 
   1985         # If we have extra keywords already set, then update them

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression.plot (build/cythonized/sage/symbolic/expression.cpp:94285)()
  12857                     param = A[0]
  12858                     try:
> 12859                         f = self._plot_fast_callable(param)
  12860                     except NotImplementedError:
  12861                         return self.function(param)

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression._plot_fast_callable (build/cythonized/sage/symbolic/expression.cpp:94693)()
  12892         from sage.ext.fast_callable import fast_callable
  12893         from sage.rings.complex_double import CDF
> 12894         return fast_callable(self, vars=vars, expect_one_var=True, domain=CDF)
  12895 
  12896     ############

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/ext/fast_callable.pyx in sage.ext.fast_callable.fast_callable (build/cythonized/sage/ext/fast_callable.c:4638)()
    463 
    464         etb = ExpressionTreeBuilder(vars=vars, domain=domain)
--> 465         et = x._fast_callable_(etb)
    466 
    467     if isinstance(domain, sage.rings.abc.RealField):

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression._fast_callable_ (build/cythonized/sage/symbolic/expression.cpp:93534)()
  12719         """
  12720         from sage.symbolic.expression_conversions import fast_callable
> 12721         return fast_callable(self, etb)
  12722 
  12723     def show(self):

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression_conversions.py in fast_callable(ex, etb)
   1866 
   1867     """
-> 1868     return FastCallableConverter(ex, etb)()
   1869 
   1870 class RingConverter(Converter):

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression_conversions.py in __call__(self, ex)
    204                 div = self.get_fake_div(ex)
    205                 return self.arithmetic(div, div.operator())
--> 206             return self.arithmetic(ex, operator)
    207         elif operator in relation_operators:
    208             return self.relation(ex, operator)

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression_conversions.py in arithmetic(self, ex, operator)
   1794         elif operator == mul_vararg:
   1795             operator = _operator.mul
-> 1796         return reduce(lambda x,y: self.etb.call(operator, x,y), operands)
   1797 
   1798     def symbol(self, ex):

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression_conversions.py in <lambda>(x, y)
   1794         elif operator == mul_vararg:
   1795             operator = _operator.mul
-> 1796         return reduce(lambda x,y: self.etb.call(operator, x,y), operands)
   1797 
   1798     def symbol(self, ex):

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/ext/fast_callable.pyx in sage.ext.fast_callable.ExpressionTreeBuilder.call (build/cythonized/sage/ext/fast_callable.c:7094)()
    741         if fn is operator.pow:
    742             base, exponent = args
--> 743             return self(base)**exponent
    744         else:
    745             return ExpressionCall(self, fn, [self(a) for a in args])

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/ext/fast_callable.pyx in sage.ext.fast_callable.ExpressionTreeBuilder.__call__ (build/cythonized/sage/ext/fast_callable.c:6236)()
    617             return self.constant(x)
    618 
--> 619         return fc(self)
    620 
    621     def _clean_var(self, v):

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression._fast_callable_ (build/cythonized/sage/symbolic/expression.cpp:93534)()
  12719         """
  12720         from sage.symbolic.expression_conversions import fast_callable
> 12721         return fast_callable(self, etb)
  12722 
  12723     def show(self):

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression_conversions.py in fast_callable(ex, etb)
   1866 
   1867     """
-> 1868     return FastCallableConverter(ex, etb)()
   1869 
   1870 class RingConverter(Converter):

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression_conversions.py in __call__(self, ex)
    198         operator = ex.operator()
    199         if operator is None:
--> 200             return self.symbol(ex)
    201 
    202         if operator in arithmetic_operators:

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/symbolic/expression_conversions.py in symbol(self, ex)
   1815             ValueError: Variable 'z' not found...
   1816         """
-> 1817         return self.etb.var(SR(ex))
   1818 
   1819     def composition(self, ex, function):

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/ext/fast_callable.pyx in sage.ext.fast_callable.ExpressionTreeBuilder.var (build/cythonized/sage/ext/fast_callable.c:6736)()
    689             ind = self._vars.index(var_name)
    690         except ValueError:
--> 691             raise ValueError(f"Variable '{var_name}' not found in {self._vars}")
    692         return ExpressionVariable(self, ind)
    693 

ValueError: Variable 'x' not found in ['r']
edit retag flag offensive close merge delete

Comments

Just use normal python syntax

  myplot = lambda r: plot(x^r,(x,-1,1))
FrédéricC gravatar imageFrédéricC ( 2022-06-22 12:18:15 +0100 )edit

2 Answers

Sort by » oldest newest most voted
1

answered 2022-06-22 12:19:40 +0100

slelievre gravatar image

Here, you want this instead:

myplot = lambda r: plot(x^r, (x, -1, 1))

Then you can do:

myplot(3)

to get the plot of $x \mapsto x^3$.

edit flag offensive delete link more

Comments

I love it. So my mistake was to write myplot(x) instead of just myplot. Thank you!

cav24 gravatar imagecav24 ( 2022-06-22 13:39:11 +0100 )edit
1

answered 2023-01-15 22:52:30 +0100

Emmanuel Charpentier gravatar image

The normal way to define a function in Sagemath is exactly the same as in Python :

sage: def myplot1(r):
....:     return plot(x^r, (x, -1,1))
....:

Using the lambda syntax is a shortcut fulfilling the same goal for functions returning the result of the expression of a single Python (Sage) expression :

sage: myplot2 = lambda r: plot(x^r, (x, -1, 1))

An important Sage-specific way to define symbolic functions (a. k. a. callable symbolic expressions) can be used to define functions taking symbolic arguments and returning symbolic expressions :

sympsimp(x) = x._sympy_().simplify()._sage_()

Other, more exotic ways of defining functions include :

  • Cython (Python code +°optional type declarations, compiled to C code) ;

  • C/Fortran library code with interface to the Python interpreter.

But these ways need more work and are more useful for library/package development or Sage extension.

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: 2022-06-22 12:04:28 +0100

Seen: 368 times

Last updated: Jan 15 '23