minimization 0.2.3 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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