7 #define MAX2(a,b) ((a) > (b) ? (a) : (b))
8 #define MIN2(a,b) ((a) < (b) ? (a) : (b))
10 /* *********************************************************************** */
11 /* SUBROUTINE PLIS ALL SYSTEMS 01/09/22 */
13 /* GENERAL SUBROUTINE FOR LARGE-SCALE BOX CONSTRAINED MINIMIZATION THAT */
14 /* USE THE LIMITED MEMORY VARIABLE METRIC METHOD BASED ON THE STRANG */
18 /* II NF NUMBER OF VARIABLES. */
19 /* II NB CHOICE OF SIMPLE BOUNDS. NB=0-SIMPLE BOUNDS SUPPRESSED. */
20 /* NB>0-SIMPLE BOUNDS ACCEPTED. */
21 /* RI X(NF) VECTOR OF VARIABLES. */
22 /* II IX(NF) VECTOR CONTAINING TYPES OF BOUNDS. IX(I)=0-VARIABLE */
23 /* X(I) IS UNBOUNDED. IX(I)=1-LOVER BOUND XL(I).LE.X(I). */
24 /* IX(I)=2-UPPER BOUND X(I).LE.XU(I). IX(I)=3-TWO SIDE BOUND */
25 /* XL(I).LE.X(I).LE.XU(I). IX(I)=5-VARIABLE X(I) IS FIXED. */
26 /* RI XL(NF) VECTOR CONTAINING LOWER BOUNDS FOR VARIABLES. */
27 /* RI XU(NF) VECTOR CONTAINING UPPER BOUNDS FOR VARIABLES. */
28 /* RO GF(NF) GRADIENT OF THE OBJECTIVE FUNCTION. */
29 /* RO S(NF) DIRECTION VECTOR. */
30 /* RU XO(NF) VECTORS OF VARIABLES DIFFERENCE. */
31 /* RI GO(NF) GRADIENTS DIFFERENCE. */
32 /* RA UO(NF) AUXILIARY VECTOR. */
33 /* RA VO(NF) AUXILIARY VECTOR. */
34 /* RI XMAX MAXIMUM STEPSIZE. */
35 /* RI TOLX TOLERANCE FOR CHANGE OF VARIABLES. */
36 /* RI TOLF TOLERANCE FOR CHANGE OF FUNCTION VALUES. */
37 /* RI TOLB TOLERANCE FOR THE FUNCTION VALUE. */
38 /* RI TOLG TOLERANCE FOR THE GRADIENT NORM. */
39 /* RI MINF_EST ESTIMATION OF THE MINIMUM FUNCTION VALUE. */
40 /* RO GMAX MAXIMUM PARTIAL DERIVATIVE. */
41 /* RO F VALUE OF THE OBJECTIVE FUNCTION. */
42 /* II MIT MAXIMUM NUMBER OF ITERATIONS. */
43 /* II MFV MAXIMUM NUMBER OF FUNCTION EVALUATIONS. */
44 /* II IEST ESTIMATION INDICATOR. IEST=0-MINIMUM IS NOT ESTIMATED. */
45 /* IEST=1-MINIMUM IS ESTIMATED BY THE VALUE MINF_EST. */
46 /* II MF NUMBER OF LIMITED MEMORY STEPS. */
47 /* IO ITERM VARIABLE THAT INDICATES THE CAUSE OF TERMINATION. */
48 /* ITERM=1-IF ABS(X-XO) WAS LESS THAN OR EQUAL TO TOLX IN */
49 /* MTESX (USUALLY TWO) SUBSEQUEBT ITERATIONS. */
50 /* ITERM=2-IF ABS(F-FO) WAS LESS THAN OR EQUAL TO TOLF IN */
51 /* MTESF (USUALLY TWO) SUBSEQUEBT ITERATIONS. */
52 /* ITERM=3-IF F IS LESS THAN OR EQUAL TO TOLB. */
53 /* ITERM=4-IF GMAX IS LESS THAN OR EQUAL TO TOLG. */
54 /* ITERM=6-IF THE TERMINATION CRITERION WAS NOT SATISFIED, */
55 /* BUT THE SOLUTION OBTAINED IS PROBABLY ACCEPTABLE. */
56 /* ITERM=11-IF NIT EXCEEDED MIT. ITERM=12-IF NFV EXCEEDED MFV. */
57 /* ITERM=13-IF NFG EXCEEDED MFG. ITERM<0-IF THE METHOD FAILED. */
59 /* VARIABLES IN COMMON /STAT/ (STATISTICS) : */
60 /* IO NRES NUMBER OF RESTARTS. */
61 /* IO NDEC NUMBER OF MATRIX DECOMPOSITION. */
62 /* IO NIN NUMBER OF INNER ITERATIONS. */
63 /* IO NIT NUMBER OF ITERATIONS. */
64 /* IO NFV NUMBER OF FUNCTION EVALUATIONS. */
65 /* IO NFG NUMBER OF GRADIENT EVALUATIONS. */
66 /* IO NFH NUMBER OF HESSIAN EVALUATIONS. */
68 /* SUBPROGRAMS USED : */
69 /* S PCBS04 ELIMINATION OF BOX CONSTRAINT VIOLATIONS. */
70 /* S PS1L01 STEPSIZE SELECTION USING LINE SEARCH. */
71 /* S PYADC0 ADDITION OF A BOX CONSTRAINT. */
72 /* S PYFUT1 TEST ON TERMINATION. */
73 /* S PYRMC0 DELETION OF A BOX CONSTRAINT. */
74 /* S PYTRCD COMPUTATION OF PROJECTED DIFFERENCES FOR THE VARIABLE METRIC */
76 /* S PYTRCG COMPUTATION OF THE PROJECTED GRADIENT. */
77 /* S PYTRCS COMPUTATION OF THE PROJECTED DIRECTION VECTOR. */
78 /* S MXDRCB BACKWARD PART OF THE STRANG FORMULA FOR PREMULTIPLICATION */
79 /* OF THE VECTOR X BY AN IMPLICIT BFGS UPDATE. */
80 /* S MXDRCF FORWARD PART OF THE STRANG FORMULA FOR PREMULTIPLICATION */
81 /* OF THE VECTOR X BY AN IMPLICIT BFGS UPDATE. */
82 /* S MXDRSU SHIFT OF COLUMNS OF THE RECTANGULAR MATRICES A AND B. */
83 /* SHIFT OF ELEMENTS OF THE VECTOR U. THESE SHIFTS ARE USED IN */
84 /* THE LIMITED MEMORY BFGS METHOD. */
85 /* S MXUDIR VECTOR AUGMENTED BY THE SCALED VECTOR. */
86 /* RF MXUDOT DOT PRODUCT OF TWO VECTORS. */
87 /* S MXUNEG COPYING OF A VECTOR WITH CHANGE OF THE SIGN. */
88 /* S MXVCOP COPYING OF A VECTOR. */
89 /* S MXVSCL SCALING OF A VECTOR. */
91 /* EXTERNAL SUBROUTINES : */
92 /* SE OBJ COMPUTATION OF THE VALUE OF THE OBJECTIVE FUNCTION. */
93 /* CALLING SEQUENCE: CALL OBJ(NF,X,FF) WHERE NF IS THE NUMBER */
94 /* OF VARIABLES, X(NF) IS THE VECTOR OF VARIABLES AND FF IS */
95 /* THE VALUE OF THE OBJECTIVE FUNCTION. */
96 /* SE DOBJ COMPUTATION OF THE GRADIENT OF THE OBJECTIVE FUNCTION. */
97 /* CALLING SEQUENCE: CALL DOBJ(NF,X,GF) WHERE NF IS THE NUMBER */
98 /* OF VARIABLES, X(NF) IS THE VECTOR OF VARIABLES AND GF(NF) */
99 /* IS THE GRADIENT OF THE OBJECTIVE FUNCTION. */
100 /* -- OBJ and DOBJ are replaced by a single function, objgrad, in NLopt */
103 /* LIMITED MEMORY VARIABLE METRIC METHOD BASED ON THE STRANG */
106 static void plis_(int *nf, int *nb, double *x, int *
107 ix, double *xl, double *xu, double *gf, double *s,
108 double *xo, double *go, double *uo, double *vo,
109 double *xmax, double *tolx, double *tolf, double *
110 tolb, double *tolg, nlopt_stopping *stop,
111 double *minf_est, double *gmax,
112 double *f, int *mit, int *mfv, int *iest, int *mf,
113 int *iterm, stat_common *stat_1,
114 nlopt_func objgrad, void *objgrad_data)
116 /* System generated locals */
120 /* Builtin functions */
122 /* Local variables */
127 double fo, fp, po, pp, ro, rp;
130 double alf1, alf2, eta0, eta9, par1, par2;
131 int mes1, mes2, mes3;
133 int mred, iold, nred;
139 double rmin, rmax, umax, tolp, tols;
142 int iterd, mtesf, ntesf;
144 int iters, irest, inits, kters, maxst;
150 /* Parameter adjustments */
200 *minf_est = -HUGE_VAL; /* changed from -1e60 by SGJ */
215 *tolg = 1e-8; /* SGJ: was 1e-6, but this sometimes stops too soon */
218 /* removed by SGJ: this check prevented us from using minf_max <= 0,
219 which doesn't make sense. Instead, if you don't want to have a
220 lower limit, you should set minf_max = -HUGE_VAL */
222 *tolb = *minf_est + 1e-16;
228 /* changed by SGJ: default is no limit (INT_MAX) on # iterations/fevals */
238 kit = -(ires1 * *nf + ires2);
241 /* INITIAL OPERATIONS WITH SIMPLE BOUNDS */
245 for (i__ = 1; i__ <= i__1; ++i__) {
246 if ((ix[i__] == 3 || ix[i__] == 4) && xu[i__] <= xl[i__]) {
249 } else if (ix[i__] == 5 || ix[i__] == 6) {
256 luksan_pcbs04__(nf, &x[1], &ix[1], &xl[1], &xu[1], &eps9, &kbf);
257 luksan_pyadc0__(nf, &n, &x[1], &ix[1], &xl[1], &xu[1], &inew);
262 *f = objgrad(*nf, &x[1], &gf[1], objgrad_data);
265 if (nlopt_stop_time(stop)) { *iterm = 100; goto L11190; }
267 luksan_pytrcg__(nf, nf, &ix[1], &gf[1], &umax, gmax, &kbf, &iold);
268 luksan_pyfut1__(nf, f, &fo, &umax, gmax, xstop, stop, tolg,
269 &kd, &stat_1->nit, &kit, mit, &stat_1->nfg, &mfg,
270 &ntesx, &mtesx, &ntesf, &mtesf, &ites, &ires1, &ires2, &irest, &
275 if (nlopt_stop_time(stop)) { *iterm = 100; goto L11190; }
276 if (kbf > 0 && rmax > 0.) {
277 luksan_pyrmc0__(nf, &n, &ix[1], &gf[1], &eps8, &umax, gmax, &rmax, &
282 /* DIRECTION DETERMINATION */
284 gnorm = sqrt(luksan_mxudot__(nf, &gf[1], &gf[1], &ix[1], &kbf));
289 i__1 = stat_1->nit - kit;
292 irest = MAX2(irest,1);
296 /* DETERMINATION OF THE PARAMETER B */
298 b = luksan_mxudot__(nf, &xo[1], &go[1], &ix[1], &kbf);
300 irest = MAX2(irest,1);
304 luksan_mxuneg__(nf, &gf[1], &s[1], &ix[1], &kbf);
305 luksan_mxdrcb__(nf, &k, &xo[1], &go[1], &uo[1], &vo[1], &s[1], &ix[1], &
307 a = luksan_mxudot__(nf, &go[1], &go[1], &ix[1], &kbf);
310 luksan_mxvscl__(nf, &d__1, &s[1], &s[1]);
312 luksan_mxdrcf__(nf, &k, &xo[1], &go[1], &uo[1], &vo[1], &s[1], &ix[1], &
314 snorm = sqrt(luksan_mxudot__(nf, &s[1], &s[1], &ix[1], &kbf));
318 luksan_mxdrsu__(nf, &k, &xo[1], &go[1], &uo[1]);
323 /* STEEPEST DESCENT DIRECTION */
325 luksan_mxuneg__(nf, &gf[1], &s[1], &ix[1], &kbf);
327 if (kit < stat_1->nit) {
338 /* TEST ON DESCENT DIRECTION AND PREPARATION OF LINE SEARCH */
341 p = luksan_mxudot__(nf, &gf[1], &s[1], &ix[1], &kbf);
347 /* TEST ON DESCENT DIRECTION */
350 irest = MAX2(irest,1);
351 } else if (p + told * gnorm * snorm <= 0.) {
355 /* UNIFORM DESCENT CRITERION */
357 irest = MAX2(irest,1);
361 /* PREPARATION OF LINE SEARCH */
364 rmin = alf1 * gnorm / snorm;
366 d__1 = alf2 * gnorm / snorm, d__2 = *xmax / snorm;
367 rmax = MIN2(d__1,d__2);
373 if (nlopt_stop_time(stop)) { *iterm = 100; goto L11190; }
377 luksan_pytrcs__(nf, &x[1], &ix[1], &xo[1], &xl[1], &xu[1], &gf[1], &go[1],
378 &s[1], &ro, &fp, &fo, f, &po, &p, &rmax, &eta9, &kbf);
383 luksan_ps1l01__(&r__, &rp, f, &fo, &fp, &p, &po, &pp, minf_est, &maxf, &rmin,
384 &rmax, &tols, &tolp, &par1, &par2, &kd, &ld, &stat_1->nit, &kit, &
385 nred, &mred, &maxst, iest, &inits, &iters, &kters, &mes, &isys);
389 luksan_mxudir__(nf, &r__, &s[1], &xo[1], &x[1], &ix[1], &kbf);
390 luksan_pcbs04__(nf, &x[1], &ix[1], &xl[1], &xu[1], &eps9, &kbf);
391 *f = objgrad(*nf, &x[1], &gf[1], objgrad_data);
394 p = luksan_mxudot__(nf, &gf[1], &s[1], &ix[1], &kbf);
401 luksan_mxvcop__(nf, &xo[1], &x[1]);
402 luksan_mxvcop__(nf, &go[1], &gf[1]);
403 irest = MAX2(irest,1);
407 luksan_pytrcd__(nf, &x[1], &ix[1], &xo[1], &gf[1], &go[1], &r__, f, &fo, &
408 p, &po, &dmax__, &kbf, &kd, &ld, &iters);
409 xstop = nlopt_stop_dx(stop, &x[1], &xo[1]);
412 luksan_mxvine__(nf, &ix[1]);
413 luksan_pyadc0__(nf, &n, &x[1], &ix[1], &xl[1], &xu[1], &inew);
420 /* NLopt wrapper around plis_, handling dynamic allocation etc. */
421 nlopt_result luksan_plis(int n, nlopt_func f, void *f_data,
422 const double *lb, const double *ub, /* bounds */
423 double *x, /* in: initial guess, out: minimizer */
425 nlopt_stopping *stop)
428 double *work, *xl, *xu, *xo, *gf, *s, *go, *uo, *vo;
429 double gmax, minf_est;
430 double xmax = 0; /* no maximum */
431 double tolg = 0; /* default gradient tolerance */
432 int iest = 0; /* we have no estimate of min function value */
433 int mit = 0; /* default no limit on #iterations */
434 int mfv = stop->maxeval;
439 ix = (int*) malloc(sizeof(int) * n);
440 if (!ix) return NLOPT_OUT_OF_MEMORY;
442 /* FIXME: what should we set mf to? The example program tlis.for
443 sets it to zero as far as I can tell, but it seems to greatly
444 improve convergence to make it > 0. The computation time
445 per iteration, and of course the memory, seem to go as O(n * mf),
446 and we'll assume that the main limiting factor is the memory.
447 We'll assume that at least MEMAVAIL memory, or 4*n memory, whichever
448 is bigger, is available. */
449 mf = MAX2(MEMAVAIL/n, 4);
450 if (stop->maxeval && stop->maxeval <= mf)
451 mf = MAX2(stop->maxeval - 5, 1); /* mf > maxeval seems not good */
454 work = (double*) malloc(sizeof(double) * (n * 4 + MAX2(n,n*mf)*2 +
458 mf = 0; /* allocate minimal memory */
462 return NLOPT_OUT_OF_MEMORY;
465 xl = work; xu = xl + n; gf = xu + n; s = gf + n;
466 xo = s + n; go = xo + MAX2(n,n*mf);
467 uo = go + MAX2(n,n*mf); vo = uo + MAX2(n,mf);
469 for (i = 0; i < n; ++i) {
470 int lbu = lb[i] <= -0.99 * HUGE_VAL; /* lb unbounded */
471 int ubu = ub[i] >= 0.99 * HUGE_VAL; /* ub unbounded */
472 ix[i] = lbu ? (ubu ? 0 : 2) : (ubu ? 1 : (lb[i] == ub[i] ? 5 : 3));
477 /* ? xo does not seem to be initialized in the
478 original Fortran code, but it is used upon
479 input to plis if mf > 0 ... perhaps ALLOCATE initializes
480 arrays to zero by default? */
481 memset(xo, 0, sizeof(double) * MAX2(n,n*mf));
483 plis_(&n, &nb, x, ix, xl, xu,
484 gf, s, xo, go, uo, vo,
487 /* fixme: pass tol_rel and tol_abs and use NLopt check */
506 case 1: return NLOPT_XTOL_REACHED;
507 case 2: return NLOPT_FTOL_REACHED;
508 case 3: return NLOPT_MINF_MAX_REACHED;
509 case 4: return NLOPT_SUCCESS; /* gradient tolerance reached */
510 case 6: return NLOPT_SUCCESS;
511 case 12: case 13: return NLOPT_MAXEVAL_REACHED;
512 case 100: return NLOPT_MAXTIME_REACHED;
513 case -999: return NLOPT_FORCED_STOP;
514 default: return NLOPT_FAILURE;