numo-libsvm 0.3.0 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,104 @@
1
+ #ifndef _LIBSVM_H
2
+ #define _LIBSVM_H
3
+
4
+ #define LIBSVM_VERSION 324
5
+
6
+ #ifdef __cplusplus
7
+ extern "C" {
8
+ #endif
9
+
10
+ extern int libsvm_version;
11
+
12
+ struct svm_node
13
+ {
14
+ int index;
15
+ double value;
16
+ };
17
+
18
+ struct svm_problem
19
+ {
20
+ int l;
21
+ double *y;
22
+ struct svm_node **x;
23
+ };
24
+
25
+ enum { C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR }; /* svm_type */
26
+ enum { LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED }; /* kernel_type */
27
+
28
+ struct svm_parameter
29
+ {
30
+ int svm_type;
31
+ int kernel_type;
32
+ int degree; /* for poly */
33
+ double gamma; /* for poly/rbf/sigmoid */
34
+ double coef0; /* for poly/sigmoid */
35
+
36
+ /* these are for training only */
37
+ double cache_size; /* in MB */
38
+ double eps; /* stopping criteria */
39
+ double C; /* for C_SVC, EPSILON_SVR and NU_SVR */
40
+ int nr_weight; /* for C_SVC */
41
+ int *weight_label; /* for C_SVC */
42
+ double* weight; /* for C_SVC */
43
+ double nu; /* for NU_SVC, ONE_CLASS, and NU_SVR */
44
+ double p; /* for EPSILON_SVR */
45
+ int shrinking; /* use the shrinking heuristics */
46
+ int probability; /* do probability estimates */
47
+ };
48
+
49
+ //
50
+ // svm_model
51
+ //
52
+ struct svm_model
53
+ {
54
+ struct svm_parameter param; /* parameter */
55
+ int nr_class; /* number of classes, = 2 in regression/one class svm */
56
+ int l; /* total #SV */
57
+ struct svm_node **SV; /* SVs (SV[l]) */
58
+ double **sv_coef; /* coefficients for SVs in decision functions (sv_coef[k-1][l]) */
59
+ double *rho; /* constants in decision functions (rho[k*(k-1)/2]) */
60
+ double *probA; /* pariwise probability information */
61
+ double *probB;
62
+ int *sv_indices; /* sv_indices[0,...,nSV-1] are values in [1,...,num_traning_data] to indicate SVs in the training set */
63
+
64
+ /* for classification only */
65
+
66
+ int *label; /* label of each class (label[k]) */
67
+ int *nSV; /* number of SVs for each class (nSV[k]) */
68
+ /* nSV[0] + nSV[1] + ... + nSV[k-1] = l */
69
+ /* XXX */
70
+ int free_sv; /* 1 if svm_model is created by svm_load_model*/
71
+ /* 0 if svm_model is created by svm_train */
72
+ };
73
+
74
+ struct svm_model *svm_train(const struct svm_problem *prob, const struct svm_parameter *param);
75
+ void svm_cross_validation(const struct svm_problem *prob, const struct svm_parameter *param, int nr_fold, double *target);
76
+
77
+ int svm_save_model(const char *model_file_name, const struct svm_model *model);
78
+ struct svm_model *svm_load_model(const char *model_file_name);
79
+
80
+ int svm_get_svm_type(const struct svm_model *model);
81
+ int svm_get_nr_class(const struct svm_model *model);
82
+ void svm_get_labels(const struct svm_model *model, int *label);
83
+ void svm_get_sv_indices(const struct svm_model *model, int *sv_indices);
84
+ int svm_get_nr_sv(const struct svm_model *model);
85
+ double svm_get_svr_probability(const struct svm_model *model);
86
+
87
+ double svm_predict_values(const struct svm_model *model, const struct svm_node *x, double* dec_values);
88
+ double svm_predict(const struct svm_model *model, const struct svm_node *x);
89
+ double svm_predict_probability(const struct svm_model *model, const struct svm_node *x, double* prob_estimates);
90
+
91
+ void svm_free_model_content(struct svm_model *model_ptr);
92
+ void svm_free_and_destroy_model(struct svm_model **model_ptr_ptr);
93
+ void svm_destroy_param(struct svm_parameter *param);
94
+
95
+ const char *svm_check_parameter(const struct svm_problem *prob, const struct svm_parameter *param);
96
+ int svm_check_probability_model(const struct svm_model *model);
97
+
98
+ void svm_set_print_string_function(void (*print_func)(const char *));
99
+
100
+ #ifdef __cplusplus
101
+ }
102
+ #endif
103
+
104
+ #endif /* _LIBSVM_H */
@@ -55,6 +55,7 @@ VALUE train(VALUE self, VALUE x_val, VALUE y_val, VALUE param_hash)
55
55
  narray_t* y_nary;
