TPCCLIB
Loading...
Searching...
No Matches
bvls.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <math.h>
13/*****************************************************************************/
14#include "tpcextensions.h"
15/*****************************************************************************/
16#include "tpclinopt.h"
17/*****************************************************************************/
18
19/*****************************************************************************/
32int bvls(
38 int key,
40 const /*unsigned*/ int m,
43 const /*unsigned*/ int n,
47 double *a,
50 double *b,
52 double *bl,
54 double *bu,
56 double *x,
59 double *w,
61 double *act,
63 double *zz,
71 int *istate,
75 int *iter,
77 int verbose
78) {
79 if(verbose>0) {printf("bvls(%d, %d, %d, ...)\n", key, m, n); fflush(stdout);}
80 /* Check the input */
81 if(a==NULL || b==NULL || bl==NULL || bu==NULL || x==NULL || w==NULL ||
82 act==NULL || zz==NULL || istate==NULL || iter==NULL || n<1 || m<1)
83 {
84 if(verbose>0) fprintf(stderr, "Error: invalid input to BVLS.\n");
85 return(1);
86 }
87
88 int maxIter=*iter; if(maxIter<3) maxIter=3*n;
89 *iter=0;
90 const double eps=1.0E-13; // stopping rule
91
92 /* Step 1. Initialize everything -- active and bound sets, initial values, etc. */
93 if(verbose>1) {printf("step 1\n"); fflush(stdout);}
94
95 /* Set mm to the smaller of matrix dimensions n and m. */
96 int mm; if(m<n) mm=m; else mm=n;
97 int aindx=0; // one-based index of X[] that determined the alpha; zero means not set.
98 int aindxsign=0; // +1 if zz[aindx]> bu[aindx], -1 if zz[aindx]<bl[aindx]
99 /* istateFromStep5 is the one-based index of the parameter that most wants to be active;
100 zero value means its is currently not set. */
101 int istateFromStep5 = 0;
102
103 /* Check the consistency of given bounds bl[] and bu[]. */
104 {
105 double maxrange=0.0;
106 for(int ni=0; ni<n; ni++) {
107 double d=bu[ni]-bl[ni];
108 if(verbose>3) printf(" bounds[%d]: %g %g\n", 1+ni, bl[ni], bu[ni]);
109 if(d<0.0) {
110 if(verbose>0) fprintf(stderr, "Error: inconsistent bounds in BVLS.\n");
111 return(1);
112 }
113 maxrange=fmax(maxrange, d);
114 }
115 if(verbose>2) printf(" maxrange := %g\n", maxrange);
116 if(maxrange<1.0E-10) {
117 if(verbose>0) fprintf(stderr, "Error: no free variables in BVLS.\n");
118 return(1);
119 }
120 }
121
122 /* In a fresh initialization (key=0), bind all variables at their lower bounds.
123 If key<>0, use the supplied istate[] array to initialize the variables. */
124 int nbound, nact; // number of bound and active parameters, respectively.
125 if(key==0) {
126 nbound=n;
127 /* Write the indices; negative sign indicates lower limit */
128 /* Note that these indices must start from 1, because 0 can not have sign */
129 for(int ni=0; ni<nbound; ni++) istate[ni]=-(1+ni);
130 } else {
131 nbound=istate[n];
132 }
133 nact=n-nbound;
134 if(nact>mm) {
135 if(verbose>0) fprintf(stderr, "Error: too many active variables in BVLS starting solution.\n");
136 return(2);
137 }
138 for(int ni=0; ni<nbound; ni++) {
139 int i=abs(istate[ni])-1;
140 if(istate[ni]<0) x[i]=bl[i]; else x[i]=bu[i];
141 }
142
143 /* In a warm start (key<>0, and nbound<n) initialize the active variables to the mean of
144 their bounds. This is needed in case the initial QR results in active variables
145 out-of-bounds and Steps 8-11 get executed the first time through. */
146 for(int ni=nbound; ni<n; ni++) {
147 int i=abs(istate[ni])-1; // indices of active variables should not have signs, but let's be sure
148 x[i]=0.5*(bl[i]+bu[i]);
149 }
150
151 /* Compute bnorm, the norm of the data vector b, for reference. */
152 double bnorm=0.0;
153 for(int mi=0; mi<m; mi++) bnorm+=b[mi]*b[mi];
154 bnorm=sqrt(bnorm); if(verbose>2) printf(" initial_bnorm := %g\n", bnorm);
155
156
157 /*
158 * Main loop
159 */
160 int skipStep2=0;
161 double obj=0.0;
162 int iact=0; // The component x[iact] is the one that most wants to become active
163
164 for(*iter=1; *iter<=maxIter; ++(*iter)) {
165
166 if(verbose>1) {printf("iteration %d\n", *iter); fflush(stdout);}
167
168 if(!skipStep2) {
169 /* Step 2. */ if(verbose>1) {printf(" step 2\n"); fflush(stdout);}
170
171 /* Initialize the negative gradient vector w(*). */
172 for(int ni=0; ni<n; ni++) w[ni]=0.0;
173
174 /* Compute the residual vector b-a.x , the negative gradient vector w[*], and
175 the current objective value obj = || a.x - b ||.
176 The residual vector is stored in the mm+1'st column of act[*,*]. */
177 obj=0.0;
178 for(int mi=0; mi<m; mi++) {
179 double ri=b[mi];
180 for(int ni=0; ni<n; ni++) ri-=a[mi+ni*m]*x[ni];
181 obj+=ri*ri;
182 for(int ni=0; ni<n; ni++) w[ni]+=a[mi+ni*m]*ri;
183 act[mi+mm*m]=ri;
184 }
185 if(verbose>3) {printf(" obj := %g\n", obj); fflush(stdout);}
186
187 /* Converged? Stop if the misfit << || b ||, or if all components are active
188 (unless this is the first iteration from a 'warm start'). */
189 if((sqrt(obj)<=bnorm*eps) || ((*iter)>1 && nbound==0)) {
190 if(verbose>1) {printf("bvls converged.\n"); fflush(stdout);}
191 istate[n]=nbound;
192 w[0]=sqrt(obj);
193 return(0);
194 }
195
196 /* Add the contribution of the active components back into the residual. */
197 for(int ni=nbound; ni<n; ni++) {
198 int i=abs(istate[ni])-1;
199 for(int mi=0; mi<m; mi++) act[mi+mm*m] += a[mi+i*m]*x[i];
200 }
201 if(verbose>9) {
202 printf("Residual vector:\n");
203 for(int mi=0; mi<m; mi++) printf("\t%g", act[mi+mm*m]);
204 printf("\n");
205 }
206
207 }
208
209
210
211 /* The first iteration in a 'warm start' requires immediate QR in Step 6
212 but mostly we want go through Steps 3-5 first . */
213 if(key!=0 && (*iter)==1) {
214 if(verbose>1) printf(" 'warm start' requires immediate QR in Step 6\n");
215 } else {
216
217 int it; // variable indicating the element in istate that most wants to be active
218
219 do {
220 /* Steps 3, 4. */ if(verbose>1) {printf(" steps 3 and 4\n"); fflush(stdout);}
221 /* Find the bound element that most wants to be active. */
222 double worst=0.0;
223 it=1;
224 for(int ni=0; ni<nbound; ni++) {
225 int i=abs(istate[ni])-1;
226 double bad; if(istate[ni] < 0) bad=-w[i]; else bad=+w[i];
227 if(bad < worst) { it=ni+1; worst=bad; iact=i; }
228 }
229
230 /* Test whether the Kuhn-Tucker condition is met. */
231 if(worst>=0.0) {
232 if(verbose>1) {printf("Kuhn-Tucker condition is met.\n"); fflush(stdout);}
233 istate[n]=nbound;
234 w[0]=sqrt(obj);
235 return(0);
236 }
237
238 /* The component x[iact] is the one that most wants to become active.
239 If the last successful change in the active set was to move x[iact] to a bound,
240 don't let x[iact] in now: set the derivative of the misfit with respect to x[iact]
241 to zero and return to the Kuhn-Tucker test. */
242 if(iact==(aindx-1)) w[aindx-1]=0.0;
243 } while(iact==(aindx-1)); // Step 3 again
244
245 /* Step 5. */ if(verbose>1) {printf(" step 5\n"); fflush(stdout);}
246
247 /* Undo the effect of the new (potentially) active variable on the residual vector. */
248 if(istate[it-1]==0) { // remove this if never happening
249 if(verbose>0) fprintf(stderr, "Error: BVLS istate is zero!\n");
250 return(1);
251 }
252 {
253 double bnd;
254 if(istate[it-1]>0) bnd=bu[iact]; else bnd=bl[iact];
255 for(int mi=0; mi<m; mi++) act[mi+mm*m]+=bnd*a[mi+iact*m];
256 }
257
258 /* Set flag istateFromStep5, indicating that Step 6 was entered from Step 5.
259 This forms the basis of a test for instability: the gradient calculation shows that x[iact]
260 wants to join the active set; if QR puts x[iact] beyond the bound from which it came,
261 the gradient calculation was in error and the variable should not have been introduced. */
262 istateFromStep5=istate[it-1];
263
264 /* Swap the indices (in istate) of the new active variable and the rightmost bound variable;
265 `unbind' that location by decrementing nbound. */
266 istate[it-1]=istate[nbound-1];
267 nbound--; nact++;
268 istate[nbound]=1+iact;
269 if(mm<nact) {
270 if(verbose>0) fprintf(stderr, "Error: too many free variables in BVLS.\n");
271 return(2);
272 }
273
274 } // finalized steps 3-5
275
276 do {
277
278 skipStep2=0;
279
280 /* Step 6. */ if(verbose>1) {printf(" step 6\n"); fflush(stdout);}
281
282 /* Load array act with the appropriate columns of A for QR. For added stability, reverse
283 the column ordering so that the most recent addition to the active set is in the last
284 column. Also copy the residual vector from act[., mm] into act[., mm+1]. */
285 for(int mi=0; mi<m; mi++) {
286 act[mi+(mm+1)*m]=act[mi+mm*m]; // vector b for QR
287 for(int ni=nbound; ni<n; ni++) {
288 int i=abs(istate[ni])-1;
289 act[mi+(nact+nbound-ni-1)*m]=a[mi+i*m];
290 }
291 }
292 if(verbose>9) {
293 printf("Matrix A for QR:\n");
294 for(int ni=0; ni<nact; ni++) {
295 for(int mi=0; mi<m; mi++) printf("\t%g", act[mi+ni*nact]);
296 printf("\n");
297 }
298 printf("Vector B for QR:\n");
299 for(int mi=0; mi<m; mi++) printf("\t%g", act[(mm+1)*m + mi]);
300 printf("\n");
301 }
302
303 /* Test for linear dependence in QR, and for an instability that moves the variable
304 just introduced away from the feasible region (rather than into the region or
305 all the way through it). In either case, remove the latest vector introduced from
306 the active set and adjust the residual vector accordingly.
307 Set the gradient component (w[iact]) to zero and return to the Kuhn-Tucker test. */
308 double r2;
309 if(qrLH(m, nact, act, &act[(mm+1)*m], zz, &r2) !=0 ||
310 (istateFromStep5>0 && zz[nact-1]>bu[iact]) ||
311 (istateFromStep5<0 && zz[nact-1]<bl[iact]) )
312 {
313 nbound++;
314 if(bu[iact]>x[iact]) istate[nbound-1]=-istate[nbound-1];
315 nact--;
316 for(int mi=0; mi<m; mi++) act[mi+mm*m]-=x[iact]*a[mi+iact*m];
317 istateFromStep5 = 0; // not from step 5
318 w[iact]=0.0;
319 skipStep2=1; // we want to skip Step 2 and go directly to Step 3
320 if(verbose>3) {printf(" going from step 6 to step 3\n"); fflush(stdout);}
321 break; // go to step 3
322 }
323
324 /* If Step 6 was entered from Step 5 and we are here, a new variable has been successfully
325 introduced into the active set; the last variable that was fixed at a bound is again
326 permitted to become active. */
327 if(istateFromStep5!=0) aindx=0;
328 istateFromStep5=0;
329
330 /* Step 7. */ if(verbose>1) {printf(" step 7\n"); fflush(stdout);}
331 /* Check for strict feasibility of the new QR solution. */
332 int qr_solution_feasible=1;
333 int indexHolder=0;
334 if(verbose>8) printf(" nact=%d nbound=%d\n", nact, nbound);
335 for(int ni=0; ni<nact; ni++) {
336 indexHolder=ni; // Loop in step 8 will start from this
337 int i=abs(istate[ni+nbound])-1;
338 if(verbose>8) {
339 printf(" istate[%d]=%d\n", ni+nbound, 1+i);
340 printf(" zz[%d]=%g bl[%d]=%g bu[%d]=%g\n", nact-ni-1, zz[nact-ni-1], i, bl[i], i, bu[i]);
341 }
342 if(zz[nact-ni-1]<bl[i] || zz[nact-ni-1]>bu[i]) {
343 if(verbose>3) {printf(" new iterate is not feasible\n"); fflush(stdout);}
344 qr_solution_feasible=0; break; // go to Step 8
345 }
346 }
347 if(verbose>8) printf(" indexHolder=%d\n", indexHolder);
348 if(qr_solution_feasible) {
349 if(verbose>3) {printf(" new iterate is feasible\n"); fflush(stdout);}
350 for(int ni=0; ni<nact; ni++) {
351 int i=abs(istate[ni+nbound])-1;
352 x[i]=zz[nact-ni-1];
353 }
354 /* New iterate is feasible; back to the top. */
355 break; // Back to the start of the main loop
356 }
357
358 { // keep local variables alpha and alf local
359 double alpha=2.0;
360 /* Steps 8 and 9 */ if(verbose>1) {printf(" steps 8 and 9\n"); fflush(stdout);}
361 double alf=alpha;
362 for(int ni=indexHolder; ni<nact; ni++) {
363 int i=abs(istate[ni+nbound])-1;
364 if(zz[nact-ni-1] > bu[i]) alf=(bu[i]-x[i])/(zz[nact-ni-1]-x[i]);
365 if(zz[nact-ni-1] < bl[i]) alf=(bl[i]-x[i])/(zz[nact-ni-1]-x[i]);
366 if(alf<alpha) {
367 alpha=alf;
368 aindx=1+i;
369 if((zz[nact-ni-1]-bl[i])<0.0) aindxsign=-1; else aindxsign=+1;
370 }
371 }
372 /* Step 10 */ if(verbose>1) {printf(" step 10\n"); fflush(stdout);}
373 for(int ni=0; ni<nact; ni++) {
374 int i=abs(istate[ni+nbound])-1;
375 x[i]+=alpha*(zz[nact-ni-1]-x[i]);
376 }
377 }
378
379 /* Step 11 */ if(verbose>1) {printf(" step 11\n"); fflush(stdout);}
380 /* Move the variable that determined alpha to the appropriate bound
381 (aindx is its index; sj is + if zz[aindx]> bu[aindx], - if zz[aindx]<bl[aindx] ).
382 If any other component of x is infeasible at this stage, it must be due to round-off.
383 Bind every infeasible component and every component at a bound to the appropriate bound.
384 Correct the residual vector for any variables moved to bounds. Since at least one
385 variable is removed from the active set in this step, Loop B
386 (Steps 6-11) terminates after at most nact steps. */
387 {
388 int noldb=nbound;
389 for(int ni=0; ni<nact; ni++) {
390 int i=abs(istate[ni+noldb])-1;
391 if((bu[i]-x[i]<=0.0) || (i==(aindx-1) && aindxsign>0)) {
392 /* Move x[i] to its upper bound. */
393 x[i]=bu[i];
394 istate[ni+noldb]=istate[nbound]; istate[nbound]=+(1+i); nbound++;
395 for(int mi=0; mi<m; mi++) act[mi+mm*m]-=bu[i]*a[mi+i*m];
396 } else if( ((x[i]-bl[i])<=0.0) || (i==(aindx-1) && aindxsign<0)) {
397 /* Move x(j) to its lower bound. */
398 x[i]=bl[i];
399 istate[ni+noldb]=istate[nbound]; istate[nbound]=-(1+i); nbound++;
400 for(int mi=0; mi<m; mi++) act[mi+mm*m]-=bl[i]*a[mi+i*m];
401 }
402 }
403 nact=n-nbound;
404 }
405 /* If there are still active variables left, repeat the QR; if not, go back to step 6. */
406 } while(nact>0);
407
408 } // main loop
409
410 /* iterMax reached */
411 if(verbose>0) fprintf(stderr, "Error: BVLS fails to converge.\n");
412 return(-1);
413}
414/*****************************************************************************/
415
416/*****************************************************************************/
427 int N,
429 int M,
431 double **A,
433 double *a,
435 double *b,
437 double *weight
438) {
439 int n, m;
440 double *w;
441
442 /* Check the arguments */
443 if(N<1 || M<1 || (A==NULL && a==NULL) || b==NULL || weight==NULL) return(1);
444
445 /* Allocate memory */
446 w=(double*)malloc(M*sizeof(double)); if(w==NULL) return(2);
447
448 /* Check that weights are not zero and get the square roots of them to w[] */
449 for(m=0; m<M; m++) {
450 if(weight[m]<=1.0e-20) w[m]=0.0;
451 else w[m]=sqrt(weight[m]);
452 }
453
454 /* Multiply rows of matrix A and elements of vector b with weights*/
455 for(m=0; m<M; m++) {
456 for(n=0; n<N; n++) {
457 if(A!=NULL) A[n][m]*=w[m];
458 if(a!=NULL) a[m+n*M]*=w[m];
459 }
460 b[m]*=w[m];
461 }
462
463 free(w);
464 return(0);
465}
466/*****************************************************************************/
467
468/*****************************************************************************/
482 int N,
484 int M,
486 double **A,
488 double *a,
490 double *b,
492 double *sweight
493) {
494 int n, m;
495
496 /* Check the arguments */
497 if(N<1 || M<1 || (A==NULL && a==NULL) || b==NULL || sweight==NULL) return(1);
498
499 /* Multiply rows of matrix A and elements of vector b with weights*/
500 for(m=0; m<M; m++) {
501 for(n=0; n<N; n++) {
502 if(A!=NULL) A[n][m]*=sweight[m];
503 if(a!=NULL) a[m+n*M]*=sweight[m];
504 }
505 b[m]*=sweight[m];
506 }
507
508 return(0);
509}
510/*****************************************************************************/
511
512/*****************************************************************************/
int bvls(int key, const int m, const int n, double *a, double *b, double *bl, double *bu, double *x, double *w, double *act, double *zz, int *istate, int *iter, int verbose)
Bounded-value least-squares method to solve the linear problem A x ~ b , subject to limit1 <= x <= li...
Definition bvls.c:32
int llsqWght(int N, int M, double **A, double *a, double *b, double *weight)
Definition bvls.c:425
int llsqWghtSquared(int N, int M, double **A, double *a, double *b, double *sweight)
Definition bvls.c:480
int qrLH(const unsigned int m, const unsigned int n, double *a, double *b, double *x, double *r2)
Solve over-determined least-squares problem A x ~ b using successive Householder rotations.
Definition qrlsq.c:946
Header file for library libtpcextensions.
Header file for libtpclinopt.