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