How to extract common factors of trigonometric functions using sympy? - python

I am new to using sympy. I checked the tutorial on the official website. There is only the "sym.collect" function for extracting common factors, but it does not support the common factors of trigonometric functions.
Here is my code:
F0,w = symbols('F0,w')
m1,m2,c,k1,k2,t = symbols('m1,m2,c,k1,k2,t')
c1, c2, d1, d2 = symbols('c1,c2,d1,d2')
res = -F0*sin(t*w) + c*c1*w*cos(t*w) - c*c2*w*sin(t*w) - c*d1*w*cos(t*w) + \
c*d2*w*sin(t*w) + c1*k1*sin(t*w) + c1*k2*sin(t*w) - \
c1*m1*w**2*sin(t*w) + c2*k1*cos(t*w) + c2*k2*cos(t*w) - c2 * \
m1*w**2*cos(t*w) - d1*k2*sin(t*w) - d2*k2*cos(t*w)
sym.collect(res,sin)
turn out:
ValueError: keyfunc gave non-binary output
The result I want to get is:
sin(wt)*(-F0- c*c2*w + c*d2*w + ....) + cos(wt)*(c*c1*w + ...)
So how can I fix it?

The collection can be done by passing one or more expressions, too:
collect(mid, (sin(t*w), cos(t*w)))

I have solved it.
q = symbols('q')
mid = sym.collect(res1.subs(cos(t*w), q), q).subs(q, cos(t*w))

Related

Passing a matrix through multiple functions

A little complicated but I'll try to explain best I can, but I have values I am trying to calculate that are based on two other functions with multiple inputs. In the code below, my inputs are various theta values which then should create an array of m & n values. From the m & n arrays, I then need to calculate the various Q_bar terms which should output an array for each term as well.
theta = np.array([0, 25, -80, 90, 20])
m = math.cos(math.radians(theta)) #[deg]
n = math.sin(math.radians(theta)) #[deg]
Q_bar11 = Q11*(m**4) + 2*(Q12 + 2*Q66)*(n**2)*(m**2) + Q22*(n**4)
Q_bar12 = (Q11 + Q22 - 4*Q66)*(n**2)*(m**2) + Q12*(n**4 + m**4)
Q_bar16 = (Q11 - Q12 - 2*Q66)*n*(m**3) + (Q12 - Q22 + 2*Q66)*(n**3)*m
Q_bar22 = Q11*(n**4) + 2*(Q12 + 2*Q66)*(n**2)*(m**2) + Q22*(m**4)
Q_bar26 = (Q11 - Q12 - 2*Q66)*(n**3)*m + (Q12 - Q22 + 2*Q66)*n*(m**3)
Q_bar66 = (Q11 + Q22 - 2*Q12 - 2*Q66)*(n**2)*(m**2) + Q66*(n**4 + m**4)
I've seen similar posts about passing arrays through functions however I have not been successful in implementing them, any help would be much appreciated!
Instead of passing a list into function. pass each values differently might help!
deg = np.array([math.cos(math.radians(theta[i])) for i in range(5)])
news = pd.Series(theta,deg)
Sorry, I couldn't understand the q part exactly but if you explain it deeper than I'll try to help it too

Why is .subs not working in JupyterLab Python

