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.
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
+