cmfrec 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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