libmf 0.2.2 → 0.2.6

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: e654382e818f1b59bc4437e71bc3e0ae6f4d4d79b9c85aeb53fb3494b2baf888
4
- data.tar.gz: 560fa519794c7cd8b29c27b9ac9f4247e0485e9f13f229c18a4562c8bee62868
3
+ metadata.gz: 33b8ba1c7cf9de8e19fa9775ecdb445bc0f2f4323401cccbf016ff6a81a04a00
4
+ data.tar.gz: 9ff88bdafac8bbfe0c99ccc0c0b7dfb7a9092246de1105c7f99ccade29b9c88b
5
5
  SHA512:
6
- metadata.gz: d16fb17f9b58cea5c53814a68fbf9de91440fd77e1669b52bbe5cb3a3837c94449d8bbc348405c0c117f219d2a513f1fc2e813b330ea127c93ac04a0c4101d07
7
- data.tar.gz: 3d5d3962d3878fe992f76ef9d2fa5e30866d007cd5ae3ab97a666fc53f97f9f3f2487bb425e15b59becde6118c61ecac6c8511692742d64efa2b9e26fe0d2872
6
+ metadata.gz: 021eca76e96ceca2cd484b7f7796a649529f3b20c80d494143cfaf43e617d23ac55ae50bdcd345808e277b31d304ea6e6a53c937b3e9a200f47ae226f27e4f2b
7
+ data.tar.gz: 916b78a5e62d19e4d6a9e1433350bb26982d43393029e4e883ed803f89a03f6db766ab10718120a73db1f0ad7ac80607d475a10a7c203d117ca1706e80618345
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 0.2.6 (2021-12-02)
2
+
3
+ - Improved ARM detection
4
+
5
+ ## 0.2.5 (2021-10-18)
6
+
7
+ - Added named loss functions
8
+ - Added `Matrix` class
9
+ - Improved error checking for `fit`, `cv`, `save_model`, and `load_model`
10
+
11
+ ## 0.2.4 (2021-08-05)
12
+
13
+ - Fixed memory leak
14
+
15
+ ## 0.2.3 (2021-03-14)
16
+
17
+ - Added ARM shared library for Linux
18
+
1
19
  ## 0.2.2 (2021-02-04)
2
20
 
3
21
  - Reduced allocations
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
- # LIBMF
1
+ # LIBMF Ruby
2
2
 