56
56
  char* err_msg;
57
57
  VALUE random_seed;
58
+ VALUE verbose;
58
59
  VALUE model_hash;
59
60
 
60
61
  if (CLASS_OF(x_val) != numo_cDFloat) {
@@ -101,7 +102,11 @@ VALUE train(VALUE self, VALUE x_val, VALUE y_val, VALUE param_hash)
101
102
  return Qnil;
102
103
  }
103
104
 
104
- svm_set_print_string_function(print_null);
105
+ verbose = rb_hash_aref(param_hash, ID2SYM(rb_intern("verbose")));
106
+ if (verbose != Qtrue) {
107
+ svm_set_print_string_function(print_null);
108
+ }
109
+
105
110
  model = svm_train(problem, param);
106
111
  model_hash = svm_model_to_rb_hash(model);
107
112
  svm_free_and_destroy_model(&model);
@@ -109,6 +114,9 @@ VALUE train(VALUE self, VALUE x_val, VALUE y_val, VALUE param_hash)
109
114
  xfree_svm_problem(problem);
110
115
  xfree_svm_parameter(param);
111
116
 
117
+ RB_GC_GUARD(x_val);
118
+ RB_GC_GUARD(y_val);
119
+
112
120
  return model_hash;
113
121
  }
114
122
 
@@ -122,6 +130,30 @@ VALUE train(VALUE self, VALUE x_val, VALUE y_val, VALUE param_hash)
122
130
  * @param param [Hash] The parameters of an SVM model.
123
131
  * @param n_folds [Integer] The number of folds.
124
132
  *
133
+ * @example
134
+ * require 'numo/libsvm'
135
+ *
136
+ * # x: samples
137
+ * # y: labels
138
+ *
139
+ * # Define parameters of C-SVC with RBF Kernel.
140
+ * param = {
141
+ * svm_type: Numo::Libsvm::SvmType::C_SVC,
142
+ * kernel_type: Numo::Libsvm::KernelType::RBF,
143
+ * gamma: 1.0,
144
+ * C: 1,
145
+ * random_seed: 1,
146
+ * verbose: true
147
+ * }
148
+ *
149
+ * # Perform 5-cross validation.
150
+ * n_folds = 5
151
+ * res = Numo::Libsvm.cv(x, y, param, n_folds)
152
+ *
153
+ * # Print mean accuracy.
154
+ * mean_accuracy = y.eq(res).count.fdiv(y.size)
155
+ * puts "Accuracy: %.1f %%" % (100 * mean_accuracy)
156
+ *
125
157
  * @raise [ArgumentError] If the sample array is not 2-dimensional, the label array is not 1-dimensional,
126
158
  * the sample array and label array do not have the same number of samples, or
127
159
  * the hyperparameter has an invalid value, this error is raised.
