integration 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/.autotest +23 -0
- data/.gemtest +0 -0
- data/History.txt +3 -0
- data/Manifest.txt +9 -0
- data/README.txt +60 -0
- data/Rakefile +23 -0
- data/lib/integration.rb +340 -0
- data/spec/integration_spec.rb +60 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +11 -0
- metadata +124 -0
- metadata.gz.sig +1 -0
data.tar.gz.sig
ADDED
Binary file
|
data/.autotest
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.extra_files << "../some/external/dependency.rb"
|
7
|
+
#
|
8
|
+
# at.libs << ":../some/external"
|
9
|
+
#
|
10
|
+
# at.add_exception 'vendor'
|
11
|
+
#
|
12
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
13
|
+
# at.files_matching(/test_.*rb$/)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# %w(TestA TestB).each do |klass|
|
17
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
# Autotest.add_hook :run_command do |at|
|
22
|
+
# system "rake build"
|
23
|
+
# end
|
data/.gemtest
ADDED
File without changes
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
= integration
|
2
|
+
|
3
|
+
* http://github.com/clbustos/integration
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Numerical integration for Ruby, with a simple interface
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Use only one method: Integration.integrate
|
12
|
+
* Rectangular, Trapezoidal, Simpson, Adaptive quadrature, Monte Carlo and Romberg integration methods available on pure Ruby.
|
13
|
+
* If available, uses Ruby/GSL QNG non-adaptive Gauss-Kronrod integration and QAG adaptive integration, with support for Infinity+ and Infinity-
|
14
|
+
|
15
|
+
|
16
|
+
== SYNOPSIS:
|
17
|
+
|
18
|
+
Integration.integrate(1,2,{:tolerance=>1e-10,:method=>:simpson}) {|x| x**2} => 2.333333
|
19
|
+
|
20
|
+
# Support for infinity bounds with GSL QAG adaptative integration
|
21
|
+
|
22
|
+
normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
|
23
|
+
Integration.integrate(Integration::MInfinity, 0 , {:tolerance=>1e-10}, &normal_pdf) => 0.5
|
24
|
+
Integration.integrate(0, Integration::Infinity , {:tolerance=>1e-10}, &normal_pdf) => 0.5
|
25
|
+
|
26
|
+
== REQUIREMENTS:
|
27
|
+
|
28
|
+
* Ruby/GSL, for better performance and support for infinite bounds
|
29
|
+
|
30
|
+
== INSTALL:
|
31
|
+
|
32
|
+
gem install integration
|
33
|
+
|
34
|
+
== LICENSE:
|
35
|
+
|
36
|
+
Copyright (c) 2005 Beng
|
37
|
+
2011 clbustos
|
38
|
+
|
39
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
40
|
+
copy of this software and associated documentation files (the "Software"),
|
41
|
+
to deal in the Software without restriction, including without limitation
|
42
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
43
|
+
and/or sell copies of the Software, and to permit persons to whom the
|
44
|
+
Software is furnished to do so, subject to the following conditions:
|
45
|
+
|
46
|
+
The above copyright notice and this permission notice shall be included in
|
47
|
+
all copies or substantial portions of the Software.
|
48
|
+
|
49
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
50
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
51
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
52
|
+
THE DEVELOPERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
53
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
54
|
+
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
55
|
+
SOFTWARE.
|
56
|
+
|
57
|
+
Except as contained in this notice, the name of the Beng shall not
|
58
|
+
be used in advertising or otherwise to promote the sale, use or other dealings
|
59
|
+
in this Software without prior written authorization from Beng.
|
60
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__)+"/lib/"))
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require 'integration'
|
6
|
+
require 'rubyforge'
|
7
|
+
# Hoe.plugin :compiler
|
8
|
+
# Hoe.plugin :gem_prelude_sucks
|
9
|
+
Hoe.plugin :git
|
10
|
+
# Hoe.plugin :inline
|
11
|
+
# Hoe.plugin :racc
|
12
|
+
# Hoe.plugin :rubyforge
|
13
|
+
|
14
|
+
Hoe.spec 'integration' do
|
15
|
+
self.developer('Ben Gimpert', 'NO_EMAIL')
|
16
|
+
self.developer('Claudio Bustos', 'clbustos_at_gmail.com')
|
17
|
+
self.version=Integration::VERSION
|
18
|
+
self.extra_dev_deps << ["rspec",">=2.0"] << ["rubyforge",">=0"]
|
19
|
+
|
20
|
+
end
|
21
|
+
# git log --pretty=format:"*%s[%cn]" v0.5.0..HEAD >> History.txt
|
22
|
+
# vim: syntax=ruby
|
23
|
+
|
data/lib/integration.rb
ADDED
@@ -0,0 +1,340 @@
|
|
1
|
+
# Copyright (c) 2005 Beng (original code)
|
2
|
+
# 2011 clbustos
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a
|
5
|
+
# copy of this software and associated documentation files (the "Software"),
|
6
|
+
# to deal in the Software without restriction, including without limitation
|
7
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
8
|
+
# and/or sell copies of the Software, and to permit persons to whom the
|
9
|
+
# Software is furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
17
|
+
# THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
18
|
+
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
19
|
+
# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
# SOFTWARE.
|
21
|
+
#
|
22
|
+
# Except as contained in this notice, the name of the Beng shall not
|
23
|
+
# be used in advertising or otherwise to promote the sale, use or other dealings
|
24
|
+
# in this Software without prior written authorization from Beng.
|
25
|
+
|
26
|
+
# Diverse integration methods
|
27
|
+
# Use Integration.integrate as wrapper to direct access to methods
|
28
|
+
#
|
29
|
+
# Method API
|
30
|
+
#
|
31
|
+
|
32
|
+
class Integration
|
33
|
+
VERSION = '0.1.0'
|
34
|
+
# Minus Infinity
|
35
|
+
MInfinity=:minfinity
|
36
|
+
# Infinity
|
37
|
+
Infinity=:infinity
|
38
|
+
class << self
|
39
|
+
|
40
|
+
# Create a method 'has_<library>' on Module
|
41
|
+
# which require a library and return true or false
|
42
|
+
# according to success of failure
|
43
|
+
def create_has_library(library) #:nodoc:
|
44
|
+
define_singleton_method("has_#{library}?") do
|
45
|
+
cv="@@#{library}"
|
46
|
+
if !class_variable_defined? cv
|
47
|
+
begin
|
48
|
+
require library.to_s
|
49
|
+
class_variable_set(cv, true)
|
50
|
+
rescue LoadError
|
51
|
+
class_variable_set(cv, false)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
class_variable_get(cv)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Rectangle method
|
59
|
+
# +n+ implies number of subdivisions
|
60
|
+
def rectangle(t1, t2, n)
|
61
|
+
total_area = 0
|
62
|
+
t = t1
|
63
|
+
dt = (t2 - t1) / n.to_f
|
64
|
+
dt_half = dt / 2
|
65
|
+
|
66
|
+
while (t + dt_half) <= t2
|
67
|
+
height = yield(t + dt_half)
|
68
|
+
area = dt * height
|
69
|
+
total_area += area
|
70
|
+
t += dt
|
71
|
+
end
|
72
|
+
return total_area
|
73
|
+
|
74
|
+
end
|
75
|
+
alias_method :midpoint, :rectangle
|
76
|
+
|
77
|
+
def trapezoid(t1, t2, n)
|
78
|
+
total_area = 0
|
79
|
+
t = t1
|
80
|
+
dt = (t2 - t1) / n.to_f
|
81
|
+
prev_height = nil
|
82
|
+
while (t + dt) <= t2
|
83
|
+
if prev_height.nil?
|
84
|
+
height1 = yield(t)
|
85
|
+
else
|
86
|
+
height1 = prev_height
|
87
|
+
end
|
88
|
+
height2 = yield(t + dt)
|
89
|
+
area = dt * ((height1 + height2) / 2)
|
90
|
+
total_area += area
|
91
|
+
t += dt
|
92
|
+
prev_height = height2
|
93
|
+
end
|
94
|
+
return total_area
|
95
|
+
end
|
96
|
+
|
97
|
+
def simpson(t1, t2, n)
|
98
|
+
n += 1 unless n % 2 == 0
|
99
|
+
dt = (t2.to_f - t1) / n
|
100
|
+
total_area = 0
|
101
|
+
(0..n).each do |i|
|
102
|
+
t = t1 + (dt * i)
|
103
|
+
if i.zero? || (i == n)
|
104
|
+
total_area += yield(t)
|
105
|
+
elsif i % 2 == 0
|
106
|
+
total_area += 2 * yield(t)
|
107
|
+
else
|
108
|
+
total_area += 4 * yield(t)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
total_area *= dt / 3
|
112
|
+
return total_area
|
113
|
+
end
|
114
|
+
|
115
|
+
def adaptive_quadrature(a, b, tolerance)
|
116
|
+
h = (b.to_f - a) / 2
|
117
|
+
fa = yield(a)
|
118
|
+
fc = yield(a + h)
|
119
|
+
fb = yield(b)
|
120
|
+
s = h * (fa + (4 * fc) + fb) / 3
|
121
|
+
helper = Proc.new { |a, b, fa, fb, fc, h, s, level|
|
122
|
+
if level < 1/tolerance.to_f
|
123
|
+
fd = yield(a + (h / 2))
|
124
|
+
fe = yield(a + (3 * (h / 2)))
|
125
|
+
s1 = h * (fa + (4.0 * fd) + fc) / 6
|
126
|
+
s2 = h * (fc + (4.0 * fe) + fb) / 6
|
127
|
+
if ((s1 + s2) - s).abs <= tolerance
|
128
|
+
s1 + s2
|
129
|
+
else
|
130
|
+
helper.call(a, a + h, fa, fc, fd, h / 2, s1, level + 1) +
|
131
|
+
helper.call(a + h, b, fc, fb, fe, h / 2, s2, level + 1)
|
132
|
+
end
|
133
|
+
else
|
134
|
+
raise "Integral did not converge"
|
135
|
+
end
|
136
|
+
}
|
137
|
+
return helper.call(a, b, fa, fb, fc, h, s, 1)
|
138
|
+
end
|
139
|
+
|
140
|
+
def gauss(t1, t2, n)
|
141
|
+
case n
|
142
|
+
when 1
|
143
|
+
z = [0.0]
|
144
|
+
w = [2.0]
|
145
|
+
when 2
|
146
|
+
z = [-0.57735026919, 0.57735026919]
|
147
|
+
w = [1.0, 1.0]
|
148
|
+
when 3
|
149
|
+
z = [-0.774596669241, 0.0, 0.774596669241]
|
150
|
+
w = [0.555555555556, 0.888888888889, 0.555555555556]
|
151
|
+
when 4
|
152
|
+
z = [-0.861136311594, -0.339981043585, 0.339981043585, 0.861136311594]
|
153
|
+
w = [0.347854845137, 0.652145154863, 0.652145154863, 0.347854845137]
|
154
|
+
when 5
|
155
|
+
z = [-0.906179845939, -0.538469310106, 0.0, 0.538469310106, 0.906179845939]
|
156
|
+
w = [0.236926885056, 0.478628670499, 0.568888888889, 0.478628670499, 0.236926885056]
|
157
|
+
when 6
|
158
|
+
z = [-0.932469514203, -0.661209386466, -0.238619186083, 0.238619186083, 0.661209386466, 0.932469514203]
|
159
|
+
w = [0.171324492379, 0.360761573048, 0.467913934573, 0.467913934573, 0.360761573048, 0.171324492379]
|
160
|
+
when 7
|
161
|
+
z = [-0.949107912343, -0.741531185599, -0.405845151377, 0.0, 0.405845151377, 0.741531185599, 0.949107912343]
|
162
|
+
w = [0.129484966169, 0.279705391489, 0.381830050505, 0.417959183673, 0.381830050505, 0.279705391489, 0.129484966169]
|
163
|
+
when 8
|
164
|
+
z = [-0.960289856498, -0.796666477414, -0.525532409916, -0.183434642496, 0.183434642496, 0.525532409916, 0.796666477414, 0.960289856498]
|
165
|
+
w = [0.10122853629, 0.222381034453, 0.313706645878, 0.362683783378, 0.362683783378, 0.313706645878, 0.222381034453, 0.10122853629]
|
166
|
+
when 9
|
167
|
+
z = [-0.968160239508, -0.836031107327, -0.613371432701, -0.324253423404, 0.0, 0.324253423404, 0.613371432701, 0.836031107327, 0.968160239508]
|
168
|
+
w = [0.0812743883616, 0.180648160695, 0.260610696403, 0.31234707704, 0.330239355001, 0.31234707704, 0.260610696403, 0.180648160695, 0.0812743883616]
|
169
|
+
when 10
|
170
|
+
z = [-0.973906528517, -0.865063366689, -0.679409568299, -0.433395394129, -0.148874338982, 0.148874338982, 0.433395394129, 0.679409568299, 0.865063366689, 0.973906528517]
|
171
|
+
w = [0.0666713443087, 0.149451349151, 0.219086362516, 0.26926671931, 0.295524224715, 0.295524224715, 0.26926671931, 0.219086362516, 0.149451349151, 0.0666713443087]
|
172
|
+
else
|
173
|
+
raise "Invalid number of spaced abscissas #{n}, should be 1-10"
|
174
|
+
end
|
175
|
+
sum = 0
|
176
|
+
(0...n).each do |i|
|
177
|
+
t = ((t1.to_f + t2) / 2) + (((t2 - t1) / 2) * z[i])
|
178
|
+
sum += w[i] * yield(t)
|
179
|
+
end
|
180
|
+
return ((t2 - t1) / 2.0) * sum
|
181
|
+
end
|
182
|
+
|
183
|
+
def romberg(a, b, tolerance)
|
184
|
+
# NOTE one-based arrays are used for convenience
|
185
|
+
|
186
|
+
h = b.to_f - a
|
187
|
+
m = 1
|
188
|
+
close = 1
|
189
|
+
r = [[], [], [], [], [], [], [], [], [], [], [], [], []];
|
190
|
+
r[1][1] = (h / 2) * (yield(a) + yield(b))
|
191
|
+
j = 1
|
192
|
+
while j <= 11 && tolerance < close
|
193
|
+
j += 1
|
194
|
+
r[j][0] = 0
|
195
|
+
h /= 2
|
196
|
+
sum = 0
|
197
|
+
(1..m).each do |k|
|
198
|
+
sum += yield(a + (h * ((2 * k) - 1)))
|
199
|
+
end
|
200
|
+
m *= 2
|
201
|
+
r[j][1] = r[j-1][1] / 2 + (h * sum)
|
202
|
+
(1..j-1).each do |k|
|
203
|
+
r[j][k+1] = r[j][k] + ((r[j][k] - r[j-1][k]) / ((4 ** k) - 1))
|
204
|
+
end
|
205
|
+
close = (r[j][j] - r[j-1][j-1])
|
206
|
+
end
|
207
|
+
return r[j][j]
|
208
|
+
end
|
209
|
+
|
210
|
+
def monte_carlo(t1, t2, n)
|
211
|
+
width = (t2 - t1).to_f
|
212
|
+
height = nil
|
213
|
+
vals = []
|
214
|
+
n.times do
|
215
|
+
t = t1 + (rand() * width)
|
216
|
+
ft = yield(t)
|
217
|
+
height = ft if height.nil? || ft > height
|
218
|
+
vals << ft
|
219
|
+
end
|
220
|
+
area_ratio = 0
|
221
|
+
vals.each do |ft|
|
222
|
+
area_ratio += (ft / height.to_f) / n.to_f
|
223
|
+
end
|
224
|
+
return (width * height) * area_ratio
|
225
|
+
end
|
226
|
+
def is_infinite?(v)
|
227
|
+
v==Infinity or v==MInfinity
|
228
|
+
end
|
229
|
+
# Methods available on pure ruby
|
230
|
+
RUBY_METHOD=[:rectangle,:trapezoid,:simpson, :adaptive_quadrature , :gauss, :romberg, :monte_carlo]
|
231
|
+
# Methods available with Ruby/GSL library
|
232
|
+
GSL_METHOD=[:qng, :qag]
|
233
|
+
# Get the integral for a function +f+, with bounds +t1+ and
|
234
|
+
# +t2+ given a hash of +options+.
|
235
|
+
# If Ruby/GSL is available, you could use +Integration::Minfinity+
|
236
|
+
# and +Integration::Infinity+ as bounds. Method
|
237
|
+
# Options are
|
238
|
+
# [:tolerance] Maximum difference between real and calculated integral.
|
239
|
+
# Default: 1e-10
|
240
|
+
# [:initial_step] Initial number of subdivitions
|
241
|
+
# [:step] Subdivitions increment on each iteration
|
242
|
+
# [:method] Integration method.
|
243
|
+
# Methods are
|
244
|
+
# [:rectangle] for [:initial_step+:step*iteration] quadrilateral subdivisions
|
245
|
+
# [:trapezoid] for [:initial_step+:step*iteration] trapezoid-al subdivisions
|
246
|
+
# [:simpson] for [:initial_step+:step*iteration] parabolic subdivisions
|
247
|
+
# [:adaptive_quadrature] for recursive appoximations until error [tolerance]
|
248
|
+
# [:gauss] [:initial_step+:step*iteration] weighted subdivisons using translated -1 -> +1 endpoints
|
249
|
+
# [:romberg] extrapolation of recursion approximation until error < [tolerance]
|
250
|
+
# [:monte_carlo] make [:initial_step+:step*iteration] random samples, and check for above/below curve
|
251
|
+
# [:qng] GSL QNG non-adaptive Gauss-Kronrod integration
|
252
|
+
# [:qag] GSL QAG adaptive integration, with support for infinite bounds
|
253
|
+
def integrate(t1,t2,options=Hash.new, &f)
|
254
|
+
inf_bounds=(is_infinite?(t1) or is_infinite?(t2))
|
255
|
+
raise "No function passed" unless block_given?
|
256
|
+
raise "Non-numeric bounds" unless ((t1.is_a? Numeric) and (t2.is_a? Numeric)) or inf_bounds
|
257
|
+
if(inf_bounds)
|
258
|
+
lower_bound=t1
|
259
|
+
upper_bound=t2
|
260
|
+
options[:method]=:qag if options[:method].nil?
|
261
|
+
else
|
262
|
+
lower_bound = [t1, t2].min
|
263
|
+
upper_bound = [t1, t2].max
|
264
|
+
end
|
265
|
+
def_method=(has_gsl?) ? :qag : :simpson
|
266
|
+
default_opts={:tolerance=>1e-10, :initial_step=>16,:step=>16, :method=>def_method}
|
267
|
+
options=default_opts.merge(options)
|
268
|
+
if RUBY_METHOD.include? options[:method]
|
269
|
+
raise "Ruby methods doesn't support infinity bounds" if inf_bounds
|
270
|
+
integrate_ruby(lower_bound,upper_bound,options,&f)
|
271
|
+
elsif GSL_METHOD.include? options[:method]
|
272
|
+
integrate_gsl(lower_bound,upper_bound,options,&f)
|
273
|
+
else
|
274
|
+
raise "Unknown integration method \"#{options[:method]}\""
|
275
|
+
end
|
276
|
+
end
|
277
|
+
def integrate_gsl(lower_bound,upper_bound,options,&f)
|
278
|
+
|
279
|
+
f = GSL::Function.alloc(&f)
|
280
|
+
method=options[:method]
|
281
|
+
tolerance=options[:tolerance]
|
282
|
+
|
283
|
+
if(method==:qag)
|
284
|
+
w = GSL::Integration::Workspace.alloc()
|
285
|
+
if(is_infinite?(lower_bound) and is_infinite?(upper_bound))
|
286
|
+
#puts "ambos"
|
287
|
+
val=f.qagi([tolerance,0.0], 1000, w)
|
288
|
+
elsif is_infinite?(lower_bound)
|
289
|
+
#puts "inferior #{upper_bound}"
|
290
|
+
val=f.qagil(upper_bound, [tolerance, 0], w)
|
291
|
+
elsif is_infinite?(upper_bound)
|
292
|
+
#puts "superior"
|
293
|
+
val=f.qagiu(lower_bound, [tolerance, 0], w)
|
294
|
+
else
|
295
|
+
|
296
|
+
val=f.qag([lower_bound,upper_bound],[tolerance,0.0], GSL::Integration::GAUSS61, w)
|
297
|
+
end
|
298
|
+
elsif(method==:qng)
|
299
|
+
val=f.qng([lower_bound, upper_bound], [tolerance, 0.0])
|
300
|
+
else
|
301
|
+
raise "Unknown integration method \"#{method}\""
|
302
|
+
end
|
303
|
+
val[0]
|
304
|
+
end
|
305
|
+
def integrate_ruby(lower_bound,upper_bound,options,&f)
|
306
|
+
method=options[:method]
|
307
|
+
tolerance=options[:tolerance]
|
308
|
+
initial_step=options[:initial_step]
|
309
|
+
step=options[:step]
|
310
|
+
|
311
|
+
begin
|
312
|
+
method_obj = Integration.method(method.to_s.downcase)
|
313
|
+
rescue
|
314
|
+
raise "Unknown integration method \"#{method}\""
|
315
|
+
end
|
316
|
+
current_step=initial_step
|
317
|
+
|
318
|
+
if(method==:adaptive_quadrature or method==:romberg or method==:gauss)
|
319
|
+
if(method==:gauss)
|
320
|
+
initial_step=10 if initial_step>10
|
321
|
+
tolerance=initial_step
|
322
|
+
end
|
323
|
+
method_obj.call(lower_bound, upper_bound, tolerance, &f)
|
324
|
+
else
|
325
|
+
#puts "iniciando"
|
326
|
+
value=method_obj.call(lower_bound, upper_bound, current_step, &f)
|
327
|
+
previous=value+(tolerance*2)
|
328
|
+
while((previous-value).abs > tolerance) do
|
329
|
+
#puts(value)
|
330
|
+
#puts(current_step)
|
331
|
+
current_step+=step
|
332
|
+
previous=value
|
333
|
+
value=method_obj.call(lower_bound, upper_bound, current_step, &f)
|
334
|
+
end
|
335
|
+
value
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
create_has_library :gsl
|
340
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb")
|
2
|
+
describe Integration do
|
3
|
+
it "should respond integration based on ruby methods" do
|
4
|
+
a=lambda {|x| x**2}
|
5
|
+
# Integration over [1,2]=x^3/3=7/3
|
6
|
+
|
7
|
+
methods=[:rectangle,:trapezoid, :simpson, :adaptive_quadrature, :romberg]
|
8
|
+
methods.each do |m|
|
9
|
+
Integration.integrate(1,2,{:method=>m,:tolerance=>1e-7},&a).should be_within(1e-6).of(7/3.0)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return a correct value for a complex integration with ruby methods" do
|
15
|
+
normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
|
16
|
+
Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:simpson},&normal_pdf).should be_within(1e-11).of(0.341344746068)
|
17
|
+
Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:adaptive_quadrature},&normal_pdf).should be_within(1e-11).of(0.341344746068)
|
18
|
+
end
|
19
|
+
it "should return a correct value for a complex integration with gsl methods" do
|
20
|
+
normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
|
21
|
+
Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:qng},&normal_pdf).should be_within(1e-11).of(0.341344746068)
|
22
|
+
Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:qag},&normal_pdf).should be_within(1e-11).of(0.341344746068)
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
it "should return correct integration for infinity bounds" do
|
27
|
+
if Integration.has_gsl?
|
28
|
+
normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
|
29
|
+
|
30
|
+
Integration.integrate(Integration::MInfinity, Integration::Infinity,{:tolerance=>1e-10}, &normal_pdf).should be_within(1e-09).of(1)
|
31
|
+
else
|
32
|
+
pending("GSL not available")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
it "should return correct integration for infinity lower bound" do
|
36
|
+
if Integration.has_gsl?
|
37
|
+
normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
|
38
|
+
|
39
|
+
Integration.integrate(Integration::MInfinity, 0 , {:tolerance=>1e-10}, &normal_pdf).should be_within(1e-09).of(0.5)
|
40
|
+
|
41
|
+
else
|
42
|
+
pending("GSL not available")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
it "should return correct integration for infinity upper bound" do
|
46
|
+
if Integration.has_gsl?
|
47
|
+
|
48
|
+
normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
|
49
|
+
Integration.integrate(0,Integration::Infinity,{:tolerance=>1e-10}, &normal_pdf).should be_within(1e-09).of(0.5)
|
50
|
+
|
51
|
+
else
|
52
|
+
pending("GSL not available")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
it "should raise an error if a ruby methods is called with infinite bounds" do
|
56
|
+
normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
|
57
|
+
lambda {Integration.integrate(0,Integration::Infinity,{:method=>:simpson}, &normal_pdf).should be_within(1e-09).of(0.5)}.should raise_exception()
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: integration
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ben Gimpert
|
9
|
+
- Claudio Bustos
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain:
|
13
|
+
- |
|
14
|
+
-----BEGIN CERTIFICATE-----
|
15
|
+
MIIDMjCCAhqgAwIBAgIBADANBgkqhkiG9w0BAQUFADA/MREwDwYDVQQDDAhjbGJ1
|
16
|
+
c3RvczEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t
|
17
|
+
MB4XDTEwMDMyOTIxMzg1NVoXDTExMDMyOTIxMzg1NVowPzERMA8GA1UEAwwIY2xi
|
18
|
+
dXN0b3MxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
|
19
|
+
bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf8JVMGqE7m5kYb+PNN
|
20
|
+
neZv2pcXV5fQCi6xkyG8bi2/SIFy/LyxuvLzEeOxBeaz1Be93bayIUquOIqw3dyw
|
21
|
+
/KXWa31FxuNuvAm6CN8fyeRYX/ou4cw3OIUUnIvB7RMNIu4wbgeM6htV/QEsNLrv
|
22
|
+
at1/mh9JpqawPrcjIOVMj4BIp67vmzJCaUf+S/H2uYtSO09F+YQE3tv85TPeRmqU
|
23
|
+
yjyXyTc/oJiw1cXskUL8UtMWZmrwNLHXuZWWIMzkjiz3UNdhJr/t5ROk8S2WPznl
|
24
|
+
0bMy/PMIlAbqWolRn1zl2VFJ3TaXScbqImY8Wf4g62b/1ZSUlGrtnLNsCYXrWiso
|
25
|
+
UPUCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFGu9
|
26
|
+
rrJ1H64qRmNNu3Jj/Qjvh0u5MA0GCSqGSIb3DQEBBQUAA4IBAQCV0Unka5isrhZk
|
27
|
+
GjqSDqY/6hF+G2pbFcbWUpjmC8NWtAxeC+7NGV3ljd0e1SLfoyBj4gnFtFmY8qX4
|
28
|
+
K02tgSZM0eDV8TpgFpWXzK6LzHvoanuahHLZEtk/+Z885lFene+nHadkem1n9iAB
|
29
|
+
cs96JO9/JfFyuXM27wFAwmfHCmJfPF09R4VvGHRAvb8MGzSVgk2i06OJTqkBTwvv
|
30
|
+
JHJdoyw3+8bw9RJ+jLaNoQ+xu+1pQdS2bb3m7xjZpufml/m8zFCtjYM/7qgkKR8z
|
31
|
+
/ZZt8lCiKfFArppRrZayE2FVsps4X6WwBdrKTMZ0CKSXTRctbEj1BAZ67eoTvBBt
|
32
|
+
rpP0jjs0
|
33
|
+
-----END CERTIFICATE-----
|
34
|
+
|
35
|
+
date: 2011-08-24 00:00:00 -03:00
|
36
|
+
default_executable:
|
37
|
+
dependencies:
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: rspec
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "2.0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id001
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rubyforge
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id002
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: hoe
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "2.12"
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id003
|
71
|
+
description: Numerical integration for Ruby, with a simple interface
|
72
|
+
email:
|
73
|
+
- NO_EMAIL
|
74
|
+
- clbustos_at_gmail.com
|
75
|
+
executables: []
|
76
|
+
|
77
|
+
extensions: []
|
78
|
+
|
79
|
+
extra_rdoc_files:
|
80
|
+
- History.txt
|
81
|
+
- Manifest.txt
|
82
|
+
- README.txt
|
83
|
+
files:
|
84
|
+
- .autotest
|
85
|
+
- History.txt
|
86
|
+
- Manifest.txt
|
87
|
+
- README.txt
|
88
|
+
- Rakefile
|
89
|
+
- lib/integration.rb
|
90
|
+
- spec/integration_spec.rb
|
91
|
+
- spec/spec.opts
|
92
|
+
- spec/spec_helper.rb
|
93
|
+
- .gemtest
|
94
|
+
has_rdoc: true
|
95
|
+
homepage: http://github.com/clbustos/integration
|
96
|
+
licenses: []
|
97
|
+
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options:
|
100
|
+
- --main
|
101
|
+
- README.txt
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: "0"
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: "0"
|
116
|
+
requirements: []
|
117
|
+
|
118
|
+
rubyforge_project: integration
|
119
|
+
rubygems_version: 1.6.0
|
120
|
+
signing_key:
|
121
|
+
specification_version: 3
|
122
|
+
summary: Numerical integration for Ruby, with a simple interface
|
123
|
+
test_files: []
|
124
|
+
|
metadata.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
�mV݈5�H�Ȗ�279s�Z�Q�eY�ڇ&����9CKy��*�p�����z�"��m�<����/��_��[!�6��a$mzj6`��Z���0��6��S
|