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
@@ -0,0 +1,394 @@
|
|
1
|
+
class Integration
|
2
|
+
class << self
|
3
|
+
|
4
|
+
# Rectangle method
|
5
|
+
# +n+ implies number of subdivisions
|
6
|
+
# Source:
|
7
|
+
# * Ayres : Outline of calculus
|
8
|
+
def rectangle(t1, t2, n, &f)
|
9
|
+
d = (t2 - t1) / n.to_f
|
10
|
+
n.times.inject(0) do|ac, i|
|
11
|
+
ac + f[t1 + d * (i + 0.5)]
|
12
|
+
end * d
|
13
|
+
end
|
14
|
+
|
15
|
+
alias_method :midpoint, :rectangle
|
16
|
+
|
17
|
+
# Trapezoid method
|
18
|
+
# +n+ implies number of subdivisions
|
19
|
+
# Source:
|
20
|
+
# * Ayres : Outline of calculus
|
21
|
+
def trapezoid(t1, t2, n, &f)
|
22
|
+
d = (t2 - t1) / n.to_f
|
23
|
+
(d / 2.0) * (f[t1] + 2 * (1..(n - 1)).inject(0) do|ac, i|
|
24
|
+
ac + f[t1 + d * i]
|
25
|
+
end + f[t2])
|
26
|
+
end
|
27
|
+
|
28
|
+
# Simpson's rule
|
29
|
+
# +n+ implies number of subdivisions
|
30
|
+
# Source:
|
31
|
+
# * Ayres : Outline of calculus
|
32
|
+
def simpson(t1, t2, n, &f)
|
33
|
+
n += 1 unless n.even?
|
34
|
+
d = (t2 - t1) / n.to_f
|
35
|
+
out = (d / 3.0) * (f[t1.to_f].to_f + ((1..(n - 1)).inject(0) do|ac, i|
|
36
|
+
ac + ((i.even?) ? 2 : 4) * f[t1 + d * i]
|
37
|
+
end) + f[t2.to_f].to_f)
|
38
|
+
out
|
39
|
+
end
|
40
|
+
|
41
|
+
# Simpson's 3/8 Rule
|
42
|
+
# +n+ implies number of subdivisions
|
43
|
+
# Source:
|
44
|
+
# * Burden, Richard L. and Faires, J. Douglas (2000): Numerical Analysis (7th ed.). Brooks/Cole
|
45
|
+
def simpson3by8(t1, t2, n, &f)
|
46
|
+
d = (t2 - t1) / n.to_f
|
47
|
+
ac = 0
|
48
|
+
(0..n - 1).each do |i|
|
49
|
+
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])
|
50
|
+
end
|
51
|
+
ac
|
52
|
+
end
|
53
|
+
|
54
|
+
# Boole's Rule
|
55
|
+
# +n+ implies number of subdivisions
|
56
|
+
# Source:
|
57
|
+
# Weisstein, Eric W. "Boole's Rule." From MathWorld—A Wolfram Web Resource
|
58
|
+
def boole(t1, t2, n, &f)
|
59
|
+
d = (t2 - t1) / n.to_f
|
60
|
+
ac = 0
|
61
|
+
(0..n - 1).each do |i|
|
62
|
+
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])
|
63
|
+
end
|
64
|
+
ac
|
65
|
+
end
|
66
|
+
|
67
|
+
# Open Trapezoid method
|
68
|
+
# +n+ implies number of subdivisions
|
69
|
+
# Values computed at mid point and end point instead of starting points
|
70
|
+
def open_trapezoid(t1, t2, n, &f)
|
71
|
+
d = (t2 - t1) / n.to_f
|
72
|
+
ac = 0
|
73
|
+
(0..n - 1).each do |i|
|
74
|
+
ac += (d / 2.0) * (f[t1 + i * d + d / 3] + f[t1 + i * d + 2 * d / 3])
|
75
|
+
end
|
76
|
+
ac
|
77
|
+
end
|
78
|
+
|
79
|
+
# Milne's Method
|
80
|
+
# +n+ implies number of subdivisions
|
81
|
+
# Source:
|
82
|
+
# Abramowitz, M. and Stegun, I. A. (Eds.).
|
83
|
+
# Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables,
|
84
|
+
# 9th printing. New York: Dover, pp. 896-897, 1972.
|
85
|
+
def milne(t1, t2, n, &f)
|
86
|
+
d = (t2 - t1) / n.to_f
|
87
|
+
ac = 0
|
88
|
+
(0..n - 1).each do |i|
|
89
|
+
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])
|
90
|
+
end
|
91
|
+
ac
|
92
|
+
end
|
93
|
+
|
94
|
+
# Adaptive Quadrature
|
95
|
+
# Calls the Simpson's rule recursively on subintervals
|
96
|
+
# in case the error exceeds the desired tolerance
|
97
|
+
# +tolerance+ is the desired tolerance of error
|
98
|
+
def adaptive_quadrature(a, b, tolerance)
|
99
|
+
h = (b.to_f - a) / 2
|
100
|
+
fa = yield(a)
|
101
|
+
fc = yield(a + h)
|
102
|
+
fb = yield(b)
|
103
|
+
s = h * (fa + (4 * fc) + fb) / 3
|
104
|
+
|
105
|
+
helper = proc do |_a, _b, _fa, _fb, _fc, _h, _s, level|
|
106
|
+
if level < 1 / tolerance.to_f
|
107
|
+
fd = yield(_a + (_h / 2))
|
108
|
+
fe = yield(_a + (3 * (_h / 2)))
|
109
|
+
s1 = _h * (_fa + (4.0 * fd) + _fc) / 6
|
110
|
+
s2 = _h * (_fc + (4.0 * fe) + _fb) / 6
|
111
|
+
if ((s1 + s2) - _s).abs <= tolerance
|
112
|
+
s1 + s2
|
113
|
+
else
|
114
|
+
helper.call(_a, _a + _h, _fa, _fc, fd, _h / 2, s1, level + 1) +
|
115
|
+
helper.call(_a + _h, _b, _fc, _fb, fe, _h / 2, s2, level + 1)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
fail 'Integral did not converge'
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
helper.call(a, b, fa, fb, fc, h, s, 1)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Gaussian Quadrature
|
126
|
+
# n-point Gaussian quadrature rule gives an exact result for polynomials of degree 2n − 1 or less
|
127
|
+
def gauss(t1, t2, n)
|
128
|
+
case n
|
129
|
+
when 1
|
130
|
+
z = [0.0]
|
131
|
+
w = [2.0]
|
132
|
+
when 2
|
133
|
+
z = [-0.57735026919, 0.57735026919]
|
134
|
+
w = [1.0, 1.0]
|
135
|
+
when 3
|
136
|
+
z = [-0.774596669241, 0.0, 0.774596669241]
|
137
|
+
w = [0.555555555556, 0.888888888889, 0.555555555556]
|
138
|
+
when 4
|
139
|
+
z = [-0.861136311594, -0.339981043585, 0.339981043585, 0.861136311594]
|
140
|
+
w = [0.347854845137, 0.652145154863, 0.652145154863, 0.347854845137]
|
141
|
+
when 5
|
142
|
+
z = [-0.906179845939, -0.538469310106, 0.0, 0.538469310106, 0.906179845939]
|
143
|
+
w = [0.236926885056, 0.478628670499, 0.568888888889, 0.478628670499, 0.236926885056]
|
144
|
+
when 6
|
145
|
+
z = [-0.932469514203, -0.661209386466, -0.238619186083, 0.238619186083, 0.661209386466, 0.932469514203]
|
146
|
+
w = [0.171324492379, 0.360761573048, 0.467913934573, 0.467913934573, 0.360761573048, 0.171324492379]
|
147
|
+
when 7
|
148
|
+
z = [-0.949107912343, -0.741531185599, -0.405845151377, 0.0, 0.405845151377, 0.741531185599, 0.949107912343]
|
149
|
+
w = [0.129484966169, 0.279705391489, 0.381830050505, 0.417959183673, 0.381830050505, 0.279705391489, 0.129484966169]
|
150
|
+
when 8
|
151
|
+
z = [-0.960289856498, -0.796666477414, -0.525532409916, -0.183434642496, 0.183434642496, 0.525532409916, 0.796666477414, 0.960289856498]
|
152
|
+
w = [0.10122853629, 0.222381034453, 0.313706645878, 0.362683783378, 0.362683783378, 0.313706645878, 0.222381034453, 0.10122853629]
|
153
|
+
when 9
|
154
|
+
z = [-0.968160239508, -0.836031107327, -0.613371432701, -0.324253423404, 0.0, 0.324253423404, 0.613371432701, 0.836031107327, 0.968160239508]
|
155
|
+
w = [0.0812743883616, 0.180648160695, 0.260610696403, 0.31234707704, 0.330239355001, 0.31234707704, 0.260610696403, 0.180648160695, 0.0812743883616]
|
156
|
+
when 10
|
157
|
+
z = [-0.973906528517, -0.865063366689, -0.679409568299, -0.433395394129, -0.148874338982, 0.148874338982, 0.433395394129, 0.679409568299, 0.865063366689, 0.973906528517]
|
158
|
+
w = [0.0666713443087, 0.149451349151, 0.219086362516, 0.26926671931, 0.295524224715, 0.295524224715, 0.26926671931, 0.219086362516, 0.149451349151, 0.0666713443087]
|
159
|
+
else
|
160
|
+
fail "Invalid number of spaced abscissas #{n}, should be 1-10"
|
161
|
+
end
|
162
|
+
|
163
|
+
sum = 0
|
164
|
+
(0...n).each do |i|
|
165
|
+
t = ((t1.to_f + t2) / 2.0) + (((t2 - t1) / 2.0) * z[i])
|
166
|
+
sum += w[i] * yield(t)
|
167
|
+
end
|
168
|
+
((t2 - t1) / 2.0) * sum
|
169
|
+
end
|
170
|
+
|
171
|
+
# Gauss Kronrod Rule:
|
172
|
+
# Provides a 3n+1 order estimate while re-using the function values of a lower-order(n order) estimate
|
173
|
+
# Source:
|
174
|
+
# "Gauss–Kronrod quadrature formula", Encyclopedia of Mathematics, Springer, ISBN 978-1-55608-010-4
|
175
|
+
def gauss_kronrod(t1, t2, n, points)
|
176
|
+
# g7k15
|
177
|
+
case points
|
178
|
+
when 15
|
179
|
+
|
180
|
+
z = [-0.9914553711208126, -0.9491079123427585, -0.8648644233597691,
|
181
|
+
-0.7415311855993945, -0.5860872354676911, -0.4058451513773972,
|
182
|
+
-0.20778495500789848, 0.0, 0.20778495500789848,
|
183
|
+
0.4058451513773972, 0.5860872354676911, 0.7415311855993945,
|
184
|
+
0.8648644233597691, 0.9491079123427585, 0.9914553711208126]
|
185
|
+
|
186
|
+
w = [0.022935322010529224, 0.06309209262997856, 0.10479001032225019,
|
187
|
+
0.14065325971552592, 0.1690047266392679, 0.19035057806478542,
|
188
|
+
0.20443294007529889, 0.20948214108472782, 0.20443294007529889,
|
189
|
+
0.19035057806478542, 0.1690047266392679, 0.14065325971552592,
|
190
|
+
0.10479001032225019, 0.06309209262997856, 0.022935322010529224]
|
191
|
+
|
192
|
+
when 21
|
193
|
+
# g10k21
|
194
|
+
|
195
|
+
z = [-0.9956571630258081, -0.9739065285171717, -0.9301574913557082,
|
196
|
+
-0.8650633666889845, -0.7808177265864169, -0.6794095682990244,
|
197
|
+
-0.5627571346686047, -0.4333953941292472, -0.2943928627014602,
|
198
|
+
-0.14887433898163122, 0.0, 0.14887433898163122,
|
199
|
+
0.2943928627014602, 0.4333953941292472, 0.5627571346686047,
|
200
|
+
0.6794095682990244, 0.7808177265864169, 0.8650633666889845,
|
201
|
+
0.9301574913557082, 0.9739065285171717, 0.9956571630258081]
|
202
|
+
|
203
|
+
w = [0.011694638867371874, 0.032558162307964725,
|
204
|
+
0.054755896574351995, 0.07503967481091996, 0.0931254545836976,
|
205
|
+
0.10938715880229764, 0.12349197626206584, 0.13470921731147334,
|
206
|
+
0.14277593857706009, 0.14773910490133849, 0.1494455540029169,
|
207
|
+
0.14773910490133849, 0.14277593857706009, 0.13470921731147334,
|
208
|
+
0.12349197626206584, 0.10938715880229764, 0.0931254545836976,
|
209
|
+
0.07503967481091996, 0.054755896574351995, 0.032558162307964725,
|
210
|
+
0.011694638867371874]
|
211
|
+
|
212
|
+
when 31
|
213
|
+
# g15k31
|
214
|
+
|
215
|
+
z = [-0.9980022986933971, -0.9879925180204854, -0.9677390756791391,
|
216
|
+
-0.937273392400706, -0.8972645323440819, -0.8482065834104272,
|
217
|
+
-0.790418501442466, -0.7244177313601701, -0.650996741297417,
|
218
|
+
-0.5709721726085388, -0.4850818636402397, -0.3941513470775634,
|
219
|
+
-0.29918000715316884, -0.20119409399743451, -0.1011420669187175,
|
220
|
+
0.0, 0.1011420669187175, 0.20119409399743451,
|
221
|
+
0.29918000715316884, 0.3941513470775634, 0.4850818636402397,
|
222
|
+
0.5709721726085388, 0.650996741297417, 0.7244177313601701,
|
223
|
+
0.790418501442466, 0.8482065834104272, 0.8972645323440819,
|
224
|
+
0.937273392400706, 0.9677390756791391, 0.9879925180204854,
|
225
|
+
0.9980022986933971]
|
226
|
+
|
227
|
+
w = [0.005377479872923349, 0.015007947329316122, 0.02546084732671532,
|
228
|
+
0.03534636079137585, 0.04458975132476488, 0.05348152469092809,
|
229
|
+
0.06200956780067064, 0.06985412131872826, 0.07684968075772038,
|
230
|
+
0.08308050282313302, 0.08856444305621176, 0.09312659817082532,
|
231
|
+
0.09664272698362368, 0.09917359872179196, 0.10076984552387559,
|
232
|
+
0.10133000701479154, 0.10076984552387559, 0.09917359872179196,
|
233
|
+
0.09664272698362368, 0.09312659817082532, 0.08856444305621176,
|
234
|
+
0.08308050282313302, 0.07684968075772038, 0.06985412131872826,
|
235
|
+
0.06200956780067064, 0.05348152469092809, 0.04458975132476488,
|
236
|
+
0.03534636079137585, 0.02546084732671532, 0.015007947329316122,
|
237
|
+
0.005377479872923349]
|
238
|
+
|
239
|
+
when 41
|
240
|
+
# g20k41
|
241
|
+
|
242
|
+
z = [-0.9988590315882777, -0.9931285991850949, -0.9815078774502503,
|
243
|
+
-0.9639719272779138, -0.9408226338317548, -0.912234428251326,
|
244
|
+
-0.878276811252282, -0.8391169718222188, -0.7950414288375512,
|
245
|
+
-0.7463319064601508, -0.6932376563347514, -0.636053680726515,
|
246
|
+
-0.5751404468197103, -0.5108670019508271, -0.4435931752387251,
|
247
|
+
-0.37370608871541955, -0.301627868114913, -0.22778585114164507,
|
248
|
+
-0.15260546524092267, -0.07652652113349734, 0.0,
|
249
|
+
0.07652652113349734, 0.15260546524092267, 0.22778585114164507,
|
250
|
+
0.301627868114913, 0.37370608871541955, 0.4435931752387251,
|
251
|
+
0.5108670019508271, 0.5751404468197103, 0.636053680726515,
|
252
|
+
0.6932376563347514, 0.7463319064601508, 0.7950414288375512,
|
253
|
+
0.8391169718222188, 0.878276811252282, 0.912234428251326,
|
254
|
+
0.9408226338317548, 0.9639719272779138, 0.9815078774502503,
|
255
|
+
0.9931285991850949, 0.9988590315882777]
|
256
|
+
|
257
|
+
w = [0.0030735837185205317, 0.008600269855642943,
|
258
|
+
0.014626169256971253, 0.020388373461266523, 0.02588213360495116,
|
259
|
+
0.0312873067770328, 0.036600169758200796, 0.041668873327973685,
|
260
|
+
0.04643482186749767, 0.05094457392372869, 0.05519510534828599,
|
261
|
+
0.05911140088063957, 0.06265323755478117, 0.06583459713361842,
|
262
|
+
0.06864867292852161, 0.07105442355344407, 0.07303069033278667,
|
263
|
+
0.07458287540049918, 0.07570449768455667, 0.07637786767208074,
|
264
|
+
0.07660071191799965, 0.07637786767208074, 0.07570449768455667,
|
265
|
+
0.07458287540049918, 0.07303069033278667, 0.07105442355344407,
|
266
|
+
0.06864867292852161, 0.06583459713361842, 0.06265323755478117,
|
267
|
+
0.05911140088063957, 0.05519510534828599, 0.05094457392372869,
|
268
|
+
0.04643482186749767, 0.041668873327973685, 0.036600169758200796,
|
269
|
+
0.0312873067770328, 0.02588213360495116, 0.020388373461266523,
|
270
|
+
0.014626169256971253, 0.008600269855642943,
|
271
|
+
0.0030735837185205317]
|
272
|
+
|
273
|
+
when 61
|
274
|
+
# g30k61
|
275
|
+
|
276
|
+
z = [-0.9994844100504906, -0.9968934840746495, -0.9916309968704046,
|
277
|
+
-0.9836681232797472, -0.9731163225011262, -0.9600218649683075,
|
278
|
+
-0.94437444474856, -0.9262000474292743, -0.9055733076999078,
|
279
|
+
-0.8825605357920527, -0.8572052335460612, -0.8295657623827684,
|
280
|
+
-0.799727835821839, -0.7677774321048262, -0.7337900624532268,
|
281
|
+
-0.6978504947933158, -0.6600610641266269, -0.6205261829892429,
|
282
|
+
-0.5793452358263617, -0.5366241481420199, -0.49248046786177857,
|
283
|
+
-0.44703376953808915, -0.4004012548303944, -0.3527047255308781,
|
284
|
+
-0.30407320227362505, -0.25463692616788985,
|
285
|
+
-0.20452511668230988, -0.15386991360858354,
|
286
|
+
-0.10280693796673702, -0.0514718425553177, 0.0,
|
287
|
+
0.0514718425553177, 0.10280693796673702, 0.15386991360858354,
|
288
|
+
0.20452511668230988, 0.25463692616788985, 0.30407320227362505,
|
289
|
+
0.3527047255308781, 0.4004012548303944, 0.44703376953808915,
|
290
|
+
0.49248046786177857, 0.5366241481420199, 0.5793452358263617,
|
291
|
+
0.6205261829892429, 0.6600610641266269, 0.6978504947933158,
|
292
|
+
0.7337900624532268, 0.7677774321048262, 0.799727835821839,
|
293
|
+
0.8295657623827684, 0.8572052335460612, 0.8825605357920527,
|
294
|
+
0.9055733076999078, 0.9262000474292743, 0.94437444474856,
|
295
|
+
0.9600218649683075, 0.9731163225011262, 0.9836681232797472,
|
296
|
+
0.9916309968704046, 0.9968934840746495, 0.9994844100504906]
|
297
|
+
|
298
|
+
w = [0.0013890136986770077, 0.003890461127099884,
|
299
|
+
0.0066307039159312926, 0.009273279659517764,
|
300
|
+
0.011823015253496341, 0.014369729507045804, 0.01692088918905327,
|
301
|
+
0.019414141193942382, 0.021828035821609193, 0.0241911620780806,
|
302
|
+
0.0265099548823331, 0.02875404876504129, 0.030907257562387762,
|
303
|
+
0.03298144705748372, 0.034979338028060025, 0.03688236465182123,
|
304
|
+
0.038678945624727595, 0.040374538951535956,
|
305
|
+
0.041969810215164244, 0.04345253970135607, 0.04481480013316266,
|
306
|
+
0.04605923827100699, 0.04718554656929915, 0.04818586175708713,
|
307
|
+
0.04905543455502978, 0.04979568342707421, 0.05040592140278235,
|
308
|
+
0.05088179589874961, 0.051221547849258774, 0.05142612853745902,
|
309
|
+
0.05149472942945157, 0.05142612853745902, 0.051221547849258774,
|
310
|
+
0.05088179589874961, 0.05040592140278235, 0.04979568342707421,
|
311
|
+
0.04905543455502978, 0.04818586175708713, 0.04718554656929915,
|
312
|
+
0.04605923827100699, 0.04481480013316266, 0.04345253970135607,
|
313
|
+
0.041969810215164244, 0.040374538951535956,
|
314
|
+
0.038678945624727595, 0.03688236465182123, 0.034979338028060025,
|
315
|
+
0.03298144705748372, 0.030907257562387762, 0.02875404876504129,
|
316
|
+
0.0265099548823331, 0.0241911620780806, 0.021828035821609193,
|
317
|
+
0.019414141193942382, 0.01692088918905327, 0.014369729507045804,
|
318
|
+
0.011823015253496341, 0.009273279659517764,
|
319
|
+
0.0066307039159312926, 0.003890461127099884,
|
320
|
+
0.0013890136986770077]
|
321
|
+
|
322
|
+
else # using 15 point quadrature
|
323
|
+
|
324
|
+
n = 15
|
325
|
+
|
326
|
+
z = [-0.9914553711208126, -0.9491079123427585, -0.8648644233597691,
|
327
|
+
-0.7415311855993945, -0.5860872354676911, -0.4058451513773972,
|
328
|
+
-0.20778495500789848, 0.0, 0.20778495500789848,
|
329
|
+
0.4058451513773972, 0.5860872354676911, 0.7415311855993945,
|
330
|
+
0.8648644233597691, 0.9491079123427585, 0.9914553711208126]
|
331
|
+
|
332
|
+
w = [0.022935322010529224, 0.06309209262997856, 0.10479001032225019,
|
333
|
+
0.14065325971552592, 0.1690047266392679, 0.19035057806478542,
|
334
|
+
0.20443294007529889, 0.20948214108472782, 0.20443294007529889,
|
335
|
+
0.19035057806478542, 0.1690047266392679, 0.14065325971552592,
|
336
|
+
0.10479001032225019, 0.06309209262997856, 0.022935322010529224]
|
337
|
+
|
338
|
+
end
|
339
|
+
|
340
|
+
sum = 0
|
341
|
+
(0...n).each do |i|
|
342
|
+
t = ((t1.to_f + t2) / 2.0) + (((t2 - t1) / 2.0) * z[i])
|
343
|
+
sum += w[i] * yield(t)
|
344
|
+
end
|
345
|
+
|
346
|
+
((t2 - t1) / 2.0) * sum
|
347
|
+
end
|
348
|
+
|
349
|
+
# Romberg Method:
|
350
|
+
# It is obtained by applying extrapolation techniques repeatedly on the trapezoidal rule
|
351
|
+
def romberg(a, b, tolerance, max_iter = 20)
|
352
|
+
# NOTE one-based arrays are used for convenience
|
353
|
+
h = b.to_f - a
|
354
|
+
close = 1
|
355
|
+
r = [[(h / 2) * (yield(a) + yield(b))]]
|
356
|
+
j = 0
|
357
|
+
hn = ->(n) { h / (2**n) }
|
358
|
+
while j <= max_iter && tolerance < close
|
359
|
+
j += 1
|
360
|
+
r.push((j + 1).times.map { [] })
|
361
|
+
ul = 2**(j - 1)
|
362
|
+
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]) }
|
363
|
+
(1..j).each do |k|
|
364
|
+
r[j][k] = ((4**k) * r[j][k - 1] - r[j - 1][k - 1]) / ((4**k) - 1)
|
365
|
+
end
|
366
|
+
close = (r[j][j] - r[j - 1][j - 1])
|
367
|
+
end
|
368
|
+
r[j][j]
|
369
|
+
end
|
370
|
+
|
371
|
+
# Monte Carlo
|
372
|
+
#
|
373
|
+
# Uses a non-deterministic approach for calculation of definite integrals.
|
374
|
+
# Estimates the integral by randomly choosing points in a set and then
|
375
|
+
# calculating the number of points that fall in the desired area.
|
376
|
+
def monte_carlo(t1, t2, n)
|
377
|
+
width = (t2 - t1).to_f
|
378
|
+
height = nil
|
379
|
+
vals = []
|
380
|
+
n.times do
|
381
|
+
t = t1 + (rand * width)
|
382
|
+
ft = yield(t)
|
383
|
+
height = ft if height.nil? || ft > height
|
384
|
+
vals << ft
|
385
|
+
end
|
386
|
+
area_ratio = 0
|
387
|
+
vals.each do |ft|
|
388
|
+
area_ratio += (ft / height.to_f) / n.to_f
|
389
|
+
end
|
390
|
+
(width * height) * area_ratio
|
391
|
+
end
|
392
|
+
|
393
|
+
end
|
394
|
+
end
|
data/lib/integration/version.rb
CHANGED
data/spec/integration_spec.rb
CHANGED
@@ -1,77 +1,66 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../spec', __FILE__)
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
2
5
|
describe Integration do
|
3
|
-
a=lambda {|x| x**2}
|
4
|
-
b=lambda {|x| Math.log(x)/x**2}
|
5
|
-
b2=lambda {|x| -(Math.log(x)+1)/x}
|
6
|
+
a = lambda { |x| x**2 }
|
7
|
+
b = lambda { |x| Math.log(x) / x**2 }
|
8
|
+
b2 = lambda { |x| -(Math.log(x) + 1) / x }
|
9
|
+
|
6
10
|
# Integration over [1,2]=x^3/3=7/3
|
7
|
-
methods=[:rectangle
|
11
|
+
methods = [:rectangle, :trapezoid, :simpson, :adaptive_quadrature, :romberg,
|
12
|
+
:gauss, :gauss_kronrod, :simpson3by8, :boole, :open_trapezoid,
|
13
|
+
:milne]
|
14
|
+
|
8
15
|
methods.each do |m|
|
9
16
|
it "should integrate int_{1}^2{2} x^2 correctly with ruby method #{m}" do
|
10
|
-
Integration.integrate(1,2,{:
|
17
|
+
Integration.integrate(1, 2, { method: m, tolerance: 1e-8 }, &a).should be_within(1e-6).of(7.0 / 3)
|
11
18
|
end
|
19
|
+
|
12
20
|
it "should integrate int_{1}^2{2} log(x)/x^2 correctly with ruby method #{m}" do
|
13
|
-
Integration.integrate(1,2,{:
|
14
|
-
b2[2]-b2[1]
|
15
|
-
|
21
|
+
Integration.integrate(1, 2, { method: m, tolerance: 1e-8 }, &b).should be_within(1e-6).of(
|
22
|
+
b2[2] - b2[1]
|
23
|
+
)
|
16
24
|
end
|
17
|
-
|
18
25
|
end
|
19
26
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
f
|
25
|
-
Integration.trapezoid(0,b,2,&f).should be_within(1e-14).of((a*b**2) / 2.0)
|
26
|
-
end
|
27
|
-
it "should return a correct value for a complex integration with ruby methods" do
|
28
|
-
normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
|
29
|
-
Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:simpson},&normal_pdf).should be_within(1e-11).of(0.341344746068)
|
30
|
-
Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:adaptive_quadrature},&normal_pdf).should be_within(1e-11).of(0.341344746068)
|
31
|
-
end
|
32
|
-
it "should return a correct value for a complex integration with gsl methods" do
|
33
|
-
if Integration.has_gsl?
|
34
|
-
normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
|
35
|
-
Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:qng},&normal_pdf).should be_within(1e-11).of(0.341344746068)
|
36
|
-
Integration.integrate(0,1,{:tolerance=>1e-12,:method=>:qag},&normal_pdf).should be_within(1e-11).of(0.341344746068)
|
37
|
-
else
|
38
|
-
skip("GSL not available")
|
39
|
-
end
|
27
|
+
it 'should return correct for trapezoid' do
|
28
|
+
a = rand
|
29
|
+
b = rand * 10
|
30
|
+
f = lambda { |x| x * a }
|
31
|
+
Integration.trapezoid(0, b, 2, &f).should be_within(1e-14).of((a * b**2) / 2.0)
|
40
32
|
end
|
41
33
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
34
|
+
it 'should return a correct value for a complex integration with ruby methods' do
|
35
|
+
normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
|
36
|
+
Integration.integrate(0, 1, { tolerance: 1e-12, method: :simpson }, &normal_pdf).should be_within(1e-11).of(0.341344746068)
|
37
|
+
Integration.integrate(0, 1, { tolerance: 1e-12, method: :adaptive_quadrature }, &normal_pdf).should be_within(1e-11).of(0.341344746068)
|
38
|
+
end
|
46
39
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
40
|
+
it 'should return a correct value for a complex integration with gsl methods' do
|
41
|
+
normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
|
42
|
+
Integration.integrate(0, 1, { tolerance: 1e-12, method: :qng }, &normal_pdf).should be_within(1e-11).of(0.341344746068)
|
43
|
+
Integration.integrate(0, 1, { tolerance: 1e-12, method: :qag }, &normal_pdf).should be_within(1e-11).of(0.341344746068)
|
51
44
|
end
|
52
|
-
it "should return correct integration for infinity lower bound" do
|
53
|
-
if Integration.has_gsl?
|
54
|
-
normal_pdf=lambda {|x| (1/Math.sqrt(2*Math::PI))*Math.exp(-(x**2/2))}
|
55
45
|
|
56
|
-
|
46
|
+
it 'should return correct integration for infinity bounds' do
|
47
|
+
normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
|
57
48
|
|
58
|
-
|
59
|
-
skip("GSL not available")
|
60
|
-
end
|
49
|
+
Integration.integrate(Integration::MInfinity, Integration::Infinity, { tolerance: 1e-10 }, &normal_pdf).should be_within(1e-09).of(1)
|
61
50
|
end
|
62
|
-
it "should return correct integration for infinity upper bound" do
|
63
|
-
if Integration.has_gsl?
|
64
51
|
|
65
|
-
|
66
|
-
|
52
|
+
it 'should return correct integration for infinity lower bound' do
|
53
|
+
normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
|
54
|
+
Integration.integrate(Integration::MInfinity, 0, { tolerance: 1e-10 }, &normal_pdf).should be_within(1e-09).of(0.5)
|
55
|
+
end
|
67
56
|
|
68
|
-
|
69
|
-
|
70
|
-
|
57
|
+
it 'should return correct integration for infinity upper bound' do
|
58
|
+
normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
|
59
|
+
Integration.integrate(0, Integration::Infinity, { tolerance: 1e-10 }, &normal_pdf).should be_within(1e-09).of(0.5)
|
71
60
|
end
|
72
|
-
|
73
|
-
|
74
|
-
lambda {
|
61
|
+
|
62
|
+
it 'should raise an error if a ruby methods is called with infinite bounds' do
|
63
|
+
normal_pdf = lambda { |x| (1 / Math.sqrt(2 * Math::PI)) * Math.exp(-(x**2 / 2)) }
|
64
|
+
lambda { Integration.integrate(0, Integration::Infinity, { method: :simpson }, &normal_pdf).should be_within(1e-09).of(0.5) }.should raise_exception
|
75
65
|
end
|
76
66
|
end
|
77
|
-
|