I have a very long symbolic expression in JupyterLab which I am trying to substitute values in. The expression is very long so I won't elaborate on what it is unless it is necessary, but I have a simplified symbolic expression which outputs (this is using SymPy). I am trying to use the .subs command as seen below, but this is not replacing any of the variables I have and rather just outputting the same symbolic notation. I have used .subs before, but in a very limited capacity so I am not sure if there is a type issue or something like that. All of these variables represent those in the symbolic notation.
replacements=[(t1,np.pi/2), (t1d,1), (t1dd,1), (l1,1), (l2,1), (m1,1), (m2,1), (m3,1), (g,-10)]
Lagrangian = Lagrangian.subs(replacements)
display(Lagrangian)
These variables are defined in the following way using the SymPy command symbols and then are manipulated to get the following expression. Not all of these symbols defined are in the final expression and are intermediary symbols.
l1, l2= sp.symbols('l_1, l_2')
y1, y2, y3, y1d, y2d, y3d = sp.symbols('y_1, y_2, y_3, ydot_1, ydot_2, ydot_3')
t1, t2, t1d, t2d= sp.symbols('theta_1, theta_1, thetadot_1, thetadot_2')
t1dd, t2dd = sp.symbols('thetaddot_1, thetaddot_2')
m1, m2, m3 = sp.symbols('m_1, m_2, m_3')
I1, I2 = sp.symbols('I_1, I_2')
g = sp.symbols('g')
When it comes to Lagrangian, it is just a manipulatioon of alll of these variables. I will show some of the following manipulations down below, but I do not think that the are not very necessary in causing the issue.
I1 = 1/3*m1*l1**2
I2 = 1/3*m2*l2**2
t2 = sp.acos(l1/l2*sp.sin(t1))
t2d = sp.diff(t2, t1) * t1d
y1 = 0.5*l1*sp.cos(t1)
y1d = sp.diff(y1,t1) * t1d
y2 = l1*sp.cos(t1) + 0.5*l2*sp.cos(t2)
y2d = 2*y1d - 0.5*l2*sp.sin(t2)*t2d
y3 = l1*sp.cos(t1) + l2*sp.cos(t2)
y3d = 2*y1d + 2*y2d
T = 0.5*m1*y1d**2 + 0.5*m2*y2d**2 + 0.5*m3*y3d**2 + 0.5*I1*t1d**2 + 0.5*I2*t2d**2
U = m1*g*y1 + m2*g*y2 + m3*g*y3
print('T=')
display(sp.simplify(T))
print('U=')
display(sp.simplify(U))
dTdTheta_dot = sp.diff(T,t1d)
dTdTheta = sp.diff(T,t1)
dUdTheta = sp.diff(U,t1)
#d_dt =
print('dT/dtheta_dot=')
display(sp.simplify(dTdTheta_dot))
print('dT/dTheta=')
display(sp.simplify(dTdTheta))
print('dU/dTheta=')
display(sp.simplify(dUdTheta))
A = (1/3)*l1**4*l2**2*m2*t1d**2*sp.sin(t1)*sp.cos(t1)**3
dA = (1/3)*l1**4*l2**4*m2*(2*t1d*t1dd*sp.sin(t1)*sp.cos(t1)**3+t1d**2*sp.cos(t1)*t1d*sp.cos(t1)**3+
t1d**2*sp.sin(t1)*3*sp.cos(t1)**2*(-sp.sin(t1)*t1d))
B = l1**2*((1/3)*l2**2*m2*l1**2*t1d*sp.sin(t1)**3*sp.cos(t1)-(1/3)*l2**4*m2*t1d*sp.cos(t1)*sp.cos(t1))
dB = l1**2*(((1/3)*l1**2*l2**2*m2*t1dd*sp.sin(t1)**3*sp.cos(t1) - (1/3)*l1**2*l2**2*m2*t1d*3*sp.sin(t1)**2*sp.cos(t1)*t1d*sp.cos(t1) +
(1/3)*l1**2/l2**2*m2*t1d*sp.sin(t1)**3*(-sp.sin(t1))*t1d) - ((1/3)*l1**4*m2*t1dd*sp.sin(t1)*sp.cos(t1)+
(1/3)*l2**4*m2*t1d*sp.cos(t1)*t1d*sp.cos(t1) + (1/3)*l2**4*m2*t1d*sp.sin(t1)*(-sp.sin(t1))*t1d))
C = l1**2*(l1**4*t1d*sp.sin(t1)**4 - 2*l1**2*l2**2*t1d*sp.sin(t1)**2 + l2**4*t1d)*((1/8)*m1*sp.sin(2*t1) + (3/8)*m2*sp.sin(2*t1) - (1/2)*m2)
dC = l1**2 * ((l1**4*(t1dd*sp.sin(t1)**4 + t1d*4*sp.sin(t1)**3*sp.cos(t1)*t1d) - 2*l1**2*l2**2*(t1dd*sp.sin(t1)**2 + t1d*2*sp.sin(t1)*sp.cos(t1)*t1d)+l2**4*t1dd) *
((1/8)*m1*sp.sin(2*t1) + (3/8)*m2*sp.sin(2*t1) - (1/2)*m2*sp.cos(2*t1)) + (l1**4*t1d*sp.sin(t1)**4 - 2*l1**2*l2**2*t1d*sp.sin(t1) + l2**4*t1d) *
((1/8)*m1*sp.cos(2*t1)*2*t1d + (3/8)*m2*sp.cos(2*t1)*2*t1d - (1/2)*m2*(-sp.sin(2*t1)*2*t1d)))
D = (4*m2*sp.sin(2*t1)-3*m3*sp.cos(2*t1)) * (l1**2*sp.sin(t1)**2-l2**2)**2
dD = (4*m2*sp.cos(2*t1)*2*t1d-3*m2*(-sp.sin(2*t1))*2*t1d)*((l1**2*sp.sin(t1)**2-l2**2)**2) + (4*m2*sp.sin(2*t1)-3*m3*sp.cos(2*t1))*(2*(l1**2*sp.sin(t1)-l2**2)*(2*l1**2*sp.sin(t1)*sp.cos(t1)*t1d))
E = (l1**2*sp.sin(t1)**2-l2**2)**-2
dE = -2*(l1**2*sp.sin(t1)-l2**2)**-3*(2*l1**2*sp.sin(t1)*sp.cos(t1)*t1d)
F = (dA+dB+dC+dD)*E + (A+B+C+D)*dE
display(sp.simplify(F))
Lagrangian = F - dTdTheta + dUdTheta
display(sp.simplify(Lagrangian))
Does anyone know why .subs doesn't work? Any help would be much appreciated. Thanks in advance!

