-
Notifications
You must be signed in to change notification settings - Fork 0
/
nelder_mead.py
144 lines (124 loc) · 5.62 KB
/
nelder_mead.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
class Point:
def __init__(self, coordinates, cost):
self.coordinates = coordinates
self.cost = cost
def __lt__(a,b):
return a.cost < b.cost
def __gt__(a,b):
return a.cost > b.cost
def __str__(self):
return "Cost: " + str(self.cost) + " / Coords: " + str(self.coordinates)
def __repr__(self):
return self.__str__()
class VectorOps:
@staticmethod
def vecadd(X,Y):
assert (len(X) == len(Y)), "error : vectors of unequal length"
return [x + y for x,y in zip(X,Y)]
@staticmethod
def veckadd(X,k):
ret = []
for x in X:
ret.append(x+k)
return ret
@staticmethod
def veckmul(X,k):
ret = []
for x in X:
ret.append(x*k)
return ret
@staticmethod
def vecsub(X, Y):
assert (len(X) == len(Y)), "error : vectors of unequal length"
return [x - y for x,y in zip(X,Y)]
class NelderMead:
REFLECTION = 0
EXPANSION = 1
CONTRACTION = 2
REVERSE = False
def __init__(self, dimension, points,
alpha=1.0, gamma=2.0, rho=0.5, theta=0.5):
assert isinstance(points, list), "Points must be a list of points"
assert all(isinstance(point, Point) for point in points), "Points must be Nelder-Mead points"
assert all(len(point.coordinates) == dimension for point in points), "Points must have appropriate dimensionality"
assert (len(points) == dimension+1 and dimension >= 1), "Number of initial points must equal dimensionality + 1"
# Reflection, Expansion, Contraction, and Shrink coefficients:
self.ALPHA = alpha
self.GAMMA = gamma
self.RHO = rho
self.THETA = theta
self.state = NelderMead.REFLECTION
self.dimension = dimension
self.n_points = dimension+1
self.centroid = None
self.expanded = None
self.reflected = None
self.contracted = None
self.points = list(points)
self.points = sorted(self.points, reverse=NelderMead.REVERSE) # SHOULD BE ASCENDING COST!!
def __str__(self):
retval = ""
if self.state == NelderMead.REFLECTION: retval += "REFLECTION\n"
elif self.state == NelderMead.EXPANSION: retval += "EXPANSION\n"
elif self.state == NelderMead.CONTRACTION: retval += "CONTRACTION\n"
for x in range (0, self.n_points):
retval += str(self.points[x])+"\n"
return retval
def get_next_point(self):
VO=VectorOps
if self.state == NelderMead.REFLECTION:
self.centroid = [0.0]*self.dimension
for point in self.points:
self.centroid = VO.vecadd(self.centroid, point.coordinates)
self.centroid = VO.veckmul(self.centroid,(1.0/(self.n_points)))
reflection = VO.vecadd(VO.veckmul(self.centroid,(self.ALPHA+1.0)),
VO.veckmul(self.points[self.n_points-1].coordinates,-self.ALPHA))
self.reflected = Point(reflection, None)
return self.reflected
elif self.state == NelderMead.EXPANSION:
expansion = VO.vecadd(self.centroid,
VO.veckmul(VO.vecsub(self.reflected.coordinates, self.centroid),
self.GAMMA))
self.expanded = Point(expansion, None)
return self.expanded
elif self.state == NelderMead.CONTRACTION:
contraction = VO.vecadd(self.centroid,
VO.veckmul(VO.vecsub(self.points[self.n_points-1].coordinates,self.centroid),
self.RHO))
self.contracted = Point(contraction, None)
return self.contracted
def set_next_point(self, point):
assert isinstance(point, Point)
VO=VectorOps
if self.state == NelderMead.REFLECTION:
self.reflected = point
if point < self.points[self.n_points-2] and point > self.points[0]:
self.points[self.n_points-1] = self.reflected
self.points = sorted(self.points, reverse=NelderMead.REVERSE)
elif point < self.points[0]:
self.state = NelderMead.EXPANSION
else:
self.state = NelderMead.CONTRACTION
elif self.state == NelderMead.EXPANSION:
self.expanded = point
if self.expanded < self.reflected:
self.points[self.n_points-1] = self.expanded
else:
self.points[self.n_points-1] = self.reflected
self.points = sorted(self.points, reverse=NelderMead.REVERSE)
self.state = NelderMead.REFLECTION
elif self.state == NelderMead.CONTRACTION:
self.contracted = point
if self.contracted < self.points[self.n_points-1]:
self.points[self.n_points-1] = self.contracted
self.points = sorted(self.points, reverse=NelderMead.REVERSE)
else:
for x in range (0, self.n_points):
self.points[x].coordinates = VO.vecadd(self.points[0].coordinates, \
VO.veckmul(
VO.vecsub(self.points[x].coordinates, self.points[0].coordinates),
self.THETA
)
)
self.points = sorted(self.points, reverse=NelderMead.REVERSE)
self.state = NelderMead.REFLECTION