Solving an Equation System in SciPy - python

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

Related

Effectively solve an overdetermined nonlinear equation system using fitted data in python

I think it’s the easiest way to describe my problem with a small example.
I have this data which is my input data. I have 3 LEDs and each LED is represented by 4 color-parts (value 1 to 4 in each array). If I increase the intensity of the LEDs (in this example from 10% to 30%) the color-parts change in different ways.
LED1_10 = np.array([1.5, 1, 0.5, 0.5])
LED1_20 = np.array([2.5, 1.75, 1.2, 1.2])
LED1_30 = np.array([3, 2.3, 1.7, 1.7])
LED2_10 = np.array([0.2, 0.8, 0.4, 0.4])
LED2_20 = np.array([0.6, 1.6, 0.5, 0.5])
LED2_30 = np.array([1.0, 2.0, 0.55, 0.55])
LED3_10 = np.array([1, 0.1, 0.4, 0.4])
LED3_20 = np.array([2.5, 0.8, 0.9, 0.9])
LED3_30 = np.array([3.25, 1, 1.3, 1.3])
The column elements of the arrays belong together. So if I bring LED1 from 10% to 30% the value in column 1 rises from 1.5 to 2.5 and then to 3. I want to find a polynomial for the rise of each of the LED color-parts, so I rearrange the data and use a polynomial fit to get the equations which describe the way the values are rising for each LED.
### Rearrange the values
LED1 = np.stack((LED1_10, LED1_20, LED1_30)).T
LED2 = np.stack((LED2_10, LED2_20, LED2_30)).T
LED3 = np.stack((LED3_10, LED3_20, LED3_30)).T
### Create x-vectro
x = np.array([10,20,30])
### Polynomal fits
Fit_LED1 = []
for i in range(len(LED1)):
z = np.polyfit(x, LED1[i], 2)
Fit_LED1.append(z)
Fit_LED2 = []
for i in range(len(LED2)):
z = np.polyfit(x, LED2[i], 2)
Fit_LED2.append(z)
Fit_LED3 = []
for i in range(len(LED3)):
z = np.polyfit(x, LED3[i], 2)
Fit_LED3.append(z)
Now I want to generate light of a specific color mixing together the light of each of the 3 different LEDs. Therefor I need to find out which intensity I need to use from each of the LEDs to get the best possible result. Color-parts 1-4 are represented by the solution vector: b = [7, 8, 2, 5] I do this solving the overdetermined nonlinear equation system like this:
def f(x):
x1, x2, x3 = x
return np.asarray(((-2.50000000e-03*x1**2 + 1.75000000e-01*x1 + -5.91091254e-15) + (-2.03207837e-18*x2**2 + 4.00000000e-02*x2 + -2.00000000e-01) + (-0.00375*x3**2 + 0.2625*x3 + -1.25),
(-0.001*x1**2 + 0.105*x1 + 0.05) + (-0.002*x2**2 + 0.14*x2 + -0.4) + (-0.0025*x3**2 + 0.145*x3 + -1.1),
(-0.001*x1**2 + 0.1*x1 + -0.4 ) + (-0.00025*x2**2 + 0.0175*x2 + 0.25) + (-0.0005*x3**2 + 0.065*x3 + -0.2),
(-0.001*x1**2 + 0.1*x1 + -0.4 ) + (-0.00025*x2**2 + 0.0175*x2 + 0.25) + (-0.0005*x3**2 + 0.065*x3 + -0.2)))
def system(x,b):
return (f(x)-b)
b = [7, 8, 2, 5]
x = scipy.optimize.leastsq(system, np.asarray((1,1,1)), args=b)[0]
I used the polynomials I got from the fit for each LED and added them to each other to get a equation for each of the four color parts. This would give the same result and maybe is a bit easier to read:
def g(x):
x1, x2, x3 = x
return np.asarray(((Fit_LED1[0][0]*x1**2 + Fit_LED1[0][1]*x1 + Fit_LED1[0][2]) + (Fit_LED2[0][0]*x1**2 + Fit_LED2[0][1]*x1 + Fit_LED2[0][2]) + (Fit_LED3[0][0]*x1**2 + Fit_LED3[0][1]*x1 + Fit_LED3[0][2]),
(Fit_LED1[1][0]*x1**2 + Fit_LED1[1][1]*x1 + Fit_LED1[1][2]) + (Fit_LED2[1][0]*x1**2 + Fit_LED2[1][1]*x1 + Fit_LED2[1][2]) + (Fit_LED3[1][0]*x1**2 + Fit_LED3[1][1]*x1 + Fit_LED3[1][2]),
(Fit_LED1[2][0]*x1**2 + Fit_LED1[2][1]*x1 + Fit_LED1[2][2]) + (Fit_LED2[2][0]*x1**2 + Fit_LED2[2][1]*x1 + Fit_LED2[2][2]) + (Fit_LED3[2][0]*x1**2 + Fit_LED3[2][1]*x1 + Fit_LED3[2][2]),
(Fit_LED1[3][0]*x1**2 + Fit_LED1[3][1]*x1 + Fit_LED1[3][2]) + (Fit_LED2[3][0]*x1**2 + Fit_LED2[3][1]*x1 + Fit_LED2[3][2]) + (Fit_LED3[3][0]*x1**2 + Fit_LED3[3][1]*x1 + Fit_LED3[3][2])))
def system(x,b):
return (f(x)-b)
b = [5, 8, 4, 12]
x = scipy.optimize.leastsq(system, np.asarray((1,1,1)), args=b)[0]
Now my problem is that I need to type each of the functions separately which is a lot of work, especially because my real-world application consists of 40 LEDs and more than 1000 color-parts for each of the LEDs. Is there an easier and more efficient way to define the equations for the equations system rather than typing each of the separately like I did here?
def g(x):
x1, x2, x3 = x
return np.asarray(((Fit_LED1[0][0]*x1**2 + Fit_LED1[0][1]*x1 + Fit_LED1[0][2]) + (Fit_LED2[0][0]*x1**2 + Fit_LED2[0][1]*x1 + Fit_LED2[0][2]) + (Fit_LED3[0][0]*x1**2 + Fit_LED3[0][1]*x1 + Fit_LED3[0][2]),
(Fit_LED1[1][0]*x1**2 + Fit_LED1[1][1]*x1 + Fit_LED1[1][2]) + (Fit_LED2[1][0]*x1**2 + Fit_LED2[1][1]*x1 + Fit_LED2[1][2]) + (Fit_LED3[1][0]*x1**2 + Fit_LED3[1][1]*x1 + Fit_LED3[1][2]),
(Fit_LED1[2][0]*x1**2 + Fit_LED1[2][1]*x1 + Fit_LED1[2][2]) + (Fit_LED2[2][0]*x1**2 + Fit_LED2[2][1]*x1 + Fit_LED2[2][2]) + (Fit_LED3[2][0]*x1**2 + Fit_LED3[2][1]*x1 + Fit_LED3[2][2]),
(Fit_LED1[3][0]*x1**2 + Fit_LED1[3][1]*x1 + Fit_LED1[3][2]) + (Fit_LED2[3][0]*x1**2 + Fit_LED2[3][1]*x1 + Fit_LED2[3][2]) + (Fit_LED3[3][0]*x1**2 + Fit_LED3[3][1]*x1 + Fit_LED3[3][2])))
I hope I was able to make my problem clear and would be very thankful if anyone could help me solving this task.
Thank you very much in advance :)
There is a pattern in your equations which you can vectorise. First of all, gather all the LED fits in a 3D array.
fits = np.array([Fit_LED1, Fit_LED2, Fit_LED3])
And then define g(x) as
def g(x):
X = np.array([x**2, x, np.ones_like(x)]).T
return np.sum(fits * X[:,None], axis=(0, 2))
You can also confirm the result is correct with np.isclose(f(x), g(x)).
Of course you should do the same to LED1, LED2, etc so you don't have to hardcode Fit_LED1, etc. Just put everything in a 3d array and loop for each LED index.
LEDs = np.array([LED1, LED2, LED3])
fits = [
[np.polyfit(np.array([10, 20, 30]), LEDs[i,j], 2) for j in range(LEDs.shape[1])]
for i in range(LEDs.shape[0])
]
fits = np.array(fits)

