How do I display a full expression in sympy? - sympy

I am trying to use sympy in a Jupyter notebook to document and perform a series of mathematical cacluations in a reporducible way.
If I define the following:
from sympy import *
init_printing()
x, y, z = symbols("x y z")
x=y+z
x
then I can display the value of x (that is, y+z).
How do I display the full equation (x=y+z)?
Running Eq(x,y+z), even with evaluate=False) returns the expression with the value of x substituted (y+z=y+z).

I tried using Eq(S('x'),y+z), also Eq(S('x'),x) and sympy keep returning a boolean variable.
So I found a way to display it using the Ipython built-in functions:
from sympy import *
from IPython.display import display, Math
init_printing()
x, y, z = symbols("x y z")
x=y+z
display(Math('x = '+latex(x)))
I think that this is a more general solution to the problem.

Although you first declare x as a sympy.Symbol, once you perform the assignment x=y+z, x becomes an alias for y+z. Whenever you use x from that point after, x will be automatically translated by python as y+z.
If you insist on this workflow, you could use Eq(S('x'),y+z) to display the equation.

I know this isn't exactly the answer, but for those just looking for a neat print of the right-hand-side of a function f(x,y,z,...), you can just do f.subs(x,x) like so:
import sympy as sp
x,y,z=sp.symbols('x,y,z')
f=x+2*y+3*sp.exp(z)
f.subs(x,x)

Related

sympy function compose - bizzare results

