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.
- data.tar.gz.sig +0 -0
- data/History.txt +3 -0
- data/Manifest.txt +3 -1
- data/README.txt +1 -0
- data/Rakefile +2 -0
- data/lib/minimization.rb +386 -311
- data/spec/minimization_unidimensional_spec.rb +62 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +15 -0
- metadata +50 -7
- metadata.gz.sig +3 -0
- data/test/test_minimization.rb +0 -28
data.tar.gz.sig
ADDED
Binary file
|
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
data/README.txt
CHANGED
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
|
data/lib/minimization.rb
CHANGED
@@ -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
|
-
|
23
|
-
FailedIteration=Class.new(Exception)
|
22
|
+
VERSION="0.2.0"
|
23
|
+
FailedIteration=Class.new(Exception)
|
24
24
|
# Base class for unidimensional minimizers
|
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
|
-
|
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
|
-
#
|
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
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
78
|
-
def
|
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
|
-
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
|
-
|
128
|
-
|
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
|
-
|
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
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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
|
-
|
179
|
-
|
180
|
-
|
181
|
-
f_right
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
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)
|
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
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
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
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
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
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
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
|
-
|
315
|
-
|
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
|
-
|
405
|
+
@x_lower = z;
|
406
|
+
@f_lower = f_z;
|
318
407
|
end
|
319
|
-
|
320
|
-
@
|
321
|
-
@
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
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 =
|
336
|
-
@f_w =
|
337
|
-
|
338
|
-
|
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
|
-
|
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
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -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.
|
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-
|
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.
|
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
|
-
-
|
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
|
-
|
117
|
+
test_files: []
|
118
|
+
|
metadata.gz.sig
ADDED
data/test/test_minimization.rb
DELETED
@@ -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
|