cmfrec 0.1.5 → 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: 7a200b99780aeee83c5a0190e593c3806c4140aa4c096b0ef2c112fd21a858b7
4
- data.tar.gz: 27b354dd491ca1d7a728d4ef2318c72c56d76c691286bc267c74d3b8dafd7c5b
3
+ metadata.gz: e6dbbc801e415a4f505ffc436be23ccf066d144da072669e782b88c02e14b0f8
4
+ data.tar.gz: 3851230f0a4dc4be9fbc24fe81681de0758bdbb583803780f8e07b10741f4bd1
5
5
  SHA512:
6
- metadata.gz: 0c1ceefeac9131a804d94b6da78c7a6614f50c15d144841277829e5279ce2583872a681e972e336e21cb82d49466dee9f5f1de6a482fe8a99ab7aa5176ab0e5c
7
- data.tar.gz: 930b20b017b92555071699b38d903230da3ca1fc7b8b91b9e2f96ae3ae4dda9c8c289a47117beaa1e2539e5c9d622fe958d431f5106e8ab7c4809ea17e9fb6e8
6
+ metadata.gz: 103c09a7c0e13fca3cb81dc68c667e776fc965a485cf358e0fc8f350a97474b54bdfc0910f4472051020dbe34b8c097908c1024d5fc036ad77d0444372885109
7
+ data.tar.gz: b107b36333f714106d981168f24fda48a2a211f288a2dbe01f570adb607b7d6a5215c18df4c67d159bb367d652f3d10faeb4dbc66688eaf117c5b7a1432ee951
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## 0.2.0 (2022-06-14)
2
+
3
+ - Updated cmfrec to 3.4.2
4
+ - Fixed missing item ids with `load_movielens`
5
+ - Dropped support for Ruby < 2.7
6
+
7
+ ## 0.1.7 (2022-03-22)
8
+
9
+ - Improved ARM detection
10
+ - Fixed error with `load_movielens`
11
+ - Fixed duplicates in `item_info` with `load_movielens`
12
+
13
+ ## 0.1.6 (2021-08-12)
14
+
15
+ - Added `user_ids` and `item_ids` methods
16
+ - Added `user_id` argument to `user_factors`
17
+ - Added `item_id` argument to `item_factors`
18
+ - Added `user_id` argument to `user_bias`
19
+ - Added `item_id` argument to `item_bias`
20
+ - Added `item_ids` argument to `new_user_recs`
21
+ - Fixed order for `user_recs`
22
+
1
23
  ## 0.1.5 (2021-08-10)
2
24
 
3
25
  - Fixed issue with `user_recs` and `new_user_recs` returning rated items
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # cmfrec
1
+ # cmfrec Ruby
2
2
 
