added Benjamin's patch from 2009-09-07

JIRA: MATH-286

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@812390 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2009-09-08 08:40:12 +00:00
parent 53a9ee3979
commit e5a77a7651
4 changed files with 121 additions and 109 deletions

View File

@ -17,6 +17,9 @@
package org.apache.commons.math.optimization.linear; package org.apache.commons.math.optimization.linear;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.math.optimization.OptimizationException; import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.RealPointValuePair; import org.apache.commons.math.optimization.RealPointValuePair;
import org.apache.commons.math.util.MathUtils; import org.apache.commons.math.util.MathUtils;
@ -73,23 +76,42 @@ public class SimplexSolver extends AbstractLinearOptimizer {
* @param col the column to test the ratio of. See {@link #getPivotColumn(SimplexTableau)} * @param col the column to test the ratio of. See {@link #getPivotColumn(SimplexTableau)}
* @return row with the minimum ratio * @return row with the minimum ratio
*/ */
private Integer getPivotRow(final int col, final SimplexTableau tableau) { private Integer getPivotRow(SimplexTableau tableau, final int col) {
// create a list of all the rows that tie for the lowest score in the minimum ratio test
List<Integer> minRatioPositions = new ArrayList<Integer>();
double minRatio = Double.MAX_VALUE; double minRatio = Double.MAX_VALUE;
Integer minRatioPos = null;
for (int i = tableau.getNumObjectiveFunctions(); i < tableau.getHeight(); i++) { for (int i = tableau.getNumObjectiveFunctions(); i < tableau.getHeight(); i++) {
final double rhs = tableau.getEntry(i, tableau.getWidth() - 1); final double rhs = tableau.getEntry(i, tableau.getWidth() - 1);
final double entry = tableau.getEntry(i, col); final double entry = tableau.getEntry(i, col);
if (MathUtils.compareTo(entry, 0, epsilon) > 0) { if (MathUtils.compareTo(entry, 0, epsilon) > 0) {
final double ratio = rhs / entry; final double ratio = rhs / entry;
if (ratio < minRatio) { if (MathUtils.equals(ratio, minRatio, epsilon)) {
minRatioPositions.add(i);
} else if (ratio < minRatio) {
minRatio = ratio; minRatio = ratio;
minRatioPos = i; minRatioPositions = new ArrayList<Integer>();
minRatioPositions.add(i);
} }
} }
} }
return minRatioPos;
}
if (minRatioPositions.size() == 0) {
return null;
} else if (minRatioPositions.size() > 1) {
// there's a degeneracy as indicated by a tie in the minimum ratio test
// check if there's an artificial variable that can be forced out of the basis
for (Integer row : minRatioPositions) {
for (int i = 0; i < tableau.getNumArtificialVariables(); i++) {
int column = i + tableau.getArtificialVariableOffset();
if (MathUtils.equals(tableau.getEntry(row, column), 1, epsilon) &&
row.equals(tableau.getBasicRow(column))) {
return row;
}
}
}
}
return minRatioPositions.get(0);
}
/** /**
* Runs one iteration of the Simplex method on the given model. * Runs one iteration of the Simplex method on the given model.
@ -103,7 +125,7 @@ public class SimplexSolver extends AbstractLinearOptimizer {
incrementIterationsCounter(); incrementIterationsCounter();
Integer pivotCol = getPivotColumn(tableau); Integer pivotCol = getPivotColumn(tableau);
Integer pivotRow = getPivotRow(pivotCol, tableau); Integer pivotRow = getPivotRow(tableau, pivotCol);
if (pivotRow == null) { if (pivotRow == null) {
throw new UnboundedSolutionException(); throw new UnboundedSolutionException();
} }
@ -121,40 +143,6 @@ public class SimplexSolver extends AbstractLinearOptimizer {
} }
} }
/**
* Checks whether Phase 1 is solved.
* @param tableau simple tableau for the problem
* @return whether Phase 1 is solved
*/
private boolean isPhase1Solved(final SimplexTableau tableau) {
if (tableau.getNumArtificialVariables() == 0) {
return true;
}
for (int i = tableau.getNumObjectiveFunctions(); i < tableau.getWidth() - 1; i++) {
if (MathUtils.compareTo(tableau.getEntry(0, i), 0, epsilon) < 0) {
return false;
}
}
return true;
}
/**
* Returns whether the problem is at an optimal state.
* @param tableau simple tableau for the problem
* @return whether the model has been solved
*/
public boolean isOptimal(final SimplexTableau tableau) {
if (tableau.getNumArtificialVariables() > 0) {
return false;
}
for (int i = tableau.getNumObjectiveFunctions(); i < tableau.getWidth() - 1; i++) {
if (MathUtils.compareTo(tableau.getEntry(0, i), 0, epsilon) < 0) {
return false;
}
}
return true;
}
/** /**
* Solves Phase 1 of the Simplex method. * Solves Phase 1 of the Simplex method.
* @param tableau simple tableau for the problem * @param tableau simple tableau for the problem
@ -162,14 +150,14 @@ public class SimplexSolver extends AbstractLinearOptimizer {
* exceeded, or if the problem is found not to have a bounded solution, or * exceeded, or if the problem is found not to have a bounded solution, or
* if there is no feasible solution * if there is no feasible solution
*/ */
protected void solvePhase1(final SimplexTableau tableau) protected void solvePhase1(final SimplexTableau tableau) throws OptimizationException {
throws OptimizationException {
// make sure we're in Phase 1 // make sure we're in Phase 1
if (tableau.getNumArtificialVariables() == 0) { if (tableau.getNumArtificialVariables() == 0) {
return; return;
} }
while (!isPhase1Solved(tableau)) { while (!tableau.isOptimal()) {
doIteration(tableau); doIteration(tableau);
} }
@ -181,13 +169,14 @@ public class SimplexSolver extends AbstractLinearOptimizer {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public RealPointValuePair doOptimize() public RealPointValuePair doOptimize() throws OptimizationException {
throws OptimizationException {
final SimplexTableau tableau = final SimplexTableau tableau =
new SimplexTableau(function, linearConstraints, goal, nonNegative, epsilon); new SimplexTableau(function, linearConstraints, goal, nonNegative, epsilon);
solvePhase1(tableau); solvePhase1(tableau);
tableau.discardArtificialVariables(); tableau.discardArtificialVariables();
while (!isOptimal(tableau)) {
while (!tableau.isOptimal()) {
doIteration(tableau); doIteration(tableau);
} }
return tableau.getSolution(); return tableau.getSolution();

View File

@ -27,9 +27,9 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.apache.commons.math.linear.Array2DRowRealMatrix;
import org.apache.commons.math.linear.MatrixUtils; import org.apache.commons.math.linear.MatrixUtils;
import org.apache.commons.math.linear.RealMatrix; import org.apache.commons.math.linear.RealMatrix;
import org.apache.commons.math.linear.Array2DRowRealMatrix;
import org.apache.commons.math.linear.RealVector; import org.apache.commons.math.linear.RealVector;
import org.apache.commons.math.optimization.GoalType; import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.RealPointValuePair; import org.apache.commons.math.optimization.RealPointValuePair;
@ -106,7 +106,8 @@ class SimplexTableau implements Serializable {
this.constraints = normalizeConstraints(constraints); this.constraints = normalizeConstraints(constraints);
this.restrictToNonNegative = restrictToNonNegative; this.restrictToNonNegative = restrictToNonNegative;
this.epsilon = epsilon; this.epsilon = epsilon;
this.numDecisionVariables = getNumVariables() + (restrictToNonNegative ? 0 : 1); this.numDecisionVariables = f.getCoefficients().getDimension() +
(restrictToNonNegative ? 0 : 1);
this.numSlackVariables = getConstraintTypeCounts(Relationship.LEQ) + this.numSlackVariables = getConstraintTypeCounts(Relationship.LEQ) +
getConstraintTypeCounts(Relationship.GEQ); getConstraintTypeCounts(Relationship.GEQ);
this.numArtificialVariables = getConstraintTypeCounts(Relationship.EQ) + this.numArtificialVariables = getConstraintTypeCounts(Relationship.EQ) +
@ -183,13 +184,6 @@ class SimplexTableau implements Serializable {
} }
/** Get the number of variables.
* @return number of variables
*/
public int getNumVariables() {
return f.getCoefficients().getDimension();
}
/** /**
* Get new versions of the constraints which have positive right hand sides. * Get new versions of the constraints which have positive right hand sides.
* @param originalConstraints original (not normalized) constraints * @param originalConstraints original (not normalized) constraints
@ -270,7 +264,7 @@ class SimplexTableau implements Serializable {
* @param col index of the column to check * @param col index of the column to check
* @return the row that the variable is basic in. null if the column is not basic * @return the row that the variable is basic in. null if the column is not basic
*/ */
private Integer getBasicRow(final int col) { Integer getBasicRow(final int col) {
return getBasicRow(col, true); return getBasicRow(col, true);
} }
@ -323,7 +317,6 @@ class SimplexTableau implements Serializable {
this.numArtificialVariables = 0; this.numArtificialVariables = 0;
} }
/** /**
* @param src the source array * @param src the source array
* @param dest the destination array * @param dest the destination array
@ -332,6 +325,19 @@ class SimplexTableau implements Serializable {
System.arraycopy(src, 0, dest, getNumObjectiveFunctions(), src.length); System.arraycopy(src, 0, dest, getNumObjectiveFunctions(), src.length);
} }
/**
* Returns whether the problem is at an optimal state.
* @return whether the model has been solved
*/
boolean isOptimal() {
for (int i = getNumObjectiveFunctions(); i < getWidth() - 1; i++) {
if (MathUtils.compareTo(tableau.getEntry(0, i), 0, epsilon) < 0) {
return false;
}
}
return true;
}
/** /**
* Get the current solution. * Get the current solution.
* *

View File

@ -17,13 +17,11 @@
package org.apache.commons.math.optimization.linear; package org.apache.commons.math.optimization.linear;
import static org.junit.Assert.assertEquals; import org.junit.Assert;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import org.apache.commons.math.linear.RealVector;
import org.apache.commons.math.linear.ArrayRealVector;
import org.apache.commons.math.optimization.GoalType; import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.OptimizationException; import org.apache.commons.math.optimization.OptimizationException;
import org.apache.commons.math.optimization.RealPointValuePair; import org.apache.commons.math.optimization.RealPointValuePair;
@ -42,20 +40,34 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MINIMIZE, true); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MINIMIZE, true);
assertEquals(0.0, solution.getPoint()[0], .0000001); Assert.assertEquals(0.0, solution.getPoint()[0], .0000001);
assertEquals(1.0, solution.getPoint()[1], .0000001); Assert.assertEquals(1.0, solution.getPoint()[1], .0000001);
assertEquals(1.0, solution.getPoint()[2], .0000001); Assert.assertEquals(1.0, solution.getPoint()[2], .0000001);
assertEquals(3.0, solution.getValue(), .0000001); Assert.assertEquals(3.0, solution.getValue(), .0000001);
} }
@Test @Test
public void testMath286() throws OptimizationException { public void testMath286() throws OptimizationException {
LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 0.2, 0.3 }, 0 ); LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 0.2, 0.3 }, 0 );
Collection<LinearConstraint> constraints = new ArrayList<LinearConstraint>(); Collection<LinearConstraint> constraints = new ArrayList<LinearConstraint>();
constraints.add(new LinearConstraint(new double[] { 1, 1 }, Relationship.EQ, 23.0)); constraints.add(new LinearConstraint(new double[] { 1, 1 }, Relationship.EQ, 23.0));
RealPointValuePair solution = new SimplexSolver().optimize(f, constraints, GoalType.MAXIMIZE, true); SimplexSolver solver = new SimplexSolver();
assertEquals(6.9, solution.getValue(), .0000001); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, true);
Assert.assertEquals(6.9, solution.getValue(), .0000001);
}
@Test
public void testDegeneracy() throws OptimizationException {
LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 0.8, 0.7 }, 0 );
Collection<LinearConstraint> constraints = new ArrayList<LinearConstraint>();
constraints.add(new LinearConstraint(new double[] { 1, 1 }, Relationship.LEQ, 18.0));
constraints.add(new LinearConstraint(new double[] { 1, 0 }, Relationship.GEQ, 10.0));
constraints.add(new LinearConstraint(new double[] { 0, 1 }, Relationship.GEQ, 8.0));
SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, true);
Assert.assertEquals(13.6, solution.getValue(), .0000001);
} }
@Test @Test
@ -70,7 +82,7 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, true); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, true);
assertEquals(10.0, solution.getValue(), .0000001); Assert.assertEquals(10.0, solution.getValue(), .0000001);
} }
@Test @Test
@ -80,9 +92,9 @@ public class SimplexSolverTest {
constraints.add(new LinearConstraint(new double[] { 2, 0 }, Relationship.GEQ, -1.0)); constraints.add(new LinearConstraint(new double[] { 2, 0 }, Relationship.GEQ, -1.0));
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MINIMIZE, true); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MINIMIZE, true);
assertEquals(0, solution.getValue(), .0000001); Assert.assertEquals(0, solution.getValue(), .0000001);
assertEquals(0, solution.getPoint()[0], .0000001); Assert.assertEquals(0, solution.getPoint()[0], .0000001);
assertEquals(0, solution.getPoint()[1], .0000001); Assert.assertEquals(0, solution.getPoint()[1], .0000001);
} }
@Test(expected=NoFeasibleSolutionException.class) @Test(expected=NoFeasibleSolutionException.class)
@ -105,9 +117,9 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, false); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, false);
assertEquals(2.0, solution.getPoint()[0], 0.0); Assert.assertEquals(2.0, solution.getPoint()[0], 0.0);
assertEquals(2.0, solution.getPoint()[1], 0.0); Assert.assertEquals(2.0, solution.getPoint()[1], 0.0);
assertEquals(57.0, solution.getValue(), 0.0); Assert.assertEquals(57.0, solution.getValue(), 0.0);
} }
@Test @Test
@ -118,8 +130,8 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, false); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, false);
assertEquals(10.0, solution.getPoint()[0], 0.0); Assert.assertEquals(10.0, solution.getPoint()[0], 0.0);
assertEquals(30.0, solution.getValue(), 0.0); Assert.assertEquals(30.0, solution.getValue(), 0.0);
} }
/** /**
@ -136,9 +148,9 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, false); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, false);
assertEquals(2.0, solution.getPoint()[0], 0.0); Assert.assertEquals(2.0, solution.getPoint()[0], 0.0);
assertEquals(2.0, solution.getPoint()[1], 0.0); Assert.assertEquals(2.0, solution.getPoint()[1], 0.0);
assertEquals(50.0, solution.getValue(), 0.0); Assert.assertEquals(50.0, solution.getValue(), 0.0);
} }
@Test @Test
@ -151,9 +163,9 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MINIMIZE, false); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MINIMIZE, false);
assertEquals(4.0, solution.getPoint()[0], 0.0); Assert.assertEquals(4.0, solution.getPoint()[0], 0.0);
assertEquals(0.0, solution.getPoint()[1], 0.0); Assert.assertEquals(0.0, solution.getPoint()[1], 0.0);
assertEquals(-13.0, solution.getValue(), 0.0); Assert.assertEquals(-13.0, solution.getValue(), 0.0);
} }
@Test @Test
@ -165,9 +177,9 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, false); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, false);
assertEquals(-2.0, solution.getPoint()[0], 0.0); Assert.assertEquals(-2.0, solution.getPoint()[0], 0.0);
assertEquals(8.0, solution.getPoint()[1], 0.0); Assert.assertEquals(8.0, solution.getPoint()[1], 0.0);
assertEquals(12.0, solution.getValue(), 0.0); Assert.assertEquals(12.0, solution.getValue(), 0.0);
} }
@Test(expected = NoFeasibleSolutionException.class) @Test(expected = NoFeasibleSolutionException.class)
@ -203,12 +215,12 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, true); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, true);
assertEquals(2902.92783505155, solution.getPoint()[0], .0000001); Assert.assertEquals(2902.92783505155, solution.getPoint()[0], .0000001);
assertEquals(480.419243986254, solution.getPoint()[1], .0000001); Assert.assertEquals(480.419243986254, solution.getPoint()[1], .0000001);
assertEquals(0.0, solution.getPoint()[2], .0000001); Assert.assertEquals(0.0, solution.getPoint()[2], .0000001);
assertEquals(0.0, solution.getPoint()[3], .0000001); Assert.assertEquals(0.0, solution.getPoint()[3], .0000001);
assertEquals(0.0, solution.getPoint()[4], .0000001); Assert.assertEquals(0.0, solution.getPoint()[4], .0000001);
assertEquals(1438556.7491409, solution.getValue(), .0000001); Assert.assertEquals(1438556.7491409, solution.getValue(), .0000001);
} }
@Test @Test
@ -222,10 +234,10 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, false); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, false);
assertEquals(1.0, solution.getPoint()[0], 0.0); Assert.assertEquals(1.0, solution.getPoint()[0], 0.0);
assertEquals(1.0, solution.getPoint()[1], 0.0); Assert.assertEquals(1.0, solution.getPoint()[1], 0.0);
assertEquals(0.0, solution.getPoint()[2], 0.0); Assert.assertEquals(0.0, solution.getPoint()[2], 0.0);
assertEquals(15.0, solution.getValue(), 0.0); Assert.assertEquals(15.0, solution.getValue(), 0.0);
} }
@Test @Test
@ -236,7 +248,7 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, true); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MAXIMIZE, true);
assertEquals(0, solution.getValue(), .0000001); Assert.assertEquals(0, solution.getValue(), .0000001);
} }
@Test @Test
@ -363,7 +375,7 @@ public class SimplexSolverTest {
SimplexSolver solver = new SimplexSolver(); SimplexSolver solver = new SimplexSolver();
RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MINIMIZE, true); RealPointValuePair solution = solver.optimize(f, constraints, GoalType.MINIMIZE, true);
assertEquals(7518.0, solution.getValue(), .0000001); Assert.assertEquals(7518.0, solution.getValue(), .0000001);
} }
/** /**
@ -385,13 +397,13 @@ public class SimplexSolverTest {
String[] equationParts = s.split("[>|<]?="); String[] equationParts = s.split("[>|<]?=");
double rhs = Double.parseDouble(equationParts[1].trim()); double rhs = Double.parseDouble(equationParts[1].trim());
RealVector lhs = new ArrayRealVector(numCoefficients); double[] lhs = new double[numCoefficients];
String left = equationParts[0].replaceAll(" ?x", ""); String left = equationParts[0].replaceAll(" ?x", "");
String[] coefficients = left.split(" "); String[] coefficients = left.split(" ");
for (String coefficient : coefficients) { for (String coefficient : coefficients) {
double value = coefficient.charAt(0) == '-' ? -1 : 1; double value = coefficient.charAt(0) == '-' ? -1 : 1;
int index = Integer.parseInt(coefficient.replaceFirst("[+|-]", "").trim()); int index = Integer.parseInt(coefficient.replaceFirst("[+|-]", "").trim());
lhs.setEntry(index, value); lhs[index] = value;
} }
return new LinearConstraint(lhs, relationship, rhs); return new LinearConstraint(lhs, relationship, rhs);
} }

View File

@ -22,11 +22,12 @@ import java.util.Collection;
import org.apache.commons.math.TestUtils; import org.apache.commons.math.TestUtils;
import org.apache.commons.math.optimization.GoalType; import org.apache.commons.math.optimization.GoalType;
import org.junit.Assert;
import org.junit.Test;
import junit.framework.TestCase; public class SimplexTableauTest {
public class SimplexTableauTest extends TestCase {
@Test
public void testInitialization() { public void testInitialization() {
LinearObjectiveFunction f = createFunction(); LinearObjectiveFunction f = createFunction();
Collection<LinearConstraint> constraints = createConstraints(); Collection<LinearConstraint> constraints = createConstraints();
@ -42,6 +43,7 @@ public class SimplexTableauTest extends TestCase {
assertMatrixEquals(expectedInitialTableau, tableau.getData()); assertMatrixEquals(expectedInitialTableau, tableau.getData());
} }
@Test
public void testdiscardArtificialVariables() { public void testdiscardArtificialVariables() {
LinearObjectiveFunction f = createFunction(); LinearObjectiveFunction f = createFunction();
Collection<LinearConstraint> constraints = createConstraints(); Collection<LinearConstraint> constraints = createConstraints();
@ -57,6 +59,7 @@ public class SimplexTableauTest extends TestCase {
assertMatrixEquals(expectedTableau, tableau.getData()); assertMatrixEquals(expectedTableau, tableau.getData());
} }
@Test
public void testTableauWithNoArtificialVars() { public void testTableauWithNoArtificialVars() {
LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] {15, 10}, 0); LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] {15, 10}, 0);
Collection<LinearConstraint> constraints = new ArrayList<LinearConstraint>(); Collection<LinearConstraint> constraints = new ArrayList<LinearConstraint>();
@ -74,13 +77,15 @@ public class SimplexTableauTest extends TestCase {
assertMatrixEquals(initialTableau, tableau.getData()); assertMatrixEquals(initialTableau, tableau.getData());
} }
@Test
public void testSerial() { public void testSerial() {
LinearObjectiveFunction f = createFunction(); LinearObjectiveFunction f = createFunction();
Collection<LinearConstraint> constraints = createConstraints(); Collection<LinearConstraint> constraints = createConstraints();
SimplexTableau tableau = SimplexTableau tableau =
new SimplexTableau(f, constraints, GoalType.MAXIMIZE, false, 1.0e-6); new SimplexTableau(f, constraints, GoalType.MAXIMIZE, false, 1.0e-6);
assertEquals(tableau, TestUtils.serializeAndRecover(tableau)); Assert.assertEquals(tableau, TestUtils.serializeAndRecover(tableau));
} }
private LinearObjectiveFunction createFunction() { private LinearObjectiveFunction createFunction() {
return new LinearObjectiveFunction(new double[] {15, 10}, 0); return new LinearObjectiveFunction(new double[] {15, 10}, 0);
} }
@ -94,11 +99,11 @@ public class SimplexTableauTest extends TestCase {
} }
private void assertMatrixEquals(double[][] expected, double[][] result) { private void assertMatrixEquals(double[][] expected, double[][] result) {
assertEquals("Wrong number of rows.", expected.length, result.length); Assert.assertEquals("Wrong number of rows.", expected.length, result.length);
for (int i = 0; i < expected.length; i++) { for (int i = 0; i < expected.length; i++) {
assertEquals("Wrong number of columns.", expected[i].length, result[i].length); Assert.assertEquals("Wrong number of columns.", expected[i].length, result[i].length);
for (int j = 0; j < expected[i].length; j++) { for (int j = 0; j < expected[i].length; j++) {
assertEquals("Wrong value at position [" + i + "," + j + "]", expected[i][j], result[i][j]); Assert.assertEquals("Wrong value at position [" + i + "," + j + "]", expected[i][j], result[i][j], 1.0e-15);
} }
} }
} }