3
3
  [LIBMF](https://github.com/cjlin1/libmf) - large-scale sparse matrix factorization - for Ruby
4
4
 
5
5
  Check out [Disco](https://github.com/ankane/disco) for higher-level collaborative filtering
6
6
 
7
- [![Build Status](https://github.com/ankane/libmf/workflows/build/badge.svg?branch=master)](https://github.com/ankane/libmf/actions)
7
+ [![Build Status](https://github.com/ankane/libmf-ruby/workflows/build/badge.svg?branch=master)](https://github.com/ankane/libmf-ruby/actions)
8
8
 
9
9
  ## Installation
10
10
 
@@ -16,14 +16,13 @@ gem 'libmf'
16
16
 
17
17
  ## Getting Started
18
18
 
19
- Prep your data in the format `[row_index, column_index, value]`
19
+ Prep your data in the format `row_index, column_index, value`
20
20
 
21
21
  ```ruby
22
- data = [
23
- [0, 0, 5.0],
24
- [0, 2, 3.5],
25
- [1, 1, 4.0]
26
- ]
22
+ data = Libmf::Matrix.new
23
+ data.push(0, 0, 5.0)
24
+ data.push(0, 2, 3.5)
25
+ data.push(1, 1, 4.0)
27
26
  ```
28
27
 
29
28
  Create a model
@@ -90,7 +89,7 @@ Pass parameters - default values below
90
89
 
91
90
  ```ruby
92
91
  Libmf::Model.new(
93
- loss: 0, # loss function
92
+ loss: :real_l2, # loss function
94
93
  factors: 8, # number of latent factors
95
94
  threads: 12, # number of threads used
96
95
  bins: 25, # number of bins
@@ -111,21 +110,21 @@ Libmf::Model.new(
111
110
 
112
111
  For real-valued matrix factorization
113
112
 
114
- - 0 - squared error (L2-norm)
115
- - 1 - absolute error (L1-norm)
116
- - 2 - generalized KL-divergence
113
+ - `:real_l2` - squared error (L2-norm)
114
+ - `:real_l1` - absolute error (L1-norm)
115
+ - `:real_kl` - generalized KL-divergence
117
116
 
118
117
  For binary matrix factorization
119
118
 
120
- - 5 - logarithmic error
121
- - 6 - squared hinge loss
122
- - 7 - hinge loss
119
+ - `:binary_log` - logarithmic error
120
+ - `:binary_l2` - squared hinge loss
121
+ - `:binary_l1` - hinge loss
123
122
 
124
123
  For one-class matrix factorization
125
124
 
126
- - 10 - row-oriented pair-wise logarithmic loss
127
- - 11 - column-oriented pair-wise logarithmic loss
128
- - 12 - squared error (L2-norm)
125
+ - `:one_class_row` - row-oriented pair-wise logarithmic loss
126
+ - `:one_class_col` - column-oriented pair-wise logarithmic loss
127
+ - `:one_class_l2` - squared error (L2-norm)
129
128
 
130
129
  ## Performance
131
130
 
@@ -159,22 +158,22 @@ model.q_factors(format: :numo)
159
158
 
160
159
  ## History
161
160
 
162
- View the [changelog](https://github.com/ankane/libmf/blob/master/CHANGELOG.md)
161
+ View the [changelog](https://github.com/ankane/libmf-ruby/blob/master/CHANGELOG.md)
163
162
 
164
163
  ## Contributing
165
164
 
166
165
  Everyone is encouraged to help improve this project. Here are a few ways you can help:
167
166
 
168
- - [Report bugs](https://github.com/ankane/libmf/issues)
169
- - Fix bugs and [submit pull requests](https://github.com/ankane/libmf/pulls)
167
+ - [Report bugs](https://github.com/ankane/libmf-ruby/issues)
168
+ - Fix bugs and [submit pull requests](https://github.com/ankane/libmf-ruby/pulls)
170
169
  - Write, clarify, or fix documentation
171
170
  - Suggest or add new features
172
171
 
173
172
  To get started with development:
174
173
 
175
174
  ```sh
176
- git clone --recursive https://github.com/ankane/libmf.git
177
- cd libmf
175
+ git clone --recursive https://github.com/ankane/libmf-ruby.git
176
+ cd libmf-ruby
178
177
  bundle install
179
178
  bundle exec rake vendor:all
180
179
  bundle exec rake test
data/lib/libmf/ffi.rb CHANGED
@@ -43,15 +43,22 @@ module Libmf
43
43
  :b, :float,
44
44
  :p, :pointer,
45
45
  :q, :pointer
46
+
47
+ def self.release(pointer)
48
+ unless pointer.null?
49
+ ref = ::FFI::MemoryPointer.new(:pointer).write_pointer(pointer)
50
+ FFI.mf_destroy_model(ref)
51
+ end
52
+ end
46
53
  end
47
54
 
48
55
  attach_function :mf_get_default_param, [], Parameter.by_value
49
56
  attach_function :mf_read_problem, [:string], Problem.by_value
50
57
  attach_function :mf_save_model, [Model.by_ref, :string], :int
51
- attach_function :mf_load_model, [:string], Model.by_ref
52
- attach_function :mf_destroy_model, [Model.by_ref], :void
53
- attach_function :mf_train, [Problem.by_ref, Parameter.by_value], Model.by_ref
54
- attach_function :mf_train_with_validation, [Problem.by_ref, Problem.by_ref, Parameter.by_value], Model.by_ref
58
+ attach_function :mf_load_model, [:string], Model.auto_ptr
59
+ attach_function :mf_destroy_model, [:pointer], :void
60
+ attach_function :mf_train, [Problem.by_ref, Parameter.by_value], Model.auto_ptr
61
+ attach_function :mf_train_with_validation, [Problem.by_ref, Problem.by_ref, Parameter.by_value], Model.auto_ptr
55
62
  attach_function :mf_predict, [Model.by_ref, :int, :int], :float
56
63
  attach_function :mf_cross_validation, [Problem.by_ref, :int, Parameter.by_value], :double
57
64
  end
@@ -0,0 +1,13 @@
1
+ module Libmf
2
+ class Matrix
3
+ attr_reader :data
4
+
5
+ def initialize
6
+ @data = []
7
+ end
8
+
9
+ def push(row_index, column_index, value)
10
+ @data << [row_index, column_index, value]
11
+ end
12
+ end
13
+ end
data/lib/libmf/model.rb CHANGED
@@ -14,6 +14,7 @@ module Libmf
14
14
  else
15
15
  FFI.mf_train(train_set, param)
16
16
  end
17
+ raise Error, "fit failed" if @model.null?
17
18
 
18
19
  nil
19
20
  end
@@ -24,15 +25,20 @@ module Libmf
24
25
 
25
26
  def cv(data, folds: 5)
26
27
  problem = create_problem(data)
27
- FFI.mf_cross_validation(problem, folds, param)
28
+ # TODO update fork to differentiate between bad parameters and zero error
29
+ res = FFI.mf_cross_validation(problem, folds, param)
30
+ raise Error, "cv failed" if res == 0
31
+ res
28
32
  end
29
33
 
30
34
  def save_model(path)
31
- FFI.mf_save_model(model, path)
35
+ status = FFI.mf_save_model(model, path)
36
+ raise Error, "Cannot save model" if status != 0
32
37
  end
33
38
 
34
39
  def load_model(path)
35
40
  @model = FFI.mf_load_model(path)
41
+ raise Error, "Cannot open model" if @model.null?
36
42
  end
37
43
 
38
44
  def rows
@@ -80,6 +86,22 @@ module Libmf
80
86
  def param
81
87
  param = FFI.mf_get_default_param
82
88
  options = @options.dup
89
+
90
+ if options[:loss].is_a?(Symbol)
91
+ loss_map = {
92
+ real_l2: 0,
93
+ real_l1: 1,
94
+ real_kl: 2,
95
+ binary_log: 5,
96
+ binary_l2: 6,
97
+ binary_l1: 7,
98
+ one_class_row: 10,
99
+ one_class_col: 11,
100
+ one_class_l2: 12
101
+ }
102
+ options[:loss] = loss_map[options[:loss]] || (raise ArgumentError, "Unknown loss")
103
+ end
104
+
83
105
  # silence insufficient blocks warning with default params
84
106
  options[:bins] ||= 25 unless options[:nr_bins]
85
107
  options[:copy_data] = false unless options.key?(:copy_data)
@@ -107,6 +129,10 @@ module Libmf
107
129
  return FFI.mf_read_problem(File.expand_path(data))
108
130
  end
109
131
 
132
+ if data.is_a?(Matrix)
133
+ data = data.data
134
+ end
135
+
110
136
  raise Error, "No data" if data.empty?
111
137
 
112
138
  # TODO do in C for better performance
data/lib/libmf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Libmf
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.6"
3
3
  end
data/lib/libmf.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  require "ffi"
3
3
 
4
4
  # modules
5
+ require "libmf/matrix"
5
6
  require "libmf/model"
6
7
  require "libmf/version"
7
8
 
@@ -15,13 +16,17 @@ module Libmf
15
16
  if Gem.win_platform?
16
17
  "mf.dll"
17
18
  elsif RbConfig::CONFIG["host_os"] =~ /darwin/i
18
- if RbConfig::CONFIG["host_cpu"] =~ /arm/i
19
+ if RbConfig::CONFIG["host_cpu"] =~ /arm|aarch64/i
19
20
  "libmf.arm64.dylib"
20
21
  else
21
22
  "libmf.dylib"
22
23
  end
23
24
  else
24
- "libmf.so"
25
+ if RbConfig::CONFIG["host_cpu"] =~ /arm|aarch64/i
26
+ "libmf.arm64.so"
27
+ else
28
+ "libmf.so"
29
+ end
25
30
  end
26
31
  vendor_lib = File.expand_path("../vendor/#{lib_name}", __dir__)
27
32
  self.ffi_lib = [vendor_lib]
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libmf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-05 00:00:00.000000000 Z
11
+ date: 2021-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -35,16 +35,18 @@ files:
35
35
  - README.md
36
36
  - lib/libmf.rb
37
37
  - lib/libmf/ffi.rb
38
+ - lib/libmf/matrix.rb
38
39
  - lib/libmf/model.rb
39
40
  - lib/libmf/version.rb
40
41
  - vendor/COPYRIGHT
41
42
  - vendor/demo/real_matrix.te.txt
42
43
  - vendor/demo/real_matrix.tr.txt
43
44
  - vendor/libmf.arm64.dylib
45
+ - vendor/libmf.arm64.so
44
46
  - vendor/libmf.dylib
45
47
  - vendor/libmf.so
46
48
  - vendor/mf.dll
47
- homepage: https://github.com/ankane/libmf
49
+ homepage: https://github.com/ankane/libmf-ruby
48
50
  licenses:
49
51
  - BSD-3-Clause
50
52
  metadata: {}
@@ -63,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
65
  - !ruby/object:Gem::Version
64
66
  version: '0'
65
67
  requirements: []
66
- rubygems_version: 3.2.3
68
+ rubygems_version: 3.2.32
67
69
  signing_key:
68
70
  specification_version: 4
69
71
  summary: Large-scale sparse matrix factorization for Ruby