forked from ubsuny/CompPhys
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrootfinding.py
158 lines (150 loc) · 5.06 KB
/
rootfinding.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env python
import math
import sys
import cmath
import numpy as np
def root_print_header(algorithm, accuracy):
sys.stdout.write("\n ROOT FINDING using " + algorithm +
"\n Requested accuracy = " +repr(accuracy) +
"\n Step Guess For Root Step Size " +
" Function Value" +
"\n ---- -------------------- --------------------" +
" --------------------" + "\n")
def root_print_step(step, x, dx, f_of_x):
sys.stdout.write(repr(step).rjust(5))
for val in [x, dx, f_of_x]:
sys.stdout.write(" " + repr(val).ljust(20))
sys.stdout.write("\n")
def root_max_steps(algorithm, max_steps):
raise Exception(" " + algorithm + ": maximum number of steps " +
repr(max_steps) + " exceeded\n")
def root_simple(f, x, dx, accuracy=1.0e-6, max_steps=1000, root_debug=False):
"""Return root of f(x) given guess x and step dx with specified accuracy.
Step must be in direction of root: dx must have same sign as (root - x).
"""
f0 = f(x)
fx = f0
step = 0
iterations = []
if root_debug:
root_print_header("Simple Search with Step Halving", accuracy)
root_print_step(step, x, dx, f0)
iterations.append([x,f0])
while abs(dx) > abs(accuracy) and f0 != 0.0:
x += dx
fx = f(x)
if f0 * fx < 0.0: # stepped past root
x -= dx # step back
dx /= 2.0 # use smaller step
step += 1
if step > max_steps:
root_max_steps("root_simple", max_steps)
if root_debug:
root_print_step(step, x, dx, fx)
iterations.append([x,fx])
return x,np.array(iterations)
def root_bisection(f, x1, x2, accuracy=1.0e-6, max_steps=1000, root_debug=False):
"""Return root of f(x) in bracketed by x1, x2 with specified accuracy.
Assumes that f(x) changes sign once in the bracketed interval.
Uses bisection root-finding algorithm.
"""
iterations = []
f1 = f(x1)
f2 = f(x2)
if f1 * f2 > 0.0:
raise Exception("f(x1) * f(x2) > 0.0")
x_mid = (x1 + x2) / 2.0
f_mid = f(x_mid)
dx = x2 - x1
step = 0
if root_debug:
iterations = []
root_print_header("Bisection Search", accuracy)
root_print_step(step, x_mid, dx, f_mid)
iterations.append([x_mid,f_mid])
while abs(dx) > accuracy:
if f_mid == 0.0:
dx = 0.0
else:
if f1 * f_mid > 0:
x1 = x_mid
f1 = f_mid
else:
x2 = x_mid
f2 = f_mid
x_mid = (x1 + x2) / 2.0
f_mid = f(x_mid)
dx = x2 - x1
step += 1
if step > max_steps:
warning = "Too many steps (" + repr(step) + ") in root_bisection"
raise Exception(warning)
if root_debug:
root_print_step(step, x_mid, dx, f_mid)
iterations.append([x_mid,f_mid])
return x_mid,np.array(iterations)
def root_secant(f, x0, x1, accuracy=1.0e-6, max_steps=20,root_debug=False):
"""Return root of f(x) given guesses x0 and x1 with specified accuracy.
Uses secant root-finding algorithm.
"""
iterations=[]
f0 = f(x0)
dx = x1 - x0
step = 0
if root_debug:
root_print_header("Secant Search", accuracy)
root_print_step(step, x0, dx, f0)
iterations.append([x0,f0])
if f0 == 0:
return x0
while abs(dx) > abs(accuracy):
f1 = f(x1)
if f1 == 0:
return x1
if f1 == f0:
raise Exception("Secant horizontal f(x0) = f(x1) algorithm fails")
dx *= - f1 / (f1 - f0)
x0 = x1
f0 = f1
x1 += dx
step += 1
if step > max_steps:
root_max_steps("root_secant", max_steps)
if root_debug:
root_print_step(step, x1, dx, f1)
iterations.append([x1,f1])
return x1,np.array(iterations)
def root_tangent(f, fp, x0, accuracy=1.0e-6, max_steps=20, root_debug=False):
"""Return root of f(x) with derivative fp = df(x)/dx
given initial guess x0, with specified accuracy.
Uses Newton-Raphson (tangent) root-finding algorithm.
"""
iterations = []
f0 = f(x0)
fp0 = fp(x0)
if fp0 == 0.0:
raise Exception(" root_tangent df/dx = 0 algorithm fails")
dx = - f0 / fp0
step = 0
if root_debug:
root_print_header("Tangent Search", accuracy)
root_print_step(step, x0, dx, f0)
iterations.append([x0,f0])
if f0 == 0.0:
return x0
while True:
fp0 = fp(x0)
if fp0 == 0.0:
raise Exception(" root_tangent df/dx = 0 algorithm fails")
dx = - f0 / fp0
x0 += dx
f0 = f(x0)
if abs(dx) <= accuracy or f0 == 0.0:
return x0
step += 1
if step > max_steps:
root_max_steps("root_tangent", max_steps)
if root_debug:
root_print_step(step, x0, dx, f0)
iterations.append([x0,f0])
return x0