private double[] Compute(OptMultivariateFunction function, OptMultivariateGradient gradient, double tolerance, double factr, ref int nMax) { double f = 0; BFGSTask TASK = BFGSTask.START; BFGSTask Csave = BFGSTask.START; int iprint = 0; bool Continue = true; int funcEvaluations = 0; while (Continue) { this._SETULB.Run(this._NumFreeVariables, this.M, ref this._FreeVariables, 0, this._LowerBounds, 0, this._UpperBounds, 0, this._NBD, 0, ref f, ref this._GradientArray, 0, factr, tolerance, ref WA, 0, ref IWA, 0, ref TASK, iprint, ref Csave, ref LSAVE, 0, ref this.ISAVE, 0, ref DSAVE, 0); if (funcEvaluations <= nMax) { if (TASK == BFGSTask.FG || TASK == BFGSTask.FG_LNSRCH || TASK == BFGSTask.FG_ST || TASK == BFGSTask.FG_START) { // c the minimization routine has returned to request the // c function f and gradient g values at the current x. // c Compute function value f for the sample problem. this.UpdateExternalVariables(); funcEvaluations++; f = function(this._ExternalVariables); this._ExternalGradientArray = gradient(this._ExternalVariables); this.UpdateInternalGradient(); // c go back to the minimization routine. Continue = true; } else if (TASK == BFGSTask.NEW_X) { Continue = true; } else { Continue = false; } } else { Continue = false; } } this.UpdateExternalVariables(); nMax = funcEvaluations; return(this._ExternalVariables); }
public void Run(int N, int M, double FACTR, double[] L, int offset_l, double[] U, int offset_u, int[] NBD, int offset_nbd , ref BFGSTask TASK, ref int INFO, ref int K) { #region Variables int I = 0; #endregion #region Array Index Correction int o_l = -1 + offset_l; int o_u = -1 + offset_u; int o_nbd = -1 + offset_nbd; #endregion #region Prolog // c ************ // c // c Subroutine errclb // c // c This subroutine checks the validity of the input data. // c // c // c * * * // c // c NEOS, November 1994. (Latest revision June 1996.) // c Optimization Technology Center. // c Argonne National Laboratory and Northwestern University. // c Written by // c Ciyou Zhu // c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. // c // c // c ************ // c Check the input arguments for errors. #endregion #region Body if (N <= 0) TASK = BFGSTask.ERROR; if (M <= 0) TASK = BFGSTask.ERROR; if (FACTR < ZERO) TASK = BFGSTask.ERROR; // c Check the validity of the arrays nbd(i), u(i), and l(i). for (I = 1; I <= N; I++) { if (NBD[I + o_nbd] < 0 || NBD[I + o_nbd] > 3) { // c return //"ERROR: INVALID NBD"; TASK = BFGSTask.ERROR; INFO = - 6; K = I; } if (NBD[I + o_nbd] == 2) { if (L[I + o_l] > U[I + o_u]) { // c return //"ERROR: NO FEASIBLE SOLUTION" TASK = BFGSTask.ERROR; INFO = - 7; K = I; } } } return; #endregion }
/// <param name="F"> /// is a double precision variable. /// On initial entry f is the value of the function at 0. /// On subsequent entries f is the value of the /// function at stp. /// On exit f is the value of the function at stp. ///</param> /// <param name="G"> /// is a double precision variable. /// On initial entry g is the derivative of the function at 0. /// On subsequent entries g is the derivative of the /// function at stp. /// On exit g is the derivative of the function at stp. /// /// stp is a double precision variable. /// On entry stp is the current estimate of a satisfactory /// step. On initial entry, a positive initial estimate /// must be provided. /// On exit stp is the current estimate of a satisfactory step /// if task = 'FG'. If task = 'CONV' then stp satisfies /// the sufficient decrease and curvature condition. /// /// ftol is a double precision variable. /// On entry ftol specifies a nonnegative tolerance for the /// sufficient decrease condition. /// On exit ftol is unchanged. /// /// gtol is a double precision variable. /// On entry gtol specifies a nonnegative tolerance for the /// curvature condition. /// On exit gtol is unchanged. /// /// xtol is a double precision variable. /// On entry xtol specifies a nonnegative relative tolerance /// for an acceptable step. The subroutine exits with a /// warning if the relative difference between sty and stx /// is less than xtol. /// On exit xtol is unchanged. /// /// stpmin is a double precision variable. /// On entry stpmin is a nonnegative lower bound for the step. /// On exit stpmin is unchanged. /// /// stpmax is a double precision variable. /// On entry stpmax is a nonnegative upper bound for the step. /// On exit stpmax is unchanged. /// /// task is a character variable of length at least 60. /// On initial entry task must be set to 'START'. /// On exit task indicates the required action: /// /// If task(1:2) = 'FG' then evaluate the function and /// derivative at stp and call dcsrch again. /// /// If task(1:4) = 'CONV' then the search is successful. /// /// If task(1:4) = 'WARN' then the subroutine is not able /// to satisfy the convergence conditions. The exit value of /// stp contains the best point found during the search. /// /// If task(1:5) = 'ERROR' then there is an error in the /// input arguments. /// /// On exit with convergence, a warning or an error, the /// variable task contains additional information. /// /// isave is an integer work array of dimension 2. /// /// dsave is a double precision work array of dimension 13. /// /// Subprograms called /// /// MINPACK-2 ... dcstep /// /// MINPACK-1 Project. June 1983. /// Argonne National Laboratory. /// Jorge J. More' and David J. Thuente. /// /// MINPACK-2 Project. October 1993. /// Argonne National Laboratory and University of Minnesota. /// Brett M. Averick, Richard G. Carter, and Jorge J. More'. /// /// ********** /// /// /// /// /// Initialization block. ///</param> /// <param name="STP"> /// is a double precision variable. /// On entry stp is the current estimate of a satisfactory /// step. On initial entry, a positive initial estimate /// must be provided. /// On exit stp is the current estimate of a satisfactory step /// if task = 'FG'. If task = 'CONV' then stp satisfies /// the sufficient decrease and curvature condition. /// /// ftol is a double precision variable. /// On entry ftol specifies a nonnegative tolerance for the /// sufficient decrease condition. /// On exit ftol is unchanged. /// /// gtol is a double precision variable. /// On entry gtol specifies a nonnegative tolerance for the /// curvature condition. /// On exit gtol is unchanged. /// /// xtol is a double precision variable. /// On entry xtol specifies a nonnegative relative tolerance /// for an acceptable step. The subroutine exits with a /// warning if the relative difference between sty and stx /// is less than xtol. /// On exit xtol is unchanged. /// /// stpmin is a double precision variable. /// On entry stpmin is a nonnegative lower bound for the step. /// On exit stpmin is unchanged. /// /// stpmax is a double precision variable. /// On entry stpmax is a nonnegative upper bound for the step. /// On exit stpmax is unchanged. /// /// task is a character variable of length at least 60. /// On initial entry task must be set to 'START'. /// On exit task indicates the required action: /// /// If task(1:2) = 'FG' then evaluate the function and /// derivative at stp and call dcsrch again. /// /// If task(1:4) = 'CONV' then the search is successful. /// /// If task(1:4) = 'WARN' then the subroutine is not able /// to satisfy the convergence conditions. The exit value of /// stp contains the best point found during the search. /// /// If task(1:5) = 'ERROR' then there is an error in the /// input arguments. /// /// On exit with convergence, a warning or an error, the /// variable task contains additional information. /// /// isave is an integer work array of dimension 2. /// /// dsave is a double precision work array of dimension 13. /// /// Subprograms called /// /// MINPACK-2 ... dcstep /// /// MINPACK-1 Project. June 1983. /// Argonne National Laboratory. /// Jorge J. More' and David J. Thuente. /// /// MINPACK-2 Project. October 1993. /// Argonne National Laboratory and University of Minnesota. /// Brett M. Averick, Richard G. Carter, and Jorge J. More'. /// /// ********** /// /// /// /// /// Initialization block. ///</param> /// <param name="FTOL"> /// is a double precision variable. /// On entry ftol specifies a nonnegative tolerance for the /// sufficient decrease condition. /// On exit ftol is unchanged. ///</param> /// <param name="GTOL"> /// is a double precision variable. /// On entry gtol specifies a nonnegative tolerance for the /// curvature condition. /// On exit gtol is unchanged. ///</param> /// <param name="XTOL"> /// is a double precision variable. /// On entry xtol specifies a nonnegative relative tolerance /// for an acceptable step. The subroutine exits with a /// warning if the relative difference between sty and stx /// is less than xtol. /// On exit xtol is unchanged. /// /// stpmin is a double precision variable. /// On entry stpmin is a nonnegative lower bound for the step. /// On exit stpmin is unchanged. /// /// stpmax is a double precision variable. /// On entry stpmax is a nonnegative upper bound for the step. /// On exit stpmax is unchanged. /// /// task is a character variable of length at least 60. /// On initial entry task must be set to 'START'. /// On exit task indicates the required action: /// /// If task(1:2) = 'FG' then evaluate the function and /// derivative at stp and call dcsrch again. /// /// If task(1:4) = 'CONV' then the search is successful. /// /// If task(1:4) = 'WARN' then the subroutine is not able /// to satisfy the convergence conditions. The exit value of /// stp contains the best point found during the search. /// /// If task(1:5) = 'ERROR' then there is an error in the /// input arguments. /// /// On exit with convergence, a warning or an error, the /// variable task contains additional information. /// /// isave is an integer work array of dimension 2. /// /// dsave is a double precision work array of dimension 13. /// /// Subprograms called /// /// MINPACK-2 ... dcstep /// /// MINPACK-1 Project. June 1983. /// Argonne National Laboratory. /// Jorge J. More' and David J. Thuente. /// /// MINPACK-2 Project. October 1993. /// Argonne National Laboratory and University of Minnesota. /// Brett M. Averick, Richard G. Carter, and Jorge J. More'. /// /// ********** /// /// /// /// /// Initialization block. ///</param> /// <param name="STPMIN"> /// is a double precision variable. /// On entry stpmin is a nonnegative lower bound for the step. /// On exit stpmin is unchanged. /// /// stpmax is a double precision variable. /// On entry stpmax is a nonnegative upper bound for the step. /// On exit stpmax is unchanged. /// /// task is a character variable of length at least 60. /// On initial entry task must be set to 'START'. /// On exit task indicates the required action: /// /// If task(1:2) = 'FG' then evaluate the function and /// derivative at stp and call dcsrch again. /// /// If task(1:4) = 'CONV' then the search is successful. /// /// If task(1:4) = 'WARN' then the subroutine is not able /// to satisfy the convergence conditions. The exit value of /// stp contains the best point found during the search. /// /// If task(1:5) = 'ERROR' then there is an error in the /// input arguments. /// /// On exit with convergence, a warning or an error, the /// variable task contains additional information. /// /// isave is an integer work array of dimension 2. /// /// dsave is a double precision work array of dimension 13. /// /// Subprograms called /// /// MINPACK-2 ... dcstep /// /// MINPACK-1 Project. June 1983. /// Argonne National Laboratory. /// Jorge J. More' and David J. Thuente. /// /// MINPACK-2 Project. October 1993. /// Argonne National Laboratory and University of Minnesota. /// Brett M. Averick, Richard G. Carter, and Jorge J. More'. /// /// ********** /// /// /// /// /// Initialization block. ///</param> /// <param name="STPMAX"> /// is a double precision variable. /// On entry stpmax is a nonnegative upper bound for the step. /// On exit stpmax is unchanged. /// /// task is a character variable of length at least 60. /// On initial entry task must be set to 'START'. /// On exit task indicates the required action: /// /// If task(1:2) = 'FG' then evaluate the function and /// derivative at stp and call dcsrch again. /// /// If task(1:4) = 'CONV' then the search is successful. /// /// If task(1:4) = 'WARN' then the subroutine is not able /// to satisfy the convergence conditions. The exit value of /// stp contains the best point found during the search. /// /// If task(1:5) = 'ERROR' then there is an error in the /// input arguments. /// /// On exit with convergence, a warning or an error, the /// variable task contains additional information. /// /// isave is an integer work array of dimension 2. /// /// dsave is a double precision work array of dimension 13. /// /// Subprograms called /// /// MINPACK-2 ... dcstep /// /// MINPACK-1 Project. June 1983. /// Argonne National Laboratory. /// Jorge J. More' and David J. Thuente. /// /// MINPACK-2 Project. October 1993. /// Argonne National Laboratory and University of Minnesota. /// Brett M. Averick, Richard G. Carter, and Jorge J. More'. /// /// ********** /// /// /// /// /// Initialization block. ///</param> /// <param name="TASK"> /// = 'START' ///</param> /// <param name="ISAVE"> /// is an integer work array of dimension 2. ///</param> /// <param name="DSAVE"> /// is a double precision work array of dimension 13. ///</param> public void Run(double F, double G, ref double STP, double FTOL, double GTOL, double XTOL , double STPMIN, double STPMAX, ref BFGSTask TASK, ref int[] ISAVE, int offset_isave, ref double[] DSAVE, int offset_dsave) { #region Variables bool BRACKT = false; int STAGE = 0; double FINIT = 0; double FTEST = 0; double FM = 0; double FX = 0; double FXM = 0; double FY = 0;double FYM = 0; double GINIT = 0; double GTEST = 0; double GM = 0; double GX = 0; double GXM = 0; double GY = 0;double GYM = 0; double STX = 0; double STY = 0; double STMIN = 0; double STMAX = 0; double WIDTH = 0; double WIDTH1 = 0; #endregion #region Array Index Correction int o_isave = -1 + offset_isave; int o_dsave = -1 + offset_dsave; #endregion #region Prolog // c ********** // c // c Subroutine dcsrch // c // c This subroutine finds a step that satisfies a sufficient // c decrease condition and a curvature condition. // c // c Each call of the subroutine updates an interval with // c endpoints stx and sty. The interval is initially chosen // c so that it contains a minimizer of the modified function // c // c psi(stp) = f(stp) - f(0) - ftol*stp*f'(0). // c // c If psi(stp) <= 0 and f'(stp) >= 0 for some step, then the // c interval is chosen so that it contains a minimizer of f. // c // c The algorithm is designed to find a step that satisfies // c the sufficient decrease condition // c // c f(stp) <= f(0) + ftol*stp*f'(0), // c // c and the curvature condition // c // c abs(f'(stp)) <= gtol*abs(f'(0)). // c // c If ftol is less than gtol and if, for example, the function // c is bounded below, then there is always a step which satisfies // c both conditions. // c // c If no step can be found that satisfies both conditions, then // c the algorithm stops with a warning. In this case stp only // c satisfies the sufficient decrease condition. // c // c A typical invocation of dcsrch has the following outline: // c // c task = 'START' // c 10 continue // c call dcsrch( ... ) // c if (task .eq. 'FG') then // c Evaluate the function and the gradient at stp // c goto 10 // c end if // c // c NOTE: The user must no alter work arrays between calls. // c // c The subroutine statement is // c // c subroutine dcsrch(f,g,stp,ftol,gtol,xtol,stpmin,stpmax, // c task,isave,dsave) // c where // c // c f is a double precision variable. // c On initial entry f is the value of the function at 0. // c On subsequent entries f is the value of the // c function at stp. // c On exit f is the value of the function at stp. // c // c g is a double precision variable. // c On initial entry g is the derivative of the function at 0. // c On subsequent entries g is the derivative of the // c function at stp. // c On exit g is the derivative of the function at stp. // c // c stp is a double precision variable. // c On entry stp is the current estimate of a satisfactory // c step. On initial entry, a positive initial estimate // c must be provided. // c On exit stp is the current estimate of a satisfactory step // c if task = 'FG'. If task = 'CONV' then stp satisfies // c the sufficient decrease and curvature condition. // c // c ftol is a double precision variable. // c On entry ftol specifies a nonnegative tolerance for the // c sufficient decrease condition. // c On exit ftol is unchanged. // c // c gtol is a double precision variable. // c On entry gtol specifies a nonnegative tolerance for the // c curvature condition. // c On exit gtol is unchanged. // c // c xtol is a double precision variable. // c On entry xtol specifies a nonnegative relative tolerance // c for an acceptable step. The subroutine exits with a // c warning if the relative difference between sty and stx // c is less than xtol. // c On exit xtol is unchanged. // c // c stpmin is a double precision variable. // c On entry stpmin is a nonnegative lower bound for the step. // c On exit stpmin is unchanged. // c // c stpmax is a double precision variable. // c On entry stpmax is a nonnegative upper bound for the step. // c On exit stpmax is unchanged. // c // c task is a character variable of length at least 60. // c On initial entry task must be set to 'START'. // c On exit task indicates the required action: // c // c If task(1:2) = 'FG' then evaluate the function and // c derivative at stp and call dcsrch again. // c // c If task(1:4) = 'CONV' then the search is successful. // c // c If task(1:4) = 'WARN' then the subroutine is not able // c to satisfy the convergence conditions. The exit value of // c stp contains the best point found during the search. // c // c If task(1:5) = 'ERROR' then there is an error in the // c input arguments. // c // c On exit with convergence, a warning or an error, the // c variable task contains additional information. // c // c isave is an integer work array of dimension 2. // c // c dsave is a double precision work array of dimension 13. // c // c Subprograms called // c // c MINPACK-2 ... dcstep // c // c MINPACK-1 Project. June 1983. // c Argonne National Laboratory. // c Jorge J. More' and David J. Thuente. // c // c MINPACK-2 Project. October 1993. // c Argonne National Laboratory and University of Minnesota. // c Brett M. Averick, Richard G. Carter, and Jorge J. More'. // c // c ********** // c Initialization block. #endregion #region Body if (TASK == BFGSTask.START) { // c Check the input arguments for errors. //if (STP < STPMIN) FortranLib.Copy(ref TASK , "ERROR: STP .LT. STPMIN"); //if (STP > STPMAX) FortranLib.Copy(ref TASK , "ERROR: STP .GT. STPMAX"); //if (G >= ZERO) FortranLib.Copy(ref TASK , "ERROR: INITIAL G .GE. ZERO"); //if (FTOL < ZERO) FortranLib.Copy(ref TASK , "ERROR: FTOL .LT. ZERO"); //if (GTOL < ZERO) FortranLib.Copy(ref TASK , "ERROR: GTOL .LT. ZERO"); //if (XTOL < ZERO) FortranLib.Copy(ref TASK , "ERROR: XTOL .LT. ZERO"); //if (STPMIN < ZERO) FortranLib.Copy(ref TASK , "ERROR: STPMIN .LT. ZERO"); //if (STPMAX < STPMIN) FortranLib.Copy(ref TASK , "ERROR: STPMAX .LT. STPMIN"); if (STP < STPMIN) { TASK = BFGSTask.ERROR;; } if (STP > STPMAX) { TASK = BFGSTask.ERROR; } if (G >= ZERO) { TASK = BFGSTask.ERROR; } if (FTOL < ZERO) { TASK = BFGSTask.ERROR; } if (GTOL < ZERO) { TASK = BFGSTask.ERROR; } if (XTOL < ZERO) { TASK = BFGSTask.ERROR; } if (STPMIN < ZERO) { TASK = BFGSTask.ERROR; } if (STPMAX < STPMIN) { TASK = BFGSTask.ERROR; } // c Exit if there are errors on input. if (TASK == BFGSTask.ERROR) return; // c Initialize local variables. BRACKT = false; STAGE = 1; FINIT = F; GINIT = G; GTEST = FTOL * GINIT; WIDTH = STPMAX - STPMIN; WIDTH1 = WIDTH / P5; // c The variables stx, fx, gx contain the values of the step, // c function, and derivative at the best step. // c The variables sty, fy, gy contain the value of the step, // c function, and derivative at sty. // c The variables stp, f, g contain the values of the step, // c function, and derivative at stp. STX = ZERO; FX = FINIT; GX = GINIT; STY = ZERO; FY = FINIT; GY = GINIT; STMIN = ZERO; STMAX = STP + XTRAPU * STP; TASK = BFGSTask.FG; goto LABEL1000; } else { // c Restore local variables. if (ISAVE[1 + o_isave] == 1) { BRACKT = true; } else { BRACKT = false; } STAGE = ISAVE[2 + o_isave]; GINIT = DSAVE[1 + o_dsave]; GTEST = DSAVE[2 + o_dsave]; GX = DSAVE[3 + o_dsave]; GY = DSAVE[4 + o_dsave]; FINIT = DSAVE[5 + o_dsave]; FX = DSAVE[6 + o_dsave]; FY = DSAVE[7 + o_dsave]; STX = DSAVE[8 + o_dsave]; STY = DSAVE[9 + o_dsave]; STMIN = DSAVE[10 + o_dsave]; STMAX = DSAVE[11 + o_dsave]; WIDTH = DSAVE[12 + o_dsave]; WIDTH1 = DSAVE[13 + o_dsave]; } // c If psi(stp) <= 0 and f'(stp) >= 0 for some step, then the // c algorithm enters the second stage. FTEST = FINIT + STP * GTEST; if (STAGE == 1 && F <= FTEST && G >= ZERO) STAGE = 2; // c Test for warnings. //if (BRACKT && (STP <= STMIN || STP >= STMAX)) FortranLib.Copy(ref TASK , "WARNING: ROUNDING ERRORS PREVENT PROGRESS"); //if (BRACKT && STMAX - STMIN <= XTOL * STMAX) FortranLib.Copy(ref TASK , "WARNING: XTOL TEST SATISFIED"); //if (STP == STPMAX && F <= FTEST && G <= GTEST) FortranLib.Copy(ref TASK , "WARNING: STP = STPMAX"); //if (STP == STPMIN && (F > FTEST || G >= GTEST)) FortranLib.Copy(ref TASK , "WARNING: STP = STPMIN"); if (BRACKT && (STP <= STMIN || STP >= STMAX)) { TASK = BFGSTask.WARNING; } if (BRACKT && STMAX - STMIN <= XTOL * STMAX) { TASK = BFGSTask.WARNING; } if (STP == STPMAX && F <= FTEST && G <= GTEST) { TASK = BFGSTask.WARNING; } if (STP == STPMIN && (F > FTEST || G >= GTEST)) { TASK = BFGSTask.WARNING; } // c Test for convergence. if (F <= FTEST && Math.Abs(G) <= GTOL * (-GINIT)) TASK = BFGSTask.CONV; // c Test for termination. if (TASK == BFGSTask.WARNING || TASK == BFGSTask.CONV) goto LABEL1000; // c A modified function is used to predict the step during the // c first stage if a lower function value has been obtained but // c the decrease is not sufficient. if (STAGE == 1 && F <= FX && F > FTEST) { // c Define the modified function and derivative values. FM = F - STP * GTEST; FXM = FX - STX * GTEST; FYM = FY - STY * GTEST; GM = G - GTEST; GXM = GX - GTEST; GYM = GY - GTEST; // c Call dcstep to update stx, sty, and to compute the new step. this._dcstep.Run(ref STX, ref FXM, ref GXM, ref STY, ref FYM, ref GYM , ref STP, FM, GM, ref BRACKT, STMIN, STMAX); // c Reset the function and derivative values for f. FX = FXM + STX * GTEST; FY = FYM + STY * GTEST; GX = GXM + GTEST; GY = GYM + GTEST; } else { // c Call dcstep to update stx, sty, and to compute the new step. this._dcstep.Run(ref STX, ref FX, ref GX, ref STY, ref FY, ref GY , ref STP, F, G, ref BRACKT, STMIN, STMAX); } // c Decide if a bisection step is needed. if (BRACKT) { if (Math.Abs(STY - STX) >= P66 * WIDTH1) STP = STX + P5 * (STY - STX); WIDTH1 = WIDTH; WIDTH = Math.Abs(STY - STX); } // c Set the minimum and maximum steps allowed for stp. if (BRACKT) { STMIN = Math.Min(STX, STY); STMAX = Math.Max(STX, STY); } else { STMIN = STP + XTRAPL * (STP - STX); STMAX = STP + XTRAPU * (STP - STX); } // c Force the step to be within the bounds stpmax and stpmin. STP = Math.Max(STP, STPMIN); STP = Math.Min(STP, STPMAX); // c If further progress is not possible, let stp be the best // c point obtained during the search. if (BRACKT && (STP <= STMIN || STP >= STMAX) || (BRACKT && STMAX - STMIN <= XTOL * STMAX)) STP = STX; // c Obtain another function and derivative. TASK = BFGSTask.FG; LABEL1000:; // c Save local variables. if (BRACKT) { ISAVE[1 + o_isave] = 1; } else { ISAVE[1 + o_isave] = 0; } ISAVE[2 + o_isave] = STAGE; DSAVE[1 + o_dsave] = GINIT; DSAVE[2 + o_dsave] = GTEST; DSAVE[3 + o_dsave] = GX; DSAVE[4 + o_dsave] = GY; DSAVE[5 + o_dsave] = FINIT; DSAVE[6 + o_dsave] = FX; DSAVE[7 + o_dsave] = FY; DSAVE[8 + o_dsave] = STX; DSAVE[9 + o_dsave] = STY; DSAVE[10 + o_dsave] = STMIN; DSAVE[11 + o_dsave] = STMAX; DSAVE[12 + o_dsave] = WIDTH; DSAVE[13 + o_dsave] = WIDTH1; #endregion }
public void Run(int N, int M, double FACTR, double[] L, int offset_l, double[] U, int offset_u, int[] NBD, int offset_nbd , ref BFGSTask TASK, ref int INFO, ref int K) { #region Variables int I = 0; #endregion #region Array Index Correction int o_l = -1 + offset_l; int o_u = -1 + offset_u; int o_nbd = -1 + offset_nbd; #endregion #region Prolog // c ************ // c // c Subroutine errclb // c // c This subroutine checks the validity of the input data. // c // c // c * * * // c // c NEOS, November 1994. (Latest revision June 1996.) // c Optimization Technology Center. // c Argonne National Laboratory and Northwestern University. // c Written by // c Ciyou Zhu // c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. // c // c // c ************ // c Check the input arguments for errors. #endregion #region Body if (N <= 0) { TASK = BFGSTask.ERROR; } if (M <= 0) { TASK = BFGSTask.ERROR; } if (FACTR < ZERO) { TASK = BFGSTask.ERROR; } // c Check the validity of the arrays nbd(i), u(i), and l(i). for (I = 1; I <= N; I++) { if (NBD[I + o_nbd] < 0 || NBD[I + o_nbd] > 3) { // c return //"ERROR: INVALID NBD"; TASK = BFGSTask.ERROR; INFO = -6; K = I; } if (NBD[I + o_nbd] == 2) { if (L[I + o_l] > U[I + o_u]) { // c return //"ERROR: NO FEASIBLE SOLUTION" TASK = BFGSTask.ERROR; INFO = -7; K = I; } } } return; #endregion }
/// <param name="F"> /// is a double precision variable. /// On initial entry f is the value of the function at 0. /// On subsequent entries f is the value of the /// function at stp. /// On exit f is the value of the function at stp. ///</param> /// <param name="G"> /// is a double precision variable. /// On initial entry g is the derivative of the function at 0. /// On subsequent entries g is the derivative of the /// function at stp. /// On exit g is the derivative of the function at stp. /// /// stp is a double precision variable. /// On entry stp is the current estimate of a satisfactory /// step. On initial entry, a positive initial estimate /// must be provided. /// On exit stp is the current estimate of a satisfactory step /// if task = 'FG'. If task = 'CONV' then stp satisfies /// the sufficient decrease and curvature condition. /// /// ftol is a double precision variable. /// On entry ftol specifies a nonnegative tolerance for the /// sufficient decrease condition. /// On exit ftol is unchanged. /// /// gtol is a double precision variable. /// On entry gtol specifies a nonnegative tolerance for the /// curvature condition. /// On exit gtol is unchanged. /// /// xtol is a double precision variable. /// On entry xtol specifies a nonnegative relative tolerance /// for an acceptable step. The subroutine exits with a /// warning if the relative difference between sty and stx /// is less than xtol. /// On exit xtol is unchanged. /// /// stpmin is a double precision variable. /// On entry stpmin is a nonnegative lower bound for the step. /// On exit stpmin is unchanged. /// /// stpmax is a double precision variable. /// On entry stpmax is a nonnegative upper bound for the step. /// On exit stpmax is unchanged. /// /// task is a character variable of length at least 60. /// On initial entry task must be set to 'START'. /// On exit task indicates the required action: /// /// If task(1:2) = 'FG' then evaluate the function and /// derivative at stp and call dcsrch again. /// /// If task(1:4) = 'CONV' then the search is successful. /// /// If task(1:4) = 'WARN' then the subroutine is not able /// to satisfy the convergence conditions. The exit value of /// stp contains the best point found during the search. /// /// If task(1:5) = 'ERROR' then there is an error in the /// input arguments. /// /// On exit with convergence, a warning or an error, the /// variable task contains additional information. /// /// isave is an integer work array of dimension 2. /// /// dsave is a double precision work array of dimension 13. /// /// Subprograms called /// /// MINPACK-2 ... dcstep /// /// MINPACK-1 Project. June 1983. /// Argonne National Laboratory. /// Jorge J. More' and David J. Thuente. /// /// MINPACK-2 Project. October 1993. /// Argonne National Laboratory and University of Minnesota. /// Brett M. Averick, Richard G. Carter, and Jorge J. More'. /// /// ********** /// /// /// /// /// Initialization block. ///</param> /// <param name="STP"> /// is a double precision variable. /// On entry stp is the current estimate of a satisfactory /// step. On initial entry, a positive initial estimate /// must be provided. /// On exit stp is the current estimate of a satisfactory step /// if task = 'FG'. If task = 'CONV' then stp satisfies /// the sufficient decrease and curvature condition. /// /// ftol is a double precision variable. /// On entry ftol specifies a nonnegative tolerance for the /// sufficient decrease condition. /// On exit ftol is unchanged. /// /// gtol is a double precision variable. /// On entry gtol specifies a nonnegative tolerance for the /// curvature condition. /// On exit gtol is unchanged. /// /// xtol is a double precision variable. /// On entry xtol specifies a nonnegative relative tolerance /// for an acceptable step. The subroutine exits with a /// warning if the relative difference between sty and stx /// is less than xtol. /// On exit xtol is unchanged. /// /// stpmin is a double precision variable. /// On entry stpmin is a nonnegative lower bound for the step. /// On exit stpmin is unchanged. /// /// stpmax is a double precision variable. /// On entry stpmax is a nonnegative upper bound for the step. /// On exit stpmax is unchanged. /// /// task is a character variable of length at least 60. /// On initial entry task must be set to 'START'. /// On exit task indicates the required action: /// /// If task(1:2) = 'FG' then evaluate the function and /// derivative at stp and call dcsrch again. /// /// If task(1:4) = 'CONV' then the search is successful. /// /// If task(1:4) = 'WARN' then the subroutine is not able /// to satisfy the convergence conditions. The exit value of /// stp contains the best point found during the search. /// /// If task(1:5) = 'ERROR' then there is an error in the /// input arguments. /// /// On exit with convergence, a warning or an error, the /// variable task contains additional information. /// /// isave is an integer work array of dimension 2. /// /// dsave is a double precision work array of dimension 13. /// /// Subprograms called /// /// MINPACK-2 ... dcstep /// /// MINPACK-1 Project. June 1983. /// Argonne National Laboratory. /// Jorge J. More' and David J. Thuente. /// /// MINPACK-2 Project. October 1993. /// Argonne National Laboratory and University of Minnesota. /// Brett M. Averick, Richard G. Carter, and Jorge J. More'. /// /// ********** /// /// /// /// /// Initialization block. ///</param> /// <param name="FTOL"> /// is a double precision variable. /// On entry ftol specifies a nonnegative tolerance for the /// sufficient decrease condition. /// On exit ftol is unchanged. ///</param> /// <param name="GTOL"> /// is a double precision variable. /// On entry gtol specifies a nonnegative tolerance for the /// curvature condition. /// On exit gtol is unchanged. ///</param> /// <param name="XTOL"> /// is a double precision variable. /// On entry xtol specifies a nonnegative relative tolerance /// for an acceptable step. The subroutine exits with a /// warning if the relative difference between sty and stx /// is less than xtol. /// On exit xtol is unchanged. /// /// stpmin is a double precision variable. /// On entry stpmin is a nonnegative lower bound for the step. /// On exit stpmin is unchanged. /// /// stpmax is a double precision variable. /// On entry stpmax is a nonnegative upper bound for the step. /// On exit stpmax is unchanged. /// /// task is a character variable of length at least 60. /// On initial entry task must be set to 'START'. /// On exit task indicates the required action: /// /// If task(1:2) = 'FG' then evaluate the function and /// derivative at stp and call dcsrch again. /// /// If task(1:4) = 'CONV' then the search is successful. /// /// If task(1:4) = 'WARN' then the subroutine is not able /// to satisfy the convergence conditions. The exit value of /// stp contains the best point found during the search. /// /// If task(1:5) = 'ERROR' then there is an error in the /// input arguments. /// /// On exit with convergence, a warning or an error, the /// variable task contains additional information. /// /// isave is an integer work array of dimension 2. /// /// dsave is a double precision work array of dimension 13. /// /// Subprograms called /// /// MINPACK-2 ... dcstep /// /// MINPACK-1 Project. June 1983. /// Argonne National Laboratory. /// Jorge J. More' and David J. Thuente. /// /// MINPACK-2 Project. October 1993. /// Argonne National Laboratory and University of Minnesota. /// Brett M. Averick, Richard G. Carter, and Jorge J. More'. /// /// ********** /// /// /// /// /// Initialization block. ///</param> /// <param name="STPMIN"> /// is a double precision variable. /// On entry stpmin is a nonnegative lower bound for the step. /// On exit stpmin is unchanged. /// /// stpmax is a double precision variable. /// On entry stpmax is a nonnegative upper bound for the step. /// On exit stpmax is unchanged. /// /// task is a character variable of length at least 60. /// On initial entry task must be set to 'START'. /// On exit task indicates the required action: /// /// If task(1:2) = 'FG' then evaluate the function and /// derivative at stp and call dcsrch again. /// /// If task(1:4) = 'CONV' then the search is successful. /// /// If task(1:4) = 'WARN' then the subroutine is not able /// to satisfy the convergence conditions. The exit value of /// stp contains the best point found during the search. /// /// If task(1:5) = 'ERROR' then there is an error in the /// input arguments. /// /// On exit with convergence, a warning or an error, the /// variable task contains additional information. /// /// isave is an integer work array of dimension 2. /// /// dsave is a double precision work array of dimension 13. /// /// Subprograms called /// /// MINPACK-2 ... dcstep /// /// MINPACK-1 Project. June 1983. /// Argonne National Laboratory. /// Jorge J. More' and David J. Thuente. /// /// MINPACK-2 Project. October 1993. /// Argonne National Laboratory and University of Minnesota. /// Brett M. Averick, Richard G. Carter, and Jorge J. More'. /// /// ********** /// /// /// /// /// Initialization block. ///</param> /// <param name="STPMAX"> /// is a double precision variable. /// On entry stpmax is a nonnegative upper bound for the step. /// On exit stpmax is unchanged. /// /// task is a character variable of length at least 60. /// On initial entry task must be set to 'START'. /// On exit task indicates the required action: /// /// If task(1:2) = 'FG' then evaluate the function and /// derivative at stp and call dcsrch again. /// /// If task(1:4) = 'CONV' then the search is successful. /// /// If task(1:4) = 'WARN' then the subroutine is not able /// to satisfy the convergence conditions. The exit value of /// stp contains the best point found during the search. /// /// If task(1:5) = 'ERROR' then there is an error in the /// input arguments. /// /// On exit with convergence, a warning or an error, the /// variable task contains additional information. /// /// isave is an integer work array of dimension 2. /// /// dsave is a double precision work array of dimension 13. /// /// Subprograms called /// /// MINPACK-2 ... dcstep /// /// MINPACK-1 Project. June 1983. /// Argonne National Laboratory. /// Jorge J. More' and David J. Thuente. /// /// MINPACK-2 Project. October 1993. /// Argonne National Laboratory and University of Minnesota. /// Brett M. Averick, Richard G. Carter, and Jorge J. More'. /// /// ********** /// /// /// /// /// Initialization block. ///</param> /// <param name="TASK"> /// = 'START' ///</param> /// <param name="ISAVE"> /// is an integer work array of dimension 2. ///</param> /// <param name="DSAVE"> /// is a double precision work array of dimension 13. ///</param> public void Run(double F, double G, ref double STP, double FTOL, double GTOL, double XTOL , double STPMIN, double STPMAX, ref BFGSTask TASK, ref int[] ISAVE, int offset_isave, ref double[] DSAVE, int offset_dsave) { #region Variables bool BRACKT = false; int STAGE = 0; double FINIT = 0; double FTEST = 0; double FM = 0; double FX = 0; double FXM = 0; double FY = 0; double FYM = 0; double GINIT = 0; double GTEST = 0; double GM = 0; double GX = 0; double GXM = 0; double GY = 0; double GYM = 0; double STX = 0; double STY = 0; double STMIN = 0; double STMAX = 0; double WIDTH = 0; double WIDTH1 = 0; #endregion #region Array Index Correction int o_isave = -1 + offset_isave; int o_dsave = -1 + offset_dsave; #endregion #region Prolog // c ********** // c // c Subroutine dcsrch // c // c This subroutine finds a step that satisfies a sufficient // c decrease condition and a curvature condition. // c // c Each call of the subroutine updates an interval with // c endpoints stx and sty. The interval is initially chosen // c so that it contains a minimizer of the modified function // c // c psi(stp) = f(stp) - f(0) - ftol*stp*f'(0). // c // c If psi(stp) <= 0 and f'(stp) >= 0 for some step, then the // c interval is chosen so that it contains a minimizer of f. // c // c The algorithm is designed to find a step that satisfies // c the sufficient decrease condition // c // c f(stp) <= f(0) + ftol*stp*f'(0), // c // c and the curvature condition // c // c abs(f'(stp)) <= gtol*abs(f'(0)). // c // c If ftol is less than gtol and if, for example, the function // c is bounded below, then there is always a step which satisfies // c both conditions. // c // c If no step can be found that satisfies both conditions, then // c the algorithm stops with a warning. In this case stp only // c satisfies the sufficient decrease condition. // c // c A typical invocation of dcsrch has the following outline: // c // c task = 'START' // c 10 continue // c call dcsrch( ... ) // c if (task .eq. 'FG') then // c Evaluate the function and the gradient at stp // c goto 10 // c end if // c // c NOTE: The user must no alter work arrays between calls. // c // c The subroutine statement is // c // c subroutine dcsrch(f,g,stp,ftol,gtol,xtol,stpmin,stpmax, // c task,isave,dsave) // c where // c // c f is a double precision variable. // c On initial entry f is the value of the function at 0. // c On subsequent entries f is the value of the // c function at stp. // c On exit f is the value of the function at stp. // c // c g is a double precision variable. // c On initial entry g is the derivative of the function at 0. // c On subsequent entries g is the derivative of the // c function at stp. // c On exit g is the derivative of the function at stp. // c // c stp is a double precision variable. // c On entry stp is the current estimate of a satisfactory // c step. On initial entry, a positive initial estimate // c must be provided. // c On exit stp is the current estimate of a satisfactory step // c if task = 'FG'. If task = 'CONV' then stp satisfies // c the sufficient decrease and curvature condition. // c // c ftol is a double precision variable. // c On entry ftol specifies a nonnegative tolerance for the // c sufficient decrease condition. // c On exit ftol is unchanged. // c // c gtol is a double precision variable. // c On entry gtol specifies a nonnegative tolerance for the // c curvature condition. // c On exit gtol is unchanged. // c // c xtol is a double precision variable. // c On entry xtol specifies a nonnegative relative tolerance // c for an acceptable step. The subroutine exits with a // c warning if the relative difference between sty and stx // c is less than xtol. // c On exit xtol is unchanged. // c // c stpmin is a double precision variable. // c On entry stpmin is a nonnegative lower bound for the step. // c On exit stpmin is unchanged. // c // c stpmax is a double precision variable. // c On entry stpmax is a nonnegative upper bound for the step. // c On exit stpmax is unchanged. // c // c task is a character variable of length at least 60. // c On initial entry task must be set to 'START'. // c On exit task indicates the required action: // c // c If task(1:2) = 'FG' then evaluate the function and // c derivative at stp and call dcsrch again. // c // c If task(1:4) = 'CONV' then the search is successful. // c // c If task(1:4) = 'WARN' then the subroutine is not able // c to satisfy the convergence conditions. The exit value of // c stp contains the best point found during the search. // c // c If task(1:5) = 'ERROR' then there is an error in the // c input arguments. // c // c On exit with convergence, a warning or an error, the // c variable task contains additional information. // c // c isave is an integer work array of dimension 2. // c // c dsave is a double precision work array of dimension 13. // c // c Subprograms called // c // c MINPACK-2 ... dcstep // c // c MINPACK-1 Project. June 1983. // c Argonne National Laboratory. // c Jorge J. More' and David J. Thuente. // c // c MINPACK-2 Project. October 1993. // c Argonne National Laboratory and University of Minnesota. // c Brett M. Averick, Richard G. Carter, and Jorge J. More'. // c // c ********** // c Initialization block. #endregion #region Body if (TASK == BFGSTask.START) { // c Check the input arguments for errors. //if (STP < STPMIN) FortranLib.Copy(ref TASK , "ERROR: STP .LT. STPMIN"); //if (STP > STPMAX) FortranLib.Copy(ref TASK , "ERROR: STP .GT. STPMAX"); //if (G >= ZERO) FortranLib.Copy(ref TASK , "ERROR: INITIAL G .GE. ZERO"); //if (FTOL < ZERO) FortranLib.Copy(ref TASK , "ERROR: FTOL .LT. ZERO"); //if (GTOL < ZERO) FortranLib.Copy(ref TASK , "ERROR: GTOL .LT. ZERO"); //if (XTOL < ZERO) FortranLib.Copy(ref TASK , "ERROR: XTOL .LT. ZERO"); //if (STPMIN < ZERO) FortranLib.Copy(ref TASK , "ERROR: STPMIN .LT. ZERO"); //if (STPMAX < STPMIN) FortranLib.Copy(ref TASK , "ERROR: STPMAX .LT. STPMIN"); if (STP < STPMIN) { TASK = BFGSTask.ERROR;; } if (STP > STPMAX) { TASK = BFGSTask.ERROR; } if (G >= ZERO) { TASK = BFGSTask.ERROR; } if (FTOL < ZERO) { TASK = BFGSTask.ERROR; } if (GTOL < ZERO) { TASK = BFGSTask.ERROR; } if (XTOL < ZERO) { TASK = BFGSTask.ERROR; } if (STPMIN < ZERO) { TASK = BFGSTask.ERROR; } if (STPMAX < STPMIN) { TASK = BFGSTask.ERROR; } // c Exit if there are errors on input. if (TASK == BFGSTask.ERROR) { return; } // c Initialize local variables. BRACKT = false; STAGE = 1; FINIT = F; GINIT = G; GTEST = FTOL * GINIT; WIDTH = STPMAX - STPMIN; WIDTH1 = WIDTH / P5; // c The variables stx, fx, gx contain the values of the step, // c function, and derivative at the best step. // c The variables sty, fy, gy contain the value of the step, // c function, and derivative at sty. // c The variables stp, f, g contain the values of the step, // c function, and derivative at stp. STX = ZERO; FX = FINIT; GX = GINIT; STY = ZERO; FY = FINIT; GY = GINIT; STMIN = ZERO; STMAX = STP + XTRAPU * STP; TASK = BFGSTask.FG; goto LABEL1000; } else { // c Restore local variables. if (ISAVE[1 + o_isave] == 1) { BRACKT = true; } else { BRACKT = false; } STAGE = ISAVE[2 + o_isave]; GINIT = DSAVE[1 + o_dsave]; GTEST = DSAVE[2 + o_dsave]; GX = DSAVE[3 + o_dsave]; GY = DSAVE[4 + o_dsave]; FINIT = DSAVE[5 + o_dsave]; FX = DSAVE[6 + o_dsave]; FY = DSAVE[7 + o_dsave]; STX = DSAVE[8 + o_dsave]; STY = DSAVE[9 + o_dsave]; STMIN = DSAVE[10 + o_dsave]; STMAX = DSAVE[11 + o_dsave]; WIDTH = DSAVE[12 + o_dsave]; WIDTH1 = DSAVE[13 + o_dsave]; } // c If psi(stp) <= 0 and f'(stp) >= 0 for some step, then the // c algorithm enters the second stage. FTEST = FINIT + STP * GTEST; if (STAGE == 1 && F <= FTEST && G >= ZERO) { STAGE = 2; } // c Test for warnings. //if (BRACKT && (STP <= STMIN || STP >= STMAX)) FortranLib.Copy(ref TASK , "WARNING: ROUNDING ERRORS PREVENT PROGRESS"); //if (BRACKT && STMAX - STMIN <= XTOL * STMAX) FortranLib.Copy(ref TASK , "WARNING: XTOL TEST SATISFIED"); //if (STP == STPMAX && F <= FTEST && G <= GTEST) FortranLib.Copy(ref TASK , "WARNING: STP = STPMAX"); //if (STP == STPMIN && (F > FTEST || G >= GTEST)) FortranLib.Copy(ref TASK , "WARNING: STP = STPMIN"); if (BRACKT && (STP <= STMIN || STP >= STMAX)) { TASK = BFGSTask.WARNING; } if (BRACKT && STMAX - STMIN <= XTOL * STMAX) { TASK = BFGSTask.WARNING; } if (STP == STPMAX && F <= FTEST && G <= GTEST) { TASK = BFGSTask.WARNING; } if (STP == STPMIN && (F > FTEST || G >= GTEST)) { TASK = BFGSTask.WARNING; } // c Test for convergence. if (F <= FTEST && Math.Abs(G) <= GTOL * (-GINIT)) { TASK = BFGSTask.CONV; } // c Test for termination. if (TASK == BFGSTask.WARNING || TASK == BFGSTask.CONV) { goto LABEL1000; } // c A modified function is used to predict the step during the // c first stage if a lower function value has been obtained but // c the decrease is not sufficient. if (STAGE == 1 && F <= FX && F > FTEST) { // c Define the modified function and derivative values. FM = F - STP * GTEST; FXM = FX - STX * GTEST; FYM = FY - STY * GTEST; GM = G - GTEST; GXM = GX - GTEST; GYM = GY - GTEST; // c Call dcstep to update stx, sty, and to compute the new step. this._dcstep.Run(ref STX, ref FXM, ref GXM, ref STY, ref FYM, ref GYM , ref STP, FM, GM, ref BRACKT, STMIN, STMAX); // c Reset the function and derivative values for f. FX = FXM + STX * GTEST; FY = FYM + STY * GTEST; GX = GXM + GTEST; GY = GYM + GTEST; } else { // c Call dcstep to update stx, sty, and to compute the new step. this._dcstep.Run(ref STX, ref FX, ref GX, ref STY, ref FY, ref GY , ref STP, F, G, ref BRACKT, STMIN, STMAX); } // c Decide if a bisection step is needed. if (BRACKT) { if (Math.Abs(STY - STX) >= P66 * WIDTH1) { STP = STX + P5 * (STY - STX); } WIDTH1 = WIDTH; WIDTH = Math.Abs(STY - STX); } // c Set the minimum and maximum steps allowed for stp. if (BRACKT) { STMIN = Math.Min(STX, STY); STMAX = Math.Max(STX, STY); } else { STMIN = STP + XTRAPL * (STP - STX); STMAX = STP + XTRAPU * (STP - STX); } // c Force the step to be within the bounds stpmax and stpmin. STP = Math.Max(STP, STPMIN); STP = Math.Min(STP, STPMAX); // c If further progress is not possible, let stp be the best // c point obtained during the search. if (BRACKT && (STP <= STMIN || STP >= STMAX) || (BRACKT && STMAX - STMIN <= XTOL * STMAX)) { STP = STX; } // c Obtain another function and derivative. TASK = BFGSTask.FG; LABEL1000 :; // c Save local variables. if (BRACKT) { ISAVE[1 + o_isave] = 1; } else { ISAVE[1 + o_isave] = 0; } ISAVE[2 + o_isave] = STAGE; DSAVE[1 + o_dsave] = GINIT; DSAVE[2 + o_dsave] = GTEST; DSAVE[3 + o_dsave] = GX; DSAVE[4 + o_dsave] = GY; DSAVE[5 + o_dsave] = FINIT; DSAVE[6 + o_dsave] = FX; DSAVE[7 + o_dsave] = FY; DSAVE[8 + o_dsave] = STX; DSAVE[9 + o_dsave] = STY; DSAVE[10 + o_dsave] = STMIN; DSAVE[11 + o_dsave] = STMAX; DSAVE[12 + o_dsave] = WIDTH; DSAVE[13 + o_dsave] = WIDTH1; #endregion }
public void Run(int N, double[] L, int offset_l, double[] U, int offset_u, int[] NBD, int offset_nbd, ref double[] X, int offset_x, double F , ref double FOLD, ref double GD, ref double GDOLD, double[] G, int offset_g, double[] D, int offset_d, ref double[] R, int offset_r , ref double[] T, int offset_t, double[] Z, int offset_z, ref double STP, ref double DNORM, ref double DTD, ref double XSTEP , ref double STPMX, int ITER, ref int IFUN, ref int IBACK, ref int NFGV, ref int INFO , ref BFGSTask TASK, bool BOXED, bool CNSTND, ref BFGSTask CSAVE, ref int[] ISAVE, int offset_isave, ref double[] DSAVE, int offset_dsave) { #region Variables int I = 0; double DDOT = 0; double A1 = 0; double A2 = 0; #endregion #region Array Index Correction int o_l = -1 + offset_l; int o_u = -1 + offset_u; int o_nbd = -1 + offset_nbd; int o_x = -1 + offset_x; int o_g = -1 + offset_g; int o_d = -1 + offset_d; int o_r = -1 + offset_r; int o_t = -1 + offset_t; int o_z = -1 + offset_z; int o_isave = -1 + offset_isave; int o_dsave = -1 + offset_dsave; #endregion #region Prolog // c ********** // c // c Subroutine lnsrlb // c // c This subroutine calls subroutine dcsrch from the Minpack2 library // c to perform the line search. Subroutine dscrch is safeguarded so // c that all trial points lie within the feasible region. // c // c Subprograms called: // c // c Minpack2 Library ... dcsrch. // c // c Linpack ... dtrsl, ddot. // c // c // c * * * // c // c NEOS, November 1994. (Latest revision June 1996.) // c Optimization Technology Center. // c Argonne National Laboratory and Northwestern University. // c Written by // c Ciyou Zhu // c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. // c // c // c ********** #endregion #region Body if (TASK == BFGSTask.FG_LNSRCH) goto LABEL556; DTD = this._ddot.Run(N, D, offset_d, 1, D, offset_d, 1); DNORM = Math.Sqrt(DTD); // c Determine the maximum step length. STPMX = BIG; if (CNSTND) { if (ITER == 0) { STPMX = ONE; } else { for (I = 1; I <= N; I++) { A1 = D[I + o_d]; if (NBD[I + o_nbd] != 0) { if (A1 < ZERO && NBD[I + o_nbd] <= 2) { A2 = L[I + o_l] - X[I + o_x]; if (A2 >= ZERO) { STPMX = ZERO; } else { if (A1 * STPMX < A2) { STPMX = A2 / A1; } } } else { if (A1 > ZERO && NBD[I + o_nbd] >= 2) { A2 = U[I + o_u] - X[I + o_x]; if (A2 <= ZERO) { STPMX = ZERO; } else { if (A1 * STPMX > A2) { STPMX = A2 / A1; } } } } } } } } if (ITER == 0 && !BOXED) { STP = Math.Min(ONE / DNORM, STPMX); } else { STP = ONE; } this._dcopy.Run(N, X, offset_x, 1, ref T, offset_t, 1); this._dcopy.Run(N, G, offset_g, 1, ref R, offset_r, 1); FOLD = F; IFUN = 0; IBACK = 0; CSAVE = BFGSTask.START; LABEL556:; GD = this._ddot.Run(N, G, offset_g, 1, D, offset_d, 1); if (IFUN == 0) { GDOLD = GD; if (GD >= ZERO) { // c the directional derivative >=0. // c Line search is impossible. INFO = - 4; return; } } this._dcsrch.Run(F, GD, ref STP, FTOL, GTOL, XTOL , ZERO, STPMX, ref CSAVE, ref ISAVE, offset_isave, ref DSAVE, offset_dsave); XSTEP = STP * DNORM; if (CSAVE != BFGSTask.CONV && CSAVE != BFGSTask.WARNING) { TASK = BFGSTask.FG_LNSRCH; IFUN += 1; NFGV += 1; IBACK = IFUN - 1; if (STP == ONE) { this._dcopy.Run(N, Z, offset_z, 1, ref X, offset_x, 1); } else { for (I = 1; I <= N; I++) { X[I + o_x] = STP * D[I + o_d] + T[I + o_t]; } } } else { TASK = BFGSTask.NEW_X; } return; #endregion }
public void Run(int N, double[] X, int offset_x, double F, BFGSTask TASK, int IPRINT, int INFO , int ITFILE, int ITER, int NFGV, int NINTOL, int NSKIP, int NACT , double SBGNRM, double TIME, int NINT, BFGSWord WORD, int IBACK, double STP , double XSTEP, int K, double CACHYT, double SBTIME, double LNSCHT) { #region Variables int I = 0; #endregion #region Array Index Correction int o_x = -1 + offset_x; #endregion #region Prolog // c ************ // c // c Subroutine prn3lb // c // c This subroutine prints out information when either a built-in // c convergence test is satisfied or when an error message is // c generated. // c // c // c * * * // c // c NEOS, November 1994. (Latest revision June 1996.) // c Optimization Technology Center. // c Argonne National Laboratory and Northwestern University. // c Written by // c Ciyou Zhu // c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. // c // c // c ************ #endregion #region Body if (TASK == BFGSTask.ERROR) { goto LABEL999; } if (IPRINT >= 0) { //ERROR-ERROR WRITE (6,3003); //ERROR-ERROR WRITE (6,3004); //ERROR-ERROR WRITE(6,3005) N,ITER,NFGV,NINTOL,NSKIP,NACT,SBGNRM,F; if (IPRINT >= 100) { //ERROR-ERROR WRITE (6,1004) 'X =',(X(I),I = 1,N); } if (IPRINT >= 1) { ; //ERROR-ERRORWRITE(6,*)' F =',F } } LABEL999 :; if (IPRINT >= 0) { //ERROR-ERROR WRITE (6,3009) TASK; if (INFO != 0) { if (INFO == -1) { ; //ERROR-ERRORWRITE(6,9011) } if (INFO == -2) { ; //ERROR-ERRORWRITE(6,9012) } if (INFO == -3) { ; //ERROR-ERRORWRITE(6,9013) } if (INFO == -4) { ; //ERROR-ERRORWRITE(6,9014) } if (INFO == -5) { ; //ERROR-ERRORWRITE(6,9015) } if (INFO == -6) { ; //ERROR-ERRORWRITE(6,*)' Input nbd(',K,') is invalid.' } if (INFO == -7) { ; //ERROR-ERRORWRITE(6,*)' l(',K,') > u(',K,'). No feasible solution.' } if (INFO == -8) { ; //ERROR-ERRORWRITE(6,9018) } if (INFO == -9) { ; //ERROR-ERRORWRITE(6,9019) } } if (IPRINT >= 1) { ; //ERROR-ERRORWRITE(6,3007)CACHYT,SBTIME,LNSCHT } //ERROR-ERROR WRITE (6,3008) TIME; if (IPRINT >= 1) { if (INFO == -4 || INFO == -9) { //ERROR-ERROR WRITE (ITFILE,3002)ITER,NFGV,NINT,NACT,WORD,IBACK,STP,XSTEP; } //ERROR-ERROR WRITE (ITFILE,3009) TASK; if (INFO != 0) { if (INFO == -1) { ; //ERROR-ERRORWRITE(ITFILE,9011) } if (INFO == -2) { ; //ERROR-ERRORWRITE(ITFILE,9012) } if (INFO == -3) { ; //ERROR-ERRORWRITE(ITFILE,9013) } if (INFO == -4) { ; //ERROR-ERRORWRITE(ITFILE,9014) } if (INFO == -5) { ; //ERROR-ERRORWRITE(ITFILE,9015) } if (INFO == -8) { ; //ERROR-ERRORWRITE(ITFILE,9018) } if (INFO == -9) { ; //ERROR-ERRORWRITE(ITFILE,9019) } } //ERROR-ERROR WRITE (ITFILE,3008) TIME; } } return; #endregion }
/// <param name="N"> /// is an integer variable. /// On entry n is the number of variables. /// On exit n is unchanged. ///</param> /// <param name="M"> /// is an integer variable. /// On entry m is the maximum number of variable metric /// corrections allowed in the limited memory matrix. /// On exit m is unchanged. ///</param> /// <param name="X"> /// is a double precision array of dimension n. /// On entry x is an approximation to the solution. /// On exit x is the current approximation. ///</param> /// <param name="L"> /// is a double precision array of dimension n. /// On entry l is the lower bound of x. /// On exit l is unchanged. ///</param> /// <param name="U"> /// is a double precision array of dimension n. /// On entry u is the upper bound of x. /// On exit u is unchanged. ///</param> /// <param name="NBD"> /// is an integer array of dimension n. /// On entry nbd represents the type of bounds imposed on the /// variables, and must be specified as follows: /// nbd(i)=0 if x(i) is unbounded, /// 1 if x(i) has only a lower bound, /// 2 if x(i) has both lower and upper bounds, /// 3 if x(i) has only an upper bound. /// On exit nbd is unchanged. ///</param> /// <param name="F"> /// is a double precision variable. /// On first entry f is unspecified. /// On final exit f is the value of the function at x. ///</param> /// <param name="G"> /// is a double precision array of dimension n. /// On first entry g is unspecified. /// On final exit g is the value of the gradient at x. ///</param> /// <param name="FACTR"> /// is a double precision variable. /// On entry factr .GE. 0 is specified by the user. The iteration /// will stop when /// /// (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} .LE. factr*epsmch /// /// where epsmch is the machine precision, which is automatically /// generated by the code. /// On exit factr is unchanged. ///</param> /// <param name="PGTOL"> /// is a double precision variable. /// On entry pgtol .GE. 0 is specified by the user. The iteration /// will stop when /// /// max{|proj g_i | i = 1, ..., n} .LE. pgtol /// /// where pg_i is the ith component of the projected gradient. /// On exit pgtol is unchanged. ///</param> /// <param name="WN"> /// is a double precision working array of dimension 2m x 2m /// used to store the LEL^T factorization of the indefinite matrix /// K = [-D -Y'ZZ'Y/theta L_a'-R_z' ] /// [L_a -R_z theta*S'AA'S ] /// /// where E = [-I 0] /// [ 0 I] ///</param> /// <param name="SND"> /// is a double precision working array of dimension 2m x 2m /// used to store the lower triangular part of /// N = [Y' ZZ'Y L_a'+R_z'] /// [L_a +R_z S'AA'S ] ///</param> /// <param name="Z"> /// is used at different times to store the Cauchy point and ///</param> /// <param name="INDEX"> /// is an integer working array of dimension n. /// In subroutine freev, index is used to store the free and fixed /// variables at the Generalized Cauchy Point (GCP). ///</param> /// <param name="IWHERE"> /// is an integer working array of dimension n used to record /// the status of the vector x for GCP computation. /// iwhere(i)=0 or -3 if x(i) is free and has bounds, /// 1 if x(i) is fixed at l(i), and l(i) .ne. u(i) /// 2 if x(i) is fixed at u(i), and u(i) .ne. l(i) /// 3 if x(i) is always fixed, i.e., u(i)=x(i)=l(i) /// -1 if x(i) is always free, i.e., no bounds on it. ///</param> /// <param name="INDX2"> /// is an integer working array of dimension n. /// Within subroutine cauchy, indx2 corresponds to the array iorder. /// In subroutine freev, a list of variables entering and leaving /// the free set is stored in indx2, and it is passed on to /// subroutine formk with this information. ///</param> /// <param name="TASK"> /// is a working string of characters of length 60 indicating /// the current job when entering and leaving this subroutine. ///</param> /// <param name="IPRINT"> /// is an INTEGER variable that must be set by the user. /// It controls the frequency and type of output generated: /// iprint.LT.0 no output is generated; /// iprint=0 print only one line at the last iteration; /// 0.LT.iprint.LT.99 print also f and |proj g| every iprint iterations; /// iprint=99 print details of every iteration except n-vectors; /// iprint=100 print also the changes of active set and final x; /// iprint.GT.100 print details of every iteration including x and g; /// When iprint .GT. 0, the file iterate.dat will be created to /// summarize the iteration. ///</param> /// <param name="CSAVE"> /// is a working string of characters of length 60. ///</param> /// <param name="LSAVE"> /// is a logical working array of dimension 4. ///</param> /// <param name="ISAVE"> /// is an integer working array of dimension 23. ///</param> /// <param name="DSAVE"> /// is a double precision working array of dimension 29. /// ///</param> public void Run(int N, int M, ref double[] X, int offset_x, double[] L, int offset_l, double[] U, int offset_u, int[] NBD, int offset_nbd , ref double F, ref double[] G, int offset_g, double FACTR, double PGTOL, ref double[] WS, int offset_ws, ref double[] WY, int offset_wy , ref double[] SY, int offset_sy, ref double[] SS, int offset_ss, double[] YY, int offset_yy, ref double[] WT, int offset_wt, ref double[] WN, int offset_wn, ref double[] SND, int offset_snd , ref double[] Z, int offset_z, ref double[] R, int offset_r, ref double[] D, int offset_d, ref double[] T, int offset_t, ref double[] WA, int offset_wa, double[] SG, int offset_sg , double[] SGO, int offset_sgo, double[] YG, int offset_yg, double[] YGO, int offset_ygo, ref int[] INDEX, int offset_index, ref int[] IWHERE, int offset_iwhere, ref int[] INDX2, int offset_indx2 , ref BFGSTask TASK, int IPRINT, ref BFGSTask CSAVE, ref bool[] LSAVE, int offset_lsave, ref int[] ISAVE, int offset_isave, ref double[] DSAVE, int offset_dsave) { #region Variables BFGSWord WORD = BFGSWord.aaa; bool PRJCTD = false; bool CNSTND = false; bool BOXED = false; bool UPDATD = false; bool WRK = false; int I = 0; int K = 0; int NINTOL = 0; int ITFILE = 0; int IBACK = 0; int NSKIP = 0; int HEAD = 0;int COL = 0; int ITER = 0; int ITAIL = 0; int IUPDAT = 0; int NINT = 0; int NFGV = 0; int INFO = 0; int IFUN = 0;int IWORD = 0; int NFREE = 0; int NACT = 0; int ILEAVE = 0; int NENTER = 0; double THETA = 0; double FOLD = 0;double DDOT = 0; double DR = 0; double RR = 0; double TOL = 0; double DPMEPS = 0; double XSTEP = 0; double SBGNRM = 0;double DDUM = 0; double DNORM = 0; double DTD = 0; double EPSMCH = 0; double CPU1 = 0; double CPU2 = 0;double CACHYT = 0; double SBTIME = 0; double LNSCHT = 0; double TIME1 = 0; double TIME2 = 0; double GD = 0;double GDOLD = 0; double STP = 0; double STPMX = 0; double TIME = 0; #endregion #region Array Index Correction int o_x = -1 + offset_x; int o_l = -1 + offset_l; int o_u = -1 + offset_u; int o_nbd = -1 + offset_nbd; int o_g = -1 + offset_g; int o_ws = -1 - N + offset_ws; int o_wy = -1 - N + offset_wy; int o_sy = -1 - M + offset_sy; int o_ss = -1 - M + offset_ss; int o_yy = -1 - M + offset_yy; int o_wt = -1 - M + offset_wt; int o_wn = -1 - (2*M) + offset_wn; int o_snd = -1 - (2*M) + offset_snd; int o_z = -1 + offset_z; int o_r = -1 + offset_r; int o_d = -1 + offset_d; int o_t = -1 + offset_t; int o_wa = -1 + offset_wa; int o_sg = -1 + offset_sg; int o_sgo = -1 + offset_sgo; int o_yg = -1 + offset_yg; int o_ygo = -1 + offset_ygo; int o_index = -1 + offset_index; int o_iwhere = -1 + offset_iwhere; int o_indx2 = -1 + offset_indx2; int o_lsave = -1 + offset_lsave; int o_isave = -1 + offset_isave; int o_dsave = -1 + offset_dsave; #endregion #region Prolog // c ************ // c // c Subroutine mainlb // c // c This subroutine solves bound constrained optimization problems by // c using the compact formula of the limited memory BFGS updates. // c // c n is an integer variable. // c On entry n is the number of variables. // c On exit n is unchanged. // c // c m is an integer variable. // c On entry m is the maximum number of variable metric // c corrections allowed in the limited memory matrix. // c On exit m is unchanged. // c // c x is a double precision array of dimension n. // c On entry x is an approximation to the solution. // c On exit x is the current approximation. // c // c l is a double precision array of dimension n. // c On entry l is the lower bound of x. // c On exit l is unchanged. // c // c u is a double precision array of dimension n. // c On entry u is the upper bound of x. // c On exit u is unchanged. // c // c nbd is an integer array of dimension n. // c On entry nbd represents the type of bounds imposed on the // c variables, and must be specified as follows: // c nbd(i)=0 if x(i) is unbounded, // c 1 if x(i) has only a lower bound, // c 2 if x(i) has both lower and upper bounds, // c 3 if x(i) has only an upper bound. // c On exit nbd is unchanged. // c // c f is a double precision variable. // c On first entry f is unspecified. // c On final exit f is the value of the function at x. // c // c g is a double precision array of dimension n. // c On first entry g is unspecified. // c On final exit g is the value of the gradient at x. // c // c factr is a double precision variable. // c On entry factr >= 0 is specified by the user. The iteration // c will stop when // c // c (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} <= factr*epsmch // c // c where epsmch is the machine precision, which is automatically // c generated by the code. // c On exit factr is unchanged. // c // c pgtol is a double precision variable. // c On entry pgtol >= 0 is specified by the user. The iteration // c will stop when // c // c max{|proj g_i | i = 1, ..., n} <= pgtol // c // c where pg_i is the ith component of the projected gradient. // c On exit pgtol is unchanged. // c // c ws, wy, sy, and wt are double precision working arrays used to // c store the following information defining the limited memory // c BFGS matrix: // c ws, of dimension n x m, stores S, the matrix of s-vectors; // c wy, of dimension n x m, stores Y, the matrix of y-vectors; // c sy, of dimension m x m, stores S'Y; // c ss, of dimension m x m, stores S'S; // c yy, of dimension m x m, stores Y'Y; // c wt, of dimension m x m, stores the Cholesky factorization // c of (theta*S'S+LD^(-1)L'); see eq. // c (2.26) in [3]. // c // c wn is a double precision working array of dimension 2m x 2m // c used to store the LEL^T factorization of the indefinite matrix // c K = [-D -Y'ZZ'Y/theta L_a'-R_z' ] // c [L_a -R_z theta*S'AA'S ] // c // c where E = [-I 0] // c [ 0 I] // c // c snd is a double precision working array of dimension 2m x 2m // c used to store the lower triangular part of // c N = [Y' ZZ'Y L_a'+R_z'] // c [L_a +R_z S'AA'S ] // c // c z(n),r(n),d(n),t(n),wa(8*m) are double precision working arrays. // c z is used at different times to store the Cauchy point and // c the Newton point. // c // c sg(m),sgo(m),yg(m),ygo(m) are double precision working arrays. // c // c index is an integer working array of dimension n. // c In subroutine freev, index is used to store the free and fixed // c variables at the Generalized Cauchy Point (GCP). // c // c iwhere is an integer working array of dimension n used to record // c the status of the vector x for GCP computation. // c iwhere(i)=0 or -3 if x(i) is free and has bounds, // c 1 if x(i) is fixed at l(i), and l(i) .ne. u(i) // c 2 if x(i) is fixed at u(i), and u(i) .ne. l(i) // c 3 if x(i) is always fixed, i.e., u(i)=x(i)=l(i) // c -1 if x(i) is always free, i.e., no bounds on it. // c // c indx2 is an integer working array of dimension n. // c Within subroutine cauchy, indx2 corresponds to the array iorder. // c In subroutine freev, a list of variables entering and leaving // c the free set is stored in indx2, and it is passed on to // c subroutine formk with this information. // c // c task is a working string of characters of length 60 indicating // c the current job when entering and leaving this subroutine. // c // c iprint is an INTEGER variable that must be set by the user. // c It controls the frequency and type of output generated: // c iprint<0 no output is generated; // c iprint=0 print only one line at the last iteration; // c 0<iprint<99 print also f and |proj g| every iprint iterations; // c iprint=99 print details of every iteration except n-vectors; // c iprint=100 print also the changes of active set and final x; // c iprint>100 print details of every iteration including x and g; // c When iprint > 0, the file iterate.dat will be created to // c summarize the iteration. // c // c csave is a working string of characters of length 60. // c // c lsave is a logical working array of dimension 4. // c // c isave is an integer working array of dimension 23. // c // c dsave is a double precision working array of dimension 29. // c // c // c Subprograms called // c // c L-BFGS-B Library ... cauchy, subsm, lnsrlb, formk, // c // c errclb, prn1lb, prn2lb, prn3lb, active, projgr, // c // c freev, cmprlb, matupd, formt. // c // c Minpack2 Library ... timer, dpmeps. // c // c Linpack Library ... dcopy, ddot. // c // c // c References: // c // c [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited // c memory algorithm for bound constrained optimization'', // c SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208. // c // c [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: FORTRAN // c Subroutines for Large Scale Bound Constrained Optimization'' // c Tech. Report, NAM-11, EECS Department, Northwestern University, // c 1994. // c // c [3] R. Byrd, J. Nocedal and R. Schnabel "Representations of // c Quasi-Newton Matrices and their use in Limited Memory Methods'', // c Mathematical Programming 63 (1994), no. 4, pp. 129-156. // c // c (Postscript files of these papers are available via anonymous // c ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.) // c // c * * * // c // c NEOS, November 1994. (Latest revision June 1996.) // c Optimization Technology Center. // c Argonne National Laboratory and Northwestern University. // c Written by // c Ciyou Zhu // c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. // c // c // c ************ #endregion #region Body if (TASK == BFGSTask.START) { this._timer.Run(ref TIME1); // c Generate the current machine precision. EPSMCH = this._dpmeps.Run(); // c Initialize counters and scalars when task='START'. // c for the limited memory BFGS matrices: COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; // c for operation counts: ITER = 0; NFGV = 0; NINT = 0; NINTOL = 0; NSKIP = 0; NFREE = N; // c for stopping tolerance: TOL = FACTR * EPSMCH; // c for measuring running time: CACHYT = 0; SBTIME = 0; LNSCHT = 0; // c 'word' records the status of subspace solutions. WORD = BFGSWord.aaa; // c 'info' records the termination information. INFO = 0; if (IPRINT >= 1) { // c open a summary file 'iterate.dat' //ERROR-ERROR OPEN (8, FILE = 'iterate.dat', STATUS = 'unknown'); ITFILE = 8; } // c Check the input arguments for errors. this._errclb.Run(N, M, FACTR, L, offset_l, U, offset_u, NBD, offset_nbd , ref TASK, ref INFO, ref K); if (TASK == BFGSTask.ERROR) { this._prn3lb.Run(N, X, offset_x, F, TASK, IPRINT, INFO , ITFILE, ITER, NFGV, NINTOL, NSKIP, NACT , SBGNRM, ZERO, NINT, WORD, IBACK, STP , XSTEP, K, CACHYT, SBTIME, LNSCHT); return; } this._prn1lb.Run(N, M, L, offset_l, U, offset_u, X, offset_x, IPRINT , ITFILE, EPSMCH); // c Initialize iwhere & project x onto the feasible set. this._active.Run(N, L, offset_l, U, offset_u, NBD, offset_nbd, ref X, offset_x, ref IWHERE, offset_iwhere , IPRINT, ref PRJCTD, ref CNSTND, ref BOXED); // c The end of the initialization. } else { // c restore local variables. PRJCTD = LSAVE[1 + o_lsave]; CNSTND = LSAVE[2 + o_lsave]; BOXED = LSAVE[3 + o_lsave]; UPDATD = LSAVE[4 + o_lsave]; NINTOL = ISAVE[1 + o_isave]; ITFILE = ISAVE[3 + o_isave]; IBACK = ISAVE[4 + o_isave]; NSKIP = ISAVE[5 + o_isave]; HEAD = ISAVE[6 + o_isave]; COL = ISAVE[7 + o_isave]; ITAIL = ISAVE[8 + o_isave]; ITER = ISAVE[9 + o_isave]; IUPDAT = ISAVE[10 + o_isave]; NINT = ISAVE[12 + o_isave]; NFGV = ISAVE[13 + o_isave]; INFO = ISAVE[14 + o_isave]; IFUN = ISAVE[15 + o_isave]; IWORD = ISAVE[16 + o_isave]; NFREE = ISAVE[17 + o_isave]; NACT = ISAVE[18 + o_isave]; ILEAVE = ISAVE[19 + o_isave]; NENTER = ISAVE[20 + o_isave]; THETA = DSAVE[1 + o_dsave]; FOLD = DSAVE[2 + o_dsave]; TOL = DSAVE[3 + o_dsave]; DNORM = DSAVE[4 + o_dsave]; EPSMCH = DSAVE[5 + o_dsave]; CPU1 = DSAVE[6 + o_dsave]; CACHYT = DSAVE[7 + o_dsave]; SBTIME = DSAVE[8 + o_dsave]; LNSCHT = DSAVE[9 + o_dsave]; TIME1 = DSAVE[10 + o_dsave]; GD = DSAVE[11 + o_dsave]; STPMX = DSAVE[12 + o_dsave]; SBGNRM = DSAVE[13 + o_dsave]; STP = DSAVE[14 + o_dsave]; GDOLD = DSAVE[15 + o_dsave]; DTD = DSAVE[16 + o_dsave]; // c After returning from the driver go to the point where execution // c is to resume. if (TASK == BFGSTask.FG_LNSRCH) goto LABEL666; if (TASK == BFGSTask.NEW_X) goto LABEL777; if (TASK == BFGSTask.FG_ST || TASK == BFGSTask.FG_START) goto LABEL111; if (TASK == BFGSTask.STOP) { if (TASK== BFGSTask.CPU) { // c restore the previous iterate. this._dcopy.Run(N, T, offset_t, 1, ref X, offset_x, 1); this._dcopy.Run(N, R, offset_r, 1, ref G, offset_g, 1); F = FOLD; } goto LABEL999; } } // c Compute f0 and g0. TASK = BFGSTask.FG_START; // c return to the driver to calculate f and g; reenter at 111. goto LABEL1000; LABEL111:; NFGV = 1; // c Compute the infinity norm of the (-) projected gradient. this._projgr.Run(N, L, offset_l, U, offset_u, NBD, offset_nbd, X, offset_x, G, offset_g , ref SBGNRM); if (IPRINT >= 1) { //ERROR-ERROR WRITE (6,1002) ITER,F,SBGNRM; //ERROR-ERROR WRITE (ITFILE,1003) ITER,NFGV,SBGNRM,F; } if (SBGNRM <= PGTOL) { // c terminate the algorithm. TASK = BFGSTask.CONV; goto LABEL999; } // c ----------------- the beginning of the loop -------------------------- LABEL222:; if (IPRINT >= 99) ;//ERROR-ERRORWRITE(6,1001)ITER+1 IWORD = - 1; // c if (!CNSTND && COL > 0) { // c skip the search for GCP. this._dcopy.Run(N, X, offset_x, 1, ref Z, offset_z, 1); WRK = UPDATD; NINT = 0; goto LABEL333; } // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // c // c Compute the Generalized Cauchy Point (GCP). // c // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc this._timer.Run(ref CPU1); this._cauchy.Run(N, X, offset_x, L, offset_l, U, offset_u, NBD, offset_nbd, G, offset_g , ref INDX2, offset_indx2, ref IWHERE, offset_iwhere, ref T, offset_t, ref D, offset_d, ref Z, offset_z, M , WY, offset_wy, WS, offset_ws, SY, offset_sy, WT, offset_wt, THETA, COL , HEAD, ref WA, 1 + o_wa, ref WA, 2 * M + 1 + o_wa, ref WA, 4 * M + 1 + o_wa, ref WA, 6 * M + 1 + o_wa, ref NINT , SG, offset_sg, YG, offset_yg, IPRINT, SBGNRM, ref INFO, EPSMCH); if (INFO != 0) { // c singular triangular system detected; refresh the lbfgs memory. if (IPRINT >= 1) ;//ERROR-ERRORWRITE(6,1005) INFO = 0; COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; this._timer.Run(ref CPU2); CACHYT += CPU2 - CPU1; goto LABEL222; } this._timer.Run(ref CPU2); CACHYT += CPU2 - CPU1; NINTOL += NINT; // c Count the entering and leaving variables for iter > 0; // c find the index set of free and active variables at the GCP. this._freev.Run(N, ref NFREE, ref INDEX, offset_index, ref NENTER, ref ILEAVE, ref INDX2, offset_indx2 , IWHERE, offset_iwhere, ref WRK, UPDATD, CNSTND, IPRINT, ITER); NACT = N - NFREE; LABEL333:; // c If there are no free variables or B=theta*I, then // c skip the subspace minimization. if (NFREE == 0 || COL == 0) goto LABEL555; // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // c // c Subspace minimization. // c // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc this._timer.Run(ref CPU1); // c Form the LEL^T factorization of the indefinite // c matrix K = [-D -Y'ZZ'Y/theta L_a'-R_z' ] // c [L_a -R_z theta*S'AA'S ] // c where E = [-I 0] // c [ 0 I] if (WRK) { this._formk.Run(N, NFREE, INDEX, offset_index, NENTER, ILEAVE, INDX2, offset_indx2 , IUPDAT, UPDATD, ref WN, offset_wn, ref SND, offset_snd, M, WS, offset_ws , WY, offset_wy, SY, offset_sy, THETA, COL, HEAD, ref INFO); } if (INFO != 0) { // c nonpositive definiteness in Cholesky factorization; // c refresh the lbfgs memory and restart the iteration. if (IPRINT >= 1) ;//ERROR-ERRORWRITE(6,1006) INFO = 0; COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; this._timer.Run(ref CPU2); SBTIME += CPU2 - CPU1; goto LABEL222; } // c compute r=-Z'B(xcp-xk)-Z'g (using wa(2m+1)=W'(xcp-x) // c from 'cauchy'). this._cmprlb.Run(N, M, X, offset_x, G, offset_g, WS, offset_ws, WY, offset_wy , SY, offset_sy, WT, offset_wt, Z, offset_z, ref R, offset_r, ref WA, offset_wa, INDEX, offset_index , THETA, COL, HEAD, NFREE, CNSTND, ref INFO); if (INFO != 0) goto LABEL444; // c call the direct method. this._subsm.Run(N, M, NFREE, INDEX, offset_index, L, offset_l, U, offset_u , NBD, offset_nbd, ref Z, offset_z, ref R, offset_r, WS, offset_ws, WY, offset_wy, THETA , COL, HEAD, ref IWORD, ref WA, offset_wa, WN, offset_wn, IPRINT , ref INFO); LABEL444:; if (INFO != 0) { // c singular triangular system detected; // c refresh the lbfgs memory and restart the iteration. if (IPRINT >= 1) ;//ERROR-ERRORWRITE(6,1005) INFO = 0; COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; this._timer.Run(ref CPU2); SBTIME += CPU2 - CPU1; goto LABEL222; } this._timer.Run(ref CPU2); SBTIME += CPU2 - CPU1; LABEL555:; // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // c // c Line search and optimality tests. // c // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // c Generate the search direction d:=z-x. for (I = 1; I <= N; I++) { D[I + o_d] = Z[I + o_z] - X[I + o_x]; } this._timer.Run(ref CPU1); LABEL666:; this._lnsrlb.Run(N, L, offset_l, U, offset_u, NBD, offset_nbd, ref X, offset_x, F , ref FOLD, ref GD, ref GDOLD, G, offset_g, D, offset_d, ref R, offset_r , ref T, offset_t, Z, offset_z, ref STP, ref DNORM, ref DTD, ref XSTEP , ref STPMX, ITER, ref IFUN, ref IBACK, ref NFGV, ref INFO , ref TASK, BOXED, CNSTND, ref CSAVE, ref ISAVE, 22 + o_isave, ref DSAVE, 17 + o_dsave); if (INFO != 0 || IBACK >= 20) { // c restore the previous iterate. this._dcopy.Run(N, T, offset_t, 1, ref X, offset_x, 1); this._dcopy.Run(N, R, offset_r, 1, ref G, offset_g, 1); F = FOLD; if (COL == 0) { // c abnormal termination. if (INFO == 0) { INFO = - 9; // c restore the actual number of f and g evaluations etc. NFGV -= 1; IFUN -= 1; IBACK -= 1; } TASK = BFGSTask.ABNO; ITER += 1; goto LABEL999; } else { // c refresh the lbfgs memory and restart the iteration. if (IPRINT >= 1) ;//ERROR-ERRORWRITE(6,1008) if (INFO == 0) NFGV -= 1; INFO = 0; COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; TASK = BFGSTask.RESTART; this._timer.Run(ref CPU2); LNSCHT += CPU2 - CPU1; goto LABEL222; } } else { if (TASK == BFGSTask.FG_LNSRCH) { // c return to the driver for calculating f and g; reenter at 666. goto LABEL1000; } else { // c calculate and print out the quantities related to the new X. this._timer.Run(ref CPU2); LNSCHT += CPU2 - CPU1; ITER += 1; // c Compute the infinity norm of the projected (-)gradient. this._projgr.Run(N, L, offset_l, U, offset_u, NBD, offset_nbd, X, offset_x, G, offset_g , ref SBGNRM); // c Print iteration information. this._prn2lb.Run(N, X, offset_x, F, G, offset_g, IPRINT, ITFILE , ITER, NFGV, NACT, SBGNRM, NINT, ref WORD , IWORD, IBACK, STP, XSTEP); goto LABEL1000; } } LABEL777:; // c Test for termination. if (SBGNRM <= PGTOL) { // c terminate the algorithm. TASK = BFGSTask.CONV; goto LABEL999; } DDUM = Math.Max(Math.Abs(FOLD), Math.Max(Math.Abs(F), ONE)); if ((FOLD - F) <= TOL * DDUM) { // c terminate the algorithm. TASK = BFGSTask.CONV; if (IBACK >= 10) INFO = - 5; // c i.e., to issue a warning if iback>10 in the line search. goto LABEL999; } // c Compute d=newx-oldx, r=newg-oldg, rr=y'y and dr=y's. for (I = 1; I <= N; I++) { R[I + o_r] = G[I + o_g] - R[I + o_r]; } RR = this._ddot.Run(N, R, offset_r, 1, R, offset_r, 1); if (STP == ONE) { DR = GD - GDOLD; DDUM = - GDOLD; } else { DR = (GD - GDOLD) * STP; this._dscal.Run(N, STP, ref D, offset_d, 1); DDUM = - GDOLD * STP; } if (DR <= EPSMCH * DDUM) { // c skip the L-BFGS update. NSKIP += 1; UPDATD = false; if (IPRINT >= 1) ;//ERROR-ERRORWRITE(6,1004)DR,DDUM goto LABEL888; } // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // c // c Update the L-BFGS matrix. // c // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc UPDATD = true; IUPDAT += 1; // c Update matrices WS and WY and form the middle matrix in B. this._matupd.Run(N, M, ref WS, offset_ws, ref WY, offset_wy, ref SY, offset_sy, ref SS, offset_ss , D, offset_d, R, offset_r, ref ITAIL, IUPDAT, ref COL, ref HEAD , ref THETA, RR, DR, STP, DTD); // c Form the upper half of the pds T = theta*SS + L*D^(-1)*L'; // c Store T in the upper triangular of the array wt; // c Cholesky factorize T to J*J' with // c J' stored in the upper triangular of wt. this._formt.Run(M, ref WT, offset_wt, SY, offset_sy, SS, offset_ss, COL, THETA , ref INFO); if (INFO != 0) { // c nonpositive definiteness in Cholesky factorization; // c refresh the lbfgs memory and restart the iteration. if (IPRINT >= 1) ;//ERROR-ERRORWRITE(6,1007) INFO = 0; COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; goto LABEL222; } // c Now the inverse of the middle matrix in B is // c [ D^(1/2) O ] [ -D^(1/2) D^(-1/2)*L' ] // c [ -L*D^(-1/2) J ] [ 0 J' ] LABEL888:; // c -------------------- the end of the loop ----------------------------- goto LABEL222; LABEL999:; this._timer.Run(ref TIME2); TIME = TIME2 - TIME1; this._prn3lb.Run(N, X, offset_x, F, TASK, IPRINT, INFO , ITFILE, ITER, NFGV, NINTOL, NSKIP, NACT , SBGNRM, TIME, NINT, WORD, IBACK, STP , XSTEP, K, CACHYT, SBTIME, LNSCHT); LABEL1000:; // c Save local variables. LSAVE[1 + o_lsave] = PRJCTD; LSAVE[2 + o_lsave] = CNSTND; LSAVE[3 + o_lsave] = BOXED; LSAVE[4 + o_lsave] = UPDATD; ISAVE[1 + o_isave] = NINTOL; ISAVE[3 + o_isave] = ITFILE; ISAVE[4 + o_isave] = IBACK; ISAVE[5 + o_isave] = NSKIP; ISAVE[6 + o_isave] = HEAD; ISAVE[7 + o_isave] = COL; ISAVE[8 + o_isave] = ITAIL; ISAVE[9 + o_isave] = ITER; ISAVE[10 + o_isave] = IUPDAT; ISAVE[12 + o_isave] = NINT; ISAVE[13 + o_isave] = NFGV; ISAVE[14 + o_isave] = INFO; ISAVE[15 + o_isave] = IFUN; ISAVE[16 + o_isave] = IWORD; ISAVE[17 + o_isave] = NFREE; ISAVE[18 + o_isave] = NACT; ISAVE[19 + o_isave] = ILEAVE; ISAVE[20 + o_isave] = NENTER; DSAVE[1 + o_dsave] = THETA; DSAVE[2 + o_dsave] = FOLD; DSAVE[3 + o_dsave] = TOL; DSAVE[4 + o_dsave] = DNORM; DSAVE[5 + o_dsave] = EPSMCH; DSAVE[6 + o_dsave] = CPU1; DSAVE[7 + o_dsave] = CACHYT; DSAVE[8 + o_dsave] = SBTIME; DSAVE[9 + o_dsave] = LNSCHT; DSAVE[10 + o_dsave] = TIME1; DSAVE[11 + o_dsave] = GD; DSAVE[12 + o_dsave] = STPMX; DSAVE[13 + o_dsave] = SBGNRM; DSAVE[14 + o_dsave] = STP; DSAVE[15 + o_dsave] = GDOLD; DSAVE[16 + o_dsave] = DTD; return; #endregion }
/// <param name="N"> /// is an integer variable. /// On entry n is the dimension of the problem. /// On exit n is unchanged. ///</param> /// <param name="M"> /// is an integer variable. /// On entry m is the maximum number of variable metric corrections /// used to define the limited memory matrix. /// On exit m is unchanged. ///</param> /// <param name="X"> /// is a double precision array of dimension n. /// On entry x is an approximation to the solution. /// On exit x is the current approximation. ///</param> /// <param name="L"> /// is a double precision array of dimension n. /// On entry l is the lower bound on x. /// On exit l is unchanged. ///</param> /// <param name="U"> /// is a double precision array of dimension n. /// On entry u is the upper bound on x. /// On exit u is unchanged. ///</param> /// <param name="NBD"> /// is an integer array of dimension n. /// On entry nbd represents the type of bounds imposed on the /// variables, and must be specified as follows: /// nbd(i)=0 if x(i) is unbounded, /// 1 if x(i) has only a lower bound, /// 2 if x(i) has both lower and upper bounds, and /// 3 if x(i) has only an upper bound. /// On exit nbd is unchanged. ///</param> /// <param name="F"> /// is a double precision variable. /// On first entry f is unspecified. /// On final exit f is the value of the function at x. ///</param> /// <param name="G"> /// is a double precision array of dimension n. /// On first entry g is unspecified. /// On final exit g is the value of the gradient at x. ///</param> /// <param name="FACTR"> /// is a double precision variable. /// On entry factr .GE. 0 is specified by the user. The iteration /// will stop when /// /// (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} .LE. factr*epsmch /// /// where epsmch is the machine precision, which is automatically /// generated by the code. Typical values for factr: 1.d+12 for /// low accuracy; 1.d+7 for moderate accuracy; 1.d+1 for extremely /// high accuracy. /// On exit factr is unchanged. ///</param> /// <param name="PGTOL"> /// is a double precision variable. /// On entry pgtol .GE. 0 is specified by the user. The iteration /// will stop when /// /// max{|proj g_i | i = 1, ..., n} .LE. pgtol /// /// where pg_i is the ith component of the projected gradient. /// On exit pgtol is unchanged. ///</param> /// <param name="WA"> /// is a double precision working array of length /// (2mmax + 4)nmax + 12mmax^2 + 12mmax. ///</param> /// <param name="IWA"> /// is an integer working array of length 3nmax. ///</param> /// <param name="TASK"> /// is a working string of characters of length 60 indicating /// the current job when entering and quitting this subroutine. ///</param> /// <param name="IPRINT"> /// is an integer variable that must be set by the user. /// It controls the frequency and type of output generated: /// iprint.LT.0 no output is generated; /// iprint=0 print only one line at the last iteration; /// 0.LT.iprint.LT.99 print also f and |proj g| every iprint iterations; /// iprint=99 print details of every iteration except n-vectors; /// iprint=100 print also the changes of active set and final x; /// iprint.GT.100 print details of every iteration including x and g; /// When iprint .GT. 0, the file iterate.dat will be created to /// summarize the iteration. ///</param> /// <param name="CSAVE"> /// is a working string of characters of length 60. ///</param> /// <param name="LSAVE"> /// is a logical working array of dimension 4. /// On exit with 'task' = NEW_X, the following information is /// available: /// If lsave(1) = .true. then the initial X has been replaced by /// its projection in the feasible set; /// If lsave(2) = .true. then the problem is constrained; /// If lsave(3) = .true. then each variable has upper and lower /// bounds; ///</param> /// <param name="ISAVE"> /// is an integer working array of dimension 44. /// On exit with 'task' = NEW_X, the following information is /// available: /// isave(22) = the total number of intervals explored in the /// search of Cauchy points; /// isave(26) = the total number of skipped BFGS updates before /// the current iteration; /// isave(30) = the number of current iteration; /// isave(31) = the total number of BFGS updates prior the current /// iteration; /// isave(33) = the number of intervals explored in the search of /// Cauchy point in the current iteration; /// isave(34) = the total number of function and gradient /// evaluations; /// isave(36) = the number of function value or gradient /// evaluations in the current iteration; /// if isave(37) = 0 then the subspace argmin is within the box; /// if isave(37) = 1 then the subspace argmin is beyond the box; /// isave(38) = the number of free variables in the current /// iteration; /// isave(39) = the number of active constraints in the current /// iteration; /// n + 1 - isave(40) = the number of variables leaving the set of /// active constraints in the current iteration; /// isave(41) = the number of variables entering the set of active /// constraints in the current iteration. ///</param> /// <param name="DSAVE"> /// is a double precision working array of dimension 29. /// On exit with 'task' = NEW_X, the following information is /// available: /// dsave(1) = current 'theta' in the BFGS matrix; /// dsave(2) = f(x) in the previous iteration; /// dsave(3) = factr*epsmch; /// dsave(4) = 2-norm of the line search direction vector; /// dsave(5) = the machine precision epsmch generated by the code; /// dsave(7) = the accumulated time spent on searching for /// Cauchy points; /// dsave(8) = the accumulated time spent on /// subspace minimization; /// dsave(9) = the accumulated time spent on line search; /// dsave(11) = the slope of the line search function at /// the current point of line search; /// dsave(12) = the maximum relative step length imposed in /// line search; /// dsave(13) = the infinity norm of the projected gradient; /// dsave(14) = the relative step length in the line search; /// dsave(15) = the slope of the line search function at /// the starting point of the line search; /// dsave(16) = the square of the 2-norm of the line search /// direction vector. ///</param> public void Run(int N, int M, ref double[] X, int offset_x, double[] L, int offset_l, double[] U, int offset_u, int[] NBD, int offset_nbd , ref double F, ref double[] G, int offset_g, double FACTR, double PGTOL, ref double[] WA, int offset_wa, ref int[] IWA, int offset_iwa , ref BFGSTask TASK, int IPRINT, ref BFGSTask CSAVE, ref bool[] LSAVE, int offset_lsave, ref int[] ISAVE, int offset_isave, ref double[] DSAVE, int offset_dsave) { #region Variables int L1 = 0; int L2 = 0; int L3 = 0; int LWS = 0; int LR = 0; int LZ = 0; int LT = 0; int LD = 0; int LSG = 0; int LWA = 0;int LYG = 0; int LSGO = 0; int LWY = 0; int LSY = 0; int LSS = 0; int LYY = 0; int LWT = 0; int LWN = 0; int LSND = 0;int LYGO = 0; #endregion #region Array Index Correction int o_x = -1 + offset_x; int o_l = -1 + offset_l; int o_u = -1 + offset_u; int o_nbd = -1 + offset_nbd; int o_g = -1 + offset_g; int o_wa = -1 + offset_wa; int o_iwa = -1 + offset_iwa; int o_lsave = -1 + offset_lsave; int o_isave = -1 + offset_isave; int o_dsave = -1 + offset_dsave; #endregion #region Prolog // c ************ // c // c Subroutine setulb // c // c This subroutine partitions the working arrays wa and iwa, and // c then uses the limited memory BFGS method to solve the bound // c constrained optimization problem by calling mainlb. // c (The direct method will be used in the subspace minimization.) // c // c n is an integer variable. // c On entry n is the dimension of the problem. // c On exit n is unchanged. // c // c m is an integer variable. // c On entry m is the maximum number of variable metric corrections // c used to define the limited memory matrix. // c On exit m is unchanged. // c // c x is a double precision array of dimension n. // c On entry x is an approximation to the solution. // c On exit x is the current approximation. // c // c l is a double precision array of dimension n. // c On entry l is the lower bound on x. // c On exit l is unchanged. // c // c u is a double precision array of dimension n. // c On entry u is the upper bound on x. // c On exit u is unchanged. // c // c nbd is an integer array of dimension n. // c On entry nbd represents the type of bounds imposed on the // c variables, and must be specified as follows: // c nbd(i)=0 if x(i) is unbounded, // c 1 if x(i) has only a lower bound, // c 2 if x(i) has both lower and upper bounds, and // c 3 if x(i) has only an upper bound. // c On exit nbd is unchanged. // c // c f is a double precision variable. // c On first entry f is unspecified. // c On final exit f is the value of the function at x. // c // c g is a double precision array of dimension n. // c On first entry g is unspecified. // c On final exit g is the value of the gradient at x. // c // c factr is a double precision variable. // c On entry factr >= 0 is specified by the user. The iteration // c will stop when // c // c (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} <= factr*epsmch // c // c where epsmch is the machine precision, which is automatically // c generated by the code. Typical values for factr: 1.d+12 for // c low accuracy; 1.d+7 for moderate accuracy; 1.d+1 for extremely // c high accuracy. // c On exit factr is unchanged. // c // c pgtol is a double precision variable. // c On entry pgtol >= 0 is specified by the user. The iteration // c will stop when // c // c max{|proj g_i | i = 1, ..., n} <= pgtol // c // c where pg_i is the ith component of the projected gradient. // c On exit pgtol is unchanged. // c // c wa is a double precision working array of length // c (2mmax + 4)nmax + 12mmax^2 + 12mmax. // c // c iwa is an integer working array of length 3nmax. // c // c task is a working string of characters of length 60 indicating // c the current job when entering and quitting this subroutine. // c // c iprint is an integer variable that must be set by the user. // c It controls the frequency and type of output generated: // c iprint<0 no output is generated; // c iprint=0 print only one line at the last iteration; // c 0<iprint<99 print also f and |proj g| every iprint iterations; // c iprint=99 print details of every iteration except n-vectors; // c iprint=100 print also the changes of active set and final x; // c iprint>100 print details of every iteration including x and g; // c When iprint > 0, the file iterate.dat will be created to // c summarize the iteration. // c // c csave is a working string of characters of length 60. // c // c lsave is a logical working array of dimension 4. // c On exit with 'task' = NEW_X, the following information is // c available: // c If lsave(1) = .true. then the initial X has been replaced by // c its projection in the feasible set; // c If lsave(2) = .true. then the problem is constrained; // c If lsave(3) = .true. then each variable has upper and lower // c bounds; // c // c isave is an integer working array of dimension 44. // c On exit with 'task' = NEW_X, the following information is // c available: // c isave(22) = the total number of intervals explored in the // c search of Cauchy points; // c isave(26) = the total number of skipped BFGS updates before // c the current iteration; // c isave(30) = the number of current iteration; // c isave(31) = the total number of BFGS updates prior the current // c iteration; // c isave(33) = the number of intervals explored in the search of // c Cauchy point in the current iteration; // c isave(34) = the total number of function and gradient // c evaluations; // c isave(36) = the number of function value or gradient // c evaluations in the current iteration; // c if isave(37) = 0 then the subspace argmin is within the box; // c if isave(37) = 1 then the subspace argmin is beyond the box; // c isave(38) = the number of free variables in the current // c iteration; // c isave(39) = the number of active constraints in the current // c iteration; // c n + 1 - isave(40) = the number of variables leaving the set of // c active constraints in the current iteration; // c isave(41) = the number of variables entering the set of active // c constraints in the current iteration. // c // c dsave is a double precision working array of dimension 29. // c On exit with 'task' = NEW_X, the following information is // c available: // c dsave(1) = current 'theta' in the BFGS matrix; // c dsave(2) = f(x) in the previous iteration; // c dsave(3) = factr*epsmch; // c dsave(4) = 2-norm of the line search direction vector; // c dsave(5) = the machine precision epsmch generated by the code; // c dsave(7) = the accumulated time spent on searching for // c Cauchy points; // c dsave(8) = the accumulated time spent on // c subspace minimization; // c dsave(9) = the accumulated time spent on line search; // c dsave(11) = the slope of the line search function at // c the current point of line search; // c dsave(12) = the maximum relative step length imposed in // c line search; // c dsave(13) = the infinity norm of the projected gradient; // c dsave(14) = the relative step length in the line search; // c dsave(15) = the slope of the line search function at // c the starting point of the line search; // c dsave(16) = the square of the 2-norm of the line search // c direction vector. // c // c Subprograms called: // c // c L-BFGS-B Library ... mainlb. // c // c // c References: // c // c [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited // c memory algorithm for bound constrained optimization'', // c SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208. // c // c [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: a // c limited memory FORTRAN code for solving bound constrained // c optimization problems'', Tech. Report, NAM-11, EECS Department, // c Northwestern University, 1994. // c // c (Postscript files of these papers are available via anonymous // c ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.) // c // c * * * // c // c NEOS, November 1994. (Latest revision June 1996.) // c Optimization Technology Center. // c Argonne National Laboratory and Northwestern University. // c Written by // c Ciyou Zhu // c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. // c // c // c ************ #endregion #region Body if (TASK == BFGSTask.START) { ISAVE[1 + o_isave] = M * N; ISAVE[2 + o_isave] = (int)Math.Pow(M,2); ISAVE[3 + o_isave] = 4 * (int)Math.Pow(M,2); ISAVE[4 + o_isave] = 1; ISAVE[5 + o_isave] = ISAVE[4 + o_isave] + ISAVE[1 + o_isave]; ISAVE[6 + o_isave] = ISAVE[5 + o_isave] + ISAVE[1 + o_isave]; ISAVE[7 + o_isave] = ISAVE[6 + o_isave] + ISAVE[2 + o_isave]; ISAVE[8 + o_isave] = ISAVE[7 + o_isave] + ISAVE[2 + o_isave]; ISAVE[9 + o_isave] = ISAVE[8 + o_isave] + ISAVE[2 + o_isave]; ISAVE[10 + o_isave] = ISAVE[9 + o_isave] + ISAVE[2 + o_isave]; ISAVE[11 + o_isave] = ISAVE[10 + o_isave] + ISAVE[3 + o_isave]; ISAVE[12 + o_isave] = ISAVE[11 + o_isave] + ISAVE[3 + o_isave]; ISAVE[13 + o_isave] = ISAVE[12 + o_isave] + N; ISAVE[14 + o_isave] = ISAVE[13 + o_isave] + N; ISAVE[15 + o_isave] = ISAVE[14 + o_isave] + N; ISAVE[16 + o_isave] = ISAVE[15 + o_isave] + N; ISAVE[17 + o_isave] = ISAVE[16 + o_isave] + 8 * M; ISAVE[18 + o_isave] = ISAVE[17 + o_isave] + M; ISAVE[19 + o_isave] = ISAVE[18 + o_isave] + M; ISAVE[20 + o_isave] = ISAVE[19 + o_isave] + M; } L1 = ISAVE[1 + o_isave]; L2 = ISAVE[2 + o_isave]; L3 = ISAVE[3 + o_isave]; LWS = ISAVE[4 + o_isave]; LWY = ISAVE[5 + o_isave]; LSY = ISAVE[6 + o_isave]; LSS = ISAVE[7 + o_isave]; LYY = ISAVE[8 + o_isave]; LWT = ISAVE[9 + o_isave]; LWN = ISAVE[10 + o_isave]; LSND = ISAVE[11 + o_isave]; LZ = ISAVE[12 + o_isave]; LR = ISAVE[13 + o_isave]; LD = ISAVE[14 + o_isave]; LT = ISAVE[15 + o_isave]; LWA = ISAVE[16 + o_isave]; LSG = ISAVE[17 + o_isave]; LSGO = ISAVE[18 + o_isave]; LYG = ISAVE[19 + o_isave]; LYGO = ISAVE[20 + o_isave]; this._mainlb.Run(N, M, ref X, offset_x, L, offset_l, U, offset_u, NBD, offset_nbd , ref F, ref G, offset_g, FACTR, PGTOL, ref WA, LWS + o_wa, ref WA, LWY + o_wa , ref WA, LSY + o_wa, ref WA, LSS + o_wa, WA, LYY + o_wa, ref WA, LWT + o_wa, ref WA, LWN + o_wa, ref WA, LSND + o_wa , ref WA, LZ + o_wa, ref WA, LR + o_wa, ref WA, LD + o_wa, ref WA, LT + o_wa, ref WA, LWA + o_wa, WA, LSG + o_wa , WA, LSGO + o_wa, WA, LYG + o_wa, WA, LYGO + o_wa, ref IWA, 1 + o_iwa, ref IWA, N + 1 + o_iwa, ref IWA, 2 * N + 1 + o_iwa , ref TASK, IPRINT, ref CSAVE, ref LSAVE, offset_lsave, ref ISAVE, 22 + o_isave, ref DSAVE, offset_dsave); return; #endregion }
/// <param name="N"> /// is an integer variable. /// On entry n is the dimension of the problem. /// On exit n is unchanged. ///</param> /// <param name="M"> /// is an integer variable. /// On entry m is the maximum number of variable metric corrections /// used to define the limited memory matrix. /// On exit m is unchanged. ///</param> /// <param name="X"> /// is a double precision array of dimension n. /// On entry x is an approximation to the solution. /// On exit x is the current approximation. ///</param> /// <param name="L"> /// is a double precision array of dimension n. /// On entry l is the lower bound on x. /// On exit l is unchanged. ///</param> /// <param name="U"> /// is a double precision array of dimension n. /// On entry u is the upper bound on x. /// On exit u is unchanged. ///</param> /// <param name="NBD"> /// is an integer array of dimension n. /// On entry nbd represents the type of bounds imposed on the /// variables, and must be specified as follows: /// nbd(i)=0 if x(i) is unbounded, /// 1 if x(i) has only a lower bound, /// 2 if x(i) has both lower and upper bounds, and /// 3 if x(i) has only an upper bound. /// On exit nbd is unchanged. ///</param> /// <param name="F"> /// is a double precision variable. /// On first entry f is unspecified. /// On final exit f is the value of the function at x. ///</param> /// <param name="G"> /// is a double precision array of dimension n. /// On first entry g is unspecified. /// On final exit g is the value of the gradient at x. ///</param> /// <param name="FACTR"> /// is a double precision variable. /// On entry factr .GE. 0 is specified by the user. The iteration /// will stop when /// /// (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} .LE. factr*epsmch /// /// where epsmch is the machine precision, which is automatically /// generated by the code. Typical values for factr: 1.d+12 for /// low accuracy; 1.d+7 for moderate accuracy; 1.d+1 for extremely /// high accuracy. /// On exit factr is unchanged. ///</param> /// <param name="PGTOL"> /// is a double precision variable. /// On entry pgtol .GE. 0 is specified by the user. The iteration /// will stop when /// /// max{|proj g_i | i = 1, ..., n} .LE. pgtol /// /// where pg_i is the ith component of the projected gradient. /// On exit pgtol is unchanged. ///</param> /// <param name="WA"> /// is a double precision working array of length /// (2mmax + 4)nmax + 12mmax^2 + 12mmax. ///</param> /// <param name="IWA"> /// is an integer working array of length 3nmax. ///</param> /// <param name="TASK"> /// is a working string of characters of length 60 indicating /// the current job when entering and quitting this subroutine. ///</param> /// <param name="IPRINT"> /// is an integer variable that must be set by the user. /// It controls the frequency and type of output generated: /// iprint.LT.0 no output is generated; /// iprint=0 print only one line at the last iteration; /// 0.LT.iprint.LT.99 print also f and |proj g| every iprint iterations; /// iprint=99 print details of every iteration except n-vectors; /// iprint=100 print also the changes of active set and final x; /// iprint.GT.100 print details of every iteration including x and g; /// When iprint .GT. 0, the file iterate.dat will be created to /// summarize the iteration. ///</param> /// <param name="CSAVE"> /// is a working string of characters of length 60. ///</param> /// <param name="LSAVE"> /// is a logical working array of dimension 4. /// On exit with 'task' = NEW_X, the following information is /// available: /// If lsave(1) = .true. then the initial X has been replaced by /// its projection in the feasible set; /// If lsave(2) = .true. then the problem is constrained; /// If lsave(3) = .true. then each variable has upper and lower /// bounds; ///</param> /// <param name="ISAVE"> /// is an integer working array of dimension 44. /// On exit with 'task' = NEW_X, the following information is /// available: /// isave(22) = the total number of intervals explored in the /// search of Cauchy points; /// isave(26) = the total number of skipped BFGS updates before /// the current iteration; /// isave(30) = the number of current iteration; /// isave(31) = the total number of BFGS updates prior the current /// iteration; /// isave(33) = the number of intervals explored in the search of /// Cauchy point in the current iteration; /// isave(34) = the total number of function and gradient /// evaluations; /// isave(36) = the number of function value or gradient /// evaluations in the current iteration; /// if isave(37) = 0 then the subspace argmin is within the box; /// if isave(37) = 1 then the subspace argmin is beyond the box; /// isave(38) = the number of free variables in the current /// iteration; /// isave(39) = the number of active constraints in the current /// iteration; /// n + 1 - isave(40) = the number of variables leaving the set of /// active constraints in the current iteration; /// isave(41) = the number of variables entering the set of active /// constraints in the current iteration. ///</param> /// <param name="DSAVE"> /// is a double precision working array of dimension 29. /// On exit with 'task' = NEW_X, the following information is /// available: /// dsave(1) = current 'theta' in the BFGS matrix; /// dsave(2) = f(x) in the previous iteration; /// dsave(3) = factr*epsmch; /// dsave(4) = 2-norm of the line search direction vector; /// dsave(5) = the machine precision epsmch generated by the code; /// dsave(7) = the accumulated time spent on searching for /// Cauchy points; /// dsave(8) = the accumulated time spent on /// subspace minimization; /// dsave(9) = the accumulated time spent on line search; /// dsave(11) = the slope of the line search function at /// the current point of line search; /// dsave(12) = the maximum relative step length imposed in /// line search; /// dsave(13) = the infinity norm of the projected gradient; /// dsave(14) = the relative step length in the line search; /// dsave(15) = the slope of the line search function at /// the starting point of the line search; /// dsave(16) = the square of the 2-norm of the line search /// direction vector. ///</param> public void Run(int N, int M, ref double[] X, int offset_x, double[] L, int offset_l, double[] U, int offset_u, int[] NBD, int offset_nbd , ref double F, ref double[] G, int offset_g, double FACTR, double PGTOL, ref double[] WA, int offset_wa, ref int[] IWA, int offset_iwa , ref BFGSTask TASK, int IPRINT, ref BFGSTask CSAVE, ref bool[] LSAVE, int offset_lsave, ref int[] ISAVE, int offset_isave, ref double[] DSAVE, int offset_dsave) { #region Variables int L1 = 0; int L2 = 0; int L3 = 0; int LWS = 0; int LR = 0; int LZ = 0; int LT = 0; int LD = 0; int LSG = 0; int LWA = 0; int LYG = 0; int LSGO = 0; int LWY = 0; int LSY = 0; int LSS = 0; int LYY = 0; int LWT = 0; int LWN = 0; int LSND = 0; int LYGO = 0; #endregion #region Array Index Correction int o_x = -1 + offset_x; int o_l = -1 + offset_l; int o_u = -1 + offset_u; int o_nbd = -1 + offset_nbd; int o_g = -1 + offset_g; int o_wa = -1 + offset_wa; int o_iwa = -1 + offset_iwa; int o_lsave = -1 + offset_lsave; int o_isave = -1 + offset_isave; int o_dsave = -1 + offset_dsave; #endregion #region Prolog // c ************ // c // c Subroutine setulb // c // c This subroutine partitions the working arrays wa and iwa, and // c then uses the limited memory BFGS method to solve the bound // c constrained optimization problem by calling mainlb. // c (The direct method will be used in the subspace minimization.) // c // c n is an integer variable. // c On entry n is the dimension of the problem. // c On exit n is unchanged. // c // c m is an integer variable. // c On entry m is the maximum number of variable metric corrections // c used to define the limited memory matrix. // c On exit m is unchanged. // c // c x is a double precision array of dimension n. // c On entry x is an approximation to the solution. // c On exit x is the current approximation. // c // c l is a double precision array of dimension n. // c On entry l is the lower bound on x. // c On exit l is unchanged. // c // c u is a double precision array of dimension n. // c On entry u is the upper bound on x. // c On exit u is unchanged. // c // c nbd is an integer array of dimension n. // c On entry nbd represents the type of bounds imposed on the // c variables, and must be specified as follows: // c nbd(i)=0 if x(i) is unbounded, // c 1 if x(i) has only a lower bound, // c 2 if x(i) has both lower and upper bounds, and // c 3 if x(i) has only an upper bound. // c On exit nbd is unchanged. // c // c f is a double precision variable. // c On first entry f is unspecified. // c On final exit f is the value of the function at x. // c // c g is a double precision array of dimension n. // c On first entry g is unspecified. // c On final exit g is the value of the gradient at x. // c // c factr is a double precision variable. // c On entry factr >= 0 is specified by the user. The iteration // c will stop when // c // c (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} <= factr*epsmch // c // c where epsmch is the machine precision, which is automatically // c generated by the code. Typical values for factr: 1.d+12 for // c low accuracy; 1.d+7 for moderate accuracy; 1.d+1 for extremely // c high accuracy. // c On exit factr is unchanged. // c // c pgtol is a double precision variable. // c On entry pgtol >= 0 is specified by the user. The iteration // c will stop when // c // c max{|proj g_i | i = 1, ..., n} <= pgtol // c // c where pg_i is the ith component of the projected gradient. // c On exit pgtol is unchanged. // c // c wa is a double precision working array of length // c (2mmax + 4)nmax + 12mmax^2 + 12mmax. // c // c iwa is an integer working array of length 3nmax. // c // c task is a working string of characters of length 60 indicating // c the current job when entering and quitting this subroutine. // c // c iprint is an integer variable that must be set by the user. // c It controls the frequency and type of output generated: // c iprint<0 no output is generated; // c iprint=0 print only one line at the last iteration; // c 0<iprint<99 print also f and |proj g| every iprint iterations; // c iprint=99 print details of every iteration except n-vectors; // c iprint=100 print also the changes of active set and final x; // c iprint>100 print details of every iteration including x and g; // c When iprint > 0, the file iterate.dat will be created to // c summarize the iteration. // c // c csave is a working string of characters of length 60. // c // c lsave is a logical working array of dimension 4. // c On exit with 'task' = NEW_X, the following information is // c available: // c If lsave(1) = .true. then the initial X has been replaced by // c its projection in the feasible set; // c If lsave(2) = .true. then the problem is constrained; // c If lsave(3) = .true. then each variable has upper and lower // c bounds; // c // c isave is an integer working array of dimension 44. // c On exit with 'task' = NEW_X, the following information is // c available: // c isave(22) = the total number of intervals explored in the // c search of Cauchy points; // c isave(26) = the total number of skipped BFGS updates before // c the current iteration; // c isave(30) = the number of current iteration; // c isave(31) = the total number of BFGS updates prior the current // c iteration; // c isave(33) = the number of intervals explored in the search of // c Cauchy point in the current iteration; // c isave(34) = the total number of function and gradient // c evaluations; // c isave(36) = the number of function value or gradient // c evaluations in the current iteration; // c if isave(37) = 0 then the subspace argmin is within the box; // c if isave(37) = 1 then the subspace argmin is beyond the box; // c isave(38) = the number of free variables in the current // c iteration; // c isave(39) = the number of active constraints in the current // c iteration; // c n + 1 - isave(40) = the number of variables leaving the set of // c active constraints in the current iteration; // c isave(41) = the number of variables entering the set of active // c constraints in the current iteration. // c // c dsave is a double precision working array of dimension 29. // c On exit with 'task' = NEW_X, the following information is // c available: // c dsave(1) = current 'theta' in the BFGS matrix; // c dsave(2) = f(x) in the previous iteration; // c dsave(3) = factr*epsmch; // c dsave(4) = 2-norm of the line search direction vector; // c dsave(5) = the machine precision epsmch generated by the code; // c dsave(7) = the accumulated time spent on searching for // c Cauchy points; // c dsave(8) = the accumulated time spent on // c subspace minimization; // c dsave(9) = the accumulated time spent on line search; // c dsave(11) = the slope of the line search function at // c the current point of line search; // c dsave(12) = the maximum relative step length imposed in // c line search; // c dsave(13) = the infinity norm of the projected gradient; // c dsave(14) = the relative step length in the line search; // c dsave(15) = the slope of the line search function at // c the starting point of the line search; // c dsave(16) = the square of the 2-norm of the line search // c direction vector. // c // c Subprograms called: // c // c L-BFGS-B Library ... mainlb. // c // c // c References: // c // c [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited // c memory algorithm for bound constrained optimization'', // c SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208. // c // c [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: a // c limited memory FORTRAN code for solving bound constrained // c optimization problems'', Tech. Report, NAM-11, EECS Department, // c Northwestern University, 1994. // c // c (Postscript files of these papers are available via anonymous // c ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.) // c // c * * * // c // c NEOS, November 1994. (Latest revision June 1996.) // c Optimization Technology Center. // c Argonne National Laboratory and Northwestern University. // c Written by // c Ciyou Zhu // c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. // c // c // c ************ #endregion #region Body if (TASK == BFGSTask.START) { ISAVE[1 + o_isave] = M * N; ISAVE[2 + o_isave] = (int)Math.Pow(M, 2); ISAVE[3 + o_isave] = 4 * (int)Math.Pow(M, 2); ISAVE[4 + o_isave] = 1; ISAVE[5 + o_isave] = ISAVE[4 + o_isave] + ISAVE[1 + o_isave]; ISAVE[6 + o_isave] = ISAVE[5 + o_isave] + ISAVE[1 + o_isave]; ISAVE[7 + o_isave] = ISAVE[6 + o_isave] + ISAVE[2 + o_isave]; ISAVE[8 + o_isave] = ISAVE[7 + o_isave] + ISAVE[2 + o_isave]; ISAVE[9 + o_isave] = ISAVE[8 + o_isave] + ISAVE[2 + o_isave]; ISAVE[10 + o_isave] = ISAVE[9 + o_isave] + ISAVE[2 + o_isave]; ISAVE[11 + o_isave] = ISAVE[10 + o_isave] + ISAVE[3 + o_isave]; ISAVE[12 + o_isave] = ISAVE[11 + o_isave] + ISAVE[3 + o_isave]; ISAVE[13 + o_isave] = ISAVE[12 + o_isave] + N; ISAVE[14 + o_isave] = ISAVE[13 + o_isave] + N; ISAVE[15 + o_isave] = ISAVE[14 + o_isave] + N; ISAVE[16 + o_isave] = ISAVE[15 + o_isave] + N; ISAVE[17 + o_isave] = ISAVE[16 + o_isave] + 8 * M; ISAVE[18 + o_isave] = ISAVE[17 + o_isave] + M; ISAVE[19 + o_isave] = ISAVE[18 + o_isave] + M; ISAVE[20 + o_isave] = ISAVE[19 + o_isave] + M; } L1 = ISAVE[1 + o_isave]; L2 = ISAVE[2 + o_isave]; L3 = ISAVE[3 + o_isave]; LWS = ISAVE[4 + o_isave]; LWY = ISAVE[5 + o_isave]; LSY = ISAVE[6 + o_isave]; LSS = ISAVE[7 + o_isave]; LYY = ISAVE[8 + o_isave]; LWT = ISAVE[9 + o_isave]; LWN = ISAVE[10 + o_isave]; LSND = ISAVE[11 + o_isave]; LZ = ISAVE[12 + o_isave]; LR = ISAVE[13 + o_isave]; LD = ISAVE[14 + o_isave]; LT = ISAVE[15 + o_isave]; LWA = ISAVE[16 + o_isave]; LSG = ISAVE[17 + o_isave]; LSGO = ISAVE[18 + o_isave]; LYG = ISAVE[19 + o_isave]; LYGO = ISAVE[20 + o_isave]; this._mainlb.Run(N, M, ref X, offset_x, L, offset_l, U, offset_u, NBD, offset_nbd , ref F, ref G, offset_g, FACTR, PGTOL, ref WA, LWS + o_wa, ref WA, LWY + o_wa , ref WA, LSY + o_wa, ref WA, LSS + o_wa, WA, LYY + o_wa, ref WA, LWT + o_wa, ref WA, LWN + o_wa, ref WA, LSND + o_wa , ref WA, LZ + o_wa, ref WA, LR + o_wa, ref WA, LD + o_wa, ref WA, LT + o_wa, ref WA, LWA + o_wa, WA, LSG + o_wa , WA, LSGO + o_wa, WA, LYG + o_wa, WA, LYGO + o_wa, ref IWA, 1 + o_iwa, ref IWA, N + 1 + o_iwa, ref IWA, 2 * N + 1 + o_iwa , ref TASK, IPRINT, ref CSAVE, ref LSAVE, offset_lsave, ref ISAVE, 22 + o_isave, ref DSAVE, offset_dsave); return; #endregion }
/// <param name="N"> /// is an integer variable. /// On entry n is the number of variables. /// On exit n is unchanged. ///</param> /// <param name="M"> /// is an integer variable. /// On entry m is the maximum number of variable metric /// corrections allowed in the limited memory matrix. /// On exit m is unchanged. ///</param> /// <param name="X"> /// is a double precision array of dimension n. /// On entry x is an approximation to the solution. /// On exit x is the current approximation. ///</param> /// <param name="L"> /// is a double precision array of dimension n. /// On entry l is the lower bound of x. /// On exit l is unchanged. ///</param> /// <param name="U"> /// is a double precision array of dimension n. /// On entry u is the upper bound of x. /// On exit u is unchanged. ///</param> /// <param name="NBD"> /// is an integer array of dimension n. /// On entry nbd represents the type of bounds imposed on the /// variables, and must be specified as follows: /// nbd(i)=0 if x(i) is unbounded, /// 1 if x(i) has only a lower bound, /// 2 if x(i) has both lower and upper bounds, /// 3 if x(i) has only an upper bound. /// On exit nbd is unchanged. ///</param> /// <param name="F"> /// is a double precision variable. /// On first entry f is unspecified. /// On final exit f is the value of the function at x. ///</param> /// <param name="G"> /// is a double precision array of dimension n. /// On first entry g is unspecified. /// On final exit g is the value of the gradient at x. ///</param> /// <param name="FACTR"> /// is a double precision variable. /// On entry factr .GE. 0 is specified by the user. The iteration /// will stop when /// /// (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} .LE. factr*epsmch /// /// where epsmch is the machine precision, which is automatically /// generated by the code. /// On exit factr is unchanged. ///</param> /// <param name="PGTOL"> /// is a double precision variable. /// On entry pgtol .GE. 0 is specified by the user. The iteration /// will stop when /// /// max{|proj g_i | i = 1, ..., n} .LE. pgtol /// /// where pg_i is the ith component of the projected gradient. /// On exit pgtol is unchanged. ///</param> /// <param name="WN"> /// is a double precision working array of dimension 2m x 2m /// used to store the LEL^T factorization of the indefinite matrix /// K = [-D -Y'ZZ'Y/theta L_a'-R_z' ] /// [L_a -R_z theta*S'AA'S ] /// /// where E = [-I 0] /// [ 0 I] ///</param> /// <param name="SND"> /// is a double precision working array of dimension 2m x 2m /// used to store the lower triangular part of /// N = [Y' ZZ'Y L_a'+R_z'] /// [L_a +R_z S'AA'S ] ///</param> /// <param name="Z"> /// is used at different times to store the Cauchy point and ///</param> /// <param name="INDEX"> /// is an integer working array of dimension n. /// In subroutine freev, index is used to store the free and fixed /// variables at the Generalized Cauchy Point (GCP). ///</param> /// <param name="IWHERE"> /// is an integer working array of dimension n used to record /// the status of the vector x for GCP computation. /// iwhere(i)=0 or -3 if x(i) is free and has bounds, /// 1 if x(i) is fixed at l(i), and l(i) .ne. u(i) /// 2 if x(i) is fixed at u(i), and u(i) .ne. l(i) /// 3 if x(i) is always fixed, i.e., u(i)=x(i)=l(i) /// -1 if x(i) is always free, i.e., no bounds on it. ///</param> /// <param name="INDX2"> /// is an integer working array of dimension n. /// Within subroutine cauchy, indx2 corresponds to the array iorder. /// In subroutine freev, a list of variables entering and leaving /// the free set is stored in indx2, and it is passed on to /// subroutine formk with this information. ///</param> /// <param name="TASK"> /// is a working string of characters of length 60 indicating /// the current job when entering and leaving this subroutine. ///</param> /// <param name="IPRINT"> /// is an INTEGER variable that must be set by the user. /// It controls the frequency and type of output generated: /// iprint.LT.0 no output is generated; /// iprint=0 print only one line at the last iteration; /// 0.LT.iprint.LT.99 print also f and |proj g| every iprint iterations; /// iprint=99 print details of every iteration except n-vectors; /// iprint=100 print also the changes of active set and final x; /// iprint.GT.100 print details of every iteration including x and g; /// When iprint .GT. 0, the file iterate.dat will be created to /// summarize the iteration. ///</param> /// <param name="CSAVE"> /// is a working string of characters of length 60. ///</param> /// <param name="LSAVE"> /// is a logical working array of dimension 4. ///</param> /// <param name="ISAVE"> /// is an integer working array of dimension 23. ///</param> /// <param name="DSAVE"> /// is a double precision working array of dimension 29. /// ///</param> public void Run(int N, int M, ref double[] X, int offset_x, double[] L, int offset_l, double[] U, int offset_u, int[] NBD, int offset_nbd , ref double F, ref double[] G, int offset_g, double FACTR, double PGTOL, ref double[] WS, int offset_ws, ref double[] WY, int offset_wy , ref double[] SY, int offset_sy, ref double[] SS, int offset_ss, double[] YY, int offset_yy, ref double[] WT, int offset_wt, ref double[] WN, int offset_wn, ref double[] SND, int offset_snd , ref double[] Z, int offset_z, ref double[] R, int offset_r, ref double[] D, int offset_d, ref double[] T, int offset_t, ref double[] WA, int offset_wa, double[] SG, int offset_sg , double[] SGO, int offset_sgo, double[] YG, int offset_yg, double[] YGO, int offset_ygo, ref int[] INDEX, int offset_index, ref int[] IWHERE, int offset_iwhere, ref int[] INDX2, int offset_indx2 , ref BFGSTask TASK, int IPRINT, ref BFGSTask CSAVE, ref bool[] LSAVE, int offset_lsave, ref int[] ISAVE, int offset_isave, ref double[] DSAVE, int offset_dsave) { #region Variables BFGSWord WORD = BFGSWord.aaa; bool PRJCTD = false; bool CNSTND = false; bool BOXED = false; bool UPDATD = false; bool WRK = false; int I = 0; int K = 0; int NINTOL = 0; int ITFILE = 0; int IBACK = 0; int NSKIP = 0; int HEAD = 0; int COL = 0; int ITER = 0; int ITAIL = 0; int IUPDAT = 0; int NINT = 0; int NFGV = 0; int INFO = 0; int IFUN = 0; int IWORD = 0; int NFREE = 0; int NACT = 0; int ILEAVE = 0; int NENTER = 0; double THETA = 0; double FOLD = 0; double DDOT = 0; double DR = 0; double RR = 0; double TOL = 0; double DPMEPS = 0; double XSTEP = 0; double SBGNRM = 0; double DDUM = 0; double DNORM = 0; double DTD = 0; double EPSMCH = 0; double CPU1 = 0; double CPU2 = 0; double CACHYT = 0; double SBTIME = 0; double LNSCHT = 0; double TIME1 = 0; double TIME2 = 0; double GD = 0; double GDOLD = 0; double STP = 0; double STPMX = 0; double TIME = 0; #endregion #region Array Index Correction int o_x = -1 + offset_x; int o_l = -1 + offset_l; int o_u = -1 + offset_u; int o_nbd = -1 + offset_nbd; int o_g = -1 + offset_g; int o_ws = -1 - N + offset_ws; int o_wy = -1 - N + offset_wy; int o_sy = -1 - M + offset_sy; int o_ss = -1 - M + offset_ss; int o_yy = -1 - M + offset_yy; int o_wt = -1 - M + offset_wt; int o_wn = -1 - (2 * M) + offset_wn; int o_snd = -1 - (2 * M) + offset_snd; int o_z = -1 + offset_z; int o_r = -1 + offset_r; int o_d = -1 + offset_d; int o_t = -1 + offset_t; int o_wa = -1 + offset_wa; int o_sg = -1 + offset_sg; int o_sgo = -1 + offset_sgo; int o_yg = -1 + offset_yg; int o_ygo = -1 + offset_ygo; int o_index = -1 + offset_index; int o_iwhere = -1 + offset_iwhere; int o_indx2 = -1 + offset_indx2; int o_lsave = -1 + offset_lsave; int o_isave = -1 + offset_isave; int o_dsave = -1 + offset_dsave; #endregion #region Prolog // c ************ // c // c Subroutine mainlb // c // c This subroutine solves bound constrained optimization problems by // c using the compact formula of the limited memory BFGS updates. // c // c n is an integer variable. // c On entry n is the number of variables. // c On exit n is unchanged. // c // c m is an integer variable. // c On entry m is the maximum number of variable metric // c corrections allowed in the limited memory matrix. // c On exit m is unchanged. // c // c x is a double precision array of dimension n. // c On entry x is an approximation to the solution. // c On exit x is the current approximation. // c // c l is a double precision array of dimension n. // c On entry l is the lower bound of x. // c On exit l is unchanged. // c // c u is a double precision array of dimension n. // c On entry u is the upper bound of x. // c On exit u is unchanged. // c // c nbd is an integer array of dimension n. // c On entry nbd represents the type of bounds imposed on the // c variables, and must be specified as follows: // c nbd(i)=0 if x(i) is unbounded, // c 1 if x(i) has only a lower bound, // c 2 if x(i) has both lower and upper bounds, // c 3 if x(i) has only an upper bound. // c On exit nbd is unchanged. // c // c f is a double precision variable. // c On first entry f is unspecified. // c On final exit f is the value of the function at x. // c // c g is a double precision array of dimension n. // c On first entry g is unspecified. // c On final exit g is the value of the gradient at x. // c // c factr is a double precision variable. // c On entry factr >= 0 is specified by the user. The iteration // c will stop when // c // c (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} <= factr*epsmch // c // c where epsmch is the machine precision, which is automatically // c generated by the code. // c On exit factr is unchanged. // c // c pgtol is a double precision variable. // c On entry pgtol >= 0 is specified by the user. The iteration // c will stop when // c // c max{|proj g_i | i = 1, ..., n} <= pgtol // c // c where pg_i is the ith component of the projected gradient. // c On exit pgtol is unchanged. // c // c ws, wy, sy, and wt are double precision working arrays used to // c store the following information defining the limited memory // c BFGS matrix: // c ws, of dimension n x m, stores S, the matrix of s-vectors; // c wy, of dimension n x m, stores Y, the matrix of y-vectors; // c sy, of dimension m x m, stores S'Y; // c ss, of dimension m x m, stores S'S; // c yy, of dimension m x m, stores Y'Y; // c wt, of dimension m x m, stores the Cholesky factorization // c of (theta*S'S+LD^(-1)L'); see eq. // c (2.26) in [3]. // c // c wn is a double precision working array of dimension 2m x 2m // c used to store the LEL^T factorization of the indefinite matrix // c K = [-D -Y'ZZ'Y/theta L_a'-R_z' ] // c [L_a -R_z theta*S'AA'S ] // c // c where E = [-I 0] // c [ 0 I] // c // c snd is a double precision working array of dimension 2m x 2m // c used to store the lower triangular part of // c N = [Y' ZZ'Y L_a'+R_z'] // c [L_a +R_z S'AA'S ] // c // c z(n),r(n),d(n),t(n),wa(8*m) are double precision working arrays. // c z is used at different times to store the Cauchy point and // c the Newton point. // c // c sg(m),sgo(m),yg(m),ygo(m) are double precision working arrays. // c // c index is an integer working array of dimension n. // c In subroutine freev, index is used to store the free and fixed // c variables at the Generalized Cauchy Point (GCP). // c // c iwhere is an integer working array of dimension n used to record // c the status of the vector x for GCP computation. // c iwhere(i)=0 or -3 if x(i) is free and has bounds, // c 1 if x(i) is fixed at l(i), and l(i) .ne. u(i) // c 2 if x(i) is fixed at u(i), and u(i) .ne. l(i) // c 3 if x(i) is always fixed, i.e., u(i)=x(i)=l(i) // c -1 if x(i) is always free, i.e., no bounds on it. // c // c indx2 is an integer working array of dimension n. // c Within subroutine cauchy, indx2 corresponds to the array iorder. // c In subroutine freev, a list of variables entering and leaving // c the free set is stored in indx2, and it is passed on to // c subroutine formk with this information. // c // c task is a working string of characters of length 60 indicating // c the current job when entering and leaving this subroutine. // c // c iprint is an INTEGER variable that must be set by the user. // c It controls the frequency and type of output generated: // c iprint<0 no output is generated; // c iprint=0 print only one line at the last iteration; // c 0<iprint<99 print also f and |proj g| every iprint iterations; // c iprint=99 print details of every iteration except n-vectors; // c iprint=100 print also the changes of active set and final x; // c iprint>100 print details of every iteration including x and g; // c When iprint > 0, the file iterate.dat will be created to // c summarize the iteration. // c // c csave is a working string of characters of length 60. // c // c lsave is a logical working array of dimension 4. // c // c isave is an integer working array of dimension 23. // c // c dsave is a double precision working array of dimension 29. // c // c // c Subprograms called // c // c L-BFGS-B Library ... cauchy, subsm, lnsrlb, formk, // c // c errclb, prn1lb, prn2lb, prn3lb, active, projgr, // c // c freev, cmprlb, matupd, formt. // c // c Minpack2 Library ... timer, dpmeps. // c // c Linpack Library ... dcopy, ddot. // c // c // c References: // c // c [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited // c memory algorithm for bound constrained optimization'', // c SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208. // c // c [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: FORTRAN // c Subroutines for Large Scale Bound Constrained Optimization'' // c Tech. Report, NAM-11, EECS Department, Northwestern University, // c 1994. // c // c [3] R. Byrd, J. Nocedal and R. Schnabel "Representations of // c Quasi-Newton Matrices and their use in Limited Memory Methods'', // c Mathematical Programming 63 (1994), no. 4, pp. 129-156. // c // c (Postscript files of these papers are available via anonymous // c ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.) // c // c * * * // c // c NEOS, November 1994. (Latest revision June 1996.) // c Optimization Technology Center. // c Argonne National Laboratory and Northwestern University. // c Written by // c Ciyou Zhu // c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. // c // c // c ************ #endregion #region Body if (TASK == BFGSTask.START) { this._timer.Run(ref TIME1); // c Generate the current machine precision. EPSMCH = this._dpmeps.Run(); // c Initialize counters and scalars when task='START'. // c for the limited memory BFGS matrices: COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; // c for operation counts: ITER = 0; NFGV = 0; NINT = 0; NINTOL = 0; NSKIP = 0; NFREE = N; // c for stopping tolerance: TOL = FACTR * EPSMCH; // c for measuring running time: CACHYT = 0; SBTIME = 0; LNSCHT = 0; // c 'word' records the status of subspace solutions. WORD = BFGSWord.aaa; // c 'info' records the termination information. INFO = 0; if (IPRINT >= 1) { // c open a summary file 'iterate.dat' //ERROR-ERROR OPEN (8, FILE = 'iterate.dat', STATUS = 'unknown'); ITFILE = 8; } // c Check the input arguments for errors. this._errclb.Run(N, M, FACTR, L, offset_l, U, offset_u, NBD, offset_nbd , ref TASK, ref INFO, ref K); if (TASK == BFGSTask.ERROR) { this._prn3lb.Run(N, X, offset_x, F, TASK, IPRINT, INFO , ITFILE, ITER, NFGV, NINTOL, NSKIP, NACT , SBGNRM, ZERO, NINT, WORD, IBACK, STP , XSTEP, K, CACHYT, SBTIME, LNSCHT); return; } this._prn1lb.Run(N, M, L, offset_l, U, offset_u, X, offset_x, IPRINT , ITFILE, EPSMCH); // c Initialize iwhere & project x onto the feasible set. this._active.Run(N, L, offset_l, U, offset_u, NBD, offset_nbd, ref X, offset_x, ref IWHERE, offset_iwhere , IPRINT, ref PRJCTD, ref CNSTND, ref BOXED); // c The end of the initialization. } else { // c restore local variables. PRJCTD = LSAVE[1 + o_lsave]; CNSTND = LSAVE[2 + o_lsave]; BOXED = LSAVE[3 + o_lsave]; UPDATD = LSAVE[4 + o_lsave]; NINTOL = ISAVE[1 + o_isave]; ITFILE = ISAVE[3 + o_isave]; IBACK = ISAVE[4 + o_isave]; NSKIP = ISAVE[5 + o_isave]; HEAD = ISAVE[6 + o_isave]; COL = ISAVE[7 + o_isave]; ITAIL = ISAVE[8 + o_isave]; ITER = ISAVE[9 + o_isave]; IUPDAT = ISAVE[10 + o_isave]; NINT = ISAVE[12 + o_isave]; NFGV = ISAVE[13 + o_isave]; INFO = ISAVE[14 + o_isave]; IFUN = ISAVE[15 + o_isave]; IWORD = ISAVE[16 + o_isave]; NFREE = ISAVE[17 + o_isave]; NACT = ISAVE[18 + o_isave]; ILEAVE = ISAVE[19 + o_isave]; NENTER = ISAVE[20 + o_isave]; THETA = DSAVE[1 + o_dsave]; FOLD = DSAVE[2 + o_dsave]; TOL = DSAVE[3 + o_dsave]; DNORM = DSAVE[4 + o_dsave]; EPSMCH = DSAVE[5 + o_dsave]; CPU1 = DSAVE[6 + o_dsave]; CACHYT = DSAVE[7 + o_dsave]; SBTIME = DSAVE[8 + o_dsave]; LNSCHT = DSAVE[9 + o_dsave]; TIME1 = DSAVE[10 + o_dsave]; GD = DSAVE[11 + o_dsave]; STPMX = DSAVE[12 + o_dsave]; SBGNRM = DSAVE[13 + o_dsave]; STP = DSAVE[14 + o_dsave]; GDOLD = DSAVE[15 + o_dsave]; DTD = DSAVE[16 + o_dsave]; // c After returning from the driver go to the point where execution // c is to resume. if (TASK == BFGSTask.FG_LNSRCH) { goto LABEL666; } if (TASK == BFGSTask.NEW_X) { goto LABEL777; } if (TASK == BFGSTask.FG_ST || TASK == BFGSTask.FG_START) { goto LABEL111; } if (TASK == BFGSTask.STOP) { if (TASK == BFGSTask.CPU) { // c restore the previous iterate. this._dcopy.Run(N, T, offset_t, 1, ref X, offset_x, 1); this._dcopy.Run(N, R, offset_r, 1, ref G, offset_g, 1); F = FOLD; } goto LABEL999; } } // c Compute f0 and g0. TASK = BFGSTask.FG_START; // c return to the driver to calculate f and g; reenter at 111. goto LABEL1000; LABEL111 :; NFGV = 1; // c Compute the infinity norm of the (-) projected gradient. this._projgr.Run(N, L, offset_l, U, offset_u, NBD, offset_nbd, X, offset_x, G, offset_g , ref SBGNRM); if (IPRINT >= 1) { //ERROR-ERROR WRITE (6,1002) ITER,F,SBGNRM; //ERROR-ERROR WRITE (ITFILE,1003) ITER,NFGV,SBGNRM,F; } if (SBGNRM <= PGTOL) { // c terminate the algorithm. TASK = BFGSTask.CONV; goto LABEL999; } // c ----------------- the beginning of the loop -------------------------- LABEL222 :; if (IPRINT >= 99) { ; //ERROR-ERRORWRITE(6,1001)ITER+1 } IWORD = -1; // c if (!CNSTND && COL > 0) { // c skip the search for GCP. this._dcopy.Run(N, X, offset_x, 1, ref Z, offset_z, 1); WRK = UPDATD; NINT = 0; goto LABEL333; } // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // c // c Compute the Generalized Cauchy Point (GCP). // c // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc this._timer.Run(ref CPU1); this._cauchy.Run(N, X, offset_x, L, offset_l, U, offset_u, NBD, offset_nbd, G, offset_g , ref INDX2, offset_indx2, ref IWHERE, offset_iwhere, ref T, offset_t, ref D, offset_d, ref Z, offset_z, M , WY, offset_wy, WS, offset_ws, SY, offset_sy, WT, offset_wt, THETA, COL , HEAD, ref WA, 1 + o_wa, ref WA, 2 * M + 1 + o_wa, ref WA, 4 * M + 1 + o_wa, ref WA, 6 * M + 1 + o_wa, ref NINT , SG, offset_sg, YG, offset_yg, IPRINT, SBGNRM, ref INFO, EPSMCH); if (INFO != 0) { // c singular triangular system detected; refresh the lbfgs memory. if (IPRINT >= 1) { ; //ERROR-ERRORWRITE(6,1005) } INFO = 0; COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; this._timer.Run(ref CPU2); CACHYT += CPU2 - CPU1; goto LABEL222; } this._timer.Run(ref CPU2); CACHYT += CPU2 - CPU1; NINTOL += NINT; // c Count the entering and leaving variables for iter > 0; // c find the index set of free and active variables at the GCP. this._freev.Run(N, ref NFREE, ref INDEX, offset_index, ref NENTER, ref ILEAVE, ref INDX2, offset_indx2 , IWHERE, offset_iwhere, ref WRK, UPDATD, CNSTND, IPRINT, ITER); NACT = N - NFREE; LABEL333 :; // c If there are no free variables or B=theta*I, then // c skip the subspace minimization. if (NFREE == 0 || COL == 0) { goto LABEL555; } // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // c // c Subspace minimization. // c // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc this._timer.Run(ref CPU1); // c Form the LEL^T factorization of the indefinite // c matrix K = [-D -Y'ZZ'Y/theta L_a'-R_z' ] // c [L_a -R_z theta*S'AA'S ] // c where E = [-I 0] // c [ 0 I] if (WRK) { this._formk.Run(N, NFREE, INDEX, offset_index, NENTER, ILEAVE, INDX2, offset_indx2 , IUPDAT, UPDATD, ref WN, offset_wn, ref SND, offset_snd, M, WS, offset_ws , WY, offset_wy, SY, offset_sy, THETA, COL, HEAD, ref INFO); } if (INFO != 0) { // c nonpositive definiteness in Cholesky factorization; // c refresh the lbfgs memory and restart the iteration. if (IPRINT >= 1) { ; //ERROR-ERRORWRITE(6,1006) } INFO = 0; COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; this._timer.Run(ref CPU2); SBTIME += CPU2 - CPU1; goto LABEL222; } // c compute r=-Z'B(xcp-xk)-Z'g (using wa(2m+1)=W'(xcp-x) // c from 'cauchy'). this._cmprlb.Run(N, M, X, offset_x, G, offset_g, WS, offset_ws, WY, offset_wy , SY, offset_sy, WT, offset_wt, Z, offset_z, ref R, offset_r, ref WA, offset_wa, INDEX, offset_index , THETA, COL, HEAD, NFREE, CNSTND, ref INFO); if (INFO != 0) { goto LABEL444; } // c call the direct method. this._subsm.Run(N, M, NFREE, INDEX, offset_index, L, offset_l, U, offset_u , NBD, offset_nbd, ref Z, offset_z, ref R, offset_r, WS, offset_ws, WY, offset_wy, THETA , COL, HEAD, ref IWORD, ref WA, offset_wa, WN, offset_wn, IPRINT , ref INFO); LABEL444 :; if (INFO != 0) { // c singular triangular system detected; // c refresh the lbfgs memory and restart the iteration. if (IPRINT >= 1) { ; //ERROR-ERRORWRITE(6,1005) } INFO = 0; COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; this._timer.Run(ref CPU2); SBTIME += CPU2 - CPU1; goto LABEL222; } this._timer.Run(ref CPU2); SBTIME += CPU2 - CPU1; LABEL555 :; // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // c // c Line search and optimality tests. // c // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // c Generate the search direction d:=z-x. for (I = 1; I <= N; I++) { D[I + o_d] = Z[I + o_z] - X[I + o_x]; } this._timer.Run(ref CPU1); LABEL666 :; this._lnsrlb.Run(N, L, offset_l, U, offset_u, NBD, offset_nbd, ref X, offset_x, F , ref FOLD, ref GD, ref GDOLD, G, offset_g, D, offset_d, ref R, offset_r , ref T, offset_t, Z, offset_z, ref STP, ref DNORM, ref DTD, ref XSTEP , ref STPMX, ITER, ref IFUN, ref IBACK, ref NFGV, ref INFO , ref TASK, BOXED, CNSTND, ref CSAVE, ref ISAVE, 22 + o_isave, ref DSAVE, 17 + o_dsave); if (INFO != 0 || IBACK >= 20) { // c restore the previous iterate. this._dcopy.Run(N, T, offset_t, 1, ref X, offset_x, 1); this._dcopy.Run(N, R, offset_r, 1, ref G, offset_g, 1); F = FOLD; if (COL == 0) { // c abnormal termination. if (INFO == 0) { INFO = -9; // c restore the actual number of f and g evaluations etc. NFGV -= 1; IFUN -= 1; IBACK -= 1; } TASK = BFGSTask.ABNO; ITER += 1; goto LABEL999; } else { // c refresh the lbfgs memory and restart the iteration. if (IPRINT >= 1) { ; //ERROR-ERRORWRITE(6,1008) } if (INFO == 0) { NFGV -= 1; } INFO = 0; COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; TASK = BFGSTask.RESTART; this._timer.Run(ref CPU2); LNSCHT += CPU2 - CPU1; goto LABEL222; } } else { if (TASK == BFGSTask.FG_LNSRCH) { // c return to the driver for calculating f and g; reenter at 666. goto LABEL1000; } else { // c calculate and print out the quantities related to the new X. this._timer.Run(ref CPU2); LNSCHT += CPU2 - CPU1; ITER += 1; // c Compute the infinity norm of the projected (-)gradient. this._projgr.Run(N, L, offset_l, U, offset_u, NBD, offset_nbd, X, offset_x, G, offset_g , ref SBGNRM); // c Print iteration information. this._prn2lb.Run(N, X, offset_x, F, G, offset_g, IPRINT, ITFILE , ITER, NFGV, NACT, SBGNRM, NINT, ref WORD , IWORD, IBACK, STP, XSTEP); goto LABEL1000; } } LABEL777 :; // c Test for termination. if (SBGNRM <= PGTOL) { // c terminate the algorithm. TASK = BFGSTask.CONV; goto LABEL999; } DDUM = Math.Max(Math.Abs(FOLD), Math.Max(Math.Abs(F), ONE)); if ((FOLD - F) <= TOL * DDUM) { // c terminate the algorithm. TASK = BFGSTask.CONV; if (IBACK >= 10) { INFO = -5; } // c i.e., to issue a warning if iback>10 in the line search. goto LABEL999; } // c Compute d=newx-oldx, r=newg-oldg, rr=y'y and dr=y's. for (I = 1; I <= N; I++) { R[I + o_r] = G[I + o_g] - R[I + o_r]; } RR = this._ddot.Run(N, R, offset_r, 1, R, offset_r, 1); if (STP == ONE) { DR = GD - GDOLD; DDUM = -GDOLD; } else { DR = (GD - GDOLD) * STP; this._dscal.Run(N, STP, ref D, offset_d, 1); DDUM = -GDOLD * STP; } if (DR <= EPSMCH * DDUM) { // c skip the L-BFGS update. NSKIP += 1; UPDATD = false; if (IPRINT >= 1) { ; //ERROR-ERRORWRITE(6,1004)DR,DDUM } goto LABEL888; } // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc // c // c Update the L-BFGS matrix. // c // cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc UPDATD = true; IUPDAT += 1; // c Update matrices WS and WY and form the middle matrix in B. this._matupd.Run(N, M, ref WS, offset_ws, ref WY, offset_wy, ref SY, offset_sy, ref SS, offset_ss , D, offset_d, R, offset_r, ref ITAIL, IUPDAT, ref COL, ref HEAD , ref THETA, RR, DR, STP, DTD); // c Form the upper half of the pds T = theta*SS + L*D^(-1)*L'; // c Store T in the upper triangular of the array wt; // c Cholesky factorize T to J*J' with // c J' stored in the upper triangular of wt. this._formt.Run(M, ref WT, offset_wt, SY, offset_sy, SS, offset_ss, COL, THETA , ref INFO); if (INFO != 0) { // c nonpositive definiteness in Cholesky factorization; // c refresh the lbfgs memory and restart the iteration. if (IPRINT >= 1) { ; //ERROR-ERRORWRITE(6,1007) } INFO = 0; COL = 0; HEAD = 1; THETA = ONE; IUPDAT = 0; UPDATD = false; goto LABEL222; } // c Now the inverse of the middle matrix in B is // c [ D^(1/2) O ] [ -D^(1/2) D^(-1/2)*L' ] // c [ -L*D^(-1/2) J ] [ 0 J' ] LABEL888 :; // c -------------------- the end of the loop ----------------------------- goto LABEL222; LABEL999 :; this._timer.Run(ref TIME2); TIME = TIME2 - TIME1; this._prn3lb.Run(N, X, offset_x, F, TASK, IPRINT, INFO , ITFILE, ITER, NFGV, NINTOL, NSKIP, NACT , SBGNRM, TIME, NINT, WORD, IBACK, STP , XSTEP, K, CACHYT, SBTIME, LNSCHT); LABEL1000 :; // c Save local variables. LSAVE[1 + o_lsave] = PRJCTD; LSAVE[2 + o_lsave] = CNSTND; LSAVE[3 + o_lsave] = BOXED; LSAVE[4 + o_lsave] = UPDATD; ISAVE[1 + o_isave] = NINTOL; ISAVE[3 + o_isave] = ITFILE; ISAVE[4 + o_isave] = IBACK; ISAVE[5 + o_isave] = NSKIP; ISAVE[6 + o_isave] = HEAD; ISAVE[7 + o_isave] = COL; ISAVE[8 + o_isave] = ITAIL; ISAVE[9 + o_isave] = ITER; ISAVE[10 + o_isave] = IUPDAT; ISAVE[12 + o_isave] = NINT; ISAVE[13 + o_isave] = NFGV; ISAVE[14 + o_isave] = INFO; ISAVE[15 + o_isave] = IFUN; ISAVE[16 + o_isave] = IWORD; ISAVE[17 + o_isave] = NFREE; ISAVE[18 + o_isave] = NACT; ISAVE[19 + o_isave] = ILEAVE; ISAVE[20 + o_isave] = NENTER; DSAVE[1 + o_dsave] = THETA; DSAVE[2 + o_dsave] = FOLD; DSAVE[3 + o_dsave] = TOL; DSAVE[4 + o_dsave] = DNORM; DSAVE[5 + o_dsave] = EPSMCH; DSAVE[6 + o_dsave] = CPU1; DSAVE[7 + o_dsave] = CACHYT; DSAVE[8 + o_dsave] = SBTIME; DSAVE[9 + o_dsave] = LNSCHT; DSAVE[10 + o_dsave] = TIME1; DSAVE[11 + o_dsave] = GD; DSAVE[12 + o_dsave] = STPMX; DSAVE[13 + o_dsave] = SBGNRM; DSAVE[14 + o_dsave] = STP; DSAVE[15 + o_dsave] = GDOLD; DSAVE[16 + o_dsave] = DTD; return; #endregion }
public void Run(int N, double[] X, int offset_x, double F, BFGSTask TASK, int IPRINT, int INFO , int ITFILE, int ITER, int NFGV, int NINTOL, int NSKIP, int NACT , double SBGNRM, double TIME, int NINT, BFGSWord WORD, int IBACK, double STP , double XSTEP, int K, double CACHYT, double SBTIME, double LNSCHT) { #region Variables int I = 0; #endregion #region Array Index Correction int o_x = -1 + offset_x; #endregion #region Prolog // c ************ // c // c Subroutine prn3lb // c // c This subroutine prints out information when either a built-in // c convergence test is satisfied or when an error message is // c generated. // c // c // c * * * // c // c NEOS, November 1994. (Latest revision June 1996.) // c Optimization Technology Center. // c Argonne National Laboratory and Northwestern University. // c Written by // c Ciyou Zhu // c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. // c // c // c ************ #endregion #region Body if (TASK == BFGSTask.ERROR) goto LABEL999; if (IPRINT >= 0) { //ERROR-ERROR WRITE (6,3003); //ERROR-ERROR WRITE (6,3004); //ERROR-ERROR WRITE(6,3005) N,ITER,NFGV,NINTOL,NSKIP,NACT,SBGNRM,F; if (IPRINT >= 100) { //ERROR-ERROR WRITE (6,1004) 'X =',(X(I),I = 1,N); } if (IPRINT >= 1) ;//ERROR-ERRORWRITE(6,*)' F =',F } LABEL999:; if (IPRINT >= 0) { //ERROR-ERROR WRITE (6,3009) TASK; if (INFO != 0) { if (INFO == - 1) ;//ERROR-ERRORWRITE(6,9011) if (INFO == - 2) ;//ERROR-ERRORWRITE(6,9012) if (INFO == - 3) ;//ERROR-ERRORWRITE(6,9013) if (INFO == - 4) ;//ERROR-ERRORWRITE(6,9014) if (INFO == - 5) ;//ERROR-ERRORWRITE(6,9015) if (INFO == - 6) ;//ERROR-ERRORWRITE(6,*)' Input nbd(',K,') is invalid.' if (INFO == - 7) ;//ERROR-ERRORWRITE(6,*)' l(',K,') > u(',K,'). No feasible solution.' if (INFO == - 8) ;//ERROR-ERRORWRITE(6,9018) if (INFO == - 9) ;//ERROR-ERRORWRITE(6,9019) } if (IPRINT >= 1) ;//ERROR-ERRORWRITE(6,3007)CACHYT,SBTIME,LNSCHT //ERROR-ERROR WRITE (6,3008) TIME; if (IPRINT >= 1) { if (INFO == - 4 || INFO == - 9) { //ERROR-ERROR WRITE (ITFILE,3002)ITER,NFGV,NINT,NACT,WORD,IBACK,STP,XSTEP; } //ERROR-ERROR WRITE (ITFILE,3009) TASK; if (INFO != 0) { if (INFO == - 1) ;//ERROR-ERRORWRITE(ITFILE,9011) if (INFO == - 2) ;//ERROR-ERRORWRITE(ITFILE,9012) if (INFO == - 3) ;//ERROR-ERRORWRITE(ITFILE,9013) if (INFO == - 4) ;//ERROR-ERRORWRITE(ITFILE,9014) if (INFO == - 5) ;//ERROR-ERRORWRITE(ITFILE,9015) if (INFO == - 8) ;//ERROR-ERRORWRITE(ITFILE,9018) if (INFO == - 9) ;//ERROR-ERRORWRITE(ITFILE,9019) } //ERROR-ERROR WRITE (ITFILE,3008) TIME; } } return; #endregion }
public void Run(int N, double[] L, int offset_l, double[] U, int offset_u, int[] NBD, int offset_nbd, ref double[] X, int offset_x, double F , ref double FOLD, ref double GD, ref double GDOLD, double[] G, int offset_g, double[] D, int offset_d, ref double[] R, int offset_r , ref double[] T, int offset_t, double[] Z, int offset_z, ref double STP, ref double DNORM, ref double DTD, ref double XSTEP , ref double STPMX, int ITER, ref int IFUN, ref int IBACK, ref int NFGV, ref int INFO , ref BFGSTask TASK, bool BOXED, bool CNSTND, ref BFGSTask CSAVE, ref int[] ISAVE, int offset_isave, ref double[] DSAVE, int offset_dsave) { #region Variables int I = 0; double DDOT = 0; double A1 = 0; double A2 = 0; #endregion #region Array Index Correction int o_l = -1 + offset_l; int o_u = -1 + offset_u; int o_nbd = -1 + offset_nbd; int o_x = -1 + offset_x; int o_g = -1 + offset_g; int o_d = -1 + offset_d; int o_r = -1 + offset_r; int o_t = -1 + offset_t; int o_z = -1 + offset_z; int o_isave = -1 + offset_isave; int o_dsave = -1 + offset_dsave; #endregion #region Prolog // c ********** // c // c Subroutine lnsrlb // c // c This subroutine calls subroutine dcsrch from the Minpack2 library // c to perform the line search. Subroutine dscrch is safeguarded so // c that all trial points lie within the feasible region. // c // c Subprograms called: // c // c Minpack2 Library ... dcsrch. // c // c Linpack ... dtrsl, ddot. // c // c // c * * * // c // c NEOS, November 1994. (Latest revision June 1996.) // c Optimization Technology Center. // c Argonne National Laboratory and Northwestern University. // c Written by // c Ciyou Zhu // c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal. // c // c // c ********** #endregion #region Body if (TASK == BFGSTask.FG_LNSRCH) { goto LABEL556; } DTD = this._ddot.Run(N, D, offset_d, 1, D, offset_d, 1); DNORM = Math.Sqrt(DTD); // c Determine the maximum step length. STPMX = BIG; if (CNSTND) { if (ITER == 0) { STPMX = ONE; } else { for (I = 1; I <= N; I++) { A1 = D[I + o_d]; if (NBD[I + o_nbd] != 0) { if (A1 < ZERO && NBD[I + o_nbd] <= 2) { A2 = L[I + o_l] - X[I + o_x]; if (A2 >= ZERO) { STPMX = ZERO; } else { if (A1 * STPMX < A2) { STPMX = A2 / A1; } } } else { if (A1 > ZERO && NBD[I + o_nbd] >= 2) { A2 = U[I + o_u] - X[I + o_x]; if (A2 <= ZERO) { STPMX = ZERO; } else { if (A1 * STPMX > A2) { STPMX = A2 / A1; } } } } } } } } if (ITER == 0 && !BOXED) { STP = Math.Min(ONE / DNORM, STPMX); } else { STP = ONE; } this._dcopy.Run(N, X, offset_x, 1, ref T, offset_t, 1); this._dcopy.Run(N, G, offset_g, 1, ref R, offset_r, 1); FOLD = F; IFUN = 0; IBACK = 0; CSAVE = BFGSTask.START; LABEL556 :; GD = this._ddot.Run(N, G, offset_g, 1, D, offset_d, 1); if (IFUN == 0) { GDOLD = GD; if (GD >= ZERO) { // c the directional derivative >=0. // c Line search is impossible. INFO = -4; return; } } this._dcsrch.Run(F, GD, ref STP, FTOL, GTOL, XTOL , ZERO, STPMX, ref CSAVE, ref ISAVE, offset_isave, ref DSAVE, offset_dsave); XSTEP = STP * DNORM; if (CSAVE != BFGSTask.CONV && CSAVE != BFGSTask.WARNING) { TASK = BFGSTask.FG_LNSRCH; IFUN += 1; NFGV += 1; IBACK = IFUN - 1; if (STP == ONE) { this._dcopy.Run(N, Z, offset_z, 1, ref X, offset_x, 1); } else { for (I = 1; I <= N; I++) { X[I + o_x] = STP * D[I + o_d] + T[I + o_t]; } } } else { TASK = BFGSTask.NEW_X; } return; #endregion }