Expand along a specific symbol in sympy - python

When I do symbolic integration using Sympy, I would like to expand an expression along a specific symbol so that later I can collect and integrate w.r.t. that symbol. Is there a way to do such "expand" without altering the forms of other (irrelevant) symbols?
For example, consider this Python code and run results:
>>> from sympy import *
>>> var('x,a,b,c')
(x, a, b, c)
>>> f = (a + 1) * a + x * (b + exp(-c*x))
>>> collect(f, (exp(-c*x), x))
a*(a + 1) + x*(b + exp(-c*x))
>>> collect(expand(f), (exp(-c*x), x))
a**2 + a + b*x + x*exp(-c*x)
The outputs are all expected. Without "expand" first, "collect" just gives me back the original form. If we use "expand" first, I get what I want. Imagine if we have a sum of many above 'f' and symbols b and c are complex expressions, the integration will take a long time if we use the original form of f. Indeed, I have an integration taking seconds to complete if "expand" is applied first, but could not be finished after nearly one hour of run.
The problem of "expand" is that it can be expensive to "fully expand" the expression. In the above example, we see a*(a+1) was also expanded (and took computing time).
I have expressions (to be integrated later), each expanded to about 40 thousand terms. The result of expansion, as function of x, is similar to the form in the above example -- I knew it must be of that form. The most time (if it would ever finish) was spent on expanding those terms having nothing to do with 'x'. Can I avoid those unnecessary expansions?

You could try masking off the non-x-containing terms like this:
>>> def ex(e,x):
... m = [i for i in e.atoms(Mul) if not i.has(x)]
... reps = dict(zip(m,[Dummy() for i in m]))
... return expand(e.xreplace(reps)).subs([(v,k) for k,v in reps.items()])
...
>>> f = (a + 1) * a + x * (b + exp(-c*x))
>>> ex(f,x)
a*(a + 1) + b*x + x*exp(-c*x)
Notice that only the x-containing term was expanded.
Also, instead of using expand, you might only want to use expand_mul; expand does several types of expansion (see docstring).

Related

Sympy subs does not working for subexpression. Is there a way to solve this?

subs (from sympy library in Python) does not replace a subexpression in all cases except simple ones. MATLAB copes with this task perfectly. Is it possible to somehow achieve the same result as in MATLAB?
Sympy
MATLAB
This fails because the product 2*(x + y) automatically expands to the sum of 2x + 2*y, as #hpaulj points out. And #oscarbenjamin points out that re-arranging your substitution so it targets only an atomic part of the expression you desire to replace will work.
In addition, if you backsubstitute to restore the original atom you will see if the substitution was not able to be fully done while retaining the original variables:
>>> f = (x + y)**2 + 1/(4*x + 4*y + sin(2*x + 2*y))
>>> (f+x).subs(x,z-y).subs(y,z-x)
x + z**2 + 1/(4*z + sin(2*z))

How to solve equations in python

I try to write a script that simulates a resistor. It takes 2 arguments for example P and R and it should calculate all missing values of this resistor.
The problem is that I don't want to write every single possible equation for every value. This means I want to write something like (U=RxI, R=U/R, I=U/R , P=UxI) and the script should then complete all equation with the given values for every equation.
For example, something like this:
in R=10
in I=5
out U=R*I
out P=I**2 * R
You can use https://pypi.org/project/Equation/ Packages.
Example
>>> from Equation import Expression
>>> fn = Expression("sin(x+y^2)",["y","x"])
>>> fn
sin((x + (y ^ (2+0j))))
>>> print fn
\sin\left(\left(x + y^{(2+0j)}\right)\right)
>>> fn(3,4)
(0.42016703682664092+0j)
Sympy
Second: https://github.com/sympy/sympy/wiki
Arbitrary precision integers, rationals and floats, as well as symbolic expressions
Simplification (e.g. ( abb + 2bab ) → (3ab^2)), expansion (e.g. ((a+b)^2) → (a^2 + 2ab + b^2)), and other methods of rewriting expressions
Functions (exp, log, sin, ...)
Complex numbers (like exp(Ix).expand(complex=True) → cos(x)+Isin(x))
Taylor (Laurent) series and limits
Differentiation and integration
In vanilla python, there is no solution as general as the one you are looking for.
The typical solution would be to write an algorithm for every option (only given U, only given R) and then logically select which option to execute.
You may also want to consider using a module like SymPy, which has a solver module that may be more up your alley.

Is there a way to expand polynomials using Sympy?

