interpolator 0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +22 -0
- data/interpolator.rb +320 -0
- metadata +56 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2009 Eric Todd Meyers
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/interpolator.rb
ADDED
@@ -0,0 +1,320 @@
|
|
1
|
+
module Interpolator
|
2
|
+
|
3
|
+
class Table
|
4
|
+
|
5
|
+
attr_reader :extrapolate,:style
|
6
|
+
attr_writer :extrapolate,:style
|
7
|
+
|
8
|
+
LINEAR = 1
|
9
|
+
LAGRANGE2 = 2
|
10
|
+
LAGRANGE3 = 3
|
11
|
+
|
12
|
+
def initialize (*args)
|
13
|
+
|
14
|
+
if (args.size==2) then
|
15
|
+
raise "duel argument table constructor must be 2 Arrays" unless args[0].kind_of? Array
|
16
|
+
raise "duel argument table constructor must be 2 Arrays" unless args[1].kind_of? Array
|
17
|
+
@inds = args[0] # better be numbers
|
18
|
+
@deps = args[1] # can either be numbers or sub tables
|
19
|
+
elsif (args.size == 1) then # hash version
|
20
|
+
raise "single argument table constructor must be a Hash" unless args[0].kind_of? Hash
|
21
|
+
# Ruby 1.8 doesnt maintain hash order so lets help it
|
22
|
+
f = args[0].sort.transpose
|
23
|
+
@inds = f[0]
|
24
|
+
@deps = f[1]
|
25
|
+
else
|
26
|
+
raise(args.size.to_s + " argument Table constructor not valid");
|
27
|
+
end
|
28
|
+
|
29
|
+
raise "number of independents must equal the number of dependents" unless @inds.size == @deps.size
|
30
|
+
ilast = nil
|
31
|
+
@inds.each do |i|
|
32
|
+
raise "independents must be monotonically increasing" unless (ilast == nil || i > ilast)
|
33
|
+
ilast = i
|
34
|
+
end
|
35
|
+
@extrapolate = true
|
36
|
+
@style = LINEAR
|
37
|
+
end
|
38
|
+
|
39
|
+
# replace later with a high speed bisection
|
40
|
+
|
41
|
+
def bracket (x)
|
42
|
+
ileft=0
|
43
|
+
for i in (0..@inds.size-2) do
|
44
|
+
ileft=i
|
45
|
+
if ( (x >= @inds[i]) && (x < @inds[i+1]) ) then
|
46
|
+
break
|
47
|
+
end
|
48
|
+
end
|
49
|
+
ileft
|
50
|
+
end
|
51
|
+
|
52
|
+
def read(*args)
|
53
|
+
|
54
|
+
raise "table requires at least 2 points for linear interpolation" if (@style == LINEAR && @inds.size<2)
|
55
|
+
raise "table requires at least 3 points for lagrange2 interpolation" if (@style == LAGRANGE2 && @inds.size<3)
|
56
|
+
raise "table requires at least 4 points for lagrange3 interpolation" if (@style == LAGRANGE3 && @inds.size<4)
|
57
|
+
raise "insufficient number of arguments to read table" unless args.size>=1
|
58
|
+
|
59
|
+
xval = args[0]
|
60
|
+
|
61
|
+
if (@extrapolate == false) && (xval < @inds[0]) then
|
62
|
+
if (args.size==1) then
|
63
|
+
ans = @deps[0]
|
64
|
+
else
|
65
|
+
subargs = args[1..-1]
|
66
|
+
tab = @deps[0]
|
67
|
+
ans = tab.read(*subargs)
|
68
|
+
end
|
69
|
+
|
70
|
+
elsif (@extrapolate == false) && (xval > @inds[-1])
|
71
|
+
if (args.size==1) then
|
72
|
+
ans = @deps[-1]
|
73
|
+
else
|
74
|
+
subargs = args[1..-1]
|
75
|
+
tab = @deps[-1]
|
76
|
+
ans = tab.read(*subargs)
|
77
|
+
end
|
78
|
+
|
79
|
+
else
|
80
|
+
|
81
|
+
ileft = bracket(xval)
|
82
|
+
|
83
|
+
case @style
|
84
|
+
when LINEAR
|
85
|
+
x1 = @inds[ileft]
|
86
|
+
x2 = @inds[ileft+1]
|
87
|
+
if (args.size==1) then
|
88
|
+
# return the answer
|
89
|
+
y1 = @deps[ileft]
|
90
|
+
y2 = @deps[ileft+1]
|
91
|
+
ans = linear(xval,x1,x2,y1,y2)
|
92
|
+
else
|
93
|
+
# interpolate the sub tables
|
94
|
+
tab1 = @deps[ileft]
|
95
|
+
tab2 = @deps[ileft+1]
|
96
|
+
subargs = args[1..-1]
|
97
|
+
y1 = tab1.read(*subargs)
|
98
|
+
y2 = tab2.read(*subargs)
|
99
|
+
ans = linear(xval,x1,x2,y1,y2)
|
100
|
+
end
|
101
|
+
|
102
|
+
when LAGRANGE2
|
103
|
+
indx = ileft
|
104
|
+
if ileft == @inds.size-2
|
105
|
+
indx = ileft - 1
|
106
|
+
end
|
107
|
+
x1 = @inds[indx]
|
108
|
+
x2 = @inds[indx+1]
|
109
|
+
x3 = @inds[indx+2]
|
110
|
+
if (args.size==1)
|
111
|
+
# return the answer
|
112
|
+
y1 = @deps[indx]
|
113
|
+
y2 = @deps[indx+1]
|
114
|
+
y3 = @deps[indx+2]
|
115
|
+
ans = lagrange2(xval,x1,x2,x3,y1,y2,y3)
|
116
|
+
else
|
117
|
+
# interpolate the sub tables
|
118
|
+
tab1 = @deps[indx]
|
119
|
+
tab2 = @deps[indx+1]
|
120
|
+
tab3 = @deps[indx+2]
|
121
|
+
subargs = args[1..-1]
|
122
|
+
y1 = tab1.read(*subargs)
|
123
|
+
y2 = tab2.read(*subargs)
|
124
|
+
y3 = tab3.read(*subargs)
|
125
|
+
ans = lagrange2(xval,x1,x2,x3,y1,y2,y3)
|
126
|
+
end
|
127
|
+
|
128
|
+
when LAGRANGE3
|
129
|
+
indx = ileft
|
130
|
+
if (ileft > @inds.size-3)
|
131
|
+
indx = @inds.size - 3;
|
132
|
+
elsif (ileft == 0)
|
133
|
+
indx = ileft + 1
|
134
|
+
end
|
135
|
+
x1 = @inds[indx-1]
|
136
|
+
x2 = @inds[indx]
|
137
|
+
x3 = @inds[indx+1]
|
138
|
+
x4 = @inds[indx+2]
|
139
|
+
if (args.size==1) then
|
140
|
+
# return the answer
|
141
|
+
y1 = @deps[indx-1]
|
142
|
+
y2 = @deps[indx]
|
143
|
+
y3 = @deps[indx+1]
|
144
|
+
y4 = @deps[indx+2]
|
145
|
+
ans = lagrange3(xval,x1,x2,x3,x4,y1,y2,y3,y4)
|
146
|
+
else
|
147
|
+
# interpolate the sub tables
|
148
|
+
tab1 = @deps[indx-1]
|
149
|
+
tab2 = @deps[indx]
|
150
|
+
tab3 = @deps[indx+1]
|
151
|
+
tab4 = @deps[indx+2]
|
152
|
+
subargs = args[1..-1]
|
153
|
+
y1 = tab1.read(*subargs)
|
154
|
+
y2 = tab2.read(*subargs)
|
155
|
+
y3 = tab3.read(*subargs)
|
156
|
+
y4 = tab4.read(*subargs)
|
157
|
+
ans = lagrange3(xval,x1,x2,x3,x4,y1,y2,y3,y4)
|
158
|
+
end
|
159
|
+
else
|
160
|
+
raise("invalid interpolation type")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
ans
|
164
|
+
end
|
165
|
+
|
166
|
+
def interpolate(*args)
|
167
|
+
read(*args)
|
168
|
+
end
|
169
|
+
|
170
|
+
def linear (x,x1,x2,y1,y2)
|
171
|
+
r = (y2-y1) / (x2-x1) * (x-x1) + y1
|
172
|
+
end
|
173
|
+
def lagrange2(x,x1,x2,x3,y1,y2,y3)
|
174
|
+
c12 = x1 - x2
|
175
|
+
c13 = x1 - x3
|
176
|
+
c23 = x2 - x3
|
177
|
+
q1 = y1/(c12*c13)
|
178
|
+
q2 = y2/(c12*c23)
|
179
|
+
q3 = y3/(c13*c23)
|
180
|
+
xx1 = x - x1
|
181
|
+
xx2 = x - x2
|
182
|
+
xx3 = x - x3
|
183
|
+
r = xx3*(q1*xx2 - q2*xx1) + q3*xx1*xx2
|
184
|
+
end
|
185
|
+
def lagrange3(x,x1,x2,x3,x4,y1,y2,y3,y4)
|
186
|
+
c12 = x1 - x2
|
187
|
+
c13 = x1 - x3
|
188
|
+
c14 = x1 - x4
|
189
|
+
c23 = x2 - x3
|
190
|
+
c24 = x2 - x4
|
191
|
+
c34 = x3 - x4
|
192
|
+
q1 = y1/(c12 * c13 * c14)
|
193
|
+
q2 = y2/(c12 * c23 * c24)
|
194
|
+
q3 = y3/(c13 * c23 * c34)
|
195
|
+
q4 = y4/(c14 * c24 * c34)
|
196
|
+
xx1 = x - x1
|
197
|
+
xx2 = x - x2
|
198
|
+
xx3 = x - x3
|
199
|
+
xx4 = x - x4
|
200
|
+
r = xx4*(xx3*(q1*xx2 - q2*xx1) + q3*xx1*xx2) - q4*xx1*xx2*xx3
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
if __FILE__ == $0 then
|
206
|
+
|
207
|
+
require 'test/unit'
|
208
|
+
|
209
|
+
class TC_LookupTest < Test::Unit::TestCase
|
210
|
+
def setup
|
211
|
+
@t1 = Table.new [1.0,2.0],[3.0,4.0]
|
212
|
+
@t2 = Table.new([1.0,2.0],[Table.new([1.0,2.0],[3.0,4.0]),Table.new([2.0,3.0,5.0],[6.0,-1.0,7.0])])
|
213
|
+
@t3 = Table.new [1.0,2.0],[3.0,4.0]
|
214
|
+
@t4 = Table.new(
|
215
|
+
1=>Table.new(
|
216
|
+
1=>Table.new([1.0,2.0,3.0],[4.0,5.0,6.0]),
|
217
|
+
4=>Table.new([11.0,12.0,13.0],[14.0,15.0,16.0]),
|
218
|
+
5=>Table.new([11.0,12.0,13.0],[-14.0,-15.0,-16.0])),
|
219
|
+
2=>Table.new(
|
220
|
+
2=>Table.new([1.1,2.0,3.0],[4.0,5.0,6.0]),
|
221
|
+
5=>Table.new([11.0,12.5,13.0],[14.0,15.0,16.0]),
|
222
|
+
6.2=>Table.new([1.0,12.0],[-14.0,-16.0])),
|
223
|
+
8=>Table.new(
|
224
|
+
1=>Table.new([1.0,2.0,3.0],[4.0,5.0,6.0]),
|
225
|
+
5=>Table.new([11.0,12.0,13.0],[-14.0,-15.0,-16.0]))
|
226
|
+
)
|
227
|
+
@t5 = Table.new [1.0,2.0,3.0],[1.0,4.0,9.0]
|
228
|
+
@t6 = Table.new [1.0,2.0,3.0,4.0],[1.0,8.0,27.0,64.0]
|
229
|
+
end
|
230
|
+
|
231
|
+
# def teardown
|
232
|
+
# end
|
233
|
+
|
234
|
+
def test_uni
|
235
|
+
assert_equal(@t1.read(1.0) , 3.0)
|
236
|
+
assert_equal(@t1.read(2.0) , 4.0)
|
237
|
+
assert_equal(@t1.read(1.5) , 3.5)
|
238
|
+
end
|
239
|
+
def test_bi
|
240
|
+
assert_equal(@t2.read(1.0,1.0) , 3.0)
|
241
|
+
assert_equal(@t2.read(2.0,3.0) , -1.0)
|
242
|
+
assert_equal(@t2.read(1.5,2.0) , 5.0)
|
243
|
+
end
|
244
|
+
def test_tri
|
245
|
+
assert_equal(@t4.read(1.5,5,13),0.0)
|
246
|
+
end
|
247
|
+
def test_create
|
248
|
+
assert_nothing_raised{
|
249
|
+
Table.new(1.0=>3.0,2.0=>4.0)
|
250
|
+
}
|
251
|
+
assert_nothing_raised( RuntimeError ){
|
252
|
+
Table.new 1=>Table.new([1.0,2.0,3.0],[4.0,5.0,6.0]),
|
253
|
+
2=>Table.new([2.0,4.0,7.0],[14.0,15.0,16.0])
|
254
|
+
}
|
255
|
+
assert_nothing_raised( RuntimeError ){
|
256
|
+
Table.new 1=>Table.new(
|
257
|
+
[1.0,2.0,3.0],
|
258
|
+
[4.0,5.0,6.0]),
|
259
|
+
2=>Table.new(
|
260
|
+
[2.0,4.0,7.0],
|
261
|
+
[14.0,15.0,16.0])
|
262
|
+
}
|
263
|
+
assert_nothing_raised( RuntimeError ){
|
264
|
+
Table.new 1=>Table.new(
|
265
|
+
1.0=>4.0,
|
266
|
+
2.0=>5.0,
|
267
|
+
3.0=>6.0),
|
268
|
+
2=>Table.new(
|
269
|
+
[2.0,4.0,7.0,12.0],
|
270
|
+
[14.0,15.0,16.0,-4.0])
|
271
|
+
}
|
272
|
+
assert_raise( RuntimeError ) {Table.new(1,2,3)}
|
273
|
+
end
|
274
|
+
def test_size
|
275
|
+
@t3.style=Table::LAGRANGE2
|
276
|
+
assert_raise( RuntimeError ) {@t3.read(1.0)}
|
277
|
+
@t3.style=Table::LAGRANGE3
|
278
|
+
assert_raise( RuntimeError ) {@t3.read(1.0)}
|
279
|
+
@t3.style=Table::LINEAR
|
280
|
+
assert_nothing_raised( RuntimeError ) {@t3.read(1)}
|
281
|
+
end
|
282
|
+
def test_notmono
|
283
|
+
assert_raise( RuntimeError ) {Table.new [1.0,2.0,1.5],[1.0,2.0,3.0]}
|
284
|
+
assert_raise( RuntimeError ) {Table.new [1.0,-2.0,1.5],[1.0,2.0,3.0]}
|
285
|
+
end
|
286
|
+
def test_extrap
|
287
|
+
@t1.extrapolate = false
|
288
|
+
assert_equal(@t1.read(0.0) , 3.0)
|
289
|
+
assert_equal(@t1.read(3.0) , 4.0)
|
290
|
+
@t1.extrapolate = true
|
291
|
+
assert_equal(@t1.read(0.0) , 2.0)
|
292
|
+
assert_equal(@t1.read(3.0) , 5.0)
|
293
|
+
end
|
294
|
+
def test_style
|
295
|
+
@t5.style=Table::LAGRANGE2
|
296
|
+
assert_equal(@t5.read(2.0),4.0)
|
297
|
+
assert_equal(@t5.read(2.5),2.5*2.5)
|
298
|
+
@t6.style=Table::LAGRANGE3
|
299
|
+
assert_equal(@t6.read(2.0),8.0)
|
300
|
+
assert_equal(@t6.read(3.5),3.5*3.5*3.5)
|
301
|
+
@t5.style=Table::LINEAR
|
302
|
+
assert_equal(@t5.read(1.5),2.5)
|
303
|
+
@t6.style=Table::LINEAR
|
304
|
+
assert_equal(@t6.read(1.5),4.5)
|
305
|
+
assert_raise( RuntimeError ) {
|
306
|
+
t = Table.new [1.0,-2.0,1.5],[1.0,2.0,3.0]
|
307
|
+
t.style=10
|
308
|
+
t.read(1)
|
309
|
+
}
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
end
|
315
|
+
|
316
|
+
|
317
|
+
end
|
318
|
+
|
319
|
+
|
320
|
+
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: interpolator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.11"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eric T Meyers
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-08-02 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: n-dimensional table interpolation
|
17
|
+
email: etm@ericmeyers.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- interpolator.rb
|
26
|
+
- LICENSE
|
27
|
+
has_rdoc: true
|
28
|
+
homepage: http://interpolator.rubyforge.org/
|
29
|
+
licenses: []
|
30
|
+
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
|
34
|
+
require_paths:
|
35
|
+
- .
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: "0"
|
41
|
+
version:
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
requirements: []
|
49
|
+
|
50
|
+
rubyforge_project: interpolator
|
51
|
+
rubygems_version: 1.3.5
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: Module Interpolation proves a table class that supports n-dimensional numerical table construction, interpolation and extrapolation. Includes linear, 2nd order and 3rd order la grange techniques.
|
55
|
+
test_files: []
|
56
|
+
|