-
Notifications
You must be signed in to change notification settings - Fork 0
/
Lagrange-Newton-IPython-Display.py
119 lines (109 loc) · 2.71 KB
/
Lagrange-Newton-IPython-Display.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# Use Gauss-Newton algorithm to fit a given model
# See http://en.wikipedia.org/wiki/Gauss-Newton_algorithm
from sympy import *
from sympy.abc import *
from IPython.display import display
init_printing(use_latex='mathjax')
def Gradient(fun, vars):
grad = []
for var in vars:
grad.append(fun.diff(var))
return grad
#def Lagrange_Newton(eqs, state_vars, data_dict, init_params_dict, eps=1e-4, max_iter=100):
def Lagrange_Newton(eq, state_var, data_dict, init_params_dict, eps=1e-4, max_iter=100):
J = [] #Jacobian
rs = [] #residuals
dlen = 0
for key, val in data_dict.items():
dlen = len(val)
break
unknown_params = init_params_dict.keys()
#
unknowns = []
for i in range(dlen):
unknowns.append(Symbol("y%d"%i))
for i in range(dlen):
unknowns.append(Symbol("lambda%d"%i))
unknowns = unknowns + unknown_params
#display(unknowns)
#
L = 0
data_y = data_dict[state_var]
for i in range(dlen):
L = L + (data_y[i] - unknowns[i])*(data_y[i] - unknowns[i])
for i in range(dlen):
lambda_i = unknowns[dlen+i]
state_eq = eq.lhs.subs(state_var, unknowns[i])
for key,val in data_dict.items():
state_eq = state_eq.subs(key, val[i])
L = L + lambda_i*state_eq
#
F = Gradient(L, unknowns)
JF = []
for f in F:
JF.append(Gradient(f, unknowns))
#
A = Matrix(JF)
unknowns_tuple = tuple(unknowns)
print "Lagrange: L", unknowns_tuple, "="; display(L)
#display(unknowns_tuple)
print "Hessian Matrix = "
display(A)
print "Grident of L = "
display(Matrix(F))
NJF = []
for row in JF:
NJFrow = []
for e in row:
NJFrow.append( lambdify(unknowns_tuple, e) )
NJF.append(NJFrow)
#display(NJF)
NF = []
for f in F:
NF.append( lambdify(unknowns_tuple, f) )
#display(NF)
init_vals = []
for idx in range(dlen):
init_vals.append(data_dict[state_var][idx])
for idx in range(dlen):
init_vals.append(0.0)
for param in unknown_params:
init_vals.append(init_params_dict[param])
print "Initial Value = "
display(init_vals)
for it in range(max_iter):
A = []
for row in NJF:
Atmp = []
for e in row:
Atmp.append( e(*init_vals) )
A.append(Atmp)
bb = []
for f in NF:
bb.append( f(*init_vals) )
#display(A)
#print bb
A = Matrix(A)
bb = Matrix(bb)
Ab = A.row_join(bb)
sol = solve_linear_system(Ab, *unknowns_tuple)
#print sol
norm = 0
for idx in range(len(unknowns_tuple)):
upd = sol[unknowns_tuple[idx]]
init_vals[idx] = init_vals[idx] - upd
norm = norm + upd*upd
if sqrt(norm) < eps:
print "Number of Newton Iteratons: %d" % it
break
return init_vals
sol = Lagrange_Newton(
Eq(y-a*x/(b+x), 0), y,
{
x:[0.038,0.194,0.425,0.626,1.253,2.500,3.740],
y:[0.050,0.127,0.094,0.2122,0.2729,0.2665,0.3317]
},
{ a: 0.9, b: 0.2 }
)
print "Solution = "
display(sol)