how to solve a set of expressions in Python, not numerical calcualtion but purely analytic way?
I checked several functions of sympy which seems unable to do the work.
Assuming we are going to find the expression for x1,x2,x3 and x4 with following equations:
x1 = a*s+b*x2 + c
x2 = (m+n) * x3 + d
x3 = l*s + k*x4 + e
x4 = i*s + j*x1 + f
where x1,x2,x3,x4,a,b,c,d,e,f,i,j,k,l,m,n are all symbols.
How to reach the result for such problems in Python.
First get the "paper" equations into SymPy Equalities:
>>> from sympy.utilities.iterables import reshape
>>> eqs=reshape(S('''(
x1 = a*s+b*x2 + c
x2 = (m+n) * x3 + d
x3 = l*s + k*x4 + e
x4 = i*s + j*x1 + f)'''.strip().replace(
'\n',',').replace('=',',')), (2,))
>>> eqs = [Eq(*i) for i in eqs]
Then solve the equations (see solve docstring):
>>> solve(eqs, var('x1:5'))
{x4: (a*s + b*d + b*(e + l*s)*(m + n) + c - (-f - i*s)/j)/(-b*k*(m + n) + 1/j),
x3: e + k*(a*s + b*d + b*(e + l*s)*(m + n) + c - (-f - i*s)/j)/(-b*k*(m+ n) + 1/j) +
l*s,
x1: (-f - i*s)/j + (a*s + b*d + b*(e + l*s)*(m + n) + c - (-f - i*s)/j)/(j*(-b*k*(m
+ n) + 1/j)),
x2: d + (m + n)*(e + k*(a*s + b*d + b*(e + l*s)*(m + n) + c - (-f -
i*s)/j)/(-b*k*(m + n) + 1/j) + l*s)}
As noted here, however, this symbolic solution is not valid for all values...it is only valid if none of the coefficients in front of the symbols for which you are solving are zero.
Related
I needed to solve $sin(x)+a*sin(3x)=0$ symbolically for $x$.
import sympy as sp
a,x = sp.symbols('a,x')
roots = sp.solve([sp.sin(x)+a*sp.sin(3*x)],[x])
print(roots)
produced
(I*(-log((-a - sqrt(-3*a**2 + 2*a + 1) - 1)/a) + log(2))/2,),
(I*(-log(-sqrt((-a + sqrt(-3*a**2 + 2*a + 1) - 1)/a)) + log(2)/2),),
(I*(-log((-a + sqrt(-3*a**2 + 2*a + 1) - 1)/a) + log(2))/2,)]
whereas WolframAlpha produced a much "better" solution:
solve sin(x) + a sin(3 x) = 0
yields
x = π n and n element Z
x = 2 π n and a = -1/3 and n element Z
x = 2 π n - 2 tan^(-1)(sqrt((5 a - 4 sqrt((a - 1) a) - 1)/(3 a + 1))) and 3 a + 1!=0 and sqrt((a - 1) a)!=2 a and n element Z
x = 2 (tan^(-1)(sqrt((5 a - 4 sqrt((a - 1) a) - 1)/(3 a + 1))) + π n) and 3 a + 1!=0 and sqrt((a - 1) a)!=2 a and n element Z
x = 2 π n - 2 tan^(-1)(sqrt((5 a + 4 sqrt((a - 1) a) - 1)/(3 a + 1))) and 3 a + 1!=0 and 2 a + sqrt((a - 1) a)!=0 and n element Z
Question:
can the SymPy solver be configured to produce solutions in the way WolframAlpha does?
Is anything known why SymPy expresses the solutions via (complex) logarithms instead of arc tangents?
i am trying to fit an exponential curve through three given Points. But i get only very wrong results of fsolve or actual 0. I need this for my Bachelor Thesis so if anyone knows a better solution for the problem, it would be very kind to tell me this solution.
from numpy import *
from scipy.optimize import *
def myFunction(variables):
x1 = 1
y1 = 100
x2 = 5
y2 = 50
x3 = 10
y3 = 1
(a,k,b) = variables
y1 = a*exp(-x1*k)+b
y2 = a*exp(-x2*k)+b
y3 = a*exp(-x3*k)+b
#0 = a*k**2 * exp(-x1+k)
return ([a, k, b])
z = fsolve(myFunction,(1,0.1,5))
print(z)
this is my problem, i need to fit an e function through this 3 given points, and in addition the second derivation of the forumla should be 0
edit: 06.12.17
in some way i have now an improvement with a polynom, but does not really fit like it should.
The second Maximum should not be there.. :D
from numpy import *
from scipy.optimize import *
import matplotlib.pyplot as plt
def myFunction(z):
a = z[0]
b = z[1]
c = z[2]
d = z[3]
e = z[4]
f = z[5]
g = z[6]
x = [0, 10 ,15 ,20 ,50 ,100]
y = [10 ,90 ,100 ,90 ,50 ,10]
s = [0, 10, 1, 0, 0, 0]
F = empty((8))
F[0] = a*x[0]**6 + b*x[0]**5 + c*x[0]**4 + d*x[0]**3 + e*x[0]**2 + f*x[0]**1 + g - y[0]
F[1] = a*x[1]**6 + b*x[1]**5 + c*x[1]**4 + d*x[1]**3 + e*x[1]**2 + f*x[1]**1 + g - y[1]
F[2] = a*x[2]**6 + b*x[2]**5 + c*x[2]**4 + d*x[2]**3 + e*x[2]**2 + f*x[2]**1 + g - y[2]
F[3] = a*x[3]**6 + b*x[3]**5 + c*x[3]**4 + d*x[3]**3 + e*x[3]**2 + f*x[3]**1 + g - y[3]
F[4] = a*x[4]**6 + b*x[4]**5 + c*x[4]**4 + d*x[4]**3 + e*x[4]**2 + f*x[4]**1 + g - y[4]
F[5] = a*x[5]**6 + b*x[5]**5 + c*x[5]**4 + d*x[5]**3 + e*x[5]**2 + f*x[5]**1 + g - y[5]
F[6] = 6*a*x[3]**5 + 5*b*x[3]**4 + 4*c*x[3]**3 + 3*d*x[3]**2 + 2*e*x[3]**1 + f - s[3]
F[7] = 6*a*x[5]**5 + 5*b*x[5]**4 + 4*c*x[5]**3 + 3*d*x[5]**2 + 2*e*x[5]**1 + f - s[5]
return F
zGuess = array([1,1,1,1,1,1,1,1])
z = fsolve(myFunction,zGuess)
print(z)
x_axis = linspace(0,100,100)
y_axis = z[0]*x_axis**6 + z[1]*x_axis**5 + z[2]*x_axis**4 + z[3]*x_axis**3 + z[4]*x_axis**2 + z[5]*x_axis**1 + z[6]
plt.plot(x_axis, y_axis)
plt.show()
edit 07.12.17
the whole signal should look like the data of the second example. But the difficulty is in the part of the first example. My suggestion was to use 2 polynoms, but my prof would prefer an polynom x<20 and an e function x>20. The overlapping of both should also be very smooth.
Well fsolve find the roots of a function, does not really do a non-linear fit. I must admit I don't actually quite get what you want to achieve with your code. If you want to do a nonlinear fit (since you are talking about exponential functions here) you may want to check my notebook here https://github.com/michelucci/Regression-with-Python/blob/master/(Non)%20linear%20fit%20in%20Python.ipynb that I hope can point you in the right direction. It contains first a part on linear regression and then a non-linear tutorial.
You can check curve_fit() python function in the scipy.optimize library. That should help you with what you want to do.
Let me know if that helps you.
You may also want to check this link to better understand what a non-linear fit is https://en.wikipedia.org/wiki/Nonlinear_regression
Best, Umberto
The equation of an ellipse is:
sqrt((x-a1)**2 + (y-b1)**2) + np.sqrt((x-a2)**2 + (y-b2)**2) = c
The focii are (a1, b1) and (a2, b2). c is also known. How do I draw this in python using matplotlib?
Thanks for your help.
You can represent the ellipse parametrically in some variable t. You could look into Wikipedia to see how this can be done, for instance.
In the following code, I've derived the parameters necessary for the parametric form from the parameters that you've supplied.
# Example focii and sum-distance
a1 = 1
b1 = 2
a2 = 5
b2 = 7
c = 9
# Compute ellipse parameters
a = c / 2 # Semimajor axis
x0 = (a1 + a2) / 2 # Center x-value
y0 = (b1 + b2) / 2 # Center y-value
f = np.sqrt((a1 - x0)**2 + (b1 - y0)**2) # Distance from center to focus
b = np.sqrt(a**2 - f**2) # Semiminor axis
phi = np.arctan2((b2 - b1), (a2 - a1)) # Angle betw major axis and x-axis
# Parametric plot in t
resolution = 1000
t = np.linspace(0, 2*np.pi, resolution)
x = x0 + a * np.cos(t) * np.cos(phi) - b * np.sin(t) * np.sin(phi)
y = y0 + a * np.cos(t) * np.sin(phi) + b * np.sin(t) * np.cos(phi)
# Plot ellipse
plt.plot(x, y)
# Show focii
plt.plot(a1, b1, 'bo')
plt.plot(a2, b2, 'bo')
plt.axis('equal')
plt.show()
This gives what you need:
you need 2 lists or arrays of X, Y such that the elements satisfy the ellipse equation
the usual ellipse plotting solutions parameterize the ellipse equation by central (or focal) angle to make the X,Y functions single valued for the angle in 0 to 2pi
I showed a solution in Drawing elliptical orbit in Python (using numpy, matplotlib)
Y as a function of X with a hack to "feel out" the xrange, then piece together the dual Y solutions for each x
just the minimum mods to that code to put in your equation, would fail for a1 = a2
the symbolic solution takes a minute or so runtime
import numpy as np
import matplotlib.pyplot as plt
from sympy import *
# sqrt((x-a1)**2 + (y-b1)**2) + np.sqrt((x-a2)**2 + (y-b2)**2) = c
coeffs = [1, 0, -1, 0, 4]
xs = [coeffs[0], coeffs[2]]
def ysolv(coeffs):
x,y,a1,b1,a2,b2,c = symbols('x y a1 b1 a2 b2 c', real = True)
ellipse = sqrt((x-a1)**2 + (y-b1)**2) + sqrt((x-a2)**2 + (y-b2)**2) - c
y_sols = solve(ellipse, y)
print(*y_sols, sep='\n')
num_coefs = [(a, f) for a, f in (zip([a1,b1,a2,b2,c], coeffs))]
y_solsf0 = y_sols[0].subs(num_coefs)
y_solsf1 = y_sols[1].subs(num_coefs)
print(y_solsf0, '\n', y_solsf1)
f0 = lambdify([x], y_solsf0)
f1 = lambdify([x], y_solsf1)
return f0, f1
f0, f1 = ysolv(coeffs)
y0 = [f0(x) for x in xs]
y1 = [f1(x) for x in xs]
def feeloutXrange(f, midx, endx):
fxs = []
x = midx
while True:
try: f(x)
except:
break
fxs.append(x)
x += (endx - midx)/200
return fxs
midx = (min(xs) + max(xs))/2
xpos = feeloutXrange(f0, midx, max(xs))
xnegs = feeloutXrange(f0, midx, min(xs))
xs_ellipse = xnegs[::-1] + xpos[1:]
y0s = [f0(x) for x in xs_ellipse]
y1s = [f1(x) for x in xs_ellipse]
ys_ellipse = y0s + y1s[::-1] + [y0s[0]] # add y start point to end to close drawing
xs_ellipse = xs_ellipse + xs_ellipse[::-1] + [xs_ellipse[0]] # added x start point
plt.plot(xs_ellipse, ys_ellipse)
plt.show()
(-c*sqrt((a1**2 - 2*a1*a2 + a2**2 + b1**2 - 2*b1*b2 + b2**2 - c**2)*(a1**2 + 2*a1*a2 - 4*a1*x + a2**2 - 4*a2*x + b1**2 - 2*b1*b2 + b2**2 - c**2 + 4*x**2))*(-b1 + b2 + c)*(b1 - b2 + c) + (b1**2 - 2*b1*b2 + b2**2 - c**2)*(-a1**2*b1 + a1**2*b2 + 2*a1*b1*x - 2*a1*b2*x + a2**2*b1 - a2**2*b2 - 2*a2*b1*x + 2*a2*b2*x - b1**3 + b1**2*b2 + b1*b2**2 + b1*c**2 - b2**3 + b2*c**2))/(2*(-b1 + b2 + c)*(b1 - b2 + c)*(b1**2 - 2*b1*b2 + b2**2 - c**2))
(c*sqrt((a1**2 - 2*a1*a2 + a2**2 + b1**2 - 2*b1*b2 + b2**2 - c**2)*(a1**2 + 2*a1*a2 - 4*a1*x + a2**2 - 4*a2*x + b1**2 - 2*b1*b2 + b2**2 - c**2 + 4*x**2))*(-b1 + b2 + c)*(b1 - b2 + c) + (b1**2 - 2*b1*b2 + b2**2 - c**2)*(-a1**2*b1 + a1**2*b2 + 2*a1*b1*x - 2*a1*b2*x + a2**2*b1 - a2**2*b2 - 2*a2*b1*x + 2*a2*b2*x - b1**3 + b1**2*b2 + b1*b2**2 + b1*c**2 - b2**3 + b2*c**2))/(2*(-b1 + b2 + c)*(b1 - b2 + c)*(b1**2 - 2*b1*b2 + b2**2 - c**2))
sqrt(-48*x**2 + 192)/8
-sqrt(-48*x**2 + 192)/8
the other answers used the parametric transform approach
I especially like showing sympy solving the equation for you rather than someone hand solving it
the symbolic expression only needs be found once for a particular Ellipse parameterization, then the symbolic expression can simply be hard coded:
"""
for Ellipse equation:
sqrt((x-a1)**2 + (y-b1)**2) + sqrt((x-a2)**2 + (y-b2)**2) = c
sympy solution to Ellipse equation, only have to run once to get y_sols
symbolic expression to paste into ysolv below
#def symEllipse():
# x,y,a1,b1,a2,b2,c = symbols('x y a1 b1 a2 b2 c', real = True)
# ellipse = sqrt((x-a1)**2 + (y-b1)**2) + sqrt((x-a2)**2 + (y-b2)**2) - c
# y_sols = solve(ellipse, y)
# print(*y_sols, sep='\n')
"""
coeffs = [1, 1, -1, -1, 3]
xs = [coeffs[0], coeffs[2]]
def ysolv(coeffs):
x,y,a1,b1,a2,b2,c = symbols('x y a1 b1 a2 b2 c', real = True)
y_sols = [
(-c*sqrt((a1**2 - 2*a1*a2 + a2**2 + b1**2 - 2*b1*b2 + b2**2 - c**2)*
(a1**2 + 2*a1*a2 - 4*a1*x + a2**2 - 4*a2*x + b1**2 - 2*b1*b2 + b2**2
- c**2 + 4*x**2))*(-b1 + b2 + c)*(b1 - b2 + c) + (b1**2 - 2*b1*b2 +
b2**2 - c**2)*(-a1**2*b1 + a1**2*b2 + 2*a1*b1*x - 2*a1*b2*x +
a2**2*b1 - a2**2*b2 - 2*a2*b1*x + 2*a2*b2*x - b1**3 + b1**2*b2 +
b1*b2**2 + b1*c**2 - b2**3 + b2*c**2))/(2*(-b1 + b2 + c)*
(b1 - b2 + c)*(b1**2 - 2*b1*b2 + b2**2 - c**2)),
(c*sqrt((a1**2 - 2*a1*a2 + a2**2 + b1**2 - 2*b1*b2 + b2**2 - c**2)*
(a1**2 + 2*a1*a2 - 4*a1*x + a2**2 - 4*a2*x + b1**2 - 2*b1*b2 + b2**2
- c**2 + 4*x**2))*(-b1 + b2 + c)*(b1 - b2 + c) + (b1**2 - 2*b1*b2 +
b2**2 - c**2)*(-a1**2*b1 + a1**2*b2 + 2*a1*b1*x - 2*a1*b2*x +
a2**2*b1 - a2**2*b2 - 2*a2*b1*x + 2*a2*b2*x - b1**3 + b1**2*b2 +
b1*b2**2 + b1*c**2 - b2**3 + b2*c**2))/(2*(-b1 + b2 + c)*
(b1 - b2 + c)*(b1**2 - 2*b1*b2 + b2**2 - c**2))
]
num_coefs = [(a, f) for a, f in (zip([a1,b1,a2,b2,c], coeffs))]
y_solsf0 = y_sols[0].subs(num_coefs)
y_solsf1 = y_sols[1].subs(num_coefs)
print(y_solsf0, '\n', y_solsf1)
f0 = lambdify([x], y_solsf0)
f1 = lambdify([x], y_solsf1)
return f0, f1
I am trying to solve a system of polynomial equations obtained by comparing coefficients of different polynomials.
# Statement of Problem:
# We are attempting to find complex numbers a, b, c, d, e, J, u, v, r, s where
# ((a*x + c)^2)*(x^3 + (3K)*x + 2K) - ((b*x^2 + d*x + e)^2) = a^2*(x - r)^2*(x - s)^3 and
# ((a*x + c)^2)*(x^3 + (3K)*x + 2K)) - ((b*x^2 + d*x + e - 1)^2) = a^2*(x - u)*(x - v)^4
R.<x> = CC['x']
a, b, c, d, e, r, s, u, v, K = var('a, b, c, d, e, r, s, u, v, K')
y2 = x^3 + (3*K)*x + 2*K
q0 = ((a*x + c)^2)*(y2) - ((b*x^2 + d*x + e)^2)
p0 = (a^2)*((x-r)^2)*((x-s)^3)
t = (b^2 - 2*a*c)/a^2
Q0 = q0.expand()
P0 = p0.expand()
P0 = P0.substitute(s = ((t - 2*r)/3))
Relations0 = []
i = 0
while i < 6:
Relations0.append(P0.coefficient(x, n = i) - Q0.coefficient(x, n = i))
i = i+1
q1 = ((a*x + c)^2)*(y2) - ((b*x^2 + d*x + e - 1)^2)
p1 = (a^2)*(x-u)*((x-v)^4)
Q1 = q1.expand()
P1 = p1.expand()
P1 = P1.substitute(u = t - 4*v)
Relations1 = []
i = 0
while i < 6:
Relations1.append(P1.coefficient(x, n = i) - Q1.coefficient(x, n = i))
i = i+1
Relations = Relations0 + Relations1
Telling Sage to solve the system of polynomials using solve(Relations, a,b,c,d,e,r,v,K) seems highly inefficient and has only led to Sage having its memory limit exceeded. Moreover, trying to reduce the number of equations and variables by solving for some of the variables is also inefficient and has not given any fruitful results. Since attempting to find all solutions has proven so difficult, is there any way to extract only a single solution?
Both equations have degree 5, which makes 12 identities. However, the degree 5 identities are identical and always satisfied for both equations. Thus you have effectively 10 or less equations for 10 variables.
Divide by a^2, i.e., replace c, b, d, e by c/a, b/a, d/a, e/a and introduce f=1/a to reduce the degrees of the coefficient equations.
Then the resulting coefficient equations for
(x + c)^2*(x^3 + 3*K*x + 2*K) - (b*x^2 + d*x + e)^2 = (x - r)^2*(x - s)^3;
(x + c)^2*(x^3 + 3*K*x + 2*K) - (b*x^2 + d*x + e - f)^2 = (x - u)*(x - v)^4;
or on http://magma.maths.usyd.edu.au/calc/
A<b, c, d, e, f, r, s, u, v, K> :=PolynomialRing(Rationals(),10,"glex");
P<x> := PolynomialRing(A);
eq1 := (x + c)^2*(x^3 + 3*K*x + 2*K) - (b*x^2 + d*x + e)^2 - (x - r)^2*(x - s)^3;
eq2 := (x + c)^2*(x^3 + 3*K*x + 2*K) - (b*x^2 + d*x + e - f)^2 - (x - u)*(x - v)^4;
I := ideal<A|Coefficients(eq1) cat Coefficients(eq2-eq1)>; I;
giving
Ideal of Polynomial ring of rank 10 over Rational Field
Order: Graded Lexicographical
Variables: b, c, d, e, f, r, s, u, v, K
Basis:
[
r^2*s^3 + 2*c^2*K - e^2,
-3*r^2*s^2 - 2*r*s^3 + 3*c^2*K + 4*c*K - 2*d*e,
3*r^2*s + 6*r*s^2 + s^3 - 2*b*e + 6*c*K - d^2 + 2*K,
-2*b*d + c^2 - r^2 - 6*r*s - 3*s^2 + 3*K,
-b^2 + 2*c + 2*r + 3*s,
-r^2*s^3 + u*v^4 + 2*e*f - f^2,
3*r^2*s^2 + 2*r*s^3 - 4*u*v^3 - v^4 + 2*d*f,
-3*r^2*s - 6*r*s^2 - s^3 + 6*u*v^2 + 4*v^3 + 2*b*f,
r^2 + 6*r*s + 3*s^2 - 4*u*v - 6*v^2,
-2*r - 3*s + u + 4*v
]
have degrees 5,4,3,2,2,5,4,3,2,1 giving an upper bound of 28800 for the number of solutions. As the Groebner basis algorithms that are commonly used have a complexity bound of O(d^(n^2)) for the better algorithms, your runtime will be optimistically be characterized by the number 28800^10 (Bezout bound instead of d^n in (d^n)^n), which is rather large however small the constant. Even removing one variable for the linear equation will not change much in these estimates.
Thus any symbolic solution will take a long time and result in univariate polynomials of rather high degrees as part of any triangular polynomial basis.
In SymPy, I am trying to perform a matrix multiplication and expand it afterwards. However, SymPy does not seem to support the expansion of matrix expressions. For example, here is the 4th order Runge-Kutta (RK4) for matrices:
from sympy import init_session
init_session()
from sympy import *
A = MatrixSymbol('A', 3, 3)
x = MatrixSymbol('x', 3, 1)
dt = symbols('dt')
k1 = A*x
k2 = A*(x + S(1)/2*k1*dt)
k3 = A*(x + S(1)/2*k2*dt)
k4 = A*(x + k3*dt)
final = dt*S(1)/6*(k1 + 2*k2 + 2*k3 + k4)
final.expand()
which produces the result
Traceback (most recent call last)
<ipython-input-38-b3ff67883c61> in <module>()
12 final = dt*1/6*(k1+2*k2+2*k3+k4)
13
---> 14 final.expand()
AttributeError: 'MatMul' object has no attribute 'expand'
I hope the expression can be expanded just like the scalar variant:
A,x,dt = symbols('A x dt')
k1 = A*x
k2 = A*(x+k1*dt*S(1)/2)
k3 = A*(x+k2*dt*S(1)/2)
k4 = A*(x+k3*dt)
final = x+dt*(S(1)/6)*(k1+k2+k3+k4)
collect(expand((final)),x)
with the result:
x*(A**4*dt**4/24 + A**3*dt**3/8 + A**2*dt**2/3 + 2*A*dt/3 + 1)
Is it possible to alter a matrix expression likewise?
nicoguaro's answer takes the error away, but expands the the whole expression into one matrix. As illustrated with the scalar example, not what I'm looking for.
Matrix(final) creates and explicit Matrix with your individual equations. It may be convenient to leave them in the matrix so that whatever you do to one entry can be done to all. To do so, define the manipulation that you want to do as a function argument for applyfunc:
>>> ex = Matrix(final)
>>> ex = ex.applyfunc(expand)
>>> ex = ex.applyfunc(lambda i: collect(i, dt))
...
For printing economy I use Matrices with compact symbol entries to compute the same and then run cse over the simplified matrix to give:
>>> A = Matrix(3, 3, var('a:3:3'))
>>> x = Matrix(3, 1, var('x:3'))
>>> dt = symbols('dt')
>>> k1 = A*x
>>> k2 = A*(x + S(1)/2*k1*dt)
>>> k3 = A*(x + S(1)/2*k2*dt)
>>> k4 = A*(x + k3*dt)
>>> final = dt*S(1)/6*(k1 + 2*k2 + 2*k3 + k4)
>>> eqi = Matrix(final)
>>> print(cse(eqi.applyfunc(simplify)))
([(x3, 4*x0), (x4, a01*x1), (x5, a02*x2), (x6, dt*(a00*x0 + x4 + x5) +
2*x0), (x7, a00*x6), (x8, a11*x1), (x9, a12*x2), (x10, dt*(a10*x0 + x8
+ x9) + 2*x1), (x11, a01*x10), (x12, a21*x1), (x13, a22*x2), (x14,
dt*(a20*x0 + x12 + x13) + 2*x2), (x15, a02*x14), (x16, dt*(x11 + x15 +
x7) + x3), (x17, a00*x16), (x18, 4*x1), (x19, a10*x6), (x20, a11*x10),
(x21, a12*x14), (x22, dt*(x19 + x20 + x21) + x18), (x23, a01*x22),
(x24, 4*x2), (x25, a20*x6), (x26, a21*x10), (x27, a22*x14), (x28,
dt*(x25 + x26 + x27) + x24), (x29, a02*x28), (x30, dt*(x17 + x23 +
x29) + x3), (x31, a10*x16), (x32, a11*x22), (x33, a12*x28), (x34,
dt*(x31 + x32 + x33) + x18), (x35, a20*x16), (x36, a21*x22), (x37,
a22*x28), (x38, dt*(x35 + x36 + x37) + x24), (x39, dt/24)], [Matrix([
[ x39*(a00*x3 + a00*x30 + a01*x34 + a02*x38 + 4*x11 + 4*x15 + 2*x17
+ 2*x23 + 2*x29 + 4*x4 + 4*x5 + 4*x7)], [ x39*(a10*x3 + a10*x30 +
a11*x34 + a12*x38 + 4*x19 + 4*x20 + 4*x21 + 2*x31 + 2*x32 + 2*x33 +
4*x8 + 4*x9)], [x39*(a20*x3 + a20*x30 + a21*x34 + a22*x38 + 4*x12 +
4*x13 + 4*x25 + 4*x26 + 4*x27 + 2*x35 + 2*x36 + 2*x37)]])])
Limited support of noncommutative expressions is also available and can help in this situation:
>>> A, x = symbols("A x", commutative=False)
>>> dt = symbols('dt')
>>> k1 = A*x
>>> k2 = A*(x + S(1)/2*k1*dt)
>>> k3 = A*(x + S(1)/2*k2*dt)
>>> k4 = A*(x + k3*dt)
>>> final = dt*S(1)/6*(k1 + 2*k2 + 2*k3 + k4)
>>> final.expand()
dt**4*A**4*x/24 + dt**3*A**3*x/6 + dt**2*A**2*x/2 + dt*A*x
>>> factor(_)
dt*A*(dt**3*A**3/24 + dt**2*A**2/6 + dt*A/2 + 1)*x
But not all simplification routines are nc aware (and this is a known issue):
>>> collect(final,x)
Traceback (most recent call last):
...
AttributeError: Can not collect noncommutative symbol
I think that you can expand Matrix expressions. But what you have is not a matrix but the multiplication of two symbolic matrices (Matsymbols). If you turn your expression to a matrix you can get the expansion you wanted. See the extra line below
from sympy import init_session
init_session()
from sympy import *
A = MatrixSymbol('A', 3, 3)
x = MatrixSymbol('x', 3, 1)
dt = symbols('dt')
k1 = A*x
k2 = A*(x + S(1)/2*k1*dt)
k3 = A*(x + S(1)/2*k2*dt)
k4 = A*(x + k3*dt)
final = dt*S(1)/6*(k1 + k2 + k3 + k4)
Matrix(final).expand()