-
Notifications
You must be signed in to change notification settings - Fork 0
/
diff_root.py
148 lines (123 loc) · 3.83 KB
/
diff_root.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
from parser_classes import *
from token_constants import *
from math import sin, cos, log
from diff import diff
from diff_lex import lex
from diff_parse_fast import parse
from diff_optim import optimize
def eval_binop(expr, v):
assert type(expr) == Binop
assert type(v) == float
op = expr.get_op()
l = expr.get_l()
r = expr.get_r()
if op == ADD:
return eval_expr(l, v) + eval_expr(r, v)
elif op == SUB:
return eval_expr(l, v) - eval_expr(r, v)
elif op == MUL:
return eval_expr(l, v) * eval_expr(r, v)
elif op == DIV:
return eval_expr(l, v) / eval_expr(r, v)
elif op == POW:
return eval_expr(l, v) ** eval_expr(r, v)
else:
raise RuntimeError(
f"Undefined operator {op} when doing arithmetic optimization.")
def eval_function(expr, v):
assert type(expr) == Function
f = expr.get_f()
e = expr.get_e()
if f == SIN:
return sin(eval_expr(e, v))
elif f == COS:
return cos(eval_expr(e, v))
elif f == LN:
return log(eval_expr(e, v))
raise RuntimeError(
f"Undefined function {f} when doing function evaluation.")
def eval_unop(expr, v):
assert type(expr) == Unop
o = expr.get_op()
e = expr.get_e()
if o == SUB:
return -1 * eval_expr(e, v)
raise RuntimeError(
f"Undefined unary operator {o} when doing unary operator evaluation.")
def eval_expr(expr, v):
assert isinstance(expr, Expr)
assert type(v) == float
assert v != None
if type(expr) == Float:
return expr.get_f()
elif type(expr) == Const:
return expr.get_c()
elif type(expr) == Var:
return v
elif type(expr) == Function:
return eval_function(expr, v)
elif type(expr) == Binop:
return eval_binop(expr, v)
elif type(expr) == Unop:
return eval_unop(expr, v)
def newton_h(expr, guess, precision, niter):
assert isinstance(expr, Expr)
assert type(guess) == float
assert type(precision) == float
assert precision >= 0
assert type(niter) == int
assert niter >= 0
if niter == 0:
if abs(eval_expr(expr, guess)) < precision:
return guess
# no valid root found
return None
if abs(eval_expr(expr, guess)) < precision:
return guess
new_guess = guess - eval_expr(expr, guess) / (
eval_expr(diff(expr), guess) if eval_expr(diff(expr), guess) != 0 else 10E-15)
return newton_h(expr, new_guess, precision, niter - 1)
def newton(expr, guess, precision, niter):
assert isinstance(expr, Expr)
assert type(guess) == float
assert type(precision) == float
assert precision >= 0
assert type(niter) == int
assert niter >= 0
return newton_h(expr, guess, precision, niter)
def main():
print("Root Finding With Newton's Method")
while True:
try:
string = input("expression > ")
guess = input("guess > ")
try:
guess = float(guess)
except Exception:
raise Exception()
precision = input("precision > ")
try:
precision = float(precision)
except Exception:
raise Exception()
niter = input("iterations > ")
try:
niter = int(niter)
except Exception:
raise Exception()
tokens = lex(string)
expr = parse(tokens)
root = newton(expr, guess, precision, niter)
if root == None:
print("No root was found.")
else:
print(root)
print()
except KeyboardInterrupt:
print("Quitting...")
exit(0)
except Exception:
print("Issue in expression or guess. ")
continue
if __name__ == "__main__":
main()