00001 #include <math.h>
00002 #include <stdio.h>
00003 #include <stdlib.h>
00004 #include <ctype.h>
00005 #include <float.h>
00006 #include <string.h>
00007 #include <stdarg.h>
00008 #include "svm.h"
00009 typedef float Qfloat;
00010 typedef signed char schar;
00011 #ifndef min
00012 template <class T> inline T min(T x,T y) { return (x<y)?x:y; }
00013 #endif
00014 #ifndef max
00015 template <class T> inline T max(T x,T y) { return (x>y)?x:y; }
00016 #endif
00017 template <class T> inline void swap(T& x, T& y) { T t=x; x=y; y=t; }
00018 template <class S, class T> inline void clone(T*& dst, S* src, int n)
00019 {
00020 dst = new T[n];
00021 memcpy((void *)dst,(void *)src,sizeof(T)*n);
00022 }
00023 #define INF HUGE_VAL
00024 #define Malloc(type,n) (type *)malloc((n)*sizeof(type))
00025 #if 1
00026 void info(char *fmt,...)
00027 {
00028 va_list ap;
00029 va_start(ap,fmt);
00030 vprintf(fmt,ap);
00031 va_end(ap);
00032 }
00033 void info_flush()
00034 {
00035 fflush(stdout);
00036 }
00037 #else
00038 void info(char *fmt,...) {}
00039 void info_flush() {}
00040 #endif
00041
00042
00043
00044
00045
00046
00047
00048 class Cache
00049 {
00050 public:
00051 Cache(int l,int size);
00052 ~Cache();
00053
00054
00055
00056
00057 int get_data(const int index, Qfloat **data, int len);
00058 void swap_index(int i, int j);
00059 private:
00060 int l;
00061 int size;
00062 struct head_t
00063 {
00064 head_t *prev, *next;
00065 Qfloat *data;
00066 int len;
00067 };
00068
00069 head_t* head;
00070 head_t lru_head;
00071 void lru_delete(head_t *h);
00072 void lru_insert(head_t *h);
00073 };
00074
00075 Cache::Cache(int l_,int size_):l(l_),size(size_)
00076 {
00077 head = (head_t *)calloc(l,sizeof(head_t));
00078 size /= sizeof(Qfloat);
00079 size -= l * sizeof(head_t) / sizeof(Qfloat);
00080 lru_head.next = lru_head.prev = &lru_head;
00081 }
00082
00083 Cache::~Cache()
00084 {
00085 for(head_t *h = lru_head.next; h != &lru_head; h=h->next)
00086 free(h->data);
00087 free(head);
00088 }
00089
00090 void Cache::lru_delete(head_t *h)
00091 {
00092
00093 h->prev->next = h->next;
00094 h->next->prev = h->prev;
00095 }
00096
00097 void Cache::lru_insert(head_t *h)
00098 {
00099
00100 h->next = &lru_head;
00101 h->prev = lru_head.prev;
00102 h->prev->next = h;
00103 h->next->prev = h;
00104 }
00105
00106 int Cache::get_data(const int index, Qfloat **data, int len)
00107 {
00108 head_t *h = &head[index];
00109 if(h->len) lru_delete(h);
00110 int more = len - h->len;
00111
00112 if(more > 0)
00113 {
00114
00115 while(size < more)
00116 {
00117 head_t *old = lru_head.next;
00118 lru_delete(old);
00119 free(old->data);
00120 size += old->len;
00121 old->data = 0;
00122 old->len = 0;
00123 }
00124
00125
00126 h->data = (Qfloat *)realloc(h->data,sizeof(Qfloat)*len);
00127 size -= more;
00128 std::swap(h->len,len);
00129 }
00130
00131 lru_insert(h);
00132 *data = h->data;
00133 return len;
00134 }
00135
00136 void Cache::swap_index(int i, int j)
00137 {
00138 if(i==j) return;
00139
00140 if(head[i].len) lru_delete(&head[i]);
00141 if(head[j].len) lru_delete(&head[j]);
00142 std::swap(head[i].data,head[j].data);
00143 std::swap(head[i].len,head[j].len);
00144 if(head[i].len) lru_insert(&head[i]);
00145 if(head[j].len) lru_insert(&head[j]);
00146
00147 if(i>j) std::swap(i,j);
00148 for(head_t *h = lru_head.next; h!=&lru_head; h=h->next)
00149 {
00150 if(h->len > i)
00151 {
00152 if(h->len > j)
00153 std::swap(h->data[i],h->data[j]);
00154 else
00155 {
00156
00157 lru_delete(h);
00158 free(h->data);
00159 size += h->len;
00160 h->data = 0;
00161 h->len = 0;
00162 }
00163 }
00164 }
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174 class Kernel {
00175 public:
00176 Kernel(int l, svm_node * const * x, const svm_parameter& param);
00177 virtual ~Kernel();
00178
00179 static double k_function(const svm_node *x, const svm_node *y,
00180 const svm_parameter& param);
00181 virtual Qfloat *get_Q(int column, int len) const = 0;
00182 virtual void swap_index(int i, int j) const
00183 {
00184 std::swap(x[i],x[j]);
00185 if(x_square) std::swap(x_square[i],x_square[j]);
00186 }
00187 protected:
00188
00189 double (Kernel::*kernel_function)(int i, int j) const;
00190
00191 private:
00192 const svm_node **x;
00193 double *x_square;
00194
00195
00196 const int kernel_type;
00197 const double degree;
00198 const double gamma;
00199 const double coef0;
00200
00201 static double dot(const svm_node *px, const svm_node *py);
00202 double kernel_linear(int i, int j) const
00203 {
00204 return dot(x[i],x[j]);
00205 }
00206 double kernel_poly(int i, int j) const
00207 {
00208 return pow(gamma*dot(x[i],x[j])+coef0,degree);
00209 }
00210 double kernel_rbf(int i, int j) const
00211 {
00212 return exp(-gamma*(x_square[i]+x_square[j]-2*dot(x[i],x[j])));
00213 }
00214 double kernel_sigmoid(int i, int j) const
00215 {
00216 return tanh(gamma*dot(x[i],x[j])+coef0);
00217 }
00218 };
00219
00220 Kernel::Kernel(int l, svm_node * const * x_, const svm_parameter& param)
00221 :kernel_type(param.kernel_type), degree(param.degree),
00222 gamma(param.gamma), coef0(param.coef0)
00223 {
00224 switch(kernel_type)
00225 {
00226 case SVM_LINEAR:
00227 kernel_function = &Kernel::kernel_linear;
00228 break;
00229 case POLY:
00230 kernel_function = &Kernel::kernel_poly;
00231 break;
00232 case RBF:
00233 kernel_function = &Kernel::kernel_rbf;
00234 break;
00235 case SIGMOID:
00236 kernel_function = &Kernel::kernel_sigmoid;
00237 break;
00238 }
00239
00240 clone(x,x_,l);
00241
00242 if(kernel_type == RBF)
00243 {
00244 x_square = new double[l];
00245 for(int i=0;i<l;i++)
00246 x_square[i] = dot(x[i],x[i]);
00247 }
00248 else
00249 x_square = 0;
00250 }
00251
00252 Kernel::~Kernel()
00253 {
00254 delete[] x;
00255 delete[] x_square;
00256 }
00257
00258 double Kernel::dot(const svm_node *px, const svm_node *py)
00259 {
00260 double sum = 0;
00261 while(px->index != -1 && py->index != -1)
00262 {
00263 if(px->index == py->index)
00264 {
00265 sum += px->value * py->value;
00266 ++px;
00267 ++py;
00268 }
00269 else
00270 {
00271 if(px->index > py->index)
00272 ++py;
00273 else
00274 ++px;
00275 }
00276 }
00277 return sum;
00278 }
00279
00280 double Kernel::k_function(const svm_node *x, const svm_node *y,
00281 const svm_parameter& param)
00282 {
00283 switch(param.kernel_type)
00284 {
00285 case SVM_LINEAR:
00286 return dot(x,y);
00287 case POLY:
00288 return pow(param.gamma*dot(x,y)+param.coef0,param.degree);
00289 case RBF:
00290 {
00291 double sum = 0;
00292 while(x->index != -1 && y->index !=-1)
00293 {
00294 if(x->index == y->index)
00295 {
00296 double d = x->value - y->value;
00297 sum += d*d;
00298 ++x;
00299 ++y;
00300 }
00301 else
00302 {
00303 if(x->index > y->index)
00304 {
00305 sum += y->value * y->value;
00306 ++y;
00307 }
00308 else
00309 {
00310 sum += x->value * x->value;
00311 ++x;
00312 }
00313 }
00314 }
00315
00316 while(x->index != -1)
00317 {
00318 sum += x->value * x->value;
00319 ++x;
00320 }
00321
00322 while(y->index != -1)
00323 {
00324 sum += y->value * y->value;
00325 ++y;
00326 }
00327
00328 return exp(-param.gamma*sum);
00329 }
00330 case SIGMOID:
00331 return tanh(param.gamma*dot(x,y)+param.coef0);
00332 default:
00333 return 0;
00334 }
00335 }
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 class Solver {
00356 public:
00357 Solver() {};
00358 virtual ~Solver() {};
00359
00360 struct SolutionInfo {
00361 double obj;
00362 double rho;
00363 double upper_bound_p;
00364 double upper_bound_n;
00365 double r;
00366 };
00367
00368 void Solve(int l, const Kernel& Q, const double *b_, const schar *y_,
00369 double *alpha_, double Cp, double Cn, double eps,
00370 SolutionInfo* si, int shrinking);
00371 protected:
00372 int active_size;
00373 schar *y;
00374 double *G;
00375 enum { LOWER_BOUND, UPPER_BOUND, FREE };
00376 char *alpha_status;
00377 double *alpha;
00378 const Kernel *Q;
00379 double eps;
00380 double Cp,Cn;
00381 double *b;
00382 int *active_set;
00383 double *G_bar;
00384 int l;
00385 bool unshrinked;
00386
00387 double get_C(int i)
00388 {
00389 return (y[i] > 0)? Cp : Cn;
00390 }
00391 void update_alpha_status(int i)
00392 {
00393 if(alpha[i] >= get_C(i))
00394 alpha_status[i] = UPPER_BOUND;
00395 else if(alpha[i] <= 0)
00396 alpha_status[i] = LOWER_BOUND;
00397 else alpha_status[i] = FREE;
00398 }
00399 bool is_upper_bound(int i) { return alpha_status[i] == UPPER_BOUND; }
00400 bool is_lower_bound(int i) { return alpha_status[i] == LOWER_BOUND; }
00401 bool is_free(int i) { return alpha_status[i] == FREE; }
00402 void swap_index(int i, int j);
00403 void reconstruct_gradient();
00404 virtual int select_working_set(int &i, int &j);
00405 virtual double calculate_rho();
00406 virtual void do_shrinking();
00407 };
00408
00409 void Solver::swap_index(int i, int j)
00410 {
00411 Q->swap_index(i,j);
00412 std::swap(y[i],y[j]);
00413 std::swap(G[i],G[j]);
00414 std::swap(alpha_status[i],alpha_status[j]);
00415 std::swap(alpha[i],alpha[j]);
00416 std::swap(b[i],b[j]);
00417 std::swap(active_set[i],active_set[j]);
00418 std::swap(G_bar[i],G_bar[j]);
00419 }
00420
00421 void Solver::reconstruct_gradient()
00422 {
00423
00424
00425 if(active_size == l) return;
00426
00427 int i;
00428 for(i=active_size;i<l;i++)
00429 G[i] = G_bar[i] + b[i];
00430
00431 for(i=0;i<active_size;i++)
00432 if(is_free(i))
00433 {
00434 const Qfloat *Q_i = Q->get_Q(i,l);
00435 double alpha_i = alpha[i];
00436 for(int j=active_size;j<l;j++)
00437 G[j] += alpha_i * Q_i[j];
00438 }
00439 }
00440
00441 void Solver::Solve(int l, const Kernel& Q, const double *b_, const schar *y_,
00442 double *alpha_, double Cp, double Cn, double eps,
00443 SolutionInfo* si, int shrinking)
00444 {
00445 this->l = l;
00446 this->Q = &Q;
00447 clone(b, b_,l);
00448 clone(y, y_,l);
00449 clone(alpha,alpha_,l);
00450 this->Cp = Cp;
00451 this->Cn = Cn;
00452 this->eps = eps;
00453 unshrinked = false;
00454
00455
00456 {
00457 alpha_status = new char[l];
00458 for(int i=0;i<l;i++)
00459 update_alpha_status(i);
00460 }
00461
00462
00463 {
00464 active_set = new int[l];
00465 for(int i=0;i<l;i++)
00466 active_set[i] = i;
00467 active_size = l;
00468 }
00469
00470
00471 {
00472 G = new double[l];
00473 G_bar = new double[l];
00474 int i;
00475 for(i=0;i<l;i++)
00476 {
00477 G[i] = b[i];
00478 G_bar[i] = 0;
00479 }
00480 for(i=0;i<l;i++)
00481 if(!is_lower_bound(i))
00482 {
00483 Qfloat *Q_i = Q.get_Q(i,l);
00484 double alpha_i = alpha[i];
00485 int j;
00486 for(j=0;j<l;j++)
00487 G[j] += alpha_i*Q_i[j];
00488 if(is_upper_bound(i))
00489 for(j=0;j<l;j++)
00490 G_bar[j] += get_C(i) * Q_i[j];
00491 }
00492 }
00493
00494
00495
00496 int iter = 0;
00497 int counter = min(l,1000)+1;
00498
00499 while(1)
00500 {
00501
00502
00503 if(--counter == 0)
00504 {
00505 counter = min(l,1000);
00506 if(shrinking) do_shrinking();
00507 info("."); info_flush();
00508 }
00509
00510 int i,j;
00511 if(select_working_set(i,j)!=0)
00512 {
00513
00514 reconstruct_gradient();
00515
00516 active_size = l;
00517 info("*"); info_flush();
00518 if(select_working_set(i,j)!=0)
00519 break;
00520 else
00521 counter = 1;
00522 }
00523
00524 ++iter;
00525
00526
00527
00528 const Qfloat *Q_i = Q.get_Q(i,active_size);
00529 const Qfloat *Q_j = Q.get_Q(j,active_size);
00530
00531 double C_i = get_C(i);
00532 double C_j = get_C(j);
00533
00534 double old_alpha_i = alpha[i];
00535 double old_alpha_j = alpha[j];
00536
00537 if(y[i]!=y[j])
00538 {
00539 double delta = (-G[i]-G[j])/std::max(Q_i[i]+Q_j[j]+2*Q_i[j],(Qfloat)0);
00540 double diff = alpha[i] - alpha[j];
00541 alpha[i] += delta;
00542 alpha[j] += delta;
00543
00544 if(diff > 0)
00545 {
00546 if(alpha[j] < 0)
00547 {
00548 alpha[j] = 0;
00549 alpha[i] = diff;
00550 }
00551 }
00552 else
00553 {
00554 if(alpha[i] < 0)
00555 {
00556 alpha[i] = 0;
00557 alpha[j] = -diff;
00558 }
00559 }
00560 if(diff > C_i - C_j)
00561 {
00562 if(alpha[i] > C_i)
00563 {
00564 alpha[i] = C_i;
00565 alpha[j] = C_i - diff;
00566 }
00567 }
00568 else
00569 {
00570 if(alpha[j] > C_j)
00571 {
00572 alpha[j] = C_j;
00573 alpha[i] = C_j + diff;
00574 }
00575 }
00576 }
00577 else
00578 {
00579 double delta = (G[i]-G[j])/std::max(Q_i[i]+Q_j[j]-2*Q_i[j],(Qfloat)0);
00580 double sum = alpha[i] + alpha[j];
00581 alpha[i] -= delta;
00582 alpha[j] += delta;
00583 if(sum > C_i)
00584 {
00585 if(alpha[i] > C_i)
00586 {
00587 alpha[i] = C_i;
00588 alpha[j] = sum - C_i;
00589 }
00590 }
00591 else
00592 {
00593 if(alpha[j] < 0)
00594 {
00595 alpha[j] = 0;
00596 alpha[i] = sum;
00597 }
00598 }
00599 if(sum > C_j)
00600 {
00601 if(alpha[j] > C_j)
00602 {
00603 alpha[j] = C_j;
00604 alpha[i] = sum - C_j;
00605 }
00606 }
00607 else
00608 {
00609 if(alpha[i] < 0)
00610 {
00611 alpha[i] = 0;
00612 alpha[j] = sum;
00613 }
00614 }
00615 }
00616
00617
00618
00619 double delta_alpha_i = alpha[i] - old_alpha_i;
00620 double delta_alpha_j = alpha[j] - old_alpha_j;
00621
00622 for(int k=0;k<active_size;k++)
00623 {
00624 G[k] += Q_i[k]*delta_alpha_i + Q_j[k]*delta_alpha_j;
00625 }
00626
00627
00628
00629 {
00630 bool ui = is_upper_bound(i);
00631 bool uj = is_upper_bound(j);
00632 update_alpha_status(i);
00633 update_alpha_status(j);
00634 int k;
00635 if(ui != is_upper_bound(i))
00636 {
00637 Q_i = Q.get_Q(i,l);
00638 if(ui)
00639 for(k=0;k<l;k++)
00640 G_bar[k] -= C_i * Q_i[k];
00641 else
00642 for(k=0;k<l;k++)
00643 G_bar[k] += C_i * Q_i[k];
00644 }
00645
00646 if(uj != is_upper_bound(j))
00647 {
00648 Q_j = Q.get_Q(j,l);
00649 if(uj)
00650 for(k=0;k<l;k++)
00651 G_bar[k] -= C_j * Q_j[k];
00652 else
00653 for(k=0;k<l;k++)
00654 G_bar[k] += C_j * Q_j[k];
00655 }
00656 }
00657 }
00658
00659
00660
00661 si->rho = calculate_rho();
00662
00663
00664 {
00665 double v = 0;
00666 int i;
00667 for(i=0;i<l;i++)
00668 v += alpha[i] * (G[i] + b[i]);
00669
00670 si->obj = v/2;
00671 }
00672
00673
00674 {
00675 for(int i=0;i<l;i++)
00676 alpha_[active_set[i]] = alpha[i];
00677 }
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687 si->upper_bound_p = Cp;
00688 si->upper_bound_n = Cn;
00689
00690 info("\noptimization finished, #iter = %d\n",iter);
00691
00692 delete[] b;
00693 delete[] y;
00694 delete[] alpha;
00695 delete[] alpha_status;
00696 delete[] active_set;
00697 delete[] G;
00698 delete[] G_bar;
00699 }
00700
00701
00702 int Solver::select_working_set(int &out_i, int &out_j)
00703 {
00704
00705
00706
00707
00708 double Gmax1 = -INF;
00709 int Gmax1_idx = -1;
00710
00711 double Gmax2 = -INF;
00712 int Gmax2_idx = -1;
00713
00714 for(int i=0;i<active_size;i++)
00715 {
00716 if(y[i]==+1)
00717 {
00718 if(!is_upper_bound(i))
00719 {
00720 if(-G[i] > Gmax1)
00721 {
00722 Gmax1 = -G[i];
00723 Gmax1_idx = i;
00724 }
00725 }
00726 if(!is_lower_bound(i))
00727 {
00728 if(G[i] > Gmax2)
00729 {
00730 Gmax2 = G[i];
00731 Gmax2_idx = i;
00732 }
00733 }
00734 }
00735 else
00736 {
00737 if(!is_upper_bound(i))
00738 {
00739 if(-G[i] > Gmax2)
00740 {
00741 Gmax2 = -G[i];
00742 Gmax2_idx = i;
00743 }
00744 }
00745 if(!is_lower_bound(i))
00746 {
00747 if(G[i] > Gmax1)
00748 {
00749 Gmax1 = G[i];
00750 Gmax1_idx = i;
00751 }
00752 }
00753 }
00754 }
00755
00756 if(Gmax1+Gmax2 < eps)
00757 return 1;
00758
00759 out_i = Gmax1_idx;
00760 out_j = Gmax2_idx;
00761 return 0;
00762 }
00763
00764 void Solver::do_shrinking()
00765 {
00766 int i,j,k;
00767 if(select_working_set(i,j)!=0) return;
00768 double Gm1 = -y[j]*G[j];
00769 double Gm2 = y[i]*G[i];
00770
00771
00772
00773 for(k=0;k<active_size;k++)
00774 {
00775 if(is_lower_bound(k))
00776 {
00777 if(y[k]==+1)
00778 {
00779 if(-G[k] >= Gm1) continue;
00780 }
00781 else if(-G[k] >= Gm2) continue;
00782 }
00783 else if(is_upper_bound(k))
00784 {
00785 if(y[k]==+1)
00786 {
00787 if(G[k] >= Gm2) continue;
00788 }
00789 else if(G[k] >= Gm1) continue;
00790 }
00791 else continue;
00792
00793 --active_size;
00794 swap_index(k,active_size);
00795 --k;
00796 }
00797
00798
00799
00800 if(unshrinked || -(Gm1 + Gm2) > eps*10) return;
00801
00802 unshrinked = true;
00803 reconstruct_gradient();
00804
00805 for(k=l-1;k>=active_size;k--)
00806 {
00807 if(is_lower_bound(k))
00808 {
00809 if(y[k]==+1)
00810 {
00811 if(-G[k] < Gm1) continue;
00812 }
00813 else if(-G[k] < Gm2) continue;
00814 }
00815 else if(is_upper_bound(k))
00816 {
00817 if(y[k]==+1)
00818 {
00819 if(G[k] < Gm2) continue;
00820 }
00821 else if(G[k] < Gm1) continue;
00822 }
00823 else continue;
00824
00825 swap_index(k,active_size);
00826 active_size++;
00827 ++k;
00828 }
00829 }
00830
00831 double Solver::calculate_rho()
00832 {
00833 double r;
00834 int nr_free = 0;
00835 double ub = INF, lb = -INF, sum_free = 0;
00836 for(int i=0;i<active_size;i++)
00837 {
00838 double yG = y[i]*G[i];
00839
00840 if(is_lower_bound(i))
00841 {
00842 if(y[i] > 0)
00843 ub = min(ub,yG);
00844 else
00845 lb = std::max(lb,yG);
00846 }
00847 else if(is_upper_bound(i))
00848 {
00849 if(y[i] < 0)
00850 ub = min(ub,yG);
00851 else
00852 lb = std::max(lb,yG);
00853 }
00854 else
00855 {
00856 ++nr_free;
00857 sum_free += yG;
00858 }
00859 }
00860
00861 if(nr_free>0)
00862 r = sum_free/nr_free;
00863 else
00864 r = (ub+lb)/2;
00865
00866 return r;
00867 }
00868
00869
00870
00871
00872
00873
00874 class Solver_NU : public Solver
00875 {
00876 public:
00877 Solver_NU() {}
00878 void Solve(int l, const Kernel& Q, const double *b, const schar *y,
00879 double *alpha, double Cp, double Cn, double eps,
00880 SolutionInfo* si, int shrinking)
00881 {
00882 this->si = si;
00883 Solver::Solve(l,Q,b,y,alpha,Cp,Cn,eps,si,shrinking);
00884 }
00885 private:
00886 SolutionInfo *si;
00887 int select_working_set(int &i, int &j);
00888 double calculate_rho();
00889 void do_shrinking();
00890 };
00891
00892 int Solver_NU::select_working_set(int &out_i, int &out_j)
00893 {
00894
00895
00896
00897
00898 double Gmax1 = -INF;
00899 int Gmax1_idx = -1;
00900
00901 double Gmax2 = -INF;
00902 int Gmax2_idx = -1;
00903
00904 double Gmax3 = -INF;
00905 int Gmax3_idx = -1;
00906
00907 double Gmax4 = -INF;
00908 int Gmax4_idx = -1;
00909
00910 for(int i=0;i<active_size;i++)
00911 {
00912 if(y[i]==+1)
00913 {
00914 if(!is_upper_bound(i))
00915 {
00916 if(-G[i] > Gmax1)
00917 {
00918 Gmax1 = -G[i];
00919 Gmax1_idx = i;
00920 }
00921 }
00922 if(!is_lower_bound(i))
00923 {
00924 if(G[i] > Gmax2)
00925 {
00926 Gmax2 = G[i];
00927 Gmax2_idx = i;
00928 }
00929 }
00930 }
00931 else
00932 {
00933 if(!is_upper_bound(i))
00934 {
00935 if(-G[i] > Gmax3)
00936 {
00937 Gmax3 = -G[i];
00938 Gmax3_idx = i;
00939 }
00940 }
00941 if(!is_lower_bound(i))
00942 {
00943 if(G[i] > Gmax4)
00944 {
00945 Gmax4 = G[i];
00946 Gmax4_idx = i;
00947 }
00948 }
00949 }
00950 }
00951
00952 if(std::max(Gmax1+Gmax2,Gmax3+Gmax4) < eps)
00953 return 1;
00954
00955 if(Gmax1+Gmax2 > Gmax3+Gmax4)
00956 {
00957 out_i = Gmax1_idx;
00958 out_j = Gmax2_idx;
00959 }
00960 else
00961 {
00962 out_i = Gmax3_idx;
00963 out_j = Gmax4_idx;
00964 }
00965 return 0;
00966 }
00967
00968 void Solver_NU::do_shrinking()
00969 {
00970 double Gmax1 = -INF;
00971 double Gmax2 = -INF;
00972 double Gmax3 = -INF;
00973 double Gmax4 = -INF;
00974
00975 int k;
00976 for(k=0;k<active_size;k++)
00977 {
00978 if(!is_upper_bound(k))
00979 {
00980 if(y[k]==+1)
00981 {
00982 if(-G[k] > Gmax1) Gmax1 = -G[k];
00983 }
00984 else if(-G[k] > Gmax3) Gmax3 = -G[k];
00985 }
00986 if(!is_lower_bound(k))
00987 {
00988 if(y[k]==+1)
00989 {
00990 if(G[k] > Gmax2) Gmax2 = G[k];
00991 }
00992 else if(G[k] > Gmax4) Gmax4 = G[k];
00993 }
00994 }
00995
00996 double Gm1 = -Gmax2;
00997 double Gm2 = -Gmax1;
00998 double Gm3 = -Gmax4;
00999 double Gm4 = -Gmax3;
01000
01001 for(k=0;k<active_size;k++)
01002 {
01003 if(is_lower_bound(k))
01004 {
01005 if(y[k]==+1)
01006 {
01007 if(-G[k] >= Gm1) continue;
01008 }
01009 else if(-G[k] >= Gm3) continue;
01010 }
01011 else if(is_upper_bound(k))
01012 {
01013 if(y[k]==+1)
01014 {
01015 if(G[k] >= Gm2) continue;
01016 }
01017 else if(G[k] >= Gm4) continue;
01018 }
01019 else continue;
01020
01021 --active_size;
01022 swap_index(k,active_size);
01023 --k;
01024 }
01025
01026
01027
01028 if(unshrinked || std::max(-(Gm1+Gm2),-(Gm3+Gm4)) > eps*10) return;
01029
01030 unshrinked = true;
01031 reconstruct_gradient();
01032
01033 for(k=l-1;k>=active_size;k--)
01034 {
01035 if(is_lower_bound(k))
01036 {
01037 if(y[k]==+1)
01038 {
01039 if(-G[k] < Gm1) continue;
01040 }
01041 else if(-G[k] < Gm3) continue;
01042 }
01043 else if(is_upper_bound(k))
01044 {
01045 if(y[k]==+1)
01046 {
01047 if(G[k] < Gm2) continue;
01048 }
01049 else if(G[k] < Gm4) continue;
01050 }
01051 else continue;
01052
01053 swap_index(k,active_size);
01054 active_size++;
01055 ++k;
01056 }
01057 }
01058
01059 double Solver_NU::calculate_rho()
01060 {
01061 int nr_free1 = 0,nr_free2 = 0;
01062 double ub1 = INF, ub2 = INF;
01063 double lb1 = -INF, lb2 = -INF;
01064 double sum_free1 = 0, sum_free2 = 0;
01065
01066 for(int i=0;i<active_size;i++)
01067 {
01068 if(y[i]==+1)
01069 {
01070 if(is_lower_bound(i))
01071 ub1 = min(ub1,G[i]);
01072 else if(is_upper_bound(i))
01073 lb1 = std::max(lb1,G[i]);
01074 else
01075 {
01076 ++nr_free1;
01077 sum_free1 += G[i];
01078 }
01079 }
01080 else
01081 {
01082 if(is_lower_bound(i))
01083 ub2 = min(ub2,G[i]);
01084 else if(is_upper_bound(i))
01085 lb2 = std::max(lb2,G[i]);
01086 else
01087 {
01088 ++nr_free2;
01089 sum_free2 += G[i];
01090 }
01091 }
01092 }
01093
01094 double r1,r2;
01095 if(nr_free1 > 0)
01096 r1 = sum_free1/nr_free1;
01097 else
01098 r1 = (ub1+lb1)/2;
01099
01100 if(nr_free2 > 0)
01101 r2 = sum_free2/nr_free2;
01102 else
01103 r2 = (ub2+lb2)/2;
01104
01105 si->r = (r1+r2)/2;
01106 return (r1-r2)/2;
01107 }
01108
01109
01110
01111
01112 class SVC_Q: public Kernel
01113 {
01114 public:
01115 SVC_Q(const svm_problem& prob, const svm_parameter& param, const schar *y_)
01116 :Kernel(prob.l, prob.x, param)
01117 {
01118 clone(y,y_,prob.l);
01119 cache = new Cache(prob.l,(int)(param.cache_size*(1<<20)));
01120 }
01121
01122 Qfloat *get_Q(int i, int len) const
01123 {
01124 Qfloat *data;
01125 int start;
01126 if((start = cache->get_data(i,&data,len)) < len)
01127 {
01128 for(int j=start;j<len;j++)
01129 data[j] = (Qfloat)(y[i]*y[j]*(this->*kernel_function)(i,j));
01130 }
01131 return data;
01132 }
01133
01134 void swap_index(int i, int j) const
01135 {
01136 cache->swap_index(i,j);
01137 Kernel::swap_index(i,j);
01138 std::swap(y[i],y[j]);
01139 }
01140
01141 ~SVC_Q()
01142 {
01143 delete[] y;
01144 delete cache;
01145 }
01146 private:
01147 schar *y;
01148 Cache *cache;
01149 };
01150
01151 class ONE_CLASS_Q: public Kernel
01152 {
01153 public:
01154 ONE_CLASS_Q(const svm_problem& prob, const svm_parameter& param)
01155 :Kernel(prob.l, prob.x, param)
01156 {
01157 cache = new Cache(prob.l,(int)(param.cache_size*(1<<20)));
01158 }
01159
01160 Qfloat *get_Q(int i, int len) const
01161 {
01162 Qfloat *data;
01163 int start;
01164 if((start = cache->get_data(i,&data,len)) < len)
01165 {
01166 for(int j=start;j<len;j++)
01167 data[j] = (Qfloat)(this->*kernel_function)(i,j);
01168 }
01169 return data;
01170 }
01171
01172 void swap_index(int i, int j) const
01173 {
01174 cache->swap_index(i,j);
01175 Kernel::swap_index(i,j);
01176 }
01177
01178 ~ONE_CLASS_Q()
01179 {
01180 delete cache;
01181 }
01182 private:
01183 Cache *cache;
01184 };
01185
01186 class SVR_Q: public Kernel
01187 {
01188 public:
01189 SVR_Q(const svm_problem& prob, const svm_parameter& param)
01190 :Kernel(prob.l, prob.x, param)
01191 {
01192 l = prob.l;
01193 cache = new Cache(l,(int)(param.cache_size*(1<<20)));
01194 sign = new schar[2*l];
01195 index = new int[2*l];
01196 for(int k=0;k<l;k++)
01197 {
01198 sign[k] = 1;
01199 sign[k+l] = -1;
01200 index[k] = k;
01201 index[k+l] = k;
01202 }
01203 buffer[0] = new Qfloat[2*l];
01204 buffer[1] = new Qfloat[2*l];
01205 next_buffer = 0;
01206 }
01207
01208 void swap_index(int i, int j) const
01209 {
01210 std::swap(sign[i],sign[j]);
01211 std::swap(index[i],index[j]);
01212 }
01213
01214 Qfloat *get_Q(int i, int len) const
01215 {
01216 Qfloat *data;
01217 int real_i = index[i];
01218 if(cache->get_data(real_i,&data,l) < l)
01219 {
01220 for(int j=0;j<l;j++)
01221 data[j] = (Qfloat)(this->*kernel_function)(real_i,j);
01222 }
01223
01224
01225 Qfloat *buf = buffer[next_buffer];
01226 next_buffer = 1 - next_buffer;
01227 schar si = sign[i];
01228 for(int j=0;j<len;j++)
01229 buf[j] = si * sign[j] * data[index[j]];
01230 return buf;
01231 }
01232
01233 ~SVR_Q()
01234 {
01235 delete cache;
01236 delete[] sign;
01237 delete[] index;
01238 delete[] buffer[0];
01239 delete[] buffer[1];
01240 }
01241 private:
01242 int l;
01243 Cache *cache;
01244 schar *sign;
01245 int *index;
01246 mutable int next_buffer;
01247 Qfloat* buffer[2];
01248 };
01249
01250
01251
01252
01253 static void solve_c_svc(
01254 const svm_problem *prob, const svm_parameter* param,
01255 double *alpha, Solver::SolutionInfo* si, double Cp, double Cn)
01256 {
01257 int l = prob->l;
01258 double *minus_ones = new double[l];
01259 schar *y = new schar[l];
01260
01261 int i;
01262
01263 for(i=0;i<l;i++)
01264 {
01265 alpha[i] = 0;
01266 minus_ones[i] = -1;
01267 if(prob->y[i] > 0) y[i] = +1; else y[i]=-1;
01268 }
01269
01270 Solver s;
01271 s.Solve(l, SVC_Q(*prob,*param,y), minus_ones, y,
01272 alpha, Cp, Cn, param->eps, si, param->shrinking);
01273
01274 double sum_alpha=0;
01275 for(i=0;i<l;i++)
01276 sum_alpha += alpha[i];
01277
01278 if (Cp==Cn)
01279 info("nu = %f\n", sum_alpha/(Cp*prob->l));
01280
01281 for(i=0;i<l;i++)
01282 alpha[i] *= y[i];
01283
01284 delete[] minus_ones;
01285 delete[] y;
01286 }
01287
01288 static void solve_nu_svc(
01289 const svm_problem *prob, const svm_parameter *param,
01290 double *alpha, Solver::SolutionInfo* si)
01291 {
01292 int i;
01293 int l = prob->l;
01294 double nu = param->nu;
01295
01296 schar *y = new schar[l];
01297
01298 for(i=0;i<l;i++)
01299 if(prob->y[i]>0)
01300 y[i] = +1;
01301 else
01302 y[i] = -1;
01303
01304 double sum_pos = nu*l/2;
01305 double sum_neg = nu*l/2;
01306
01307 for(i=0;i<l;i++)
01308 if(y[i] == +1)
01309 {
01310 alpha[i] = min(1.0,sum_pos);
01311 sum_pos -= alpha[i];
01312 }
01313 else
01314 {
01315 alpha[i] = min(1.0,sum_neg);
01316 sum_neg -= alpha[i];
01317 }
01318
01319 double *zeros = new double[l];
01320
01321 for(i=0;i<l;i++)
01322 zeros[i] = 0;
01323
01324 Solver_NU s;
01325 s.Solve(l, SVC_Q(*prob,*param,y), zeros, y,
01326 alpha, 1.0, 1.0, param->eps, si, param->shrinking);
01327 double r = si->r;
01328
01329 info("C = %f\n",1/r);
01330
01331 for(i=0;i<l;i++)
01332 alpha[i] *= y[i]/r;
01333
01334 si->rho /= r;
01335 si->obj /= (r*r);
01336 si->upper_bound_p = 1/r;
01337 si->upper_bound_n = 1/r;
01338
01339 delete[] y;
01340 delete[] zeros;
01341 }
01342
01343 static void solve_one_class(
01344 const svm_problem *prob, const svm_parameter *param,
01345 double *alpha, Solver::SolutionInfo* si)
01346 {
01347 int l = prob->l;
01348 double *zeros = new double[l];
01349 schar *ones = new schar[l];
01350 int i;
01351
01352 int n = (int)(param->nu*prob->l);
01353
01354 for(i=0;i<n;i++)
01355 alpha[i] = 1;
01356 alpha[n] = param->nu * prob->l - n;
01357 for(i=n+1;i<l;i++)
01358 alpha[i] = 0;
01359
01360 for(i=0;i<l;i++)
01361 {
01362 zeros[i] = 0;
01363 ones[i] = 1;
01364 }
01365
01366 Solver s;
01367 s.Solve(l, ONE_CLASS_Q(*prob,*param), zeros, ones,
01368 alpha, 1.0, 1.0, param->eps, si, param->shrinking);
01369
01370 delete[] zeros;
01371 delete[] ones;
01372 }
01373
01374 static void solve_epsilon_svr(
01375 const svm_problem *prob, const svm_parameter *param,
01376 double *alpha, Solver::SolutionInfo* si)
01377 {
01378 int l = prob->l;
01379 double *alpha2 = new double[2*l];
01380 double *linear_term = new double[2*l];
01381 schar *y = new schar[2*l];
01382 int i;
01383
01384 for(i=0;i<l;i++)
01385 {
01386 alpha2[i] = 0;
01387 linear_term[i] = param->p - prob->y[i];
01388 y[i] = 1;
01389
01390 alpha2[i+l] = 0;
01391 linear_term[i+l] = param->p + prob->y[i];
01392 y[i+l] = -1;
01393 }
01394
01395 Solver s;
01396 s.Solve(2*l, SVR_Q(*prob,*param), linear_term, y,
01397 alpha2, param->C, param->C, param->eps, si, param->shrinking);
01398
01399 double sum_alpha = 0;
01400 for(i=0;i<l;i++)
01401 {
01402 alpha[i] = alpha2[i] - alpha2[i+l];
01403 sum_alpha += fabs(alpha[i]);
01404 }
01405 info("nu = %f\n",sum_alpha/(param->C*l));
01406
01407 delete[] alpha2;
01408 delete[] linear_term;
01409 delete[] y;
01410 }
01411
01412 static void solve_nu_svr(
01413 const svm_problem *prob, const svm_parameter *param,
01414 double *alpha, Solver::SolutionInfo* si)
01415 {
01416 int l = prob->l;
01417 double C = param->C;
01418 double *alpha2 = new double[2*l];
01419 double *linear_term = new double[2*l];
01420 schar *y = new schar[2*l];
01421 int i;
01422
01423 double sum = C * param->nu * l / 2;
01424 for(i=0;i<l;i++)
01425 {
01426 alpha2[i] = alpha2[i+l] = min(sum,C);
01427 sum -= alpha2[i];
01428
01429 linear_term[i] = - prob->y[i];
01430 y[i] = 1;
01431
01432 linear_term[i+l] = prob->y[i];
01433 y[i+l] = -1;
01434 }
01435
01436 Solver_NU s;
01437 s.Solve(2*l, SVR_Q(*prob,*param), linear_term, y,
01438 alpha2, C, C, param->eps, si, param->shrinking);
01439
01440 info("epsilon = %f\n",-si->r);
01441
01442 for(i=0;i<l;i++)
01443 alpha[i] = alpha2[i] - alpha2[i+l];
01444
01445 delete[] alpha2;
01446 delete[] linear_term;
01447 delete[] y;
01448 }
01449
01450
01451
01452
01453 struct decision_function
01454 {
01455 double *alpha;
01456 double rho;
01457 };
01458
01459 decision_function svm_train_one(
01460 const svm_problem *prob, const svm_parameter *param,
01461 double Cp, double Cn)
01462 {
01463 double *alpha = Malloc(double,prob->l);
01464 Solver::SolutionInfo si;
01465 switch(param->svm_type)
01466 {
01467 case C_SVC:
01468 solve_c_svc(prob,param,alpha,&si,Cp,Cn);
01469 break;
01470 case NU_SVC:
01471 solve_nu_svc(prob,param,alpha,&si);
01472 break;
01473 case ONE_CLASS:
01474 solve_one_class(prob,param,alpha,&si);
01475 break;
01476 case EPSILON_SVR:
01477 solve_epsilon_svr(prob,param,alpha,&si);
01478 break;
01479 case NU_SVR:
01480 solve_nu_svr(prob,param,alpha,&si);
01481 break;
01482 }
01483
01484 info("obj = %f, rho = %f\n",si.obj,si.rho);
01485
01486
01487
01488 int nSV = 0;
01489 int nBSV = 0;
01490 for(int i=0;i<prob->l;i++)
01491 {
01492 if(fabs(alpha[i]) > 0)
01493 {
01494 ++nSV;
01495 if(prob->y[i] > 0)
01496 {
01497 if(fabs(alpha[i]) >= si.upper_bound_p)
01498 ++nBSV;
01499 }
01500 else
01501 {
01502 if(fabs(alpha[i]) >= si.upper_bound_n)
01503 ++nBSV;
01504 }
01505 }
01506 }
01507
01508 info("nSV = %d, nBSV = %d\n",nSV,nBSV);
01509
01510 decision_function f;
01511 f.alpha = alpha;
01512 f.rho = si.rho;
01513 return f;
01514 }
01515
01516
01517
01518
01519 struct svm_model
01520 {
01521 svm_parameter param;
01522 int nr_class;
01523 int l;
01524 svm_node **SV;
01525 double **sv_coef;
01526 double *rho;
01527 double *probA;
01528 double *probB;
01529
01530
01531
01532 int *label;
01533 int *nSV;
01534
01535
01536 int free_sv;
01537
01538 };
01539
01540
01541 void sigmoid_train(
01542 int l, const double *dec_values, const double *labels,
01543 double& A, double& B)
01544 {
01545 double prior1=0, prior0 = 0;
01546 int i;
01547
01548 for (i=0;i<l;i++)
01549 if (labels[i] > 0) prior1+=1;
01550 else prior0+=1;
01551
01552 int max_iter=100;
01553 double min_step=1e-10;
01554 double sigma=1e-3;
01555 double eps=1e-5;
01556 double hiTarget=(prior1+1.0)/(prior1+2.0);
01557 double loTarget=1/(prior0+2.0);
01558 double *t=Malloc(double,l);
01559 double fApB,p,q,h11,h22,h21,g1,g2,det,dA,dB,gd,stepsize;
01560 double newA,newB,newf,d1,d2;
01561 int iter;
01562
01563
01564 A=0.0; B=log((prior0+1.0)/(prior1+1.0));
01565 double fval = 0.0;
01566
01567 for (i=0;i<l;i++)
01568 {
01569 if (labels[i]>0) t[i]=hiTarget;
01570 else t[i]=loTarget;
01571 fApB = dec_values[i]*A+B;
01572 if (fApB>=0)
01573 fval += t[i]*fApB + log(1+exp(-fApB));
01574 else
01575 fval += (t[i] - 1)*fApB +log(1+exp(fApB));
01576 }
01577 for (iter=0;iter<max_iter;iter++)
01578 {
01579
01580 h11=sigma;
01581 h22=sigma;
01582 h21=0.0;g1=0.0;g2=0.0;
01583 for (i=0;i<l;i++)
01584 {
01585 fApB = dec_values[i]*A+B;
01586 if (fApB >= 0)
01587 {
01588 p=exp(-fApB)/(1.0+exp(-fApB));
01589 q=1.0/(1.0+exp(-fApB));
01590 }
01591 else
01592 {
01593 p=1.0/(1.0+exp(fApB));
01594 q=exp(fApB)/(1.0+exp(fApB));
01595 }
01596 d2=p*q;
01597 h11+=dec_values[i]*dec_values[i]*d2;
01598 h22+=d2;
01599 h21+=dec_values[i]*d2;
01600 d1=t[i]-p;
01601 g1+=dec_values[i]*d1;
01602 g2+=d1;
01603 }
01604
01605
01606 if (fabs(g1)<eps && fabs(g2)<eps)
01607 break;
01608
01609
01610 det=h11*h22-h21*h21;
01611 dA=-(h22*g1 - h21 * g2) / det;
01612 dB=-(-h21*g1+ h11 * g2) / det;
01613 gd=g1*dA+g2*dB;
01614
01615
01616 stepsize = 1;
01617 while (stepsize >= min_step)
01618 {
01619 newA = A + stepsize * dA;
01620 newB = B + stepsize * dB;
01621
01622
01623 newf = 0.0;
01624 for (i=0;i<l;i++)
01625 {
01626 fApB = dec_values[i]*newA+newB;
01627 if (fApB >= 0)
01628 newf += t[i]*fApB + log(1+exp(-fApB));
01629 else
01630 newf += (t[i] - 1)*fApB +log(1+exp(fApB));
01631 }
01632
01633 if (newf<fval+0.0001*stepsize*gd)
01634 {
01635 A=newA;B=newB;fval=newf;
01636 break;
01637 }
01638 else
01639 stepsize = stepsize / 2.0;
01640 }
01641
01642 if (stepsize < min_step)
01643 {
01644 info("Line search fails in two-class probability estimates\n");
01645 break;
01646 }
01647 }
01648
01649 if (iter>=max_iter)
01650 info("Reaching maximal iterations in two-class probability estimates\n");
01651 free(t);
01652 }
01653
01654 double sigmoid_predict(double decision_value, double A, double B)
01655 {
01656 double fApB = decision_value*A+B;
01657 if (fApB >= 0)
01658 return exp(-fApB)/(1.0+exp(-fApB));
01659 else
01660 return 1.0/(1+exp(fApB)) ;
01661 }
01662
01663
01664 void multiclass_probability(int k, double **r, double *p)
01665 {
01666 int t;
01667 int iter = 0, max_iter=100;
01668 double **Q=Malloc(double *,k);
01669 double *Qp=Malloc(double,k);
01670 double pQp, eps=0.001;
01671
01672 for (t=0;t<k;t++)
01673 {
01674 p[t]=1.0/k;
01675 Q[t]=Malloc(double,k);
01676 Q[t][t]=0;
01677 int j;
01678 for ( j=0;j<t;j++)
01679 {
01680 Q[t][t]+=r[j][t]*r[j][t];
01681 Q[t][j]=Q[j][t];
01682 }
01683 for ( j=t+1;j<k;j++)
01684 {
01685 Q[t][t]+=r[j][t]*r[j][t];
01686 Q[t][j]=-r[j][t]*r[t][j];
01687 }
01688 }
01689 for (iter=0;iter<max_iter;iter++)
01690 {
01691
01692 pQp=0;
01693 for (t=0;t<k;t++)
01694 {
01695 Qp[t]=0;
01696 for (int j=0;j<k;j++)
01697 Qp[t]+=Q[t][j]*p[j];
01698 pQp+=p[t]*Qp[t];
01699 }
01700 double max_error=0;
01701 for (t=0;t<k;t++)
01702 {
01703 double error=fabs(Qp[t]-pQp);
01704 if (error>max_error)
01705 max_error=error;
01706 }
01707 if (max_error<eps) break;
01708
01709 for (t=0;t<k;t++)
01710 {
01711 double diff=(-Qp[t]+pQp)/Q[t][t];
01712 p[t]+=diff;
01713 pQp=(pQp+diff*(diff*Q[t][t]+2*Qp[t]))/(1+diff)/(1+diff);
01714 for (int j=0;j<k;j++)
01715 {
01716 Qp[j]=(Qp[j]+diff*Q[t][j])/(1+diff);
01717 p[j]/=(1+diff);
01718 }
01719 }
01720 }
01721 if (iter>=max_iter)
01722 info("Exceeds max_iter in multiclass_prob\n");
01723 for(t=0;t<k;t++) free(Q[t]);
01724 free(Q);
01725 free(Qp);
01726 }
01727
01728
01729 void svm_binary_svc_probability(
01730 const svm_problem *prob, const svm_parameter *param,
01731 double Cp, double Cn, double& probA, double& probB)
01732 {
01733 int i;
01734 int nr_fold = 5;
01735 int *perm = Malloc(int,prob->l);
01736 double *dec_values = Malloc(double,prob->l);
01737
01738
01739 for(i=0;i<prob->l;i++) perm[i]=i;
01740 for(i=0;i<prob->l;i++)
01741 {
01742 int j = i+rand()%(prob->l-i);
01743 std::swap(perm[i],perm[j]);
01744 }
01745 for(i=0;i<nr_fold;i++)
01746 {
01747 int begin = i*prob->l/nr_fold;
01748 int end = (i+1)*prob->l/nr_fold;
01749 int j,k;
01750 struct svm_problem subprob;
01751
01752 subprob.l = prob->l-(end-begin);
01753 subprob.x = Malloc(struct svm_node*,subprob.l);
01754 subprob.y = Malloc(double,subprob.l);
01755
01756 k=0;
01757 for(j=0;j<begin;j++)
01758 {
01759 subprob.x[k] = prob->x[perm[j]];
01760 subprob.y[k] = prob->y[perm[j]];
01761 ++k;
01762 }
01763 for(j=end;j<prob->l;j++)
01764 {
01765 subprob.x[k] = prob->x[perm[j]];
01766 subprob.y[k] = prob->y[perm[j]];
01767 ++k;
01768 }
01769 int p_count=0,n_count=0;
01770 for(j=0;j<k;j++)
01771 if(subprob.y[j]>0)
01772 p_count++;
01773 else
01774 n_count++;
01775
01776 if(p_count==0 && n_count==0)
01777 for(j=begin;j<end;j++)
01778 dec_values[perm[j]] = 0;
01779 else if(p_count > 0 && n_count == 0)
01780 for(j=begin;j<end;j++)
01781 dec_values[perm[j]] = 1;
01782 else if(p_count == 0 && n_count > 0)
01783 for(j=begin;j<end;j++)
01784 dec_values[perm[j]] = -1;
01785 else
01786 {
01787 svm_parameter subparam = *param;
01788 subparam.probability=0;
01789 subparam.C=1.0;
01790 subparam.nr_weight=2;
01791 subparam.weight_label = Malloc(int,2);
01792 subparam.weight = Malloc(double,2);
01793 subparam.weight_label[0]=+1;
01794 subparam.weight_label[1]=-1;
01795 subparam.weight[0]=Cp;
01796 subparam.weight[1]=Cn;
01797 struct svm_model *submodel = svm_train(&subprob,&subparam);
01798 for(j=begin;j<end;j++)
01799 {
01800 svm_predict_values(submodel,prob->x[perm[j]],&(dec_values[perm[j]]));
01801
01802 dec_values[perm[j]] *= submodel->label[0];
01803 }
01804 svm_destroy_model(submodel);
01805 svm_destroy_param(&subparam);
01806 free(subprob.x);
01807 free(subprob.y);
01808 }
01809 }
01810 sigmoid_train(prob->l,dec_values,prob->y,probA,probB);
01811 free(dec_values);
01812 free(perm);
01813 }
01814
01815
01816 double svm_svr_probability(
01817 const svm_problem *prob, const svm_parameter *param)
01818 {
01819 int i;
01820 int nr_fold = 5;
01821 double *ymv = Malloc(double,prob->l);
01822 double mae = 0;
01823
01824 svm_parameter newparam = *param;
01825 newparam.probability = 0;
01826 svm_cross_validation(prob,&newparam,nr_fold,ymv);
01827 for(i=0;i<prob->l;i++)
01828 {
01829 ymv[i]=prob->y[i]-ymv[i];
01830 mae += fabs(ymv[i]);
01831 }
01832 mae /= prob->l;
01833 double std=sqrt(2*mae*mae);
01834 int count=0;
01835 mae=0;
01836 for(i=0;i<prob->l;i++)
01837 if (fabs(ymv[i]) > 5*std)
01838 count=count+1;
01839 else
01840 mae+=fabs(ymv[i]);
01841 mae /= (prob->l-count);
01842 info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma= %g\n",mae);
01843 free(ymv);
01844 return mae;
01845 }
01846
01847
01848
01849
01850 svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
01851 {
01852 svm_model *model = Malloc(svm_model,1);
01853 model->param = *param;
01854 model->free_sv = 0;
01855
01856 if(param->svm_type == ONE_CLASS ||
01857 param->svm_type == EPSILON_SVR ||
01858 param->svm_type == NU_SVR)
01859 {
01860
01861 model->nr_class = 2;
01862 model->label = NULL;
01863 model->nSV = NULL;
01864 model->probA = NULL; model->probB = NULL;
01865 model->sv_coef = Malloc(double *,1);
01866
01867 if(param->probability &&
01868 (param->svm_type == EPSILON_SVR ||
01869 param->svm_type == NU_SVR))
01870 {
01871 model->probA = Malloc(double,1);
01872 model->probA[0] = svm_svr_probability(prob,param);
01873 }
01874
01875 decision_function f = svm_train_one(prob,param,0,0);
01876 model->rho = Malloc(double,1);
01877 model->rho[0] = f.rho;
01878
01879 int nSV = 0;
01880 int i;
01881 for(i=0;i<prob->l;i++)
01882 if(fabs(f.alpha[i]) > 0) ++nSV;
01883 model->l = nSV;
01884 model->SV = Malloc(svm_node *,nSV);
01885 model->sv_coef[0] = Malloc(double,nSV);
01886 int j = 0;
01887 for(i=0;i<prob->l;i++)
01888 if(fabs(f.alpha[i]) > 0)
01889 {
01890 model->SV[j] = prob->x[i];
01891 model->sv_coef[0][j] = f.alpha[i];
01892 ++j;
01893 }
01894
01895 free(f.alpha);
01896 }
01897 else
01898 {
01899
01900
01901 int l = prob->l;
01902 int max_nr_class = 16;
01903 int nr_class = 0;
01904 int *label = Malloc(int,max_nr_class);
01905 int *count = Malloc(int,max_nr_class);
01906 int *index = Malloc(int,l);
01907
01908 int i;
01909 for(i=0;i<l;i++)
01910 {
01911 int this_label = (int)prob->y[i];
01912 int j;
01913 for(j=0;j<nr_class;j++)
01914 if(this_label == label[j])
01915 {
01916 ++count[j];
01917 break;
01918 }
01919 index[i] = j;
01920 if(j == nr_class)
01921 {
01922 if(nr_class == max_nr_class)
01923 {
01924 max_nr_class *= 2;
01925 label = (int *)realloc(label,max_nr_class*sizeof(int));
01926 count = (int *)realloc(count,max_nr_class*sizeof(int));
01927 }
01928 label[nr_class] = this_label;
01929 count[nr_class] = 1;
01930 ++nr_class;
01931 }
01932 }
01933
01934
01935
01936 int *start = Malloc(int,nr_class);
01937 start[0] = 0;
01938 for(i=1;i<nr_class;i++)
01939 start[i] = start[i-1]+count[i-1];
01940
01941 svm_node **x = Malloc(svm_node *,l);
01942
01943 for(i=0;i<l;i++)
01944 {
01945 x[start[index[i]]] = prob->x[i];
01946 ++start[index[i]];
01947 }
01948
01949 start[0] = 0;
01950 for(i=1;i<nr_class;i++)
01951 start[i] = start[i-1]+count[i-1];
01952
01953
01954
01955 double *weighted_C = Malloc(double, nr_class);
01956 for(i=0;i<nr_class;i++)
01957 weighted_C[i] = param->C;
01958 for(i=0;i<param->nr_weight;i++)
01959 {
01960 int j;
01961 for(j=0;j<nr_class;j++)
01962 if(param->weight_label[i] == label[j])
01963 break;
01964 if(j == nr_class)
01965 fprintf(stderr,"warning: class label %d specified in weight is not found\n", param->weight_label[i]);
01966 else
01967 weighted_C[j] *= param->weight[i];
01968 }
01969
01970
01971
01972 bool *nonzero = Malloc(bool,l);
01973 for(i=0;i<l;i++)
01974 nonzero[i] = false;
01975 decision_function *f = Malloc(decision_function,nr_class*(nr_class-1)/2);
01976
01977 double *probA=NULL,*probB=NULL;
01978 if (param->probability)
01979 {
01980 probA=Malloc(double,nr_class*(nr_class-1)/2);
01981 probB=Malloc(double,nr_class*(nr_class-1)/2);
01982 }
01983
01984 int p = 0;
01985 for(i=0;i<nr_class;i++)
01986 for(int j=i+1;j<nr_class;j++)
01987 {
01988 svm_problem sub_prob;
01989 int si = start[i], sj = start[j];
01990 int ci = count[i], cj = count[j];
01991 sub_prob.l = ci+cj;
01992 sub_prob.x = Malloc(svm_node *,sub_prob.l);
01993 sub_prob.y = Malloc(double,sub_prob.l);
01994 int k;
01995 for(k=0;k<ci;k++)
01996 {
01997 sub_prob.x[k] = x[si+k];
01998 sub_prob.y[k] = +1;
01999 }
02000 for(k=0;k<cj;k++)
02001 {
02002 sub_prob.x[ci+k] = x[sj+k];
02003 sub_prob.y[ci+k] = -1;
02004 }
02005
02006 if(param->probability)
02007 svm_binary_svc_probability(&sub_prob,param,weighted_C[i],weighted_C[j],probA[p],probB[p]);
02008
02009 f[p] = svm_train_one(&sub_prob,param,weighted_C[i],weighted_C[j]);
02010 for(k=0;k<ci;k++)
02011 if(!nonzero[si+k] && fabs(f[p].alpha[k]) > 0)
02012 nonzero[si+k] = true;
02013 for(k=0;k<cj;k++)
02014 if(!nonzero[sj+k] && fabs(f[p].alpha[ci+k]) > 0)
02015 nonzero[sj+k] = true;
02016 free(sub_prob.x);
02017 free(sub_prob.y);
02018 ++p;
02019 }
02020
02021
02022
02023 model->nr_class = nr_class;
02024
02025 model->label = Malloc(int,nr_class);
02026 for(i=0;i<nr_class;i++)
02027 model->label[i] = label[i];
02028
02029 model->rho = Malloc(double,nr_class*(nr_class-1)/2);
02030 for(i=0;i<nr_class*(nr_class-1)/2;i++)
02031 model->rho[i] = f[i].rho;
02032
02033 if(param->probability)
02034 {
02035 model->probA = Malloc(double,nr_class*(nr_class-1)/2);
02036 model->probB = Malloc(double,nr_class*(nr_class-1)/2);
02037 for(i=0;i<nr_class*(nr_class-1)/2;i++)
02038 {
02039 model->probA[i] = probA[i];
02040 model->probB[i] = probB[i];
02041 }
02042 }
02043 else
02044 {
02045 model->probA=NULL;
02046 model->probB=NULL;
02047 }
02048
02049 int total_sv = 0;
02050 int *nz_count = Malloc(int,nr_class);
02051 model->nSV = Malloc(int,nr_class);
02052 for(i=0;i<nr_class;i++)
02053 {
02054 int nSV = 0;
02055 for(int j=0;j<count[i];j++)
02056 if(nonzero[start[i]+j])
02057 {
02058 ++nSV;
02059 ++total_sv;
02060 }
02061 model->nSV[i] = nSV;
02062 nz_count[i] = nSV;
02063 }
02064
02065 info("Total nSV = %d\n",total_sv);
02066
02067 model->l = total_sv;
02068 model->SV = Malloc(svm_node *,total_sv);
02069 p = 0;
02070 for(i=0;i<l;i++)
02071 if(nonzero[i]) model->SV[p++] = x[i];
02072
02073 int *nz_start = Malloc(int,nr_class);
02074 nz_start[0] = 0;
02075 for(i=1;i<nr_class;i++)
02076 nz_start[i] = nz_start[i-1]+nz_count[i-1];
02077
02078 model->sv_coef = Malloc(double *,nr_class-1);
02079 for(i=0;i<nr_class-1;i++)
02080 model->sv_coef[i] = Malloc(double,total_sv);
02081
02082 p = 0;
02083 for(i=0;i<nr_class;i++)
02084 for(int j=i+1;j<nr_class;j++)
02085 {
02086
02087
02088
02089
02090 int si = start[i];
02091 int sj = start[j];
02092 int ci = count[i];
02093 int cj = count[j];
02094
02095 int q = nz_start[i];
02096 int k;
02097 for(k=0;k<ci;k++)
02098 if(nonzero[si+k])
02099 model->sv_coef[j-1][q++] = f[p].alpha[k];
02100 q = nz_start[j];
02101 for(k=0;k<cj;k++)
02102 if(nonzero[sj+k])
02103 model->sv_coef[i][q++] = f[p].alpha[ci+k];
02104 ++p;
02105 }
02106
02107 free(label);
02108 free(probA);
02109 free(probB);
02110 free(count);
02111 free(index);
02112 free(start);
02113 free(x);
02114 free(weighted_C);
02115 free(nonzero);
02116 for(i=0;i<nr_class*(nr_class-1)/2;i++)
02117 free(f[i].alpha);
02118 free(f);
02119 free(nz_count);
02120 free(nz_start);
02121 }
02122 return model;
02123 }
02124
02125 void svm_cross_validation(const svm_problem *prob, const svm_parameter *param, int nr_fold, double *target)
02126 {
02127 int i;
02128 int *perm = Malloc(int,prob->l);
02129
02130
02131 for(i=0;i<prob->l;i++) perm[i]=i;
02132 for(i=0;i<prob->l;i++)
02133 {
02134 int j = i+rand()%(prob->l-i);
02135 std::swap(perm[i],perm[j]);
02136 }
02137 for(i=0;i<nr_fold;i++)
02138 {
02139 int begin = i*prob->l/nr_fold;
02140 int end = (i+1)*prob->l/nr_fold;
02141 int j,k;
02142 struct svm_problem subprob;
02143
02144 subprob.l = prob->l-(end-begin);
02145 subprob.x = Malloc(struct svm_node*,subprob.l);
02146 subprob.y = Malloc(double,subprob.l);
02147
02148 k=0;
02149 for(j=0;j<begin;j++)
02150 {
02151 subprob.x[k] = prob->x[perm[j]];
02152 subprob.y[k] = prob->y[perm[j]];
02153 ++k;
02154 }
02155 for(j=end;j<prob->l;j++)
02156 {
02157 subprob.x[k] = prob->x[perm[j]];
02158 subprob.y[k] = prob->y[perm[j]];
02159 ++k;
02160 }
02161 struct svm_model *submodel = svm_train(&subprob,param);
02162 if(param->probability &&
02163 (param->svm_type == C_SVC || param->svm_type == NU_SVC))
02164 {
02165 double *prob_estimates=Malloc(double,svm_get_nr_class(submodel));
02166 for(j=begin;j<end;j++)
02167 target[perm[j]] = svm_predict_probability(submodel,prob->x[perm[j]],prob_estimates);
02168 free(prob_estimates);
02169 }
02170 else
02171 for(j=begin;j<end;j++)
02172 target[perm[j]] = svm_predict(submodel,prob->x[perm[j]]);
02173 svm_destroy_model(submodel);
02174 free(subprob.x);
02175 free(subprob.y);
02176 }
02177 free(perm);
02178 }
02179
02180 int svm_get_svm_type(const svm_model *model)
02181 {
02182 return model->param.svm_type;
02183 }
02184
02185 int svm_get_nr_class(const svm_model *model)
02186 {
02187 return model->nr_class;
02188 }
02189
02190 void svm_get_labels(const svm_model *model, int* label)
02191 {
02192 if (model->label != NULL)
02193 for(int i=0;i<model->nr_class;i++)
02194 label[i] = model->label[i];
02195 }
02196
02197 double svm_get_svr_probability(const svm_model *model)
02198 {
02199 if ((model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) &&
02200 model->probA!=NULL)
02201 return model->probA[0];
02202 else
02203 {
02204 info("Model doesn't contain information for SVR probability inference\n");
02205 return 0;
02206 }
02207 }
02208
02209 void svm_predict_values(const svm_model *model, const svm_node *x, double* dec_values)
02210 {
02211 if(model->param.svm_type == ONE_CLASS ||
02212 model->param.svm_type == EPSILON_SVR ||
02213 model->param.svm_type == NU_SVR)
02214 {
02215 double *sv_coef = model->sv_coef[0];
02216 double sum = 0;
02217 for(int i=0;i<model->l;i++)
02218 sum += sv_coef[i] * Kernel::k_function(x,model->SV[i],model->param);
02219 sum -= model->rho[0];
02220 *dec_values = sum;
02221 }
02222 else
02223 {
02224 int i;
02225 int nr_class = model->nr_class;
02226 int l = model->l;
02227
02228 double *kvalue = Malloc(double,l);
02229 for(i=0;i<l;i++)
02230 kvalue[i] = Kernel::k_function(x,model->SV[i],model->param);
02231
02232 int *start = Malloc(int,nr_class);
02233 start[0] = 0;
02234 for(i=1;i<nr_class;i++)
02235 start[i] = start[i-1]+model->nSV[i-1];
02236
02237 int p=0;
02238 int pos=0;
02239 for(i=0;i<nr_class;i++)
02240 for(int j=i+1;j<nr_class;j++)
02241 {
02242 double sum = 0;
02243 int si = start[i];
02244 int sj = start[j];
02245 int ci = model->nSV[i];
02246 int cj = model->nSV[j];
02247
02248 int k;
02249 double *coef1 = model->sv_coef[j-1];
02250 double *coef2 = model->sv_coef[i];
02251 for(k=0;k<ci;k++)
02252 sum += coef1[si+k] * kvalue[si+k];
02253 for(k=0;k<cj;k++)
02254 sum += coef2[sj+k] * kvalue[sj+k];
02255 sum -= model->rho[p++];
02256 dec_values[pos++] = sum;
02257 }
02258
02259 free(kvalue);
02260 free(start);
02261 }
02262 }
02263
02264 double svm_predict(const svm_model *model, const svm_node *x)
02265 {
02266 if(model->param.svm_type == ONE_CLASS ||
02267 model->param.svm_type == EPSILON_SVR ||
02268 model->param.svm_type == NU_SVR)
02269 {
02270 double res;
02271 svm_predict_values(model, x, &res);
02272
02273 if(model->param.svm_type == ONE_CLASS)
02274 return (res>0)?1:-1;
02275 else
02276 return res;
02277 }
02278 else
02279 {
02280 int i;
02281 int nr_class = model->nr_class;
02282 double *dec_values = Malloc(double, nr_class*(nr_class-1)/2);
02283 svm_predict_values(model, x, dec_values);
02284
02285 int *vote = Malloc(int,nr_class);
02286 for(i=0;i<nr_class;i++)
02287 vote[i] = 0;
02288 int pos=0;
02289 for(i=0;i<nr_class;i++)
02290 for(int j=i+1;j<nr_class;j++)
02291 {
02292 if(dec_values[pos++] > 0)
02293 ++vote[i];
02294 else
02295 ++vote[j];
02296 }
02297
02298 int vote_max_idx = 0;
02299 for(i=1;i<nr_class;i++)
02300 if(vote[i] > vote[vote_max_idx])
02301 vote_max_idx = i;
02302 free(vote);
02303 free(dec_values);
02304 return model->label[vote_max_idx];
02305 }
02306 }
02307
02308 double svm_predict_probability(
02309 const svm_model *model, const svm_node *x, double *prob_estimates)
02310 {
02311 if ((model->param.svm_type == C_SVC || model->param.svm_type == NU_SVC) &&
02312 model->probA!=NULL && model->probB!=NULL)
02313 {
02314 int i;
02315 int nr_class = model->nr_class;
02316 double *dec_values = Malloc(double, nr_class*(nr_class-1)/2);
02317 svm_predict_values(model, x, dec_values);
02318
02319 double min_prob=1e-7;
02320 double **pairwise_prob=Malloc(double *,nr_class);
02321 for(i=0;i<nr_class;i++)
02322 pairwise_prob[i]=Malloc(double,nr_class);
02323 int k=0;
02324 for(i=0;i<nr_class;i++)
02325 for(int j=i+1;j<nr_class;j++)
02326 {
02327 pairwise_prob[i][j]=min(std::max(sigmoid_predict(dec_values[k],model->probA[k],model->probB[k]),min_prob),1-min_prob);
02328 pairwise_prob[j][i]=1-pairwise_prob[i][j];
02329 k++;
02330 }
02331 multiclass_probability(nr_class,pairwise_prob,prob_estimates);
02332
02333 int prob_max_idx = 0;
02334 for(i=1;i<nr_class;i++)
02335 if(prob_estimates[i] > prob_estimates[prob_max_idx])
02336 prob_max_idx = i;
02337 for(i=0;i<nr_class;i++)
02338 free(pairwise_prob[i]);
02339 free(dec_values);
02340 free(pairwise_prob);
02341 return model->label[prob_max_idx];
02342 }
02343 else
02344 return svm_predict(model, x);
02345 }
02346
02347 const char *svm_type_table[] =
02348 {
02349 "c_svc","nu_svc","one_class","epsilon_svr","nu_svr",NULL
02350 };
02351
02352 const char *kernel_type_table[]=
02353 {
02354 "linear","polynomial","rbf","sigmoid",NULL
02355 };
02356
02357 int svm_save_model(const char *model_file_name, const svm_model *model)
02358 {
02359 FILE *fp = fopen(model_file_name,"w");
02360 if(fp==NULL) return -1;
02361
02362 const svm_parameter& param = model->param;
02363
02364 fprintf(fp,"svm_type %s\n", svm_type_table[param.svm_type]);
02365 fprintf(fp,"kernel_type %s\n", kernel_type_table[param.kernel_type]);
02366
02367 if(param.kernel_type == POLY)
02368 fprintf(fp,"degree %g\n", param.degree);
02369
02370 if(param.kernel_type == POLY || param.kernel_type == RBF || param.kernel_type == SIGMOID)
02371 fprintf(fp,"gamma %g\n", param.gamma);
02372
02373 if(param.kernel_type == POLY || param.kernel_type == SIGMOID)
02374 fprintf(fp,"coef0 %g\n", param.coef0);
02375
02376 int nr_class = model->nr_class;
02377 int l = model->l;
02378 fprintf(fp, "nr_class %d\n", nr_class);
02379 fprintf(fp, "total_sv %d\n",l);
02380
02381 {
02382 fprintf(fp, "rho");
02383 for(int i=0;i<nr_class*(nr_class-1)/2;i++)
02384 fprintf(fp," %g",model->rho[i]);
02385 fprintf(fp, "\n");
02386 }
02387
02388 if(model->label)
02389 {
02390 fprintf(fp, "label");
02391 for(int i=0;i<nr_class;i++)
02392 fprintf(fp," %d",model->label[i]);
02393 fprintf(fp, "\n");
02394 }
02395
02396 if(model->probA)
02397 {
02398 fprintf(fp, "probA");
02399 for(int i=0;i<nr_class*(nr_class-1)/2;i++)
02400 fprintf(fp," %g",model->probA[i]);
02401 fprintf(fp, "\n");
02402 }
02403 if(model->probB)
02404 {
02405 fprintf(fp, "probB");
02406 for(int i=0;i<nr_class*(nr_class-1)/2;i++)
02407 fprintf(fp," %g",model->probB[i]);
02408 fprintf(fp, "\n");
02409 }
02410
02411 if(model->nSV)
02412 {
02413 fprintf(fp, "nr_sv");
02414 for(int i=0;i<nr_class;i++)
02415 fprintf(fp," %d",model->nSV[i]);
02416 fprintf(fp, "\n");
02417 }
02418
02419 fprintf(fp, "SV\n");
02420 const double * const *sv_coef = model->sv_coef;
02421 const svm_node * const *SV = model->SV;
02422
02423 for(int i=0;i<l;i++)
02424 {
02425 for(int j=0;j<nr_class-1;j++)
02426 fprintf(fp, "%.16g ",sv_coef[j][i]);
02427
02428 const svm_node *p = SV[i];
02429 while(p->index != -1)
02430 {
02431 fprintf(fp,"%d:%.8g ",p->index,p->value);
02432 p++;
02433 }
02434 fprintf(fp, "\n");
02435 }
02436
02437 fclose(fp);
02438 return 0;
02439 }
02440
02441 svm_model *svm_load_model(const char *model_file_name)
02442 {
02443 FILE *fp = fopen(model_file_name,"rb");
02444 if(fp==NULL) return NULL;
02445
02446
02447
02448 svm_model *model = Malloc(svm_model,1);
02449 svm_parameter& param = model->param;
02450 model->rho = NULL;
02451 model->probA = NULL;
02452 model->probB = NULL;
02453 model->label = NULL;
02454 model->nSV = NULL;
02455
02456 char cmd[81];
02457 while(1)
02458 {
02459 fscanf(fp,"%80s",cmd);
02460
02461 if(strcmp(cmd,"svm_type")==0)
02462 {
02463 fscanf(fp,"%80s",cmd);
02464 int i;
02465 for(i=0;svm_type_table[i];i++)
02466 {
02467 if(strcmp(svm_type_table[i],cmd)==0)
02468 {
02469 param.svm_type=i;
02470 break;
02471 }
02472 }
02473 if(svm_type_table[i] == NULL)
02474 {
02475 fprintf(stderr,"unknown svm type.\n");
02476 free(model->rho);
02477 free(model->label);
02478 free(model->nSV);
02479 free(model);
02480 return NULL;
02481 }
02482 }
02483 else if(strcmp(cmd,"kernel_type")==0)
02484 {
02485 fscanf(fp,"%80s",cmd);
02486 int i;
02487 for(i=0;kernel_type_table[i];i++)
02488 {
02489 if(strcmp(kernel_type_table[i],cmd)==0)
02490 {
02491 param.kernel_type=i;
02492 break;
02493 }
02494 }
02495 if(kernel_type_table[i] == NULL)
02496 {
02497 fprintf(stderr,"unknown kernel function.\n");
02498 free(model->rho);
02499 free(model->label);
02500 free(model->nSV);
02501 free(model);
02502 return NULL;
02503 }
02504 }
02505 else if(strcmp(cmd,"degree")==0)
02506 fscanf(fp,"%lf",¶m.degree);
02507 else if(strcmp(cmd,"gamma")==0)
02508 fscanf(fp,"%lf",¶m.gamma);
02509 else if(strcmp(cmd,"coef0")==0)
02510 fscanf(fp,"%lf",¶m.coef0);
02511 else if(strcmp(cmd,"nr_class")==0)
02512 fscanf(fp,"%d",&model->nr_class);
02513 else if(strcmp(cmd,"total_sv")==0)
02514 fscanf(fp,"%d",&model->l);
02515 else if(strcmp(cmd,"rho")==0)
02516 {
02517 int n = model->nr_class * (model->nr_class-1)/2;
02518 model->rho = Malloc(double,n);
02519 for(int i=0;i<n;i++)
02520 fscanf(fp,"%lf",&model->rho[i]);
02521 }
02522 else if(strcmp(cmd,"label")==0)
02523 {
02524 int n = model->nr_class;
02525 model->label = Malloc(int,n);
02526 for(int i=0;i<n;i++)
02527 fscanf(fp,"%d",&model->label[i]);
02528 }
02529 else if(strcmp(cmd,"probA")==0)
02530 {
02531 int n = model->nr_class * (model->nr_class-1)/2;
02532 model->probA = Malloc(double,n);
02533 for(int i=0;i<n;i++)
02534 fscanf(fp,"%lf",&model->probA[i]);
02535 }
02536 else if(strcmp(cmd,"probB")==0)
02537 {
02538 int n = model->nr_class * (model->nr_class-1)/2;
02539 model->probB = Malloc(double,n);
02540 for(int i=0;i<n;i++)
02541 fscanf(fp,"%lf",&model->probB[i]);
02542 }
02543 else if(strcmp(cmd,"nr_sv")==0)
02544 {
02545 int n = model->nr_class;
02546 model->nSV = Malloc(int,n);
02547 for(int i=0;i<n;i++)
02548 fscanf(fp,"%d",&model->nSV[i]);
02549 }
02550 else if(strcmp(cmd,"SV")==0)
02551 {
02552 while(1)
02553 {
02554 int c = getc(fp);
02555 if(c==EOF || c=='\n') break;
02556 }
02557 break;
02558 }
02559 else
02560 {
02561 fprintf(stderr,"unknown text in model file\n");
02562 free(model->rho);
02563 free(model->label);
02564 free(model->nSV);
02565 free(model);
02566 return NULL;
02567 }
02568 }
02569
02570
02571
02572 int elements = 0;
02573 long pos = ftell(fp);
02574
02575 while(1)
02576 {
02577 int c = fgetc(fp);
02578 switch(c)
02579 {
02580 case '\n':
02581
02582 case ':':
02583 ++elements;
02584 break;
02585 case EOF:
02586 goto out;
02587 default:
02588 ;
02589 }
02590 }
02591 out:
02592 fseek(fp,pos,SEEK_SET);
02593
02594 int m = model->nr_class - 1;
02595 int l = model->l;
02596 model->sv_coef = Malloc(double *,m);
02597 int i;
02598 for(i=0;i<m;i++)
02599 model->sv_coef[i] = Malloc(double,l);
02600 model->SV = Malloc(svm_node*,l);
02601 svm_node *x_space = Malloc(svm_node,elements);
02602
02603 int j=0;
02604 for(i=0;i<l;i++)
02605 {
02606 model->SV[i] = &x_space[j];
02607 for(int k=0;k<m;k++)
02608 fscanf(fp,"%lf",&model->sv_coef[k][i]);
02609 while(1)
02610 {
02611 int c;
02612 do {
02613 c = getc(fp);
02614 if(c=='\n') goto out2;
02615 } while(isspace(c));
02616 ungetc(c,fp);
02617 fscanf(fp,"%d:%lf",&(x_space[j].index),&(x_space[j].value));
02618 ++j;
02619 }
02620 out2:
02621 x_space[j++].index = -1;
02622 }
02623
02624 fclose(fp);
02625
02626 model->free_sv = 1;
02627 return model;
02628 }
02629
02630 void svm_destroy_model(svm_model* model)
02631 {
02632 if(model->free_sv)
02633 free((void *)(model->SV[0]));
02634 for(int i=0;i<model->nr_class-1;i++)
02635 free(model->sv_coef[i]);
02636 free(model->SV);
02637 free(model->sv_coef);
02638 free(model->rho);
02639 free(model->label);
02640 free(model->probA);
02641 free(model->probB);
02642 free(model->nSV);
02643 free(model);
02644 }
02645
02646 void svm_destroy_param(svm_parameter* param)
02647 {
02648 free(param->weight_label);
02649 free(param->weight);
02650 }
02651
02652 const char *svm_check_parameter(const svm_problem *prob, const svm_parameter *param)
02653 {
02654
02655
02656 int svm_type = param->svm_type;
02657 if(svm_type != C_SVC &&
02658 svm_type != NU_SVC &&
02659 svm_type != ONE_CLASS &&
02660 svm_type != EPSILON_SVR &&
02661 svm_type != NU_SVR)
02662 return "unknown svm type";
02663
02664
02665
02666 int kernel_type = param->kernel_type;
02667 if(kernel_type != SVM_LINEAR &&
02668 kernel_type != POLY &&
02669 kernel_type != RBF &&
02670 kernel_type != SIGMOID)
02671 return "unknown kernel type";
02672
02673
02674
02675 if(param->cache_size <= 0)
02676 return "cache_size <= 0";
02677
02678 if(param->eps <= 0)
02679 return "eps <= 0";
02680
02681 if(svm_type == C_SVC ||
02682 svm_type == EPSILON_SVR ||
02683 svm_type == NU_SVR)
02684 if(param->C <= 0)
02685 return "C <= 0";
02686
02687 if(svm_type == NU_SVC ||
02688 svm_type == ONE_CLASS ||
02689 svm_type == NU_SVR)
02690 if(param->nu < 0 || param->nu > 1)
02691 return "nu < 0 or nu > 1";
02692
02693 if(svm_type == EPSILON_SVR)
02694 if(param->p < 0)
02695 return "p < 0";
02696
02697 if(param->shrinking != 0 &&
02698 param->shrinking != 1)
02699 return "shrinking != 0 and shrinking != 1";
02700
02701 if(param->probability != 0 &&
02702 param->probability != 1)
02703 return "probability != 0 and probability != 1";
02704
02705 if(param->probability == 1 &&
02706 svm_type == ONE_CLASS)
02707 return "one-class SVM probability output not supported yet";
02708
02709
02710
02711
02712 if(svm_type == NU_SVC)
02713 {
02714 int l = prob->l;
02715 int max_nr_class = 16;
02716 int nr_class = 0;
02717 int *label = Malloc(int,max_nr_class);
02718 int *count = Malloc(int,max_nr_class);
02719
02720 int i;
02721 for(i=0;i<l;i++)
02722 {
02723 int this_label = (int)prob->y[i];
02724 int j;
02725 for(j=0;j<nr_class;j++)
02726 if(this_label == label[j])
02727 {
02728 ++count[j];
02729 break;
02730 }
02731 if(j == nr_class)
02732 {
02733 if(nr_class == max_nr_class)
02734 {
02735 max_nr_class *= 2;
02736 label = (int *)realloc(label,max_nr_class*sizeof(int));
02737 count = (int *)realloc(count,max_nr_class*sizeof(int));
02738 }
02739 label[nr_class] = this_label;
02740 count[nr_class] = 1;
02741 ++nr_class;
02742 }
02743 }
02744
02745 for(i=0;i<nr_class;i++)
02746 {
02747 int n1 = count[i];
02748 for(int j=i+1;j<nr_class;j++)
02749 {
02750 int n2 = count[j];
02751 if(param->nu*(n1+n2)/2 > min(n1,n2))
02752 {
02753 free(label);
02754 free(count);
02755 return "specified nu is infeasible";
02756 }
02757 }
02758 }
02759 free(label);
02760 free(count);
02761 }
02762
02763 return NULL;
02764 }
02765
02766 int svm_check_probability_model(const svm_model *model)
02767 {
02768 return ((model->param.svm_type == C_SVC || model->param.svm_type == NU_SVC) &&
02769 model->probA!=NULL && model->probB!=NULL) ||
02770 ((model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) &&
02771 model->probA!=NULL);
02772 }