Skip to content

Commit 49991e5

Browse files
committed
Add PivOptions
1 parent 5da62e7 commit 49991e5

File tree

2 files changed

+52
-14
lines changed

2 files changed

+52
-14
lines changed

quantecon/optimize/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
"""
33
Initialization of the optimize subpackage
44
"""
5-
from .linprog_simplex import linprog_simplex, solve_tableau, get_solution
5+
from .linprog_simplex import (
6+
linprog_simplex, solve_tableau, get_solution, PivOptions
7+
)
68
from .scalar_maximization import brent_max
79
from .nelder_mead import nelder_mead
810
from .root_finding import newton, newton_halley, newton_secant, bisect, brentq

quantecon/optimize/linprog_simplex.py

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,24 @@
88
from .pivoting import _pivoting, _lex_min_ratio_test
99

1010

11-
FEA_TOL = 1e-6
12-
13-
1411
SimplexResult = namedtuple(
1512
'SimplexResult', ['x', 'lambd', 'fun', 'success', 'status', 'num_iter']
1613
)
1714

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+
1824

1925
@jit(nopython=True, cache=True)
2026
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(),
2229
tableau=None, basis=None, x=None, lambd=None):
2330
"""
2431
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,)),
5461
max_iter : int, optional(default=10**6)
5562
Maximum number of iteration to perform.
5663
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+
5777
tableau : ndarray(float, ndim=2), optional
5878
Temporary ndarray of shape (L+1, n+m+L+1) to store the tableau,
5979
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,)),
129149

130150
# Phase 1
131151
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)
133154
num_iter += num_iter_1
134155
if not success: # max_iter exceeded
135156
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
137158
success = False
138159
status = 2
139160
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,)),
143164

144165
# Phase 2
145166
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)
147169
num_iter += num_iter_2
148170
fun = get_solution(tableau, basis, x, lambd, b_signs)
149171

150172
return SimplexResult(x, lambd, fun, success, status, num_iter)
151173

152174

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+
153180
@jit(nopython=True, cache=True)
154181
def _initialize_tableau(A_ub, b_ub, A_eq, b_eq, tableau, basis):
155182
"""
@@ -309,7 +336,8 @@ def _set_criterion_row(c, basis, tableau):
309336

310337

311338
@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()):
313341
"""
314342
Perform the simplex algorithm on a given tableau in canonical form.
315343
@@ -349,6 +377,9 @@ def solve_tableau(tableau, basis, max_iter=10**6, skip_aux=True):
349377
Whether to skip the coefficients of the auxiliary (or
350378
artificial) variables in pivot column selection.
351379
380+
piv_options : PivOptions, optional
381+
PivOptions namedtuple to set the tolerance values.
382+
352383
Returns
353384
-------
354385
success : bool
@@ -373,16 +404,18 @@ def solve_tableau(tableau, basis, max_iter=10**6, skip_aux=True):
373404
while num_iter < max_iter:
374405
num_iter += 1
375406

376-
pivcol_found, pivcol = _pivot_col(tableau, skip_aux)
407+
pivcol_found, pivcol = _pivot_col(tableau, skip_aux, piv_options)
377408

378409
if not pivcol_found: # Optimal
379410
success = True
380411
status = 0
381412
break
382413

383414
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+
)
386419

387420
if not pivrow_found: # Unbounded
388421
success = False
@@ -396,7 +429,7 @@ def solve_tableau(tableau, basis, max_iter=10**6, skip_aux=True):
396429

397430

398431
@jit(nopython=True, cache=True)
399-
def _pivot_col(tableau, skip_aux):
432+
def _pivot_col(tableau, skip_aux, piv_options):
400433
"""
401434
Choose the column containing the pivot element: the column
402435
containing the maximum positive element in the last row of the
@@ -413,6 +446,9 @@ def _pivot_col(tableau, skip_aux):
413446
Whether to skip the coefficients of the auxiliary (or
414447
artificial) variables in pivot column selection.
415448
449+
piv_options : PivOptions, optional
450+
PivOptions namedtuple to set the tolerance values.
451+
416452
Returns
417453
-------
418454
found : bool
@@ -431,7 +467,7 @@ def _pivot_col(tableau, skip_aux):
431467

432468
found = False
433469
pivcol = -1
434-
coeff = FEA_TOL
470+
coeff = piv_options.fea_tol
435471
for j in range(criterion_row_stop):
436472
if tableau[-1, j] > coeff:
437473
coeff = tableau[-1, j]

0 commit comments

Comments
 (0)