8
8
from .pivoting import _pivoting , _lex_min_ratio_test
9
9
10
10
11
- FEA_TOL = 1e-6
12
-
13
-
14
11
SimplexResult = namedtuple (
15
12
'SimplexResult' , ['x' , 'lambd' , 'fun' , 'success' , 'status' , 'num_iter' ]
16
13
)
17
14
15
+ FEA_TOL = 1e-6
16
+ TOL_PIV = 1e-7
17
+ TOL_RATIO_DIFF = 1e-13
18
+
19
+ PivOptions = namedtuple (
20
+ 'PivOptions' , ['fea_tol' , 'tol_piv' , 'tol_ratio_diff' ]
21
+ )
22
+ PivOptions .__new__ .__defaults__ = (FEA_TOL , TOL_PIV , TOL_RATIO_DIFF )
23
+
18
24
19
25
@jit (nopython = True , cache = True )
20
26
def linprog_simplex (c , A_ub = np .empty ((0 , 0 )), b_ub = np .empty ((0 ,)),
21
- A_eq = np .empty ((0 , 0 )), b_eq = np .empty ((0 ,)), max_iter = 10 ** 6 ,
27
+ A_eq = np .empty ((0 , 0 )), b_eq = np .empty ((0 ,)),
28
+ max_iter = 10 ** 6 , piv_options = PivOptions (),
22
29
tableau = None , basis = None , x = None , lambd = None ):
23
30
"""
24
31
Solve a linear program in the following form by the simplex
@@ -54,6 +61,19 @@ def linprog_simplex(c, A_ub=np.empty((0, 0)), b_ub=np.empty((0,)),
54
61
max_iter : int, optional(default=10**6)
55
62
Maximum number of iteration to perform.
56
63
64
+ piv_options : PivOptions, optional
65
+ PivOptions namedtuple to set the following tolerance values:
66
+
67
+ fea_tol : float
68
+ Feasibility tolerance (default={FEA_TOL}).
69
+
70
+ tol_piv : float
71
+ Pivot tolerance (default={TOL_PIV}).
72
+
73
+ tol_ratio_diff : float
74
+ Tolerance used in the the lexicographic pivoting
75
+ (default={TOL_RATIO_DIFF}).
76
+
57
77
tableau : ndarray(float, ndim=2), optional
58
78
Temporary ndarray of shape (L+1, n+m+L+1) to store the tableau,
59
79
where L=m+k. Modified in place.
@@ -129,11 +149,12 @@ def linprog_simplex(c, A_ub=np.empty((0, 0)), b_ub=np.empty((0,)),
129
149
130
150
# Phase 1
131
151
success , status , num_iter_1 = \
132
- solve_tableau (tableau , basis , max_iter , skip_aux = False )
152
+ solve_tableau (tableau , basis , max_iter , skip_aux = False ,
153
+ piv_options = piv_options )
133
154
num_iter += num_iter_1
134
155
if not success : # max_iter exceeded
135
156
return SimplexResult (x , lambd , fun , success , status , num_iter )
136
- if tableau [- 1 , - 1 ] > FEA_TOL : # Infeasible
157
+ if tableau [- 1 , - 1 ] > piv_options . fea_tol : # Infeasible
137
158
success = False
138
159
status = 2
139
160
return SimplexResult (x , lambd , fun , success , status , num_iter )
@@ -143,13 +164,19 @@ def linprog_simplex(c, A_ub=np.empty((0, 0)), b_ub=np.empty((0,)),
143
164
144
165
# Phase 2
145
166
success , status , num_iter_2 = \
146
- solve_tableau (tableau , basis , max_iter - num_iter , skip_aux = True )
167
+ solve_tableau (tableau , basis , max_iter - num_iter , skip_aux = True ,
168
+ piv_options = piv_options )
147
169
num_iter += num_iter_2
148
170
fun = get_solution (tableau , basis , x , lambd , b_signs )
149
171
150
172
return SimplexResult (x , lambd , fun , success , status , num_iter )
151
173
152
174
175
+ linprog_simplex .__doc__ = linprog_simplex .__doc__ .format (
176
+ FEA_TOL = FEA_TOL , TOL_PIV = TOL_PIV , TOL_RATIO_DIFF = TOL_RATIO_DIFF
177
+ )
178
+
179
+
153
180
@jit (nopython = True , cache = True )
154
181
def _initialize_tableau (A_ub , b_ub , A_eq , b_eq , tableau , basis ):
155
182
"""
@@ -309,7 +336,8 @@ def _set_criterion_row(c, basis, tableau):
309
336
310
337
311
338
@jit (nopython = True , cache = True )
312
- def solve_tableau (tableau , basis , max_iter = 10 ** 6 , skip_aux = True ):
339
+ def solve_tableau (tableau , basis , max_iter = 10 ** 6 , skip_aux = True ,
340
+ piv_options = PivOptions ()):
313
341
"""
314
342
Perform the simplex algorithm on a given tableau in canonical form.
315
343
@@ -349,6 +377,9 @@ def solve_tableau(tableau, basis, max_iter=10**6, skip_aux=True):
349
377
Whether to skip the coefficients of the auxiliary (or
350
378
artificial) variables in pivot column selection.
351
379
380
+ piv_options : PivOptions, optional
381
+ PivOptions namedtuple to set the tolerance values.
382
+
352
383
Returns
353
384
-------
354
385
success : bool
@@ -373,16 +404,18 @@ def solve_tableau(tableau, basis, max_iter=10**6, skip_aux=True):
373
404
while num_iter < max_iter :
374
405
num_iter += 1
375
406
376
- pivcol_found , pivcol = _pivot_col (tableau , skip_aux )
407
+ pivcol_found , pivcol = _pivot_col (tableau , skip_aux , piv_options )
377
408
378
409
if not pivcol_found : # Optimal
379
410
success = True
380
411
status = 0
381
412
break
382
413
383
414
aux_start = tableau .shape [1 ] - L - 1
384
- pivrow_found , pivrow = _lex_min_ratio_test (tableau [:- 1 , :], pivcol ,
385
- aux_start , argmins )
415
+ pivrow_found , pivrow = _lex_min_ratio_test (
416
+ tableau [:- 1 , :], pivcol , aux_start , argmins ,
417
+ piv_options .tol_piv , piv_options .tol_ratio_diff
418
+ )
386
419
387
420
if not pivrow_found : # Unbounded
388
421
success = False
@@ -396,7 +429,7 @@ def solve_tableau(tableau, basis, max_iter=10**6, skip_aux=True):
396
429
397
430
398
431
@jit (nopython = True , cache = True )
399
- def _pivot_col (tableau , skip_aux ):
432
+ def _pivot_col (tableau , skip_aux , piv_options ):
400
433
"""
401
434
Choose the column containing the pivot element: the column
402
435
containing the maximum positive element in the last row of the
@@ -413,6 +446,9 @@ def _pivot_col(tableau, skip_aux):
413
446
Whether to skip the coefficients of the auxiliary (or
414
447
artificial) variables in pivot column selection.
415
448
449
+ piv_options : PivOptions, optional
450
+ PivOptions namedtuple to set the tolerance values.
451
+
416
452
Returns
417
453
-------
418
454
found : bool
@@ -431,7 +467,7 @@ def _pivot_col(tableau, skip_aux):
431
467
432
468
found = False
433
469
pivcol = - 1
434
- coeff = FEA_TOL
470
+ coeff = piv_options . fea_tol
435
471
for j in range (criterion_row_stop ):
436
472
if tableau [- 1 , j ] > coeff :
437
473
coeff = tableau [- 1 , j ]
0 commit comments