lbfgsr.h

00001 #ifndef LBFGSR_H
00002 #define LBFGSR_H
00003 
00004 #include <cmath>
00005 #include <cstdlib>
00006 #include <fstream>
00007 #include "timer.h"
00008 #include "gfeature.h"
00009 
00010 const int LBFGSB_PRINT = 1; //-1: no output; 1: output for every iteration
00011 
00012 // The code below from setulb() onwards is ported from: 
00013 // C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: a
00014 // limited memory FORTRAN code for solving bound constrained
00015 // optimization problems'', Tech. Report, NAM-11, EECS Department,
00016 // Northwestern University.
00017 
00018 class LBFGSR
00019 {
00020  public:
00021   LBFGSR(const int& maxIter, const double& ftol, double samplingFrac,
00022          RRF* const& rrf, GroundRRF* const& grrf, 
00023          const Array<int>& queryPreds, const int& numWts, 
00024          int wtOffset, double sigmaSq, bool fast=false) 
00025     : maxIter_(maxIter), ftol_(ftol), samplingFrac_(samplingFrac),
00026       rrf_(rrf), grrf_(grrf), wtOffset_(wtOffset), sigmaSq_(sigmaSq),
00027       pseudoFast_(fast),
00028       nbd_(NULL), iwa_(NULL), l_(NULL), u_(NULL), g_(NULL), wa_(NULL), 
00029       gArray_(numWts), queryPreds_(queryPreds)
00030   { init(numWts); }
00031 
00032 
00033   ~LBFGSR() { destroy(); }
00034 
00035   
00036   void setMaxIter(const int& iter) { maxIter_ = iter; }
00037 
00038   void setFtol(const double& tol)  { ftol_ = tol; }
00039 
00040 
00041   void init(const int& numWts)
00042   {
00043     destroy();
00044     numWts_ = numWts;
00045     int mmax = 17;
00046     nbd_ = new int[numWts_+1];
00047     iwa_ = new int[3*numWts_+1];
00048     l_   = new double[numWts_+1];
00049     u_   = new double[numWts_+1];
00050     g_   = new double[numWts_+1];
00051     wa_  = new double[2*mmax*numWts_+4*numWts_+12*mmax*mmax+12*mmax+1];    
00052   }
00053 
00054 
00055   void reInit(const int& numWts)
00056   {
00057     if (numWts_ == numWts) return;
00058     init(numWts);
00059   }
00060 
00061   
00062   void destroy() 
00063   {
00064     if (nbd_ != NULL) delete [] nbd_;
00065     if (iwa_ != NULL) delete [] iwa_;
00066     if (l_   != NULL) delete [] l_;
00067     if (u_   != NULL) delete [] u_;
00068     if (g_   != NULL) delete [] g_;
00069     if (wa_  != NULL) delete [] wa_;
00070   }
00071 
00072 
00073   double minimize(const int& numWts, double* const & wts, int& iter,bool& error)
00074   {
00075     reInit(numWts);
00076     return minimize(wts, iter, error);
00077   }
00078 
00079 
00080   double minimize(double* const & wts, int& iter, bool& error)
00081   {
00082     error = false;
00083     int m = 5; //max number of limited memory corrections
00084     double f; // value of function to be optimized
00085     double factr = 0;
00086     double pgtol = 0;
00087      // -1: silent (-1); 1: out at every iteration
00088     ofstream* itfile = NULL;
00089     int iprint = LBFGSB_PRINT; 
00090     if (iprint >= 1) itfile = new ofstream("iterate.dat");
00091 
00092 
00093     iter = 0;
00094 
00095       //indicate that the elements of x[] are unbounded
00096     for (int i = 0; i <= numWts_; i++) nbd_[i] = 0;
00097     
00098     strcpy(task_,"START");
00099     for (int i = 5; i <= 60; i++) task_[i]=' ';
00100     
00101     setulb(numWts_,m,wts,l_,u_,nbd_,f,g_,factr,pgtol,wa_,iwa_,task_,
00102            iprint,csave_,lsave_,isave_,dsave_,itfile);
00103 
00104     double initialValue = 0, prevValue = 0, newValue;
00105     bool firstIter = true;
00106 
00107       //while routine returns "FG" or "NEW_X" in task, keep calling it
00108     while (strncmp(task_,"FG",2)==0 || strncmp(task_,"NEW_X",5)==0)
00109     {
00110       if (strncmp(task_,"FG",2)==0)
00111       {
00112         f = getValueAndGradient(g_, wts);
00113 
00114         setulb(numWts_,m,wts,l_,u_,nbd_,f,g_,factr,pgtol,wa_,iwa_,task_,
00115                iprint,csave_,lsave_,isave_,dsave_,itfile);
00116 
00117         if (firstIter) { firstIter = false; prevValue = f; initialValue = f; }
00118       }
00119       else
00120       {
00121           //the minimization routine has returned with a new iterate,
00122           //and we have opted to continue the iteration
00123         if (iter+1 > maxIter_) break;
00124         ++iter;
00125         newValue = f;
00126         
00127         if (fabs(newValue-prevValue) < ftol_*fabs(prevValue)) break;
00128         prevValue = newValue;
00129         
00130         setulb(numWts_,m,wts,l_,u_,nbd_,f,g_,factr,pgtol,wa_,iwa_,task_,
00131                iprint,csave_,lsave_,isave_,dsave_,itfile);
00132       }
00133     }
00134     
00135 
00136     //If task is neither FG nor NEW_X we terminate execution.
00137     //the minimization routine has returned with one of
00138     //{CONV, ABNO, ERROR}
00139     
00140     if (strncmp(task_,"ABNO",4) == 0)
00141     {
00142       cout << "ERROR: LBFGSB failed. Returned ABNO" << endl;
00143       error = true;
00144       return initialValue;
00145     }
00146     
00147     if (strncmp(task_,"ERROR",5)==0)
00148     {
00149       cout << "ERROR: LBFGSB failed. Returned ERROR" << endl;
00150       error = true;
00151       return initialValue;
00152     }
00153     
00154     if (strncmp(task_,"CONV",4)==0)
00155     {
00156       //cout << "LBFGSB converged!" << endl;
00157     }
00158         
00159     return f;    
00160   }
00161 
00162 
00163  private:
00164   int maxIter_;
00165   double ftol_;
00166   double samplingFrac_; // Fraction of ground preds to consider
00167   RRF*   rrf_; //not owned by LBFGSR; do not delete
00168   GroundRRF* grrf_; //not owned by LBFGSR; do not delete
00169   int numWts_;
00170   int wtOffset_;
00171   double sigmaSq_;
00172   bool pseudoFast_;
00173   
00174     // params of lbfgsb algorithm
00175   int*    nbd_;
00176   int*    iwa_;
00177   double* l_;
00178   double* u_;
00179   double* g_;
00180   double* wa_;
00181 
00182   // Other parameters, to assist in computing pseudo-log-likelihood
00183   Array<double> gArray_;
00184   Array<int> queryPreds_;
00185 
00186   char task_[61];
00187   char csave_[61];
00188   bool lsave_[5];
00189   int  isave_[45];
00190   double dsave_[30];
00191 
00192 
00193  private:
00194   double getValueAndGradient(double* const & g, const double* const & wts)
00195   {
00196       for (int i = 0; i < numWts_; i++) {
00197           // NOTE: wts is 1-indexed, not 0-indexed
00198           rrf_->setWeight(i + wtOffset_, wts[i+1]);
00199       }
00200 
00201       // Get gradient
00202       grrf_->dirtyAll();
00203       if (pseudoFast_) {
00204           grrf_->getPseudoCountsFast(gArray_, queryPreds_, samplingFrac_);
00205       } else {
00206           grrf_->getPseudoCounts(gArray_, queryPreds_, samplingFrac_);
00207       }
00208 
00209       // Copy into the array
00210       // TODO: apply prior!
00211       double wll = 0.0;
00212       for (int i = 0; i < numWts_; i++) {
00213           g_[i+1] = -gArray_[i + wtOffset_] + wts[i+1]/sigmaSq_;
00214           wll -= wts[i+1] * wts[i+1]/sigmaSq_;
00215       }
00216 
00217       double value = -(grrf_->getLogPseudoLikelihood(queryPreds_) + wll);
00218 
00219 #define VERBOSE_DEBUG 0
00220 #if VERBOSE_DEBUG
00221       cout << "wts";
00222       for (int i = 0; i < numWts_; i++) {
00223           cout << " " << wts[i+1];
00224       }
00225       cout << "\nval = " << value << endl;
00226       cout << "grad";
00227       for (int i = 0; i < numWts_; i++) {
00228           cout << " " << g_[i+1];
00229       }
00230       cout << endl;
00231 #endif
00232       // DEBUG
00233       cout << "Getting value: " << value << endl;
00234 
00235       return value;
00236   }
00237 
00238     //function
00239   int getIdx(const int& i, const int& j, const int& idim)
00240   {
00241     return (j-1)*idim + i;
00242   }
00243 
00244 
00245   double max(const double& a, const double& b) { if (a>=b) return a; return b; }
00246 
00247   double min(const double& a, const double& b) { if (a<=b) return a; return b; }
00248 
00249   int min(const int& a, const int& b) { if (a<=b) return a; return b; }
00250 
00251   double max(const double& a, const double& b, const double& c)
00252   {
00253     if (a >= b && a >= c) return a;
00254     if (b >= a && b >= c) return b;
00255     assert(c >= a && c >= b);
00256     return c;
00257   }
00258 
00259 
00260   // The code below is ported from: 
00261   // C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: a
00262   // limited memory FORTRAN code for solving bound constrained
00263   // optimization problems'', Tech. Report, NAM-11, EECS Department,
00264   // Northwestern University.
00265 
00266   // The comments before each function are from the original fortran code.
00267 
00268   //   ************
00269   //
00270   //   Subroutine setulb
00271   //
00272   //   This subroutine partitions the working arrays wa and iwa, and 
00273   //     then uses the limited memory BFGS method to solve the bound
00274   //     constrained optimization problem by calling mainlb.
00275   //     (The direct method will be used in the subspace minimization.)
00276   //
00277   //   n is an integer variable.
00278   //     On entry n is the dimension of the problem.
00279   //     On exit n is unchanged.
00280   //
00281   //   m is an integer variable.
00282   //     On entry m is the maximum number of variable metric corrections
00283   //       used to define the limited memory matrix.
00284   //     On exit m is unchanged.
00285   //
00286   //   x is a double precision array of dimension n.
00287   //     On entry x is an approximation to the solution.
00288   //     On exit x is the current approximation.
00289   //
00290   //   l is a double precision array of dimension n.
00291   //     On entry l is the lower bound on x.
00292   //     On exit l is unchanged.
00293   //
00294   //   u is a double precision array of dimension n.
00295   //     On entry u is the upper bound on x.
00296   //     On exit u is unchanged.
00297   //
00298   //   nbd is an integer array of dimension n.
00299   //     On entry nbd represents the type of bounds imposed on the
00300   //       variables, and must be specified as follows:
00301   //       nbd(i)=0 if x(i) is unbounded,
00302   //              1 if x(i) has only a lower bound,
00303   //              2 if x(i) has both lower and upper bounds, and
00304   //              3 if x(i) has only an upper bound.
00305   //     On exit nbd is unchanged.
00306   //
00307   //   f is a double precision variable.
00308   //     On first entry f is unspecified.
00309   //     On final exit f is the value of the function at x.
00310   //
00311   //   g is a double precision array of dimension n.
00312   //     On first entry g is unspecified.
00313   //     On final exit g is the value of the gradient at x.
00314   //
00315   //   factr is a double precision variable.
00316   //     On entry factr >= 0 is specified by the user.  The iteration
00317   //       will stop when
00318   //
00319   //       (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} <= factr*epsmch
00320   //
00321   //       where epsmch is the machine precision, which is automatically
00322   //       generated by the code. Typical values for factr: 1.d+12 for
00323   //       low accuracy; 1.d+7 for moderate accuracy; 1.d+1 for extremely
00324   //       high accuracy.
00325   //     On exit factr is unchanged.
00326   //
00327   //   pgtol is a double precision variable.
00328   //     On entry pgtol >= 0 is specified by the user.  The iteration
00329   //       will stop when
00330   //
00331   //               max{|proj g_i | i = 1, ..., n} <= pgtol
00332   //
00333   //       where pg_i is the ith component of the projected gradient.   
00334   //     On exit pgtol is unchanged.
00335   //
00336   //   wa is a double precision working array of length 
00337   //     (2mmax + 4)nmax + 12mmax^2 + 12mmax.
00338   //
00339   //   iwa is an integer working array of length 3nmax.
00340   //
00341   //   task is a working string of characters of length 60 indicating
00342   //     the current job when entering and quitting this subroutine.
00343   //
00344   //   iprint is an integer variable that must be set by the user.
00345   //     It controls the frequency and type of output generated:
00346   //      iprint<0    no output is generated;
00347   //      iprint=0    print only one line at the last iteration;
00348   //      0<iprint<99 print also f and |proj g| every iprint iterations;
00349   //      iprint=99   print details of every iteration except n-vectors;
00350   //      iprint=100  print also the changes of active set and final x;
00351   //      iprint>100  print details of every iteration including x and g;
00352   //     When iprint > 0, the file iterate.dat will be created to
00353   //                      summarize the iteration.
00354   //
00355   //   csave is a working string of characters of length 60.
00356   //
00357   //   lsave is a logical working array of dimension 4.
00358   //     On exit with 'task' = NEW_X, the following information is 
00359   //                                                           available:
00360   //       If lsave(1) = true  then  the initial X has been replaced by
00361   //                                   its projection in the feasible set;
00362   //       If lsave(2) = true  then  the problem is constrained;
00363   //       If lsave(3) = true  then  each variable has upper and lower
00364   //                                   bounds;
00365   //
00366   //   isave is an integer working array of dimension 44.
00367   //     On exit with 'task' = NEW_X, the following information is 
00368   //                                                           available:
00369   //       isave(22) = the total number of intervals explored in the 
00370   //                       search of Cauchy points;
00371   //       isave(26) = the total number of skipped BFGS updates before 
00372   //                       the current iteration;
00373   //       isave(30) = the number of current iteration;
00374   //       isave(31) = the total number of BFGS updates prior the current
00375   //                       iteration;
00376   //       isave(33) = the number of intervals explored in the search of
00377   //                       Cauchy point in the current iteration;
00378   //       isave(34) = the total number of function and gradient 
00379   //                       evaluations;
00380   //       isave(36) = the number of function value or gradient
00381   //                                evaluations in the current iteration;
00382   //       if isave(37) = 0  then the subspace argmin is within the box;
00383   //       if isave(37) = 1  then the subspace argmin is beyond the box;
00384   //       isave(38) = the number of free variables in the current
00385   //                       iteration;
00386   //       isave(39) = the number of active constraints in the current
00387   //                       iteration;
00388   //       n + 1 - isave(40) = the number of variables leaving the set of
00389   //                         active constraints in the current iteration;
00390   //       isave(41) = the number of variables entering the set of active
00391   //                       constraints in the current iteration.
00392   //
00393   //   dsave is a double precision working array of dimension 29.
00394   //     On exit with 'task' = NEW_X, the following information is
00395   //                                                           available:
00396   //       dsave(1) = current 'theta' in the BFGS matrix;
00397   //       dsave(2) = f(x) in the previous iteration;
00398   //       dsave(3) = factr*epsmch;
00399   //       dsave(4) = 2-norm of the line search direction vector;
00400   //       dsave(5) = the machine precision epsmch generated by the code;
00401   //       dsave(7) = the accumulated time spent on searching for
00402   //                                                       Cauchy points;
00403   //       dsave(8) = the accumulated time spent on
00404   //                                               subspace minimization;
00405   //       dsave(9) = the accumulated time spent on line search;
00406   //       dsave(11) = the slope of the line search function at
00407   //                                the current point of line search;
00408   //       dsave(12) = the maximum relative step length imposed in
00409   //                                                         line search;
00410   //       dsave(13) = the infinity norm of the projected gradient;
00411   //       dsave(14) = the relative step length in the line search;
00412   //       dsave(15) = the slope of the line search function at
00413   //                               the starting point of the line search;
00414   //       dsave(16) = the square of the 2-norm of the line search
00415   //                                                    direction vector.
00416   //
00417   //   Subprograms called:
00418   //
00419   //     L-BFGS-B Library ... mainlb.    
00420   //
00421   //
00422   //   References:
00423   //
00424   //     [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
00425   //     memory algorithm for bound constrained optimization'',
00426   //     SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
00427   //
00428   //     [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: a
00429   //     limited memory FORTRAN code for solving bound constrained
00430   //     optimization problems'', Tech. Report, NAM-11, EECS Department,
00431   //     Northwestern University, 1994.
00432   //
00433   //     (Postscript files of these papers are available via anonymous
00434   //      ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.)
00435   //
00436   //                         *  *  *
00437   //
00438   //   NEOS, November 1994. (Latest revision June 1996.)
00439   //   Optimization Technology Center.
00440   //   Argonne National Laboratory and Northwestern University.
00441   //   Written by
00442   //                      Ciyou Zhu
00443   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
00444   //
00445   //
00446   // ************
00447   //function
00448   void setulb(const int& n, const int& m, double* const & x, 
00449               const double* const & l, const double* const & u, 
00450               const int* const & nbd, double& f, double* const & g, 
00451               const double& factr, const double& pgtol, 
00452               double* const & wa, int* const & iwa,
00453               char* const & task, const int& iprint,  
00454               char* const & csave, bool* const & lsave, 
00455               int* const & isave, double* const & dsave,
00456               ofstream* itfile)
00457   { 
00458     int l1,l2,l3,lws,lr,lz,lt,ld,lsg,lwa,lyg,
00459         lsgo,lwy,lsy,lss,lyy,lwt,lwn,lsnd,lygo;
00460 
00461     if (strncmp(task,"START",5)==0)
00462     {
00463       isave[1]  = m*n;
00464       isave[2]  = m*m;
00465       isave[3]  = 4*m*m;
00466       isave[4]  = 1;
00467       isave[5]  = isave[4]  + isave[1];
00468       isave[6]  = isave[5]  + isave[1];
00469       isave[7]  = isave[6]  + isave[2];
00470       isave[8]  = isave[7]  + isave[2];
00471       isave[9]  = isave[8]  + isave[2];
00472       isave[10] = isave[9]  + isave[2];
00473       isave[11] = isave[10] + isave[3];
00474       isave[12] = isave[11] + isave[3];
00475       isave[13] = isave[12] + n;
00476       isave[14] = isave[13] + n;
00477       isave[15] = isave[14] + n;
00478       isave[16] = isave[15] + n;
00479       isave[17] = isave[16] + 8*m;
00480       isave[18] = isave[17] + m;
00481       isave[19] = isave[18] + m;
00482       isave[20] = isave[19] + m;
00483     }
00484     l1   = isave[1];
00485     l2   = isave[2];
00486     l3   = isave[3];
00487     lws  = isave[4];
00488     lwy  = isave[5];
00489     lsy  = isave[6];
00490     lss  = isave[7];
00491     lyy  = isave[8];
00492     lwt  = isave[9];
00493     lwn  = isave[10];
00494     lsnd = isave[11];
00495     lz   = isave[12];
00496     lr   = isave[13];
00497     ld   = isave[14];
00498     lt   = isave[15];
00499     lwa  = isave[16];
00500     lsg  = isave[17];
00501     lsgo = isave[18];
00502     lyg  = isave[19];
00503     lygo = isave[20];
00504 
00505     timer_.reset();
00506     
00507     mainlb(n,m,x,l,u,nbd,f,g,factr,pgtol,
00508            &(wa[lws-1]),&(wa[lwy-1]),&(wa[lsy-1]),&(wa[lss-1]),&(wa[lyy-1]),
00509            &(wa[lwt-1]),&(wa[lwn-1]),&(wa[lsnd-1]),&(wa[lz-1]),&(wa[lr-1]),
00510            &(wa[ld-1]),&(wa[lt-1]),&(wa[lwa-1]),&(wa[lsg-1]),&(wa[lsgo-1]),
00511            &(wa[lyg-1]),&(wa[lygo-1]),&(iwa[1-1]),&(iwa[n+1-1]),&(iwa[2*n+1-1]),
00512            task,iprint,csave,lsave,&(isave[22-1]),dsave, itfile);
00513   } //setulb()
00514 
00515 
00516   //   ************
00517   //
00518   //   Subroutine mainlb
00519   //
00520   //   This subroutine solves bound constrained optimization problems by
00521   //     using the compact formula of the limited memory BFGS updates.
00522   //     
00523   //   n is an integer variable.
00524   //     On entry n is the number of variables.
00525   //     On exit n is unchanged.
00526   //
00527   //   m is an integer variable.
00528   //     On entry m is the maximum number of variable metri//
00529   //        corrections allowed in the limited memory matrix.
00530   //     On exit m is unchanged.
00531   //
00532   //   x is a double precision array of dimension n.
00533   //     On entry x is an approximation to the solution.
00534   //     On exit x is the current approximation.
00535   //
00536   //   l is a double precision array of dimension n.
00537   //     On entry l is the lower bound of x.
00538   //     On exit l is unchanged.
00539   //
00540   //   u is a double precision array of dimension n.
00541   //     On entry u is the upper bound of x.
00542   //     On exit u is unchanged.
00543   //
00544   //   nbd is an integer array of dimension n.
00545   //     On entry nbd represents the type of bounds imposed on the
00546   //       variables, and must be specified as follows:
00547   //       nbd(i)=0 if x(i) is unbounded,
00548   //              1 if x(i) has only a lower bound,
00549   //              2 if x(i) has both lower and upper bounds,
00550   //              3 if x(i) has only an upper bound.
00551   //     On exit nbd is unchanged.
00552   //
00553   //   f is a double precision variable.
00554   //     On first entry f is unspecified.
00555   //     On final exit f is the value of the function at x.
00556   //
00557   //   g is a double precision array of dimension n.
00558   //     On first entry g is unspecified.
00559   //     On final exit g is the value of the gradient at x.
00560   //
00561   //   factr is a double precision variable.
00562   //     On entry factr >= 0 is specified by the user.  The iteration
00563   //       will stop when
00564   //
00565   //       (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} <= factr*epsmch
00566   //
00567   //       where epsmch is the machine precision, which is automatically
00568   //       generated by the code.
00569   //     On exit factr is unchanged.
00570   //
00571   //   pgtol is a double precision variable.
00572   //     On entry pgtol >= 0 is specified by the user.  The iteration
00573   //       will stop when
00574   //
00575   //               max{|proj g_i | i = 1, ..., n} <= pgtol
00576   //
00577   //       where pg_i is the ith component of the projected gradient.
00578   //     On exit pgtol is unchanged.
00579   //
00580   //   ws, wy, sy, and wt are double precision working arrays used to
00581   //     store the following information defining the limited memory
00582   //        BFGS matrix:
00583   //        ws, of dimension n x m, stores S, the matrix of s-vectors;
00584   //        wy, of dimension n x m, stores Y, the matrix of y-vectors;
00585   //        sy, of dimension m x m, stores S'Y;
00586   //        ss, of dimension m x m, stores S'S;
00587   //       yy, of dimension m x m, stores Y'Y;
00588   //        wt, of dimension m x m, stores the Cholesky factorization
00589   //                                of (theta*S'S+LD^(-1)L'); see eq.
00590   //                                (2.26) in [3].
00591   //
00592   //   wn is a double precision working array of dimension 2m x 2m
00593   //     used to store the LEL^T factorization of the indefinite matrix
00594   //               K = [-D -Y'ZZ'Y/theta     L_a'-R_z'  ]
00595   //                   [L_a -R_z           theta*S'AA'S ]
00596   //
00597   //     where     E = [-I  0]
00598   //                   [ 0  I]
00599   //
00600   //   snd is a double precision working array of dimension 2m x 2m
00601   //     used to store the lower triangular part of
00602   //               N = [Y' ZZ'Y   L_a'+R_z']
00603   //                   [L_a +R_z  S'AA'S   ]
00604   //         
00605   //   z(n),r(n),d(n),t(n),wa(8*m) are double precision working arrays.
00606   //     z is used at different times to store the Cauchy point and
00607   //     the Newton point.
00608   //
00609   //   sg(m),sgo(m),yg(m),ygo(m) are double precision working arrays. 
00610   //
00611   //   index is an integer working array of dimension n.
00612   //     In subroutine freev, index is used to store the free and fixed
00613   //        variables at the Generalized Cauchy Point (GCP).
00614   //
00615   //   iwhere is an integer working array of dimension n used to record
00616   //     the status of the vector x for GCP computation.
00617   //     iwhere(i)=0 or -3 if x(i) is free and has bounds,
00618   //               1       if x(i) is fixed at l(i), and l(i) != u(i)
00619   //               2       if x(i) is fixed at u(i), and u(i) != l(i)
00620   //               3       if x(i) is always fixed, i.e.,  u(i)=x(i)=l(i)
00621   //              -1       if x(i) is always free, i.e., no bounds on it.
00622   //
00623   //   indx2 is an integer working array of dimension n.
00624   //     Within subroutine cauchy, indx2 corresponds to the array iorder.
00625   //     In subroutine freev, a list of variables entering and leaving
00626   //     the free set is stored in indx2, and it is passed on to
00627   //     subroutine formk with this information.
00628   //
00629   //   task is a working string of characters of length 60 indicating
00630   //     the current job when entering and leaving this subroutine.
00631   //
00632   //   iprint is an INTEGER variable that must be set by the user.
00633   //     It controls the frequency and type of output generated:
00634   //      iprint<0    no output is generated;
00635   //      iprint=0    print only one line at the last iteration;
00636   //      0<iprint<99 print also f and |proj g| every iprint iterations;
00637   //      iprint=99   print details of every iteration except n-vectors;
00638   //      iprint=100  print also the changes of active set and final x;
00639   //      iprint>100  print details of every iteration including x and g;
00640   //     When iprint > 0, the file iterate.dat will be created to
00641   //                      summarize the iteration.
00642   //
00643   //   csave is a working string of characters of length 60.
00644   //
00645   //   lsave is a logical working array of dimension 4.
00646   //
00647   //   isave is an integer working array of dimension 23.
00648   //
00649   //   dsave is a double precision working array of dimension 29.
00650   //
00651   //
00652   //   Subprograms called
00653   //
00654   //     L-BFGS-B Library ... cauchy, subsm, lnsrlb, formk, 
00655   //
00656   //      errclb, prn1lb, prn2lb, prn3lb, active, projgr,
00657   //
00658   //      freev, cmprlb, matupd, formt.
00659   //
00660   //     Minpack2 Library ... timer, dpmeps.
00661   //
00662   //     Linpack Library ... dcopy, ddot.
00663   //
00664   //
00665   //   References:
00666   //
00667   //     [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
00668   //     memory algorithm for bound constrained optimization'',
00669   //     SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
00670   //
00671   //     [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: FORTRAN
00672   //     Subroutines for Large Scale Bound Constrained Optimization''
00673   //     Tech. Report, NAM-11, EECS Department, Northwestern University,
00674   //     1994.
00675   // 
00676   //     [3] R. Byrd, J. Nocedal and R. Schnabel "Representations of
00677   //     Quasi-Newton Matrices and their use in Limited Memory Methods'',
00678   //     Mathematical Programming 63 (1994), no. 4, pp. 129-156.
00679   //
00680   //     (Postscript files of these papers are available via anonymous
00681   //      ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.)
00682   //
00683   //                         *  *  *
00684   //
00685   //   NEOS, November 1994. (Latest revision June 1996.)
00686   //   Optimization Technology Center.
00687   //   Argonne National Laboratory and Northwestern University.
00688   //   Written by
00689   //                      Ciyou Zhu
00690   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
00691   //
00692   //
00693   //   ************
00694   //function
00695   void mainlb(const int& n, const int& m, double* const & x, 
00696               const double* const & l, const double* const & u, 
00697               const int* const & nbd, double& f,  double* const & g, 
00698               const double& factr, const double& pgtol, 
00699               double* const & ws, double* const & wy, double* const & sy,
00700               double* const & ss, double* const & yy, double* const & wt,
00701               double* const & wn, double* const & snd, double* const & z,
00702               double* const & r, double* const & d, double* const & t, 
00703               double* const & wa, double* const & sg, double* const& sgo,
00704               double* const & yg, double* const & ygo, int* const& index,
00705               int* const & iwhere, int* const & indx2, char* const& task,
00706               const int& iprint, char* const& csave, bool * const& lsave,
00707               int* const & isave, double* const & dsave, ofstream* itfile)
00708   {
00709     bool   prjctd,cnstnd,boxed,updatd,wrk;
00710     char   word[4];
00711     int    k,nintol,iback,nskip,
00712            head,col,iter,itail,iupdat,
00713            nint,nfgv,info,ifun=0,
00714            iword,nfree,nact,ileave,nenter;
00715     double theta,fold=0,dr,rr,tol,
00716            xstep,sbgnrm,ddum,dnorm=0,dtd,epsmch,
00717            cpu1=0,cpu2,cachyt,sbtime,lnscht,time1,time2,
00718            gd,gdold=0,stp,stpmx=0,time;
00719     double one=1.0,zero=0.0;
00720 
00721     if (iprint > 1) { assert(itfile); }
00722 
00723     if (strncmp(task,"START",5)==0)
00724     {
00725       time1 = timer_.time();
00726 
00727       //Generate the current machine precision.
00728       epsmch = dpmeps();
00729       //epsmch = 1.08420217E-19;
00730       //cout << "L-BFGS-B computed machine precision = " << epsmch << endl;
00731 
00732       //Initialize counters and scalars when task='START'.
00733 
00734       //for the limited memory BFGS matrices:
00735       col    = 0;
00736       head   = 1;
00737       theta  = one;
00738       iupdat = 0;
00739       updatd = false;
00740  
00741       //for operation counts:
00742       iter   = 0;
00743       nfgv   = 0;
00744       nint   = 0;
00745       nintol = 0;
00746       nskip  = 0;
00747       nfree  = n;
00748 
00749       //for stopping tolerance:
00750       tol = factr*epsmch;
00751 
00752       //for measuring running time:
00753       cachyt = 0;
00754       sbtime = 0;
00755       lnscht = 0;
00756 
00757  
00758       //'word' records the status of subspace solutions.
00759       strcpy(word, "---");
00760 
00761       //'info' records the termination information.
00762       info = 0;
00763 
00764       //commented out: file opened at beginning of function
00765       //if (iprint >= 1)
00766       //{
00767       //  //open a summary file 'iterate.dat'
00768       //  ofstream itfile("lbfgsb-iterate.dat");
00769       //}
00770 
00771       //Check the input arguments for errors.
00772       errclb(n,m,factr,l,u,nbd,task,info,k);
00773       if (strncmp(task,"ERROR",5)==0)
00774       {
00775         prn3lb(n,x,f,task,iprint,info,itfile,
00776                iter,nfgv,nintol,nskip,nact,sbgnrm,
00777                zero,nint,word,iback,stp,xstep,k,
00778                cachyt,sbtime,lnscht);
00779         return;
00780       }
00781 
00782       prn1lb(n,m,l,u,x,iprint,itfile,epsmch);
00783  
00784       //Initialize iwhere & project x onto the feasible set.
00785       active(n,l,u,nbd,x,iwhere,iprint,prjctd,cnstnd,boxed) ;
00786 
00787       //The end of the initialization.
00788     } //if (strncmp(task,"START",5)==0)
00789     else
00790     {
00791       //restore local variables.
00792 
00793       prjctd = lsave[1];
00794       cnstnd = lsave[2];
00795       boxed  = lsave[3];
00796       updatd = lsave[4];
00797       
00798       nintol = isave[1];
00799       //itfile = isave[3];
00800       iback  = isave[4];
00801       nskip  = isave[5];
00802       head   = isave[6];
00803       col    = isave[7];
00804       itail  = isave[8];
00805       iter   = isave[9];
00806       iupdat = isave[10];
00807       nint   = isave[12];
00808       nfgv   = isave[13];
00809       info   = isave[14];
00810       ifun   = isave[15];
00811       iword  = isave[16];
00812       nfree  = isave[17];
00813       nact   = isave[18];
00814       ileave = isave[19];
00815       nenter = isave[20];
00816 
00817       theta  = dsave[1];
00818       fold   = dsave[2];
00819       tol    = dsave[3];
00820       dnorm  = dsave[4];
00821       epsmch = dsave[5];
00822       cpu1   = dsave[6];
00823       cachyt = dsave[7];
00824       sbtime = dsave[8];
00825       lnscht = dsave[9];
00826       time1  = dsave[10];
00827       gd     = dsave[11];
00828       stpmx  = dsave[12];
00829       sbgnrm = dsave[13];
00830       stp    = dsave[14];
00831       gdold  = dsave[15];
00832       dtd    = dsave[16];
00833          
00834    
00835       //After returning from the driver go to the point where execution
00836       //is to resume.
00837       if (strncmp(task,"FG_LN",5)==0) goto goto66;
00838       if (strncmp(task,"NEW_X",5)==0) goto goto777;
00839       if (strncmp(task,"FG_ST",5)==0) goto goto111;
00840       if (strncmp(task,"STOP",4)==0)  
00841       {
00842         if (strncmp(&(task[6]),"CPU",3)==0)
00843         {
00844           //restore the previous iterate.
00845           dcopy(n,t,1,x,1);
00846           dcopy(n,r,1,g,1);
00847           f = fold;
00848         }
00849         goto goto999;
00850       }
00851     }
00852 
00853     //Compute f0 and g0.
00854     
00855     strcpy(task, "FG_START");
00856     //return to the driver to calculate f and g; reenter at goto111.
00857     goto goto1000;
00858 
00859   goto111:
00860     
00861     nfgv = 1;
00862  
00863     //Compute the infinity norm of the (-) projected gradient.
00864  
00865     projgr(n,l,u,nbd,x,g,sbgnrm);
00866 
00867     if (iprint >= 1)
00868     {
00869       cout << "At iterate " << iter << ": f=" <<f<<",  |proj g|="<<sbgnrm<<endl;
00870       *itfile << "At iterate " << iter << ": nfgv=" << nfgv 
00871               << ", sbgnrm=" << sbgnrm << ", f=" << f << endl;
00872     }
00873 
00874     if (sbgnrm <= pgtol) 
00875     {
00876       //terminate the algorithm.
00877       strcpy(task,"CONVERGENCE: NORM OF PROJECTED GRADIENT <= PGTOL");
00878       goto goto999;
00879     }
00880  
00881     //----------------- the beginning of the loop ---------------------
00882  
00883   goto222:
00884     if (iprint >= 99) cout << "ITERATION " << (iter + 1) << endl;
00885     iword = -1;
00886 
00887     if (!cnstnd && col > 0) 
00888     {
00889       //skip the search for GCP.
00890       dcopy(n,x,1,z,1);
00891       wrk = updatd;
00892       nint = 0;
00893       goto goto333;
00894     }
00895 
00896     /*********************************************************************
00897      *
00898      *     Compute the Generalized Cauchy Point (GCP).
00899      *
00900      *********************************************************************/
00901 
00902     cpu1 = timer_.time();
00903 
00904     cauchy(n,x,l,u,nbd,g,indx2,iwhere,t,d,z,
00905            m,wy,ws,sy,wt,theta,col,head,
00906            &(wa[1-1]),&(wa[2*m+1-1]),&(wa[4*m+1-1]),&(wa[6*m+1-1]),nint,
00907            sg,yg,iprint,sbgnrm,info,epsmch);
00908 
00909     if (info > 0)
00910     { 
00911       //singular triangular system detected; refresh the lbfgs memory.
00912       if (iprint >= 1) 
00913         cout << "Singular triangular system detected; " 
00914              << "refresh the lbfgs memory and restart the iteration." <<endl;
00915       info   = 0;
00916       col    = 0;
00917       head   = 1;
00918       theta  = one;
00919       iupdat = 0;
00920       updatd = false;
00921       cpu2 = timer_.time();
00922       cachyt = cachyt + cpu2 - cpu1;
00923       goto goto222;
00924     }
00925     cpu2 = timer_.time(); 
00926     cachyt = cachyt + cpu2 - cpu1;
00927     nintol = nintol + nint;
00928 
00929     //Count the entering and leaving variables for iter > 0; 
00930     //find the index set of free and active variables at the GCP.
00931 
00932     freev(n,nfree,index,nenter,ileave,indx2,
00933           iwhere,wrk,updatd,cnstnd,iprint,iter);
00934 
00935     nact = n - nfree;
00936  
00937   goto333:
00938  
00939     //If there are no free variables or B=theta*I, then
00940     //skip the subspace minimization.
00941  
00942     if (nfree == 0 || col == 0) goto goto555;
00943  
00944     /**********************************************************************
00945      *
00946      *     Subspace minimization.
00947      *
00948      **********************************************************************/
00949 
00950     cpu1 = timer_.time();
00951 
00952     //Form  the LEL^T factorization of the indefinite
00953     //matrix    K = [-D -Y'ZZ'Y/theta     L_a'-R_z'  ]
00954     //              [L_a -R_z           theta*S'AA'S ]
00955     //where     E = [-I  0]
00956     //              [ 0  I]
00957 
00958     if (wrk) formk(n,nfree,index,nenter,ileave,indx2,iupdat,
00959                    updatd,wn,snd,m,ws,wy,sy,theta,col,head,info);
00960 
00961     if (info != 0) 
00962     {
00963       //nonpositive definiteness in Cholesky factorization;
00964       //refresh the lbfgs memory and restart the iteration.
00965       if(iprint >= 1) 
00966         cout << "Nonpositive definiteness in Cholesky factorization in formk;"
00967              << "refresh the lbfgs memory and restart the iteration." << endl;
00968       info   = 0;
00969       col    = 0;
00970       head   = 1;
00971       theta  = one;
00972       iupdat = 0;
00973       updatd = false;
00974       cpu2 = timer_.time() ;
00975       sbtime = sbtime + cpu2 - cpu1;
00976       goto goto222;
00977     }
00978 
00979     //compute r=-Z'B(xcp-xk)-Z'g (using wa(2m+1)=W'(xcp-x)
00980     //from 'cauchy').
00981     cmprlb(n,m,x,g,ws,wy,sy,wt,z,r,wa,index,
00982            theta,col,head,nfree,cnstnd,info);
00983     
00984     if (info != 0) goto goto444;
00985     //call the direct method.
00986     subsm(n,m,nfree,index,l,u,nbd,z,r,ws,wy,theta,
00987           col,head,iword,wa,wn,iprint,info);
00988 
00989 
00990   goto444:
00991     if (info != 0) 
00992     {
00993       //singular triangular system detected;
00994       //refresh the lbfgs memory and restart the iteration.
00995       if(iprint >= 1)         
00996         cout << "Singular triangular system detected; " 
00997              << "refresh the lbfgs memory and restart the iteration." <<endl;
00998       info   = 0;
00999       col    = 0;
01000       head   = 1;
01001       theta  = one;
01002       iupdat = 0;
01003       updatd = false;
01004       cpu2   = timer_.time(); 
01005       sbtime = sbtime + cpu2 - cpu1;
01006       goto goto222;
01007     }
01008  
01009     cpu2 = timer_.time(); 
01010     sbtime = sbtime + cpu2 - cpu1 ;
01011   goto555:  
01012 
01013     /*********************************************************************
01014      *
01015      *     Line search and optimality tests.
01016      *
01017      *********************************************************************/
01018  
01019     //Generate the search direction d:=z-x.
01020 
01021     for (int i = 1; i <= n; i++)
01022       d[i] = z[i] - x[i];
01023     
01024     cpu1 = timer_.time();
01025   goto66: 
01026 
01027     lnsrlb(n,l,u,nbd,x,f,fold,gd,gdold,g,d,r,t,z,stp,dnorm,
01028            dtd,xstep,stpmx,iter,ifun,iback,nfgv,info,task,
01029            boxed,cnstnd,csave,&(isave[22-1]),&(dsave[17-1]));
01030 
01031     if (info != 0 || iback >= 20)
01032     {
01033       //restore the previous iterate.
01034       dcopy(n,t,1,x,1);
01035       dcopy(n,r,1,g,1);
01036       f = fold;
01037       if (col == 0) 
01038       {
01039         //abnormal termination.
01040         if (info == 0) 
01041         {
01042           info = -9;
01043           //restore the actual number of f and g evaluations etc.
01044           nfgv  -=  1;
01045           ifun  -=  1;
01046           iback -= 1;
01047         }
01048         strcpy(task, "ABNORMAL_TERMINATION_IN_LNSRCH");
01049         iter += 1;
01050         goto goto999;
01051       }
01052       else
01053       {
01054         //refresh the lbfgs memory and restart the iteration.
01055         if(iprint >= 1)
01056           cout << "Bad direction in the line search; " 
01057                << "the lbfgs memory and restart the iteration" << endl;
01058         if (info == 0) nfgv = nfgv - 1;
01059         info   = 0;
01060         col    = 0;
01061         head   = 1;
01062         theta  = one;
01063         iupdat = 0;
01064         updatd = false;
01065         strcpy(task, "RESTART_FROM_LNSRCH");
01066         cpu2 = timer_.time();
01067         lnscht += cpu2 - cpu1;
01068         goto goto222;
01069       }
01070     }
01071     else 
01072     if (strncmp(task,"FG_LN",5)==0) 
01073     {
01074       //return to the driver for calculating f and g; reenter at goto66.
01075       goto goto1000;
01076     }
01077     else 
01078     {
01079       //calculate and print out the quantities related to the new X.
01080       cpu2 = timer_.time() ;
01081       lnscht += cpu2 - cpu1;
01082       iter += 1;
01083       
01084       //Compute the infinity norm of the projected (-)gradient.
01085       
01086       projgr(n,l,u,nbd,x,g,sbgnrm);
01087       
01088       //Print iteration information.
01089       
01090       prn2lb(n,x,f,g,iprint,itfile,iter,nfgv,nact,
01091              sbgnrm,nint,word,iword,iback,stp,xstep);
01092       goto goto1000;
01093     }
01094   goto777:
01095 
01096     //Test for termination.
01097     
01098     if (sbgnrm <= pgtol) 
01099     {
01100       //terminate the algorithm.
01101       strcpy(task, "CONVERGENCE: NORM OF PROJECTED GRADIENT <= PGTOL");
01102       goto goto999;
01103     } 
01104     
01105     ddum = max(fabs(fold), fabs(f), one);
01106     if ((fold - f) <= tol*ddum) 
01107     {
01108       //terminate the algorithm.
01109       strcpy(task, "CONVERGENCE: REL_REDUCTION_OF_F <= FACTR*EPSMCH");
01110       if (iback >= 10) info = -5;
01111         //i.e., to issue a warning if iback>10 in the line search.
01112       goto goto999;
01113     } 
01114     
01115     //Compute d=newx-oldx, r=newg-oldg, rr=y'y and dr=y's.
01116     
01117     for (int i = 1; i <= n; i++)
01118       r[i] = g[i] - r[i];
01119     rr = ddot(n,r,1,r,1);
01120     if (stp == one) 
01121     {  
01122       dr = gd - gdold;
01123       ddum = -gdold;
01124     }
01125     else
01126     {
01127       dr = (gd - gdold)*stp;
01128       dscal(n,stp,d,1);
01129       ddum = -gdold*stp;
01130     }
01131     
01132     if (dr <= epsmch*ddum) 
01133     {
01134       //skip the L-BFGS update.
01135       nskip = nskip + 1;
01136       updatd = false;
01137       if (iprint >= 1) 
01138         cout << "  ys=" << dr << "   -gs=" <<ddum<<" BFSG update SKIPPED"<<endl;
01139       goto goto888;
01140     } 
01141     
01142   /*********************************************************************
01143    *
01144    *     Update the L-BFGS matrix.
01145    *
01146    *********************************************************************/
01147  
01148     updatd = true;
01149     iupdat += 1;
01150 
01151     //Update matrices WS and WY and form the middle matrix in B.
01152 
01153     matupd(n,m,ws,wy,sy,ss,d,r,itail,
01154            iupdat,col,head,theta,rr,dr,stp,dtd);
01155 
01156     //Form the upper half of the pds T = theta*SS + L*D^(-1)*L';
01157     //Store T in the upper triangular of the array wt;
01158     //Cholesky factorize T to J*J' with
01159     //J' stored in the upper triangular of wt.
01160 
01161     formt(m,wt,sy,ss,col,theta,info);
01162  
01163     if (info != 0) 
01164     {
01165       //nonpositive definiteness in Cholesky factorization;
01166       //refresh the lbfgs memory and restart the iteration.
01167       if(iprint >= 1) 
01168         cout << "Nonpositive definiteness in Cholesky factorization in formt; "
01169              << "refresh the lbfgs memory and restart the iteration." << endl;
01170       info = 0;
01171       col  = 0;
01172       head = 1;
01173       theta = one;
01174       iupdat = 0;
01175       updatd = false;
01176       goto goto222;
01177     }
01178 
01179     //Now the inverse of the middle matrix in B is
01180 
01181     //[  D^(1/2)      O ] [ -D^(1/2)  D^(-1/2)*L' ]
01182     //[ -L*D^(-1/2)   J ] [  0        J'          ]
01183 
01184   goto888:
01185  
01186     //-------------------- the end of the loop -----------------------------
01187  
01188     goto goto222;
01189 
01190   goto999:
01191     time2 = timer_.time();
01192     time = time2 - time1;
01193     prn3lb(n,x,f,task,iprint,info,itfile,
01194            iter,nfgv,nintol,nskip,nact,sbgnrm,
01195            time,nint,word,iback,stp,xstep,k,
01196            cachyt,sbtime,lnscht);
01197   goto1000:
01198 
01199     //Save local variables.
01200     lsave[1]  = prjctd;
01201     lsave[2]  = cnstnd;
01202     lsave[3]  = boxed;
01203     lsave[4]  = updatd;
01204 
01205     isave[1]  = nintol; 
01206     //isave[3]  = itfile;
01207     isave[4]  = iback;
01208     isave[5]  = nskip; 
01209     isave[6]  = head;
01210     isave[7]  = col;
01211     isave[8]  = itail;
01212     isave[9]  = iter; 
01213     isave[10] = iupdat; 
01214     isave[12] = nint; 
01215     isave[13] = nfgv; 
01216     isave[14] = info; 
01217     isave[15] = ifun; 
01218     isave[16] = iword; 
01219     isave[17] = nfree; 
01220     isave[18] = nact; 
01221     isave[19] = ileave; 
01222     isave[20] = nenter; 
01223 
01224     dsave[1]  = theta; 
01225     dsave[2]  = fold; 
01226     dsave[3]  = tol; 
01227     dsave[4]  = dnorm; 
01228     dsave[5]  = epsmch; 
01229     dsave[6]  = cpu1; 
01230     dsave[7]  = cachyt; 
01231     dsave[8]  = sbtime; 
01232     dsave[9]  = lnscht; 
01233     dsave[10] = time1;
01234     dsave[11] = gd;
01235     dsave[12] = stpmx; 
01236     dsave[13] = sbgnrm;
01237     dsave[14] = stp;
01238     dsave[15] = gdold;
01239     dsave[16] = dtd;
01240 
01241   }//mainlb()
01242 
01243 
01244   //   ************
01245   //
01246   //   Subroutine active
01247   //
01248   //   This subroutine initializes iwhere and projects the initial x to
01249   //     the feasible set if necessary.
01250   //
01251   //   iwhere is an integer array of dimension n.
01252   //     On entry iwhere is unspecified.
01253   //     On exit iwhere(i)=-1  if x(i) has no bounds
01254   //                       3   if l(i)=u(i)
01255   //                       0   otherwise.
01256   //     In cauchy, iwhere is given finer gradations.
01257   //
01258   //
01259   //                         *  *  *
01260   //
01261   //   NEOS, November 1994. (Latest revision June 1996.)
01262   //   Optimization Technology Center.
01263   //   Argonne National Laboratory and Northwestern University.
01264   //   Written by
01265   //                      Ciyou Zhu
01266   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
01267   //
01268   //
01269   //   ************
01270     //function
01271   void active(const int& n, const double* const & l, 
01272               const double* const & u, const int* const & nbd, 
01273               double* const & x, int* const & iwhere, const int& iprint,
01274               bool& prjctd, bool& cnstnd, bool& boxed)
01275   {
01276     //int i;
01277     int nbdd;
01278     double zero=0.0;
01279 
01280     //Initialize nbdd, prjctd, cnstnd and boxed.
01281     nbdd   = 0;
01282     prjctd = false;
01283     cnstnd = false;
01284     boxed  = true;
01285 
01286     //Project the initial x to the easible set if necessary.
01287 
01288     for (int i = 1; i <= n; i++)
01289     {
01290       if (nbd[i] > 0)
01291       {
01292         if (nbd[i] <= 2 && x[i] <= l[i])
01293         {
01294                 if (x[i] < l[i])
01295           {
01296             prjctd = true;
01297                   x[i] = l[i];
01298           }
01299           nbdd += 1;
01300         }
01301         else 
01302         if (nbd[i] >= 2 && x[i] >= u[i])
01303         {
01304                 if (x[i] > u[i])
01305           {
01306             prjctd = true;
01307                   x[i] = u[i];
01308           }
01309           nbdd += 1;
01310         }
01311       }
01312     }
01313 
01314     //Initialize iwhere and assign values to cnstnd and boxed.
01315 
01316     for (int i = 1; i <= n; i++)
01317     {
01318       if (nbd[i] != 2) boxed = false;
01319       if (nbd[i] == 0)
01320       {
01321         //this variable is always free
01322         iwhere[i] = -1;
01323         //otherwise set x(i)=mid(x(i), u(i), l(i)).
01324       }
01325       else
01326       {
01327         cnstnd = true;
01328         if (nbd[i] == 2 && (u[i]-l[i]) <= zero)
01329         {
01330           //this variable is always fixed
01331           iwhere[i] = 3;
01332         }
01333         else 
01334           iwhere[i] = 0;
01335       }
01336     }
01337     
01338     if (iprint >= 0)
01339     {
01340       if (prjctd) 
01341         cout << "The initial X is infeasible.  Restart with its projection."
01342              << endl;
01343       if (!cnstnd) cout << "This problem is unconstrained." << endl;
01344     }
01345 
01346     if (iprint > 0) 
01347       cout << "At X0 " << nbdd << " variables are exactly at the bounds" <<endl;
01348   }//active()
01349 
01350 
01351   //   ************
01352   //
01353   //   Subroutine bmv
01354   //
01355   //   This subroutine computes the product of the 2m x 2m middle matrix 
01356   //     in the compact L-BFGS formula of B and a 2m vector v;  
01357   //     it returns the product in p.
01358   //    
01359   //   m is an integer variable.
01360   //     On entry m is the maximum number of variable metric corrections
01361   //       used to define the limited memory matrix.
01362   //     On exit m is unchanged.
01363   //
01364   //   sy is a double precision array of dimension m x m.
01365   //     On entry sy specifies the matrix S'Y.
01366   //     On exit sy is unchanged.
01367   //
01368   //   wt is a double precision array of dimension m x m.
01369   //     On entry wt specifies the upper triangular matrix J' which is 
01370   //       the Cholesky factor of (thetaS'S+LD^(-1)L').
01371   //     On exit wt is unchanged.
01372   //
01373   //   col is an integer variable.
01374   //     On entry col specifies the number of s-vectors (or y-vectors)
01375   //       stored in the compact L-BFGS formula.
01376   //     On exit col is unchanged.
01377   //
01378   //   v is a double precision array of dimension 2col.
01379   //     On entry v specifies vector v.
01380   //     On exit v is unchanged.
01381   //
01382   //   p is a double precision array of dimension 2col.
01383   //     On entry p is unspecified.
01384   //     On exit p is the product Mv.
01385   //
01386   //   info is an integer variable.
01387   //     On entry info is unspecified.
01388   //     On exit info = 0       for normal return,
01389   //                  = nonzero for abnormal return when the system
01390   //                              to be solved by dtrsl is singular.
01391   //
01392   //   Subprograms called:
01393   //
01394   //     Linpack ... dtrsl.
01395   //
01396   //
01397   //                         *  *  *
01398   //
01399   //   NEOS, November 1994. (Latest revision June 1996.)
01400   //   Optimization Technology Center.
01401   //   Argonne National Laboratory and Northwestern University.
01402   //   Written by
01403   //                      Ciyou Zhu
01404   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
01405   //
01406   //
01407   //   ************
01408     //function
01409   void bmv(const int& m, double* const & sy, double* const & wt, 
01410            const int& col, const double* const & v, double* const & p, 
01411            int& info)
01412   {
01413     //int i,k;
01414     int i2;
01415     double sum;
01416  
01417     if (col == 0) return;
01418  
01419     //PART I: solve [  D^(1/2)      O ] [ p1 ] = [ v1 ]
01420     //              [ -L*D^(-1/2)   J ] [ p2 ]   [ v2 ].
01421 
01422     //solve Jp2=v2+LD^(-1)v1.
01423     p[col+1] = v[col+1];
01424 
01425     for (int i = 2; i <= col; i++)
01426     {
01427       i2 = col + i;
01428       sum = 0;
01429       for (int k = 1; k <= i-1; k++)
01430         sum += sy[getIdx(i,k,m)]*v[k]/sy[getIdx(k,k,m)];
01431       
01432       p[i2] = v[i2] + sum;
01433     }
01434 
01435     //Solve the triangular system
01436     dtrsl(wt,m,col,&(p[col+1-1]),11,info);
01437     if (info != 0) return; 
01438  
01439     //solve D^(1/2)p1=v1.
01440     for (int i = 1; i <= col; i++)
01441       p[i] = v[i]/sqrt(sy[getIdx(i,i,m)]);
01442  
01443     //PART II: solve [ -D^(1/2)   D^(-1/2)*L'  ] [ p1 ] = [ p1 ]
01444     //               [  0         J'           ] [ p2 ]   [ p2 ]. 
01445  
01446     //solve J^Tp2=p2. 
01447     dtrsl(wt,m,col,&(p[col+1-1]),1,info);
01448     if (info != 0) return;
01449  
01450     //compute p1=-D^(-1/2)(p1-D^(-1/2)L'p2)
01451     //          =-D^(-1/2)p1+D^(-1)L'p2.  
01452     for (int i = 1; i <= col; i++)
01453       p[i] = -p[i]/sqrt(sy[getIdx(i,i,m)]);
01454     
01455     for (int i = 1; i <= col; i++)
01456     {
01457       sum = 0;
01458       for (int k = i+1; i <= col; i++)
01459         sum += sy[getIdx(k,i,m)]*p[col+k]/sy[getIdx(i,i,m)];
01460       p[i] += sum;
01461     }
01462   }//bmv()
01463 
01464 
01465   //   ************
01466   //
01467   //   Subroutine cauchy
01468   //
01469   //   For given x, l, u, g (with sbgnrm > 0), and a limited memory
01470   //     BFGS matrix B defined in terms of matrices WY, WS, WT, and
01471   //     scalars head, col, and theta, this subroutine computes the
01472   //     generalized Cauchy point (GCP), defined as the first local
01473   //     minimizer of the quadrati//
01474   //
01475   //                Q(x + s) = g's + 1/2 s'Bs
01476   //
01477   //     along the projected gradient direction P(x-tg,l,u).
01478   //     The routine returns the GCP in xcp. 
01479   //     
01480   //   n is an integer variable.
01481   //     On entry n is the dimension of the problem.
01482   //     On exit n is unchanged.
01483   //
01484   //   x is a double precision array of dimension n.
01485   //     On entry x is the starting point for the GCP computation.
01486   //     On exit x is unchanged.
01487   //
01488   //   l is a double precision array of dimension n.
01489   //     On entry l is the lower bound of x.
01490   //     On exit l is unchanged.
01491   //
01492   //   u is a double precision array of dimension n.
01493   //     On entry u is the upper bound of x.
01494   //     On exit u is unchanged.
01495   //
01496   //   nbd is an integer array of dimension n.
01497   //     On entry nbd represents the type of bounds imposed on the
01498   //       variables, and must be specified as follows:
01499   //       nbd(i)=0 if x(i) is unbounded,
01500   //              1 if x(i) has only a lower bound,
01501   //              2 if x(i) has both lower and upper bounds, and
01502   //              3 if x(i) has only an upper bound. 
01503   //     On exit nbd is unchanged.
01504   //
01505   //   g is a double precision array of dimension n.
01506   //     On entry g is the gradient of f(x).  g must be a nonzero vector.
01507   //     On exit g is unchanged.
01508   //
01509   //   iorder is an integer working array of dimension n.
01510   //     iorder will be used to store the breakpoints in the piecewise
01511   //     linear path and free variables encountered. On exit,
01512   //       iorder(1),...,iorder(nleft) are indices of breakpoints
01513   //                              which have not been encountered; 
01514   //       iorder(nleft+1),...,iorder(nbreak) are indices of
01515   //                                   encountered breakpoints; and
01516   //       iorder(nfree),...,iorder(n) are indices of variables which
01517   //               have no bound constraits along the search direction.
01518   //
01519   //   iwhere is an integer array of dimension n.
01520   //     On entry iwhere indicates only the permanently fixed (iwhere=3)
01521   //     or free (iwhere= -1) components of x.
01522   //     On exit iwhere records the status of the current x variables.
01523   //     iwhere(i)=-3  if x(i) is free and has bounds, but is not moved
01524   //               0   if x(i) is free and has bounds, and is moved
01525   //               1   if x(i) is fixed at l(i), and l(i) != u(i)
01526   //               2   if x(i) is fixed at u(i), and u(i) != l(i)
01527   //               3   if x(i) is always fixed, i.e.,  u(i)=x(i)=l(i)
01528   //               -1  if x(i) is always free, i.e., it has no bounds.
01529   //
01530   //   t is a double precision working array of dimension n. 
01531   //     t will be used to store the break points.
01532   //
01533   //   d is a double precision array of dimension n used to store
01534   //     the Cauchy direction P(x-tg)-x.
01535   //
01536   //   xcp is a double precision array of dimension n used to return the
01537   //     GCP on exit.
01538   //
01539   //   m is an integer variable.
01540   //     On entry m is the maximum number of variable metric corrections 
01541   //       used to define the limited memory matrix.
01542   //     On exit m is unchanged.
01543   //
01544   //   ws, wy, sy, and wt are double precision arrays.
01545   //     On entry they store information that defines the
01546   //                           limited memory BFGS matrix:
01547   //       ws(n,m) stores S, a set of s-vectors;
01548   //       wy(n,m) stores Y, a set of y-vectors;
01549   //       sy(m,m) stores S'Y;
01550   //       wt(m,m) stores the
01551   //               Cholesky factorization of (theta*S'S+LD^(-1)L').
01552   //     On exit these arrays are unchanged.
01553   //
01554   //   theta is a double precision variable.
01555   //     On entry theta is the scaling factor specifying B_0 = theta I.
01556   //     On exit theta is unchanged.
01557   //
01558   //   col is an integer variable.
01559   //     On entry col is the actual number of variable metri//
01560   //       corrections stored so far.
01561   //     On exit col is unchanged.
01562   //
01563   //   head is an integer variable.
01564   //     On entry head is the location of the first s-vector (or y-vector)
01565   //       in S (or Y).
01566   //     On exit col is unchanged.
01567   //
01568   //   p is a double precision working array of dimension 2m.
01569   //     p will be used to store the vector p = W^(T)d.
01570   //
01571   //   c is a double precision working array of dimension 2m.
01572   //     c will be used to store the vector c = W^(T)(xcp-x).
01573   //
01574   //   wbp is a double precision working array of dimension 2m.
01575   //     wbp will be used to store the row of W corresponding
01576   //       to a breakpoint.
01577   //
01578   //   v is a double precision working array of dimension 2m.
01579   //
01580   //   nint is an integer variable.
01581   //     On exit nint records the number of quadratic segments explored
01582   //       in searching for the GCP.
01583   //
01584   //   sg and yg are double precision arrays of dimension m.
01585   //     On entry sg  and yg store S'g and Y'g correspondingly.
01586   //     On exit they are unchanged. 
01587   // 
01588   //   iprint is an INTEGER variable that must be set by the user.
01589   //     It controls the frequency and type of output generated:
01590   //      iprint<0    no output is generated;
01591   //      iprint=0    print only one line at the last iteration;
01592   //      0<iprint<99 print also f and |proj g| every iprint iterations;
01593   //      iprint=99   print details of every iteration except n-vectors;
01594   //      iprint=100  print also the changes of active set and final x;
01595   //      iprint>100  print details of every iteration including x and g;
01596   //     When iprint > 0, the file iterate.dat will be created to
01597   //                      summarize the iteration.
01598   //
01599   //   sbgnrm is a double precision variable.
01600   //     On entry sbgnrm is the norm of the projected gradient at x.
01601   //     On exit sbgnrm is unchanged.
01602   //
01603   //   info is an integer variable.
01604   //     On entry info is 0.
01605   //     On exit info = 0       for normal return,
01606   //                  = nonzero for abnormal return when the the system
01607   //                            used in routine bmv is singular.
01608   //
01609   //   Subprograms called:
01610   // 
01611   //     L-BFGS-B Library ... hpsolb, bmv.
01612   //
01613   //     Linpack ... dscal dcopy, daxpy.
01614   //
01615   //
01616   //   References:
01617   //
01618   //     [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
01619   //     memory algorithm for bound constrained optimization'',
01620   //     SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
01621   //
01622   //     [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: FORTRAN
01623   //     Subroutines for Large Scale Bound Constrained Optimization''
01624   //     Tech. Report, NAM-11, EECS Department, Northwestern University,
01625   //     1994.
01626   //
01627   //     (Postscript files of these papers are available via anonymous
01628   //      ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.)
01629   //
01630   //                         *  *  *
01631   //
01632   //   NEOS, November 1994. (Latest revision June 1996.)
01633   //   Optimization Technology Center.
01634   //   Argonne National Laboratory and Northwestern University.
01635   //   Written by
01636   //                      Ciyou Zhu
01637   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
01638   //
01639   //
01640   //   ************  
01641     //function
01642   void cauchy(const int& n, const double* const & x, 
01643               const double* const & l, const double* const & u, 
01644               const int* const & nbd, const double* const & g, 
01645               int* const & iorder, int* const & iwhere, 
01646               double* const & t, double* const & d, double* const & xcp, 
01647               const int& m, double* const & wy, 
01648               double* const & ws, double* const & sy, 
01649               double* const & wt, double& theta, 
01650               const int& col, const int& head, double* const & p, 
01651               double* const & c, double* const & wbp, 
01652               double* const & v, int& nint, const double* const & sg, 
01653               const double* const & yg, const int& iprint, 
01654               const double& sbgnrm, int& info, const double& epsmch)
01655   {
01656     bool xlower,xupper,bnded;
01657     //int i,j;
01658     int col2,nfree,nbreak,pointr,
01659         ibp,nleft,ibkmin,iter;
01660     double f1,f2,dt,dtm,tsum,dibp,zibp,dibp2,bkmin,
01661            tu=0,tl=0,wmc,wmp,wmw,tj,tj0,neggi,
01662            f2_org;
01663     double one=1,zero=0;
01664  
01665     //Check the status of the variables, reset iwhere(i) if necessary;
01666     //compute the Cauchy direction d and the breakpoints t; initialize
01667     //the derivative f1 and the vector p = W'd (for theta = 1).
01668  
01669     if (sbgnrm <= zero)
01670     {
01671       if (iprint >= 0) cout << "Subgnorm = 0.  GCP = X." << endl;
01672       dcopy(n,x,1,xcp,1);
01673       return;
01674     }
01675     bnded = true;
01676     nfree = n + 1;
01677     nbreak = 0;
01678     ibkmin = 0;
01679     bkmin = zero;
01680     col2 = 2*col;
01681     f1 = zero;
01682     if (iprint >= 99) 
01683       cout << "---------------- CAUCHY entered-------------------" << endl;
01684 
01685     //We set p to zero and build it up as we determine d.
01686     for (int i = 1; i <= col2; i++)
01687       p[i] = zero;
01688 
01689     //In the following loop we determine for each variable its bound
01690     //status and its breakpoint, and update p accordingly.
01691     //Smallest breakpoint is identified.
01692 
01693     for (int i = 1; i <= n; i++)      
01694     {
01695       neggi = -g[i];  
01696       if (iwhere[i] != 3 && iwhere[i] != -1)
01697       {
01698         //if x(i) is not a constant and has bounds,
01699         //compute the difference between x(i) and its bounds.
01700         if (nbd[i] <= 2) tl = x[i] - l[i];
01701         if (nbd[i] >= 2) tu = u[i] - x[i];
01702 
01703         //If a variable is close enough to a bound
01704         //we treat it as at bound.
01705         xlower = (nbd[i] <= 2 && tl <= zero);
01706         xupper = (nbd[i] >= 2 && tu <= zero);
01707 
01708         //reset iwhere(i).
01709         iwhere[i] = 0;
01710         if (xlower)
01711         { 
01712           if (neggi <= zero) iwhere[i] = 1;
01713         }
01714         else 
01715         if (xupper)
01716         {
01717           if (neggi >= zero) iwhere[i] = 2;
01718         }
01719         else
01720         {
01721           if (fabs(neggi) <= zero) iwhere[i] = -3;
01722         }
01723       }
01724       pointr = head;
01725       if (iwhere[i] != 0 && iwhere[i] != -1)
01726         d[i] = zero;
01727       else
01728       {
01729         d[i] = neggi;
01730         f1 -= neggi*neggi;
01731         //calculate p := p - W'e_i* (g_i).
01732         for (int j = 1; j <= col; j++)
01733         {
01734           p[j] += wy[getIdx(i,pointr,n)] * neggi;
01735           p[col + j] += ws[getIdx(i,pointr,n)] * neggi;
01736           pointr = pointr%m + 1;
01737         }
01738         if (nbd[i] <= 2 && nbd[i] != 0 && neggi < zero)
01739         {
01740           //x[i] + d[i] is bounded; compute t[i].
01741           nbreak += 1;
01742           iorder[nbreak] = i;
01743           t[nbreak] = tl/(-neggi);
01744           if (nbreak == 1 || t[nbreak] < bkmin)
01745           {
01746             bkmin = t[nbreak];
01747             ibkmin = nbreak;
01748           }
01749         }
01750         else
01751         if (nbd[i] >= 2 && neggi > zero)
01752         {
01753           //x(i) + d(i) is bounded; compute t(i).
01754           nbreak += 1;
01755           iorder[nbreak] = i;
01756           t[nbreak] = tu/neggi;
01757           if (nbreak == 1 || t[nbreak] < bkmin)
01758           {
01759             bkmin = t[nbreak];
01760             ibkmin = nbreak;
01761           }          
01762         }
01763         else
01764         {
01765           //x(i) + d(i) is not bounded.
01766           nfree -= 1;
01767           iorder[nfree] = i;
01768           if (fabs(neggi) > zero) bnded = false;
01769         }
01770       }
01771     } //for (int i = 1; i <= n; i++)      
01772 
01773  
01774     //The indices of the nonzero components of d are now stored
01775     //in iorder(1),...,iorder(nbreak) and iorder(nfree),...,iorder(n).
01776     //The smallest of the nbreak breakpoints is in t(ibkmin)=bkmin.
01777  
01778     if (theta != one)
01779     {
01780       //complete the initialization of p for theta not= one.
01781       dscal(col,theta,&(p[col+1-1]),1);
01782     }
01783  
01784     //Initialize GCP xcp = x.
01785 
01786     dcopy(n,x,1,xcp,1);
01787 
01788     if (nbreak == 0 && nfree == n + 1)
01789     {
01790       //is a zero vector, return with the initial xcp as GCP.
01791       if (iprint > 100) 
01792       {
01793         cout << "Cauchy X = ";
01794         for (int i = 1; i <= n; i++)
01795           cout << xcp[i] << " ";
01796         cout << endl;
01797       }
01798       return;
01799     }    
01800     
01801     //Initialize c = W'(xcp - x) = 0.
01802     
01803     for (int j = 1; j <= col2; j++)
01804       c[j] = zero;
01805     
01806     //Initialize derivative f2.
01807     
01808     f2 = -theta*f1;
01809     f2_org = f2;
01810     if (col > 0) 
01811     {
01812       bmv(m,sy,wt,col,p,v,info);
01813       if (info != 0) return;
01814       f2 -= ddot(col2,v,1,p,1);
01815     }
01816     dtm = -f1/f2;
01817     tsum = zero;
01818     nint = 1;
01819     if (iprint >= 99)
01820       cout << "There are " << nbreak << " breakpoints" << endl;
01821     
01822     //If there are no breakpoints, locate the GCP and return. 
01823     
01824     if (nbreak == 0) goto goto888;
01825     
01826     nleft = nbreak;
01827     iter = 1;
01828     
01829     tj = zero;
01830     
01831     //------------------- the beginning of the loop -------------------------
01832     
01833   goto777:
01834     
01835     //Find the next smallest breakpoint;
01836     //compute dt = t(nleft) - t(nleft + 1).
01837     
01838     tj0 = tj;
01839     if (iter == 1) 
01840     {
01841       //Since we already have the smallest breakpoint we need not do
01842       //heapsort yet. Often only one breakpoint is used and the
01843       //cost of heapsort is avoided.
01844       tj = bkmin;
01845       ibp = iorder[ibkmin];
01846     }
01847     else
01848     {
01849       if (iter == 2)
01850       {
01851         //Replace the already used smallest breakpoint with the
01852         //breakpoint numbered nbreak > nlast, before heapsort call.
01853         if (ibkmin != nbreak)
01854         {
01855           t[ibkmin] = t[nbreak];
01856           iorder[ibkmin] = iorder[nbreak];
01857         }
01858         //Update heap structure of breakpoints
01859         //(if iter=2, initialize heap).
01860       }
01861       
01862       hpsolb(nleft,t,iorder,iter-2);
01863       tj = t[nleft];
01864      ibp = iorder[nleft];    
01865     }    
01866 
01867     dt = tj - tj0;
01868     
01869     if (dt != zero && iprint >= 100)
01870     {
01871       cout << "Piece    " << nint << " --f1, f2 at start point " 
01872            << f1 << "," << f2 << endl;
01873       cout << "Distance to the next break point = " << dt << endl;
01874       cout << "Distance to the stationary point = " << dtm << endl;
01875     }
01876     
01877     //If a minimizer is within this interval, locate the GCP and return. 
01878     
01879     if (dtm < dt) goto goto888;
01880     
01881     //Otherwise fix one variable and
01882     //reset the corresponding component of d to zero.
01883     
01884     tsum += dt;
01885     nleft -= 1;
01886     iter += 1;
01887     dibp = d[ibp];
01888     d[ibp] = zero;
01889     if (dibp > zero) 
01890     {
01891       zibp = u[ibp] - x[ibp];
01892       xcp[ibp] = u[ibp];
01893       iwhere[ibp] = 2;
01894     }
01895     else
01896     {
01897      zibp = l[ibp] - x[ibp];
01898      xcp[ibp] = l[ibp];
01899      iwhere[ibp] = 1;
01900     }
01901     if (iprint >= 100) cout << "Variable  " << ibp << " is fixed." << endl;
01902     if (nleft == 0 && nbreak == n) 
01903     {
01904       //all n variables are fixed, return with xcp as GCP.
01905       dtm = dt;
01906       goto goto999;
01907     }
01908     
01909     //Update the derivative information.
01910     
01911     nint += 1;
01912     dibp2 = dibp*dibp;
01913     
01914    //Update f1 and f2.
01915     
01916    //temporarily set f1 and f2 for col=0.
01917     f1 += dt*f2 + dibp2 - theta*dibp*zibp;
01918     f2 -= theta*dibp2;
01919     
01920     if (col > 0)
01921     {
01922       //update c = c + dt*p.
01923      daxpy(col2,dt,p,1,c,1);
01924      
01925      //choose wbp,
01926      //the row of W corresponding to the breakpoint encountered.
01927      pointr = head;
01928      for (int j = 1; j <= col; j++)
01929      {
01930        wbp[j] = wy[getIdx(ibp,pointr,n)];
01931        wbp[col + j] = theta*ws[getIdx(ibp,pointr,n)];
01932        pointr = pointr%m + 1;
01933      }
01934      //compute (wbp)Mc, (wbp)Mp, and (wbp)M(wbp)'.
01935      bmv(m,sy,wt,col,wbp,v,info);
01936      if (info != 0) return;
01937      wmc = ddot(col2,c,1,v,1);
01938      wmp = ddot(col2,p,1,v,1); 
01939      wmw = ddot(col2,wbp,1,v,1);
01940      
01941      //update p = p - dibp*wbp. 
01942      daxpy(col2,-dibp,wbp,1,p,1);
01943      
01944      //complete updating f1 and f2 while col > 0.
01945      f1 += dibp*wmc;
01946      f2 += 2.0*dibp*wmp - dibp2*wmw;
01947     }
01948     
01949     f2 = max(epsmch*f2_org,f2);
01950     if (nleft > 0)
01951     {
01952      dtm = -f1/f2;
01953      goto goto777;
01954      //to repeat the loop for unsearched intervals. 
01955     }
01956     else
01957     if(bnded)
01958     {
01959       f1 = zero;
01960       f2 = zero;
01961       dtm = zero;
01962     }
01963     else
01964       dtm = -f1/f2;
01965     
01966     //------------------- the end of the loop -------------------------------
01967     
01968   goto888:
01969     if (iprint >= 99)
01970     {
01971       cout << endl << "GCP found in this segment" << endl
01972            << "Piece    " << nint << " --f1, f2 at start point " 
01973            << f1 << ","  << f2 << endl
01974            << "Distance to the stationary point = " << dtm << endl;
01975     }
01976     
01977     if (dtm <= zero) dtm = zero;
01978     tsum += dtm;
01979     
01980     //Move free variables (i.e., the ones w/o breakpoints) and 
01981     //the variables whose breakpoints haven't been reached.
01982     
01983     daxpy(n,tsum,d,1,xcp,1);
01984     
01985   goto999:
01986     
01987     //Update c = c + dtm*p = W'(x^c - x) 
01988     //which will be used in computing r = Z'(B(x^c - x) + g).
01989    
01990     if (col > 0) daxpy(col2,dtm,p,1,c,1);
01991     if (iprint > 100)
01992     {
01993       cout<< "Cauchy X = ";
01994       for (int i = 1; i <=n; i++)
01995         cout << xcp[i] << " ";
01996       cout << endl;
01997     }
01998     if (iprint >= 99) 
01999       cout << "---------------- exit CAUCHY----------------------" << endl;
02000   }//cauchy()
02001 
02002 
02003 //   ************
02004 //
02005 //   Subroutine cmprlb 
02006 //
02007 //     This subroutine computes r=-Z'B(xcp-xk)-Z'g by using 
02008 //       wa(2m+1)=W'(xcp-x) from subroutine cauchy.
02009 //
02010 //   Subprograms called:
02011 //
02012 //     L-BFGS-B Library ... bmv.
02013 //
02014 //
02015 //                         *  *  *
02016 //
02017 //   NEOS, November 1994. (Latest revision June 1996.)
02018 //   Optimization Technology Center.
02019 //   Argonne National Laboratory and Northwestern University.
02020 //   Written by
02021 //                      Ciyou Zhu
02022 //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
02023 //
02024 //
02025 //   ************
02026     //function
02027   void cmprlb(const int& n, const int& m, const double* const & x, 
02028               const double* const & g, double* const & ws, 
02029               double* const & wy, double* const & sy, 
02030               double* const & wt, const double* const & z, 
02031               double* const & r, double* const & wa, 
02032               const int* const & index, const double& theta, 
02033               const int& col, const int& head, const int& nfree, 
02034               const bool& cnstnd, int& info)
02035   {
02036     //int i,j;
02037     int k,pointr,idx;
02038     double a1,a2;
02039 
02040     if (!cnstnd && col > 0)
02041     {
02042       for (int i = 1; i <= n; i++)
02043         r[i] = -g[i];
02044     }
02045     else
02046     {
02047       for (int i = 1; i <= nfree; i++)
02048       {
02049         k = index[i];
02050         r[i] = -theta*(z[k] - x[k]) - g[k];
02051       }
02052       bmv(m,sy,wt,col,&(wa[2*m+1-1]),&(wa[1-1]),info);
02053       if (info != 0)
02054       {
02055         info = -8;
02056         return;
02057       }
02058       pointr = head;
02059       for (int j = 1; j <= col; j++)
02060       {
02061         a1 = wa[j];
02062         a2 = theta*wa[col + j];
02063         for (int i = 1; i <= nfree; i++)
02064         {
02065           k = index[i];
02066           idx = getIdx(k,pointr,n);
02067           r[i] += wy[idx]*a1 + ws[idx]*a2;
02068         }
02069             
02070         pointr = pointr%m + 1;
02071       }
02072     }
02073   }//cmprlb()
02074 
02075 
02076   //   ************
02077   //
02078   //   Subroutine errclb
02079   //
02080   //   This subroutine checks the validity of the input data.
02081   //
02082   //
02083   //                         *  *  *
02084   //
02085   //   NEOS, November 1994. (Latest revision June 1996.)
02086   //   Optimization Technology Center.
02087   //   Argonne National Laboratory and Northwestern University.
02088   //   Written by
02089   //                      Ciyou Zhu
02090   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
02091   //
02092   //
02093   //   ************
02094     //function
02095   void errclb(const int& n, const int& m, const double& factr, 
02096               const double* const & l, const double* const & u, 
02097               const int* const & nbd, char* const & task, int& info, 
02098               int& k)
02099   {
02100     //int i;
02101     //double one=1.0;
02102     double zero=0.0;
02103 
02104     //Check the input arguments for errors.
02105     
02106     if (n <= 0) strcpy(task,"ERROR: N <= 0");
02107     if (m <= 0) strcpy(task,"ERROR: M <= 0");
02108     if (factr < zero) strcpy(task,"ERROR: FACTR < 0");
02109 
02110     //Check the validity of the arrays nbd[i], u[i], and l[i].
02111     for (int i = 1; i <= n; i++)
02112     {
02113       if (nbd[i] < 0 || nbd[i] > 3)
02114       {
02115         //return
02116         strcpy(task,"ERROR: INVALID NBD");
02117         info = -6;
02118         k = i;
02119       }
02120       if (nbd[i] == 2)
02121       {
02122         if (l[i] > u[i])
02123         {
02124           //return
02125           strcpy(task, "ERROR: NO FEASIBLE SOLUTION");
02126           info = -7;
02127           k = i;
02128         }
02129       }
02130     }
02131   }//errclb
02132 
02133 
02134   //   ************
02135   //
02136   //   Subroutine formk 
02137   //
02138   //   This subroutine forms  the LEL^T factorization of the indefinite
02139   //
02140   //     matrix    K = [-D -Y'ZZ'Y/theta     L_a'-R_z'  ]
02141   //                   [L_a -R_z           theta*S'AA'S ]
02142   //                                                  where E = [-I  0]
02143   //                                                            [ 0  I]
02144   //   The matrix K can be shown to be equal to the matrix M^[-1]N
02145   //     occurring in section 5.1 of [1], as well as to the matrix
02146   //     Mbar^[-1] Nbar in section 5.3.
02147   //
02148   //   n is an integer variable.
02149   //     On entry n is the dimension of the problem.
02150   //     On exit n is unchanged.
02151   //
02152   //   nsub is an integer variable
02153   //     On entry nsub is the number of subspace variables in free set.
02154   //     On exit nsub is not changed.
02155   //
02156   //   ind is an integer array of dimension nsub.
02157   //     On entry ind specifies the indices of subspace variables.
02158   //     On exit ind is unchanged. 
02159   //
02160   //   nenter is an integer variable.
02161   //     On entry nenter is the number of variables entering the 
02162   //       free set.
02163   //     On exit nenter is unchanged. 
02164   //
02165   //   ileave is an integer variable.
02166   //     On entry indx2(ileave),...,indx2(n) are the variables leaving
02167   //       the free set.
02168   //     On exit ileave is unchanged. 
02169   //
02170   //   indx2 is an integer array of dimension n.
02171   //     On entry indx2(1),...,indx2(nenter) are the variables entering
02172   //       the free set, while indx2(ileave),...,indx2(n) are the
02173   //       variables leaving the free set.
02174   //     On exit indx2 is unchanged. 
02175   //
02176   //   iupdat is an integer variable.
02177   //     On entry iupdat is the total number of BFGS updates made so far.
02178   //     On exit iupdat is unchanged. 
02179   //
02180   //   updatd is a logical variable.
02181   //     On entry 'updatd' is true if the L-BFGS matrix is updatd.
02182   //     On exit 'updatd' is unchanged. 
02183   //
02184   //   wn is a double precision array of dimension 2m x 2m.
02185   //     On entry wn is unspecified.
02186   //     On exit the upper triangle of wn stores the LEL^T factorization
02187   //       of the 2*col x 2*col indefinite matrix
02188   //                   [-D -Y'ZZ'Y/theta     L_a'-R_z'  ]
02189   //                   [L_a -R_z           theta*S'AA'S ]
02190   //
02191   //   wn1 is a double precision array of dimension 2m x 2m.
02192   //     On entry wn1 stores the lower triangular part of 
02193   //                   [Y' ZZ'Y   L_a'+R_z']
02194   //                   [L_a+R_z   S'AA'S   ]
02195   //       in the previous iteration.
02196   //     On exit wn1 stores the corresponding updated matrices.
02197   //     The purpose of wn1 is just to store these inner products
02198   //     so they can be easily updated and inserted into wn.
02199   //
02200   //   m is an integer variable.
02201   //     On entry m is the maximum number of variable metric corrections
02202   //       used to define the limited memory matrix.
02203   //     On exit m is unchanged.
02204   //
02205   //   ws, wy, sy, and wtyy are double precision arrays;
02206   //   theta is a double precision variable;
02207   //   col is an integer variable;
02208   //   head is an integer variable.
02209   //     On entry they store the information defining the
02210   //                                        limited memory BFGS matrix:
02211   //       ws(n,m) stores S, a set of s-vectors;
02212   //       wy(n,m) stores Y, a set of y-vectors;
02213   //       sy(m,m) stores S'Y;
02214   //       wtyy(m,m) stores the Cholesky factorization
02215   //                                 of (theta*S'S+LD^(-1)L')
02216   //       theta is the scaling factor specifying B_0 = theta I;
02217   //       col is the number of variable metric corrections stored;
02218   //       head is the location of the 1st s- (or y-) vector in S (or Y).
02219   //     On exit they are unchanged.
02220   //
02221   //   info is an integer variable.
02222   //     On entry info is unspecified.
02223   //     On exit info =  0 for normal return;
02224   //                  = -1 when the 1st Cholesky factorization failed;
02225   //                  = -2 when the 2st Cholesky factorization failed.
02226   //
02227   //   Subprograms called:
02228   //
02229   //     Linpack ... dcopy, dpofa, dtrsl.
02230   //
02231   //
02232   //   References:
02233   //     [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
02234   //     memory algorithm for bound constrained optimization'',
02235   //     SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
02236   //
02237   //     [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: a
02238   //     limited memory FORTRAN code for solving bound constrained
02239   //     optimization problems'', Tech. Report, NAM-11, EECS Department,
02240   //     Northwestern University, 1994.
02241   //
02242   //     (Postscript files of these papers are available via anonymous
02243   //      ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.)
02244   //
02245   //                         *  *  *
02246   //
02247   //   NEOS, November 1994. (Latest revision June 1996.)
02248   //   Optimization Technology Center.
02249   //   Argonne National Laboratory and Northwestern University.
02250   //   Written by
02251   //                      Ciyou Zhu
02252   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
02253   //
02254   //
02255   //   ************
02256     //function
02257   void formk(const int& n, const int& nsub, const int* const & ind, 
02258              const int& nenter, const int& ileave, 
02259              const int* const & indx2, const int& iupdat, 
02260              const bool& updatd, double* const & wn, 
02261              double* const & wn1, const int& m, 
02262              double* const & ws, double* const & wy, 
02263              double* const & sy, const double& theta, 
02264              const int& col, const int& head, int& info)
02265   {
02266     //int i,k;
02267     int m2,ipntr,jpntr,iy,is,jy,js,is1,js1,k1,
02268         col2,pbegin,pend,dbegin,dend,upcl;
02269     int idx1, idx2;
02270     double temp1,temp2,temp3,temp4;
02271     //double one=1.0;
02272     double zero=0.0;
02273 
02274     m2 = 2*m;
02275 
02276     //Form the lower triangular part of
02277     //WN1 = [Y' ZZ'Y   L_a'+R_z'] 
02278     //      [L_a+R_z   S'AA'S   ]
02279     //where L_a is the strictly lower triangular part of S'AA'Y
02280     //      R_z is the upper triangular part of S'ZZ'Y.
02281       
02282     if (updatd)
02283     {
02284       if (iupdat > m)
02285       { 
02286         //shift old part of WN1.
02287         for (int jy = 1; jy <= m-1; jy++)
02288         { 
02289           js = m + jy;
02290           dcopy(m-jy,&(wn1[getIdx(jy+1,jy+1,m2)-1]),1,
02291                      &(wn1[getIdx(jy,jy,m2)-1]),1);
02292           dcopy(m-jy,&(wn1[getIdx(js+1,js+1,m2)-1]),1,
02293                      &(wn1[getIdx(js,js,m2)-1]), 1);
02294           dcopy(m-1, &(wn1[getIdx(m+2,jy+1,m2)-1]), 1,
02295                      &(wn1[getIdx(m+1,jy,m2)-1]),1);
02296         }
02297       }
02298 
02299       //put new rows in blocks (1,1), (2,1) and (2,2).
02300       pbegin = 1;
02301       pend = nsub;
02302       dbegin = nsub + 1;
02303       dend = n;
02304       iy = col;
02305       is = m + col;
02306       ipntr = head + col - 1;
02307       if (ipntr > m) ipntr -= m ;
02308       jpntr = head;
02309   
02310       for (jy = 1; jy <= col; jy++)
02311       {
02312         js = m + jy;
02313         temp1 = zero;
02314         temp2 = zero;
02315         temp3 = zero;
02316         //compute element jy of row 'col' of Y'ZZ'Y
02317         for (int k = pbegin; k <= pend; k++)
02318         {
02319           k1 = ind[k];
02320           temp1 += wy[getIdx(k1,ipntr,n)]*wy[getIdx(k1,jpntr,n)];
02321         }
02322         //compute elements jy of row 'col' of L_a and S'AA'S
02323         for (int k = dbegin; k <= dend; k++)
02324         {
02325           k1 = ind[k];
02326           idx1 = getIdx(k1,ipntr,n);
02327           idx2 = getIdx(k1,jpntr,n);
02328           temp2 += ws[idx1] * ws[idx2];
02329           temp3 += ws[idx1] * wy[idx2];
02330         }
02331         wn1[getIdx(iy,jy,m2)] = temp1;
02332         wn1[getIdx(is,js,m2)] = temp2;
02333         wn1[getIdx(is,jy,m2)] = temp3;
02334         jpntr = jpntr%m + 1;
02335       }
02336  
02337       //put new column in block (2,1).
02338       jy = col;
02339       jpntr = head + col - 1;
02340       if (jpntr > m) jpntr -= m;
02341       ipntr = head;
02342       for (int i = 1; i <= col; i++)
02343       {
02344         is = m + i;
02345         temp3 = zero;
02346         //compute element i of column 'col' of R_z
02347         for (int k = pbegin; k <= pend; k++)
02348         {
02349           k1 = ind[k];
02350           temp3 += ws[getIdx(k1,ipntr,n)]*wy[getIdx(k1,jpntr,n)];
02351         }
02352         ipntr = ipntr%m + 1;
02353         wn1[getIdx(is,jy,m2)] = temp3;
02354       }
02355       upcl = col - 1;
02356     }
02357     else
02358       upcl = col;
02359 
02360     //modify the old parts in blocks (1,1) and (2,2) due to changes
02361     //in the set of free variables.
02362     ipntr = head;
02363     
02364     for (int iy = 1; iy <= upcl; iy++)
02365     {
02366       is = m + iy;
02367       jpntr = head;
02368 
02369       for (int jy = 1; jy <= iy; jy++)
02370       {
02371         js = m + jy;
02372         temp1 = zero;
02373         temp2 = zero;
02374         temp3 = zero;
02375         temp4 = zero;
02376         for (int k = 1; k <= nenter; k++)
02377         {
02378           k1 = indx2[k];
02379           idx1 = getIdx(k1,ipntr,n);
02380           idx2 = getIdx(k1,jpntr,n);
02381           temp1 += wy[idx1]*wy[idx2];
02382           temp2 += ws[idx1]*ws[idx2];
02383         }
02384         for (int k = ileave; k <= n; k++)
02385         {
02386           k1 = indx2[k];
02387           idx1 = getIdx(k1,ipntr,n);
02388           idx2 = getIdx(k1,jpntr,n);
02389           temp3 += wy[idx1]*wy[idx2];
02390           temp4 += ws[idx1]*ws[idx2];
02391         }
02392         wn1[getIdx(iy,jy,m2)] += temp1 - temp3;
02393         wn1[getIdx(is,js,m2)] += temp4 - temp2;
02394         jpntr = jpntr%m + 1;
02395       }
02396       ipntr = ipntr%m + 1;
02397     } 
02398     //modify the old parts in block (2,1).
02399     ipntr = head;
02400 
02401     for (int is = m+1; is <= m + upcl; is++)
02402     {
02403       jpntr = head;
02404       for (int jy = 1; jy <= upcl; jy++)
02405       {
02406         temp1 = zero;
02407         temp3 = zero;
02408 
02409         for (int k = 1; k <= nenter; k++)
02410         {
02411           k1 = indx2[k];
02412           temp1 += ws[getIdx(k1,ipntr,n)]*wy[getIdx(k1,jpntr,n)];
02413         }
02414         for (int k = ileave; k <= n; k++)
02415         {
02416           k1 = indx2[k];
02417           temp3 += ws[getIdx(k1,ipntr,n)]*wy[getIdx(k1,jpntr,n)];
02418         }
02419         if (is <= jy + m)
02420           wn1[getIdx(is,jy,m2)] += temp1 - temp3;
02421         else
02422           wn1[getIdx(is,jy,m2)] += temp3 - temp1;
02423             
02424         jpntr = jpntr%m + 1;
02425       }
02426       ipntr = ipntr%m + 1;
02427     } 
02428     //Form the upper triangle of WN = [D+Y' ZZ'Y/theta   -L_a'+R_z' ] 
02429     //                                [-L_a +R_z        S'AA'S*theta]
02430 
02431     for (int iy = 1; iy <= col; iy++)
02432     {
02433       is = col + iy;
02434       is1 = m + iy;
02435       for (int jy = 1; jy <= iy; jy++)
02436       {
02437         js = col + jy;
02438         js1 = m + jy;
02439         wn[getIdx(jy,iy,m2)] = wn1[getIdx(iy,jy,m2)]/theta;
02440         wn[getIdx(js,is,m2)] = wn1[getIdx(is1,js1,m2)]*theta;
02441       }
02442 
02443       for (int jy = 1; jy <= iy-1; jy++)
02444         wn[getIdx(jy,is,m2)] = -wn1[getIdx(is1,jy,m2)];
02445 
02446       for (int jy = iy; jy <= col; jy++)
02447         wn[getIdx(jy,is,m2)] = wn1[getIdx(is1,jy,m2)];
02448       wn[getIdx(iy,iy,m2)] += sy[getIdx(iy,iy,m)];
02449     }
02450 
02451     //Form the upper triangle of WN= [  LL'            L^-1(-L_a'+R_z')] 
02452     //                               [(-L_a +R_z)L'^-1   S'AA'S*theta  ]
02453 
02454     //first Cholesky factor (1,1) block of wn to get LL'
02455     //with L' stored in the upper triangle of wn.
02456     dpofa(wn,m2,col,info);
02457     if (info != 0) 
02458     {
02459       info = -1;
02460       return;
02461     }
02462 
02463     //then form L^-1(-L_a'+R_z') in the (1,2) block.
02464     col2 = 2*col;
02465     for (int js = col+1; js <= col2; js++)
02466       dtrsl(wn,m2,col,&(wn[getIdx(1,js,m2)-1]),11,info);
02467 
02468 
02469 
02470     //Form S'AA'S*theta + (L^-1(-L_a'+R_z'))'L^-1(-L_a'+R_z') in the
02471     //upper triangle of (2,2) block of wn.
02472     //HH                      
02473     for (int is = col+1; is <= col2; is++)
02474       for (int js = is; js <= col2; js++)
02475         wn[getIdx(is,js,m2)] += ddot(col,&(wn[getIdx(1,is,m2)-1]),1,
02476                                          &(wn[getIdx(1,js,m2)-1]),1);
02477 
02478     //Cholesky factorization of (2,2) block of wn.
02479     dpofa(&(wn[getIdx(col+1,col+1,m2)-1]),m2,col,info);
02480 
02481     if (info != 0)
02482     {
02483       info = -2;
02484       return;
02485     }
02486   }//formk()
02487 
02488 
02489   //   ************
02490   //
02491   //   Subroutine formt
02492   //
02493   //     This subroutine forms the upper half of the pos. def. and symm.
02494   //       T = theta*SS + L*D^(-1)*L', stores T in the upper triangle
02495   //       of the array wt, and performs the Cholesky factorization of T
02496   //       to produce J*J', with J' stored in the upper triangle of wt.
02497   //
02498   //   Subprograms called:
02499   //
02500   //     Linpack ... dpofa.
02501   //
02502   //
02503   //                         *  *  *
02504   //
02505   //   NEOS, November 1994. (Latest revision June 1996.)
02506   //   Optimization Technology Center.
02507   //   Argonne National Laboratory and Northwestern University.
02508   //   Written by
02509   //                      Ciyou Zhu
02510   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
02511   //
02512   //
02513   //   ***********
02514     //function
02515   void formt(const int& m, double* const & wt, double* const& sy,
02516              double* const &  ss, const int& col, const double& theta, 
02517              int& info)
02518   {
02519     //int i,j,k;
02520     int k1, idx;
02521     double ddum;
02522     double zero=0.0;
02523 
02524     //Form the upper half of  T = theta*SS + L*D^(-1)*L',
02525     //store T in the upper triangle of the array wt.
02526     for (int j = 1; j <= col; j++)
02527     {
02528       idx = getIdx(1,j,m);
02529       wt[idx] = theta*ss[idx];
02530     }
02531 
02532     for (int i = 2; i <= col; i++) 
02533       for (int j = i; j <= col; j++) 
02534       {
02535         k1 = min(i,j) - 1;
02536         ddum = zero;
02537         for (int k = 1; k <= k1; k++) 
02538           ddum  += sy[getIdx(i,k,m)]*sy[getIdx(j,k,m)]/sy[getIdx(k,k,m)];
02539         wt[getIdx(i,j,m)] = ddum + theta*ss[getIdx(i,j,m)];
02540       }
02541  
02542     //Cholesky factorize T to J*J' with 
02543     //J' stored in the upper triangle of wt.
02544  
02545     dpofa(wt,m,col,info);
02546     if (info != 0) info = -3;
02547   }//formt()
02548 
02549 
02550   //   ************
02551   //
02552   //   Subroutine freev 
02553   //
02554   //   This subroutine counts the entering and leaving variables when
02555   //     iter > 0, and finds the index set of free and active variables
02556   //     at the GCP.
02557   //
02558   //   cnstnd is a logical variable indicating whether bounds are present
02559   //
02560   //   index is an integer array of dimension n
02561   //     for i=1,...,nfree, index(i) are the indices of free variables
02562   //     for i=nfree+1,...,n, index(i) are the indices of bound variables
02563   //     On entry after the first iteration, index gives 
02564   //       the free variables at the previous iteration.
02565   //     On exit it gives the free variables based on the determination
02566   //       in cauchy using the array iwhere.
02567   //
02568   //   indx2 is an integer array of dimension n
02569   //     On entry indx2 is unspecified.
02570   //     On exit with iter>0, indx2 indicates which variables
02571   //        have changed status since the previous iteration.
02572   //     For i= 1,...,nenter, indx2(i) have changed from bound to free.
02573   //     For i= ileave+1,...,n, indx2(i) have changed from free to bound.
02574   // 
02575   //
02576   //                         *  *  *
02577   //
02578   //   NEOS, November 1994. (Latest revision June 1996.)
02579   //   Optimization Technology Center.
02580   //   Argonne National Laboratory and Northwestern University.
02581   //   Written by
02582   //                      Ciyou Zhu
02583   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
02584   //
02585   //
02586   //   ************
02587     //function
02588   void freev(const int& n, int& nfree, int* const & index, int& nenter, 
02589              int& ileave, int* const & indx2, int* const & iwhere, 
02590              bool& wrk, const bool& updatd, const bool& cnstnd, 
02591              const int& iprint, const int& iter)
02592   {
02593     //int i;
02594     int iact,k;
02595 
02596     nenter = 0;
02597     ileave = n + 1;
02598     if (iter > 0 && cnstnd) 
02599     {
02600       //count the entering and leaving variables.
02601       for (int i = 1; i <= nfree; i++) 
02602       {
02603         k = index[i];
02604         if (iwhere[k] > 0)
02605         {
02606           ileave -= 1;
02607           indx2[ileave] = k;
02608           if (iprint >= 100) 
02609             cout << "Variable " << k<<" leaves the set of free variables"<<endl;
02610         }
02611       }
02612 
02613       for (int i = 1+nfree; i <= n; i++) 
02614       {
02615         k = index[i];
02616         if (iwhere[k] <= 0)
02617         {
02618           nenter += 1;
02619           indx2[nenter] = k;
02620           if (iprint >= 100) 
02621             cout << "Variable " << k<<" enters the set of free variables"<<endl;
02622         }
02623       }
02624       if (iprint >= 99) 
02625         cout << n+1-ileave << " variables leave; " 
02626              << nenter << " variables enter" << endl;
02627     }
02628     wrk = (ileave < n+1) || (nenter > 0) || updatd;
02629  
02630     //Find the index set of free and active variables at the GCP.
02631  
02632     nfree = 0;
02633     iact = n + 1;
02634     for (int i = 1; i <= n; i++) 
02635     {
02636       if (iwhere[i] <= 0)
02637       {
02638         nfree += 1;
02639         index[nfree] = i;
02640       }
02641       else
02642       {
02643         iact -= 1;
02644         index[iact] = i;
02645       }
02646     }
02647 
02648     if (iprint >= 99) 
02649       cout << nfree << " variables are free at GCP " << iter + 1 << endl;
02650   }//freev()
02651 
02652 
02653   //   ************
02654   //
02655   //   Subroutine hpsolb 
02656   //
02657   //   This subroutine sorts out the least element of t, and puts the
02658   //     remaining elements of t in a heap.
02659   // 
02660   //   n is an integer variable.
02661   //     On entry n is the dimension of the arrays t and iorder.
02662   //     On exit n is unchanged.
02663   //
02664   //   t is a double precision array of dimension n.
02665   //     On entry t stores the elements to be sorted,
02666   //     On exit t(n) stores the least elements of t, and t(1) to t(n-1)
02667   //       stores the remaining elements in the form of a heap.
02668   //
02669   //   iorder is an integer array of dimension n.
02670   //     On entry iorder(i) is the index of t(i).
02671   //     On exit iorder(i) is still the index of t(i), but iorder may be
02672   //       permuted in accordance with t.
02673   //
02674   //   iheap is an integer variable specifying the task.
02675   //     On entry iheap should be set as follows:
02676   //       iheap == 0 if t(1) to t(n) is not in the form of a heap,
02677   //       iheap != 0 if otherwise.
02678   //     On exit iheap is unchanged.
02679   //
02680   //
02681   //   References:
02682   //     Algorithm 232 of CACM (J. W. J. Williams): HEAPSORT.
02683   //
02684   //                         *  *  *
02685   //
02686   //   NEOS, November 1994. (Latest revision June 1996.)
02687   //   Optimization Technology Center.
02688   //   Argonne National Laboratory and Northwestern University.
02689   //   Written by
02690   //                      Ciyou Zhu
02691   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
02692   //
02693   //   ************
02694     //function
02695   void hpsolb(const int& n, double* const & t, int* const & iorder, 
02696               const int& iheap)
02697   {
02698     //int k;
02699     int i,j,indxin,indxou;
02700     double ddum,out;
02701 
02702     if (iheap == 0)
02703     {
02704       //Rearrange the elements t[1] to t[n] to form a heap.
02705       for (int k = 2; k <= n; k++) 
02706       {
02707         ddum  = t[k];
02708         indxin = iorder[k];
02709 
02710         //Add ddum to the heap.
02711         i = k;
02712       goto10:
02713         if (i>1)
02714         {
02715           j = i/2;
02716           if (ddum < t[j])
02717           {
02718             t[i] = t[j];
02719             iorder[i] = iorder[j];
02720             i = j;
02721             goto goto10;
02722           }
02723                  
02724         }  
02725         t[i] = ddum;
02726         iorder[i] = indxin;
02727       }
02728     }
02729  
02730     //Assign to 'out' the value of t(1), the least member of the heap,
02731     //and rearrange the remaining members to form a heap as
02732     //elements 1 to n-1 of t.
02733  
02734     if (n > 1)
02735     {
02736       i = 1;
02737       out = t[1];
02738       indxou = iorder[1];
02739       ddum = t[n];
02740       indxin = iorder[n];
02741 
02742       //Restore the heap 
02743     goto30:
02744       j = i+i;
02745       if (j <= n-1) 
02746       {
02747         if (t[j+1] < t[j]) j = j+1;
02748         if (t[j] < ddum )
02749         {
02750           t[i] = t[j];
02751           iorder[i] = iorder[j];
02752           i = j;
02753           goto goto30;
02754         } 
02755       } 
02756       t[i] = ddum;
02757       iorder[i] = indxin;
02758  
02759       //Put the least member in t(n). 
02760 
02761       t[n] = out;
02762       iorder[n] = indxou;
02763     }
02764   }//hpsolb()
02765 
02766 
02767   //   **********
02768   //
02769   //   Subroutine lnsrlb
02770   //
02771   //   This subroutine calls subroutine dcsrch from the Minpack2 library
02772   //     to perform the line search.  Subroutine dscrch is safeguarded so
02773   //     that all trial points lie within the feasible region.
02774   //
02775   //   Subprograms called:
02776   //
02777   //     Minpack2 Library ... dcsrch.
02778   //
02779   //     Linpack ... dtrsl, ddot.
02780   //
02781   //
02782   //                         *  *  *
02783   //
02784   //   NEOS, November 1994. (Latest revision June 1996.)
02785   //   Optimization Technology Center.
02786   //   Argonne National Laboratory and Northwestern University.
02787   //   Written by
02788   //                      Ciyou Zhu
02789   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
02790   //
02791   //
02792   //   **********
02793     //function
02794   void lnsrlb(const int& n, const double* const & l, const double* const & u, 
02795               const int* const& nbd, double* const & x, double& f, 
02796               double& fold, double& gd, double& gdold, double* const& g, 
02797               double* const& d, double* const& r, double* const& t,
02798               double* const& z, double& stp, double& dnorm, double& dtd, 
02799               double& xstep, double& stpmx, const int& iter, int& ifun,
02800               int& iback, int& nfgv, int& info, char* const & task, 
02801               const bool& boxed, const bool& cnstnd, char* const & csave,
02802               int* const & isave, double* const & dsave)
02803   {
02804     //int i;
02805     double a1,a2;
02806     double one=1.0,zero=0.0,big=1e10;
02807     double ftol=1.0e-3,gtol=0.9,xtol=0.1;
02808 
02809     
02810     if (strncmp(task,"FG_LN",5)==0) goto goto556;
02811 
02812     dtd = ddot(n,d,1,d,1);
02813     dnorm = sqrt(dtd);
02814 
02815     //Determine the maximum step length.
02816 
02817     stpmx = big;
02818     if (cnstnd)
02819     {
02820       if (iter == 0)
02821         stpmx = one;
02822       else
02823       {
02824         for (int i = 1; i <= n; i++) 
02825         {
02826           a1 = d[i];
02827           if (nbd[i] != 0)
02828           {
02829             if (a1 < zero && nbd[i] <= 2)
02830             {
02831               a2 = l[i] - x[i];
02832               if (a2 >= zero)
02833                 stpmx = zero;
02834               else 
02835               if (a1*stpmx < a2)
02836                 stpmx = a2/a1;
02837             }
02838             else 
02839             if (a1 > zero && nbd[i] >= 2)
02840             {
02841               a2 = u[i] - x[i];
02842               if (a2 <= zero)
02843                 stpmx = zero;
02844               else 
02845               if (a1*stpmx > a2)
02846                 stpmx = a2/a1;
02847             }
02848           }
02849         } // for (int i = 1; i <= n; i++) 
02850       }
02851     }
02852  
02853     if (iter == 0 && !boxed)
02854       stp = min(one/dnorm, stpmx);
02855     else
02856       stp = one;
02857 
02858     dcopy(n,x,1,t,1);
02859     dcopy(n,g,1,r,1);
02860     fold = f;
02861     ifun = 0;
02862     iback = 0;
02863     strcpy(csave,"START");
02864   goto556:
02865     gd = ddot(n,g,1,d,1);
02866     if (ifun == 0)
02867     {
02868       gdold=gd;
02869       if (gd >= zero)
02870       {
02871         //the directional derivative >=0.
02872         //Line search is impossible.
02873         info = -4;
02874         return;
02875       }
02876     }
02877 
02878     dcsrch(f,gd,stp,ftol,gtol,xtol,zero,stpmx,csave,isave,dsave);
02879 
02880     xstep = stp*dnorm;
02881     if (strncmp(csave,"CONV",4) != 0 && strncmp(csave,"WARN",4) != 0) 
02882     {
02883       strcpy(task,"FG_LNSRCH");
02884       ifun += 1;
02885       nfgv += 1;
02886       iback = ifun - 1;
02887       if (stp == one)
02888         dcopy(n,z,1,x,1);
02889       else
02890       {
02891         for (int i = 1; i <= n; i++) 
02892           x[i] = stp*d[i] + t[i];
02893       }
02894     }
02895     else
02896       strcpy(task,"NEW_X");    
02897   } //lnsrlb()
02898 
02899 
02900   //   ************
02901   //
02902   //   Subroutine matupd
02903   //
02904   //     This subroutine updates matrices WS and WY, and forms the
02905   //       middle matrix in B.
02906   //
02907   //   Subprograms called:
02908   //
02909   //     Linpack ... dcopy, ddot.
02910   //
02911   //
02912   //                         *  *  *
02913   //
02914   //   NEOS, November 1994. (Latest revision June 1996.)
02915   //   Optimization Technology Center.
02916   //   Argonne National Laboratory and Northwestern University.
02917   //   Written by
02918   //                      Ciyou Zhu
02919   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
02920   //
02921   //
02922   //   ************
02923     //function
02924   void matupd(const int& n, const int& m, double* const & ws, 
02925               double* const & wy, double* const & sy, double* const & ss, 
02926               double* const & d, double* const & r, int& itail, int& iupdat, 
02927               int& col, int& head, double& theta, double& rr, double& dr, 
02928               double& stp, double& dtd)
02929   {
02930     //int j;
02931     int pointr;
02932     double one=1.0;
02933     int idx;
02934 
02935     //Set pointers for matrices WS and WY.
02936     if (iupdat <= m)
02937     {
02938       col = iupdat;
02939       itail = (head+iupdat-2)%m + 1;
02940     }
02941     else
02942     {
02943       itail = itail%m + 1;
02944       head = head%m + 1;
02945     }
02946  
02947     //Update matrices WS and WY.
02948     idx = getIdx(1,itail,n)-1;
02949     dcopy(n,d,1,&(ws[idx]),1);
02950     dcopy(n,r,1,&(wy[idx]),1);
02951  
02952     //Set theta=yy/ys.
02953     theta = rr/dr;
02954  
02955     //Form the middle matrix in B.
02956     //update the upper triangle of SS,
02957     //and the lower triangle of SY:
02958     if (iupdat > m)
02959     {
02960       //move old information
02961       for (int j = 1; j <= col-1; j++)
02962       {
02963         dcopy(j,&(ss[getIdx(2,j+1,m)-1]),1,&(ss[getIdx(1,j,m)-1]),1);
02964         dcopy(col-j,&(sy[getIdx(j+1,j+1,m)-1]),1,&(sy[getIdx(j,j,m)-1]),1);
02965       }
02966     }
02967 
02968     //add new information: the last row of SY
02969     //and the last column of SS:
02970     pointr = head;
02971     for (int j = 1; j <= col-1; j++)
02972     {
02973       idx = getIdx(1,pointr,n)-1;
02974       sy[getIdx(col,j,m)] = ddot(n,d,1,&(wy[idx]),1);
02975       ss[getIdx(j,col,m)] = ddot(n,&(ws[idx]),1,d,1);   
02976       pointr = pointr%m + 1;
02977     }
02978 
02979     idx = getIdx(col,col,m);
02980     if (stp == one)
02981       ss[idx] = dtd;
02982     else
02983       ss[idx] = stp*stp*dtd;
02984     
02985     sy[idx] = dr;
02986   }//matupd() 
02987 
02988 
02989   //   ************
02990   //
02991   //   Subroutine prn1lb
02992   //
02993   //   This subroutine prints the input data, initial point, upper and
02994   //     lower bounds of each variable, machine precision, as well as 
02995   //     the headings of the output.
02996   //
02997   //
02998   //                         *  *  *
02999   //
03000   //   NEOS, November 1994. (Latest revision June 1996.)
03001   //   Optimization Technology Center.
03002   //   Argonne National Laboratory and Northwestern University.
03003   //   Written by
03004   //                      Ciyou Zhu
03005   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
03006   //
03007   //
03008   //   ************
03009     //function
03010   void prn1lb(const int& n, const int& m, const double* const & l, 
03011               const double* const & u, const double* const & x, 
03012               const int& iprint, ofstream* itfile, const double& epsmch)
03013   {
03014     //int i;
03015 
03016     if (iprint >= 0)
03017     {
03018       cout << "RUNNING THE L-BFGS-B CODE, " << endl
03019            << "epsmch = machine precision" << endl
03020            << "it    = iteration number" << endl
03021            << "nf    = number of function evaluations" << endl
03022            << "nint  = number of segments explored during the Cauchy search" 
03023            << endl
03024            << "nact  = number of active bounds at the generalized Cauchy point"
03025            << endl
03026            << "sub   = manner in which the subspace minimization terminated:"
03027            << endl
03028            <<"con = converged, bnd = a bound was reached" << endl
03029            << "itls  = number of iterations performed in the line search" 
03030            << endl
03031            << "stepl = step length used" << endl
03032            << "tstep = norm of the displacement (total step)" << endl
03033            << "projg = norm of the projected gradient" << endl
03034            << "f     = function value" << endl
03035            << "Machine precision = " << epsmch << endl;
03036       cout << "N = " << n << ",    M = " << m << endl;
03037       if (iprint >= 1)
03038       {
03039         *itfile << "RUNNING THE L-BFGS-B CODE, epsmch = " 
03040                 << "it    = iteration number" << endl
03041                 << "nf    = number of function evaluations" << endl
03042                 <<"nint  = number of segments explored during the Cauchy search"
03043                 << endl
03044                 <<"nact  = number of active bounds at generalized Cauchy point"
03045                 << endl
03046                 <<"sub   =manner in which the subspace minimization terminated:"
03047                 << endl
03048                 <<"con = converged, bnd = a bound was reached" << endl
03049                 << "itls  = number of iterations performed in the line search" 
03050                 << endl
03051                 << "stepl = step length used" << endl
03052                 << "tstep = norm of the displacement (total step)" << endl
03053                 << "projg = norm of the projected gradient" << endl
03054                 << "f     = function value" << endl
03055                 << "Machine precision = " << epsmch << endl;
03056         *itfile << "N = " << n << ",    M = " << m << endl;
03057         *itfile << "   it   nf  nint  nact  sub  itls  stepl    tstep     projg"
03058                 << "        f" << endl;
03059         if (iprint > 100)
03060         {
03061           cout << "L = ";
03062           for (int i = 1; i <= n; i++) cout << l[i] << " "; 
03063           cout << endl;
03064           cout << "X0 = ";
03065           for (int i = 1; i <= n; i++) cout << x[i] << " "; 
03066           cout << endl;
03067           cout << "U = ";
03068           for (int i = 1; i <= n; i++) cout << u[i] << " ";
03069           cout << endl;
03070         }
03071       }
03072     }
03073   } //prn2lb()
03074 
03075 
03076   //   ************
03077   //
03078   //   Subroutine prn2lb
03079   //
03080   //   This subroutine prints out new information after a successful
03081   //     line search. 
03082   //
03083   //
03084   //                         *  *  *
03085   //
03086   //   NEOS, November 1994. (Latest revision June 1996.)
03087   //   Optimization Technology Center.
03088   //   Argonne National Laboratory and Northwestern University.
03089   //   Written by
03090   //                      Ciyou Zhu
03091   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
03092   //
03093   //
03094   //   ************
03095     //function
03096   void prn2lb(const int& n, const double* const & x, const double& f, 
03097               const double* const & g, const int& iprint, 
03098               ofstream* itfile, const int& iter, const int& nfgv, 
03099               const int& nact, const double& sbgnrm, const int& nint, 
03100               char* const & word, const int& iword, const int& iback, 
03101               const double& stp, const double& xstep)
03102   {
03103     //int i;
03104     int imod;
03105 
03106     //'word' records the status of subspace solutions.
03107     if (iword == 0)
03108     {
03109       //the subspace minimization converged.
03110       strcpy(word, "con");
03111     }
03112     else 
03113     if (iword == 1)
03114     {
03115       //the subspace minimization stopped at a bound.
03116       strcpy(word, "bnd");
03117     }
03118     else 
03119     if (iword == 5)
03120     {
03121       //the truncated Newton step has been used.
03122       strcpy(word, "TNT");
03123 
03124     }      
03125     else
03126       strcpy(word, "---");
03127 
03128     if (iprint >= 99)
03129     {
03130       cout << "LINE SEARCH " << iback <<" times; norm of step = " <<xstep<<endl;
03131       cout << "At iterate " << iter << " f=" << f <<"  |proj g|="<<sbgnrm<<endl;
03132 
03133       if (iprint > 100)
03134       { 
03135         cout << "X = " << endl;
03136         for (int i = 1; i <= n; i++) cout << x[i] << " ";
03137         cout << endl;
03138         cout << "G = " << endl;
03139         for (int i = 1; i <= n; i++) cout << g[i] << " ";
03140         cout << endl;
03141       }
03142     }
03143     else 
03144     if (iprint > 0)
03145     {
03146       imod = iter%iprint;
03147       if (imod == 0) {
03148         cout << "At iterate " << iter << " f="<<f<< "  |proj g|="<<sbgnrm<<endl;
03149       }
03150     }
03151     if (iprint >= 1)
03152       *itfile << " " << iter << " " << nfgv << " " << nint << " " << nact << " "
03153            << word << " " << iback << " " << stp << " " << xstep << " " 
03154            << sbgnrm << " " << f << endl;
03155   }//prn2lb()
03156 
03157 
03158   //   ************
03159   //
03160   //   Subroutine prn3lb
03161   //
03162   //   This subroutine prints out information when either a built-in
03163   //     convergence test is satisfied or when an error message is
03164   //     generated.
03165   //     
03166   //
03167   //                         *  *  *
03168   //
03169   //   NEOS, November 1994. (Latest revision June 1996.)
03170   //   Optimization Technology Center.
03171   //   Argonne National Laboratory and Northwestern University.
03172   //   Written by
03173   //                      Ciyou Zhu
03174   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
03175   //
03176   //
03177   //   ************
03178     //function
03179   void prn3lb(const int& n, const double* const & x, double& f, 
03180               const char* const & task, const int& iprint, 
03181               const int& info, ofstream* itfile, const int& iter, 
03182               const int& nfgv, const int& nintol, const int& nskip, 
03183               const int& nact, const double& sbgnrm, const double& time, 
03184               const int& nint, const char* const & word, const int& iback, 
03185               const double& stp,const double& xstep, const int& k, 
03186               const double& cachyt, const double& sbtime, const double& lnscht)
03187   {
03188     //int i;
03189     if (strncmp(task,"ERROR",5)==0) goto goto999;
03190 
03191     if (iprint >= 0)
03192     {
03193       cout << "           * * *" 
03194            << "Tit   = total number of iterations" << endl
03195            << "Tnf   = total number of function evaluations" << endl
03196            << "Tnint = total number of segments explored during"
03197            << " Cauchy searches" << endl
03198            << "Skip  = number of BFGS updates skipped" << endl
03199            << "Nact  = number of active bounds at final generalized"
03200            << " Cauchy point" << endl
03201            << "Projg = norm of the final projected gradient" << endl
03202            << "F     = final function value" << endl
03203            << "           * * *" << endl;
03204       
03205       cout << "   N   Tit  Tnf  Tnint  Skip  Nact     Projg        F" << endl;
03206       cout << " " << n << " " << iter << " " << nfgv << " " << nintol << " " 
03207            << nskip << " " << nact << " " << sbgnrm << " " << f << endl;
03208       if (iprint >= 100)
03209       {
03210         cout << "X = ";
03211         for (int i = 1; i <= n; i++)
03212           cout << x[i] << " ";
03213         cout << endl;
03214       }
03215       if (iprint >= 1) cout << " F = " << f << endl;
03216     }
03217        
03218   goto999:
03219 
03220     if (iprint >= 0)
03221     {
03222       cout << task << endl;
03223       if (info != 0)
03224       {
03225         if (info == -1)
03226           cout << "Matrix in 1st Cholesky factorization in formk is not " 
03227                << "Pos. Def." << endl;
03228         if (info == -2)
03229           cout << "Matrix in 2st Cholesky factorization in formk is not "
03230                << "Pos. Def." << endl;
03231         if (info == -3) 
03232           cout << "Matrix in the Cholesky factorization in formt is not "
03233                << "Pos. Def." << endl;
03234         if (info == -4)
03235           cout << "Derivative >= 0, backtracking line search impossible."
03236                << endl << "Previous x, f and g restored." << endl
03237                << "Possible causes: 1 error in function or gradient "
03238                <<"evaluation;" << endl
03239                << "2 rounding errors dominate computation." << endl;
03240         if (info == -5) 
03241           cout << "Warning:  more than 10 function and gradient" << endl
03242                << "evaluations in the last line search.  Termination"
03243                << "may possibly be caused by a bad search direction."<<endl;
03244         if (info == -6) 
03245           cout << " Input nbd(" << k << ") is invalid."<<endl;
03246         if (info == -7)
03247           cout << " l(" << k << ") > u(" << k << ").  No feasible solution."
03248                << endl;
03249         if (info == -8) 
03250           cout << "The triangular system is singular" << endl;
03251         if (info == -9)
03252           cout << " Line search cannot locate an adequate point after"<<endl
03253                << " 20 function and gradient evaluations. Previous x, f and"
03254                << " g restored." << endl
03255                << "Possible causes: 1 error in function or gradient "
03256                << "evaluation; 2 rounding error dominate computation" 
03257                << endl;
03258       }
03259       
03260       if (iprint >= 1) 
03261         cout << "Cauchy                time " << cachyt << " seconds."<<endl
03262              << "Subspace minimization time " << sbtime << " seconds."<<endl
03263              << "Line search           time " << lnscht << " seconds."<<endl;
03264       
03265       cout << "Total User time " << time << " seconds." << endl;
03266 
03267       if (iprint >= 1)
03268       {
03269         if (info == -4 || info == -9)
03270         {              
03271           *itfile << " " << n << " " << iter << " " << nfgv << " " << nintol 
03272                  << " " << nskip << " " << nact << " " << sbgnrm << " " << f
03273                  << endl;
03274         }
03275         *itfile << task << endl;
03276         if (info != 0)
03277         {
03278           if (info == -1)
03279             *itfile << "Matrix in 1st Cholesky factorization in formk is not"
03280                     << " Pos. Def." << endl;
03281           if (info == -2)
03282             *itfile << "Matrix in 2st Cholesky factorization in formk is not"
03283                     << " Pos. Def." << endl;
03284           if (info == -3) 
03285             *itfile << "Matrix in the Cholesky factorization in formt is not"
03286                     << " Pos. Def." << endl;
03287           if (info == -4)
03288             *itfile << "Derivative>=0, backtracking line search impossible."
03289                     << endl << "Previous x, f and g restored." << endl
03290                     << "Possible causes: 1 error in function or gradient "
03291                     <<"evaluation;" << endl
03292                     << "2 rounding errors dominate computation." << endl;
03293           if (info == -5) 
03294             *itfile << "Warning:  more than 10 function and gradient" << endl
03295                     << "evaluations in the last line search.  Termination"
03296                     << "may possibly be caused by a bad search direction."
03297                     << endl;
03298           if (info == -8) 
03299             cout << "The triangular system is singular" << endl;
03300           if (info == -9)
03301             cout << " Line search cannot locate an adequate point after"
03302                  << endl
03303                  << " 20 function and gradient evaluations. Previous x, f "
03304                  << "and g restored." << endl
03305                  << "Possible causes: 1 error in function or gradient "
03306                  << "evaluation; 2 rounding error dominate computation" 
03307                  << endl;
03308         }
03309         *itfile << "Total User time " << time << " seconds." << endl;
03310       }
03311     }    
03312   }//prn3lb()
03313 
03314   
03315   //   ************
03316   //
03317   //   Subroutine projgr
03318   //
03319   //   This subroutine computes the infinity norm of the projected
03320   //     gradient.
03321   //
03322   //
03323   //                         *  *  *
03324   //
03325   //   NEOS, November 1994. (Latest revision June 1996.)
03326   //   Optimization Technology Center.
03327   //   Argonne National Laboratory and Northwestern University.
03328   //   Written by
03329   //                      Ciyou Zhu
03330   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
03331   //
03332   //
03333   //   ************
03334     //functions
03335   void projgr(const int& n, const double* const & l, const double* const & u, 
03336               const int* const & nbd, const double* const & x, 
03337               const double* const & g, double& sbgnrm)
03338   {
03339     //int i;
03340     double gi;
03341     //double one=1.0;
03342     double zero=0.0;
03343 
03344     sbgnrm = zero;
03345     for (int i = 1; i <= n; i++)
03346     {
03347       gi = g[i];
03348       if (nbd[i] != 0)
03349       {
03350         if (gi < zero)
03351         {
03352           if (nbd[i] >= 2) gi = max((x[i]-u[i]),gi);
03353         }
03354         else
03355         {
03356           if (nbd[i] <= 2) gi = min((x[i]-l[i]),gi);
03357         }
03358       }
03359       sbgnrm = max(sbgnrm,fabs(gi));
03360     }
03361   }//projgr()
03362 
03363 
03364   //   ************
03365   //
03366   //   Subroutine subsm
03367   //
03368   //   Given xcp, l, u, r, an index set that specifies
03369   //     the active set at xcp, and an l-BFGS matrix B 
03370   //     (in terms of WY, WS, SY, WT, head, col, and theta), 
03371   //     this subroutine computes an approximate solution
03372   //     of the subspace problem
03373   //
03374   //    (P)   min Q(x) = r'(x-xcp) + 1/2 (x-xcp)' B (x-xcp)
03375   //
03376   //           subject to l<=x<=u
03377   //                    x_i=xcp_i for all i in A(xcp)
03378   //                  
03379   //    along the subspace unconstrained Newton direction 
03380   //    
03381   //       d = -(Z'BZ)^(-1) r.
03382   //
03383   //     The formula for the Newton direction, given the L-BFGS matrix
03384   //     and the Sherman-Morrison formula, is
03385   //
03386   //       d = (1/theta)r + (1/theta*2) Z'WK^(-1)W'Z r.
03387   //  
03388   //     where
03389   //               K = [-D -Y'ZZ'Y/theta     L_a'-R_z'  ]
03390   //                   [L_a -R_z           theta*S'AA'S ]
03391   //
03392   //   Note that this procedure for computing d differs 
03393   //   from that described in [1]. One can show that the matrix K is
03394   //   equal to the matrix M^[-1]N in that paper.
03395   //
03396   //   n is an integer variable.
03397   //     On entry n is the dimension of the problem.
03398   //     On exit n is unchanged.
03399   //
03400   //   m is an integer variable.
03401   //     On entry m is the maximum number of variable metric corrections
03402   //       used to define the limited memory matrix.
03403   //     On exit m is unchanged.
03404   //
03405   //   nsub is an integer variable.
03406   //     On entry nsub is the number of free variables.
03407   //     On exit nsub is unchanged.
03408   //
03409   //   ind is an integer array of dimension nsub.
03410   //     On entry ind specifies the coordinate indices of free variables.
03411   //     On exit ind is unchanged.
03412   //
03413   //   l is a double precision array of dimension n.
03414   //     On entry l is the lower bound of x.
03415   //     On exit l is unchanged.
03416   //
03417   //   u is a double precision array of dimension n.
03418   //     On entry u is the upper bound of x.
03419   //     On exit u is unchanged.
03420   //
03421   //   nbd is a integer array of dimension n.
03422   //     On entry nbd represents the type of bounds imposed on the
03423   //       variables, and must be specified as follows:
03424   //       nbd(i)=0 if x(i) is unbounded,
03425   //              1 if x(i) has only a lower bound,
03426   //              2 if x(i) has both lower and upper bounds, and
03427   //              3 if x(i) has only an upper bound.
03428   //     On exit nbd is unchanged.
03429   //
03430   //   x is a double precision array of dimension n.
03431   //     On entry x specifies the Cauchy point xcp. 
03432   //     On exit x(i) is the minimizer of Q over the subspace of
03433   //                                                      free variables. 
03434   //
03435   //   d is a double precision array of dimension n.
03436   //     On entry d is the reduced gradient of Q at xcp.
03437   //     On exit d is the Newton direction of Q. 
03438   //
03439   //   ws and wy are double precision arrays;
03440   //   theta is a double precision variable;
03441   //   col is an integer variable;
03442   //   head is an integer variable.
03443   //     On entry they store the information defining the
03444   //                                        limited memory BFGS matrix:
03445   //       ws(n,m) stores S, a set of s-vectors;
03446   //       wy(n,m) stores Y, a set of y-vectors;
03447   //       theta is the scaling factor specifying B_0 = theta I;
03448   //       col is the number of variable metric corrections stored;
03449   //       head is the location of the 1st s- (or y-) vector in S (or Y).
03450   //     On exit they are unchanged.
03451   //
03452   //   iword is an integer variable.
03453   //     On entry iword is unspecified.
03454   //     On exit iword specifies the status of the subspace solution.
03455   //       iword = 0 if the solution is in the box,
03456   //               1 if some bound is encountered.
03457   //
03458   //   wv is a double precision working array of dimension 2m.
03459   //
03460   //   wn is a double precision array of dimension 2m x 2m.
03461   //     On entry the upper triangle of wn stores the LEL^T factorization
03462   //       of the indefinite matrix
03463   //
03464   //            k = [-D -Y'ZZ'Y/theta     L_a'-R_z'  ]
03465   //                [L_a -R_z           theta*S'AA'S ]
03466   //                                                  where E = [-I  0]
03467   //                                                            [ 0  I]
03468   //     On exit wn is unchanged.
03469   //
03470   //   iprint is an INTEGER variable that must be set by the user.
03471   //     It controls the frequency and type of output generated:
03472   //      iprint<0    no output is generated;
03473   //      iprint=0    print only one line at the last iteration;
03474   //      0<iprint<99 print also f and |proj g| every iprint iterations;
03475   //      iprint=99   print details of every iteration except n-vectors;
03476   //      iprint=100  print also the changes of active set and final x;
03477   //      iprint>100  print details of every iteration including x and g;
03478   //     When iprint > 0, the file iterate.dat will be created to
03479   //                      summarize the iteration.
03480   //
03481   //   info is an integer variable.
03482   //     On entry info is unspecified.
03483   //     On exit info = 0       for normal return,
03484   //                  = nonzero for abnormal return 
03485   //                                when the matrix K is ill-conditioned.
03486   //
03487   //   Subprograms called:
03488   //
03489   //     Linpack dtrsl.
03490   //
03491   //
03492   //   References:
03493   //
03494   //     [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
03495   //     memory algorithm for bound constrained optimization'',
03496   //     SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
03497   //
03498   //
03499   //
03500   //                         *  *  *
03501   //
03502   //   NEOS, November 1994. (Latest revision June 1996.)
03503   //   Optimization Technology Center.
03504   //   Argonne National Laboratory and Northwestern University.
03505   //   Written by
03506   //                      Ciyou Zhu
03507   //   in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
03508   //
03509   //
03510   //   ************
03511     //function
03512   void subsm(const int& n, const int& m, const int& nsub, const int* const& ind,
03513              const double* const & l, const double* const & u, 
03514              const int* const & nbd, double* const & x, double* const & d, 
03515              double* const & ws, double* const & wy, const double& theta, 
03516              const int& col, const int& head, int& iword, double* const & wv, 
03517              double* const & wn, const int& iprint, int& info) 
03518   {
03519     //int jy,i,j;
03520     int pointr,m2,col2,ibd=0,js,k;
03521     double alpha,dk,temp1,temp2;
03522     double one=1.0,zero=0.0;
03523     int idx;
03524 
03525     if (nsub <= 0) return;
03526     if (iprint >= 99) 
03527       cout << "----------------SUBSM entered-----------------" << endl;
03528 
03529     //Compute wv = W'Zd.
03530 
03531     pointr = head;
03532     for (int i = 1; i <= col; i++)
03533     {
03534       temp1 = zero;
03535       temp2 = zero;
03536       for (int j = 1; j <= nsub; j++)
03537       {
03538         k = ind[j];
03539         idx = getIdx(k,pointr,n);
03540         temp1 += wy[idx]*d[j];
03541         temp2 += ws[idx]*d[j];
03542       }
03543       wv[i] = temp1;
03544       wv[col + i] = theta*temp2;
03545       pointr = pointr%m + 1;
03546     }
03547 
03548 
03549     //Compute wv:=K^(-1)wv.
03550 
03551     m2 = 2*m;
03552     col2 = 2*col;
03553     dtrsl(wn,m2,col2,wv,11,info);
03554 
03555     if (info != 0) return;
03556     for (int i = 1; i <= col; i++)
03557       wv[i] = -wv[i];
03558     dtrsl(wn,m2,col2,wv,01,info);
03559 
03560     if (info != 0) return;
03561  
03562     //Compute d = (1/theta)d + (1/theta**2)Z'W wv.
03563  
03564     pointr = head;
03565     for (int jy = 1; jy <= col; jy++)
03566     {
03567       js = col + jy;
03568       for (int i = 1; i <= nsub; i++)        
03569       {
03570         k = ind[i];
03571         idx = getIdx(k,pointr,n);
03572         d[i] += wy[idx]*wv[jy]/theta + ws[idx]*wv[js];
03573       }
03574       pointr = pointr%m + 1;
03575     }
03576 
03577     for (int i = 1; i <= nsub; i++)
03578       d[i] /= theta;
03579  
03580     //Backtrack to the feasible region.
03581  
03582     alpha = one;
03583     temp1 = alpha;
03584 
03585     for (int i = 1; i <= nsub; i++)
03586     {
03587       k = ind[i];
03588       dk = d[i];
03589       if (nbd[k] != 0)
03590       {
03591             if (dk < zero && nbd[k] <= 2)
03592         {
03593                 temp2 = l[k] - x[k];
03594                 if (temp2 >= zero)
03595                       temp1 = zero;
03596                 else 
03597           if (dk*alpha < temp2)
03598                         temp1 = temp2/dk;               
03599         }
03600             else 
03601         if (dk > zero && nbd[k] >= 2)
03602         {
03603                 temp2 = u[k] - x[k];
03604                 if (temp2 <= zero)
03605                         temp1 = zero;
03606           else
03607           if (dk*alpha > temp2)
03608                         temp1 = temp2/dk;
03609         }
03610         if (temp1 < alpha)
03611         {
03612                 alpha = temp1;
03613                 ibd = i;
03614         }
03615       }
03616     }
03617 
03618 
03619     if (alpha < one)
03620     {
03621       dk = d[ibd];
03622       k = ind[ibd];
03623       if (dk > zero)
03624       {
03625         x[k] = u[k];
03626         d[ibd] = zero;
03627       }
03628       else 
03629       if (dk < zero)
03630       {
03631         x[k] = l[k];
03632         d[ibd] = zero;
03633       }
03634     }
03635 
03636     for (int i = 1; i <= nsub; i++)
03637     {
03638       k = ind[i];
03639       x[k] += alpha*d[i];
03640     } 
03641     
03642     if (iprint >= 99)
03643     {
03644       if (alpha < one)
03645         cout << "ALPHA = " << alpha << " backtrack to the BOX" << endl;
03646       else
03647         cout  << "SM solution inside the box" << endl;
03648 
03649       if (iprint >100)
03650       {
03651         cout << "Subspace solution X = ";
03652         for (int i = 1; i <= n; i++) cout << x[i] << " ";
03653         cout << endl;
03654       }
03655     }
03656  
03657     if (alpha < one)
03658       iword = 1;
03659     else
03660       iword = 0;
03661 
03662     if (iprint >= 99) 
03663       cout << "----------------exit SUBSM --------------------" << endl;    
03664   }//subsm()
03665 
03666 
03667   //   **********
03668   //
03669   //   Subroutine dcsrch
03670   //
03671   //   This subroutine finds a step that satisfies a sufficient
03672   //   decrease condition and a curvature condition.
03673   //
03674   //   Each call of the subroutine updates an interval with 
03675   //   endpoints stx and sty. The interval is initially chosen 
03676   //   so that it contains a minimizer of the modified function
03677   //
03678   //         psi(stp) = f(stp) - f(0) - ftol*stp*f'(0).
03679   //
03680   //   If psi(stp) <= 0 and f'(stp) >= 0 for some step, then the
03681   //   interval is chosen so that it contains a minimizer of f. 
03682   //
03683   //   The algorithm is designed to find a step that satisfies 
03684   //   the sufficient decrease condition 
03685   //
03686   //         f(stp) <= f(0) + ftol*stp*f'(0),
03687   //
03688   //   and the curvature condition
03689   //
03690   //         abs(f'(stp)) <= gtol*abs(f'(0)).
03691   //
03692   //   If ftol is less than gtol and if, for example, the function
03693   //   is bounded below, then there is always a step which satisfies
03694   //   both conditions. 
03695   //
03696   //   If no step can be found that satisfies both conditions, then 
03697   //   the algorithm stops with a warning. In this case stp only 
03698   //   satisfies the sufficient decrease condition.
03699   //
03700   //   A typical invocation of dcsrch has the following outline:
03701   //
03702   //   task = 'START'
03703   //  10 continue
03704   //      call dcsrch( ... )
03705   //      if (task == 'FG') then
03706   //         Evaluate the function and the gradient at stp 
03707   //         goto 10
03708   //         end if
03709   //
03710   //   NOTE: The user must no alter work arrays between calls.
03711   //
03712   //   The subroutine statement is
03713   //
03714   //      subroutine dcsrch(f,g,stp,ftol,gtol,xtol,stpmin,stpmax,
03715   //                        task,isave,dsave)
03716   //   where
03717   //
03718   //     f is a double precision variable.
03719   //       On initial entry f is the value of the function at 0.
03720   //          On subsequent entries f is the value of the 
03721   //          function at stp.
03722   //       On exit f is the value of the function at stp.
03723   //
03724   //    g is a double precision variable.
03725   //       On initial entry g is the derivative of the function at 0.
03726   //          On subsequent entries g is the derivative of the 
03727   //          function at stp.
03728   //       On exit g is the derivative of the function at stp.
03729   //
03730   //    stp is a double precision variable. 
03731   //       On entry stp is the current estimate of a satisfactory 
03732   //          step. On initial entry, a positive initial estimate 
03733   //          must be provided. 
03734   //       On exit stp is the current estimate of a satisfactory step
03735   //          if task = 'FG'. If task = 'CONV' then stp satisfies
03736   //          the sufficient decrease and curvature condition.
03737   //
03738   //     ftol is a double precision variable.
03739   //       On entry ftol specifies a nonnegative tolerance for the 
03740   //          sufficient decrease condition.
03741   //       On exit ftol is unchanged.
03742   //
03743   //     gtol is a double precision variable.
03744   //       On entry gtol specifies a nonnegative tolerance for the 
03745   //          curvature condition. 
03746   //       On exit gtol is unchanged.
03747   //
03748   //    xtol is a double precision variable.
03749   //       On entry xtol specifies a nonnegative relative tolerance
03750   //          for an acceptable step. The subroutine exits with a
03751   //          warning if the relative difference between sty and stx
03752   //          is less than xtol.
03753   //       On exit xtol is unchanged.
03754   //
03755   //    stpmin is a double precision variable.
03756   //       On entry stpmin is a nonnegative lower bound for the step.
03757   //       On exit stpmin is unchanged.
03758   //
03759   //    stpmax is a double precision variable.
03760   //       On entry stpmax is a nonnegative upper bound for the step.
03761   //       On exit stpmax is unchanged.
03762   //
03763   //     task is a character variable of length at least 60.
03764   //       On initial entry task must be set to 'START'.
03765   //       On exit task indicates the required action:
03766   //
03767   //          If task(1:2) = 'FG' then evaluate the function and 
03768   //          derivative at stp and call dcsrch again.
03769   //
03770   //          If task(1:4) = 'CONV' then the search is successful.
03771   //
03772   //          If task(1:4) = 'WARN' then the subroutine is not able
03773   //          to satisfy the convergence conditions. The exit value of
03774   //          stp contains the best point found during the search.
03775   //
03776   //          If task(1:5) = 'ERROR' then there is an error in the
03777   //          input arguments.
03778   //
03779   //       On exit with convergence, a warning or an error, the
03780   //          variable task contains additional information.
03781   //
03782   //     isave is an integer work array of dimension 2.
03783   //       
03784   //     dsave is a double precision work array of dimension 13.
03785   //
03786   //   Subprograms called
03787   //
03788   //     MINPACK-2 ... dcstep
03789   //
03790   //   MINPACK-1 Project. June 1983.
03791   //   Argonne National Laboratory. 
03792   //   Jorge J. More' and David J. Thuente.
03793   //
03794   //   MINPACK-2 Project. October 1993.
03795   //   Argonne National Laboratory and University of Minnesota. 
03796   //   Brett M. Averick, Richard G. Carter, and Jorge J. More'. 
03797   //
03798   //   **********
03799     //function
03800   void dcsrch(double& f, double& g, double& stp, const double& ftol, 
03801               const double& gtol, const double& xtol, const double& stpmin, 
03802               const double& stpmax, char* const & task, int* const & isave, 
03803               double* const & dsave)
03804   {
03805     double zero=0.0,p5=0.5,p66=0.66;
03806     double xtrapl=1.1,xtrapu=4.0;
03807     
03808     bool brackt;
03809     int stage;
03810     double finit,ftest,fm,fx,fxm,fy,fym,ginit,gtest,
03811            gm,gx,gxm,gy,gym,stx,sty,stmin,stmax,width,width1;
03812 
03813     //Initialization block.
03814 
03815     if (strncmp(task,"START",5)==0)
03816     {
03817       //Check the input arguments for errors.
03818 
03819       if (stp < stpmin)    strcpy(task, "ERROR: STP < STPMIN");
03820       if (stp > stpmax)    strcpy(task, "ERROR: STP > STPMAX");
03821       if (g >zero)         strcpy(task, "ERROR: INITIAL G >ZERO");
03822       if (ftol < zero)     strcpy(task, "ERROR: FTOL < ZERO");
03823       if (gtol < zero)     strcpy(task, "ERROR: GTOL < ZERO");
03824       if (xtol < zero)     strcpy(task, "ERROR: XTOL < ZERO");
03825       if (stpmin < zero)   strcpy(task, "ERROR: STPMIN < ZERO");
03826       if (stpmax < stpmin) strcpy(task, "ERROR: STPMAX < STPMIN");
03827 
03828       //Exit if there are errors on input.
03829       if (strncmp(task,"ERROR",5)==0) return;
03830       
03831       //Initialize local variables.
03832 
03833       brackt = false;
03834       stage = 1;
03835       finit = f;
03836       ginit = g;
03837       gtest = ftol*ginit;
03838       width = stpmax - stpmin;
03839       width1 = width/p5;
03840 
03841       //The variables stx, fx, gx contain the values of the step, 
03842       //function, and derivative at the best step. 
03843       //The variables sty, fy, gy contain the value of the step, 
03844       //function, and derivative at sty.
03845       //The variables stp, f, g contain the values of the step, 
03846       //function, and derivative at stp.
03847       
03848       stx = zero;
03849       fx = finit;
03850       gx = ginit;
03851       sty = zero;
03852       fy = finit;
03853       gy = ginit;
03854       stmin = zero;
03855       stmax = stp + xtrapu*stp;
03856       strcpy(task, "FG");
03857 
03858       goto goto1000;
03859     }
03860     else
03861     {
03862       //Restore local variables.
03863       
03864       if (isave[1] == 1)
03865         brackt = true;
03866       else
03867         brackt = false;
03868       
03869       stage  = isave[2]; 
03870       ginit  = dsave[1]; 
03871       gtest  = dsave[2]; 
03872       gx     = dsave[3]; 
03873       gy     = dsave[4]; 
03874       finit  = dsave[5]; 
03875       fx     = dsave[6]; 
03876       fy     = dsave[7]; 
03877       stx    = dsave[8]; 
03878       sty    = dsave[9]; 
03879       stmin  = dsave[10]; 
03880       stmax  = dsave[11]; 
03881       width  = dsave[12]; 
03882       width1 = dsave[13]; 
03883     }
03884 
03885     //If psi(stp) <= 0 and f'(stp) >= 0 for some step, then the
03886     //algorithm enters the second stage.
03887 
03888     ftest = finit + stp*gtest;
03889     if (stage == 1 && f <= ftest && g >= zero) stage = 2;
03890 
03891     //Test for warnings.
03892 
03893     if (brackt && (stp <= stmin || stp >= stmax))
03894       strcpy(task, "WARNING: ROUNDING ERRORS PREVENT PROGRESS");
03895     if (brackt && stmax - stmin <= xtol*stmax) 
03896       strcpy(task, "WARNING: XTOL TEST SATISFIED");
03897     if (stp == stpmax && f <= ftest && g <= gtest) 
03898       strcpy(task, "WARNING: STP = STPMAX");
03899     if (stp == stpmin && (f > ftest || g >= gtest)) 
03900       strcpy(task, "WARNING: STP = STPMIN");
03901     
03902     //Test for convergence.
03903     
03904     if (f <= ftest && fabs(g) <= gtol*(-ginit)) 
03905       strcpy(task, "CONVERGENCE");
03906     
03907     //Test for termination.
03908     
03909     if (strncmp(task,"WARN",4)==0 || strncmp(task,"CONV",4)==0) goto goto1000;
03910     
03911     //A modified function is used to predict the step during the
03912     //first stage if a lower function value has been obtained but 
03913     //the decrease is not sufficient.
03914     
03915     if (stage == 1 && f <= fx && f > ftest)
03916     {
03917       //Define the modified function and derivative values.
03918       
03919       fm = f - stp*gtest;
03920       fxm = fx - stx*gtest;
03921       fym = fy - sty*gtest;
03922       gm = g - gtest;
03923       gxm = gx - gtest;
03924       gym = gy - gtest;
03925       
03926       //Call dcstep to update stx, sty, and to compute the new step.
03927       
03928       dcstep(stx,fxm,gxm,sty,fym,gym,stp,fm,gm,
03929              brackt,stmin,stmax);
03930       
03931       //Reset the function and derivative values for f.
03932       
03933       fx = fxm + stx*gtest;
03934       fy = fym + sty*gtest;
03935       gx = gxm + gtest;
03936       gy = gym + gtest;
03937     }
03938     else
03939     {
03940       //Call dcstep to update stx, sty, and to compute the new step.
03941       
03942       dcstep(stx,fx,gx,sty,fy,gy,stp,f,g,
03943              brackt,stmin,stmax);
03944     }
03945     
03946     //Decide if a bisection step is needed.
03947     
03948     if (brackt)
03949     {
03950       if (fabs(sty-stx) >= p66*width1) stp = stx + p5*(sty - stx);
03951       width1 = width;
03952       width = fabs(sty-stx);
03953     }
03954     
03955     //Set the minimum and maximum steps allowed for stp.
03956     
03957     if (brackt)
03958     {
03959       stmin = min(stx,sty);
03960       stmax = max(stx,sty);
03961     }
03962     else
03963     {
03964       stmin = stp + xtrapl*(stp - stx);
03965       stmax = stp + xtrapu*(stp - stx);
03966     }
03967     
03968     //Force the step to be within the bounds stpmax and stpmin.
03969     
03970     stp = max(stp,stpmin);
03971     stp = min(stp,stpmax);
03972     
03973     //If further progress is not possible, let stp be the best
03974     //point obtained during the search.
03975 
03976     if (brackt && (stp <= stmin || stp >= stmax)
03977         || (brackt && stmax-stmin <= xtol*stmax)) stp = stx;
03978     
03979     //Obtain another function and derivative.
03980     strcpy(task,"FG");
03981     
03982   goto1000:
03983     
03984     //Save local variables.
03985     
03986     if (brackt)
03987       isave[1]  = 1;
03988     else    
03989       isave[1]  = 0;
03990 
03991     isave[2]  = stage;
03992     dsave[1]  = ginit;
03993     dsave[2]  = gtest;
03994     dsave[3]  = gx;
03995     dsave[4]  = gy;
03996     dsave[5]  = finit;
03997     dsave[6]  = fx;
03998     dsave[7]  = fy;
03999     dsave[8]  = stx;
04000     dsave[9]  = sty;
04001     dsave[10] = stmin;
04002     dsave[11] = stmax;
04003     dsave[12] = width;
04004     dsave[13] = width1;
04005   }//dcsrch()
04006 
04007 
04008   //   **********
04009   //
04010   //   Subroutine dcstep
04011   //
04012   //   This subroutine computes a safeguarded step for a search
04013   //   procedure and updates an interval that contains a step that
04014   //   satisfies a sufficient decrease and a curvature condition.
04015   //
04016   //   The parameter stx contains the step with the least function
04017   //   value. If brackt is set to true then a minimizer has
04018   //   been bracketed in an interval with endpoints stx and sty.
04019   //   The parameter stp contains the current step. 
04020   //   The subroutine assumes that if brackt is set to true then
04021   //
04022   //         min(stx,sty) < stp < max(stx,sty),
04023   //
04024   //   and that the derivative at stx is negative in the direction 
04025   //   of the step.
04026   //
04027   //   The subroutine statement is
04028   //
04029   //     subroutine dcstep(stx,fx,dx,sty,fy,dy,stp,fp,dp,brackt,
04030   //                       stpmin,stpmax)
04031   //
04032   //   where
04033   //
04034   //     stx is a double precision variable.
04035   //       On entry stx is the best step obtained so far and is an
04036   //          endpoint of the interval that contains the minimizer. 
04037   //       On exit stx is the updated best step.
04038   //
04039   //     fx is a double precision variable.
04040   //       On entry fx is the function at stx.
04041   //       On exit fx is the function at stx.
04042   //
04043   //     dx is a double precision variable.
04044   //       On entry dx is the derivative of the function at 
04045   //          stx. The derivative must be negative in the direction of 
04046   //          the step, that is, dx and stp - stx must have opposite 
04047   //          signs.
04048   //       On exit dx is the derivative of the function at stx.
04049   //
04050   //     sty is a double precision variable.
04051   //       On entry sty is the second endpoint of the interval that 
04052   //          contains the minimizer.
04053   //       On exit sty is the updated endpoint of the interval that 
04054   //          contains the minimizer.
04055   //
04056   //     fy is a double precision variable.
04057   //       On entry fy is the function at sty.
04058   //       On exit fy is the function at sty.
04059   //
04060   //     dy is a double precision variable.
04061   //       On entry dy is the derivative of the function at sty.
04062   //       On exit dy is the derivative of the function at the exit sty.
04063   //
04064   //     stp is a double precision variable.
04065   //       On entry stp is the current step. If brackt is set to true
04066   //          then on input stp must be between stx and sty. 
04067   //       On exit stp is a new trial step.
04068   //
04069   //     fp is a double precision variable.
04070   //       On entry fp is the function at stp
04071   //       On exit fp is unchanged.
04072   //
04073   //     dp is a double precision variable.
04074   //       On entry dp is the the derivative of the function at stp.
04075   //       On exit dp is unchanged.
04076   //
04077   //     brackt is an logical variable.
04078   //       On entry brackt specifies if a minimizer has been bracketed.
04079   //          Initially brackt must be set to false
04080   //       On exit brackt specifies if a minimizer has been bracketed.
04081   //          When a minimizer is bracketed brackt is set to true
04082   //
04083   //     stpmin is a double precision variable.
04084   //       On entry stpmin is a lower bound for the step.
04085   //       On exit stpmin is unchanged.
04086   //
04087   //     stpmax is a double precision variable.
04088   //       On entry stpmax is an upper bound for the step.
04089   //       On exit stpmax is unchanged.
04090   //
04091   //   MINPACK-1 Project. June 1983
04092   //   Argonne National Laboratory. 
04093   //   Jorge J. More' and David J. Thuente.
04094   //
04095   //   MINPACK-2 Project. October 1993.
04096   //   Argonne National Laboratory and University of Minnesota. 
04097   //   Brett M. Averick and Jorge J. More'.
04098   //
04099   //   **********
04100     //function
04101   void dcstep(double& stx, double& fx, double& dx, double& sty, double& fy, 
04102               double& dy, double& stp, const double& fp, const double& dp, 
04103               bool& brackt, const double& stpmin, const double& stpmax)
04104   {
04105     double zero=0.0,p66=0.66,two=2.0,three=3.0;
04106     double gamma,p,q,r,s,sgnd,stpc,stpf,stpq,theta;
04107 
04108     sgnd = dp*(dx/fabs(dx));
04109 
04110     //First case: A higher function value. The minimum is bracketed. 
04111     //If the cubic step is closer to stx than the quadratic step, the 
04112     //cubic step is taken, otherwise the average of the cubic and 
04113     //quadratic steps is taken.
04114 
04115     if (fp > fx)
04116     {
04117       theta = three*(fx - fp)/(stp - stx) + dx + dp;
04118       s = max(fabs(theta),fabs(dx),fabs(dp));
04119       gamma = s*sqrt( (theta/s)*(theta/s) - (dx/s)*(dp/s) );
04120       if (stp < stx) gamma = -gamma;
04121       p = (gamma - dx) + theta;
04122       q = ((gamma - dx) + gamma) + dp;
04123       r = p/q;
04124       stpc = stx + r*(stp - stx);
04125       stpq = stx + ((dx/((fx - fp)/(stp - stx) + dx))/two)*(stp - stx);
04126       if (fabs(stpc-stx) < fabs(stpq-stx))
04127         stpf = stpc;
04128       else
04129         stpf = stpc + (stpq - stpc)/two;
04130       brackt = true;
04131     }
04132 
04133     //Second case: A lower function value and derivatives of opposite 
04134     //sign. The minimum is bracketed. If the cubic step is farther from 
04135     //stp than the secant step, the cubic step is taken, otherwise the 
04136     //secant step is taken.
04137 
04138     else 
04139     if (sgnd < zero)
04140     {
04141       theta = three*(fx - fp)/(stp - stx) + dx + dp;
04142       s = max(fabs(theta),fabs(dx),fabs(dp));
04143       gamma = s*sqrt( (theta/s)*(theta/s) - (dx/s)*(dp/s) );
04144       if (stp > stx) gamma = -gamma;
04145       p = (gamma - dp) + theta;
04146       q = ((gamma - dp) + gamma) + dx;
04147       r = p/q;
04148       stpc = stp + r*(stx - stp);
04149       stpq = stp + (dp/(dp - dx))*(stx - stp);
04150       if (fabs(stpc-stp) > fabs(stpq-stp))
04151         stpf = stpc;
04152       else
04153         stpf = stpq;
04154       brackt = true;
04155     }
04156 
04157     //Third case: A lower function value, derivatives of the same sign,
04158     //and the magnitude of the derivative decreases.
04159 
04160     else 
04161     if (fabs(dp) < fabs(dx))
04162     {
04163       //The cubic step is computed only if the cubic tends to infinity 
04164       //in the direction of the step or if the minimum of the cubic
04165       //is beyond stp. Otherwise the cubic step is defined to be the 
04166       //secant step.
04167 
04168       theta = three*(fx - fp)/(stp - stx) + dx + dp;
04169       s = max(fabs(theta),fabs(dx),fabs(dp));
04170 
04171       //The case gamma = 0 only arises if the cubic does not tend
04172       //to infinity in the direction of the step.
04173       
04174       gamma = s*sqrt(max(zero, (theta/s)*(theta/s)-(dx/s)*(dp/s)));
04175       if (stp > stx) gamma = -gamma;
04176       p = (gamma - dp) + theta;
04177       q = (gamma + (dx - dp)) + gamma;
04178       r = p/q;
04179       if (r < zero && gamma != zero)
04180         stpc = stp + r*(stx - stp);
04181       else 
04182       if (stp > stx)
04183         stpc = stpmax;
04184       else
04185         stpc = stpmin;
04186       
04187       stpq = stp + (dp/(dp - dx))*(stx - stp);
04188 
04189       if (brackt)
04190       {
04191 
04192         //A minimizer has been bracketed. If the cubic step is 
04193         //closer to stp than the secant step, the cubic step is 
04194         //taken, otherwise the secant step is taken.
04195 
04196         if (fabs(stpc-stp) < fabs(stpq-stp))
04197           stpf = stpc;
04198         else
04199           stpf = stpq;
04200 
04201         if (stp > stx) 
04202           stpf = min(stp+p66*(sty-stp),stpf);
04203         else
04204           stpf = max(stp+p66*(sty-stp),stpf);
04205       }
04206       else
04207       {
04208         //A minimizer has not been bracketed. If the cubic step is 
04209         //farther from stp than the secant step, the cubic step is 
04210         //taken, otherwise the secant step is taken.
04211 
04212         if (fabs(stpc-stp) > fabs(stpq-stp))
04213           stpf = stpc;
04214         else
04215           stpf = stpq;
04216         
04217         stpf = min(stpmax,stpf);
04218         stpf = max(stpmin,stpf);
04219       }
04220     }
04221     //Fourth case: A lower function value, derivatives of the same sign, 
04222     //and the magnitude of the derivative does not decrease. If the 
04223     //minimum is not bracketed, the step is either stpmin or stpmax, 
04224     //otherwise the cubic step is taken.
04225     else
04226     {
04227       if (brackt)
04228       {
04229         theta = three*(fp - fy)/(sty - stp) + dy + dp;
04230         s = max(fabs(theta),fabs(dy),fabs(dp));
04231         gamma = s*sqrt((theta/s)*(theta/s) - (dy/s)*(dp/s));
04232         if (stp > sty) gamma = -gamma;
04233         p = (gamma - dp) + theta;
04234         q = ((gamma - dp) + gamma) + dy;
04235         r = p/q;
04236         stpc = stp + r*(sty - stp);
04237         stpf = stpc;
04238       }
04239       else 
04240       if (stp > stx)
04241         stpf = stpmax;
04242       else
04243         stpf = stpmin;
04244     }
04245 
04246     //Update the interval which contains a minimizer.
04247 
04248     if (fp > fx)
04249     {
04250       sty = stp;
04251       fy = fp;
04252       dy = dp;
04253     }
04254     else
04255     {
04256       if (sgnd < zero)
04257       {
04258         sty = stx;
04259         fy = fx;
04260         dy = dx;
04261       }
04262       stx = stp;
04263       fx = fp;
04264       dx = dp;
04265     }
04266 
04267     //Compute the new step.
04268 
04269     stp = stpf;    
04270   }//dcstep()
04271 
04272 
04273   //   **********
04274   //
04275   //   Function dnrm2
04276   //
04277   //   Given a vector x of length n, this function calculates the
04278   //   Euclidean norm of x with stride incx.
04279   //
04280   //   The function statement is
04281   //
04282   //     double precision function dnrm2(n,x,incx)
04283   //
04284   //   where
04285   //
04286   //     n is a positive integer input variable.
04287   //
04288   //     x is an input array of length n.
04289   //
04290   //     incx is a positive integer variable that specifies the 
04291   //       stride of the vector.
04292   //
04293   //   Subprograms called
04294   //
04295   //     FORTRAN-supplied ... abs, max, sqrt
04296   //
04297   //   MINPACK-2 Project. February 1991.
04298   //   Argonne National Laboratory.
04299   //   Brett M. Averick.
04300   //
04301   //   **********
04302     //function
04303   double dnrm2(int& n,double* const & x, int& incx)
04304   {
04305     //int i;
04306     double scale = 0.0;
04307     double ddnrm2 = 0.0;
04308 
04309     for (int i = 1; i <= n; i+=incx)
04310       scale = max(scale, fabs(x[i]));
04311 
04312     if (scale == 0.0) return ddnrm2;
04313 
04314     for (int i = 1; i <= n; i+=incx)  
04315       ddnrm2 += (x[i]/scale)*(x[i]/scale);
04316 
04317     ddnrm2 = scale*sqrt(ddnrm2);
04318     return ddnrm2;
04319   }
04320 
04321 
04322   //   **********
04323   //
04324   //   Subroutine dpeps
04325   //
04326   //   This subroutine computes the machine precision parameter
04327   //   dpmeps as the smallest floating point number such that
04328   //   1 + dpmeps differs from 1.
04329   //
04330   //   This subroutine is based on the subroutine machar described in
04331   //
04332   //   W. J. Cody,
04333   //   MACHAR: A subroutine to dynamically determine machine parameters,
04334   //   ACM Transactions on Mathematical Software, 14, 1988, pages 303-311.
04335   //
04336   //   The subroutine statement is:
04337   //
04338   //     subroutine dpeps(dpmeps)
04339   //
04340   //   where
04341   //
04342   //     dpmeps is a double precision variable.
04343   //       On entry dpmeps need not be specified.
04344   //       On exit dpmeps is the machine precision.
04345   //
04346   //   MINPACK-2 Project. February 1991.
04347   //   Argonne National Laboratory and University of Minnesota.
04348   //   Brett M. Averick.
04349   //
04350   //   *******
04351     //function
04352   double dpmeps()
04353   {
04354     //int i ;
04355     long int ibeta,irnd,it,itemp,negep;
04356     long double a,b,beta,betain,betah,temp,tempa,temp1,
04357            zero=0.0,one=1.0,two=2.0;
04358     long double ddpmeps;
04359  
04360     //determine ibeta, beta ala malcolm.
04361 
04362     a = one;
04363     b = one;
04364   goto10:
04365     a = a + a;
04366     temp = a + one;
04367     temp1 = temp - a;
04368     if (temp1 - one == zero) goto goto10;
04369    
04370   goto20:
04371     b = b + b;
04372     temp = a + b;
04373     itemp = int(temp - a);
04374     if (itemp == 0) goto goto20;
04375     ibeta = itemp;
04376     beta = double(ibeta);
04377 
04378     //determine it, irnd.
04379 
04380     it = 0;
04381     b = one;
04382   goto30:
04383     it += 1;
04384     b *= beta;
04385     temp = b + one;
04386     temp1 = temp - b;
04387     if (temp1 - one == zero) goto goto30;
04388     irnd = 0;
04389     betah = beta/two;
04390     temp = a + betah;
04391     if (temp - a != zero) irnd = 1;
04392     tempa = a + beta;
04393     temp = tempa + betah;
04394     if ((irnd == 0) && (temp - tempa != zero)) irnd = 2;
04395 
04396     //determine ddpmeps.
04397 
04398     negep = it + 3;
04399     betain = one/beta;
04400     a = one;
04401     for (int i = 1; i <= negep; i++)
04402       a *= betain;
04403 
04404   goto50:
04405     temp = one + a;
04406     if (temp - one != zero) goto goto60;
04407     a *= beta;
04408     goto goto50;
04409 
04410   goto60:
04411     ddpmeps = a;
04412     if ((ibeta == 2) || (irnd == 0)) goto goto70;
04413     a = (a*(one + a))/two;
04414     temp = one + a;
04415     if (temp - one != zero) ddpmeps = a;
04416 
04417   goto70:
04418     return ddpmeps;
04419   }//dpmeps()
04420 
04421 
04422   //   constant times a vector plus a vector.
04423   //   uses unrolled loops for increments equal to one.
04424   //   jack dongarra, linpack, 3/11/78.
04425     //function
04426   void daxpy(const int& n, const double& da, const double* const & dx, 
04427              const int& incx, double* const & dy, const int& incy)
04428   {
04429     //int i;
04430     int ix,iy,m,mp1;
04431     if (n <= 0) return;
04432     if (da == 0.0) return;
04433     if(incx==1 && incy==1) goto goto20;
04434 
04435     //code for unequal increments or equal increments
04436     //not equal to 1
04437 
04438     ix = 1;
04439     iy = 1;
04440     if(incx < 0) ix = (-n+1)*incx + 1;
04441     if(incy < 0) iy = (-n+1)*incy + 1;
04442 
04443     for (int i = 1; i <= n; i++)
04444     {    
04445       dy[iy] += da*dx[ix];
04446       ix += incx;
04447       iy += incy;
04448     }
04449     return;
04450 
04451     //code for both increments equal to 1
04452     //clean-up loop
04453 
04454   goto20:
04455     m = n%4;
04456     if (m == 0) goto goto40;
04457     
04458     for (int i = 1; i <= m; i++)
04459       dy[i] += da*dx[i];
04460 
04461     if (n < 4) return;
04462 
04463   goto40:
04464     mp1 = m + 1;
04465 
04466     for (int i = mp1; i <= n; i+=4)
04467     {
04468       dy[i] += da*dx[i];
04469       dy[i + 1] += da*dx[i + 1];
04470       dy[i + 2] += da*dx[i + 2];
04471       dy[i + 3] += da*dx[i + 3];
04472     }
04473   }//daxpy()
04474 
04475 
04476   //   copies a vector, x, to a vector, y.
04477   //   uses unrolled loops for increments equal to one.
04478   //   jack dongarra, linpack, 3/11/78.
04479     //function  
04480   void dcopy(const int& n, const double* const & dx, const int& incx, 
04481              double* const & dy,const int& incy)
04482   {
04483     //int i;
04484     int ix,iy,m,mp1;
04485 
04486     if (n <= 0) return;
04487     if(incx==1 && incy==1) goto goto20;
04488 
04489     //code for unequal increments or equal increments
04490     //not equal to 1
04491     
04492     ix = 1;
04493     iy = 1;
04494     if (incx < 0) ix = (-n+1)*incx + 1;
04495     if (incy < 0) iy = (-n+1)*incy + 1;
04496     for (int i = 1; i <= n; i++)
04497     {
04498       dy[iy] = dx[ix];
04499       ix += incx;
04500       iy += incy;
04501     }
04502     return;
04503 
04504     //code for both increments equal to 1
04505 
04506     //clean-up loop
04507 
04508   goto20:
04509     m = n%7;
04510     if (m == 0) goto goto40;
04511     for (int i = 1; i <= m; i++)
04512       dy[i] = dx[i];
04513 
04514     if (n < 7) return;
04515 
04516   goto40:
04517     mp1 = m + 1;
04518     for (int i = mp1; i <= n; i+=7)
04519     {
04520       dy[i] = dx[i];
04521       dy[i + 1] = dx[i + 1];
04522       dy[i + 2] = dx[i + 2];
04523       dy[i + 3] = dx[i + 3];
04524       dy[i + 4] = dx[i + 4];
04525       dy[i + 5] = dx[i + 5];
04526       dy[i + 6] = dx[i + 6];
04527     }      
04528   }//dcopy()
04529 
04530 
04531   //forms the dot product of two vectors.
04532   //uses unrolled loops for increments equal to one.
04533   //jack dongarra, linpack, 3/11/78.
04534     //function
04535   double ddot(const int& n, const double* const & dx, const int& incx, 
04536               const double* const & dy, const int& incy)
04537   {
04538     double dtemp;
04539     //int i;
04540     int ix,iy,m,mp1;
04541 
04542     double dddot = 0.0;
04543     dtemp = 0.0;
04544     if (n <= 0) return dddot;
04545     if (incx==1 && incy==1) goto goto20;
04546 
04547     //code for unequal increments or equal increments
04548     //not equal to 1
04549     
04550     ix = 1;
04551     iy = 1;
04552     if (incx < 0) ix = (-n+1)*incx + 1;
04553     if (incy < 0) iy = (-n+1)*incy + 1;
04554 
04555     for (int i = 1; i <= n; i++)
04556     {
04557       dtemp += dx[ix]*dy[iy];
04558       ix += incx;
04559       iy += incy;
04560     }
04561     dddot = dtemp;
04562     return dddot;
04563 
04564     //code for both increments equal to 1
04565 
04566     //clean-up loop
04567 
04568   goto20:
04569     m = n%5;
04570     if (m == 0) goto goto40;
04571 
04572     for (int i = 1; i <= m; i++)
04573       dtemp += dx[i]*dy[i];
04574 
04575     if( n < 5 ) goto goto60;
04576 
04577   goto40:
04578     mp1 = m + 1;
04579 
04580 
04581     for (int i = mp1; i <= n; i+=5)
04582     {
04583       dtemp += dx[i]*dy[i] + dx[i + 1]*dy[i + 1] +
04584                dx[i + 2]*dy[i + 2] + dx[i + 3]*dy[i + 3] + dx[i + 4]*dy[i + 4];
04585     }
04586 
04587   goto60:
04588     dddot = dtemp;
04589     return dddot;
04590   }//ddot()
04591 
04592 
04593   //   dpofa factors a double precision symmetric positive definite
04594   //   matrix.
04595   //
04596   //   dpofa is usually called by dpoco, but it can be called
04597   //   directly with a saving in time if  rcond  is not needed.
04598   //   (time for dpoco) = (1 + 18/n)*(time for dpofa) .
04599   //
04600   //   on entry
04601   //
04602   //      a       double precision(lda, n)
04603   //              the symmetric matrix to be factored.  only the
04604   //              diagonal and upper triangle are used.
04605   //
04606   //      lda     integer
04607   //              the leading dimension of the array  a .
04608   //
04609   //      n       integer
04610   //              the order of the matrix  a .
04611   //
04612   //   on return
04613   //
04614   //      a       an upper triangular matrix  r  so that  a = trans(r)*r
04615   //              where  trans(r)  is the transpose.
04616   //              the strict lower triangle is unaltered.
04617   //              if  info != 0 , the factorization is not complete.
04618   //
04619   //      info    integer
04620   //              = 0  for normal return.
04621   //              = k  signals an error condition.  the leading minor
04622   //                   of order  k  is not positive definite.
04623   //
04624   //   linpack.  this version dated 08/14/78 .
04625   //   cleve moler, university of new mexico, argonne national lab.
04626   //
04627   //   subroutines and functions
04628   //
04629   //   blas ddot
04630   //   fortran sqrt
04631   //
04632   //   internal variables
04633   //  
04634     //function
04635   void dpofa(double* const & a, const int& lda, const int& n, int& info,
04636              bool smallerMatrix=false)
04637   {
04638     double t;
04639     double s;
04640     //int j,k
04641     int jm1;
04642     int idx;
04643     //begin block with ...exits to 40
04644 
04645     for (int j = 1; j <= n; j++)
04646     {
04647       info = j;
04648       s = 0.0;
04649       jm1 = j - 1;
04650       if (jm1 < 1) goto goto20;
04651       for (int k = 1; k <= jm1; k++)
04652       {
04653         idx = getIdx(k,j,lda);
04654         t = a[idx] - ddot(k-1,&(a[getIdx(1,k,lda)-1]),1,
04655                               &(a[getIdx(1,j,lda)-1]),1);
04656         t = t/a[getIdx(k,k,lda)];
04657         a[idx] = t;
04658         s += t*t;
04659       }
04660 
04661     goto20:
04662       idx = getIdx(j,j,lda);
04663       s = a[idx] - s;
04664 
04665       //......exit
04666       if (s <= 0.0) goto goto40;
04667       a[idx] = sqrt(s);
04668     }
04669     info = 0;
04670   goto40:
04671     t = 0;
04672   }//dpofa()
04673 
04674 
04675   //scales a vector by a constant.
04676   //uses unrolled loops for increment equal to one.
04677   //jack dongarra, linpack, 3/11/78.
04678   //modified 3/93 to return if incx <= 0.
04679     //function    
04680   void dscal(const int& n, const double& da, double* const & dx, 
04681              const int& incx)
04682   {
04683     //int i;
04684     int m,mp1,nincx;
04685 
04686     if (n <= 0 || incx <= 0) return;
04687     if (incx == 1) goto goto20;
04688 
04689     //code for increment not equal to 1
04690 
04691     nincx = n*incx;
04692 
04693     for (int i = 1; i <= nincx; i+=incx)
04694       dx[i] = da*dx[i];
04695     return;
04696 
04697     //code for increment equal to 1
04698 
04699     //clean-up loop
04700 
04701   goto20:
04702     m = n%5;
04703     if (m == 0) goto goto40;
04704 
04705     for (int i = 1; i <= m; i++)
04706       dx[i] = da*dx[i];
04707 
04708     if (n < 5) return;
04709 
04710   goto40:
04711     mp1 = m + 1;
04712     for (int i = mp1; i <= n; i+=5)
04713     {
04714       dx[i] = da*dx[i];
04715       dx[i + 1] = da*dx[i + 1];
04716       dx[i + 2] = da*dx[i + 2];
04717       dx[i + 3] = da*dx[i + 3];
04718       dx[i + 4] = da*dx[i + 4];
04719     }
04720   }//dscal()
04721 
04722   //
04723   //
04724   //   dtrsl solves systems of the form
04725   //
04726   //                 t * x = b
04727   //   or
04728   //                 trans(t) * x = b
04729   //
04730   //   where t is a triangular matrix of order n. here trans(t)
04731   //   denotes the transpose of the matrix t.
04732   //
04733   //   on entry
04734   //
04735   //       t         double precision(ldt,n)
04736   //                 t contains the matrix of the system. the zero
04737   //                 elements of the matrix are not referenced, and
04738   //                 the corresponding elements of the array can be
04739   //                 used to store other information.
04740   //
04741   //       ldt       integer
04742   //                 ldt is the leading dimension of the array t.
04743   //
04744   //       n         integer
04745   //                 n is the order of the system.
04746   //
04747   //       b         double precision(n).
04748   //                 b contains the right hand side of the system.
04749   //
04750   //       job       integer
04751   //                 job specifies what kind of system is to be solved.
04752   //                 if job is
04753   //
04754   //                      00   solve t*x=b, t lower triangular,
04755   //                      01   solve t*x=b, t upper triangular,
04756   //                      10   solve trans(t)*x=b, t lower triangular,
04757   //                      11   solve trans(t)*x=b, t upper triangular.
04758   //
04759   //   on return
04760   //
04761   //       b         b contains the solution, if info == 0.
04762   //                 otherwise b is unaltered.
04763   //
04764   //       info      integer
04765   //                 info contains zero if the system is nonsingular.
04766   //                 otherwise info contains the index of
04767   //                 the first zero diagonal element of t.
04768   //
04769   //   linpack. this version dated 08/14/78 .
04770   //   g. w. stewart, university of maryland, argonne national lab.
04771   //
04772   //   subroutines and functions
04773   //
04774   //   blas daxpy,ddot
04775   //   fortran mod
04776     //function
04777   void dtrsl(double* const & t, const int& ldt, const int& n, 
04778              double* const &b, const int& job, int& info)
04779   {
04780     double temp;
04781     int ccase,j;
04782     //int jj;
04783 
04784     //begin block permitting ...exits to 150
04785     
04786     //check for zero diagonal elements.
04787     
04788     for (info = 1; info <= n; info++)
04789     {
04790       //......exit
04791       if (t[getIdx(info,info,ldt)] == 0.0) goto goto150;
04792     }
04793     info = 0;
04794 
04795     //determine the task and go to it.
04796 
04797     ccase = 1;
04798     if (job%10 != 0) ccase = 2;
04799     if ((job%100)/10 != 0) ccase += 2;
04800     if (ccase==1) goto goto20;
04801     if (ccase==2) goto goto50;
04802     if (ccase==3) goto goto80;
04803     if (ccase==4) goto goto110;
04804 
04805     //solve t*x=b for t lower triangular
04806 
04807   goto20:
04808     b[1] /= t[getIdx(1,1,ldt)];
04809     if (n < 2) goto goto40;
04810     for (int j = 2; j <= n; j++)
04811     {
04812       temp = -b[j-1];
04813       daxpy(n-j+1,temp,&(t[getIdx(j,j-1,ldt)-1]),1,&(b[j-1]),1);
04814       b[j] /= t[getIdx(j,j,ldt)];
04815     }
04816   goto40:
04817     goto goto140;
04818 
04819     //solve t*x=b for t upper triangular.
04820 
04821   goto50:    
04822     b[n] /= t[getIdx(n,n,ldt)];
04823     if (n < 2) goto goto70;
04824     for (int jj = 2; jj <= n; jj++)
04825     {
04826       j = n - jj + 1;
04827       temp = -b[j+1];
04828       daxpy(j,temp,&(t[getIdx(1,j+1,ldt)-1]),1,&(b[1-1]),1);
04829       b[j] /= t[getIdx(j,j,ldt)];
04830     }
04831 
04832   goto70:
04833     goto goto140;
04834 
04835     //solve trans(t)*x=b for t lower triangular.
04836 
04837   goto80:
04838     b[n] /= t[getIdx(n,n,ldt)];
04839     if (n < 2) goto goto100;
04840     for (int jj = 2; jj <= n; jj++)
04841     {
04842       j = n - jj + 1;
04843       b[j] = b[j] - ddot(jj-1,&(t[getIdx(j+1,j,ldt)-1]),1,&(b[j+1-1]),1);
04844       b[j] /= t[getIdx(j,j,ldt)];
04845     }
04846   goto100:
04847     goto goto140;
04848 
04849     //solve trans(t)*x=b for t upper triangular.
04850 
04851   goto110:
04852     b[1] /= t[getIdx(1,1,ldt)];
04853     if (n < 2) goto goto130;
04854     for (int j = 2; j <= n; j++)
04855     {
04856       b[j] = b[j] - ddot(j-1,&(t[getIdx(1,j,ldt)-1]),1,&(b[1-1]),1);
04857       b[j] /= t[getIdx(j,j,ldt)];
04858     }
04859 
04860   goto130:
04861     
04862     if (false);
04863 
04864   goto140:
04865 
04866     if (false);
04867 
04868   goto150:
04869 
04870     if (false);
04871     
04872   }//dtrsl()
04873 
04874  private:
04875   Timer timer_;
04876 
04877 };
04878 
04879 #endif

Generated on Sun Jun 7 11:55:20 2009 for Alchemy by  doxygen 1.5.1