@@ -138,6 +170,7 @@ VALUE cross_validation(VALUE self, VALUE x_val, VALUE y_val, VALUE param_hash, V
138
170
  narray_t* y_nary;
139
171
  char* err_msg;
140
172
  VALUE random_seed;
173
+ VALUE verbose;
141
174
  struct svm_problem* problem;
142
175
  struct svm_parameter* param;
143
176
 
@@ -189,12 +222,19 @@ VALUE cross_validation(VALUE self, VALUE x_val, VALUE y_val, VALUE param_hash, V
189
222
  t_val = rb_narray_new(numo_cDFloat, 1, t_shape);
190
223
  t_pt = (double*)na_get_pointer_for_write(t_val);
191
224
 
192
- svm_set_print_string_function(print_null);
225
+ verbose = rb_hash_aref(param_hash, ID2SYM(rb_intern("verbose")));
226
+ if (verbose != Qtrue) {
227
+ svm_set_print_string_function(print_null);
228
+ }
229
+
193
230
  svm_cross_validation(problem, param, n_folds, t_pt);
194
231
 
195
232
  xfree_svm_problem(problem);
196
233
  xfree_svm_parameter(param);
197
234
 
235
+ RB_GC_GUARD(x_val);
236
+ RB_GC_GUARD(y_val);
237
+
198
238
  return t_val;
199
239
  }
200
240
 
@@ -220,9 +260,10 @@ VALUE predict(VALUE self, VALUE x_val, VALUE param_hash, VALUE model_hash)
220
260
  size_t y_shape[1];
221
261
  VALUE y_val;
222
262
  double* y_pt;
223
- int i, j;
263
+ int i, j, k;
224
264
  int n_samples;
225
265
  int n_features;
266
+ int n_nonzero_features;
226
267
 
227
268
  /* Obtain C data structures. */
228
269
  if (CLASS_OF(x_val) != numo_cDFloat) {
@@ -251,21 +292,17 @@ VALUE predict(VALUE self, VALUE x_val, VALUE param_hash, VALUE model_hash)
251
292
  x_pt = (double*)na_get_pointer_for_read(x_val);
252
293
 
253
294
  /* Predict values. */
254
- x_nodes = ALLOC_N(struct svm_node, n_features + 1);
255
- x_nodes[n_features].index = -1;
256
- x_nodes[n_features].value = 0.0;
257
295
  for (i = 0; i < n_samples; i++) {
258
- for (j = 0; j < n_features; j++) {
259
- x_nodes[j].index = j + 1;
260
- x_nodes[j].value = (double)x_pt[i * n_features + j];
261
- }
296
+ x_nodes = dbl_vec_to_svm_node(&x_pt[i * n_features], n_features);
262
297
  y_pt[i] = svm_predict(model, x_nodes);
298
+ xfree(x_nodes);
263
299
  }
264
300
 
265
- xfree(x_nodes);
266
301
  xfree_svm_model(model);
267
302
  xfree_svm_parameter(param);
268
303
 
304
+ RB_GC_GUARD(x_val);
305
+
269
306
  return y_val;
270
307
  }
271
308
 
@@ -334,40 +371,30 @@ VALUE decision_function(VALUE self, VALUE x_val, VALUE param_hash, VALUE model_h
334
371
 
335
372
  /* Predict values. */
336
373
  if (model->param.svm_type == ONE_CLASS || model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) {
337
- x_nodes = ALLOC_N(struct svm_node, n_features + 1);
338
- x_nodes[n_features].index = -1;
339
- x_nodes[n_features].value = 0.0;
340
374
  for (i = 0; i < n_samples; i++) {
341
- for (j = 0; j < n_features; j++) {
342
- x_nodes[j].index = j + 1;
343
- x_nodes[j].value = (double)x_pt[i * n_features + j];
344
- }
375
+ x_nodes = dbl_vec_to_svm_node(&x_pt[i * n_features], n_features);
345
376
  svm_predict_values(model, x_nodes, &y_pt[i]);
377
+ xfree(x_nodes);
346
378
  }
347
- xfree(x_nodes);
348
379
  } else {
349
380
  y_cols = (int)y_shape[1];
350
381
  dec_values = ALLOC_N(double, y_cols);
351
- x_nodes = ALLOC_N(struct svm_node, n_features + 1);
352
- x_nodes[n_features].index = -1;
353
- x_nodes[n_features].value = 0.0;
354
382
  for (i = 0; i < n_samples; i++) {
355
- for (j = 0; j < n_features; j++) {
356
- x_nodes[j].index = j + 1;
357
- x_nodes[j].value = (double)x_pt[i * n_features + j];
358
- }
383
+ x_nodes = dbl_vec_to_svm_node(&x_pt[i * n_features], n_features);
359
384
  svm_predict_values(model, x_nodes, dec_values);
385
+ xfree(x_nodes);
360
386
  for (j = 0; j < y_cols; j++) {
361
387
  y_pt[i * y_cols + j] = dec_values[j];
362
388
  }
363
389
  }
364
- xfree(x_nodes);
365
390
  xfree(dec_values);
366
391
  }
367
392
 
368
393
  xfree_svm_model(model);
369
394
  xfree_svm_parameter(param);
370
395
 
396
+ RB_GC_GUARD(x_val);
397
+
371
398
  return y_val;
372
399
  }
373
400
 
@@ -429,26 +456,22 @@ VALUE predict_proba(VALUE self, VALUE x_val, VALUE param_hash, VALUE model_hash)
429
456
 
430
457
  /* Predict values. */
431
458
  probs = ALLOC_N(double, model->nr_class);
432
- x_nodes = ALLOC_N(struct svm_node, n_features + 1);
433
- x_nodes[n_features].index = -1;
434
- x_nodes[n_features].value = 0.0;
435
459
  for (i = 0; i < n_samples; i++) {
436
- for (j = 0; j < n_features; j++) {
437
- x_nodes[j].index = j + 1;
438
- x_nodes[j].value = (double)x_pt[i * n_features + j];
439
- }
460
+ x_nodes = dbl_vec_to_svm_node(&x_pt[i * n_features], n_features);
440
461
  svm_predict_probability(model, x_nodes, probs);
462
+ xfree(x_nodes);
441
463
  for (j = 0; j < model->nr_class; j++) {
442
464
  y_pt[i * model->nr_class + j] = probs[j];
443
465
  }
444
466
  }
445
- xfree(x_nodes);
446
467
  xfree(probs);
447
468
  }
