SQPOptimizerS.java

  1. /*
  2.  * Licensed to the Hipparchus project 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 Hipparchus project 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.  *      https://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. package org.hipparchus.optim.nonlinear.vector.constrained;

  18. import java.util.ArrayList;
  19. import java.util.Collections;

  20. import org.hipparchus.linear.Array2DRowRealMatrix;
  21. import org.hipparchus.linear.ArrayRealVector;
  22. import org.hipparchus.linear.EigenDecompositionSymmetric;
  23. import org.hipparchus.linear.MatrixUtils;
  24. import org.hipparchus.linear.RealMatrix;
  25. import org.hipparchus.linear.RealVector;
  26. import org.hipparchus.optim.nonlinear.scalar.ObjectiveFunction;
  27. import org.hipparchus.util.FastMath;

  28. /**
  29.  * Sequential Quadratic Programming Optimizer.
  30.  * <br/>
  31.  * min f(x)
  32.  * <br/>
  33.  * q(x)=b1
  34.  * <br/>
  35.  * h(x)>=b2
  36.  * <br/>
  37.  * Algorithm based on paper:"On the convergence of a sequential quadratic
  38.  * programming method(Klaus Shittkowki,January 1982)"
  39.  * @since 3.1
  40.  */
  41. public class SQPOptimizerS extends AbstractSQPOptimizer {

  42.     /** Forgetting factor. */
  43.     private static final int FORGETTING_FACTOR = 10;

  44.     /** Jacobian constraint. */
  45.     private RealMatrix constraintJacob;

  46.     /** Value of the equality constraint. */
  47.     private RealVector equalityEval;

  48.     /** Value of the inequality constraint. */
  49.     private RealVector inequalityEval;

  50.     /** Gradient of the objective function. */
  51.     private RealVector functionGradient;

  52.     /** Hessian of the objective function. */
  53.     private RealMatrix hessian;

  54.     /** {@inheritDoc} */
  55.     @Override
  56.     public LagrangeSolution doOptimize() {
  57.         int me = 0;
  58.         int mi = 0;

  59.         //EQUALITY CONSTRAINT
  60.         if (this.getEqConstraint() != null) {
  61.             me = getEqConstraint().dimY();
  62.         }
  63.         //INEQUALITY CONSTRAINT
  64.         if (this.getIqConstraint() != null) {
  65.             mi = getIqConstraint().dimY();
  66.         }

  67.         double alpha;
  68.         double rho = 100.0;
  69.         int failedSearch = 0;
  70.         RealVector x;
  71.         if (this.getStartPoint() != null) {
  72.             x = new ArrayRealVector(this.getStartPoint());
  73.         } else {
  74.             x = new ArrayRealVector(this.getObj().dim());
  75.         }

  76.         RealVector y = new ArrayRealVector(me + mi, 0.0);
  77.         RealVector r = new ArrayRealVector(me + mi, 1.0);
  78.         ArrayList<Double> oldPenalty = new ArrayList<>();
  79.         //INITIAL VALUES
  80.         double functionEval = this.getObj().value(x);
  81.         functionGradient = this.getObj().gradient(x);
  82.         double maxGrad = functionGradient.getLInfNorm();


  83.         if (this.getEqConstraint() != null) {

  84.             equalityEval = this.getEqConstraint().value(x);
  85.         }
  86.         if (this.getIqConstraint() != null) {

  87.             inequalityEval = this.getIqConstraint().value(x);
  88.         }
  89.         constraintJacob = computeJacobianConstraint(x);

  90.         if (this.getEqConstraint() != null) {
  91.             maxGrad = FastMath.max(maxGrad, equalityEval.getLInfNorm());
  92.         }
  93.         if (this.getIqConstraint() != null) {
  94.             maxGrad = FastMath.max(maxGrad, inequalityEval.getLInfNorm());
  95.         }

  96.         if (!getSettings().useFunHessian()) {
  97.             hessian = MatrixUtils.createRealIdentityMatrix(x.getDimension());
  98.         } else {
  99.             hessian = this.getObj().hessian(x);
  100.         }

  101.         for (int i = 0; i < this.getMaxIterations(); i++) {
  102.             iterations.increment();

  103.             alpha = 1.0;
  104.             LagrangeSolution sol1 = null;

  105.             int qpLoop = 0;
  106.             double sigma = maxGrad;
  107.             double currentPenaltyGrad;

  108.             //LOOP TO FIND SOLUTION WITH SIGMA<SIGMA THRESHOLD
  109.             while (sigma > getSettings().getSigmaMax() && qpLoop < getSettings().getQpMaxLoop()) {
  110.                 sol1 = solveQP(x, y, rho);
  111.                 sigma = sol1.getValue();

  112.                 if (sigma > getSettings().getSigmaMax()) {
  113.                     rho = getSettings().getRhoCons() * rho;
  114.                     qpLoop += 1;

  115.                 }

  116.             }
  117.             //IF SIGMA>SIGMA THRESHOLD ASSIGN DIRECTION FROM PENALTY GRADIENT
  118.             final RealVector dx;
  119.             final RealVector dy;
  120.             if (qpLoop == getSettings().getQpMaxLoop()) {

  121.                 dx = (MatrixUtils.inverse(hessian).operate(penaltyFunctionGradX(functionGradient, x, y, r))).mapMultiply(-1.0);
  122.                 dy = y.subtract(penaltyFunctionGradY(x, y, r));
  123.                 sigma = 0;

  124.             } else {
  125.                 dx = sol1.getX();
  126.                 sigma = sol1.getValue();
  127.                 if (sigma < 0) {
  128.                     sigma = 0;
  129.                 }
  130.                 dy = sol1.getLambda();
  131.                 r = updateRj(hessian, y, dx, dy, r, sigma);
  132.             }

  133.             currentPenaltyGrad = penaltyFunctionGrad(functionGradient, dx, dy, x, y, r);
  134.             int search = 0;

  135.             rho = updateRho(dx, dy, hessian, constraintJacob, sigma);

  136.             double currentPenalty = penaltyFunction(functionEval, 0, x, y, dx, dy.subtract(y), r);

  137.             double alphaF = this.getObj().value(x.add(dx.mapMultiply(alpha)));
  138.             double alfaPenalty = penaltyFunction(alphaF, alpha, x, y, dx, dy.subtract(y), r);


  139.             //LINE SEARCH

  140.             while ((alfaPenalty - currentPenalty) >= getSettings().getMu() * alpha * currentPenaltyGrad &&
  141.                     search < getSettings().getMaxLineSearchIteration()) {
  142.                 double alfaStar = -0.5 * alpha * alpha * currentPenaltyGrad / (-alpha * currentPenaltyGrad + alfaPenalty - currentPenalty);


  143.                 alpha = FastMath.max(getSettings().getB() * alpha, FastMath.min(1.0, alfaStar));
  144.                 alphaF = this.getObj().value(x.add(dx.mapMultiply(alpha)));
  145.                 alfaPenalty = penaltyFunction(alphaF, alpha, x, y, dx, dy.subtract(y), r);
  146.                 search = search + 1;

  147.             }



  148.             if (getSettings().getConvCriteria() == 0) {
  149.                 if (dx.mapMultiply(alpha).dotProduct(hessian.operate(dx.mapMultiply(alpha))) < getSettings().getEps() * getSettings().getEps()) {
  150. //                    x = x.add(dx.mapMultiply(alfa));
  151. //                    y = y.add((dy.subtract(y)).mapMultiply(alfa));
  152.                     break;
  153.                 }
  154.             } else {
  155.                 if (alpha * dx.getNorm() < getSettings().getEps() * (1 + x.getNorm())) {
  156. //                    x = x.add(dx.mapMultiply(alfa));
  157. //                    y = y.add((dy.subtract(y)).mapMultiply(alfa));
  158.                     break;
  159.                 }

  160.             }

  161.             if (search == getSettings().getMaxLineSearchIteration()) {
  162.                 failedSearch += 1;
  163.             }

  164.             boolean notMonotone = false;
  165.             if (search == getSettings().getMaxLineSearchIteration()) {

  166.                 alpha = 1.0;
  167.                 search = 0;
  168.                 Double max = Collections.max(oldPenalty);
  169.                 if (oldPenalty.size() == 1) {
  170.                     max = max * 1.3;
  171.                 }
  172.                 while ((alfaPenalty - max) >= getSettings().getMu() * alpha * currentPenaltyGrad &&
  173.                        search < getSettings().getMaxLineSearchIteration()) {

  174.                     double alfaStar = -0.5 * alpha * alpha * currentPenaltyGrad / (-alpha * currentPenaltyGrad + alfaPenalty - currentPenalty);


  175.                     alpha = FastMath.max(getSettings().getB() * alpha, FastMath.min(1.0, alfaStar));
  176.                     // alfa = FastMath.min(1.0, FastMath.max(this.b * alfa, alfaStar));
  177.                     // alfa = FastMath.max(this.b * alfa, alfaStar);
  178.                     alphaF = this.getObj().value(x.add(dx.mapMultiply(alpha)));
  179.                     alfaPenalty = penaltyFunction(alphaF, alpha, x, y, dx, dy.subtract(y), r);
  180.                     search = search + 1;

  181.                 }
  182.                 notMonotone = true;
  183.                 // if (search < maxLineSearchIteration) failedSearch = 0;
  184.             }

  185.             //UPDATE ALL FUNCTION
  186.             RealVector oldGradient = functionGradient;
  187.             RealMatrix oldJacob = constraintJacob;
  188.             // RealVector old1 = penaltyFunctionGradX(oldGradient,x, y.add((dy.subtract(y)).mapMultiply(alfa)),r);
  189.             RealVector old1 = lagrangianGradX(oldGradient, oldJacob, x, y.add((dy.subtract(y)).mapMultiply(alpha)));
  190.             functionEval = alphaF;
  191.             functionGradient = this.getObj().gradient(x.add(dx.mapMultiply(alpha)));
  192.             if (this.getEqConstraint() != null) {

  193.                 equalityEval = this.getEqConstraint().value(x.add(dx.mapMultiply(alpha)));
  194.             }
  195.             if (this.getIqConstraint() != null) {

  196.                 inequalityEval = this.getIqConstraint().value(x.add(dx.mapMultiply(alpha)));
  197.             }

  198.             constraintJacob = computeJacobianConstraint(x.add(dx.mapMultiply(alpha)));
  199.             // RealVector new1 = penaltyFunctionGradX(functionGradient,x.add(dx.mapMultiply(alfa)), y.add((dy.subtract(y)).mapMultiply(alfa)),r);
  200.             RealVector new1 = lagrangianGradX(functionGradient, constraintJacob, x.add(dx.mapMultiply(alpha)), y.add((dy.subtract(y)).mapMultiply(alpha)));

  201.             if (failedSearch == 2) {
  202.                 hessian = MatrixUtils.createRealIdentityMatrix(x.getDimension());
  203.                 failedSearch = 0;
  204.             }

  205.             if (!notMonotone) {
  206. //                if (iterations.getCount()==1)
  207. //                {
  208. //                    RealVector yfirst = new1.subtract(old1);
  209. //                    RealVector sfirst = dx.mapMultiply(alfa);
  210. //                    double scaleFactor = yfirst.dotProduct(sfirst)/yfirst.dotProduct(yfirst);
  211. //                    hessian = hessian.scalarMultiply(scaleFactor);
  212. //                }
  213.                 hessian = BFGSFormula(hessian, dx, alpha, new1, old1);
  214.             }

  215.             //STORE PENALTY IN QUEQUE TO PERFORM NOT MONOTONE LINE SEARCH IF NECESSARY
  216.             // oldPenalty.add(alfaPenalty);
  217.             oldPenalty.add(currentPenalty);
  218.             if (oldPenalty.size() > FORGETTING_FACTOR) {
  219.                 oldPenalty.remove(0);
  220.             }

  221.             x = x.add(dx.mapMultiply(alpha));
  222.             y = y.add((dy.subtract(y)).mapMultiply(alpha));
  223.         }

  224.         return new LagrangeSolution(x, y, functionEval);
  225.     }

  226.     private double penaltyFunction(double currentF, double alfa, RealVector x, RealVector y, RealVector dx, RealVector uv, RealVector r) {
  227.         // the set of constraints is the same as the previous one but they must be evaluated with the increment

  228.         int me = 0;
  229.         int mi;
  230.         double partial = currentF;
  231.         RealVector yalfa = y.add(uv.mapMultiply(alfa));
  232.         if (getEqConstraint() != null) {
  233.             me = getEqConstraint().dimY();
  234.             RealVector re = r.getSubVector(0, me);
  235.             RealVector ye = yalfa.getSubVector(0, me);
  236.             RealVector g = this.getEqConstraint().value(x.add(dx.mapMultiply(alfa))).subtract(getEqConstraint().getLowerBound());
  237.             RealVector g2 = g.ebeMultiply(g);
  238.             partial -= ye.dotProduct(g) - 0.5 * re.dotProduct(g2);
  239.         }

  240.         if (getIqConstraint() != null) {
  241.             mi = getIqConstraint().dimY();
  242.             RealVector ri = r.getSubVector(me, mi);
  243.             RealVector yi = yalfa.getSubVector(me, mi);
  244.             RealVector yk = y.getSubVector(me, mi);
  245.             RealVector gk = this.inequalityEval.subtract(getIqConstraint().getLowerBound());
  246.             RealVector g = this.getIqConstraint().value(x.add(dx.mapMultiply(alfa))).subtract(getIqConstraint().getLowerBound());
  247.             RealVector mask = new ArrayRealVector(g.getDimension(), 1.0);

  248.             for (int i = 0; i < gk.getDimension(); i++) {

  249.                 if (gk.getEntry(i) > (yk.getEntry(i) / ri.getEntry(i))) {

  250.                     mask.setEntry(i, 0.0);

  251.                     partial -= 0.5 * yi.getEntry(i) * yi.getEntry(i) / ri.getEntry(i);
  252.                 }

  253.             }

  254.             RealVector g2 = g.ebeMultiply(g.ebeMultiply(mask));
  255.             partial -= yi.dotProduct(g.ebeMultiply(mask)) - 0.5 * ri.dotProduct(g2);

  256.         }

  257.         return partial;
  258.     }

  259.     private double penaltyFunctionGrad(RealVector currentGrad, RealVector dx, RealVector dy, RealVector x, RealVector y, RealVector r) {

  260.         int me = 0;
  261.         int mi;
  262.         double partial = currentGrad.dotProduct(dx);
  263.         if (getEqConstraint() != null) {
  264.             me = getEqConstraint().dimY();
  265.             RealVector re = r.getSubVector(0, me);
  266.             RealVector ye = y.getSubVector(0, me);
  267.             RealVector dye = dy.getSubVector(0, me);
  268.             RealVector ge = this.getEqConstraint().value(x).subtract(getEqConstraint().getLowerBound());
  269.             RealMatrix jacob = this.getEqConstraint().jacobian(x);
  270.             RealVector firstTerm = jacob.transpose().operate(ye);
  271.             RealVector secondTerm = jacob.transpose().operate(ge.ebeMultiply(re));
  272. //partial -= firstTerm.dotProduct(dx) - secondTerm.dotProduct(dx) + g.dotProduct(dye);
  273.             partial += -firstTerm.dotProduct(dx) + secondTerm.dotProduct(dx) - ge.dotProduct(dye.subtract(ye));
  274.         }

  275.         if (getIqConstraint() != null) {
  276.             mi = getIqConstraint().dimY();

  277.             RealVector ri = r.getSubVector(me, mi);
  278.             RealVector dyi = dy.getSubVector(me, mi);
  279.             RealVector yi = y.getSubVector(me, mi);

  280.             RealVector gi = this.getIqConstraint().value(x).subtract(getIqConstraint().getLowerBound());
  281.             RealMatrix jacob = this.getIqConstraint().jacobian(x);

  282.             RealVector mask = new ArrayRealVector(mi, 1.0);
  283.             RealVector viri = new ArrayRealVector(mi, 0.0);

  284.             for (int i = 0; i < gi.getDimension(); i++) {

  285.                 if (gi.getEntry(i) > yi.getEntry(i) / ri.getEntry(i)) {
  286.                     mask.setEntry(i, 0.0);

  287.                 } else {
  288.                     viri.setEntry(i, yi.getEntry(i) / ri.getEntry(i));
  289.                 }

  290.             }
  291.             RealVector firstTerm = jacob.transpose().operate(yi.ebeMultiply(mask));
  292.             RealVector secondTerm = jacob.transpose().operate(gi.ebeMultiply(ri.ebeMultiply(mask)));

  293.             partial -= firstTerm.dotProduct(dx) - secondTerm.dotProduct(dx) + (gi.ebeMultiply(mask)).dotProduct(dyi.subtract(yi)) + viri.dotProduct(dyi.subtract(yi));
  294.             // partial -= firstTerm.dotProduct(dx) - secondTerm.dotProduct(dx) + g.dotProduct(dyi.ebeMultiply(mask));
  295.         }

  296.         return partial;
  297.     }

  298.     private RealVector penaltyFunctionGradX(RealVector currentGrad, RealVector x, RealVector y, RealVector r) {

  299.         int me = 0;
  300.         int mi;
  301.         RealVector partial = currentGrad.copy();
  302.         if (getEqConstraint() != null) {
  303.             me = getEqConstraint().dimY();
  304.             RealVector re = r.getSubVector(0, me);
  305.             RealVector ye = y.getSubVector(0, me);

  306.             RealVector ge = this.getEqConstraint().value(x).subtract(getEqConstraint().getLowerBound());
  307.             RealMatrix jacob = this.getEqConstraint().jacobian(x);

  308.             RealVector firstTerm = jacob.transpose().operate(ye);
  309.             RealVector secondTerm = jacob.transpose().operate(ge.ebeMultiply(re));

  310.             partial = partial.subtract(firstTerm.subtract(secondTerm));
  311.         }

  312.         if (getIqConstraint() != null) {
  313.             mi = getIqConstraint().dimY();

  314.             RealVector ri = r.getSubVector(me, mi);

  315.             RealVector yi = y.getSubVector(me, mi);
  316.             RealVector gi = this.getIqConstraint().value(x).subtract(getIqConstraint().getLowerBound());
  317.             RealMatrix jacob = this.getIqConstraint().jacobian(x);

  318.             RealVector mask = new ArrayRealVector(mi, 1.0);

  319.             for (int i = 0; i < gi.getDimension(); i++) {

  320.                 if (gi.getEntry(i) > yi.getEntry(i) / ri.getEntry(i)) {
  321.                     mask.setEntry(i, 0.0);

  322.                 }

  323.             }
  324.             RealVector firstTerm = jacob.transpose().operate(yi.ebeMultiply(mask));
  325.             RealVector secondTerm = jacob.transpose().operate(gi.ebeMultiply(ri.ebeMultiply(mask)));
  326.             partial = partial.subtract(firstTerm.subtract(secondTerm));
  327.         }

  328.         return partial;
  329.     }

  330.     private RealVector penaltyFunctionGradY(RealVector x, RealVector y, RealVector r) {

  331.         int me = 0;
  332.         int mi;
  333.         RealVector partial = new ArrayRealVector(y.getDimension());
  334.         if (getEqConstraint() != null) {
  335.             me = getEqConstraint().dimY();
  336.             RealVector g = this.getEqConstraint().value(x).subtract(getEqConstraint().getLowerBound());
  337.             partial.setSubVector(0, g.mapMultiply(-1.0));
  338.         }

  339.         if (getIqConstraint() != null) {
  340.             mi = getIqConstraint().dimY();

  341.             RealVector ri = r.getSubVector(me, mi);

  342.             RealVector yi = y.getSubVector(me, mi);
  343.             RealVector gi = this.getIqConstraint().value(x).subtract(getIqConstraint().getLowerBound());

  344.             RealVector mask = new ArrayRealVector(mi, 1.0);

  345.             RealVector viri = new ArrayRealVector(mi, 0.0);

  346.             for (int i = 0; i < gi.getDimension(); i++) {

  347.                 if (gi.getEntry(i) > yi.getEntry(i) / ri.getEntry(i)) {
  348.                     mask.setEntry(i, 0.0);

  349.                 } else {
  350.                     viri.setEntry(i, yi.getEntry(i) / ri.getEntry(i));
  351.                 }

  352.             }

  353.             partial.setSubVector(me, gi.ebeMultiply(mask).add(viri).mapMultiply(-1.0));
  354.         }

  355.         return partial;
  356.     }

  357.     private RealVector updateRj(RealMatrix H, RealVector y, RealVector dx, RealVector dy, RealVector r, double additional) { //r = updateRj(currentH,dx,y,u,r,sigm);
  358.         //CALCULATE SIGMA VECTOR THAT DEPEND FROM ITERATION
  359.         RealVector sigma = new ArrayRealVector(r.getDimension());
  360.         for (int i = 0; i < sigma.getDimension(); i++) {
  361.             final double appoggio = iterations.getCount() / FastMath.sqrt(r.getEntry(i));
  362.             sigma.setEntry(i, FastMath.min(1.0, appoggio));
  363.         }

  364.         int me = 0;
  365.         int mi = 0;
  366.         if (getEqConstraint() != null) {
  367.             me = getEqConstraint().dimY();
  368.         }
  369.         if (getIqConstraint() != null) {
  370.             mi = getIqConstraint().dimY();
  371.         }

  372.         RealVector sigmar = sigma.ebeMultiply(r);
  373.         //(u-v)^2 or (ru-v)
  374.         RealVector numerator = ((dy.subtract(y)).ebeMultiply(dy.subtract(y))).mapMultiply(2.0 * (mi + me));

  375.         double denominator = dx.dotProduct(H.operate(dx)) * (1.0 - additional);
  376.         RealVector r1 = r.copy();
  377.         if (getEqConstraint() != null) {
  378.             for (int i = 0; i < me; i++) {
  379.                 r1.setEntry(i, FastMath.max(sigmar.getEntry(i), numerator.getEntry(i) / denominator));
  380.             }
  381.         }
  382.         if (getIqConstraint() != null) {
  383.             for (int i = 0; i < mi; i++) {
  384.                 r1.setEntry(me + i, FastMath.max(sigmar.getEntry(me + i), numerator.getEntry(me + i) / denominator));
  385.             }
  386.         }


  387.         return r1;
  388.     }

  389.     private double updateRho(RealVector dx, RealVector dy, RealMatrix H, RealMatrix jacobianG, double additionalVariable) {

  390.         double num = 10.0 * FastMath.pow(dx.dotProduct(jacobianG.transpose().operate(dy)), 2);
  391.         double den = (1.0 - additionalVariable) * (1.0 - additionalVariable) * dx.dotProduct(H.operate(dx));
  392.         //double den = (1.0 - additionalVariable) * dx.dotProduct(H.operate(dx));

  393.         return FastMath.max(10.0, num / den);
  394.     }

  395.     private LagrangeSolution solveQP(RealVector x, RealVector y, double rho) {

  396.         RealMatrix H = hessian;
  397.         RealVector g = functionGradient;

  398.         int me = 0;
  399.         int mi = 0;
  400.         int add = 0;
  401.         boolean violated = false;
  402.         if (getEqConstraint() != null) {
  403.             me = getEqConstraint().dimY();
  404.         }
  405.         if (getIqConstraint() != null) {

  406.             mi = getIqConstraint().dimY();
  407.             violated = inequalityEval.subtract(getIqConstraint().getLowerBound()).getMinValue() <= getSettings().getEps() ||
  408.                        y.getMaxValue() >= 0;

  409.         }
  410.         // violated = true;
  411.         if (me > 0 || violated) {
  412.             add = 1;

  413.         }

  414.         RealMatrix H1 = new Array2DRowRealMatrix(H.getRowDimension() + add, H.getRowDimension() + add);
  415.         H1.setSubMatrix(H.getData(), 0, 0);
  416.         if (add == 1) {
  417.             H1.setEntry(H.getRowDimension(), H.getRowDimension(), rho);
  418.         }

  419.         RealVector g1 = new ArrayRealVector(g.getDimension() + add);
  420.         g1.setSubVector(0, g);

  421.         LinearEqualityConstraint eqc = null;
  422.         RealVector conditioneq;
  423.         if (getEqConstraint() != null) {
  424.             RealMatrix eqJacob = constraintJacob.getSubMatrix(0, me - 1, 0, x.getDimension() - 1);

  425.             RealMatrix Ae = new Array2DRowRealMatrix(me, x.getDimension() + add);
  426.             RealVector be = new ArrayRealVector(me);
  427.             Ae.setSubMatrix(eqJacob.getData(), 0, 0);
  428.             conditioneq = this.equalityEval.subtract(getEqConstraint().getLowerBound());
  429.             Ae.setColumnVector(x.getDimension(), conditioneq.mapMultiply(-1.0));

  430.             be.setSubVector(0, getEqConstraint().getLowerBound().subtract(this.equalityEval));
  431.             eqc = new LinearEqualityConstraint(Ae, be);

  432.         }
  433.         LinearInequalityConstraint iqc = null;

  434.         if (getIqConstraint() != null) {
  435. //
  436.             RealMatrix iqJacob = constraintJacob.getSubMatrix(me, me + mi - 1, 0, x.getDimension() - 1);

  437.             RealMatrix Ai = new Array2DRowRealMatrix(mi, x.getDimension() + add);
  438.             RealVector bi = new ArrayRealVector(mi);
  439.             Ai.setSubMatrix(iqJacob.getData(), 0, 0);

  440.             RealVector conditioniq = this.inequalityEval.subtract(getIqConstraint().getLowerBound());

  441.             if (add == 1) {

  442.                 for (int i = 0; i < conditioniq.getDimension(); i++) {

  443.                     if (!(conditioniq.getEntry(i) <= getSettings().getEps() || y.getEntry(me + i) > 0)) {
  444.                         conditioniq.setEntry(i, 0);
  445.                     }
  446.                 }

  447.                 Ai.setColumnVector(x.getDimension(), conditioniq.mapMultiply(-1.0));

  448.             }
  449.             bi.setSubVector(0, getIqConstraint().getLowerBound().subtract(this.inequalityEval));
  450.             iqc = new LinearInequalityConstraint(Ai, bi);

  451.         }
  452.         LinearBoundedConstraint bc = null;
  453.         if (add == 1) {

  454.             RealMatrix sigmaA = new Array2DRowRealMatrix(1, x.getDimension() + 1);
  455.             sigmaA.setEntry(0, x.getDimension(), 1.0);
  456.             ArrayRealVector lb = new ArrayRealVector(1, 0.0);
  457.             ArrayRealVector ub = new ArrayRealVector(1, 1.0);

  458.             bc = new LinearBoundedConstraint(sigmaA, lb, ub);

  459.         }

  460.         QuadraticFunction q = new QuadraticFunction(H1, g1, 0);

  461.         ADMMQPOptimizer solver = new ADMMQPOptimizer();
  462.         LagrangeSolution sol = solver.optimize(new ObjectiveFunction(q), iqc, eqc, bc);

  463.         final double sigma;
  464.         if (add == 1) {
  465.             sigma = sol.getX().getEntry(x.getDimension());
  466.         } else {
  467.             sigma = 0;
  468.         }

  469.         return new LagrangeSolution(sol.getX().getSubVector(0, x.getDimension()),
  470.                                     sol.getLambda().getSubVector(0, me + mi),
  471.                                     sigma);

  472.     }

  473.     private RealMatrix computeJacobianConstraint(RealVector x) {
  474.         int me = 0;
  475.         int mi = 0;
  476.         RealMatrix je = null;
  477.         RealMatrix ji = null;
  478.         if (this.getEqConstraint() != null) {
  479.             me = this.getEqConstraint().dimY();
  480.             je = this.getEqConstraint().jacobian(x);
  481.         }

  482.         if (this.getIqConstraint() != null) {
  483.             mi = this.getIqConstraint().dimY();
  484.             ji = this.getIqConstraint().jacobian(x);
  485.         }

  486.         RealMatrix jacobian = new Array2DRowRealMatrix(me + mi, x.getDimension());
  487.         if (me > 0) {
  488.             jacobian.setSubMatrix(je.getData(), 0, 0);
  489.         }
  490.         if (mi > 0) {
  491.             jacobian.setSubMatrix(ji.getData(), me, 0);
  492.         }

  493.         return jacobian;
  494.     }
  495.     /*
  496.      *DAMPED BFGS FORMULA
  497.      */

  498.     private RealMatrix BFGSFormula(RealMatrix oldH, RealVector dx, double alfa, RealVector newGrad, RealVector oldGrad) {

  499.         RealMatrix oldH1 = oldH.copy();
  500.         RealVector y1 = newGrad.subtract(oldGrad);
  501.         RealVector s = dx.mapMultiply(alfa);
  502.         double theta = 1.0;
  503.         if (s.dotProduct(y1) < 0.2 * s.dotProduct(oldH.operate(s))) {
  504.             theta = 0.8 * s.dotProduct(oldH.operate(s)) / (s.dotProduct(oldH.operate(s)) - s.dotProduct(y1));
  505.         }

  506.         RealVector y = y1.mapMultiply(theta).add((oldH.operate(s)).mapMultiply(1.0 - theta));

  507.         RealMatrix firstTerm = y.outerProduct(y).scalarMultiply(1.0 / s.dotProduct(y));
  508.         RealMatrix secondTerm = oldH1.multiply(s.outerProduct(s)).multiply(oldH);
  509.         double thirtTerm = s.dotProduct(oldH1.operate(s));
  510.         RealMatrix Hnew = oldH1.add(firstTerm).subtract(secondTerm.scalarMultiply(1.0 / thirtTerm));
  511.         //RESET HESSIAN IF NOT POSITIVE DEFINITE
  512.         EigenDecompositionSymmetric dsX = new EigenDecompositionSymmetric(Hnew);
  513.         double min = new ArrayRealVector(dsX.getEigenvalues()).getMinValue();
  514.         if (min < 0) {
  515.             Hnew = MatrixUtils.createRealIdentityMatrix(oldH.getRowDimension());
  516.         }
  517.         return Hnew;

  518.     }

  519. }