0

I am trying to understand about sympy's symbolic functions:

import sympy from sympy.abc import x,y,z

with sympy.evaluate(False):
    print(sympy.sympify("diff(x,x)").func)
    print(sympy.parse_expr("diff(x, x)", local_dict={'diff':sympy.Derivative}).func)
    print(sympy.sympify("Derivative(x,x)").func)
    pass

This puts out:

Piecewise
<class 'sympy.core.function.Derivative'>
<class 'sympy.core.function.Derivative'>

This example should illustrate that diff is not a symbolic function yet Derivative is. sympy.sympify("diff(x,x)").func results in Piecewise. What exactly makes a function in sympy 'symbolic'? Why don't both of the functions belong to <class 'sympy.core.function.Derivative'>?

I tried to test on a few examples if a function is symbolic using:

list_of_funcs = [sin, cos, tan, sec, csc, cot, sinh, cosh, tanh, sech, csch, coth, asin, acos, atan, asec, acsc, acot, asinh, acosh, atanh, asech, acsch, acoth, log, log, log, exp, <class 'sympy.concrete.summations.Sum'>, <class 'sympy.concrete.products.Product'>, Piecewise, jacobi, Piecewise]
with sympy.evaluate(False):
    for f in list_of_funcs:
        if issubclass(f, sympy.Basic):
            print(f'{f}: True')

It returned True for all yet as far as I understood Piecewise is not symbolic. Could you help me finding a way to test if a function is symbolic?

  • It would be easier to follow your question if you showed the results of all those `print` statements. Without that we have to either "run" the code mentally, or start up a `sympy` session to test them there. Many of us are either too dumb or too lazy to do that! – hpaulj Dec 14 '22 at 16:59
  • That first `func` is `Piecewise((x, Eq(1, 0)), (1, Eq(1, 1)), (0, True))`. `diff(x,x, evaluate=False)` does the same as `Derivative(x,x)`. So somehow the context plus `sympify` forces a different result. `diff` is a Python function, whose code you can examine. It isn't a `sympy` function. – hpaulj Dec 14 '22 at 21:12

2 Answers2

1

Answering this question without going too deep into coding concepts is not easy, but I can give it a try.

SymPy exposes many functions:

  • cos, sin, exp, Derivative, Integral... we can think of them as symbolic functions. Let's say you provide one or more arguments, then:
    • the function might evaluate to some symbolic numerical value. For example, cos(0) will return the symbolic number 1.
    • the function might return an "unevaluated" object. For example, cos(x) returns cos(x): this is a symbolic expression of type cos (as you have seen by running the func attribute). Similarly, you can create a derivative object Derivative(expr, x): this is a symbolic expression that represents a derivative, it doesn't actually compute the derivative!
  • Unevaluate functions, for example Function("f")(x), which will render as f(x): this is a symbolic expression of type f.
  • diff, integrate, series, limit, ... : those are ordinary python functions (for example, created with def diff(...)) that are going to apply some operation to a symbolic expression. When you call diff(expr, x) you are asking SymPy to compute the derivative of expr with respect to x. What if you wanted to represent the derivative without actually computing it? You write Derivative(expr, x).

So, going back to your example:

sympy.parse_expr("diff(x, x)", local_dict={'diff':sympy.Derivative})

this can be easily simplified to:

sympy.parse_expr("Derivative(x, x)")

A few more "relationships":

  • diff and Derivative
  • integrate and Integral
  • limit and Limit
Davide_sd
  • 10,578
  • 3
  • 18
  • 30
1

Think of "symbolic" functions as nouns and "non symbolic" as verbs.

noun-like        verb-like
----------       ---------
Integral         integrate
Derivative       diff
Sum              summation
Product          product

Those that are Python functions (I think what you mean by non-symbolic) emit some evaluated form of something that could also exist in an unevaluated form, e.g. prod(x, (x, 1, 5)) -> 120; Product(x, (x, 1, 5)) -> no change.

It would be better to refer to them in some other way. What I think you mean is "evaluated" vs "non-evaluated" (since almost all of SymPy's functions will return SymPy objects with "symbols", even if numeric).

If the type(thing) -> function it is not a class itself, it is a Python function. If you check the type of cos or Sum you will not get function as the result.

Whereas some of the evaluates and unevaluated forms may have different names (Sum vs summation) others, like Add are evaluative by default but you can use the evaluate=False arg to stop that: Add(x, x) = x + x != Add(x,x,evaluate=False). Those which are evaluative can be made non-evaluative by passing evaluate=True, e.g. Derivative(x, x, evaluate=True) -> 1.

smichr
  • 16,948
  • 2
  • 27
  • 34
  • Thanks a lot, I really like the metaphor! Yet I don't fully understand why sin, cos, etc are 'verbs'. https://docs.sympy.org/latest/modules/functions/elementary.html#sympy-functions-elementary-trigonometric There is a seperate sympy class for them. Will they be used in the unevaluated case and the python function in the evaluated case? –  Dec 15 '22 at 06:51
  • Almost every function has some basic evaluation that takes place at instantiation - that evaluation is the "verb" character, e.g. `cos(0) -> 1` whereas `cos(0, evaluate=False) -> cos(0)`. There is no "noun" form of `cos` however, only the use of `evaluate=False` in the call keeps it from taking action on certain arguments. – smichr Dec 15 '22 at 07:55