448
469
 
449
470
  xfree_svm_model(model);
450
471
  xfree_svm_parameter(param);
451
472
 
473
+ RB_GC_GUARD(x_val);
474
+
452
475
  return y_val;
453
476
  }
454
477
 
@@ -482,6 +505,8 @@ VALUE load_svm_model(VALUE self, VALUE filename)
482
505
  rb_ary_store(res, 0, param_hash);
483
506
  rb_ary_store(res, 1, model_hash);
484
507
 
508
+ RB_GC_GUARD(filename);
509
+
485
510
  return res;
486
511
  }
487
512
 
@@ -516,6 +541,8 @@ VALUE save_svm_model(VALUE self, VALUE filename, VALUE param_hash, VALUE model_h
516
541
  return Qfalse;
517
542
  }
518
543
 
544
+ RB_GC_GUARD(filename);
545
+
519
546
  return Qtrue;
520
547
  }
521
548
 
@@ -35,13 +35,13 @@ struct svm_parameter* rb_hash_to_svm_parameter(VALUE param_hash)
35
35
  param->weight_label = NULL;
36
36
  if (!NIL_P(el)) {
37
37
  param->weight_label = ALLOC_N(int, param->nr_weight);
38
- memcpy(param->weight_label, (int32_t*)na_get_pointer_for_read(el), param->nr_weight);
38
+ memcpy(param->weight_label, (int32_t*)na_get_pointer_for_read(el), param->nr_weight * sizeof(int32_t));
39
39
  }
