Logging Backend#
It records, for debugging and unit testing purposes, all calls to backend methods in one of three ways.
See LoggingBackendFactory
for more information.
- class sage.numerical.backends.logging_backend.LoggingBackend(backend, printing=True, doctest=None, test_method=None, base_ring=None)[source]#
Bases:
GenericBackend
See
LoggingBackendFactory
for documentation.EXAMPLES:
sage: import sage.numerical.backends.logging_backend sage: from sage.numerical.backends.logging_backend import LoggingBackend sage: from sage.numerical.backends.generic_backend import get_solver sage: b = get_solver(solver = "GLPK") sage: lb = LoggingBackend(backend=b) sage: lb.add_variable(obj=42, name='Helloooooo') # p.add_variable(obj=42, name='Helloooooo') # result: 0 0 sage: lb.add_variable(obj=1789) # p.add_variable(obj=1789) # result: 1 1
>>> from sage.all import * >>> import sage.numerical.backends.logging_backend >>> from sage.numerical.backends.logging_backend import LoggingBackend >>> from sage.numerical.backends.generic_backend import get_solver >>> b = get_solver(solver = "GLPK") >>> lb = LoggingBackend(backend=b) >>> lb.add_variable(obj=Integer(42), name='Helloooooo') # p.add_variable(obj=42, name='Helloooooo') # result: 0 0 >>> lb.add_variable(obj=Integer(1789)) # p.add_variable(obj=1789) # result: 1 1
- add_col(indices, coeffs)[source]#
Add a column.
INPUT:
indices
(list of integers) – this list contains the indices of the constraints in which the variable’s coefficient is nonzerocoeffs
(list of real values) – associates a coefficient to the variable in each of the constraints in which it appears. Namely, the i-th entry ofcoeffs
corresponds to the coefficient of the variable in the constraint represented by the i-th entry inindices
.
Note
indices
andcoeffs
are expected to be of the same length.EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.ncols() 0 sage: p.nrows() 0 sage: p.add_linear_constraints(5, 0, None) sage: p.add_col(list(range(5)), list(range(5))) sage: p.nrows() 5
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.ncols() 0 >>> p.nrows() 0 >>> p.add_linear_constraints(Integer(5), Integer(0), None) >>> p.add_col(list(range(Integer(5))), list(range(Integer(5)))) >>> p.nrows() 5
- add_linear_constraint(coefficients, lower_bound, upper_bound, name=None)[source]#
Add a linear constraint.
INPUT:
coefficients
– an iterable of pairs(i, v)
. In each pair,i
is a variable index (integer) andv
is a value (element ofbase_ring()
).lower_bound
– element ofbase_ring()
orNone
. The lower bound.upper_bound
– element ofbase_ring()
orNone
. The upper bound.name
– string orNone
. Optional name for this row.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variables(5) 4 sage: p.add_linear_constraint( zip(range(5), range(5)), 2.0, 2.0) sage: p.row(0) ([0, 1, 2, 3, 4], [0.0, 1.0, 2.0, 3.0, 4.0]) sage: p.row_bounds(0) (2.0, 2.0) sage: p.add_linear_constraint( zip(range(5), range(5)), 1.0, 1.0, name='foo') sage: p.row_name(1) 'foo'
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variables(Integer(5)) 4 >>> p.add_linear_constraint( zip(range(Integer(5)), range(Integer(5))), RealNumber('2.0'), RealNumber('2.0')) >>> p.row(Integer(0)) ([0, 1, 2, 3, 4], [0.0, 1.0, 2.0, 3.0, 4.0]) >>> p.row_bounds(Integer(0)) (2.0, 2.0) >>> p.add_linear_constraint( zip(range(Integer(5)), range(Integer(5))), RealNumber('1.0'), RealNumber('1.0'), name='foo') >>> p.row_name(Integer(1)) 'foo'
- add_linear_constraint_vector(degree, coefficients, lower_bound, upper_bound, name=None)[source]#
Add a vector-valued linear constraint.
Note
This is the generic implementation, which will split the vector-valued constraint into components and add these individually. Backends are encouraged to replace it with their own optimized implementation.
INPUT:
degree
– integer. The vector degree, that is, the number of new scalar constraints.coefficients
– an iterable of pairs(i, v)
. In each pair,i
is a variable index (integer) andv
is a vector (real and of lengthdegree
).lower_bound
– either a vector orNone
. The component-wise lower bound.upper_bound
– either a vector orNone
. The component-wise upper bound.name
– string orNone
. An optional name for all new rows.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: coeffs = ([0, vector([1, 2])], [1, vector([2, 3])]) sage: upper = vector([5, 5]) sage: lower = vector([0, 0]) sage: p.add_variables(2) 1 sage: p.add_linear_constraint_vector(2, coeffs, lower, upper, 'foo')
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> coeffs = ([Integer(0), vector([Integer(1), Integer(2)])], [Integer(1), vector([Integer(2), Integer(3)])]) >>> upper = vector([Integer(5), Integer(5)]) >>> lower = vector([Integer(0), Integer(0)]) >>> p.add_variables(Integer(2)) 1 >>> p.add_linear_constraint_vector(Integer(2), coeffs, lower, upper, 'foo')
- add_linear_constraints(number, lower_bound, upper_bound, names=None)[source]#
Add
'number
linear constraints.INPUT:
number
(integer) – the number of constraints to add.lower_bound
– a lower bound, either a real value orNone
upper_bound
– an upper bound, either a real value orNone
names
– an optional list of names (default:None
)
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variables(5) 5 sage: p.add_linear_constraints(5, None, 2) sage: p.row(4) ([], []) sage: p.row_bounds(4) (None, 2.0)
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variables(Integer(5)) 5 >>> p.add_linear_constraints(Integer(5), None, Integer(2)) >>> p.row(Integer(4)) ([], []) >>> p.row_bounds(Integer(4)) (None, 2.0)
- add_variable(*args, **kwdargs)[source]#
Add a variable.
This amounts to adding a new column to the matrix. By default, the variable is both positive and real.
INPUT:
lower_bound
– the lower bound of the variable (default: 0)upper_bound
– the upper bound of the variable (default:None
)binary
–True
if the variable is binary (default:False
).continuous
–True
if the variable is continuous (default:True
).integer
–True
if the variable is integral (default:False
).obj
– (optional) coefficient of this variable in the objective function (default: 0.0)name
– an optional name for the newly added variable (default:None
).
OUTPUT: The index of the newly created variable
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.ncols() 0 sage: p.add_variable() 0 sage: p.ncols() 1 sage: p.add_variable(binary=True) 1 sage: p.add_variable(lower_bound=-2.0, integer=True) 2 sage: p.add_variable(continuous=True, integer=True) Traceback (most recent call last): ... ValueError: ... sage: p.add_variable(name='x', obj=1.0) 3 sage: p.col_name(3) 'x' sage: p.objective_coefficient(3) 1.0
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.ncols() 0 >>> p.add_variable() 0 >>> p.ncols() 1 >>> p.add_variable(binary=True) 1 >>> p.add_variable(lower_bound=-RealNumber('2.0'), integer=True) 2 >>> p.add_variable(continuous=True, integer=True) Traceback (most recent call last): ... ValueError: ... >>> p.add_variable(name='x', obj=RealNumber('1.0')) 3 >>> p.col_name(Integer(3)) 'x' >>> p.objective_coefficient(Integer(3)) 1.0
- add_variables(*args, **kwdargs)[source]#
Add
n
variables.This amounts to adding new columns to the matrix. By default, the variables are both nonnegative and real.
INPUT:
n
– the number of new variables (must be > 0)lower_bound
– the lower bound of the variable (default: 0)upper_bound
– the upper bound of the variable (default:None
)binary
–True
if the variable is binary (default:False
).continuous
–True
if the variable is binary (default:True
).integer
–True
if the variable is binary (default:False
).obj
– (optional) coefficient of all variables in the objective function (default: 0.0)names
– optional list of names (default:None
)
OUTPUT: The index of the variable created last.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.ncols() 0 sage: p.add_variables(5) 4 sage: p.ncols() 5 sage: p.add_variables(2, lower_bound=-2.0, integer=True, names=['a','b']) 6
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.ncols() 0 >>> p.add_variables(Integer(5)) 4 >>> p.ncols() 5 >>> p.add_variables(Integer(2), lower_bound=-RealNumber('2.0'), integer=True, names=['a','b']) 6
- base_ring()[source]#
Return the base ring.
The backend’s base ring can be overridden. It is best to run the tests with GLPK and override the base ring to
QQ
. Then default input to backend methods, prepared byMixedIntegerLinearProgram
, depends on the base ring. This way input will be rational and so suitable for both exact and inexact methods; whereas output will be float and will thus triggerassertAlmostEqual()
tests.EXAMPLES:
sage: import sage.numerical.backends.logging_backend sage: from sage.numerical.backends.logging_backend import LoggingBackend sage: from sage.numerical.backends.generic_backend import get_solver sage: b = get_solver(solver = "GLPK") sage: lb = LoggingBackend(backend=b) sage: lb.base_ring() Real Double Field sage: from sage.rings.rational_field import QQ sage: lb = LoggingBackend(backend=b, base_ring=QQ) sage: lb.base_ring() Rational Field
>>> from sage.all import * >>> import sage.numerical.backends.logging_backend >>> from sage.numerical.backends.logging_backend import LoggingBackend >>> from sage.numerical.backends.generic_backend import get_solver >>> b = get_solver(solver = "GLPK") >>> lb = LoggingBackend(backend=b) >>> lb.base_ring() Real Double Field >>> from sage.rings.rational_field import QQ >>> lb = LoggingBackend(backend=b, base_ring=QQ) >>> lb.base_ring() Rational Field
- best_known_objective_bound()[source]#
Return the value of the currently best known bound.
This method returns the current best upper (resp. lower) bound on the optimal value of the objective function in a maximization (resp. minimization) problem. It is equal to the output of
get_objective_value()
if the MILP found an optimal solution, but it can differ if it was interrupted manually or after a time limit (cfsolver_parameter()
).Note
Has no meaning unless
solve
has been called before.EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver") sage: b = p.new_variable(binary=True) sage: for u,v in graphs.CycleGraph(5).edges(labels=False): ....: p.add_constraint(b[u]+b[v]<=1) sage: p.set_objective(p.sum(b[x] for x in range(5))) sage: p.solve() 2.0 sage: pb = p.get_backend() sage: pb.get_objective_value() 2.0 sage: pb.best_known_objective_bound() 2.0
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver") >>> b = p.new_variable(binary=True) >>> for u,v in graphs.CycleGraph(Integer(5)).edges(labels=False): ... p.add_constraint(b[u]+b[v]<=Integer(1)) >>> p.set_objective(p.sum(b[x] for x in range(Integer(5)))) >>> p.solve() 2.0 >>> pb = p.get_backend() >>> pb.get_objective_value() 2.0 >>> pb.best_known_objective_bound() 2.0
- col_bounds(index)[source]#
Return the bounds of a specific variable.
INPUT:
index
(integer) – the variable’s id.
OUTPUT:
A pair
(lower_bound, upper_bound)
. Each of them can be set toNone
if the variable is not bounded in the corresponding direction, and is a real value otherwise.EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variable() 0 sage: p.col_bounds(0) (0.0, None) sage: p.variable_upper_bound(0, 5) sage: p.col_bounds(0) (0.0, 5.0)
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variable() 0 >>> p.col_bounds(Integer(0)) (0.0, None) >>> p.variable_upper_bound(Integer(0), Integer(5)) >>> p.col_bounds(Integer(0)) (0.0, 5.0)
- col_name(index)[source]#
Return the
index
-th column nameINPUT:
index
(integer) – the column idname
(char *
) – its name. When set toNULL
(default), the method returns the current name.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variable(name="I am a variable") 1 sage: p.col_name(0) 'I am a variable'
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variable(name="I am a variable") 1 >>> p.col_name(Integer(0)) 'I am a variable'
- copy()[source]#
Returns a copy of self.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver") sage: b = p.new_variable() sage: p.add_constraint(b[1] + b[2] <= 6) sage: p.set_objective(b[1] + b[2]) sage: copy(p).solve() 6.0
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver") >>> b = p.new_variable() >>> p.add_constraint(b[Integer(1)] + b[Integer(2)] <= Integer(6)) >>> p.set_objective(b[Integer(1)] + b[Integer(2)]) >>> copy(p).solve() 6.0
- dumps(compress=True)[source]#
Dump
self
to a strings
, which can later be reconstituted asself
usingloads(s)
.There is an optional boolean argument
compress
which defaults toTrue
.EXAMPLES:
sage: from sage.misc.persist import comp sage: O = SageObject() sage: p_comp = O.dumps() sage: p_uncomp = O.dumps(compress=False) sage: comp.decompress(p_comp) == p_uncomp True sage: import pickletools sage: pickletools.dis(p_uncomp) 0: \x80 PROTO 2 2: c GLOBAL 'sage.structure.sage_object SageObject' 41: q BINPUT ... 43: ) EMPTY_TUPLE 44: \x81 NEWOBJ 45: q BINPUT ... 47: . STOP highest protocol among opcodes = 2
>>> from sage.all import * >>> from sage.misc.persist import comp >>> O = SageObject() >>> p_comp = O.dumps() >>> p_uncomp = O.dumps(compress=False) >>> comp.decompress(p_comp) == p_uncomp True >>> import pickletools >>> pickletools.dis(p_uncomp) 0: \x80 PROTO 2 2: c GLOBAL 'sage.structure.sage_object SageObject' 41: q BINPUT ... 43: ) EMPTY_TUPLE 44: \x81 NEWOBJ 45: q BINPUT ... 47: . STOP highest protocol among opcodes = 2
- get_custom_name()[source]#
Return the custom name of this object, or
None
if it is not renamed.EXAMPLES:
sage: P.<x> = QQ[] sage: P.get_custom_name() is None True sage: P.rename('A polynomial ring') sage: P.get_custom_name() 'A polynomial ring' sage: P.reset_name() sage: P.get_custom_name() is None True
>>> from sage.all import * >>> P = QQ['x']; (x,) = P._first_ngens(1) >>> P.get_custom_name() is None True >>> P.rename('A polynomial ring') >>> P.get_custom_name() 'A polynomial ring' >>> P.reset_name() >>> P.get_custom_name() is None True
- get_objective_value()[source]#
Return the value of the objective function.
Note
Behavior is undefined unless
solve
has been called before.EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variables(2) 1 sage: p.add_linear_constraint([(0,1), (1,2)], None, 3) sage: p.set_objective([2, 5]) sage: p.solve() 0 sage: p.get_objective_value() 7.5 sage: p.get_variable_value(0) 0.0 sage: p.get_variable_value(1) 1.5
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variables(Integer(2)) 1 >>> p.add_linear_constraint([(Integer(0),Integer(1)), (Integer(1),Integer(2))], None, Integer(3)) >>> p.set_objective([Integer(2), Integer(5)]) >>> p.solve() 0 >>> p.get_objective_value() 7.5 >>> p.get_variable_value(Integer(0)) 0.0 >>> p.get_variable_value(Integer(1)) 1.5
- get_relative_objective_gap()[source]#
Return the relative objective gap of the best known solution.
For a minimization problem, this value is computed by \((\texttt{bestinteger} - \texttt{bestobjective}) / (1e-10 + |\texttt{bestobjective}|)\), where
bestinteger
is the value returned byget_objective_value()
andbestobjective
is the value returned bybest_known_objective_bound()
. For a maximization problem, the value is computed by \((\texttt{bestobjective} - \texttt{bestinteger}) / (1e-10 + |\texttt{bestobjective}|)\).Note
Has no meaning unless
solve
has been called before.EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver") sage: b = p.new_variable(binary=True) sage: for u,v in graphs.CycleGraph(5).edges(labels=False): ....: p.add_constraint(b[u]+b[v]<=1) sage: p.set_objective(p.sum(b[x] for x in range(5))) sage: p.solve() 2.0 sage: pb = p.get_backend() sage: pb.get_objective_value() 2.0 sage: pb.get_relative_objective_gap() 0.0
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver") >>> b = p.new_variable(binary=True) >>> for u,v in graphs.CycleGraph(Integer(5)).edges(labels=False): ... p.add_constraint(b[u]+b[v]<=Integer(1)) >>> p.set_objective(p.sum(b[x] for x in range(Integer(5)))) >>> p.solve() 2.0 >>> pb = p.get_backend() >>> pb.get_objective_value() 2.0 >>> pb.get_relative_objective_gap() 0.0
- get_variable_value(variable)[source]#
Return the value of a variable given by the solver.
Note
Behavior is undefined unless
solve
has been called before.EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variables(2) 1 sage: p.add_linear_constraint([(0,1), (1, 2)], None, 3) sage: p.set_objective([2, 5]) sage: p.solve() 0 sage: p.get_objective_value() 7.5 sage: p.get_variable_value(0) 0.0 sage: p.get_variable_value(1) 1.5
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variables(Integer(2)) 1 >>> p.add_linear_constraint([(Integer(0),Integer(1)), (Integer(1), Integer(2))], None, Integer(3)) >>> p.set_objective([Integer(2), Integer(5)]) >>> p.solve() 0 >>> p.get_objective_value() 7.5 >>> p.get_variable_value(Integer(0)) 0.0 >>> p.get_variable_value(Integer(1)) 1.5
- is_maximization(*args, **kwdargs)[source]#
Test whether the problem is a maximization
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.is_maximization() True sage: p.set_sense(-1) sage: p.is_maximization() False
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.is_maximization() True >>> p.set_sense(-Integer(1)) >>> p.is_maximization() False
- is_slack_variable_basic(*args, **kwdargs)[source]#
Test whether the slack variable of the given row is basic.
This assumes that the problem has been solved with the simplex method and a basis is available. Otherwise an exception will be raised.
INPUT:
index
(integer) – the variable’s id
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: p = MixedIntegerLinearProgram(maximization=True, ....: solver="Nonexistent_LP_solver") sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) sage: p.set_objective(5.5 * x[0] - 3 * x[1]) sage: b = p.get_backend() sage: # Backend-specific commands to instruct solver to use simplex method here sage: b.solve() 0 sage: b.is_slack_variable_basic(0) True sage: b.is_slack_variable_basic(1) False
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> p = MixedIntegerLinearProgram(maximization=True, ... solver="Nonexistent_LP_solver") >>> x = p.new_variable(nonnegative=True) >>> p.add_constraint(-x[Integer(0)] + x[Integer(1)] <= Integer(2)) >>> p.add_constraint(Integer(8) * x[Integer(0)] + Integer(2) * x[Integer(1)] <= Integer(17)) >>> p.set_objective(RealNumber('5.5') * x[Integer(0)] - Integer(3) * x[Integer(1)]) >>> b = p.get_backend() >>> # Backend-specific commands to instruct solver to use simplex method here >>> b.solve() 0 >>> b.is_slack_variable_basic(Integer(0)) True >>> b.is_slack_variable_basic(Integer(1)) False
- is_slack_variable_nonbasic_at_lower_bound(*args, **kwdargs)[source]#
Test whether the given variable is nonbasic at lower bound.
This assumes that the problem has been solved with the simplex method and a basis is available. Otherwise an exception will be raised.
INPUT:
index
(integer) – the variable’s id
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: p = MixedIntegerLinearProgram(maximization=True, ....: solver="Nonexistent_LP_solver") sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) sage: p.set_objective(5.5 * x[0] - 3 * x[1]) sage: b = p.get_backend() sage: # Backend-specific commands to instruct solver to use simplex method here sage: b.solve() 0 sage: b.is_slack_variable_nonbasic_at_lower_bound(0) False sage: b.is_slack_variable_nonbasic_at_lower_bound(1) True
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> p = MixedIntegerLinearProgram(maximization=True, ... solver="Nonexistent_LP_solver") >>> x = p.new_variable(nonnegative=True) >>> p.add_constraint(-x[Integer(0)] + x[Integer(1)] <= Integer(2)) >>> p.add_constraint(Integer(8) * x[Integer(0)] + Integer(2) * x[Integer(1)] <= Integer(17)) >>> p.set_objective(RealNumber('5.5') * x[Integer(0)] - Integer(3) * x[Integer(1)]) >>> b = p.get_backend() >>> # Backend-specific commands to instruct solver to use simplex method here >>> b.solve() 0 >>> b.is_slack_variable_nonbasic_at_lower_bound(Integer(0)) False >>> b.is_slack_variable_nonbasic_at_lower_bound(Integer(1)) True
- is_variable_basic(*args, **kwdargs)[source]#
Test whether the given variable is basic.
This assumes that the problem has been solved with the simplex method and a basis is available. Otherwise an exception will be raised.
INPUT:
index
(integer) – the variable’s id
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: p = MixedIntegerLinearProgram(maximization=True, ....: solver="Nonexistent_LP_solver") sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) sage: p.set_objective(5.5 * x[0] - 3 * x[1]) sage: b = p.get_backend() sage: # Backend-specific commands to instruct solver to use simplex method here sage: b.solve() 0 sage: b.is_variable_basic(0) True sage: b.is_variable_basic(1) False
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> p = MixedIntegerLinearProgram(maximization=True, ... solver="Nonexistent_LP_solver") >>> x = p.new_variable(nonnegative=True) >>> p.add_constraint(-x[Integer(0)] + x[Integer(1)] <= Integer(2)) >>> p.add_constraint(Integer(8) * x[Integer(0)] + Integer(2) * x[Integer(1)] <= Integer(17)) >>> p.set_objective(RealNumber('5.5') * x[Integer(0)] - Integer(3) * x[Integer(1)]) >>> b = p.get_backend() >>> # Backend-specific commands to instruct solver to use simplex method here >>> b.solve() 0 >>> b.is_variable_basic(Integer(0)) True >>> b.is_variable_basic(Integer(1)) False
- is_variable_binary(*args, **kwdargs)[source]#
Test whether the given variable is of binary type.
INPUT:
index
(integer) – the variable’s id
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.ncols() 0 sage: p.add_variable() 0 sage: p.set_variable_type(0,0) sage: p.is_variable_binary(0) True
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.ncols() 0 >>> p.add_variable() 0 >>> p.set_variable_type(Integer(0),Integer(0)) >>> p.is_variable_binary(Integer(0)) True
- is_variable_continuous(*args, **kwdargs)[source]#
Test whether the given variable is of continuous/real type.
INPUT:
index
(integer) – the variable’s id
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.ncols() 0 sage: p.add_variable() 0 sage: p.is_variable_continuous(0) True sage: p.set_variable_type(0,1) sage: p.is_variable_continuous(0) False
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.ncols() 0 >>> p.add_variable() 0 >>> p.is_variable_continuous(Integer(0)) True >>> p.set_variable_type(Integer(0),Integer(1)) >>> p.is_variable_continuous(Integer(0)) False
- is_variable_integer(*args, **kwdargs)[source]#
Test whether the given variable is of integer type.
INPUT:
index
(integer) – the variable’s id
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.ncols() 0 sage: p.add_variable() 0 sage: p.set_variable_type(0,1) sage: p.is_variable_integer(0) True
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.ncols() 0 >>> p.add_variable() 0 >>> p.set_variable_type(Integer(0),Integer(1)) >>> p.is_variable_integer(Integer(0)) True
- is_variable_nonbasic_at_lower_bound(*args, **kwdargs)[source]#
Test whether the given variable is nonbasic at lower bound.
This assumes that the problem has been solved with the simplex method and a basis is available. Otherwise an exception will be raised.
INPUT:
index
(integer) – the variable’s id
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: p = MixedIntegerLinearProgram(maximization=True, ....: solver="Nonexistent_LP_solver") sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) sage: p.set_objective(5.5 * x[0] - 3 * x[1]) sage: b = p.get_backend() sage: # Backend-specific commands to instruct solver to use simplex method here sage: b.solve() 0 sage: b.is_variable_nonbasic_at_lower_bound(0) False sage: b.is_variable_nonbasic_at_lower_bound(1) True
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> p = MixedIntegerLinearProgram(maximization=True, ... solver="Nonexistent_LP_solver") >>> x = p.new_variable(nonnegative=True) >>> p.add_constraint(-x[Integer(0)] + x[Integer(1)] <= Integer(2)) >>> p.add_constraint(Integer(8) * x[Integer(0)] + Integer(2) * x[Integer(1)] <= Integer(17)) >>> p.set_objective(RealNumber('5.5') * x[Integer(0)] - Integer(3) * x[Integer(1)]) >>> b = p.get_backend() >>> # Backend-specific commands to instruct solver to use simplex method here >>> b.solve() 0 >>> b.is_variable_nonbasic_at_lower_bound(Integer(0)) False >>> b.is_variable_nonbasic_at_lower_bound(Integer(1)) True
- ncols(*args, **kwdargs)[source]#
Return the number of columns/variables.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.ncols() 0 sage: p.add_variables(2) 1 sage: p.ncols() 2
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.ncols() 0 >>> p.add_variables(Integer(2)) 1 >>> p.ncols() 2
- nrows(*args, **kwdargs)[source]#
Return the number of rows/constraints.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.nrows() 0 sage: p.add_linear_constraints(2, 2.0, None) sage: p.nrows() 2
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.nrows() 0 >>> p.add_linear_constraints(Integer(2), RealNumber('2.0'), None) >>> p.nrows() 2
- objective_coefficient(variable, coeff=None)[source]#
Set or get the coefficient of a variable in the objective function
INPUT:
variable
(integer) – the variable’s idcoeff
(double) – its coefficient
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variable() 0 sage: p.objective_coefficient(0) 0.0 sage: p.objective_coefficient(0,2) sage: p.objective_coefficient(0) 2.0
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variable() 0 >>> p.objective_coefficient(Integer(0)) 0.0 >>> p.objective_coefficient(Integer(0),Integer(2)) >>> p.objective_coefficient(Integer(0)) 2.0
- objective_constant_term(d=None)[source]#
Set or get the constant term in the objective function
INPUT:
d
(double) – its coefficient. If \(None\) (default), return the current value.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.objective_constant_term() 0.0 sage: p.objective_constant_term(42) sage: p.objective_constant_term() 42.0
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.objective_constant_term() 0.0 >>> p.objective_constant_term(Integer(42)) >>> p.objective_constant_term() 42.0
- parent()[source]#
Return the type of
self
to support the coercion framework.EXAMPLES:
sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t # needs sage.symbolic log(sqrt(2) + 1) + log(sqrt(2) - 1) sage: u = t.maxima_methods() # needs sage.symbolic sage: u.parent() # needs sage.symbolic <class 'sage.symbolic.maxima_wrapper.MaximaWrapper'>
>>> from sage.all import * >>> t = log(sqrt(Integer(2)) - Integer(1)) + log(sqrt(Integer(2)) + Integer(1)); t # needs sage.symbolic log(sqrt(2) + 1) + log(sqrt(2) - 1) >>> u = t.maxima_methods() # needs sage.symbolic >>> u.parent() # needs sage.symbolic <class 'sage.symbolic.maxima_wrapper.MaximaWrapper'>
- problem_name(name=None)[source]#
Return or define the problem’s name
INPUT:
name
(str
) – the problem’s name. When set toNone
(default), the method returns the problem’s name.
EXAMPLES:
sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") # optional - Nonexistent_LP_solver sage: p.problem_name("There once was a french fry") # optional - Nonexistent_LP_solver sage: print(p.problem_name()) # optional - Nonexistent_LP_solver There once was a french fry
>>> from sage.all import * >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") # optional - Nonexistent_LP_solver >>> p.problem_name("There once was a french fry") # optional - Nonexistent_LP_solver >>> print(p.problem_name()) # optional - Nonexistent_LP_solver There once was a french fry
- remove_constraint(i)[source]#
Remove a constraint.
INPUT:
i
– index of the constraint to remove.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver") sage: v = p.new_variable(nonnegative=True) sage: x,y = v[0], v[1] sage: p.add_constraint(2*x + 3*y, max=6) sage: p.add_constraint(3*x + 2*y, max=6) sage: p.set_objective(x + y + 7) sage: p.set_integer(x); p.set_integer(y) sage: p.solve() 9.0 sage: p.remove_constraint(0) sage: p.solve() 10.0 sage: p.get_values([x,y]) [0.0, 3.0]
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver") >>> v = p.new_variable(nonnegative=True) >>> x,y = v[Integer(0)], v[Integer(1)] >>> p.add_constraint(Integer(2)*x + Integer(3)*y, max=Integer(6)) >>> p.add_constraint(Integer(3)*x + Integer(2)*y, max=Integer(6)) >>> p.set_objective(x + y + Integer(7)) >>> p.set_integer(x); p.set_integer(y) >>> p.solve() 9.0 >>> p.remove_constraint(Integer(0)) >>> p.solve() 10.0 >>> p.get_values([x,y]) [0.0, 3.0]
- remove_constraints(constraints)[source]#
Remove several constraints.
INPUT:
constraints
– an iterable containing the indices of the rows to remove.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variables(2) 1 sage: p.add_linear_constraint([(0, 2), (1, 3)], None, 6) sage: p.add_linear_constraint([(0, 3), (1, 2)], None, 6) sage: p.remove_constraints([0, 1])
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variables(Integer(2)) 1 >>> p.add_linear_constraint([(Integer(0), Integer(2)), (Integer(1), Integer(3))], None, Integer(6)) >>> p.add_linear_constraint([(Integer(0), Integer(3)), (Integer(1), Integer(2))], None, Integer(6)) >>> p.remove_constraints([Integer(0), Integer(1)])
- rename(x=None)[source]#
Change self so it prints as x, where x is a string.
If x is
None
, the existing custom name is removed.Note
This is only supported for Python classes that derive from SageObject.
EXAMPLES:
sage: x = PolynomialRing(QQ, 'x', sparse=True).gen() sage: g = x^3 + x - 5 sage: g x^3 + x - 5 sage: g.rename('a polynomial') sage: g a polynomial sage: g + x x^3 + 2*x - 5 sage: h = g^100 sage: str(h)[:20] 'x^300 + 100*x^298 - ' sage: h.rename('x^300 + ...') sage: h x^300 + ... sage: g.rename(None) sage: g x^3 + x - 5
>>> from sage.all import * >>> x = PolynomialRing(QQ, 'x', sparse=True).gen() >>> g = x**Integer(3) + x - Integer(5) >>> g x^3 + x - 5 >>> g.rename('a polynomial') >>> g a polynomial >>> g + x x^3 + 2*x - 5 >>> h = g**Integer(100) >>> str(h)[:Integer(20)] 'x^300 + 100*x^298 - ' >>> h.rename('x^300 + ...') >>> h x^300 + ... >>> g.rename(None) >>> g x^3 + x - 5
Real numbers are not Python classes, so rename is not supported:
sage: a = 3.14 sage: type(a) # needs sage.rings.real_mpfr <... 'sage.rings.real_mpfr.RealLiteral'> sage: a.rename('pi') # needs sage.rings.real_mpfr Traceback (most recent call last): ... NotImplementedError: object does not support renaming: 3.14000000000000
>>> from sage.all import * >>> a = RealNumber('3.14') >>> type(a) # needs sage.rings.real_mpfr <... 'sage.rings.real_mpfr.RealLiteral'> >>> a.rename('pi') # needs sage.rings.real_mpfr Traceback (most recent call last): ... NotImplementedError: object does not support renaming: 3.14000000000000
Note
The reason C-extension types are not supported by default is if they were then every single one would have to carry around an extra attribute, which would be slower and waste a lot of memory.
To support them for a specific class, add a
cdef public _SageObject__custom_name
attribute.
- reset_name()[source]#
Remove the custom name of an object.
EXAMPLES:
sage: P.<x> = QQ[] sage: P Univariate Polynomial Ring in x over Rational Field sage: P.rename('A polynomial ring') sage: P A polynomial ring sage: P.reset_name() sage: P Univariate Polynomial Ring in x over Rational Field
>>> from sage.all import * >>> P = QQ['x']; (x,) = P._first_ngens(1) >>> P Univariate Polynomial Ring in x over Rational Field >>> P.rename('A polynomial ring') >>> P A polynomial ring >>> P.reset_name() >>> P Univariate Polynomial Ring in x over Rational Field
- row(i)[source]#
Return a row
INPUT:
index
(integer) – the constraint’s id.
OUTPUT:
A pair
(indices, coeffs)
whereindices
lists the entries whose coefficient is nonzero, and to whichcoeffs
associates their coefficient on the model of theadd_linear_constraint
method.EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variables(5) 4 sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2) sage: p.row(0) ([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0]) ## FIXME: Why backwards? sage: p.row_bounds(0) (2.0, 2.0)
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variables(Integer(5)) 4 >>> p.add_linear_constraint(zip(range(Integer(5)), range(Integer(5))), Integer(2), Integer(2)) >>> p.row(Integer(0)) ([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0]) ## FIXME: Why backwards? >>> p.row_bounds(Integer(0)) (2.0, 2.0)
- row_bounds(index)[source]#
Return the bounds of a specific constraint.
INPUT:
index
(integer) – the constraint’s id.
OUTPUT:
A pair
(lower_bound, upper_bound)
. Each of them can be set toNone
if the constraint is not bounded in the corresponding direction, and is a real value otherwise.EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variables(5) 4 sage: p.add_linear_constraint(list(range(5)), list(range(5)), 2, 2) sage: p.row(0) ([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0]) ## FIXME: Why backwards? sage: p.row_bounds(0) (2.0, 2.0)
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variables(Integer(5)) 4 >>> p.add_linear_constraint(list(range(Integer(5))), list(range(Integer(5))), Integer(2), Integer(2)) >>> p.row(Integer(0)) ([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0]) ## FIXME: Why backwards? >>> p.row_bounds(Integer(0)) (2.0, 2.0)
- row_name(index)[source]#
Return the
index
th row nameINPUT:
index
(integer) – the row’s id
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_linear_constraints(1, 2, None, names=['Empty constraint 1']) sage: p.row_name(0) 'Empty constraint 1'
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_linear_constraints(Integer(1), Integer(2), None, names=['Empty constraint 1']) >>> p.row_name(Integer(0)) 'Empty constraint 1'
- save(filename=None, compress=True)[source]#
Save self to the given filename.
EXAMPLES:
sage: # needs sage.symbolic sage: x = SR.var("x") sage: f = x^3 + 5 sage: from tempfile import NamedTemporaryFile sage: with NamedTemporaryFile(suffix=".sobj") as t: ....: f.save(t.name) ....: load(t.name) x^3 + 5
>>> from sage.all import * >>> # needs sage.symbolic >>> x = SR.var("x") >>> f = x**Integer(3) + Integer(5) >>> from tempfile import NamedTemporaryFile >>> with NamedTemporaryFile(suffix=".sobj") as t: ... f.save(t.name) ... load(t.name) x^3 + 5
- set_objective(coeff, d=0.0)[source]#
Set the objective function.
INPUT:
coeff
– a list of real values, whose i-th element is the coefficient of the i-th variable in the objective function.d
(double) – the constant term in the linear function (set to \(0\) by default)
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variables(5) 4 sage: p.set_objective([1, 1, 2, 1, 3]) sage: [p.objective_coefficient(x) for x in range(5)] [1.0, 1.0, 2.0, 1.0, 3.0]
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variables(Integer(5)) 4 >>> p.set_objective([Integer(1), Integer(1), Integer(2), Integer(1), Integer(3)]) >>> [p.objective_coefficient(x) for x in range(Integer(5))] [1.0, 1.0, 2.0, 1.0, 3.0]
Constants in the objective function are respected:
sage: # optional - nonexistent_lp_solver sage: p = MixedIntegerLinearProgram(solver='Nonexistent_LP_solver') sage: x,y = p[0], p[1] sage: p.add_constraint(2*x + 3*y, max=6) sage: p.add_constraint(3*x + 2*y, max=6) sage: p.set_objective(x + y + 7) sage: p.set_integer(x); p.set_integer(y) sage: p.solve() 9.0
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> p = MixedIntegerLinearProgram(solver='Nonexistent_LP_solver') >>> x,y = p[Integer(0)], p[Integer(1)] >>> p.add_constraint(Integer(2)*x + Integer(3)*y, max=Integer(6)) >>> p.add_constraint(Integer(3)*x + Integer(2)*y, max=Integer(6)) >>> p.set_objective(x + y + Integer(7)) >>> p.set_integer(x); p.set_integer(y) >>> p.solve() 9.0
- set_sense(sense)[source]#
Set the direction (maximization/minimization).
INPUT:
sense
(integer) :+1 => Maximization
-1 => Minimization
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.is_maximization() True sage: p.set_sense(-1) sage: p.is_maximization() False
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.is_maximization() True >>> p.set_sense(-Integer(1)) >>> p.is_maximization() False
- set_variable_type(variable, vtype)[source]#
Set the type of a variable
INPUT:
variable
(integer) – the variable’s idvtype
(integer):\(1\) Integer
\(0\) Binary
\(-1\) Continuous
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.ncols() 0 sage: p.add_variable() 0 sage: p.set_variable_type(0,1) sage: p.is_variable_integer(0) True
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.ncols() 0 >>> p.add_variable() 0 >>> p.set_variable_type(Integer(0),Integer(1)) >>> p.is_variable_integer(Integer(0)) True
- set_verbosity(level)[source]#
Set the log (verbosity) level
INPUT:
level
(integer) – From 0 (no verbosity) to 3.
EXAMPLES:
sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") # optional - Nonexistent_LP_solver sage: p.set_verbosity(2) # optional - Nonexistent_LP_solver
>>> from sage.all import * >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") # optional - Nonexistent_LP_solver >>> p.set_verbosity(Integer(2)) # optional - Nonexistent_LP_solver
- solve(*args, **kwdargs)[source]#
Solve the problem.
Note
This method raises
MIPSolverException
exceptions when the solution cannot be computed for any reason (none exists, or the LP solver was not able to find it, etc…)EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_linear_constraints(5, 0, None) sage: p.add_col(list(range(5)), list(range(5))) sage: p.solve() 0 sage: p.objective_coefficient(0,1) sage: p.solve() Traceback (most recent call last): ... MIPSolverException: ...
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_linear_constraints(Integer(5), Integer(0), None) >>> p.add_col(list(range(Integer(5))), list(range(Integer(5)))) >>> p.solve() 0 >>> p.objective_coefficient(Integer(0),Integer(1)) >>> p.solve() Traceback (most recent call last): ... MIPSolverException: ...
- solver_parameter(name, value=None)[source]#
Return or define a solver parameter
INPUT:
name
(string) – the parametervalue
– the parameter’s value if it is to be defined, orNone
(default) to obtain its current value.
Note
The list of available parameters is available at
solver_parameter()
.EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.solver_parameter("timelimit") sage: p.solver_parameter("timelimit", 60) sage: p.solver_parameter("timelimit")
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.solver_parameter("timelimit") >>> p.solver_parameter("timelimit", Integer(60)) >>> p.solver_parameter("timelimit")
- variable_lower_bound(index, value=False)[source]#
Return or define the lower bound on a variable
INPUT:
index
(integer) – the variable’s idvalue
– real value, orNone
to mean that the variable has not lower bound. When set toFalse
(default), the method returns the current value.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variable() 0 sage: p.col_bounds(0) (0.0, None) sage: p.variable_lower_bound(0, 5) sage: p.col_bounds(0) (5.0, None)
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variable() 0 >>> p.col_bounds(Integer(0)) (0.0, None) >>> p.variable_lower_bound(Integer(0), Integer(5)) >>> p.col_bounds(Integer(0)) (5.0, None)
- variable_upper_bound(index, value=False)[source]#
Return or define the upper bound on a variable
INPUT:
index
(integer) – the variable’s idvalue
– real value, orNone
to mean that the variable has not upper bound. When set toFalse
(default), the method returns the current value.
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variable() 0 sage: p.col_bounds(0) (0.0, None) sage: p.variable_upper_bound(0, 5) sage: p.col_bounds(0) (0.0, 5.0)
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variable() 0 >>> p.col_bounds(Integer(0)) (0.0, None) >>> p.variable_upper_bound(Integer(0), Integer(5)) >>> p.col_bounds(Integer(0)) (0.0, 5.0)
- write_lp(name)[source]#
Write the problem to a
.lp
fileINPUT:
filename
(string)
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variables(2) 2 sage: p.add_linear_constraint([(0, 1], (1, 2)], None, 3) sage: p.set_objective([2, 5]) sage: from tempfile import NamedTemporaryFile sage: with NamedTemporaryFile(suffix=".lp") as f: ....: p.write_lp(f.name)
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variables(Integer(2)) 2 >>> p.add_linear_constraint([(Integer(0), Integer(1)], (Integer(1), Integer(2))], None, Integer(3)) >>> p.set_objective([Integer(2), Integer(5)]) >>> from tempfile import NamedTemporaryFile >>> with NamedTemporaryFile(suffix=".lp") as f: ... p.write_lp(f.name)
- write_mps(name, modern)[source]#
Write the problem to a
.mps
fileINPUT:
filename
(string)
EXAMPLES:
sage: # optional - nonexistent_lp_solver sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver="Nonexistent_LP_solver") sage: p.add_variables(2) 2 sage: p.add_linear_constraint([(0, 1), (1, 2)], None, 3) sage: p.set_objective([2, 5]) sage: from tempfile import NamedTemporaryFile sage: with NamedTemporaryFile(suffix=".lp") as f: ....: p.write_lp(f.name)
>>> from sage.all import * >>> # optional - nonexistent_lp_solver >>> from sage.numerical.backends.generic_backend import get_solver >>> p = get_solver(solver="Nonexistent_LP_solver") >>> p.add_variables(Integer(2)) 2 >>> p.add_linear_constraint([(Integer(0), Integer(1)), (Integer(1), Integer(2))], None, Integer(3)) >>> p.set_objective([Integer(2), Integer(5)]) >>> from tempfile import NamedTemporaryFile >>> with NamedTemporaryFile(suffix=".lp") as f: ... p.write_lp(f.name)
- sage.numerical.backends.logging_backend.LoggingBackendFactory(solver=None, printing=True, doctest_file=None, test_method_file=None, test_method=None, base_ring=Rational Field)[source]#
Factory that constructs a
LoggingBackend
for debugging and testing.An instance of it can be passed as the solver argument of
sage.numerical.backends.generic_backend.get_solver()
andMixedIntegerLinearProgram
.EXAMPLES:
Assume that we have the following function that does some computation using
MixedIntegerLinearProgram
(or MIP backend methods), and suppose we have observed that it works with the GLPK backend, but not with the COIN backend:sage: def compute_something(solver='GLPK'): ....: from sage.numerical.mip import MIPSolverException ....: mip = MixedIntegerLinearProgram(solver=solver) ....: lb = mip.get_backend() ....: lb.add_variable(obj=42, name='Helloooooo') ....: lb.add_variable(obj=1789) ....: try: ....: lb.solve() ....: except MIPSolverException: ....: return 4711 ....: else: ....: return 91
>>> from sage.all import * >>> def compute_something(solver='GLPK'): ... from sage.numerical.mip import MIPSolverException ... mip = MixedIntegerLinearProgram(solver=solver) ... lb = mip.get_backend() ... lb.add_variable(obj=Integer(42), name='Helloooooo') ... lb.add_variable(obj=Integer(1789)) ... try: ... lb.solve() ... except MIPSolverException: ... return Integer(4711) ... else: ... return Integer(91)
We can investigate what the backend methods are doing by running a
LoggingBackend
in its in-terminal logging mode:sage: import sage.numerical.backends.logging_backend sage: from sage.numerical.backends.logging_backend import LoggingBackendFactory sage: compute_something(solver = LoggingBackendFactory(solver='GLPK')) # p = get_solver(solver='GLPK') # p.add_variable(obj=42, name='Helloooooo') # result: 0 # p.add_variable(obj=1789) # result: 1 # p.solve() # exception: GLPK: The LP (relaxation) problem has no dual feasible solution 4711
>>> from sage.all import * >>> import sage.numerical.backends.logging_backend >>> from sage.numerical.backends.logging_backend import LoggingBackendFactory >>> compute_something(solver = LoggingBackendFactory(solver='GLPK')) # p = get_solver(solver='GLPK') # p.add_variable(obj=42, name='Helloooooo') # result: 0 # p.add_variable(obj=1789) # result: 1 # p.solve() # exception: GLPK: The LP (relaxation) problem has no dual feasible solution 4711
By replacing ‘GLPK’ by ‘COIN’ above, we can then compare the two logs and see where they differ.
Imagine that we have now fixed the bug in the COIN backend, and we want to add a doctest that documents this fact. We do not want to call
compute_something
in the doctest, but rather just have a sequence of calls to backend methods.We can have the doctest autogenerated by running a
LoggingBackend
in its doctest-writing mode:sage: fname = tmp_filename() sage: compute_something(solver = LoggingBackendFactory(solver='GLPK', printing=False, ....: doctest_file=fname)) 4711 sage: with open(fname) as f: ....: for line in f.readlines(): _ = sys.stdout.write('|{}'.format(line)) | sage: p = get_solver(solver='GLPK') | sage: p.add_variable(obj=42, name='Helloooooo') | 0 | sage: p.add_variable(obj=1789) | 1 | sage: p.solve() | Traceback (most recent call last): | ... | MIPSolverException: GLPK: The LP (relaxation) problem has no dual feasible solution
>>> from sage.all import * >>> fname = tmp_filename() >>> compute_something(solver = LoggingBackendFactory(solver='GLPK', printing=False, ... doctest_file=fname)) 4711 >>> with open(fname) as f: ... for line in f.readlines(): _ = sys.stdout.write('|{}'.format(line)) | sage: p = get_solver(solver='GLPK') | sage: p.add_variable(obj=42, name='Helloooooo') | 0 | sage: p.add_variable(obj=1789) | 1 | sage: p.solve() | Traceback (most recent call last): | ... | MIPSolverException: GLPK: The LP (relaxation) problem has no dual feasible solution
We then copy from the generated file and paste into the source code of the COIN backend.
If this test seems valuable enough that all backends should be tested against it, we should create a test method instead of a docstring.
We can have the test method autogenerated by running a
LoggingBackend
in its test-method-writing mode:sage: fname = tmp_filename() sage: compute_something(solver= LoggingBackendFactory(solver='GLPK', printing=False, ....: test_method_file=fname, ....: test_method='something')) 4711 sage: with open(fname) as f: ....: for line in f.readlines(): _ = sys.stdout.write('|{}'.format(line)) | | @classmethod | def _test_something(cls, tester=None, **options): | ... | Run tests on ... | | TESTS:: | | sage: from sage.numerical.backends.generic_backend import GenericBackend | sage: p = GenericBackend() | sage: p._test_something() | Traceback (most recent call last): | ... | NotImplementedError | | ... | p = cls() # fresh instance of the backend | if tester is None: | tester = p._tester(**options) | tester.assertEqual(p.add_variable(obj=42, name='Helloooooo'), 0) | tester.assertEqual(p.add_variable(obj=1789), 1) | with tester.assertRaises(MIPSolverException) as cm: | p.solve()
>>> from sage.all import * >>> fname = tmp_filename() >>> compute_something(solver= LoggingBackendFactory(solver='GLPK', printing=False, ... test_method_file=fname, ... test_method='something')) 4711 >>> with open(fname) as f: ... for line in f.readlines(): _ = sys.stdout.write('|{}'.format(line)) | | @classmethod | def _test_something(cls, tester=None, **options): | ... | Run tests on ... | | TESTS:: | | sage: from sage.numerical.backends.generic_backend import GenericBackend | sage: p = GenericBackend() | sage: p._test_something() | Traceback (most recent call last): | ... | NotImplementedError | | ... | p = cls() # fresh instance of the backend | if tester is None: | tester = p._tester(**options) | tester.assertEqual(p.add_variable(obj=42, name='Helloooooo'), 0) | tester.assertEqual(p.add_variable(obj=1789), 1) | with tester.assertRaises(MIPSolverException) as cm: | p.solve()
We then copy from the generated file and paste into the source code of the generic backend, where all test methods are defined.
If
test_method_file
is not provided, a default output file name will be computed fromtest_method
.