libffm 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc1d79899f98f45cbcfab6278aae23893c8304fbe2fae308a842e4ccb14a1d77
4
- data.tar.gz: d908f0576dc9090db280627a45574547b05ebec82ccc43f15b1fca8e54f86044
3
+ metadata.gz: 07323e72497473a0d74016a0f038bf20e3630975d209ff7f5ba35735d4950c70
4
+ data.tar.gz: 28723358a87d007aff3ee1c5e8cd007272c08fbac568a92c9f02855c41e764c1
5
5
  SHA512:
6
- metadata.gz: ad89c269232bf72ed62dd2a347a6d9cf4129e17240fa2eac843b56cfd02bfd54a5fe7d36420119f7bb4f2f6ff7136fd3a31051ede1a5b6bfea59f6afa3ce771c
7
- data.tar.gz: 8fbe76a119fe45a5ae8086d99c8c9998aaaa8bd85c81908db9bdf4e340c0754c26014a45be0dc558ccae07d2e21fa3cc5c7b99d75be4e58327d52714acb812f0
6
+ metadata.gz: f14d21212c9466cd073f29648e880a085910437b404baaa20534f90b1ff9c6e196978eb55172cae353a5fbe35d08fa2aaf8c63cf1c8e613dbf24f9551efc2375
7
+ data.tar.gz: dece73854d082f55ba1aa8b772a44ede96e62f87af3295d01bf4a8de0039e61021e6eb6bc9b8abc64fae10fe74ed3fd6c7ced28e08513ad6ec027381950e1e66
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.5.0 (2026-04-04)
2
+
3
+ - Improved installation time
4
+ - Dropped support for Ruby < 3.3
5
+
1
6
  ## 0.4.1 (2025-10-26)
2
7
 
3
8
  - Fixed error with Rice 4.7
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  Copyright (c) 2017 The LIBFFM Project.
3
- Copyright (c) 2020-2025 Andrew Kane.
3
+ Copyright (c) 2020-2026 Andrew Kane.
4
4
  All rights reserved.
5
5
 
6
6
  Redistribution and use in source and binary forms, with or without
data/ext/libffm/ext.cpp CHANGED
@@ -1,12 +1,14 @@
1
1
  #include <cstdio>
2
2
  #include <cstdlib>
3
3
  #include <cstring>
4
+ #include <fstream>
4
5
  #include <iostream>
5
6
  #include <string>
7
+ #include <string_view>
8
+ #include <vector>
6
9
 
7
10
  #include <ffm.h>
8
11
  #include <rice/rice.hpp>
9
- #include <rice/stl.hpp>
10
12
 
11
13
  extern "C"
12
14
  void Init_ext() {
@@ -23,17 +25,17 @@ void Init_ext() {
23
25
  })
