I am using sympy to generate the determinant in of a matrix:
from sympy import *
X1, Y1 = symbols ("X1 Y1")
x1, x2, x3, y1, y2, y3 = symbols ("x1 x2 x3 y1 y2 y3")
th12, th13 = symbols ("theta_{12} theta_{13}")
X2 = cos(th12)*X1-sin(th12)*Y1+x2-y1*cos(th12)-y1*sin(th12)
Y2 = sin(th12)*X1+cos(th12)*Y1+y2-x1*sin(th12)-y1*cos(th12)
X3 = cos(th13)*X1-sin(th13)*Y1+x3-y1*cos(th13)-y1*sin(th13)
Y3 = sin(th13)*X1+cos(th13)*Y1+y3-x1*sin(th13)-y1*cos(th13)
M=Matrix([[X1,Y1,1],[X2,Y2,1],[X3,Y3,1]])
Det=M.det()
print Det
If you run the code you will notice that it generates a very "long" expression. I would like to get an expression like:
X1**2 + Y1**2 + A*X1 + B*Y1 + C = 0 (equation of a circumference)
So I would like Python to generate the coefficients A, B and C. Basically I would like to group all the therms that share X1**2, all the therms that share Y1**2, etc.
If I insert numerical values for x1, x2, x3, y1, y2, y3, th12, th13 I can get an expression in the form that I need, but I would like to get also the coefficients A, B and C.
EDIT: correction in the Xi and Yi formulas, added more information.
collect is the right tool for this:
Example from the above link:
>>> collect(a*x**2 + b*x**2 + a*x - b*x + c, x)
c + x**2*(a + b) + x*(a - b)
In your case (coefficients are not normalized here):
col = collect(Det, [X1, Y1], evaluate=False)
A = col[X1]
B = col[Y1]
C = col[S.One]
With evaluate=False, you will get a dict with the factors. Otherwise, you get the full expression.
Related
I am trying to find a common tangent to two curves using python but I am not able to solve it.
The equations to the two curves are complicated that involve logarithms.
Is there a way in python to compute the x coordinates of a tangent that is common to both the curves in general. If I have 2 curves f(x) and g(x), I want to find the x-coordinates x1 and x2 on a common tangent where x1 lies on f(x) and x2 on g(x). I am trying f'(x1) = g'(x2) and f'(x1) = f(x1) - f(x2) / (x1 - x2) to get x1 and x2 but I am not able to get values using nonlinsolve as the equations are too complicated.
I want to just find x-coordinates of the common tangent
Can anyone suggest a better way?
import numpy as np
import sympy
from sympy import *
from matplotlib import pyplot as plt
x = symbols('x')
a, b, c, d, e, f = -99322.50019502985, -86864.87072433547, -96876.05627516498, -89703.35055202093, -3390.863799999999, -20942.518
def func(x):
y1_1 = a - a*x + b*x
y1_2 = c - c*x + d*x
c1 = (1 - x) ** (1 - x)
c2 = (x ** x)
y2 = 12471 * (sympy.log((c1*c2)))
y3 = 2*f*x**3 - x**2*(e + 3*f) + x*(e + f)
eqn1 = y1_1 + y2 + y3
eqn2 = y1_2 + y2 + y3
return eqn1, eqn2
val = np.linspace(0, 1)
f1 = sympy.lambdify(x, func(x)[0])(val)
f2 = sympy.lambdify(x, func(x)[1])(val)
plt.plot(val, f1)
plt.plot(val, f2)
plt.show()
I am trying this
x1, x2 = sympy.symbols('x1 x2')
fun1 = func(x1)[0]
fun2 = func(x2)[0]
diff1 = diff(fun1,x1)
diff2 = diff(fun2,x2)
eq1 = diff1 - diff2
eq2 = diff1 - ((fun1 - fun2) / (x1 - x2))
sol = nonlinsolve([eq1, eq2], [x1, x2])
the first thing that needs to be done is to reduce the formulas
for example the first formula is actually this:
formula = x*(1 - x)*(17551.6542 - 41885.036*x) + x*(1 - x)*(41885.036*x - 24333.3818) + 12457.6294706944*x + log((x/(1 - x))**(12000*x)*(1 - x)**12000) - 99322.5001950298
formula = (x-x^2)*(17551.6542 - 41885.036*x) + (x-x^2)*(41885.036*x - 24333.3818) + 12457.6294706944*x + log((x/(1 - x))**(12000*x)*(1 - x)**12000) - 99322.5001950298
# constants
a = 41885.036
b = 17551.6542
c = 24333.3818
d = 12457.6294706944
e = 99322.5001950298
f = 12000
formula = (x-x^2)*(b - a*x) + (x-x^2)*(a*x - c) + d*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e
formula = (ax^3 -bx^2 + bx - ax^2) + (x-x^2)*(a*x - c) + d*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e
formula = ax^3 -bx^2 + bx - ax^2 -ax^3 + ax^2 + cx^2 -cx + d*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e
# collect x terms by power (note how the x^3 tern drops out, so its easier).
formula = (c-b)*x^2 + (b-c+d)*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e
which is much cleaner and is a quadratic with a log term.
i expect that you can do some work on the log term too, but this is an excercise for the original poster.
likewise the second formula can be reduced in the same way, which is again an excercise for the original poster.
From this, both equations need to be differentiated with respect to x to find the tangent. Then set both formulas to be equal to each other (for a common tangent).
This would completely solve the question.
I actually wonder if this is a python question at all or actually a pure maths question.....
The important point to note is that, since the derivatives are monotonic, for any value of derivative of fun1, there is a solution for fun2. This can be easily seen if you plot both derivatives.
Thus, we want a function that, given an x1, returns an x2 that matches it. I'll use numerical solution because the system is too cumbersome for numerical solution.
import scipy.optimize
def find_equal_value(f1, f2, x, x1):
goal = f1.subs(x, x1)
to_solve = sympy.lambdify(x, (f2 - goal)**2) # Quadratic functions tend to be better behaved, and the result is the same
sol = scipy.optimize.fmin(func=to_solve, x0=x1, ftol=1e-8, disp=False) # The value for f1 is a good starting guess
return sol[0]
I used fmin as the solver above because it worked and I knew how to use it by heart. Maybe root_scalar can give better results.
Using the function above, let's get some pairs (x1, x2) where the derivatives are equal:
df1 = sympy.diff(func(x)[0])
df2 = sympy.diff(func(x)[1])
x1 = 0.25236537 # Close to the zero derivative
x2 = find_equal_value(df1, df2, x, x1)
print(f'Derivative of f1 in x1: {df1.subs(x, x1)}')
print(f'Derivative of f2 in x2: {df2.subs(x, x2)}')
print(f'Error: {df1.subs(x, x1) - df2.subs(x, x2)}')
This results is:
Derivative of f1 in x1: 0.0000768765858083498
Derivative of f2 in x2: 0.0000681969431752805
Error: 0.00000867964263306931
If you want a x2 for several x1s (beware that in some cases the solver hits a value where the logs are invalid. Always check your result for validity):
x1s = np.linspace(0.2, 0.8, 50)
x2s = [find_equal_value(df1, df2, x, x1) for x1 in x1s]
plt.plot(x1s, x2s); plt.grid(); plt.show()
I've been digging in stackoverflow for a while and can't find any example for multiple piecewise curve fitting. I want to convert a quadratic function into multiple chaining (I don't know the exact name of it, but i need every tail connected to the head of the next piecewise, simply "connected") of piecewise function. This is my code so far using scipy.optimize to convert quadratic into 2 pieces of piecewise linear function.
import scipy.optimize as opt
import numpy as np
import copy
def func_2piecewise(x, m_0, x_1, y_1, m_1):
y = np.piecewise(x, [x <= x_1, x > x_1],
[lambda x:m_0*(x-x_1) + y_1, lambda x:m_1*(x-x_1) + y_1])
return y
xmin=0
xmax=100
a=0.1
a0=1
a00=10
piece_number=2
sigma=np.ones(numberOfStep)
if piece_number==2:
lower_bounds=[-np.inf,xmin,-np.inf,-np.inf]
upper_bounds=[np.inf,xmax,np.inf,np.inf]
w, _ = opt.curve_fit(func_2piecewise, x_sample, y_sample,bounds=(lower_bounds,upper_bounds),sigma=sigma)
x_0=copy.deepcopy(xmin)
y_0=func_2piecewise(x_0, *w).tolist()
[m_0, x_1, y_1, m_1]=w
result=[x_0,y_0,m_0,x_1,y_1,m_1]
The problem is, I can't implement the same approach for three piecewise (i don't know how to make x_2 > x_1):
def func_gradients(x_list,y_list):
len_x_list=len(x_list)
if len_x_list==1:
m_list=y_list/x_list
return m_list
m_list=[]
for idx in range(len_x_list-1):
m_list.append((y_list[idx+1]-y_list[idx])/(x_list[idx+1]-x_list[idx]))
return m_list
def func_3piecewise(x, m_0, x_1, y_1, x_2, y_2, m_2):
y = np.piecewise(x, [x <= x_1, (x > x_1) & (x <= x_2), x > x_2],
[lambda x:m_0*(x-x_1) + y_1, lambda x:y_1+(y_2-y_1)*(x-x_1)/(x_2-x_1), lambda x:m_2*(x-x_2) + y_2])
return y
if piece_number==3:
lower_bounds=[-np.inf,xmin,-np.inf,xmin,-np.inf,-np.inf]
upper_bounds=[np.inf,xmax,np.inf,xmax,np.inf,np.inf]
w, _ = opt.curve_fit(func_3piecewise, x_sample, y_sample,bounds=(lower_bounds,upper_bounds),sigma=sigma)
x_0=copy.deepcopy(xmin)
y_0=func_3piecewise(x_0, *w).tolist()
[m_0, x_1, y_1, x_2, y_2, m_2]=w
m_1=func_gradients(x_2-x_1,y_2-y_1)
result=[x_0,y_0,m_0,x_1,y_1,m_1, x_2, y_2, m_2]
The full code can be seen in pastebin
So, the question is:
How to make a chaining (every tail of the piecewise function connected to the head of the next piece, or simply "connected") picewise function in python for general n-pieces? Other algorithm or solver is acceptable.
Edit: I add my result so far for 2 piecewise.
Update: I found that my code (for three pieces) is not working because of a small typo (sorry about this, just tell me if I should delete this question). Now it's working and I update the paste bin. But, if you have a general (flexible, no need to write function for each number variant) function that can generate n number of pieces,I'll gladly accept the answer.
You can parametrize on the distance x2-x1 instead of parametrizing on x2. Because you can give the optimizer bounds, you can set the distance to be greater than 0.
For example, to make a general piecewise-linear function with 4 intervals, define the following:
The points which separate the intervals and x0, x1 and x2. The slopes in the 4 intervals are m0, m1, m2 and m3. The value of the function at x0 is y0.
Define d1 = x1 - x0, d2 = x2 - x1. From here:
x1 = x0 + d1
x2 = x0 + d1 + d2
Then, you have 8 optimization parameters: x0, y0, d1, d2, m0, m1, m2 and m3. By nature of your optimization problem, all except x0 and y0 are non-negative.
Equation for the first interval:
y = m0 * (x - x0) + y0
Equation for the second interval:
y = m1 * (x - x0) + y0
Now you can get the rest of the equations in a recursive way, by applying the previous equation at the rightmost point of its interval. For the x1 point, the value of the function is:
y1 = m1 * d1 + y0
So the third equation is
y =
m2 * (x - x1) + y1 =
m2 * (x - x0 - d1) + m1 * d1 + y0
For the x2 point, this gives
y2 = m2 * d2 + y1
So the fourth equation is
y =
m3 * (x - x2) + y2 =
m3 * (x - x0 - d1 - d2) + m2 * d2 + m1 * d1 + y0
I am trying to solve a constrained optimization problem using
cipy.optimize.minimize but so far had no success.
Specifically I want to minimize the objective function over y1 and y2:
f(y1,y2)=(x1(y1,y2)-x1)^2+(x2(y1,y2)-x2)^2
Subject to the constraint:
y1*y2>0
The goal is to find the values of y1 and y2 for different pairs of x1 and x2.
This is what i have so far
def f(x1,x2):
k=(x1(y1,y2)-x1)^2+(x2(y1,y2)-x2)^2
return k
But i am not sure how to set up the function holding the aforementioned constraint:
def constraint(x):
....
Once i have the constraint is the following syntax correct?
optimize.minimize(f, np.array([0, 0]), method="SLSQP",
constraints={"fun": constraint, "type": "ineq"})
I am new in Python so any help would be appreciated.
For constraints. From the docs:
Equality constraint means that the constraint function result is to be zero whereas inequality means that it is to be non-negative. Note that COBYLA only supports inequality constraints.
Therefore, your constraint is simply a function that must be non-negative. In your case:
def constraint(y):
return y[0] * y[1]
Note that the function must input a vector. e.g.:
def f(x):
x1, x2 = x
return x1**2 + x2**2
EDIT Using a function that tries to fit calculated vs. observed data.
def calculated_x(y):
""" example """
y1, y2 = y
x1 = 0.5 + 0.2 * y1 + 0.3 * y2
x2 = 0.4 + 0.1 * y1 + 0.3 * y2
def f(y, x1, x2):
x1_calc, x2_calc = calculated_x(y)
return (x1- x1_calc)**2 + (x2 - x2_calc)**2
m = minimize(f, [0,0], args=(3,2), constraints=({'fun': lambda y: y[0] * y[1], 'type': 'ineq'},))
print(m)
>> array([3, 1.999999])
You can also build a function based on your minimization (example above):
def minimize_y(x1, x2):
# note that x1 and x2 become arguments
m = minimize(f, [0,0], args=(x1,x2), constraints=({'fun': lambda y: y[0] * y[1], 'type': 'ineq'},)
return m.x
I am trying to solve for C in the following equation
I can do this with sympy for an enumrated number of x's, e.g x0, x2, ..., x4 but cannot seem to figure out how to do this for i=0 to t. E.g. for a limited number
from sympy import summation, symbols, solve
x0, x1, x2, x3, x4, alpha, C = symbols('x0, x1, x2, x3, x4, alpha, C')
e1 = ((x0 + alpha * x1 + alpha**(2) * x2 + alpha**(3) * x3 + alpha**(4) * x4)
/ (1 + alpha + alpha**(2) + alpha**(3) + alpha**(4)))
e2 = (x3 + alpha * x4) / (1 + alpha)
rhs = (x0 + alpha * x1 + alpha**(2) * x2) / (1 + alpha + alpha**(2))
soln_C = solve(e1 - C*e2 - rhs, C)
Any insight would be much appreciated.
Thanks to #bryans for pointing me in the direction of Sum. Elaborating on his comment, here is one solution that seems to work. As I am fairly new to sympy if anyone has a more concise approach please share.
from sympy import summation, symbols, solve, Function, Sum
alpha, C, t, i = symbols('alpha, C, t, i')
x = Function('x')
s1 = Sum(alpha**i * x(t-i), (i, 0, t)) / Sum(alpha**i, (i, 0, t))
s2 = Sum(alpha**i * x(t-3-i), (i, 0, t-3)) / Sum(alpha**i, (i, 0, t-3))
rhs = (x(0) + alpha * x(1) + alpha**(2) * x(2)) / (1 + alpha + alpha**(2))
soln_C = solve(s1 - C*s2 - rhs, C)
I'm not sure if this can be catalogued as more "concise", but it could be useful too, when you know the upper limit of the summatory. Let's suppose that we want to evaluate this expression:
We can express it, and solve it, in sympy as follows:
from sympy import init_session
init_session(use_latex=True)
n = 4
As = symbols('A_1:' + str(n+1))
x = symbols('x')
exp = 0
for i in range(n):
exp += As[i]/(1+x)**(i+1)
Ec = Eq(exp,0)
sol = solve(Ec,x)
#print(sol)
#sol #Or, if you're working on jupyter...
Consider the following simple three expressions:
from sympy import *
x1,y1,x2,y2,x,y,a,xn,yn = symbols('x1 y1 x2 y2 x y a xn yn')
yn = (1 - xn)/(1 - a*xn)
xn = (x - x1)/(x2 - x1)
yn = (y - y1)/(y2 - y1)
I would like to express y as a function of x, x1, x2, y1, y2 and a.
How do I do that? Can sub be used to do this type of expansion / simplification?
Assuming that your equations represent equality, and not variable assignmnent, then your system of equations is:
xn = (x - x1)(x2 - x1)
(1 - xn)/(1 - a*xn) = (y - y1)/(y2 - y1)
This can be solved in SymPy as follows:
from sympy import *
x1, y1, x2, y2, x, y, a = symbols('x1 y1 x2 y2 x y a')
xn = (x - x1)/(x2 - x1)
yn1 = (1 - xn)/(1 - a*xn)
yn2 = (y - y1)/(y2 - y1)
eq0 = yn1 - yn2
solve(eq0, y)
which returns:
[(a*x*y1 - a*x1*y1 - x*y1 + x*y2 + x1*y1 - x2*y2)/(a*x - a*x1 + x1 - x2)]
A bit of explanation:
xn didn't depend on yn, so we can just define it as an expression, rather than create a symbol for it on it's own.
The expression eq0 is the yn equivalence equations from above, rearranged to have only 0 on the right hand side. Many numerical solvers have the same interface, and sympy borrows it here.
solve takes an expression equivalent to 0 and symbols to solve for. Here we only want to solve for y.
The results from solve are an iterable of solutions (a list). Since SymPy only found one solution, the list is only 1 long. Other equations might return more.