rb-libsvm 1.0.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.
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +28 -0
- data/MIT-LICENSE +20 -0
- data/README.textile +37 -0
- data/Rakefile +13 -0
- data/ext/rb-libsvm/extconf.rb +46 -0
- data/ext/rb-libsvm/libsvm.c +489 -0
- data/ext/rb-libsvm/ruby-ext.h +42 -0
- data/ext/rb-libsvm/svm.cpp +3072 -0
- data/ext/rb-libsvm/svm.h +101 -0
- data/ferret_valgrind.supp +478 -0
- data/lib/libsvm.rb +63 -0
- data/lib/rb-libsvm/version.rb +3 -0
- data/rb-libsvm.gemspec +27 -0
- data/spec/model_spec.rb +95 -0
- data/spec/node_spec.rb +68 -0
- data/spec/parameter_spec.rb +76 -0
- data/spec/problem_spec.rb +37 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/usage_spec.rb +37 -0
- metadata +97 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.2@rblibsvm --create
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rb-libsvm (1.0.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.1.3)
|
10
|
+
rake (0.9.2.2)
|
11
|
+
rake-compiler (0.7.9)
|
12
|
+
rake
|
13
|
+
rspec (2.7.0)
|
14
|
+
rspec-core (~> 2.7.0)
|
15
|
+
rspec-expectations (~> 2.7.0)
|
16
|
+
rspec-mocks (~> 2.7.0)
|
17
|
+
rspec-core (2.7.1)
|
18
|
+
rspec-expectations (2.7.0)
|
19
|
+
diff-lcs (~> 1.1.2)
|
20
|
+
rspec-mocks (2.7.0)
|
21
|
+
|
22
|
+
PLATFORMS
|
23
|
+
ruby
|
24
|
+
|
25
|
+
DEPENDENCIES
|
26
|
+
rake-compiler
|
27
|
+
rb-libsvm!
|
28
|
+
rspec (= 2.7.0)
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2004-2008 Caspar Florian Ebeling
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
h1. rb-libsvm -- Ruby language bindings for LIBSVM
|
2
|
+
|
3
|
+
This is a module which provides a Ruby API to the LIBSVM [1] library.
|
4
|
+
SVM is a machine learning and classification algorithm, and LIBSVM is
|
5
|
+
a popular free implementation of it, written by Chih-Chung Chang and
|
6
|
+
Chih-Jen Lin, of National Taiwan University, Taipei. See "Programming
|
7
|
+
Collective Intelligence," [2] among others, for a usage example.
|
8
|
+
|
9
|
+
Note: There exists another Ruby binding for LIBSVM, named Ruby SVM,
|
10
|
+
[3] written by Rudi Cilibrasi. (That's the one mentioned in the
|
11
|
+
libsvm documentation.) This package is not related but written
|
12
|
+
independently and from scratch.
|
13
|
+
|
14
|
+
h2. Dependencies
|
15
|
+
|
16
|
+
None. Libsvm is bundled with the project. Just clone and go!
|
17
|
+
|
18
|
+
Currently using libsvm version 3.1
|
19
|
+
|
20
|
+
h2. Author, License
|
21
|
+
|
22
|
+
Written by C. Florian Ebeling. This software can be freely used under
|
23
|
+
the terms of the MIT license, see file MIT-LICENSE.
|
24
|
+
|
25
|
+
h2. Contributors
|
26
|
+
|
27
|
+
Rimas Silkaitis
|
28
|
+
|
29
|
+
h3. Notes
|
30
|
+
|
31
|
+
fn1. http://www.csie.ntu.edu.tw/~cjlin/libsvm/
|
32
|
+
|
33
|
+
fn2. http://books.google.com/books?id=fEsZ3Ey-Hq4C
|
34
|
+
|
35
|
+
fn3. http://rubysvm.cilibrar.com/
|
36
|
+
|
37
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/extensiontask"
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
Rake::ExtensionTask.new('rb-libsvm') do |ext|
|
6
|
+
ext.lib_dir = File.join('lib', 'rb-libsvm')
|
7
|
+
ext.name = 'libsvm'
|
8
|
+
end
|
9
|
+
|
10
|
+
RSpec::Core::RakeTask.new('spec')
|
11
|
+
Rake::Task[:spec].prerequisites << :clean
|
12
|
+
Rake::Task[:spec].prerequisites << :compile
|
13
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
# $CFLAGS << " -save-temps -ggdb3 "
|
4
|
+
# $LDFLAGS << " -lstdc++ "
|
5
|
+
|
6
|
+
# find_header('ruby.h')
|
7
|
+
# find_library('svm', 'svm_train', '/opt/local/lib/', '/usr/lib/') || raise("svm library not found.")
|
8
|
+
# find_header('svm.h', "/opt/local/include/", "/usr/include/libsvm-2.0/libsvm/")
|
9
|
+
# create_makefile('libsvm_ext')
|
10
|
+
|
11
|
+
LIBDIR = Config::CONFIG['libdir']
|
12
|
+
INCLUDEDIR = Config::CONFIG['includedir']
|
13
|
+
|
14
|
+
HEADER_DIRS = [
|
15
|
+
# First search /opt/local for macports
|
16
|
+
'/opt/local/include',
|
17
|
+
|
18
|
+
# Then search /usr/local for people that installed from source
|
19
|
+
'/usr/local/include',
|
20
|
+
|
21
|
+
# Check the ruby install locations
|
22
|
+
INCLUDEDIR,
|
23
|
+
|
24
|
+
# Finally fall back to /usr
|
25
|
+
'/usr/include',
|
26
|
+
]
|
27
|
+
|
28
|
+
LIB_DIRS = [
|
29
|
+
# First search /opt/local for macports
|
30
|
+
'/opt/local/lib',
|
31
|
+
|
32
|
+
# Then search /usr/local for people that installed from source
|
33
|
+
'/usr/local/lib',
|
34
|
+
|
35
|
+
# Check the ruby install locations
|
36
|
+
LIBDIR,
|
37
|
+
|
38
|
+
# Finally fall back to /usr
|
39
|
+
'/usr/lib',
|
40
|
+
]
|
41
|
+
|
42
|
+
dir_config('rb-libsvm',HEADER_DIRS,LIB_DIRS)
|
43
|
+
|
44
|
+
# Don't think I need to search the dirs for the header file
|
45
|
+
|
46
|
+
create_makefile('rb-libsvm/libsvm')
|
@@ -0,0 +1,489 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "svm.h"
|
3
|
+
#include "ruby-ext.h"
|
4
|
+
#include <string.h>
|
5
|
+
|
6
|
+
VALUE mLibsvm;
|
7
|
+
|
8
|
+
VALUE cNode;
|
9
|
+
VALUE cProblem;
|
10
|
+
VALUE cSvmParameter;
|
11
|
+
VALUE cModel;
|
12
|
+
|
13
|
+
VALUE mKernelType;
|
14
|
+
VALUE mSvmType;
|
15
|
+
|
16
|
+
const struct svm_node TERMINATOR = (struct svm_node) { -1, 0.0 };
|
17
|
+
|
18
|
+
/* Libsvm::Node */
|
19
|
+
static struct svm_node *node_new() {
|
20
|
+
struct svm_node *n;
|
21
|
+
n = (struct svm_node *) calloc(1,sizeof(struct svm_node));
|
22
|
+
if(n == NULL)
|
23
|
+
return NULL;
|
24
|
+
return n;
|
25
|
+
}
|
26
|
+
|
27
|
+
static void node_free(struct svm_node *n) {
|
28
|
+
free(n);
|
29
|
+
}
|
30
|
+
|
31
|
+
static VALUE node_alloc(VALUE cls) {
|
32
|
+
struct svm_node *n;
|
33
|
+
n = node_new();
|
34
|
+
if(n == NULL)
|
35
|
+
rb_raise(rb_eNoMemError, "Not enough memory for allocating Node.");
|
36
|
+
|
37
|
+
return Data_Wrap_Struct(cls, 0, node_free, n);
|
38
|
+
}
|
39
|
+
|
40
|
+
rx_def_accessor(cNode,struct svm_node,int,index);
|
41
|
+
rx_def_accessor(cNode,struct svm_node,double,value);
|
42
|
+
|
43
|
+
/* Libsvm::Problem */
|
44
|
+
static struct svm_problem *problem_new() {
|
45
|
+
struct svm_problem *n;
|
46
|
+
n = (struct svm_problem *) calloc(1,sizeof(struct svm_problem));
|
47
|
+
if(n == NULL)
|
48
|
+
return NULL;
|
49
|
+
return n;
|
50
|
+
}
|
51
|
+
|
52
|
+
static void problem_free(struct svm_problem *n) {
|
53
|
+
/*
|
54
|
+
Deliberate no-op, because of this note from the README:
|
55
|
+
|
56
|
+
`*NOTE* Because svm_model contains pointers to svm_problem, you can
|
57
|
+
not free the memory used by svm_problem if you are still using the
|
58
|
+
svm_model produced by svm_train().'
|
59
|
+
*/
|
60
|
+
}
|
61
|
+
|
62
|
+
static VALUE problem_alloc(VALUE cls) {
|
63
|
+
struct svm_problem *n;
|
64
|
+
n = problem_new();
|
65
|
+
if(n == NULL)
|
66
|
+
rb_raise(rb_eNoMemError, "Not enough memory for allocating Libsvm::Problem.");
|
67
|
+
return Data_Wrap_Struct(cls, 0, problem_free, n);
|
68
|
+
}
|
69
|
+
|
70
|
+
rx_def_accessor(cProblem,struct svm_problem,int,l);
|
71
|
+
|
72
|
+
static struct svm_node *example_to_internal(VALUE example_ary)
|
73
|
+
{
|
74
|
+
struct svm_node *x, *node_struct;
|
75
|
+
int example_ary_len, j;
|
76
|
+
VALUE node;
|
77
|
+
|
78
|
+
/* allocate memory for it */
|
79
|
+
example_ary_len = rx_ary_size(example_ary);
|
80
|
+
x = (struct svm_node *)calloc(example_ary_len+1,sizeof(struct svm_node));
|
81
|
+
if(x == 0) {
|
82
|
+
rb_raise(rb_eNoMemError, "on Libsvm::Node allocation" " %s:%i", __FILE__,__LINE__);
|
83
|
+
}
|
84
|
+
/* loop it's element nodes */
|
85
|
+
for(j = 0; j < example_ary_len; ++j) {
|
86
|
+
node = rb_ary_entry(example_ary,j);
|
87
|
+
Data_Get_Struct(node,struct svm_node,node_struct);
|
88
|
+
memcpy(x+j,node_struct,sizeof(struct svm_node));
|
89
|
+
}
|
90
|
+
/* add terminator */
|
91
|
+
memcpy(x+example_ary_len,&TERMINATOR,sizeof(struct svm_node));
|
92
|
+
|
93
|
+
return x;
|
94
|
+
}
|
95
|
+
|
96
|
+
static struct svm_node **examples_ary_to_internal(VALUE examples_ary)
|
97
|
+
{
|
98
|
+
struct svm_node **x;
|
99
|
+
struct svm_node *node_struct;
|
100
|
+
VALUE nodes_ary, node;
|
101
|
+
int nodes_ary_len, i;
|
102
|
+
|
103
|
+
int num = rx_ary_size(examples_ary);
|
104
|
+
|
105
|
+
x = (struct svm_node **)calloc(num,sizeof(struct svm_node *));
|
106
|
+
if(x == 0) {
|
107
|
+
rb_raise(rb_eNoMemError, "%s:%i", __FILE__,__LINE__);
|
108
|
+
}
|
109
|
+
|
110
|
+
for(i = 0; i < num; ++i) {
|
111
|
+
nodes_ary = rb_ary_entry(examples_ary,i);
|
112
|
+
*(x+i) = example_to_internal(nodes_ary);
|
113
|
+
}
|
114
|
+
|
115
|
+
return x;
|
116
|
+
}
|
117
|
+
|
118
|
+
/*
|
119
|
+
call-seq:
|
120
|
+
problem.set_examples(labels, examples_array)
|
121
|
+
|
122
|
+
double *y; // class (aka. label) of the example
|
123
|
+
struct svm_node **x; // examples
|
124
|
+
|
125
|
+
This method sets the contents of an SVM Problem, which consists
|
126
|
+
of lables (or classifications) and examples (or feature vectors).
|
127
|
+
If those 2 don't match in length and ArgumentError is raised.
|
128
|
+
*/
|
129
|
+
static VALUE cProblem_examples_set(VALUE obj,VALUE labels_ary,VALUE examples_ary)
|
130
|
+
{
|
131
|
+
struct svm_problem *prob;
|
132
|
+
struct svm_node *node_struct;
|
133
|
+
/* VALUE num;*/
|
134
|
+
int i, nodes_ary_len;
|
135
|
+
VALUE label, node, nodes_ary;
|
136
|
+
|
137
|
+
int num = rx_ary_size(labels_ary);
|
138
|
+
|
139
|
+
if(num != rx_ary_size(examples_ary)) {
|
140
|
+
rb_raise(rb_eArgError, "Number of labels (%i) does not match number of features (%i).", num, rx_ary_size(examples_ary));
|
141
|
+
}
|
142
|
+
|
143
|
+
Data_Get_Struct(obj, struct svm_problem, prob);
|
144
|
+
|
145
|
+
if(prob->l > 0) {
|
146
|
+
free(prob->y);
|
147
|
+
for(i = 0; i < num; ++i) {
|
148
|
+
free(*(prob->x+i));
|
149
|
+
}
|
150
|
+
free(prob->x);
|
151
|
+
}
|
152
|
+
|
153
|
+
prob->y = (double *)calloc(num,sizeof(double));
|
154
|
+
if(prob->y == 0) {
|
155
|
+
rb_raise(rb_eNoMemError, "%s:%i", __FILE__,__LINE__);
|
156
|
+
}
|
157
|
+
|
158
|
+
for(i = 0; i < num; ++i) {
|
159
|
+
*(prob->y+i) = NUM2DBL(rb_ary_entry(labels_ary,i));
|
160
|
+
}
|
161
|
+
|
162
|
+
prob->x = examples_ary_to_internal(examples_ary);
|
163
|
+
prob->l = num;
|
164
|
+
|
165
|
+
return INT2FIX(num);
|
166
|
+
}
|
167
|
+
|
168
|
+
/*
|
169
|
+
call-seq:
|
170
|
+
labels, array_of_arrays = problem.examples
|
171
|
+
|
172
|
+
double *y; // class/label of the example
|
173
|
+
struct svm_node **x;
|
174
|
+
*/
|
175
|
+
static VALUE cProblem_examples(VALUE problem) {
|
176
|
+
struct svm_problem *prob;
|
177
|
+
struct svm_node *node, *node_copy;
|
178
|
+
double label;
|
179
|
+
struct svm_node *features;
|
180
|
+
VALUE labels_ary, examples_ary, example_ary, v_node, result;
|
181
|
+
int i,n;
|
182
|
+
|
183
|
+
Data_Get_Struct(problem, struct svm_problem, prob);
|
184
|
+
|
185
|
+
labels_ary = rb_ary_new2(prob->l);
|
186
|
+
examples_ary = rb_ary_new2(prob->l);
|
187
|
+
|
188
|
+
features = (struct svm_node *)calloc(prob->l, sizeof(struct svm_node));
|
189
|
+
if(features == 0) {
|
190
|
+
rb_raise(rb_eNoMemError, "on allocating Libsvm::Node" " %s:%i", __FILE__,__LINE__);
|
191
|
+
}
|
192
|
+
|
193
|
+
for(i = 0; i < prob->l; ++i) {
|
194
|
+
label = *(prob->y+i);
|
195
|
+
rb_ary_push(labels_ary,rb_float_new(label));
|
196
|
+
|
197
|
+
node = *(prob->x+i); /* example start pointer */
|
198
|
+
example_ary = rb_ary_new();
|
199
|
+
while(node->index != -1) {
|
200
|
+
node_copy = (struct svm_node *)malloc(sizeof(struct svm_node));
|
201
|
+
if(node_copy == 0) {
|
202
|
+
rb_raise(rb_eNoMemError, "on allocating Libsvm::Node" " %s:%i", __FILE__,__LINE__);
|
203
|
+
}
|
204
|
+
memcpy(node_copy,node,sizeof(struct svm_node));
|
205
|
+
v_node = Data_Wrap_Struct(cNode,0,node_free,node_copy);
|
206
|
+
rb_ary_push(example_ary,v_node);
|
207
|
+
++node;
|
208
|
+
}
|
209
|
+
rb_ary_push(examples_ary,example_ary);
|
210
|
+
}
|
211
|
+
|
212
|
+
result = rb_ary_new2(2);
|
213
|
+
rb_ary_push(result,labels_ary);
|
214
|
+
rb_ary_push(result,examples_ary);
|
215
|
+
|
216
|
+
return result;
|
217
|
+
}
|
218
|
+
|
219
|
+
/* SvmParameter */
|
220
|
+
|
221
|
+
static struct svm_parameter *parameter_new() {
|
222
|
+
struct svm_parameter *n;
|
223
|
+
n = (struct svm_parameter *) calloc(1,sizeof(struct svm_parameter));
|
224
|
+
if(n == NULL)
|
225
|
+
return NULL;
|
226
|
+
return n;
|
227
|
+
}
|
228
|
+
|
229
|
+
static void parameter_free(struct svm_parameter *n) {
|
230
|
+
// svm_destroy_param(n);
|
231
|
+
free(n);
|
232
|
+
}
|
233
|
+
|
234
|
+
static VALUE parameter_alloc(VALUE cls) {
|
235
|
+
struct svm_parameter *n;
|
236
|
+
n = parameter_new();
|
237
|
+
if(n == NULL)
|
238
|
+
rb_raise(rb_eNoMemError, "Not enough memory for allocating SvmParameter.");
|
239
|
+
|
240
|
+
return Data_Wrap_Struct(cls, 0, parameter_free, n);
|
241
|
+
}
|
242
|
+
|
243
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,int,svm_type)
|
244
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,int,kernel_type);
|
245
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,int,degree);
|
246
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,double,gamma);
|
247
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,double,coef0);
|
248
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,double,cache_size);
|
249
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,double,eps);
|
250
|
+
rx_def_accessor_as(cSvmParameter,struct svm_parameter,double,C,c);
|
251
|
+
|
252
|
+
/* Label weight.
|
253
|
+
|
254
|
+
nr_weight, weight_label, and weight are used to change the penalty
|
255
|
+
for some classes (If the weight for a class is not changed, it is
|
256
|
+
set to 1). This is useful for training classifier using unbalanced
|
257
|
+
input data or with asymmetric misclassification cost.
|
258
|
+
|
259
|
+
nr_weight is the number of elements in the array weight_label and
|
260
|
+
weight. Each weight[i] corresponds to weight_label[i], meaning that
|
261
|
+
the penalty of class weight_label[i] is scaled by a factor of weight[i].
|
262
|
+
|
263
|
+
If you do not want to change penalty for any of the classes,
|
264
|
+
just set nr_weight to 0.
|
265
|
+
|
266
|
+
*/
|
267
|
+
static VALUE cSvmParameter_label_weights_set(VALUE obj,VALUE weight_hash) {
|
268
|
+
struct svm_parameter *param;
|
269
|
+
int i,len,weight_label;
|
270
|
+
double weight;
|
271
|
+
VALUE keys,key,val;
|
272
|
+
|
273
|
+
Data_Get_Struct(obj,struct svm_parameter,param);
|
274
|
+
|
275
|
+
if(param->nr_weight > 0) {
|
276
|
+
free(param->weight);
|
277
|
+
free(param->weight_label);
|
278
|
+
}
|
279
|
+
|
280
|
+
param->nr_weight = rx_hash_size(weight_hash);
|
281
|
+
param->weight = (double *)calloc(param->nr_weight,sizeof(double));
|
282
|
+
param->weight_label = (int *)calloc(param->nr_weight,sizeof(int));
|
283
|
+
|
284
|
+
keys = rb_funcall(weight_hash, rb_intern("keys"),0);
|
285
|
+
|
286
|
+
for(i = 0; i < param->nr_weight; ++i) {
|
287
|
+
key = rb_ary_entry(keys,i);
|
288
|
+
val = rb_hash_aref(weight_hash,key);
|
289
|
+
|
290
|
+
param->weight_label[i] = NUM2INT(key);
|
291
|
+
param->weight[i] = NUM2DBL(val);
|
292
|
+
}
|
293
|
+
|
294
|
+
return Qnil;
|
295
|
+
}
|
296
|
+
|
297
|
+
static VALUE cSvmParameter_label_weights(VALUE obj) {
|
298
|
+
struct svm_parameter *param;
|
299
|
+
int i;
|
300
|
+
VALUE hash,key,val;
|
301
|
+
|
302
|
+
Data_Get_Struct(obj,struct svm_parameter,param);
|
303
|
+
|
304
|
+
hash = rb_hash_new();
|
305
|
+
|
306
|
+
for(i = 0; i < param->nr_weight; ++i) {
|
307
|
+
key = INT2NUM(param->weight_label[i]);
|
308
|
+
val = rb_float_new(param->weight[i]);
|
309
|
+
rb_hash_aset(hash,key,val);
|
310
|
+
}
|
311
|
+
|
312
|
+
return hash;
|
313
|
+
}
|
314
|
+
|
315
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,double,nu);
|
316
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,double,p);
|
317
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,int,shrinking);
|
318
|
+
rx_def_accessor(cSvmParameter,struct svm_parameter,int,probability);
|
319
|
+
|
320
|
+
/* Libsvm::Model */
|
321
|
+
|
322
|
+
static VALUE cModel_class_train(VALUE obj,VALUE problem,VALUE parameter) {
|
323
|
+
const struct svm_problem *prob;
|
324
|
+
const struct svm_parameter *param;
|
325
|
+
struct svm_model *model;
|
326
|
+
const char *check_error;
|
327
|
+
|
328
|
+
Data_Get_Struct(problem, struct svm_problem, prob);
|
329
|
+
Data_Get_Struct(parameter, struct svm_parameter, param);
|
330
|
+
|
331
|
+
check_error = svm_check_parameter(prob, param);
|
332
|
+
if(check_error != NULL) {
|
333
|
+
rb_raise(rb_eArgError, "Parameters not valid for Problem: '%s'", check_error);
|
334
|
+
}
|
335
|
+
model = svm_train(prob,param);
|
336
|
+
|
337
|
+
return Data_Wrap_Struct(cModel, 0, svm_free_and_destroy_model, model);
|
338
|
+
}
|
339
|
+
|
340
|
+
static VALUE cModel_predict(VALUE obj,VALUE example) {
|
341
|
+
struct svm_node *x;
|
342
|
+
struct svm_model *model;
|
343
|
+
double class;
|
344
|
+
|
345
|
+
x = example_to_internal(example);
|
346
|
+
Data_Get_Struct(obj, struct svm_model, model);
|
347
|
+
class = svm_predict(model, x);
|
348
|
+
|
349
|
+
return rb_float_new(class);
|
350
|
+
}
|
351
|
+
|
352
|
+
static VALUE cModel_save(VALUE obj, VALUE filename)
|
353
|
+
{
|
354
|
+
const struct svm_model *model;
|
355
|
+
const char *path;
|
356
|
+
int rc;
|
357
|
+
|
358
|
+
Data_Get_Struct(obj, struct svm_model, model);
|
359
|
+
path = StringValueCStr(filename);
|
360
|
+
|
361
|
+
if(rc = svm_save_model(path, model)) {
|
362
|
+
rb_raise(rb_eStandardError, "Error on saving model, code: %i", rc);
|
363
|
+
}
|
364
|
+
|
365
|
+
return Qnil;
|
366
|
+
}
|
367
|
+
|
368
|
+
static VALUE cModel_svm_type(VALUE obj)
|
369
|
+
{
|
370
|
+
const struct svm_model *model;
|
371
|
+
Data_Get_Struct(obj, struct svm_model, model);
|
372
|
+
return INT2NUM(svm_get_svm_type(model));
|
373
|
+
}
|
374
|
+
|
375
|
+
static VALUE cModel_classes(VALUE obj)
|
376
|
+
{
|
377
|
+
const struct svm_model *model;
|
378
|
+
Data_Get_Struct(obj, struct svm_model, model);
|
379
|
+
return INT2NUM(svm_get_nr_class(model));
|
380
|
+
}
|
381
|
+
|
382
|
+
static VALUE cModel_class_load(VALUE cls, VALUE filename)
|
383
|
+
{
|
384
|
+
struct svm_model *model;
|
385
|
+
char *path;
|
386
|
+
path = StringValueCStr(filename);
|
387
|
+
model = svm_load_model(path);
|
388
|
+
return Data_Wrap_Struct(cModel, 0, svm_free_and_destroy_model, model);
|
389
|
+
}
|
390
|
+
|
391
|
+
static VALUE cModel_class_cross_validation(VALUE cls, VALUE problem, VALUE parameter, VALUE num_fold)
|
392
|
+
{
|
393
|
+
const struct svm_problem *prob;
|
394
|
+
const struct svm_parameter *param;
|
395
|
+
int nr_fold, i;
|
396
|
+
double *target_ptr;
|
397
|
+
VALUE target;
|
398
|
+
|
399
|
+
Data_Get_Struct(problem, struct svm_problem, prob);
|
400
|
+
Data_Get_Struct(parameter, struct svm_parameter, param);
|
401
|
+
|
402
|
+
nr_fold = NUM2INT(num_fold);
|
403
|
+
|
404
|
+
target = rb_ary_new2(prob->l);
|
405
|
+
target_ptr = (double *)calloc(prob->l, sizeof(double));
|
406
|
+
if(target_ptr == 0) {
|
407
|
+
rb_raise(rb_eNoMemError, "on cross-validation result allocation" " %s:%i", __FILE__,__LINE__);
|
408
|
+
}
|
409
|
+
|
410
|
+
svm_cross_validation(prob, param, nr_fold, target_ptr);
|
411
|
+
|
412
|
+
for(i = 0; i < prob->l; ++i) {
|
413
|
+
rb_ary_push(target, rb_float_new(*(target_ptr+i)));
|
414
|
+
}
|
415
|
+
|
416
|
+
free(target_ptr);
|
417
|
+
|
418
|
+
return target;
|
419
|
+
}
|
420
|
+
|
421
|
+
void Init_libsvm() {
|
422
|
+
mLibsvm = rb_define_module("Libsvm");
|
423
|
+
|
424
|
+
/* Libsvm::Problem */
|
425
|
+
cProblem = rb_define_class_under(mLibsvm, "Problem", rb_cObject);
|
426
|
+
rb_define_alloc_func(cProblem, problem_alloc);
|
427
|
+
rx_reg_accessor(cProblem, l);
|
428
|
+
rb_define_method(cProblem, "set_examples", cProblem_examples_set, 2);
|
429
|
+
rb_define_method(cProblem, "examples", cProblem_examples, 0);
|
430
|
+
|
431
|
+
/* Libsvm::SvmParameter */
|
432
|
+
cSvmParameter = rb_define_class_under(mLibsvm, "SvmParameter", rb_cObject);
|
433
|
+
rb_define_alloc_func(cSvmParameter, parameter_alloc);
|
434
|
+
rx_reg_accessor(cSvmParameter,svm_type);
|
435
|
+
rx_reg_accessor(cSvmParameter,kernel_type);
|
436
|
+
rx_reg_accessor(cSvmParameter,degree);
|
437
|
+
rx_reg_accessor(cSvmParameter,gamma);
|
438
|
+
rx_reg_accessor(cSvmParameter,coef0);
|
439
|
+
rx_reg_accessor(cSvmParameter,cache_size);
|
440
|
+
rx_reg_accessor(cSvmParameter,eps);
|
441
|
+
rx_reg_accessor_as(cSvmParameter,C,c);
|
442
|
+
rb_define_method(cSvmParameter,"label_weights=",cSvmParameter_label_weights_set,1);
|
443
|
+
rb_define_method(cSvmParameter,"label_weights",cSvmParameter_label_weights,0);
|
444
|
+
rx_reg_accessor(cSvmParameter,nu);
|
445
|
+
rx_reg_accessor(cSvmParameter,p);
|
446
|
+
rx_reg_accessor(cSvmParameter,shrinking);
|
447
|
+
rx_reg_accessor(cSvmParameter,probability);
|
448
|
+
|
449
|
+
/* Libsvm::Node */
|
450
|
+
cNode = rb_define_class_under(mLibsvm, "Node", rb_cObject);
|
451
|
+
rb_define_alloc_func(cNode, node_alloc);
|
452
|
+
rx_reg_accessor(cNode,index);
|
453
|
+
rx_reg_accessor(cNode,value);
|
454
|
+
|
455
|
+
/* Libsvm::Model */
|
456
|
+
cModel = rb_define_class_under(mLibsvm, "Model", rb_cObject);
|
457
|
+
// model_alloc not necessary, since we don't ever create, only wrap it.
|
458
|
+
rb_define_singleton_method(cModel, "train", cModel_class_train, 2);
|
459
|
+
rb_define_singleton_method(cModel, "cross_validation", cModel_class_cross_validation, 3);
|
460
|
+
rb_define_singleton_method(cModel, "load", cModel_class_load, 1);
|
461
|
+
rb_define_method(cModel, "save", cModel_save, 1);
|
462
|
+
rb_define_method(cModel, "svm_type", cModel_svm_type, 0);
|
463
|
+
rb_define_method(cModel, "classes", cModel_classes, 0);
|
464
|
+
rb_define_method(cModel, "predict", cModel_predict, 1);
|
465
|
+
|
466
|
+
/*
|
467
|
+
Not covered, for various reasons:
|
468
|
+
TODO - void svm_get_labels(const struct svm_model *model, int *label);
|
469
|
+
SVR? - double svm_get_svr_probability(const struct svm_model *model);
|
470
|
+
SVR? - double svm_predict_probability(const struct svm_model *model, const struct svm_node *x, double* prob_estimates);
|
471
|
+
Model holds reference to this, so when to use it?
|
472
|
+
void svm_destroy_param(struct svm_parameter *param);
|
473
|
+
SVR? - int svm_check_probability_model(const struct svm_model *model);
|
474
|
+
*/
|
475
|
+
|
476
|
+
mKernelType = rb_define_module_under(mLibsvm, "KernelType");
|
477
|
+
rb_define_const(mKernelType, "LINEAR", INT2NUM(LINEAR));
|
478
|
+
rb_define_const(mKernelType, "POLY", INT2NUM(POLY));
|
479
|
+
rb_define_const(mKernelType, "RBF", INT2NUM(RBF));
|
480
|
+
rb_define_const(mKernelType, "SIGMOID", INT2NUM(SIGMOID));
|
481
|
+
rb_define_const(mKernelType, "PRECOMPUTED", INT2NUM(PRECOMPUTED));
|
482
|
+
|
483
|
+
mSvmType = rb_define_module_under(mLibsvm,"SvmType");
|
484
|
+
rb_define_const(mSvmType, "C_SVC", INT2NUM(C_SVC));
|
485
|
+
rb_define_const(mSvmType, "NU_SVC", INT2NUM(NU_SVC));
|
486
|
+
rb_define_const(mSvmType, "ONE_CLASS", INT2NUM(ONE_CLASS));
|
487
|
+
rb_define_const(mSvmType, "EPSILON_SVR", INT2NUM(EPSILON_SVR));
|
488
|
+
rb_define_const(mSvmType, "NU_SVR", INT2NUM(NU_SVR));
|
489
|
+
}
|