fit hyperbola from data points

I have experimental data points (x1, x2, ..., xn), (y1, y2, ..., yn) of turbocharger pressure map and want to get trendline equation. In result of my research it's something like:
y = (ax^5 + bx^4 + cx^3 + dx^2 + ex + f)/(x+g) # my equation
Tell me please, are there any ready-made functions for this?
I tried using np.polyfit, but it works with usual polynoms and I must guess "g" in this way:
# y*(x-g) = ax^5 + bx^4 + cx^3 + dx^2 + ex + f
pc = np.polyfit(x, y*(x+g), 5)
y = (pc[0]*x**5 + pc[1]*x**4 + pc[2]*x**3 + pc[3]*x**2 + pc[4]*x + pc[5])/(x + g)
It would be nice if someone could help to get coefficiens of my equation.
Though this will lead to a slightly different minimization, you can linearize the equation as
x y = ax^5 + bx^4 + cx^3 + dx^2 + ex + f - g y
and solve by linear least-squares.

how to solve a set of expression

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.

Changing coefficients modulo p in a SymPy polynomial

I took a cryptography course this semester in graduate school, and once of the topics we covered was NTRU. I am trying to code this in pure Python, purely as a hobby. When I attempt to find a polynomial's inverse modulo p (in this example p = 3), SymPy always returns negative coefficients, when I want strictly positive coefficients. Here is the code I have. I'll explain what I mean.
import sympy as sym
from sympy import GF
def make_poly(N,coeffs):
"""Create a polynomial in x."""
x = sym.Symbol('x')
coeffs = list(reversed(coeffs))
y = 0
for i in range(N):
y += (x**i)*coeffs[i]
y = sym.poly(y)
return y
N = 7
p = 3
q = 41
f = [1,0,-1,1,1,0,-1]
f_poly = make_poly(N,f)
x = sym.Symbol('x')
Fp = sym.polys.polytools.invert(f_poly,x**N-1,domain=GF(p))
Fq = sym.polys.polytools.invert(f_poly,x**N-1,domain=GF(q))
print('\nf =',f_poly)
print('\nFp =',Fp)
print('\nFq =',Fq)
In this code, f_poly is a polynomial with degree at most 6 (its degree is at most N-1), whose coefficients come from the list f (the first entry in f is the coefficient on the highest power of x, continuing in descending order).
Now, I want to find the inverse polynomial of f_poly in the convolution polynomial ring Rp = (Z/pZ)[x]/(x^N - 1)(Z/pZ)[x] (similarly for q). The output of the print statements at the bottom are:
f = Poly(x**6 - x**4 + x**3 + x**2 - 1, x, domain='ZZ')
Fp = Poly(x**6 - x**5 + x**3 + x**2 + x + 1, x, modulus=3)
Fq = Poly(8*x**6 - 15*x**5 - 10*x**4 - 20*x**3 - x**2 + 2*x - 4, x, modulus=41)
These polynomials are correct in modulus, but I would like to have positive coefficients everywhere, as later on in the algorithm there is some centerlifting involved, so I need to have positive coefficients. The results should be
Fp = x^6 + 2x^5 + x^3 + x^2 + x + 1
Fq = 8x^6 + 26x^5 + 31x^4 + 21x^3 + 40x^2 + 2x + 37
The answers I'm getting are correct in modulus, but I think that SymPy's invert is changing some of the coefficients to negative variants, instead of staying inside the mod.
Is there any way I can update the coefficients of this polynomial to have only positive coefficients in modulus, or is this just an artifact of SymPy's function? I want to keep the SymPy Poly format so I can use some of its embedded functions later on down the line. Any insight would be much appreciated!
This seems to be down to how the finite field object implemented in GF "wraps" integers around the given modulus. The default behavior is symmetric, which means that any integer x for which x % modulo <= modulo//2 maps to x % modulo, and otherwise maps to (x % modulo) - modulo. So GF(10)(5) == 5, whereas GF(10)(6) == -4. You can make GF always map to positive numbers instead by passing the symmetric=False argument:
import sympy as sym
from sympy import GF
def make_poly(N, coeffs):
"""Create a polynomial in x."""
x = sym.Symbol('x')
coeffs = list(reversed(coeffs))
y = 0
for i in range(N):
y += (x**i)*coeffs[i]
y = sym.poly(y)
return y
N = 7
p = 3
q = 41
f = [1,0,-1,1,1,0,-1]
f_poly = make_poly(N,f)
x = sym.Symbol('x')
Fp = sym.polys.polytools.invert(f_poly,x**N-1,domain=GF(p, symmetric=False))
Fq = sym.polys.polytools.invert(f_poly,x**N-1,domain=GF(q, symmetric=False))
print('\nf =',f_poly)
print('\nFp =',Fp)
print('\nFq =',Fq)
Now you'll get the polynomials you wanted. The output from the print(...) statements at the end of the example should look like:
f = Poly(x**6 - x**4 + x**3 + x**2 - 1, x, domain='ZZ')
Fp = Poly(x**6 + 2*x**5 + x**3 + x**2 + x + 1, x, modulus=3)
Fq = Poly(8*x**6 + 26*x**5 + 31*x**4 + 21*x**3 + 40*x**2 + 2*x + 37, x, modulus=41)
Mostly as a note for my own reference, here's how you would get Fp using Mathematica:
Fp = PolynomialMod[Algebra`PolynomialPowerMod`PolynomialPowerMod[x^6 - x^4 + x^3 + x^2 - 1, -1, x, x^7 - 1], 3]
output:
1 + x + x^2 + x^3 + 2 x^5 + x^6

