integration 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b284dcf8ea2203fe8f91d2d8f46a5a2e866c9aa9
4
- data.tar.gz: 0973511e4961d3ff5f3cb1378396c20594456e51
3
+ metadata.gz: 4dbd1debd129047a700d50d3934dd668da72b23d
4
+ data.tar.gz: 572db4475376afd86960f615c795312106ffab5b
5
5
  SHA512:
6
- metadata.gz: df5ef6303e64fc54085aa861cd82e158d37efb196e6465423d0a293f862c9091bedf8baa631df226e4dd39942e6c2017a925909e1e7200f3e1bd891a32daa794
7
- data.tar.gz: 533823b375f08fe5811affb0586252f2c5f3e4ea7deb09cbc7572530c05dc4ac6c9ddc2c6cf6c9218b169890eaadb0b0a8d78f15b737088f9b2c808fa47f3e24
6
+ metadata.gz: fc7f3547bee2355ff9f846f6a9b7e91d5d44058ac4eabcddad19b1e25ab019708e6fc1e03b4169b798f871f7aa79c5b3b9ff27842d852f5514616f54cc3d08be
7
+ data.tar.gz: 007a90888618d8b75c6aec71340644db283ead8b3b5d5ba70d6fc7736f04d57f5a5349507245d81759c85fd910e87444e86f0fe69a2b9b46096adbd56b592313
data/.gitignore CHANGED
@@ -2,3 +2,7 @@
2
2
  Gemfile.lock
3
3
  coverage/*
4
4
  pkg/*
5
+
6
+ doc/
7
+ .yardoc/
8
+
@@ -0,0 +1,4 @@
1
+ --title "Integration"
2
+ --markup markdown
3
+ lib/**/*.rb
4
+ README.md History.txt
@@ -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
@@ -1,3 +1,5 @@
1
1
  source "https://www.rubygems.org"
2
2
 
3
+ gem 'rb-gsl', '~> 1.16'
4
+
3
5
  gemspec
@@ -1,3 +1,8 @@
1
+ === 0.1.4 / 2015-05-23
2
+ * GSL will be used if available. The tests will only pass if rb-gsl is installed.
3
+ * Specs depending on GSL will fail without `rb-gsl` installed.
4
+ * Added CONTRIBUTING.md file.
5
+
1
6
  === 0.1.3 / 2015-05-22
2
7
  * Remove rb-gsl dependency.
3
8
 
@@ -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 = "integration"
6
+ s.name = 'integration'
7
7
  s.version = Integration::VERSION
