integration 0.1.3 → 0.1.4
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.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.yardopts +4 -0
- data/CONTRIBUTING.md +61 -0
- data/Gemfile +2 -0
- data/History.txt +5 -0
- data/integration.gemspec +14 -7
- data/lib/integration.rb +124 -500
- data/lib/integration/methods.rb +394 -0
- data/lib/integration/version.rb +1 -1
- data/spec/integration_spec.rb +45 -56
- data/spec/spec_helper.rb +7 -7
- metadata +25 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4dbd1debd129047a700d50d3934dd668da72b23d
|
4
|
+
data.tar.gz: 572db4475376afd86960f615c795312106ffab5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc7f3547bee2355ff9f846f6a9b7e91d5d44058ac4eabcddad19b1e25ab019708e6fc1e03b4169b798f871f7aa79c5b3b9ff27842d852f5514616f54cc3d08be
|
7
|
+
data.tar.gz: 007a90888618d8b75c6aec71340644db283ead8b3b5d5ba70d6fc7736f04d57f5a5349507245d81759c85fd910e87444e86f0fe69a2b9b46096adbd56b592313
|
data/.gitignore
CHANGED
data/.yardopts
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
Integration is part of SciRuby, a collaborative effort to bring scientific computation to Ruby. If you want to help, please
|
2
|
+
do so!
|
3
|
+
|
4
|
+
This guide covers ways in which you can contribute to the development of SciRuby and, more specifically, Integration.
|
5
|
+
|
6
|
+
## How to help
|
7
|
+
|
8
|
+
There are various ways to help Integration: bug reports, coding and documentation. All of them are important.
|
9
|
+
|
10
|
+
First, you can help implement new features or bug fixes. To do that, visit our [issue tracker][2]. If you find something that you want to work on, post it in the issue or on our [mailing list][1].
|
11
|
+
|
12
|
+
You need to send tests together with your code. No exceptions. You can ask for our opinion, but we won't accept patches without good spec coverage.
|
13
|
+
|
14
|
+
We use RSpec for testing. If you aren't familiar with it, there's a good [guide to better specs with RSpec](http://betterspecs.org/) that shows a bit of the syntax and how to use it properly.
|
15
|
+
However, the best resource is probably the specs that already exist -- so just read them.
|
16
|
+
|
17
|
+
And don't forget to write documentation (we use YARD). It's necessary to allow others to know what's available in the library. There's a section on it later in this guide.
|
18
|
+
|
19
|
+
We only accept bug reports and pull requests in GitHub. You'll need to create a new (free) account if you don't have one already. To learn how to create a pull request, please see [this guide on collaborating](https://help.github.com/categories/63/articles).
|
20
|
+
|
21
|
+
If you have a question about how to use Integration or SciRuby in general or a feature/change in mind, please ask the [sciruby-dev mailing list][1].
|
22
|
+
|
23
|
+
Thanks!
|
24
|
+
|
25
|
+
## Coding
|
26
|
+
|
27
|
+
To start working on Integration, clone the repository and use bundler to install the dependencies:
|
28
|
+
|
29
|
+
```bash
|
30
|
+
$ git clone git://github.com/SciRuby/integration.git
|
31
|
+
$ cd integration
|
32
|
+
$ bundle install
|
33
|
+
```
|
34
|
+
|
35
|
+
If everything's fine until now, you can create a new branch to work on your feature:
|
36
|
+
|
37
|
+
```bash
|
38
|
+
$ git branch new-feature
|
39
|
+
$ git checkout new-feature
|
40
|
+
```
|
41
|
+
|
42
|
+
Before commiting any code, please read our
|
43
|
+
[Contributor Agreement](http://github.com/SciRuby/sciruby/wiki/Contributor-Agreement).
|
44
|
+
|
45
|
+
## Style guide
|
46
|
+
|
47
|
+
Follow the [GitHub styleguide](https://github.com/styleguide/ruby). If you have any doubt, contact us.
|
48
|
+
|
49
|
+
## Documentation
|
50
|
+
|
51
|
+
We are using [YARD](http://yardoc.org/) for documenting the source. There is still a lot to do: more references, more examples, better names for parameters, etc. We accept patches for each and every one of these problems -- if you want to send a patch improving documentation, we will be pleased to review it!
|
52
|
+
|
53
|
+
See the [YARD guides](http://www.yardoc.org/guides/index.html) for more information.
|
54
|
+
|
55
|
+
## Conclusion
|
56
|
+
|
57
|
+
This guide was heavily based on the
|
58
|
+
[Contributing to Ruby on Rails guide](http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html).
|
59
|
+
|
60
|
+
[1]: https://groups.google.com/forum/?fromgroups#!forum/sciruby-dev
|
61
|
+
[2]: https://github.com/sciruby/integration/issues
|
data/Gemfile
CHANGED
data/History.txt
CHANGED
data/integration.gemspec
CHANGED
@@ -3,20 +3,27 @@ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
|
3
3
|
require 'integration/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
6
|
+
s.name = 'integration'
|
7
7
|
s.version = Integration::VERSION
|
8
|
-
|
9
|
-
s.
|
10
|
-
s.email = [
|
8
|
+
|
9
|
+
s.authors = ['Claudio Bustos', 'Ben Gimpert']
|
10
|
+
s.email = ['clbustos@gmail.com']
|
11
|
+
s.homepage = 'http://sciruby.com'
|
12
|
+
|
13
|
+
s.summary = 'Numerical integration for Ruby with a simple interface.'
|
14
|
+
s.description = 'Numerical integration for Ruby with a simple interface.'
|
15
|
+
s.license = 'See README.md.'
|
16
|
+
|
11
17
|
s.files = `git ls-files`.split("\n")
|
12
18
|
s.test_files = `git ls-files -- {test,spec,features,benchmark}/*`.split("\n")
|
13
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
|
-
s.require_paths = [
|
15
|
-
|
20
|
+
s.require_paths = ['lib']
|
21
|
+
|
22
|
+
s.required_ruby_version = '>= 1.9.3'
|
16
23
|
|
17
24
|
s.add_runtime_dependency 'text-table', '~> 1.2'
|
18
25
|
|
26
|
+
s.add_development_dependency 'bundler', '>= 1.3.0', '< 2.0'
|
19
27
|
s.add_development_dependency 'rake', '~> 10.4'
|
20
|
-
s.add_development_dependency 'bundler', '~> 1.9'
|
21
28
|
s.add_development_dependency 'rspec', '~> 3.2'
|
22
29
|
end
|
data/lib/integration.rb
CHANGED
@@ -23,554 +23,178 @@
|
|
23
23
|
# be used in advertising or otherwise to promote the sale, use or other dealings
|
24
24
|
# in this Software without prior written authorization from Beng.
|
25
25
|
|
26
|
+
require 'integration/methods'
|
27
|
+
|
26
28
|
# Diverse integration methods
|
27
29
|
# Use Integration.integrate as wrapper to direct access to methods
|
28
30
|
#
|
29
|
-
# Method API
|
30
|
-
#
|
31
|
-
|
32
31
|
class Integration
|
33
|
-
# Minus Infinity
|
34
|
-
MInfinity=:minfinity
|
35
|
-
# Infinity
|
36
|
-
Infinity=:infinity
|
37
|
-
class << self
|
38
|
-
|
39
|
-
# Create a method 'has_<library>' on Module
|
40
|
-
# which require a library and return true or false
|
41
|
-
# according to success of failure
|
42
|
-
def create_has_library(library) #:nodoc:
|
43
|
-
define_singleton_method("has_#{library}?") do
|
44
|
-
cv="@@#{library}"
|
45
|
-
if !class_variable_defined? cv
|
46
|
-
begin
|
47
|
-
require library.to_s
|
48
|
-
class_variable_set(cv, true)
|
49
|
-
rescue LoadError
|
50
|
-
class_variable_set(cv, false)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
class_variable_get(cv)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
# Rectangle method
|
57
|
-
# +n+ implies number of subdivisions
|
58
|
-
# Source:
|
59
|
-
# * Ayres : Outline of calculus
|
60
|
-
def rectangle(t1, t2, n, &f)
|
61
|
-
d=(t2-t1) / n.to_f
|
62
|
-
n.times.inject(0) {|ac,i|
|
63
|
-
ac+f[t1+d*(i+0.5)]
|
64
|
-
}*d
|
65
|
-
end
|
66
|
-
alias_method :midpoint, :rectangle
|
67
|
-
# Trapezoid method
|
68
|
-
# +n+ implies number of subdivisions
|
69
|
-
# Source:
|
70
|
-
# * Ayres : Outline of calculus
|
71
|
-
def trapezoid(t1, t2, n, &f)
|
72
|
-
d=(t2-t1) / n.to_f
|
73
|
-
(d/2.0)*(f[t1]+
|
74
|
-
2*(1..(n-1)).inject(0){|ac,i|
|
75
|
-
ac+f[t1+d*i]
|
76
|
-
}+f[t2])
|
77
|
-
end
|
78
|
-
|
79
|
-
# Simpson's rule
|
80
|
-
# +n+ implies number of subdivisions
|
81
|
-
# Source:
|
82
|
-
# * Ayres : Outline of calculus
|
83
|
-
def simpson(t1, t2, n, &f)
|
84
|
-
n += 1 unless n % 2 == 0
|
85
|
-
d=(t2-t1) / n.to_f
|
86
|
-
out= (d / 3.0)*(f[t1.to_f].to_f+
|
87
|
-
((1..(n-1)).inject(0) {|ac,i|
|
88
|
-
ac+((i%2==0) ? 2 : 4)*f[t1+d*i]
|
89
|
-
})+f[t2.to_f].to_f)
|
90
|
-
out
|
91
|
-
end
|
92
|
-
|
93
|
-
# Simpson's 3/8 Rule
|
94
|
-
# +n+ implies number of subdivisions
|
95
|
-
# Source:
|
96
|
-
# * Burden, Richard L. and Faires, J. Douglas (2000): Numerical Analysis (7th ed.). Brooks/Cole
|
97
|
-
def simpson3by8(t1, t2, n, &f)
|
98
|
-
d = (t2-t1) / n.to_f
|
99
|
-
ac = 0
|
100
|
-
(0..n-1).each do |i|
|
101
|
-
ac+=(d/8.0)*(f[t1+i*d]+3*f[t1+i*d+d/3]+3*f[t1+i*d+2*d/3]+f[t1+(i+1)*d])
|
102
|
-
end
|
103
|
-
ac
|
104
|
-
end
|
105
|
-
|
106
|
-
# Boole's Rule
|
107
|
-
# +n+ implies number of subdivisions
|
108
|
-
# Source:
|
109
|
-
# Weisstein, Eric W. "Boole's Rule." From MathWorld—A Wolfram Web Resource
|
110
|
-
def boole(t1, t2, n, &f)
|
111
|
-
d = (t2-t1) / n.to_f
|
112
|
-
ac = 0
|
113
|
-
(0..n-1).each do |i|
|
114
|
-
ac+=(d/90.0)*(7*f[t1+i*d]+32*f[t1+i*d+d/4]+12*f[t1+i*d+d/2]+32*f[t1+i*d+3*d/4]+7*f[t1+(i+1)*d])
|
115
|
-
end
|
116
|
-
ac
|
117
|
-
end
|
118
|
-
|
119
|
-
# Open Trapezoid method
|
120
|
-
# +n+ implies number of subdivisions
|
121
|
-
# Values computed at mid point and end point instead of starting points
|
122
|
-
def open_trapezoid(t1, t2, n, &f)
|
123
|
-
d = (t2-t1) / n.to_f
|
124
|
-
ac = 0
|
125
|
-
(0..n-1).each do |i|
|
126
|
-
ac+=(d/2.0)*(f[t1+i*d+d/3]+f[t1+i*d+2*d/3])
|
127
|
-
end
|
128
|
-
ac
|
129
|
-
end
|
130
|
-
|
131
|
-
# Milne's Method
|
132
|
-
# +n+ implies number of subdivisions
|
133
|
-
# Source:
|
134
|
-
# Abramowitz, M. and Stegun, I. A. (Eds.).
|
135
|
-
# Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables,
|
136
|
-
# 9th printing. New York: Dover, pp. 896-897, 1972.
|
137
|
-
def milne(t1, t2, n, &f)
|
138
|
-
d = (t2-t1) / n.to_f
|
139
|
-
ac = 0
|
140
|
-
(0..n-1).each do |i|
|
141
|
-
ac+=(d/3.0)*(2*f[t1+i*d+d/4]-f[t1+i*d+d/2]+2*f[t1+i*d+3*d/4])
|
142
|
-
end
|
143
|
-
ac
|
144
|
-
end
|
145
|
-
|
146
|
-
# Adaptive Quadrature
|
147
|
-
# Calls the Simpson's rule recursively on subintervals
|
148
|
-
# in case the error exceeds the desired tolerance
|
149
|
-
# +tolerance+ is the desired tolerance of error
|
150
|
-
def adaptive_quadrature(a, b, tolerance)
|
151
|
-
h = (b.to_f - a) / 2
|
152
|
-
fa = yield(a)
|
153
|
-
fc = yield(a + h)
|
154
|
-
fb = yield(b)
|
155
|
-
s = h * (fa + (4 * fc) + fb) / 3
|
156
|
-
helper = Proc.new { |a, b, fa, fb, fc, h, s, level|
|
157
|
-
if level < 1/tolerance.to_f
|
158
|
-
fd = yield(a + (h / 2))
|
159
|
-
fe = yield(a + (3 * (h / 2)))
|
160
|
-
s1 = h * (fa + (4.0 * fd) + fc) / 6
|
161
|
-
s2 = h * (fc + (4.0 * fe) + fb) / 6
|
162
|
-
if ((s1 + s2) - s).abs <= tolerance
|
163
|
-
s1 + s2
|
164
|
-
else
|
165
|
-
helper.call(a, a + h, fa, fc, fd, h / 2, s1, level + 1) +
|
166
|
-
helper.call(a + h, b, fc, fb, fe, h / 2, s2, level + 1)
|
167
|
-
end
|
168
|
-
else
|
169
|
-
raise "Integral did not converge"
|
170
|
-
end
|
171
|
-
}
|
172
|
-
return helper.call(a, b, fa, fb, fc, h, s, 1)
|
173
|
-
end
|
174
|
-
|
175
|
-
# Gaussian Quadrature
|
176
|
-
# n-point Gaussian quadrature rule gives an exact result for polynomials of degree 2n − 1 or less
|
177
|
-
def gauss(t1, t2, n)
|
178
|
-
case n
|
179
|
-
when 1
|
180
|
-
z = [0.0]
|
181
|
-
w = [2.0]
|
182
|
-
when 2
|
183
|
-
z = [-0.57735026919, 0.57735026919]
|
184
|
-
w = [1.0, 1.0]
|
185
|
-
when 3
|
186
|
-
z = [-0.774596669241, 0.0, 0.774596669241]
|
187
|
-
w = [0.555555555556, 0.888888888889, 0.555555555556]
|
188
|
-
when 4
|
189
|
-
z = [-0.861136311594, -0.339981043585, 0.339981043585, 0.861136311594]
|
190
|
-
w = [0.347854845137, 0.652145154863, 0.652145154863, 0.347854845137]
|
191
|
-
when 5
|
192
|
-
z = [-0.906179845939, -0.538469310106, 0.0, 0.538469310106, 0.906179845939]
|
193
|
-
w = [0.236926885056, 0.478628670499, 0.568888888889, 0.478628670499, 0.236926885056]
|
194
|
-
when 6
|
195
|
-
z = [-0.932469514203, -0.661209386466, -0.238619186083, 0.238619186083, 0.661209386466, 0.932469514203]
|
196
|
-
w = [0.171324492379, 0.360761573048, 0.467913934573, 0.467913934573, 0.360761573048, 0.171324492379]
|
197
|
-
when 7
|
198
|
-
z = [-0.949107912343, -0.741531185599, -0.405845151377, 0.0, 0.405845151377, 0.741531185599, 0.949107912343]
|
199
|
-
w = [0.129484966169, 0.279705391489, 0.381830050505, 0.417959183673, 0.381830050505, 0.279705391489, 0.129484966169]
|
200
|
-
when 8
|
201
|
-
z = [-0.960289856498, -0.796666477414, -0.525532409916, -0.183434642496, 0.183434642496, 0.525532409916, 0.796666477414, 0.960289856498]
|
202
|
-
w = [0.10122853629, 0.222381034453, 0.313706645878, 0.362683783378, 0.362683783378, 0.313706645878, 0.222381034453, 0.10122853629]
|
203
|
-
when 9
|
204
|
-
z = [-0.968160239508, -0.836031107327, -0.613371432701, -0.324253423404, 0.0, 0.324253423404, 0.613371432701, 0.836031107327, 0.968160239508]
|
205
|
-
w = [0.0812743883616, 0.180648160695, 0.260610696403, 0.31234707704, 0.330239355001, 0.31234707704, 0.260610696403, 0.180648160695, 0.0812743883616]
|
206
|
-
when 10
|
207
|
-
z = [-0.973906528517, -0.865063366689, -0.679409568299, -0.433395394129, -0.148874338982, 0.148874338982, 0.433395394129, 0.679409568299, 0.865063366689, 0.973906528517]
|
208
|
-
w = [0.0666713443087, 0.149451349151, 0.219086362516, 0.26926671931, 0.295524224715, 0.295524224715, 0.26926671931, 0.219086362516, 0.149451349151, 0.0666713443087]
|
209
|
-
else
|
210
|
-
raise "Invalid number of spaced abscissas #{n}, should be 1-10"
|
211
|
-
end
|
212
|
-
|
213
|
-
sum = 0
|
214
|
-
(0...n).each do |i|
|
215
|
-
t = ((t1.to_f + t2) / 2.0) + (((t2 - t1) / 2.0) * z[i])
|
216
|
-
sum += w[i] * yield(t)
|
217
|
-
end
|
218
|
-
return ((t2 - t1) / 2.0) * sum
|
219
|
-
end
|
220
|
-
|
221
|
-
# Gauss Kronrod Rule:
|
222
|
-
# Provides a 3n+1 order estimate while re-using the function values of a lower-order(n order) estimate
|
223
|
-
# Source:
|
224
|
-
# "Gauss–Kronrod quadrature formula", Encyclopedia of Mathematics, Springer, ISBN 978-1-55608-010-4
|
225
|
-
def gauss_kronrod(t1,t2,n,points)
|
226
|
-
#g7k15
|
227
|
-
case points
|
228
|
-
when 15
|
229
|
-
|
230
|
-
z = [-0.9914553711208126, -0.9491079123427585, -0.8648644233597691,
|
231
|
-
-0.7415311855993945, -0.5860872354676911, -0.4058451513773972,
|
232
|
-
-0.20778495500789848, 0.0, 0.20778495500789848,
|
233
|
-
0.4058451513773972, 0.5860872354676911, 0.7415311855993945,
|
234
|
-
0.8648644233597691, 0.9491079123427585, 0.9914553711208126]
|
235
|
-
|
236
|
-
w = [0.022935322010529224, 0.06309209262997856, 0.10479001032225019,
|
237
|
-
0.14065325971552592, 0.1690047266392679, 0.19035057806478542,
|
238
|
-
0.20443294007529889, 0.20948214108472782, 0.20443294007529889,
|
239
|
-
0.19035057806478542, 0.1690047266392679, 0.14065325971552592,
|
240
|
-
0.10479001032225019, 0.06309209262997856, 0.022935322010529224]
|
241
|
-
|
242
|
-
when 21
|
243
|
-
#g10k21
|
244
|
-
|
245
|
-
z = [-0.9956571630258081, -0.9739065285171717, -0.9301574913557082,
|
246
|
-
-0.8650633666889845, -0.7808177265864169, -0.6794095682990244,
|
247
|
-
-0.5627571346686047, -0.4333953941292472, -0.2943928627014602,
|
248
|
-
-0.14887433898163122, 0.0, 0.14887433898163122,
|
249
|
-
0.2943928627014602, 0.4333953941292472, 0.5627571346686047,
|
250
|
-
0.6794095682990244, 0.7808177265864169, 0.8650633666889845,
|
251
|
-
0.9301574913557082, 0.9739065285171717, 0.9956571630258081]
|
252
|
-
|
253
|
-
w = [0.011694638867371874, 0.032558162307964725,
|
254
|
-
0.054755896574351995, 0.07503967481091996, 0.0931254545836976,
|
255
|
-
0.10938715880229764, 0.12349197626206584, 0.13470921731147334,
|
256
|
-
0.14277593857706009, 0.14773910490133849, 0.1494455540029169,
|
257
|
-
0.14773910490133849, 0.14277593857706009, 0.13470921731147334,
|
258
|
-
0.12349197626206584, 0.10938715880229764, 0.0931254545836976,
|
259
|
-
0.07503967481091996, 0.054755896574351995, 0.032558162307964725,
|
260
|
-
0.011694638867371874]
|
261
|
-
|
262
|
-
when 31
|
263
|
-
#g15k31
|
264
|
-
|
265
|
-
z = [-0.9980022986933971, -0.9879925180204854, -0.9677390756791391,
|
266
|
-
-0.937273392400706, -0.8972645323440819, -0.8482065834104272,
|
267
|
-
-0.790418501442466, -0.7244177313601701, -0.650996741297417,
|
268
|
-
-0.5709721726085388, -0.4850818636402397, -0.3941513470775634,
|
269
|
-
-0.29918000715316884, -0.20119409399743451, -0.1011420669187175,
|
270
|
-
0.0, 0.1011420669187175, 0.20119409399743451,
|
271
|
-
0.29918000715316884, 0.3941513470775634, 0.4850818636402397,
|
272
|
-
0.5709721726085388, 0.650996741297417, 0.7244177313601701,
|
273
|
-
0.790418501442466, 0.8482065834104272, 0.8972645323440819,
|
274
|
-
0.937273392400706, 0.9677390756791391, 0.9879925180204854,
|
275
|
-
0.9980022986933971]
|
276
32
|
|
277
|
-
|
278
|
-
|
279
|
-
0.06200956780067064, 0.06985412131872826, 0.07684968075772038,
|
280
|
-
0.08308050282313302, 0.08856444305621176, 0.09312659817082532,
|
281
|
-
0.09664272698362368, 0.09917359872179196, 0.10076984552387559,
|
282
|
-
0.10133000701479154, 0.10076984552387559, 0.09917359872179196,
|
283
|
-
0.09664272698362368, 0.09312659817082532, 0.08856444305621176,
|
284
|
-
0.08308050282313302, 0.07684968075772038, 0.06985412131872826,
|
285
|
-
0.06200956780067064, 0.05348152469092809, 0.04458975132476488,
|
286
|
-
0.03534636079137585, 0.02546084732671532, 0.015007947329316122,
|
287
|
-
0.005377479872923349]
|
288
|
-
|
289
|
-
when 41
|
290
|
-
#g20k41
|
291
|
-
|
292
|
-
z = [-0.9988590315882777, -0.9931285991850949, -0.9815078774502503,
|
293
|
-
-0.9639719272779138, -0.9408226338317548, -0.912234428251326,
|
294
|
-
-0.878276811252282, -0.8391169718222188, -0.7950414288375512,
|
295
|
-
-0.7463319064601508, -0.6932376563347514, -0.636053680726515,
|
296
|
-
-0.5751404468197103, -0.5108670019508271, -0.4435931752387251,
|
297
|
-
-0.37370608871541955, -0.301627868114913, -0.22778585114164507,
|
298
|
-
-0.15260546524092267, -0.07652652113349734, 0.0,
|
299
|
-
0.07652652113349734, 0.15260546524092267, 0.22778585114164507,
|
300
|
-
0.301627868114913, 0.37370608871541955, 0.4435931752387251,
|
301
|
-
0.5108670019508271, 0.5751404468197103, 0.636053680726515,
|
302
|
-
0.6932376563347514, 0.7463319064601508, 0.7950414288375512,
|
303
|
-
0.8391169718222188, 0.878276811252282, 0.912234428251326,
|
304
|
-
0.9408226338317548, 0.9639719272779138, 0.9815078774502503,
|
305
|
-
0.9931285991850949, 0.9988590315882777]
|
306
|
-
|
307
|
-
w = [0.0030735837185205317, 0.008600269855642943,
|
308
|
-
0.014626169256971253, 0.020388373461266523, 0.02588213360495116,
|
309
|
-
0.0312873067770328, 0.036600169758200796, 0.041668873327973685,
|
310
|
-
0.04643482186749767, 0.05094457392372869, 0.05519510534828599,
|
311
|
-
0.05911140088063957, 0.06265323755478117, 0.06583459713361842,
|
312
|
-
0.06864867292852161, 0.07105442355344407, 0.07303069033278667,
|
313
|
-
0.07458287540049918, 0.07570449768455667, 0.07637786767208074,
|
314
|
-
0.07660071191799965, 0.07637786767208074, 0.07570449768455667,
|
315
|
-
0.07458287540049918, 0.07303069033278667, 0.07105442355344407,
|
316
|
-
0.06864867292852161, 0.06583459713361842, 0.06265323755478117,
|
317
|
-
0.05911140088063957, 0.05519510534828599, 0.05094457392372869,
|
318
|
-
0.04643482186749767, 0.041668873327973685, 0.036600169758200796,
|
319
|
-
0.0312873067770328, 0.02588213360495116, 0.020388373461266523,
|
320
|
-
0.014626169256971253, 0.008600269855642943,
|
321
|
-
0.0030735837185205317]
|
322
|
-
|
323
|
-
when 61
|
324
|
-
#g30k61
|
325
|
-
|
326
|
-
z = [-0.9994844100504906, -0.9968934840746495, -0.9916309968704046,
|
327
|
-
-0.9836681232797472, -0.9731163225011262, -0.9600218649683075,
|
328
|
-
-0.94437444474856, -0.9262000474292743, -0.9055733076999078,
|
329
|
-
-0.8825605357920527, -0.8572052335460612, -0.8295657623827684,
|
330
|
-
-0.799727835821839, -0.7677774321048262, -0.7337900624532268,
|
331
|
-
-0.6978504947933158, -0.6600610641266269, -0.6205261829892429,
|
332
|
-
-0.5793452358263617, -0.5366241481420199, -0.49248046786177857,
|
333
|
-
-0.44703376953808915, -0.4004012548303944, -0.3527047255308781,
|
334
|
-
-0.30407320227362505, -0.25463692616788985,
|
335
|
-
-0.20452511668230988, -0.15386991360858354,
|
336
|
-
-0.10280693796673702, -0.0514718425553177, 0.0,
|
337
|
-
0.0514718425553177, 0.10280693796673702, 0.15386991360858354,
|
338
|
-
0.20452511668230988, 0.25463692616788985, 0.30407320227362505,
|
339
|
-
0.3527047255308781, 0.4004012548303944, 0.44703376953808915,
|
340
|
-
0.49248046786177857, 0.5366241481420199, 0.5793452358263617,
|
341
|
-
0.6205261829892429, 0.6600610641266269, 0.6978504947933158,
|
342
|
-
0.7337900624532268, 0.7677774321048262, 0.799727835821839,
|
343
|
-
0.8295657623827684, 0.8572052335460612, 0.8825605357920527,
|
344
|
-
0.9055733076999078, 0.9262000474292743, 0.94437444474856,
|
345
|
-
0.9600218649683075, 0.9731163225011262, 0.9836681232797472,
|
346
|
-
0.9916309968704046, 0.9968934840746495, 0.9994844100504906]
|
347
|
-
|
348
|
-
w = [0.0013890136986770077, 0.003890461127099884,
|
349
|
-
0.0066307039159312926, 0.009273279659517764,
|
350
|
-
0.011823015253496341, 0.014369729507045804, 0.01692088918905327,
|
351
|
-
0.019414141193942382, 0.021828035821609193, 0.0241911620780806,
|
352
|
-
0.0265099548823331, 0.02875404876504129, 0.030907257562387762,
|
353
|
-
0.03298144705748372, 0.034979338028060025, 0.03688236465182123,
|
354
|
-
0.038678945624727595, 0.040374538951535956,
|
355
|
-
0.041969810215164244, 0.04345253970135607, 0.04481480013316266,
|
356
|
-
0.04605923827100699, 0.04718554656929915, 0.04818586175708713,
|
357
|
-
0.04905543455502978, 0.04979568342707421, 0.05040592140278235,
|
358
|
-
0.05088179589874961, 0.051221547849258774, 0.05142612853745902,
|
359
|
-
0.05149472942945157, 0.05142612853745902, 0.051221547849258774,
|
360
|
-
0.05088179589874961, 0.05040592140278235, 0.04979568342707421,
|
361
|
-
0.04905543455502978, 0.04818586175708713, 0.04718554656929915,
|
362
|
-
0.04605923827100699, 0.04481480013316266, 0.04345253970135607,
|
363
|
-
0.041969810215164244, 0.040374538951535956,
|
364
|
-
0.038678945624727595, 0.03688236465182123, 0.034979338028060025,
|
365
|
-
0.03298144705748372, 0.030907257562387762, 0.02875404876504129,
|
366
|
-
0.0265099548823331, 0.0241911620780806, 0.021828035821609193,
|
367
|
-
0.019414141193942382, 0.01692088918905327, 0.014369729507045804,
|
368
|
-
0.011823015253496341, 0.009273279659517764,
|
369
|
-
0.0066307039159312926, 0.003890461127099884,
|
370
|
-
0.0013890136986770077]
|
371
|
-
|
372
|
-
else # using 15 point quadrature
|
373
|
-
|
374
|
-
n = 15
|
375
|
-
|
376
|
-
z = [-0.9914553711208126, -0.9491079123427585, -0.8648644233597691,
|
377
|
-
-0.7415311855993945, -0.5860872354676911, -0.4058451513773972,
|
378
|
-
-0.20778495500789848, 0.0, 0.20778495500789848,
|
379
|
-
0.4058451513773972, 0.5860872354676911, 0.7415311855993945,
|
380
|
-
0.8648644233597691, 0.9491079123427585, 0.9914553711208126]
|
381
|
-
|
382
|
-
w = [0.022935322010529224, 0.06309209262997856, 0.10479001032225019,
|
383
|
-
0.14065325971552592, 0.1690047266392679, 0.19035057806478542,
|
384
|
-
0.20443294007529889, 0.20948214108472782, 0.20443294007529889,
|
385
|
-
0.19035057806478542, 0.1690047266392679, 0.14065325971552592,
|
386
|
-
0.10479001032225019, 0.06309209262997856, 0.022935322010529224]
|
387
|
-
|
388
|
-
end
|
33
|
+
# Minus Infinity
|
34
|
+
MInfinity = :minfinity
|
389
35
|
|
390
|
-
|
391
|
-
|
392
|
-
t = ((t1.to_f + t2) / 2.0) + (((t2 - t1) / 2.0) * z[i])
|
393
|
-
sum += w[i] * yield(t)
|
394
|
-
end
|
36
|
+
# Infinity
|
37
|
+
Infinity = :infinity
|
395
38
|
|
396
|
-
|
397
|
-
|
39
|
+
# Pure Ruby methods available.
|
40
|
+
RUBY_METHODS = [:rectangle, :trapezoid, :simpson, :adaptive_quadrature,
|
41
|
+
:gauss, :romberg, :monte_carlo, :gauss_kronrod,
|
42
|
+
:simpson3by8, :boole, :open_trapezoid, :milne]
|
398
43
|
|
399
|
-
|
400
|
-
|
401
|
-
def romberg(a, b, tolerance,max_iter=20)
|
402
|
-
# NOTE one-based arrays are used for convenience
|
403
|
-
h = b.to_f - a
|
404
|
-
m = 1
|
405
|
-
close = 1
|
406
|
-
r = [[(h / 2) * (yield(a) + yield(b))]]
|
407
|
-
j = 0
|
408
|
-
hn=lambda {|n| h/(2**n)}
|
409
|
-
while j <= max_iter && tolerance < close
|
410
|
-
j+=1
|
411
|
-
r.push((j+1).times.map{[]})
|
412
|
-
ul=2**(j-1)
|
413
|
-
r[j][0]=r[j-1][0] / 2.0 + hn[j] * (1..ul).inject(0) {|ac,k| ac+yield(a + (2*k-1)* hn[j])}
|
414
|
-
(1..j).each do |k|
|
415
|
-
r[j][k] = ( (4**k) * r[j][k-1] - r[j-1][k-1]) / ((4**k)-1)
|
416
|
-
end
|
417
|
-
close = (r[j][j] - r[j-1][j-1])
|
418
|
-
end
|
419
|
-
r[j][j]
|
420
|
-
end
|
44
|
+
# Methods available when using the `rb-gsl` gem.
|
45
|
+
GSL_METHODS = [:qng, :qag]
|
421
46
|
|
422
|
-
|
423
|
-
# Uses a non deterministic(probabilistic) approach for calculation of definite integrals
|
424
|
-
# Estimates the integral by randomly choosing points in a set and then calculating the number of points that fall in the desired area
|
425
|
-
def monte_carlo(t1, t2, n)
|
426
|
-
width = (t2 - t1).to_f
|
427
|
-
height = nil
|
428
|
-
vals = []
|
429
|
-
n.times do
|
430
|
-
t = t1 + (rand() * width)
|
431
|
-
ft = yield(t)
|
432
|
-
height = ft if height.nil? || ft > height
|
433
|
-
vals << ft
|
434
|
-
end
|
435
|
-
area_ratio = 0
|
436
|
-
vals.each do |ft|
|
437
|
-
area_ratio += (ft / height.to_f) / n.to_f
|
438
|
-
end
|
439
|
-
return (width * height) * area_ratio
|
440
|
-
end
|
47
|
+
class << self
|
441
48
|
|
442
|
-
|
443
|
-
|
49
|
+
# Check if `value` is plus or minus infinity.
|
50
|
+
#
|
51
|
+
# @param value Value to be tested.
|
52
|
+
def infinite?(value)
|
53
|
+
value == Integration::Infinity || value == Integration::MInfinity
|
444
54
|
end
|
445
55
|
|
446
|
-
#
|
447
|
-
|
448
|
-
|
449
|
-
#
|
450
|
-
|
451
|
-
|
452
|
-
# Get the integral for a function +f+, with bounds +t1+ and
|
453
|
-
# +t2+ given a hash of +options+.
|
454
|
-
# If Ruby/GSL is available, you could use +Integration::Minfinity+
|
455
|
-
# and +Integration::Infinity+ as bounds. Method
|
456
|
-
# Options are
|
56
|
+
# Get the integral for a function +f+, with bounds +t1+ and +t2+ given a
|
57
|
+
# hash of +options+. If Ruby/GSL is available, you can use
|
58
|
+
# +Integration::Minfinity+ and +Integration::Infinity+ as bounds. Method
|
59
|
+
#
|
60
|
+
# Options are:
|
457
61
|
# [:tolerance] Maximum difference between real and calculated integral.
|
458
|
-
# Default: 1e-10
|
459
|
-
# [:initial_step] Initial number of
|
460
|
-
# [:step]
|
62
|
+
# Default: 1e-10.
|
63
|
+
# [:initial_step] Initial number of subdivisions.
|
64
|
+
# [:step] Subdivition increment on each iteration.
|
461
65
|
# [:method] Integration method.
|
462
|
-
#
|
463
|
-
#
|
464
|
-
#
|
465
|
-
# [:
|
466
|
-
# [:
|
467
|
-
# [:
|
468
|
-
# [:
|
469
|
-
# [:
|
470
|
-
#
|
471
|
-
# [:
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
66
|
+
#
|
67
|
+
# Available methods are:
|
68
|
+
#
|
69
|
+
# [:rectangle] for [:initial_step+:step*iteration] quadrilateral subdivisions.
|
70
|
+
# [:trapezoid] for [:initial_step+:step*iteration] trapezoid-al subdivisions.
|
71
|
+
# [:simpson] for [:initial_step+:step*iteration] parabolic subdivisions.
|
72
|
+
# [:adaptive_quadrature] for recursive appoximations until error [tolerance].
|
73
|
+
# [:gauss] [:initial_step+:step*iteration] weighted subdivisons using
|
74
|
+
# translated -1 -> +1 endpoints.
|
75
|
+
# [:romberg] extrapolation of recursion approximation until error < [tolerance].
|
76
|
+
# [:monte_carlo] make [:initial_step+:step*iteration] random samples, and
|
77
|
+
# check for above/below curve.
|
78
|
+
# [:qng] GSL QNG non-adaptive Gauss-Kronrod integration.
|
79
|
+
# [:qag] GSL QAG adaptive integration, with support for infinite bounds.
|
80
|
+
def integrate(t1, t2, options = {}, &f)
|
81
|
+
inf_bounds = (infinite?(t1) || infinite?(t2))
|
82
|
+
|
83
|
+
fail 'No function passed' unless block_given?
|
84
|
+
fail 'Non-numeric bounds' unless ((t1.is_a? Numeric) && (t2.is_a? Numeric)) || inf_bounds
|
85
|
+
|
86
|
+
if inf_bounds
|
87
|
+
lower_bound = t1
|
88
|
+
upper_bound = t2
|
89
|
+
options[:method] = :qag if options[:method].nil?
|
480
90
|
else
|
481
91
|
lower_bound = [t1, t2].min
|
482
92
|
upper_bound = [t1, t2].max
|
483
93
|
end
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
94
|
+
|
95
|
+
def_method = (Integration.has_gsl?) ? :qag : :simpson
|
96
|
+
default_opts = { tolerance: 1e-10, initial_step: 16, step: 16, method: def_method }
|
97
|
+
options = default_opts.merge(options)
|
98
|
+
|
99
|
+
if RUBY_METHODS.include? options[:method]
|
100
|
+
fail "Ruby methods doesn't support infinity bounds" if inf_bounds
|
101
|
+
integrate_ruby(lower_bound, upper_bound, options, &f)
|
102
|
+
elsif GSL_METHODS.include? options[:method]
|
103
|
+
integrate_gsl(lower_bound, upper_bound, options, &f)
|
492
104
|
else
|
493
|
-
|
105
|
+
fail "Unknown integration method \"#{options[:method]}\""
|
494
106
|
end
|
495
107
|
end
|
496
108
|
|
497
|
-
#
|
498
|
-
def integrate_gsl(lower_bound,upper_bound,options
|
499
|
-
|
109
|
+
# Integrate using the GSL bindings.
|
110
|
+
def integrate_gsl(lower_bound, upper_bound, options, &f)
|
500
111
|
f = GSL::Function.alloc(&f)
|
501
|
-
method=options[:method]
|
502
|
-
tolerance=options[:tolerance]
|
503
|
-
|
504
|
-
if(method
|
505
|
-
w = GSL::Integration::Workspace.alloc
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
elsif
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
#puts "superior"
|
514
|
-
val=f.qagiu(lower_bound, [tolerance, 0], w)
|
112
|
+
method = options[:method]
|
113
|
+
tolerance = options[:tolerance]
|
114
|
+
|
115
|
+
if (method == :qag)
|
116
|
+
w = GSL::Integration::Workspace.alloc
|
117
|
+
|
118
|
+
val = if infinite?(lower_bound) && infinite?(upper_bound)
|
119
|
+
f.qagi([tolerance, 0.0], 1000, w)
|
120
|
+
elsif infinite?(lower_bound)
|
121
|
+
f.qagil(upper_bound, [tolerance, 0], w)
|
122
|
+
elsif infinite?(upper_bound)
|
123
|
+
f.qagiu(lower_bound, [tolerance, 0], w)
|
515
124
|
else
|
516
|
-
|
517
|
-
val=f.qag([lower_bound,upper_bound],[tolerance,0.0], GSL::Integration::GAUSS61, w)
|
125
|
+
f.qag([lower_bound, upper_bound], [tolerance, 0.0], GSL::Integration::GAUSS61, w)
|
518
126
|
end
|
519
|
-
|
520
|
-
|
127
|
+
|
128
|
+
elsif (method == :qng)
|
129
|
+
val = f.qng([lower_bound, upper_bound], [tolerance, 0.0])
|
130
|
+
|
521
131
|
else
|
522
|
-
|
132
|
+
fail "Unknown integration method \"#{method}\""
|
523
133
|
end
|
134
|
+
|
524
135
|
val[0]
|
525
136
|
end
|
526
137
|
|
527
|
-
def integrate_ruby(lower_bound,upper_bound,options
|
528
|
-
method=options[:method]
|
529
|
-
tolerance=options[:tolerance]
|
530
|
-
initial_step=options[:initial_step]
|
531
|
-
step=options[:step]
|
138
|
+
def integrate_ruby(lower_bound, upper_bound, options, &f)
|
139
|
+
method = options[:method]
|
140
|
+
tolerance = options[:tolerance]
|
141
|
+
initial_step = options[:initial_step]
|
142
|
+
step = options[:step]
|
532
143
|
points = options[:points]
|
144
|
+
|
533
145
|
begin
|
534
146
|
method_obj = Integration.method(method.to_s.downcase)
|
535
147
|
rescue
|
536
148
|
raise "Unknown integration method \"#{method}\""
|
537
149
|
end
|
538
|
-
current_step=initial_step
|
539
150
|
|
540
|
-
|
541
|
-
|
542
|
-
|
151
|
+
current_step = initial_step
|
152
|
+
|
153
|
+
if [:adaptive_quadrature, :romberg, :gauss, :gauss_kronrod].include? method
|
154
|
+
if (method == :gauss)
|
155
|
+
initial_step = 10 if initial_step > 10
|
543
156
|
tolerance = initial_step
|
544
157
|
method_obj.call(lower_bound, upper_bound, tolerance, &f)
|
545
|
-
elsif (method
|
546
|
-
initial_step=10 if initial_step>10
|
547
|
-
tolerance=initial_step
|
548
|
-
points = points
|
158
|
+
elsif (method == :gauss_kronrod)
|
159
|
+
initial_step = 10 if initial_step > 10
|
160
|
+
tolerance = initial_step
|
161
|
+
points = points unless points.nil?
|
549
162
|
method_obj.call(lower_bound, upper_bound, tolerance, points, &f)
|
550
163
|
else
|
551
164
|
method_obj.call(lower_bound, upper_bound, tolerance, &f)
|
552
165
|
end
|
553
166
|
else
|
554
|
-
|
555
|
-
value
|
556
|
-
|
557
|
-
|
558
|
-
while(
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
current_step+=step
|
564
|
-
previous=value
|
565
|
-
#puts "Llamando al metodo"
|
566
|
-
|
567
|
-
value=method_obj.call(lower_bound, upper_bound, current_step, &f)
|
167
|
+
value = method_obj.call(lower_bound, upper_bound, current_step, &f)
|
168
|
+
previous = value + (tolerance * 2)
|
169
|
+
diffs = []
|
170
|
+
|
171
|
+
while (previous - value).abs > tolerance
|
172
|
+
diffs.push((previous - value).abs)
|
173
|
+
current_step += step
|
174
|
+
previous = value
|
175
|
+
value = method_obj.call(lower_bound, upper_bound, current_step, &f)
|
568
176
|
end
|
569
177
|
|
570
178
|
value
|
571
179
|
end
|
572
180
|
end
|
573
|
-
end
|
574
181
|
|
575
|
-
|
182
|
+
# Check if GSL is available. Require the library if it is present. Return a
|
183
|
+
# boolean indicating its availability.
|
184
|
+
#
|
185
|
+
# @return [Boolean] Whether GSL is available.
|
186
|
+
def has_gsl?
|
187
|
+
gsl_available = '@@gsl'
|
188
|
+
if class_variable_defined? gsl_available
|
189
|
+
class_variable_get(gsl_available)
|
190
|
+
else
|
191
|
+
begin
|
192
|
+
require 'gsl'
|
193
|
+
class_variable_set(gsl_available, true)
|
194
|
+
rescue LoadError
|
195
|
+
class_variable_set(gsl_available, false)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
576
200
|
end
|