source: orange/source/orange/libsvm_interface.cpp @ 9389:f05efbabf25f

Revision 9389:f05efbabf25f, 22.8 KB checked in by ales_erjavec <ales.erjavec@…>, 2 years ago (diff)

When reading the rho's, read the number into a string and then use strtod for conversion to double. This should properly handles NaN's.

Line 
1/*
2    This file is part of Orange.
3
4    Copyright 1996-2011 Faculty of Computer and Information Science, University of Ljubljana
5    Contact: janez.demsar@fri.uni-lj.si
6
7    Orange is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Orange is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Orange.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include <iostream>
22#include <sstream>
23
24#include "libsvm_interface.ppp"
25
26#include "slist.hpp"
27
28// Defined in svm.cpp. If new svm or kernel types are added this should be updated.
29
30static const char *svm_type_table[] =
31{
32    "c_svc","nu_svc","one_class","epsilon_svr","nu_svr",NULL
33};
34
35static const char *kernel_type_table[]=
36{
37    "linear","polynomial","rbf","sigmoid","precomputed",NULL
38};
39
40#define Malloc(type,n) (type *)malloc((n)*sizeof(type))
41
42/*
43 * Save load functions for use with orange pickling.
44 * They are a copy of the standard libSVM save-load functions
45 * except that they read/write from/to std::iostream objects.
46 */
47
48int svm_save_model_alt(std::ostream& stream, const svm_model *model){
49    const svm_parameter& param = model->param;
50    stream.precision(17);
51
52    stream << "svm_type " << svm_type_table[param.svm_type] << endl;
53    stream << "kernel_type " << kernel_type_table[param.kernel_type] << endl;
54
55    if(param.kernel_type == POLY)
56        stream << "degree " << param.degree << endl;
57
58    if(param.kernel_type == POLY || param.kernel_type == RBF || param.kernel_type == SIGMOID)
59        stream << "gamma " << param.gamma << endl;
60
61    if(param.kernel_type == POLY || param.kernel_type == SIGMOID)
62        stream << "coef0 " << param.coef0 << endl;
63
64    int nr_class = model->nr_class;
65    int l = model->l;
66    stream << "nr_class " << nr_class << endl;
67    stream << "total_sv " << l << endl;
68    {
69        stream << "rho";
70        for(int i=0;i<nr_class*(nr_class-1)/2;i++)
71            stream << " " << model->rho[i];
72        stream << endl;
73    }
74
75    if(model->label)
76    {
77        stream << "label";
78        for(int i=0;i<nr_class;i++)
79            stream << " " << model->label[i];
80        stream << endl;
81    }
82
83    if(model->probA) // regression has probA only
84    {
85        stream << "probA";
86        for(int i=0;i<nr_class*(nr_class-1)/2;i++)
87            stream << " " << model->probA[i];
88        stream << endl;
89    }
90    if(model->probB)
91    {
92        stream << "probB";
93        for(int i=0;i<nr_class*(nr_class-1)/2;i++)
94            stream << " " << model->probB[i];
95        stream << endl;
96    }
97
98    if(model->nSV)
99    {
100        stream << "nr_sv";
101        for(int i=0;i<nr_class;i++)
102            stream << " " << model->nSV[i];
103        stream << endl;
104    }
105
106    stream << "SV" << endl;
107    const double * const *sv_coef = model->sv_coef;
108    const svm_node * const *SV = model->SV;
109
110    for(int i=0;i<l;i++)
111    {
112        for(int j=0;j<nr_class-1;j++)
113            stream << sv_coef[j][i] << " ";
114
115        const svm_node *p = SV[i];
116
117        if(param.kernel_type == PRECOMPUTED)
118            stream << "0:" << (int)(p->value) << " ";
119        else
120            while(p->index != -1)
121            {
122                stream << (int)(p->index) << ":" << p->value << " ";
123                p++;
124            }
125        stream << endl;
126    }
127
128    if (!stream.fail())
129        return 0;
130    else
131        return 1;
132}
133
134int svm_save_model_alt(std::string& buffer, const svm_model *model){
135    std::ostringstream strstream;
136    int ret = svm_save_model_alt(strstream, model);
137    buffer = strstream.rdbuf()->str();
138    return ret;
139}
140
141
142#include <algorithm>
143
144svm_model *svm_load_model_alt(std::istream& stream)
145{
146    svm_model *model = Malloc(svm_model,1);
147    svm_parameter& param = model->param;
148    model->rho = NULL;
149    model->probA = NULL;
150    model->probB = NULL;
151    model->label = NULL;
152    model->nSV = NULL;
153
154    char cmd[81];
155    stream.width(80);
156    while (stream.good())
157    {
158        stream >> cmd;
159
160        if(strcmp(cmd, "svm_type") == 0)
161        {
162            stream >> cmd;
163            int i;
164            for(i=0; svm_type_table[i]; i++)
165            {
166                if(strcmp(cmd, svm_type_table[i]) == 0)
167                {
168                    param.svm_type=i;
169                    break;
170                }
171            }
172            if(svm_type_table[i] == NULL)
173            {
174                fprintf(stderr, "unknown svm type.\n");
175                free(model->rho);
176                free(model->label);
177                free(model->nSV);
178                free(model);
179                return NULL;
180            }
181        }
182        else if(strcmp(cmd, "kernel_type") == 0)
183        {
184            stream >> cmd;
185            int i;
186            for(i=0;kernel_type_table[i];i++)
187            {
188                if(strcmp(kernel_type_table[i], cmd)==0)
189                {
190                    param.kernel_type=i;
191                    break;
192                }
193            }
194            if(kernel_type_table[i] == NULL)
195            {
196                fprintf(stderr,"unknown kernel function.\n");
197                free(model->rho);
198                free(model->label);
199                free(model->nSV);
200                free(model);
201                return NULL;
202            }
203        }
204        else if(strcmp(cmd,"degree")==0)
205            stream >> param.degree;
206        else if(strcmp(cmd,"gamma")==0)
207            stream >> param.gamma;
208        else if(strcmp(cmd,"coef0")==0)
209            stream >> param.coef0;
210        else if(strcmp(cmd,"nr_class")==0)
211            stream >> model->nr_class;
212        else if(strcmp(cmd,"total_sv")==0)
213            stream >> model->l;
214        else if(strcmp(cmd,"rho")==0)
215        {
216            int n = model->nr_class * (model->nr_class-1)/2;
217            model->rho = Malloc(double,n);
218            string rho_str;
219            for(int i=0;i<n;i++){
220                // Read the number into a string and then use strtod
221                // for proper handling of NaN's
222                stream >> rho_str;
223                model->rho[i] = strtod(rho_str.c_str(), NULL);
224            }
225        }
226        else if(strcmp(cmd,"label")==0)
227        {
228            int n = model->nr_class;
229            model->label = Malloc(int,n);
230            for(int i=0;i<n;i++)
231                stream >> model->label[i];
232        }
233        else if(strcmp(cmd,"probA")==0)
234        {
235            int n = model->nr_class * (model->nr_class-1)/2;
236            model->probA = Malloc(double,n);
237            for(int i=0;i<n;i++)
238                stream >> model->probA[i];
239        }
240        else if(strcmp(cmd,"probB")==0)
241        {
242            int n = model->nr_class * (model->nr_class-1)/2;
243            model->probB = Malloc(double,n);
244            for(int i=0;i<n;i++)
245                stream >> model->probB[i];
246        }
247        else if(strcmp(cmd,"nr_sv")==0)
248        {
249            int n = model->nr_class;
250            model->nSV = Malloc(int,n);
251            for(int i=0;i<n;i++)
252                stream >> model->nSV[i];
253        }
254        else if(strcmp(cmd,"SV")==0)
255        {
256            while(1)
257            {
258                int c = stream.get();
259                if(stream.eof() || c=='\n') break;
260            }
261            break;
262        }
263        else
264        {
265            fprintf(stderr,"unknown text in model file: [%s]\n",cmd);
266            free(model->rho);
267            free(model->label);
268            free(model->nSV);
269            free(model);
270            return NULL;
271        }
272    }
273    if (stream.fail()){
274        free(model->rho);
275        free(model->label);
276        free(model->nSV);
277        free(model);
278        return NULL;
279
280    }
281
282    // read sv_coef and SV
283
284    int elements = 0;
285    long pos = stream.tellg();
286
287    char *p,*endptr,*idx,*val;
288    string str_line;
289    while (!stream.eof() && !stream.fail())
290    {
291        getline(stream, str_line);
292        elements += std::count(str_line.begin(), str_line.end(), ':');
293    }
294
295    elements += model->l;
296
297    stream.clear();
298    stream.seekg(pos, ios::beg);
299
300    int m = model->nr_class - 1;
301    int l = model->l;
302    model->sv_coef = Malloc(double *,m);
303    int i;
304    for(i=0;i<m;i++)
305        model->sv_coef[i] = Malloc(double,l);
306    model->SV = Malloc(svm_node*,l);
307    svm_node *x_space = NULL;
308    if(l>0) x_space = Malloc(svm_node,elements);
309
310    int j=0;
311    char *line;
312    for(i=0;i<l;i++)
313    {
314        getline(stream, str_line);
315        if (str_line.size() == 0)
316            continue;
317
318        line = (char *) Malloc(char, str_line.size() + 1);
319        // Copy the line for strtok.
320        strcpy(line, str_line.c_str());
321
322        model->SV[i] = &x_space[j];
323
324        p = strtok(line, " \t");
325        model->sv_coef[0][i] = strtod(p,&endptr);
326        for(int k=1;k<m;k++)
327        {
328            p = strtok(NULL, " \t");
329            model->sv_coef[k][i] = strtod(p,&endptr);
330        }
331
332        while(1)
333        {
334            idx = strtok(NULL, ":");
335            val = strtok(NULL, " \t");
336
337            if(val == NULL)
338                break;
339            x_space[j].index = (int) strtol(idx,&endptr,10);
340            x_space[j].value = strtod(val,&endptr);
341
342            ++j;
343        }
344        x_space[j++].index = -1;
345        free(line);
346    }
347
348    if (stream.fail())
349        return NULL;
350
351    model->free_sv = 1; // XXX
352    return model;
353}
354
355svm_model *svm_load_model_alt(std::string& stream)
356{
357    std::istringstream strstream(stream);
358    return svm_load_model_alt(strstream);
359}
360
361svm_node* example_to_svm(const TExample &ex, svm_node* node, float last=0.0, int type=0){
362    if(type==0){
363        int index=1;
364        for(TExample::iterator i=ex.begin(); i!=ex.end(); i++){
365            if(i->isRegular() && i!=&ex.getClass()){
366                if(i->varType==TValue::FLOATVAR)
367                    node->value=float(*i);
368                else
369                    node->value=int(*i);
370                node->index=index++;
371                if(node->value==numeric_limits<float>::signaling_NaN() ||
372                    node->value==numeric_limits<int>::max())
373                    node--;
374                node++;
375            }
376        }
377    }
378    if(type == 1){ /*one dummy attr so we can pickle the classifier and keep the SV index in the training table*/
379        node->index=1;
380        node->value=last;
381        node++;
382    }
383    //cout<<(node-1)->index<<endl<<(node-2)->index<<endl;
384    node->index=-1;
385    node->value=last;
386    node++;
387    return node;
388}
389
390class SVM_NodeSort{
391public:
392    bool operator() (const svm_node &lhs, const svm_node &rhs){
393        return lhs.index < rhs.index;
394    }
395};
396
397svm_node* example_to_svm_sparse(const TExample &ex, svm_node* node, float last=0.0, bool useNonMeta=false){
398    svm_node *first=node;
399    int j=1;
400    int index=1;
401    if(useNonMeta)
402        for(TExample::iterator i=ex.begin(); i!=ex.end(); i++){
403            if(i->isRegular() && i!=&ex.getClass()){
404                if(i->varType==TValue::FLOATVAR)
405                    node->value=float(*i);
406                else
407                    node->value=int(*i);
408                node->index=index;
409                if(node->value==numeric_limits<float>::signaling_NaN() ||
410                    node->value==numeric_limits<int>::max())
411                    node--;
412                node++;
413            }
414            index++;
415        }
416    for(TMetaValues::const_iterator i=ex.meta.begin(); i!=ex.meta.end();i++,j++){
417        if(i->second.isRegular()){
418            if(i->second.varType==TValue::FLOATVAR)
419                node->value=float(i->second);
420            else
421                node->value=int(i->second);
422            node->index=index-i->first;
423            if(node->value==numeric_limits<float>::signaling_NaN() ||
424                node->value==numeric_limits<int>::max())
425                node--;
426            node++;
427        }
428    }
429    sort(first, node, SVM_NodeSort());
430    //cout<<first->index<<endl<<(first+1)->index<<endl;
431    node->index=-1;
432    node->value=last;
433    node++;
434    return node;
435}
436
437/*
438 * Precompute Gram matrix row for ex.
439 * Used for prediction when using the PRECOMPUTED kernel.
440 */
441svm_node* example_to_svm_precomputed(const TExample &ex, PExampleGenerator examples, PKernelFunc kernel, svm_node* node){
442    node->index = 0;
443    node->value = 0.0;
444    node++;
445    int k = 0;
446    PEITERATE(iter, examples){
447        node->index = ++k;
448        node->value = kernel.getReference()(*iter, ex);
449        node++;
450    }
451    node->index = -1; // sentry
452    node++;
453    return node;
454}
455
456int getNumOfElements(const TExample &ex, bool meta=false, bool useNonMeta=false){
457    if(!meta)
458        return std::max(ex.domain->attributes->size()+1, 2);
459    else{
460        int count=1; //we need one to indicate the end of a sequence
461        if(useNonMeta)
462            count+=ex.domain->attributes->size();
463        for(TMetaValues::const_iterator i=ex.meta.begin(); i!=ex.meta.end();i++)
464            if(i->second.isRegular())
465                count++;
466        return std::max(count,2);
467    }
468}
469
470int getNumOfElements(PExampleGenerator &examples, bool meta=false, bool useNonMeta=false){
471    if(!meta)
472        return getNumOfElements(*(examples->begin()), meta)*examples->numberOfExamples();
473    else{
474        int count=0;
475        for(TExampleGenerator::iterator ex(examples->begin()); ex!=examples->end(); ++ex){
476            count+=getNumOfElements(*ex, meta, useNonMeta);
477        }
478        return count;
479    }
480}
481
482#include "symmatrix.hpp"
483svm_node* init_precomputed_problem(svm_problem &problem, PExampleTable examples, TKernelFunc &kernel){
484    int n_examples = examples->numberOfExamples();
485    int i,j;
486    PSymMatrix matrix = mlnew TSymMatrix(n_examples, 0.0);
487    for (i = 0; i < n_examples; i++)
488        for (j = 0; j <= i; j++){
489            matrix->getref(i, j) = kernel(examples->at(i), examples->at(j));
490//          cout << i << " " << j << " " << matrix->getitem(i, j) << endl;
491        }
492    svm_node *x_space = Malloc(svm_node, n_examples * (n_examples + 2));
493    svm_node *node = x_space;
494
495    problem.l = n_examples;
496    problem.x = Malloc(svm_node*, n_examples);
497    problem.y = Malloc(double, n_examples);
498
499    for (i = 0; i < n_examples; i++){
500        problem.x[i] = node;
501        if (examples->domain->classVar->varType == TValue::FLOATVAR)
502            problem.y[i] = examples->at(i).getClass().floatV;
503        else
504            problem.y[i] = examples->at(i).getClass().intV;
505
506        node->index = 0;
507        node->value = i + 1; // instance indices are 1 based
508        node++;
509        for (j = 0; j < n_examples; j++){
510            node->index = j + 1;
511            node->value = matrix->getitem(i, j);
512            node++;
513        }
514        node->index = -1; // sentry
515        node++;
516    }
517    return x_space;
518}
519
520static void print_string_null(const char* s) {}
521
522TSVMLearner::TSVMLearner(){
523    //sparse=false; //if this learners supports sparse datasets (set to true in TSMVLearnerSparse subclass)
524    svm_type = NU_SVC;
525    kernel_type = RBF;
526    degree = 3;
527    gamma = 0;
528    coef0 = 0;
529    nu = 0.5;
530    cache_size = 250;
531    C = 1;
532    eps = 1e-3f;
533    p = 0.1f;
534    shrinking = 1;
535    probability = 0;
536    verbose = false;
537    nr_weight = 0;
538    weight_label = NULL;
539    weight = NULL;
540};
541
542PClassifier TSVMLearner::operator ()(PExampleGenerator examples, const int&){
543    svm_parameter param;
544    svm_problem prob;
545    svm_model* model;
546    svm_node* x_space;
547
548//  PExampleTable table = dynamic_cast<TExampleTable *>(examples.getUnwrappedPtr());
549
550    param.svm_type = svm_type;
551    param.kernel_type = kernel_type;
552    param.degree = degree;
553    param.gamma = gamma;
554    param.coef0 = coef0;
555    param.nu = nu;
556    param.C = C;
557    param.eps = eps;
558    param.p = p;
559    param.cache_size=cache_size;
560    param.shrinking=shrinking;
561    param.probability=probability;
562    param.nr_weight = nr_weight;
563    if (nr_weight > 0) {
564        param.weight_label = Malloc(int, nr_weight);
565        param.weight = Malloc(double, nr_weight);
566        int i;
567        for (i=0; i<nr_weight; i++) {
568            param.weight_label[i] = weight_label[i];
569            param.weight[i] = weight[i];
570        }
571    } else {
572        param.weight_label = NULL;
573        param.weight = NULL;
574    }
575
576    int classVarType;
577    if(examples->domain->classVar)
578        classVarType=examples->domain->classVar->varType;
579    else{
580        classVarType=TValue::NONE;
581        if(svm_type!=ONE_CLASS)
582            raiseError("Domain has no class variable");
583    }
584    if(classVarType==TValue::FLOATVAR && !(svm_type==EPSILON_SVR || svm_type==NU_SVR ||svm_type==ONE_CLASS))
585        raiseError("Domain has continuous class");
586
587    if(kernel_type==PRECOMPUTED && !kernelFunc)
588        raiseError("Custom kernel function not supplied");
589
590    int numElements=getNumOfElements(examples);
591
592    if(kernel_type != PRECOMPUTED)
593        x_space = init_problem(prob, examples, numElements);
594    else // Compute the matrix using the kernelFunc
595        x_space = init_precomputed_problem(prob, examples, kernelFunc.getReference());
596
597    if(param.gamma==0)
598        param.gamma=1.0f/(float(numElements)/float(prob.l)-1);
599
600    const char* error=svm_check_parameter(&prob,&param);
601    if(error){
602        free(x_space);
603        free(prob.y);
604        free(prob.x);
605        raiseError("LibSVM parameter error: %s", error);
606    }
607
608//  svm_print_string = (verbose)? &print_string_stdout : &print_string_null;
609
610    // If a probability model was requested LibSVM uses 5 fold
611    // cross-validation to estimate the prediction errors. This includes a
612    // random shuffle of the data. To make the results reproducible and
613    // consistent with 'svm-train' (which always learns just on one dataset
614    // in a process run) we reset the random seed. This could have unintended
615    // consequences.
616    if (param.probability)
617    {
618        srand(1);
619    }
620    svm_set_print_string_function((verbose)? NULL : &print_string_null);
621    model=svm_train(&prob,&param);
622
623  if ((svm_type==C_SVC || svm_type==NU_SVC) && !model->nSV) {
624    svm_free_and_destroy_model(&model);
625    if (x_space)
626      free(x_space);
627      raiseError("LibSVM returned no support vectors");
628  }
629
630    //cout<<"end training"<<endl;
631    svm_destroy_param(&param);
632    free(prob.y);
633    free(prob.x);
634//  tempExamples=NULL;
635    return PClassifier(createClassifier((param.svm_type==ONE_CLASS)?  \
636        mlnew TFloatVariable("one class") : examples->domain->classVar, examples, model, x_space));
637}
638
639svm_node* TSVMLearner::example_to_svm(const TExample &ex, svm_node* node, float last, int type){
640    return ::example_to_svm(ex, node, last, type);
641}
642
643svm_node* TSVMLearner::init_problem(svm_problem &problem, PExampleTable examples, int n_elements){
644    problem.l = examples->numberOfExamples();
645    problem.y = Malloc(double ,problem.l);
646    problem.x = Malloc(svm_node*, problem.l);
647    svm_node *x_space = Malloc(svm_node, n_elements);
648    svm_node *node = x_space;
649
650    for (int i = 0; i < problem.l; i++){
651        problem.x[i] = node;
652        node = example_to_svm(examples->at(i), node, i);
653        if (examples->domain->classVar)
654            if (examples->domain->classVar->varType == TValue::FLOATVAR)
655                problem.y[i] = examples->at(i).getClass().floatV;
656            else if (examples->domain->classVar->varType == TValue::INTVAR)
657                problem.y[i] = examples->at(i).getClass().intV;
658    }
659    return x_space;
660}
661
662int TSVMLearner::getNumOfElements(PExampleGenerator examples){
663    return ::getNumOfElements(examples);
664}
665
666TSVMClassifier* TSVMLearner::createClassifier(PVariable var, PExampleTable ex, svm_model* model, svm_node* x_space){
667    return mlnew TSVMClassifier(var, ex, model, x_space, kernelFunc);
668}
669
670TSVMLearner::~TSVMLearner(){
671    if(weight_label)
672        free(weight_label);
673
674    if(weight)
675            free(weight);
676}
677
678svm_node* TSVMLearnerSparse::example_to_svm(const TExample &ex, svm_node* node, float last, int type){
679    return ::example_to_svm_sparse(ex, node, last, useNonMeta);
680}
681
682int TSVMLearnerSparse::getNumOfElements(PExampleGenerator examples){
683    return ::getNumOfElements(examples, true, useNonMeta);
684}
685
686TSVMClassifier* TSVMLearnerSparse::createClassifier(PVariable var, PExampleTable ex, svm_model* model, svm_node *x_space){
687    return mlnew TSVMClassifierSparse(var, ex, model, x_space, useNonMeta, kernelFunc);
688}
689
690TSVMClassifier::TSVMClassifier(const PVariable &var, PExampleTable examples, svm_model* model, svm_node* x_space, PKernelFunc kernelFunc){
691    this->classVar = var;
692    this->model = model;
693    this->x_space = x_space;
694    this->examples = examples;
695    domain = examples->domain;
696    svm_type = svm_get_svm_type(model);
697    kernel_type = model->param.kernel_type;
698    this->kernelFunc = kernelFunc;
699
700    computesProbabilities = model && svm_check_probability_model(model) && \
701            (svm_type != NU_SVR && svm_type != EPSILON_SVR); // Disable prob. estimation for regression
702
703    int nr_class = svm_get_nr_class(model);
704    int i = 0;
705    supportVectors = mlnew TExampleTable(examples->domain);
706    if(x_space){
707        for(i = 0;i < model->l; i++){
708            svm_node *node = model->SV[i];
709            int sv_index = 0;
710            if(model->param.kernel_type != PRECOMPUTED){
711                // The value of the last node (with index == -1) holds the index of the training example.
712                while(node->index != -1)
713                    node++;
714                sv_index = int(node->value);
715            }
716            else
717                sv_index = int(node->value) - 1; // The indices for precomputed kernels are 1 based.
718            supportVectors->addExample(mlnew TExample(examples->at(sv_index)));
719        }
720    }
721   
722    if (svm_type == C_SVC || svm_type == NU_SVC){
723        nSV = mlnew TIntList(nr_class); // num of SVs for each class (sum = model->l)
724        for(i = 0;i < nr_class; i++)
725            nSV->at(i) = model->nSV[i];
726    }
727
728    coef = mlnew TFloatListList(nr_class-1);
729    for(i = 0; i < nr_class - 1; i++){
730        TFloatList *coefs = mlnew TFloatList(model->l);
731        for(int j = 0;j < model->l; j++)
732            coefs->at(j) = model->sv_coef[i][j];
733        coef->at(i)=coefs;
734    }
735    rho = mlnew TFloatList(nr_class*(nr_class-1)/2);
736    for(i = 0; i < nr_class*(nr_class-1)/2; i++)
737        rho->at(i) = model->rho[i];
738    if(model->probA){
739        probA = mlnew TFloatList(nr_class*(nr_class-1)/2);
740        if (model->param.svm_type != NU_SVR && model->param.svm_type != EPSILON_SVR && model->probB) // Regression has only probA
741            probB = mlnew TFloatList(nr_class*(nr_class-1)/2);
742        for(i=0; i<nr_class*(nr_class-1)/2; i++){
743            probA->at(i) = model->probA[i];
744            if (model->param.svm_type != NU_SVR && model->param.svm_type != EPSILON_SVR && model->probB)
745                probB->at(i) = model->probB[i];
746        }
747    }
748}
749
750TSVMClassifier::~TSVMClassifier(){
751    if (model)
752        svm_free_and_destroy_model(&model);
753    if(x_space)
754        free(x_space);
755}
756
757PDistribution TSVMClassifier::classDistribution(const TExample & example){
758    if(!model)
759        raiseError("No Model");
760
761    if(!computesProbabilities)
762        return TClassifierFD::classDistribution(example);
763
764    int n_elements;
765    if (model->param.kernel_type != PRECOMPUTED)
766        n_elements = getNumOfElements(example);
767    else
768        n_elements = examples->numberOfExamples() + 2;
769
770    int svm_type = svm_get_svm_type(model);
771    int nr_class = svm_get_nr_class(model);
772
773    svm_node *x = Malloc(svm_node, n_elements);
774    try{
775        if (model->param.kernel_type != PRECOMPUTED)
776            example_to_svm(example, x, -1.0);
777        else
778            example_to_svm_precomputed(example, examples, kernelFunc, x);
779    } catch (...) {
780        free(x);
781        throw;
782    }
783
784    int *labels=(int *) malloc(nr_class*sizeof(int));
785    svm_get_labels(model, labels);
786
787    double *prob_estimates = (double *) malloc(nr_class*sizeof(double));;
788    svm_predict_probability(model, x, prob_estimates);
789
790    PDistribution dist = TDistribution::create(example.domain->classVar);
791    for(int i=0; i<nr_class; i++)
792        dist->setint(labels[i], prob_estimates[i]);
793    free(x);
794    free(prob_estimates);
795    free(labels);
796    return dist;
797}
798
799TValue TSVMClassifier::operator()(const TExample & example){
800    if(!model)
801        raiseError("No Model");
802
803    int n_elements;
804    if (model->param.kernel_type != PRECOMPUTED)
805        n_elements = getNumOfElements(example); //example.domain->attributes->size();
806    else
807        n_elements = examples->numberOfExamples() + 2;
808
809    int svm_type = svm_get_svm_type(model);
810    int nr_class = svm_get_nr_class(model);
811
812    svm_node *x = Malloc(svm_node, n_elements);
813    try {
814        if (model->param.kernel_type != PRECOMPUTED)
815            example_to_svm(example, x);
816        else
817            example_to_svm_precomputed(example, examples, kernelFunc, x);
818    } catch (...) {
819        free(x);
820        throw;
821    }
822
823    double v;
824
825    if(svm_check_probability_model(model)){
826        double *prob = (double *) malloc(nr_class*sizeof(double));
827        v = svm_predict_probability(model, x, prob);
828        free(prob);
829    } else
830        v = svm_predict(model, x);
831
832    free(x);
833    if(svm_type==NU_SVR || svm_type==EPSILON_SVR || svm_type==ONE_CLASS)
834        return TValue(v);
835    else
836        return TValue(int(v));
837}
838
839PFloatList TSVMClassifier::getDecisionValues(const TExample &example){
840    if(!model)
841        raiseError("No Model");
842
843    int n_elements;
844        if (model->param.kernel_type != PRECOMPUTED)
845            n_elements = getNumOfElements(example); //example.domain->attributes->size();
846        else
847            n_elements = examples->numberOfExamples() + 2;
848
849    int svm_type=svm_get_svm_type(model);
850    int nr_class=svm_get_nr_class(model);
851
852    svm_node *x = Malloc(svm_node, n_elements);
853    try {
854        if (model->param.kernel_type != PRECOMPUTED)
855            example_to_svm(example, x);
856        else
857            example_to_svm_precomputed(example, examples, kernelFunc, x);
858    } catch (...) {
859        free(x);
860        throw;
861    }
862
863    int nDecValues = nr_class*(nr_class-1)/2;
864    double *dec = (double*) malloc(sizeof(double)*nDecValues);
865    svm_predict_values(model, x, dec);
866    PFloatList res = mlnew TFloatList(nDecValues);
867    for(int i=0; i<nDecValues; i++){
868        res->at(i) = dec[i];
869    }
870    free(x);
871    free(dec);
872    return res;
873}
874
875svm_node *TSVMClassifier::example_to_svm(const TExample &ex, svm_node *node, float last, int type){
876    return ::example_to_svm(ex, node, last, type);
877}
878
879int TSVMClassifier::getNumOfElements(const TExample& example){
880    return ::getNumOfElements(example);
881}
882svm_node *TSVMClassifierSparse::example_to_svm(const TExample &ex, svm_node *node, float last, int type){
883    return ::example_to_svm_sparse(ex, node, last, useNonMeta);
884}
885
886int TSVMClassifierSparse::getNumOfElements(const TExample& example){
887    return ::getNumOfElements(example, true, useNonMeta);
888}
889
890
Note: See TracBrowser for help on using the repository browser.