8
- s.authors = ["Claudio Bustos","Ben Gimpert"]
9
- s.description = "Numerical integration for Ruby, with a simple interface"
10
- s.email = ["clbustos@gmail.com", "No 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 = ["lib"]
15
- s.summary = "A suite for integration in Ruby"
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
@@ -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
- w = [0.005377479872923349, 0.015007947329316122, 0.02546084732671532,
278
- 0.03534636079137585, 0.04458975132476488, 0.05348152469092809,
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
- sum = 0
391
- (0...n).each do |i|
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
- ((t2 - t1) / 2.0) * sum
397
- end
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
- # Romberg Method:
400
- # It is obtained by applying extrapolation techniques repeatedly on the trapezoidal rule
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
- # Monte Carlo:
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
- def is_infinite?(v)
443
- v == Infinity || v == MInfinity
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
- # Methods available on pure ruby
447
- RUBY_METHOD=[:rectangle,:trapezoid,:simpson, :adaptive_quadrature , :gauss, :romberg, :monte_carlo, :gauss_kronrod, :simpson3by8, :boole, :open_trapezoid, :milne]
448
-
449
- # Methods available with Ruby/GSL library
450
- GSL_METHOD=[:qng, :qag]
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 subdivitions
460
- # [:step] Subdivitions increment on each iteration
62
+ # Default: 1e-10.
63
+ # [:initial_step] Initial number of subdivisions.
64
+ # [:step] Subdivition increment on each iteration.
461
65
  # [:method] Integration method.
462
- # Methods are
463
- # [:rectangle] for [:initial_step+:step*iteration] quadrilateral subdivisions
464
- # [:trapezoid] for [:initial_step+:step*iteration] trapezoid-al subdivisions
465
- # [:simpson] for [:initial_step+:step*iteration] parabolic subdivisions
466
- # [:adaptive_quadrature] for recursive appoximations until error [tolerance]
467
- # [:gauss] [:initial_step+:step*iteration] weighted subdivisons using translated -1 -> +1 endpoints
468
- # [:romberg] extrapolation of recursion approximation until error < [tolerance]
469
- # [:monte_carlo] make [:initial_step+:step*iteration] random samples, and check for above/below curve
470
- # [:qng] GSL QNG non-adaptive Gauss-Kronrod integration
471
- # [:qag] GSL QAG adaptive integration, with support for infinite bounds
472
- def integrate(t1,t2,options=Hash.new, &f)
473
- inf_bounds=(is_infinite?(t1) or is_infinite?(t2))
474
- raise "No function passed" unless block_given?
475
- raise "Non-numeric bounds" unless ((t1.is_a? Numeric) and (t2.is_a? Numeric)) or inf_bounds
476
- if(inf_bounds)
477
- lower_bound=t1
478
- upper_bound=t2
479
- options[:method]=:qag if options[:method].nil?
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
- def_method=(has_gsl?) ? :qag : :simpson
485
- default_opts={:tolerance=>1e-10, :initial_step=>16, :step=>16, :method=>def_method}
486
- options=default_opts.merge(options)
487
- if RUBY_METHOD.include? options[:method]
488
- raise "Ruby methods doesn't support infinity bounds" if inf_bounds
489
- integrate_ruby(lower_bound,upper_bound,options,&f)
490
- elsif GSL_METHOD.include? options[:method]
491
- integrate_gsl(lower_bound,upper_bound,options,&f)
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
- raise "Unknown integration method \"#{options[:method]}\""
105
+ fail "Unknown integration method \"#{options[:method]}\""
494
106
  end
495
107
  end
496
108
 
497
- # TODO: Document method
498
- def integrate_gsl(lower_bound,upper_bound,options,&f)
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==:qag)
505
- w = GSL::Integration::Workspace.alloc()
506
- if(is_infinite?(lower_bound) and is_infinite?(upper_bound))
507
- #puts "ambos"
508
- val=f.qagi([tolerance,0.0], 1000, w)
509
- elsif is_infinite?(lower_bound)
510
- #puts "inferior #{upper_bound}"
511
- val=f.qagil(upper_bound, [tolerance, 0], w)
512
- elsif is_infinite?(upper_bound)
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
- elsif(method==:qng)
520
- val=f.qng([lower_bound, upper_bound], [tolerance, 0.0])
127
+
128
+ elsif (method == :qng)
129
+ val = f.qng([lower_bound, upper_bound], [tolerance, 0.0])
130
+
521
131
  else
522
- raise "Unknown integration method \"#{method}\""
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,&f)
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
- if(method==:adaptive_quadrature or method==:romberg or method==:gauss or method== :gauss_kronrod)
541
- if(method==:gauss )
542
- initial_step=10 if initial_step>10
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==:gauss_kronrod)
546
- initial_step=10 if initial_step>10
547
- tolerance=initial_step
548
- points = points if points != nil
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
- #puts "iniciando"
555
- value=method_obj.call(lower_bound, upper_bound, current_step, &f)
556
- previous=value+(tolerance*2)
557
- diffs=[]
558
- while((previous-value).abs > tolerance) do
559
- #puts("Valor:#{value}, paso:#{current_step}")
560
- #puts(current_step)
561
- diffs.push((previous-value).abs)
562
- #diffs.push value
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
- create_has_library :gsl
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