gslr 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8ff1543c6434c221e210a9269d673c2b84632839f80e0ec0db047d30cc9a4b60
4
- data.tar.gz: 10967bdbb5ab82e61b90f3f528d6d947b854f3993fbb4ee5bc0c11d25e71b63c
3
+ metadata.gz: 521c330d9040f7959bda2aa653e1151b081145eefcfee8cbdb18d1e795cf020b
4
+ data.tar.gz: 34e28e1a9a6920e75d103e58b6f26d86b4bffbd3d5be16f6ae85b2e902ec5567
5
5
  SHA512:
6
- metadata.gz: b48d6c388ff6e93a1e0c2aa4c7f9406ab96a3e77ee4852dc24bd736e71cc864fa8f6eee1d9da8a8778a2653d624da860ef69fe32334915ff5cfef8d4759a1920
7
- data.tar.gz: 04b1cdb82277e30e4abfc10004605479bf6a0064cd29122c279221ff3d62483486bdac4c29b30e488fbf315ab0d5c59b612625db80ffc9dd5cf7aa89c99b419f
6
+ metadata.gz: 257651df760713ed75f60907c423dd6bcdd4bbd63621d89bd2243269631311d07ea1b9045b4d3adcdfc2d8499f29eec9e29983fc0e3f71a572715ed363429432
7
+ data.tar.gz: 2baadaa2e4da0650ccd630549e57ca3cbfe3781d278ee2653602a12062a586427cef50fd980cd8563a7efa6565464b39b1b323fba41ef02ee269577c8fcfaae7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 0.2.0 (2022-09-02)
2
+
3
+ - Fixed error on Mac
4
+ - Dropped support for Ruby < 2.7
5
+
6
+ ## 0.1.3 (2020-07-26)
7
+
8
+ - Improved performance
9
+ - Improved error message when GSL not found on Mac
10
+
11
+ ## 0.1.2 (2019-12-08)
12
+
13
+ - Added `covariance` and `chi2` methods
14
+
1
15
  ## 0.1.1 (2019-12-07)
2
16
 
3
17
  - Fixed `undefined symbol` error on Linux
data/NOTICE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2019 Andrew Kane
1
+ Copyright (C) 2019-2022 Andrew Kane
2
2
 
3
3
  This program is free software: you can redistribute it and/or modify
4
4
  it under the terms of the GNU General Public License as published by
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  :fire: High performance linear regression for Ruby, powered by [GSL](https://www.gnu.org/software/gsl/)
4
4
 
5
- [![Build Status](https://travis-ci.org/ankane/gslr.svg?branch=master)](https://travis-ci.org/ankane/gslr)
5
+ [![Build Status](https://github.com/ankane/gslr/workflows/build/badge.svg?branch=master)](https://github.com/ankane/gslr/actions)
6
6
 
7
7
  ## Installation
8
8
 
@@ -15,7 +15,7 @@ brew install gsl
15
15
  Add this line to your application’s Gemfile:
16
16
 
17
17
  ```ruby
18
- gem 'gslr'
18
+ gem "gslr"
19
19
  ```
20
20
 
21
21
  ## Getting Started
@@ -49,6 +49,13 @@ model.coefficients
49
49
  model.intercept
50
50
  ```
51
51
 
52
+ Get the covariance matrix and chi-squared
53
+
54
+ ```ruby
55
+ model.covariance
56
+ model.chi2
57
+ ```
58
+
52
59
  Pass weights
53
60
 
54
61
  ```ruby
@@ -94,10 +101,10 @@ Check out [the options](https://www.gnu.org/software/gsl/extras/native_win_build
94
101
  ### Ubuntu
95
102
 
96
103
  ```sh
97
- sudo apt-get install libgsl-dev
104
+ sudo apt install libgsl-dev
98
105
  ```
99
106
 
100
- ## Heroku
107
+ ### Heroku
101
108
 
102
109
  Use the [Apt buildpack](https://github.com/heroku/heroku-buildpack-apt) and create an `Aptfile` with:
103
110
 
@@ -105,17 +112,6 @@ Use the [Apt buildpack](https://github.com/heroku/heroku-buildpack-apt) and crea
105
112
  libgsl-dev
106
113
  ```
107
114
 
108
- ## Travis CI
109
-
110
- Add to `.travis.yml`:
111
-
112
- ```yml
113
- addons:
114
- apt:
115
- packages:
116
- - libgsl-dev
117
- ```
118
-
119
115
  ## History
120
116
 
121
117
  View the [changelog](https://github.com/ankane/gslr/blob/master/CHANGELOG.md)
data/lib/gslr/ffi.rb CHANGED
@@ -11,7 +11,7 @@ module GSLR
11
11
  rescue Fiddle::DLError => e
12
12
  retry if libs.any?
13
13
  raise e if ENV["GSLR_DEBUG"]
14
- raise LoadError, "Could not find GSL"
14
+ raise LoadError, "GSL CBLAS not found"
15
15
  end
16
16
  end
17
17
 
@@ -21,9 +21,17 @@ module GSLR
21
21
  rescue Fiddle::DLError => e
22
22
  retry if libs.any?
23
23
  raise e if ENV["GSLR_DEBUG"]
24
- raise LoadError, "Could not find GSL"
24
+
25
+ if e.message.include?("libgsl.dylib")
26
+ raise LoadError, "GSL not found. Run `brew install gsl`"
27
+ else
28
+ raise LoadError, "GSL not found"
29
+ end
25
30
  end
26
31
 
32
+ # https://www.gnu.org/software/gsl/doc/html/err.html
33
+ extern "char * gsl_strerror(int gsl_errno)"
34
+
27
35
  # https://www.gnu.org/software/gsl/doc/html/vectors.html
28
36
  extern "gsl_vector * gsl_vector_alloc(size_t n)"
29
37
  extern "void gsl_vector_free(gsl_vector * v)"
@@ -40,5 +48,6 @@ module GSLR
40
48
  extern "void gsl_multifit_linear_free(gsl_multifit_linear_workspace * work)"
41
49
  extern "int gsl_multifit_linear_solve(double lambda, gsl_matrix * Xs, gsl_vector * ys, gsl_vector * cs, double * rnorm, double * snorm, gsl_multifit_linear_workspace * work)"
42
50
  extern "int gsl_multifit_linear_svd(gsl_matrix * X, gsl_multifit_linear_workspace * work)"
51
+ extern "int gsl_multifit_linear_applyW(gsl_matrix * X, gsl_vector * w, gsl_vector * y, gsl_matrix * WX, gsl_vector * Wy)"
43
52
  end
44
53
  end
data/lib/gslr/model.rb CHANGED
@@ -37,7 +37,7 @@ module GSLR
37
37
  one = [1].pack("d*")
38
38
  x.each do |xi|
39
39
  str << one if intercept
40
- str << xi.pack("d*")
40
+ xi.pack("d*", buffer: str)
41
41
  end
42
42
  x_ptr[0, str.bytesize] = str
43
43
  end
@@ -73,5 +73,9 @@ module GSLR
73
73
  def dfloat(x)
74
74
  x.is_a?(Numo::DFloat) ? x : x.cast_to(Numo::DFloat)
75
75
  end
76
+
77
+ def check_status(status)
78
+ raise Error, FFI.gsl_strerror(status).to_s if status != 0
79
+ end
76
80
  end
77
81
  end
data/lib/gslr/ols.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module GSLR
2
2
  class OLS < Model
3
+ attr_reader :covariance, :chi2
4
+
3
5
  def fit(x, y, weight: nil)
4
6
  # set data
5
7
  xc, s1, s2 = set_matrix(x, intercept: @fit_intercept)
@@ -14,15 +16,17 @@ module GSLR
14
16
  # fit
15
17
  if weight
16
18
  wc = set_vector(weight)
17
- FFI.gsl_multifit_wlinear(xc, wc, yc, c, cov, chisq.ref, work)
19
+ check_status FFI.gsl_multifit_wlinear(xc, wc, yc, c, cov, chisq, work)
18
20
  else
19
- FFI.gsl_multifit_linear(xc, yc, c, cov, chisq.ref, work)
21
+ check_status FFI.gsl_multifit_linear(xc, yc, c, cov, chisq, work)
20
22
  end
21
23
 
22
24
  # read solution
23
25
  c_ptr = FFI.gsl_vector_ptr(c, 0)
24
26
  @coefficients = c_ptr[0, s2 * Fiddle::SIZEOF_DOUBLE].unpack("d*")
25
27
  @intercept = @fit_intercept ? @coefficients.shift : 0.0
28
+ @covariance = read_matrix(cov, s2)
29
+ @chi2 = chisq[0, Fiddle::SIZEOF_DOUBLE].unpack1("d")
26
30
 
27
31
  nil
28
32
  ensure
@@ -33,5 +37,15 @@ module GSLR
33
37
  FFI.gsl_matrix_free(cov) if cov
34
38
  FFI.gsl_multifit_linear_free(work) if work
35
39
  end
40
+
41
+ private
42
+
43
+ def read_matrix(cov, s2)
44
+ ptr = FFI.gsl_matrix_ptr(cov, 0, 0)
45
+ row_size = s2 * Fiddle::SIZEOF_DOUBLE
46
+ s2.times.map do |i|
47
+ ptr[i * row_size, row_size].unpack("d*")
48
+ end
49
+ end
36
50
  end
37
51
  end
data/lib/gslr/ridge.rb CHANGED
@@ -5,16 +5,29 @@ module GSLR
5
5
  @alpha = alpha
6
6
  end
7
7
 
8
- def fit(x, y)
8
+ def fit(x, y, weight: nil)
9
9
  if @fit_intercept
10
10
  # the intercept should not be regularized
11
11
  # so we need to center x and y
12
12
  # and exclude the intercept
13
13
  xc, x_offset, s1, s2 = centered_matrix(x)
14
14
  yc, y_offset = centered_vector(y)
15
+
16
+ if weight
17
+ # TODO apply weights before centering
18
+ # not a great way to calculate and subtract the mean
19
+ # with GSL and FFI
20
+ raise "weight not supported with intercept yet"
21
+ end
15
22
  else
16
23
  xc, s1, s2 = set_matrix(x, intercept: false)
17
24
  yc = set_vector(y)
25
+
26
+ if weight
27
+ wc = set_vector(weight)
28
+ # in place transformation
29
+ check_status FFI.gsl_multifit_linear_applyW(xc, wc, yc, xc, yc)
30
+ end
18
31
  end
19
32
 
20
33
  # allocate solution
@@ -24,8 +37,8 @@ module GSLR
24
37
  work = FFI.gsl_multifit_linear_alloc(s1, s2)
25
38
 
26
39
  # fit
27
- FFI.gsl_multifit_linear_svd(xc, work)
28
- FFI.gsl_multifit_linear_solve(Math.sqrt(@alpha), xc, yc, c, rnorm.ref, snorm.ref, work)
40
+ check_status FFI.gsl_multifit_linear_svd(xc, work)
41
+ check_status FFI.gsl_multifit_linear_solve(Math.sqrt(@alpha), xc, yc, c, rnorm, snorm, work)
29
42
 
30
43
  # read solution
31
44
  c_ptr = FFI.gsl_vector_ptr(c, 0)
@@ -66,7 +79,7 @@ module GSLR
66
79
  # pack efficiently
67
80
  str = String.new
68
81
  x.each do |xi|
69
- str << xi.zip(x_offset).map { |v, o| v - o }.pack("d*")
82
+ xi.zip(x_offset).map { |v, o| v - o }.pack("d*", buffer: str)
70
83
  end
71
84
  x_ptr[0, str.bytesize] = str
72
85
  end
@@ -83,7 +96,7 @@ module GSLR
83
96
  end
84
97
 
85
98
  yc = set_vector(y)
86
- FFI.gsl_vector_add_constant(yc, -y_offset)
99
+ check_status FFI.gsl_vector_add_constant(yc, -y_offset)
87
100
 
88
101
  [yc, y_offset]
89
102
  end
data/lib/gslr/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module GSLR
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/gslr.rb CHANGED
@@ -18,6 +18,7 @@ module GSLR
18
18
  if Gem.win_platform?
19
19
  ["gsl.dll"]
20
20
  elsif RbConfig::CONFIG["host_os"] =~ /darwin/i
21
+ self.cblas_lib = ["libgslcblas.dylib"]
21
22
  ["libgsl.dylib"]
22
23
  else
23
24
  self.cblas_lib = ["libgslcblas.so"]
metadata CHANGED
@@ -1,73 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gslr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-08 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: minitest
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '5'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '5'
55
- - !ruby/object:Gem::Dependency
56
- name: numo-narray
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- description:
70
- email: andrew@chartkick.com
11
+ date: 2022-09-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: andrew@ankane.org
71
15
  executables: []
72
16
  extensions: []
73
17
  extra_rdoc_files: []
@@ -86,7 +30,7 @@ homepage: https://github.com/ankane/gslr
86
30
  licenses:
87
31
  - GPL-3.0-or-later
88
32
  metadata: {}
89
- post_install_message:
33
+ post_install_message:
90
34
  rdoc_options: []
91
35
  require_paths:
92
36
  - lib
@@ -94,15 +38,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
94
38
  requirements:
95
39
  - - ">="
96
40
  - !ruby/object:Gem::Version
97
- version: '2.4'
41
+ version: '2.7'
98
42
  required_rubygems_version: !ruby/object:Gem::Requirement
99
43
  requirements:
100
44
  - - ">="
101
45
  - !ruby/object:Gem::Version
102
46
  version: '0'
103
47
  requirements: []
104
- rubygems_version: 3.0.3
105
- signing_key:
48
+ rubygems_version: 3.3.7
49
+ signing_key:
106
50
  specification_version: 4
107
51
  summary: High performance linear regression for Ruby, powered by GSL
108
52
  test_files: []