1 package de.bwaldvogel.liblinear;
2
3 import static de.bwaldvogel.liblinear.Linear.info;
4
5
6 class Tron {
7
8 private final Function fun_obj;
9
10 private final double eps;
11
12 private final int max_iter;
13
14 public Tron( final Function fun_obj ) {
15 this(fun_obj, 0.1);
16 }
17
18 public Tron( final Function fun_obj, double eps ) {
19 this(fun_obj, eps, 1000);
20 }
21
22 public Tron( final Function fun_obj, double eps, int max_iter ) {
23 this.fun_obj = fun_obj;
24 this.eps = eps;
25 this.max_iter = max_iter;
26 }
27
28 void tron(double[] w) {
29
30 double eta0 = 1e-4, eta1 = 0.25, eta2 = 0.75;
31
32
33 double sigma1 = 0.25, sigma2 = 0.5, sigma3 = 4;
34
35 int n = fun_obj.get_nr_variable();
36 int i, cg_iter;
37 double delta, snorm, one = 1.0;
38 double alpha, f, fnew, prered, actred, gs;
39 int search = 1, iter = 1;
40 double[] s = new double[n];
41 double[] r = new double[n];
42 double[] w_new = new double[n];
43 double[] g = new double[n];
44
45 for (i = 0; i < n; i++)
46 w[i] = 0;
47
48 f = fun_obj.fun(w);
49 fun_obj.grad(w, g);
50 delta = euclideanNorm(g);
51 double gnorm1 = delta;
52 double gnorm = gnorm1;
53
54 if (gnorm <= eps * gnorm1) search = 0;
55
56 iter = 1;
57
58 while (iter <= max_iter && search != 0) {
59 cg_iter = trcg(delta, g, s, r);
60
61 System.arraycopy(w, 0, w_new, 0, n);
62 daxpy(one, s, w_new);
63
64 gs = dot(g, s);
65 prered = -0.5 * (gs - dot(s, r));
66 fnew = fun_obj.fun(w_new);
67
68
69 actred = f - fnew;
70
71
72 snorm = euclideanNorm(s);
73 if (iter == 1) delta = Math.min(delta, snorm);
74
75
76 if (fnew - f - gs <= 0)
77 alpha = sigma3;
78 else
79 alpha = Math.max(sigma1, -0.5 * (gs / (fnew - f - gs)));
80
81
82
83 if (actred < eta0 * prered)
84 delta = Math.min(Math.max(alpha, sigma1) * snorm, sigma2 * delta);
85 else if (actred < eta1 * prered)
86 delta = Math.max(sigma1 * delta, Math.min(alpha * snorm, sigma2 * delta));
87 else if (actred < eta2 * prered)
88 delta = Math.max(sigma1 * delta, Math.min(alpha * snorm, sigma3 * delta));
89 else
90 delta = Math.max(delta, Math.min(alpha * snorm, sigma3 * delta));
91
92 info("iter %2d act %5.3e pre %5.3e delta %5.3e f %5.3e |g| %5.3e CG %3d%n", iter, actred, prered, delta, f, gnorm, cg_iter);
93
94 if (actred > eta0 * prered) {
95 iter++;
96 System.arraycopy(w_new, 0, w, 0, n);
97 f = fnew;
98 fun_obj.grad(w, g);
99
100 gnorm = euclideanNorm(g);
101 if (gnorm <= eps * gnorm1) break;
102 }
103 if (f < -1.0e+32) {
104 info("warning: f < -1.0e+32%n");
105 break;
106 }
107 if (Math.abs(actred) <= 0 && prered <= 0) {
108 info("warning: actred and prered <= 0%n");
109 break;
110 }
111 if (Math.abs(actred) <= 1.0e-12 * Math.abs(f) && Math.abs(prered) <= 1.0e-12 * Math.abs(f)) {
112 info("warning: actred and prered too small%n");
113 break;
114 }
115 }
116 }
117
118 private int trcg(double delta, double[] g, double[] s, double[] r) {
119 int n = fun_obj.get_nr_variable();
120 double one = 1;
121 double[] d = new double[n];
122 double[] Hd = new double[n];
123 double rTr, rnewTrnew, cgtol;
124
125 for (int i = 0; i < n; i++) {
126 s[i] = 0;
127 r[i] = -g[i];
128 d[i] = r[i];
129 }
130 cgtol = 0.1 * euclideanNorm(g);
131
132 int cg_iter = 0;
133 rTr = dot(r, r);
134
135 while (true) {
136 if (euclideanNorm(r) <= cgtol) break;
137 cg_iter++;
138 fun_obj.Hv(d, Hd);
139
140 double alpha = rTr / dot(d, Hd);
141 daxpy(alpha, d, s);
142 if (euclideanNorm(s) > delta) {
143 info("cg reaches trust region boundary%n");
144 alpha = -alpha;
145 daxpy(alpha, d, s);
146
147 double std = dot(s, d);
148 double sts = dot(s, s);
149 double dtd = dot(d, d);
150 double dsq = delta * delta;
151 double rad = Math.sqrt(std * std + dtd * (dsq - sts));
152 if (std >= 0)
153 alpha = (dsq - sts) / (std + rad);
154 else
155 alpha = (rad - std) / dtd;
156 daxpy(alpha, d, s);
157 alpha = -alpha;
158 daxpy(alpha, Hd, r);
159 break;
160 }
161 alpha = -alpha;
162 daxpy(alpha, Hd, r);
163 rnewTrnew = dot(r, r);
164 double beta = rnewTrnew / rTr;
165 scale(beta, d);
166 daxpy(one, r, d);
167 rTr = rnewTrnew;
168 }
169
170 return (cg_iter);
171 }
172
173
174
175
176
177
178
179
180
181
182 private static void daxpy(double constant, double vector1[], double vector2[]) {
183 if (constant == 0) return;
184
185 assert vector1.length == vector2.length;
186 for (int i = 0; i < vector1.length; i++) {
187 vector2[i] += constant * vector1[i];
188 }
189 }
190
191
192
193
194
195
196 private static double dot(double vector1[], double vector2[]) {
197
198 double product = 0;
199 assert vector1.length == vector2.length;
200 for (int i = 0; i < vector1.length; i++) {
201 product += vector1[i] * vector2[i];
202 }
203 return product;
204
205 }
206
207
208
209
210
211
212 private static double euclideanNorm(double vector[]) {
213
214 int n = vector.length;
215
216 if (n < 1) {
217 return 0;
218 }
219
220 if (n == 1) {
221 return Math.abs(vector[0]);
222 }
223
224
225
226 double scale = 0;
227 double sum = 1;
228 for (int i = 0; i < n; i++) {
229 if (vector[i] != 0) {
230 double abs = Math.abs(vector[i]);
231
232 if (scale < abs) {
233 double t = scale / abs;
234 sum = 1 + sum * (t * t);
235 scale = abs;
236 } else {
237 double t = abs / scale;
238 sum += t * t;
239 }
240 }
241 }
242
243 return scale * Math.sqrt(sum);
244 }
245
246
247
248
249
250
251 private static void scale(double constant, double vector[]) {
252 if (constant == 1.0) return;
253 for (int i = 0; i < vector.length; i++) {
254 vector[i] *= constant;
255 }
256
257 }
258 }