/** {@inheritDoc} */ @Override public RealPointValuePair doOptimize() throws OptimizationException { final SimplexTableau tableau = new SimplexTableau(function, linearConstraints, goal, nonNegative, epsilon); solvePhase1(tableau); tableau.dropPhase1Objective(); while (!tableau.isOptimal()) { doIteration(tableau); } return tableau.getSolution(); }
/** Simple constructor with default settings. * <p>The maximal number of evaluation is set to its default value.</p> */ protected AbstractLinearOptimizer() { setMaxIterations(DEFAULT_MAX_ITERATIONS); }
/** * Get the offset of the first artificial variable. * @return offset of the first artificial variable */ protected final int getArtificialVariableOffset() { return getNumObjectiveFunctions() + numDecisionVariables + numSlackVariables; }
/** * Runs one iteration of the Simplex method on the given model. * @param tableau simple tableau for the problem * @throws OptimizationException if the maximal iteration count has been * exceeded or if the model is found not to have a bounded solution */ protected void doIteration(final SimplexTableau tableau) throws OptimizationException { incrementIterationsCounter(); Integer pivotCol = getPivotColumn(tableau); Integer pivotRow = getPivotRow(tableau, pivotCol); if (pivotRow == null) { throw new UnboundedSolutionException(); } // set the pivot element to 1 double pivotVal = tableau.getEntry(pivotRow, pivotCol); tableau.divideRow(pivotRow, pivotVal); // set the rest of the pivot column to 0 for (int i = 0; i < tableau.getHeight(); i++) { if (i != pivotRow) { double multiplier = tableau.getEntry(i, pivotCol); tableau.subtractRow(i, pivotRow, multiplier); } } }
/** * Get a new equation equivalent to this one with a positive right hand side. * @param constraint reference constraint * @return new equation */ private LinearConstraint normalize(final LinearConstraint constraint) { if (constraint.getValue() < 0) { return new LinearConstraint(constraint.getCoefficients().mapMultiply(-1), constraint.getRelationship().oppositeRelationship(), -1 * constraint.getValue()); } return new LinearConstraint(constraint.getCoefficients(), constraint.getRelationship(), constraint.getValue()); }
/** * Solves Phase 1 of the Simplex method. * @param tableau simple tableau for the problem * @exception OptimizationException if the maximal number of iterations is * exceeded, or if the problem is found not to have a bounded solution, or * if there is no feasible solution */ protected void solvePhase1(final SimplexTableau tableau) throws OptimizationException { // make sure we're in Phase 1 if (tableau.getNumArtificialVariables() == 0) { return; } while (!tableau.isOptimal()) { doIteration(tableau); } // if W is not zero then we have no feasible solution if (!MathUtils.equals(tableau.getEntry(0, tableau.getRhsOffset()), 0, epsilon)) { throw new NoFeasibleSolutionException(); } }
/** * Get the offset of the right hand side. * @return offset of the right hand side */ protected final int getRhsOffset() { return getWidth() - 1; }
/** * Get a count of constraints corresponding to a specified relationship. * @param relationship relationship to count * @return number of constraint with the specified relationship */ private int getConstraintTypeCounts(final Relationship relationship) { int count = 0; for (final LinearConstraint constraint : constraints) { if (constraint.getRelationship() == relationship) { ++count; } } return count; }
/** {@inheritDoc} */ public RealPointValuePair optimize(final LinearObjectiveFunction f, final Collection<LinearConstraint> constraints, final GoalType goalType, final boolean restrictToNonNegative) throws OptimizationException { // store linear problem characteristics this.function = f; this.linearConstraints = constraints; this.goal = goalType; this.nonNegative = restrictToNonNegative; iterations = 0; // solve the problem return doOptimize(); }
/** * Get the original number of decision variables. * @return original number of decision variables * @see #getNumDecisionVariables() */ protected final int getOriginalNumDecisionVariables() { return f.getCoefficients().getDimension(); }
/** {@inheritDoc} */ @Override public RealPointValuePair doOptimize() throws OptimizationException { final SimplexTableau tableau = new SimplexTableau(function, linearConstraints, goal, nonNegative, epsilon); solvePhase1(tableau); tableau.dropPhase1Objective(); while (!tableau.isOptimal()) { doIteration(tableau); } return tableau.getSolution(); }
/** * Get a new equation equivalent to this one with a positive right hand side. * @param constraint reference constraint * @return new equation */ private LinearConstraint normalize(final LinearConstraint constraint) { if (constraint.getValue() < 0) { return new LinearConstraint(constraint.getCoefficients().mapMultiply(-1), constraint.getRelationship().oppositeRelationship(), -1 * constraint.getValue()); } return new LinearConstraint(constraint.getCoefficients(), constraint.getRelationship(), constraint.getValue()); }
/** * Get the offset of the first slack variable. * @return offset of the first slack variable */ protected final int getSlackVariableOffset() { return getNumObjectiveFunctions() + numDecisionVariables; }
/** Simple constructor with default settings. * <p>The maximal number of evaluation is set to its default value.</p> */ protected AbstractLinearOptimizer() { setMaxIterations(DEFAULT_MAX_ITERATIONS); }
/** * Get the offset of the right hand side. * @return offset of the right hand side */ protected final int getRhsOffset() { return getWidth() - 1; }
/** * Get a count of constraints corresponding to a specified relationship. * @param relationship relationship to count * @return number of constraint with the specified relationship */ private int getConstraintTypeCounts(final Relationship relationship) { int count = 0; for (final LinearConstraint constraint : constraints) { if (constraint.getRelationship() == relationship) { ++count; } } return count; }
/** {@inheritDoc} */ public RealPointValuePair optimize(final LinearObjectiveFunction f, final Collection<LinearConstraint> constraints, final GoalType goalType, final boolean restrictToNonNegative) throws OptimizationException { // store linear problem characteristics this.function = f; this.linearConstraints = constraints; this.goal = goalType; this.nonNegative = restrictToNonNegative; iterations = 0; // solve the problem return doOptimize(); }
/** * Get the offset of the first slack variable. * @return offset of the first slack variable */ protected final int getSlackVariableOffset() { return getNumObjectiveFunctions() + numDecisionVariables; }
/** * Get the offset of the first artificial variable. * @return offset of the first artificial variable */ protected final int getArtificialVariableOffset() { return getNumObjectiveFunctions() + numDecisionVariables + numSlackVariables; }
/** * @param src the source array * @param dest the destination array */ private void copyArray(final double[] src, final double[] dest) { System.arraycopy(src, 0, dest, getNumObjectiveFunctions(), src.length); }