jrb-libsvm 0.1.2-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }