Implementing Newtons method - python

I'm trying to use Newtons method to solve a Satellite Navigation problem, also I'm fairly new to programming.
I keep getting the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\Ninjasoup\Anaconda3\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 714, in runfile
execfile(filename, namespace)
File "C:\Users\Ninjasoup\Anaconda3\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 89, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/Ninjasoup/Desktop/MSc Space Science/SatNav AssignmentCode/SatNavCode1.3.py", line 72, in <module>
fA = np.sqrt((x-xA)**2 + (y-yA)**2 + (z-zA)**2) - (dA-b)
TypeError: unsupported operand type(s) for -: 'type' and 'float'
I've tried changing the declaration of the unkown variables to different types but I keep getting the same error.
Any help would be greatly appreciated.
import math
import numpy as np
from sympy import diff
#Constants
R = 6371
SD = 20200
c = 299792458
#Given Data
latA = 47.074834081442773
lonA = 18.487157448324282
latB = 17.949919573189003
lonB = 17.786195009535710
latC = 48.196896294687626
lonC = -67.929788607990332
latD = 77.374761092966111
lonD = -25.681600844602748
tofA = 0.070745909570054
tofB = 0.075407082536252
tofC = 0.074696101874954
tofD = 0.071921760657713
#Pseudo Range error
dA = c*tofA
dB = c*tofB
dC = c*tofC
dD = c*tofD
#Unknown Variables
x =float
y =float
z =float
b =float
#Coversion of Shperical to Cartesian Co-ordinates
xA = (R+SD) * math.cos(math.radians(latA)) * math.cos(math.radians(lonA))
yA = (R+SD) * math.cos(math.radians(latA)) * math.sin(math.radians(lonA))
zA = (R+SD) *math.sin(math.radians(latA))
xB = (R+SD) * math.cos(math.radians(latB)) * math.cos(math.radians(lonB))
yB = (R+SD) * math.cos(math.radians(latB)) * math.sin(math.radians(lonB))
zB = (R+SD) *math.sin(math.radians(latB))
xC = (R+SD) * math.cos(math.radians(latC)) * math.cos(math.radians(lonC))
yC = (R+SD) * math.cos(math.radians(latC)) * math.sin(math.radians(lonC))
zC = (R+SD) *math.sin(math.radians(latC))
xD = (R+SD) * math.cos(math.radians(latD)) * math.cos(math.radians(lonD))
yD = (R+SD) * math.cos(math.radians(latD)) * math.sin(math.radians(lonD))
zD = (R+SD) *math.sin(math.radians(latD))
#P1 = np.array([xA,yA,zA])
#P2 = np.array([xB,yB,zB])
#P3 = np.array([xC,yC,zC])
#P4 = np.array([xD,yD,zD])
#print(P1,P2,P3,P4)
fA = np.sqrt((x-xA)**2 + (y-yA)**2 + (z-zA)**2) - (dA-b)
dfA1 = diff(fA, x)
dfA2 = diff(fA, y)
dfA3 = diff(fA, z)
dfA4 = diff(fA, b)
fB = np.sqrt((x-xB)**2 + (y-yB)**2 + (z-zB)**2) - (dB-b)
dfB1 = diff(fB, x)
dfB2 = diff(fB, y)
dfB3 = diff(fB, z)
dfB4 = diff(fB, b)
fC = np.sqrt((x-xC)**2 + (y-yC)**2 + (z-zC)**2) - (dC-b)
dfC1 = diff(fC, x)
dfC2 = diff(fC, y)
dfC3 = diff(fC, z)
dfC4 = diff(fC, b)
fD = np.sqrt((x-xD)**2 + (y-yD)**2 + (z-zD)**2) - (dD-b)
dfD1 = diff(fD, x)
dfD2 = diff(fD, y)
dfD3 = diff(fD, z)
dfD4 = diff(fD, b)
#Matrix of Partial derivatives (Jacobian)
J = [[dfA1,dfA2,dfA3,dfA4],
[dfB1,dfB2,dfB3,dfB4],
[dfC1,dfC2,dfC3,dfC4],
[dfD1,dfD2,dfD3,dfD4]]
print(J)
#Matrix of functions
F = [[fA],
[fB],
[fC],
[fD]]
print(F)
#Guess Values
U = [[1],
[1],
[1],
[1]]
#Evaluated values
x,y,z,b = U - np.linalg.solve(J,F)
#Iteration 2..will do more iterations later.
U1 = [[x],
[y],
[z],
[b]]
x1,y1,z1,b1 = U1 - np.linalg.solve(J,F)
#Convert x,y,z back to spherical constants once code is working

From the x=float lines, it looks like you want to do symbolic calculation. Having "unknown variables" isn't possible with the basic python syntax (and in a large portion of progamming languages afaik) but the sympy package you're already using is meant just for that (you should probably check out the tutorial page here).
Here is how you would create symbolic variables (aka "unknow variables") :
from sympy import symbols
x, y, z, b = symbols('x y z b')
But once that's is done you will notice that your code break a bit further down the road when you try to use np.linalg.solve. The numpy module is only meant to operate on special objects called numpy arrays ,they are essentially N-dimentionnal matrices of numbers aka "not symbolic expressions".
But sympy also has a solution to that problem : you can create matrices containing symbolic expressions and solve matricial equations too with ot . I'll just link you to the tutorial so you can see how to properly define said matrices and how to use them.

You need to initialize x, y, z, and b to actual floating values like 0.0, not to float.
>>> 0.0 # a floating-point number
0.0
>>> float # an object of class 'type' named 'float'
<class 'float'>
>>> x = float # initialize to an object of class 'type'
>>> y = 0.0 # initialize to a floating number
>>> x
<class 'float'>
>>> y
0.0
>>> type(x)
<class 'type'>
>>> type(y)
<class 'float'>

Related

Trying to get eigenvalues for the system of equations with sympy and get ': AttributeError: 'float' object has no attribute 'arctan2''

I am trying to get eigenvalues' real parts for the equation system in its stationary points
Here is the code:
# equation system
x0, y0, e_x, d_x, d_y, e_y, K, t = sym.symbols('x0, y0, e_x, d_x, d_y, e_y, K, t')
x = sym.Function('x')(t)
y = sym.Function('y')(t)
x_rate = e_x * x - d_x * x * y + K/ x
y_rate = d_y * x * y - e_y * y
eq1 = sym.Eq(x.diff(t), x_rate)
eq2 = sym.Eq(y.diff(t), y_rate)
# parameters
# e_x_, e_y_, d_x_, d_y_, K
e_x0 = 0.4
e_y0 = 1
d_x0 = 0.4
d_y0 = 1
K0 = 0.00000001
# jacobian
J = sym.Matrix([x_rate, y_rate]).jacobian(sym.Matrix([x,y]))
# eigen vectors
J_vects = J.eigenvects()
# stationary points
roots = sym.nonlinsolve([eq1.rhs.subs({e_x:e_x0, d_x:d_x0, K:K0}),
eq2.rhs.subs({e_y:e_y0, d_y:d_y0})],
[x, y])
roots_list = [(x, y) for x, y in roots.args]
# eigen values
f_eigen1 = sym.lambdify([x, y, e_x, e_y, d_x, d_y, K], sym.re(J_vects[0][0]))
f_eigen2 = sym.lambdify([x, y, e_x, e_y, d_x, d_y, K], sym.re(J_vects[1][0]))
f_eigen1(roots_list[0][0], roots_list[0][1], e_x0, d_x0, e_y0, d_y0, K0)
And i get an error in the last string:
AttributeError: 'float' object has no attribute 'arctan2'
I can't understand which library tries to find an artcan2 attribute for the float values.
And if i won't turn them into floats, the lambdified function won't be able to deal with them?
UPD: the problem was in the line
roots_list = [(x, y) for x, y in roots.args]
values in the list had the type sympy.core.numbers.Float
When i run
roots_list = [(float(sym.re(x)), float(sym.re(y))) for x, y in roots.args]
the error disapperars.
But. Now i realise that i don't clearly mathematically understand how to deal with this roots with imaginary parts - without 'i' they just turn into zeros...
Now i can get eigen values for at least the first pair of roots, and can analyse its stability, but what about other two pairs?
If I specify 'sympy' as the lambdifing language, rather than the default numpy, I get:
In [19]: f_eigen1 = sym.lambdify([x, y, e_x, d_x, K], sym.re(J_vects[0][0]),['sympy'])
In [20]: f_eigen1(roots_list[0][0], roots_list[0][1], e_x0, d_x0, K0)
Out[20]:
-0.707106781186548*((re(d_y)*im(d_y) + re(e_y)*im(e_y) - 0.8*im(d_y) - 0.000200000000000033*im(e_y) - im(d_y*e_y))**2 + (0.5*re(d_y)**2 - 0.8*re(d_y) + 0.5*re(e_y)**2 - 0.000200000000000033*re(e_y) - re(d_y*e_y) - 0.5*im(d_y)**2 - 0.5*im(e_y)**2 + 2.00000000172285e-8)**2)**0.25*cos(0.5*atan2(2.0*re(d_y)*im(d_y) + 2.0*re(e_y)*im(e_y) - 1.6*im(d_y) - 0.000400000000000067*im(e_y) - 2.0*im(d_y*e_y), 1.0*re(d_y)**2 - 1.6*re(d_y) + 1.0*re(e_y)**2 - 0.000400000000000067*re(e_y) - 2.0*re(d_y*e_y) - 1.0*im(d_y)**2 - 1.0*im(e_y)**2 + 4.00000000344569e-8)) + 0.5*re(d_y) - 0.5*re(e_y) - 0.000100000000000017
I don't know if that's useful, but it does tell me that d_y and e_y are still symbols. Leaving symbols in a numpy lamdified function is bound to give errors like this.
In [22]: np.arctan2(d_y,e_y)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[22], line 1
----> 1 np.arctan2(d_y,e_y)
AttributeError: 'Symbol' object has no attribute 'arctan2'
In [24]: np.arctan2(1.0,e_y)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[24], line 1
----> 1 np.arctan2(1.0,e_y)
AttributeError: 'float' object has no attribute 'arctan2'
In [25]: np.arctan2(1.0,2)
Out[25]: 0.4636476090008061

