minimization 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,326 @@
1
+ # = nelder_mead.rb -
2
+ # Minimization- Minimization algorithms on pure Ruby
3
+ # Copyright (C) 2010 Claudio Bustos
4
+ #
5
+ # This program is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU General Public License
7
+ # as published by the Free Software Foundation; either version 2
8
+ # of the License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
+ #
19
+ # This algorith was adopted and ported into Ruby from Apache-commons
20
+ # Math library's NelderMead.java file. Therefore this file is under
21
+ # Apache License Version 2.
22
+ #
23
+ # Nelder Mead Algorithm for Multidimensional minimization
24
+
25
+ require "#{File.expand_path(File.dirname(__FILE__))}/point_value_pair.rb"
26
+
27
+ module Minimization
28
+
29
+ class DirectSearchMinimizer
30
+
31
+ EPSILON_DEFAULT = 1e-6
32
+ MAX_ITERATIONS_DEFAULT = 1000000
33
+
34
+ attr_reader :x_minimum
35
+ attr_reader :f_minimum
36
+ attr_reader :epsilon
37
+
38
+ def initialize(f, start_point, iterate_simplex_ref)
39
+ @epsilon = EPSILON_DEFAULT
40
+ # Default number of maximum iterations
41
+ @max_iterations = MAX_ITERATIONS_DEFAULT
42
+ # proc which iterates the simplex
43
+ @iterate_simplex_ref = iterate_simplex_ref
44
+ @relative_threshold = 100 * @epsilon
45
+ @absolute_threshold = @epsilon
46
+ @x_minimum = nil
47
+ @f_minimum = nil
48
+ @f = f
49
+
50
+ # create and initializ start configurations
51
+ if @start_configuration == nil
52
+ # sets the start configuration point as unit
53
+ self.start_configuration = Array.new(start_point.length) { 1.0 }
54
+ end
55
+
56
+ @iterations = 0
57
+ @evaluations = 0
58
+ # create the simplex for the first time
59
+ build_simplex(start_point)
60
+ evaluate_simplex
61
+ end
62
+
63
+ def f(x)
64
+ return @f.call(x)
65
+ end
66
+
67
+ def iterate_simplex
68
+ return iterate_simplex_ref.call
69
+ end
70
+
71
+ # increment iteration counter by 1
72
+ def increment_iterations_counter
73
+ @iterations += 1
74
+ raise "iteration limit reached" if @iterations > @max_iterations
75
+ end
76
+
77
+ # compares 2 PointValuePair points
78
+ def compare(v1, v2)
79
+ if v1.value == v2.value
80
+ return 0
81
+ elsif v1.value > v2.value
82
+ return 1
83
+ else
84
+ return -1
85
+ end
86
+ end
87
+
88
+ # checks whether the function is converging
89
+ def converging?
90
+ # check the convergence in a given direction comparing the previous and current values
91
+ def point_converged?(previous, current)
92
+ pre = previous.value
93
+ curr = current.value
94
+ diff = (pre - curr).abs
95
+ size = [pre.abs, curr.abs].max
96
+ return !((diff <= (size * @relative_threshold)) and (diff <= @absolute_threshold))
97
+ end
98
+
99
+ # returns true if converging is possible atleast in one direction
100
+ if @iterations > 0
101
+ # given direction is converged
102
+ converged = true
103
+ 0.upto(@simplex.length - 1) do |i|
104
+ converged &= !point_converged?(@previous[i], @simplex[i])
105
+ end
106
+ return !converged
107
+ end
108
+
109
+ # if no iterations were done, convergence undefined
110
+ return true
111
+ end
112
+
113
+ # only the relative position of the n vertices with respect
114
+ # to the first one are stored
115
+ def start_configuration=(steps)
116
+ n = steps.length
117
+ @start_configuration = Array.new(n) { Array.new(n, 0) }
118
+ 0.upto(n - 1) do |i|
119
+ vertex_i = @start_configuration[i]
120
+ 0.upto(i) do |j|
121
+ raise "equals vertices #{j} and #{j+1} in simplex configuration" if steps[j] == 0.0
122
+ 0.upto(j) do |k|
123
+ vertex_i[k] = steps[k]
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ # Build an initial simplex
130
+ # == Parameters:
131
+ # * <tt>start_point</tt>: starting point of the minimization search
132
+ #
133
+ def build_simplex(start_point)
134
+ n = start_point.length
135
+ raise "dimension mismatch" if n != @start_configuration.length
136
+ # set first vertex
137
+ @simplex = Array.new(n+1)
138
+ @simplex[0] = PointValuePair.new(start_point, Float::NAN)
139
+
140
+ # set remaining vertices
141
+ 0.upto(n - 1) do |i|
142
+ conf_i = @start_configuration[i]
143
+ vertex_i = Array.new(n)
144
+ 0.upto(n - 1) do |k|
145
+ vertex_i[k] = start_point[k] + conf_i[k]
146
+ end
147
+ @simplex[i + 1] = PointValuePair.new(vertex_i, Float::NAN)
148
+ end
149
+ end
150
+
151
+ # Evaluate all the non-evaluated points of the simplex
152
+ def evaluate_simplex
153
+ # evaluate the objective function at all non-evaluated simplex points
154
+ 0.upto(@simplex.length - 1) do |i|
155
+ vertex = @simplex[i]
156
+ point = vertex.point
157
+ if vertex.value.nan?
158
+ @simplex[i] = PointValuePair.new(point, f(point))
159
+ end
160
+ end
161
+ # sort the simplex from best to worst
162
+ @simplex.sort!{ |x1, x2| x1.value <=> x2.value }
163
+ end
164
+
165
+ # Replace the worst point of the simplex by a new point
166
+ # == Parameters:
167
+ # * <tt>point_value_pair</tt>: point to insert
168
+ #
169
+ def replace_worst_point(point_value_pair)
170
+ n = @simplex.length - 1
171
+ 0.upto(n - 1) do |i|
172
+ if (compare(@simplex[i], point_value_pair) > 0)
173
+ point_value_pair, @simplex[i] = @simplex[i], point_value_pair
174
+ end
175
+ end
176
+ @simplex[n] = point_value_pair
177
+ end
178
+
179
+ # Convenience method to minimize
180
+ # == Parameters:
181
+ # * <tt>start_point</tt>: Starting points
182
+ # * <tt>f</tt>: Function to minimize
183
+ # == Usage:
184
+ # minimizer=Minimization::NelderMead.minimize(proc{|x| (x[0] - 1) ** 2 + (x[1] - 5) ** 2}, [0, 0])
185
+ #
186
+ def self.minimize(f, start_point)
187
+ min=Minimization::NelderMead.new(f, start_point)
188
+ while min.converging?
189
+ min.iterate
190
+ end
191
+ return min
192
+ end
193
+
194
+ # Iterate the simplex one step. Use this when iteration needs to be done manually
195
+ # == Usage:
196
+ # minimizer=Minimization::NelderMead.new(proc{|x| (x[0] - 1) ** 2 + (x[1] - 5) ** 2}, [0, 0])
197
+ # while minimizer.converging?
198
+ # minimizer.Iterate
199
+ # end
200
+ # minimizer.x_minimum
201
+ # minimizer.f_minimum
202
+ #
203
+ def iterate
204
+ # set previous simplex as the current simplex
205
+ @previous = Array.new(@simplex.length)
206
+ 0.upto(@simplex.length - 1) do |i|
207
+ point = @simplex[i].point # clone require?
208
+ @previous[i] = PointValuePair.new(point, f(point))
209
+ end
210
+ # iterate simplex
211
+ iterate_simplex
212
+ # set results
213
+ @x_minimum = @simplex[0].point
214
+ @f_minimum = @simplex[0].value
215
+ end
216
+ end
217
+
218
+ # = Nelder Mead Minimizer.
219
+ # A multidimensional minimization methods.
220
+ # == Usage.
221
+ # require 'minimization'
222
+ # min=Minimization::NelderMead.new(proc {|x| (x[0] - 2)**2 + (x[1] - 5)**2}, [1, 2])
223
+ # while min.converging?
224
+ # min.iterate
225
+ # end
226
+ # min.x_minimum
227
+ # min.f_minimum
228
+ #
229
+ class NelderMead < DirectSearchMinimizer
230
+ def initialize(f, start_point)
231
+ # Reflection coefficient
232
+ @rho = 1.0
233
+ # Expansion coefficient
234
+ @khi = 2.0
235
+ # Contraction coefficient
236
+ @gamma = 0.5
237
+ # Shrinkage coefficient
238
+ @sigma = 0.5
239
+ super(f, start_point, proc{iterate_simplex})
240
+ end
241
+
242
+ def iterate_simplex
243
+ increment_iterations_counter
244
+ n = @simplex.length - 1
245
+ # the simplex has n+1 point if dimension is n
246
+ best = @simplex[0]
247
+ secondBest = @simplex[n - 1]
248
+ worst = @simplex[n]
249
+ x_worst = worst.point
250
+ centroid = Array.new(n, 0)
251
+ # compute the centroid of the best vertices
252
+ # (dismissing the worst point at index n)
253
+ 0.upto(n - 1) do |i|
254
+ x = @simplex[i].point
255
+ 0.upto(n - 1) do |j|
256
+ centroid[j] += x[j]
257
+ end
258
+ end
259
+ scaling = 1.0 / n
260
+ 0.upto(n - 1) do |j|
261
+ centroid[j] *= scaling
262
+ end
263
+ xr = Array.new(n)
264
+ # compute the reflection point
265
+ 0.upto(n - 1) do |j|
266
+ xr[j] = centroid[j] + @rho * (centroid[j] - x_worst[j])
267
+ end
268
+ reflected = PointValuePair.new(xr, f(xr))
269
+ if ((compare(best, reflected) <= 0) && (compare(reflected, secondBest) < 0))
270
+ # accept the reflected point
271
+ replace_worst_point(reflected)
272
+ elsif (compare(reflected, best) < 0)
273
+ xe = Array.new(n)
274
+ # compute the expansion point
275
+ 0.upto(n - 1) do |j|
276
+ xe[j] = centroid[j] + @khi * (xr[j] - centroid[j])
277
+ end
278
+ expanded = PointValuePair.new(xe, f(xe))
279
+ if (compare(expanded, reflected) < 0)
280
+ # accept the expansion point
281
+ replace_worst_point(expanded)
282
+ else
283
+ # accept the reflected point
284
+ replace_worst_point(reflected)
285
+ end
286
+ else
287
+ if (compare(reflected, worst) < 0)
288
+ xc = Array.new(n)
289
+ # perform an outside contraction
290
+ 0.upto(n - 1) do |j|
291
+ xc[j] = centroid[j] + @gamma * (xr[j] - centroid[j])
292
+ end
293
+ out_contracted = PointValuePair.new(xc, f(xc))
294
+ if (compare(out_contracted, reflected) <= 0)
295
+ # accept the contraction point
296
+ replace_worst_point(out_contracted)
297
+ return
298
+ end
299
+ else
300
+ xc = Array.new(n)
301
+ # perform an inside contraction
302
+ 0.upto(n - 1) do |j|
303
+ xc[j] = centroid[j] - @gamma * (centroid[j] - x_worst[j])
304
+ end
305
+ in_contracted = PointValuePair.new(xc, f(xc))
306
+
307
+ if (compare(in_contracted, worst) < 0)
308
+ # accept the contraction point
309
+ replace_worst_point(in_contracted)
310
+ return
311
+ end
312
+ end
313
+ # perform a shrink
314
+ x_smallest = @simplex[0].point
315
+ 0.upto(@simplex.length - 1) do |i|
316
+ x = @simplex[i].get_point_clone
317
+ 0.upto(n - 1) do |j|
318
+ x[j] = x_smallest[j] + @sigma * (x[j] - x_smallest[j])
319
+ end
320
+ @simplex[i] = PointValuePair.new(x, Float::NAN)
321
+ end
322
+ evaluate_simplex
323
+ end
324
+ end
325
+ end
326
+ end
@@ -0,0 +1,22 @@
1
+ module Minimization
2
+ # class which holds the point,value pair
3
+ class PointValuePair
4
+ attr_reader :value
5
+ attr_accessor :value
6
+ attr_reader :point
7
+
8
+ # == Parameters:
9
+ # * <tt>point</tt>: Coordinates of the point
10
+ # * <tt>value</tt>: Function value at the point
11
+ #
12
+ def initialize(point, value)
13
+ @point = point.clone
14
+ @value = value
15
+ end
16
+
17
+ # returns a copy of the point
18
+ def get_point_clone
19
+ return @point.clone
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,319 @@
1
+ # = powell.rb -
2
+ # Minimization- Minimization algorithms on pure Ruby
3
+ # Copyright (C) 2010 Claudio Bustos
4
+ #
5
+ # This program is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU General Public License
7
+ # as published by the Free Software Foundation; either version 2
8
+ # of the License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
+ #
19
+ # This algorith was adopted and ported into Ruby from Apache-commons
20
+ # Math library's PowellOptimizer.java and
21
+ # BaseAbstractMultivariateVectorOptimizer.java
22
+ # files. Therefore this file is under Apache License Version 2.
23
+ #
24
+ # Powell's Algorithm for Multidimensional minimization
25
+ require "#{File.expand_path(File.dirname(__FILE__))}/point_value_pair.rb"
26
+ require "#{File.expand_path(File.dirname(__FILE__))}/../minimization.rb"
27
+
28
+ module Minimization
29
+ class ConjugateDirectionMinimizer
30
+ attr_accessor :max_iterations
31
+ attr_accessor :max_brent_iterations
32
+ attr_accessor :x_minimum
33
+ attr_accessor :f_minimum
34
+
35
+ # default maximum Powell's iteration value
36
+ Max_Iterations_Default = 100
37
+ # default Brent iteration value
38
+ MAX_BRENT_ITERATION_DEFAULT = 10 # give a suitable value
39
+
40
+ def initialize(f, initial_guess, lower_bound, upper_bound)
41
+ @iterations = 0
42
+ @max_iterations = Max_Iterations_Default
43
+ @evaluations = 0
44
+ @max_brent_iterations = MAX_BRENT_ITERATION_DEFAULT
45
+ @converging = true
46
+
47
+ # set minimizing function
48
+ @f = f
49
+ @start = initial_guess
50
+ @lower_bound = lower_bound
51
+ @upper_bound = upper_bound
52
+
53
+ # set maximum and minimum coordinate value a point can have
54
+ # while minimization process
55
+ @min_coordinate_val = lower_bound.min
56
+ @max_coordinate_val = upper_bound.max
57
+
58
+ # validate input parameters
59
+ check_parameters
60
+ end
61
+
62
+ # return the convergence of the search
63
+ def converging?
64
+ return @converging
65
+ end
66
+
67
+ # set minimization function
68
+ def f(x)
69
+ @f.call(x)
70
+ end
71
+
72
+ # validate input parameters
73
+ def check_parameters
74
+ if (!@start.nil?)
75
+ dim = @start.length
76
+ if (!@lower_bound.nil?)
77
+ # check for dimension mismatches
78
+ raise "dimension mismatching #{@lower_bound.length} and #{dim}" if @lower_bound.length != dim
79
+ # check whether start point exeeds the lower bound
80
+ 0.upto(dim - 1) do |i|
81
+ v = @start[i]
82
+ lo = @lower_bound[i]
83
+ raise "start point is lower than lower bound" if v < lo
84
+ end
85
+ end
86
+ if (!@upper_bound.nil?)
87
+ # check for dimension mismatches
88
+ raise "dimension mismatching #{@upper_bound.length} and #{dim}" if @upper_bound.length != dim
89
+ # check whether strating point exceeds the upper bound
90
+ 0.upto(dim - 1) do |i|
91
+ v = @start[i]
92
+ hi = @upper_bound[i]
93
+ raise "start point is higher than the upper bound" if v > hi
94
+ end
95
+ end
96
+
97
+ if (@lower_bound.nil?)
98
+ @lower_bound = Array.new(dim)
99
+ 0.upto(dim - 1) do |i|
100
+ @lower_bound[i] = Float::INFINITY # eventually this will occur an error
101
+ end
102
+ end
103
+ if (@upper_bound.nil?)
104
+ @upper_bound = Array.new(dim)
105
+ 0.upto(dim - 1) do |i|
106
+ @upper_bound[i] = -Float::INFINITY # eventually this will occur an error
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ # line minimization using Brent's minimization
113
+ # == Parameters:
114
+ # * <tt>point</tt>: Starting point
115
+ # * <tt>direction</tt>: Search direction
116
+ #
117
+ def brent_search(point, direction)
118
+ n = point.length
119
+ # Create a proc to minimize using brent search
120
+ # Function value varies with alpha value and represent a point
121
+ # of the minimizing function which is on the given plane
122
+ func = proc{ |alpha|
123
+ x = Array.new(n)
124
+ 0.upto(n - 1) do |i|
125
+ # create a point according to the given alpha value
126
+ x[i] = point[i] + alpha * direction[i]
127
+ end
128
+ # return the function value of the obtained point
129
+ f(x)
130
+ }
131
+
132
+ # create Brent minimizer
133
+ line_minimizer = Minimization::Brent.new(@min_coordinate_val, @max_coordinate_val, func)
134
+ # iterate Brent minimizer for given number of iteration value
135
+ 0.upto(@max_brent_iterations) do
136
+ line_minimizer.iterate
137
+ end
138
+ # return the minimum point
139
+ return {:alpha_min => line_minimizer.x_minimum, :f_val => line_minimizer.f_minimum}
140
+ end
141
+
142
+ end
143
+
144
+ # = Powell's Minimizer.
145
+ # A multidimensional minimization methods
146
+ # == Usage.
147
+ # require 'minimization'
148
+ # f = proc{ |x| (x[0] - 1)**2 + (2*x[1] - 5)**2 + (x[2]-3.3)**2}
149
+ # min = Minimization::Powell.minimize(f, [1, 2, 3], [0, 0, 0], [5, 5, 5])
150
+ # min.f_minimum
151
+ # min.x_minimum
152
+ #
153
+ class Powell < ConjugateDirectionMinimizer
154
+
155
+ attr_accessor :relative_threshold
156
+ attr_accessor :absolute_threshold
157
+
158
+ # default of relative threshold
159
+ RELATIVE_THRESHOLD_DEFAULT = 0.1
160
+ # default of absolute threshold
161
+ ABSOLUTE_THRESHOLD_DEFAULT =0.1
162
+
163
+ # == Parameters:
164
+ # * <tt>f</tt>: Minimization function
165
+ # * <tt>initial_guess</tt>: Initial position of Minimization
166
+ # * <tt>lower_bound</tt>: Lower bound of the minimization
167
+ # * <tt>upper_bound</tt>: Upper bound of the minimization
168
+ #
169
+ def initialize(f, initial_guess, lower_bound, upper_bound)
170
+ super(f, initial_guess.clone, lower_bound, upper_bound)
171
+ @relative_threshold = RELATIVE_THRESHOLD_DEFAULT
172
+ @absolute_threshold = ABSOLUTE_THRESHOLD_DEFAULT
173
+ end
174
+
175
+ # Obtain new point and direction from the previous point,
176
+ # previous direction and a parameter value
177
+ # == Parameters:
178
+ # * <tt>point</tt>: Previous point
179
+ # * <tt>direction</tt>: Previous direction
180
+ # * <tt>minimum</tt>: parameter value
181
+ #
182
+ def new_point_and_direction(point, direction, minimum)
183
+ n = point.length
184
+ new_point = Array.new(n)
185
+ new_dir = Array.new(n)
186
+ 0.upto(n - 1) do |i|
187
+ new_dir[i] = direction[i] * minimum
188
+ new_point[i] = point[i] + new_dir[i]
189
+ end
190
+ return {:point => new_point, :dir => new_dir}
191
+ end
192
+
193
+ # Iterate Powell's minimizer one step
194
+ # == Parameters:
195
+ # * <tt>f</tt>: Function to minimize
196
+ # * <tt>starting_point</tt>: starting point
197
+ # * <tt>lower_bound</tt>: Lowest possible values of each direction
198
+ # * <tt>upper_bound</tt>: Highest possible values of each direction
199
+ # == Usage:
200
+ # minimizer = Minimization::Powell.new(proc{|x| (x[0] - 1)**2 + (x[1] -1)**2},
201
+ # [0, 0, 0], [-5, -5, -5], [5, 5, 5])
202
+ # while minimizer.converging?
203
+ # minimizer.iterate
204
+ # end
205
+ # minimizer.x_minimum
206
+ # minimizer.f_minimum
207
+ #
208
+ def iterate
209
+ @iterations += 1
210
+
211
+ # set initial configurations
212
+ if(@iterations <= 1)
213
+ guess = @start
214
+ @n = guess.length
215
+ # initialize all to 0
216
+ @direc = Array.new(@n) { Array.new(@n) {0} }
217
+ 0.upto(@n - 1) do |i|
218
+ # set diagonal values to 1
219
+ @direc[i][i] = 1
220
+ end
221
+
222
+ @x = guess
223
+ @f_val = f(@x)
224
+ @x1 = @x.clone
225
+ end
226
+
227
+ fx = @f_val
228
+ fx2 = 0
229
+ delta = 0
230
+ big_ind = 0
231
+ alpha_min = 0
232
+
233
+ 0.upto(@n - 1) do |i|
234
+ direction = @direc[i].clone
235
+ fx2 = @f_val
236
+ # Find line minimum
237
+ minimum = brent_search(@x, direction)
238
+ @f_val = minimum[:f_val]
239
+ alpha_min = minimum[:alpha_min]
240
+ # Obtain new point and direction
241
+ new_pnd = new_point_and_direction(@x, direction, alpha_min)
242
+ new_point = new_pnd[:point]
243
+ new_dir = new_pnd[:dir]
244
+ @x = new_point
245
+
246
+ if ((fx2 - @f_val) > delta)
247
+ delta = fx2 - @f_val
248
+ big_ind = i
249
+ end
250
+ end
251
+
252
+ # convergence check
253
+ @converging = !(2 * (fx - @f_val) <= (@relative_threshold * (fx.abs + @f_val.abs) + @absolute_threshold))
254
+
255
+ # storing results
256
+ if((@f_val < fx))
257
+ @x_minimum = @x
258
+ @f_minimum = @f_val
259
+ else
260
+ @x_minimum = @x1
261
+ @f_minimum = fx
262
+ end
263
+
264
+ direction = Array.new(@n)
265
+ x2 = Array.new(@n)
266
+ 0.upto(@n -1) do |i|
267
+ direction[i] = @x[i] - @x1[i]
268
+ x2[i] = 2 * @x[i] - @x1[i]
269
+ end
270
+
271
+ @x1 = @x.clone
272
+ fx2 = f(x2)
273
+
274
+ if (fx > fx2)
275
+ t = 2 * (fx + fx2 - 2 * @f_val)
276
+ temp = fx - @f_val - delta
277
+ t *= temp * temp
278
+ temp = fx - fx2
279
+ t -= delta * temp * temp
280
+
281
+ if (t < 0.0)
282
+ minimum = brent_search(@x, direction)
283
+ @f_val = minimum[:f_val]
284
+ alpha_min = minimum[:alpha_min]
285
+ # Obtain new point and direction
286
+ new_pnd = new_point_and_direction(@x, direction, alpha_min)
287
+ new_point = new_pnd[:point]
288
+ new_dir = new_pnd[:dir]
289
+ @x = new_point
290
+
291
+ last_ind = @n - 1
292
+ @direc[big_ind] = @direc[last_ind]
293
+ @direc[last_ind] = new_dir
294
+ end
295
+ end
296
+ end
297
+
298
+ # Convenience method to minimize
299
+ # == Parameters:
300
+ # * <tt>f</tt>: Function to minimize
301
+ # * <tt>starting_point</tt>: starting point
302
+ # * <tt>lower_bound</tt>: Lowest possible values of each direction
303
+ # * <tt>upper_bound</tt>: Highest possible values of each direction
304
+ # == Usage:
305
+ # minimizer = Minimization::Powell.minimize(proc{|x| (x[0] - 1)**2 + (x[1] -1)**2},
306
+ # [0, 0, 0], [-5, -5, -5], [5, 5, 5])
307
+ # minimizer.x_minimum
308
+ # minimizer.f_minimum
309
+ #
310
+ def self.minimize(f, starting_point, lower_bound, upper_bound)
311
+ min = Minimization::Powell.new(f, starting_point, lower_bound, upper_bound)
312
+ while min.converging?
313
+ min.iterate
314
+ end
315
+ return min
316
+ end
317
+
318
+ end
319
+ end