minimization 0.1.1 → 0.2.0

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.
Binary file
@@ -1,3 +1,6 @@
1
+ === 0.2.0 / 2010-04-15
2
+ * New Minimization::NewtonRahpson class, which implements a naive Newton-Rahpson minimization method
3
+ x=x_n-(f'(x)/f''(x))
1
4
  === 0.1.1 / 2010-03-19
2
5
 
3
6
  * New Minimization#minimize convenience method
@@ -4,4 +4,6 @@ Manifest.txt
4
4
  README.txt
5
5
  Rakefile
6
6
  lib/minimization.rb
7
- test/test_minimization.rb
7
+ spec/minimization_unidimensional_spec.rb
8
+ spec/spec.opts
9
+ spec/spec_helper.rb
data/README.txt CHANGED
@@ -9,6 +9,7 @@ Minimization algorithms on pure Ruby.
9
9
  == FEATURES/PROBLEMS:
10
10
 
11
11
  Unidimensional:
12
+ * Newton-Rahpson (requires first and second derivative)
12
13
  * Golden Section
13
14
  * Brent (Port of GSL code)
14
15
 
data/Rakefile CHANGED
@@ -3,12 +3,14 @@
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
5
  require './lib/minimization'
6
+ Hoe.plugin :git
6
7
 
7
8
  Hoe.spec 'minimization' do
8
9
  self.version=Minimization::VERSION
9
10
  self.rubyforge_name = 'ruby-statsample' # if different than 'minimization'
10
11
  self.developer('Claudio Bustos', 'clbustos_AT_gmail.com')
11
12
  self.remote_rdoc_dir = 'minimization'
13
+ self.extra_deps << ['text-table', "~>1.2"]
12
14
  end
13
15
 
14
16
  # vim: syntax=ruby
@@ -1,4 +1,4 @@
1
- # = minimization.rb -
1
+ # = minimization.rb -
2
2
  # Minimization- Minimization algorithms on pure Ruby
3
3
  # Copyright (C) 2010 Claudio Bustos
4
4
  #
@@ -16,353 +16,428 @@
16
16
  # along with this program; if not, write to the Free Software
17
17
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
18
  #
19
-
19
+ require 'text-table'
20
+ # Algorithms for unidimensional minimization
20
21
  module Minimization
21
-
22
- VERSION="0.1.1"
23
- FailedIteration=Class.new(Exception)
22
+ VERSION="0.2.0"
23
+ FailedIteration=Class.new(Exception)
24
24
  # Base class for unidimensional minimizers
25
- class Unidimensional
26
- # Default value for error
27
- EPSILON=1e-6
28
- # Default number of maximum iterations
29
- MAX_ITERATIONS=100
30
- # Minimum value for x
31
- attr_reader :x_minimum
32
- # Minimum value for f(x)
33
- attr_reader :f_minimum
34
- # Log of iterations
35
- attr_reader :log
36
- # Absolute error on x
37
- attr_accessor :epsilon
38
- # Create a new minimizer
39
- def initialize(lower, upper, proc)
40
- raise "first argument should be lower than second" if lower>=upper
41
- @lower=lower
42
- @upper=upper
43
- @proc=proc
44
- golden = 0.3819660;
45
- @expected = @lower + golden * (@upper - @lower);
46
- @max_iteration=MAX_ITERATIONS
47
- @epsilon=EPSILON
48
- @iterations=0
49
- @log=""
25
+ class Unidimensional
26
+ # Default value for error on f(x)
27
+ EPSILON=1e-6
28
+ # Default number of maximum iterations
29
+ MAX_ITERATIONS=100
30
+ # Minimum value for x
31
+ attr_reader :x_minimum
32
+ # Minimum value for f(x)
33
+ attr_reader :f_minimum
34
+ # Log of iterations. Should be an array
35
+ attr_reader :log
36
+ # Name of fields of log
37
+ attr_reader :log_header
38
+ # Absolute error on x
39
+ attr_accessor :epsilon
40
+ # Expected value. Fast minimum finding if set
41
+ attr_reader :expected
42
+ # Create a new minimizer
43
+ def initialize(lower, upper, proc)
44
+ raise "first argument should be lower than second" if lower>=upper
45
+ @lower=lower
46
+ @upper=upper
47
+ @proc=proc
48
+ golden = 0.3819660;
49
+ @expected = @lower + golden * (@upper - @lower);
50
+ @max_iteration=MAX_ITERATIONS
51
+ @epsilon=EPSILON
52
+ @iterations=0
53
+ @log=[]
54
+ @log_header=%w{I xl xh f(xl) f(xh) dx df(x)}
55
+ end
56
+ # Set expected value
57
+ def expected=(v)
58
+ @expected=v
59
+ end
60
+ def log_summary
61
+ @log.join("\n")
50
62
  end
51
63
  # Convenience method to minimize
52
- # Usage:
64
+ # == Parameters:
65
+ # * <tt>lower</tt>: Lower possible value
66
+ # * <tt>upper</tt>: Higher possible value
67
+ # * <tt>expected</tt>: Optional expected value. Faster the search is near correct value.
68
+ # * <tt>&block</tt>: Block with function to minimize
69
+ # == Usage:
53
70
  # minimizer=Minimization::GoldenSection.minimize(-1000, 1000) {|x|
54
71
  # x**2 }
55
- #
72
+ #
56
73
  def self.minimize(lower,upper,expected=nil,&block)
57
74
  minimizer=new(lower,upper,block)
58
75
  minimizer.expected=expected unless expected.nil?
59
76
  raise FailedIteration unless minimizer.iterate
60
77
  minimizer
61
78
  end
62
- def f(x)
79
+ # Iterate to find the minimum
80
+ def iterate
81
+ raise "You should implement this"
82
+ end
83
+ def f(x)
63
84
  @proc.call(x)
64
85
  end
65
- end
66
- # = Golden Section Minimizer.
67
- # Basic minimization algorithm. Slow, but robust
68
- # Use:
69
- # require 'minimization'
70
- # min=Minimization::GoldenSection.new(-1000,20000 , proc {|x| (x+1)**2}
71
- # min.expected=1.5 # Expected value
72
- # min.iterate
73
- # min.x_minimum
74
- # min.f_minimum
75
- # min.log
86
+ end
87
+ # Classic Newton-Raphson minimization method.
88
+ # Requires first and second derivative
89
+ # == Usage
90
+ # f = lambda {|x| x**2}
91
+ # fd = lambda {|x| 2x}
92
+ # fdd = lambda {|x| 2}
93
+ # min = Minimization::NewtonRaphson.new(-1000,1000, f,fd,fdd)
94
+ # min.iterate
95
+ # min.x_minimum
96
+ # min.f_minimum
97
+ #
98
+ class NewtonRaphson < Unidimensional
99
+ # == Parameters:
100
+ # * <tt>lower</tt>: Lower possible value
101
+ # * <tt>upper</tt>: Higher possible value
102
+ # * <tt>proc</tt>: Original function
103
+ # * <tt>proc_1d</tt>: First derivative
104
+ # * <tt>proc_2d</tt>: Second derivative
105
+ #
106
+ def initialize(lower, upper, proc, proc_1d, proc_2d)
107
+ super(lower,upper,proc)
108
+ @proc_1d=proc_1d
109
+ @proc_2d=proc_2d
110
+ end
111
+ # Raises an error
112
+ def self.minimize(*args)
113
+ raise "You should use #new and #iterate"
114
+ end
115
+ def iterate
116
+ # First
117
+ x_prev=@lower
118
+ x=@expected
119
+ failed=true
120
+ k=0
121
+ while (x-x_prev).abs > @epsilon and k<@max_iteration
122
+ k+=1
123
+ x_prev=x
124
+ x=x-(@proc_1d.call(x).quo(@proc_2d.call(x)))
125
+ f_prev=f(x_prev)
126
+ f=f(x)
127
+ x_min,x_max=[x,x_prev].min, [x,x_prev].max
128
+ f_min,f_max=[f,f_prev].min, [f,f_prev].max
129
+ @log << [k, x_min, x_max, f_min, f_max, (x_prev-x).abs, (f-f_prev).abs]
130
+ end
131
+ raise FailedIteration, "Not converged" if k>=@max_iteration
132
+ @x_minimum = x;
133
+ @f_minimum = f(x);
134
+ end
135
+ end
136
+ # = Golden Section Minimizer.
137
+ # Basic minimization algorithm. Slow, but robust.
138
+ # See Unidimensional for methods.
139
+ # == Usage.
140
+ # require 'minimization'
141
+ # min=Minimization::GoldenSection.new(-1000,20000 , proc {|x| (x+1)**2}
142
+ # min.expected=1.5 # Expected value
143
+ # min.iterate
144
+ # min.x_minimum
145
+ # min.f_minimum
146
+ # min.log
76
147
  class GoldenSection < Unidimensional
77
- attr_accessor :expected
78
- def initialize(lower,upper, proc)
79
- super
80
- end
81
- # Start the iteration
82
- def iterate
83
- ax=@lower
84
- bx=@expected
85
- cx=@upper
86
- c = (3-Math::sqrt(5)).quo(2);
87
- r = 1-c;
88
-
89
- x0 = ax;
90
- x3 = cx;
91
- if ((cx-bx).abs > (bx-ax).abs)
92
- x1 = bx;
93
- x2 = bx + c*(cx-bx);
94
- else
95
- x2 = bx;
96
- x1 = bx - c*(bx-ax);
97
- end
98
- f1 = f(x1);
99
- f2 = f(x2);
100
-
101
- k = 1;
102
-
103
-
104
-
105
- while (x3-x0).abs > @epsilon and k<@max_iteration
106
- @log+=sprintf("k=%4d, |a-b|=%e\n", k, (x3-x0).abs)
107
- if f2 < f1
108
- x0 = x1;
109
- x1 = x2;
110
- x2 = r*x1 + c*x3; # x2 = x1+c*(x3-x1)
111
- f1 = f2;
112
- f2 = f(x2);
113
- else
114
- x3 = x2;
115
- x2 = x1;
116
- x1 = r*x2 + c*x0; # x1 = x2+c*(x0-x2)
117
- f2 = f1;
118
- f1 = f(x1);
119
- end
120
- k +=1;
121
- end
122
-
123
- if f1 < f2
124
- @x_minimum = x1;
125
- @f_minimum = f1;
148
+ # Start the iteration
149
+ def iterate
150
+ ax=@lower
151
+ bx=@expected
152
+ cx=@upper
153
+ c = (3-Math::sqrt(5)).quo(2);
154
+ r = 1-c;
155
+
156
+ x0 = ax;
157
+ x3 = cx;
158
+ if ((cx-bx).abs > (bx-ax).abs)
159
+ x1 = bx;
160
+ x2 = bx + c*(cx-bx);
161
+ else
162
+ x2 = bx;
163
+ x1 = bx - c*(bx-ax);
164
+ end
165
+ f1 = f(x1);
166
+ f2 = f(x2);
167
+
168
+ k = 1;
169
+
170
+
171
+
172
+ while (x3-x0).abs > @epsilon and k<@max_iteration
173
+ if f2 < f1
174
+ x0 = x1;
175
+ x1 = x2;
176
+ x2 = r*x1 + c*x3; # x2 = x1+c*(x3-x1)
177
+ f1 = f2;
178
+ f2 = f(x2);
126
179
  else
127
- @x_minimum = x2;
128
- @f_minimum = f2;
180
+ x3 = x2;
181
+ x2 = x1;
182
+ x1 = r*x2 + c*x0; # x1 = x2+c*(x0-x2)
183
+ f2 = f1;
184
+ f1 = f(x1);
129
185
  end
130
- true
186
+ @log << [k, x3,x0, f1,f2,(x3-x0).abs, (f1-f2).abs]
187
+
188
+ k +=1;
131
189
  end
132
190
 
191
+ if f1 < f2
192
+ @x_minimum = x1;
193
+ @f_minimum = f1;
194
+ else
195
+ @x_minimum = x2;
196
+ @f_minimum = f2;
197
+ end
198
+ true
199
+ end
200
+
201
+ end
202
+
203
+ # Direct port of Brent algorithm found on GSL.
204
+ # See Unidimensional for methods.
205
+ # == Usage
206
+ # min=Minimization::Brent.new(-1000,20000 , proc {|x| (x+1)**2}
207
+ # min.expected=1.5 # Expected value
208
+ # min.iterate
209
+ # min.x_minimum
210
+ # min.f_minimum
211
+ # min.log
212
+
213
+ class Brent < Unidimensional
214
+ GSL_SQRT_DBL_EPSILON=1.4901161193847656e-08
215
+ def initialize(lower,upper, proc)
216
+ super
217
+
218
+ @do_bracketing=true
219
+
220
+ # Init
221
+
222
+ golden = 0.3819660; #golden = (3 - sqrt(5))/2
223
+
224
+ v = @lower + golden * (@upper - @lower);
225
+ w = v;
226
+
227
+ @x_minimum = v ;
228
+ @f_minimum = f(v) ;
229
+ @x_lower=@lower
230
+ @x_upper=@upper
231
+ @f_lower = f(@lower) ;
232
+ @f_upper = f(@lower) ;
233
+
234
+ @v = v;
235
+ @w = w;
236
+
237
+ @d = 0;
238
+ @e = 0;
239
+ @f_v=f(v)
240
+ @f_w=@f_v
241
+ end
242
+
243
+ def expected=(v)
244
+ @x_minimum=v
245
+ @f_minimum=f(v)
246
+ @do_bracketing=false
133
247
  end
134
248
 
135
- # Direct port of Brent algorithm found on GSL
136
- # min=Minimization::Brent.new(-1000,20000 , proc {|x| (x+1)**2}
137
- # min.expected=1.5 # Expected value
138
- # min.iterate
139
- # min.x_minimum
140
- # min.f_minimum
141
- # min.log
142
-
143
- class Brent < Unidimensional
144
- GSL_SQRT_DBL_EPSILON=1.4901161193847656e-08
145
- def initialize(lower,upper, proc)
146
- super
147
-
148
- @do_bracketing=true
149
-
150
- # Init
151
-
152
- golden = 0.3819660; #golden = (3 - sqrt(5))/2
153
-
154
- v = @lower + golden * (@upper - @lower);
155
- w = v;
156
-
157
- @x_minimum = v ;
158
- @f_minimum = f(v) ;
159
- @x_lower=@lower
160
- @x_upper=@upper
161
- @f_lower = f(@lower) ;
162
- @f_upper = f(@lower) ;
163
-
164
- @v = v;
165
- @w = w;
166
-
167
- @d = 0;
168
- @e = 0;
169
- @f_v=f(v)
170
- @f_w=@f_v
171
- end
172
-
173
- def expected=(v)
174
- @x_minimum=v
175
- @f_minimum=f(v)
176
- @do_bracketing=false
249
+ def bracketing
250
+ eval_max=10
251
+ f_left = @f_lower;
252
+ f_right = @f_upper;
253
+ x_left = @x_lower;
254
+ x_right= @x_upper;
255
+ golden = 0.3819660; # golden = (3 - sqrt(5))/2 */
256
+ nb_eval=0
257
+
258
+ if (f_right >= f_left)
259
+ x_center = (x_right - x_left) * golden + x_left;
260
+ nb_eval+=1;
261
+ f_center=f(x_center)
262
+ else
263
+ x_center = x_right ;
264
+ f_center = f_right ;
265
+ x_right = (x_center - x_left).quo(golden) + x_left;
266
+ nb_eval+=1;
267
+ f_right=f(x_right);
177
268
  end
178
- def bracketing
179
- eval_max=10
180
- f_left = @f_lower;
181
- f_right = @f_upper;
182
- x_left = @x_lower;
183
- x_right= @x_upper;
184
- golden = 0.3819660; # golden = (3 - sqrt(5))/2 */
185
- nb_eval=0
186
-
187
- if (f_right >= f_left)
188
- x_center = (x_right - x_left) * golden + x_left;
189
- nb_eval+=1;
190
- f_center=f(x_center)
191
- else
192
- x_center = x_right ;
193
- f_center = f_right ;
194
- x_right = (x_center - x_left).quo(golden) + x_left;
195
- nb_eval+=1;
196
- f_right=f(x_right);
197
- end
198
-
199
-
200
- begin
201
- @log+=sprintf("B%d: [%0.5f - %0.5f] -> [%0.5f - %0.5f] E: %0.6f\n", nb_eval, x_left, x_right, f_left, f_right, (x_left-x_right).abs)
202
- if (f_center < f_left )
203
- if (f_center < f_right)
204
- @x_lower = x_left;
205
- @x_upper = x_right;
206
- @x_minimum = x_center;
207
- @f_lower = f_left;
208
- @f_upper = f_right;
209
- @f_minimum = f_center;
210
- return true;
211
- elsif (f_center > f_right)
212
- x_left = x_center;
213
- f_left = f_center;
214
- x_center = x_right;
215
- f_center = f_right;
216
- x_right = (x_center - x_left).quo(golden) + x_left;
217
- nb_eval+=1;
218
- f_right=f(x_right);
219
- else # f_center == f_right */
220
- x_right = x_center;
221
- f_right = f_center;
222
- x_center = (x_right - x_left).quo(golden) + x_left;
223
- nb_eval+=1;
224
- f_center=f(x_center);
225
- end
226
- else # f_center >= f_left */
269
+
270
+
271
+ begin
272
+ @log << ["B#{nb_eval}", x_left, x_right, f_left, f_right, (x_left-x_right).abs, (f_left-f_right).abs]
273
+ if (f_center < f_left )
274
+ if (f_center < f_right)
275
+ @x_lower = x_left;
276
+ @x_upper = x_right;
277
+ @x_minimum = x_center;
278
+ @f_lower = f_left;
279
+ @f_upper = f_right;
280
+ @f_minimum = f_center;
281
+ return true;
282
+ elsif (f_center > f_right)
283
+ x_left = x_center;
284
+ f_left = f_center;
285
+ x_center = x_right;
286
+ f_center = f_right;
287
+ x_right = (x_center - x_left).quo(golden) + x_left;
288
+ nb_eval+=1;
289
+ f_right=f(x_right);
290
+ else # f_center == f_right */
227
291
  x_right = x_center;
228
292
  f_right = f_center;
229
- x_center = (x_right - x_left) * golden + x_left;
293
+ x_center = (x_right - x_left).quo(golden) + x_left;
230
294
  nb_eval+=1;
231
295
  f_center=f(x_center);
232
296
  end
233
- end while ((nb_eval < eval_max) and
234
- ((x_right - x_left) > GSL_SQRT_DBL_EPSILON * ( (x_right + x_left) * 0.5 ) + GSL_SQRT_DBL_EPSILON))
235
- @x_lower = x_left;
236
- @x_upper = x_right;
237
- @x_minimum = x_center;
238
- @f_lower = f_left;
239
- @f_upper = f_right;
240
- @f_minimum = f_center;
241
- return false;
242
-
243
- end
244
- # Start the minimization process
245
- # If you want to control manually the process, use brent_iterate
246
- def iterate
247
- k=0
248
- bracketing if @do_bracketing
249
- while k<@max_iteration and (@x_lower-@x_upper).abs>@epsilon
250
- k+=1
251
- result=brent_iterate
252
- raise "Error on iteration" if !result
253
- @log+=sprintf("%d: [%0.5f - %0.5f] -> [%0.5f - %0.5f] E: %0.6f\n", k, @x_lower, @x_upper, @f_lower, @f_upper, (@x_lower-@x_upper).abs)
297
+ else # f_center >= f_left */
298
+ x_right = x_center;
299
+ f_right = f_center;
300
+ x_center = (x_right - x_left) * golden + x_left;
301
+ nb_eval+=1;
302
+ f_center=f(x_center);
254
303
  end
255
- @iterations=k
256
- return true
257
- end
258
- # Generate one iteration.
259
- def brent_iterate
260
- x_left = @x_lower;
261
- x_right = @x_upper;
262
-
263
- z = @x_minimum;
264
- d = @e;
265
- e = @d;
266
- v = @v;
267
- w = @w;
268
- f_v = @f_v;
269
- f_w = @f_w;
270
- f_z = @f_minimum;
271
-
272
- golden = 0.3819660; # golden = (3 - sqrt(5))/2 */
273
-
274
- w_lower = (z - x_left)
275
- w_upper = (x_right - z)
276
-
277
- tolerance = GSL_SQRT_DBL_EPSILON * z.abs
278
-
279
- midpoint = 0.5 * (x_left + x_right)
280
- _p,q,r=0,0,0
281
- if (e.abs > tolerance)
282
-
283
- # fit parabola */
284
-
285
- r = (z - w) * (f_z - f_v);
286
- q = (z - v) * (f_z - f_w);
287
- _p = (z - v) * q - (z - w) * r;
288
- q = 2 * (q - r);
289
-
290
- if (q > 0)
291
- _p = -_p
292
- else
293
- q = -q;
294
- end
295
- r = e;
296
- e = d;
304
+ end while ((nb_eval < eval_max) and
305
+ ((x_right - x_left) > GSL_SQRT_DBL_EPSILON * ( (x_right + x_left) * 0.5 ) + GSL_SQRT_DBL_EPSILON))
306
+ @x_lower = x_left;
307
+ @x_upper = x_right;
308
+ @x_minimum = x_center;
309
+ @f_lower = f_left;
310
+ @f_upper = f_right;
311
+ @f_minimum = f_center;
312
+ return false;
313
+
314
+ end
315
+ # Start the minimization process
316
+ # If you want to control manually the process, use brent_iterate
317
+ def iterate
318
+ k=0
319
+ bracketing if @do_bracketing
320
+ while k<@max_iteration and (@x_lower-@x_upper).abs>@epsilon
321
+ k+=1
322
+ result=brent_iterate
323
+ raise FailedIteration,"Error on iteration" if !result
324
+ begin
325
+ @log << [k, @x_lower, @x_upper, @f_lower, @f_upper, (@x_lower-@x_upper).abs, (@f_lower-@f_upper).abs]
326
+ rescue =>@e
327
+ @log << [k, @e.to_s,nil,nil,nil,nil,nil]
297
328
  end
298
-
299
- if (_p.abs < (0.5 * q * r).abs and _p < q * w_lower and _p < q * w_upper)
300
- t2 = 2 * tolerance ;
301
-
302
- d = _p.quo(q);
303
- u = z + d;
304
-
305
- if ((u - x_left) < t2 or (x_right - u) < t2)
306
- d = (z < midpoint) ? tolerance : -tolerance ;
307
- end
329
+ end
330
+ @iterations=k
331
+ return true
332
+ end
333
+ # Generate one iteration.
334
+ def brent_iterate
335
+ x_left = @x_lower;
336
+ x_right = @x_upper;
337
+
338
+ z = @x_minimum;
339
+ d = @e;
340
+ e = @d;
341
+ v = @v;
342
+ w = @w;
343
+ f_v = @f_v;
344
+ f_w = @f_w;
345
+ f_z = @f_minimum;
346
+
347
+ golden = 0.3819660; # golden = (3 - sqrt(5))/2 */
348
+
349
+ w_lower = (z - x_left)
350
+ w_upper = (x_right - z)
351
+
352
+ tolerance = GSL_SQRT_DBL_EPSILON * z.abs
353
+
354
+ midpoint = 0.5 * (x_left + x_right)
355
+ _p,q,r=0,0,0
356
+ if (e.abs > tolerance)
357
+
358
+ # fit parabola */
359
+
360
+ r = (z - w) * (f_z - f_v);
361
+ q = (z - v) * (f_z - f_w);
362
+ _p = (z - v) * q - (z - w) * r;
363
+ q = 2 * (q - r);
364
+
365
+ if (q > 0)
366
+ _p = -_p
308
367
  else
309
-
310
- e = (z < midpoint) ? x_right - z : -(z - x_left) ;
311
- d = golden * e;
368
+ q = -q;
312
369
  end
313
-
314
- if ( d.abs >= tolerance)
315
- u = z + d;
370
+ r = e;
371
+ e = d;
372
+ end
373
+
374
+ if (_p.abs < (0.5 * q * r).abs and _p < q * w_lower and _p < q * w_upper)
375
+ t2 = 2 * tolerance ;
376
+
377
+ d = _p.quo(q);
378
+ u = z + d;
379
+
380
+ if ((u - x_left) < t2 or (x_right - u) < t2)
381
+ d = (z < midpoint) ? tolerance : -tolerance ;
382
+ end
383
+ else
384
+
385
+ e = (z < midpoint) ? x_right - z : -(z - x_left) ;
386
+ d = golden * e;
387
+ end
388
+
389
+ if ( d.abs >= tolerance)
390
+ u = z + d;
391
+ else
392
+ u = z + ((d > 0) ? tolerance : -tolerance) ;
393
+ end
394
+
395
+ @e = e;
396
+ @d = d;
397
+
398
+ f_u=f(u)
399
+
400
+ if (f_u <= f_z)
401
+ if (u < z)
402
+ @x_upper = z;
403
+ @f_upper = f_z;
316
404
  else
317
- u = z + ((d > 0) ? tolerance : -tolerance) ;
405
+ @x_lower = z;
406
+ @f_lower = f_z;
318
407
  end
319
-
320
- @e = e;
321
- @d = d;
322
-
323
- f_u=f(u)
324
-
325
- if (f_u <= f_z)
326
- if (u < z)
327
- @x_upper = z;
328
- @f_upper = f_z;
329
- else
330
- @x_lower = z;
331
- @f_lower = f_z;
332
- end
408
+ @v = w;
409
+ @f_v = f_w;
410
+ @w = z;
411
+ @f_w = f_z;
412
+ @x_minimum = u;
413
+ @f_minimum = f_u;
414
+ return true;
415
+ else
416
+ if (u < z)
417
+ @x_lower = u;
418
+ @f_lower = f_u;
419
+ return true;
420
+ else
421
+ @x_upper = u;
422
+ @f_upper = f_u;
423
+ return true;
424
+ end
425
+
426
+ if (f_u <= f_w or w == z)
333
427
  @v = w;
334
428
  @f_v = f_w;
335
- @w = z;
336
- @f_w = f_z;
337
- @x_minimum = u;
338
- @f_minimum = f_u;
429
+ @w = u;
430
+ @f_w = f_u;
431
+ return true;
432
+ elsif f_u <= f_v or v == z or v == w
433
+ @v = u;
434
+ @f_v = f_u;
339
435
  return true;
340
- else
341
- if (u < z)
342
- @x_lower = u;
343
- @f_lower = f_u;
344
- return true;
345
- else
346
- @x_upper = u;
347
- @f_upper = f_u;
348
- return true;
349
- end
350
-
351
- if (f_u <= f_w or w == z)
352
- @v = w;
353
- @f_v = f_w;
354
- @w = u;
355
- @f_w = f_u;
356
- return true;
357
- elsif f_u <= f_v or v == z or v == w
358
- @v = u;
359
- @f_v = f_u;
360
- return true;
361
- end
362
-
363
436
  end
364
- return false
365
-
437
+
366
438
  end
439
+ return false
440
+
367
441
  end
368
442
  end
443
+ end
@@ -0,0 +1,62 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ describe Minimization::Unidimensional, "subclass" do
3
+ before(:all) do
4
+ @p1=rand(100)
5
+ @p2=rand(100)
6
+ @func=lambda {|x| (x-@p1)**2+@p2}
7
+ @funcd=lambda {|x| 2*(x-@p1)}
8
+ @funcdd=lambda {|x| 2}
9
+ end
10
+
11
+ describe Minimization::NewtonRaphson do
12
+ before do
13
+ @min = Minimization::NewtonRaphson.new(-1000,1000, @func,@funcd, @funcdd)
14
+ @min.iterate
15
+ end
16
+ it "#x_minimum be close to expected" do
17
+ @min.x_minimum.should be_close(@p1,@min.epsilon)
18
+ end
19
+ it "#f_minimum ( f(x)) be close to expected" do
20
+ @min.f_minimum.should be_close(@p2,@min.epsilon)
21
+ end
22
+ context "#log" do
23
+ subject {@min.log}
24
+ it {should be_instance_of Array}
25
+ it {should respond_to :to_table}
26
+ end
27
+ end
28
+
29
+
30
+ describe Minimization::GoldenSection do
31
+ before do
32
+ @min = Minimization::GoldenSection.minimize(-1000,1000, &@func)
33
+ end
34
+ it "#x_minimum be close to expected" do
35
+ @min.x_minimum.should be_close(@p1,@min.epsilon)
36
+ end
37
+ it "#f_minimum ( f(x)) be close to expected" do
38
+ @min.f_minimum.should be_close(@p2,@min.epsilon)
39
+ end
40
+ context "#log" do
41
+ subject {@min.log}
42
+ it {should be_instance_of Array}
43
+ it {should respond_to :to_table}
44
+ end
45
+ end
46
+ describe Minimization::Brent do
47
+ before do
48
+ @min = Minimization::Brent.minimize(-1000,1000, &@func)
49
+ end
50
+ it "should x be correct" do
51
+ @min.x_minimum.should be_close(@p1,@min.epsilon)
52
+ end
53
+ it "should f(x) be correct" do
54
+ @min.f_minimum.should be_close(@p2,@min.epsilon)
55
+ end
56
+ context "#log" do
57
+ subject {@min.log}
58
+ it {should be_instance_of Array}
59
+ it {should respond_to :to_table}
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,2 @@
1
+ --color
2
+ -f s
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'minimization.rb'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
10
+
11
+ class String
12
+ def deindent
13
+ gsub /^[ \t]*/, ''
14
+ end
15
+ end
metadata CHANGED
@@ -1,17 +1,58 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minimization
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claudio Bustos
8
8
  autorequire:
9
9
  bindir: bin
10
- cert_chain: []
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDMjCCAhqgAwIBAgIBADANBgkqhkiG9w0BAQUFADA/MREwDwYDVQQDDAhjbGJ1
14
+ c3RvczEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t
15
+ MB4XDTEwMDMyOTIxMzg1NVoXDTExMDMyOTIxMzg1NVowPzERMA8GA1UEAwwIY2xi
16
+ dXN0b3MxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
17
+ bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf8JVMGqE7m5kYb+PNN
18
+ neZv2pcXV5fQCi6xkyG8bi2/SIFy/LyxuvLzEeOxBeaz1Be93bayIUquOIqw3dyw
19
+ /KXWa31FxuNuvAm6CN8fyeRYX/ou4cw3OIUUnIvB7RMNIu4wbgeM6htV/QEsNLrv
20
+ at1/mh9JpqawPrcjIOVMj4BIp67vmzJCaUf+S/H2uYtSO09F+YQE3tv85TPeRmqU
21
+ yjyXyTc/oJiw1cXskUL8UtMWZmrwNLHXuZWWIMzkjiz3UNdhJr/t5ROk8S2WPznl
22
+ 0bMy/PMIlAbqWolRn1zl2VFJ3TaXScbqImY8Wf4g62b/1ZSUlGrtnLNsCYXrWiso
23
+ UPUCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFGu9
24
+ rrJ1H64qRmNNu3Jj/Qjvh0u5MA0GCSqGSIb3DQEBBQUAA4IBAQCV0Unka5isrhZk
25
+ GjqSDqY/6hF+G2pbFcbWUpjmC8NWtAxeC+7NGV3ljd0e1SLfoyBj4gnFtFmY8qX4
26
+ K02tgSZM0eDV8TpgFpWXzK6LzHvoanuahHLZEtk/+Z885lFene+nHadkem1n9iAB
27
+ cs96JO9/JfFyuXM27wFAwmfHCmJfPF09R4VvGHRAvb8MGzSVgk2i06OJTqkBTwvv
28
+ JHJdoyw3+8bw9RJ+jLaNoQ+xu+1pQdS2bb3m7xjZpufml/m8zFCtjYM/7qgkKR8z
29
+ /ZZt8lCiKfFArppRrZayE2FVsps4X6WwBdrKTMZ0CKSXTRctbEj1BAZ67eoTvBBt
30
+ rpP0jjs0
31
+ -----END CERTIFICATE-----
11
32
 
12
- date: 2010-03-19 00:00:00 -03:00
33
+ date: 2010-04-15 00:00:00 -04:00
13
34
  default_executable:
14
35
  dependencies:
36
+ - !ruby/object:Gem::Dependency
37
+ name: text-table
38
+ type: :runtime
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: "1.2"
45
+ version:
46
+ - !ruby/object:Gem::Dependency
47
+ name: rubyforge
48
+ type: :development
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.0.4
55
+ version:
15
56
  - !ruby/object:Gem::Dependency
16
57
  name: hoe
17
58
  type: :development
@@ -20,7 +61,7 @@ dependencies:
20
61
  requirements:
21
62
  - - ">="
22
63
  - !ruby/object:Gem::Version
23
- version: 2.4.0
64
+ version: 2.6.0
24
65
  version:
25
66
  description: Minimization algorithms on pure Ruby.
26
67
  email:
@@ -41,7 +82,9 @@ files:
41
82
  - README.txt
42
83
  - Rakefile
43
84
  - lib/minimization.rb
44
- - test/test_minimization.rb
85
+ - spec/minimization_unidimensional_spec.rb
86
+ - spec/spec.opts
87
+ - spec/spec_helper.rb
45
88
  has_rdoc: true
46
89
  homepage: http://ruby-statsample.rubyforge.org/
47
90
  licenses: []
@@ -71,5 +114,5 @@ rubygems_version: 1.3.5
71
114
  signing_key:
72
115
  specification_version: 3
73
116
  summary: Minimization algorithms on pure Ruby.
74
- test_files:
75
- - test/test_minimization.rb
117
+ test_files: []
118
+
@@ -0,0 +1,3 @@
1
+ b��G4B ���1њ�h��r5vt���Ԯ�ᗅ�~Nӫ�&
2
+ H ,����9! �\m�_�L��]6����i�*��3)�'���&�����~{`-z�,V ���"u"��C�|�PBpۢ�%5 �~Z��<\��f�dC�rj��v^�
3
+ �x�[D��Ù���Pځ�`��"CE�� ����E'4%�!?�O��_��p
@@ -1,28 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__)+'/../lib/')
2
- require "test/unit"
3
- require "minimization"
4
-
5
- class TestMinimization < Test::Unit::TestCase
6
- def setup
7
- @p1=rand(100)
8
- @p2=rand(100)
9
- @func=lambda {|x| (x-@p1)**2+@p2}
10
- end
11
- def test_facade
12
- min=Minimization::GoldenSection.minimize(-1000,1000) {|x| (x-@p1)**2+@p2}
13
- assert_in_delta(@p1,min.x_minimum, min.epsilon)
14
- assert_in_delta(@p2,min.f_minimum, min.epsilon)
15
- end
16
- def test_golden
17
- min=Minimization::GoldenSection.new(-1000,1000, @func)
18
- min.iterate
19
- assert_in_delta(@p1, min.x_minimum, min.epsilon)
20
- assert_in_delta(@p2, min.f_minimum, min.epsilon)
21
- end
22
- def test_brent
23
- min=Minimization::Brent.new(-1000,1000, @func)
24
- min.iterate
25
- assert_in_delta(@p1, min.x_minimum, min.epsilon)
26
- assert_in_delta(@p2, min.f_minimum, min.epsilon)
27
- end
28
- end