How to stop python from automatically converting a float number to a complex number?

I'm creating a function to compute Newton's method. However, the functions f and df keep returning a complex number. I am getting a type error: "can't convert complex to float" at the line where I am defining f.
How do I stop python from returning a complex number and not a float?
from cmath import cos, sin
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
def Newtons_method(f, df, x0, i_max, eps_x, eps_f):
errors = []
conv = 0
xk = x0
for k in range(i_max):
res = f(xk)
approx_err = -1.0 * res / df(xk)
errors.append([k, abs(approx_err), res])
if (abs(approx_err) < eps_x) and (res < eps_f):
array_errors = np.array(errors)
conv = 1
return xk, array_errors, conv
der = df(xk)
if der == 0:
print("Derivative is zero")
return None
xk = xk + approx_err
print("Exceeded maximum iterations")
return None
def f(x):
return float(x * x - 2 * x * cos(x) + cos(x) * cos(x))
def df(x):
return float(2 * x - 2 * (cos(x) - x * sin(x)) - sin(2 * x))
x0 = 1.0
i_max = 50
eps_x = 1.0e-12
eps_f = 1.0
solution_Newton, record_Newton, flag_Newton = Newtons_method(f, df, x0, i_max, eps_x, eps_f)
x = record_Newton[:,0]
y = record_Newton[:,1]
plt.plot(x, y)
plt.yscale("log")
plt.title("Newton's method")
plt.xlabel("Number of iterations")
plt.ylabel("Approximate errors")
plt.show()
I think it is because you are using cmath instead of math:
>>> import cmath
>>> import math
>>> cmath.cos(0)
(1-0j)
>>> math.cos(0)
1.0
The help for cmath starts by explaining that it is for complex numbers:
Help on built-in module cmath:
NAME
cmath
DESCRIPTION
This module provides access to mathematical functions for complex
numbers.
If you don't want to be working with complex numbers, simply replace cmath with math and your error should go away. When I do that your code runs and produces this figure instead of spitting out a TypeError:

How do you convert a system of symbolic sympy ODEs to matrix form?

