cmfrec 0.1.6 → 0.2.1
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 +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +21 -23
- data/lib/cmfrec/data.rb +12 -7
- data/lib/cmfrec/ffi.rb +8 -7
- data/lib/cmfrec/recommender.rb +329 -156
- data/lib/cmfrec/version.rb +1 -1
- data/lib/cmfrec.rb +7 -7
- data/vendor/arm64-darwin/COPYRIGHTS +57 -0
- data/vendor/arm64-darwin/LICENSE +23 -0
- data/vendor/arm64-darwin/libcmfrec.dylib +0 -0
- data/vendor/x86_64-darwin/COPYRIGHTS +57 -0
- data/vendor/x86_64-darwin/LICENSE +23 -0
- data/vendor/x86_64-darwin/libcmfrec.dylib +0 -0
- data/vendor/x86_64-linux/COPYRIGHTS +57 -0
- data/vendor/x86_64-linux/LICENSE +23 -0
- data/vendor/x86_64-linux/libcmfrec.so +0 -0
- metadata +14 -9
- data/vendor/LICENSE.txt +0 -74
- data/vendor/libcmfrec.arm64.dylib +0 -0
- data/vendor/libcmfrec.dylib +0 -0
- data/vendor/libcmfrec.so +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3bd946bc2c7425ba3550a9cd5bf346b0cac6de5597d0d38ff0dfb49db32e754d
|
4
|
+
data.tar.gz: 20038dc0c401389d75dc3a35415919f6721dab7e32459eeb34c9dcb23569c49a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d0019e89fe0ca946cd83d60c052bff2e3dcc3990e3bf37de92b620870b6bf8a31010aec87bb2e5a352c446441b683f0148da83497b5d44ef89d62396f4b7d3c
|
7
|
+
data.tar.gz: f4d65f294b9a313c2c86111eaf66e734999924392fedc4715c51919a4ca4de3864ba3eec732f3d707dd06ea62ddb931d9b28b8436a09a807c01e14ac2c542e44
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
## 0.2.1 (2022-07-11)
|
2
|
+
|
3
|
+
- Added support for JSON serialization
|
4
|
+
|
5
|
+
## 0.2.0 (2022-06-14)
|
6
|
+
|
7
|
+
- Updated cmfrec to 3.4.2
|
8
|
+
- Fixed missing item ids with `load_movielens`
|
9
|
+
- Dropped support for Ruby < 2.7
|
10
|
+
|
11
|
+
## 0.1.7 (2022-03-22)
|
12
|
+
|
13
|
+
- Improved ARM detection
|
14
|
+
- Fixed error with `load_movielens`
|
15
|
+
- Fixed duplicates in `item_info` with `load_movielens`
|
16
|
+
|
1
17
|
## 0.1.6 (2021-08-12)
|
2
18
|
|
3
19
|
- Added `user_ids` and `item_ids` methods
|
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
|
-
[](https://github.com/ankane/cmfrec/actions)
|
9
|
+
[](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
|
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,
|
62
|
-
{item_id: 2,
|
61
|
+
{item_id: 1, rating: 5},
|
62
|
+
{item_id: 2, rating: 3}
|
63
63
|
])
|
64
64
|
```
|
65
65
|
|
@@ -82,11 +82,11 @@ Add side information about users, items, or both
|
|
82
82
|
```ruby
|
83
83
|
user_info = [
|
84
84
|
{user_id: 1, cats: 1, dogs: 0},
|
85
|
-
{user_id: 2, cats: 2, dogs: 1}
|
85
|
+
{user_id: 2, cats: 2, dogs: 1}
|
86
86
|
]
|
87
87
|
item_info = [
|
88
88
|
{item_id: 1, genre_comedy: 1, genre_drama: 0},
|
89
|
-
{item_id: 2, genre_comedy: 0, genre_drama: 1}
|
89
|
+
{item_id: 2, genre_comedy: 0, genre_drama: 1}
|
90
90
|
]
|
91
91
|
recommender.fit(ratings, user_info: user_info, item_info: item_info)
|
92
92
|
```
|
@@ -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
|
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|
|
@@ -217,19 +213,21 @@ Rover.read_csv("ratings.csv")
|
|
217
213
|
Store the recommender
|
218
214
|
|
219
215
|
```ruby
|
220
|
-
|
221
|
-
File.
|
216
|
+
json = recommender.to_json
|
217
|
+
File.write("recommender.json", json)
|
222
218
|
```
|
223
219
|
|
224
|
-
|
220
|
+
The serialized recommender includes user activity from the training data (to avoid recommending previously rated items), so be sure to protect it. You can save it to a file, database, or any other storage system, or use a tool like [Trove](https://github.com/ankane/trove). Also, user and item IDs should be integers or strings for this.
|
225
221
|
|
226
222
|
Load a recommender
|
227
223
|
|
228
224
|
```ruby
|
229
|
-
|
230
|
-
recommender =
|
225
|
+
json = File.read("recommender.json")
|
226
|
+
recommender = Cmfrec::Recommender.load_json(json)
|
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
|
|
235
233
|
Get ids
|
@@ -269,22 +267,22 @@ Cmfrec.ffi_lib = "path/to/cmfrec.dll"
|
|
269
267
|
|
270
268
|
## History
|
271
269
|
|
272
|
-
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)
|
273
271
|
|
274
272
|
## Contributing
|
275
273
|
|
276
274
|
Everyone is encouraged to help improve this project. Here are a few ways you can help:
|
277
275
|
|
278
|
-
- [Report bugs](https://github.com/ankane/cmfrec/issues)
|
279
|
-
- 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)
|
280
278
|
- Write, clarify, or fix documentation
|
281
279
|
- Suggest or add new features
|
282
280
|
|
283
281
|
To get started with development:
|
284
282
|
|
285
283
|
```sh
|
286
|
-
git clone https://github.com/ankane/cmfrec.git
|
287
|
-
cd cmfrec
|
284
|
+
git clone https://github.com/ankane/cmfrec-ruby.git
|
285
|
+
cd cmfrec-ruby
|
288
286
|
bundle install
|
289
287
|
bundle exec rake vendor:all
|
290
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", "
|
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", "
|
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", "
|
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,
|
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,
|
22
|
-
extern "int_t
|
23
|
-
extern "int_t
|
24
|
-
extern "int_t
|
25
|
-
extern "int_t
|
26
|
-
extern "int_t
|
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
|
data/lib/cmfrec/recommender.rb
CHANGED
@@ -70,7 +70,7 @@ module Cmfrec
|
|
70
70
|
a_vec = @a[user * @k * Fiddle::SIZEOF_DOUBLE, @k * Fiddle::SIZEOF_DOUBLE]
|
71
71
|
a_bias = @bias_a ? @bias_a[user * Fiddle::SIZEOF_DOUBLE, Fiddle::SIZEOF_DOUBLE].unpack1("d") : 0
|
72
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)
|
73
|
+
top_n(a_vec: a_vec, a_bias: a_bias, count: count, rated: (@rated[user] || {}).keys, item_ids: item_ids, row_index: user)
|
74
74
|
else
|
75
75
|
# no items if user is unknown
|
76
76
|
# TODO maybe most popular items
|
@@ -81,8 +81,137 @@ module Cmfrec
|
|
81
81
|
def new_user_recs(data, count: 5, user_info: nil, item_ids: nil)
|
82
82
|
check_fit
|
83
83
|
|
84
|
-
|
85
|
-
|
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)
|
86
215
|
end
|
87
216
|
|
88
217
|
def user_ids
|
@@ -120,6 +249,68 @@ module Cmfrec
|
|
120
249
|
similar(user_id, @user_map, user_factors, count, user_index)
|
121
250
|
end
|
122
251
|
|
252
|
+
def to_json
|
253
|
+
require "base64"
|
254
|
+
require "json"
|
255
|
+
|
256
|
+
obj = {
|
257
|
+
implicit: @implicit
|
258
|
+
}
|
259
|
+
|
260
|
+
# options
|
261
|
+
obj[:factors] = @k
|
262
|
+
obj[:epochs] = @niter
|
263
|
+
obj[:verbose] = @verbose
|
264
|
+
|
265
|
+
# factors
|
266
|
+
obj[:user_ids] = @user_map.keys
|
267
|
+
obj[:item_ids] = @item_map.keys
|
268
|
+
obj[:rated] = @user_map.map { |_, u| (@rated[u] || {}).keys }
|
269
|
+
obj[:user_factors] = json_dump_ptr(@a)
|
270
|
+
obj[:item_factors] = json_dump_ptr(@b)
|
271
|
+
|
272
|
+
# bias
|
273
|
+
obj[:user_bias] = json_dump_ptr(@bias_a)
|
274
|
+
obj[:item_bias] = json_dump_ptr(@bias_b)
|
275
|
+
|
276
|
+
# mean
|
277
|
+
obj[:global_mean] = @global_mean
|
278
|
+
|
279
|
+
unless (@user_info_map.keys + @item_info_map.keys).all? { |v| v.is_a?(Symbol) }
|
280
|
+
raise "Side info keys must be symbols to save"
|
281
|
+
end
|
282
|
+
|
283
|
+
# side info
|
284
|
+
obj[:user_info_ids] = @user_info_map.keys
|
285
|
+
obj[:item_info_ids] = @item_info_map.keys
|
286
|
+
obj[:user_info_factors] = json_dump_ptr(@c)
|
287
|
+
obj[:item_info_factors] = json_dump_ptr(@d)
|
288
|
+
|
289
|
+
# implicit features
|
290
|
+
obj[:add_implicit_features] = @add_implicit_features
|
291
|
+
obj[:user_factors_implicit] = json_dump_ptr(@ai)
|
292
|
+
obj[:item_factors_implicit] = json_dump_ptr(@bi)
|
293
|
+
|
294
|
+
unless @implicit
|
295
|
+
obj[:min_rating] = @min_rating
|
296
|
+
obj[:max_rating] = @max_rating
|
297
|
+
end
|
298
|
+
|
299
|
+
obj[:user_means] = json_dump_ptr(@u_colmeans)
|
300
|
+
|
301
|
+
JSON.generate(obj)
|
302
|
+
end
|
303
|
+
|
304
|
+
def self.load_json(json)
|
305
|
+
require "json"
|
306
|
+
|
307
|
+
obj = JSON.parse(json)
|
308
|
+
|
309
|
+
recommender = new
|
310
|
+
recommender.send(:json_load, obj)
|
311
|
+
recommender
|
312
|
+
end
|
313
|
+
|
123
314
|
private
|
124
315
|
|
125
316
|
def user_index
|
@@ -210,7 +401,6 @@ module Cmfrec
|
|
210
401
|
x_full = nil
|
211
402
|
weight = nil
|
212
403
|
lam_unique = nil
|
213
|
-
l1_lambda = 0
|
214
404
|
l1_lam_unique = nil
|
215
405
|
|
216
406
|
uu = nil
|
@@ -247,7 +437,7 @@ module Cmfrec
|
|
247
437
|
@m, @n, @k,
|
248
438
|
x_row, x_col, x, nnz,
|
249
439
|
@lambda_, lam_unique,
|
250
|
-
l1_lambda, l1_lam_unique,
|
440
|
+
@l1_lambda, l1_lam_unique,
|
251
441
|
uu, @m_u, p_,
|
252
442
|
ii, @n_i, q,
|
253
443
|
u_row, u_col, u_sp, nnz_u,
|
@@ -257,12 +447,13 @@ module Cmfrec
|
|
257
447
|
@w_main, @w_user, @w_item, real_ptr([@w_main_multiplier]),
|
258
448
|
@alpha, @adjust_weight, @apply_log_transf,
|
259
449
|
@niter, @nthreads, @verbose, @handle_interrupt,
|
260
|
-
@use_cg, @max_cg_steps, @finalize_chol,
|
450
|
+
@use_cg, @max_cg_steps, @precondition_cg, @finalize_chol,
|
261
451
|
@nonneg, @max_cd_steps, @nonneg_c, @nonneg_d,
|
262
452
|
@precompute_for_predictions,
|
263
453
|
nil, #precomputedBtB,
|
264
454
|
nil, #precomputedBeTBe,
|
265
|
-
nil
|
455
|
+
nil, #precomputedBeTBeChol
|
456
|
+
nil #precomputedCtUbias
|
266
457
|
]
|
267
458
|
check_status FFI.fit_collective_implicit_als(*fiddle_args(args))
|
268
459
|
|
@@ -281,9 +472,9 @@ module Cmfrec
|
|
281
472
|
|
282
473
|
glob_mean = Fiddle::Pointer.malloc(Fiddle::SIZEOF_DOUBLE)
|
283
474
|
|
284
|
-
|
285
|
-
|
286
|
-
|
475
|
+
# TODO add
|
476
|
+
scaling_bias_a = nil
|
477
|
+
scaling_bias_b = nil
|
287
478
|
|
288
479
|
args = [
|
289
480
|
@bias_a, @bias_b,
|
@@ -298,10 +489,11 @@ module Cmfrec
|
|
298
489
|
x_row, x_col, x, nnz,
|
299
490
|
x_full,
|
300
491
|
weight,
|
301
|
-
@user_bias, @item_bias, center,
|
492
|
+
@user_bias, @item_bias, @center,
|
302
493
|
@lambda_, lam_unique,
|
303
|
-
l1_lambda, l1_lam_unique,
|
304
|
-
scale_lam, scale_lam_sideinfo,
|
494
|
+
@l1_lambda, l1_lam_unique,
|
495
|
+
@scale_lam, @scale_lam_sideinfo,
|
496
|
+
@scale_bias_const, scaling_bias_a, scaling_bias_b,
|
305
497
|
uu, @m_u, p_,
|
306
498
|
ii, @n_i, q,
|
307
499
|
u_row, u_col, u_sp, nnz_u,
|
@@ -310,7 +502,7 @@ module Cmfrec
|
|
310
502
|
@k_main, @k_user, @k_item,
|
311
503
|
@w_main, @w_user, @w_item, @w_implicit,
|
312
504
|
@niter, @nthreads, @verbose, @handle_interrupt,
|
313
|
-
@use_cg, @max_cg_steps, @finalize_chol,
|
505
|
+
@use_cg, @max_cg_steps, @precondition_cg, @finalize_chol,
|
314
506
|
@nonneg, @max_cd_steps, @nonneg_c, @nonneg_d,
|
315
507
|
@precompute_for_predictions,
|
316
508
|
@include_all_x,
|
@@ -321,7 +513,8 @@ module Cmfrec
|
|
321
513
|
nil, #precomputedBeTBeChol,
|
322
514
|
nil, #precomputedBiTBi,
|
323
515
|
nil, #precomputedTransCtCinvCt,
|
324
|
-
nil
|
516
|
+
nil, #precomputedCtCw
|
517
|
+
nil, #precomputedCtUbias
|
325
518
|
]
|
326
519
|
check_status FFI.fit_collective_explicit_als(*fiddle_args(args))
|
327
520
|
|
@@ -336,21 +529,20 @@ module Cmfrec
|
|
336
529
|
end
|
337
530
|
|
338
531
|
def set_params(
|
339
|
-
k: 40, lambda_:
|
340
|
-
item_bias: true, add_implicit_features: false,
|
532
|
+
k: 40, lambda_: 10.0, method: "als", use_cg: true,
|
533
|
+
user_bias: true, item_bias: true, center: true, add_implicit_features: false,
|
534
|
+
scale_lam: false, scale_lam_sideinfo: false, scale_bias_const: false,
|
341
535
|
k_user: 0, k_item: 0, k_main: 0,
|
342
536
|
w_main: 1.0, w_user: 1.0, w_item: 1.0, w_implicit: 0.5,
|
537
|
+
l1_lambda: 0.0, center_u: true, center_i: true,
|
343
538
|
maxiter: 800, niter: 10, parallelize: "separate", corr_pairs: 4,
|
344
|
-
max_cg_steps: 3, finalize_chol: true,
|
539
|
+
max_cg_steps: 3, precondition_cg: false, finalize_chol: true,
|
345
540
|
na_as_zero: false, na_as_zero_user: false, na_as_zero_item: false,
|
346
541
|
nonneg: false, nonneg_c: false, nonneg_d: false, max_cd_steps: 100,
|
347
542
|
precompute_for_predictions: true, include_all_x: true,
|
348
|
-
use_float:
|
349
|
-
|
350
|
-
handle_interrupt: true, produce_dicts: false,
|
351
|
-
copy_data: true, nthreads: -1
|
543
|
+
use_float: true, random_state: 1, verbose: true, print_every: 10,
|
544
|
+
handle_interrupt: true, produce_dicts: false, nthreads: -1
|
352
545
|
)
|
353
|
-
|
354
546
|
@k = k
|
355
547
|
@k_user = k_user
|
356
548
|
@k_item = k_item
|
@@ -386,9 +578,17 @@ module Cmfrec
|
|
386
578
|
@random_state = random_state.to_i
|
387
579
|
@produce_dicts = !!produce_dicts
|
388
580
|
@handle_interrupt = !!handle_interrupt
|
389
|
-
@copy_data = !!copy_data
|
390
581
|
nthreads = Etc.nprocessors if nthreads < 0
|
391
582
|
@nthreads = nthreads
|
583
|
+
|
584
|
+
@center = center
|
585
|
+
@scale_lam = scale_lam
|
586
|
+
@scale_lam_sideinfo = scale_lam_sideinfo
|
587
|
+
@scale_bias_const = scale_bias_const
|
588
|
+
@l1_lambda = l1_lambda
|
589
|
+
@precondition_cg = precondition_cg
|
590
|
+
|
591
|
+
# TODO center_u, center_i
|
392
592
|
end
|
393
593
|
|
394
594
|
def update_maps(train_set)
|
@@ -462,7 +662,7 @@ module Cmfrec
|
|
462
662
|
end
|
463
663
|
end
|
464
664
|
|
465
|
-
def
|
665
|
+
def prepare_top_n(count: nil, rated: nil, item_ids: nil)
|
466
666
|
if item_ids
|
467
667
|
# remove missing ids
|
468
668
|
item_ids = item_ids.map { |v| @item_map[v] }.compact
|
@@ -471,8 +671,7 @@ module Cmfrec
|
|
471
671
|
include_ix = int_ptr(item_ids)
|
472
672
|
n_include = item_ids.size
|
473
673
|
|
474
|
-
|
475
|
-
count = n_include # if n_include < count
|
674
|
+
count = n_include if n_include < count
|
476
675
|
else
|
477
676
|
include_ix = nil
|
478
677
|
n_include = 0
|
@@ -494,145 +693,54 @@ module Cmfrec
|
|
494
693
|
outp_ix = Fiddle::Pointer.malloc(count * Fiddle::SIZEOF_INT)
|
495
694
|
outp_score = Fiddle::Pointer.malloc(count * Fiddle::SIZEOF_DOUBLE)
|
496
695
|
|
497
|
-
|
498
|
-
a_vec, @k_user,
|
499
|
-
@b, @k_item,
|
500
|
-
@bias_b, @global_mean, a_bias,
|
501
|
-
@k, @k_main,
|
502
|
-
include_ix, n_include,
|
503
|
-
exclude_ix, n_exclude,
|
504
|
-
outp_ix, outp_score,
|
505
|
-
count, @n,
|
506
|
-
@nthreads
|
507
|
-
)
|
508
|
-
|
509
|
-
imap = @item_map.map(&:reverse).to_h
|
510
|
-
item_ids = int_array(outp_ix).map { |v| imap[v] }
|
511
|
-
scores = real_array(outp_score)
|
512
|
-
|
513
|
-
item_ids.zip(scores).map do |item_id, score|
|
514
|
-
{item_id: item_id, score: score}
|
515
|
-
end
|
696
|
+
[include_ix, n_include, exclude_ix, n_exclude, outp_ix, outp_score, count]
|
516
697
|
end
|
517
698
|
|
518
|
-
def
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
# remove unknown items
|
523
|
-
data, unknown_data = data.partition { |d| @item_map[d[:item_id]] }
|
524
|
-
|
525
|
-
if unknown_data.any?
|
526
|
-
# TODO warn for unknown items?
|
527
|
-
# warn "[cmfrec] Unknown items: #{unknown_data.map { |d| d[:item_id] }.join(", ")}"
|
528
|
-
end
|
529
|
-
|
530
|
-
item_ids = data.map { |d| @item_map[d[:item_id]] }
|
531
|
-
|
532
|
-
nnz = data.size
|
533
|
-
a_vec = Fiddle::Pointer.malloc((@k_user + @k + @k_main) * Fiddle::SIZEOF_DOUBLE)
|
534
|
-
bias_a = Fiddle::Pointer.malloc(Fiddle::SIZEOF_DOUBLE)
|
535
|
-
|
536
|
-
u_vec_sp = []
|
537
|
-
u_vec_x_col = []
|
538
|
-
if user_info
|
539
|
-
user_info.each do |k, v|
|
540
|
-
next if k == :user_id
|
541
|
-
|
542
|
-
uc = @user_info_map[k]
|
543
|
-
raise "Bad key: #{k}" unless uc
|
544
|
-
|
545
|
-
u_vec_x_col << uc
|
546
|
-
u_vec_sp << v
|
547
|
-
end
|
548
|
-
end
|
549
|
-
p_ = @user_info_map.size
|
550
|
-
nnz_u_vec = u_vec_sp.size
|
551
|
-
u_vec_x_col = int_ptr(u_vec_x_col)
|
552
|
-
u_vec_sp = real_ptr(u_vec_sp)
|
553
|
-
|
554
|
-
u_vec = nil
|
555
|
-
u_bin_vec = nil
|
556
|
-
pbin = 0
|
557
|
-
|
558
|
-
weight = nil
|
559
|
-
lam_unique = nil
|
560
|
-
l1_lambda = 0
|
561
|
-
l1_lam_unique = nil
|
562
|
-
n_max = @n
|
563
|
-
|
564
|
-
if data.any?
|
565
|
-
if @implicit
|
566
|
-
ratings = data.map { |d| d[:value] || 1 }
|
567
|
-
else
|
568
|
-
ratings = data.map { |d| d[:rating] }
|
569
|
-
check_ratings(ratings)
|
570
|
-
end
|
571
|
-
xa = real_ptr(ratings)
|
572
|
-
x_col = int_ptr(item_ids)
|
573
|
-
else
|
574
|
-
xa = nil
|
575
|
-
x_col = nil
|
576
|
-
end
|
577
|
-
xa_dense = nil
|
699
|
+
def top_n(a_vec:, a_bias:, count:, rated: nil, item_ids: nil, row_index:)
|
700
|
+
prep = prepare_top_n(count: count, rated: rated, item_ids: item_ids)
|
701
|
+
return [] if prep.empty?
|
702
|
+
include_ix, n_include, exclude_ix, n_exclude, outp_ix, outp_score, count = prep
|
578
703
|
|
579
704
|
if @implicit
|
580
|
-
|
705
|
+
check_status FFI.topN_old_collective_implicit(
|
581
706
|
a_vec,
|
582
|
-
|
583
|
-
|
584
|
-
@na_as_zero_user,
|
585
|
-
@nonneg,
|
586
|
-
@u_colmeans,
|
587
|
-
@b, @n, @c,
|
588
|
-
xa, x_col, nnz,
|
707
|
+
@a, row_index,
|
708
|
+
@b,
|
589
709
|
@k, @k_user, @k_item, @k_main,
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
nil #BeTBeChol
|
596
|
-
]
|
597
|
-
check_status FFI.factors_collective_implicit_single(*fiddle_args(args))
|
710
|
+
include_ix, n_include,
|
711
|
+
exclude_ix, n_exclude,
|
712
|
+
outp_ix, outp_score,
|
713
|
+
count, @n, @nthreads
|
714
|
+
)
|
598
715
|
else
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
u_bin_vec, pbin,
|
609
|
-
@na_as_zero_user, @na_as_zero,
|
610
|
-
@nonneg,
|
611
|
-
@c, cb,
|
612
|
-
@global_mean, @bias_b, @u_colmeans,
|
613
|
-
xa, x_col, nnz, xa_dense,
|
614
|
-
@n, weight, @b, @bi,
|
615
|
-
@add_implicit_features,
|
716
|
+
# TODO add param
|
717
|
+
n_max = @n
|
718
|
+
|
719
|
+
check_status FFI.topN_old_collective_explicit(
|
720
|
+
a_vec, a_bias,
|
721
|
+
@a, @bias_a, row_index,
|
722
|
+
@b,
|
723
|
+
@bias_b,
|
724
|
+
@global_mean,
|
616
725
|
@k, @k_user, @k_item, @k_main,
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
@
|
621
|
-
|
622
|
-
@include_all_x,
|
623
|
-
nil, #BtB,
|
624
|
-
nil, #TransBtBinvBt,
|
625
|
-
nil, #BtXbias,
|
626
|
-
nil, #BeTBeChol,
|
627
|
-
nil, #BiTBi,
|
628
|
-
nil, #CtCw,
|
629
|
-
nil, #TransCtCinvCt,
|
630
|
-
nil #B_plus_bias
|
631
|
-
]
|
632
|
-
check_status FFI.factors_collective_explicit_single(*fiddle_args(args))
|
726
|
+
include_ix, n_include,
|
727
|
+
exclude_ix, n_exclude,
|
728
|
+
outp_ix, outp_score,
|
729
|
+
count, @n, n_max, @include_all_x ? 1 : 0, @nthreads
|
730
|
+
)
|
633
731
|
end
|
634
732
|
|
635
|
-
|
733
|
+
top_n_output(outp_ix, outp_score)
|
734
|
+
end
|
735
|
+
|
736
|
+
def top_n_output(outp_ix, outp_score)
|
737
|
+
imap = @item_map.map(&:reverse).to_h
|
738
|
+
item_ids = int_array(outp_ix).map { |v| imap[v] }
|
739
|
+
scores = real_array(outp_score)
|
740
|
+
|
741
|
+
item_ids.zip(scores).map do |item_id, score|
|
742
|
+
{item_id: item_id, score: score}
|
743
|
+
end
|
636
744
|
end
|
637
745
|
|
638
746
|
# convert boolean to int
|
@@ -810,5 +918,70 @@ module Cmfrec
|
|
810
918
|
|
811
919
|
@fit = @m > 0
|
812
920
|
end
|
921
|
+
|
922
|
+
def json_dump_ptr(ptr)
|
923
|
+
Base64.strict_encode64(ptr.to_s(ptr.size)) if ptr
|
924
|
+
end
|
925
|
+
|
926
|
+
def json_load_ptr(str)
|
927
|
+
Fiddle::Pointer[Base64.strict_decode64(str)] if str
|
928
|
+
end
|
929
|
+
|
930
|
+
def json_load(obj)
|
931
|
+
require "base64"
|
932
|
+
|
933
|
+
@implicit = obj["implicit"]
|
934
|
+
|
935
|
+
# options
|
936
|
+
set_params(
|
937
|
+
k: obj["factors"],
|
938
|
+
niter: obj["epochs"],
|
939
|
+
verbose: obj["verbose"],
|
940
|
+
user_bias: !obj["user_bias"].nil?,
|
941
|
+
item_bias: !obj["item_bias"].nil?,
|
942
|
+
add_implicit_features: obj["add_implicit_features"]
|
943
|
+
)
|
944
|
+
|
945
|
+
# factors
|
946
|
+
@user_map = obj["user_ids"].map.with_index.to_h
|
947
|
+
@item_map = obj["item_ids"].map.with_index.to_h
|
948
|
+
@rated = obj["rated"].map.with_index.to_h { |r, i| [i, r.to_h { |v| [v, true] }] }
|
949
|
+
@a = json_load_ptr(obj["user_factors"])
|
950
|
+
@b = json_load_ptr(obj["item_factors"])
|
951
|
+
|
952
|
+
# bias
|
953
|
+
@bias_a = json_load_ptr(obj["user_bias"])
|
954
|
+
@bias_b = json_load_ptr(obj["item_bias"])
|
955
|
+
|
956
|
+
# mean
|
957
|
+
@global_mean = obj["global_mean"]
|
958
|
+
|
959
|
+
# side info
|
960
|
+
@user_info_map = obj["user_info_ids"].map(&:to_sym).map.with_index.to_h
|
961
|
+
@item_info_map = obj["item_info_ids"].map(&:to_sym).map.with_index.to_h
|
962
|
+
@c = json_load_ptr(obj["user_info_factors"])
|
963
|
+
@d = json_load_ptr(obj["item_info_factors"])
|
964
|
+
|
965
|
+
# implicit features
|
966
|
+
@add_implicit_features = obj["add_implicit_features"]
|
967
|
+
@ai = json_load_ptr(obj["user_factors_implicit"])
|
968
|
+
@bi = json_load_ptr(obj["item_factors_implicit"])
|
969
|
+
|
970
|
+
unless @implicit
|
971
|
+
@min_rating = obj["min_rating"]
|
972
|
+
@max_rating = obj["max_rating"]
|
973
|
+
end
|
974
|
+
|
975
|
+
@u_colmeans = json_load_ptr(obj["user_means"])
|
976
|
+
|
977
|
+
@m = @user_map.size
|
978
|
+
@n = @item_map.size
|
979
|
+
@m_u = @user_info_map.size
|
980
|
+
@n_i = @item_info_map.size
|
981
|
+
|
982
|
+
set_implicit_vars if @implicit
|
983
|
+
|
984
|
+
@fit = @m > 0
|
985
|
+
end
|
813
986
|
end
|
814
987
|
end
|
data/lib/cmfrec/version.rb
CHANGED
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
|
-
|
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.
|
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/#{
|
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.
|
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.
|
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
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-11 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/
|
28
|
-
- vendor/
|
29
|
-
- vendor/libcmfrec.dylib
|
30
|
-
- vendor/
|
31
|
-
|
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.
|
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.
|
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
|
data/vendor/libcmfrec.dylib
DELETED
Binary file
|
data/vendor/libcmfrec.so
DELETED
Binary file
|