-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdescent_algorithm.py
More file actions
146 lines (116 loc) · 3.61 KB
/
descent_algorithm.py
File metadata and controls
146 lines (116 loc) · 3.61 KB
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
"""
Demonstrates rudimentary descent algorithm, along with good/bad choices for
1. Initialization
2. Descent direction
3. Stepsize
4. Termination criterion
To see how these all affect things, change "good_X" to "bad_X" on any of lines 55-58.
"""
from numpy import sin, cos, exp, linspace, meshgrid, zeros, reshape, vstack, min, max
from numpy.linalg import norm
from matplotlib.pyplot import figure, contour, plot, semilogy, subplot, show, xlabel, ylabel, title, subplots_adjust
from matplotlib.cm import jet
from descent_algorithm_utils import good_init, good_descent, good_stepsize, good_termination
from descent_algorithm_utils import bad_init, bad_descent, bad_stepsize, bad_termination
# The function and its gradient
def f(xy):
if len(xy.shape) > 1:
x = xy[:,0]
y = xy[:,1]
else:
x = xy[0]
y = xy[1]
fxy = cos(x + 0.5*y)*cos(0.5*x + y)
fxy += (10 - 10*exp(-(3*x**2 + y**2)))
return fxy
def gradf(xy):
if len(xy.shape) > 1:
x = xy[:,0]
y = xy[:,1]
gf = zeros([len(x), 2])
else:
x = xy[0]
y = xy[1]
gf = zeros([1, 2])
# x derivative
gf[:,0] += 60*x*exp(-(3*x**2 + y**2))
gf[:,0] += -sin(x+0.5*y)*cos(0.5*x+y)
gf[:,0] += -0.5*cos(x+0.5*y)*sin(0.5*x+y)
# y derivative
gf[:,1] += 20*y*exp(-(3*x**2 + y**2))
gf[:,1] += -0.5*sin(x+0.5*y)*cos(0.5*x+y)
gf[:,1] += -cos(x+0.5*y)*sin(0.5*x+y)
return gf
# Make some choices
init = good_init
descent = good_descent
stepsize = good_stepsize
terminate = good_termination
# Metrics
max_iter = 50
xy_k = zeros([max_iter+1, 2]) # iterates
f_k = zeros(max_iter+1) # function values
t_k = zeros(max_iter+1) # stepsizes
gf_k = zeros(max_iter+1) # gradient norms
k = 0 # Iteration count
# Initialize
xy_k[0,:] = init()
f_k[0] = f(xy_k[0,:])
gf = gradf(xy_k[0,:])
gf_k[0] = norm(gf)
while (k < max_iter) and not terminate(xy_k, f_k, t_k, gf_k, k):
# Descent direction
d_k = descent(gf)
# Stepsize
t_k[k] = stepsize(d_k, xy_k[k,:], gf, f)
# Update
xy_k[k+1,:] = xy_k[k,:] + t_k[k]*d_k
# Compute metrics for iterate k+1
f_k[k+1] = f(xy_k[k+1,:])
gf = gradf(xy_k[k+1,:])
gf_k[k+1] = norm(gf)
k += 1
# Truncate unused allocation
xy_k = xy_k[:k+1,:]
f_k = f_k[:k+1]
gf_k = gf_k[:k+1]
t_k = t_k[:k]
grid = linspace(-7, 7, 300)
x, y = meshgrid(grid, grid)
fxy = reshape(f(vstack((x.flatten(),y.flatten())).T), x.shape)
# Contour plot
fig = figure(figsize=(12, 8))
subplot(2,2,1)
contour(x, y, fxy, 20, cmap=jet)
plot(xy_k[0,0], xy_k[0,1], 'o', color='k', markerfacecolor="None")
plot(xy_k[-1,0], xy_k[-1,1], 'ko-')
xlabel('$x_1$'); ylabel('$x_2$'); title('$f(x_1, x_2)$')
# Surface plot
ax = subplot(2,2,2, projection="3d")
ax.plot_surface(x, y, fxy, antialiased=False, linewidth=0, cmap=jet)
xlabel('$x_1$'); ylabel('$x_2$');
ax = subplot(2,2,3)
contour(x, y, fxy, 20, cmap=jet)
plot(xy_k[:,0], xy_k[:,1], 'o-', color='k', markerfacecolor="None")
plot(xy_k[1:,0], xy_k[1:,1], 'ko-')
xmin, ymin = min(xy_k[:,0]) - 0.2, min(xy_k[:,1]) - 0.2
xmax, ymax = max(xy_k[:,0]) + 0.2, max(xy_k[:,1]) + 0.2
ax.set_xlim([xmin, xmax])
ax.set_ylim([ymin, ymax])
xlabel('$x_1$'); ylabel('$x_2$');
title('Descent algorithm iteration')
fig2 = figure(figsize=(8, 6))
subplot(3,1,1)
plot(range(k), t_k, 'k.-')
xlabel('Iteration index $k$')
title('Step size $t_k$')
subplot(3,1,2)
plot(range(k+1), f_k, 'k.-')
xlabel('Iteration index $k$')
title('Function value $f(x_k)$')
subplot(3,1,3)
semilogy(range(k+1), gf_k, 'k.-')
xlabel('Iteration index $k$')
title('Gradient norm $\\|\\nabla f(x_k)\\|$')
subplots_adjust(hspace=0.5)
show()