I am trying to (ultimately) simulate an inverted pendulum having a PID controller.
I am employing the Euler-Lagrange method to derive the equations of motion using SymPy.
I can compute the Euler-Lagrange equations in SymPy just fine.
Now that I have my symbolic differential equations, I would like to write them in matrix form.
It can be done by hand, but I would like to know if SymPy can separate the 2nd time-derivates out, put them in a vector, and put the rest into a matrix.
Here is the code I have so far:
#Import Libraries
import math
import numpy as np
import vpython as vp
import sympy as sp
from sympy import *
from numpy import *
from scipy.integrate import odeint
import matplotlib.pyplot as plt
#Allow display of symbols
sp.init_printing()
#Set up symbolic equations
####Symbolic Variables####
m1, m2 = sp.symbols('m1 m2') #masses of rad & cart
l = sp.symbols('l') #Length of rod
J = sp.symbols('J') #Rotational moment of inertia
t, g, F, b = sp.symbols('t g F b') #Gravitational acceleration, time, forces
z, theta1 = sp.symbols('z, theta1', cls = sp.Function)
x, y =sp.symbols('x y')
#Rotational Inertia
J = (m1*(l/2)**2)/12
####Time Derivatives####
theta1 = theta1(t)
z = z(t)
z_d = sp.diff(z, t)
theta1_d = sp.diff(theta1, t)
z_dd = sp.diff(z_d, t)
theta1_dd = sp.diff(theta1_d, t)
####Coordinates of component centers of mass####
x1 = l/2*sp.sin(theta1) + z
y1 = l/2*sp.cos(theta1)
x2 = z
y2 = 0
v1_sq = sp.diff(x1,t)**2 + sp.diff(y1,t)**2
v1 = sp.sqrt(v1_sq)
v2 = sp.diff(x2,t)
#Kinetic Energy
K1 = (1/2)*m1*(v1**2) + (1/2)*J*(sp.diff(theta1,t)**2)
K2 = (1/2)*m2*(sp.diff(z,t)**2)
K = K1 + K2
#Potential Energy
P = m1*g*l/2*sp.cos(theta1)
#Lagrangian
L = K - P
#Compute the Euler Lagrange Equation
#Compute dL/dq
dL_dz = sp.diff(L, z).simplify()
dL_dtheta1 = sp.diff(L, theta1).simplify()
#Compute dL/dq_dt
dL_dz_dt = sp.diff(L, z_d).simplify()
dL_dtheta1_dt = sp.diff(L, theta1_d).simplify()
#Compute d/dt(dL/dq_dt)
d_dt_dL_dz_dt = sp.diff(dL_dz_dt, t).simplify()
d_dt_dL_dtheta1_dt = sp.diff(dL_dtheta1_dt, t).simplify()
#Compute d/dt(dL/dq_dt) - dL/dq
LE1 = d_dt_dL_dz_dt.simplify() - dL_dz.simplify()
LE2 = d_dt_dL_dtheta1_dt.simplify() - dL_dtheta1.simplify()
LE = LE1 + LE2
I have tried using sympy.linear_eq_to_matrix(equations, *symbols), but the 'symbols' portion is a differentiated variable in my case, causing SymPy to issue this error:
ValueError Traceback (most recent call last)
<ipython-input-8-eab6a82bce2c> in <module>
88
89 b = sp.linsolve([LE1, LE2], (z_dd, theta1_dd))
---> 90 sp.linear_eq_to_matrix([LE1, LE2], *[z_dd, theta1_dd])
~\Anaconda3\lib\site-packages\sympy\solvers\solveset.py in linear_eq_to_matrix(equations, *symbols)
2555 for i in symbols:
2556 if not isinstance(i, Symbol):
-> 2557 raise ValueError(filldedent('''
2558 Expecting a Symbol but got %s
2559 ''' % i))
ValueError:
Expecting a Symbol but got Derivative(theta1(t), (t, 2))
Any help would be appreciated.
Thanks.

Optimizing a function where one of the parameters is an array