Collect and substitute terms in very long and nested expressions with sympy

Short version:I want to collect and substitute some terms that I can clearly read in the expression but are not picked by sympy subs function.
I've done the symbolic computation in python, but in the end I will have to make these computation in C#. For this purpose, I'm trying to do some substitutions and partial numerical evaluations that I will hardcode in C#
As example this is one of the expressions (simple, I have to do this job on expressions ten times longer and with more levels of parenthesis):
from sympy import symbols
x,y,rho_0,v = symbols('x y rho_0 v')
expr = 4*x*(x**2 + y**2)*(7*(-1 + 2*(x**2 + y**2)/rho_0**2)**2 + 8 - 14*(x**2 + y**2)/rho_0**2)/rho_0**4 + (x**2 + y**2)**2*(56*x*(-1 + 2*(x**2 + y**2)/rho_0**2)/rho_0**2 - 28*x/rho_0**2)/rho_0**4
I don't know how to display equations in a better format here, sorry.
But the point is that I can clearly see that I can collect and substitute (x**2 + y**2)/rho_0**2 with very small manipulations
Using expr.subs((x**2 + y**2)/rho_0**2, v) has not given any result. I started using sympy last week so I don't know much yet, I think should try to navigate the expression from the innermost level of parenthesis, factorize and try to substitute, but I don't have any clue on how to do it.
subs has a hard time when a target contains an Add and is multiplied by a Rational. Targeting the Add first and continuing from there brings more success:
>>> expr
4*x*(x**2 + y**2)*(7*(-1 + (2*x**2 + 2*y**2)/rho_0**2)**2 + 8 - (14*x**2 +
14*y**2)/rho_0**2)/rho_0**4 + (x**2 + y**2)**2*(56*x*(-1 + (2*x**2 +
2*y**2)/rho_0**2)/rho_0**2 - 28*x/rho_0**2)/rho_0**4
Get the Rational separated from the Add
>>> factor_terms(expr)
4*x*(x**2 + y**2)*(7*(-1 + 2*(x**2 + y**2)/rho_0**2)**2 + 8 + 7*(-3 + 4*(x**2 +
y**2)/rho_0**2)*(x**2 + y**2)/rho_0**2 - 14*(x**2 + y**2)/rho_0**2)/rho_0**4
Do subs in two steps: make Add a Symbol and then Add/Pow the Symbol
>>> _.subs(x**2+y**2, v).subs(v/rho_0**2, v)
4*v*x*(7*v*(4*v - 3) - 14*v + 7*(2*v - 1)**2 + 8)/rho_0**2
Simplify if desired
>>> _.simplify()
4*v*x*(56*v**2 - 63*v + 15)/rho_0**2