I'm trying to compose two functions and I get a bizzare result
'''
#!/usr/bin/python
from sympy import *
init_printing(use_unicode=True)
x= symbols('x')
f = x/(x+1);
g = x/(x+2);
print(compose(f,g))
This shows : x/((x + 1)*(x + 2))
Should be x/(2x+2)
I don't get it. Does anyone has an idea?
Thanks
Despite being available in the top-level sympy namespace under the plain name compose, sympy.compose doesn't actually do general function composition.
sympy.compose is actually sympy.polys.polytools.compose. It's actually a function for polynomial composition. When you try to compose x/(x+1) and x/(x+2), it ends up interpreting these inputs as multivariate polynomials in 3 variables, x, 1/(x+1), and 1/(x+2), and the results are total nonsense.

SymPy integration of Matrix with multivariable entries

I am using Sympy to integrate a Sympy Matrix whose components depend on variables (x,y). Integrating with respect to a single variable x (or y) works, and returns the expected Matrix whose components are the integrals of the components of the original vector.
import sympy as sp
from sympy.abc import x,y
V = sp.Matrix(4,1,[1,x,y,x*y])
display(V)
# This works
I = sp.integrate(V,(x,0,1))
display(I)
Ultimately, I would like a double integral. I can accomplish this with the following
Ix = sp.integrate(V,(x,0,1))
I = sp.integrate(Ix,(y,0,1))
display(I)
My question is why the following does not seem to work.
I = sp.integrate(V,(x,0,1),(y,0,1))
The error I get is :
ValueError: Invalid limits given: (((x, 0, 1), (y, 0, 1)),)
Is this a bug? Or am I using the wrong syntax for the double integral with a Matrix type? This syntax works on components of the Matrix, i.e.
# This works
I3 = sp.integrate(V[3,0],(x,0,1),(y,0,1))
Thanks for confirming that this was a bug in SymPy. This is now fixed in SymPy. See https://github.com/sympy/sympy/pull/23277.
The other suggestion - using
I = V.integrate((x,0,1),(y,0,1))
may even be a nicer solution.

Sympy: prevent a subscripted symbol to be evaluated

Given a symbol s, which ultimately will be an Array, I want to define the following expression
A = Array([-s[1]/2, s[0]/2])
but I'd like A to be evaluated only when I compute some other expressions containing it, because s changes over time. I tried
A = UnevaluatedExpr(Array([-s[1]/2,s[0]/2]))
but I got the error TypeError: 'Symbol' object is not subscriptable, which make me think that some evaluation is performed on s.
Thanks for your patience, I'm just learning Sympy and I'm used to Maxima where this kind of construct is straightforward. To be more precise, with Maxima the full working code I'm trying to translate into Sympy is (in Maxima everything is a symbol, colon is the assignment operator, ev forces evaluation with custom values, the dot before diff is the vector scalar product):
A: [-s[2],s[1]]/2; /* define A in terms of subscripted symbols */
P1: [x1,y1];
P2: [x2,y2];
segment: P1+t*(P2-P1); /* --> [t*(x2-x1)+x1,t*(y2-y1)+y1] */
factor(integrate(ev(A,s=segment).diff(segment,t),t,0,1)); /* integrates the scalar product of A evaluated over segment and the derivative of segment */
Follow up
Thanks to Oscar answer I was able to come up with a working Sympy translation of the above Maxima code (improvements are welcomed!):
from sympy import *
def dotprod(*vectors): # scalar product, is there a built in better way?
return sum(Mul(*x) for x in zip(*vectors))
s = IndexedBase('s')
A = Array([-s[1]/2,s[0]/2])
t,x1,y1,x2,y2 = symbols('t x1 y1 x2 y2')
P1 = Array([x1,y1])
P2 = Array([x2,y2])
segment = P1 + t * (P2-P1)
dotprod(A.subs(s,segment),segment.diff(t)).integrate((t,0,1)).factor()
Apart from the IndexedBase magic the structure of the code in Maxima and Sympy is very similar.
I'm not sure I understand what you want. It's possible that your problem is better approached in a different way rather than using Array. In any case a direct answer to your question is that you can use IndexedBase to make a subscriptable symbol:
In [1]: s = IndexedBase('s')
In [2]: A = Array([-s[1]/2, s[0]/2])
In [3]: A
Out[3]:
⎡-s[1] s[0]⎤
⎢────── ────⎥
⎣ 2 2 ⎦

Using sympy.integrate on a function that involves int()

I'm trying to integrate functions in Python. scipy.integrate.quad seems to work ok; but just be sure I'd like to check the results against other integration code. It was suggested that I try sympy.integrate. Now the code for the functions I want to integrate contains int(), which I use to convert floats into ints. This is ok for quad, but not for sympy.integrate.
Here's a simple example that reproduces the error:
import sympy
def f(x):
return sympy.exp(int(x))
sympy.symbols('x')
print(sympy.integrate(f(x),(x,0,2)))
This yields the error: TypeError: can't convert symbols to int
So is there a way to integrate functions that involve int() with scipy.integrate?
Thanks
To use integrate f must be a SymPy symbolic function which disallows your particular use of int. int(x) where x is a Symbol will always yield a type error however you could represent this symbolically using the floor function:
def f(x):
return sympy.exp(sympy.floor(x))
However, using floor may defeat some of the purpose of using SymPy in the first place because it will probably prevent discovery of an analytic solution as the following python session demonstrates:
>>> from sympy import *
>>> x = symbols("x")
>>> integrate(exp(floor(x)), (x, 0, 2)) # use of floor prevents evaluated result
Integral(exp(floor(x)), (x, 0, 2))
Though you can use the evalf method to compute a numeric result (which is ultimately performed by mpmath):
>>> integrate(exp(floor(x)), (x, 0, 2)).evalf()
3.7
(perhaps this result suggests sympy could better handle this integral? Wolfram Alpha computes this as 1 + e = 3.71828... so I suppose there is at least a floating point precision bug here too - see comment re ceiling)
In any case, I don't know if you consider that an appropriate result considering the version of f without floor:
>>> integrate(exp(x), (x, 0, 2))
-1 + exp(2)
>>> _.evalf()
6.38905609893065

how pass variable as string, then later use it as sympy symbol?

I have need to pass to a function, both the integrand and also the integration variable as string. It is not possible to do it in other ways (too long to explain).
The question is, how to do the standard thing, which is x = symbols('x') to define the integration variable (which is passed as string) inside the called function in order to use it in the next call to integrate?
Here is a MWE, and showing what I tried
from sympy import *
def foo(integrand,var):
var = symbols(var)
anti = integrate(integrand,x)
return anti
foo("x*cos(x)","x")
This ofcourse does not work, since var is string on both sides of var = symbols(var)
Then I tried to use eval to first convert the string var which is "x" to variable x, but this does not work either,
x = eval(var)
x = symbols('x')
This fail since x is not defined.
Ofcourse, I could do this
from sympy import *
x = symbols('x')
def foo(integrand,var):
anti = integrate(integrand,x)
return anti
foo("x*cos(x)","x")
But this is not what I want, since the function foo being called, needs to be called with different integration variables from outside, and these have to be strings.
Any suggestion how to handle this? Notice that the issue is with the integration variable only. sympy integrate accepts the integrand as string with no problem, but not the integration variable. So this would also fail
def foo(integrand,var):
anti = integrate(integrand,var)
Python 4.7 with sympy 1.5
Everything is almost fine. Just use var instead of x as the second arg of integrate: it is the name of the Python variable that is connected to the SymPy symbol x:
>>> def foo(integrand,var):
... var = symbols(var)
... anti = integrate(integrand,var)
... return anti
...
>>> foo("x*cos(x)","x")
x*sin(x) + cos(x)