Python's sympy solver returning bad roots on 4th degree equation

I need to solve a 4th degree equation with python. For this I'm using the sympy module.
When I run the script, sympy returns the 4 solutions of the equation as complex numbers (see output), while, in fact, all of them are real.
What is making sympy return the wrong answer?
import numpy as np
import math
from numpy import linalg as la
import sympy as sy
from matplotlib.pyplot import *
L = np.array([0,1,-20.0])
S = np.array([0,0,-10.0])
a = np.dot(S,S)
b = np.dot(S,L)
c = np.dot(L,L)
k0 = a - 1
k1 = 2*(a-b)
k2 = a + 2*b + c - 4*a*c
k3 = -4*(a*c - b**2)
k4 = 4*c*(a*c - b**2)
y = sy.Symbol('y')
r = sy.solvers.solve(k4*y**4 + k3*y**3 + k2*y**2 + k1*y + k0, y)
print r
y = np.linspace(-1.1, 1.1, 1000)
x = k4*y**4 + k3*y**3 + k2*y**2 + k1*y + k0
figure()
plot(y, x)
grid(True)
show()
Output:
[-0.994999960838935 + 1.66799419488535e-31*I,
-0.0255580200028216 - 6.34301512012529e-30*I,
0.0243009597954184 + 6.32628752256216e-30*I,
0.998750786632373 - 1.50071821925406e-31*I]
Plot (there are 4 zero-crossings):
Notice that the result is actually real, up to numerical precision. e-30 is really a small number. The solutions reported are also consistent with the plot, so nothing to worry about.
Real values can also be obtained directly from nroots:
>>> eq=k4*y**4 + k3*y**3 + k2*y**2 + k1*y + k0
>>> eq
160400.0*y**4 - 400.0*y**3 - 159499.0*y**2 - 200.0*y + 99.0
>>> nroots(eq)
[-0.994999960838935, -0.0255580200028216, 0.0243009597954184, 0.998750786632373]

Categories

Resources