@@ -4,9 +4,9 @@ jupytext:
44extension: .md
55format_name: myst
66format_version: 0.13
7-jupytext_version: 1.10.3
7+jupytext_version: 1.14.4
88kernelspec:
9-display_name: Python 3
9+display_name: Python 3 (ipykernel)
1010language: python
1111name: python3
1212---
@@ -38,13 +38,11 @@ several implementations of linear programming, including, in order,
38382. the [linprog_simplex](https://quanteconpy.readthedocs.io/en/latest/optimize/linprog_simplex.html) solver from QuantEcon and
39393. the simplex-based solvers included in the [Python Optimal Transport](https://pythonot.github.io/) package.
404041-42-43-4441```{code-cell} ipython3
4542:tags: [hide-output]
43+4644!pip install --upgrade quantecon
47-!pip install --upgrade POT jax jaxlib
45+!pip install --upgrade POT
4846```
49475048Let's start with some imports.
@@ -59,11 +57,6 @@ from scipy.stats import binom, betabinom
5957import networkx as nx
6058```
615962-63-64-65-66-6760## The Optimal Transport Problem
68616962Suppose that $m$ factories produce goods that must be sent to $n$ locations.
@@ -356,7 +349,7 @@ A = np.vstack([A1, A2])
356349b = np.hstack([p, q])
357350358351# Solve the primal problem
359-res = linprog(C_vec, A_eq=A, b_eq=b, method='Revised simplex')
352+res = linprog(C_vec, A_eq=A, b_eq=b)
360353361354# Print results
362355print("message:", res.message)
@@ -405,15 +398,15 @@ However, we find a different transportation plan.
405398Though it is a different plan, it attains the same cost!
406399407400```{code-cell} ipython3
408-linprog(C_vec, A_eq=A[:-1], b_eq=b[:-1], method='Revised simplex')
401+linprog(C_vec, A_eq=A[:-1], b_eq=b[:-1])
409402```
410403411404```{code-cell} ipython3
412-%time linprog(C_vec, A_eq=A[:-1], b_eq=b[:-1], method='Revised simplex')
405+%time linprog(C_vec, A_eq=A[:-1], b_eq=b[:-1])
413406```
414407415408```{code-cell} ipython3
416-%time linprog(C_vec, A_eq=A, b_eq=b, method='Revised simplex')
409+%time linprog(C_vec, A_eq=A, b_eq=b)
417410```
418411419412Evidently, it is slightly quicker to work with the system that removed a redundant constraint.
@@ -438,7 +431,7 @@ cost = []
438431for i in range(1000):
439432440433 np.random.shuffle(arr)
441- res_shuffle = linprog(C_vec, A_eq=A[arr], b_eq=b[arr], method='Revised simplex')
434+ res_shuffle = linprog(C_vec, A_eq=A[arr], b_eq=b[arr])
442435443436 # if find a new solution
444437 sol = tuple(res_shuffle.x)
@@ -460,7 +453,7 @@ These are the same two plans computed earlier.
460453Next, we show that leaving out the first constraint "accidentally" leads to the initial plan that we computed.
461454462455```{code-cell} ipython3
463-linprog(C_vec, A_eq=A[1:], b_eq=b[1:], method='Revised simplex')
456+linprog(C_vec, A_eq=A[1:], b_eq=b[1:])
464457```
465458466459Let's compare this transport plan with
@@ -480,7 +473,7 @@ The minimized cost from the optimal transport plan is given by the $fun$ variabl
480473### Using a Just-in-Time Compiler
481474482475We can also solve optimal transportation problems using a powerful tool from
483-QuantEcon, namely,`quantecon.optimize.linprog_simplex`.
476+QuantEcon, namely, `quantecon.optimize.linprog_simplex`.
484477485478While this routine uses the same simplex algorithm as
486479`scipy.optimize.linprog`, the code is accelerated by using a just-in-time
@@ -523,7 +516,7 @@ Let's do a speed comparison between `scipy.optimize.linprog` and `quantecon.opti
523516524517```{code-cell} ipython3
525518# scipy.optimize.linprog
526-%time res = linprog(C_vec, A_eq=A[:-1, :], b_eq=b[:-1], method='Revised simplex')
519+%time res = linprog(C_vec, A_eq=A[:-1, :], b_eq=b[:-1])
527520```
528521529522```{code-cell} ipython3
@@ -581,7 +574,7 @@ For the same numerical example described above, let's solve the dual problem.
581574```{code-cell} ipython3
582575# Solve the dual problem
583576res_dual = linprog(-b, A_ub=A.T, b_ub=C_vec,
584- bounds=[(None, None)]*(m+n), method='Revised simplex')
577+ bounds=[(None, None)]*(m+n))
585578586579#Print results
587580print("message:", res_dual.message)
@@ -610,7 +603,7 @@ res_dual.x
610603We can compare computational times from using our two tools.
611604612605```{code-cell} ipython3
613-%time linprog(-b, A_ub=A.T, b_ub=C_vec, bounds=[(None, None)]*(m+n), method='Revised simplex')
606+%time linprog(-b, A_ub=A.T, b_ub=C_vec, bounds=[(None, None)]*(m+n))
614607```
615608616609```{code-cell} ipython3
@@ -625,14 +618,14 @@ Try first leaving out the first constraint:
625618626619```{code-cell} ipython3
627620linprog(-b[1:], A_ub=A[1:].T, b_ub=C_vec,
628- bounds=[(None, None)]*(m+n-1), method='Revised simplex')
621+ bounds=[(None, None)]*(m+n-1))
629622```
630623631624Not let's instead leave out the last constraint:
632625633626```{code-cell} ipython3
634627linprog(-b[:-1], A_ub=A[:-1].T, b_ub=C_vec,
635- bounds=[(None, None)]*(m+n-1), method='Revised simplex')
628+ bounds=[(None, None)]*(m+n-1))
636629```
637630638631### Interpretation of dual problem
@@ -687,7 +680,6 @@ X
687680688681Sure enough, we have the same solution and the same cost
689682690-691683```{code-cell} ipython3
692684total_cost = np.sum(X * C)
693685total_cost
@@ -725,8 +717,6 @@ It allocates to the nodes it creates their location, mass, and group.
725717726718Locations are assigned randomly.
727719728-729-730720```{code-cell} ipython3
731721def build_nodes_of_one_type(group='p', n=100, seed=123):
732722@@ -753,7 +743,6 @@ def build_nodes_of_one_type(group='p', n=100, seed=123):
753743Now we build two lists of nodes, each one containing one type (factories or
754744 locations)
755745756-757746```{code-cell} ipython3
758747n_p = 32
759748n_q = 32
@@ -836,8 +825,8 @@ nx.draw_networkx_edges(g,
836825 connectionstyle='arc3,rad=0.1',
837826 alpha=0.6)
838827plt.show()
839-840828```
841829830+```{code-cell} ipython3
842831843-832+```