interpolator 0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/LICENSE +22 -0
  2. data/interpolator.rb +320 -0
  3. 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
+