40
40
  el = rb_hash_aref(param_hash, ID2SYM(rb_intern("weight")));
41
41
  param->weight = NULL;
42
42
  if (!NIL_P(el)) {
43
43
  param->weight = ALLOC_N(double, param->nr_weight);
44
- memcpy(param->weight, (double*)na_get_pointer_for_read(el), param->nr_weight);
44
+ memcpy(param->weight, (double*)na_get_pointer_for_read(el), param->nr_weight * sizeof(double));
45
45
  }
46
46
  return param;
47
47
  }
@@ -29,9 +29,12 @@ struct svm_problem* dataset_to_svm_problem(VALUE x_val, VALUE y_val)
29
29
  narray_t* x_nary;
30
30
  double* x_pt;
31
31
  double* y_pt;
32
- int i, j;
32
+ int i, j, k;
33
33
  int n_samples;
34
34
  int n_features;
35
+ int n_nonzero_features;
36
+ int is_padded;
37
+ int last_feature_id;
35
38
 
36
39
  GetNArray(x_val, x_nary);
37
40
  n_samples = (int)NA_SHAPE(x_nary)[0];
@@ -43,16 +46,45 @@ struct svm_problem* dataset_to_svm_problem(VALUE x_val, VALUE y_val)
43
46
  problem->l = n_samples;
44
47
  problem->x = ALLOC_N(struct svm_node*, n_samples);
45
48
  problem->y = ALLOC_N(double, n_samples);
49
+
50
+ is_padded = 0;
46
51
  for (i = 0; i < n_samples; i++) {
47
- problem->x[i] = ALLOC_N(struct svm_node, n_features + 1);
52
+ n_nonzero_features = 0;
48
53
  for (j = 0; j < n_features; j++) {
49
- problem->x[i][j].index = j + 1;
50
- problem->x[i][j].value = x_pt[i * n_features + j];
54
+ if (x_pt[i * n_features + j] != 0.0) {
55
+ n_nonzero_features += 1;
56
+ last_feature_id = j + 1;
57
+ }
58
+ }
59
+ if (is_padded == 0 && last_feature_id == n_features) {
60
+ is_padded = 1;
61
+ }
62
+ if (is_padded == 1) {
63
+ problem->x[i] = ALLOC_N(struct svm_node, n_nonzero_features + 1);
64
+ } else {
65
+ problem->x[i] = ALLOC_N(struct svm_node, n_nonzero_features + 2);
66
+ }
67
+ for (j = 0, k = 0; j < n_features; j++) {
68
+ if (x_pt[i * n_features + j] != 0.0) {
69
+ problem->x[i][k].index = j + 1;
70
+ problem->x[i][k].value = (double)x_pt[i * n_features + j];
71
+ k++;
72
+ }
73
+ }
74
+ if (is_padded == 1) {
75
+ problem->x[i][n_nonzero_features].index = -1;
76
+ problem->x[i][n_nonzero_features].value = 0.0;
77
+ } else {
78
+ problem->x[i][n_nonzero_features].index = n_features;
79
+ problem->x[i][n_nonzero_features].value = 0.0;
80
+ problem->x[i][n_nonzero_features + 1].index = -1;
81
+ problem->x[i][n_nonzero_features + 1].value = 0.0;
51
82
  }
52
- problem->x[i][n_features].index = -1;
53
- problem->x[i][n_features].value = 0.0;
54
83
  problem->y[i] = y_pt[i];
55
84
  }
56
85
 
86
+ RB_GC_GUARD(x_val);
87
+ RB_GC_GUARD(y_val);
88
+
57
89
  return problem;
58
90
  }
@@ -3,6 +3,6 @@
3
3
  module Numo
4
4
  module Libsvm
5
5
  # The version of Numo::Libsvm you are using.
6
- VERSION = '0.3.0'
6
+ VERSION = '1.0.2'
7
7
  end
8
8
  end