Looking at the Sympy documentation, there seems to be an "expand" function which can be called upon to expand polynomial expressions; however, in practice, this is not working for me. I started off using imaginary numbers:
import sympy
sympy.expand((x - 1)(x + i)(x - i))
Hoping for "x^3 - x^2 + x - 1", however, instead, this returned the following error: module 'sympy' has no attribute 'expand'
I then changed the expression I wanted to be expanded, as this had caused me to assume that Sympy could not handle complex numbers, to what can be seen below:
import sympy
sympy.expand((x - 1)(x - 1)(x + 1))
Yet this returned the same error.
The imaginary i is represented by the capital I in sympy. To have a multiplication, an * needs to be used explicitly. Also, in Python ^ is strictly reserved for a boolean (or bitwise) exclusive or. Power is represented as **.
from sympy import symbols, I, expand
x = symbols('x')
print(expand((x - 1)*(x + I)*(x - I)))
Output: x**3 - x**2 + x - 1
Note that an alternative way to call expand() is as expression.expand() (or ((x - 1)*(x + I)*(x - I)).expand() as in the example). Often this is a handy way to concatenate several operations.
I don't have problem to run
import sympy
x = sympy.Symbol('x')
i = sympy.Symbol('i')
sympy.expand( (x - 1)*(x + i)*(x - i) )
and this gives me
-i**2*x + i**2 + x**3 - x**2
The only idea: you created file with name sympy.py and now import sympy loads your file instead of module sympy and it can't find expand in your file. You have to rename your file sympy.py to something different (which is not name of other module).
But you didn't add full error message in question so I can't confirm it.

Rounding coefficients of a symbolic expression in SymPy

I'm currently trying to calculate a negative group delay of analog filters by using symbolic calculations in Python. The problem that I'm currently trying to resolve is to get rid of some very small imaginary coefficients.
For example, consider fraction with such numerator (imaginary parts are bolded):
(-1.705768*w^18 + 14.702976409432*w^16 + 1.06581410364015e-14*I*w^15 - 28.7694094371724*w^14 - 9.94759830064144e-14*I*w^13 + 59.0191623753299*w^12 + 5.6843418860808e-14*I*w^11 + 24.7015297857594*w^10 - 1.13686837721616e-13*I*w^9 - 549.093511217598*w^8 - 5.6843418860808e-14*I*w^7 + 1345.40434657845*w^6 + 2.27373675443232e-13*I*w^5 - 1594.14046181284*w^4 - 1.13686837721616e-13*I*w^3 + 980.58940367608*w^2 - 254.8428594382)
Is there any way to automatically round those small coefficients, so they would be equal 0 (in general any negligligible values)? Or at least, can I somehow filter imaginary values out? I've tried to use re(given_fraction), but it couldn't return anything. Also standard rounding function can't cope with symbolic expressions.
The rounding part was already addressed in Printing the output rounded to 3 decimals in SymPy so I won't repeat my answer there, focusing instead of dropping imaginary parts of coefficients.
Method 1
You can simply do re(expr) where expr is your expression. But for this to work, w must be known to be a real variable; otherwise there is no way for SymPy to tell what the real part of (3+4*I)*w is. (SymPy symbols are assumed to be complex unless stated otherwise.) This will do the job:
w = symbols('w', real=True)
expr = # your formula
expr = re(expr)
Method 2
If for some reason you can't do the above... another, somewhat intrusive, way to drop the imaginary part of everything is to replace I with 0:
expr = expr.xreplace({I: 0})
This assumes the expression is already in the expanded form (as shown), so there is no (3+4*I)**2, for example; otherwise the result would be wrong.
Method 3
A more robust approach than 2, but specialized to polynomials:
expr = Poly([re(c) for c in Poly(expr, w).all_coeffs()], w).as_expr()
Here the expression is first turned into a polynomial in w (which is possible in your example, since it has a polynomial form). Then the real part of each coefficient is taken, and a polynomial is rebuilt from them. The final part as_expr() returns it back to expression form, if desired.
Either way, the output for your expression:
-1.705768*w**18 + 14.702976409432*w**16 - 28.7694094371724*w**14 + 59.0191623753299*w**12 + 24.7015297857594*w**10 - 549.093511217598*w**8 + 1345.40434657845*w**6 - 1594.14046181284*w**4 + 980.58940367608*w**2 - 254.8428594382

Trigonometric identities with Python and Sympy, tan(A/2) = (sin A )/(1 + cos A)

I'm not sure how to get Sympy to perform / simplify these types of identities?
It does things like sin(a + b), but doesn't seem to do others (like the one in the title)
One approach is to try various combinations of simplification functions/methods such as rewrite and simplify. For example, the following gives the result you want:
import sympy as sp
x = sp.var('x', real = True)
f = sp.tan(x/2)
sp.re(f.rewrite(sp.exp).simplify().rewrite(sp.sin)).simplify()
sin(x)/(cos(x) + 1)

Categories