1 | /* $Id: ClpPdco.cpp 1665 2011-01-04 17:55:54Z lou $ */ |
2 | // Copyright (C) 2003, International Business Machines |
3 | // Corporation and others. All Rights Reserved. |
4 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
5 | |
6 | #ifdef COIN_DO_PDCO |
7 | |
8 | /* Pdco algorithm |
9 | |
10 | Method |
11 | |
12 | |
13 | */ |
14 | |
15 | |
16 | |
17 | #include "CoinPragma.hpp" |
18 | |
19 | #include <math.h> |
20 | |
21 | #include "CoinDenseVector.hpp" |
22 | #include "ClpPdco.hpp" |
23 | #include "ClpPdcoBase.hpp" |
24 | #include "CoinHelperFunctions.hpp" |
25 | #include "ClpHelperFunctions.hpp" |
26 | #include "ClpLsqr.hpp" |
27 | #include "CoinTime.hpp" |
28 | #include "ClpMessage.hpp" |
29 | #include <cfloat> |
30 | #include <cassert> |
31 | #include <string> |
32 | #include <stdio.h> |
33 | #include <iostream> |
34 | |
35 | int |
36 | ClpPdco::pdco() |
37 | { |
38 | printf("Dummy pdco solve\n" ); |
39 | return 0; |
40 | } |
41 | // ** Temporary version |
42 | int |
43 | ClpPdco::pdco( ClpPdcoBase * stuff, Options &options, Info &info, Outfo &outfo) |
44 | { |
45 | // D1, D2 are positive-definite diagonal matrices defined from d1, d2. |
46 | // In particular, d2 indicates the accuracy required for |
47 | // satisfying each row of Ax = b. |
48 | // |
49 | // D1 and D2 (via d1 and d2) provide primal and dual regularization |
50 | // respectively. They ensure that the primal and dual solutions |
51 | // (x,r) and (y,z) are unique and bounded. |
52 | // |
53 | // A scalar d1 is equivalent to d1 = ones(n,1), D1 = diag(d1). |
54 | // A scalar d2 is equivalent to d2 = ones(m,1), D2 = diag(d2). |
55 | // Typically, d1 = d2 = 1e-4. |
56 | // These values perturb phi(x) only slightly (by about 1e-8) and request |
57 | // that A*x = b be satisfied quite accurately (to about 1e-8). |
58 | // Set d1 = 1e-4, d2 = 1 for least-squares problems with bound constraints. |
59 | // The problem is then |
60 | // |
61 | // minimize phi(x) + 1/2 norm(d1*x)^2 + 1/2 norm(A*x - b)^2 |
62 | // subject to bl <= x <= bu. |
63 | // |
64 | // More generally, d1 and d2 may be n and m vectors containing any positive |
65 | // values (preferably not too small, and typically no larger than 1). |
66 | // Bigger elements of d1 and d2 improve the stability of the solver. |
67 | // |
68 | // At an optimal solution, if x(j) is on its lower or upper bound, |
69 | // the corresponding z(j) is positive or negative respectively. |
70 | // If x(j) is between its bounds, z(j) = 0. |
71 | // If bl(j) = bu(j), x(j) is fixed at that value and z(j) may have |
72 | // either sign. |
73 | // |
74 | // Also, r and y satisfy r = D2 y, so that Ax + D2^2 y = b. |
75 | // Thus if d2(i) = 1e-4, the i-th row of Ax = b will be satisfied to |
76 | // approximately 1e-8. This determines how large d2(i) can safely be. |
77 | // |
78 | // |
79 | // EXTERNAL FUNCTIONS: |
80 | // options = pdcoSet; provided with pdco.m |
81 | // [obj,grad,hess] = pdObj( x ); provided by user |
82 | // y = pdMat( name,mode,m,n,x ); provided by user if pdMat |
83 | // is a string, not a matrix |
84 | // |
85 | // INPUT ARGUMENTS: |
86 | // pdObj is a string containing the name of a function pdObj.m |
87 | // or a function_handle for such a function |
88 | // such that [obj,grad,hess] = pdObj(x) defines |
89 | // obj = phi(x) : a scalar, |
90 | // grad = gradient of phi(x) : an n-vector, |
91 | // hess = diag(Hessian of phi): an n-vector. |
92 | // Examples: |
93 | // If phi(x) is the linear function c"x, pdObj should return |
94 | // [obj,grad,hess] = [c"*x, c, zeros(n,1)]. |
95 | // If phi(x) is the entropy function E(x) = sum x(j) log x(j), |
96 | // [obj,grad,hess] = [E(x), log(x)+1, 1./x]. |
97 | // pdMat may be an ifexplicit m x n matrix A (preferably sparse!), |
98 | // or a string containing the name of a function pdMat.m |
99 | // or a function_handle for such a function |
100 | // such that y = pdMat( name,mode,m,n,x ) |
101 | // returns y = A*x (mode=1) or y = A"*x (mode=2). |
102 | // The input parameter "name" will be the string pdMat. |
103 | // b is an m-vector. |
104 | // bl is an n-vector of lower bounds. Non-existent bounds |
105 | // may be represented by bl(j) = -Inf or bl(j) <= -1e+20. |
106 | // bu is an n-vector of upper bounds. Non-existent bounds |
107 | // may be represented by bu(j) = Inf or bu(j) >= 1e+20. |
108 | // d1, d2 may be positive scalars or positive vectors (see above). |
109 | // options is a structure that may be set and altered by pdcoSet |
110 | // (type help pdcoSet). |
111 | // x0, y0, z0 provide an initial solution. |
112 | // xsize, zsize are estimates of the biggest x and z at the solution. |
113 | // They are used to scale (x,y,z). Good estimates |
114 | // should improve the performance of the barrier method. |
115 | // |
116 | // |
117 | // OUTPUT ARGUMENTS: |
118 | // x is the primal solution. |
119 | // y is the dual solution associated with Ax + D2 r = b. |
120 | // z is the dual solution associated with bl <= x <= bu. |
121 | // inform = 0 if a solution is found; |
122 | // = 1 if too many iterations were required; |
123 | // = 2 if the linesearch failed too often. |
124 | // PDitns is the number of Primal-Dual Barrier iterations required. |
125 | // CGitns is the number of Conjugate-Gradient iterations required |
126 | // if an iterative solver is used (LSQR). |
127 | // time is the cpu time used. |
128 | //---------------------------------------------------------------------- |
129 | |
130 | // PRIVATE FUNCTIONS: |
131 | // pdxxxbounds |
132 | // pdxxxdistrib |
133 | // pdxxxlsqr |
134 | // pdxxxlsqrmat |
135 | // pdxxxmat |
136 | // pdxxxmerit |
137 | // pdxxxresid1 |
138 | // pdxxxresid2 |
139 | // pdxxxstep |
140 | // |
141 | // GLOBAL VARIABLES: |
142 | // global pdDDD1 pdDDD2 pdDDD3 |
143 | // |
144 | // |
145 | // NOTES: |
146 | // The matrix A should be reasonably well scaled: norm(A,inf) =~ 1. |
147 | // The vector b and objective phi(x) may be of any size, but ensure that |
148 | // xsize and zsize are reasonably close to norm(x,inf) and norm(z,inf) |
149 | // at the solution. |
150 | // |
151 | // The files defining pdObj and pdMat |
152 | // must not be called Fname.m or Aname.m!! |
153 | // |
154 | // |
155 | // AUTHOR: |
156 | // Michael Saunders, Systems Optimization Laboratory (SOL), |
157 | // Stanford University, Stanford, California, USA. |
158 | // saunders@stanford.edu |
159 | // |
160 | // CONTRIBUTORS: |
161 | // Byunggyoo Kim, SOL, Stanford University. |
162 | // bgkim@stanford.edu |
163 | // |
164 | // DEVELOPMENT: |
165 | // 20 Jun 1997: Original version of pdsco.m derived from pdlp0.m. |
166 | // 29 Sep 2002: Original version of pdco.m derived from pdsco.m. |
167 | // Introduced D1, D2 in place of gamma*I, delta*I |
168 | // and allowed for general bounds bl <= x <= bu. |
169 | // 06 Oct 2002: Allowed for fixed variabes: bl(j) = bu(j) for any j. |
170 | // 15 Oct 2002: Eliminated some work vectors (since m, n might be LARGE). |
171 | // Modularized residuals, linesearch |
172 | // 16 Oct 2002: pdxxx..., pdDDD... names rationalized. |
173 | // pdAAA eliminated (global copy of A). |
174 | // Aname is now used directly as an ifexplicit A or a function. |
175 | // NOTE: If Aname is a function, it now has an extra parameter. |
176 | // 23 Oct 2002: Fname and Aname can now be function handles. |
177 | // 01 Nov 2002: Bug fixed in feval in pdxxxmat. |
178 | //----------------------------------------------------------------------- |
179 | |
180 | // global pdDDD1 pdDDD2 pdDDD3 |
181 | double inf = 1.0e30; |
182 | double eps = 1.0e-15; |
183 | double atolold, r3ratio, Pinf, Dinf, Cinf, Cinf0; |
184 | |
185 | printf("\n --------------------------------------------------------" ); |
186 | printf("\n pdco.m Version of 01 Nov 2002" ); |
187 | printf("\n Primal-dual barrier method to minimize a convex function" ); |
188 | printf("\n subject to linear constraints Ax + r = b, bl <= x <= bu" ); |
189 | printf("\n --------------------------------------------------------\n" ); |
190 | |
191 | int m = numberRows_; |
192 | int n = numberColumns_; |
193 | bool ifexplicit = true; |
194 | |
195 | CoinDenseVector<double> b(m, rhs_); |
196 | CoinDenseVector<double> x(n, x_); |
197 | CoinDenseVector<double> y(m, y_); |
198 | CoinDenseVector<double> z(n, dj_); |
199 | //delete old arrays |
200 | delete [] rhs_; |
201 | delete [] x_; |
202 | delete [] y_; |
203 | delete [] dj_; |
204 | rhs_ = NULL; |
205 | x_ = NULL; |
206 | y_ = NULL; |
207 | dj_ = NULL; |
208 | |
209 | // Save stuff so available elsewhere |
210 | pdcoStuff_ = stuff; |
211 | |
212 | double normb = b.infNorm(); |
213 | double normx0 = x.infNorm(); |
214 | double normy0 = y.infNorm(); |
215 | double normz0 = z.infNorm(); |
216 | |
217 | printf("\nmax |b | = %8g max |x0| = %8g" , normb , normx0); |
218 | printf( " xsize = %8g" , xsize_); |
219 | printf("\nmax |y0| = %8g max |z0| = %8g" , normy0, normz0); |
220 | printf( " zsize = %8g" , zsize_); |
221 | |
222 | //--------------------------------------------------------------------- |
223 | // Initialize. |
224 | //--------------------------------------------------------------------- |
225 | //true = 1; |
226 | //false = 0; |
227 | //zn = zeros(n,1); |
228 | int nb = n + m; |
229 | int nkkt = nb; |
230 | int CGitns = 0; |
231 | int inform = 0; |
232 | //--------------------------------------------------------------------- |
233 | // Only allow scalar d1, d2 for now |
234 | //--------------------------------------------------------------------- |
235 | /* |
236 | if (d1_->size()==1) |
237 | d1_->resize(n, d1_->getElements()[0]); // Allow scalar d1, d2 |
238 | if (d2_->size()==1) |
239 | d2->resize(m, d2->getElements()[0]); // to mean dk * unit vector |
240 | */ |
241 | assert (stuff->sizeD1() == 1); |
242 | double d1 = stuff->getD1(); |
243 | double d2 = stuff->getD2(); |
244 | |
245 | //--------------------------------------------------------------------- |
246 | // Grab input options. |
247 | //--------------------------------------------------------------------- |
248 | int maxitn = options.MaxIter; |
249 | double featol = options.FeaTol; |
250 | double opttol = options.OptTol; |
251 | double steptol = options.StepTol; |
252 | int stepSame = 1; /* options.StepSame; // 1 means stepx == stepz */ |
253 | double x0min = options.x0min; |
254 | double z0min = options.z0min; |
255 | double mu0 = options.mu0; |
256 | int LSproblem = options.LSproblem; // See below |
257 | int LSmethod = options.LSmethod; // 1=Cholesky 2=QR 3=LSQR |
258 | int itnlim = options.LSQRMaxIter * CoinMin(m, n); |
259 | double atol1 = options.LSQRatol1; // Initial atol |
260 | double atol2 = options.LSQRatol2; // Smallest atol,unless atol1 is smaller |
261 | double conlim = options.LSQRconlim; |
262 | int wait = options.wait; |
263 | |
264 | // LSproblem: |
265 | // 1 = dy 2 = dy shifted, DLS |
266 | // 11 = s 12 = s shifted, DLS (dx = Ds) |
267 | // 21 = dx |
268 | // 31 = 3x3 system, symmetrized by Z^{1/2} |
269 | // 32 = 2x2 system, symmetrized by X^{1/2} |
270 | |
271 | //--------------------------------------------------------------------- |
272 | // Set other parameters. |
273 | //--------------------------------------------------------------------- |
274 | int kminor = 0; // 1 stops after each iteration |
275 | double eta = 1e-4; // Linesearch tolerance for "sufficient descent" |
276 | double maxf = 10; // Linesearch backtrack limit (function evaluations) |
277 | double maxfail = 1; // Linesearch failure limit (consecutive iterations) |
278 | double bigcenter = 1e+3; // mu is reduced if center < bigcenter. |
279 | |
280 | // Parameters for LSQR. |
281 | double atolmin = eps; // Smallest atol if linesearch back-tracks |
282 | double btol = 0; // Should be small (zero is ok) |
283 | double show = false; // Controls lsqr iteration log |
284 | /* |
285 | double gamma = d1->infNorm(); |
286 | double delta = d2->infNorm(); |
287 | */ |
288 | double gamma = d1; |
289 | double delta = d2; |
290 | |
291 | printf("\n\nx0min = %8g featol = %8.1e" , x0min, featol); |
292 | printf( " d1max = %8.1e" , gamma); |
293 | printf( "\nz0min = %8g opttol = %8.1e" , z0min, opttol); |
294 | printf( " d2max = %8.1e" , delta); |
295 | printf( "\nmu0 = %8.1e steptol = %8g" , mu0 , steptol); |
296 | printf( " bigcenter= %8g" , bigcenter); |
297 | |
298 | printf("\n\nLSQR:" ); |
299 | printf("\natol1 = %8.1e atol2 = %8.1e" , atol1 , atol2 ); |
300 | printf( " btol = %8.1e" , btol ); |
301 | printf("\nconlim = %8.1e itnlim = %8d" , conlim, itnlim); |
302 | printf( " show = %8g" , show ); |
303 | |
304 | // LSmethod = 3; ////// Hardwire LSQR |
305 | // LSproblem = 1; ////// and LS problem defining "dy". |
306 | /* |
307 | if wait |
308 | printf("\n\nReview parameters... then type "return"\n") |
309 | keyboard |
310 | end |
311 | */ |
312 | if (eta < 0) |
313 | printf("\n\nLinesearch disabled by eta < 0" ); |
314 | |
315 | //--------------------------------------------------------------------- |
316 | // All parameters have now been set. |
317 | //--------------------------------------------------------------------- |
318 | double time = CoinCpuTime(); |
319 | bool useChol = (LSmethod == 1); |
320 | bool useQR = (LSmethod == 2); |
321 | bool direct = (LSmethod <= 2 && ifexplicit); |
322 | char solver[6]; |
323 | strcpy(solver, " LSQR" ); |
324 | |
325 | |
326 | //--------------------------------------------------------------------- |
327 | // Categorize bounds and allow for fixed variables by modifying b. |
328 | //--------------------------------------------------------------------- |
329 | |
330 | int nlow, nupp, nfix; |
331 | int *bptrs[3] = {0}; |
332 | getBoundTypes(&nlow, &nupp, &nfix, bptrs ); |
333 | int *low = bptrs[0]; |
334 | int *upp = bptrs[1]; |
335 | int *fix = bptrs[2]; |
336 | |
337 | int nU = n; |
338 | if (nupp == 0) nU = 1; //Make dummy vectors if no Upper bounds |
339 | |
340 | //--------------------------------------------------------------------- |
341 | // Get pointers to local copy of model bounds |
342 | //--------------------------------------------------------------------- |
343 | |
344 | CoinDenseVector<double> bl(n, columnLower_); |
345 | double *bl_elts = bl.getElements(); |
346 | CoinDenseVector<double> bu(nU, columnUpper_); // this is dummy if no UB |
347 | double *bu_elts = bu.getElements(); |
348 | |
349 | CoinDenseVector<double> r1(m, 0.0); |
350 | double *r1_elts = r1.getElements(); |
351 | CoinDenseVector<double> x1(n, 0.0); |
352 | double *x1_elts = x1.getElements(); |
353 | |
354 | if (nfix > 0) { |
355 | for (int k = 0; k < nfix; k++) |
356 | x1_elts[fix[k]] = bl[fix[k]]; |
357 | matVecMult(1, r1, x1); |
358 | b = b - r1; |
359 | // At some stage, might want to look at normfix = norm(r1,inf); |
360 | } |
361 | |
362 | //--------------------------------------------------------------------- |
363 | // Scale the input data. |
364 | // The scaled variables are |
365 | // xbar = x/beta, |
366 | // ybar = y/zeta, |
367 | // zbar = z/zeta. |
368 | // Define |
369 | // theta = beta*zeta; |
370 | // The scaled function is |
371 | // phibar = ( 1 /theta) fbar(beta*xbar), |
372 | // gradient = (beta /theta) grad, |
373 | // Hessian = (beta2/theta) hess. |
374 | //--------------------------------------------------------------------- |
375 | double beta = xsize_; |
376 | if (beta == 0) beta = 1; // beta scales b, x. |
377 | double zeta = zsize_; |
378 | if (zeta == 0) zeta = 1; // zeta scales y, z. |
379 | double theta = beta * zeta; // theta scales obj. |
380 | // (theta could be anything, but theta = beta*zeta makes |
381 | // scaled grad = grad/zeta = 1 approximately if zeta is chosen right.) |
382 | |
383 | for (int k = 0; k < nlow; k++) |
384 | bl_elts[low[k]] = bl_elts[low[k]] / beta; |
385 | for (int k = 0; k < nupp; k++) |
386 | bu_elts[upp[k]] = bu_elts[upp[k]] / beta; |
387 | d1 = d1 * ( beta / sqrt(theta) ); |
388 | d2 = d2 * ( sqrt(theta) / beta ); |
389 | |
390 | double beta2 = beta * beta; |
391 | b.scale( (1.0 / beta) ); |
392 | y.scale( (1.0 / zeta) ); |
393 | x.scale( (1.0 / beta) ); |
394 | z.scale( (1.0 / zeta) ); |
395 | |
396 | //--------------------------------------------------------------------- |
397 | // Initialize vectors that are not fully used if bounds are missing. |
398 | //--------------------------------------------------------------------- |
399 | CoinDenseVector<double> rL(n, 0.0); |
400 | CoinDenseVector<double> cL(n, 0.0); |
401 | CoinDenseVector<double> z1(n, 0.0); |
402 | CoinDenseVector<double> dx1(n, 0.0); |
403 | CoinDenseVector<double> dz1(n, 0.0); |
404 | CoinDenseVector<double> r2(n, 0.0); |
405 | |
406 | // Assign upper bd regions (dummy if no UBs) |
407 | |
408 | CoinDenseVector<double> rU(nU, 0.0); |
409 | CoinDenseVector<double> cU(nU, 0.0); |
410 | CoinDenseVector<double> x2(nU, 0.0); |
411 | CoinDenseVector<double> z2(nU, 0.0); |
412 | CoinDenseVector<double> dx2(nU, 0.0); |
413 | CoinDenseVector<double> dz2(nU, 0.0); |
414 | |
415 | //--------------------------------------------------------------------- |
416 | // Initialize x, y, z, objective, etc. |
417 | //--------------------------------------------------------------------- |
418 | CoinDenseVector<double> dx(n, 0.0); |
419 | CoinDenseVector<double> dy(m, 0.0); |
420 | CoinDenseVector<double> Pr(m); |
421 | CoinDenseVector<double> D(n); |
422 | double *D_elts = D.getElements(); |
423 | CoinDenseVector<double> w(n); |
424 | double *w_elts = w.getElements(); |
425 | CoinDenseVector<double> rhs(m + n); |
426 | |
427 | |
428 | //--------------------------------------------------------------------- |
429 | // Pull out the element array pointers for efficiency |
430 | //--------------------------------------------------------------------- |
431 | double *x_elts = x.getElements(); |
432 | double *x2_elts = x2.getElements(); |
433 | double *z_elts = z.getElements(); |
434 | double *z1_elts = z1.getElements(); |
435 | double *z2_elts = z2.getElements(); |
436 | |
437 | for (int k = 0; k < nlow; k++) { |
438 | x_elts[low[k]] = CoinMax( x_elts[low[k]], bl[low[k]]); |
439 | x1_elts[low[k]] = CoinMax( x_elts[low[k]] - bl[low[k]], x0min ); |
440 | z1_elts[low[k]] = CoinMax( z_elts[low[k]], z0min ); |
441 | } |
442 | for (int k = 0; k < nupp; k++) { |
443 | x_elts[upp[k]] = CoinMin( x_elts[upp[k]], bu[upp[k]]); |
444 | x2_elts[upp[k]] = CoinMax(bu[upp[k]] - x_elts[upp[k]], x0min ); |
445 | z2_elts[upp[k]] = CoinMax(-z_elts[upp[k]], z0min ); |
446 | } |
447 | //////////////////// Assume hessian is diagonal. ////////////////////// |
448 | |
449 | // [obj,grad,hess] = feval( Fname, (x*beta) ); |
450 | x.scale(beta); |
451 | double obj = getObj(x); |
452 | CoinDenseVector<double> grad(n); |
453 | getGrad(x, grad); |
454 | CoinDenseVector<double> H(n); |
455 | getHessian(x , H); |
456 | x.scale((1.0 / beta)); |
457 | |
458 | double * g_elts = grad.getElements(); |
459 | double * H_elts = H.getElements(); |
460 | |
461 | obj /= theta; // Scaled obj. |
462 | grad = grad * (beta / theta) + (d1 * d1) * x; // grad includes x regularization. |
463 | H = H * (beta2 / theta) + (d1 * d1) ; // H includes x regularization. |
464 | |
465 | |
466 | /*--------------------------------------------------------------------- |
467 | // Compute primal and dual residuals: |
468 | // r1 = b - Aprod(x) - d2*d2*y; |
469 | // r2 = grad - Atprod(y) + z2 - z1; |
470 | // rL = bl - x + x1; |
471 | // rU = x + x2 - bu; */ |
472 | //--------------------------------------------------------------------- |
473 | // [r1,r2,rL,rU,Pinf,Dinf] = ... |
474 | // pdxxxresid1( Aname,fix,low,upp, ... |
475 | // b,bl,bu,d1,d2,grad,rL,rU,x,x1,x2,y,z1,z2 ); |
476 | pdxxxresid1( this, nlow, nupp, nfix, low, upp, fix, |
477 | b, bl_elts, bu_elts, d1, d2, grad, rL, rU, x, x1, x2, y, z1, z2, |
478 | r1, r2, &Pinf, &Dinf); |
479 | //--------------------------------------------------------------------- |
480 | // Initialize mu and complementarity residuals: |
481 | // cL = mu*e - X1*z1. |
482 | // cU = mu*e - X2*z2. |
483 | // |
484 | // 25 Jan 2001: Now that b and obj are scaled (and hence x,y,z), |
485 | // we should be able to use mufirst = mu0 (absolute value). |
486 | // 0.1 worked poorly on StarTest1 with x0min = z0min = 0.1. |
487 | // 29 Jan 2001: We might as well use mu0 = x0min * z0min; |
488 | // so that most variables are centered after a warm start. |
489 | // 29 Sep 2002: Use mufirst = mu0*(x0min * z0min), |
490 | // regarding mu0 as a scaling of the initial center. |
491 | //--------------------------------------------------------------------- |
492 | // double mufirst = mu0*(x0min * z0min); |
493 | double mufirst = mu0; // revert to absolute value |
494 | double mulast = 0.1 * opttol; |
495 | mulast = CoinMin( mulast, mufirst ); |
496 | double mu = mufirst; |
497 | double center, fmerit; |
498 | pdxxxresid2( mu, nlow, nupp, low, upp, cL, cU, x1, x2, |
499 | z1, z2, ¢er, &Cinf, &Cinf0 ); |
500 | fmerit = pdxxxmerit(nlow, nupp, low, upp, r1, r2, rL, rU, cL, cU ); |
501 | |
502 | // Initialize other things. |
503 | |
504 | bool precon = true; |
505 | double PDitns = 0; |
506 | bool converged = false; |
507 | double atol = atol1; |
508 | atol2 = CoinMax( atol2, atolmin ); |
509 | atolmin = atol2; |
510 | // pdDDD2 = d2; // Global vector for diagonal matrix D2 |
511 | |
512 | // Iteration log. |
513 | |
514 | double stepx = 0; |
515 | double stepz = 0; |
516 | int nf = 0; |
517 | int itncg = 0; |
518 | int nfail = 0; |
519 | |
520 | printf("\n\nItn mu stepx stepz Pinf Dinf" ); |
521 | printf(" Cinf Objective nf center" ); |
522 | if (direct) { |
523 | printf("\n" ); |
524 | } else { |
525 | printf(" atol solver Inexact\n" ); |
526 | } |
527 | |
528 | double regx = (d1 * x).twoNorm(); |
529 | double regy = (d2 * y).twoNorm(); |
530 | // regterm = twoNorm(d1.*x)^2 + norm(d2.*y)^2; |
531 | double regterm = regx * regx + regy * regy; |
532 | double objreg = obj + 0.5 * regterm; |
533 | double objtrue = objreg * theta; |
534 | |
535 | printf("\n%3g " , PDitns ); |
536 | printf("%6.1f%6.1f" , log10(Pinf ), log10(Dinf)); |
537 | printf("%6.1f%15.7e" , log10(Cinf0), objtrue ); |
538 | printf(" %8.1f\n" , center ); |
539 | /* |
540 | if kminor |
541 | printf("\n\nStart of first minor itn...\n"); |
542 | keyboard |
543 | end |
544 | */ |
545 | //--------------------------------------------------------------------- |
546 | // Main loop. |
547 | //--------------------------------------------------------------------- |
548 | // Lsqr |
549 | ClpLsqr thisLsqr(this); |
550 | // while (converged) { |
551 | while(PDitns < maxitn) { |
552 | PDitns = PDitns + 1; |
553 | |
554 | // 31 Jan 2001: Set atol according to progress, a la Inexact Newton. |
555 | // 07 Feb 2001: 0.1 not small enough for Satellite problem. Try 0.01. |
556 | // 25 Apr 2001: 0.01 seems wasteful for Star problem. |
557 | // Now that starting conditions are better, go back to 0.1. |
558 | |
559 | double r3norm = CoinMax(Pinf, CoinMax(Dinf, Cinf)); |
560 | atol = CoinMin(atol, r3norm * 0.1); |
561 | atol = CoinMax(atol, atolmin ); |
562 | info.r3norm = r3norm; |
563 | |
564 | //------------------------------------------------------------------- |
565 | // Define a damped Newton iteration for solving f = 0, |
566 | // keeping x1, x2, z1, z2 > 0. We eliminate dx1, dx2, dz1, dz2 |
567 | // to obtain the system |
568 | // |
569 | // [-H2 A" ] [ dx ] = [ w ], H2 = H + D1^2 + X1inv Z1 + X2inv Z2, |
570 | // [ A D2^2] [ dy ] = [ r1] w = r2 - X1inv(cL + Z1 rL) |
571 | // + X2inv(cU + Z2 rU), |
572 | // |
573 | // which is equivalent to the least-squares problem |
574 | // |
575 | // min || [ D A"]dy - [ D w ] ||, D = H2^{-1/2}. (*) |
576 | // || [ D2 ] [D2inv r1] || |
577 | //------------------------------------------------------------------- |
578 | for (int k = 0; k < nlow; k++) |
579 | H_elts[low[k]] = H_elts[low[k]] + z1[low[k]] / x1[low[k]]; |
580 | for (int k = 0; k < nupp; k++) |
581 | H[upp[k]] = H[upp[k]] + z2[upp[k]] / x2[upp[k]]; |
582 | w = r2; |
583 | for (int k = 0; k < nlow; k++) |
584 | w[low[k]] = w[low[k]] - (cL[low[k]] + z1[low[k]] * rL[low[k]]) / x1[low[k]]; |
585 | for (int k = 0; k < nupp; k++) |
586 | w[upp[k]] = w[upp[k]] + (cU[upp[k]] + z2[upp[k]] * rU[upp[k]]) / x2[upp[k]]; |
587 | |
588 | if (LSproblem == 1) { |
589 | //----------------------------------------------------------------- |
590 | // Solve (*) for dy. |
591 | //----------------------------------------------------------------- |
592 | H = 1.0 / H; // H is now Hinv (NOTE!) |
593 | for (int k = 0; k < nfix; k++) |
594 | H[fix[k]] = 0; |
595 | for (int k = 0; k < n; k++) |
596 | D_elts[k] = sqrt(H_elts[k]); |
597 | thisLsqr.borrowDiag1(D_elts); |
598 | thisLsqr.diag2_ = d2; |
599 | |
600 | if (direct) { |
601 | // Omit direct option for now |
602 | } else {// Iterative solve using LSQR. |
603 | //rhs = [ D.*w; r1./d2 ]; |
604 | for (int k = 0; k < n; k++) |
605 | rhs[k] = D_elts[k] * w_elts[k]; |
606 | for (int k = 0; k < m; k++) |
607 | rhs[n+k] = r1_elts[k] * (1.0 / d2); |
608 | double damp = 0; |
609 | |
610 | if (precon) { // Construct diagonal preconditioner for LSQR |
611 | matPrecon(d2, Pr, D); |
612 | } |
613 | /* |
614 | rw(7) = precon; |
615 | info.atolmin = atolmin; |
616 | info.r3norm = fmerit; // Must be the 2-norm here. |
617 | |
618 | [ dy, istop, itncg, outfo ] = ... |
619 | pdxxxlsqr( nb,m,"pdxxxlsqrmat",Aname,rw,rhs,damp, ... |
620 | atol,btol,conlim,itnlim,show,info ); |
621 | |
622 | |
623 | thisLsqr.input->rhs_vec = &rhs; |
624 | thisLsqr.input->sol_vec = &dy; |
625 | thisLsqr.input->rel_mat_err = atol; |
626 | thisLsqr.do_lsqr(this); |
627 | */ |
628 | // New version of lsqr |
629 | |
630 | int istop, itn; |
631 | dy.clear(); |
632 | show = false; |
633 | info.atolmin = atolmin; |
634 | info.r3norm = fmerit; // Must be the 2-norm here. |
635 | |
636 | thisLsqr.do_lsqr( rhs, damp, atol, btol, conlim, itnlim, |
637 | show, info, dy , &istop, &itncg, &outfo, precon, Pr); |
638 | if (precon) |
639 | dy = dy * Pr; |
640 | |
641 | if (!precon && itncg > 999999) |
642 | precon = true; |
643 | |
644 | if (istop == 3 || istop == 7 ) // conlim or itnlim |
645 | printf("\n LSQR stopped early: istop = //%d" , istop); |
646 | |
647 | |
648 | atolold = outfo.atolold; |
649 | atol = outfo.atolnew; |
650 | r3ratio = outfo.r3ratio; |
651 | }// LSproblem 1 |
652 | |
653 | // grad = pdxxxmat( Aname,2,m,n,dy ); // grad = A"dy |
654 | grad.clear(); |
655 | matVecMult(2, grad, dy); |
656 | for (int k = 0; k < nfix; k++) |
657 | grad[fix[k]] = 0; // grad is a work vector |
658 | dx = H * (grad - w); |
659 | |
660 | } else { |
661 | perror( "This LSproblem not yet implemented\n" ); |
662 | } |
663 | //------------------------------------------------------------------- |
664 | |
665 | CGitns += itncg; |
666 | |
667 | //------------------------------------------------------------------- |
668 | // dx and dy are now known. Get dx1, dx2, dz1, dz2. |
669 | //------------------------------------------------------------------- |
670 | for (int k = 0; k < nlow; k++) { |
671 | dx1[low[k]] = - rL[low[k]] + dx[low[k]]; |
672 | dz1[low[k]] = (cL[low[k]] - z1[low[k]] * dx1[low[k]]) / x1[low[k]]; |
673 | } |
674 | for (int k = 0; k < nupp; k++) { |
675 | dx2[upp[k]] = - rU[upp[k]] - dx[upp[k]]; |
676 | dz2[upp[k]] = (cU[upp[k]] - z2[upp[k]] * dx2[upp[k]]) / x2[upp[k]]; |
677 | } |
678 | //------------------------------------------------------------------- |
679 | // Find the maximum step. |
680 | //-------------------------------------------------------------------- |
681 | double stepx1 = pdxxxstep(nlow, low, x1, dx1 ); |
682 | double stepx2 = inf; |
683 | if (nupp > 0) |
684 | stepx2 = pdxxxstep(nupp, upp, x2, dx2 ); |
685 | double stepz1 = pdxxxstep( z1 , dz1 ); |
686 | double stepz2 = inf; |
687 | if (nupp > 0) |
688 | stepz2 = pdxxxstep( z2 , dz2 ); |
689 | double stepx = CoinMin( stepx1, stepx2 ); |
690 | double stepz = CoinMin( stepz1, stepz2 ); |
691 | stepx = CoinMin( steptol * stepx, 1.0 ); |
692 | stepz = CoinMin( steptol * stepz, 1.0 ); |
693 | if (stepSame) { // For NLPs, force same step |
694 | stepx = CoinMin( stepx, stepz ); // (true Newton method) |
695 | stepz = stepx; |
696 | } |
697 | |
698 | //------------------------------------------------------------------- |
699 | // Backtracking linesearch. |
700 | //------------------------------------------------------------------- |
701 | bool fail = true; |
702 | nf = 0; |
703 | |
704 | while (nf < maxf) { |
705 | nf = nf + 1; |
706 | x = x + stepx * dx; |
707 | y = y + stepz * dy; |
708 | for (int k = 0; k < nlow; k++) { |
709 | x1[low[k]] = x1[low[k]] + stepx * dx1[low[k]]; |
710 | z1[low[k]] = z1[low[k]] + stepz * dz1[low[k]]; |
711 | } |
712 | for (int k = 0; k < nupp; k++) { |
713 | x2[upp[k]] = x2[upp[k]] + stepx * dx2[upp[k]]; |
714 | z2[upp[k]] = z2[upp[k]] + stepz * dz2[upp[k]]; |
715 | } |
716 | // [obj,grad,hess] = feval( Fname, (x*beta) ); |
717 | x.scale(beta); |
718 | obj = getObj(x); |
719 | getGrad(x, grad); |
720 | getHessian(x, H); |
721 | x.scale((1.0 / beta)); |
722 | |
723 | obj /= theta; |
724 | grad = grad * (beta / theta) + d1 * d1 * x; |
725 | H = H * (beta2 / theta) + d1 * d1; |
726 | |
727 | // [r1,r2,rL,rU,Pinf,Dinf] = ... |
728 | pdxxxresid1( this, nlow, nupp, nfix, low, upp, fix, |
729 | b, bl_elts, bu_elts, d1, d2, grad, rL, rU, x, x1, x2, |
730 | y, z1, z2, r1, r2, &Pinf, &Dinf ); |
731 | //double center, Cinf, Cinf0; |
732 | // [cL,cU,center,Cinf,Cinf0] = ... |
733 | pdxxxresid2( mu, nlow, nupp, low, upp, cL, cU, x1, x2, z1, z2, |
734 | ¢er, &Cinf, &Cinf0); |
735 | double fmeritnew = pdxxxmerit(nlow, nupp, low, upp, r1, r2, rL, rU, cL, cU ); |
736 | double step = CoinMin( stepx, stepz ); |
737 | |
738 | if (fmeritnew <= (1 - eta * step)*fmerit) { |
739 | fail = false; |
740 | break; |
741 | } |
742 | |
743 | // Merit function didn"t decrease. |
744 | // Restore variables to previous values. |
745 | // (This introduces a little error, but save lots of space.) |
746 | |
747 | x = x - stepx * dx; |
748 | y = y - stepz * dy; |
749 | for (int k = 0; k < nlow; k++) { |
750 | x1[low[k]] = x1[low[k]] - stepx * dx1[low[k]]; |
751 | z1[low[k]] = z1[low[k]] - stepz * dz1[low[k]]; |
752 | } |
753 | for (int k = 0; k < nupp; k++) { |
754 | x2[upp[k]] = x2[upp[k]] - stepx * dx2[upp[k]]; |
755 | z2[upp[k]] = z2[upp[k]] - stepz * dz2[upp[k]]; |
756 | } |
757 | // Back-track. |
758 | // If it"s the first time, |
759 | // make stepx and stepz the same. |
760 | |
761 | if (nf == 1 && stepx != stepz) { |
762 | stepx = step; |
763 | } else if (nf < maxf) { |
764 | stepx = stepx / 2; |
765 | } |
766 | stepz = stepx; |
767 | } |
768 | |
769 | if (fail) { |
770 | printf("\n Linesearch failed (nf too big)" ); |
771 | nfail += 1; |
772 | } else { |
773 | nfail = 0; |
774 | } |
775 | |
776 | //------------------------------------------------------------------- |
777 | // Set convergence measures. |
778 | //-------------------------------------------------------------------- |
779 | regx = (d1 * x).twoNorm(); |
780 | regy = (d2 * y).twoNorm(); |
781 | regterm = regx * regx + regy * regy; |
782 | objreg = obj + 0.5 * regterm; |
783 | objtrue = objreg * theta; |
784 | |
785 | bool primalfeas = Pinf <= featol; |
786 | bool dualfeas = Dinf <= featol; |
787 | bool complementary = Cinf0 <= opttol; |
788 | bool enough = PDitns >= 4; // Prevent premature termination. |
789 | bool converged = primalfeas & dualfeas & complementary & enough; |
790 | |
791 | //------------------------------------------------------------------- |
792 | // Iteration log. |
793 | //------------------------------------------------------------------- |
794 | char str1[100], str2[100], str3[100], str4[100], str5[100]; |
795 | sprintf(str1, "\n%3g%5.1f" , PDitns , log10(mu) ); |
796 | sprintf(str2, "%8.5f%8.5f" , stepx , stepz ); |
797 | if (stepx < 0.0001 || stepz < 0.0001) { |
798 | sprintf(str2, " %6.1e %6.1e" , stepx , stepz ); |
799 | } |
800 | |
801 | sprintf(str3, "%6.1f%6.1f" , log10(Pinf) , log10(Dinf)); |
802 | sprintf(str4, "%6.1f%15.7e" , log10(Cinf0), objtrue ); |
803 | sprintf(str5, "%3d%8.1f" , nf , center ); |
804 | if (center > 99999) { |
805 | sprintf(str5, "%3d%8.1e" , nf , center ); |
806 | } |
807 | printf("%s%s%s%s%s" , str1, str2, str3, str4, str5); |
808 | if (direct) { |
809 | // relax |
810 | } else { |
811 | printf(" %5.1f%7d%7.3f" , log10(atolold), itncg, r3ratio); |
812 | } |
813 | //------------------------------------------------------------------- |
814 | // Test for termination. |
815 | //------------------------------------------------------------------- |
816 | if (kminor) { |
817 | printf( "\nStart of next minor itn...\n" ); |
818 | // keyboard; |
819 | } |
820 | |
821 | if (converged) { |
822 | printf("\n Converged" ); |
823 | break; |
824 | } else if (PDitns >= maxitn) { |
825 | printf("\n Too many iterations" ); |
826 | inform = 1; |
827 | break; |
828 | } else if (nfail >= maxfail) { |
829 | printf("\n Too many linesearch failures" ); |
830 | inform = 2; |
831 | break; |
832 | } else { |
833 | |
834 | // Reduce mu, and reset certain residuals. |
835 | |
836 | double stepmu = CoinMin( stepx , stepz ); |
837 | stepmu = CoinMin( stepmu, steptol ); |
838 | double muold = mu; |
839 | mu = mu - stepmu * mu; |
840 | if (center >= bigcenter) |
841 | mu = muold; |
842 | |
843 | // mutrad = mu0*(sum(Xz)/n); // 24 May 1998: Traditional value, but |
844 | // mu = CoinMin(mu,mutrad ); // it seemed to decrease mu too much. |
845 | |
846 | mu = CoinMax(mu, mulast); // 13 Jun 1998: No need for smaller mu. |
847 | // [cL,cU,center,Cinf,Cinf0] = ... |
848 | pdxxxresid2( mu, nlow, nupp, low, upp, cL, cU, x1, x2, z1, z2, |
849 | ¢er, &Cinf, &Cinf0 ); |
850 | fmerit = pdxxxmerit( nlow, nupp, low, upp, r1, r2, rL, rU, cL, cU ); |
851 | |
852 | // Reduce atol for LSQR (and SYMMLQ). |
853 | // NOW DONE AT TOP OF LOOP. |
854 | |
855 | atolold = atol; |
856 | // if atol > atol2 |
857 | // atolfac = (mu/mufirst)^0.25; |
858 | // atol = CoinMax( atol*atolfac, atol2 ); |
859 | // end |
860 | |
861 | // atol = CoinMin( atol, mu ); // 22 Jan 2001: a la Inexact Newton. |
862 | // atol = CoinMin( atol, 0.5*mu ); // 30 Jan 2001: A bit tighter |
863 | |
864 | // If the linesearch took more than one function (nf > 1), |
865 | // we assume the search direction needed more accuracy |
866 | // (though this may be true only for LPs). |
867 | // 12 Jun 1998: Ask for more accuracy if nf > 2. |
868 | // 24 Nov 2000: Also if the steps are small. |
869 | // 30 Jan 2001: Small steps might be ok with warm start. |
870 | // 06 Feb 2001: Not necessarily. Reinstated tests in next line. |
871 | |
872 | if (nf > 2 || CoinMin( stepx, stepz ) <= 0.01) |
873 | atol = atolold * 0.1; |
874 | } |
875 | //--------------------------------------------------------------------- |
876 | // End of main loop. |
877 | //--------------------------------------------------------------------- |
878 | } |
879 | |
880 | |
881 | for (int k = 0; k < nfix; k++) |
882 | x[fix[k]] = bl[fix[k]]; |
883 | z = z1; |
884 | if (nupp > 0) |
885 | z = z - z2; |
886 | printf("\n\nmax |x| =%10.3f" , x.infNorm() ); |
887 | printf(" max |y| =%10.3f" , y.infNorm() ); |
888 | printf(" max |z| =%10.3f" , z.infNorm() ); |
889 | printf(" scaled" ); |
890 | |
891 | x.scale(beta); |
892 | y.scale(zeta); |
893 | z.scale(zeta); // Unscale x, y, z. |
894 | |
895 | printf( "\nmax |x| =%10.3f" , x.infNorm() ); |
896 | printf(" max |y| =%10.3f" , y.infNorm() ); |
897 | printf(" max |z| =%10.3f" , z.infNorm() ); |
898 | printf(" unscaled\n" ); |
899 | |
900 | time = CoinCpuTime() - time; |
901 | char str1[100], str2[100]; |
902 | sprintf(str1, "\nPDitns =%10g" , PDitns ); |
903 | sprintf(str2, "itns =%10d" , CGitns ); |
904 | // printf( [str1 " " solver str2] ); |
905 | printf(" time =%10.1f\n" , time); |
906 | /* |
907 | pdxxxdistrib( abs(x),abs(z) ); // Private function |
908 | |
909 | if (wait) |
910 | keyboard; |
911 | */ |
912 | //----------------------------------------------------------------------- |
913 | // End function pdco.m |
914 | //----------------------------------------------------------------------- |
915 | /* printf("Solution x values:\n\n"); |
916 | for (int k=0; k<n; k++) |
917 | printf(" %d %e\n", k, x[k]); |
918 | */ |
919 | // Print distribution |
920 | float thresh[9] = { 0.00000001, 0.0000001, 0.000001, 0.00001, 0.0001, 0.001, 0.01, 0.1, 1.00001}; |
921 | int counts[9] = {0}; |
922 | for (int ij = 0; ij < n; ij++) { |
923 | for (int j = 0; j < 9; j++) { |
924 | if(x[ij] < thresh[j]) { |
925 | counts[j] += 1; |
926 | break; |
927 | } |
928 | } |
929 | } |
930 | printf ("Distribution of Solution Values\n" ); |
931 | for (int j = 8; j > 1; j--) |
932 | printf(" %f to %f %d\n" , thresh[j-1], thresh[j], counts[j]); |
933 | printf(" Less than %f %d\n" , thresh[2], counts[0]); |
934 | |
935 | return 0; |
936 | } |
937 | // LSQR |
938 | void |
939 | ClpPdco::lsqr() |
940 | { |
941 | } |
942 | |
943 | void ClpPdco::matVecMult( int mode, double* x_elts, double* y_elts) |
944 | { |
945 | pdcoStuff_->matVecMult(this, mode, x_elts, y_elts); |
946 | } |
947 | void ClpPdco::matVecMult( int mode, CoinDenseVector<double> &x, double *y_elts) |
948 | { |
949 | double *x_elts = x.getElements(); |
950 | matVecMult( mode, x_elts, y_elts); |
951 | return; |
952 | } |
953 | |
954 | void ClpPdco::matVecMult( int mode, CoinDenseVector<double> &x, CoinDenseVector<double> &y) |
955 | { |
956 | double *x_elts = x.getElements(); |
957 | double *y_elts = y.getElements(); |
958 | matVecMult( mode, x_elts, y_elts); |
959 | return; |
960 | } |
961 | |
962 | void ClpPdco::matVecMult( int mode, CoinDenseVector<double> *x, CoinDenseVector<double> *y) |
963 | { |
964 | double *x_elts = x->getElements(); |
965 | double *y_elts = y->getElements(); |
966 | matVecMult( mode, x_elts, y_elts); |
967 | return; |
968 | } |
969 | void ClpPdco::matPrecon(double delta, double* x_elts, double* y_elts) |
970 | { |
971 | pdcoStuff_->matPrecon(this, delta, x_elts, y_elts); |
972 | } |
973 | void ClpPdco::matPrecon(double delta, CoinDenseVector<double> &x, double *y_elts) |
974 | { |
975 | double *x_elts = x.getElements(); |
976 | matPrecon(delta, x_elts, y_elts); |
977 | return; |
978 | } |
979 | |
980 | void ClpPdco::matPrecon(double delta, CoinDenseVector<double> &x, CoinDenseVector<double> &y) |
981 | { |
982 | double *x_elts = x.getElements(); |
983 | double *y_elts = y.getElements(); |
984 | matPrecon(delta, x_elts, y_elts); |
985 | return; |
986 | } |
987 | |
988 | void ClpPdco::matPrecon(double delta, CoinDenseVector<double> *x, CoinDenseVector<double> *y) |
989 | { |
990 | double *x_elts = x->getElements(); |
991 | double *y_elts = y->getElements(); |
992 | matPrecon(delta, x_elts, y_elts); |
993 | return; |
994 | } |
995 | void ClpPdco::getBoundTypes(int *nlow, int *nupp, int *nfix, int **bptrs) |
996 | { |
997 | *nlow = numberColumns_; |
998 | *nupp = *nfix = 0; |
999 | int *low_ = (int *)malloc(numberColumns_ * sizeof(int)) ; |
1000 | for (int k = 0; k < numberColumns_; k++) |
1001 | low_[k] = k; |
1002 | bptrs[0] = low_; |
1003 | return; |
1004 | } |
1005 | |
1006 | double ClpPdco::getObj(CoinDenseVector<double> &x) |
1007 | { |
1008 | return pdcoStuff_->getObj(this, x); |
1009 | } |
1010 | |
1011 | void ClpPdco::getGrad(CoinDenseVector<double> &x, CoinDenseVector<double> &g) |
1012 | { |
1013 | pdcoStuff_->getGrad(this, x, g); |
1014 | } |
1015 | |
1016 | void ClpPdco::getHessian(CoinDenseVector<double> &x, CoinDenseVector<double> &H) |
1017 | { |
1018 | pdcoStuff_->getHessian(this, x, H); |
1019 | } |
1020 | #endif |
1021 | |