Collecting like term of an expression in Sympy

I am currently dealing with functions of more than one variable and need to collect like terms in an attempt to simplify an expression.
Say the expression is written as follows:
x = sympy.Symbol('x')
y = sympy.Symbol('y')
k = sympy.Symbol('k')
a = sympy.Symbol('a')
z = k*(y**2*(a + x) + (a + x)**3/3) - k((2*k*y*(a + x)*(n - 1)*(-k*(y**2*(-a + x) + (-a + x)**3/3) + k*(y**2*(a + x) + (a + x)**3/3)) + y)**2*(-a + k*(n - 1)*(y**2 + (a + x)**2)*(-k*(y**2*(-a + x)))))
zEx = z.expand()
print type(z)
print type(zEx)
EDIT: Formatting to add clarity and changed the expression z to make the problem easier to understand.
Say z contains so many terms, that sifting through them by eye. and selecting the appropriate terms, would take an unsatisfactory amount of time.
I want to collect all of the terms which are ONLY a multiple of a**1. I do not care for quadratic or higher powers of a, and I do not care for terms which do not contain a.
The type of z and zEx return the following:
print type(z)
print type(zEx)
>>>
<class 'sympy.core.add.Add'>
<class 'sympy.core.mul.Mul'>
Does anyone know how I can collect the terms which are a multiple of a , not a^0 or a^2?
tl'dr
Where z(x,y) with constants a and k described by z and zEx and their type(): How can one remove all non-a terms from z AND remove all quadratic or higher terms of a from the expression? Such that what is left is only the terms which contain a unity power of a.
In addition to the other answers given, you can also use collect as a dictionary.
print(collect(zEx,a,evaluate=False)[a])
yields the expression
k*x**2 + k*y**2
In the end it is just an one-liner. #asmeurer brought me on the right track (check the comments below this post). Here is the code; explanations can be found below:
from sympy import *
from sympy.parsing.sympy_parser import parse_expr
import sys
x, y, k, a = symbols('x y k a')
# modified string: I added a few terms
z = x*(k*a**9) + (k**1)*x**2 - k*a**8 + y*x*(k**2) + y*(x**2)*k**3 + x*(k*a**1) - k*a**3 + y*a**5
zmod = Add(*[argi for argi in z.args if argi.has(a)])
Then zmod is
a**9*k*x - a**8*k + a**5*y - a**3*k + a*k*x
So let's look at this more carefully:
z.args
is just a collection of all individual terms in your expression (please note, that also the sign is parsed which makes things easier):
(k*x**2, a**5*y, -a**3*k, -a**8*k, a*k*x, a**9*k*x, k**2*x*y, k**3*x**2*y)
In the list comprehension you then select all the terms that contain an a using the function has. All these terms can then be glued back together using Add which gives you the desired output.
EDIT
The above returns all all the expressions that contain an a. If you only want to filter out the expressions that contain a with unity power, you can use collect and Mul:
from sympy import *
from sympy.parsing.sympy_parser import parse_expr
import sys
x, y, k, a = symbols('x y k a')
z2 = x**2*(k*a**1) + (k**1)*x**2 - k*a**8 + y*x*(k**2) + y*(x**2)*k**3 + x*k*a - k*a**3 + y*a**1
zc = collect(z2, a, evaluate=False)
zmod2 = Mul(zc[a], a)
then zmod2 is
a*(k*x**2 + k*x + y)
and zmod2.expand()
a*k*x**2 + a*k*x + a*y
which is correct.
With the updated z you provide I run:
z3 = k*(y**2*(a + x) + (a + x)**3/3) - k((2*k*y*(a + x)*(n - 1)*(-k*(y**2*(-a + x) + (-a + x)**3/3) + k*(y**2*(a + x) + (a + x)**3/3)) + y)**2*(-a + k*(n - 1)*(y**2 + (a + x)**2)*(-k*(y**2*(-a + x)))))
zc3 = collect(z3.expand(), a, evaluate=False)
zmod3 = Mul(zc3[a], a)
and then obtain for zmod3.expand():
a*k*x**2 + a*k*y**2
Is this the result you were looking for?
PS: Thanks to #asmeurer for all these helpful comments!
To iterate over the terms of an expression use expr.args.
I'm unclear what a is supposed to be, but the collect function may do what you want.

