BCLS: Bound Constrained Least Squares

Version 0.1

bclib.c

Go to the documentation of this file.
00001 /* bclib.c
00002    $Revision: 285 $ $Date: 2006-12-20 09:33:50 -0800 (Wed, 20 Dec 2006) $
00003 
00004    ----------------------------------------------------------------------
00005    This file is part of BCLS (Bound-Constrained Least Squares).
00006 
00007    Copyright (C) 2006 Michael P. Friedlander, Department of Computer
00008    Science, University of British Columbia, Canada. All rights
00009    reserved. E-mail: <mpf@cs.ubc.ca>.
00010    
00011    BCLS is free software; you can redistribute it and/or modify it
00012    under the terms of the GNU Lesser General Public License as
00013    published by the Free Software Foundation; either version 2.1 of the
00014    License, or (at your option) any later version.
00015    
00016    BCLS is distributed in the hope that it will be useful, but WITHOUT
00017    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00018    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
00019    Public License for more details.
00020    
00021    You should have received a copy of the GNU Lesser General Public
00022    License along with BCLS; if not, write to the Free Software
00023    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
00024    USA
00025    ----------------------------------------------------------------------
00026 */
00032 #include <math.h>
00033 #include <stdarg.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <stdio.h>
00037 #include <assert.h>
00038 #include <float.h>
00039 #include <setjmp.h>
00040 
00041 #include "bclib.h"
00042 
00059 void
00060 bcls_project_step( int n, double s[], double step, double x[],
00061                    double dx[], double bl[], double bu[] )
00062 {
00063     int j;
00064     double xpj;
00065 
00066     for (j = 0; j < n; j++) {
00067 
00068         xpj = x[j] + step*dx[j];
00069 
00070         if ( xpj < bl[j] )
00071             s[j] = bl[j] - x[j];
00072         
00073         else if ( xpj > bu[j] )
00074             s[j] = bu[j] - x[j];
00075         
00076         else
00077             s[j] = step * dx[j];
00078     }
00079     return;
00080 }
00081 
00099 int
00100 bcls_examine_bnds( BCLS *ls, const int n, double bl[], double bu[] )
00101 {
00102     int j, jopen;
00103     double blj, buj;
00104     const double bigL = - ls->BigNum;
00105     const double bigU =   ls->BigNum;
00106     const double epsfixed = ls->epsfixed;
00107 
00108     // Variable-type counts.  No. of variables that
00109     int neql = 0; // are "open" (have an interior)
00110     int nfix = 0; // are fixed
00111     int nneg = 0; // are unbounded below
00112     int npos = 0; // are unbounded above
00113     int nlow = 0; // have a finite lower bound
00114     int nupp = 0; // have a finite upper bound
00115     int nnrm = 0; // have finite lower and upper bounds
00116     int nfre = 0; // are free.
00117 
00118     for (j = 0; j < n; j++) {
00119         jopen = 0;
00120         blj   = bl[j];
00121         buj   = bu[j];
00122         
00123         if (buj < blj)                  // Infeasible interval.  Exit.
00124             goto infeas;
00125         
00126         else if (buj - blj <= epsfixed) // Fixed variable.
00127             nfix++;
00128 
00129         else {                          // Open interval.
00130             neql++;
00131             jopen = 1;
00132         }
00133 
00134         if     (blj <= bigL  &&  buj == 0            ) nneg++;
00135         if     (blj == 0     &&  buj >= bigU         ) npos++;
00136         if     (blj >  bigL                  && jopen) nlow++;
00137         if     (                 buj <  bigU && jopen) nupp++;
00138         if     (blj >  bigL  &&  buj <  bigU         ) nnrm++;
00139         if     (blj <= bigL  &&  buj >= bigU         ) nfre++;
00140     }
00141     
00142     ls->unconstrained = nfre == n;
00143 
00144     PRINT1("\n Bounds:");
00145     if (ls->unconstrained) {
00146         PRINT1(" problem is unconstrained\n");
00147     }
00148     else {
00149         PRINT1("\n   [-inf,0]    [0,inf]  Finite bl  Finite bu  "
00150                " Two bnds      Fixed       Free\n");
00151         PRINT1("  %9d  %9d  %9d  %9d  %9d  %9d  %9d\n",
00152                nneg, npos, nlow, nupp, nnrm, nfix, nfre );
00153     }
00154 
00155     return 0;
00156 
00157  infeas:
00158     PRINT1(" Infeasible problem: bl[%d] = %10.2e > %10.2e bu[%d]\n",
00159            j, blj, buj, j);
00160 
00161     return BCLS_EXIT_INFEA;
00162 }
00163 
00174 void
00175 bcls_print_params( BCLS *ls )
00176 {
00177     PRINT2("\n");
00178     PRINT2(" Parameters:\n");
00179     PRINT2("  Rows............. %8d\t",   ls->m);
00180     PRINT2("  Columns.......... %8d\n",   ls->n);
00181     PRINT2("  Optimality tol... %8.1e\t", ls->optTol);
00182     PRINT2("  Major itn limit.. %8d\n",   ls->itnMajLim);
00183     PRINT2("  Damp............. %8.1e\t", ls->damp);
00184     PRINT2("  Minor itn limit.. %8d\n",   ls->itnMinLim);
00185     PRINT2("  Linsearch type... %8s\t", 
00186            ls->proj_search == BCLS_PROJ_SEARCH_APPROX
00187            ? "approx" : "exact");
00188     PRINT2("  Linear term...... %8s\n",
00189            ls->c == NULL ? "no" : "yes" );
00190     PRINT2("  Newton step...... %8s\t",
00191            ls->newton_step == BCLS_NEWTON_STEP_LSQR
00192            ? "lsqr" : "cgls");
00193     PRINT2("  Gradient step.... %8s\n",
00194            ls->anorm == NULL
00195            ? "unscaled" : "scaled");
00196     PRINT2("  Preconditoner.... %8s\n",
00197            ls->Usolve == NULL
00198            ? "no" : "yes");
00199 
00200     return;
00201 }
00202 
00211 void
00212 bcls_examine_column_scales( BCLS *ls, double anorm[] )
00213 {
00214     int j;
00215     int    minj;     // Index of the column with the minimum col scale.
00216     int    maxj;     // ............................ maximum col scale.
00217     double minnorm;  // The value of the minimum             col scale.
00218     double maxnorm;  // ........................             col scale.
00219 
00220     if ( anorm == NULL ) return;
00221     if ( ls->print_level < 2 ) return;
00222 
00223     minnorm = 1.0e20;
00224     maxnorm = 0.0;
00225 
00226     for (j = 0; j < ls->n; j++) {
00227         if ( minnorm > anorm[j] ) { minnorm = anorm[j]; minj = j; };
00228         if ( maxnorm < anorm[j] ) { maxnorm = anorm[j]; maxj = j; };
00229     }
00230     PRINT2( "\n" );
00231     PRINT2( " Column scales:  %6s   %7s\n", "column", "norm" );
00232     PRINT2( "       minimum   %6d   %7.1e\n", minj, minnorm  );
00233     PRINT2( "       maximum   %6d   %7.1e\n", maxj, maxnorm  );
00234 
00235     return;
00236 }
00237 
00252 void
00253 bcls_print( BCLS *ls, int current_print_level, char *fmt, ...)
00254 { 
00255     va_list arg;
00256     char msg[4095+1];
00257 
00258     // Exit immediately if the current print level is too low.
00259     if ( ls->print_level < current_print_level )
00260         return;
00261 
00262     // Format the message.
00263     va_start(arg, fmt);
00264     vsprintf(msg, fmt, arg);
00265     assert(strlen(msg) <= 4095);
00266     va_end(arg);
00267     
00268     // Pass the message to the user-defined hook routine.
00269     if (ls->print_hook != NULL && ls->print_hook(ls->print_info, msg) == 0)
00270         return;
00271 
00272     // Othwerise, send the message to the standard output */
00273       fprintf(stdout, "%s", msg);
00274 
00275       return;
00276 }
00277 
00290 void
00291 bcls_fault( BCLS *ls, char *fmt, ...)
00292 { 
00293     va_list arg;
00294     char msg[4095+1];
00295 
00296     // Format the message.
00297     va_start(arg, fmt);
00298     vsprintf(msg, fmt, arg);
00299     assert(strlen(msg) <= 4095);
00300     va_end(arg);
00301     
00302     // Pass the message to the user-defined hook routine.
00303     if (ls->fault_hook != NULL &&
00304         ls->fault_hook(ls->fault_info, msg) == 0) goto skip;
00305 
00306     // Othwerise, send the message to the standard output */
00307       fprintf(stderr, "%s\n", msg);
00308 
00309  skip:
00310       // return to the calling program.
00311       exit(EXIT_FAILURE);     
00312 }
00313 
00333 int
00334 bcls_primal_inf( int n, double x[], double bl[], double bu[],
00335                  double *pInf, int *jpInf )
00336 {
00337     int j;
00338     double pj = 0;
00339     double blj, buj, xj;
00340 
00341     *pInf  = 0.0;
00342     *jpInf = -1;
00343     
00344     for (j = 0; j < n; j++) {
00345         blj = bl[j];
00346         buj = bu[j];
00347         xj  =  x[j];
00348         if ( xj > buj )
00349             pj = xj - buj;
00350         else if ( blj > xj )
00351             pj = blj - xj;
00352         
00353         if (*pInf  < pj ) {
00354             *pInf  = pj;
00355             *jpInf = j;
00356         }
00357         
00358     }
00359 
00360     return *pInf > DBL_EPSILON;
00361 }
00362 
00382 void
00383 bcls_dual_inf( int n, double x[], double z[], double bl[], double bu[],
00384                double *dInf, int *jInf )
00385 {
00386     int    j;
00387     double dj, blj, buj;
00388 
00389     *dInf = 0.0;
00390     *jInf = 0;
00391    
00392     for (j = 0; j < n; j++) {
00393         blj = bl[j];
00394         buj = bu[j];
00395         if (blj < buj) {
00396             dj  = z[j];
00397             if      (dj > 0)
00398                 dj =   dj * fmin( x[j] - blj, 1.0 );
00399             else if (dj < 0)
00400                 dj = - dj * fmin( buj - x[j], 1.0 );
00401      
00402             if (*dInf  < dj) {
00403                 *dInf  = dj;
00404                 *jInf  = j;
00405             }
00406         }
00407     }
00408 
00409     return;
00410 }
00411 
00424 void
00425 bcls_mid( int n, double x[], double bl[], double bu[] )
00426 {    
00427     int j;
00428 
00429     for (j = 0; j < n; j++ ) {
00430         if      ( x[j] < bl[j] ) x[j] = bl[j];
00431         else if ( x[j] > bu[j] ) x[j] = bu[j];
00432     }
00433     return;
00434 }
00435 
00452 void
00453 bcls_aprod( BCLS *ls, int mode, int nix,
00454             int ix[], double x[], double y[] )
00455 {    
00456     // Increase the mat-vec counters, unless this is an initialization
00457     // or de-initialization call.
00458     if (mode == BCLS_PROD_INIT ||
00459         mode == BCLS_PROD_TERM )
00460         ;// Relax.
00461     else {
00462         if      (nix == 1    ) ls->nAprod1++;
00463         else if (nix  < ls->n) ls->nAprodF++;
00464                                ls->nAprodT++;
00465     }
00466 
00467     // Call the user's routine.
00468     bcls_timer( &(ls->stopwatch[BCLS_TIMER_APROD]), BCLS_TIMER_START );
00469 
00470     int err = ls->Aprod( mode, ls->m, ls->n, nix, ix, x, y, ls->UsrWrk );
00471 
00472     bcls_timer( &(ls->stopwatch[BCLS_TIMER_APROD]), BCLS_TIMER_STOP );
00473 
00474     // Return to top of BCLS's stack if error is signaled.
00475     if (err)
00476         longjmp(ls->jmp_env, BCLS_EXIT_APROD);
00477     return;
00478 }
00479 
00496 void
00497 bcls_usolve( BCLS *ls, int mode, int nix,
00498              int ix[], double v[], double w[] )
00499 {    
00500     // Increase the counters only for actual solves.
00501     if (mode == BCLS_PRECON_U  ||  mode == BCLS_PRECON_Ut )
00502         ls->nUsolve++;
00503 
00504     // Call the user's routine.
00505     bcls_timer( &(ls->stopwatch[BCLS_TIMER_USOLVE]), BCLS_TIMER_START );
00506 
00507     int err = ls->Usolve( mode, ls->m, ls->n, nix, ix, v, w, ls->UsrWrk );
00508 
00509     bcls_timer( &(ls->stopwatch[BCLS_TIMER_USOLVE]), BCLS_TIMER_STOP );
00510 
00511     // Return to top of BCLS's stack if error is signaled.
00512     if (err)
00513         longjmp(ls->jmp_env, BCLS_EXIT_USOLVE);
00514     return;
00515 }
00516 
00532 int
00533 bcls_callback( BCLS *ls )
00534 {    
00535     if ( ls->CallBack )
00536         return ls->CallBack( ls, ls->UsrWrk );
00537     else
00538         return 0;
00539 }
00540 
00568 int
00569 bcls_free_vars( BCLS *ls, int n, int ix[], double x[], 
00570                 double g[], double bl[], double bu[] )
00571 {
00572     int j;
00573     int nFree = 0;
00574     int low, upp, inc, dec;
00575     const double epsx = ls->epsx;
00576     const double eps  = ls->eps;
00577 
00578     for (j = 0; j < n; j++) {
00579 
00580         low  = x[j]  - bl[j]  <  epsx;
00581         upp  = bu[j] -  x[j]  <  epsx;
00582 
00583         inc  = g[j]  <  eps;
00584         dec  = g[j]  >  eps;
00585 
00586         if      ( low )
00587             ; // Relax -- lower bound binding.
00588         else if ( upp )
00589             ; // Relax -- upper bound binding.
00590         else {
00591               // Var is free to move.
00592             ix[nFree] = j;
00593             nFree++;
00594         }
00595     }
00596     return nFree;
00597 }
00598 
00618 int
00619 bcls_heap_del_min( int numElems, double x[], int ix[] )
00620 {
00621     assert(numElems > 0);
00622     
00623     int lastChild = numElems - 1;
00624 
00625     // Swap the smallest element with the lastChild.
00626     bcls_dswap(  x[0],  x[lastChild] );
00627     bcls_iswap( ix[0], ix[lastChild] );
00628 
00629     // Contract the heap size, thereby discarding the smallest element.
00630     lastChild--;
00631     
00632     // Restore the heap property of the contracted heap.
00633     bcls_heap_sift( 0, lastChild, x, ix );
00634 
00635     return numElems - 1;
00636 }
00637 
00656 void
00657 bcls_heap_sift( int root, int lastChild, double x[], int ix[] )
00658 {
00659     int child;
00660 
00661     for (; (child = (root * 2) + 1) <= lastChild; root = child) {
00662 
00663         if (child < lastChild)
00664             if ( x[child] > x[child+1] )
00665                 child++;
00666         
00667         if ( x[child] >= x[root] )
00668             break;
00669 
00670         bcls_iswap( ix[root], ix[child] );
00671         bcls_dswap(  x[root],  x[child] );
00672     }
00673     return;
00674 }
00675 
00685 void
00686 bcls_heap_build( int n, double x[], int ix[] )
00687 {    
00688     int i;
00689 
00690     for (i = n/2; i >= 0; i--)
00691         bcls_heap_sift( i, n-1, x, ix );
00692 
00693     return;
00694 }
00695 
00707 double
00708 bcls_vec_dnorm2( int nix, int ix[], double x[] )
00709 {    
00710     int j, k;
00711     double norm = 0.0;
00712     
00713     for (j = 0; j < nix; j++) {
00714         k     = ix[j];
00715         norm +=  x[k] * x[k];
00716     }
00717     norm = sqrt(norm);
00718     
00719     return norm;
00720 }
00721 
00735 void
00736 bcls_dload( const int n, const double alpha, double x[], const int incx )
00737 {    
00738     int i, ix;
00739 
00740     if (incx <= 0) return;
00741 
00742     ix = 0;
00743 
00744     for (i = 0; i < n; i++) {
00745         x[ix]  = alpha;
00746         ix    += incx;
00747     }
00748     return;
00749 }
00750 
00761 void
00762 bcls_gather( const int nix, const int ix[], const double x[], double y[] )
00763 {
00764     int j, k;
00765     for (j = 0; j < nix; j++) {
00766         k = ix[ j ];
00767         y[ j ] = x[ k ];
00768     }
00769 }
00770 
00781 void
00782 bcls_scatter( const int nix, const int ix[], const double x[], double y[] )
00783 {
00784     int j, k;
00785     for (j = 0; j < nix; j++) {
00786         k = ix[ j ];
00787         y[ k ] = x[ j ];
00788     }
00789 }

Generated on Sun Mar 4 22:50:03 2007 by Doxygen 1.5.1