View Javadoc
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  package org.apache.commons.math4.legacy.optim.linear;
18  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.List;
22  import org.junit.Test;
23  import org.junit.Assert;
24  
25  import org.apache.commons.numbers.core.Precision;
26  import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
27  import org.apache.commons.math4.legacy.exception.TooManyIterationsException;
28  import org.apache.commons.math4.legacy.optim.MaxIter;
29  import org.apache.commons.math4.legacy.optim.PointValuePair;
30  import org.apache.commons.math4.legacy.optim.nonlinear.scalar.GoalType;
31  
32  public class SimplexSolverTest {
33      private static final MaxIter DEFAULT_MAX_ITER = new MaxIter(100);
34  
35      @Test
36      public void testMath842Cycle() {
37          // from http://www.math.toronto.edu/mpugh/Teaching/APM236_04/bland
38          //      maximize 10 x1 - 57 x2 - 9 x3 - 24 x4
39          //      subject to
40          //          1/2 x1 - 11/2 x2 - 5/2 x3 + 9 x4  <= 0
41          //          1/2 x1 -  3/2 x2 - 1/2 x3 +   x4  <= 0
42          //              x1                  <= 1
43          //      x1,x2,x3,x4 >= 0
44  
45          LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 10, -57, -9, -24}, 0);
46  
47          ArrayList<LinearConstraint> constraints = new ArrayList<>();
48  
49          constraints.add(new LinearConstraint(new double[] {0.5, -5.5, -2.5, 9}, Relationship.LEQ, 0));
50          constraints.add(new LinearConstraint(new double[] {0.5, -1.5, -0.5, 1}, Relationship.LEQ, 0));
51          constraints.add(new LinearConstraint(new double[] {  1,    0,    0, 0}, Relationship.LEQ, 1));
52  
53          double epsilon = 1e-6;
54          SimplexSolver solver = new SimplexSolver();
55          PointValuePair solution = solver.optimize(f, new LinearConstraintSet(constraints),
56                                                    GoalType.MAXIMIZE,
57                                                    new NonNegativeConstraint(true),
58                                                    PivotSelectionRule.BLAND);
59          Assert.assertEquals(1.0d, solution.getValue(), epsilon);
60          Assert.assertTrue(validSolution(solution, constraints, epsilon));
61      }
62  
63      @Test
64      public void testMath828() {
65          LinearObjectiveFunction f = new LinearObjectiveFunction(
66                  new double[] { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, 0.0);
67  
68          ArrayList<LinearConstraint> constraints = new ArrayList<>();
69  
70          constraints.add(new LinearConstraint(new double[] {0.0, 39.0, 23.0, 96.0, 15.0, 48.0, 9.0, 21.0, 48.0, 36.0, 76.0, 19.0, 88.0, 17.0, 16.0, 36.0,}, Relationship.GEQ, 15.0));
71          constraints.add(new LinearConstraint(new double[] {0.0, 59.0, 93.0, 12.0, 29.0, 78.0, 73.0, 87.0, 32.0, 70.0, 68.0, 24.0, 11.0, 26.0, 65.0, 25.0,}, Relationship.GEQ, 29.0));
72          constraints.add(new LinearConstraint(new double[] {0.0, 74.0, 5.0, 82.0, 6.0, 97.0, 55.0, 44.0, 52.0, 54.0, 5.0, 93.0, 91.0, 8.0, 20.0, 97.0,}, Relationship.GEQ, 6.0));
73          constraints.add(new LinearConstraint(new double[] {8.0, -3.0, -28.0, -72.0, -8.0, -31.0, -31.0, -74.0, -47.0, -59.0, -24.0, -57.0, -56.0, -16.0, -92.0, -59.0,}, Relationship.GEQ, 0.0));
74          constraints.add(new LinearConstraint(new double[] {25.0, -7.0, -99.0, -78.0, -25.0, -14.0, -16.0, -89.0, -39.0, -56.0, -53.0, -9.0, -18.0, -26.0, -11.0, -61.0,}, Relationship.GEQ, 0.0));
75          constraints.add(new LinearConstraint(new double[] {33.0, -95.0, -15.0, -4.0, -33.0, -3.0, -20.0, -96.0, -27.0, -13.0, -80.0, -24.0, -3.0, -13.0, -57.0, -76.0,}, Relationship.GEQ, 0.0));
76          constraints.add(new LinearConstraint(new double[] {7.0, -95.0, -39.0, -93.0, -7.0, -94.0, -94.0, -62.0, -76.0, -26.0, -53.0, -57.0, -31.0, -76.0, -53.0, -52.0,}, Relationship.GEQ, 0.0));
77  
78          double epsilon = 1e-6;
79          PointValuePair solution = new SimplexSolver().optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
80                                                                 GoalType.MINIMIZE, new NonNegativeConstraint(true));
81          Assert.assertEquals(1.0d, solution.getValue(), epsilon);
82          Assert.assertTrue(validSolution(solution, constraints, epsilon));
83      }
84  
85      @Test
86      public void testMath828Cycle() {
87          LinearObjectiveFunction f = new LinearObjectiveFunction(
88                  new double[] { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, 0.0);
89  
90          ArrayList<LinearConstraint> constraints = new ArrayList<>();
91  
92          constraints.add(new LinearConstraint(new double[] {0.0, 16.0, 14.0, 69.0, 1.0, 85.0, 52.0, 43.0, 64.0, 97.0, 14.0, 74.0, 89.0, 28.0, 94.0, 58.0, 13.0, 22.0, 21.0, 17.0, 30.0, 25.0, 1.0, 59.0, 91.0, 78.0, 12.0, 74.0, 56.0, 3.0, 88.0,}, Relationship.GEQ, 91.0));
93          constraints.add(new LinearConstraint(new double[] {0.0, 60.0, 40.0, 81.0, 71.0, 72.0, 46.0, 45.0, 38.0, 48.0, 40.0, 17.0, 33.0, 85.0, 64.0, 32.0, 84.0, 3.0, 54.0, 44.0, 71.0, 67.0, 90.0, 95.0, 54.0, 99.0, 99.0, 29.0, 52.0, 98.0, 9.0,}, Relationship.GEQ, 54.0));
94          constraints.add(new LinearConstraint(new double[] {0.0, 41.0, 12.0, 86.0, 90.0, 61.0, 31.0, 41.0, 23.0, 89.0, 17.0, 74.0, 44.0, 27.0, 16.0, 47.0, 80.0, 32.0, 11.0, 56.0, 68.0, 82.0, 11.0, 62.0, 62.0, 53.0, 39.0, 16.0, 48.0, 1.0, 63.0,}, Relationship.GEQ, 62.0));
95          constraints.add(new LinearConstraint(new double[] {83.0, -76.0, -94.0, -19.0, -15.0, -70.0, -72.0, -57.0, -63.0, -65.0, -22.0, -94.0, -22.0, -88.0, -86.0, -89.0, -72.0, -16.0, -80.0, -49.0, -70.0, -93.0, -95.0, -17.0, -83.0, -97.0, -31.0, -47.0, -31.0, -13.0, -23.0,}, Relationship.GEQ, 0.0));
96          constraints.add(new LinearConstraint(new double[] {41.0, -96.0, -41.0, -48.0, -70.0, -43.0, -43.0, -43.0, -97.0, -37.0, -85.0, -70.0, -45.0, -67.0, -87.0, -69.0, -94.0, -54.0, -54.0, -92.0, -79.0, -10.0, -35.0, -20.0, -41.0, -41.0, -65.0, -25.0, -12.0, -8.0, -46.0,}, Relationship.GEQ, 0.0));
97          constraints.add(new LinearConstraint(new double[] {27.0, -42.0, -65.0, -49.0, -53.0, -42.0, -17.0, -2.0, -61.0, -31.0, -76.0, -47.0, -8.0, -93.0, -86.0, -62.0, -65.0, -63.0, -22.0, -43.0, -27.0, -23.0, -32.0, -74.0, -27.0, -63.0, -47.0, -78.0, -29.0, -95.0, -73.0,}, Relationship.GEQ, 0.0));
98          constraints.add(new LinearConstraint(new double[] {15.0, -46.0, -41.0, -83.0, -98.0, -99.0, -21.0, -35.0, -7.0, -14.0, -80.0, -63.0, -18.0, -42.0, -5.0, -34.0, -56.0, -70.0, -16.0, -18.0, -74.0, -61.0, -47.0, -41.0, -15.0, -79.0, -18.0, -47.0, -88.0, -68.0, -55.0,}, Relationship.GEQ, 0.0));
99  
100         double epsilon = 1e-6;
101         PointValuePair solution = new SimplexSolver().optimize(DEFAULT_MAX_ITER, f,
102                                                                new LinearConstraintSet(constraints),
103                                                                GoalType.MINIMIZE, new NonNegativeConstraint(true),
104                                                                PivotSelectionRule.BLAND);
105         Assert.assertEquals(1.0d, solution.getValue(), epsilon);
106         Assert.assertTrue(validSolution(solution, constraints, epsilon));
107     }
108 
109     @Test
110     public void testMath781() {
111         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 2, 6, 7 }, 0);
112 
113         ArrayList<LinearConstraint> constraints = new ArrayList<>();
114         constraints.add(new LinearConstraint(new double[] { 1, 2, 1 }, Relationship.LEQ, 2));
115         constraints.add(new LinearConstraint(new double[] { -1, 1, 1 }, Relationship.LEQ, -1));
116         constraints.add(new LinearConstraint(new double[] { 2, -3, 1 }, Relationship.LEQ, -1));
117 
118         double epsilon = 1e-6;
119         SimplexSolver solver = new SimplexSolver();
120         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
121                                                   GoalType.MAXIMIZE, new NonNegativeConstraint(false));
122 
123         Assert.assertTrue(Precision.compareTo(solution.getPoint()[0], 0.0d, epsilon) > 0);
124         Assert.assertTrue(Precision.compareTo(solution.getPoint()[1], 0.0d, epsilon) > 0);
125         Assert.assertTrue(Precision.compareTo(solution.getPoint()[2], 0.0d, epsilon) < 0);
126         Assert.assertEquals(2.0d, solution.getValue(), epsilon);
127     }
128 
129     @Test
130     public void testMath713NegativeVariable() {
131         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] {1.0, 1.0}, 0.0d);
132         ArrayList<LinearConstraint> constraints = new ArrayList<>();
133         constraints.add(new LinearConstraint(new double[] {1, 0}, Relationship.EQ, 1));
134 
135         double epsilon = 1e-6;
136         SimplexSolver solver = new SimplexSolver();
137         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
138                                                   GoalType.MINIMIZE, new NonNegativeConstraint(true));
139 
140         Assert.assertTrue(Precision.compareTo(solution.getPoint()[0], 0.0d, epsilon) >= 0);
141         Assert.assertTrue(Precision.compareTo(solution.getPoint()[1], 0.0d, epsilon) >= 0);
142     }
143 
144     @Test
145     public void testMath434NegativeVariable() {
146         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] {0.0, 0.0, 1.0}, 0.0d);
147         ArrayList<LinearConstraint> constraints = new ArrayList<>();
148         constraints.add(new LinearConstraint(new double[] {1, 1, 0}, Relationship.EQ, 5));
149         constraints.add(new LinearConstraint(new double[] {0, 0, 1}, Relationship.GEQ, -10));
150 
151         double epsilon = 1e-6;
152         SimplexSolver solver = new SimplexSolver();
153         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
154                                                   GoalType.MINIMIZE, new NonNegativeConstraint(false));
155 
156         Assert.assertEquals(5.0, solution.getPoint()[0] + solution.getPoint()[1], epsilon);
157         Assert.assertEquals(-10.0, solution.getPoint()[2], epsilon);
158         Assert.assertEquals(-10.0, solution.getValue(), epsilon);
159     }
160 
161     @Test(expected = NoFeasibleSolutionException.class)
162     public void testMath434UnfeasibleSolution() {
163         double epsilon = 1e-6;
164 
165         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] {1.0, 0.0}, 0.0);
166         ArrayList<LinearConstraint> constraints = new ArrayList<>();
167         constraints.add(new LinearConstraint(new double[] {epsilon/2, 0.5}, Relationship.EQ, 0));
168         constraints.add(new LinearConstraint(new double[] {1e-3, 0.1}, Relationship.EQ, 10));
169 
170         SimplexSolver solver = new SimplexSolver();
171         // allowing only non-negative values, no feasible solution shall be found
172         solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
173                         GoalType.MINIMIZE, new NonNegativeConstraint(true));
174     }
175 
176     @Test
177     public void testMath434PivotRowSelection() {
178         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] {1.0}, 0.0);
179 
180         double epsilon = 1e-6;
181         ArrayList<LinearConstraint> constraints = new ArrayList<>();
182         constraints.add(new LinearConstraint(new double[] {200}, Relationship.GEQ, 1));
183         constraints.add(new LinearConstraint(new double[] {100}, Relationship.GEQ, 0.499900001));
184 
185         SimplexSolver solver = new SimplexSolver();
186         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
187                                                   GoalType.MINIMIZE, new NonNegativeConstraint(false));
188 
189         Assert.assertTrue(Precision.compareTo(solution.getPoint()[0] * 200.d, 1.d, epsilon) >= 0);
190         Assert.assertEquals(0.0050, solution.getValue(), epsilon);
191     }
192 
193     @Test
194     public void testMath434PivotRowSelection2() {
195         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] {0.0d, 1.0d, 1.0d, 0.0d, 0.0d, 0.0d, 0.0d}, 0.0d);
196 
197         ArrayList<LinearConstraint> constraints = new ArrayList<>();
198         constraints.add(new LinearConstraint(new double[] {1.0d, -0.1d, 0.0d, 0.0d, 0.0d, 0.0d, 0.0d}, Relationship.EQ, -0.1d));
199         constraints.add(new LinearConstraint(new double[] {1.0d, 0.0d, 0.0d, 0.0d, 0.0d, 0.0d, 0.0d}, Relationship.GEQ, -1e-18d));
200         constraints.add(new LinearConstraint(new double[] {0.0d, 1.0d, 0.0d, 0.0d, 0.0d, 0.0d, 0.0d}, Relationship.GEQ, 0.0d));
201         constraints.add(new LinearConstraint(new double[] {0.0d, 0.0d, 0.0d, 1.0d, 0.0d, -0.0128588d, 1e-5d}, Relationship.EQ, 0.0d));
202         constraints.add(new LinearConstraint(new double[] {0.0d, 0.0d, 0.0d, 0.0d, 1.0d, 1e-5d, -0.0128586d}, Relationship.EQ, 1e-10d));
203         constraints.add(new LinearConstraint(new double[] {0.0d, 0.0d, 1.0d, -1.0d, 0.0d, 0.0d, 0.0d}, Relationship.GEQ, 0.0d));
204         constraints.add(new LinearConstraint(new double[] {0.0d, 0.0d, 1.0d, 1.0d, 0.0d, 0.0d, 0.0d}, Relationship.GEQ, 0.0d));
205         constraints.add(new LinearConstraint(new double[] {0.0d, 0.0d, 1.0d, 0.0d, -1.0d, 0.0d, 0.0d}, Relationship.GEQ, 0.0d));
206         constraints.add(new LinearConstraint(new double[] {0.0d, 0.0d, 1.0d, 0.0d, 1.0d, 0.0d, 0.0d}, Relationship.GEQ, 0.0d));
207 
208         double epsilon = 1e-7;
209         SimplexSolver simplex = new SimplexSolver();
210         PointValuePair solution = simplex.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
211                                                    GoalType.MINIMIZE, new NonNegativeConstraint(false));
212 
213         Assert.assertTrue(Precision.compareTo(solution.getPoint()[0], -1e-18d, epsilon) >= 0);
214         Assert.assertEquals(1.0d, solution.getPoint()[1], epsilon);
215         Assert.assertEquals(0.0d, solution.getPoint()[2], epsilon);
216         Assert.assertEquals(1.0d, solution.getValue(), epsilon);
217     }
218 
219     @Test
220     public void testMath272() {
221         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 2, 2, 1 }, 0);
222         Collection<LinearConstraint> constraints = new ArrayList<>();
223         constraints.add(new LinearConstraint(new double[] { 1, 1, 0 }, Relationship.GEQ,  1));
224         constraints.add(new LinearConstraint(new double[] { 1, 0, 1 }, Relationship.GEQ,  1));
225         constraints.add(new LinearConstraint(new double[] { 0, 1, 0 }, Relationship.GEQ,  1));
226 
227         SimplexSolver solver = new SimplexSolver();
228         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
229                                                   GoalType.MINIMIZE, new NonNegativeConstraint(true));
230 
231         Assert.assertEquals(0.0, solution.getPoint()[0], .0000001);
232         Assert.assertEquals(1.0, solution.getPoint()[1], .0000001);
233         Assert.assertEquals(1.0, solution.getPoint()[2], .0000001);
234         Assert.assertEquals(3.0, solution.getValue(), .0000001);
235     }
236 
237     @Test
238     public void testMath286() {
239         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 0.8, 0.2, 0.7, 0.3, 0.6, 0.4 }, 0 );
240         Collection<LinearConstraint> constraints = new ArrayList<>();
241         constraints.add(new LinearConstraint(new double[] { 1, 0, 1, 0, 1, 0 }, Relationship.EQ, 23.0));
242         constraints.add(new LinearConstraint(new double[] { 0, 1, 0, 1, 0, 1 }, Relationship.EQ, 23.0));
243         constraints.add(new LinearConstraint(new double[] { 1, 0, 0, 0, 0, 0 }, Relationship.GEQ, 10.0));
244         constraints.add(new LinearConstraint(new double[] { 0, 0, 1, 0, 0, 0 }, Relationship.GEQ, 8.0));
245         constraints.add(new LinearConstraint(new double[] { 0, 0, 0, 0, 1, 0 }, Relationship.GEQ, 5.0));
246 
247         SimplexSolver solver = new SimplexSolver();
248         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
249                                                   GoalType.MAXIMIZE, new NonNegativeConstraint(true));
250 
251         Assert.assertEquals(25.8, solution.getValue(), .0000001);
252         Assert.assertEquals(23.0, solution.getPoint()[0] + solution.getPoint()[2] + solution.getPoint()[4], 0.0000001);
253         Assert.assertEquals(23.0, solution.getPoint()[1] + solution.getPoint()[3] + solution.getPoint()[5], 0.0000001);
254         Assert.assertTrue(solution.getPoint()[0] >= 10.0 - 0.0000001);
255         Assert.assertTrue(solution.getPoint()[2] >= 8.0 - 0.0000001);
256         Assert.assertTrue(solution.getPoint()[4] >= 5.0 - 0.0000001);
257     }
258 
259     @Test
260     public void testDegeneracy() {
261         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 0.8, 0.7 }, 0 );
262         Collection<LinearConstraint> constraints = new ArrayList<>();
263         constraints.add(new LinearConstraint(new double[] { 1, 1 }, Relationship.LEQ, 18.0));
264         constraints.add(new LinearConstraint(new double[] { 1, 0 }, Relationship.GEQ, 10.0));
265         constraints.add(new LinearConstraint(new double[] { 0, 1 }, Relationship.GEQ, 8.0));
266 
267         SimplexSolver solver = new SimplexSolver();
268         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
269                                                   GoalType.MINIMIZE, new NonNegativeConstraint(true));
270         Assert.assertEquals(13.6, solution.getValue(), .0000001);
271     }
272 
273     @Test
274     public void testMath288() {
275         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 7, 3, 0, 0 }, 0 );
276         Collection<LinearConstraint> constraints = new ArrayList<>();
277         constraints.add(new LinearConstraint(new double[] { 3, 0, -5, 0 }, Relationship.LEQ, 0.0));
278         constraints.add(new LinearConstraint(new double[] { 2, 0, 0, -5 }, Relationship.LEQ, 0.0));
279         constraints.add(new LinearConstraint(new double[] { 0, 3, 0, -5 }, Relationship.LEQ, 0.0));
280         constraints.add(new LinearConstraint(new double[] { 1, 0, 0, 0 }, Relationship.LEQ, 1.0));
281         constraints.add(new LinearConstraint(new double[] { 0, 1, 0, 0 }, Relationship.LEQ, 1.0));
282 
283         SimplexSolver solver = new SimplexSolver();
284         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
285                                                   GoalType.MAXIMIZE, new NonNegativeConstraint(true));
286         Assert.assertEquals(10.0, solution.getValue(), .0000001);
287     }
288 
289     @Test
290     public void testMath290GEQ() {
291         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 1, 5 }, 0 );
292         Collection<LinearConstraint> constraints = new ArrayList<>();
293         constraints.add(new LinearConstraint(new double[] { 2, 0 }, Relationship.GEQ, -1.0));
294         SimplexSolver solver = new SimplexSolver();
295         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
296                                                   GoalType.MINIMIZE, new NonNegativeConstraint(true));
297         Assert.assertEquals(0, solution.getValue(), .0000001);
298         Assert.assertEquals(0, solution.getPoint()[0], .0000001);
299         Assert.assertEquals(0, solution.getPoint()[1], .0000001);
300     }
301 
302     @Test(expected=NoFeasibleSolutionException.class)
303     public void testMath290LEQ() {
304         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 1, 5 }, 0 );
305         Collection<LinearConstraint> constraints = new ArrayList<>();
306         constraints.add(new LinearConstraint(new double[] { 2, 0 }, Relationship.LEQ, -1.0));
307         SimplexSolver solver = new SimplexSolver();
308         solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
309                         GoalType.MINIMIZE, new NonNegativeConstraint(true));
310     }
311 
312     @Test
313     public void testMath293() {
314       LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 0.8, 0.2, 0.7, 0.3, 0.4, 0.6}, 0 );
315       Collection<LinearConstraint> constraints = new ArrayList<>();
316       constraints.add(new LinearConstraint(new double[] { 1, 0, 1, 0, 1, 0 }, Relationship.EQ, 30.0));
317       constraints.add(new LinearConstraint(new double[] { 0, 1, 0, 1, 0, 1 }, Relationship.EQ, 30.0));
318       constraints.add(new LinearConstraint(new double[] { 0.8, 0.2, 0.0, 0.0, 0.0, 0.0 }, Relationship.GEQ, 10.0));
319       constraints.add(new LinearConstraint(new double[] { 0.0, 0.0, 0.7, 0.3, 0.0, 0.0 }, Relationship.GEQ, 10.0));
320       constraints.add(new LinearConstraint(new double[] { 0.0, 0.0, 0.0, 0.0, 0.4, 0.6 }, Relationship.GEQ, 10.0));
321 
322       SimplexSolver solver = new SimplexSolver();
323       PointValuePair solution1 = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
324                                                  GoalType.MAXIMIZE, new NonNegativeConstraint(true));
325 
326       Assert.assertEquals(15.7143, solution1.getPoint()[0], .0001);
327       Assert.assertEquals(0.0, solution1.getPoint()[1], .0001);
328       Assert.assertEquals(14.2857, solution1.getPoint()[2], .0001);
329       Assert.assertEquals(0.0, solution1.getPoint()[3], .0001);
330       Assert.assertEquals(0.0, solution1.getPoint()[4], .0001);
331       Assert.assertEquals(30.0, solution1.getPoint()[5], .0001);
332       Assert.assertEquals(40.57143, solution1.getValue(), .0001);
333 
334       double valA = 0.8 * solution1.getPoint()[0] + 0.2 * solution1.getPoint()[1];
335       double valB = 0.7 * solution1.getPoint()[2] + 0.3 * solution1.getPoint()[3];
336       double valC = 0.4 * solution1.getPoint()[4] + 0.6 * solution1.getPoint()[5];
337 
338       f = new LinearObjectiveFunction(new double[] { 0.8, 0.2, 0.7, 0.3, 0.4, 0.6}, 0 );
339       constraints = new ArrayList<>();
340       constraints.add(new LinearConstraint(new double[] { 1, 0, 1, 0, 1, 0 }, Relationship.EQ, 30.0));
341       constraints.add(new LinearConstraint(new double[] { 0, 1, 0, 1, 0, 1 }, Relationship.EQ, 30.0));
342       constraints.add(new LinearConstraint(new double[] { 0.8, 0.2, 0.0, 0.0, 0.0, 0.0 }, Relationship.GEQ, valA));
343       constraints.add(new LinearConstraint(new double[] { 0.0, 0.0, 0.7, 0.3, 0.0, 0.0 }, Relationship.GEQ, valB));
344       constraints.add(new LinearConstraint(new double[] { 0.0, 0.0, 0.0, 0.0, 0.4, 0.6 }, Relationship.GEQ, valC));
345 
346       PointValuePair solution2 = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
347                                                  GoalType.MAXIMIZE, new NonNegativeConstraint(true));
348       Assert.assertEquals(40.57143, solution2.getValue(), .0001);
349     }
350 
351     @Test
352     public void testMath930() {
353         Collection<LinearConstraint> constraints = createMath930Constraints();
354 
355         double[] objFunctionCoeff = new double[33];
356         objFunctionCoeff[3] = 1;
357         LinearObjectiveFunction f = new LinearObjectiveFunction(objFunctionCoeff, 0);
358         SimplexSolver solver = new SimplexSolver(1e-4, 10, 1e-6);
359 
360         PointValuePair solution = solver.optimize(new MaxIter(1000), f, new LinearConstraintSet(constraints),
361                                                   GoalType.MINIMIZE, new NonNegativeConstraint(true));
362         Assert.assertEquals(0.3752298, solution.getValue(), 1e-4);
363     }
364 
365     private List<LinearConstraint> createMath930Constraints() {
366         List<LinearConstraint> constraints = new ArrayList<>();
367         constraints.add(new LinearConstraint(new double[] {1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 0}, Relationship.GEQ, 0.0));
368         constraints.add(new LinearConstraint(new double[] {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, Relationship.GEQ, 0.0));
369         constraints.add(new LinearConstraint(new double[] {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, Relationship.LEQ, 0.0));
370         constraints.add(new LinearConstraint(new double[] {0, 1, 0, -1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, -1, 0, 1, 0}, Relationship.GEQ, 0.0));
371         constraints.add(new LinearConstraint(new double[] {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.628803}, Relationship.GEQ, 0.0));
372         constraints.add(new LinearConstraint(new double[] {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.676993}, Relationship.LEQ, 0.0));
373         constraints.add(new LinearConstraint(new double[] {0, 0, 1, -1, 0, 0, -1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, -1, 1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, -1, 1, 0}, Relationship.GEQ, 0.0));
374         constraints.add(new LinearConstraint(new double[] {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.136677}, Relationship.GEQ, 0.0));
375         constraints.add(new LinearConstraint(new double[] {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.444434}, Relationship.LEQ, 0.0));
376         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, -1, 0}, Relationship.GEQ, 0.0));
377         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.254028}, Relationship.GEQ, 0.0));
378         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.302218}, Relationship.LEQ, 0.0));
379         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 1, -1, -1, 1, 0, 0, 0, 0, -1, 1, 1, -1, 0, 0, 0, 0, -1, 1, 1, -1, 0, 0, 0, 0, 1, -1, -1, 1, 0}, Relationship.GEQ, 0.0));
380         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.653981}, Relationship.GEQ, 0.0));
381         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.690437}, Relationship.LEQ, 0.0));
382         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 1, 0, -1, 0}, Relationship.GEQ, 0.0));
383         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.423786}, Relationship.GEQ, 0.0));
384         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.486717}, Relationship.LEQ, 0.0));
385         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 1, -1, 0}, Relationship.GEQ, 0.0));
386         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.049232}, Relationship.GEQ, 0.0));
387         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.304747}, Relationship.LEQ, 0.0));
388         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 1, 0}, Relationship.GEQ, 0.0));
389         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.129826}, Relationship.GEQ, 0.0));
390         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.205625}, Relationship.LEQ, 0.0));
391         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 1, -1, 1, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 1, -1, 1, -1, -1, 1, 0}, Relationship.GEQ, 0.0));
392         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.621944}, Relationship.GEQ, 0.0));
393         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.764385}, Relationship.LEQ, 0.0));
394         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 1, 0, -1, 0}, Relationship.GEQ, 0.0));
395         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.432572}, Relationship.GEQ, 0.0));
396         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.480762}, Relationship.LEQ, 0.0));
397         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 1, -1, 0}, Relationship.GEQ, 0.0));
398         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.055983}, Relationship.GEQ, 0.0));
399         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.11378}, Relationship.LEQ, 0.0));
400         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0}, Relationship.GEQ, 0.0));
401         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.009607}, Relationship.GEQ, 0.0));
402         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.057797}, Relationship.LEQ, 0.0));
403         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 1, -1, 0}, Relationship.GEQ, 0.0));
404         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.407308}, Relationship.GEQ, 0.0));
405         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.452749}, Relationship.LEQ, 0.0));
406         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0}, Relationship.GEQ, 0.0));
407         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.269677}, Relationship.GEQ, 0.0));
408         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.321806}, Relationship.LEQ, 0.0));
409         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0}, Relationship.GEQ, 0.0));
410         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.049232}, Relationship.GEQ, 0.0));
411         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.06902}, Relationship.LEQ, 0.0));
412         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0}, Relationship.GEQ, 0.0));
413         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0}, Relationship.GEQ, 0.0));
414         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.028754}, Relationship.LEQ, 0.0));
415         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 0}, Relationship.GEQ, 0.0));
416         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.484254}, Relationship.GEQ, 0.0));
417         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.524607}, Relationship.LEQ, 0.0));
418         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 1, 0, -1, 0}, Relationship.GEQ, 0.0));
419         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.385492}, Relationship.GEQ, 0.0));
420         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.430134}, Relationship.LEQ, 0.0));
421         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, -1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 0}, Relationship.GEQ, 0.0));
422         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.34983}, Relationship.GEQ, 0.0));
423         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.375781}, Relationship.LEQ, 0.0));
424         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, 1, 0}, Relationship.GEQ, 0.0));
425         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.254028}, Relationship.GEQ, 0.0));
426         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.281308}, Relationship.LEQ, 0.0));
427         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 1, 0, 0, 0, 0, -1, 1, 1, -1, 0}, Relationship.GEQ, 0.0));
428         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.304995}, Relationship.GEQ, 0.0));
429         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.345347}, Relationship.LEQ, 0.0));
430         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, -1, 0, 1, 0}, Relationship.GEQ, 0.0));
431         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.288899}, Relationship.GEQ, 0.0));
432         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.332212}, Relationship.LEQ, 0.0));
433         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, -1, 1, 0}, Relationship.GEQ, 0.0));
434         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.14351}, Relationship.GEQ, 0.0));
435         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.17057}, Relationship.LEQ, 0.0));
436         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0}, Relationship.GEQ, 0.0));
437         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -0.129826}, Relationship.GEQ, 0.0));
438         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -0.157435}, Relationship.LEQ, 0.0));
439         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 1, -1, 1, 1, -1, 0}, Relationship.GEQ, 0.0));
440         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -0}, Relationship.GEQ, 0.0));
441         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1}, Relationship.LEQ, 0.0));
442         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, -1, 0, 1, 0}, Relationship.GEQ, 0.0));
443         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -0.141071}, Relationship.GEQ, 0.0));
444         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -0.232574}, Relationship.LEQ, 0.0));
445         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, -1, 1, 0}, Relationship.GEQ, 0.0));
446         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -0}, Relationship.GEQ, 0.0));
447         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1}, Relationship.LEQ, 0.0));
448         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0}, Relationship.GEQ, 0.0));
449         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -0.009607}, Relationship.GEQ, 0.0));
450         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -0.057797}, Relationship.LEQ, 0.0));
451         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 1, 0}, Relationship.GEQ, 0.0));
452         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -0}, Relationship.GEQ, 0.0));
453         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1}, Relationship.LEQ, 0.0));
454         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0}, Relationship.GEQ, 0.0));
455         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -0.091644}, Relationship.GEQ, 0.0));
456         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -0.203531}, Relationship.LEQ, 0.0));
457         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0}, Relationship.GEQ, 0.0));
458         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -0}, Relationship.GEQ, 0.0));
459         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1}, Relationship.LEQ, 0.0));
460         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, Relationship.GEQ, 0.0));
461         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, Relationship.GEQ, 0.0));
462         constraints.add(new LinearConstraint(new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -0.028754}, Relationship.LEQ, 0.0));
463         constraints.add(new LinearConstraint(new double[] {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Relationship.EQ, 1.0));
464         return constraints;
465     }
466 
467     @Test
468     public void testSimplexSolver() {
469         LinearObjectiveFunction f =
470             new LinearObjectiveFunction(new double[] { 15, 10 }, 7);
471         Collection<LinearConstraint> constraints = new ArrayList<>();
472         constraints.add(new LinearConstraint(new double[] { 1, 0 }, Relationship.LEQ, 2));
473         constraints.add(new LinearConstraint(new double[] { 0, 1 }, Relationship.LEQ, 3));
474         constraints.add(new LinearConstraint(new double[] { 1, 1 }, Relationship.EQ, 4));
475 
476         SimplexSolver solver = new SimplexSolver();
477         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
478                                                   GoalType.MAXIMIZE, new NonNegativeConstraint(true));
479         Assert.assertEquals(2.0, solution.getPoint()[0], 0.0);
480         Assert.assertEquals(2.0, solution.getPoint()[1], 0.0);
481         Assert.assertEquals(57.0, solution.getValue(), 0.0);
482     }
483 
484     @Test
485     public void testSingleVariableAndConstraint() {
486         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 3 }, 0);
487         Collection<LinearConstraint> constraints = new ArrayList<>();
488         constraints.add(new LinearConstraint(new double[] { 1 }, Relationship.LEQ, 10));
489 
490         SimplexSolver solver = new SimplexSolver();
491         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
492                                                   GoalType.MAXIMIZE, new NonNegativeConstraint(false));
493         Assert.assertEquals(10.0, solution.getPoint()[0], 0.0);
494         Assert.assertEquals(30.0, solution.getValue(), 0.0);
495     }
496 
497     /**
498      * With no artificial variables needed (no equals and no greater than
499      * constraints) we can go straight to Phase 2.
500      */
501     @Test
502     public void testModelWithNoArtificialVars() {
503         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 15, 10 }, 0);
504         Collection<LinearConstraint> constraints = new ArrayList<>();
505         constraints.add(new LinearConstraint(new double[] { 1, 0 }, Relationship.LEQ, 2));
506         constraints.add(new LinearConstraint(new double[] { 0, 1 }, Relationship.LEQ, 3));
507         constraints.add(new LinearConstraint(new double[] { 1, 1 }, Relationship.LEQ, 4));
508 
509         SimplexSolver solver = new SimplexSolver();
510         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
511                                                   GoalType.MAXIMIZE, new NonNegativeConstraint(false));
512         Assert.assertEquals(2.0, solution.getPoint()[0], 0.0);
513         Assert.assertEquals(2.0, solution.getPoint()[1], 0.0);
514         Assert.assertEquals(50.0, solution.getValue(), 0.0);
515     }
516 
517     @Test
518     public void testMinimization() {
519         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { -2, 1 }, -5);
520         Collection<LinearConstraint> constraints = new ArrayList<>();
521         constraints.add(new LinearConstraint(new double[] { 1, 2 }, Relationship.LEQ, 6));
522         constraints.add(new LinearConstraint(new double[] { 3, 2 }, Relationship.LEQ, 12));
523         constraints.add(new LinearConstraint(new double[] { 0, 1 }, Relationship.GEQ, 0));
524 
525         SimplexSolver solver = new SimplexSolver();
526         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
527                                                   GoalType.MINIMIZE, new NonNegativeConstraint(false));
528         Assert.assertEquals(4.0, solution.getPoint()[0], 0.0);
529         Assert.assertEquals(0.0, solution.getPoint()[1], 0.0);
530         Assert.assertEquals(-13.0, solution.getValue(), 0.0);
531     }
532 
533     @Test
534     public void testSolutionWithNegativeDecisionVariable() {
535         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { -2, 1 }, 0);
536         Collection<LinearConstraint> constraints = new ArrayList<>();
537         constraints.add(new LinearConstraint(new double[] { 1, 1 }, Relationship.GEQ, 6));
538         constraints.add(new LinearConstraint(new double[] { 1, 2 }, Relationship.LEQ, 14));
539 
540         SimplexSolver solver = new SimplexSolver();
541         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
542                                                   GoalType.MAXIMIZE, new NonNegativeConstraint(false));
543         Assert.assertEquals(-2.0, solution.getPoint()[0], 0.0);
544         Assert.assertEquals(8.0, solution.getPoint()[1], 0.0);
545         Assert.assertEquals(12.0, solution.getValue(), 0.0);
546     }
547 
548     @Test(expected = NoFeasibleSolutionException.class)
549     public void testInfeasibleSolution() {
550         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 15 }, 0);
551         Collection<LinearConstraint> constraints = new ArrayList<>();
552         constraints.add(new LinearConstraint(new double[] { 1 }, Relationship.LEQ, 1));
553         constraints.add(new LinearConstraint(new double[] { 1 }, Relationship.GEQ, 3));
554 
555         SimplexSolver solver = new SimplexSolver();
556         solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
557                         GoalType.MAXIMIZE, new NonNegativeConstraint(false));
558     }
559 
560     @Test(expected = UnboundedSolutionException.class)
561     public void testUnboundedSolution() {
562         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 15, 10 }, 0);
563         Collection<LinearConstraint> constraints = new ArrayList<>();
564         constraints.add(new LinearConstraint(new double[] { 1, 0 }, Relationship.EQ, 2));
565 
566         SimplexSolver solver = new SimplexSolver();
567         solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
568                         GoalType.MAXIMIZE, new NonNegativeConstraint(false));
569     }
570 
571     @Test
572     public void testRestrictVariablesToNonNegative() {
573         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 409, 523, 70, 204, 339 }, 0);
574         Collection<LinearConstraint> constraints = new ArrayList<>();
575         constraints.add(new LinearConstraint(new double[] {    43,   56, 345,  56,    5 }, Relationship.LEQ,  4567456));
576         constraints.add(new LinearConstraint(new double[] {    12,   45,   7,  56,   23 }, Relationship.LEQ,    56454));
577         constraints.add(new LinearConstraint(new double[] {     8,  768,   0,  34, 7456 }, Relationship.LEQ,  1923421));
578         constraints.add(new LinearConstraint(new double[] { 12342, 2342,  34, 678, 2342 }, Relationship.GEQ,     4356));
579         constraints.add(new LinearConstraint(new double[] {    45,  678,  76,  52,   23 }, Relationship.EQ,    456356));
580 
581         SimplexSolver solver = new SimplexSolver();
582         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
583                                                   GoalType.MAXIMIZE, new NonNegativeConstraint(true));
584         Assert.assertEquals(2902.92783505155, solution.getPoint()[0], .0000001);
585         Assert.assertEquals(480.419243986254, solution.getPoint()[1], .0000001);
586         Assert.assertEquals(0.0, solution.getPoint()[2], .0000001);
587         Assert.assertEquals(0.0, solution.getPoint()[3], .0000001);
588         Assert.assertEquals(0.0, solution.getPoint()[4], .0000001);
589         Assert.assertEquals(1438556.7491409, solution.getValue(), .0000001);
590     }
591 
592     @Test
593     public void testEpsilon() {
594       LinearObjectiveFunction f =
595           new LinearObjectiveFunction(new double[] { 10, 5, 1 }, 0);
596       Collection<LinearConstraint> constraints = new ArrayList<>();
597       constraints.add(new LinearConstraint(new double[] {  9, 8, 0 }, Relationship.EQ,  17));
598       constraints.add(new LinearConstraint(new double[] {  0, 7, 8 }, Relationship.LEQ,  7));
599       constraints.add(new LinearConstraint(new double[] { 10, 0, 2 }, Relationship.LEQ, 10));
600 
601       SimplexSolver solver = new SimplexSolver();
602       PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
603                                                 GoalType.MAXIMIZE, new NonNegativeConstraint(false));
604       Assert.assertEquals(1.0, solution.getPoint()[0], 0.0);
605       Assert.assertEquals(1.0, solution.getPoint()[1], 0.0);
606       Assert.assertEquals(0.0, solution.getPoint()[2], 0.0);
607       Assert.assertEquals(15.0, solution.getValue(), 0.0);
608   }
609 
610     @Test
611     public void testTrivialModel() {
612         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 1, 1 }, 0);
613         Collection<LinearConstraint> constraints = new ArrayList<>();
614         constraints.add(new LinearConstraint(new double[] { 1, 1 }, Relationship.EQ,  0));
615 
616         SimplexSolver solver = new SimplexSolver();
617         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
618                                                   GoalType.MAXIMIZE, new NonNegativeConstraint(true));
619         Assert.assertEquals(0, solution.getValue(), .0000001);
620     }
621 
622     @Test
623     public void testLargeModel() {
624         double[] objective = new double[] {
625                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
626                                            1, 1, 12, 1, 1, 1, 1, 1, 1, 1,
627                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
628                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
629                                            12, 1, 1, 1, 1, 1, 1, 1, 1, 1,
630                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
631                                            1, 1, 1, 1, 1, 1, 1, 1, 12, 1,
632                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
633                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
634                                            1, 1, 1, 1, 1, 1, 12, 1, 1, 1,
635                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
636                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
637                                            1, 1, 1, 1, 12, 1, 1, 1, 1, 1,
638                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
639                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
640                                            1, 1, 12, 1, 1, 1, 1, 1, 1, 1,
641                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
642                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
643                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
644                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
645                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
646                                            1, 1, 1, 1, 1, 1};
647 
648         LinearObjectiveFunction f = new LinearObjectiveFunction(objective, 0);
649         Collection<LinearConstraint> constraints = new ArrayList<>();
650         constraints.add(equationFromString(objective.length, "x0 + x1 + x2 + x3 - x12 = 0"));
651         constraints.add(equationFromString(objective.length, "x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 - x13 = 0"));
652         constraints.add(equationFromString(objective.length, "x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 >= 49"));
653         constraints.add(equationFromString(objective.length, "x0 + x1 + x2 + x3 >= 42"));
654         constraints.add(equationFromString(objective.length, "x14 + x15 + x16 + x17 - x26 = 0"));
655         constraints.add(equationFromString(objective.length, "x18 + x19 + x20 + x21 + x22 + x23 + x24 + x25 - x27 = 0"));
656         constraints.add(equationFromString(objective.length, "x14 + x15 + x16 + x17 - x12 = 0"));
657         constraints.add(equationFromString(objective.length, "x18 + x19 + x20 + x21 + x22 + x23 + x24 + x25 - x13 = 0"));
658         constraints.add(equationFromString(objective.length, "x28 + x29 + x30 + x31 - x40 = 0"));
659         constraints.add(equationFromString(objective.length, "x32 + x33 + x34 + x35 + x36 + x37 + x38 + x39 - x41 = 0"));
660         constraints.add(equationFromString(objective.length, "x32 + x33 + x34 + x35 + x36 + x37 + x38 + x39 >= 49"));
661         constraints.add(equationFromString(objective.length, "x28 + x29 + x30 + x31 >= 42"));
662         constraints.add(equationFromString(objective.length, "x42 + x43 + x44 + x45 - x54 = 0"));
663         constraints.add(equationFromString(objective.length, "x46 + x47 + x48 + x49 + x50 + x51 + x52 + x53 - x55 = 0"));
664         constraints.add(equationFromString(objective.length, "x42 + x43 + x44 + x45 - x40 = 0"));
665         constraints.add(equationFromString(objective.length, "x46 + x47 + x48 + x49 + x50 + x51 + x52 + x53 - x41 = 0"));
666         constraints.add(equationFromString(objective.length, "x56 + x57 + x58 + x59 - x68 = 0"));
667         constraints.add(equationFromString(objective.length, "x60 + x61 + x62 + x63 + x64 + x65 + x66 + x67 - x69 = 0"));
668         constraints.add(equationFromString(objective.length, "x60 + x61 + x62 + x63 + x64 + x65 + x66 + x67 >= 51"));
669         constraints.add(equationFromString(objective.length, "x56 + x57 + x58 + x59 >= 44"));
670         constraints.add(equationFromString(objective.length, "x70 + x71 + x72 + x73 - x82 = 0"));
671         constraints.add(equationFromString(objective.length, "x74 + x75 + x76 + x77 + x78 + x79 + x80 + x81 - x83 = 0"));
672         constraints.add(equationFromString(objective.length, "x70 + x71 + x72 + x73 - x68 = 0"));
673         constraints.add(equationFromString(objective.length, "x74 + x75 + x76 + x77 + x78 + x79 + x80 + x81 - x69 = 0"));
674         constraints.add(equationFromString(objective.length, "x84 + x85 + x86 + x87 - x96 = 0"));
675         constraints.add(equationFromString(objective.length, "x88 + x89 + x90 + x91 + x92 + x93 + x94 + x95 - x97 = 0"));
676         constraints.add(equationFromString(objective.length, "x88 + x89 + x90 + x91 + x92 + x93 + x94 + x95 >= 51"));
677         constraints.add(equationFromString(objective.length, "x84 + x85 + x86 + x87 >= 44"));
678         constraints.add(equationFromString(objective.length, "x98 + x99 + x100 + x101 - x110 = 0"));
679         constraints.add(equationFromString(objective.length, "x102 + x103 + x104 + x105 + x106 + x107 + x108 + x109 - x111 = 0"));
680         constraints.add(equationFromString(objective.length, "x98 + x99 + x100 + x101 - x96 = 0"));
681         constraints.add(equationFromString(objective.length, "x102 + x103 + x104 + x105 + x106 + x107 + x108 + x109 - x97 = 0"));
682         constraints.add(equationFromString(objective.length, "x112 + x113 + x114 + x115 - x124 = 0"));
683         constraints.add(equationFromString(objective.length, "x116 + x117 + x118 + x119 + x120 + x121 + x122 + x123 - x125 = 0"));
684         constraints.add(equationFromString(objective.length, "x116 + x117 + x118 + x119 + x120 + x121 + x122 + x123 >= 49"));
685         constraints.add(equationFromString(objective.length, "x112 + x113 + x114 + x115 >= 42"));
686         constraints.add(equationFromString(objective.length, "x126 + x127 + x128 + x129 - x138 = 0"));
687         constraints.add(equationFromString(objective.length, "x130 + x131 + x132 + x133 + x134 + x135 + x136 + x137 - x139 = 0"));
688         constraints.add(equationFromString(objective.length, "x126 + x127 + x128 + x129 - x124 = 0"));
689         constraints.add(equationFromString(objective.length, "x130 + x131 + x132 + x133 + x134 + x135 + x136 + x137 - x125 = 0"));
690         constraints.add(equationFromString(objective.length, "x140 + x141 + x142 + x143 - x152 = 0"));
691         constraints.add(equationFromString(objective.length, "x144 + x145 + x146 + x147 + x148 + x149 + x150 + x151 - x153 = 0"));
692         constraints.add(equationFromString(objective.length, "x144 + x145 + x146 + x147 + x148 + x149 + x150 + x151 >= 59"));
693         constraints.add(equationFromString(objective.length, "x140 + x141 + x142 + x143 >= 42"));
694         constraints.add(equationFromString(objective.length, "x154 + x155 + x156 + x157 - x166 = 0"));
695         constraints.add(equationFromString(objective.length, "x158 + x159 + x160 + x161 + x162 + x163 + x164 + x165 - x167 = 0"));
696         constraints.add(equationFromString(objective.length, "x154 + x155 + x156 + x157 - x152 = 0"));
697         constraints.add(equationFromString(objective.length, "x158 + x159 + x160 + x161 + x162 + x163 + x164 + x165 - x153 = 0"));
698         constraints.add(equationFromString(objective.length, "x83 + x82 - x168 = 0"));
699         constraints.add(equationFromString(objective.length, "x111 + x110 - x169 = 0"));
700         constraints.add(equationFromString(objective.length, "x170 - x182 = 0"));
701         constraints.add(equationFromString(objective.length, "x171 - x183 = 0"));
702         constraints.add(equationFromString(objective.length, "x172 - x184 = 0"));
703         constraints.add(equationFromString(objective.length, "x173 - x185 = 0"));
704         constraints.add(equationFromString(objective.length, "x174 - x186 = 0"));
705         constraints.add(equationFromString(objective.length, "x175 + x176 - x187 = 0"));
706         constraints.add(equationFromString(objective.length, "x177 - x188 = 0"));
707         constraints.add(equationFromString(objective.length, "x178 - x189 = 0"));
708         constraints.add(equationFromString(objective.length, "x179 - x190 = 0"));
709         constraints.add(equationFromString(objective.length, "x180 - x191 = 0"));
710         constraints.add(equationFromString(objective.length, "x181 - x192 = 0"));
711         constraints.add(equationFromString(objective.length, "x170 - x26 = 0"));
712         constraints.add(equationFromString(objective.length, "x171 - x27 = 0"));
713         constraints.add(equationFromString(objective.length, "x172 - x54 = 0"));
714         constraints.add(equationFromString(objective.length, "x173 - x55 = 0"));
715         constraints.add(equationFromString(objective.length, "x174 - x168 = 0"));
716         constraints.add(equationFromString(objective.length, "x177 - x169 = 0"));
717         constraints.add(equationFromString(objective.length, "x178 - x138 = 0"));
718         constraints.add(equationFromString(objective.length, "x179 - x139 = 0"));
719         constraints.add(equationFromString(objective.length, "x180 - x166 = 0"));
720         constraints.add(equationFromString(objective.length, "x181 - x167 = 0"));
721         constraints.add(equationFromString(objective.length, "x193 - x205 = 0"));
722         constraints.add(equationFromString(objective.length, "x194 - x206 = 0"));
723         constraints.add(equationFromString(objective.length, "x195 - x207 = 0"));
724         constraints.add(equationFromString(objective.length, "x196 - x208 = 0"));
725         constraints.add(equationFromString(objective.length, "x197 - x209 = 0"));
726         constraints.add(equationFromString(objective.length, "x198 + x199 - x210 = 0"));
727         constraints.add(equationFromString(objective.length, "x200 - x211 = 0"));
728         constraints.add(equationFromString(objective.length, "x201 - x212 = 0"));
729         constraints.add(equationFromString(objective.length, "x202 - x213 = 0"));
730         constraints.add(equationFromString(objective.length, "x203 - x214 = 0"));
731         constraints.add(equationFromString(objective.length, "x204 - x215 = 0"));
732         constraints.add(equationFromString(objective.length, "x193 - x182 = 0"));
733         constraints.add(equationFromString(objective.length, "x194 - x183 = 0"));
734         constraints.add(equationFromString(objective.length, "x195 - x184 = 0"));
735         constraints.add(equationFromString(objective.length, "x196 - x185 = 0"));
736         constraints.add(equationFromString(objective.length, "x197 - x186 = 0"));
737         constraints.add(equationFromString(objective.length, "x198 + x199 - x187 = 0"));
738         constraints.add(equationFromString(objective.length, "x200 - x188 = 0"));
739         constraints.add(equationFromString(objective.length, "x201 - x189 = 0"));
740         constraints.add(equationFromString(objective.length, "x202 - x190 = 0"));
741         constraints.add(equationFromString(objective.length, "x203 - x191 = 0"));
742         constraints.add(equationFromString(objective.length, "x204 - x192 = 0"));
743 
744         SimplexSolver solver = new SimplexSolver();
745         PointValuePair solution = solver.optimize(DEFAULT_MAX_ITER, f, new LinearConstraintSet(constraints),
746                                                   GoalType.MINIMIZE, new NonNegativeConstraint(true));
747         Assert.assertEquals(7518.0, solution.getValue(), .0000001);
748     }
749 
750     @Test
751     public void testSolutionCallback() {
752         // re-use the problem from testcase for MATH-288
753         // it normally requires 5 iterations
754 
755         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 7, 3, 0, 0 }, 0 );
756 
757         List<LinearConstraint> constraints = new ArrayList<>();
758         constraints.add(new LinearConstraint(new double[] { 3, 0, -5, 0 }, Relationship.LEQ, 0.0));
759         constraints.add(new LinearConstraint(new double[] { 2, 0, 0, -5 }, Relationship.LEQ, 0.0));
760         constraints.add(new LinearConstraint(new double[] { 0, 3, 0, -5 }, Relationship.LEQ, 0.0));
761         constraints.add(new LinearConstraint(new double[] { 1, 0, 0, 0 }, Relationship.LEQ, 1.0));
762         constraints.add(new LinearConstraint(new double[] { 0, 1, 0, 0 }, Relationship.LEQ, 1.0));
763 
764         final SimplexSolver solver = new SimplexSolver();
765         final SolutionCallback callback = new SolutionCallback();
766 
767         Assert.assertNull(callback.getSolution());
768         Assert.assertFalse(callback.isSolutionOptimal());
769 
770         try {
771             solver.optimize(new MaxIter(4), f, new LinearConstraintSet(constraints),
772                             GoalType.MAXIMIZE, new NonNegativeConstraint(true), callback);
773             Assert.fail("expected TooManyIterationsException");
774         } catch (TooManyIterationsException ex) {
775             // expected
776         }
777 
778         final PointValuePair solution = callback.getSolution();
779         Assert.assertNotNull(solution);
780         Assert.assertTrue(validSolution(solution, constraints, 1e-4));
781         Assert.assertFalse(callback.isSolutionOptimal());
782         // the solution is clearly not optimal: optimal = 10.0
783         Assert.assertEquals(7.0, solution.getValue(), 1e-4);
784     }
785 
786     @Test(expected=DimensionMismatchException.class)
787     public void testDimensionMatch() {
788         // min 2x1 +15x2 +18x3
789         // Subject to
790         //   -x1 +2x2 -6x3  <=-10
791         //         x2 +2x3  <= 6
792         //   2x1      +10x3 <= 19
793         //   -x1  +x2       <= -2
794         // x1,x2,x3 >= 0
795 
796         LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] { 2, 15, 18 }, 0);
797         Collection<LinearConstraint> constraints = new ArrayList<>();
798         // this constraint is wrong, the dimension is less than expected one
799         constraints.add(new LinearConstraint(new double[] { -1, 2 - 6 }, Relationship.LEQ, -10));
800         constraints.add(new LinearConstraint(new double[] { 0, 1, 2 }, Relationship.LEQ, 6));
801         constraints.add(new LinearConstraint(new double[] { 2, 0, 10 }, Relationship.LEQ, 19));
802         constraints.add(new LinearConstraint(new double[] { -1, 1, 0 }, Relationship.LEQ, -2));
803 
804         SimplexSolver solver = new SimplexSolver();
805         solver.optimize(f,
806                         new LinearConstraintSet(constraints),
807                         new NonNegativeConstraint(true),
808                         PivotSelectionRule.BLAND);
809     }
810 
811     /* linear transformation of constants should produce the same result */
812     @Test
813     public void testMath1549() {
814         final double m = 10;
815         double scale = 1e-12;
816         for (int pow = 0; pow < 26; pow++) {
817             tryMath1549(scale);
818             scale *= m;
819         }
820     }
821 
822     /* See JIRA issue: MATH-1549 */
823     private void tryMath1549(double scale) {
824         final NonNegativeConstraint nnegconstr = new NonNegativeConstraint(true);
825         final int ulps = 10;
826         final double cutoff = 1e-10;
827         final double eps = 1e-6;
828         final SimplexSolver solver = new SimplexSolver(eps, ulps, cutoff);
829 
830         final LinearObjectiveFunction f = new LinearObjectiveFunction(new double[] {1, 1}, 0);
831         final List<LinearConstraint> constraints = new ArrayList<>();
832         constraints.add(new LinearConstraint(new double[] {scale * 9000, scale * 1}, Relationship.GEQ, 0));
833         constraints.add(new LinearConstraint(new double[] {scale * 10000, scale}, Relationship.GEQ, scale * 2000));
834         constraints.add(new LinearConstraint(new double[] {scale, 0}, Relationship.GEQ, scale * 2));
835         final LinearConstraintSet constraintSet = new LinearConstraintSet(constraints);
836         final PointValuePair solution = solver.optimize(f, constraintSet, GoalType.MINIMIZE, nnegconstr);
837 
838         Assert.assertEquals(2.0, solution.getPoint()[0], eps);
839     }
840 
841     /**
842      * Converts a test string to a {@link LinearConstraint}.
843      * Ex: x0 + x1 + x2 + x3 - x12 = 0
844      */
845     private LinearConstraint equationFromString(int numCoefficients, String s) {
846         Relationship relationship;
847         if (s.contains(">=")) {
848             relationship = Relationship.GEQ;
849         } else if (s.contains("<=")) {
850             relationship = Relationship.LEQ;
851         } else if (s.contains("=")) {
852             relationship = Relationship.EQ;
853         } else {
854             throw new IllegalArgumentException();
855         }
856 
857         String[] equationParts = s.split("[>|<]?=");
858         double rhs = Double.parseDouble(equationParts[1].trim());
859 
860         double[] lhs = new double[numCoefficients];
861         String left = equationParts[0].replaceAll(" ?x", "");
862         String[] coefficients = left.split(" ");
863         for (String coefficient : coefficients) {
864             double value = coefficient.charAt(0) == '-' ? -1 : 1;
865             int index = Integer.parseInt(coefficient.replaceFirst("[+|-]", "").trim());
866             lhs[index] = value;
867         }
868         return new LinearConstraint(lhs, relationship, rhs);
869     }
870 
871     private static boolean validSolution(PointValuePair solution, List<LinearConstraint> constraints, double epsilon) {
872         double[] vals = solution.getPoint();
873         for (LinearConstraint c : constraints) {
874             double[] coeffs = c.getCoefficients().toArray();
875             double result = 0.0d;
876             for (int i = 0; i < vals.length; i++) {
877                 result += vals[i] * coeffs[i];
878             }
879 
880             switch (c.getRelationship()) {
881             case EQ:
882                 if (!Precision.equals(result, c.getValue(), epsilon)) {
883                     return false;
884                 }
885                 break;
886 
887             case GEQ:
888                 if (Precision.compareTo(result, c.getValue(), epsilon) < 0) {
889                     return false;
890                 }
891                 break;
892 
893             case LEQ:
894                 if (Precision.compareTo(result, c.getValue(), epsilon) > 0) {
895                     return false;
896                 }
897                 break;
898             default:
899                 Assert.fail();
900             }
901         }
902 
903         return true;
904     }
905 }