3
3
  :fire: Recommendations for Ruby, powered by [cmfrec](https://github.com/david-cortes/cmfrec)
4
4
 
@@ -6,14 +6,14 @@
6
6
  - Works with explicit and implicit feedback
7
7
  - Uses high-performance matrix factorization
8
8
 
9
- [![Build Status](https://github.com/ankane/cmfrec/workflows/build/badge.svg?branch=master)](https://github.com/ankane/cmfrec/actions)
9
+ [![Build Status](https://github.com/ankane/cmfrec-ruby/workflows/build/badge.svg?branch=master)](https://github.com/ankane/cmfrec-ruby/actions)
10
10
 
11
11
  ## Installation
12
12
 
13
13
  Add this line to your application’s Gemfile:
14
14
 
15
15
  ```ruby
16
- gem 'cmfrec'
16
+ gem "cmfrec"
17
17
  ```
18
18
 
19
19
  For Windows, also follow [these instructions](#windows-installation).
@@ -58,8 +58,8 @@ Get recommendations for a new user
58
58
 
59
59
  ```ruby
60
60
  recommender.new_user_recs([
61
- {item_id: 1, value: 5},
62
- {item_id: 2, value: 3}
61
+ {item_id: 1, rating: 5},
62
+ {item_id: 2, rating: 3}
63
63
  ])
64
64
  ```
65
65
 
@@ -112,7 +112,7 @@ recommender.new_user_recs([], user_info: {cats: 0, dogs: 2})
112
112
  Add this line to your application’s Gemfile:
113
113
 
114
114
  ```ruby
115
- gem 'ngt'
115
+ gem "ngt"
116
116
  ```
117
117
 
118
118
  Get similar users
@@ -150,11 +150,7 @@ recommender.predict(ratings.last(20000))
150
150
  [Ahoy](https://github.com/ankane/ahoy) is a great source for implicit feedback
151
151
 
152
152
  ```ruby
153
- views = Ahoy::Event.
154
- where(name: "Viewed post").
155
- group(:user_id).
156
- group("properties->>'post_id'"). # postgres syntax
157
- count
153
+ views = Ahoy::Event.where(name: "Viewed post").group(:user_id).group_prop(:post_id).count
158
154
 
159
155
  data =
160
156
  views.map do |(user_id, post_id), count|
@@ -230,8 +226,17 @@ bin = File.binread("recommender.bin")
230
226
  recommender = Marshal.load(bin)
231
227
  ```
232
228
 
229
+ Alternatively, you can store only the factors and use a library like [Neighbor](https://github.com/ankane/neighbor). See the [examples](https://github.com/ankane/neighbor/tree/master/examples) for Disco, which has a similar API. For explicit feedback, you should [disable the bias](#explicit-feedback) with this approach.
230
+
233
231
  ## Reference
234
232
 
233
+ Get ids
234
+
235
+ ```ruby
236
+ recommender.user_ids
237
+ recommender.item_ids
238
+ ```
239
+
235
240
  Get the global mean
236
241
 
237
242
  ```ruby
@@ -262,22 +267,22 @@ Cmfrec.ffi_lib = "path/to/cmfrec.dll"
262
267
 
263
268
  ## History
264
269
 
265
- View the [changelog](https://github.com/ankane/cmfrec/blob/master/CHANGELOG.md)
270
+ View the [changelog](https://github.com/ankane/cmfrec-ruby/blob/master/CHANGELOG.md)
266
271
 
267
272
  ## Contributing
268
273
 
269
274
  Everyone is encouraged to help improve this project. Here are a few ways you can help:
270
275
 
271
- - [Report bugs](https://github.com/ankane/cmfrec/issues)
272
- - Fix bugs and [submit pull requests](https://github.com/ankane/cmfrec/pulls)
276
+ - [Report bugs](https://github.com/ankane/cmfrec-ruby/issues)
277
+ - Fix bugs and [submit pull requests](https://github.com/ankane/cmfrec-ruby/pulls)
273
278
  - Write, clarify, or fix documentation
274
279
  - Suggest or add new features
275
280
 
276
281
  To get started with development:
277
282
 
278
283
  ```sh
279
- git clone https://github.com/ankane/cmfrec.git
280
- cd cmfrec
284
+ git clone https://github.com/ankane/cmfrec-ruby.git
285
+ cd cmfrec-ruby
281
286
  bundle install
282
287
  bundle exec rake vendor:all
283
288
  bundle exec rake test
data/lib/cmfrec/data.rb CHANGED
@@ -3,11 +3,11 @@ module Cmfrec
3
3
  def load_movielens
4
4
  require "csv"
5
5
 
6
- data_path = download_file("ml-100k/u.data", "http://files.grouplens.org/datasets/movielens/ml-100k/u.data",
6
+ data_path = download_file("ml-100k/u.data", "https://files.grouplens.org/datasets/movielens/ml-100k/u.data",
7
7
  file_hash: "06416e597f82b7342361e41163890c81036900f418ad91315590814211dca490")
8
- user_path = download_file("ml-100k/u.user", "http://files.grouplens.org/datasets/movielens/ml-100k/u.user",
8
+ user_path = download_file("ml-100k/u.user", "https://files.grouplens.org/datasets/movielens/ml-100k/u.user",
9
9
  file_hash: "f120e114da2e8cf314fd28f99417c94ae9ddf1cb6db8ce0e4b5995d40e90e62c")
10
- item_path = download_file("ml-100k/u.item", "http://files.grouplens.org/datasets/movielens/ml-100k/u.item",
10
+ item_path = download_file("ml-100k/u.item", "https://files.grouplens.org/datasets/movielens/ml-100k/u.item",
11
11
  file_hash: "553841ebc7de3a0fd0d6b62a204ea30c1e651aacfb2814c7a6584ac52f2c5701")
12
12
 
13
13
  # convert u.item to utf-8
@@ -24,9 +24,15 @@ module Cmfrec
24
24
 
25
25
  item_info = []
26
26
  movies = {}
27
+ movie_names = {}
27
28
  genres = %w(unknown action adventure animation childrens comedy crime documentary drama fantasy filmnoir horror musical mystery romance scifi thriller war western)
28
29
  CSV.parse(movies_str, col_sep: "|", converters: [:numeric]) do |row|
29
30
  movies[row[0]] = row[1]
31
+
32
+ # filter duplicates
33
+ next if movie_names[row[1]]
34
+ movie_names[row[1]] = true
35
+
30
36
  item = {item_id: row[1], year: row[2] ? Date.parse(row[2]).year : 1970}
31
37
  genres.each_with_index do |genre, i|
32
38
  item[:"genre_#{genre}"] = row[i + 5]
@@ -49,7 +55,10 @@ module Cmfrec
49
55
  private
50
56
 
51
57
  def download_file(fname, origin, file_hash:)
58
+ require "digest"
52
59
  require "fileutils"
60
+ require "net/http"
61
+ require "tmpdir"
53
62
 
54
63
  # TODO handle this better
55
64
  raise "No HOME" unless ENV["HOME"]
@@ -58,10 +67,6 @@ module Cmfrec
58
67
 
59
68
  return dest if File.exist?(dest)
60
69
 
61
- require "digest"
62
- require "net/http"
63
- require "tmpdir"
64
-
65
70
  temp_path = "#{Dir.tmpdir}/cmfrec-#{Time.now.to_f}" # TODO better name
66
71
 
67
72
  digest = Digest::SHA2.new
data/lib/cmfrec/ffi.rb CHANGED
@@ -17,12 +17,13 @@ module Cmfrec
17
17
  typealias "int_t", "int"
18
18
  typealias "real_t", "double"
19
19
 
20
- extern "int_t fit_collective_explicit_als(real_t *restrict biasA, real_t *restrict biasB, real_t *restrict A, real_t *restrict B, real_t *restrict C, real_t *restrict D, real_t *restrict Ai, real_t *restrict Bi, bool add_implicit_features, bool reset_values, int_t seed, real_t *restrict glob_mean, real_t *restrict U_colmeans, real_t *restrict I_colmeans, int_t m, int_t n, int_t k, int_t ixA[], int_t ixB[], real_t *restrict X, size_t nnz, real_t *restrict Xfull, real_t *restrict weight, bool user_bias, bool item_bias, bool center, real_t lam, real_t *restrict lam_unique, real_t l1_lam, real_t *restrict l1_lam_unique, bool scale_lam, bool scale_lam_sideinfo, real_t *restrict U, int_t m_u, int_t p, real_t *restrict II, int_t n_i, int_t q, int_t U_row[], int_t U_col[], real_t *restrict U_sp, size_t nnz_U, int_t I_row[], int_t I_col[], real_t *restrict I_sp, size_t nnz_I, bool NA_as_zero_X, bool NA_as_zero_U, bool NA_as_zero_I, int_t k_main, int_t k_user, int_t k_item, real_t w_main, real_t w_user, real_t w_item, real_t w_implicit, int_t niter, int_t nthreads, bool verbose, bool handle_interrupt, bool use_cg, int_t max_cg_steps, bool finalize_chol, bool nonneg, int_t max_cd_steps, bool nonneg_C, bool nonneg_D, bool precompute_for_predictions, bool include_all_X, real_t *restrict B_plus_bias, real_t *restrict precomputedBtB, real_t *restrict precomputedTransBtBinvBt, real_t *restrict precomputedBtXbias, real_t *restrict precomputedBeTBeChol, real_t *restrict precomputedBiTBi, real_t *restrict precomputedTransCtCinvCt, real_t *restrict precomputedCtCw)"
21
- extern "int_t fit_collective_implicit_als(real_t *restrict A, real_t *restrict B, real_t *restrict C, real_t *restrict D, bool reset_values, int_t seed, real_t *restrict U_colmeans, real_t *restrict I_colmeans, int_t m, int_t n, int_t k, int_t ixA[], int_t ixB[], real_t *restrict X, size_t nnz, real_t lam, real_t *restrict lam_unique, real_t l1_lam, real_t *restrict l1_lam_unique, real_t *restrict U, int_t m_u, int_t p, real_t *restrict II, int_t n_i, int_t q, int_t U_row[], int_t U_col[], real_t *restrict U_sp, size_t nnz_U, int_t I_row[], int_t I_col[], real_t *restrict I_sp, size_t nnz_I, bool NA_as_zero_U, bool NA_as_zero_I, int_t k_main, int_t k_user, int_t k_item, real_t w_main, real_t w_user, real_t w_item, real_t *restrict w_main_multiplier, real_t alpha, bool adjust_weight, bool apply_log_transf, int_t niter, int_t nthreads, bool verbose, bool handle_interrupt, bool use_cg, int_t max_cg_steps, bool finalize_chol, bool nonneg, int_t max_cd_steps, bool nonneg_C, bool nonneg_D, bool precompute_for_predictions, real_t *restrict precomputedBtB, real_t *restrict precomputedBeTBe, real_t *restrict precomputedBeTBeChol)"
22
- extern "int_t factors_collective_explicit_single(real_t *restrict a_vec, real_t *restrict a_bias,real_t *restrict u_vec, int_t p,real_t *restrict u_vec_sp, int_t u_vec_ixB[], size_t nnz_u_vec,real_t *restrict u_bin_vec, int_t pbin,bool NA_as_zero_U, bool NA_as_zero_X,bool nonneg,real_t *restrict C, real_t *restrict Cb,real_t glob_mean, real_t *restrict biasB,real_t *restrict U_colmeans,real_t *restrict Xa, int_t ixB[], size_t nnz,real_t *restrict Xa_dense, int_t n,real_t *restrict weight,real_t *restrict B,real_t *restrict Bi, bool add_implicit_features,int_t k, int_t k_user, int_t k_item, int_t k_main,real_t lam, real_t *restrict lam_unique,real_t l1_lam, real_t *restrict l1_lam_unique,bool scale_lam, bool scale_lam_sideinfo,real_t w_main, real_t w_user, real_t w_implicit,int_t n_max, bool include_all_X,real_t *restrict BtB,real_t *restrict TransBtBinvBt,real_t *restrict BtXbias,real_t *restrict BeTBeChol,real_t *restrict BiTBi,real_t *restrict CtCw,real_t *restrict TransCtCinvCt,real_t *restrict B_plus_bias)"
23
- extern "int_t factors_collective_implicit_single(real_t *restrict a_vec,real_t *restrict u_vec, int_t p,real_t *restrict u_vec_sp, int_t u_vec_ixB[], size_t nnz_u_vec,bool NA_as_zero_U,bool nonneg,real_t *restrict U_colmeans,real_t *restrict B, int_t n, real_t *restrict C,real_t *restrict Xa, int_t ixB[], size_t nnz,int_t k, int_t k_user, int_t k_item, int_t k_main,real_t lam, real_t l1_lam, real_t alpha, real_t w_main, real_t w_user,real_t w_main_multiplier,bool apply_log_transf,real_t *restrict BeTBe,real_t *restrict BtB,real_t *restrict BeTBeChol)"
24
- extern "int_t predict_X_old_collective_explicit(int_t row[], int_t col[], real_t *restrict predicted, size_t n_predict, real_t *restrict A, real_t *restrict biasA, real_t *restrict B, real_t *restrict biasB, real_t glob_mean, int_t k, int_t k_user, int_t k_item, int_t k_main, int_t m, int_t n_max, int_t nthreads)"
25
- extern "int_t predict_X_old_collective_implicit(int_t row[], int_t col[], real_t *restrict predicted, size_t n_predict, real_t *restrict A, real_t *restrict B, int_t k, int_t k_user, int_t k_item, int_t k_main, int_t m, int_t n, int_t nthreads)"
26
- extern "int_t topN(real_t *restrict a_vec, int_t k_user, real_t *restrict B, int_t k_item, real_t *restrict biasB, real_t glob_mean, real_t biasA, int_t k, int_t k_main, int_t *restrict include_ix, int_t n_include, int_t *restrict exclude_ix, int_t n_exclude, int_t *restrict outp_ix, real_t *restrict outp_score, int_t n_top, int_t n, int_t nthreads)"
20
+ extern "int_t fit_collective_explicit_als(real_t *restrict biasA, real_t *restrict biasB, real_t *restrict A, real_t *restrict B, real_t *restrict C, real_t *restrict D, real_t *restrict Ai, real_t *restrict Bi, bool add_implicit_features, bool reset_values, int_t seed, real_t *restrict glob_mean, real_t *restrict U_colmeans, real_t *restrict I_colmeans, int_t m, int_t n, int_t k, int_t ixA[], int_t ixB[], real_t *restrict X, size_t nnz, real_t *restrict Xfull, real_t *restrict weight, bool user_bias, bool item_bias, bool center, real_t lam, real_t *restrict lam_unique, real_t l1_lam, real_t *restrict l1_lam_unique, bool scale_lam, bool scale_lam_sideinfo, bool scale_bias_const, real_t *scaling_biasA, real_t *scaling_biasB, real_t *restrict U, int_t m_u, int_t p, real_t *restrict II, int_t n_i, int_t q, int_t U_row[], int_t U_col[], real_t *restrict U_sp, size_t nnz_U, int_t I_row[], int_t I_col[], real_t *restrict I_sp, size_t nnz_I, bool NA_as_zero_X, bool NA_as_zero_U, bool NA_as_zero_I, int_t k_main, int_t k_user, int_t k_item, real_t w_main, real_t w_user, real_t w_item, real_t w_implicit, int_t niter, int nthreads, bool verbose, bool handle_interrupt, bool use_cg, int_t max_cg_steps, bool precondition_cg, bool finalize_chol, bool nonneg, int_t max_cd_steps, bool nonneg_C, bool nonneg_D, bool precompute_for_predictions, bool include_all_X, real_t *restrict B_plus_bias, real_t *restrict precomputedBtB, real_t *restrict precomputedTransBtBinvBt, real_t *restrict precomputedBtXbias, real_t *restrict precomputedBeTBeChol, real_t *restrict precomputedBiTBi, real_t *restrict precomputedTransCtCinvCt, real_t *restrict precomputedCtCw, real_t *precomputedCtUbias)"
21
+ extern "int_t fit_collective_implicit_als(real_t *restrict A, real_t *restrict B, real_t *restrict C, real_t *restrict D, bool reset_values, int_t seed, real_t *restrict U_colmeans, real_t *restrict I_colmeans, int_t m, int_t n, int_t k, int_t ixA[], int_t ixB[], real_t *restrict X, size_t nnz, real_t lam, real_t *restrict lam_unique, real_t l1_lam, real_t *restrict l1_lam_unique, real_t *restrict U, int_t m_u, int_t p, real_t *restrict II, int_t n_i, int_t q, int_t U_row[], int_t U_col[], real_t *restrict U_sp, size_t nnz_U, int_t I_row[], int_t I_col[], real_t *restrict I_sp, size_t nnz_I, bool NA_as_zero_U, bool NA_as_zero_I, int_t k_main, int_t k_user, int_t k_item, real_t w_main, real_t w_user, real_t w_item, real_t *restrict w_main_multiplier, real_t alpha, bool adjust_weight, bool apply_log_transf, int_t niter, int nthreads, bool verbose, bool handle_interrupt, bool use_cg, int_t max_cg_steps, bool precondition_cg, bool finalize_chol, bool nonneg, int_t max_cd_steps, bool nonneg_C, bool nonneg_D, bool precompute_for_predictions, real_t *restrict precomputedBtB, real_t *restrict precomputedBeTBe, real_t *restrict precomputedBeTBeChol, real_t *precomputedCtUbias)"
22
+ extern "int_t predict_X_old_collective_explicit(int_t row[], int_t col[], real_t *restrict predicted, size_t n_predict, real_t *restrict A, real_t *restrict biasA, real_t *restrict B, real_t *restrict biasB, real_t glob_mean, int_t k, int_t k_user, int_t k_item, int_t k_main, int_t m, int_t n_max, int nthreads)"
23
+ extern "int_t predict_X_old_collective_implicit(int_t row[], int_t col[], real_t *restrict predicted, size_t n_predict, real_t *restrict A, real_t *restrict B, int_t k, int_t k_user, int_t k_item, int_t k_main, int_t m, int_t n, int nthreads)"
24
+ extern "int_t topN_old_collective_explicit(real_t *a_vec, real_t a_bias, real_t *A, real_t *biasA, int_t row_index, real_t *B, real_t *biasB, real_t glob_mean, int_t k, int_t k_user, int_t k_item, int_t k_main, int_t *include_ix, int_t n_include, int_t *exclude_ix, int_t n_exclude, int_t *outp_ix, real_t *outp_score, int_t n_top, int_t n, int_t n_max, bool include_all_X, int nthreads)"
25
+ extern "int_t topN_old_collective_implicit(real_t *a_vec, real_t *A, int_t row_index, real_t *B, int_t k, int_t k_user, int_t k_item, int_t k_main, int_t *include_ix, int_t n_include, int_t *exclude_ix, int_t n_exclude, int_t *outp_ix, real_t *outp_score, int_t n_top, int_t n, int nthreads)"
26
+ extern "int_t topN_new_collective_explicit(bool user_bias, real_t *u_vec, int_t p, real_t *u_vec_sp, int_t u_vec_X_col[], size_t nnz_u_vec, real_t *u_bin_vec, int_t pbin, bool NA_as_zero_U, bool NA_as_zero_X, bool nonneg, real_t *C, real_t *Cb, real_t glob_mean, real_t *biasB, real_t *U_colmeans, real_t *Xa, int_t X_col[], size_t nnz, real_t *Xa_dense, int_t n, real_t *weight, real_t *B, real_t *Bi, bool add_implicit_features, int_t k, int_t k_user, int_t k_item, int_t k_main, real_t lam, real_t *lam_unique, real_t l1_lam, real_t *l1_lam_unique, bool scale_lam, bool scale_lam_sideinfo, bool scale_bias_const, real_t scaling_biasA, real_t w_main, real_t w_user, real_t w_implicit, int_t n_max, bool include_all_X, real_t *BtB, real_t *TransBtBinvBt, real_t *BtXbias, real_t *BeTBeChol, real_t *BiTBi, real_t *CtCw, real_t *TransCtCinvCt, real_t *CtUbias, real_t *B_plus_bias, int_t *include_ix, int_t n_include, int_t *exclude_ix, int_t n_exclude, int_t *outp_ix, real_t *outp_score, int_t n_top, int nthreads)"
27
+ extern "int_t topN_new_collective_implicit(int_t n, real_t *u_vec, int_t p, real_t *u_vec_sp, int_t u_vec_X_col[], size_t nnz_u_vec, bool NA_as_zero_U, bool nonneg, real_t *U_colmeans, real_t *B, real_t *C, real_t *Xa, int_t X_col[], size_t nnz, int_t k, int_t k_user, int_t k_item, int_t k_main, real_t lam, real_t l1_lam, real_t alpha, real_t w_main, real_t w_user, real_t w_main_multiplier, bool apply_log_transf, real_t *BeTBe, real_t *BtB, real_t *BeTBeChol, real_t *CtUbias, int_t *include_ix, int_t n_include, int_t *exclude_ix, int_t n_exclude, int_t *outp_ix, real_t *outp_score, int_t n_top, int nthreads)"
27
28
  end
28
29
  end
@@ -67,23 +67,10 @@ module Cmfrec
67
67
  user = @user_map[user_id]
68
68
 
69
69
  if user
70
- # TODO use top_n for item_ids as well
71
- if item_ids
72
- # remove missing ids
73
- item_ids = item_ids.select { |v| @item_map[v] }
74
-
75
- data = item_ids.map { |v| {user_id: user_id, item_id: v} }
76
- scores = predict(data)
77
-
78
- item_ids.zip(scores).map do |item_id, score|
79
- {item_id: item_id, score: score}
80
- end
81
- else
82
- a_vec = @a[user * @k * Fiddle::SIZEOF_DOUBLE, @k * Fiddle::SIZEOF_DOUBLE]
83
- a_bias = @bias_a ? @bias_a[user * Fiddle::SIZEOF_DOUBLE, Fiddle::SIZEOF_DOUBLE].unpack1("d") : 0
84
- # @rated[user] will be nil for recommenders saved before 0.1.5
85
- top_n(a_vec: a_vec, a_bias: a_bias, count: count, rated: (@rated[user] || {}).keys)
86
- end
70
+ a_vec = @a[user * @k * Fiddle::SIZEOF_DOUBLE, @k * Fiddle::SIZEOF_DOUBLE]
71
+ a_bias = @bias_a ? @bias_a[user * Fiddle::SIZEOF_DOUBLE, Fiddle::SIZEOF_DOUBLE].unpack1("d") : 0
72
+ # @rated[user] will be nil for recommenders saved before 0.1.5
73
+ top_n(a_vec: a_vec, a_bias: a_bias, count: count, rated: (@rated[user] || {}).keys, item_ids: item_ids, row_index: user)
87
74
  else
88
75
  # no items if user is unknown
89
76
  # TODO maybe most popular items
@@ -91,28 +78,164 @@ module Cmfrec
91
78
  end
92
79
  end
93
80
 
94
- # TODO add item_ids
95
- def new_user_recs(data, count: 5, user_info: nil)
81
+ def new_user_recs(data, count: 5, user_info: nil, item_ids: nil)
96
82
  check_fit
97
83
 
98
- a_vec, a_bias, rated = factors_warm(data, user_info: user_info)
99
- top_n(a_vec: a_vec, a_bias: a_bias, count: count, rated: rated)
84
+ data = to_dataset(data)
85
+ user_info = to_dataset(user_info) if user_info
86
+
87
+ # remove unknown items
88
+ data, unknown_data = data.partition { |d| @item_map[d[:item_id]] }
89
+
90
+ if unknown_data.any?
91
+ # TODO warn for unknown items?
92
+ # warn "[cmfrec] Unknown items: #{unknown_data.map { |d| d[:item_id] }.join(", ")}"
93
+ end
94
+
95
+ rated_ids = data.map { |d| @item_map[d[:item_id]] }
96
+
97
+ nnz = data.size
98
+
99
+ u_vec_sp = []
100
+ u_vec_x_col = []
101
+ if user_info
102
+ user_info.each do |k, v|
103
+ next if k == :user_id
104
+
105
+ uc = @user_info_map[k]
106
+ raise "Bad key: #{k}" unless uc
107
+
108
+ u_vec_x_col << uc
109
+ u_vec_sp << v
110
+ end
111
+ end
112
+ p_ = @user_info_map.size
113
+ nnz_u_vec = u_vec_sp.size
114
+ u_vec_x_col = int_ptr(u_vec_x_col)
115
+ u_vec_sp = real_ptr(u_vec_sp)
116
+
117
+ u_vec = nil
118
+ u_bin_vec = nil
119
+ pbin = 0
120
+
121
+ weight = nil
122
+ lam_unique = nil
123
+ l1_lam_unique = nil
124
+ n_max = @n
125
+
126
+ if data.any?
127
+ if @implicit
128
+ ratings = data.map { |d| d[:value] || 1 }
129
+ else
130
+ ratings = data.map { |d| d[:rating] }
131
+ check_ratings(ratings)
132
+ end
133
+ xa = real_ptr(ratings)
134
+ x_col = int_ptr(rated_ids)
135
+ else
136
+ xa = nil
137
+ x_col = nil
138
+ end
139
+ xa_dense = nil
140
+
141
+ rated = rated_ids.uniq
142
+
143
+ prep = prepare_top_n(count: count, rated: rated, item_ids: item_ids)
144
+ return [] if prep.empty?
145
+ include_ix, n_include, exclude_ix, n_exclude, outp_ix, outp_score, count = prep
146
+
147
+ if @implicit
148
+ args = [
149
+ @n,
150
+ u_vec, p_,
151
+ u_vec_sp, u_vec_x_col, nnz_u_vec,
152
+ @na_as_zero_user,
153
+ @nonneg,
154
+ @u_colmeans,
155
+ @b, @c,
156
+ xa, x_col, nnz,
157
+ @k, @k_user, @k_item, @k_main,
158
+ @lambda_, @l1_lambda, @alpha, @w_main, @w_user,
159
+ @w_main_multiplier,
160
+ @apply_log_transf,
161
+ nil, #BeTBe,
162
+ nil, #BtB,
163
+ nil, #BeTBeChol,
164
+ nil, #CtUbias,
165
+ include_ix, n_include,
166
+ exclude_ix, n_exclude,
167
+ outp_ix, outp_score,
168
+ count, @nthreads
169
+ ]
170
+ check_status FFI.topN_new_collective_implicit(*fiddle_args(args))
171
+ else
172
+ cb = nil
173
+ scaling_bias_a = 0
174
+
175
+ args = [
176
+ @user_bias,
177
+ u_vec, p_,
178
+ u_vec_sp, u_vec_x_col, nnz_u_vec,
179
+ u_bin_vec, pbin,
180
+ @na_as_zero_user, @na_as_zero,
181
+ @nonneg,
182
+ @c, cb,
183
+ @global_mean, @bias_b,
184
+ @u_colmeans,
185
+ xa, x_col, nnz,
186
+ xa_dense, @n,
187
+ weight,
188
+ @b,
189
+ @bi, @add_implicit_features,
190
+ @k, @k_user, @k_item, @k_main,
191
+ @lambda_, lam_unique,
192
+ @l1_lambda, l1_lam_unique,
193
+ @scale_lam, @scale_lam_sideinfo,
194
+ @scale_bias_const, scaling_bias_a,
195
+ @w_main, @w_user, @w_implicit,
196
+ n_max, @include_all_x,
197
+ nil, #BtB,
198
+ nil, #TransBtBinvBt,
199
+ nil, #BtXbias,
200
+ nil, #BeTBeChol,
201
+ nil, #BiTBi,
202
+ nil, #CtCw,
203
+ nil, #TransCtCinvCt,
204
+ nil, #CtUbias,
205
+ nil, #B_plus_bias,
206
+ include_ix, n_include,
207
+ exclude_ix, n_exclude,
208
+ outp_ix, outp_score,
209
+ count, @nthreads
210
+ ]
211
+ check_status FFI.topN_new_collective_explicit(*fiddle_args(args))
212
+ end
213
+
214
+ top_n_output(outp_ix, outp_score)
215
+ end
216
+
217
+ def user_ids
218
+ @user_map.keys
219
+ end
220
+
221
+ def item_ids
222
+ @item_map.keys
100
223
  end
101
224
 
102
- def user_factors
103
- read_factors(@a, [@m, @m_u].max, @k_user + @k + @k_main)
225
+ def user_factors(user_id = nil)
226
+ read_factors(@a, [@m, @m_u].max, @k_user + @k + @k_main, user_id, @user_map)
104
227
  end
105
228
 
106
- def item_factors
107
- read_factors(@b, [@n, @n_i].max, @k_item + @k + @k_main)
229
+ def item_factors(item_id = nil)
230
+ read_factors(@b, [@n, @n_i].max, @k_item + @k + @k_main, item_id, @item_map)
108
231
  end
109
232
 
110
- def user_bias
111
- read_bias(@bias_a) if @bias_a
233
+ def user_bias(user_id = nil)
234
+ read_bias(@bias_a, user_id, @user_map) if @bias_a
112
235
  end
113
236
 
114
- def item_bias
115
- read_bias(@bias_b) if @bias_b
237
+ def item_bias(item_id = nil)
238
+ read_bias(@bias_b, item_id, @item_map) if @bias_b
116
239
  end
117
240
 
118
241
  def similar_items(item_id, count: 5)
@@ -216,7 +339,6 @@ module Cmfrec
216
339
  x_full = nil
217
340
  weight = nil
218
341
  lam_unique = nil
219
- l1_lambda = 0
220
342
  l1_lam_unique = nil
221
343
 
222
344
  uu = nil
@@ -253,7 +375,7 @@ module Cmfrec
253
375
  @m, @n, @k,
254
376
  x_row, x_col, x, nnz,
255
377
  @lambda_, lam_unique,
256
- l1_lambda, l1_lam_unique,
378
+ @l1_lambda, l1_lam_unique,
257
379
  uu, @m_u, p_,
258
380
  ii, @n_i, q,
259
381
  u_row, u_col, u_sp, nnz_u,
@@ -263,12 +385,13 @@ module Cmfrec
263
385
  @w_main, @w_user, @w_item, real_ptr([@w_main_multiplier]),
264
386
  @alpha, @adjust_weight, @apply_log_transf,
265
387
  @niter, @nthreads, @verbose, @handle_interrupt,
266
- @use_cg, @max_cg_steps, @finalize_chol,
388
+ @use_cg, @max_cg_steps, @precondition_cg, @finalize_chol,
267
389
  @nonneg, @max_cd_steps, @nonneg_c, @nonneg_d,
268
390
  @precompute_for_predictions,
269
391
  nil, #precomputedBtB,
270
392
  nil, #precomputedBeTBe,
271
- nil #precomputedBeTBeChol
393
+ nil, #precomputedBeTBeChol
394
+ nil #precomputedCtUbias
272
395
  ]
273
396
  check_status FFI.fit_collective_implicit_als(*fiddle_args(args))
274
397
 
@@ -287,9 +410,9 @@ module Cmfrec
287
410
 
288
411
  glob_mean = Fiddle::Pointer.malloc(Fiddle::SIZEOF_DOUBLE)
289
412
 
290
- center = true
291
- scale_lam = false
292
- scale_lam_sideinfo = false
413
+ # TODO add
414
+ scaling_bias_a = nil
415
+ scaling_bias_b = nil
293
416
 
294
417
  args = [
295
418
  @bias_a, @bias_b,
@@ -304,10 +427,11 @@ module Cmfrec
304
427
  x_row, x_col, x, nnz,
305
428
  x_full,
306
429
  weight,
307
- @user_bias, @item_bias, center,
430
+ @user_bias, @item_bias, @center,
308
431
  @lambda_, lam_unique,
309
- l1_lambda, l1_lam_unique,
310
- scale_lam, scale_lam_sideinfo,
432
+ @l1_lambda, l1_lam_unique,
433
+ @scale_lam, @scale_lam_sideinfo,
434
+ @scale_bias_const, scaling_bias_a, scaling_bias_b,
311
435
  uu, @m_u, p_,
312
436
  ii, @n_i, q,
313
437
  u_row, u_col, u_sp, nnz_u,
@@ -316,7 +440,7 @@ module Cmfrec
316
440
  @k_main, @k_user, @k_item,
317
441
  @w_main, @w_user, @w_item, @w_implicit,
318
442
  @niter, @nthreads, @verbose, @handle_interrupt,
319
- @use_cg, @max_cg_steps, @finalize_chol,
443
+ @use_cg, @max_cg_steps, @precondition_cg, @finalize_chol,
320
444
  @nonneg, @max_cd_steps, @nonneg_c, @nonneg_d,
321
445
  @precompute_for_predictions,
322
446
  @include_all_x,
@@ -327,7 +451,8 @@ module Cmfrec
327
451
  nil, #precomputedBeTBeChol,
328
452
  nil, #precomputedBiTBi,
329
453
  nil, #precomputedTransCtCinvCt,
330
- nil #precomputedCtCw
454
+ nil, #precomputedCtCw
455
+ nil, #precomputedCtUbias
331
456
  ]
332
457
  check_status FFI.fit_collective_explicit_als(*fiddle_args(args))
333
458
 
@@ -342,21 +467,20 @@ module Cmfrec
342
467
  end
343
468
 
344
469
  def set_params(
345
- k: 40, lambda_: 1e+1, method: "als", use_cg: true, user_bias: true,
346
- item_bias: true, add_implicit_features: false,
470
+ k: 40, lambda_: 10.0, method: "als", use_cg: true,
471
+ user_bias: true, item_bias: true, center: true, add_implicit_features: false,
472
+ scale_lam: false, scale_lam_sideinfo: false, scale_bias_const: false,
347
473
  k_user: 0, k_item: 0, k_main: 0,
348
474
  w_main: 1.0, w_user: 1.0, w_item: 1.0, w_implicit: 0.5,
475
+ l1_lambda: 0.0, center_u: true, center_i: true,
349
476
  maxiter: 800, niter: 10, parallelize: "separate", corr_pairs: 4,
350
- max_cg_steps: 3, finalize_chol: true,
477
+ max_cg_steps: 3, precondition_cg: false, finalize_chol: true,
351
478
  na_as_zero: false, na_as_zero_user: false, na_as_zero_item: false,
352
479
  nonneg: false, nonneg_c: false, nonneg_d: false, max_cd_steps: 100,
353
480
  precompute_for_predictions: true, include_all_x: true,
354
- use_float: false,
355
- random_state: 1, verbose: true, print_every: 10,
356
- handle_interrupt: true, produce_dicts: false,
357
- copy_data: true, nthreads: -1
481
+ use_float: true, random_state: 1, verbose: true, print_every: 10,
482
+ handle_interrupt: true, produce_dicts: false, nthreads: -1
358
483
  )
359
-
360
484
  @k = k
361
485
  @k_user = k_user
362
486
  @k_item = k_item
@@ -392,9 +516,17 @@ module Cmfrec
392
516
  @random_state = random_state.to_i
393
517
  @produce_dicts = !!produce_dicts
394
518
  @handle_interrupt = !!handle_interrupt
395
- @copy_data = !!copy_data
396
519
  nthreads = Etc.nprocessors if nthreads < 0
397
520
  @nthreads = nthreads
521
+
522
+ @center = center
523
+ @scale_lam = scale_lam
524
+ @scale_lam_sideinfo = scale_lam_sideinfo
525
+ @scale_bias_const = scale_bias_const
526
+ @l1_lambda = l1_lambda
527
+ @precondition_cg = precondition_cg
528
+
529
+ # TODO center_u, center_i
398
530
  end
399
531
 
400
532
  def update_maps(train_set)
@@ -443,26 +575,47 @@ module Cmfrec
443
575
  end
444
576
  end
445
577
 
446
- def read_factors(ptr, d1, d2)
447
- arr = []
448
- offset = 0
578
+ def read_factors(ptr, d1, d2, id, map)
449
579
  width = d2 * Fiddle::SIZEOF_DOUBLE
450
- d1.times do |i|
451
- arr << ptr[offset, width].unpack("d*")
452
- offset += width
580
+ if id
581
+ i = map[id]
582
+ ptr[i * width, width].unpack("d*") if i
583
+ else
584
+ arr = []
585
+ offset = 0
586
+ d1.times do |i|
587
+ arr << ptr[offset, width].unpack("d*")
588
+ offset += width
589
+ end
590
+ arr
453
591
  end
454
- arr
455
592
  end
456
593
 
457
- def read_bias(ptr)
458
- real_array(ptr)
594
+ def read_bias(ptr, id, map)
595
+ if id
596
+ i = map[id]
597
+ ptr[i * Fiddle::SIZEOF_DOUBLE, Fiddle::SIZEOF_DOUBLE].unpack1("d") if i
598
+ else
599
+ real_array(ptr)
600
+ end
459
601
  end
460
602
 
461
- def top_n(a_vec:, a_bias:, count:, rated: nil)
462
- include_ix = nil
463
- n_include = 0
603
+ def prepare_top_n(count: nil, rated: nil, item_ids: nil)
604
+ if item_ids
605
+ # remove missing ids
606
+ item_ids = item_ids.map { |v| @item_map[v] }.compact
607
+ return [] if item_ids.empty?
608
+
609
+ include_ix = int_ptr(item_ids)
610
+ n_include = item_ids.size
464
611
 
465
- if rated
612
+ count = n_include if n_include < count
613
+ else
614
+ include_ix = nil
615
+ n_include = 0
616
+ end
617
+
618
+ if rated && !item_ids
466
619
  # assumes rated is unique and all items are known
467
620
  # calling code is responsible for this
468
621
  exclude_ix = int_ptr(rated)
@@ -478,145 +631,54 @@ module Cmfrec
478
631
  outp_ix = Fiddle::Pointer.malloc(count * Fiddle::SIZEOF_INT)
479
632
  outp_score = Fiddle::Pointer.malloc(count * Fiddle::SIZEOF_DOUBLE)
480
633
 
481
- check_status FFI.topN(
482
- a_vec, @k_user,
483
- @b, @k_item,
484
- @bias_b, @global_mean, a_bias,
485
- @k, @k_main,
486
- include_ix, n_include,
487
- exclude_ix, n_exclude,
488
- outp_ix, outp_score,
489
- count, @n,
490
- @nthreads
491
- )
492
-
493
- imap = @item_map.map(&:reverse).to_h
494
- item_ids = int_array(outp_ix).map { |v| imap[v] }
495
- scores = real_array(outp_score)
496
-
497
- item_ids.zip(scores).map do |item_id, score|
498
- {item_id: item_id, score: score}
499
- end
634
+ [include_ix, n_include, exclude_ix, n_exclude, outp_ix, outp_score, count]
500
635
  end
501
636
 
502
- def factors_warm(data, user_info: nil)
503
- data = to_dataset(data)
504
- user_info = to_dataset(user_info) if user_info
505
-
506
- # remove unknown items
507
- data, unknown_data = data.partition { |d| @item_map[d[:item_id]] }
508
-
509
- if unknown_data.any?
510
- # TODO warn for unknown items?
511
- # warn "[cmfrec] Unknown items: #{unknown_data.map { |d| d[:item_id] }.join(", ")}"
512
- end
513
-
514
- item_ids = data.map { |d| @item_map[d[:item_id]] }
515
-
516
- nnz = data.size
517
- a_vec = Fiddle::Pointer.malloc((@k_user + @k + @k_main) * Fiddle::SIZEOF_DOUBLE)
518
- bias_a = Fiddle::Pointer.malloc(Fiddle::SIZEOF_DOUBLE)
519
-
520
- u_vec_sp = []
521
- u_vec_x_col = []
522
- if user_info
523
- user_info.each do |k, v|
524
- next if k == :user_id
525
-
526
- uc = @user_info_map[k]
527
- raise "Bad key: #{k}" unless uc
528
-
529
- u_vec_x_col << uc
530
- u_vec_sp << v
531
- end
532
- end
533
- p_ = @user_info_map.size
534
- nnz_u_vec = u_vec_sp.size
535
- u_vec_x_col = int_ptr(u_vec_x_col)
536
- u_vec_sp = real_ptr(u_vec_sp)
537
-
538
- u_vec = nil
539
- u_bin_vec = nil
540
- pbin = 0
541
-
542
- weight = nil
543
- lam_unique = nil
544
- l1_lambda = 0
545
- l1_lam_unique = nil
546
- n_max = @n
547
-
548
- if data.any?
549
- if @implicit
550
- ratings = data.map { |d| d[:value] || 1 }
551
- else
552
- ratings = data.map { |d| d[:rating] }
553
- check_ratings(ratings)
554
- end
555
- xa = real_ptr(ratings)
556
- x_col = int_ptr(item_ids)
557
- else
558
- xa = nil
559
- x_col = nil
560
- end
561
- xa_dense = nil
637
+ def top_n(a_vec:, a_bias:, count:, rated: nil, item_ids: nil, row_index:)
638
+ prep = prepare_top_n(count: count, rated: rated, item_ids: item_ids)
639
+ return [] if prep.empty?
640
+ include_ix, n_include, exclude_ix, n_exclude, outp_ix, outp_score, count = prep
562
641
 
563
642
  if @implicit
564
- args = [
643
+ check_status FFI.topN_old_collective_implicit(
565
644
  a_vec,
566
- u_vec, p_,
567
- u_vec_sp, u_vec_x_col, nnz_u_vec,
568
- @na_as_zero_user,
569
- @nonneg,
570
- @u_colmeans,
571
- @b, @n, @c,
572
- xa, x_col, nnz,
645
+ @a, row_index,
646
+ @b,
573
647
  @k, @k_user, @k_item, @k_main,
574
- @lambda_, l1_lambda, @alpha,
575
- @w_main, @w_user, @w_main_multiplier,
576
- @apply_log_transf,
577
- nil, #BeTBe,
578
- nil, #BtB
579
- nil #BeTBeChol
580
- ]
581
- check_status FFI.factors_collective_implicit_single(*fiddle_args(args))
648
+ include_ix, n_include,
649
+ exclude_ix, n_exclude,
650
+ outp_ix, outp_score,
651
+ count, @n, @nthreads
652
+ )
582
653
  else
583
- cb = nil
584
-
585
- scale_lam = false
586
- scale_lam_sideinfo = false
587
-
588
- args = [
589
- a_vec, bias_a,
590
- u_vec, p_,
591
- u_vec_sp, u_vec_x_col, nnz_u_vec,
592
- u_bin_vec, pbin,
593
- @na_as_zero_user, @na_as_zero,
594
- @nonneg,
595
- @c, cb,
596
- @global_mean, @bias_b, @u_colmeans,
597
- xa, x_col, nnz, xa_dense,
598
- @n, weight, @b, @bi,
599
- @add_implicit_features,
654
+ # TODO add param
655
+ n_max = @n
656
+
657
+ check_status FFI.topN_old_collective_explicit(
658
+ a_vec, a_bias,
659
+ @a, @bias_a, row_index,
660
+ @b,
661
+ @bias_b,
662
+ @global_mean,
600
663
  @k, @k_user, @k_item, @k_main,
601
- @lambda_, lam_unique,
602
- l1_lambda, l1_lam_unique,
603
- scale_lam, scale_lam_sideinfo,
604
- @w_main, @w_user, @w_implicit,
605
- n_max,
606
- @include_all_x,
607
- nil, #BtB,
608
- nil, #TransBtBinvBt,
609
- nil, #BtXbias,
610
- nil, #BeTBeChol,
611
- nil, #BiTBi,
612
- nil, #CtCw,
613
- nil, #TransCtCinvCt,
614
- nil #B_plus_bias
615
- ]
616
- check_status FFI.factors_collective_explicit_single(*fiddle_args(args))
664
+ include_ix, n_include,
665
+ exclude_ix, n_exclude,
666
+ outp_ix, outp_score,
667
+ count, @n, n_max, @include_all_x ? 1 : 0, @nthreads
668
+ )
617
669
  end
618
670
 
619
- [a_vec, real_array(bias_a).first, item_ids.uniq]
671
+ top_n_output(outp_ix, outp_score)
672
+ end
673
+
674
+ def top_n_output(outp_ix, outp_score)
675
+ imap = @item_map.map(&:reverse).to_h
676
+ item_ids = int_array(outp_ix).map { |v| imap[v] }
677
+ scores = real_array(outp_score)
678
+
679
+ item_ids.zip(scores).map do |item_id, score|
680
+ {item_id: item_id, score: score}
681
+ end
620
682
  end
621
683
 
622
684
  # convert boolean to int
@@ -1,3 +1,3 @@
1
1
  module Cmfrec
2
- VERSION = "0.1.5"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/cmfrec.rb CHANGED
@@ -15,19 +15,19 @@ module Cmfrec
15
15
  class << self
16
16
  attr_accessor :ffi_lib
17
17
  end
18
- lib_name =
18
+ lib_path =
19
19
  if Gem.win_platform?
20
- "cmfrec.dll"
20
+ "x64-mingw/cmfrec.dll"
21
21
  elsif RbConfig::CONFIG["host_os"] =~ /darwin/i
22
- if RbConfig::CONFIG["host_cpu"] =~ /arm/i
23
- "libcmfrec.arm64.dylib"
22
+ if RbConfig::CONFIG["host_cpu"] =~ /arm|aarch64/i
23
+ "arm64-darwin/libcmfrec.dylib"
24
24
  else
25
- "libcmfrec.dylib"
25
+ "x86_64-darwin/libcmfrec.dylib"
26
26
  end
27
27
  else
28
- "libcmfrec.so"
28
+ "x86_64-linux/libcmfrec.so"
29
29
  end
30
- vendor_lib = File.expand_path("../vendor/#{lib_name}", __dir__)
30
+ vendor_lib = File.expand_path("../vendor/#{lib_path}", __dir__)
31
31
  self.ffi_lib = [vendor_lib]
32
32
 
33
33
  # friendlier error message
@@ -0,0 +1,57 @@
1
+ For the included LFBGS library (files "lbfgs.h", "lbfgs.c", "arithmetic_ansi.h"):
2
+
3
+ The MIT License
4
+
5
+ Copyright (c) 1990 Jorge Nocedal
6
+ Copyright (c) 2007-2010 Naoaki Okazaki
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a
9
+ copy of this software and associated documentation files (the "Software"),
10
+ to deal in the Software without restriction, including without limitation
11
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
+ and/or sell copies of the Software, and to permit persons to whom the
13
+ Software is furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ THE SOFTWARE.
25
+
26
+ For the included ziggurat tables (file "ziggurat.h"):
27
+
28
+ Copyright (c) 2005-2022, NumPy Developers.
29
+ All rights reserved.
30
+
31
+ Redistribution and use in source and binary forms, with or without
32
+ modification, are permitted provided that the following conditions are
33
+ met:
34
+
35
+ * Redistributions of source code must retain the above copyright
36
+ notice, this list of conditions and the following disclaimer.
37
+
38
+ * Redistributions in binary form must reproduce the above
39
+ copyright notice, this list of conditions and the following
40
+ disclaimer in the documentation and/or other materials provided
41
+ with the distribution.
42
+
43
+ * Neither the name of the NumPy Developers nor the names of any
44
+ contributors may be used to endorse or promote products derived
45
+ from this software without specific prior written permission.
46
+
47
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
48
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
49
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
50
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
51
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
57
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020-2022 David Cortes
4
+
5
+ All rights reserved.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to
9
+ deal in the Software without restriction, including without limitation the
10
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11
+ sell copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23
+ IN THE SOFTWARE.
Binary file
@@ -0,0 +1,57 @@
1
+ For the included LFBGS library (files "lbfgs.h", "lbfgs.c", "arithmetic_ansi.h"):
2
+
3
+ The MIT License
4
+
5
+ Copyright (c) 1990 Jorge Nocedal
6
+ Copyright (c) 2007-2010 Naoaki Okazaki
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a
9
+ copy of this software and associated documentation files (the "Software"),
10
+ to deal in the Software without restriction, including without limitation
11
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
+ and/or sell copies of the Software, and to permit persons to whom the
13
+ Software is furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ THE SOFTWARE.
25
+
26
+ For the included ziggurat tables (file "ziggurat.h"):
27
+
28
+ Copyright (c) 2005-2022, NumPy Developers.
29
+ All rights reserved.
30
+
31
+ Redistribution and use in source and binary forms, with or without
32
+ modification, are permitted provided that the following conditions are
33
+ met:
34
+
35
+ * Redistributions of source code must retain the above copyright
36
+ notice, this list of conditions and the following disclaimer.
37
+
38
+ * Redistributions in binary form must reproduce the above
39
+ copyright notice, this list of conditions and the following
40
+ disclaimer in the documentation and/or other materials provided
41
+ with the distribution.
42
+
43
+ * Neither the name of the NumPy Developers nor the names of any
44
+ contributors may be used to endorse or promote products derived
45
+ from this software without specific prior written permission.
46
+
47
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
48
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
49
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
50
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
51
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
57
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020-2022 David Cortes
4
+
5
+ All rights reserved.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to
9
+ deal in the Software without restriction, including without limitation the
10
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11
+ sell copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23
+ IN THE SOFTWARE.
@@ -0,0 +1,57 @@
1
+ For the included LFBGS library (files "lbfgs.h", "lbfgs.c", "arithmetic_ansi.h"):
2
+
3
+ The MIT License
4
+
5
+ Copyright (c) 1990 Jorge Nocedal
6
+ Copyright (c) 2007-2010 Naoaki Okazaki
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a
9
+ copy of this software and associated documentation files (the "Software"),
10
+ to deal in the Software without restriction, including without limitation
11
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
+ and/or sell copies of the Software, and to permit persons to whom the
13
+ Software is furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ THE SOFTWARE.
25
+
26
+ For the included ziggurat tables (file "ziggurat.h"):
27
+
28
+ Copyright (c) 2005-2022, NumPy Developers.
29
+ All rights reserved.
30
+
31
+ Redistribution and use in source and binary forms, with or without
32
+ modification, are permitted provided that the following conditions are
33
+ met:
34
+
35
+ * Redistributions of source code must retain the above copyright
36
+ notice, this list of conditions and the following disclaimer.
37
+
38
+ * Redistributions in binary form must reproduce the above
39
+ copyright notice, this list of conditions and the following
40
+ disclaimer in the documentation and/or other materials provided
41
+ with the distribution.
42
+
43
+ * Neither the name of the NumPy Developers nor the names of any
44
+ contributors may be used to endorse or promote products derived
45
+ from this software without specific prior written permission.
46
+
47
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
48
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
49
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
50
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
51
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
57
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020-2022 David Cortes
4
+
5
+ All rights reserved.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to
9
+ deal in the Software without restriction, including without limitation the
10
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11
+ sell copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23
+ IN THE SOFTWARE.
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmfrec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
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-08-11 00:00:00.000000000 Z
11
+ date: 2022-06-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: andrew@ankane.org
@@ -24,11 +24,16 @@ files:
24
24
  - lib/cmfrec/ffi.rb
25
25
  - lib/cmfrec/recommender.rb
26
26
  - lib/cmfrec/version.rb
27
- - vendor/LICENSE.txt
28
- - vendor/libcmfrec.arm64.dylib
29
- - vendor/libcmfrec.dylib
30
- - vendor/libcmfrec.so
31
- homepage: https://github.com/ankane/cmfrec
27
+ - vendor/arm64-darwin/COPYRIGHTS
28
+ - vendor/arm64-darwin/LICENSE
29
+ - vendor/arm64-darwin/libcmfrec.dylib
30
+ - vendor/x86_64-darwin/COPYRIGHTS
31
+ - vendor/x86_64-darwin/LICENSE
32
+ - vendor/x86_64-darwin/libcmfrec.dylib
33
+ - vendor/x86_64-linux/COPYRIGHTS
34
+ - vendor/x86_64-linux/LICENSE
35
+ - vendor/x86_64-linux/libcmfrec.so
36
+ homepage: https://github.com/ankane/cmfrec-ruby
32
37
  licenses:
33
38
  - MIT
34
39
  metadata: {}
@@ -40,14 +45,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
40
45
  requirements:
41
46
  - - ">="
42
47
  - !ruby/object:Gem::Version
43
- version: '2.5'
48
+ version: '2.7'
44
49
  required_rubygems_version: !ruby/object:Gem::Requirement
45
50
  requirements:
46
51
  - - ">="
47
52
  - !ruby/object:Gem::Version
48
53
  version: '0'
49
54
  requirements: []
50
- rubygems_version: 3.2.22
55
+ rubygems_version: 3.3.7
51
56
  signing_key:
52
57
  specification_version: 4
53
58
  summary: Recommendations for Ruby using collective matrix factorization
data/vendor/LICENSE.txt DELETED
@@ -1,74 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2020 David Cortes
4
-
5
- All rights reserved.
6
-
7
- Permission is hereby granted, free of charge, to any person obtaining a copy
8
- of this software and associated documentation files (the "Software"), to
9
- deal in the Software without restriction, including without limitation the
10
- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11
- sell copies of the Software, and to permit persons to whom the Software is
12
- furnished to do so, subject to the following conditions:
13
-
14
- The above copyright notice and this permission notice shall be included in
15
- all copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23
- IN THE SOFTWARE.
24
-
25
- ---
26
-
27
- ANSI C implementation of vector operations.
28
-
29
- Copyright (c) 2007-2010 Naoaki Okazaki
30
- All rights reserved.
31
-
32
- Permission is hereby granted, free of charge, to any person obtaining a copy
33
- of this software and associated documentation files (the "Software"), to deal
34
- in the Software without restriction, including without limitation the rights
35
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36
- copies of the Software, and to permit persons to whom the Software is
37
- furnished to do so, subject to the following conditions:
38
-
39
- The above copyright notice and this permission notice shall be included in
40
- all copies or substantial portions of the Software.
41
-
42
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48
- THE SOFTWARE.
49
-
50
- ---
51
-
52
- C library of Limited memory BFGS (L-BFGS).
53
-
54
- Copyright (c) 1990, Jorge Nocedal
55
- Copyright (c) 2007-2010 Naoaki Okazaki
56
- All rights reserved.
57
-
58
- Permission is hereby granted, free of charge, to any person obtaining a copy
59
- of this software and associated documentation files (the "Software"), to deal
60
- in the Software without restriction, including without limitation the rights
61
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
62
- copies of the Software, and to permit persons to whom the Software is
63
- furnished to do so, subject to the following conditions:
64
-
65
- The above copyright notice and this permission notice shall be included in
66
- all copies or substantial portions of the Software.
67
-
68
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
69
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
70
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
71
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
72
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
73
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
74
- THE SOFTWARE.
Binary file
Binary file
data/vendor/libcmfrec.so DELETED
Binary file