spliner 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ Gemfile.lock
data/.travis.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  rvm:
2
- - 1.9.1
2
+ - 1.9.2
3
3
  - 1.9.3
4
4
  - jruby
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+ gemspec
3
+
4
+
data/README.markdown CHANGED
@@ -1,27 +1,41 @@
1
+ [![Build Status](https://secure.travis-ci.org/tallakt/spliner.png?branch=master)](http://travis-ci.org/tallakt/spliner)
2
+
1
3
  Spliner
2
4
  =======
3
5
 
4
6
  Spliner is a Ruby library to perform cubic spline interpolation
5
7
  based on provided key points (X1, Y1), (X2, Y2), ... , (Xn,Yn)
6
8
 
9
+ It also supports extrapolation outside the provided range of X
10
+ values.
11
+
7
12
  Installation
8
13
  ------------
9
14
 
10
15
  Spliner requires Ruby 1.9 or later. Install with rubygems:
11
16
 
12
- gem install spliner
17
+ gem install spliner
13
18
 
14
19
  Quick Start
15
20
  -----------
16
21
 
17
22
  require 'spliner'
18
23
 
19
- # Initialize a spline interpolation with x range 0.0..2.0
20
- my_spline = Spliner::Spliner.new({0.0 => 0.0, 1.0 => 1.0, 2.0 => 0.5})
24
+ # Initialize a spline interpolation with x range 0.0..2.0
25
+ my_spline = Spliner::Spliner.new({0.0 => 0.0, 1.0 => 1.0, 2.0 => 0.5})
26
+
27
+ # Perform interpolation on 31 values ranging from 0..2.0
28
+ x_values = (0..30).map {|x| x / 30.0 * 2.0 }
29
+ y_values = x_values.map {|x| my_spline[x] }
30
+
21
31
 
22
- # Perform interpolation on 31 values ranging from 0..2.0
23
- x_values = (0..30).map {|x| x / 30.0 * 2.0 }
24
- y_values = x_values.map {|x| my_spline[x] }
32
+ # perform extrapolation outside key points using linear Y = aX + b
33
+ ex_spline = Spliner::Spliner.new({0.0 => 0.0, 1.0 => 1.0, 2.0 => 0.5}, :extrapolate => '10%')
34
+ xx = ex_spline[2.1] # returns 0.4124999999999999
35
+
36
+ # perform extrapolation outside key points using linear Y = aX + b
37
+ ex_spline = Spliner::Spliner.new({0.0 => 0.0, 1.0 => 1.0, 2.0 => 0.5}, :extrapolate => '10%', :emethod => :hold)
38
+ xx = ex_spline[2.1] # returns 0.5
25
39
 
26
40
  Spliner is based on the interpolation described on this page
27
41
  http://en.wikipedia.org/wiki/Spline_interpolation
@@ -59,3 +73,5 @@ License
59
73
  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
60
74
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
61
75
 
76
+
77
+
data/lib/spliner.rb CHANGED
@@ -4,7 +4,7 @@
4
4
  require 'matrix'
5
5
 
6
6
  module Spliner
7
- VERSION = '1.0.0'
7
+ VERSION = '1.0.1'
8
8
 
9
9
  # Spliner::Spliner provides cubic spline interpolation based on provided
10
10
  # key points on a X-Y curve.
@@ -20,12 +20,27 @@ module Spliner
20
20
  # http://en.wikipedia.org/wiki/Spline_interpolation
21
21
  #
22
22
  class Spliner
23
+ attr_reader :range
24
+
23
25
  # Creates a new Spliner::Spliner object to interpolate between
24
26
  # the supplied key points. The key points are provided in a hash where
25
27
  # the key is the X value, and the value is the Y value. The X values
26
28
  # mush be increasing and not duplicate. You must provide at least
27
29
  # two values.
28
- def initialize(key_points)
30
+ #
31
+ # options may take the following keys:
32
+ #
33
+ # :extrapolate
34
+ # Specify an area outside the given X values provided that should return
35
+ # a valid number. The value may be either a range (eg. -10..110) or a
36
+ # percentage value written as a string (eg '10%'). Default is no
37
+ # extrapolation.
38
+ #
39
+ # :emethod
40
+ # Specify a method of extrapolation, one of :linear (continue curve as
41
+ # a straigt line, default), or :hold (use Y values at the curve endpoints)
42
+ #
43
+ def initialize(key_points, options = {})
29
44
 
30
45
  @points = key_points
31
46
  @x = @points.keys
@@ -58,18 +73,38 @@ module Spliner
58
73
  b = vector_helper(tmp)
59
74
 
60
75
  @k = a.inv * b
76
+
77
+ options[:extrapolate].tap do |ex|
78
+ case ex
79
+ when /^\d+(\.\d+)?\s?%$/
80
+ percentage = ex[/\d+(\.\d+)?/].to_f
81
+ span = @x.last - @x.first
82
+ extra = span * percentage * 0.01
83
+ @range = (@x.first - extra)..(@x.last + extra)
84
+ when Range
85
+ @range = ex
86
+ when nil
87
+ @range = @x.first..@x.last
88
+ else
89
+ raise 'Unable to use extrapolation parameter'
90
+ end
91
+ end
92
+
93
+ @extrapolation_method = options[:emethod] || :linear
61
94
  end
62
95
 
63
96
  # returns an interpolated value
64
- def get(x)
65
- i = @x_pairs.find_index {|pair| pair.member? x }
97
+ def get(v)
98
+ i = @x_pairs.find_index {|pair| pair.member? v }
66
99
  if i
67
100
  dx = @x[i + 1] - @x[i]
68
101
  dy = @y[i + 1] - @y[i]
69
- t = (x - @x[i]) / dx
102
+ t = (v - @x[i]) / dx
70
103
  a = @k[i] * dx - dy
71
104
  b = -(@k[i + 1] * dx - dy)
72
105
  (1 - t) * @y[i] + t * @y[i + 1] + t * (1 - t) * (a * (1 - t) + b * t)
106
+ elsif range.member? v
107
+ extrapolate(v)
73
108
  else
74
109
  nil
75
110
  end
@@ -95,5 +130,25 @@ module Spliner
95
130
  end
96
131
  private :check_points_increasing
97
132
 
133
+ # :nodoc:
134
+ def extrapolate(v)
135
+ case @extrapolation_method
136
+ when :hold
137
+ if v < @x.first
138
+ @y.first
139
+ else
140
+ @y.last
141
+ end
142
+ else
143
+ x, y, k = if v < @x.first
144
+ [@x.first, @y.first, @k.first]
145
+ else
146
+ [@x.last, @y.last, @k[-1]]
147
+ end
148
+ y + k * (v - x)
149
+ end
150
+ end
151
+ private :extrapolate
152
+
98
153
  end
99
154
  end
data/spec/spliner_spec.rb CHANGED
@@ -2,6 +2,8 @@ require 'spliner'
2
2
 
3
3
  describe Spliner::Spliner do
4
4
  DATASET = {0.0 => 0.0, 1.0 => 1.0, 2.0 => 0.5}
5
+ KEYS_0_100 = {0.0 => 0.0, 100.0 => 100.0}
6
+
5
7
 
6
8
  it 'should not accept x values that are not increasing' do
7
9
  expect(lambda { Spliner::Spliner.new({0 => 0, 0 => 10})}).to raise_exception
@@ -42,4 +44,31 @@ describe Spliner::Spliner do
42
44
  expect(s[-1]).to be_nil
43
45
  expect(s[0]).to be_within(0.0001).of(0.0)
44
46
  end
47
+
48
+ it 'performs :linear extrapolation outside the data range when such is given' do
49
+ s = Spliner::Spliner.new KEYS_0_100, :extrapolate => -200..200
50
+ expect(s.get -110).not_to be_nil
51
+ expect(s.get -150).to be_within(0.0001).of(-150)
52
+ expect(s.get 150).to be_within(0.0001).of(150)
53
+ end
54
+
55
+ it 'performs :hold extrapolation' do
56
+ s = Spliner::Spliner.new KEYS_0_100, :extrapolate => -200..200, :emethod => :hold
57
+ expect(s.get -150).to be_within(0.0001).of(0)
58
+ expect(s.get 150).to be_within(0.0001).of(100)
59
+ end
60
+
61
+ it 'supports data ranges given as a string like "10%"' do
62
+ s1 = Spliner::Spliner.new KEYS_0_100, :extrapolate => '10%'
63
+ expect(s1.range.first).to be_within(0.0001).of(-10.0)
64
+ expect(s1.range.last).to be_within(0.0001).of(110.0)
65
+
66
+ s2 = Spliner::Spliner.new KEYS_0_100, :extrapolate => '10.0%'
67
+ expect(s2.range.first).to be_within(0.0001).of(-10.0)
68
+ expect(s2.range.last).to be_within(0.0001).of(110.0)
69
+
70
+ s3 = Spliner::Spliner.new KEYS_0_100, :extrapolate => '10 %'
71
+ expect(s3.range.first).to be_within(0.0001).of(-10.0)
72
+ expect(s3.range.last).to be_within(0.0001).of(110.0)
73
+ end
45
74
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spliner
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -51,7 +51,9 @@ executables: []
51
51
  extensions: []
52
52
  extra_rdoc_files: []
53
53
  files:
54
+ - .gitignore
54
55
  - .travis.yml
56
+ - Gemfile
55
57
  - README.markdown
56
58
  - Rakefile
57
59
  - lib/spliner.rb