BOBYQAOptimizer.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. // CHECKSTYLE: stop all
  18. package org.apache.commons.math4.legacy.optim.nonlinear.scalar.noderiv;

  19. import org.apache.commons.math4.legacy.analysis.MultivariateFunction;
  20. import org.apache.commons.math4.legacy.exception.MathIllegalStateException;
  21. import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
  22. import org.apache.commons.math4.legacy.exception.OutOfRangeException;
  23. import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
  24. import org.apache.commons.math4.legacy.linear.Array2DRowRealMatrix;
  25. import org.apache.commons.math4.legacy.linear.ArrayRealVector;
  26. import org.apache.commons.math4.legacy.linear.RealVector;
  27. import org.apache.commons.math4.legacy.optim.PointValuePair;
  28. import org.apache.commons.math4.legacy.optim.nonlinear.scalar.GoalType;
  29. import org.apache.commons.math4.legacy.optim.nonlinear.scalar.MultivariateOptimizer;
  30. import org.apache.commons.math4.core.jdkmath.JdkMath;

  31. /**
  32.  * Powell's BOBYQA algorithm. This implementation is translated and
  33.  * adapted from the Fortran version available
  34.  * <a href="http://plato.asu.edu/ftp/other_software/bobyqa.zip">here</a>.
  35.  * See <a href="http://www.optimization-online.org/DB_HTML/2010/05/2616.html">
  36.  * this paper</a> for an introduction.
  37.  * <br>
  38.  * BOBYQA is particularly well suited for high dimensional problems
  39.  * where derivatives are not available. In most cases it outperforms the
  40.  * {@link PowellOptimizer} significantly. Stochastic algorithms like
  41.  * {@link CMAESOptimizer} succeed more often than BOBYQA, but are more
  42.  * expensive. BOBYQA could also be considered as a replacement of any
  43.  * derivative-based optimizer when the derivatives are approximated by
  44.  * finite differences.
  45.  *
  46.  * @since 3.0
  47.  */
  48. public class BOBYQAOptimizer
  49.     extends MultivariateOptimizer {
  50.     /** Minimum dimension of the problem: {@value}. */
  51.     public static final int MINIMUM_PROBLEM_DIMENSION = 2;
  52.     /** Default value for {@link #initialTrustRegionRadius}: {@value}. */
  53.     public static final double DEFAULT_INITIAL_RADIUS = 10.0;
  54.     /** Default value for {@link #stoppingTrustRegionRadius}: {@value}. */
  55.     public static final double DEFAULT_STOPPING_RADIUS = 1E-8;
  56.     /** Constant 0. */
  57.     private static final double ZERO = 0d;
  58.     /** Constant 1. */
  59.     private static final double ONE = 1d;
  60.     /** Constant 2. */
  61.     private static final double TWO = 2d;
  62.     /** Constant 10. */
  63.     private static final double TEN = 10d;
  64.     /** Constant 16. */
  65.     private static final double SIXTEEN = 16d;
  66.     /** Constant 250. */
  67.     private static final double TWO_HUNDRED_FIFTY = 250d;
  68.     /** Constant -1. */
  69.     private static final double MINUS_ONE = -ONE;
  70.     /** Constant 1/2. */
  71.     private static final double HALF = ONE / 2;
  72.     /** Constant 1/4. */
  73.     private static final double ONE_OVER_FOUR = ONE / 4;
  74.     /** Constant 1/8. */
  75.     private static final double ONE_OVER_EIGHT = ONE / 8;
  76.     /** Constant 1/10. */
  77.     private static final double ONE_OVER_TEN = ONE / 10;
  78.     /** Constant 1/1000. */
  79.     private static final double ONE_OVER_A_THOUSAND = ONE / 1000;

  80.     /**
  81.      * numberOfInterpolationPoints XXX.
  82.      */
  83.     private final int numberOfInterpolationPoints;
  84.     /**
  85.      * initialTrustRegionRadius XXX.
  86.      */
  87.     private double initialTrustRegionRadius;
  88.     /**
  89.      * stoppingTrustRegionRadius XXX.
  90.      */
  91.     private final double stoppingTrustRegionRadius;
  92.     /** Goal type (minimize or maximize). */
  93.     private boolean isMinimize;
  94.     /**
  95.      * Current best values for the variables to be optimized.
  96.      * The vector will be changed in-place to contain the values of the least
  97.      * calculated objective function values.
  98.      */
  99.     private ArrayRealVector currentBest;
  100.     /** Differences between the upper and lower bounds. */
  101.     private double[] boundDifference;
  102.     /**
  103.      * Index of the interpolation point at the trust region center.
  104.      */
  105.     private int trustRegionCenterInterpolationPointIndex;
  106.     /**
  107.      * Last <em>n</em> columns of matrix H (where <em>n</em> is the dimension
  108.      * of the problem).
  109.      * XXX "bmat" in the original code.
  110.      */
  111.     private Array2DRowRealMatrix bMatrix;
  112.     /**
  113.      * Factorization of the leading <em>npt</em> square submatrix of H, this
  114.      * factorization being Z Z<sup>T</sup>, which provides both the correct
  115.      * rank and positive semi-definiteness.
  116.      * XXX "zmat" in the original code.
  117.      */
  118.     private Array2DRowRealMatrix zMatrix;
  119.     /**
  120.      * Coordinates of the interpolation points relative to {@link #originShift}.
  121.      * XXX "xpt" in the original code.
  122.      */
  123.     private Array2DRowRealMatrix interpolationPoints;
  124.     /**
  125.      * Shift of origin that should reduce the contributions from rounding
  126.      * errors to values of the model and Lagrange functions.
  127.      * XXX "xbase" in the original code.
  128.      */
  129.     private ArrayRealVector originShift;
  130.     /**
  131.      * Values of the objective function at the interpolation points.
  132.      * XXX "fval" in the original code.
  133.      */
  134.     private ArrayRealVector fAtInterpolationPoints;
  135.     /**
  136.      * Displacement from {@link #originShift} of the trust region center.
  137.      * XXX "xopt" in the original code.
  138.      */
  139.     private ArrayRealVector trustRegionCenterOffset;
  140.     /**
  141.      * Gradient of the quadratic model at {@link #originShift} +
  142.      * {@link #trustRegionCenterOffset}.
  143.      * XXX "gopt" in the original code.
  144.      */
  145.     private ArrayRealVector gradientAtTrustRegionCenter;
  146.     /**
  147.      * Differences {@link #getLowerBound()} - {@link #originShift}.
  148.      * All the components of every {@link #trustRegionCenterOffset} are going
  149.      * to satisfy the bounds<br>
  150.      * {@link #getLowerBound() lowerBound}<sub>i</sub> &le;
  151.      * {@link #trustRegionCenterOffset}<sub>i</sub>,<br>
  152.      * with appropriate equalities when {@link #trustRegionCenterOffset} is
  153.      * on a constraint boundary.
  154.      * XXX "sl" in the original code.
  155.      */
  156.     private ArrayRealVector lowerDifference;
  157.     /**
  158.      * Differences {@link #getUpperBound()} - {@link #originShift}
  159.      * All the components of every {@link #trustRegionCenterOffset} are going
  160.      * to satisfy the bounds<br>
  161.      *  {@link #trustRegionCenterOffset}<sub>i</sub> &le;
  162.      *  {@link #getUpperBound() upperBound}<sub>i</sub>,<br>
  163.      * with appropriate equalities when {@link #trustRegionCenterOffset} is
  164.      * on a constraint boundary.
  165.      * XXX "su" in the original code.
  166.      */
  167.     private ArrayRealVector upperDifference;
  168.     /**
  169.      * Parameters of the implicit second derivatives of the quadratic model.
  170.      * XXX "pq" in the original code.
  171.      */
  172.     private ArrayRealVector modelSecondDerivativesParameters;
  173.     /**
  174.      * Point chosen by function {@link #trsbox(double,ArrayRealVector,
  175.      * ArrayRealVector, ArrayRealVector,ArrayRealVector,ArrayRealVector) trsbox}
  176.      * or {@link #altmov(int,double) altmov}.
  177.      * Usually {@link #originShift} + {@link #newPoint} is the vector of
  178.      * variables for the next evaluation of the objective function.
  179.      * It also satisfies the constraints indicated in {@link #lowerDifference}
  180.      * and {@link #upperDifference}.
  181.      * XXX "xnew" in the original code.
  182.      */
  183.     private ArrayRealVector newPoint;
  184.     /**
  185.      * Alternative to {@link #newPoint}, chosen by
  186.      * {@link #altmov(int,double) altmov}.
  187.      * It may replace {@link #newPoint} in order to increase the denominator
  188.      * in the {@link #update(double, double, int) updating procedure}.
  189.      * XXX "xalt" in the original code.
  190.      */
  191.     private ArrayRealVector alternativeNewPoint;
  192.     /**
  193.      * Trial step from {@link #trustRegionCenterOffset} which is usually
  194.      * {@link #newPoint} - {@link #trustRegionCenterOffset}.
  195.      * XXX "d__" in the original code.
  196.      */
  197.     private ArrayRealVector trialStepPoint;
  198.     /**
  199.      * Values of the Lagrange functions at a new point.
  200.      * XXX "vlag" in the original code.
  201.      */
  202.     private ArrayRealVector lagrangeValuesAtNewPoint;
  203.     /**
  204.      * Explicit second derivatives of the quadratic model.
  205.      * XXX "hq" in the original code.
  206.      */
  207.     private ArrayRealVector modelSecondDerivativesValues;

  208.     /**
  209.      * @param numberOfInterpolationPoints Number of interpolation conditions.
  210.      * For a problem of dimension {@code n}, its value must be in the interval
  211.      * {@code [n+2, (n+1)(n+2)/2]}.
  212.      * Choices that exceed {@code 2n+1} are not recommended.
  213.      */
  214.     public BOBYQAOptimizer(int numberOfInterpolationPoints) {
  215.         this(numberOfInterpolationPoints,
  216.              DEFAULT_INITIAL_RADIUS,
  217.              DEFAULT_STOPPING_RADIUS);
  218.     }

  219.     /**
  220.      * @param numberOfInterpolationPoints Number of interpolation conditions.
  221.      * For a problem of dimension {@code n}, its value must be in the interval
  222.      * {@code [n+2, (n+1)(n+2)/2]}.
  223.      * Choices that exceed {@code 2n+1} are not recommended.
  224.      * @param initialTrustRegionRadius Initial trust region radius.
  225.      * @param stoppingTrustRegionRadius Stopping trust region radius.
  226.      */
  227.     public BOBYQAOptimizer(int numberOfInterpolationPoints,
  228.                            double initialTrustRegionRadius,
  229.                            double stoppingTrustRegionRadius) {
  230.         super(null); // No custom convergence criterion.
  231.         this.numberOfInterpolationPoints = numberOfInterpolationPoints;
  232.         this.initialTrustRegionRadius = initialTrustRegionRadius;
  233.         this.stoppingTrustRegionRadius = stoppingTrustRegionRadius;
  234.     }

  235.     /** {@inheritDoc} */
  236.     @Override
  237.     protected PointValuePair doOptimize() {
  238.         final double[] lowerBound = getLowerBound();
  239.         final double[] upperBound = getUpperBound();

  240.         // Validity checks.
  241.         setup(lowerBound, upperBound);

  242.         isMinimize = (getGoalType() == GoalType.MINIMIZE);
  243.         currentBest = new ArrayRealVector(getStartPoint());

  244.         final double value = bobyqa(lowerBound, upperBound);

  245.         return new PointValuePair(currentBest.getDataRef(),
  246.                                   isMinimize ? value : -value);
  247.     }

  248.     /**
  249.      *     This subroutine seeks the least value of a function of many variables,
  250.      *     by applying a trust region method that forms quadratic models by
  251.      *     interpolation. There is usually some freedom in the interpolation
  252.      *     conditions, which is taken up by minimizing the Frobenius norm of
  253.      *     the change to the second derivative of the model, beginning with the
  254.      *     zero matrix. The values of the variables are constrained by upper and
  255.      *     lower bounds. The arguments of the subroutine are as follows.
  256.      *
  257.      *     N must be set to the number of variables and must be at least two.
  258.      *     NPT is the number of interpolation conditions. Its value must be in
  259.      *       the interval [N+2,(N+1)(N+2)/2]. Choices that exceed 2*N+1 are not
  260.      *       recommended.
  261.      *     Initial values of the variables must be set in X(1),X(2),...,X(N). They
  262.      *       will be changed to the values that give the least calculated F.
  263.      *     For I=1,2,...,N, XL(I) and XU(I) must provide the lower and upper
  264.      *       bounds, respectively, on X(I). The construction of quadratic models
  265.      *       requires XL(I) to be strictly less than XU(I) for each I. Further,
  266.      *       the contribution to a model from changes to the I-th variable is
  267.      *       damaged severely by rounding errors if XU(I)-XL(I) is too small.
  268.      *     RHOBEG and RHOEND must be set to the initial and final values of a trust
  269.      *       region radius, so both must be positive with RHOEND no greater than
  270.      *       RHOBEG. Typically, RHOBEG should be about one tenth of the greatest
  271.      *       expected change to a variable, while RHOEND should indicate the
  272.      *       accuracy that is required in the final values of the variables. An
  273.      *       error return occurs if any of the differences XU(I)-XL(I), I=1,...,N,
  274.      *       is less than 2*RHOBEG.
  275.      *     MAXFUN must be set to an upper bound on the number of calls of CALFUN.
  276.      *     The array W will be used for working space. Its length must be at least
  277.      *       (NPT+5)*(NPT+N)+3*N*(N+5)/2.
  278.      *
  279.      * @param lowerBound Lower bounds.
  280.      * @param upperBound Upper bounds.
  281.      * @return the value of the objective at the optimum.
  282.      */
  283.     private double bobyqa(double[] lowerBound,
  284.                           double[] upperBound) {
  285.         printMethod(); // XXX

  286.         final int n = currentBest.getDimension();

  287.         // Return if there is insufficient space between the bounds. Modify the
  288.         // initial X if necessary in order to avoid conflicts between the bounds
  289.         // and the construction of the first quadratic model. The lower and upper
  290.         // bounds on moves from the updated X are set now, in the ISL and ISU
  291.         // partitions of W, in order to provide useful and exact information about
  292.         // components of X that become within distance RHOBEG from their bounds.

  293.         for (int j = 0; j < n; j++) {
  294.             final double boundDiff = boundDifference[j];
  295.             lowerDifference.setEntry(j, lowerBound[j] - currentBest.getEntry(j));
  296.             upperDifference.setEntry(j, upperBound[j] - currentBest.getEntry(j));
  297.             if (lowerDifference.getEntry(j) >= -initialTrustRegionRadius) {
  298.                 if (lowerDifference.getEntry(j) >= ZERO) {
  299.                     currentBest.setEntry(j, lowerBound[j]);
  300.                     lowerDifference.setEntry(j, ZERO);
  301.                     upperDifference.setEntry(j, boundDiff);
  302.                 } else {
  303.                     currentBest.setEntry(j, lowerBound[j] + initialTrustRegionRadius);
  304.                     lowerDifference.setEntry(j, -initialTrustRegionRadius);
  305.                     // Computing MAX
  306.                     final double deltaOne = upperBound[j] - currentBest.getEntry(j);
  307.                     upperDifference.setEntry(j, JdkMath.max(deltaOne, initialTrustRegionRadius));
  308.                 }
  309.             } else if (upperDifference.getEntry(j) <= initialTrustRegionRadius) {
  310.                 if (upperDifference.getEntry(j) <= ZERO) {
  311.                     currentBest.setEntry(j, upperBound[j]);
  312.                     lowerDifference.setEntry(j, -boundDiff);
  313.                     upperDifference.setEntry(j, ZERO);
  314.                 } else {
  315.                     currentBest.setEntry(j, upperBound[j] - initialTrustRegionRadius);
  316.                     // Computing MIN
  317.                     final double deltaOne = lowerBound[j] - currentBest.getEntry(j);
  318.                     final double deltaTwo = -initialTrustRegionRadius;
  319.                     lowerDifference.setEntry(j, JdkMath.min(deltaOne, deltaTwo));
  320.                     upperDifference.setEntry(j, initialTrustRegionRadius);
  321.                 }
  322.             }
  323.         }

  324.         // Make the call of BOBYQB.

  325.         return bobyqb(lowerBound, upperBound);
  326.     } // bobyqa

  327.     // ----------------------------------------------------------------------------------------

  328.     /**
  329.      *     The arguments N, NPT, X, XL, XU, RHOBEG, RHOEND, IPRINT and MAXFUN
  330.      *       are identical to the corresponding arguments in SUBROUTINE BOBYQA.
  331.      *     XBASE holds a shift of origin that should reduce the contributions
  332.      *       from rounding errors to values of the model and Lagrange functions.
  333.      *     XPT is a two-dimensional array that holds the coordinates of the
  334.      *       interpolation points relative to XBASE.
  335.      *     FVAL holds the values of F at the interpolation points.
  336.      *     XOPT is set to the displacement from XBASE of the trust region centre.
  337.      *     GOPT holds the gradient of the quadratic model at XBASE+XOPT.
  338.      *     HQ holds the explicit second derivatives of the quadratic model.
  339.      *     PQ contains the parameters of the implicit second derivatives of the
  340.      *       quadratic model.
  341.      *     BMAT holds the last N columns of H.
  342.      *     ZMAT holds the factorization of the leading NPT by NPT submatrix of H,
  343.      *       this factorization being ZMAT times ZMAT^T, which provides both the
  344.      *       correct rank and positive semi-definiteness.
  345.      *     NDIM is the first dimension of BMAT and has the value NPT+N.
  346.      *     SL and SU hold the differences XL-XBASE and XU-XBASE, respectively.
  347.      *       All the components of every XOPT are going to satisfy the bounds
  348.      *       SL(I) .LEQ. XOPT(I) .LEQ. SU(I), with appropriate equalities when
  349.      *       XOPT is on a constraint boundary.
  350.      *     XNEW is chosen by SUBROUTINE TRSBOX or ALTMOV. Usually XBASE+XNEW is the
  351.      *       vector of variables for the next call of CALFUN. XNEW also satisfies
  352.      *       the SL and SU constraints in the way that has just been mentioned.
  353.      *     XALT is an alternative to XNEW, chosen by ALTMOV, that may replace XNEW
  354.      *       in order to increase the denominator in the updating of UPDATE.
  355.      *     D is reserved for a trial step from XOPT, which is usually XNEW-XOPT.
  356.      *     VLAG contains the values of the Lagrange functions at a new point X.
  357.      *       They are part of a product that requires VLAG to be of length NDIM.
  358.      *     W is a one-dimensional array that is used for working space. Its length
  359.      *       must be at least 3*NDIM = 3*(NPT+N).
  360.      *
  361.      * @param lowerBound Lower bounds.
  362.      * @param upperBound Upper bounds.
  363.      * @return the value of the objective at the optimum.
  364.      */
  365.     private double bobyqb(double[] lowerBound,
  366.                           double[] upperBound) {
  367.         printMethod(); // XXX

  368.         final int n = currentBest.getDimension();
  369.         final int npt = numberOfInterpolationPoints;
  370.         final int np = n + 1;
  371.         final int nptm = npt - np;
  372.         final int nh = n * np / 2;

  373.         final ArrayRealVector work1 = new ArrayRealVector(n);
  374.         final ArrayRealVector work2 = new ArrayRealVector(npt);
  375.         final ArrayRealVector work3 = new ArrayRealVector(npt);

  376.         double cauchy = Double.NaN;
  377.         double alpha = Double.NaN;
  378.         double dsq = Double.NaN;
  379.         double crvmin = Double.NaN;

  380.         // Set some constants.
  381.         // Parameter adjustments

  382.         // Function Body

  383.         // The call of PRELIM sets the elements of XBASE, XPT, FVAL, GOPT, HQ, PQ,
  384.         // BMAT and ZMAT for the first iteration, with the corresponding values of
  385.         // of NF and KOPT, which are the number of calls of CALFUN so far and the
  386.         // index of the interpolation point at the trust region centre. Then the
  387.         // initial XOPT is set too. The branch to label 720 occurs if MAXFUN is
  388.         // less than NPT. GOPT will be updated if KOPT is different from KBASE.

  389.         trustRegionCenterInterpolationPointIndex = 0;

  390.         prelim(lowerBound, upperBound);
  391.         double xoptsq = ZERO;
  392.         for (int i = 0; i < n; i++) {
  393.             trustRegionCenterOffset.setEntry(i, interpolationPoints.getEntry(trustRegionCenterInterpolationPointIndex, i));
  394.             // Computing 2nd power
  395.             final double deltaOne = trustRegionCenterOffset.getEntry(i);
  396.             xoptsq += deltaOne * deltaOne;
  397.         }
  398.         double fsave = fAtInterpolationPoints.getEntry(0);
  399.         final int kbase = 0;

  400.         // Complete the settings that are required for the iterative procedure.

  401.         int ntrits = 0;
  402.         int itest = 0;
  403.         int knew = 0;
  404.         int nfsav = getEvaluations();
  405.         double rho = initialTrustRegionRadius;
  406.         double delta = rho;
  407.         double diffa = ZERO;
  408.         double diffb = ZERO;
  409.         double diffc = ZERO;
  410.         double f = ZERO;
  411.         double beta = ZERO;
  412.         double adelt = ZERO;
  413.         double denom = ZERO;
  414.         double ratio = ZERO;
  415.         double dnorm = ZERO;
  416.         double scaden = ZERO;
  417.         double biglsq = ZERO;
  418.         double distsq = ZERO;

  419.         // Update GOPT if necessary before the first iteration and after each
  420.         // call of RESCUE that makes a call of CALFUN.

  421.         int state = 20;
  422.         for(;;) {
  423.         switch (state) {
  424.         case 20: {
  425.             printState(20); // XXX
  426.             if (trustRegionCenterInterpolationPointIndex != kbase) {
  427.                 int ih = 0;
  428.                 for (int j = 0; j < n; j++) {
  429.                     for (int i = 0; i <= j; i++) {
  430.                         if (i < j) {
  431.                             gradientAtTrustRegionCenter.setEntry(j, gradientAtTrustRegionCenter.getEntry(j) + modelSecondDerivativesValues.getEntry(ih) * trustRegionCenterOffset.getEntry(i));
  432.                         }
  433.                         gradientAtTrustRegionCenter.setEntry(i, gradientAtTrustRegionCenter.getEntry(i) + modelSecondDerivativesValues.getEntry(ih) * trustRegionCenterOffset.getEntry(j));
  434.                         ih++;
  435.                     }
  436.                 }
  437.                 if (getEvaluations() > npt) {
  438.                     for (int k = 0; k < npt; k++) {
  439.                         double temp = ZERO;
  440.                         for (int j = 0; j < n; j++) {
  441.                             temp += interpolationPoints.getEntry(k, j) * trustRegionCenterOffset.getEntry(j);
  442.                         }
  443.                         temp *= modelSecondDerivativesParameters.getEntry(k);
  444.                         for (int i = 0; i < n; i++) {
  445.                             gradientAtTrustRegionCenter.setEntry(i, gradientAtTrustRegionCenter.getEntry(i) + temp * interpolationPoints.getEntry(k, i));
  446.                         }
  447.                     }
  448.                     // throw new PathIsExploredException(); // XXX
  449.                 }
  450.             }

  451.             // Generate the next point in the trust region that provides a small value
  452.             // of the quadratic model subject to the constraints on the variables.
  453.             // The int NTRITS is set to the number "trust region" iterations that
  454.             // have occurred since the last "alternative" iteration. If the length
  455.             // of XNEW-XOPT is less than HALF*RHO, however, then there is a branch to
  456.             // label 650 or 680 with NTRITS=-1, instead of calculating F at XNEW.
  457.         }
  458.         case 60: {
  459.             printState(60); // XXX
  460.             final ArrayRealVector gnew = new ArrayRealVector(n);
  461.             final ArrayRealVector xbdi = new ArrayRealVector(n);
  462.             final ArrayRealVector s = new ArrayRealVector(n);
  463.             final ArrayRealVector hs = new ArrayRealVector(n);
  464.             final ArrayRealVector hred = new ArrayRealVector(n);

  465.             final double[] dsqCrvmin = trsbox(delta, gnew, xbdi, s,
  466.                                               hs, hred);
  467.             dsq = dsqCrvmin[0];
  468.             crvmin = dsqCrvmin[1];

  469.             // Computing MIN
  470.             double deltaOne = delta;
  471.             double deltaTwo = JdkMath.sqrt(dsq);
  472.             dnorm = JdkMath.min(deltaOne, deltaTwo);
  473.             if (dnorm < HALF * rho) {
  474.                 ntrits = -1;
  475.                 // Computing 2nd power
  476.                 deltaOne = TEN * rho;
  477.                 distsq = deltaOne * deltaOne;
  478.                 if (getEvaluations() <= nfsav + 2) {
  479.                     state = 650; break;
  480.                 }

  481.                 // The following choice between labels 650 and 680 depends on whether or
  482.                 // not our work with the current RHO seems to be complete. Either RHO is
  483.                 // decreased or termination occurs if the errors in the quadratic model at
  484.                 // the last three interpolation points compare favourably with predictions
  485.                 // of likely improvements to the model within distance HALF*RHO of XOPT.

  486.                 // Computing MAX
  487.                 deltaOne = JdkMath.max(diffa, diffb);
  488.                 final double errbig = JdkMath.max(deltaOne, diffc);
  489.                 final double frhosq = rho * ONE_OVER_EIGHT * rho;
  490.                 if (crvmin > ZERO &&
  491.                     errbig > frhosq * crvmin) {
  492.                     state = 650; break;
  493.                 }
  494.                 final double bdtol = errbig / rho;
  495.                 for (int j = 0; j < n; j++) {
  496.                     double bdtest = bdtol;
  497.                     if (newPoint.getEntry(j) == lowerDifference.getEntry(j)) {
  498.                         bdtest = work1.getEntry(j);
  499.                     }
  500.                     if (newPoint.getEntry(j) == upperDifference.getEntry(j)) {
  501.                         bdtest = -work1.getEntry(j);
  502.                     }
  503.                     if (bdtest < bdtol) {
  504.                         double curv = modelSecondDerivativesValues.getEntry((j + j * j) / 2);
  505.                         for (int k = 0; k < npt; k++) {
  506.                             // Computing 2nd power
  507.                             final double d1 = interpolationPoints.getEntry(k, j);
  508.                             curv += modelSecondDerivativesParameters.getEntry(k) * (d1 * d1);
  509.                         }
  510.                         bdtest += HALF * curv * rho;
  511.                         if (bdtest < bdtol) {
  512.                             state = 650; break;
  513.                         }
  514.                         // throw new PathIsExploredException(); // XXX
  515.                     }
  516.                 }
  517.                 state = 680; break;
  518.             }
  519.             ++ntrits;

  520.             // Severe cancellation is likely to occur if XOPT is too far from XBASE.
  521.             // If the following test holds, then XBASE is shifted so that XOPT becomes
  522.             // zero. The appropriate changes are made to BMAT and to the second
  523.             // derivatives of the current model, beginning with the changes to BMAT
  524.             // that do not depend on ZMAT. VLAG is used temporarily for working space.
  525.         }
  526.         case 90: {
  527.             printState(90); // XXX
  528.             if (dsq <= xoptsq * ONE_OVER_A_THOUSAND) {
  529.                 final double fracsq = xoptsq * ONE_OVER_FOUR;
  530.                 double sumpq = ZERO;
  531.                 // final RealVector sumVector
  532.                 //     = new ArrayRealVector(npt, -HALF * xoptsq).add(interpolationPoints.operate(trustRegionCenter));
  533.                 for (int k = 0; k < npt; k++) {
  534.                     sumpq += modelSecondDerivativesParameters.getEntry(k);
  535.                     double sum = -HALF * xoptsq;
  536.                     for (int i = 0; i < n; i++) {
  537.                         sum += interpolationPoints.getEntry(k, i) * trustRegionCenterOffset.getEntry(i);
  538.                     }
  539.                     // sum = sumVector.getEntry(k); // XXX "testAckley" and "testDiffPow" fail.
  540.                     work2.setEntry(k, sum);
  541.                     final double temp = fracsq - HALF * sum;
  542.                     for (int i = 0; i < n; i++) {
  543.                         work1.setEntry(i, bMatrix.getEntry(k, i));
  544.                         lagrangeValuesAtNewPoint.setEntry(i, sum * interpolationPoints.getEntry(k, i) + temp * trustRegionCenterOffset.getEntry(i));
  545.                         final int ip = npt + i;
  546.                         for (int j = 0; j <= i; j++) {
  547.                             bMatrix.setEntry(ip, j,
  548.                                           bMatrix.getEntry(ip, j)
  549.                                           + work1.getEntry(i) * lagrangeValuesAtNewPoint.getEntry(j)
  550.                                           + lagrangeValuesAtNewPoint.getEntry(i) * work1.getEntry(j));
  551.                         }
  552.                     }
  553.                 }

  554.                 // Then the revisions of BMAT that depend on ZMAT are calculated.

  555.                 for (int m = 0; m < nptm; m++) {
  556.                     double sumz = ZERO;
  557.                     double sumw = ZERO;
  558.                     for (int k = 0; k < npt; k++) {
  559.                         sumz += zMatrix.getEntry(k, m);
  560.                         lagrangeValuesAtNewPoint.setEntry(k, work2.getEntry(k) * zMatrix.getEntry(k, m));
  561.                         sumw += lagrangeValuesAtNewPoint.getEntry(k);
  562.                     }
  563.                     for (int j = 0; j < n; j++) {
  564.                         double sum = (fracsq * sumz - HALF * sumw) * trustRegionCenterOffset.getEntry(j);
  565.                         for (int k = 0; k < npt; k++) {
  566.                             sum += lagrangeValuesAtNewPoint.getEntry(k) * interpolationPoints.getEntry(k, j);
  567.                         }
  568.                         work1.setEntry(j, sum);
  569.                         for (int k = 0; k < npt; k++) {
  570.                             bMatrix.setEntry(k, j,
  571.                                           bMatrix.getEntry(k, j)
  572.                                           + sum * zMatrix.getEntry(k, m));
  573.                         }
  574.                     }
  575.                     for (int i = 0; i < n; i++) {
  576.                         final int ip = i + npt;
  577.                         final double temp = work1.getEntry(i);
  578.                         for (int j = 0; j <= i; j++) {
  579.                             bMatrix.setEntry(ip, j,
  580.                                           bMatrix.getEntry(ip, j)
  581.                                           + temp * work1.getEntry(j));
  582.                         }
  583.                     }
  584.                 }

  585.                 // The following instructions complete the shift, including the changes
  586.                 // to the second derivative parameters of the quadratic model.

  587.                 int ih = 0;
  588.                 for (int j = 0; j < n; j++) {
  589.                     work1.setEntry(j, -HALF * sumpq * trustRegionCenterOffset.getEntry(j));
  590.                     for (int k = 0; k < npt; k++) {
  591.                         work1.setEntry(j, work1.getEntry(j) + modelSecondDerivativesParameters.getEntry(k) * interpolationPoints.getEntry(k, j));
  592.                         interpolationPoints.setEntry(k, j, interpolationPoints.getEntry(k, j) - trustRegionCenterOffset.getEntry(j));
  593.                     }
  594.                     for (int i = 0; i <= j; i++) {
  595.                          modelSecondDerivativesValues.setEntry(ih,
  596.                                     modelSecondDerivativesValues.getEntry(ih)
  597.                                     + work1.getEntry(i) * trustRegionCenterOffset.getEntry(j)
  598.                                     + trustRegionCenterOffset.getEntry(i) * work1.getEntry(j));
  599.                         bMatrix.setEntry(npt + i, j, bMatrix.getEntry(npt + j, i));
  600.                         ih++;
  601.                     }
  602.                 }
  603.                 for (int i = 0; i < n; i++) {
  604.                     originShift.setEntry(i, originShift.getEntry(i) + trustRegionCenterOffset.getEntry(i));
  605.                     newPoint.setEntry(i, newPoint.getEntry(i) - trustRegionCenterOffset.getEntry(i));
  606.                     lowerDifference.setEntry(i, lowerDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i));
  607.                     upperDifference.setEntry(i, upperDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i));
  608.                     trustRegionCenterOffset.setEntry(i, ZERO);
  609.                 }
  610.                 xoptsq = ZERO;
  611.             }
  612.             if (ntrits == 0) {
  613.                 state = 210; break;
  614.             }
  615.             state = 230; break;

  616.             // XBASE is also moved to XOPT by a call of RESCUE. This calculation is
  617.             // more expensive than the previous shift, because new matrices BMAT and
  618.             // ZMAT are generated from scratch, which may include the replacement of
  619.             // interpolation points whose positions seem to be causing near linear
  620.             // dependence in the interpolation conditions. Therefore RESCUE is called
  621.             // only if rounding errors have reduced by at least a factor of two the
  622.             // denominator of the formula for updating the H matrix. It provides a
  623.             // useful safeguard, but is not invoked in most applications of BOBYQA.
  624.         }
  625.         case 210: {
  626.             printState(210); // XXX
  627.             // Pick two alternative vectors of variables, relative to XBASE, that
  628.             // are suitable as new positions of the KNEW-th interpolation point.
  629.             // Firstly, XNEW is set to the point on a line through XOPT and another
  630.             // interpolation point that minimizes the predicted value of the next
  631.             // denominator, subject to ||XNEW - XOPT|| .LEQ. ADELT and to the SL
  632.             // and SU bounds. Secondly, XALT is set to the best feasible point on
  633.             // a constrained version of the Cauchy step of the KNEW-th Lagrange
  634.             // function, the corresponding value of the square of this function
  635.             // being returned in CAUCHY. The choice between these alternatives is
  636.             // going to be made when the denominator is calculated.

  637.             final double[] alphaCauchy = altmov(knew, adelt);
  638.             alpha = alphaCauchy[0];
  639.             cauchy = alphaCauchy[1];

  640.             for (int i = 0; i < n; i++) {
  641.                 trialStepPoint.setEntry(i, newPoint.getEntry(i) - trustRegionCenterOffset.getEntry(i));
  642.             }

  643.             // Calculate VLAG and BETA for the current choice of D. The scalar
  644.             // product of D with XPT(K,.) is going to be held in W(NPT+K) for
  645.             // use when VQUAD is calculated.
  646.         }
  647.         case 230: {
  648.             printState(230); // XXX
  649.             for (int k = 0; k < npt; k++) {
  650.                 double suma = ZERO;
  651.                 double sumb = ZERO;
  652.                 double sum = ZERO;
  653.                 for (int j = 0; j < n; j++) {
  654.                     suma += interpolationPoints.getEntry(k, j) * trialStepPoint.getEntry(j);
  655.                     sumb += interpolationPoints.getEntry(k, j) * trustRegionCenterOffset.getEntry(j);
  656.                     sum += bMatrix.getEntry(k, j) * trialStepPoint.getEntry(j);
  657.                 }
  658.                 work3.setEntry(k, suma * (HALF * suma + sumb));
  659.                 lagrangeValuesAtNewPoint.setEntry(k, sum);
  660.                 work2.setEntry(k, suma);
  661.             }
  662.             beta = ZERO;
  663.             for (int m = 0; m < nptm; m++) {
  664.                 double sum = ZERO;
  665.                 for (int k = 0; k < npt; k++) {
  666.                     sum += zMatrix.getEntry(k, m) * work3.getEntry(k);
  667.                 }
  668.                 beta -= sum * sum;
  669.                 for (int k = 0; k < npt; k++) {
  670.                     lagrangeValuesAtNewPoint.setEntry(k, lagrangeValuesAtNewPoint.getEntry(k) + sum * zMatrix.getEntry(k, m));
  671.                 }
  672.             }
  673.             dsq = ZERO;
  674.             double bsum = ZERO;
  675.             double dx = ZERO;
  676.             for (int j = 0; j < n; j++) {
  677.                 // Computing 2nd power
  678.                 final double d1 = trialStepPoint.getEntry(j);
  679.                 dsq += d1 * d1;
  680.                 double sum = ZERO;
  681.                 for (int k = 0; k < npt; k++) {
  682.                     sum += work3.getEntry(k) * bMatrix.getEntry(k, j);
  683.                 }
  684.                 bsum += sum * trialStepPoint.getEntry(j);
  685.                 final int jp = npt + j;
  686.                 for (int i = 0; i < n; i++) {
  687.                     sum += bMatrix.getEntry(jp, i) * trialStepPoint.getEntry(i);
  688.                 }
  689.                 lagrangeValuesAtNewPoint.setEntry(jp, sum);
  690.                 bsum += sum * trialStepPoint.getEntry(j);
  691.                 dx += trialStepPoint.getEntry(j) * trustRegionCenterOffset.getEntry(j);
  692.             }

  693.             beta = dx * dx + dsq * (xoptsq + dx + dx + HALF * dsq) + beta - bsum; // Original
  694.             // beta += dx * dx + dsq * (xoptsq + dx + dx + HALF * dsq) - bsum; // XXX "testAckley" and "testDiffPow" fail.
  695.             // beta = dx * dx + dsq * (xoptsq + 2 * dx + HALF * dsq) + beta - bsum; // XXX "testDiffPow" fails.

  696.             lagrangeValuesAtNewPoint.setEntry(trustRegionCenterInterpolationPointIndex,
  697.                           lagrangeValuesAtNewPoint.getEntry(trustRegionCenterInterpolationPointIndex) + ONE);

  698.             // If NTRITS is zero, the denominator may be increased by replacing
  699.             // the step D of ALTMOV by a Cauchy step. Then RESCUE may be called if
  700.             // rounding errors have damaged the chosen denominator.

  701.             if (ntrits == 0) {
  702.                 // Computing 2nd power
  703.                 final double d1 = lagrangeValuesAtNewPoint.getEntry(knew);
  704.                 denom = d1 * d1 + alpha * beta;
  705.                 if (denom < cauchy && cauchy > ZERO) {
  706.                     for (int i = 0; i < n; i++) {
  707.                         newPoint.setEntry(i, alternativeNewPoint.getEntry(i));
  708.                         trialStepPoint.setEntry(i, newPoint.getEntry(i) - trustRegionCenterOffset.getEntry(i));
  709.                     }
  710.                     cauchy = ZERO; // XXX Useful statement?
  711.                     state = 230; break;
  712.                 }
  713.                 // Alternatively, if NTRITS is positive, then set KNEW to the index of
  714.                 // the next interpolation point to be deleted to make room for a trust
  715.                 // region step. Again RESCUE may be called if rounding errors have damaged_
  716.                 // the chosen denominator, which is the reason for attempting to select
  717.                 // KNEW before calculating the next value of the objective function.
  718.             } else {
  719.                 final double delsq = delta * delta;
  720.                 scaden = ZERO;
  721.                 biglsq = ZERO;
  722.                 knew = 0;
  723.                 for (int k = 0; k < npt; k++) {
  724.                     if (k == trustRegionCenterInterpolationPointIndex) {
  725.                         continue;
  726.                     }
  727.                     double hdiag = ZERO;
  728.                     for (int m = 0; m < nptm; m++) {
  729.                         // Computing 2nd power
  730.                         final double d1 = zMatrix.getEntry(k, m);
  731.                         hdiag += d1 * d1;
  732.                     }
  733.                     // Computing 2nd power
  734.                     final double d2 = lagrangeValuesAtNewPoint.getEntry(k);
  735.                     final double den = beta * hdiag + d2 * d2;
  736.                     distsq = ZERO;
  737.                     for (int j = 0; j < n; j++) {
  738.                         // Computing 2nd power
  739.                         final double d3 = interpolationPoints.getEntry(k, j) - trustRegionCenterOffset.getEntry(j);
  740.                         distsq += d3 * d3;
  741.                     }
  742.                     // Computing MAX
  743.                     // Computing 2nd power
  744.                     final double d4 = distsq / delsq;
  745.                     final double temp = JdkMath.max(ONE, d4 * d4);
  746.                     if (temp * den > scaden) {
  747.                         scaden = temp * den;
  748.                         knew = k;
  749.                         denom = den;
  750.                     }
  751.                     // Computing MAX
  752.                     // Computing 2nd power
  753.                     final double d5 = lagrangeValuesAtNewPoint.getEntry(k);
  754.                     biglsq = JdkMath.max(biglsq, temp * (d5 * d5));
  755.                 }
  756.             }

  757.             // Put the variables for the next calculation of the objective function
  758.             //   in XNEW, with any adjustments for the bounds.

  759.             // Calculate the value of the objective function at XBASE+XNEW, unless
  760.             //   the limit on the number of calculations of F has been reached.
  761.         }
  762.         case 360: {
  763.             printState(360); // XXX
  764.             for (int i = 0; i < n; i++) {
  765.                 // Computing MIN
  766.                 // Computing MAX
  767.                 final double d3 = lowerBound[i];
  768.                 final double d4 = originShift.getEntry(i) + newPoint.getEntry(i);
  769.                 final double d1 = JdkMath.max(d3, d4);
  770.                 final double d2 = upperBound[i];
  771.                 currentBest.setEntry(i, JdkMath.min(d1, d2));
  772.                 if (newPoint.getEntry(i) == lowerDifference.getEntry(i)) {
  773.                     currentBest.setEntry(i, lowerBound[i]);
  774.                 }
  775.                 if (newPoint.getEntry(i) == upperDifference.getEntry(i)) {
  776.                     currentBest.setEntry(i, upperBound[i]);
  777.                 }
  778.             }

  779.             f = getObjectiveFunction().value(currentBest.toArray());

  780.             if (!isMinimize) {
  781.                 f = -f;
  782.             }
  783.             if (ntrits == -1) {
  784.                 fsave = f;
  785.                 state = 720; break;
  786.             }

  787.             // Use the quadratic model to predict the change in F due to the step D,
  788.             //   and set DIFF to the error of this prediction.

  789.             final double fopt = fAtInterpolationPoints.getEntry(trustRegionCenterInterpolationPointIndex);
  790.             double vquad = ZERO;
  791.             int ih = 0;
  792.             for (int j = 0; j < n; j++) {
  793.                 vquad += trialStepPoint.getEntry(j) * gradientAtTrustRegionCenter.getEntry(j);
  794.                 for (int i = 0; i <= j; i++) {
  795.                     double temp = trialStepPoint.getEntry(i) * trialStepPoint.getEntry(j);
  796.                     if (i == j) {
  797.                         temp *= HALF;
  798.                     }
  799.                     vquad += modelSecondDerivativesValues.getEntry(ih) * temp;
  800.                     ih++;
  801.                }
  802.             }
  803.             for (int k = 0; k < npt; k++) {
  804.                 // Computing 2nd power
  805.                 final double d1 = work2.getEntry(k);
  806.                 final double d2 = d1 * d1; // "d1" must be squared first to prevent test failures.
  807.                 vquad += HALF * modelSecondDerivativesParameters.getEntry(k) * d2;
  808.             }
  809.             final double diff = f - fopt - vquad;
  810.             diffc = diffb;
  811.             diffb = diffa;
  812.             diffa = JdkMath.abs(diff);
  813.             if (dnorm > rho) {
  814.                 nfsav = getEvaluations();
  815.             }

  816.             // Pick the next value of DELTA after a trust region step.

  817.             if (ntrits > 0) {
  818.                 if (vquad >= ZERO) {
  819.                     throw new MathIllegalStateException(LocalizedFormats.TRUST_REGION_STEP_FAILED, vquad);
  820.                 }
  821.                 ratio = (f - fopt) / vquad;
  822.                 final double hDelta = HALF * delta;
  823.                 if (ratio <= ONE_OVER_TEN) {
  824.                     // Computing MIN
  825.                     delta = JdkMath.min(hDelta, dnorm);
  826.                 } else if (ratio <= .7) {
  827.                     // Computing MAX
  828.                     delta = JdkMath.max(hDelta, dnorm);
  829.                 } else {
  830.                     // Computing MAX
  831.                     delta = JdkMath.max(hDelta, 2 * dnorm);
  832.                 }
  833.                 if (delta <= rho * 1.5) {
  834.                     delta = rho;
  835.                 }

  836.                 // Recalculate KNEW and DENOM if the new F is less than FOPT.

  837.                 if (f < fopt) {
  838.                     final int ksav = knew;
  839.                     final double densav = denom;
  840.                     final double delsq = delta * delta;
  841.                     scaden = ZERO;
  842.                     biglsq = ZERO;
  843.                     knew = 0;
  844.                     for (int k = 0; k < npt; k++) {
  845.                         double hdiag = ZERO;
  846.                         for (int m = 0; m < nptm; m++) {
  847.                             // Computing 2nd power
  848.                             final double d1 = zMatrix.getEntry(k, m);
  849.                             hdiag += d1 * d1;
  850.                         }
  851.                         // Computing 2nd power
  852.                         final double d1 = lagrangeValuesAtNewPoint.getEntry(k);
  853.                         final double den = beta * hdiag + d1 * d1;
  854.                         distsq = ZERO;
  855.                         for (int j = 0; j < n; j++) {
  856.                             // Computing 2nd power
  857.                             final double d2 = interpolationPoints.getEntry(k, j) - newPoint.getEntry(j);
  858.                             distsq += d2 * d2;
  859.                         }
  860.                         // Computing MAX
  861.                         // Computing 2nd power
  862.                         final double d3 = distsq / delsq;
  863.                         final double temp = JdkMath.max(ONE, d3 * d3);
  864.                         if (temp * den > scaden) {
  865.                             scaden = temp * den;
  866.                             knew = k;
  867.                             denom = den;
  868.                         }
  869.                         // Computing MAX
  870.                         // Computing 2nd power
  871.                         final double d4 = lagrangeValuesAtNewPoint.getEntry(k);
  872.                         final double d5 = temp * (d4 * d4);
  873.                         biglsq = JdkMath.max(biglsq, d5);
  874.                     }
  875.                     if (scaden <= HALF * biglsq) {
  876.                         knew = ksav;
  877.                         denom = densav;
  878.                     }
  879.                 }
  880.             }

  881.             // Update BMAT and ZMAT, so that the KNEW-th interpolation point can be
  882.             // moved. Also update the second derivative terms of the model.

  883.             update(beta, denom, knew);

  884.             ih = 0;
  885.             final double pqold = modelSecondDerivativesParameters.getEntry(knew);
  886.             modelSecondDerivativesParameters.setEntry(knew, ZERO);
  887.             for (int i = 0; i < n; i++) {
  888.                 final double temp = pqold * interpolationPoints.getEntry(knew, i);
  889.                 for (int j = 0; j <= i; j++) {
  890.                     modelSecondDerivativesValues.setEntry(ih, modelSecondDerivativesValues.getEntry(ih) + temp * interpolationPoints.getEntry(knew, j));
  891.                     ih++;
  892.                 }
  893.             }
  894.             for (int m = 0; m < nptm; m++) {
  895.                 final double temp = diff * zMatrix.getEntry(knew, m);
  896.                 for (int k = 0; k < npt; k++) {
  897.                     modelSecondDerivativesParameters.setEntry(k, modelSecondDerivativesParameters.getEntry(k) + temp * zMatrix.getEntry(k, m));
  898.                 }
  899.             }

  900.             // Include the new interpolation point, and make the changes to GOPT at
  901.             // the old XOPT that are caused by the updating of the quadratic model.

  902.             fAtInterpolationPoints.setEntry(knew,  f);
  903.             for (int i = 0; i < n; i++) {
  904.                 interpolationPoints.setEntry(knew, i, newPoint.getEntry(i));
  905.                 work1.setEntry(i, bMatrix.getEntry(knew, i));
  906.             }
  907.             for (int k = 0; k < npt; k++) {
  908.                 double suma = ZERO;
  909.                 for (int m = 0; m < nptm; m++) {
  910.                     suma += zMatrix.getEntry(knew, m) * zMatrix.getEntry(k, m);
  911.                 }
  912.                 double sumb = ZERO;
  913.                 for (int j = 0; j < n; j++) {
  914.                     sumb += interpolationPoints.getEntry(k, j) * trustRegionCenterOffset.getEntry(j);
  915.                 }
  916.                 final double temp = suma * sumb;
  917.                 for (int i = 0; i < n; i++) {
  918.                     work1.setEntry(i, work1.getEntry(i) + temp * interpolationPoints.getEntry(k, i));
  919.                 }
  920.             }
  921.             for (int i = 0; i < n; i++) {
  922.                 gradientAtTrustRegionCenter.setEntry(i, gradientAtTrustRegionCenter.getEntry(i) + diff * work1.getEntry(i));
  923.             }

  924.             // Update XOPT, GOPT and KOPT if the new calculated F is less than FOPT.

  925.             if (f < fopt) {
  926.                 trustRegionCenterInterpolationPointIndex = knew;
  927.                 xoptsq = ZERO;
  928.                 ih = 0;
  929.                 for (int j = 0; j < n; j++) {
  930.                     trustRegionCenterOffset.setEntry(j, newPoint.getEntry(j));
  931.                     // Computing 2nd power
  932.                     final double d1 = trustRegionCenterOffset.getEntry(j);
  933.                     xoptsq += d1 * d1;
  934.                     for (int i = 0; i <= j; i++) {
  935.                         if (i < j) {
  936.                             gradientAtTrustRegionCenter.setEntry(j, gradientAtTrustRegionCenter.getEntry(j) + modelSecondDerivativesValues.getEntry(ih) * trialStepPoint.getEntry(i));
  937.                         }
  938.                         gradientAtTrustRegionCenter.setEntry(i, gradientAtTrustRegionCenter.getEntry(i) + modelSecondDerivativesValues.getEntry(ih) * trialStepPoint.getEntry(j));
  939.                         ih++;
  940.                     }
  941.                 }
  942.                 for (int k = 0; k < npt; k++) {
  943.                     double temp = ZERO;
  944.                     for (int j = 0; j < n; j++) {
  945.                         temp += interpolationPoints.getEntry(k, j) * trialStepPoint.getEntry(j);
  946.                     }
  947.                     temp *= modelSecondDerivativesParameters.getEntry(k);
  948.                     for (int i = 0; i < n; i++) {
  949.                         gradientAtTrustRegionCenter.setEntry(i, gradientAtTrustRegionCenter.getEntry(i) + temp * interpolationPoints.getEntry(k, i));
  950.                     }
  951.                 }
  952.             }

  953.             // Calculate the parameters of the least Frobenius norm interpolant to
  954.             // the current data, the gradient of this interpolant at XOPT being put
  955.             // into VLAG(NPT+I), I=1,2,...,N.

  956.             if (ntrits > 0) {
  957.                 for (int k = 0; k < npt; k++) {
  958.                     lagrangeValuesAtNewPoint.setEntry(k, fAtInterpolationPoints.getEntry(k) - fAtInterpolationPoints.getEntry(trustRegionCenterInterpolationPointIndex));
  959.                     work3.setEntry(k, ZERO);
  960.                 }
  961.                 for (int j = 0; j < nptm; j++) {
  962.                     double sum = ZERO;
  963.                     for (int k = 0; k < npt; k++) {
  964.                         sum += zMatrix.getEntry(k, j) * lagrangeValuesAtNewPoint.getEntry(k);
  965.                     }
  966.                     for (int k = 0; k < npt; k++) {
  967.                         work3.setEntry(k, work3.getEntry(k) + sum * zMatrix.getEntry(k, j));
  968.                     }
  969.                 }
  970.                 for (int k = 0; k < npt; k++) {
  971.                     double sum = ZERO;
  972.                     for (int j = 0; j < n; j++) {
  973.                         sum += interpolationPoints.getEntry(k, j) * trustRegionCenterOffset.getEntry(j);
  974.                     }
  975.                     work2.setEntry(k, work3.getEntry(k));
  976.                     work3.setEntry(k, sum * work3.getEntry(k));
  977.                 }
  978.                 double gqsq = ZERO;
  979.                 double gisq = ZERO;
  980.                 for (int i = 0; i < n; i++) {
  981.                     double sum = ZERO;
  982.                     for (int k = 0; k < npt; k++) {
  983.                         sum += bMatrix.getEntry(k, i) *
  984.                             lagrangeValuesAtNewPoint.getEntry(k) + interpolationPoints.getEntry(k, i) * work3.getEntry(k);
  985.                     }
  986.                     if (trustRegionCenterOffset.getEntry(i) == lowerDifference.getEntry(i)) {
  987.                         // Computing MIN
  988.                         // Computing 2nd power
  989.                         final double d1 = JdkMath.min(ZERO, gradientAtTrustRegionCenter.getEntry(i));
  990.                         gqsq += d1 * d1;
  991.                         // Computing 2nd power
  992.                         final double d2 = JdkMath.min(ZERO, sum);
  993.                         gisq += d2 * d2;
  994.                     } else if (trustRegionCenterOffset.getEntry(i) == upperDifference.getEntry(i)) {
  995.                         // Computing MAX
  996.                         // Computing 2nd power
  997.                         final double d1 = JdkMath.max(ZERO, gradientAtTrustRegionCenter.getEntry(i));
  998.                         gqsq += d1 * d1;
  999.                         // Computing 2nd power
  1000.                         final double d2 = JdkMath.max(ZERO, sum);
  1001.                         gisq += d2 * d2;
  1002.                     } else {
  1003.                         // Computing 2nd power
  1004.                         final double d1 = gradientAtTrustRegionCenter.getEntry(i);
  1005.                         gqsq += d1 * d1;
  1006.                         gisq += sum * sum;
  1007.                     }
  1008.                     lagrangeValuesAtNewPoint.setEntry(npt + i, sum);
  1009.                 }

  1010.                 // Test whether to replace the new quadratic model by the least Frobenius
  1011.                 // norm interpolant, making the replacement if the test is satisfied.

  1012.                 ++itest;
  1013.                 if (gqsq < TEN * gisq) {
  1014.                     itest = 0;
  1015.                 }
  1016.                 if (itest >= 3) {
  1017.                     for (int i = 0, max = JdkMath.max(npt, nh); i < max; i++) {
  1018.                         if (i < n) {
  1019.                             gradientAtTrustRegionCenter.setEntry(i, lagrangeValuesAtNewPoint.getEntry(npt + i));
  1020.                         }
  1021.                         if (i < npt) {
  1022.                             modelSecondDerivativesParameters.setEntry(i, work2.getEntry(i));
  1023.                         }
  1024.                         if (i < nh) {
  1025.                             modelSecondDerivativesValues.setEntry(i, ZERO);
  1026.                         }
  1027.                         itest = 0;
  1028.                     }
  1029.                 }
  1030.             }

  1031.             // If a trust region step has provided a sufficient decrease in F, then
  1032.             // branch for another trust region calculation. The case NTRITS=0 occurs
  1033.             // when the new interpolation point was reached by an alternative step.

  1034.             if (ntrits == 0) {
  1035.                 state = 60; break;
  1036.             }
  1037.             if (f <= fopt + ONE_OVER_TEN * vquad) {
  1038.                 state = 60; break;
  1039.             }

  1040.             // Alternatively, find out if the interpolation points are close enough
  1041.             //   to the best point so far.

  1042.             // Computing MAX
  1043.             // Computing 2nd power
  1044.             final double d1 = TWO * delta;
  1045.             // Computing 2nd power
  1046.             final double d2 = TEN * rho;
  1047.             distsq = JdkMath.max(d1 * d1, d2 * d2);
  1048.         }
  1049.         case 650: {
  1050.             printState(650); // XXX
  1051.             knew = -1;
  1052.             for (int k = 0; k < npt; k++) {
  1053.                 double sum = ZERO;
  1054.                 for (int j = 0; j < n; j++) {
  1055.                     // Computing 2nd power
  1056.                     final double d1 = interpolationPoints.getEntry(k, j) - trustRegionCenterOffset.getEntry(j);
  1057.                     sum += d1 * d1;
  1058.                 }
  1059.                 if (sum > distsq) {
  1060.                     knew = k;
  1061.                     distsq = sum;
  1062.                 }
  1063.             }

  1064.             // If KNEW is positive, then ALTMOV finds alternative new positions for
  1065.             // the KNEW-th interpolation point within distance ADELT of XOPT. It is
  1066.             // reached via label 90. Otherwise, there is a branch to label 60 for
  1067.             // another trust region iteration, unless the calculations with the
  1068.             // current RHO are complete.

  1069.             if (knew >= 0) {
  1070.                 final double dist = JdkMath.sqrt(distsq);
  1071.                 if (ntrits == -1) {
  1072.                     // Computing MIN
  1073.                     delta = JdkMath.min(ONE_OVER_TEN * delta, HALF * dist);
  1074.                     if (delta <= rho * 1.5) {
  1075.                         delta = rho;
  1076.                     }
  1077.                 }
  1078.                 ntrits = 0;
  1079.                 // Computing MAX
  1080.                 // Computing MIN
  1081.                 final double d1 = JdkMath.min(ONE_OVER_TEN * dist, delta);
  1082.                 adelt = JdkMath.max(d1, rho);
  1083.                 dsq = adelt * adelt;
  1084.                 state = 90; break;
  1085.             }
  1086.             if (ntrits == -1) {
  1087.                 state = 680; break;
  1088.             }
  1089.             if (ratio > ZERO) {
  1090.                 state = 60; break;
  1091.             }
  1092.             if (JdkMath.max(delta, dnorm) > rho) {
  1093.                 state = 60; break;
  1094.             }

  1095.             // The calculations with the current value of RHO are complete. Pick the
  1096.             //   next values of RHO and DELTA.
  1097.         }
  1098.         case 680: {
  1099.             printState(680); // XXX
  1100.             if (rho > stoppingTrustRegionRadius) {
  1101.                 delta = HALF * rho;
  1102.                 ratio = rho / stoppingTrustRegionRadius;
  1103.                 if (ratio <= SIXTEEN) {
  1104.                     rho = stoppingTrustRegionRadius;
  1105.                 } else if (ratio <= TWO_HUNDRED_FIFTY) {
  1106.                     rho = JdkMath.sqrt(ratio) * stoppingTrustRegionRadius;
  1107.                 } else {
  1108.                     rho *= ONE_OVER_TEN;
  1109.                 }
  1110.                 delta = JdkMath.max(delta, rho);
  1111.                 ntrits = 0;
  1112.                 nfsav = getEvaluations();
  1113.                 state = 60; break;
  1114.             }

  1115.             // Return from the calculation, after another Newton-Raphson step, if
  1116.             //   it is too short to have been tried before.

  1117.             if (ntrits == -1) {
  1118.                 state = 360; break;
  1119.             }
  1120.         }
  1121.         case 720: {
  1122.             printState(720); // XXX
  1123.             if (fAtInterpolationPoints.getEntry(trustRegionCenterInterpolationPointIndex) <= fsave) {
  1124.                 for (int i = 0; i < n; i++) {
  1125.                     // Computing MIN
  1126.                     // Computing MAX
  1127.                     final double d3 = lowerBound[i];
  1128.                     final double d4 = originShift.getEntry(i) + trustRegionCenterOffset.getEntry(i);
  1129.                     final double d1 = JdkMath.max(d3, d4);
  1130.                     final double d2 = upperBound[i];
  1131.                     currentBest.setEntry(i, JdkMath.min(d1, d2));
  1132.                     if (trustRegionCenterOffset.getEntry(i) == lowerDifference.getEntry(i)) {
  1133.                         currentBest.setEntry(i, lowerBound[i]);
  1134.                     }
  1135.                     if (trustRegionCenterOffset.getEntry(i) == upperDifference.getEntry(i)) {
  1136.                         currentBest.setEntry(i, upperBound[i]);
  1137.                     }
  1138.                 }
  1139.                 f = fAtInterpolationPoints.getEntry(trustRegionCenterInterpolationPointIndex);
  1140.             }
  1141.             return f;
  1142.         }
  1143.         default: {
  1144.             throw new MathIllegalStateException(LocalizedFormats.SIMPLE_MESSAGE, "bobyqb");
  1145.         }}}
  1146.     } // bobyqb

  1147.     // ----------------------------------------------------------------------------------------

  1148.     /**
  1149.      *     The arguments N, NPT, XPT, XOPT, BMAT, ZMAT, NDIM, SL and SU all have
  1150.      *       the same meanings as the corresponding arguments of BOBYQB.
  1151.      *     KOPT is the index of the optimal interpolation point.
  1152.      *     KNEW is the index of the interpolation point that is going to be moved.
  1153.      *     ADELT is the current trust region bound.
  1154.      *     XNEW will be set to a suitable new position for the interpolation point
  1155.      *       XPT(KNEW,.). Specifically, it satisfies the SL, SU and trust region
  1156.      *       bounds and it should provide a large denominator in the next call of
  1157.      *       UPDATE. The step XNEW-XOPT from XOPT is restricted to moves along the
  1158.      *       straight lines through XOPT and another interpolation point.
  1159.      *     XALT also provides a large value of the modulus of the KNEW-th Lagrange
  1160.      *       function subject to the constraints that have been mentioned, its main
  1161.      *       difference from XNEW being that XALT-XOPT is a constrained version of
  1162.      *       the Cauchy step within the trust region. An exception is that XALT is
  1163.      *       not calculated if all components of GLAG (see below) are zero.
  1164.      *     ALPHA will be set to the KNEW-th diagonal element of the H matrix.
  1165.      *     CAUCHY will be set to the square of the KNEW-th Lagrange function at
  1166.      *       the step XALT-XOPT from XOPT for the vector XALT that is returned,
  1167.      *       except that CAUCHY is set to zero if XALT is not calculated.
  1168.      *     GLAG is a working space vector of length N for the gradient of the
  1169.      *       KNEW-th Lagrange function at XOPT.
  1170.      *     HCOL is a working space vector of length NPT for the second derivative
  1171.      *       coefficients of the KNEW-th Lagrange function.
  1172.      *     W is a working space vector of length 2N that is going to hold the
  1173.      *       constrained Cauchy step from XOPT of the Lagrange function, followed
  1174.      *       by the downhill version of XALT when the uphill step is calculated.
  1175.      *
  1176.      *     Set the first NPT components of W to the leading elements of the
  1177.      *     KNEW-th column of the H matrix.
  1178.      * @param knew
  1179.      * @param adelt
  1180.      * @return { alpha, cauchy }
  1181.      */
  1182.     private double[] altmov(
  1183.             int knew,
  1184.             double adelt
  1185.     ) {
  1186.         printMethod(); // XXX

  1187.         final int n = currentBest.getDimension();
  1188.         final int npt = numberOfInterpolationPoints;

  1189.         final ArrayRealVector glag = new ArrayRealVector(n);
  1190.         final ArrayRealVector hcol = new ArrayRealVector(npt);

  1191.         final ArrayRealVector work1 = new ArrayRealVector(n);
  1192.         final ArrayRealVector work2 = new ArrayRealVector(n);

  1193.         for (int k = 0; k < npt; k++) {
  1194.             hcol.setEntry(k, ZERO);
  1195.         }
  1196.         for (int j = 0, max = npt - n - 1; j < max; j++) {
  1197.             final double tmp = zMatrix.getEntry(knew, j);
  1198.             for (int k = 0; k < npt; k++) {
  1199.                 hcol.setEntry(k, hcol.getEntry(k) + tmp * zMatrix.getEntry(k, j));
  1200.             }
  1201.         }
  1202.         final double alpha = hcol.getEntry(knew);
  1203.         final double ha = HALF * alpha;

  1204.         // Calculate the gradient of the KNEW-th Lagrange function at XOPT.

  1205.         for (int i = 0; i < n; i++) {
  1206.             glag.setEntry(i, bMatrix.getEntry(knew, i));
  1207.         }
  1208.         for (int k = 0; k < npt; k++) {
  1209.             double tmp = ZERO;
  1210.             for (int j = 0; j < n; j++) {
  1211.                 tmp += interpolationPoints.getEntry(k, j) * trustRegionCenterOffset.getEntry(j);
  1212.             }
  1213.             tmp *= hcol.getEntry(k);
  1214.             for (int i = 0; i < n; i++) {
  1215.                 glag.setEntry(i, glag.getEntry(i) + tmp * interpolationPoints.getEntry(k, i));
  1216.             }
  1217.         }

  1218.         // Search for a large denominator along the straight lines through XOPT
  1219.         // and another interpolation point. SLBD and SUBD will be lower and upper
  1220.         // bounds on the step along each of these lines in turn. PREDSQ will be
  1221.         // set to the square of the predicted denominator for each line. PRESAV
  1222.         // will be set to the largest admissible value of PREDSQ that occurs.

  1223.         double presav = ZERO;
  1224.         double step = Double.NaN;
  1225.         int ksav = 0;
  1226.         int ibdsav = 0;
  1227.         double stpsav = 0;
  1228.         for (int k = 0; k < npt; k++) {
  1229.             if (k == trustRegionCenterInterpolationPointIndex) {
  1230.                 continue;
  1231.             }
  1232.             double dderiv = ZERO;
  1233.             double distsq = ZERO;
  1234.             for (int i = 0; i < n; i++) {
  1235.                 final double tmp = interpolationPoints.getEntry(k, i) - trustRegionCenterOffset.getEntry(i);
  1236.                 dderiv += glag.getEntry(i) * tmp;
  1237.                 distsq += tmp * tmp;
  1238.             }
  1239.             double subd = adelt / JdkMath.sqrt(distsq);
  1240.             double slbd = -subd;
  1241.             int ilbd = 0;
  1242.             int iubd = 0;
  1243.             final double sumin = JdkMath.min(ONE, subd);

  1244.             // Revise SLBD and SUBD if necessary because of the bounds in SL and SU.

  1245.             for (int i = 0; i < n; i++) {
  1246.                 final double tmp = interpolationPoints.getEntry(k, i) - trustRegionCenterOffset.getEntry(i);
  1247.                 if (tmp > ZERO) {
  1248.                     if (slbd * tmp < lowerDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i)) {
  1249.                         slbd = (lowerDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i)) / tmp;
  1250.                         ilbd = -i - 1;
  1251.                     }
  1252.                     if (subd * tmp > upperDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i)) {
  1253.                         // Computing MAX
  1254.                         subd = JdkMath.max(sumin,
  1255.                                             (upperDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i)) / tmp);
  1256.                         iubd = i + 1;
  1257.                     }
  1258.                 } else if (tmp < ZERO) {
  1259.                     if (slbd * tmp > upperDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i)) {
  1260.                         slbd = (upperDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i)) / tmp;
  1261.                         ilbd = i + 1;
  1262.                     }
  1263.                     if (subd * tmp < lowerDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i)) {
  1264.                         // Computing MAX
  1265.                         subd = JdkMath.max(sumin,
  1266.                                             (lowerDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i)) / tmp);
  1267.                         iubd = -i - 1;
  1268.                     }
  1269.                 }
  1270.             }

  1271.             // Seek a large modulus of the KNEW-th Lagrange function when the index
  1272.             // of the other interpolation point on the line through XOPT is KNEW.

  1273.             step = slbd;
  1274.             int isbd = ilbd;
  1275.             double vlag = Double.NaN;
  1276.             if (k == knew) {
  1277.                 final double diff = dderiv - ONE;
  1278.                 vlag = slbd * (dderiv - slbd * diff);
  1279.                 final double d1 = subd * (dderiv - subd * diff);
  1280.                 if (JdkMath.abs(d1) > JdkMath.abs(vlag)) {
  1281.                     step = subd;
  1282.                     vlag = d1;
  1283.                     isbd = iubd;
  1284.                 }
  1285.                 final double d2 = HALF * dderiv;
  1286.                 final double d3 = d2 - diff * slbd;
  1287.                 final double d4 = d2 - diff * subd;
  1288.                 if (d3 * d4 < ZERO) {
  1289.                     final double d5 = d2 * d2 / diff;
  1290.                     if (JdkMath.abs(d5) > JdkMath.abs(vlag)) {
  1291.                         step = d2 / diff;
  1292.                         vlag = d5;
  1293.                         isbd = 0;
  1294.                     }
  1295.                 }

  1296.                 // Search along each of the other lines through XOPT and another point.
  1297.             } else {
  1298.                 vlag = slbd * (ONE - slbd);
  1299.                 final double tmp = subd * (ONE - subd);
  1300.                 if (JdkMath.abs(tmp) > JdkMath.abs(vlag)) {
  1301.                     step = subd;
  1302.                     vlag = tmp;
  1303.                     isbd = iubd;
  1304.                 }
  1305.                 if (subd > HALF && JdkMath.abs(vlag) < ONE_OVER_FOUR) {
  1306.                     step = HALF;
  1307.                     vlag = ONE_OVER_FOUR;
  1308.                     isbd = 0;
  1309.                 }
  1310.                 vlag *= dderiv;
  1311.             }

  1312.             // Calculate PREDSQ for the current line search and maintain PRESAV.

  1313.             final double tmp = step * (ONE - step) * distsq;
  1314.             final double predsq = vlag * vlag * (vlag * vlag + ha * tmp * tmp);
  1315.             if (predsq > presav) {
  1316.                 presav = predsq;
  1317.                 ksav = k;
  1318.                 stpsav = step;
  1319.                 ibdsav = isbd;
  1320.             }
  1321.         }

  1322.         // Construct XNEW in a way that satisfies the bound constraints exactly.

  1323.         for (int i = 0; i < n; i++) {
  1324.             final double tmp = trustRegionCenterOffset.getEntry(i) + stpsav * (interpolationPoints.getEntry(ksav, i) - trustRegionCenterOffset.getEntry(i));
  1325.             newPoint.setEntry(i, JdkMath.max(lowerDifference.getEntry(i),
  1326.                                               JdkMath.min(upperDifference.getEntry(i), tmp)));
  1327.         }
  1328.         if (ibdsav < 0) {
  1329.             newPoint.setEntry(-ibdsav - 1, lowerDifference.getEntry(-ibdsav - 1));
  1330.         }
  1331.         if (ibdsav > 0) {
  1332.             newPoint.setEntry(ibdsav - 1, upperDifference.getEntry(ibdsav - 1));
  1333.         }

  1334.         // Prepare for the iterative method that assembles the constrained Cauchy
  1335.         // step in W. The sum of squares of the fixed components of W is formed in
  1336.         // WFIXSQ, and the free components of W are set to BIGSTP.

  1337.         final double bigstp = adelt + adelt;
  1338.         int iflag = 0;
  1339.         double cauchy = Double.NaN;
  1340.         double csave = ZERO;
  1341.         while (true) {
  1342.             double wfixsq = ZERO;
  1343.             double ggfree = ZERO;
  1344.             for (int i = 0; i < n; i++) {
  1345.                 final double glagValue = glag.getEntry(i);
  1346.                 work1.setEntry(i, ZERO);
  1347.                 if (JdkMath.min(trustRegionCenterOffset.getEntry(i) - lowerDifference.getEntry(i), glagValue) > ZERO ||
  1348.                     JdkMath.max(trustRegionCenterOffset.getEntry(i) - upperDifference.getEntry(i), glagValue) < ZERO) {
  1349.                     work1.setEntry(i, bigstp);
  1350.                     // Computing 2nd power
  1351.                     ggfree += glagValue * glagValue;
  1352.                 }
  1353.             }
  1354.             if (ggfree == ZERO) {
  1355.                 return new double[] { alpha, ZERO };
  1356.             }

  1357.             // Investigate whether more components of W can be fixed.
  1358.             final double tmp1 = adelt * adelt - wfixsq;
  1359.             if (tmp1 > ZERO) {
  1360.                 step = JdkMath.sqrt(tmp1 / ggfree);
  1361.                 ggfree = ZERO;
  1362.                 for (int i = 0; i < n; i++) {
  1363.                     if (work1.getEntry(i) == bigstp) {
  1364.                         final double tmp2 = trustRegionCenterOffset.getEntry(i) - step * glag.getEntry(i);
  1365.                         if (tmp2 <= lowerDifference.getEntry(i)) {
  1366.                             work1.setEntry(i, lowerDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i));
  1367.                             // Computing 2nd power
  1368.                             final double d1 = work1.getEntry(i);
  1369.                             wfixsq += d1 * d1;
  1370.                         } else if (tmp2 >= upperDifference.getEntry(i)) {
  1371.                             work1.setEntry(i, upperDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i));
  1372.                             // Computing 2nd power
  1373.                             final double d1 = work1.getEntry(i);
  1374.                             wfixsq += d1 * d1;
  1375.                         } else {
  1376.                             // Computing 2nd power
  1377.                             final double d1 = glag.getEntry(i);
  1378.                             ggfree += d1 * d1;
  1379.                         }
  1380.                     }
  1381.                 }
  1382.             }

  1383.             // Set the remaining free components of W and all components of XALT,
  1384.             // except that W may be scaled later.

  1385.             double gw = ZERO;
  1386.             for (int i = 0; i < n; i++) {
  1387.                 final double glagValue = glag.getEntry(i);
  1388.                 if (work1.getEntry(i) == bigstp) {
  1389.                     work1.setEntry(i, -step * glagValue);
  1390.                     final double min = JdkMath.min(upperDifference.getEntry(i),
  1391.                                                     trustRegionCenterOffset.getEntry(i) + work1.getEntry(i));
  1392.                     alternativeNewPoint.setEntry(i, JdkMath.max(lowerDifference.getEntry(i), min));
  1393.                 } else if (work1.getEntry(i) == ZERO) {
  1394.                     alternativeNewPoint.setEntry(i, trustRegionCenterOffset.getEntry(i));
  1395.                 } else if (glagValue > ZERO) {
  1396.                     alternativeNewPoint.setEntry(i, lowerDifference.getEntry(i));
  1397.                 } else {
  1398.                     alternativeNewPoint.setEntry(i, upperDifference.getEntry(i));
  1399.                 }
  1400.                 gw += glagValue * work1.getEntry(i);
  1401.             }

  1402.             // Set CURV to the curvature of the KNEW-th Lagrange function along W.
  1403.             // Scale W by a factor less than one if that can reduce the modulus of
  1404.             // the Lagrange function at XOPT+W. Set CAUCHY to the final value of
  1405.             // the square of this function.

  1406.             double curv = ZERO;
  1407.             for (int k = 0; k < npt; k++) {
  1408.                 double tmp = ZERO;
  1409.                 for (int j = 0; j < n; j++) {
  1410.                     tmp += interpolationPoints.getEntry(k, j) * work1.getEntry(j);
  1411.                 }
  1412.                 curv += hcol.getEntry(k) * tmp * tmp;
  1413.             }
  1414.             if (iflag == 1) {
  1415.                 curv = -curv;
  1416.             }
  1417.             if (curv > -gw &&
  1418.                 curv < -gw * (ONE + JdkMath.sqrt(TWO))) {
  1419.                 final double scale = -gw / curv;
  1420.                 for (int i = 0; i < n; i++) {
  1421.                     final double tmp = trustRegionCenterOffset.getEntry(i) + scale * work1.getEntry(i);
  1422.                     alternativeNewPoint.setEntry(i, JdkMath.max(lowerDifference.getEntry(i),
  1423.                                                     JdkMath.min(upperDifference.getEntry(i), tmp)));
  1424.                 }
  1425.                 // Computing 2nd power
  1426.                 final double d1 = HALF * gw * scale;
  1427.                 cauchy = d1 * d1;
  1428.             } else {
  1429.                 // Computing 2nd power
  1430.                 final double d1 = gw + HALF * curv;
  1431.                 cauchy = d1 * d1;
  1432.             }

  1433.             // If IFLAG is zero, then XALT is calculated as before after reversing
  1434.             // the sign of GLAG. Thus two XALT vectors become available. The one that
  1435.             // is chosen is the one that gives the larger value of CAUCHY.

  1436.             if (iflag == 0) {
  1437.                 for (int i = 0; i < n; i++) {
  1438.                     glag.setEntry(i, -glag.getEntry(i));
  1439.                     work2.setEntry(i, alternativeNewPoint.getEntry(i));
  1440.                 }
  1441.                 csave = cauchy;
  1442.                 iflag = 1;
  1443.             } else {
  1444.                 break;
  1445.             }
  1446.         }
  1447.         if (csave > cauchy) {
  1448.             for (int i = 0; i < n; i++) {
  1449.                 alternativeNewPoint.setEntry(i, work2.getEntry(i));
  1450.             }
  1451.             cauchy = csave;
  1452.         }

  1453.         return new double[] { alpha, cauchy };
  1454.     } // altmov

  1455.     // ----------------------------------------------------------------------------------------

  1456.     /**
  1457.      *     SUBROUTINE PRELIM sets the elements of XBASE, XPT, FVAL, GOPT, HQ, PQ,
  1458.      *     BMAT and ZMAT for the first iteration, and it maintains the values of
  1459.      *     NF and KOPT. The vector X is also changed by PRELIM.
  1460.      *
  1461.      *     The arguments N, NPT, X, XL, XU, RHOBEG, IPRINT and MAXFUN are the
  1462.      *       same as the corresponding arguments in SUBROUTINE BOBYQA.
  1463.      *     The arguments XBASE, XPT, FVAL, HQ, PQ, BMAT, ZMAT, NDIM, SL and SU
  1464.      *       are the same as the corresponding arguments in BOBYQB, the elements
  1465.      *       of SL and SU being set in BOBYQA.
  1466.      *     GOPT is usually the gradient of the quadratic model at XOPT+XBASE, but
  1467.      *       it is set by PRELIM to the gradient of the quadratic model at XBASE.
  1468.      *       If XOPT is nonzero, BOBYQB will change it to its usual value later.
  1469.      *     NF is maintaned as the number of calls of CALFUN so far.
  1470.      *     KOPT will be such that the least calculated value of F so far is at
  1471.      *       the point XPT(KOPT,.)+XBASE in the space of the variables.
  1472.      *
  1473.      * @param lowerBound Lower bounds.
  1474.      * @param upperBound Upper bounds.
  1475.      */
  1476.     private void prelim(double[] lowerBound,
  1477.                         double[] upperBound) {
  1478.         printMethod(); // XXX

  1479.         final int n = currentBest.getDimension();
  1480.         final int npt = numberOfInterpolationPoints;
  1481.         final int ndim = bMatrix.getRowDimension();

  1482.         final double rhosq = initialTrustRegionRadius * initialTrustRegionRadius;
  1483.         final double recip = 1d / rhosq;
  1484.         final int np = n + 1;

  1485.         // Set XBASE to the initial vector of variables, and set the initial
  1486.         // elements of XPT, BMAT, HQ, PQ and ZMAT to zero.

  1487.         for (int j = 0; j < n; j++) {
  1488.             originShift.setEntry(j, currentBest.getEntry(j));
  1489.             for (int k = 0; k < npt; k++) {
  1490.                 interpolationPoints.setEntry(k, j, ZERO);
  1491.             }
  1492.             for (int i = 0; i < ndim; i++) {
  1493.                 bMatrix.setEntry(i, j, ZERO);
  1494.             }
  1495.         }
  1496.         for (int i = 0, max = n * np / 2; i < max; i++) {
  1497.             modelSecondDerivativesValues.setEntry(i, ZERO);
  1498.         }
  1499.         for (int k = 0; k < npt; k++) {
  1500.             modelSecondDerivativesParameters.setEntry(k, ZERO);
  1501.             for (int j = 0, max = npt - np; j < max; j++) {
  1502.                 zMatrix.setEntry(k, j, ZERO);
  1503.             }
  1504.         }

  1505.         // Begin the initialization procedure. NF becomes one more than the number
  1506.         // of function values so far. The coordinates of the displacement of the
  1507.         // next initial interpolation point from XBASE are set in XPT(NF+1,.).

  1508.         int ipt = 0;
  1509.         int jpt = 0;
  1510.         double fbeg = Double.NaN;
  1511.         do {
  1512.             final int nfm = getEvaluations();
  1513.             final int nfx = nfm - n;
  1514.             final int nfmm = nfm - 1;
  1515.             final int nfxm = nfx - 1;
  1516.             double stepa = 0;
  1517.             double stepb = 0;
  1518.             if (nfm <= 2 * n) {
  1519.                 if (nfm >= 1 &&
  1520.                     nfm <= n) {
  1521.                     stepa = initialTrustRegionRadius;
  1522.                     if (upperDifference.getEntry(nfmm) == ZERO) {
  1523.                         stepa = -stepa;
  1524.                         // throw new PathIsExploredException(); // XXX
  1525.                     }
  1526.                     interpolationPoints.setEntry(nfm, nfmm, stepa);
  1527.                 } else if (nfm > n) {
  1528.                     stepa = interpolationPoints.getEntry(nfx, nfxm);
  1529.                     stepb = -initialTrustRegionRadius;
  1530.                     if (lowerDifference.getEntry(nfxm) == ZERO) {
  1531.                         stepb = JdkMath.min(TWO * initialTrustRegionRadius, upperDifference.getEntry(nfxm));
  1532.                         // throw new PathIsExploredException(); // XXX
  1533.                     }
  1534.                     if (upperDifference.getEntry(nfxm) == ZERO) {
  1535.                         stepb = JdkMath.max(-TWO * initialTrustRegionRadius, lowerDifference.getEntry(nfxm));
  1536.                         // throw new PathIsExploredException(); // XXX
  1537.                     }
  1538.                     interpolationPoints.setEntry(nfm, nfxm, stepb);
  1539.                 }
  1540.             } else {
  1541.                 final int tmp1 = (nfm - np) / n;
  1542.                 jpt = nfm - tmp1 * n - n;
  1543.                 ipt = jpt + tmp1;
  1544.                 if (ipt > n) {
  1545.                     final int tmp2 = jpt;
  1546.                     jpt = ipt - n;
  1547.                     ipt = tmp2;
  1548. //                     throw new PathIsExploredException(); // XXX
  1549.                 }
  1550.                 final int iptMinus1 = ipt - 1;
  1551.                 final int jptMinus1 = jpt - 1;
  1552.                 interpolationPoints.setEntry(nfm, iptMinus1, interpolationPoints.getEntry(ipt, iptMinus1));
  1553.                 interpolationPoints.setEntry(nfm, jptMinus1, interpolationPoints.getEntry(jpt, jptMinus1));
  1554.             }

  1555.             // Calculate the next value of F. The least function value so far and
  1556.             // its index are required.

  1557.             for (int j = 0; j < n; j++) {
  1558.                 currentBest.setEntry(j, JdkMath.min(JdkMath.max(lowerBound[j],
  1559.                                                                   originShift.getEntry(j) + interpolationPoints.getEntry(nfm, j)),
  1560.                                                      upperBound[j]));
  1561.                 if (interpolationPoints.getEntry(nfm, j) == lowerDifference.getEntry(j)) {
  1562.                     currentBest.setEntry(j, lowerBound[j]);
  1563.                 }
  1564.                 if (interpolationPoints.getEntry(nfm, j) == upperDifference.getEntry(j)) {
  1565.                     currentBest.setEntry(j, upperBound[j]);
  1566.                 }
  1567.             }

  1568.             final double objectiveValue = getObjectiveFunction().value(currentBest.toArray());
  1569.             final double f = isMinimize ? objectiveValue : -objectiveValue;
  1570.             final int numEval = getEvaluations(); // nfm + 1
  1571.             fAtInterpolationPoints.setEntry(nfm, f);

  1572.             if (numEval == 1) {
  1573.                 fbeg = f;
  1574.                 trustRegionCenterInterpolationPointIndex = 0;
  1575.             } else if (f < fAtInterpolationPoints.getEntry(trustRegionCenterInterpolationPointIndex)) {
  1576.                 trustRegionCenterInterpolationPointIndex = nfm;
  1577.             }

  1578.             // Set the nonzero initial elements of BMAT and the quadratic model in the
  1579.             // cases when NF is at most 2*N+1. If NF exceeds N+1, then the positions
  1580.             // of the NF-th and (NF-N)-th interpolation points may be switched, in
  1581.             // order that the function value at the first of them contributes to the
  1582.             // off-diagonal second derivative terms of the initial quadratic model.

  1583.             if (numEval <= 2 * n + 1) {
  1584.                 if (numEval >= 2 &&
  1585.                     numEval <= n + 1) {
  1586.                     gradientAtTrustRegionCenter.setEntry(nfmm, (f - fbeg) / stepa);
  1587.                     if (npt < numEval + n) {
  1588.                         final double oneOverStepA = ONE / stepa;
  1589.                         bMatrix.setEntry(0, nfmm, -oneOverStepA);
  1590.                         bMatrix.setEntry(nfm, nfmm, oneOverStepA);
  1591.                         bMatrix.setEntry(npt + nfmm, nfmm, -HALF * rhosq);
  1592.                         // throw new PathIsExploredException(); // XXX
  1593.                     }
  1594.                 } else if (numEval >= n + 2) {
  1595.                     final int ih = nfx * (nfx + 1) / 2 - 1;
  1596.                     final double tmp = (f - fbeg) / stepb;
  1597.                     final double diff = stepb - stepa;
  1598.                     modelSecondDerivativesValues.setEntry(ih, TWO * (tmp - gradientAtTrustRegionCenter.getEntry(nfxm)) / diff);
  1599.                     gradientAtTrustRegionCenter.setEntry(nfxm, (gradientAtTrustRegionCenter.getEntry(nfxm) * stepb - tmp * stepa) / diff);
  1600.                     if (stepa * stepb < ZERO && f < fAtInterpolationPoints.getEntry(nfm - n)) {
  1601.                         fAtInterpolationPoints.setEntry(nfm, fAtInterpolationPoints.getEntry(nfm - n));
  1602.                         fAtInterpolationPoints.setEntry(nfm - n, f);
  1603.                         if (trustRegionCenterInterpolationPointIndex == nfm) {
  1604.                             trustRegionCenterInterpolationPointIndex = nfm - n;
  1605.                         }
  1606.                         interpolationPoints.setEntry(nfm - n, nfxm, stepb);
  1607.                         interpolationPoints.setEntry(nfm, nfxm, stepa);
  1608.                     }
  1609.                     bMatrix.setEntry(0, nfxm, -(stepa + stepb) / (stepa * stepb));
  1610.                     bMatrix.setEntry(nfm, nfxm, -HALF / interpolationPoints.getEntry(nfm - n, nfxm));
  1611.                     bMatrix.setEntry(nfm - n, nfxm,
  1612.                                   -bMatrix.getEntry(0, nfxm) - bMatrix.getEntry(nfm, nfxm));
  1613.                     zMatrix.setEntry(0, nfxm, JdkMath.sqrt(TWO) / (stepa * stepb));
  1614.                     zMatrix.setEntry(nfm, nfxm, JdkMath.sqrt(HALF) / rhosq);
  1615.                     // zMatrix.setEntry(nfm, nfxm, JdkMath.sqrt(HALF) * recip); // XXX "testAckley" and "testDiffPow" fail.
  1616.                     zMatrix.setEntry(nfm - n, nfxm,
  1617.                                   -zMatrix.getEntry(0, nfxm) - zMatrix.getEntry(nfm, nfxm));
  1618.                 }

  1619.                 // Set the off-diagonal second derivatives of the Lagrange functions and
  1620.                 // the initial quadratic model.
  1621.             } else {
  1622.                 zMatrix.setEntry(0, nfxm, recip);
  1623.                 zMatrix.setEntry(nfm, nfxm, recip);
  1624.                 zMatrix.setEntry(ipt, nfxm, -recip);
  1625.                 zMatrix.setEntry(jpt, nfxm, -recip);

  1626.                 final int ih = ipt * (ipt - 1) / 2 + jpt - 1;
  1627.                 final double tmp = interpolationPoints.getEntry(nfm, ipt - 1) * interpolationPoints.getEntry(nfm, jpt - 1);
  1628.                 modelSecondDerivativesValues.setEntry(ih, (fbeg - fAtInterpolationPoints.getEntry(ipt) - fAtInterpolationPoints.getEntry(jpt) + f) / tmp);
  1629. //                 throw new PathIsExploredException(); // XXX
  1630.             }
  1631.         } while (getEvaluations() < npt);
  1632.     } // prelim


  1633.     // ----------------------------------------------------------------------------------------

  1634.     /**
  1635.      *     A version of the truncated conjugate gradient is applied. If a line
  1636.      *     search is restricted by a constraint, then the procedure is restarted,
  1637.      *     the values of the variables that are at their bounds being fixed. If
  1638.      *     the trust region boundary is reached, then further changes may be made
  1639.      *     to D, each one being in the two dimensional space that is spanned
  1640.      *     by the current D and the gradient of Q at XOPT+D, staying on the trust
  1641.      *     region boundary. Termination occurs when the reduction in Q seems to
  1642.      *     be close to the greatest reduction that can be achieved.
  1643.      *     The arguments N, NPT, XPT, XOPT, GOPT, HQ, PQ, SL and SU have the same
  1644.      *       meanings as the corresponding arguments of BOBYQB.
  1645.      *     DELTA is the trust region radius for the present calculation, which
  1646.      *       seeks a small value of the quadratic model within distance DELTA of
  1647.      *       XOPT subject to the bounds on the variables.
  1648.      *     XNEW will be set to a new vector of variables that is approximately
  1649.      *       the one that minimizes the quadratic model within the trust region
  1650.      *       subject to the SL and SU constraints on the variables. It satisfies
  1651.      *       as equations the bounds that become active during the calculation.
  1652.      *     D is the calculated trial step from XOPT, generated iteratively from an
  1653.      *       initial value of zero. Thus XNEW is XOPT+D after the final iteration.
  1654.      *     GNEW holds the gradient of the quadratic model at XOPT+D. It is updated
  1655.      *       when D is updated.
  1656.      *     xbdi.get( is a working space vector. For I=1,2,...,N, the element xbdi.get((I) is
  1657.      *       set to -1.0, 0.0, or 1.0, the value being nonzero if and only if the
  1658.      *       I-th variable has become fixed at a bound, the bound being SL(I) or
  1659.      *       SU(I) in the case xbdi.get((I)=-1.0 or xbdi.get((I)=1.0, respectively. This
  1660.      *       information is accumulated during the construction of XNEW.
  1661.      *     The arrays S, HS and HRED are also used for working space. They hold the
  1662.      *       current search direction, and the changes in the gradient of Q along S
  1663.      *       and the reduced D, respectively, where the reduced D is the same as D,
  1664.      *       except that the components of the fixed variables are zero.
  1665.      *     DSQ will be set to the square of the length of XNEW-XOPT.
  1666.      *     CRVMIN is set to zero if D reaches the trust region boundary. Otherwise
  1667.      *       it is set to the least curvature of H that occurs in the conjugate
  1668.      *       gradient searches that are not restricted by any constraints. The
  1669.      *       value CRVMIN=-1.0D0 is set, however, if all of these searches are
  1670.      *       constrained.
  1671.      * @param delta
  1672.      * @param gnew
  1673.      * @param xbdi
  1674.      * @param s
  1675.      * @param hs
  1676.      * @param hred
  1677.      * @return { dsq, crvmin }
  1678.      */
  1679.     private double[] trsbox(
  1680.             double delta,
  1681.             ArrayRealVector gnew,
  1682.             ArrayRealVector xbdi,
  1683.             ArrayRealVector s,
  1684.             ArrayRealVector hs,
  1685.             ArrayRealVector hred
  1686.     ) {
  1687.         printMethod(); // XXX

  1688.         final int n = currentBest.getDimension();
  1689.         final int npt = numberOfInterpolationPoints;

  1690.         double dsq = Double.NaN;
  1691.         double crvmin = Double.NaN;

  1692.         // Local variables
  1693.         double ds;
  1694.         int iu;
  1695.         double dhd, dhs, cth, shs, sth, ssq, beta=0, sdec, blen;
  1696.         int iact = -1;
  1697.         int nact = 0;
  1698.         double angt = 0, qred;
  1699.         int isav;
  1700.         double temp = 0, xsav = 0, xsum = 0, angbd = 0, dredg = 0, sredg = 0;
  1701.         int iterc;
  1702.         double resid = 0, delsq = 0, ggsav = 0, tempa = 0, tempb = 0,
  1703.         redmax = 0, dredsq = 0, redsav = 0, gredsq = 0, rednew = 0;
  1704.         int itcsav = 0;
  1705.         double rdprev = 0, rdnext = 0, stplen = 0, stepsq = 0;
  1706.         int itermax = 0;

  1707.         // Set some constants.

  1708.         // Function Body

  1709.         // The sign of GOPT(I) gives the sign of the change to the I-th variable
  1710.         // that will reduce Q from its value at XOPT. Thus xbdi.get((I) shows whether
  1711.         // or not to fix the I-th variable at one of its bounds initially, with
  1712.         // NACT being set to the number of fixed variables. D and GNEW are also
  1713.         // set for the first iteration. DELSQ is the upper bound on the sum of
  1714.         // squares of the free variables. QRED is the reduction in Q so far.

  1715.         iterc = 0;
  1716.         nact = 0;
  1717.         for (int i = 0; i < n; i++) {
  1718.             xbdi.setEntry(i, ZERO);
  1719.             if (trustRegionCenterOffset.getEntry(i) <= lowerDifference.getEntry(i)) {
  1720.                 if (gradientAtTrustRegionCenter.getEntry(i) >= ZERO) {
  1721.                     xbdi.setEntry(i, MINUS_ONE);
  1722.                 }
  1723.             } else if (trustRegionCenterOffset.getEntry(i) >= upperDifference.getEntry(i) &&
  1724.                     gradientAtTrustRegionCenter.getEntry(i) <= ZERO) {
  1725.                 xbdi.setEntry(i, ONE);
  1726.             }
  1727.             if (xbdi.getEntry(i) != ZERO) {
  1728.                 ++nact;
  1729.             }
  1730.             trialStepPoint.setEntry(i, ZERO);
  1731.             gnew.setEntry(i, gradientAtTrustRegionCenter.getEntry(i));
  1732.         }
  1733.         delsq = delta * delta;
  1734.         qred = ZERO;
  1735.         crvmin = MINUS_ONE;

  1736.         // Set the next search direction of the conjugate gradient method. It is
  1737.         // the steepest descent direction initially and when the iterations are
  1738.         // restarted because a variable has just been fixed by a bound, and of
  1739.         // course the components of the fixed variables are zero. ITERMAX is an
  1740.         // upper bound on the indices of the conjugate gradient iterations.

  1741.         int state = 20;
  1742.         for(;;) {
  1743.             switch (state) {
  1744.         case 20: {
  1745.             printState(20); // XXX
  1746.             beta = ZERO;
  1747.         }
  1748.         case 30: {
  1749.             printState(30); // XXX
  1750.             stepsq = ZERO;
  1751.             for (int i = 0; i < n; i++) {
  1752.                 if (xbdi.getEntry(i) != ZERO) {
  1753.                     s.setEntry(i, ZERO);
  1754.                 } else if (beta == ZERO) {
  1755.                     s.setEntry(i, -gnew.getEntry(i));
  1756.                 } else {
  1757.                     s.setEntry(i, beta * s.getEntry(i) - gnew.getEntry(i));
  1758.                 }
  1759.                 // Computing 2nd power
  1760.                 final double d1 = s.getEntry(i);
  1761.                 stepsq += d1 * d1;
  1762.             }
  1763.             if (stepsq == ZERO) {
  1764.                 state = 190; break;
  1765.             }
  1766.             if (beta == ZERO) {
  1767.                 gredsq = stepsq;
  1768.                 itermax = iterc + n - nact;
  1769.             }
  1770.             if (gredsq * delsq <= qred * 1e-4 * qred) {
  1771.                 state = 190; break;
  1772.             }

  1773.             // Multiply the search direction by the second derivative matrix of Q and
  1774.             // calculate some scalars for the choice of steplength. Then set BLEN to
  1775.             // the length of the step to the trust region boundary and STPLEN to
  1776.             // the steplength, ignoring the simple bounds.

  1777.             state = 210; break;
  1778.         }
  1779.         case 50: {
  1780.             printState(50); // XXX
  1781.             resid = delsq;
  1782.             ds = ZERO;
  1783.             shs = ZERO;
  1784.             for (int i = 0; i < n; i++) {
  1785.                 if (xbdi.getEntry(i) == ZERO) {
  1786.                     // Computing 2nd power
  1787.                     final double d1 = trialStepPoint.getEntry(i);
  1788.                     resid -= d1 * d1;
  1789.                     ds += s.getEntry(i) * trialStepPoint.getEntry(i);
  1790.                     shs += s.getEntry(i) * hs.getEntry(i);
  1791.                 }
  1792.             }
  1793.             if (resid <= ZERO) {
  1794.                 state = 90; break;
  1795.             }
  1796.             temp = JdkMath.sqrt(stepsq * resid + ds * ds);
  1797.             if (ds < ZERO) {
  1798.                 blen = (temp - ds) / stepsq;
  1799.             } else {
  1800.                 blen = resid / (temp + ds);
  1801.             }
  1802.             stplen = blen;
  1803.             if (shs > ZERO) {
  1804.                 // Computing MIN
  1805.                 stplen = JdkMath.min(blen, gredsq / shs);
  1806.             }

  1807.             // Reduce STPLEN if necessary in order to preserve the simple bounds,
  1808.             // letting IACT be the index of the new constrained variable.

  1809.             iact = -1;
  1810.             for (int i = 0; i < n; i++) {
  1811.                 if (s.getEntry(i) != ZERO) {
  1812.                     xsum = trustRegionCenterOffset.getEntry(i) + trialStepPoint.getEntry(i);
  1813.                     if (s.getEntry(i) > ZERO) {
  1814.                         temp = (upperDifference.getEntry(i) - xsum) / s.getEntry(i);
  1815.                     } else {
  1816.                         temp = (lowerDifference.getEntry(i) - xsum) / s.getEntry(i);
  1817.                     }
  1818.                     if (temp < stplen) {
  1819.                         stplen = temp;
  1820.                         iact = i;
  1821.                     }
  1822.                 }
  1823.             }

  1824.             // Update CRVMIN, GNEW and D. Set SDEC to the decrease that occurs in Q.

  1825.             sdec = ZERO;
  1826.             if (stplen > ZERO) {
  1827.                 ++iterc;
  1828.                 temp = shs / stepsq;
  1829.                 if (iact == -1 && temp > ZERO) {
  1830.                     crvmin = JdkMath.min(crvmin,temp);
  1831.                     if (crvmin == MINUS_ONE) {
  1832.                         crvmin = temp;
  1833.                     }
  1834.                 }
  1835.                 ggsav = gredsq;
  1836.                 gredsq = ZERO;
  1837.                 for (int i = 0; i < n; i++) {
  1838.                     gnew.setEntry(i, gnew.getEntry(i) + stplen * hs.getEntry(i));
  1839.                     if (xbdi.getEntry(i) == ZERO) {
  1840.                         // Computing 2nd power
  1841.                         final double d1 = gnew.getEntry(i);
  1842.                         gredsq += d1 * d1;
  1843.                     }
  1844.                     trialStepPoint.setEntry(i, trialStepPoint.getEntry(i) + stplen * s.getEntry(i));
  1845.                 }
  1846.                 // Computing MAX
  1847.                 final double d1 = stplen * (ggsav - HALF * stplen * shs);
  1848.                 sdec = JdkMath.max(d1, ZERO);
  1849.                 qred += sdec;
  1850.             }

  1851.             // Restart the conjugate gradient method if it has hit a new bound.

  1852.             if (iact >= 0) {
  1853.                 ++nact;
  1854.                 xbdi.setEntry(iact, ONE);
  1855.                 if (s.getEntry(iact) < ZERO) {
  1856.                     xbdi.setEntry(iact, MINUS_ONE);
  1857.                 }
  1858.                 // Computing 2nd power
  1859.                 final double d1 = trialStepPoint.getEntry(iact);
  1860.                 delsq -= d1 * d1;
  1861.                 if (delsq <= ZERO) {
  1862.                     state = 190; break;
  1863.                 }
  1864.                 state = 20; break;
  1865.             }

  1866.             // If STPLEN is less than BLEN, then either apply another conjugate
  1867.             // gradient iteration or RETURN.

  1868.             if (stplen < blen) {
  1869.                 if (iterc == itermax) {
  1870.                     state = 190; break;
  1871.                 }
  1872.                 if (sdec <= qred * .01) {
  1873.                     state = 190; break;
  1874.                 }
  1875.                 beta = gredsq / ggsav;
  1876.                 state = 30; break;
  1877.             }
  1878.         }
  1879.         case 90: {
  1880.             printState(90); // XXX
  1881.             crvmin = ZERO;

  1882.             // Prepare for the alternative iteration by calculating some scalars
  1883.             // and by multiplying the reduced D by the second derivative matrix of
  1884.             // Q, where S holds the reduced D in the call of GGMULT.
  1885.         }
  1886.         case 100: {
  1887.             printState(100); // XXX
  1888.             if (nact >= n - 1) {
  1889.                 state = 190; break;
  1890.             }
  1891.             dredsq = ZERO;
  1892.             dredg = ZERO;
  1893.             gredsq = ZERO;
  1894.             for (int i = 0; i < n; i++) {
  1895.                 if (xbdi.getEntry(i) == ZERO) {
  1896.                     // Computing 2nd power
  1897.                     double d1 = trialStepPoint.getEntry(i);
  1898.                     dredsq += d1 * d1;
  1899.                     dredg += trialStepPoint.getEntry(i) * gnew.getEntry(i);
  1900.                     // Computing 2nd power
  1901.                     d1 = gnew.getEntry(i);
  1902.                     gredsq += d1 * d1;
  1903.                     s.setEntry(i, trialStepPoint.getEntry(i));
  1904.                 } else {
  1905.                     s.setEntry(i, ZERO);
  1906.                 }
  1907.             }
  1908.             itcsav = iterc;
  1909.             state = 210; break;
  1910.             // Let the search direction S be a linear combination of the reduced D
  1911.             // and the reduced G that is orthogonal to the reduced D.
  1912.         }
  1913.         case 120: {
  1914.             printState(120); // XXX
  1915.             ++iterc;
  1916.             temp = gredsq * dredsq - dredg * dredg;
  1917.             if (temp <= qred * 1e-4 * qred) {
  1918.                 state = 190; break;
  1919.             }
  1920.             temp = JdkMath.sqrt(temp);
  1921.             for (int i = 0; i < n; i++) {
  1922.                 if (xbdi.getEntry(i) == ZERO) {
  1923.                     s.setEntry(i, (dredg * trialStepPoint.getEntry(i) - dredsq * gnew.getEntry(i)) / temp);
  1924.                 } else {
  1925.                     s.setEntry(i, ZERO);
  1926.                 }
  1927.             }
  1928.             sredg = -temp;

  1929.             // By considering the simple bounds on the variables, calculate an upper
  1930.             // bound on the tangent of half the angle of the alternative iteration,
  1931.             // namely ANGBD, except that, if already a free variable has reached a
  1932.             // bound, there is a branch back to label 100 after fixing that variable.

  1933.             angbd = ONE;
  1934.             iact = -1;
  1935.             for (int i = 0; i < n; i++) {
  1936.                 if (xbdi.getEntry(i) == ZERO) {
  1937.                     tempa = trustRegionCenterOffset.getEntry(i) + trialStepPoint.getEntry(i) - lowerDifference.getEntry(i);
  1938.                     tempb = upperDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i) - trialStepPoint.getEntry(i);
  1939.                     if (tempa <= ZERO) {
  1940.                         ++nact;
  1941.                         xbdi.setEntry(i, MINUS_ONE);
  1942.                         state = 100; break;
  1943.                     } else if (tempb <= ZERO) {
  1944.                         ++nact;
  1945.                         xbdi.setEntry(i, ONE);
  1946.                         state = 100; break;
  1947.                     }
  1948.                     // Computing 2nd power
  1949.                     double d1 = trialStepPoint.getEntry(i);
  1950.                     // Computing 2nd power
  1951.                     double d2 = s.getEntry(i);
  1952.                     ssq = d1 * d1 + d2 * d2;
  1953.                     // Computing 2nd power
  1954.                     d1 = trustRegionCenterOffset.getEntry(i) - lowerDifference.getEntry(i);
  1955.                     temp = ssq - d1 * d1;
  1956.                     if (temp > ZERO) {
  1957.                         temp = JdkMath.sqrt(temp) - s.getEntry(i);
  1958.                         if (angbd * temp > tempa) {
  1959.                             angbd = tempa / temp;
  1960.                             iact = i;
  1961.                             xsav = MINUS_ONE;
  1962.                         }
  1963.                     }
  1964.                     // Computing 2nd power
  1965.                     d1 = upperDifference.getEntry(i) - trustRegionCenterOffset.getEntry(i);
  1966.                     temp = ssq - d1 * d1;
  1967.                     if (temp > ZERO) {
  1968.                         temp = JdkMath.sqrt(temp) + s.getEntry(i);
  1969.                         if (angbd * temp > tempb) {
  1970.                             angbd = tempb / temp;
  1971.                             iact = i;
  1972.                             xsav = ONE;
  1973.                         }
  1974.                     }
  1975.                 }
  1976.             }

  1977.             // Calculate HHD and some curvatures for the alternative iteration.

  1978.             state = 210; break;
  1979.         }
  1980.         case 150: {
  1981.             printState(150); // XXX
  1982.             shs = ZERO;
  1983.             dhs = ZERO;
  1984.             dhd = ZERO;
  1985.             for (int i = 0; i < n; i++) {
  1986.                 if (xbdi.getEntry(i) == ZERO) {
  1987.                     shs += s.getEntry(i) * hs.getEntry(i);
  1988.                     dhs += trialStepPoint.getEntry(i) * hs.getEntry(i);
  1989.                     dhd += trialStepPoint.getEntry(i) * hred.getEntry(i);
  1990.                 }
  1991.             }

  1992.             // Seek the greatest reduction in Q for a range of equally spaced values
  1993.             // of ANGT in [0,ANGBD], where ANGT is the tangent of half the angle of
  1994.             // the alternative iteration.

  1995.             redmax = ZERO;
  1996.             isav = -1;
  1997.             redsav = ZERO;
  1998.             iu = (int) (angbd * 17. + 3.1);
  1999.             for (int i = 0; i < iu; i++) {
  2000.                 angt = angbd * i / iu;
  2001.                 sth = (angt + angt) / (ONE + angt * angt);
  2002.                 temp = shs + angt * (angt * dhd - dhs - dhs);
  2003.                 rednew = sth * (angt * dredg - sredg - HALF * sth * temp);
  2004.                 if (rednew > redmax) {
  2005.                     redmax = rednew;
  2006.                     isav = i;
  2007.                     rdprev = redsav;
  2008.                 } else if (i == isav + 1) {
  2009.                     rdnext = rednew;
  2010.                 }
  2011.                 redsav = rednew;
  2012.             }

  2013.             // Return if the reduction is zero. Otherwise, set the sine and cosine
  2014.             // of the angle of the alternative iteration, and calculate SDEC.

  2015.             if (isav < 0) {
  2016.                 state = 190; break;
  2017.             }
  2018.             if (isav < iu) {
  2019.                 temp = (rdnext - rdprev) / (redmax + redmax - rdprev - rdnext);
  2020.                 angt = angbd * (isav + HALF * temp) / iu;
  2021.             }
  2022.             cth = (ONE - angt * angt) / (ONE + angt * angt);
  2023.             sth = (angt + angt) / (ONE + angt * angt);
  2024.             temp = shs + angt * (angt * dhd - dhs - dhs);
  2025.             sdec = sth * (angt * dredg - sredg - HALF * sth * temp);
  2026.             if (sdec <= ZERO) {
  2027.                 state = 190; break;
  2028.             }

  2029.             // Update GNEW, D and HRED. If the angle of the alternative iteration
  2030.             // is restricted by a bound on a free variable, that variable is fixed
  2031.             // at the bound.

  2032.             dredg = ZERO;
  2033.             gredsq = ZERO;
  2034.             for (int i = 0; i < n; i++) {
  2035.                 gnew.setEntry(i, gnew.getEntry(i) + (cth - ONE) * hred.getEntry(i) + sth * hs.getEntry(i));
  2036.                 if (xbdi.getEntry(i) == ZERO) {
  2037.                     trialStepPoint.setEntry(i, cth * trialStepPoint.getEntry(i) + sth * s.getEntry(i));
  2038.                     dredg += trialStepPoint.getEntry(i) * gnew.getEntry(i);
  2039.                     // Computing 2nd power
  2040.                     final double d1 = gnew.getEntry(i);
  2041.                     gredsq += d1 * d1;
  2042.                 }
  2043.                 hred.setEntry(i, cth * hred.getEntry(i) + sth * hs.getEntry(i));
  2044.             }
  2045.             qred += sdec;
  2046.             if (iact >= 0 && isav == iu) {
  2047.                 ++nact;
  2048.                 xbdi.setEntry(iact, xsav);
  2049.                 state = 100; break;
  2050.             }

  2051.             // If SDEC is sufficiently small, then RETURN after setting XNEW to
  2052.             // XOPT+D, giving careful attention to the bounds.

  2053.             if (sdec > qred * .01) {
  2054.                 state = 120; break;
  2055.             }
  2056.         }
  2057.         case 190: {
  2058.             printState(190); // XXX
  2059.             dsq = ZERO;
  2060.             for (int i = 0; i < n; i++) {
  2061.                 // Computing MAX
  2062.                 // Computing MIN
  2063.                 final double min = JdkMath.min(trustRegionCenterOffset.getEntry(i) + trialStepPoint.getEntry(i),
  2064.                                             upperDifference.getEntry(i));
  2065.                 newPoint.setEntry(i, JdkMath.max(min, lowerDifference.getEntry(i)));
  2066.                 if (xbdi.getEntry(i) == MINUS_ONE) {
  2067.                     newPoint.setEntry(i, lowerDifference.getEntry(i));
  2068.                 }
  2069.                 if (xbdi.getEntry(i) == ONE) {
  2070.                     newPoint.setEntry(i, upperDifference.getEntry(i));
  2071.                 }
  2072.                 trialStepPoint.setEntry(i, newPoint.getEntry(i) - trustRegionCenterOffset.getEntry(i));
  2073.                 // Computing 2nd power
  2074.                 final double d1 = trialStepPoint.getEntry(i);
  2075.                 dsq += d1 * d1;
  2076.             }
  2077.             return new double[] { dsq, crvmin };
  2078.             // The following instructions multiply the current S-vector by the second
  2079.             // derivative matrix of the quadratic model, putting the product in HS.
  2080.             // They are reached from three different parts of the software above and
  2081.             // they can be regarded as an external subroutine.
  2082.         }
  2083.         case 210: {
  2084.             printState(210); // XXX
  2085.             int ih = 0;
  2086.             for (int j = 0; j < n; j++) {
  2087.                 hs.setEntry(j, ZERO);
  2088.                 for (int i = 0; i <= j; i++) {
  2089.                     if (i < j) {
  2090.                         hs.setEntry(j, hs.getEntry(j) + modelSecondDerivativesValues.getEntry(ih) * s.getEntry(i));
  2091.                     }
  2092.                     hs.setEntry(i, hs.getEntry(i) + modelSecondDerivativesValues.getEntry(ih) * s.getEntry(j));
  2093.                     ih++;
  2094.                 }
  2095.             }
  2096.             final RealVector tmp = interpolationPoints.operate(s).ebeMultiply(modelSecondDerivativesParameters);
  2097.             for (int k = 0; k < npt; k++) {
  2098.                 if (modelSecondDerivativesParameters.getEntry(k) != ZERO) {
  2099.                     for (int i = 0; i < n; i++) {
  2100.                         hs.setEntry(i, hs.getEntry(i) + tmp.getEntry(k) * interpolationPoints.getEntry(k, i));
  2101.                     }
  2102.                 }
  2103.             }
  2104.             if (crvmin != ZERO) {
  2105.                 state = 50; break;
  2106.             }
  2107.             if (iterc > itcsav) {
  2108.                 state = 150; break;
  2109.             }
  2110.             for (int i = 0; i < n; i++) {
  2111.                 hred.setEntry(i, hs.getEntry(i));
  2112.             }
  2113.             state = 120; break;
  2114.         }
  2115.         default: {
  2116.             throw new MathIllegalStateException(LocalizedFormats.SIMPLE_MESSAGE, "trsbox");
  2117.         }}
  2118.         }
  2119.     } // trsbox

  2120.     // ----------------------------------------------------------------------------------------

  2121.     /**
  2122.      *     The arrays BMAT and ZMAT are updated, as required by the new position
  2123.      *     of the interpolation point that has the index KNEW. The vector VLAG has
  2124.      *     N+NPT components, set on entry to the first NPT and last N components
  2125.      *     of the product Hw in equation (4.11) of the Powell (2006) paper on
  2126.      *     NEWUOA. Further, BETA is set on entry to the value of the parameter
  2127.      *     with that name, and DENOM is set to the denominator of the updating
  2128.      *     formula. Elements of ZMAT may be treated as zero if their moduli are
  2129.      *     at most ZTEST. The first NDIM elements of W are used for working space.
  2130.      * @param beta
  2131.      * @param denom
  2132.      * @param knew
  2133.      */
  2134.     private void update(
  2135.             double beta,
  2136.             double denom,
  2137.             int knew
  2138.     ) {
  2139.         printMethod(); // XXX

  2140.         final int n = currentBest.getDimension();
  2141.         final int npt = numberOfInterpolationPoints;
  2142.         final int nptm = npt - n - 1;

  2143.         // XXX Should probably be split into two arrays.
  2144.         final ArrayRealVector work = new ArrayRealVector(npt + n);

  2145.         double ztest = ZERO;
  2146.         for (int k = 0; k < npt; k++) {
  2147.             for (int j = 0; j < nptm; j++) {
  2148.                 // Computing MAX
  2149.                 ztest = JdkMath.max(ztest, JdkMath.abs(zMatrix.getEntry(k, j)));
  2150.             }
  2151.         }
  2152.         ztest *= 1e-20;

  2153.         // Apply the rotations that put zeros in the KNEW-th row of ZMAT.

  2154.         for (int j = 1; j < nptm; j++) {
  2155.             final double d1 = zMatrix.getEntry(knew, j);
  2156.             if (JdkMath.abs(d1) > ztest) {
  2157.                 // Computing 2nd power
  2158.                 final double d2 = zMatrix.getEntry(knew, 0);
  2159.                 // Computing 2nd power
  2160.                 final double d3 = zMatrix.getEntry(knew, j);
  2161.                 final double d4 = JdkMath.sqrt(d2 * d2 + d3 * d3);
  2162.                 final double d5 = zMatrix.getEntry(knew, 0) / d4;
  2163.                 final double d6 = zMatrix.getEntry(knew, j) / d4;
  2164.                 for (int i = 0; i < npt; i++) {
  2165.                     final double d7 = d5 * zMatrix.getEntry(i, 0) + d6 * zMatrix.getEntry(i, j);
  2166.                     zMatrix.setEntry(i, j, d5 * zMatrix.getEntry(i, j) - d6 * zMatrix.getEntry(i, 0));
  2167.                     zMatrix.setEntry(i, 0, d7);
  2168.                 }
  2169.             }
  2170.             zMatrix.setEntry(knew, j, ZERO);
  2171.         }

  2172.         // Put the first NPT components of the KNEW-th column of HLAG into W,
  2173.         // and calculate the parameters of the updating formula.

  2174.         for (int i = 0; i < npt; i++) {
  2175.             work.setEntry(i, zMatrix.getEntry(knew, 0) * zMatrix.getEntry(i, 0));
  2176.         }
  2177.         final double alpha = work.getEntry(knew);
  2178.         final double tau = lagrangeValuesAtNewPoint.getEntry(knew);
  2179.         lagrangeValuesAtNewPoint.setEntry(knew, lagrangeValuesAtNewPoint.getEntry(knew) - ONE);

  2180.         // Complete the updating of ZMAT.

  2181.         final double sqrtDenom = JdkMath.sqrt(denom);
  2182.         final double d1 = tau / sqrtDenom;
  2183.         final double d2 = zMatrix.getEntry(knew, 0) / sqrtDenom;
  2184.         for (int i = 0; i < npt; i++) {
  2185.             zMatrix.setEntry(i, 0,
  2186.                           d1 * zMatrix.getEntry(i, 0) - d2 * lagrangeValuesAtNewPoint.getEntry(i));
  2187.         }

  2188.         // Finally, update the matrix BMAT.

  2189.         for (int j = 0; j < n; j++) {
  2190.             final int jp = npt + j;
  2191.             work.setEntry(jp, bMatrix.getEntry(knew, j));
  2192.             final double d3 = (alpha * lagrangeValuesAtNewPoint.getEntry(jp) - tau * work.getEntry(jp)) / denom;
  2193.             final double d4 = (-beta * work.getEntry(jp) - tau * lagrangeValuesAtNewPoint.getEntry(jp)) / denom;
  2194.             for (int i = 0; i <= jp; i++) {
  2195.                 bMatrix.setEntry(i, j,
  2196.                               bMatrix.getEntry(i, j) + d3 * lagrangeValuesAtNewPoint.getEntry(i) + d4 * work.getEntry(i));
  2197.                 if (i >= npt) {
  2198.                     bMatrix.setEntry(jp, (i - npt), bMatrix.getEntry(i, j));
  2199.                 }
  2200.             }
  2201.         }
  2202.     } // update

  2203.     /**
  2204.      * Performs validity checks.
  2205.      *
  2206.      * @param lowerBound Lower bounds (constraints) of the objective variables.
  2207.      * @param upperBound Upperer bounds (constraints) of the objective variables.
  2208.      */
  2209.     private void setup(double[] lowerBound,
  2210.                        double[] upperBound) {
  2211.         printMethod(); // XXX

  2212.         double[] init = getStartPoint();
  2213.         final int dimension = init.length;

  2214.         // Check problem dimension.
  2215.         if (dimension < MINIMUM_PROBLEM_DIMENSION) {
  2216.             throw new NumberIsTooSmallException(dimension, MINIMUM_PROBLEM_DIMENSION, true);
  2217.         }
  2218.         // Check number of interpolation points.
  2219.         final int[] nPointsInterval = { dimension + 2, (dimension + 2) * (dimension + 1) / 2 };
  2220.         if (numberOfInterpolationPoints < nPointsInterval[0] ||
  2221.             numberOfInterpolationPoints > nPointsInterval[1]) {
  2222.             throw new OutOfRangeException(LocalizedFormats.NUMBER_OF_INTERPOLATION_POINTS,
  2223.                                           numberOfInterpolationPoints,
  2224.                                           nPointsInterval[0],
  2225.                                           nPointsInterval[1]);
  2226.         }

  2227.         // Initialize bound differences.
  2228.         boundDifference = new double[dimension];

  2229.         double requiredMinDiff = 2 * initialTrustRegionRadius;
  2230.         double minDiff = Double.POSITIVE_INFINITY;
  2231.         for (int i = 0; i < dimension; i++) {
  2232.             boundDifference[i] = upperBound[i] - lowerBound[i];
  2233.             minDiff = JdkMath.min(minDiff, boundDifference[i]);
  2234.         }
  2235.         if (minDiff < requiredMinDiff) {
  2236.             initialTrustRegionRadius = minDiff / 3.0;
  2237.         }

  2238.         // Initialize the data structures used by the "bobyqa" method.
  2239.         bMatrix = new Array2DRowRealMatrix(dimension + numberOfInterpolationPoints,
  2240.                                            dimension);
  2241.         zMatrix = new Array2DRowRealMatrix(numberOfInterpolationPoints,
  2242.                                            numberOfInterpolationPoints - dimension - 1);
  2243.         interpolationPoints = new Array2DRowRealMatrix(numberOfInterpolationPoints,
  2244.                                                        dimension);
  2245.         originShift = new ArrayRealVector(dimension);
  2246.         fAtInterpolationPoints = new ArrayRealVector(numberOfInterpolationPoints);
  2247.         trustRegionCenterOffset = new ArrayRealVector(dimension);
  2248.         gradientAtTrustRegionCenter = new ArrayRealVector(dimension);
  2249.         lowerDifference = new ArrayRealVector(dimension);
  2250.         upperDifference = new ArrayRealVector(dimension);
  2251.         modelSecondDerivativesParameters = new ArrayRealVector(numberOfInterpolationPoints);
  2252.         newPoint = new ArrayRealVector(dimension);
  2253.         alternativeNewPoint = new ArrayRealVector(dimension);
  2254.         trialStepPoint = new ArrayRealVector(dimension);
  2255.         lagrangeValuesAtNewPoint = new ArrayRealVector(dimension + numberOfInterpolationPoints);
  2256.         modelSecondDerivativesValues = new ArrayRealVector(dimension * (dimension + 1) / 2);
  2257.     }

  2258.     // XXX utility for figuring out call sequence.
  2259.     private static String caller(int n) {
  2260.         final Throwable t = new Throwable();
  2261.         final StackTraceElement[] elements = t.getStackTrace();
  2262.         final StackTraceElement e = elements[n];
  2263.         return e.getMethodName() + " (at line " + e.getLineNumber() + ")";
  2264.     }
  2265.     // XXX utility for figuring out call sequence.
  2266.     private static void printState(int s) {
  2267.         //        System.out.println(caller(2) + ": state " + s);
  2268.     }
  2269.     // XXX utility for figuring out call sequence.
  2270.     private static void printMethod() {
  2271.         //        System.out.println(caller(2));
  2272.     }

  2273.     /**
  2274.      * Marker for code paths that are not explored with the current unit tests.
  2275.      * If the path becomes explored, it should just be removed from the code.
  2276.      */
  2277.     private static final class PathIsExploredException extends RuntimeException {
  2278.         /** Serializable UID. */
  2279.         private static final long serialVersionUID = 745350979634801853L;

  2280.         /** Message string. */
  2281.         private static final String PATH_IS_EXPLORED
  2282.             = "If this exception is thrown, just remove it from the code";

  2283.         PathIsExploredException() {
  2284.             super(PATH_IS_EXPLORED + " " + BOBYQAOptimizer.caller(3));
  2285.         }
  2286.     }
  2287. }
  2288. //CHECKSTYLE: resume all