Solving Equations with Python and Sympy and getting numerical answers

I'm trying to use sympy to solve equations, but I would like to get a straight numerical answer. My script is like this:
from sympy import *
A,B,V=symbols('A,B,V')
eq1=Eq(630.26*(V-39.0)*V*(V+39)-A+B,0)
eq2=Eq(B,1.36*10**8*(V-39))
eq3=Eq(A,5.75*10**5*V*(V+39.0))
solve([eq1,eq2,eq3], [A,B,V], dict=True)
It gives me a long list of solutions that are in very expanded form. As an example,
[{V: 304.107299632956 - (-5162698.06009073 + 3004043.12120894*I)**(1/3)*(-0.5 + 0.866025403784439*I) - 32920.4469842867/((-5162698.06009073 + 3004043.12120894*I)**(1/3)*(-0.5 + 0.866025403784439*I)), B: 36054592750.082 - 1245.8292864816*I*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3) + 8.46536389385714e+17/((-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3)*(1.0 - 1.73205080756888*I)) + 719.279873914469*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3), A: 97854838797.9765 - 3957.60119254414*I*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3) - 3.13901978017549e-5*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(2/3) - 0.000285202926135405*I*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(2/3) + 2925.78725273524*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3)}, {V: 304.107299632956 - (-5162698.06009073 + 3004043.12120894*I)**(1/3) - 32920.4469842867/(-5162698.06009073 + 3004043.12120894*I)**(1/3), B: -1.05776452046245e-5*(4.0015351858068e+22 - 136000000.0*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3)*(25062979.0 - (-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3)))/(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3), A: 97854838797.9765 - 3936.45368131564*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3) + 5.56956529342379e+24/(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(2/3) + 6.43347823930771e-5*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(2/3) - 1.15822484655024e+18/(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3)}, {V: 304.107299632956 - 32920.4469842867/((-5162698.06009073 + 3004043.12120894*I)**(1/3)*(-0.5 - 0.866025403784439*I)) - (-5162698.06009073 + 3004043.12120894*I)**(1/3)*(-0.5 - 0.866025403784439*I), B: 36054592750.082 + 8.46536389385714e+17/((-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3)*(1.0 + 1.73205080756888*I)) + 719.279873914469*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3) + 1245.8292864816*I*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3), A: 97854838797.9765 + 2.31644969310047e+18/((-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3)*(1.0 + 1.73205080756888*I)) - 3.21673911965385e-5*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(2/3) + 5.57155558993486e-5*I*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(2/3) - 1.11391305868476e+25/((-4.36224183723014e+21 + 2.53827793755398e+21*I)**(2/3)*(1.0 - 1.73205080756888*I)) + 1968.22684065782*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3) + 3409.06888884012*I*(-4.36224183723014e+21 + 2.53827793755398e+21*I)**(1/3)}]
I can of course evaluate them with evalf but not all at once. I'm looking for a clean way receive the solutions of the equation in numerical form. I've made a workaround function for now. If there's a better way, I'd really like to know. My function to print answers is as follows:
def printeqsolve(input):
for i in input:
for j in i:
print "%r:" %j, i[j].evalf(chop=True)
print "---"
I'd also like to exclude non-real solutions, but when I restrict my symbols to Real no solutions are found.
You could also use nsolve but need to give a "good enough" guess and cannot pass Eq instances:
>>> nsolve([e.lhs - e.rhs for e in eq1,eq2,eq3], [A,B,V], [0,0,0])
matrix(
[['4442890172.68209'],
['4289299466.1432'],
['70.5389666628177']])
>>> nsolve([e.lhs - e.rhs for e in eq1,eq2,eq3], [A,B,V], [1e5,1e4,1e3])
matrix(
[['266367838273.086'],
['84646784928.5322'],
['661.402830356854']])
In Python 3.8.3, it should be written as follows; otherwise, an error will be reported:
nsolve([e.lhs - e.rhs for e in (eq1,eq2,eq3)], [A,B,V], [0,0,0])
(eq1,eq2,eq3)

Categories

Resources