24
26
  .define_singleton_function(
25
27
  "fit",
26
- [](const std::string& tr_path, const std::string& va_path, const std::string& tmp_prefix, ffm::ffm_float eta, ffm::ffm_float lambda, ffm::ffm_int nr_iters, ffm::ffm_int k, bool normalization, bool auto_stop) {
28
+ [](Rice::String tr_path, Rice::String va_path, Rice::String tmp_prefix, ffm::ffm_float eta, ffm::ffm_float lambda, ffm::ffm_int nr_iters, ffm::ffm_int k, bool normalization, bool auto_stop) {
27
29
  // quiet
28
- ffm::cout.setstate(ffm::ios_base::badbit);
30
+ std::cout.setstate(std::ios_base::badbit);
29
31
 
30
- std::string tr_bin_path = tmp_prefix + "train.bin";
31
- ffm::ffm_read_problem_to_disk(tr_path, tr_bin_path);
32
+ std::string tr_bin_path = tmp_prefix.str() + "train.bin";
33
+ ffm::ffm_read_problem_to_disk(tr_path.str(), tr_bin_path);
32
34
 
33
- std::string va_bin_path = "";
34
- if (va_path.size() > 0) {
35
- va_bin_path = tmp_prefix + "validation.bin";
36
- ffm::ffm_read_problem_to_disk(va_path, va_bin_path);
35
+ std::string va_bin_path;
36
+ if (va_path.length() != 0) {
37
+ va_bin_path = tmp_prefix.str() + "validation.bin";
38
+ ffm::ffm_read_problem_to_disk(va_path.str(), va_bin_path);
37
39
  }
38
40
 
39
41
  ffm::ffm_parameter param;
@@ -48,51 +50,75 @@ void Init_ext() {
48
50
  })
49
51
  .define_singleton_function(
50
52
  "predict",
51
- [](ffm::ffm_model& model, const std::string& test_path) {
52
- int const kMaxLineSize = 1000000;
53
+ [](ffm::ffm_model& model, Rice::String test_path) {
54
+ std::ifstream f_in(test_path.str());
55
+ if (!f_in.is_open()) {
56
+ throw std::runtime_error{"Cannot open file"};
57
+ }
58
+ std::string line;
53
59
 
54
- std::FILE *f_in = std::fopen(test_path.c_str(), "r");
55
- char line[kMaxLineSize];
60
+ Rice::Array ret;
61
+ while (std::getline(f_in, line)) {
62
+ std::vector<ffm::ffm_node> x;
56
63
 
57
- ffm::vector<ffm::ffm_node> x;
58
- ffm::ffm_int i = 0;
64
+ std::string_view line_view{line};
59
65
 
60
- Rice::Array ret;
61
- for(; std::fgets(line, kMaxLineSize, f_in) != nullptr; i++) {
62
- x.clear();
63
- std::strtok(line, " \t");
66
+ size_t n = line_view.find_first_of(" \t");
67
+ if (n == std::string_view::npos) {
68
+ throw std::runtime_error{"Invalid line"};
69
+ }
70
+
71
+ size_t start = n + 1;
64
72
 
65
73
  while (true) {
66
- char *field_char = std::strtok(nullptr, ":");
67
- char *idx_char = std::strtok(nullptr, ":");
68
- char *value_char = std::strtok(nullptr, " \t");
69
- if (field_char == nullptr || *field_char == '\n')
70
- break;
74
+ n = line_view.find_first_of(" \t", start);
75
+
76
+ std::string_view s = n == std::string_view::npos ? line_view.substr(start) : line_view.substr(start, n - start);
71
77
 
72
- ffm::ffm_node N;
73
- N.f = std::atoi(field_char);
74
- N.j = std::atoi(idx_char);
75
- N.v = std::atof(value_char);
78
+ size_t n2 = s.find(':');
79
+ if (n2 == std::string_view::npos) {
80
+ throw std::runtime_error{"Invalid line"};
81
+ }
82
+
83
+ size_t n3 = s.find(':', n2 + 1);
84
+ if (n3 == std::string_view::npos) {
85
+ throw std::runtime_error{"Invalid line"};
86
+ }
87
+
88
+ std::string_view field_char = s.substr(0, n2);
89
+ std::string_view idx_char = s.substr(n2 + 1, n3 - n2 - 1);
90
+ std::string_view value_char = s.substr(n3 + 1);
91
+
92
+ // cannot pass string view to stoi/stof
93
+ ffm::ffm_node N{
94
+ std::stoi(std::string{field_char}),
95
+ std::stoi(std::string{idx_char}),
96
+ std::stof(std::string{value_char})
97
+ };
76
98
 
77
99
  x.push_back(N);
100
+
101
+ if (n == std::string::npos) {
102
+ break;
103
+ }
104
+
105
+ start = n + 1;
78
106
  }
79
107
 
80
- ffm::ffm_float y_bar = ffm::ffm_predict(x.data(), x.data()+x.size(), model);
108
+ ffm::ffm_float y_bar = ffm::ffm_predict(x.data(), x.data() + x.size(), model);
81
109
  ret.push(y_bar, false);
82
110
  }
83
111
 
84
- std::fclose(f_in);
85
-
86
112
  return ret;
87
113
  })
88
114
  .define_singleton_function(
89
115
  "save_model",
90
- [](ffm::ffm_model& model, const std::string& path) {
91
- ffm::ffm_save_model(model, path);
116
+ [](ffm::ffm_model& model, Rice::String path) {
117
+ ffm::ffm_save_model(model, path.str());
92
118
  })
93
119
  .define_singleton_function(
94
120
  "load_model",
95
- [](const std::string& path) {
96
- return ffm::ffm_load_model(path);
121
+ [](Rice::String path) {
122
+ return ffm::ffm_load_model(path.str());
97
123
  });
98
124
  }
@@ -1,3 +1,3 @@
1
1
  module Libffm
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libffm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
@@ -58,14 +58,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '3.2'
61
+ version: '3.3'
62
62
  required_rubygems_version: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - ">="
65
65
  - !ruby/object:Gem::Version
66
66
  version: '0'
67
67
  requirements: []
68
- rubygems_version: 3.6.9
68
+ rubygems_version: 4.0.6
69
69
  specification_version: 4
70
70
  summary: Field-aware factorization machines for Ruby
71
71
  test_files: []