cmfrec 0.1.6 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![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
|
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
|