fixed an error leading the simplex solver to compute the right solution but return another one

JIRA: MATH-286

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@806753 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2009-08-21 23:07:42 +00:00
parent 3f9613be38
commit dbdff0758b
3 changed files with 61 additions and 20 deletions

View File

@ -270,8 +270,27 @@ class SimplexTableau implements Serializable {
* @return the row that the variable is basic in. null if the column is not basic
*/
private Integer getBasicRow(final int col) {
return getBasicRow(col, true);
}
/**
* Checks whether the given column is basic.
* @param col index of the column to check
* @return the row that the variable is basic in. null if the column is not basic
*/
private Integer getBasicRowForSolution(final int col) {
return getBasicRow(col, false);
}
/**
* Checks whether the given column is basic.
* @param col index of the column to check
* @return the row that the variable is basic in. null if the column is not basic
*/
private Integer getBasicRow(final int col, boolean ignoreObjectiveRows) {
Integer row = null;
for (int i = getNumObjectiveFunctions(); i < getHeight(); i++) {
int start = ignoreObjectiveRows ? getNumObjectiveFunctions() : 0;
for (int i = start; i < getHeight(); i++) {
if (MathUtils.equals(getEntry(i, col), 1.0, epsilon) && (row == null)) {
row = i;
} else if (!MathUtils.equals(getEntry(i, col), 0.0, epsilon)) {
@ -318,24 +337,23 @@ class SimplexTableau implements Serializable {
* @return current solution
*/
protected RealPointValuePair getSolution() {
double[] coefficients = new double[getOriginalNumDecisionVariables()];
Integer basicRow =
getBasicRow(getNumObjectiveFunctions() + getOriginalNumDecisionVariables());
double mostNegative = basicRow == null ? 0 : getEntry(basicRow, getRhsOffset());
Set<Integer> basicRows = new HashSet<Integer>();
for (int i = 0; i < coefficients.length; i++) {
basicRow = getBasicRow(getNumObjectiveFunctions() + i);
if (basicRows.contains(basicRow)) {
// if multiple variables can take a given value
// then we choose the first and set the rest equal to 0
coefficients[i] = 0;
} else {
basicRows.add(basicRow);
coefficients[i] =
(basicRow == null ? 0 : getEntry(basicRow, getRhsOffset())) -
(restrictToNonNegative ? 0 : mostNegative);
}
}
double[] coefficients = new double[getOriginalNumDecisionVariables()];
Integer negativeVarBasicRow = getBasicRowForSolution(getNegativeDecisionVariableOffset());
double mostNegative = negativeVarBasicRow == null ? 0 : getEntry(negativeVarBasicRow, getRhsOffset());
Set<Integer> basicRows = new HashSet<Integer>();
for (int i = 0; i < coefficients.length; i++) {
Integer basicRow = getBasicRowForSolution(getNumObjectiveFunctions() + i);
if (basicRows.contains(basicRow)) {
// if multiple variables can take a given value
// then we choose the first and set the rest equal to 0
coefficients[i] = 0;
} else {
basicRows.add(basicRow);
coefficients[i] =
(basicRow == null ? 0 : getEntry(basicRow, getRhsOffset())) -
(restrictToNonNegative ? 0 : mostNegative);
}
}
return new RealPointValuePair(coefficients, f.getValue(coefficients));
}
@ -430,6 +448,15 @@ class SimplexTableau implements Serializable {
protected final int getRhsOffset() {
return getWidth() - 1;
}
/**
* Returns the offset of the extra decision variable added when there is a
* negative decision variable in the original problem.
* @return the offset of x-
*/
protected final int getNegativeDecisionVariableOffset() {
return getNumObjectiveFunctions() + getOriginalNumDecisionVariables();
}
/**
* Get the number of decision variables.

View File

@ -39,6 +39,10 @@ The <action> type attribute can be add,update,fix,remove.
</properties>
<body>
<release version="2.1" date="TBD" description="TBD">
<action dev="luc" type="fix" issue="MATH-286" due-to="Benjamin McCann">
Fixed an error leading the simplex solver to compute the right solution
but return another one
</action>
<action dev="luc" type="fix" issue="MATH-283" due-to="Michael Nischt">
Prevent infinite loops in multi-directional direct optimization method when
the start point is exactly at the optimal point

View File

@ -46,8 +46,18 @@ public class SimplexSolverTest {
assertEquals(1.0, solution.getPoint()[1], .0000001);
assertEquals(1.0, solution.getPoint()[2], .0000001);
assertEquals(3.0, solution.getValue(), .0000001);
}
}
@Test
public void testMath286() throws OptimizationException {
LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 0.2, 0.3 }, 0 );
Collection<LinearConstraint> constraints = new ArrayList<LinearConstraint>();
constraints.add(new LinearConstraint(new double[] { 1, 1 }, Relationship.EQ, 23.0));
RealPointValuePair solution = new SimplexSolver().optimize(f, constraints, GoalType.MAXIMIZE, true);
assertEquals(6.9, solution.getValue(), .0000001);
}
@Test
public void testSimplexSolver() throws OptimizationException {
LinearObjectiveFunction f =