@@ -28,14 +28,28 @@ Gem::Specification.new do |spec|
28
28
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
29
29
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
30
30
  end
31
+
32
+ gem_dir = File.expand_path(__dir__) + '/'
33
+ submodule_path = `git submodule --quiet foreach pwd`.split($OUTPUT_RECORD_SEPARATOR).first
34
+ submodule_relative_path = submodule_path.sub gem_dir, ''
35
+ spec.files << "#{submodule_relative_path}/svm.cpp"
36
+ spec.files << "#{submodule_relative_path}/svm.h"
37
+
31
38
  spec.bindir = 'exe'
32
39
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33
40
  spec.require_paths = ['lib']
34
41
  spec.extensions = ['ext/numo/libsvm/extconf.rb']
35
42
 
43
+ spec.metadata = {
44
+ 'homepage_uri' => 'https://github.com/yoshoku/numo-libsvm',
45
+ 'source_code_uri' => 'https://github.com/yoshoku/numo-libsvm',
46
+ 'documentation_uri' => 'https://yoshoku.github.io/numo-libsvm/doc/'
47
+ }
48
+
36
49
  spec.add_runtime_dependency 'numo-narray', '~> 0.9.1'
50
+
37
51
  spec.add_development_dependency 'bundler', '~> 2.0'
38
- spec.add_development_dependency 'rake', '~> 10.0'
52
+ spec.add_development_dependency 'rake', '~> 12.0'
39
53
  spec.add_development_dependency 'rake-compiler', '~> 1.0'
40
54
  spec.add_development_dependency 'rspec', '~> 3.0'
41
55
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: numo-libsvm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - yoshoku
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-22 00:00:00.000000000 Z
11
+ date: 2021-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: numo-narray
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '12.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '12.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake-compiler
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -92,9 +92,10 @@ extensions:
92
92
  - ext/numo/libsvm/extconf.rb
93
93
  extra_rdoc_files: []
94
94
  files:
95
+ - ".github/workflows/build.yml"
95
96
  - ".gitignore"
97
+ - ".gitmodules"
96
98
  - ".rspec"
97
- - ".travis.yml"
98
99
  - CHANGELOG.md
99
100
  - CODE_OF_CONDUCT.md
100
101
  - Gemfile
@@ -106,6 +107,8 @@ files:
106
107
  - ext/numo/libsvm/extconf.rb
107
108
  - ext/numo/libsvm/kernel_type.c
108
109
  - ext/numo/libsvm/kernel_type.h
110
+ - ext/numo/libsvm/libsvm/svm.cpp
111
+ - ext/numo/libsvm/libsvm/svm.h
109
112
  - ext/numo/libsvm/libsvmext.c
110
113
  - ext/numo/libsvm/libsvmext.h
111
114
  - ext/numo/libsvm/svm_model.c
@@ -122,8 +125,11 @@ files:
122
125
  homepage: https://github.com/yoshoku/numo-libsvm
123
126
  licenses:
124
127
  - BSD-3-Clause
125
- metadata: {}
126
- post_install_message:
128
+ metadata:
129
+ homepage_uri: https://github.com/yoshoku/numo-libsvm
130
+ source_code_uri: https://github.com/yoshoku/numo-libsvm
131
+ documentation_uri: https://yoshoku.github.io/numo-libsvm/doc/
132
+ post_install_message:
127
133
  rdoc_options: []
128
134
  require_paths:
129
135
  - lib
@@ -138,9 +144,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
144
  - !ruby/object:Gem::Version
139
145
  version: '0'
140
146
  requirements: []
141
- rubyforge_project:
142
- rubygems_version: 2.6.14.4
143
- signing_key:
147
+ rubygems_version: 3.2.3
148
+ signing_key:
144
149
  specification_version: 4
145
150
  summary: Numo::Libsvm is a Ruby gem binding to the LIBSVM library. Numo::Libsvm makes
146
151
  to use the LIBSVM functions with dataset represented by Numo::NArray.