spliner 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - 1.9.1
3
+ - 1.9.3
4
+ - jruby
data/README.markdown ADDED
@@ -0,0 +1,61 @@
1
+ Spliner
2
+ =======
3
+
4
+ Spliner is a Ruby library to perform cubic spline interpolation
5
+ based on provided key points (X1, Y1), (X2, Y2), ... , (Xn,Yn)
6
+
7
+ Installation
8
+ ------------
9
+
10
+ Spliner requires Ruby 1.9 or later. Install with rubygems:
11
+
12
+ gem install spliner
13
+
14
+ Quick Start
15
+ -----------
16
+
17
+ require 'spliner'
18
+
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})
21
+
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] }
25
+
26
+ Spliner is based on the interpolation described on this page
27
+ http://en.wikipedia.org/wiki/Spline_interpolation
28
+
29
+
30
+ Contributing to Spliner
31
+ --------------------------
32
+
33
+ Feel free to fork the project on GitHub and send fork requests. Please
34
+ try to have each feature separated in commits.
35
+
36
+
37
+
38
+ License
39
+ -------
40
+
41
+ (The MIT License)
42
+
43
+ Copyright (C) 2012 Tallak Tveide
44
+
45
+ Permission is hereby granted, free of charge, to any person obtaining a copy
46
+ of this software and associated documentation files (the "Software"), to
47
+ deal in the Software without restriction, including without limitation the
48
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
49
+ sell copies of the Software, and to permit persons to whom the Software is
50
+ furnished to do so, subject to the following conditions:
51
+
52
+ The above copyright notice and this permission notice shall be included in
53
+ all copies or substantial portions of the Software.
54
+
55
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
58
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
59
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
60
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
61
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task :default => :spec
6
+
data/lib/spliner.rb ADDED
@@ -0,0 +1,99 @@
1
+ #
2
+ # Spliner::Spliner
3
+ #
4
+ require 'matrix'
5
+
6
+ module Spliner
7
+ VERSION = '1.0.0'
8
+
9
+ # Spliner::Spliner provides cubic spline interpolation based on provided
10
+ # key points on a X-Y curve.
11
+ #
12
+ # == Example
13
+ # require 'spliner'
14
+ # # Initialize a spline interpolation with x range 0.0..2.0
15
+ # my_spline = Spliner::Spliner.new({0.0 => 0.0, 1.0 => 1.0, 2.0 => 0.5})
16
+ # # Perform interpolation on 31 values ranging from 0..2.0
17
+ # x_values = (0..30).map {|x| x / 30.0 * 2.0 }
18
+ # y_values = x_values.map {|x| my_spline[x] }
19
+ #
20
+ # http://en.wikipedia.org/wiki/Spline_interpolation
21
+ #
22
+ class Spliner
23
+ # Creates a new Spliner::Spliner object to interpolate between
24
+ # the supplied key points. The key points are provided in a hash where
25
+ # the key is the X value, and the value is the Y value. The X values
26
+ # mush be increasing and not duplicate. You must provide at least
27
+ # two values.
28
+ def initialize(key_points)
29
+
30
+ @points = key_points
31
+ @x = @points.keys
32
+ @y = @points.values
33
+
34
+ check_points_increasing
35
+ raise 'Interpolation needs at least two points' unless @points.size >= 2
36
+
37
+ @x_pairs = @points.keys.each_cons(2).map {|pair| pair.first..pair.last }
38
+
39
+ inv_diff = @x.each_cons(2).map {|x1, x2| 1 / (x2 - x1) }
40
+ a_diag = 2.0 * Matrix::diagonal(*vector_helper(inv_diff))
41
+ a_non_diag = Matrix::build(@points.size) do |row, col|
42
+ if row == col+ 1
43
+ inv_diff[col]
44
+ elsif col == row + 1
45
+ inv_diff[row]
46
+ else
47
+ 0.0
48
+ end
49
+ end
50
+
51
+ a = a_diag + a_non_diag
52
+
53
+ tmp = @points.each_cons(2).map do |p1, p2|
54
+ x1, y1 = p1
55
+ x2, y2 = p2
56
+ 3.0 * (y2 - y1) / (x2 - x1) ** 2.0
57
+ end
58
+ b = vector_helper(tmp)
59
+
60
+ @k = a.inv * b
61
+ end
62
+
63
+ # returns an interpolated value
64
+ def get(x)
65
+ i = @x_pairs.find_index {|pair| pair.member? x }
66
+ if i
67
+ dx = @x[i + 1] - @x[i]
68
+ dy = @y[i + 1] - @y[i]
69
+ t = (x - @x[i]) / dx
70
+ a = @k[i] * dx - dy
71
+ b = -(@k[i + 1] * dx - dy)
72
+ (1 - t) * @y[i] + t * @y[i + 1] + t * (1 - t) * (a * (1 - t) + b * t)
73
+ else
74
+ nil
75
+ end
76
+ end
77
+
78
+ alias :'[]' :get
79
+
80
+
81
+ # for a vector [a, b, c] returns [a, a + b, b + c, c]
82
+ # :nodoc:
83
+ def vector_helper(a)
84
+ Vector[*([0.0] + a)] + Vector[*(a + [0.0])]
85
+ end
86
+ private :vector_helper
87
+
88
+
89
+
90
+ # :nodoc:
91
+ def check_points_increasing
92
+ @x.each_cons(2) do |x1, x2|
93
+ raise 'Points must form a series of x and y values where x is increasing' unless x2 > x1
94
+ end
95
+ end
96
+ private :check_points_increasing
97
+
98
+ end
99
+ end
@@ -0,0 +1,45 @@
1
+ require 'spliner'
2
+
3
+ describe Spliner::Spliner do
4
+ DATASET = {0.0 => 0.0, 1.0 => 1.0, 2.0 => 0.5}
5
+
6
+ it 'should not accept x values that are not increasing' do
7
+ expect(lambda { Spliner::Spliner.new({0 => 0, 0 => 10})}).to raise_exception
8
+ end
9
+
10
+ it 'should not accept less than two values' do
11
+ expect(lambda { Spliner::Spliner.new({0 => 0})}).to raise_exception
12
+ end
13
+
14
+ it 'should return the data points themselves' do
15
+ s = Spliner::Spliner.new DATASET
16
+ DATASET.each do |k,v|
17
+ expect(s.get(k)).to be_within(0.00001).of(v)
18
+ end
19
+ end
20
+
21
+ it 'should return nil outside the data area' do
22
+ s = Spliner::Spliner.new DATASET
23
+ expect(s.get(-1.0)).to be_nil
24
+ expect(s.get(3.0)).to be_nil
25
+ end
26
+
27
+ it 'should generate a smooth curve (predefined points)' do
28
+ s = Spliner::Spliner.new DATASET
29
+ expect(s.get(0.4)).to be_within(0.0001).of(0.5260)
30
+ expect(s.get(0.8)).to be_within(0.0001).of(0.9080)
31
+ expect(s.get(1.2)).to be_within(0.0001).of(1.0080)
32
+ expect(s.get(1.6)).to be_within(0.0001).of(0.8260)
33
+ end
34
+
35
+ it 'should perform linear interpolation in the case of two data points' do
36
+ s = Spliner::Spliner.new({0 => 0, 10.0 => 100.0})
37
+ expect(s.get(3.0)).to be_within(0.0001).of(30.0)
38
+ end
39
+
40
+ it 'supports the [] operator (indexing like)' do
41
+ s = Spliner::Spliner.new DATASET
42
+ expect(s[-1]).to be_nil
43
+ expect(s[0]).to be_within(0.0001).of(0.0)
44
+ end
45
+ end
data/spliner.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "spliner"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "spliner"
7
+ s.version = Spliner::VERSION
8
+ s.authors = ["Tallak Tveide"]
9
+ s.email = ["tallak@tveide.net"]
10
+ s.homepage = "http://www.github.com/tallakt/spliner"
11
+ s.summary = %q{Cubic spline interpolation library}
12
+ s.description = %q{Simple library to perform cubic spline interpolation based on key X,Y values}
13
+ s.required_ruby_version = '>= 1.9.1'
14
+
15
+ s.rubyforge_project = "spliner"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ # s.add_runtime_dependency "clamp", '~> 0.3'
23
+ s.add_development_dependency "rspec", '~> 2.11'
24
+ s.add_development_dependency "rake", '~> 0.9'
25
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spliner
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tallak Tveide
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.11'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.11'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '0.9'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '0.9'
46
+ description: Simple library to perform cubic spline interpolation based on key X,Y
47
+ values
48
+ email:
49
+ - tallak@tveide.net
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .travis.yml
55
+ - README.markdown
56
+ - Rakefile
57
+ - lib/spliner.rb
58
+ - spec/spliner_spec.rb
59
+ - spliner.gemspec
60
+ homepage: http://www.github.com/tallakt/spliner
61
+ licenses: []
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: 1.9.1
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project: spliner
80
+ rubygems_version: 1.8.24
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Cubic spline interpolation library
84
+ test_files: []