jrb-libsvm 0.1.2-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2826 @@
1
+
2
+ package libsvm;
3
+ import java.io.*;
4
+ import java.util.*;
5
+
6
+ //
7
+ // Kernel Cache
8
+ //
9
+ // l is the number of total data items
10
+ // size is the cache size limit in bytes
11
+ //
12
+ class Cache {
13
+ private final int l;
14
+ private long size;
15
+ private final class head_t
16
+ {
17
+ head_t prev, next; // a cicular list
18
+ float[] data;
19
+ int len; // data[0,len) is cached in this entry
20
+ }
21
+ private final head_t[] head;
22
+ private head_t lru_head;
23
+
24
+ Cache(int l_, long size_)
25
+ {
26
+ l = l_;
27
+ size = size_;
28
+ head = new head_t[l];
29
+ for(int i=0;i<l;i++) head[i] = new head_t();
30
+ size /= 4;
31
+ size -= l * (16/4); // sizeof(head_t) == 16
32
+ size = Math.max(size, 2* (long) l); // cache must be large enough for two columns
33
+ lru_head = new head_t();
34
+ lru_head.next = lru_head.prev = lru_head;
35
+ }
36
+
37
+ private void lru_delete(head_t h)
38
+ {
39
+ // delete from current location
40
+ h.prev.next = h.next;
41
+ h.next.prev = h.prev;
42
+ }
43
+
44
+ private void lru_insert(head_t h)
45
+ {
46
+ // insert to last position
47
+ h.next = lru_head;
48
+ h.prev = lru_head.prev;
49
+ h.prev.next = h;
50
+ h.next.prev = h;
51
+ }
52
+
53
+ // request data [0,len)
54
+ // return some position p where [p,len) need to be filled
55
+ // (p >= len if nothing needs to be filled)
56
+ // java: simulate pointer using single-element array
57
+ int get_data(int index, float[][] data, int len)
58
+ {
59
+ head_t h = head[index];
60
+ if(h.len > 0) lru_delete(h);
61
+ int more = len - h.len;
62
+
63
+ if(more > 0)
64
+ {
65
+ // free old space
66
+ while(size < more)
67
+ {
68
+ head_t old = lru_head.next;
69
+ lru_delete(old);
70
+ size += old.len;
71
+ old.data = null;
72
+ old.len = 0;
73
+ }
74
+
75
+ // allocate new space
76
+ float[] new_data = new float[len];
77
+ if(h.data != null) System.arraycopy(h.data,0,new_data,0,h.len);
78
+ h.data = new_data;
79
+ size -= more;
80
+ do {int _=h.len; h.len=len; len=_;} while(false);
81
+ }
82
+
83
+ lru_insert(h);
84
+ data[0] = h.data;
85
+ return len;
86
+ }
87
+
88
+ void swap_index(int i, int j)
89
+ {
90
+ if(i==j) return;
91
+
92
+ if(head[i].len > 0) lru_delete(head[i]);
93
+ if(head[j].len > 0) lru_delete(head[j]);
94
+ do {float[] _=head[i].data; head[i].data=head[j].data; head[j].data=_;} while(false);
95
+ do {int _=head[i].len; head[i].len=head[j].len; head[j].len=_;} while(false);
96
+ if(head[i].len > 0) lru_insert(head[i]);
97
+ if(head[j].len > 0) lru_insert(head[j]);
98
+
99
+ if(i>j) do {int _=i; i=j; j=_;} while(false);
100
+ for(head_t h = lru_head.next; h!=lru_head; h=h.next)
101
+ {
102
+ if(h.len > i)
103
+ {
104
+ if(h.len > j)
105
+ do {float _=h.data[i]; h.data[i]=h.data[j]; h.data[j]=_;} while(false);
106
+ else
107
+ {
108
+ // give up
109
+ lru_delete(h);
110
+ size += h.len;
111
+ h.data = null;
112
+ h.len = 0;
113
+ }
114
+ }
115
+ }
116
+ }
117
+ }
118
+
119
+ //
120
+ // Kernel evaluation
121
+ //
122
+ // the static method k_function is for doing single kernel evaluation
123
+ // the constructor of Kernel prepares to calculate the l*l kernel matrix
124
+ // the member function get_Q is for getting one column from the Q Matrix
125
+ //
126
+ abstract class QMatrix {
127
+ abstract float[] get_Q(int column, int len);
128
+ abstract double[] get_QD();
129
+ abstract void swap_index(int i, int j);
130
+ };
131
+
132
+ abstract class Kernel extends QMatrix {
133
+ private Node[][] x;
134
+ private final double[] x_square;
135
+
136
+ // Parameter
137
+ private final int kernel_type;
138
+ private final int degree;
139
+ private final double gamma;
140
+ private final double coef0;
141
+
142
+ abstract float[] get_Q(int column, int len);
143
+ abstract double[] get_QD();
144
+
145
+ void swap_index(int i, int j)
146
+ {
147
+ do {Node[] _=x[i]; x[i]=x[j]; x[j]=_;} while(false);
148
+ if(x_square != null) do {double _=x_square[i]; x_square[i]=x_square[j]; x_square[j]=_;} while(false);
149
+ }
150
+
151
+ private static double powi(double base, int times)
152
+ {
153
+ double tmp = base, ret = 1.0;
154
+
155
+ for(int t=times; t>0; t/=2)
156
+ {
157
+ if(t%2==1) ret*=tmp;
158
+ tmp = tmp * tmp;
159
+ }
160
+ return ret;
161
+ }
162
+
163
+ double kernel_function(int i, int j)
164
+ {
165
+ switch(kernel_type)
166
+ {
167
+ case Parameter.LINEAR:
168
+ return dot(x[i],x[j]);
169
+ case Parameter.POLY:
170
+ return powi(gamma*dot(x[i],x[j])+coef0,degree);
171
+ case Parameter.RBF:
172
+ return Math.exp(-gamma*(x_square[i]+x_square[j]-2*dot(x[i],x[j])));
173
+ case Parameter.SIGMOID:
174
+ return Math.tanh(gamma*dot(x[i],x[j])+coef0);
175
+ case Parameter.PRECOMPUTED:
176
+ return x[i][(int)(x[j][0].value)].value;
177
+ default:
178
+ return 0; // java
179
+ }
180
+ }
181
+
182
+ Kernel(int l, Node[][] x_, Parameter param)
183
+ {
184
+ this.kernel_type = param.kernel_type;
185
+ this.degree = param.degree;
186
+ this.gamma = param.gamma;
187
+ this.coef0 = param.coef0;
188
+
189
+ x = (Node[][])x_.clone();
190
+
191
+ if(kernel_type == Parameter.RBF)
192
+ {
193
+ x_square = new double[l];
194
+ for(int i=0;i<l;i++)
195
+ x_square[i] = dot(x[i],x[i]);
196
+ }
197
+ else x_square = null;
198
+ }
199
+
200
+ static double dot(Node[] x, Node[] y)
201
+ {
202
+ double sum = 0;
203
+ int xlen = x.length;
204
+ int ylen = y.length;
205
+ int i = 0;
206
+ int j = 0;
207
+ while(i < xlen && j < ylen)
208
+ {
209
+ if(x[i].index == y[j].index)
210
+ sum += x[i++].value * y[j++].value;
211
+ else
212
+ {
213
+ if(x[i].index > y[j].index)
214
+ ++j;
215
+ else
216
+ ++i;
217
+ }
218
+ }
219
+ return sum;
220
+ }
221
+
222
+ static double k_function(Node[] x, Node[] y,
223
+ Parameter param)
224
+ {
225
+ switch(param.kernel_type)
226
+ {
227
+ case Parameter.LINEAR:
228
+ return dot(x,y);
229
+ case Parameter.POLY:
230
+ return powi(param.gamma*dot(x,y)+param.coef0,param.degree);
231
+ case Parameter.RBF:
232
+ {
233
+ double sum = 0;
234
+ int xlen = x.length;
235
+ int ylen = y.length;
236
+ int i = 0;
237
+ int j = 0;
238
+ while(i < xlen && j < ylen)
239
+ {
240
+ if(x[i].index == y[j].index)
241
+ {
242
+ double d = x[i++].value - y[j++].value;
243
+ sum += d*d;
244
+ }
245
+ else if(x[i].index > y[j].index)
246
+ {
247
+ sum += y[j].value * y[j].value;
248
+ ++j;
249
+ }
250
+ else
251
+ {
252
+ sum += x[i].value * x[i].value;
253
+ ++i;
254
+ }
255
+ }
256
+
257
+ while(i < xlen)
258
+ {
259
+ sum += x[i].value * x[i].value;
260
+ ++i;
261
+ }
262
+
263
+ while(j < ylen)
264
+ {
265
+ sum += y[j].value * y[j].value;
266
+ ++j;
267
+ }
268
+
269
+ return Math.exp(-param.gamma*sum);
270
+ }
271
+ case Parameter.SIGMOID:
272
+ return Math.tanh(param.gamma*dot(x,y)+param.coef0);
273
+ case Parameter.PRECOMPUTED:
274
+ return x[(int)(y[0].value)].value;
275
+ default:
276
+ return 0; // java
277
+ }
278
+ }
279
+ }
280
+
281
+ // An SMO algorithm in Fan et al., JMLR 6(2005), p. 1889--1918
282
+ // Solves:
283
+ //
284
+ // min 0.5(\alpha^T Q \alpha) + p^T \alpha
285
+ //
286
+ // y^T \alpha = \delta
287
+ // y_i = +1 or -1
288
+ // 0 <= alpha_i <= Cp for y_i = 1
289
+ // 0 <= alpha_i <= Cn for y_i = -1
290
+ //
291
+ // Given:
292
+ //
293
+ // Q, p, y, Cp, Cn, and an initial feasible point \alpha
294
+ // l is the size of vectors and matrices
295
+ // eps is the stopping tolerance
296
+ //
297
+ // solution will be put in \alpha, objective value will be put in obj
298
+ //
299
+ class Solver {
300
+ int active_size;
301
+ byte[] y;
302
+ double[] G; // gradient of objective function
303
+ static final byte LOWER_BOUND = 0;
304
+ static final byte UPPER_BOUND = 1;
305
+ static final byte FREE = 2;
306
+ byte[] alpha_status; // LOWER_BOUND, UPPER_BOUND, FREE
307
+ double[] alpha;
308
+ QMatrix Q;
309
+ double[] QD;
310
+ double eps;
311
+ double Cp,Cn;
312
+ double[] p;
313
+ int[] active_set;
314
+ double[] G_bar; // gradient, if we treat free variables as 0
315
+ int l;
316
+ boolean unshrink; // XXX
317
+
318
+ static final double INF = java.lang.Double.POSITIVE_INFINITY;
319
+
320
+ double get_C(int i)
321
+ {
322
+ return (y[i] > 0)? Cp : Cn;
323
+ }
324
+ void update_alpha_status(int i)
325
+ {
326
+ if(alpha[i] >= get_C(i))
327
+ alpha_status[i] = UPPER_BOUND;
328
+ else if(alpha[i] <= 0)
329
+ alpha_status[i] = LOWER_BOUND;
330
+ else alpha_status[i] = FREE;
331
+ }
332
+ boolean is_upper_bound(int i) { return alpha_status[i] == UPPER_BOUND; }
333
+ boolean is_lower_bound(int i) { return alpha_status[i] == LOWER_BOUND; }
334
+ boolean is_free(int i) { return alpha_status[i] == FREE; }
335
+
336
+ // java: information about solution except alpha,
337
+ // because we cannot return multiple values otherwise...
338
+ static class SolutionInfo {
339
+ double obj;
340
+ double rho;
341
+ double w_2; // for hyperplane (PCL, taken from Gabor Melis)
342
+ double upper_bound_p;
343
+ double upper_bound_n;
344
+ double r; // for Solver_NU
345
+ }
346
+
347
+ void swap_index(int i, int j)
348
+ {
349
+ Q.swap_index(i,j);
350
+ do {byte _=y[i]; y[i]=y[j]; y[j]=_;} while(false);
351
+ do {double _=G[i]; G[i]=G[j]; G[j]=_;} while(false);
352
+ do {byte _=alpha_status[i]; alpha_status[i]=alpha_status[j]; alpha_status[j]=_;} while(false);
353
+ do {double _=alpha[i]; alpha[i]=alpha[j]; alpha[j]=_;} while(false);
354
+ do {double _=p[i]; p[i]=p[j]; p[j]=_;} while(false);
355
+ do {int _=active_set[i]; active_set[i]=active_set[j]; active_set[j]=_;} while(false);
356
+ do {double _=G_bar[i]; G_bar[i]=G_bar[j]; G_bar[j]=_;} while(false);
357
+ }
358
+
359
+ void reconstruct_gradient()
360
+ {
361
+ // reconstruct inactive elements of G from G_bar and free variables
362
+
363
+ if(active_size == l) return;
364
+
365
+ int i,j;
366
+ int nr_free = 0;
367
+
368
+ for(j=active_size;j<l;j++)
369
+ G[j] = G_bar[j] + p[j];
370
+
371
+ for(j=0;j<active_size;j++)
372
+ if(is_free(j))
373
+ nr_free++;
374
+
375
+ if(2*nr_free < active_size)
376
+ Svm.info("\nWARNING: using -h 0 may be faster\n");
377
+
378
+ if (nr_free*l > 2*active_size*(l-active_size))
379
+ {
380
+ for(i=active_size;i<l;i++)
381
+ {
382
+ float[] Q_i = Q.get_Q(i,active_size);
383
+ for(j=0;j<active_size;j++)
384
+ if(is_free(j))
385
+ G[i] += alpha[j] * Q_i[j];
386
+ }
387
+ }
388
+ else
389
+ {
390
+ for(i=0;i<active_size;i++)
391
+ if(is_free(i))
392
+ {
393
+ float[] Q_i = Q.get_Q(i,l);
394
+ double alpha_i = alpha[i];
395
+ for(j=active_size;j<l;j++)
396
+ G[j] += alpha_i * Q_i[j];
397
+ }
398
+ }
399
+ }
400
+
401
+ void Solve(int l, QMatrix Q, double[] p_, byte[] y_,
402
+ double[] alpha_, double Cp, double Cn, double eps, SolutionInfo si, int shrinking)
403
+ {
404
+ this.l = l;
405
+ this.Q = Q;
406
+ QD = Q.get_QD();
407
+ p = (double[])p_.clone();
408
+ y = (byte[])y_.clone();
409
+ alpha = (double[])alpha_.clone();
410
+ this.Cp = Cp;
411
+ this.Cn = Cn;
412
+ this.eps = eps;
413
+ this.unshrink = false;
414
+
415
+ // initialize alpha_status
416
+ {
417
+ alpha_status = new byte[l];
418
+ for(int i=0;i<l;i++)
419
+ update_alpha_status(i);
420
+ }
421
+
422
+ // initialize active set (for shrinking)
423
+ {
424
+ active_set = new int[l];
425
+ for(int i=0;i<l;i++)
426
+ active_set[i] = i;
427
+ active_size = l;
428
+ }
429
+
430
+ // initialize gradient
431
+ {
432
+ G = new double[l];
433
+ G_bar = new double[l];
434
+ int i;
435
+ for(i=0;i<l;i++)
436
+ {
437
+ G[i] = p[i];
438
+ G_bar[i] = 0;
439
+ }
440
+ for(i=0;i<l;i++)
441
+ if(!is_lower_bound(i))
442
+ {
443
+ float[] Q_i = Q.get_Q(i,l);
444
+ double alpha_i = alpha[i];
445
+ int j;
446
+ for(j=0;j<l;j++)
447
+ G[j] += alpha_i*Q_i[j];
448
+ if(is_upper_bound(i))
449
+ for(j=0;j<l;j++)
450
+ G_bar[j] += get_C(i) * Q_i[j];
451
+ }
452
+ }
453
+
454
+ // optimization step
455
+
456
+ int iter = 0;
457
+ int max_iter = Math.max(10000000, l>Integer.MAX_VALUE/100 ? Integer.MAX_VALUE : 100*l);
458
+ int counter = Math.min(l,1000)+1;
459
+ int[] working_set = new int[2];
460
+
461
+ while(iter < max_iter)
462
+ {
463
+ // show progress and do shrinking
464
+
465
+ if(--counter == 0)
466
+ {
467
+ counter = Math.min(l,1000);
468
+ if(shrinking!=0) do_shrinking();
469
+ Svm.info(".");
470
+ }
471
+
472
+ if(select_working_set(working_set)!=0)
473
+ {
474
+ // reconstruct the whole gradient
475
+ reconstruct_gradient();
476
+ // reset active set size and check
477
+ active_size = l;
478
+ Svm.info("*");
479
+ if(select_working_set(working_set)!=0)
480
+ break;
481
+ else
482
+ counter = 1; // do shrinking next iteration
483
+ }
484
+
485
+ int i = working_set[0];
486
+ int j = working_set[1];
487
+
488
+ ++iter;
489
+
490
+ // update alpha[i] and alpha[j], handle bounds carefully
491
+
492
+ float[] Q_i = Q.get_Q(i,active_size);
493
+ float[] Q_j = Q.get_Q(j,active_size);
494
+
495
+ double C_i = get_C(i);
496
+ double C_j = get_C(j);
497
+
498
+ double old_alpha_i = alpha[i];
499
+ double old_alpha_j = alpha[j];
500
+
501
+ if(y[i]!=y[j])
502
+ {
503
+ double quad_coef = QD[i]+QD[j]+2*Q_i[j];
504
+ if (quad_coef <= 0)
505
+ quad_coef = 1e-12;
506
+ double delta = (-G[i]-G[j])/quad_coef;
507
+ double diff = alpha[i] - alpha[j];
508
+ alpha[i] += delta;
509
+ alpha[j] += delta;
510
+
511
+ if(diff > 0)
512
+ {
513
+ if(alpha[j] < 0)
514
+ {
515
+ alpha[j] = 0;
516
+ alpha[i] = diff;
517
+ }
518
+ }
519
+ else
520
+ {
521
+ if(alpha[i] < 0)
522
+ {
523
+ alpha[i] = 0;
524
+ alpha[j] = -diff;
525
+ }
526
+ }
527
+ if(diff > C_i - C_j)
528
+ {
529
+ if(alpha[i] > C_i)
530
+ {
531
+ alpha[i] = C_i;
532
+ alpha[j] = C_i - diff;
533
+ }
534
+ }
535
+ else
536
+ {
537
+ if(alpha[j] > C_j)
538
+ {
539
+ alpha[j] = C_j;
540
+ alpha[i] = C_j + diff;
541
+ }
542
+ }
543
+ }
544
+ else
545
+ {
546
+ double quad_coef = QD[i]+QD[j]-2*Q_i[j];
547
+ if (quad_coef <= 0)
548
+ quad_coef = 1e-12;
549
+ double delta = (G[i]-G[j])/quad_coef;
550
+ double sum = alpha[i] + alpha[j];
551
+ alpha[i] -= delta;
552
+ alpha[j] += delta;
553
+
554
+ if(sum > C_i)
555
+ {
556
+ if(alpha[i] > C_i)
557
+ {
558
+ alpha[i] = C_i;
559
+ alpha[j] = sum - C_i;
560
+ }
561
+ }
562
+ else
563
+ {
564
+ if(alpha[j] < 0)
565
+ {
566
+ alpha[j] = 0;
567
+ alpha[i] = sum;
568
+ }
569
+ }
570
+ if(sum > C_j)
571
+ {
572
+ if(alpha[j] > C_j)
573
+ {
574
+ alpha[j] = C_j;
575
+ alpha[i] = sum - C_j;
576
+ }
577
+ }
578
+ else
579
+ {
580
+ if(alpha[i] < 0)
581
+ {
582
+ alpha[i] = 0;
583
+ alpha[j] = sum;
584
+ }
585
+ }
586
+ }
587
+
588
+ // update G
589
+
590
+ double delta_alpha_i = alpha[i] - old_alpha_i;
591
+ double delta_alpha_j = alpha[j] - old_alpha_j;
592
+
593
+ for(int k=0;k<active_size;k++)
594
+ {
595
+ G[k] += Q_i[k]*delta_alpha_i + Q_j[k]*delta_alpha_j;
596
+ }
597
+
598
+ // update alpha_status and G_bar
599
+
600
+ {
601
+ boolean ui = is_upper_bound(i);
602
+ boolean uj = is_upper_bound(j);
603
+ update_alpha_status(i);
604
+ update_alpha_status(j);
605
+ int k;
606
+ if(ui != is_upper_bound(i))
607
+ {
608
+ Q_i = Q.get_Q(i,l);
609
+ if(ui)
610
+ for(k=0;k<l;k++)
611
+ G_bar[k] -= C_i * Q_i[k];
612
+ else
613
+ for(k=0;k<l;k++)
614
+ G_bar[k] += C_i * Q_i[k];
615
+ }
616
+
617
+ if(uj != is_upper_bound(j))
618
+ {
619
+ Q_j = Q.get_Q(j,l);
620
+ if(uj)
621
+ for(k=0;k<l;k++)
622
+ G_bar[k] -= C_j * Q_j[k];
623
+ else
624
+ for(k=0;k<l;k++)
625
+ G_bar[k] += C_j * Q_j[k];
626
+ }
627
+ }
628
+
629
+ }
630
+
631
+ if(iter >= max_iter)
632
+ {
633
+ if(active_size < l)
634
+ {
635
+ // reconstruct the whole gradient to calculate objective value
636
+ reconstruct_gradient();
637
+ active_size = l;
638
+ Svm.info("*");
639
+ }
640
+ Svm.info("\nWARNING: reaching max number of iterations");
641
+ }
642
+
643
+ // calculate rho
644
+
645
+ si.rho = calculate_rho();
646
+
647
+ // calculate objective value
648
+ {
649
+ double v = 0;
650
+ int i;
651
+ for(i=0;i<l;i++)
652
+ v += alpha[i] * (G[i] + p[i]);
653
+
654
+ si.obj = v/2;
655
+ }
656
+
657
+ // put back the solution
658
+ {
659
+ for(int i=0;i<l;i++)
660
+ alpha_[active_set[i]] = alpha[i];
661
+ }
662
+
663
+ si.upper_bound_p = Cp;
664
+ si.upper_bound_n = Cn;
665
+
666
+ Svm.info("\noptimization finished, #iter = "+iter+"\n");
667
+ }
668
+
669
+ // return 1 if already optimal, return 0 otherwise
670
+ int select_working_set(int[] working_set)
671
+ {
672
+ // return i,j such that
673
+ // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha)
674
+ // j: mimimizes the decrease of obj value
675
+ // (if quadratic coefficeint <= 0, replace it with tau)
676
+ // -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha)
677
+
678
+ double Gmax = -INF;
679
+ double Gmax2 = -INF;
680
+ int Gmax_idx = -1;
681
+ int Gmin_idx = -1;
682
+ double obj_diff_min = INF;
683
+
684
+ for(int t=0;t<active_size;t++)
685
+ if(y[t]==+1)
686
+ {
687
+ if(!is_upper_bound(t))
688
+ if(-G[t] >= Gmax)
689
+ {
690
+ Gmax = -G[t];
691
+ Gmax_idx = t;
692
+ }
693
+ }
694
+ else
695
+ {
696
+ if(!is_lower_bound(t))
697
+ if(G[t] >= Gmax)
698
+ {
699
+ Gmax = G[t];
700
+ Gmax_idx = t;
701
+ }
702
+ }
703
+
704
+ int i = Gmax_idx;
705
+ float[] Q_i = null;
706
+ if(i != -1) // null Q_i not accessed: Gmax=-INF if i=-1
707
+ Q_i = Q.get_Q(i,active_size);
708
+
709
+ for(int j=0;j<active_size;j++)
710
+ {
711
+ if(y[j]==+1)
712
+ {
713
+ if (!is_lower_bound(j))
714
+ {
715
+ double grad_diff=Gmax+G[j];
716
+ if (G[j] >= Gmax2)
717
+ Gmax2 = G[j];
718
+ if (grad_diff > 0)
719
+ {
720
+ double obj_diff;
721
+ double quad_coef = QD[i]+QD[j]-2.0*y[i]*Q_i[j];
722
+ if (quad_coef > 0)
723
+ obj_diff = -(grad_diff*grad_diff)/quad_coef;
724
+ else
725
+ obj_diff = -(grad_diff*grad_diff)/1e-12;
726
+
727
+ if (obj_diff <= obj_diff_min)
728
+ {
729
+ Gmin_idx=j;
730
+ obj_diff_min = obj_diff;
731
+ }
732
+ }
733
+ }
734
+ }
735
+ else
736
+ {
737
+ if (!is_upper_bound(j))
738
+ {
739
+ double grad_diff= Gmax-G[j];
740
+ if (-G[j] >= Gmax2)
741
+ Gmax2 = -G[j];
742
+ if (grad_diff > 0)
743
+ {
744
+ double obj_diff;
745
+ double quad_coef = QD[i]+QD[j]+2.0*y[i]*Q_i[j];
746
+ if (quad_coef > 0)
747
+ obj_diff = -(grad_diff*grad_diff)/quad_coef;
748
+ else
749
+ obj_diff = -(grad_diff*grad_diff)/1e-12;
750
+
751
+ if (obj_diff <= obj_diff_min)
752
+ {
753
+ Gmin_idx=j;
754
+ obj_diff_min = obj_diff;
755
+ }
756
+ }
757
+ }
758
+ }
759
+ }
760
+
761
+ if(Gmax+Gmax2 < eps)
762
+ return 1;
763
+
764
+ working_set[0] = Gmax_idx;
765
+ working_set[1] = Gmin_idx;
766
+ return 0;
767
+ }
768
+
769
+ private boolean be_shrunk(int i, double Gmax1, double Gmax2)
770
+ {
771
+ if(is_upper_bound(i))
772
+ {
773
+ if(y[i]==+1)
774
+ return(-G[i] > Gmax1);
775
+ else
776
+ return(-G[i] > Gmax2);
777
+ }
778
+ else if(is_lower_bound(i))
779
+ {
780
+ if(y[i]==+1)
781
+ return(G[i] > Gmax2);
782
+ else
783
+ return(G[i] > Gmax1);
784
+ }
785
+ else
786
+ return(false);
787
+ }
788
+
789
+ void do_shrinking()
790
+ {
791
+ int i;
792
+ double Gmax1 = -INF; // max { -y_i * grad(f)_i | i in I_up(\alpha) }
793
+ double Gmax2 = -INF; // max { y_i * grad(f)_i | i in I_low(\alpha) }
794
+
795
+ // find maximal violating pair first
796
+ for(i=0;i<active_size;i++)
797
+ {
798
+ if(y[i]==+1)
799
+ {
800
+ if(!is_upper_bound(i))
801
+ {
802
+ if(-G[i] >= Gmax1)
803
+ Gmax1 = -G[i];
804
+ }
805
+ if(!is_lower_bound(i))
806
+ {
807
+ if(G[i] >= Gmax2)
808
+ Gmax2 = G[i];
809
+ }
810
+ }
811
+ else
812
+ {
813
+ if(!is_upper_bound(i))
814
+ {
815
+ if(-G[i] >= Gmax2)
816
+ Gmax2 = -G[i];
817
+ }
818
+ if(!is_lower_bound(i))
819
+ {
820
+ if(G[i] >= Gmax1)
821
+ Gmax1 = G[i];
822
+ }
823
+ }
824
+ }
825
+
826
+ if(unshrink == false && Gmax1 + Gmax2 <= eps*10)
827
+ {
828
+ unshrink = true;
829
+ reconstruct_gradient();
830
+ active_size = l;
831
+ }
832
+
833
+ for(i=0;i<active_size;i++)
834
+ if (be_shrunk(i, Gmax1, Gmax2))
835
+ {
836
+ active_size--;
837
+ while (active_size > i)
838
+ {
839
+ if (!be_shrunk(active_size, Gmax1, Gmax2))
840
+ {
841
+ swap_index(i,active_size);
842
+ break;
843
+ }
844
+ active_size--;
845
+ }
846
+ }
847
+ }
848
+
849
+ double calculate_rho()
850
+ {
851
+ double r;
852
+ int nr_free = 0;
853
+ double ub = INF, lb = -INF, sum_free = 0;
854
+ for(int i=0;i<active_size;i++)
855
+ {
856
+ double yG = y[i]*G[i];
857
+
858
+ if(is_lower_bound(i))
859
+ {
860
+ if(y[i] > 0)
861
+ ub = Math.min(ub,yG);
862
+ else
863
+ lb = Math.max(lb,yG);
864
+ }
865
+ else if(is_upper_bound(i))
866
+ {
867
+ if(y[i] < 0)
868
+ ub = Math.min(ub,yG);
869
+ else
870
+ lb = Math.max(lb,yG);
871
+ }
872
+ else
873
+ {
874
+ ++nr_free;
875
+ sum_free += yG;
876
+ }
877
+ }
878
+
879
+ if(nr_free>0)
880
+ r = sum_free/nr_free;
881
+ else
882
+ r = (ub+lb)/2;
883
+
884
+ return r;
885
+ }
886
+
887
+ }
888
+
889
+ //
890
+ // Solver for nu-svm classification and regression
891
+ //
892
+ // additional constraint: e^T \alpha = constant
893
+ //
894
+ final class Solver_NU extends Solver
895
+ {
896
+ private SolutionInfo si;
897
+
898
+ void Solve(int l, QMatrix Q, double[] p, byte[] y,
899
+ double[] alpha, double Cp, double Cn, double eps,
900
+ SolutionInfo si, int shrinking)
901
+ {
902
+ this.si = si;
903
+ super.Solve(l,Q,p,y,alpha,Cp,Cn,eps,si,shrinking);
904
+ }
905
+
906
+ // return 1 if already optimal, return 0 otherwise
907
+ int select_working_set(int[] working_set)
908
+ {
909
+ // return i,j such that y_i = y_j and
910
+ // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha)
911
+ // j: minimizes the decrease of obj value
912
+ // (if quadratic coefficeint <= 0, replace it with tau)
913
+ // -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha)
914
+
915
+ double Gmaxp = -INF;
916
+ double Gmaxp2 = -INF;
917
+ int Gmaxp_idx = -1;
918
+
919
+ double Gmaxn = -INF;
920
+ double Gmaxn2 = -INF;
921
+ int Gmaxn_idx = -1;
922
+
923
+ int Gmin_idx = -1;
924
+ double obj_diff_min = INF;
925
+
926
+ for(int t=0;t<active_size;t++)
927
+ if(y[t]==+1)
928
+ {
929
+ if(!is_upper_bound(t))
930
+ if(-G[t] >= Gmaxp)
931
+ {
932
+ Gmaxp = -G[t];
933
+ Gmaxp_idx = t;
934
+ }
935
+ }
936
+ else
937
+ {
938
+ if(!is_lower_bound(t))
939
+ if(G[t] >= Gmaxn)
940
+ {
941
+ Gmaxn = G[t];
942
+ Gmaxn_idx = t;
943
+ }
944
+ }
945
+
946
+ int ip = Gmaxp_idx;
947
+ int in = Gmaxn_idx;
948
+ float[] Q_ip = null;
949
+ float[] Q_in = null;
950
+ if(ip != -1) // null Q_ip not accessed: Gmaxp=-INF if ip=-1
951
+ Q_ip = Q.get_Q(ip,active_size);
952
+ if(in != -1)
953
+ Q_in = Q.get_Q(in,active_size);
954
+
955
+ for(int j=0;j<active_size;j++)
956
+ {
957
+ if(y[j]==+1)
958
+ {
959
+ if (!is_lower_bound(j))
960
+ {
961
+ double grad_diff=Gmaxp+G[j];
962
+ if (G[j] >= Gmaxp2)
963
+ Gmaxp2 = G[j];
964
+ if (grad_diff > 0)
965
+ {
966
+ double obj_diff;
967
+ double quad_coef = QD[ip]+QD[j]-2*Q_ip[j];
968
+ if (quad_coef > 0)
969
+ obj_diff = -(grad_diff*grad_diff)/quad_coef;
970
+ else
971
+ obj_diff = -(grad_diff*grad_diff)/1e-12;
972
+
973
+ if (obj_diff <= obj_diff_min)
974
+ {
975
+ Gmin_idx=j;
976
+ obj_diff_min = obj_diff;
977
+ }
978
+ }
979
+ }
980
+ }
981
+ else
982
+ {
983
+ if (!is_upper_bound(j))
984
+ {
985
+ double grad_diff=Gmaxn-G[j];
986
+ if (-G[j] >= Gmaxn2)
987
+ Gmaxn2 = -G[j];
988
+ if (grad_diff > 0)
989
+ {
990
+ double obj_diff;
991
+ double quad_coef = QD[in]+QD[j]-2*Q_in[j];
992
+ if (quad_coef > 0)
993
+ obj_diff = -(grad_diff*grad_diff)/quad_coef;
994
+ else
995
+ obj_diff = -(grad_diff*grad_diff)/1e-12;
996
+
997
+ if (obj_diff <= obj_diff_min)
998
+ {
999
+ Gmin_idx=j;
1000
+ obj_diff_min = obj_diff;
1001
+ }
1002
+ }
1003
+ }
1004
+ }
1005
+ }
1006
+
1007
+ if(Math.max(Gmaxp+Gmaxp2,Gmaxn+Gmaxn2) < eps)
1008
+ return 1;
1009
+
1010
+ if(y[Gmin_idx] == +1)
1011
+ working_set[0] = Gmaxp_idx;
1012
+ else
1013
+ working_set[0] = Gmaxn_idx;
1014
+ working_set[1] = Gmin_idx;
1015
+
1016
+ return 0;
1017
+ }
1018
+
1019
+ private boolean be_shrunk(int i, double Gmax1, double Gmax2, double Gmax3, double Gmax4)
1020
+ {
1021
+ if(is_upper_bound(i))
1022
+ {
1023
+ if(y[i]==+1)
1024
+ return(-G[i] > Gmax1);
1025
+ else
1026
+ return(-G[i] > Gmax4);
1027
+ }
1028
+ else if(is_lower_bound(i))
1029
+ {
1030
+ if(y[i]==+1)
1031
+ return(G[i] > Gmax2);
1032
+ else
1033
+ return(G[i] > Gmax3);
1034
+ }
1035
+ else
1036
+ return(false);
1037
+ }
1038
+
1039
+ void do_shrinking()
1040
+ {
1041
+ double Gmax1 = -INF; // max { -y_i * grad(f)_i | y_i = +1, i in I_up(\alpha) }
1042
+ double Gmax2 = -INF; // max { y_i * grad(f)_i | y_i = +1, i in I_low(\alpha) }
1043
+ double Gmax3 = -INF; // max { -y_i * grad(f)_i | y_i = -1, i in I_up(\alpha) }
1044
+ double Gmax4 = -INF; // max { y_i * grad(f)_i | y_i = -1, i in I_low(\alpha) }
1045
+
1046
+ // find maximal violating pair first
1047
+ int i;
1048
+ for(i=0;i<active_size;i++)
1049
+ {
1050
+ if(!is_upper_bound(i))
1051
+ {
1052
+ if(y[i]==+1)
1053
+ {
1054
+ if(-G[i] > Gmax1) Gmax1 = -G[i];
1055
+ }
1056
+ else if(-G[i] > Gmax4) Gmax4 = -G[i];
1057
+ }
1058
+ if(!is_lower_bound(i))
1059
+ {
1060
+ if(y[i]==+1)
1061
+ {
1062
+ if(G[i] > Gmax2) Gmax2 = G[i];
1063
+ }
1064
+ else if(G[i] > Gmax3) Gmax3 = G[i];
1065
+ }
1066
+ }
1067
+
1068
+ if(unshrink == false && Math.max(Gmax1+Gmax2,Gmax3+Gmax4) <= eps*10)
1069
+ {
1070
+ unshrink = true;
1071
+ reconstruct_gradient();
1072
+ active_size = l;
1073
+ }
1074
+
1075
+ for(i=0;i<active_size;i++)
1076
+ if (be_shrunk(i, Gmax1, Gmax2, Gmax3, Gmax4))
1077
+ {
1078
+ active_size--;
1079
+ while (active_size > i)
1080
+ {
1081
+ if (!be_shrunk(active_size, Gmax1, Gmax2, Gmax3, Gmax4))
1082
+ {
1083
+ swap_index(i,active_size);
1084
+ break;
1085
+ }
1086
+ active_size--;
1087
+ }
1088
+ }
1089
+ }
1090
+
1091
+ double calculate_rho()
1092
+ {
1093
+ int nr_free1 = 0,nr_free2 = 0;
1094
+ double ub1 = INF, ub2 = INF;
1095
+ double lb1 = -INF, lb2 = -INF;
1096
+ double sum_free1 = 0, sum_free2 = 0;
1097
+
1098
+ for(int i=0;i<active_size;i++)
1099
+ {
1100
+ if(y[i]==+1)
1101
+ {
1102
+ if(is_lower_bound(i))
1103
+ ub1 = Math.min(ub1,G[i]);
1104
+ else if(is_upper_bound(i))
1105
+ lb1 = Math.max(lb1,G[i]);
1106
+ else
1107
+ {
1108
+ ++nr_free1;
1109
+ sum_free1 += G[i];
1110
+ }
1111
+ }
1112
+ else
1113
+ {
1114
+ if(is_lower_bound(i))
1115
+ ub2 = Math.min(ub2,G[i]);
1116
+ else if(is_upper_bound(i))
1117
+ lb2 = Math.max(lb2,G[i]);
1118
+ else
1119
+ {
1120
+ ++nr_free2;
1121
+ sum_free2 += G[i];
1122
+ }
1123
+ }
1124
+ }
1125
+
1126
+ double r1,r2;
1127
+ if(nr_free1 > 0)
1128
+ r1 = sum_free1/nr_free1;
1129
+ else
1130
+ r1 = (ub1+lb1)/2;
1131
+
1132
+ if(nr_free2 > 0)
1133
+ r2 = sum_free2/nr_free2;
1134
+ else
1135
+ r2 = (ub2+lb2)/2;
1136
+
1137
+ si.r = (r1+r2)/2;
1138
+ return (r1-r2)/2;
1139
+ }
1140
+ }
1141
+
1142
+ //
1143
+ // Q matrices for various formulations
1144
+ //
1145
+ class SVC_Q extends Kernel
1146
+ {
1147
+ private final byte[] y;
1148
+ private final Cache cache;
1149
+ private final double[] QD;
1150
+
1151
+ SVC_Q(Problem prob, Parameter param, byte[] y_)
1152
+ {
1153
+ super(prob.l, prob.x, param);
1154
+ y = (byte[])y_.clone();
1155
+ cache = new Cache(prob.l,(long)(param.cache_size*(1<<20)));
1156
+ QD = new double[prob.l];
1157
+ for(int i=0;i<prob.l;i++)
1158
+ QD[i] = kernel_function(i,i);
1159
+ }
1160
+
1161
+ float[] get_Q(int i, int len)
1162
+ {
1163
+ float[][] data = new float[1][];
1164
+ int start, j;
1165
+ if((start = cache.get_data(i,data,len)) < len)
1166
+ {
1167
+ for(j=start;j<len;j++)
1168
+ data[0][j] = (float)(y[i]*y[j]*kernel_function(i,j));
1169
+ }
1170
+ return data[0];
1171
+ }
1172
+
1173
+ double[] get_QD()
1174
+ {
1175
+ return QD;
1176
+ }
1177
+
1178
+ void swap_index(int i, int j)
1179
+ {
1180
+ cache.swap_index(i,j);
1181
+ super.swap_index(i,j);
1182
+ do {byte _=y[i]; y[i]=y[j]; y[j]=_;} while(false);
1183
+ do {double _=QD[i]; QD[i]=QD[j]; QD[j]=_;} while(false);
1184
+ }
1185
+ }
1186
+
1187
+ class ONE_CLASS_Q extends Kernel
1188
+ {
1189
+ private final Cache cache;
1190
+ private final double[] QD;
1191
+
1192
+ ONE_CLASS_Q(Problem prob, Parameter param)
1193
+ {
1194
+ super(prob.l, prob.x, param);
1195
+ cache = new Cache(prob.l,(long)(param.cache_size*(1<<20)));
1196
+ QD = new double[prob.l];
1197
+ for(int i=0;i<prob.l;i++)
1198
+ QD[i] = kernel_function(i,i);
1199
+ }
1200
+
1201
+ float[] get_Q(int i, int len)
1202
+ {
1203
+ float[][] data = new float[1][];
1204
+ int start, j;
1205
+ if((start = cache.get_data(i,data,len)) < len)
1206
+ {
1207
+ for(j=start;j<len;j++)
1208
+ data[0][j] = (float)kernel_function(i,j);
1209
+ }
1210
+ return data[0];
1211
+ }
1212
+
1213
+ double[] get_QD()
1214
+ {
1215
+ return QD;
1216
+ }
1217
+
1218
+ void swap_index(int i, int j)
1219
+ {
1220
+ cache.swap_index(i,j);
1221
+ super.swap_index(i,j);
1222
+ do {double _=QD[i]; QD[i]=QD[j]; QD[j]=_;} while(false);
1223
+ }
1224
+ }
1225
+
1226
+ class SVR_Q extends Kernel
1227
+ {
1228
+ private final int l;
1229
+ private final Cache cache;
1230
+ private final byte[] sign;
1231
+ private final int[] index;
1232
+ private int next_buffer;
1233
+ private float[][] buffer;
1234
+ private final double[] QD;
1235
+
1236
+ SVR_Q(Problem prob, Parameter param)
1237
+ {
1238
+ super(prob.l, prob.x, param);
1239
+ l = prob.l;
1240
+ cache = new Cache(l,(long)(param.cache_size*(1<<20)));
1241
+ QD = new double[2*l];
1242
+ sign = new byte[2*l];
1243
+ index = new int[2*l];
1244
+ for(int k=0;k<l;k++)
1245
+ {
1246
+ sign[k] = 1;
1247
+ sign[k+l] = -1;
1248
+ index[k] = k;
1249
+ index[k+l] = k;
1250
+ QD[k] = kernel_function(k,k);
1251
+ QD[k+l] = QD[k];
1252
+ }
1253
+ buffer = new float[2][2*l];
1254
+ next_buffer = 0;
1255
+ }
1256
+
1257
+ void swap_index(int i, int j)
1258
+ {
1259
+ do {byte _=sign[i]; sign[i]=sign[j]; sign[j]=_;} while(false);
1260
+ do {int _=index[i]; index[i]=index[j]; index[j]=_;} while(false);
1261
+ do {double _=QD[i]; QD[i]=QD[j]; QD[j]=_;} while(false);
1262
+ }
1263
+
1264
+ float[] get_Q(int i, int len)
1265
+ {
1266
+ float[][] data = new float[1][];
1267
+ int j, real_i = index[i];
1268
+ if(cache.get_data(real_i,data,l) < l)
1269
+ {
1270
+ for(j=0;j<l;j++)
1271
+ data[0][j] = (float)kernel_function(real_i,j);
1272
+ }
1273
+
1274
+ // reorder and copy
1275
+ float buf[] = buffer[next_buffer];
1276
+ next_buffer = 1 - next_buffer;
1277
+ byte si = sign[i];
1278
+ for(j=0;j<len;j++)
1279
+ buf[j] = (float) si * sign[j] * data[0][index[j]];
1280
+ return buf;
1281
+ }
1282
+
1283
+ double[] get_QD()
1284
+ {
1285
+ return QD;
1286
+ }
1287
+ }
1288
+
1289
+ public class Svm {
1290
+ //
1291
+ // construct and solve various formulations
1292
+ //
1293
+ public static final int LIBSVM_VERSION=314;
1294
+ public static final Random rand = new Random();
1295
+
1296
+ private static PrintInterface svm_print_stdout = new PrintInterface()
1297
+ {
1298
+ public void print(String s)
1299
+ {
1300
+ System.out.print(s);
1301
+ System.out.flush();
1302
+ }
1303
+ };
1304
+
1305
+ private static PrintInterface svm_print_string = svm_print_stdout;
1306
+
1307
+ static void info(String s)
1308
+ {
1309
+ // svm_print_string.print(s);
1310
+ }
1311
+
1312
+ private static void solve_c_svc(Problem prob, Parameter param,
1313
+ double[] alpha, Solver.SolutionInfo si,
1314
+ double Cp, double Cn)
1315
+ {
1316
+ int l = prob.l;
1317
+ double[] minus_ones = new double[l];
1318
+ byte[] y = new byte[l];
1319
+
1320
+ int i;
1321
+
1322
+ for(i=0;i<l;i++)
1323
+ {
1324
+ alpha[i] = 0;
1325
+ minus_ones[i] = -1;
1326
+ if(prob.y[i] > 0) y[i] = +1; else y[i] = -1;
1327
+ }
1328
+
1329
+ Solver s = new Solver();
1330
+ s.Solve(l, new SVC_Q(prob,param,y), minus_ones, y,
1331
+ alpha, Cp, Cn, param.eps, si, param.shrinking);
1332
+
1333
+ double sum_alpha=0;
1334
+ for(i=0;i<l;i++)
1335
+ sum_alpha += alpha[i];
1336
+
1337
+ if (Cp==Cn)
1338
+ Svm.info("nu = "+sum_alpha/(Cp*prob.l)+"\n");
1339
+
1340
+ for(i=0;i<l;i++)
1341
+ alpha[i] *= y[i];
1342
+
1343
+ si.w_2 = -2 * (Math.abs(si.obj) - sum_alpha); // PCL taken from Gabor Melis
1344
+ }
1345
+
1346
+ private static void solve_nu_svc(Problem prob, Parameter param,
1347
+ double[] alpha, Solver.SolutionInfo si)
1348
+ {
1349
+ int i;
1350
+ int l = prob.l;
1351
+ double nu = param.nu;
1352
+
1353
+ byte[] y = new byte[l];
1354
+
1355
+ for(i=0;i<l;i++)
1356
+ if(prob.y[i]>0)
1357
+ y[i] = +1;
1358
+ else
1359
+ y[i] = -1;
1360
+
1361
+ double sum_pos = nu*l/2;
1362
+ double sum_neg = nu*l/2;
1363
+
1364
+ for(i=0;i<l;i++)
1365
+ if(y[i] == +1)
1366
+ {
1367
+ alpha[i] = Math.min(1.0,sum_pos);
1368
+ sum_pos -= alpha[i];
1369
+ }
1370
+ else
1371
+ {
1372
+ alpha[i] = Math.min(1.0,sum_neg);
1373
+ sum_neg -= alpha[i];
1374
+ }
1375
+
1376
+ double[] zeros = new double[l];
1377
+
1378
+ for(i=0;i<l;i++)
1379
+ zeros[i] = 0;
1380
+
1381
+ Solver_NU s = new Solver_NU();
1382
+ s.Solve(l, new SVC_Q(prob,param,y), zeros, y,
1383
+ alpha, 1.0, 1.0, param.eps, si, param.shrinking);
1384
+ double r = si.r;
1385
+
1386
+ Svm.info("C = "+1/r+"\n");
1387
+
1388
+ for(i=0;i<l;i++)
1389
+ alpha[i] *= y[i]/r;
1390
+
1391
+ si.rho /= r;
1392
+ si.obj /= (r*r);
1393
+ si.upper_bound_p = 1/r;
1394
+ si.upper_bound_n = 1/r;
1395
+ }
1396
+
1397
+ private static void solve_one_class(Problem prob, Parameter param,
1398
+ double[] alpha, Solver.SolutionInfo si)
1399
+ {
1400
+ int l = prob.l;
1401
+ double[] zeros = new double[l];
1402
+ byte[] ones = new byte[l];
1403
+ int i;
1404
+
1405
+ int n = (int)(param.nu*prob.l); // # of alpha's at upper bound
1406
+
1407
+ for(i=0;i<n;i++)
1408
+ alpha[i] = 1;
1409
+ if(n<prob.l)
1410
+ alpha[n] = param.nu * prob.l - n;
1411
+ for(i=n+1;i<l;i++)
1412
+ alpha[i] = 0;
1413
+
1414
+ for(i=0;i<l;i++)
1415
+ {
1416
+ zeros[i] = 0;
1417
+ ones[i] = 1;
1418
+ }
1419
+
1420
+ Solver s = new Solver();
1421
+ s.Solve(l, new ONE_CLASS_Q(prob,param), zeros, ones,
1422
+ alpha, 1.0, 1.0, param.eps, si, param.shrinking);
1423
+ }
1424
+
1425
+ private static void solve_epsilon_svr(Problem prob, Parameter param,
1426
+ double[] alpha, Solver.SolutionInfo si)
1427
+ {
1428
+ int l = prob.l;
1429
+ double[] alpha2 = new double[2*l];
1430
+ double[] linear_term = new double[2*l];
1431
+ byte[] y = new byte[2*l];
1432
+ int i;
1433
+
1434
+ for(i=0;i<l;i++)
1435
+ {
1436
+ alpha2[i] = 0;
1437
+ linear_term[i] = param.p - prob.y[i];
1438
+ y[i] = 1;
1439
+
1440
+ alpha2[i+l] = 0;
1441
+ linear_term[i+l] = param.p + prob.y[i];
1442
+ y[i+l] = -1;
1443
+ }
1444
+
1445
+ Solver s = new Solver();
1446
+ s.Solve(2*l, new SVR_Q(prob,param), linear_term, y,
1447
+ alpha2, param.C, param.C, param.eps, si, param.shrinking);
1448
+
1449
+ double sum_alpha = 0;
1450
+ for(i=0;i<l;i++)
1451
+ {
1452
+ alpha[i] = alpha2[i] - alpha2[i+l];
1453
+ sum_alpha += Math.abs(alpha[i]);
1454
+ }
1455
+ Svm.info("nu = "+sum_alpha/(param.C*l)+"\n");
1456
+ }
1457
+
1458
+ private static void solve_nu_svr(Problem prob, Parameter param,
1459
+ double[] alpha, Solver.SolutionInfo si)
1460
+ {
1461
+ int l = prob.l;
1462
+ double C = param.C;
1463
+ double[] alpha2 = new double[2*l];
1464
+ double[] linear_term = new double[2*l];
1465
+ byte[] y = new byte[2*l];
1466
+ int i;
1467
+
1468
+ double sum = C * param.nu * l / 2;
1469
+ for(i=0;i<l;i++)
1470
+ {
1471
+ alpha2[i] = alpha2[i+l] = Math.min(sum,C);
1472
+ sum -= alpha2[i];
1473
+
1474
+ linear_term[i] = - prob.y[i];
1475
+ y[i] = 1;
1476
+
1477
+ linear_term[i+l] = prob.y[i];
1478
+ y[i+l] = -1;
1479
+ }
1480
+
1481
+ Solver_NU s = new Solver_NU();
1482
+ s.Solve(2*l, new SVR_Q(prob,param), linear_term, y,
1483
+ alpha2, C, C, param.eps, si, param.shrinking);
1484
+
1485
+ Svm.info("epsilon = "+(-si.r)+"\n");
1486
+
1487
+ for(i=0;i<l;i++)
1488
+ alpha[i] = alpha2[i] - alpha2[i+l];
1489
+ }
1490
+
1491
+ //
1492
+ // decision_function
1493
+ //
1494
+ static class decision_function
1495
+ {
1496
+ double[] alpha;
1497
+ double rho;
1498
+ double w_2; // PCL, taken from Gabor Melis
1499
+ };
1500
+
1501
+ static decision_function svm_train_one(
1502
+ Problem prob, Parameter param,
1503
+ double Cp, double Cn)
1504
+ {
1505
+ double[] alpha = new double[prob.l];
1506
+ Solver.SolutionInfo si = new Solver.SolutionInfo();
1507
+ switch(param.svm_type)
1508
+ {
1509
+ case Parameter.C_SVC:
1510
+ solve_c_svc(prob,param,alpha,si,Cp,Cn);
1511
+ break;
1512
+ case Parameter.NU_SVC:
1513
+ solve_nu_svc(prob,param,alpha,si);
1514
+ break;
1515
+ case Parameter.ONE_CLASS:
1516
+ solve_one_class(prob,param,alpha,si);
1517
+ break;
1518
+ case Parameter.EPSILON_SVR:
1519
+ solve_epsilon_svr(prob,param,alpha,si);
1520
+ break;
1521
+ case Parameter.NU_SVR:
1522
+ solve_nu_svr(prob,param,alpha,si);
1523
+ break;
1524
+ }
1525
+
1526
+ Svm.info("obj = "+si.obj+", rho = "+si.rho+"\n");
1527
+
1528
+ // output SVs
1529
+
1530
+ int nSV = 0;
1531
+ int nBSV = 0;
1532
+ for(int i=0;i<prob.l;i++)
1533
+ {
1534
+ if(Math.abs(alpha[i]) > 0)
1535
+ {
1536
+ ++nSV;
1537
+ if(prob.y[i] > 0)
1538
+ {
1539
+ if(Math.abs(alpha[i]) >= si.upper_bound_p)
1540
+ ++nBSV;
1541
+ }
1542
+ else
1543
+ {
1544
+ if(Math.abs(alpha[i]) >= si.upper_bound_n)
1545
+ ++nBSV;
1546
+ }
1547
+ }
1548
+ }
1549
+
1550
+ Svm.info("nSV = "+nSV+", nBSV = "+nBSV+"\n");
1551
+
1552
+ decision_function f = new decision_function();
1553
+ f.alpha = alpha;
1554
+ f.rho = si.rho;
1555
+ f.w_2 = si.w_2; // PCL, taken from Gabor Melis
1556
+
1557
+ return f;
1558
+ }
1559
+
1560
+ // Platt's binary SVM Probablistic Output: an improvement from Lin et al.
1561
+ private static void sigmoid_train(int l, double[] dec_values, double[] labels,
1562
+ double[] probAB)
1563
+ {
1564
+ double A, B;
1565
+ double prior1=0, prior0 = 0;
1566
+ int i;
1567
+
1568
+ for (i=0;i<l;i++)
1569
+ if (labels[i] > 0) prior1+=1;
1570
+ else prior0+=1;
1571
+
1572
+ int max_iter=100; // Maximal number of iterations
1573
+ double min_step=1e-10; // Minimal step taken in line search
1574
+ double sigma=1e-12; // For numerically strict PD of Hessian
1575
+ double eps=1e-5;
1576
+ double hiTarget=(prior1+1.0)/(prior1+2.0);
1577
+ double loTarget=1/(prior0+2.0);
1578
+ double[] t= new double[l];
1579
+ double fApB,p,q,h11,h22,h21,g1,g2,det,dA,dB,gd,stepsize;
1580
+ double newA,newB,newf,d1,d2;
1581
+ int iter;
1582
+
1583
+ // Initial Point and Initial Fun Value
1584
+ A=0.0; B=Math.log((prior0+1.0)/(prior1+1.0));
1585
+ double fval = 0.0;
1586
+
1587
+ for (i=0;i<l;i++)
1588
+ {
1589
+ if (labels[i]>0) t[i]=hiTarget;
1590
+ else t[i]=loTarget;
1591
+ fApB = dec_values[i]*A+B;
1592
+ if (fApB>=0)
1593
+ fval += t[i]*fApB + Math.log(1+Math.exp(-fApB));
1594
+ else
1595
+ fval += (t[i] - 1)*fApB +Math.log(1+Math.exp(fApB));
1596
+ }
1597
+ for (iter=0;iter<max_iter;iter++)
1598
+ {
1599
+ // Update Gradient and Hessian (use H' = H + sigma I)
1600
+ h11=sigma; // numerically ensures strict PD
1601
+ h22=sigma;
1602
+ h21=0.0;g1=0.0;g2=0.0;
1603
+ for (i=0;i<l;i++)
1604
+ {
1605
+ fApB = dec_values[i]*A+B;
1606
+ if (fApB >= 0)
1607
+ {
1608
+ p=Math.exp(-fApB)/(1.0+Math.exp(-fApB));
1609
+ q=1.0/(1.0+Math.exp(-fApB));
1610
+ }
1611
+ else
1612
+ {
1613
+ p=1.0/(1.0+Math.exp(fApB));
1614
+ q=Math.exp(fApB)/(1.0+Math.exp(fApB));
1615
+ }
1616
+ d2=p*q;
1617
+ h11+=dec_values[i]*dec_values[i]*d2;
1618
+ h22+=d2;
1619
+ h21+=dec_values[i]*d2;
1620
+ d1=t[i]-p;
1621
+ g1+=dec_values[i]*d1;
1622
+ g2+=d1;
1623
+ }
1624
+
1625
+ // Stopping Criteria
1626
+ if (Math.abs(g1)<eps && Math.abs(g2)<eps)
1627
+ break;
1628
+
1629
+ // Finding Newton direction: -inv(H') * g
1630
+ det=h11*h22-h21*h21;
1631
+ dA=-(h22*g1 - h21 * g2) / det;
1632
+ dB=-(-h21*g1+ h11 * g2) / det;
1633
+ gd=g1*dA+g2*dB;
1634
+
1635
+
1636
+ stepsize = 1; // Line Search
1637
+ while (stepsize >= min_step)
1638
+ {
1639
+ newA = A + stepsize * dA;
1640
+ newB = B + stepsize * dB;
1641
+
1642
+ // New function value
1643
+ newf = 0.0;
1644
+ for (i=0;i<l;i++)
1645
+ {
1646
+ fApB = dec_values[i]*newA+newB;
1647
+ if (fApB >= 0)
1648
+ newf += t[i]*fApB + Math.log(1+Math.exp(-fApB));
1649
+ else
1650
+ newf += (t[i] - 1)*fApB +Math.log(1+Math.exp(fApB));
1651
+ }
1652
+ // Check sufficient decrease
1653
+ if (newf<fval+0.0001*stepsize*gd)
1654
+ {
1655
+ A=newA;B=newB;fval=newf;
1656
+ break;
1657
+ }
1658
+ else
1659
+ stepsize = stepsize / 2.0;
1660
+ }
1661
+
1662
+ if (stepsize < min_step)
1663
+ {
1664
+ Svm.info("Line search fails in two-class probability estimates\n");
1665
+ break;
1666
+ }
1667
+ }
1668
+
1669
+ if (iter>=max_iter)
1670
+ Svm.info("Reaching maximal iterations in two-class probability estimates\n");
1671
+ probAB[0]=A;probAB[1]=B;
1672
+ }
1673
+
1674
+ private static double sigmoid_predict(double decision_value, double A, double B)
1675
+ {
1676
+ double fApB = decision_value*A+B;
1677
+ if (fApB >= 0)
1678
+ return Math.exp(-fApB)/(1.0+Math.exp(-fApB));
1679
+ else
1680
+ return 1.0/(1+Math.exp(fApB)) ;
1681
+ }
1682
+
1683
+ // Method 2 from the multiclass_prob paper by Wu, Lin, and Weng
1684
+ private static void multiclass_probability(int k, double[][] r, double[] p)
1685
+ {
1686
+ int t,j;
1687
+ int iter = 0, max_iter=Math.max(100,k);
1688
+ double[][] Q=new double[k][k];
1689
+ double[] Qp=new double[k];
1690
+ double pQp, eps=0.005/k;
1691
+
1692
+ for (t=0;t<k;t++)
1693
+ {
1694
+ p[t]=1.0/k; // Valid if k = 1
1695
+ Q[t][t]=0;
1696
+ for (j=0;j<t;j++)
1697
+ {
1698
+ Q[t][t]+=r[j][t]*r[j][t];
1699
+ Q[t][j]=Q[j][t];
1700
+ }
1701
+ for (j=t+1;j<k;j++)
1702
+ {
1703
+ Q[t][t]+=r[j][t]*r[j][t];
1704
+ Q[t][j]=-r[j][t]*r[t][j];
1705
+ }
1706
+ }
1707
+ for (iter=0;iter<max_iter;iter++)
1708
+ {
1709
+ // stopping condition, recalculate QP,pQP for numerical accuracy
1710
+ pQp=0;
1711
+ for (t=0;t<k;t++)
1712
+ {
1713
+ Qp[t]=0;
1714
+ for (j=0;j<k;j++)
1715
+ Qp[t]+=Q[t][j]*p[j];
1716
+ pQp+=p[t]*Qp[t];
1717
+ }
1718
+ double max_error=0;
1719
+ for (t=0;t<k;t++)
1720
+ {
1721
+ double error=Math.abs(Qp[t]-pQp);
1722
+ if (error>max_error)
1723
+ max_error=error;
1724
+ }
1725
+ if (max_error<eps) break;
1726
+
1727
+ for (t=0;t<k;t++)
1728
+ {
1729
+ double diff=(-Qp[t]+pQp)/Q[t][t];
1730
+ p[t]+=diff;
1731
+ pQp=(pQp+diff*(diff*Q[t][t]+2*Qp[t]))/(1+diff)/(1+diff);
1732
+ for (j=0;j<k;j++)
1733
+ {
1734
+ Qp[j]=(Qp[j]+diff*Q[t][j])/(1+diff);
1735
+ p[j]/=(1+diff);
1736
+ }
1737
+ }
1738
+ }
1739
+ if (iter>=max_iter)
1740
+ Svm.info("Exceeds max_iter in multiclass_prob\n");
1741
+ }
1742
+
1743
+ // Cross-validation decision values for probability estimates
1744
+ private static void svm_binary_svc_probability(Problem prob, Parameter param, double Cp, double Cn, double[] probAB)
1745
+ {
1746
+ int i;
1747
+ int nr_fold = 5;
1748
+ int[] perm = new int[prob.l];
1749
+ double[] dec_values = new double[prob.l];
1750
+
1751
+ // random shuffle
1752
+ for(i=0;i<prob.l;i++) perm[i]=i;
1753
+ for(i=0;i<prob.l;i++)
1754
+ {
1755
+ int j = i+rand.nextInt(prob.l-i);
1756
+ do {int _=perm[i]; perm[i]=perm[j]; perm[j]=_;} while(false);
1757
+ }
1758
+ for(i=0;i<nr_fold;i++)
1759
+ {
1760
+ int begin = i*prob.l/nr_fold;
1761
+ int end = (i+1)*prob.l/nr_fold;
1762
+ int j,k;
1763
+ Problem subprob = new Problem();
1764
+
1765
+ subprob.l = prob.l-(end-begin);
1766
+ subprob.x = new Node[subprob.l][];
1767
+ subprob.y = new double[subprob.l];
1768
+
1769
+ k=0;
1770
+ for(j=0;j<begin;j++)
1771
+ {
1772
+ subprob.x[k] = prob.x[perm[j]];
1773
+ subprob.y[k] = prob.y[perm[j]];
1774
+ ++k;
1775
+ }
1776
+ for(j=end;j<prob.l;j++)
1777
+ {
1778
+ subprob.x[k] = prob.x[perm[j]];
1779
+ subprob.y[k] = prob.y[perm[j]];
1780
+ ++k;
1781
+ }
1782
+ int p_count=0,n_count=0;
1783
+ for(j=0;j<k;j++)
1784
+ if(subprob.y[j]>0)
1785
+ p_count++;
1786
+ else
1787
+ n_count++;
1788
+
1789
+ if(p_count==0 && n_count==0)
1790
+ for(j=begin;j<end;j++)
1791
+ dec_values[perm[j]] = 0;
1792
+ else if(p_count > 0 && n_count == 0)
1793
+ for(j=begin;j<end;j++)
1794
+ dec_values[perm[j]] = 1;
1795
+ else if(p_count == 0 && n_count > 0)
1796
+ for(j=begin;j<end;j++)
1797
+ dec_values[perm[j]] = -1;
1798
+ else
1799
+ {
1800
+ Parameter subparam = (Parameter)param.clone();
1801
+ subparam.probability=0;
1802
+ subparam.C=1.0;
1803
+ subparam.nr_weight=2;
1804
+ subparam.weight_label = new int[2];
1805
+ subparam.weight = new double[2];
1806
+ subparam.weight_label[0]=+1;
1807
+ subparam.weight_label[1]=-1;
1808
+ subparam.weight[0]=Cp;
1809
+ subparam.weight[1]=Cn;
1810
+ Model submodel = svm_train(subprob,subparam);
1811
+ for(j=begin;j<end;j++)
1812
+ {
1813
+ double[] dec_value=new double[1];
1814
+ svm_predict_values(submodel,prob.x[perm[j]],dec_value);
1815
+ dec_values[perm[j]]=dec_value[0];
1816
+ // ensure +1 -1 order; reason not using CV subroutine
1817
+ dec_values[perm[j]] *= submodel.label[0];
1818
+ }
1819
+ }
1820
+ }
1821
+ sigmoid_train(prob.l,dec_values,prob.y,probAB);
1822
+ }
1823
+
1824
+ // Return parameter of a Laplace distribution
1825
+ private static double svm_svr_probability(Problem prob, Parameter param)
1826
+ {
1827
+ int i;
1828
+ int nr_fold = 5;
1829
+ double[] ymv = new double[prob.l];
1830
+ double mae = 0;
1831
+
1832
+ Parameter newparam = (Parameter)param.clone();
1833
+ newparam.probability = 0;
1834
+ svm_cross_validation(prob,newparam,nr_fold,ymv);
1835
+ for(i=0;i<prob.l;i++)
1836
+ {
1837
+ ymv[i]=prob.y[i]-ymv[i];
1838
+ mae += Math.abs(ymv[i]);
1839
+ }
1840
+ mae /= prob.l;
1841
+ double std=Math.sqrt(2*mae*mae);
1842
+ int count=0;
1843
+ mae=0;
1844
+ for(i=0;i<prob.l;i++)
1845
+ if (Math.abs(ymv[i]) > 5*std)
1846
+ count=count+1;
1847
+ else
1848
+ mae+=Math.abs(ymv[i]);
1849
+ mae /= (prob.l-count);
1850
+ Svm.info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma="+mae+"\n");
1851
+ return mae;
1852
+ }
1853
+
1854
+ // label: label name, start: begin of each class, count: #data of classes, perm: indices to the original data
1855
+ // perm, length l, must be allocated before calling this subroutine
1856
+ private static void svm_group_classes(Problem prob, int[] nr_class_ret, int[][] label_ret, int[][] start_ret, int[][] count_ret, int[] perm)
1857
+ {
1858
+ int l = prob.l;
1859
+ int max_nr_class = 16;
1860
+ int nr_class = 0;
1861
+ int[] label = new int[max_nr_class];
1862
+ int[] count = new int[max_nr_class];
1863
+ int[] data_label = new int[l];
1864
+ int i;
1865
+
1866
+ for(i=0;i<l;i++)
1867
+ {
1868
+ int this_label = (int)(prob.y[i]);
1869
+ int j;
1870
+ for(j=0;j<nr_class;j++)
1871
+ {
1872
+ if(this_label == label[j])
1873
+ {
1874
+ ++count[j];
1875
+ break;
1876
+ }
1877
+ }
1878
+ data_label[i] = j;
1879
+ if(j == nr_class)
1880
+ {
1881
+ if(nr_class == max_nr_class)
1882
+ {
1883
+ max_nr_class *= 2;
1884
+ int[] new_data = new int[max_nr_class];
1885
+ System.arraycopy(label,0,new_data,0,label.length);
1886
+ label = new_data;
1887
+ new_data = new int[max_nr_class];
1888
+ System.arraycopy(count,0,new_data,0,count.length);
1889
+ count = new_data;
1890
+ }
1891
+ label[nr_class] = this_label;
1892
+ count[nr_class] = 1;
1893
+ ++nr_class;
1894
+ }
1895
+ }
1896
+
1897
+ int[] start = new int[nr_class];
1898
+ start[0] = 0;
1899
+ for(i=1;i<nr_class;i++)
1900
+ start[i] = start[i-1]+count[i-1];
1901
+ for(i=0;i<l;i++)
1902
+ {
1903
+ perm[start[data_label[i]]] = i;
1904
+ ++start[data_label[i]];
1905
+ }
1906
+ start[0] = 0;
1907
+ for(i=1;i<nr_class;i++)
1908
+ start[i] = start[i-1]+count[i-1];
1909
+
1910
+ nr_class_ret[0] = nr_class;
1911
+ label_ret[0] = label;
1912
+ start_ret[0] = start;
1913
+ count_ret[0] = count;
1914
+ }
1915
+
1916
+ //
1917
+ // Interface functions
1918
+ //
1919
+ public static Model svm_train(Problem prob, Parameter param)
1920
+ {
1921
+ Model model = new Model();
1922
+ model.param = param;
1923
+
1924
+ if(param.svm_type == Parameter.ONE_CLASS ||
1925
+ param.svm_type == Parameter.EPSILON_SVR ||
1926
+ param.svm_type == Parameter.NU_SVR)
1927
+ {
1928
+ // regression or one-class-svm
1929
+ model.nr_class = 2;
1930
+ model.label = null;
1931
+ model.nSV = null;
1932
+ model.probA = null; model.probB = null;
1933
+ model.sv_coef = new double[1][];
1934
+
1935
+ if(param.probability == 1 &&
1936
+ (param.svm_type == Parameter.EPSILON_SVR ||
1937
+ param.svm_type == Parameter.NU_SVR))
1938
+ {
1939
+ model.probA = new double[1];
1940
+ model.probA[0] = svm_svr_probability(prob,param);
1941
+ }
1942
+
1943
+ decision_function f = svm_train_one(prob,param,0,0);
1944
+ model.rho = new double[1];
1945
+ model.rho[0] = f.rho;
1946
+ model.w_2 = new double[] { f.w_2 }; // PCL, from Gabor Melis
1947
+
1948
+ int nSV = 0;
1949
+ int i;
1950
+ for(i=0;i<prob.l;i++)
1951
+ if(Math.abs(f.alpha[i]) > 0) ++nSV;
1952
+ model.l = nSV;
1953
+ model.SV = new Node[nSV][];
1954
+ model.sv_coef[0] = new double[nSV];
1955
+ int j = 0;
1956
+ for(i=0;i<prob.l;i++)
1957
+ if(Math.abs(f.alpha[i]) > 0)
1958
+ {
1959
+ model.SV[j] = prob.x[i];
1960
+ model.sv_coef[0][j] = f.alpha[i];
1961
+ ++j;
1962
+ }
1963
+ }
1964
+ else
1965
+ {
1966
+ // classification
1967
+ int l = prob.l;
1968
+ int[] tmp_nr_class = new int[1];
1969
+ int[][] tmp_label = new int[1][];
1970
+ int[][] tmp_start = new int[1][];
1971
+ int[][] tmp_count = new int[1][];
1972
+ int[] perm = new int[l];
1973
+
1974
+ // group training data of the same class
1975
+ svm_group_classes(prob,tmp_nr_class,tmp_label,tmp_start,tmp_count,perm);
1976
+ int nr_class = tmp_nr_class[0];
1977
+ int[] label = tmp_label[0];
1978
+ int[] start = tmp_start[0];
1979
+ int[] count = tmp_count[0];
1980
+
1981
+ if(nr_class == 1)
1982
+ Svm.info("WARNING: training data in only one class. See README for details.\n");
1983
+
1984
+ Node[][] x = new Node[l][];
1985
+ int i;
1986
+ for(i=0;i<l;i++)
1987
+ x[i] = prob.x[perm[i]];
1988
+
1989
+ // calculate weighted C
1990
+
1991
+ double[] weighted_C = new double[nr_class];
1992
+ for(i=0;i<nr_class;i++)
1993
+ weighted_C[i] = param.C;
1994
+ for(i=0;i<param.nr_weight;i++)
1995
+ {
1996
+ int j;
1997
+ for(j=0;j<nr_class;j++)
1998
+ if(param.weight_label[i] == label[j])
1999
+ break;
2000
+ if(j == nr_class)
2001
+ System.err.print("WARNING: class label "+param.weight_label[i]+" specified in weight is not found\n");
2002
+ else
2003
+ weighted_C[j] *= param.weight[i];
2004
+ }
2005
+
2006
+ // train k*(k-1)/2 models
2007
+
2008
+ boolean[] nonzero = new boolean[l];
2009
+ for(i=0;i<l;i++)
2010
+ nonzero[i] = false;
2011
+ decision_function[] f = new decision_function[nr_class*(nr_class-1)/2];
2012
+
2013
+ double[] probA=null,probB=null;
2014
+ if (param.probability == 1)
2015
+ {
2016
+ probA=new double[nr_class*(nr_class-1)/2];
2017
+ probB=new double[nr_class*(nr_class-1)/2];
2018
+ }
2019
+
2020
+ int p = 0;
2021
+ for(i=0;i<nr_class;i++)
2022
+ for(int j=i+1;j<nr_class;j++)
2023
+ {
2024
+ Problem sub_prob = new Problem();
2025
+ int si = start[i], sj = start[j];
2026
+ int ci = count[i], cj = count[j];
2027
+ sub_prob.l = ci+cj;
2028
+ sub_prob.x = new Node[sub_prob.l][];
2029
+ sub_prob.y = new double[sub_prob.l];
2030
+ int k;
2031
+ for(k=0;k<ci;k++)
2032
+ {
2033
+ sub_prob.x[k] = x[si+k];
2034
+ sub_prob.y[k] = +1;
2035
+ }
2036
+ for(k=0;k<cj;k++)
2037
+ {
2038
+ sub_prob.x[ci+k] = x[sj+k];
2039
+ sub_prob.y[ci+k] = -1;
2040
+ }
2041
+
2042
+ if(param.probability == 1)
2043
+ {
2044
+ double[] probAB=new double[2];
2045
+ svm_binary_svc_probability(sub_prob,param,weighted_C[i],weighted_C[j],probAB);
2046
+ probA[p]=probAB[0];
2047
+ probB[p]=probAB[1];
2048
+ }
2049
+
2050
+ f[p] = svm_train_one(sub_prob,param,weighted_C[i],weighted_C[j]);
2051
+ for(k=0;k<ci;k++)
2052
+ if(!nonzero[si+k] && Math.abs(f[p].alpha[k]) > 0)
2053
+ nonzero[si+k] = true;
2054
+ for(k=0;k<cj;k++)
2055
+ if(!nonzero[sj+k] && Math.abs(f[p].alpha[ci+k]) > 0)
2056
+ nonzero[sj+k] = true;
2057
+ ++p;
2058
+ }
2059
+
2060
+ // build output
2061
+
2062
+ model.nr_class = nr_class;
2063
+
2064
+ model.label = new int[nr_class];
2065
+ for(i=0;i<nr_class;i++)
2066
+ model.label[i] = label[i];
2067
+
2068
+ model.rho = new double[nr_class*(nr_class-1)/2];
2069
+ model.w_2 = new double[nr_class*(nr_class-1)/2]; // PCL
2070
+ for(i=0;i<nr_class*(nr_class-1)/2;i++) {
2071
+ model.rho[i] = f[i].rho;
2072
+ model.w_2[i] = f[i].w_2; // PCL
2073
+ }
2074
+
2075
+ if(param.probability == 1)
2076
+ {
2077
+ model.probA = new double[nr_class*(nr_class-1)/2];
2078
+ model.probB = new double[nr_class*(nr_class-1)/2];
2079
+ for(i=0;i<nr_class*(nr_class-1)/2;i++)
2080
+ {
2081
+ model.probA[i] = probA[i];
2082
+ model.probB[i] = probB[i];
2083
+ }
2084
+ }
2085
+ else
2086
+ {
2087
+ model.probA=null;
2088
+ model.probB=null;
2089
+ }
2090
+
2091
+ int nnz = 0;
2092
+ int[] nz_count = new int[nr_class];
2093
+ model.nSV = new int[nr_class];
2094
+ for(i=0;i<nr_class;i++)
2095
+ {
2096
+ int nSV = 0;
2097
+ for(int j=0;j<count[i];j++)
2098
+ if(nonzero[start[i]+j])
2099
+ {
2100
+ ++nSV;
2101
+ ++nnz;
2102
+ }
2103
+ model.nSV[i] = nSV;
2104
+ nz_count[i] = nSV;
2105
+ }
2106
+
2107
+ Svm.info("Total nSV = "+nnz+"\n");
2108
+
2109
+ model.l = nnz;
2110
+ model.SV = new Node[nnz][];
2111
+ model.sv_indices = new int[nnz];
2112
+ p = 0;
2113
+ for(i=0;i<l;i++)
2114
+ if(nonzero[i]) {
2115
+ model.SV[p] = x[i];
2116
+ model.sv_indices[p] = perm[i]; // PCL, to retrieve support-vectors
2117
+ p += 1;
2118
+ }
2119
+
2120
+ int[] nz_start = new int[nr_class];
2121
+ nz_start[0] = 0;
2122
+ for(i=1;i<nr_class;i++)
2123
+ nz_start[i] = nz_start[i-1]+nz_count[i-1];
2124
+
2125
+ model.sv_coef = new double[nr_class-1][];
2126
+ for(i=0;i<nr_class-1;i++)
2127
+ model.sv_coef[i] = new double[nnz];
2128
+
2129
+ p = 0;
2130
+ for(i=0;i<nr_class;i++)
2131
+ for(int j=i+1;j<nr_class;j++)
2132
+ {
2133
+ // classifier (i,j): coefficients with
2134
+ // i are in sv_coef[j-1][nz_start[i]...],
2135
+ // j are in sv_coef[i][nz_start[j]...]
2136
+
2137
+ int si = start[i];
2138
+ int sj = start[j];
2139
+ int ci = count[i];
2140
+ int cj = count[j];
2141
+
2142
+ int q = nz_start[i];
2143
+ int k;
2144
+ for(k=0;k<ci;k++)
2145
+ if(nonzero[si+k])
2146
+ model.sv_coef[j-1][q++] = f[p].alpha[k];
2147
+ q = nz_start[j];
2148
+ for(k=0;k<cj;k++)
2149
+ if(nonzero[sj+k])
2150
+ model.sv_coef[i][q++] = f[p].alpha[ci+k];
2151
+ ++p;
2152
+ }
2153
+ }
2154
+ return model;
2155
+ }
2156
+
2157
+ // Stratified cross validation
2158
+ public static void svm_cross_validation(Problem prob, Parameter param, int nr_fold, double[] target)
2159
+ {
2160
+ int i;
2161
+ int[] fold_start = new int[nr_fold+1];
2162
+ int l = prob.l;
2163
+ int[] perm = new int[l];
2164
+
2165
+ // stratified cv may not give leave-one-out rate
2166
+ // Each class to l folds -> some folds may have zero elements
2167
+ if((param.svm_type == Parameter.C_SVC ||
2168
+ param.svm_type == Parameter.NU_SVC) && nr_fold < l)
2169
+ {
2170
+ int[] tmp_nr_class = new int[1];
2171
+ int[][] tmp_label = new int[1][];
2172
+ int[][] tmp_start = new int[1][];
2173
+ int[][] tmp_count = new int[1][];
2174
+
2175
+ svm_group_classes(prob,tmp_nr_class,tmp_label,tmp_start,tmp_count,perm);
2176
+
2177
+ int nr_class = tmp_nr_class[0];
2178
+ int[] start = tmp_start[0];
2179
+ int[] count = tmp_count[0];
2180
+
2181
+ // random shuffle and then data grouped by fold using the array perm
2182
+ int[] fold_count = new int[nr_fold];
2183
+ int c;
2184
+ int[] index = new int[l];
2185
+ for(i=0;i<l;i++)
2186
+ index[i]=perm[i];
2187
+ for (c=0; c<nr_class; c++)
2188
+ for(i=0;i<count[c];i++)
2189
+ {
2190
+ int j = i+rand.nextInt(count[c]-i);
2191
+ do {int _=index[start[c]+j]; index[start[c]+j]=index[start[c]+i]; index[start[c]+i]=_;} while(false);
2192
+ }
2193
+ for(i=0;i<nr_fold;i++)
2194
+ {
2195
+ fold_count[i] = 0;
2196
+ for (c=0; c<nr_class;c++)
2197
+ fold_count[i]+=(i+1)*count[c]/nr_fold-i*count[c]/nr_fold;
2198
+ }
2199
+ fold_start[0]=0;
2200
+ for (i=1;i<=nr_fold;i++)
2201
+ fold_start[i] = fold_start[i-1]+fold_count[i-1];
2202
+ for (c=0; c<nr_class;c++)
2203
+ for(i=0;i<nr_fold;i++)
2204
+ {
2205
+ int begin = start[c]+i*count[c]/nr_fold;
2206
+ int end = start[c]+(i+1)*count[c]/nr_fold;
2207
+ for(int j=begin;j<end;j++)
2208
+ {
2209
+ perm[fold_start[i]] = index[j];
2210
+ fold_start[i]++;
2211
+ }
2212
+ }
2213
+ fold_start[0]=0;
2214
+ for (i=1;i<=nr_fold;i++)
2215
+ fold_start[i] = fold_start[i-1]+fold_count[i-1];
2216
+ }
2217
+ else
2218
+ {
2219
+ for(i=0;i<l;i++) perm[i]=i;
2220
+ for(i=0;i<l;i++)
2221
+ {
2222
+ int j = i+rand.nextInt(l-i);
2223
+ do {int _=perm[i]; perm[i]=perm[j]; perm[j]=_;} while(false);
2224
+ }
2225
+ for(i=0;i<=nr_fold;i++)
2226
+ fold_start[i]=i*l/nr_fold;
2227
+ }
2228
+
2229
+ for(i=0;i<nr_fold;i++)
2230
+ {
2231
+ int begin = fold_start[i];
2232
+ int end = fold_start[i+1];
2233
+ int j,k;
2234
+ Problem subprob = new Problem();
2235
+
2236
+ subprob.l = l-(end-begin);
2237
+ subprob.x = new Node[subprob.l][];
2238
+ subprob.y = new double[subprob.l];
2239
+
2240
+ k=0;
2241
+ for(j=0;j<begin;j++)
2242
+ {
2243
+ subprob.x[k] = prob.x[perm[j]];
2244
+ subprob.y[k] = prob.y[perm[j]];
2245
+ ++k;
2246
+ }
2247
+ for(j=end;j<l;j++)
2248
+ {
2249
+ subprob.x[k] = prob.x[perm[j]];
2250
+ subprob.y[k] = prob.y[perm[j]];
2251
+ ++k;
2252
+ }
2253
+ Model submodel = svm_train(subprob,param);
2254
+ if(param.probability==1 &&
2255
+ (param.svm_type == Parameter.C_SVC ||
2256
+ param.svm_type == Parameter.NU_SVC))
2257
+ {
2258
+ double[] prob_estimates= new double[svm_get_nr_class(submodel)];
2259
+ for(j=begin;j<end;j++)
2260
+ target[perm[j]] = svm_predict_probability(submodel,prob.x[perm[j]],prob_estimates);
2261
+ }
2262
+ else
2263
+ for(j=begin;j<end;j++)
2264
+ target[perm[j]] = svm_predict(submodel,prob.x[perm[j]]);
2265
+ }
2266
+ }
2267
+
2268
+ public static int svm_get_svm_type(Model model)
2269
+ {
2270
+ return model.param.svm_type;
2271
+ }
2272
+
2273
+ public static int svm_get_nr_class(Model model)
2274
+ {
2275
+ return model.nr_class;
2276
+ }
2277
+
2278
+ public static void svm_get_labels(Model model, int[] label)
2279
+ {
2280
+ if (model.label != null)
2281
+ for(int i=0;i<model.nr_class;i++)
2282
+ label[i] = model.label[i];
2283
+ }
2284
+
2285
+ public static double svm_get_svr_probability(Model model)
2286
+ {
2287
+ if ((model.param.svm_type == Parameter.EPSILON_SVR || model.param.svm_type == Parameter.NU_SVR) &&
2288
+ model.probA!=null)
2289
+ return model.probA[0];
2290
+ else
2291
+ {
2292
+ System.err.print("Model doesn't contain information for SVR probability inference\n");
2293
+ return 0;
2294
+ }
2295
+ }
2296
+
2297
+ public static double svm_predict_values(Model model, Node[] x, double[] dec_values)
2298
+ {
2299
+ int i;
2300
+ if(model.param.svm_type == Parameter.ONE_CLASS ||
2301
+ model.param.svm_type == Parameter.EPSILON_SVR ||
2302
+ model.param.svm_type == Parameter.NU_SVR)
2303
+ {
2304
+ double[] sv_coef = model.sv_coef[0];
2305
+ double sum = 0;
2306
+ for(i=0;i<model.l;i++)
2307
+ sum += sv_coef[i] * Kernel.k_function(x,model.SV[i],model.param);
2308
+ sum -= model.rho[0];
2309
+ dec_values[0] = sum;
2310
+
2311
+ if(model.param.svm_type == Parameter.ONE_CLASS)
2312
+ return (sum>0)?1:-1;
2313
+ else
2314
+ return sum;
2315
+ }
2316
+ else
2317
+ {
2318
+ int nr_class = model.nr_class;
2319
+ int l = model.l;
2320
+
2321
+ double[] kvalue = new double[l];
2322
+ for(i=0;i<l;i++)
2323
+ kvalue[i] = Kernel.k_function(x,model.SV[i],model.param);
2324
+
2325
+ int[] start = new int[nr_class];
2326
+ start[0] = 0;
2327
+ for(i=1;i<nr_class;i++)
2328
+ start[i] = start[i-1]+model.nSV[i-1];
2329
+
2330
+ int[] vote = new int[nr_class];
2331
+ for(i=0;i<nr_class;i++)
2332
+ vote[i] = 0;
2333
+
2334
+ int p=0;
2335
+ for(i=0;i<nr_class;i++)
2336
+ for(int j=i+1;j<nr_class;j++)
2337
+ {
2338
+ double sum = 0;
2339
+ int si = start[i];
2340
+ int sj = start[j];
2341
+ int ci = model.nSV[i];
2342
+ int cj = model.nSV[j];
2343
+
2344
+ int k;
2345
+ double[] coef1 = model.sv_coef[j-1];
2346
+ double[] coef2 = model.sv_coef[i];
2347
+ for(k=0;k<ci;k++)
2348
+ sum += coef1[si+k] * kvalue[si+k];
2349
+ for(k=0;k<cj;k++)
2350
+ sum += coef2[sj+k] * kvalue[sj+k];
2351
+ sum -= model.rho[p];
2352
+ dec_values[p] = sum;
2353
+
2354
+ if(dec_values[p] > 0)
2355
+ ++vote[i];
2356
+ else
2357
+ ++vote[j];
2358
+ p++;
2359
+ }
2360
+
2361
+ int vote_max_idx = 0;
2362
+ for(i=1;i<nr_class;i++)
2363
+ if(vote[i] > vote[vote_max_idx])
2364
+ vote_max_idx = i;
2365
+
2366
+ return model.label[vote_max_idx];
2367
+ }
2368
+ }
2369
+
2370
+ public static double svm_predict(Model model, Node[] x)
2371
+ {
2372
+ int nr_class = model.nr_class;
2373
+ double[] dec_values;
2374
+ if(model.param.svm_type == Parameter.ONE_CLASS ||
2375
+ model.param.svm_type == Parameter.EPSILON_SVR ||
2376
+ model.param.svm_type == Parameter.NU_SVR)
2377
+ dec_values = new double[1];
2378
+ else
2379
+ dec_values = new double[nr_class*(nr_class-1)/2];
2380
+ double pred_result = svm_predict_values(model, x, dec_values);
2381
+ return pred_result;
2382
+ }
2383
+
2384
+ public static double svm_predict_probability(Model model, Node[] x, double[] prob_estimates)
2385
+ {
2386
+ if ((model.param.svm_type == Parameter.C_SVC || model.param.svm_type == Parameter.NU_SVC) &&
2387
+ model.probA!=null && model.probB!=null)
2388
+ {
2389
+ int i;
2390
+ int nr_class = model.nr_class;
2391
+ double[] dec_values = new double[nr_class*(nr_class-1)/2];
2392
+ svm_predict_values(model, x, dec_values);
2393
+
2394
+ double min_prob=1e-7;
2395
+ double[][] pairwise_prob=new double[nr_class][nr_class];
2396
+
2397
+ int k=0;
2398
+ for(i=0;i<nr_class;i++)
2399
+ for(int j=i+1;j<nr_class;j++)
2400
+ {
2401
+ pairwise_prob[i][j]=Math.min(Math.max(sigmoid_predict(dec_values[k],model.probA[k],model.probB[k]),min_prob),1-min_prob);
2402
+ pairwise_prob[j][i]=1-pairwise_prob[i][j];
2403
+ k++;
2404
+ }
2405
+ multiclass_probability(nr_class,pairwise_prob,prob_estimates);
2406
+
2407
+ int prob_max_idx = 0;
2408
+ for(i=1;i<nr_class;i++)
2409
+ if(prob_estimates[i] > prob_estimates[prob_max_idx])
2410
+ prob_max_idx = i;
2411
+ return model.label[prob_max_idx];
2412
+ }
2413
+ else
2414
+ return svm_predict(model, x);
2415
+ }
2416
+
2417
+ static final String svm_type_table[] =
2418
+ {
2419
+ "c_svc","nu_svc","one_class","epsilon_svr","nu_svr",
2420
+ };
2421
+
2422
+ static final String kernel_type_table[]=
2423
+ {
2424
+ "linear","polynomial","rbf","sigmoid","precomputed"
2425
+ };
2426
+
2427
+ public static void svm_save_model(String model_file_name, Model model) throws IOException
2428
+ {
2429
+ DataOutputStream fp = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(model_file_name)));
2430
+ svm_save_model(fp, model);
2431
+ }
2432
+
2433
+ public static void svm_save_model(DataOutputStream fp, Model model) throws IOException
2434
+ {
2435
+ Parameter param = model.param;
2436
+
2437
+ fp.writeBytes("svm_type "+svm_type_table[param.svm_type]+"\n");
2438
+ fp.writeBytes("kernel_type "+kernel_type_table[param.kernel_type]+"\n");
2439
+
2440
+ if(param.kernel_type == Parameter.POLY)
2441
+ fp.writeBytes("degree "+param.degree+"\n");
2442
+
2443
+ if(param.kernel_type == Parameter.POLY ||
2444
+ param.kernel_type == Parameter.RBF ||
2445
+ param.kernel_type == Parameter.SIGMOID)
2446
+ fp.writeBytes("gamma "+param.gamma+"\n");
2447
+
2448
+ if(param.kernel_type == Parameter.POLY ||
2449
+ param.kernel_type == Parameter.SIGMOID)
2450
+ fp.writeBytes("coef0 "+param.coef0+"\n");
2451
+
2452
+ int nr_class = model.nr_class;
2453
+ int l = model.l;
2454
+ fp.writeBytes("nr_class "+nr_class+"\n");
2455
+ fp.writeBytes("total_sv "+l+"\n");
2456
+
2457
+ {
2458
+ fp.writeBytes("rho");
2459
+ for(int i=0;i<nr_class*(nr_class-1)/2;i++)
2460
+ fp.writeBytes(" "+model.rho[i]);
2461
+ fp.writeBytes("\n");
2462
+ }
2463
+
2464
+ { // PCL, from Gabor Melis
2465
+ fp.writeBytes("w_2");
2466
+ for(int i=0;i<nr_class*(nr_class-1)/2;i++)
2467
+ fp.writeBytes(" "+model.w_2[i]);
2468
+ fp.writeBytes("\n");
2469
+ }
2470
+
2471
+ if(model.label != null)
2472
+ {
2473
+ fp.writeBytes("label");
2474
+ for(int i=0;i<nr_class;i++)
2475
+ fp.writeBytes(" "+model.label[i]);
2476
+ fp.writeBytes("\n");
2477
+ }
2478
+
2479
+ if(model.probA != null) // regression has probA only
2480
+ {
2481
+ fp.writeBytes("probA");
2482
+ for(int i=0;i<nr_class*(nr_class-1)/2;i++)
2483
+ fp.writeBytes(" "+model.probA[i]);
2484
+ fp.writeBytes("\n");
2485
+ }
2486
+ if(model.probB != null)
2487
+ {
2488
+ fp.writeBytes("probB");
2489
+ for(int i=0;i<nr_class*(nr_class-1)/2;i++)
2490
+ fp.writeBytes(" "+model.probB[i]);
2491
+ fp.writeBytes("\n");
2492
+ }
2493
+
2494
+ if(model.nSV != null)
2495
+ {
2496
+ fp.writeBytes("nr_sv");
2497
+ for(int i=0;i<nr_class;i++)
2498
+ fp.writeBytes(" "+model.nSV[i]);
2499
+ fp.writeBytes("\n");
2500
+ }
2501
+
2502
+ fp.writeBytes("SV\n");
2503
+ double[][] sv_coef = model.sv_coef;
2504
+ Node[][] SV = model.SV;
2505
+
2506
+ for(int i=0;i<l;i++)
2507
+ {
2508
+ for(int j=0;j<nr_class-1;j++)
2509
+ fp.writeBytes(sv_coef[j][i]+" ");
2510
+
2511
+ Node[] p = SV[i];
2512
+ if(param.kernel_type == Parameter.PRECOMPUTED)
2513
+ fp.writeBytes("0:"+(int)(p[0].value));
2514
+ else
2515
+ for(int j=0;j<p.length;j++)
2516
+ fp.writeBytes(p[j].index+":"+p[j].value+" ");
2517
+ fp.writeBytes("\n");
2518
+ }
2519
+
2520
+ fp.close();
2521
+ }
2522
+
2523
+ private static double atof(String s)
2524
+ {
2525
+ return Double.valueOf(s).doubleValue();
2526
+ }
2527
+
2528
+ private static int atoi(String s)
2529
+ {
2530
+ return Integer.parseInt(s);
2531
+ }
2532
+
2533
+ public static Model svm_load_model(String model_file_name) throws IOException
2534
+ {
2535
+ return svm_load_model(new BufferedReader(new FileReader(model_file_name)));
2536
+ }
2537
+
2538
+ public static Model svm_load_model(BufferedReader fp) throws IOException
2539
+ {
2540
+ // read parameters
2541
+
2542
+ Model model = new Model();
2543
+ Parameter param = new Parameter();
2544
+ model.param = param;
2545
+ model.rho = null;
2546
+ model.w_2 = null;
2547
+ model.probA = null;
2548
+ model.probB = null;
2549
+ model.label = null;
2550
+ model.nSV = null;
2551
+
2552
+ while(true)
2553
+ {
2554
+ String cmd = fp.readLine();
2555
+ String arg = cmd.substring(cmd.indexOf(' ')+1);
2556
+
2557
+ if(cmd.startsWith("svm_type"))
2558
+ {
2559
+ int i;
2560
+ for(i=0;i<svm_type_table.length;i++)
2561
+ {
2562
+ if(arg.indexOf(svm_type_table[i])!=-1)
2563
+ {
2564
+ param.svm_type=i;
2565
+ break;
2566
+ }
2567
+ }
2568
+ if(i == svm_type_table.length)
2569
+ {
2570
+ System.err.print("unknown svm type.\n");
2571
+ return null;
2572
+ }
2573
+ }
2574
+ else if(cmd.startsWith("kernel_type"))
2575
+ {
2576
+ int i;
2577
+ for(i=0;i<kernel_type_table.length;i++)
2578
+ {
2579
+ if(arg.indexOf(kernel_type_table[i])!=-1)
2580
+ {
2581
+ param.kernel_type=i;
2582
+ break;
2583
+ }
2584
+ }
2585
+ if(i == kernel_type_table.length)
2586
+ {
2587
+ System.err.print("unknown kernel function.\n");
2588
+ return null;
2589
+ }
2590
+ }
2591
+ else if(cmd.startsWith("degree"))
2592
+ param.degree = atoi(arg);
2593
+ else if(cmd.startsWith("gamma"))
2594
+ param.gamma = atof(arg);
2595
+ else if(cmd.startsWith("coef0"))
2596
+ param.coef0 = atof(arg);
2597
+ else if(cmd.startsWith("nr_class"))
2598
+ model.nr_class = atoi(arg);
2599
+ else if(cmd.startsWith("total_sv"))
2600
+ model.l = atoi(arg);
2601
+ else if(cmd.startsWith("rho"))
2602
+ {
2603
+ int n = model.nr_class * (model.nr_class-1)/2;
2604
+ model.rho = new double[n];
2605
+ StringTokenizer st = new StringTokenizer(arg);
2606
+ for(int i=0;i<n;i++)
2607
+ model.rho[i] = atof(st.nextToken());
2608
+ }
2609
+ else if(cmd.startsWith("w_2")) // PCL, from Gabor Melis
2610
+ {
2611
+ int n = model.nr_class * (model.nr_class-1)/2;
2612
+ model.w_2 = new double[n];
2613
+ StringTokenizer st = new StringTokenizer(arg);
2614
+ for(int i=0;i<n;i++)
2615
+ model.w_2[i] = atof(st.nextToken());
2616
+ }
2617
+ else if(cmd.startsWith("label"))
2618
+ {
2619
+ int n = model.nr_class;
2620
+ model.label = new int[n];
2621
+ StringTokenizer st = new StringTokenizer(arg);
2622
+ for(int i=0;i<n;i++)
2623
+ model.label[i] = atoi(st.nextToken());
2624
+ }
2625
+ else if(cmd.startsWith("probA"))
2626
+ {
2627
+ int n = model.nr_class*(model.nr_class-1)/2;
2628
+ model.probA = new double[n];
2629
+ StringTokenizer st = new StringTokenizer(arg);
2630
+ for(int i=0;i<n;i++)
2631
+ model.probA[i] = atof(st.nextToken());
2632
+ }
2633
+ else if(cmd.startsWith("probB"))
2634
+ {
2635
+ int n = model.nr_class*(model.nr_class-1)/2;
2636
+ model.probB = new double[n];
2637
+ StringTokenizer st = new StringTokenizer(arg);
2638
+ for(int i=0;i<n;i++)
2639
+ model.probB[i] = atof(st.nextToken());
2640
+ }
2641
+ else if(cmd.startsWith("nr_sv"))
2642
+ {
2643
+ int n = model.nr_class;
2644
+ model.nSV = new int[n];
2645
+ StringTokenizer st = new StringTokenizer(arg);
2646
+ for(int i=0;i<n;i++)
2647
+ model.nSV[i] = atoi(st.nextToken());
2648
+ }
2649
+ else if(cmd.startsWith("SV"))
2650
+ {
2651
+ break;
2652
+ }
2653
+ else
2654
+ {
2655
+ System.err.print("unknown text in model file: ["+cmd+"]\n");
2656
+ return null;
2657
+ }
2658
+ }
2659
+
2660
+ // read sv_coef and SV
2661
+
2662
+ int m = model.nr_class - 1;
2663
+ int l = model.l;
2664
+ model.sv_coef = new double[m][l];
2665
+ model.SV = new Node[l][];
2666
+
2667
+ for(int i=0;i<l;i++)
2668
+ {
2669
+ String line = fp.readLine();
2670
+ StringTokenizer st = new StringTokenizer(line," \t\n\r\f:");
2671
+
2672
+ for(int k=0;k<m;k++)
2673
+ model.sv_coef[k][i] = atof(st.nextToken());
2674
+ int n = st.countTokens()/2;
2675
+ model.SV[i] = new Node[n];
2676
+ for(int j=0;j<n;j++)
2677
+ {
2678
+ model.SV[i][j] = new Node();
2679
+ model.SV[i][j].index = atoi(st.nextToken());
2680
+ model.SV[i][j].value = atof(st.nextToken());
2681
+ }
2682
+ }
2683
+
2684
+ fp.close();
2685
+ return model;
2686
+ }
2687
+
2688
+ public static String svm_check_parameter(Problem prob, Parameter param)
2689
+ {
2690
+ // svm_type
2691
+
2692
+ int svm_type = param.svm_type;
2693
+ if(svm_type != Parameter.C_SVC &&
2694
+ svm_type != Parameter.NU_SVC &&
2695
+ svm_type != Parameter.ONE_CLASS &&
2696
+ svm_type != Parameter.EPSILON_SVR &&
2697
+ svm_type != Parameter.NU_SVR)
2698
+ return "unknown svm type";
2699
+
2700
+ // kernel_type, degree
2701
+
2702
+ int kernel_type = param.kernel_type;
2703
+ if(kernel_type != Parameter.LINEAR &&
2704
+ kernel_type != Parameter.POLY &&
2705
+ kernel_type != Parameter.RBF &&
2706
+ kernel_type != Parameter.SIGMOID &&
2707
+ kernel_type != Parameter.PRECOMPUTED)
2708
+ return "unknown kernel type";
2709
+
2710
+ if(param.gamma < 0)
2711
+ return "gamma < 0";
2712
+
2713
+ if(param.degree < 0)
2714
+ return "degree of polynomial kernel < 0";
2715
+
2716
+ // cache_size,eps,C,nu,p,shrinking
2717
+
2718
+ if(param.cache_size <= 0)
2719
+ return "cache_size <= 0";
2720
+
2721
+ if(param.eps <= 0)
2722
+ return "eps <= 0";
2723
+
2724
+ if(svm_type == Parameter.C_SVC ||
2725
+ svm_type == Parameter.EPSILON_SVR ||
2726
+ svm_type == Parameter.NU_SVR)
2727
+ if(param.C <= 0)
2728
+ return "C <= 0";
2729
+
2730
+ if(svm_type == Parameter.NU_SVC ||
2731
+ svm_type == Parameter.ONE_CLASS ||
2732
+ svm_type == Parameter.NU_SVR)
2733
+ if(param.nu <= 0 || param.nu > 1)
2734
+ return "nu <= 0 or nu > 1";
2735
+
2736
+ if(svm_type == Parameter.EPSILON_SVR)
2737
+ if(param.p < 0)
2738
+ return "p < 0";
2739
+
2740
+ if(param.shrinking != 0 &&
2741
+ param.shrinking != 1)
2742
+ return "shrinking != 0 and shrinking != 1";
2743
+
2744
+ if(param.probability != 0 &&
2745
+ param.probability != 1)
2746
+ return "probability != 0 and probability != 1";
2747
+
2748
+ if(param.probability == 1 &&
2749
+ svm_type == Parameter.ONE_CLASS)
2750
+ return "one-class SVM probability output not supported yet";
2751
+
2752
+ // check whether nu-svc is feasible
2753
+
2754
+ if(svm_type == Parameter.NU_SVC)
2755
+ {
2756
+ int l = prob.l;
2757
+ int max_nr_class = 16;
2758
+ int nr_class = 0;
2759
+ int[] label = new int[max_nr_class];
2760
+ int[] count = new int[max_nr_class];
2761
+
2762
+ int i;
2763
+ for(i=0;i<l;i++)
2764
+ {
2765
+ int this_label = (int)prob.y[i];
2766
+ int j;
2767
+ for(j=0;j<nr_class;j++)
2768
+ if(this_label == label[j])
2769
+ {
2770
+ ++count[j];
2771
+ break;
2772
+ }
2773
+
2774
+ if(j == nr_class)
2775
+ {
2776
+ if(nr_class == max_nr_class)
2777
+ {
2778
+ max_nr_class *= 2;
2779
+ int[] new_data = new int[max_nr_class];
2780
+ System.arraycopy(label,0,new_data,0,label.length);
2781
+ label = new_data;
2782
+
2783
+ new_data = new int[max_nr_class];
2784
+ System.arraycopy(count,0,new_data,0,count.length);
2785
+ count = new_data;
2786
+ }
2787
+ label[nr_class] = this_label;
2788
+ count[nr_class] = 1;
2789
+ ++nr_class;
2790
+ }
2791
+ }
2792
+
2793
+ for(i=0;i<nr_class;i++)
2794
+ {
2795
+ int n1 = count[i];
2796
+ for(int j=i+1;j<nr_class;j++)
2797
+ {
2798
+ int n2 = count[j];
2799
+ if(param.nu*(n1+n2)/2 > Math.min(n1,n2))
2800
+ return "specified nu is infeasible";
2801
+ }
2802
+ }
2803
+ }
2804
+
2805
+ return null;
2806
+ }
2807
+
2808
+ public static int svm_check_probability_model(Model model)
2809
+ {
2810
+ if (((model.param.svm_type == Parameter.C_SVC || model.param.svm_type == Parameter.NU_SVC) &&
2811
+ model.probA!=null && model.probB!=null) ||
2812
+ ((model.param.svm_type == Parameter.EPSILON_SVR || model.param.svm_type == Parameter.NU_SVR) &&
2813
+ model.probA!=null))
2814
+ return 1;
2815
+ else
2816
+ return 0;
2817
+ }
2818
+
2819
+ public static void svm_set_print_string_function(PrintInterface print_func)
2820
+ {
2821
+ if (print_func == null)
2822
+ svm_print_string = svm_print_stdout;
2823
+ else
2824
+ svm_print_string = print_func;
2825
+ }
2826
+ }