I want to optimize a function by varying the parameters where two of the parameters are actually arrays. I've tried to do
...
# initial parameters
params0 = np.array([p1, p2, ... , p_array1, p_array2])
p_min = minimize(myfunc, params0, args)
...
where the pj's are scalars and p_array1 and p_array2 are arrays of the same length, but this gave me an error saying
ValueError: setting an array element with a sequence.
I've also tried passing p_array1 and p_array2 as scalars into myfunc and then create predetermined arrays from those two inside myfunc (e.g. setting p_array1 = p_array1*np.arange(6) and similarly for p_array2), eliminating the error, but I don't want them to be predetermined -- instead I want 'minimize' to figure out what they should be.
Is there any way that I can utilize one of Scipy's optimization functions without getting this error while still keeping p_array1 and p_array2 as arrays and not scalars?
EDIT
Sorry for being very broad but here is my code:
NOTE: 'myfunc' here is actually norm_residual .
import pandas as pd
import numpy as np
def f(yvec, t, a, b, c, d, M, theta):
# the system of ODEs to be solved
x, y = yvec
dydt = [ a*x - b*y**2 + 1, -c*x - d*x*y + np.sum(M * np.cos(theta*t)) ]
return dydt
ni = 3 # the number of periodic forcing functions to add to the DE system
M = 0.56*np.random.rand(ni) # the initial amplitudes of forcing functions
theta = np.pi/6*np.arange(ni) # the initial coefficients of the forcing functions
# initialize the parameters
params0 = [0.75, 0.23, 1.0, 0.2, M, theta]
# grabbing the data to be used later
data = pd.read_csv('data.csv')
y_data = data['Y']
N = y_data.shape[0] #20
t = np.linspace(0, N, N) # array of t values to integrate over
yvec0 = [0.3, 0.34] # initial conditions for x and y respectively
def norm_residual(params, *args):
"""
Computes the L^2 norm of the residual of y and the data (y as defined above).
Input: params = array of parameters (scalars or arrays) for the DE system
args = other arguments to pass into the function f or to use
to compute the residual.
Output: err = L^2 error of the solution vector (scalar).
"""
data, yvec0, t = args
a, b, c, d, M, theta = params
sol = odeint(f, yvec0, t, args=(a, b, c, d, M, theta))
x = sol[:, 0]; y = sol[:, 1]
res = data - y
err = np.linalg.norm(res, 2)
return err
from scipy.optimize import minimize
p_min = minimize(norm_residual, params0, args=(y_data, yvec0, t))
print(p_min)
And the traceback
Traceback (most recent call last):
File "model_ex_1.py", line 62, in <module>
p_min = minimize(norm_residual, params0, args=(y_anom, yvec0, t))
File "/usr/lib/python2.7/dist-packages/scipy/optimize/_minimize.py", line 354, in minimize
x0 = np.asarray(x0)
File "/usr/lib/python2.7/dist-packages/numpy/core/numeric.py", line 482, in asarray
return array(a, dtype, copy=False, order=order)
ValueError: setting an array element with a sequence.
You cannot put a list in a numpy array if the other elements are scalars.
>>> import numpy as np
>>> foo_array = np.array([1,2,3,[5,6,7]])
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
foo_array = np.array([1,2,3,[5,6,7]])
ValueError: setting an array element with a sequence.
It would be helpful if you post myfunc
but you can do this -
def foo():
return [p0,p1,p2..pn]
params0 = numpy.array([foo(), p_array1, p_array2])
p_min = minimize(myfunc, params0, args)
OR from Multiple variables in SciPy's optimize.minimize
import scipy.optimize as optimize
def f(params):
# print(params) # <-- you'll see that params is a NumPy array
a, b, c = params # <-- for readability you may wish to assign names to the component variables
return a**2 + b**2 + c**2
initial_guess = [1, 1, 1]
result = optimize.minimize(f, initial_guess)
if result.success:
fitted_params = result.x
print(fitted_params)
else:
raise ValueError(result.message)
I figured it out! The solution that I found to work was to change
params0 = [0.75, 0.23, 1.0, 0.2, M, theta]
in line 6 to
params0 = np.array([ 0.75, 0.23, 1.0, 0.2, *M, *theta], dtype=np.float64)
and in my function definition of my system of ODEs to be solved, instead of having
def f(yvec, t, a, b, c, d, M, theta):
x, y = yvec
dydt = [ a*x - b*y**2 + 1, -c*x - d*x*y + np.sum(M * np.cos(theta*t)) ]
return dydt
I now have
def f(yvec, t, myparams):
x, y = yvec
a, b, c, d = myparams[:4]
ni = (myparams[4:].shape[0])//2 # halved b/c M and theta are of the same shape
M = myparams[4:ni+4]
theta = myparams[ni+4:]
dydt = [ a*x - b*y**2 + 1, -c*x - d*x*y + np.sum(M * np.cos(theta*t)) ]
return dydt
NOTE: I had to add "dtype=np.float64" for 'params0' because I was getting the error
AttributeError: 'numpy.float64' object has no attribute 'cos'
when I did not have it there and it appears that 'cos' does not know how to handle 'ndarray' objects. The workaround can be found here.
Thanks everyone for the suggestions!

How to substitute symbol for matrix using symPy and numPy

I'm trying to substitute two symbols in my equation for the matrix form of each of them.
I created a commutator function which formed my expression:
t, vS, = sy.symbols('t, vS', commutative = False)
hS = t + vS
eta = myComm(t,hS)
dHs = myComm(eta,hS)
print dHs.expand()
yielding the correct expression I want:
2*t*vS*t + t*vS**2 - t**2*vS - 2*vS*t*vS - vS*t**2 + vS**2*t
So now I wish to substitute the symbols t and vS with matrices, however when using subs I get an error, "unhashable type: 'list'" I assume it has to do with my initialization of the matrices or how they should be properly substituted as I'm new to both numPy and symPy.
The rest of the code:
tRel = ([e0, 0],[0,e1])
vtmp = ([v0, v1],[v2,v3])
dHs = dHs.subs(t, tRel)
dHs = dHs.subs(vS, vtmp)
print dHs
Perhaps use lambdify:
import sympy as sy
import numpy as np
from sympy.abc import x, y
z = ((x+y)**2).expand()
print(z)
# x**2 + 2*x*y + y**2
X = np.arange(6).reshape(2,3)
Y = np.arange(1,7).reshape(2,3)
f = sy.lambdify((x, y), z, 'numpy')
print(f(X, Y))
# [[ 1 9 25]
# [ 49 81 121]]
assert np.allclose(f(X, Y), (X**2 + 2*X*Y + Y**2))

Categories

Resources