Interactive Simplex Method#
This module, meant for educational purposes only, supports learning and exploring of the simplex method.
Do you want to solve Linear Programs efficiently? use
MixedIntegerLinearProgram
instead.
The methods implemented here allow solving Linear Programming Problems (LPPs) in a number of ways, may require explicit (and correct!) description of steps and are likely to be much slower than “regular” LP solvers. If, however, you want to learn how the simplex method works and see what happens in different situations using different strategies, but don’t want to deal with tedious arithmetic, this module is for you!
Historically it was created to complement the Math 373 course on Mathematical Programming and Optimization at the University of Alberta, Edmonton, Canada.
AUTHORS:
Andrey Novoseltsev (2013-03-16): initial version.
Matthias Koeppe, Peijun Xiao (2015-07-05): allow different output styles.
EXAMPLES:
Most of the module functionality is demonstrated on the following problem.
Using variables \(C\) and \(B\) for land used to grow corn and barley respectively, in acres, we can construct the following LP problem:
sage: A = ([1, 1], [3, 1])
sage: b = (1000, 1500)
sage: c = (10, 5)
sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=")
sage: P
LP problem (use 'view(...)' or '%display typeset' for details)
It is recommended to copy-paste such examples into your own worksheet, so that
you can run these commands with typeset mode on (%display typeset
) and get
Since it has only two variables, we can solve it graphically:
sage: P.plot()
Graphics object consisting of 19 graphics primitives
The simplex method can be applied only to problems in standard form
, which can be created either directly
sage: InteractiveLPProblemStandardForm(A, b, c, ["C", "B"])
LP problem (use ...)
or from an already constructed problem of “general type”:
sage: P = P.standard_form()
In this case the problem does not require any modifications to be written in standard form, but this step is still necessary to enable methods related to the simplex method.
The simplest way to use the simplex method is:
sage: P.run_simplex_method()
\begin{equation*}
...
The optimal value: $6250$. An optimal solution: $\left(250,\,750\right)$.
(This method produces quite long formulas which have been omitted here.) But, of course, it is much more fun to do most of the steps by hand. Let’s start by creating the initial dictionary:
sage: D = P.initial_dictionary()
sage: D
LP problem dictionary (use ...)
Using typeset mode as recommended, you’ll see
With the initial or any other dictionary you can perform a number of checks:
sage: D.is_feasible()
True
sage: D.is_optimal()
False
You can look at many of its pieces and associated data:
sage: D.basic_variables()
(x3, x4)
sage: D.basic_solution()
(0, 0)
sage: D.objective_value()
0
Most importantly, you can perform steps of the simplex method by picking an entering variable, a leaving variable, and updating the dictionary:
sage: D.enter("C")
sage: D.leave(4)
sage: D.update()
If everything was done correctly, the new dictionary is still feasible and the objective value did not decrease:
sage: D.is_feasible()
True
sage: D.objective_value()
5000
If you are unsure about picking entering and leaving variables, you can use helper methods that will try their best to tell you what are your next options:
sage: D.possible_entering()
[B]
sage: D.possible_leaving()
Traceback (most recent call last):
...
ValueError: leaving variables can be determined
for feasible dictionaries with a set entering variable
or for dual feasible dictionaries
It is also possible to obtain feasible sets
and final dictionaries
of
problems, work with revised dictionaries
,
and use the dual simplex method!
Note
Currently this does not have a display format for the terminal.
Classes and functions#
- class sage.numerical.interactive_simplex_method.InteractiveLPProblem(A, b, c, x='x', constraint_type='<=', variable_type='', problem_type='max', base_ring=None, is_primal=True, objective_constant_term=0)#
Bases:
SageObject
Construct an LP (Linear Programming) problem.
Note
This class is for educational purposes only: if you want to solve Linear Programs efficiently, use
MixedIntegerLinearProgram
instead.This class supports LP problems with “variables on the left” constraints.
INPUT:
A
– a matrix of constraint coefficientsb
– a vector of constraint constant termsc
– a vector of objective coefficientsx
– (default:"x"
) a vector of decision variables or a string giving the base nameconstraint_type
– (default:"<="
) a string specifying constraint type(s): either"<="
,">="
,"=="
, or a list of themvariable_type
– (default:""
) a string specifying variable type(s): either">="
,"<="
,""
(the empty string), or a list of them, corresponding, respectively, to non-negative, non-positive, and free variablesproblem_type
– (default:"max"
) a string specifying the problem type:"max"
,"min"
,"-max"
, or"-min"
base_ring
– (default: the fraction field of a common ring for all input coefficients) a field to which all input coefficients will be convertedis_primal
– (default:True
) whether this problem is primal or dual: each problem is of course dual to its own dual, this flag is mostly for internal use and affects default variable names onlyobjective_constant_term
– (default: 0) a constant term of the objective
EXAMPLES:
We will construct the following problem:
\[\begin{split}\begin{array}{l} \begin{array}{lcrcrcl} \max \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} 10 C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 5 B \mspace{-6mu} \\ \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} B \mspace{-6mu}&\mspace{-6mu} \leq \mspace{-6mu}&\mspace{-6mu} 1000 \\ \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} 3 C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} B \mspace{-6mu}&\mspace{-6mu} \leq \mspace{-6mu}&\mspace{-6mu} 1500 \\ \end{array} \\ C, B \geq 0 \end{array}\end{split}\]sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=")
Same problem, but more explicitly:
sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], ....: constraint_type="<=", variable_type=">=")
Even more explicitly:
sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], problem_type="max", ....: constraint_type=["<=", "<="], variable_type=[">=", ">="])
Using the last form you should be able to represent any LP problem, as long as all like terms are collected and in constraints variables and constants are on different sides.
- A()#
Return coefficients of constraints of
self
, i.e. \(A\).OUTPUT:
a matrix
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.constraint_coefficients() [1 1] [3 1] sage: P.A() [1 1] [3 1]
- Abcx()#
Return \(A\), \(b\), \(c\), and \(x\) of
self
as a tuple.OUTPUT:
a tuple
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.Abcx() ( [1 1] [3 1], (1000, 1500), (10, 5), (C, B) )
- add_constraint(coefficients, constant_term, constraint_type='<=')#
Return a new LP problem by adding a constraint to``self``.
INPUT:
coefficients
– coefficients of the new constraintconstant_term
– a constant term of the new constraintconstraint_type
– (default:"<="
) a string indicating the constraint type of the new constraint
OUTPUT:
an
LP problem
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c) sage: P1 = P.add_constraint(([2, 4]), 2000, "<=") sage: P1.Abcx() ( [1 1] [3 1] [2 4], (1000, 1500, 2000), (10, 5), (x1, x2) ) sage: P1.constraint_types() ('<=', '<=', '<=') sage: P.Abcx() ( [1 1] [3 1], (1000, 1500), (10, 5), (x1, x2) ) sage: P.constraint_types() ('<=', '<=') sage: P2 = P.add_constraint(([2, 4, 6]), 2000, "<=") Traceback (most recent call last): ... TypeError: number of columns must be the same, not 2 and 3 sage: P3 = P.add_constraint(([2, 4]), 2000, "<") Traceback (most recent call last): ... ValueError: unknown constraint type
- b()#
Return constant terms of constraints of
self
, i.e. \(b\).OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.constant_terms() (1000, 1500) sage: P.b() (1000, 1500)
- base_ring()#
Return the base ring of
self
.Note
The base ring of LP problems is always a field.
OUTPUT:
a ring
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.base_ring() Rational Field sage: c = (10, 5.) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.base_ring() Real Field with 53 bits of precision
- c()#
Return coefficients of the objective of
self
, i.e. \(c\).OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.objective_coefficients() (10, 5) sage: P.c() (10, 5)
- constant_terms()#
Return constant terms of constraints of
self
, i.e. \(b\).OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.constant_terms() (1000, 1500) sage: P.b() (1000, 1500)
- constraint_coefficients()#
Return coefficients of constraints of
self
, i.e. \(A\).OUTPUT:
a matrix
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.constraint_coefficients() [1 1] [3 1] sage: P.A() [1 1] [3 1]
- constraint_types()#
Return a tuple listing the constraint types of all rows.
OUTPUT:
a tuple of strings
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=", constraint_type=["<=", "=="]) sage: P.constraint_types() ('<=', '==')
- decision_variables()#
Return decision variables of
self
, i.e. \(x\).OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.decision_variables() (C, B) sage: P.x() (C, B)
- dual(y=None)#
Construct the dual LP problem for
self
.INPUT:
y
– (default: depends onstyle()
) a vector of dual decision variables or a string giving the base name
OUTPUT:
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: DP = P.dual() sage: DP.b() == P.c() True sage: DP.dual(["C", "B"]) == P True
- feasible_set()#
Return the feasible set of
self
.OUTPUT:
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.feasible_set() A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices
- is_bounded()#
Check if
self
is bounded.OUTPUT:
True
isself
is bounded,False
otherwise
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.is_bounded() True
Note that infeasible problems are always bounded:
sage: b = (-1000, 1500) sage: P = InteractiveLPProblem(A, b, c, variable_type=">=") sage: P.is_feasible() False sage: P.is_bounded() True
- is_feasible(*x)#
Check if
self
or given solution is feasible.INPUT:
(optional) anything that can be interpreted as a valid solution for this problem, i.e. a sequence of values for all decision variables
OUTPUT:
True
is this problem or given solution is feasible,False
otherwise
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, variable_type=">=") sage: P.is_feasible() True sage: P.is_feasible(100, 200) True sage: P.is_feasible(1000, 200) False sage: P.is_feasible([1000, 200]) False sage: P.is_feasible(1000) Traceback (most recent call last): ... TypeError: given input is not a solution for this problem
- is_negative()#
Return \(True\) when the problem is of type
"-max"
or"-min"
.EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.is_negative() False sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=", problem_type="-min") sage: P.is_negative() True
- is_optimal(*x)#
Check if given solution is feasible.
INPUT:
anything that can be interpreted as a valid solution for this problem, i.e. a sequence of values for all decision variables
OUTPUT:
True
is the given solution is optimal,False
otherwise
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (15, 5) sage: P = InteractiveLPProblem(A, b, c, variable_type=">=") sage: P.is_optimal(100, 200) False sage: P.is_optimal(500, 0) True sage: P.is_optimal(499, 3) True sage: P.is_optimal(501, -3) False
- is_primal()#
Check if we consider this problem to be primal or dual.
This distinction affects only some automatically chosen variable names.
OUTPUT:
boolean
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.is_primal() True sage: P.dual().is_primal() False
- m()#
Return the number of constraints of
self
, i.e. \(m\).OUTPUT:
an integer
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.n_constraints() 2 sage: P.m() 2
- n()#
Return the number of decision variables of
self
, i.e. \(n\).OUTPUT:
an integer
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.n_variables() 2 sage: P.n() 2
- n_constraints()#
Return the number of constraints of
self
, i.e. \(m\).OUTPUT:
an integer
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.n_constraints() 2 sage: P.m() 2
- n_variables()#
Return the number of decision variables of
self
, i.e. \(n\).OUTPUT:
an integer
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.n_variables() 2 sage: P.n() 2
- objective_coefficients()#
Return coefficients of the objective of
self
, i.e. \(c\).OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.objective_coefficients() (10, 5) sage: P.c() (10, 5)
- objective_constant_term()#
Return the constant term of the objective.
OUTPUT:
a number
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.objective_constant_term() 0 sage: P.optimal_value() 6250 sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], ....: variable_type=">=", objective_constant_term=-1250) sage: P.objective_constant_term() -1250 sage: P.optimal_value() 5000
- objective_value(*x)#
Return the value of the objective on the given solution.
INPUT:
anything that can be interpreted as a valid solution for this problem, i.e. a sequence of values for all decision variables
OUTPUT:
the value of the objective on the given solution taking into account
objective_constant_term()
andis_negative()
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, variable_type=">=") sage: P.objective_value(100, 200) 2000
- optimal_solution()#
Return an optimal solution of
self
.OUTPUT:
a vector or
None
if there are no optimal solutions
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.optimal_solution() (250, 750)
- optimal_value()#
Return the optimal value for
self
.OUTPUT:
a number if the problem is bounded, \(\pm \infty\) if it is unbounded, or
None
if it is infeasible
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.optimal_value() 6250
- plot(*args, **kwds)#
Return a plot for solving
self
graphically.INPUT:
xmin
,xmax
,ymin
,ymax
– bounds for the axes, if not given, an attempt will be made to pick reasonable valuesalpha
– (default: 0.2) determines how opaque are shadows
OUTPUT:
a plot
This only works for problems with two decision variables. On the plot the black arrow indicates the direction of growth of the objective. The lines perpendicular to it are level curves of the objective. If there are optimal solutions, the arrow originates in one of them and the corresponding level curve is solid: all points of the feasible set on it are optimal solutions. Otherwise the arrow is placed in the center. If the problem is infeasible or the objective is zero, a plot of the feasible set only is returned.
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: p = P.plot() sage: p.show()
In this case the plot works better with the following axes ranges:
sage: p = P.plot(0, 1000, 0, 1500) sage: p.show()
- plot_feasible_set(xmin=None, xmax=None, ymin=None, ymax=None, alpha=0.2)#
Return a plot of the feasible set of
self
.INPUT:
xmin
,xmax
,ymin
,ymax
– bounds for the axes, if not given, an attempt will be made to pick reasonable valuesalpha
– (default: 0.2) determines how opaque are shadows
OUTPUT:
a plot
This only works for a problem with two decision variables. The plot shows boundaries of constraints with a shadow on one side for inequalities. If the
feasible_set()
is not empty and at least part of it is in the given boundaries, it will be shaded gray and \(F\) will be placed in its middle.EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: p = P.plot_feasible_set() sage: p.show()
In this case the plot works better with the following axes ranges:
sage: p = P.plot_feasible_set(0, 1000, 0, 1500) sage: p.show()
- problem_type()#
Return the problem type.
Needs to be used together with
is_negative
.OUTPUT:
a string, one of
"max"
,"min"
.
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.problem_type() 'max' sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=", problem_type="-min") sage: P.problem_type() 'min'
- standard_form(transformation=False, **kwds)#
Construct the LP problem in standard form equivalent to
self
.INPUT:
transformation
– (default:False
) ifTrue
, a map converting solutions of the problem in standard form to the original one will be returned as wellyou can pass (as keywords only)
slack_variables
,auxiliary_variable
,``objective_name`` to the constructor ofInteractiveLPProblemStandardForm
OUTPUT:
an
InteractiveLPProblemStandardForm
by itself or a tuple with variable transformation as the second component
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, variable_type=">=") sage: DP = P.dual() sage: DPSF = DP.standard_form() sage: DPSF.b() (-10, -5) sage: DPSF.slack_variables() (y3, y4) sage: DPSF = DP.standard_form(slack_variables=["L", "F"]) sage: DPSF.slack_variables() (L, F) sage: DPSF, f = DP.standard_form(True) sage: f Vector space morphism represented by the matrix: [1 0] [0 1] Domain: Vector space of dimension 2 over Rational Field Codomain: Vector space of dimension 2 over Rational Field
A more complicated transformation map:
sage: P = InteractiveLPProblem(A, b, c, variable_type=["<=", ""], ....: objective_constant_term=42) sage: PSF, f = P.standard_form(True) sage: f Vector space morphism represented by the matrix: [-1 0] [ 0 1] [ 0 -1] Domain: Vector space of dimension 3 over Rational Field Codomain: Vector space of dimension 2 over Rational Field sage: PSF.optimal_solution() (0, 1000, 0) sage: P.optimal_solution() (0, 1000) sage: P.is_optimal(PSF.optimal_solution()) Traceback (most recent call last): ... TypeError: given input is not a solution for this problem sage: P.is_optimal(f(PSF.optimal_solution())) True sage: PSF.optimal_value() 5042 sage: P.optimal_value() 5042
- variable_types()#
Return a tuple listing the variable types of all decision variables.
OUTPUT:
a tuple of strings
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=[">=", ""]) sage: P.variable_types() ('>=', '')
- x()#
Return decision variables of
self
, i.e. \(x\).OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: P.decision_variables() (C, B) sage: P.x() (C, B)
- class sage.numerical.interactive_simplex_method.InteractiveLPProblemStandardForm(A, b, c, x='x', problem_type='max', slack_variables=None, auxiliary_variable=None, base_ring=None, is_primal=True, objective_name=None, objective_constant_term=0)#
Bases:
InteractiveLPProblem
Construct an LP (Linear Programming) problem in standard form.
Note
This class is for educational purposes only: if you want to solve Linear Programs efficiently, use
MixedIntegerLinearProgram
instead.The used standard form is:
\[\begin{split}\begin{array}{l} \pm \max cx \\ Ax \leq b \\ x \geq 0 \end{array}\end{split}\]INPUT:
A
– a matrix of constraint coefficientsb
– a vector of constraint constant termsc
– a vector of objective coefficientsx
– (default:"x"
) a vector of decision variables or a string the base name givingproblem_type
– (default:"max"
) a string specifying the problem type: either"max"
or"-max"
slack_variables
– (default: depends onstyle()
) a vector of slack variables or a string giving the base nameauxiliary_variable
– (default: same asx
parameter with adjoined"0"
if it was given as a string, otherwise"x0"
) the auxiliary name, expected to be the same as the first decision variable for auxiliary problemsbase_ring
– (default: the fraction field of a common ring for all input coefficients) a field to which all input coefficients will be convertedis_primal
– (default:True
) whether this problem is primal or dual: each problem is of course dual to its own dual, this flag is mostly for internal use and affects default variable names onlyobjective_name
– a string or a symbolic expression for the objective used in dictionaries, default depends onstyle()
objective_constant_term
– (default: 0) a constant term of the objective
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c)
Unlike
InteractiveLPProblem
, this class does not allow you to adjust types of constraints (they are always"<="
) and variables (they are always">="
), and the problem type may only be"max"
or"-max"
. You may give custom names to slack and auxiliary variables, but in most cases defaults should work:sage: P.decision_variables() (x1, x2) sage: P.slack_variables() (x3, x4)
- add_constraint(coefficients, constant_term, slack_variable=None)#
Return a new LP problem by adding a constraint to``self``.
INPUT:
coefficients
– coefficients of the new constraintconstant_term
– a constant term of the new constraintslack_variable
– (default: depends onstyle()
) a string giving the name of the slack variable of the new constraint
OUTPUT:
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.Abcx() ( [1 1] [3 1], (1000, 1500), (10, 5), (x1, x2) ) sage: P.slack_variables() (x3, x4) sage: P1 = P.add_constraint(([2, 4]), 2000) sage: P1.Abcx() ( [1 1] [3 1] [2 4], (1000, 1500, 2000), (10, 5), (x1, x2) ) sage: P1.slack_variables() (x3, x4, x5) sage: P2 = P.add_constraint(([2, 4]), 2000, slack_variable='c') sage: P2.slack_variables() (x3, x4, c) sage: P3 = P.add_constraint(([2, 4, 6]), 2000) Traceback (most recent call last): ... TypeError: number of columns must be the same, not 2 and 3
- auxiliary_problem(objective_name=None)#
Construct the auxiliary problem for
self
.INPUT:
objective_name
– a string or a symbolic expression for the objective used in dictionaries, default depends onstyle()
OUTPUT:
The auxiliary problem with the auxiliary variable \(x_0\) is
\[\begin{split}\begin{array}{l} \max - x_0 \\ - x_0 + A_i x \leq b_i \text{ for all } i \\ x \geq 0 \end{array}\ .\end{split}\]Such problems are used when the
initial_dictionary()
is infeasible.EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: AP = P.auxiliary_problem()
- auxiliary_variable()#
Return the auxiliary variable of
self
.Note that the auxiliary variable may or may not be among
decision_variables()
.OUTPUT:
a variable of the
coordinate_ring()
ofself
EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.auxiliary_variable() x0 sage: P.decision_variables() (x1, x2) sage: AP = P.auxiliary_problem() sage: AP.auxiliary_variable() x0 sage: AP.decision_variables() (x0, x1, x2)
- coordinate_ring()#
Return the coordinate ring of
self
.OUTPUT:
a polynomial ring over the
base_ring()
ofself
in theauxiliary_variable()
,decision_variables()
, andslack_variables()
with “neglex” order
EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.coordinate_ring() Multivariate Polynomial Ring in x0, x1, x2, x3, x4, x5 over Rational Field sage: P.base_ring() Rational Field sage: P.auxiliary_variable() x0 sage: P.decision_variables() (x1, x2) sage: P.slack_variables() (x3, x4, x5)
- dictionary(*x_B)#
Construct a dictionary for
self
with given basic variables.INPUT:
basic variables for the dictionary to be constructed
OUTPUT:
Note
This is a synonym for
self.revised_dictionary(x_B).dictionary()
, but basic variables are mandatory.EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.dictionary("x1", "x2") sage: D.basic_variables() (x1, x2)
- feasible_dictionary(auxiliary_dictionary)#
Construct a feasible dictionary for
self
.INPUT:
auxiliary_dictionary
– an optimal dictionary for theauxiliary_problem()
ofself
with the optimal value \(0\) and a non-basic auxiliary variable
OUTPUT:
a feasible
dictionary
forself
EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: AP = P.auxiliary_problem() sage: D = AP.initial_dictionary() sage: D.enter(0) sage: D.leave(5) sage: D.update() sage: D.enter(1) sage: D.leave(0) sage: D.update() sage: D.is_optimal() True sage: D.objective_value() 0 sage: D.basic_solution() (0, 400, 0) sage: D = P.feasible_dictionary(D) sage: D.is_optimal() False sage: D.is_feasible() True sage: D.objective_value() 4000 sage: D.basic_solution() (400, 0)
- final_dictionary()#
Return the final dictionary of the simplex method applied to
self
.See
run_simplex_method()
for the description of possibilities.OUTPUT:
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.final_dictionary() sage: D.is_optimal() True
- final_revised_dictionary()#
Return the final dictionary of the revised simplex method applied to
self
.See
run_revised_simplex_method()
for the description of possibilities.OUTPUT:
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.final_revised_dictionary() sage: D.is_optimal() True
- initial_dictionary()#
Construct the initial dictionary of
self
.The initial dictionary “defines”
slack_variables()
in terms of thedecision_variables()
, i.e. it has slack variables as basic ones.OUTPUT:
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary()
- inject_variables(scope=None, verbose=True)#
Inject variables of
self
intoscope
.INPUT:
scope
– namespace (default: global)verbose
– ifTrue
(default), names of injected variables will be printed
OUTPUT:
none
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.inject_variables() Defining x0, x1, x2, x3, x4 sage: 3*x1 + x2 x2 + 3*x1
- objective_name()#
Return the objective name used in dictionaries for this problem.
OUTPUT:
a symbolic expression
EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.objective_name() z sage: sage.numerical.interactive_simplex_method.style("Vanderbei") 'Vanderbei' sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.objective_name() zeta sage: sage.numerical.interactive_simplex_method.style("UAlberta") 'UAlberta' sage: P = InteractiveLPProblemStandardForm(A, b, c, objective_name="custom") sage: P.objective_name() custom
- static random_element(m, n, bound=5, special_probability=0.2, **kwds)#
Construct a random
InteractiveLPProblemStandardForm
.INPUT:
m
– the number of constraints/basic variablesn
– the number of decision/non-basic variablesbound
– (default: 5) a bound on coefficientsspecial_probability
– (default: 0.2) probability of constructing a problem whose initial dictionary is allowed to be primal infeasible or dual feasible
All other keyword arguments are passed to the constructor.
EXAMPLES:
sage: InteractiveLPProblemStandardForm.random_element(3, 4) LP problem (use 'view(...)' or '%display typeset' for details)
- revised_dictionary(*x_B)#
Construct a revised dictionary for
self
.INPUT:
basic variables for the dictionary to be constructed; if not given,
slack_variables()
will be used, perhaps with theauxiliary_variable()
to give a feasible dictionary
OUTPUT:
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary("x1", "x2") sage: D.basic_variables() (x1, x2)
If basic variables are not given the initial dictionary is constructed:
sage: P.revised_dictionary().basic_variables() (x3, x4) sage: P.initial_dictionary().basic_variables() (x3, x4)
Unless it is infeasible, in which case a feasible dictionary for the auxiliary problem is constructed:
sage: A = ([1, 1], [3, 1], [-1,-1]) sage: b = (1000, 1500, -400) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.initial_dictionary().is_feasible() False sage: P.revised_dictionary().basic_variables() (x3, x4, x0)
- run_revised_simplex_method()#
Apply the revised simplex method and return all steps.
OUTPUT:
HtmlFragment
with HTML/\(\LaTeX\) code of all encountered dictionaries
Note
You can access the
final_revised_dictionary()
, which can be one of the following:an optimal dictionary with the
auxiliary_variable()
amongbasic_variables()
and a non-zero optimal value indicating thatself
is infeasible;a non-optimal dictionary that has marked entering variable for which there is no choice of the leaving variable, indicating that
self
is unbounded;an optimal dictionary.
EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.run_revised_simplex_method() \begin{equation*} ... \end{equation*} Entering: $x_{1}$. Leaving: $x_{0}$. \begin{equation*} ... \end{equation*} Entering: $x_{5}$. Leaving: $x_{4}$. \begin{equation*} ... \end{equation*} Entering: $x_{2}$. Leaving: $x_{3}$. \begin{equation*} ... \end{equation*} The optimal value: $6250$. An optimal solution: $\left(250,\,750\right)$.
- run_simplex_method()#
Apply the simplex method and return all steps and intermediate states.
OUTPUT:
HtmlFragment
with HTML/\(\LaTeX\) code of all encountered dictionaries
Note
You can access the
final_dictionary()
, which can be one of the following:an optimal dictionary for the
auxiliary_problem()
with a non-zero optimal value indicating thatself
is infeasible;a non-optimal dictionary for
self
that has marked entering variable for which there is no choice of the leaving variable, indicating thatself
is unbounded;an optimal dictionary for
self
.
EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.run_simplex_method() \begin{equation*} ... \end{equation*} The initial dictionary is infeasible, solving auxiliary problem. ... Entering: $x_{0}$. Leaving: $x_{5}$. ... Entering: $x_{1}$. Leaving: $x_{0}$. ... Back to the original problem. ... Entering: $x_{5}$. Leaving: $x_{4}$. ... Entering: $x_{2}$. Leaving: $x_{3}$. ... The optimal value: $6250$. An optimal solution: $\left(250,\,750\right)$.
- slack_variables()#
Return slack variables of
self
.Slack variables are differences between the constant terms and left hand sides of the constraints.
If you want to give custom names to slack variables, you have to do so during construction of the problem.
OUTPUT:
a tuple
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.slack_variables() (x3, x4) sage: P = InteractiveLPProblemStandardForm(A, b, c, ["C", "B"], ....: slack_variables=["L", "F"]) sage: P.slack_variables() (L, F)
- class sage.numerical.interactive_simplex_method.LPAbstractDictionary#
Bases:
SageObject
Abstract base class for dictionaries for LP problems.
Instantiating this class directly is meaningless, see
LPDictionary
andLPRevisedDictionary
for useful extensions.- add_row(nonbasic_coefficients, constant, basic_variable=None)#
Return a dictionary with an additional row based on a given dictionary.
INPUT:
nonbasic_coefficients
– a list of the coefficients for the new row (with which nonbasic variables are subtracted in the relation for the new basic variable)constant
– the constant term for the new rowbasic_variable
– (default: depends onstyle()
) a string giving the name of the basic variable of the new row
OUTPUT:
a new dictionary of the same class
EXAMPLES:
sage: A = ([-1, 1, 7], [8, 2, 13], [34, 17, 12]) sage: b = (2, 17, 6) sage: c = (55/10, 21/10, 14/30) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.dictionary("x1", "x2", "x4") sage: D1 = D.add_row([7, 11, 19], 42, basic_variable='c') sage: D1.row_coefficients("c") (7, 11, 19)
- base_ring()#
Return the base ring of
self
, i.e. the ring of coefficients.OUTPUT:
a ring
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.base_ring() Rational Field sage: D = P.revised_dictionary() sage: D.base_ring() Rational Field
- basic_solution(include_slack_variables=False)#
Return the basic solution of
self
.The basic solution associated to a dictionary is obtained by setting to zero all
nonbasic_variables()
, in which casebasic_variables()
have to be equal toconstant_terms()
in equations. It may refer to values ofdecision_variables()
only or includeslack_variables()
as well.INPUT:
include_slack_variables
– (default:False
) ifTrue
, values of slack variables will be appended at the end
OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.basic_solution() (0, 0) sage: D.basic_solution(True) (0, 0, 1000, 1500) sage: D = P.revised_dictionary() sage: D.basic_solution() (0, 0) sage: D.basic_solution(True) (0, 0, 1000, 1500)
- basic_variables()#
Return the basic variables of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.basic_variables() (x3, x4)
- column_coefficients(v)#
Return the coefficients of a nonbasic variable.
INPUT:
v
– a nonbasic variable ofself
, can be given as a string, an actual variable, or an integer interpreted as the index of a variable
OUTPUT:
a vector of coefficients of a nonbasic variable
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.column_coefficients(1) (1, 3)
- constant_terms()#
Return the constant terms of relations of
self
.OUTPUT:
a vector.
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.constant_terms() (1000, 1500)
- coordinate_ring()#
Return the coordinate ring of
self
.OUTPUT:
a polynomial ring in
auxiliary_variable()
,decision_variables()
, andslack_variables()
ofself
over thebase_ring()
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.coordinate_ring() Multivariate Polynomial Ring in x0, x1, x2, x3, x4 over Rational Field sage: D = P.revised_dictionary() sage: D.coordinate_ring() Multivariate Polynomial Ring in x0, x1, x2, x3, x4 over Rational Field
- dual_ratios()#
Return ratios used to determine the entering variable based on leaving.
OUTPUT:
A list of pairs \((r_j, x_j)\) where \(x_j\) is a non-basic variable and \(r_j = c_j / a_{ij}\) is the ratio of the objective coefficient \(c_j\) to the coefficient \(a_{ij}\) of \(x_j\) in the relation for the leaving variable \(x_i\):
\[x_i = b_i - \cdots - a_{ij} x_j - \cdots.\]The order of pairs matches the order of
nonbasic_variables()
, but only \(x_j\) with negative \(a_{ij}\) are considered.
EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.dictionary(2, 3, 5) sage: D.leave(3) sage: D.dual_ratios() [(5/2, x1), (5, x4)] sage: D = P.revised_dictionary(2, 3, 5) sage: D.leave(3) sage: D.dual_ratios() [(5/2, x1), (5, x4)]
- enter(v)#
Set
v
as the entering variable ofself
.INPUT:
v
– a non-basic variable ofself
, can be given as a string, an actual variable, or an integer interpreted as the index of a variable. It is also possible to enterNone
to reset choice.
OUTPUT:
none, but the selected variable will be used as entering by methods that require an entering variable and the corresponding column will be typeset in green
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.enter("x1")
We can also use indices of variables:
sage: D.enter(1)
Or variable names without quotes after injecting them:
sage: P.inject_variables() Defining x0, x1, x2, x3, x4 sage: D.enter(x1)
The same works for revised dictionaries as well:
sage: D = P.revised_dictionary() sage: D.enter(x1)
- entering()#
Return the currently chosen entering variable.
OUTPUT:
a variable if the entering one was chosen, otherwise
None
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.entering() is None True sage: D.enter(1) sage: D.entering() x1
- entering_coefficients()#
Return coefficients of the entering variable.
OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.enter(1) sage: D.entering_coefficients() (1, 3)
- is_dual_feasible()#
Check if
self
is dual feasible.OUTPUT:
True
if allobjective_coefficients()
are non-positive,False
otherwise
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.is_dual_feasible() False sage: D = P.revised_dictionary() sage: D.is_dual_feasible() False
- is_feasible()#
Check if
self
is feasible.OUTPUT:
True
if allconstant_terms()
are non-negative,False
otherwise
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.is_feasible() True sage: D = P.revised_dictionary() sage: D.is_feasible() True
- is_optimal()#
Check if
self
is optimal.OUTPUT:
True
ifself
is_feasible()
andis_dual_feasible()
(i.e. allconstant_terms()
are non-negative and allobjective_coefficients()
are non-positive),False
otherwise.
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.is_optimal() False sage: D = P.revised_dictionary() sage: D.is_optimal() False sage: D = P.revised_dictionary(1, 2) sage: D.is_optimal() True
- leave(v)#
Set
v
as the leaving variable ofself
.INPUT:
v
– a basic variable ofself
, can be given as a string, an actual variable, or an integer interpreted as the index of a variable. It is also possible to leaveNone
to reset choice.
OUTPUT:
none, but the selected variable will be used as leaving by methods that require a leaving variable and the corresponding row will be typeset in red
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.leave("x4")
We can also use indices of variables:
sage: D.leave(4)
Or variable names without quotes after injecting them:
sage: P.inject_variables() Defining x0, x1, x2, x3, x4 sage: D.leave(x4)
The same works for revised dictionaries as well:
sage: D = P.revised_dictionary() sage: D.leave(x4)
- leaving()#
Return the currently chosen leaving variable.
OUTPUT:
a variable if the leaving one was chosen, otherwise
None
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.leaving() is None True sage: D.leave(4) sage: D.leaving() x4
- leaving_coefficients()#
Return coefficients of the leaving variable.
OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.dictionary(2, 3) sage: D.leave(3) sage: D.leaving_coefficients() (-2, -1)
The same works for revised dictionaries as well:
sage: D = P.revised_dictionary(2, 3) sage: D.leave(3) sage: D.leaving_coefficients() (-2, -1)
- nonbasic_variables()#
Return non-basic variables of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.nonbasic_variables() (x1, x2)
- objective_coefficients()#
Return coefficients of the objective of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.objective_coefficients() (10, 5)
- objective_name()#
Return the objective name of
self
.OUTPUT:
a symbolic expression
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.objective_name() z
- objective_value()#
Return the value of the objective at the
basic_solution()
ofself
.OUTPUT:
a number
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.objective_value() 0
- possible_dual_simplex_method_steps()#
Return possible dual simplex method steps for
self
.OUTPUT:
A list of pairs
(leaving, entering)
, whereleaving
is a basic variable that mayleave()
andentering
is a list of non-basic variables that mayenter()
whenleaving
leaves. Note thatentering
may be empty, indicating that the problem is infeasible (since the dual one is unbounded).
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.dictionary(2, 3) sage: D.possible_dual_simplex_method_steps() [(x3, [x1])] sage: D = P.revised_dictionary(2, 3) sage: D.possible_dual_simplex_method_steps() [(x3, [x1])]
- possible_entering()#
Return possible entering variables for
self
.OUTPUT:
a list of non-basic variables of
self
that canenter()
on the next step of the (dual) simplex method
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.possible_entering() [x1, x2] sage: D = P.revised_dictionary() sage: D.possible_entering() [x1, x2]
- possible_leaving()#
Return possible leaving variables for
self
.OUTPUT:
a list of basic variables of
self
that canleave()
on the next step of the (dual) simplex method
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.enter(1) sage: D.possible_leaving() [x4] sage: D = P.revised_dictionary() sage: D.enter(1) sage: D.possible_leaving() [x4]
- possible_simplex_method_steps()#
Return possible simplex method steps for
self
.OUTPUT:
A list of pairs
(entering, leaving)
, whereentering
is a non-basic variable that mayenter()
andleaving
is a list of basic variables that mayleave()
whenentering
enters. Note thatleaving
may be empty, indicating that the problem is unbounded.
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.possible_simplex_method_steps() [(x1, [x4]), (x2, [x3])] sage: D = P.revised_dictionary() sage: D.possible_simplex_method_steps() [(x1, [x4]), (x2, [x3])]
- ratios()#
Return ratios used to determine the leaving variable based on entering.
OUTPUT:
A list of pairs \((r_i, x_i)\) where \(x_i\) is a basic variable and \(r_i = b_i / a_{ik}\) is the ratio of the constant term \(b_i\) to the coefficient \(a_{ik}\) of the entering variable \(x_k\) in the relation for \(x_i\):
\[x_i = b_i - \cdots - a_{ik} x_k - \cdots.\]The order of pairs matches the order of
basic_variables()
, but only \(x_i\) with positive \(a_{ik}\) are considered.
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.enter(1) sage: D.ratios() [(1000, x3), (500, x4)] sage: D = P.revised_dictionary() sage: D.enter(1) sage: D.ratios() [(1000, x3), (500, x4)]
- row_coefficients(v)#
Return the coefficients of the basic variable
v
.These are the coefficients with which nonbasic variables are subtracted in the relation for
v
.INPUT:
v
– a basic variable ofself
, can be given as a string, an actual variable, or an integer interpreted as the index of a variable
OUTPUT:
a vector of coefficients of a basic variable
EXAMPLES:
sage: A = ([-1, 1], [8, 2]) sage: b = (2, 17) sage: c = (55/10, 21/10) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.final_dictionary() sage: D.row_coefficients("x1") (1/10, -1/5)
We can also use indices of variables:
sage: D.row_coefficients(1) (1/10, -1/5)
Or use variable names without quotes after injecting them:
sage: P.inject_variables() Defining x0, x1, x2, x3, x4 sage: D.row_coefficients(x1) (1/10, -1/5)
- run_dual_simplex_method()#
Apply the dual simplex method and return all steps/intermediate states.
If either entering or leaving variables were already set, they will be used.
OUTPUT:
HtmlFragment
with HTML/\(\LaTeX\) code of all encountered dictionaries
EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.run_dual_simplex_method() Traceback (most recent call last): ... ValueError: leaving variables can be determined for feasible dictionaries with a set entering variable or for dual feasible dictionaries
Let’s start with a dual feasible dictionary then:
sage: D = P.dictionary(2, 3, 5) sage: D.is_dual_feasible() True sage: D.is_optimal() False sage: D.run_dual_simplex_method() \begin{equation*} ... \end{equation*} Leaving: $x_{3}$. Entering: $x_{1}$. \begin{equation*} ... \end{equation*} sage: D.is_optimal() True
This method detects infeasible problems:
sage: A = ([1, 0],) sage: b = (-1,) sage: c = (0, -1) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.run_dual_simplex_method() \begin{equation*} ... \end{equation*} The problem is infeasible because of $x_{3}$ constraint.
- run_simplex_method()#
Apply the simplex method and return all steps and intermediate states.
If either entering or leaving variables were already set, they will be used.
OUTPUT:
HtmlFragment
with HTML/\(\LaTeX\) code of all encountered dictionaries
EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.run_simplex_method() Traceback (most recent call last): ... ValueError: entering variables can be determined for feasible dictionaries or for dual feasible dictionaries with a set leaving variable
Let’s start with a feasible dictionary then:
sage: D = P.dictionary(1, 3, 4) sage: D.is_feasible() True sage: D.is_optimal() False sage: D.run_simplex_method() \begin{equation*} ... \end{equation*} Entering: $x_{5}$. Leaving: $x_{4}$. \begin{equation*} ... \end{equation*} Entering: $x_{2}$. Leaving: $x_{3}$. \begin{equation*} ... \end{equation*} sage: D.is_optimal() True
This method detects unbounded problems:
sage: A = ([1, 0],) sage: b = (1,) sage: c = (0, 1) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.run_simplex_method() \begin{equation*} ... \end{equation*} The problem is unbounded in $x_{2}$ direction.
- update()#
Update
self
using previously set entering and leaving variables.EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.objective_value() 0 sage: D.enter("x1") sage: D.leave("x4") sage: D.update() sage: D.objective_value() 5000
- class sage.numerical.interactive_simplex_method.LPDictionary(A, b, c, objective_value, basic_variables, nonbasic_variables, objective_name)#
Bases:
LPAbstractDictionary
Construct a dictionary for an LP problem.
A dictionary consists of the following data:
\[\begin{split}\begin{array}{|l|} \hline x_B = b - A x_N\\ \hline z = z^* + c x_N\\ \hline \end{array}\end{split}\]INPUT:
A
– a matrix of relation coefficientsb
– a vector of relation constant termsc
– a vector of objective coefficientsobjective_value
– current value of the objective \(z^*\)basic_variables
– a list of basic variables \(x_B\)nonbasic_variables
– a list of non-basic variables \(x_N\)objective_name
– a “name” for the objective \(z\)
OUTPUT:
Note
This constructor does not check correctness of input, as it is intended to be used internally by
InteractiveLPProblemStandardForm
.EXAMPLES:
The intended way to use this class is indirect:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D LP problem dictionary (use ...)
But if you want you can create a dictionary without starting with an LP problem, here is construction of the same dictionary as above:
sage: A = matrix(QQ, ([1, 1], [3, 1])) sage: b = vector(QQ, (1000, 1500)) sage: c = vector(QQ, (10, 5)) sage: R = PolynomialRing(QQ, "x1, x2, x3, x4", order="neglex") sage: from sage.numerical.interactive_simplex_method \ ....: import LPDictionary sage: D2 = LPDictionary(A, b, c, 0, R.gens()[2:], R.gens()[:2], "z") sage: D2 == D True
- add_row(nonbasic_coefficients, constant, basic_variable=None)#
Return a dictionary with an additional row based on a given dictionary.
INPUT:
nonbasic_coefficients
– a list of the coefficients for the new row (with which nonbasic variables are subtracted in the relation for the new basic variable)constant
– the constant term for the new rowbasic_variable
– (default: depends onstyle()
) a string giving the name of the basic variable of the new row
OUTPUT:
EXAMPLES:
sage: A = ([-1, 1, 7], [8, 2, 13], [34, 17, 12]) sage: b = (2, 17, 6) sage: c = (55/10, 21/10, 14/30) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.dictionary("x1", "x2", "x4") sage: D1 = D.add_row([7, 11, 19], 42, basic_variable='c') sage: D1.row_coefficients("c") (7, 11, 19) sage: D1.constant_terms()[-1] 42 sage: D1.basic_variables()[-1] c
- basic_variables()#
Return the basic variables of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.basic_variables() (x3, x4)
- column_coefficients(v)#
Return coefficients of a nonbasic variable.
INPUT:
v
– a nonbasic variable ofself
, can be given as a string, an actual variable, or an integer interpreted as the index of a variable
OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.column_coefficients(1) (1, 3)
- constant_terms()#
Return the constant terms of relations of
self
.OUTPUT:
a vector.
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.constant_terms() (1000, 1500)
- nonbasic_variables()#
Return non-basic variables of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.nonbasic_variables() (x1, x2)
- objective_coefficients()#
Return coefficients of the objective of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.objective_coefficients() (10, 5)
- objective_name()#
Return the objective name of
self
.OUTPUT:
a symbolic expression
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.objective_name() z
- objective_value()#
Return the value of the objective at the
basic_solution()
ofself
.OUTPUT:
a number
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.objective_value() 0
- static random_element(m, n, bound=5, special_probability=0.2)#
Construct a random dictionary.
INPUT:
m
– the number of constraints/basic variablesn
– the number of decision/non-basic variablesbound
– (default: 5) a bound on dictionary entriesspecial_probability
– (default: 0.2) probability of constructing a potentially infeasible or potentially optimal dictionary
OUTPUT:
EXAMPLES:
sage: from sage.numerical.interactive_simplex_method \ ....: import random_dictionary sage: random_dictionary(3, 4) # indirect doctest LP problem dictionary (use 'view(...)' or '%display typeset' for details)
- row_coefficients(v)#
Return the coefficients of the basic variable
v
.These are the coefficients with which nonbasic variables are subtracted in the relation for
v
.INPUT:
v
– a basic variable ofself
, can be given as a string, an actual variable, or an integer interpreted as the index of a variable
OUTPUT:
a vector of coefficients of a basic variable
EXAMPLES:
sage: A = ([-1, 1], [8, 2]) sage: b = (2, 17) sage: c = (55/10, 21/10) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.final_dictionary() sage: D.row_coefficients("x1") (1/10, -1/5)
We can also use indices of variables:
sage: D.row_coefficients(1) (1/10, -1/5)
Or use variable names without quotes after injecting them:
sage: P.inject_variables() Defining x0, x1, x2, x3, x4 sage: D.row_coefficients(x1) (1/10, -1/5)
- update()#
Update
self
using previously set entering and leaving variables.EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.objective_value() 0 sage: D.enter("x1") sage: D.leave("x4") sage: D.update() sage: D.objective_value() 5000
- class sage.numerical.interactive_simplex_method.LPRevisedDictionary(problem, basic_variables)#
Bases:
LPAbstractDictionary
Construct a revised dictionary for an LP problem.
INPUT:
problem
– anLP problem in standard form
basic_variables
– a list of basic variables or their indices
OUTPUT:
A revised dictionary encodes the same relations as a
regular dictionary
, but stores only what is “necessary to efficiently compute data for the simplex method”.Let the original problem be
\[\begin{split}\begin{array}{l} \pm \max cx \\ Ax \leq b \\ x \geq 0 \end{array}\end{split}\]Let \(\bar{x}\) be the vector of
decision_variables()
\(x\) followed by theslack_variables()
. Let \(\bar{c}\) be the vector ofobjective_coefficients()
\(c\) followed by zeroes for all slack variables. Let \(\bar{A} = (A | I)\) be the matrix ofconstraint_coefficients()
\(A\) augmented by the identity matrix as columns corresponding to the slack variables. Then the problem above can be written as\[\begin{split}\begin{array}{l} \pm \max \bar{c} \bar{x} \\ \bar{A} \bar{x} = b \\ \bar{x} \geq 0 \end{array}\end{split}\]and any dictionary is a system of equations equivalent to \(\bar{A} \bar{x} = b\), but resolved for
basic_variables()
\(x_B\) in terms ofnonbasic_variables()
\(x_N\) together with the expression for the objective in terms of \(x_N\). Letc_B()
andc_N()
be vectors “splitting \(\bar{c}\) into basic and non-basic parts”. LetB()
andA_N()
be the splitting of \(\bar{A}\). Then the corresponding dictionary is\[\begin{split}\begin{array}{|l|} \hline x_B = B^{-1} b - B^{-1} A_N x_N\\ \hline z = y b + \left(c_N - y^T A_N\right) x_N\\ \hline \end{array}\end{split}\]where \(y = c_B^T B^{-1}\). To proceed with the simplex method, it is not necessary to compute all entries of this dictionary. On the other hand, any entry is easy to compute, if you know \(B^{-1}\), so we keep track of it through the update steps.
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: from sage.numerical.interactive_simplex_method \ ....: import LPRevisedDictionary sage: D = LPRevisedDictionary(P, [1, 2]) sage: D.basic_variables() (x1, x2) sage: D LP problem dictionary (use ...)
The same dictionary can be constructed through the problem:
sage: P.revised_dictionary(1, 2) == D True
When this dictionary is typeset, you will see two tables like these ones:
\[\begin{split}\renewcommand{\arraystretch}{1.500000} \begin{array}{l} \begin{array}{l|r|rr||r||r} x_B & c_B & & \mspace{-16mu} B^{-1} & y & B^{-1} b \\ \hline x_{1} & 10 & -\frac{1}{2} & \frac{1}{2} & \frac{5}{2} & 250 \\ x_{2} & 5 & \frac{3}{2} & -\frac{1}{2} & \frac{5}{2} & 750 \\ \end{array}\\ \\ \begin{array}{r|rr} x_N & x_{3} & x_{4} \\ \hline c_N^T & 0 & 0 \\ \hline y^T A_N & \frac{5}{2} & \frac{5}{2} \\ \hline c_N^T - y^T A_N & -\frac{5}{2} & -\frac{5}{2} \\ \end{array} \end{array}\end{split}\]More details will be shown if entering and leaving variables are set, but in any case the top table shows \(B^{-1}\) and a few extra columns, while the bottom one shows several rows: these are related to columns and rows of dictionary entries.
- A(v)#
Return the column of constraint coefficients corresponding to
v
.INPUT:
v
– a variable, its name, or its index
OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.A(1) (1, 3) sage: D.A(0) (-1, -1) sage: D.A("x3") (1, 0)
- A_N()#
Return the \(A_N\) matrix, constraint coefficients of non-basic variables.
OUTPUT:
a matrix
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.A_N() [1 1] [3 1]
- B()#
Return the \(B\) matrix, i.e. constraint coefficients of basic variables.
OUTPUT:
a matrix
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary(1, 2) sage: D.B() [1 1] [3 1]
- B_inverse()#
Return the inverse of the
B()
matrix.This inverse matrix is stored and computed during dictionary update in a more efficient way than generic inversion.
OUTPUT:
a matrix
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary(1, 2) sage: D.B_inverse() [-1/2 1/2] [ 3/2 -1/2]
- E()#
Return the eta matrix between
self
and the next dictionary.OUTPUT:
a matrix
If \(B_{\mathrm{old}}\) is the current matrix \(B\) and \(B_{\mathrm{new}}\) is the \(B\) matrix of the next dictionary (after the update step), then \(B_{\mathrm{new}} = B_{\mathrm{old}} E\).
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.enter(1) sage: D.leave(4) sage: D.E() [1 1] [0 3]
- E_inverse()#
Return the inverse of the matrix
E()
.This inverse matrix is computed in a more efficient way than generic inversion.
OUTPUT:
a matrix
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.enter(1) sage: D.leave(4) sage: D.E_inverse() [ 1 -1/3] [ 0 1/3]
- add_row(nonbasic_coefficients, constant, basic_variable=None)#
Return a dictionary with an additional row based on a given dictionary.
The implementation of this method for revised dictionaries adds a new inequality constraint to the problem, in which the given \(basic_variable\) becomes the slack variable. The resulting dictionary (with \(basic_variable\) added to the basis) will have the given \(nonbasic_coefficients\) and \(constant\) as a new row.
INPUT:
nonbasic_coefficients
– a list of the coefficients for the new row (with which nonbasic variables are subtracted in the relation for the new basic variable)constant
– the constant term for the new rowbasic_variable
– (default: depends onstyle()
) a string giving the name of the basic variable of the new row
OUTPUT:
EXAMPLES:
sage: A = ([-1, 1111, 3, 17], [8, 222, 7, 6], ....: [3, 7, 17, 5], [9, 5, 7, 3]) sage: b = (2, 17, 11, 27) sage: c = (5/133, 1/10, 1/18, 47/3) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.final_revised_dictionary() sage: D1 = D.add_row([7, 11, 13, 9], 42) sage: D1.row_coefficients("x9") (7, 11, 13, 9) sage: D1.constant_terms()[-1] 42 sage: D1.basic_variables()[-1] x9 sage: A = ([-9, 7, 48, 31, 23], [5, 2, 9, 13, 98], ....: [14, 15, 97, 49, 1], [9, 5, 7, 3, 17], ....: [119, 7, 121, 5, 111]) sage: b = (33, 27, 1, 272, 61) sage: c = (51/133, 1/100, 149/18, 47/37, 13/17) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary("x1", "x2", "x3", "x4", "x5") sage: D2 = D.add_row([5 ,7, 11, 13, 9], 99, basic_variable='c') sage: D2.row_coefficients("c") (5, 7, 11, 13, 9) sage: D2.constant_terms()[-1] 99 sage: D2.basic_variables()[-1] c sage: D = P.revised_dictionary(0, 1, 2, 3, 4) sage: D.add_row([1, 2, 3, 4, 5, 6], 0) Traceback (most recent call last): ... ValueError: the sum of coefficients of nonbasic slack variables has to be equal to -1 when inserting a row into a dictionary for the auxiliary problem sage: D3 = D.add_row([1, 2, 3, 4, 5, -15], 0) sage: D3.row_coefficients(11) (1, 2, 3, 4, 5, -15)
- basic_indices()#
Return the basic indices of
self
.Note
Basic indices are indices of
basic_variables()
in the list of generators of thecoordinate_ring()
of theproblem()
ofself
, they may not coincide with the indices of variables which are parts of their names. (They will for the default indexed names.)OUTPUT:
a list.
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.basic_indices() [3, 4]
- basic_variables()#
Return the basic variables of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.basic_variables() (x3, x4)
- c_B()#
Return the \(c_B\) vector, objective coefficients of basic variables.
OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary(1, 2) sage: D.c_B() (10, 5)
- c_N()#
Return the \(c_N\) vector, objective coefficients of non-basic variables.
OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.c_N() (10, 5)
- column_coefficients(v)#
Return the coefficients of a nonbasic variable.
INPUT:
v
– a nonbasic variable ofself
, can be given as a string, an actual variable, or an integer interpreted as the index of a variable
OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.column_coefficients(1) (1, 3)
- constant_terms()#
Return constant terms in the relations of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.constant_terms() (1000, 1500)
- dictionary()#
Return a regular LP dictionary matching
self
.OUTPUT:
EXAMPLES:
sage: A = ([1, 1], [3, 1], [-1, -1]) sage: b = (1000, 1500, -400) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.dictionary() LP problem dictionary (use ...)
- nonbasic_indices()#
Return the non-basic indices of
self
.Note
Non-basic indices are indices of
nonbasic_variables()
in the list of generators of thecoordinate_ring()
of theproblem()
ofself
, they may not coincide with the indices of variables which are parts of their names. (They will for the default indexed names.)OUTPUT:
a list
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.nonbasic_indices() [1, 2]
- nonbasic_variables()#
Return non-basic variables of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.nonbasic_variables() (x1, x2)
- objective_coefficients()#
Return coefficients of the objective of
self
.OUTPUT:
a vector
These are coefficients of non-basic variables when basic variables are eliminated.
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.objective_coefficients() (10, 5)
- objective_name()#
Return the objective name of
self
.OUTPUT:
a symbolic expression
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.objective_name() z
- objective_value()#
Return the value of the objective at the basic solution of
self
.OUTPUT:
a number
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.objective_value() 0
- problem()#
Return the original problem.
OUTPUT:
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.problem() is P True
- row_coefficients(v)#
Return the coefficients of the basic variable
v
.These are the coefficients with which nonbasic variables are subtracted in the relation for
v
.INPUT:
v
– a basic variable ofself
, can be given as a string, an actual variable, or an integer interpreted as the index of a variable
OUTPUT:
a vector of coefficients of a basic variable
EXAMPLES:
sage: A = ([-1, 1], [8, 2]) sage: b = (2, 17) sage: c = (55/10, 21/10) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.row_coefficients("x3") (-1, 1)
We can also use indices of variables:
sage: D.row_coefficients(3) (-1, 1)
Or variable names without quotes after injecting them:
sage: P.inject_variables() Defining x0, x1, x2, x3, x4 sage: D.row_coefficients(x3) (-1, 1)
- update()#
Update
self
using previously set entering and leaving variables.EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.objective_value() 0 sage: D.enter("x1") sage: D.leave("x4") sage: D.update() sage: D.objective_value() 5000
- x_B()#
Return the basic variables of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.basic_variables() (x3, x4)
- x_N()#
Return non-basic variables of
self
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.nonbasic_variables() (x1, x2)
- y()#
Return the \(y\) vector, the product of
c_B()
andB_inverse()
.OUTPUT:
a vector
EXAMPLES:
sage: A = ([1, 1], [3, 1]) sage: b = (1000, 1500) sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.revised_dictionary() sage: D.y() (0, 0)
- sage.numerical.interactive_simplex_method.default_variable_name(variable)#
Return default variable name for the current
style()
.INPUT:
variable
- a string describing requested name
OUTPUT:
a string with the requested name for current style
EXAMPLES:
sage: sage.numerical.interactive_simplex_method.default_variable_name("primal slack") 'x' sage: sage.numerical.interactive_simplex_method.style('Vanderbei') 'Vanderbei' sage: sage.numerical.interactive_simplex_method.default_variable_name("primal slack") 'w' sage: sage.numerical.interactive_simplex_method.style('UAlberta') 'UAlberta'
- sage.numerical.interactive_simplex_method.random_dictionary(m, n, bound=5, special_probability=0.2)#
Construct a random dictionary.
INPUT:
m
– the number of constraints/basic variablesn
– the number of decision/non-basic variablesbound
– (default: 5) a bound on dictionary entriesspecial_probability
– (default: 0.2) probability of constructing a potentially infeasible or potentially optimal dictionary
OUTPUT:
EXAMPLES:
sage: from sage.numerical.interactive_simplex_method \ ....: import random_dictionary sage: random_dictionary(3, 4) # indirect doctest LP problem dictionary (use 'view(...)' or '%display typeset' for details)
- sage.numerical.interactive_simplex_method.style(new_style=None)#
Set or get the current style of problems and dictionaries.
INPUT:
new_style
– a string orNone
(default)
OUTPUT:
a string with current style (same as
new_style
if it was given)
If the input is not recognized as a valid style, a
ValueError
exception is raised.Currently supported styles are:
‘UAlberta’ (default): Follows the style used in the Math 373 course on Mathematical Programming and Optimization at the University of Alberta, Edmonton, Canada; based on Chvatal’s book.
Objective functions of dictionaries are printed at the bottom.
Variable names default to
\(z\) for primal objective
\(z\) for dual objective
\(w\) for auxiliary objective
\(x_1, x_2, \dots, x_n\) for primal decision variables
\(x_{n+1}, x_{n+2}, \dots, x_{n+m}\) for primal slack variables
\(y_1, y_2, \dots, y_m\) for dual decision variables
\(y_{m+1}, y_{m+2}, \dots, y_{m+n}\) for dual slack variables
‘Vanderbei’: Follows the style of Robert Vanderbei’s textbook, Linear Programming – Foundations and Extensions.
Objective functions of dictionaries are printed at the top.
Variable names default to
\(zeta\) for primal objective
\(xi\) for dual objective
\(xi\) for auxiliary objective
\(x_1, x_2, \dots, x_n\) for primal decision variables
\(w_1, w_2, \dots, w_m\) for primal slack variables
\(y_1, y_2, \dots, y_m\) for dual decision variables
\(z_1, z_2, \dots, z_n\) for dual slack variables
EXAMPLES:
sage: sage.numerical.interactive_simplex_method.style() 'UAlberta' sage: sage.numerical.interactive_simplex_method.style('Vanderbei') 'Vanderbei' sage: sage.numerical.interactive_simplex_method.style('Doesntexist') Traceback (most recent call last): ... ValueError: Style must be one of: UAlberta, Vanderbei sage: sage.numerical.interactive_simplex_method.style('UAlberta') 'UAlberta'
- sage.numerical.interactive_simplex_method.variable(v)#
Interpret
v
as a variable ofR
.INPUT:
R
– a polynomial ringv
– a variable ofR
or convertible intoR
, a string with the name of a variable ofR
or an index of a variable inR
OUTPUT:
a variable of
R
EXAMPLES:
sage: from sage.numerical.interactive_simplex_method \ ....: import variable sage: R = PolynomialRing(QQ, "x3, y5, x5, y") sage: R.inject_variables() Defining x3, y5, x5, y sage: variable(R, "x3") x3 sage: variable(R, x3) x3 sage: variable(R, 3) x3 sage: variable(R, 0) Traceback (most recent call last): ... ValueError: there is no variable with the given index sage: variable(R, 5) Traceback (most recent call last): ... ValueError: the given index is ambiguous sage: variable(R, 2 * x3) Traceback (most recent call last): ... ValueError: cannot interpret given data as a variable sage: variable(R, "z") Traceback (most recent call last): ... ValueError: cannot interpret given data as a variable