passagemath-polyhedra 10.6.37__cp314-cp314-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_polyhedra/__init__.py +3 -0
- passagemath_polyhedra-10.6.37.dist-info/METADATA +367 -0
- passagemath_polyhedra-10.6.37.dist-info/METADATA.bak +369 -0
- passagemath_polyhedra-10.6.37.dist-info/RECORD +209 -0
- passagemath_polyhedra-10.6.37.dist-info/WHEEL +5 -0
- passagemath_polyhedra-10.6.37.dist-info/top_level.txt +3 -0
- passagemath_polyhedra.libs/libgcc_s-0cd532bd.so.1 +0 -0
- passagemath_polyhedra.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_polyhedra.libs/libgomp-8949ffbe.so.1.0.0 +0 -0
- passagemath_polyhedra.libs/libstdc++-5d72f927.so.6.0.33 +0 -0
- sage/all__sagemath_polyhedra.py +50 -0
- sage/game_theory/all.py +8 -0
- sage/game_theory/catalog.py +6 -0
- sage/game_theory/catalog_normal_form_games.py +923 -0
- sage/game_theory/cooperative_game.py +844 -0
- sage/game_theory/matching_game.py +1181 -0
- sage/game_theory/normal_form_game.py +2697 -0
- sage/game_theory/parser.py +275 -0
- sage/geometry/all__sagemath_polyhedra.py +22 -0
- sage/geometry/cone.py +6940 -0
- sage/geometry/cone_catalog.py +847 -0
- sage/geometry/cone_critical_angles.py +1027 -0
- sage/geometry/convex_set.py +1119 -0
- sage/geometry/fan.py +3743 -0
- sage/geometry/fan_isomorphism.py +389 -0
- sage/geometry/fan_morphism.py +1884 -0
- sage/geometry/hasse_diagram.py +202 -0
- sage/geometry/hyperplane_arrangement/affine_subspace.py +390 -0
- sage/geometry/hyperplane_arrangement/all.py +1 -0
- sage/geometry/hyperplane_arrangement/arrangement.py +3905 -0
- sage/geometry/hyperplane_arrangement/check_freeness.py +145 -0
- sage/geometry/hyperplane_arrangement/hyperplane.py +773 -0
- sage/geometry/hyperplane_arrangement/library.py +825 -0
- sage/geometry/hyperplane_arrangement/ordered_arrangement.py +642 -0
- sage/geometry/hyperplane_arrangement/plot.py +520 -0
- sage/geometry/integral_points.py +35 -0
- sage/geometry/integral_points_generic_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/integral_points_generic_dense.pyx +7 -0
- sage/geometry/lattice_polytope.py +5894 -0
- sage/geometry/linear_expression.py +773 -0
- sage/geometry/newton_polygon.py +767 -0
- sage/geometry/point_collection.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/point_collection.pyx +1008 -0
- sage/geometry/polyhedral_complex.py +2616 -0
- sage/geometry/polyhedron/all.py +8 -0
- sage/geometry/polyhedron/backend_cdd.py +460 -0
- sage/geometry/polyhedron/backend_cdd_rdf.py +231 -0
- sage/geometry/polyhedron/backend_field.py +347 -0
- sage/geometry/polyhedron/backend_normaliz.py +2503 -0
- sage/geometry/polyhedron/backend_number_field.py +168 -0
- sage/geometry/polyhedron/backend_polymake.py +765 -0
- sage/geometry/polyhedron/backend_ppl.py +582 -0
- sage/geometry/polyhedron/base.py +1206 -0
- sage/geometry/polyhedron/base0.py +1444 -0
- sage/geometry/polyhedron/base1.py +886 -0
- sage/geometry/polyhedron/base2.py +812 -0
- sage/geometry/polyhedron/base3.py +1845 -0
- sage/geometry/polyhedron/base4.py +1262 -0
- sage/geometry/polyhedron/base5.py +2700 -0
- sage/geometry/polyhedron/base6.py +1741 -0
- sage/geometry/polyhedron/base7.py +997 -0
- sage/geometry/polyhedron/base_QQ.py +1258 -0
- sage/geometry/polyhedron/base_RDF.py +98 -0
- sage/geometry/polyhedron/base_ZZ.py +934 -0
- sage/geometry/polyhedron/base_mutable.py +215 -0
- sage/geometry/polyhedron/base_number_field.py +122 -0
- sage/geometry/polyhedron/cdd_file_format.py +155 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/all.py +1 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +76 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +3859 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +39 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +1038 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pxd +9 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +501 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +207 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +102 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +2274 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +370 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +84 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +31 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +587 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +52 -0
- sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +560 -0
- sage/geometry/polyhedron/constructor.py +773 -0
- sage/geometry/polyhedron/double_description.py +753 -0
- sage/geometry/polyhedron/double_description_inhomogeneous.py +564 -0
- sage/geometry/polyhedron/face.py +1060 -0
- sage/geometry/polyhedron/generating_function.py +1810 -0
- sage/geometry/polyhedron/lattice_euclidean_group_element.py +178 -0
- sage/geometry/polyhedron/library.py +3502 -0
- sage/geometry/polyhedron/misc.py +121 -0
- sage/geometry/polyhedron/modules/all.py +1 -0
- sage/geometry/polyhedron/modules/formal_polyhedra_module.py +155 -0
- sage/geometry/polyhedron/palp_database.py +447 -0
- sage/geometry/polyhedron/parent.py +1279 -0
- sage/geometry/polyhedron/plot.py +1986 -0
- sage/geometry/polyhedron/ppl_lattice_polygon.py +556 -0
- sage/geometry/polyhedron/ppl_lattice_polytope.py +1257 -0
- sage/geometry/polyhedron/representation.py +1723 -0
- sage/geometry/pseudolines.py +515 -0
- sage/geometry/relative_interior.py +445 -0
- sage/geometry/toric_plotter.py +1103 -0
- sage/geometry/triangulation/all.py +2 -0
- sage/geometry/triangulation/base.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/triangulation/base.pyx +963 -0
- sage/geometry/triangulation/data.h +147 -0
- sage/geometry/triangulation/data.pxd +4 -0
- sage/geometry/triangulation/element.py +914 -0
- sage/geometry/triangulation/functions.h +10 -0
- sage/geometry/triangulation/functions.pxd +4 -0
- sage/geometry/triangulation/point_configuration.py +2256 -0
- sage/geometry/triangulation/triangulations.h +49 -0
- sage/geometry/triangulation/triangulations.pxd +7 -0
- sage/geometry/voronoi_diagram.py +319 -0
- sage/interfaces/all__sagemath_polyhedra.py +1 -0
- sage/interfaces/polymake.py +2028 -0
- sage/numerical/all.py +13 -0
- sage/numerical/all__sagemath_polyhedra.py +11 -0
- sage/numerical/backends/all.py +1 -0
- sage/numerical/backends/all__sagemath_polyhedra.py +1 -0
- sage/numerical/backends/cvxopt_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxopt_backend.pyx +1006 -0
- sage/numerical/backends/cvxopt_backend_test.py +19 -0
- sage/numerical/backends/cvxopt_sdp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxopt_sdp_backend.pyx +382 -0
- sage/numerical/backends/cvxpy_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/cvxpy_backend.pxd +41 -0
- sage/numerical/backends/cvxpy_backend.pyx +934 -0
- sage/numerical/backends/cvxpy_backend_test.py +13 -0
- sage/numerical/backends/generic_backend_test.py +24 -0
- sage/numerical/backends/interactivelp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/interactivelp_backend.pxd +36 -0
- sage/numerical/backends/interactivelp_backend.pyx +1231 -0
- sage/numerical/backends/interactivelp_backend_test.py +12 -0
- sage/numerical/backends/logging_backend.py +391 -0
- sage/numerical/backends/matrix_sdp_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/matrix_sdp_backend.pxd +15 -0
- sage/numerical/backends/matrix_sdp_backend.pyx +478 -0
- sage/numerical/backends/ppl_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/ppl_backend.pyx +1126 -0
- sage/numerical/backends/ppl_backend_test.py +13 -0
- sage/numerical/backends/scip_backend.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/backends/scip_backend.pxd +22 -0
- sage/numerical/backends/scip_backend.pyx +1289 -0
- sage/numerical/backends/scip_backend_test.py +13 -0
- sage/numerical/interactive_simplex_method.py +5338 -0
- sage/numerical/knapsack.py +665 -0
- sage/numerical/linear_functions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/linear_functions.pxd +31 -0
- sage/numerical/linear_functions.pyx +1648 -0
- sage/numerical/linear_tensor.py +470 -0
- sage/numerical/linear_tensor_constraints.py +448 -0
- sage/numerical/linear_tensor_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/linear_tensor_element.pxd +6 -0
- sage/numerical/linear_tensor_element.pyx +459 -0
- sage/numerical/mip.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/mip.pxd +40 -0
- sage/numerical/mip.pyx +3667 -0
- sage/numerical/sdp.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/sdp.pxd +39 -0
- sage/numerical/sdp.pyx +1433 -0
- sage/rings/all__sagemath_polyhedra.py +3 -0
- sage/rings/polynomial/all__sagemath_polyhedra.py +10 -0
- sage/rings/polynomial/omega.py +982 -0
- sage/schemes/all__sagemath_polyhedra.py +2 -0
- sage/schemes/toric/all.py +10 -0
- sage/schemes/toric/chow_group.py +1248 -0
- sage/schemes/toric/divisor.py +2082 -0
- sage/schemes/toric/divisor_class.cpython-314-x86_64-linux-musl.so +0 -0
- sage/schemes/toric/divisor_class.pyx +322 -0
- sage/schemes/toric/fano_variety.py +1606 -0
- sage/schemes/toric/homset.py +650 -0
- sage/schemes/toric/ideal.py +451 -0
- sage/schemes/toric/library.py +1322 -0
- sage/schemes/toric/morphism.py +1958 -0
- sage/schemes/toric/points.py +1032 -0
- sage/schemes/toric/sheaf/all.py +1 -0
- sage/schemes/toric/sheaf/constructor.py +302 -0
- sage/schemes/toric/sheaf/klyachko.py +921 -0
- sage/schemes/toric/toric_subscheme.py +905 -0
- sage/schemes/toric/variety.py +3460 -0
- sage/schemes/toric/weierstrass.py +1078 -0
- sage/schemes/toric/weierstrass_covering.py +457 -0
- sage/schemes/toric/weierstrass_higher.py +288 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.info +10 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v03 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v05 +1 -0
- sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v06 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.info +22 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v04 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v05 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v06 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v07 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v08 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v09 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v10 +0 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v11 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v12 +1 -0
- sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v13 +1 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_2d +80 -0
- sage_wheels/share/reflexive_polytopes/reflexive_polytopes_3d +37977 -0
|
@@ -0,0 +1,1231 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-polyhedra
|
|
2
|
+
r"""
|
|
3
|
+
InteractiveLP Backend
|
|
4
|
+
|
|
5
|
+
AUTHORS:
|
|
6
|
+
|
|
7
|
+
- Nathann Cohen (2010-10) : generic_backend template
|
|
8
|
+
- Matthias Koeppe (2016-03) : this backend
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# ****************************************************************************
|
|
12
|
+
# Copyright (C) 2010 Nathann Cohen <nathann.cohen@gmail.com>
|
|
13
|
+
# Copyright (C) 2016 Matthias Koeppe <mkoeppe@math.ucdavis.edu>
|
|
14
|
+
#
|
|
15
|
+
# This program is free software: you can redistribute it and/or modify
|
|
16
|
+
# it under the terms of the GNU General Public License as published by
|
|
17
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
18
|
+
# (at your option) any later version.
|
|
19
|
+
# https://www.gnu.org/licenses/
|
|
20
|
+
# ****************************************************************************
|
|
21
|
+
|
|
22
|
+
from sage.numerical.mip import MIPSolverException
|
|
23
|
+
from sage.numerical.interactive_simplex_method import InteractiveLPProblem, default_variable_name
|
|
24
|
+
from sage.modules.free_module_element import vector
|
|
25
|
+
from copy import copy
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
cdef class InteractiveLPBackend:
|
|
29
|
+
"""
|
|
30
|
+
MIP Backend that works with :class:`InteractiveLPProblem`.
|
|
31
|
+
|
|
32
|
+
This backend should be used only for linear programs over general fields,
|
|
33
|
+
or for educational purposes. For fast computations with floating point
|
|
34
|
+
arithmetic, use one of the numerical backends. For exact computations
|
|
35
|
+
with rational numbers, use backend 'PPL'.
|
|
36
|
+
|
|
37
|
+
There is no support for integer variables.
|
|
38
|
+
|
|
39
|
+
EXAMPLES::
|
|
40
|
+
|
|
41
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
42
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __cinit__(self, maximization=True, base_ring=None):
|
|
46
|
+
"""
|
|
47
|
+
Cython constructor.
|
|
48
|
+
|
|
49
|
+
EXAMPLES::
|
|
50
|
+
|
|
51
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
52
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
53
|
+
|
|
54
|
+
This backend can work with irrational algebraic numbers::
|
|
55
|
+
|
|
56
|
+
sage: # needs sage.groups sage.rings.number_field
|
|
57
|
+
sage: poly = polytopes.dodecahedron(base_ring=AA)
|
|
58
|
+
sage: lp, x = poly.to_linear_program(solver='InteractiveLP', return_variable=True)
|
|
59
|
+
sage: lp.set_objective(x[0] + x[1] + x[2])
|
|
60
|
+
sage: lp.solve()
|
|
61
|
+
2.291796067500631?
|
|
62
|
+
sage: lp.get_values(x[0], x[1], x[2])
|
|
63
|
+
[0.763932022500211?, 0.763932022500211?, 0.763932022500211?]
|
|
64
|
+
sage: lp.set_objective(x[0] - x[1] - x[2])
|
|
65
|
+
sage: lp.solve()
|
|
66
|
+
2.291796067500631?
|
|
67
|
+
sage: lp.get_values(x[0], x[1], x[2])
|
|
68
|
+
[0.763932022500211?, -0.763932022500211?, -0.763932022500211?]
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
if base_ring is None:
|
|
72
|
+
from sage.rings.rational_field import QQ
|
|
73
|
+
base_ring = QQ
|
|
74
|
+
|
|
75
|
+
self.lp = InteractiveLPProblem([], [], [], base_ring=base_ring)
|
|
76
|
+
self.set_verbosity(0)
|
|
77
|
+
|
|
78
|
+
if maximization:
|
|
79
|
+
self.set_sense(+1)
|
|
80
|
+
else:
|
|
81
|
+
self.set_sense(-1)
|
|
82
|
+
|
|
83
|
+
self.row_names = []
|
|
84
|
+
|
|
85
|
+
cpdef __copy__(self):
|
|
86
|
+
"""
|
|
87
|
+
Return a copy of ``self``.
|
|
88
|
+
|
|
89
|
+
EXAMPLES::
|
|
90
|
+
|
|
91
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
92
|
+
sage: p = MixedIntegerLinearProgram(solver = "InteractiveLP")
|
|
93
|
+
sage: b = p.new_variable()
|
|
94
|
+
sage: p.add_constraint(b[1] + b[2] <= 6)
|
|
95
|
+
sage: p.set_objective(b[1] + b[2])
|
|
96
|
+
sage: cp = copy(p.get_backend())
|
|
97
|
+
sage: cp.solve()
|
|
98
|
+
0
|
|
99
|
+
sage: cp.get_objective_value()
|
|
100
|
+
6
|
|
101
|
+
"""
|
|
102
|
+
cdef InteractiveLPBackend cp = type(self)(base_ring=self.base_ring())
|
|
103
|
+
cp.lp = self.lp # it's considered immutable; so no need to copy.
|
|
104
|
+
cp.row_names = copy(self.row_names)
|
|
105
|
+
cp.prob_name = self.prob_name
|
|
106
|
+
return cp
|
|
107
|
+
|
|
108
|
+
cpdef base_ring(self):
|
|
109
|
+
"""
|
|
110
|
+
Return the base ring.
|
|
111
|
+
|
|
112
|
+
OUTPUT: a ring; the coefficients that the chosen solver supports
|
|
113
|
+
|
|
114
|
+
EXAMPLES::
|
|
115
|
+
|
|
116
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
117
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
118
|
+
sage: p.base_ring()
|
|
119
|
+
Rational Field
|
|
120
|
+
"""
|
|
121
|
+
return self.lp.base_ring()
|
|
122
|
+
|
|
123
|
+
def _variable_type_from_bounds(self, lower_bound, upper_bound):
|
|
124
|
+
"""
|
|
125
|
+
Return a string designating a variable type in `InteractiveLPProblem`.
|
|
126
|
+
|
|
127
|
+
INPUT:
|
|
128
|
+
|
|
129
|
+
- ``lower_bound`` -- the lower bound of the variable
|
|
130
|
+
|
|
131
|
+
- ``upper_bound`` -- the upper bound of the variable
|
|
132
|
+
|
|
133
|
+
OUTPUT: string, one of ``''``, ``'<='``, ``'>='``
|
|
134
|
+
|
|
135
|
+
The function raises an error if this pair of bounds cannot be
|
|
136
|
+
represented by an `InteractiveLPProblem` variable type.
|
|
137
|
+
|
|
138
|
+
EXAMPLES::
|
|
139
|
+
|
|
140
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
141
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
142
|
+
sage: p._variable_type_from_bounds(0, None)
|
|
143
|
+
'>='
|
|
144
|
+
sage: p._variable_type_from_bounds(None, 0)
|
|
145
|
+
'<='
|
|
146
|
+
sage: p._variable_type_from_bounds(None, None)
|
|
147
|
+
''
|
|
148
|
+
sage: p._variable_type_from_bounds(None, 5)
|
|
149
|
+
Traceback (most recent call last):
|
|
150
|
+
...
|
|
151
|
+
NotImplementedError: General variable bounds not supported
|
|
152
|
+
"""
|
|
153
|
+
if lower_bound is None:
|
|
154
|
+
if upper_bound is None:
|
|
155
|
+
return ""
|
|
156
|
+
elif upper_bound == 0:
|
|
157
|
+
return "<="
|
|
158
|
+
else:
|
|
159
|
+
raise NotImplementedError("General variable bounds not supported")
|
|
160
|
+
elif lower_bound == 0:
|
|
161
|
+
if upper_bound is None:
|
|
162
|
+
return ">="
|
|
163
|
+
else:
|
|
164
|
+
raise NotImplementedError("General variable bounds not supported")
|
|
165
|
+
else:
|
|
166
|
+
raise NotImplementedError("General variable bounds not supported")
|
|
167
|
+
|
|
168
|
+
cpdef int add_variable(self, lower_bound=0, upper_bound=None,
|
|
169
|
+
binary=False, continuous=True, integer=False,
|
|
170
|
+
obj=None, name=None, coefficients=None) except -1:
|
|
171
|
+
## coefficients is an extension in this backend,
|
|
172
|
+
## and a proposed addition to the interface, to unify this with add_col.
|
|
173
|
+
"""
|
|
174
|
+
Add a variable.
|
|
175
|
+
|
|
176
|
+
This amounts to adding a new column to the matrix. By default,
|
|
177
|
+
the variable is both nonnegative and real.
|
|
178
|
+
|
|
179
|
+
In this backend, variables are always continuous (real).
|
|
180
|
+
If integer variables are requested via the parameters
|
|
181
|
+
``binary`` and ``integer``, an error will be raised.
|
|
182
|
+
|
|
183
|
+
INPUT:
|
|
184
|
+
|
|
185
|
+
- ``lower_bound`` -- the lower bound of the variable (default: 0)
|
|
186
|
+
|
|
187
|
+
- ``upper_bound`` -- the upper bound of the variable (default: ``None``)
|
|
188
|
+
|
|
189
|
+
- ``binary`` -- ``True`` if the variable is binary (default: ``False``)
|
|
190
|
+
|
|
191
|
+
- ``continuous`` -- ``True`` if the variable is continuous (default: ``True``)
|
|
192
|
+
|
|
193
|
+
- ``integer`` -- ``True`` if the variable is integral (default: ``False``)
|
|
194
|
+
|
|
195
|
+
- ``obj`` -- (optional) coefficient of this variable in the objective function (default: 0)
|
|
196
|
+
|
|
197
|
+
- ``name`` -- an optional name for the newly added variable (default: ``None``)
|
|
198
|
+
|
|
199
|
+
- ``coefficients`` -- (optional) an iterable of pairs ``(i, v)``. In each
|
|
200
|
+
pair, ``i`` is a variable index (integer) and ``v`` is a
|
|
201
|
+
value (element of :meth:`base_ring`).
|
|
202
|
+
|
|
203
|
+
OUTPUT: the index of the newly created variable
|
|
204
|
+
|
|
205
|
+
EXAMPLES::
|
|
206
|
+
|
|
207
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
208
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
209
|
+
sage: p.ncols()
|
|
210
|
+
0
|
|
211
|
+
sage: p.add_variable()
|
|
212
|
+
0
|
|
213
|
+
sage: p.ncols()
|
|
214
|
+
1
|
|
215
|
+
sage: p.add_variable(continuous=True, integer=True)
|
|
216
|
+
Traceback (most recent call last):
|
|
217
|
+
...
|
|
218
|
+
ValueError: ...
|
|
219
|
+
sage: p.add_variable(name='x',obj=1)
|
|
220
|
+
1
|
|
221
|
+
sage: p.col_name(1)
|
|
222
|
+
'x'
|
|
223
|
+
sage: p.objective_coefficient(1)
|
|
224
|
+
1
|
|
225
|
+
"""
|
|
226
|
+
A, b, c, x, constraint_types, variable_types, problem_type, ring, d = self._AbcxCVPRd()
|
|
227
|
+
cdef int vtype = int(binary) + int(continuous) + int(integer)
|
|
228
|
+
if vtype == 0:
|
|
229
|
+
continuous = True
|
|
230
|
+
elif vtype != 1:
|
|
231
|
+
raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.")
|
|
232
|
+
if not continuous:
|
|
233
|
+
raise NotImplementedError("Integer variables are not supported")
|
|
234
|
+
variable_types = variable_types + (self._variable_type_from_bounds(lower_bound, upper_bound),)
|
|
235
|
+
col = vector(ring, self.nrows())
|
|
236
|
+
if coefficients is not None:
|
|
237
|
+
for (i, v) in coefficients:
|
|
238
|
+
col[i] = v
|
|
239
|
+
A = A.augment(col)
|
|
240
|
+
if obj is None:
|
|
241
|
+
obj = 0
|
|
242
|
+
c = tuple(c) + (obj,)
|
|
243
|
+
if name is None:
|
|
244
|
+
var_names = default_variable_name("primal decision")
|
|
245
|
+
name = "{}{:d}".format(var_names, self.ncols() + 1)
|
|
246
|
+
x = tuple(x) + (name,)
|
|
247
|
+
self.lp = InteractiveLPProblem(A, b, c, x,
|
|
248
|
+
constraint_types, variable_types,
|
|
249
|
+
problem_type, ring, objective_constant_term=d)
|
|
250
|
+
return self.ncols() - 1
|
|
251
|
+
|
|
252
|
+
cpdef set_variable_type(self, int variable, int vtype):
|
|
253
|
+
"""
|
|
254
|
+
Set the type of a variable.
|
|
255
|
+
|
|
256
|
+
In this backend, variables are always continuous (real).
|
|
257
|
+
If integer or binary variables are requested via the parameter
|
|
258
|
+
``vtype``, an error will be raised.
|
|
259
|
+
|
|
260
|
+
INPUT:
|
|
261
|
+
|
|
262
|
+
- ``variable`` -- integer; the variable's id
|
|
263
|
+
|
|
264
|
+
- ``vtype`` -- integer:
|
|
265
|
+
|
|
266
|
+
* 1 Integer
|
|
267
|
+
* 0 Binary
|
|
268
|
+
* -1 Continuous
|
|
269
|
+
|
|
270
|
+
EXAMPLES::
|
|
271
|
+
|
|
272
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
273
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
274
|
+
sage: p.ncols()
|
|
275
|
+
0
|
|
276
|
+
sage: p.add_variable()
|
|
277
|
+
0
|
|
278
|
+
sage: p.set_variable_type(0,-1)
|
|
279
|
+
sage: p.is_variable_continuous(0)
|
|
280
|
+
True
|
|
281
|
+
"""
|
|
282
|
+
if vtype == -1:
|
|
283
|
+
pass
|
|
284
|
+
else:
|
|
285
|
+
raise NotImplementedError()
|
|
286
|
+
|
|
287
|
+
def _AbcxCVPRd(self):
|
|
288
|
+
"""
|
|
289
|
+
Retrieve all problem data from the LP.
|
|
290
|
+
|
|
291
|
+
EXAMPLES::
|
|
292
|
+
|
|
293
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
294
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
295
|
+
sage: p._AbcxCVPRd()
|
|
296
|
+
([], (), (), (), (), (), 'max', Rational Field, 0)
|
|
297
|
+
"""
|
|
298
|
+
A, b, c, x = self.lp.Abcx()
|
|
299
|
+
constraint_types = self.lp.constraint_types()
|
|
300
|
+
variable_types = self.lp.variable_types()
|
|
301
|
+
problem_type = self.lp.problem_type()
|
|
302
|
+
base_ring = self.lp.base_ring()
|
|
303
|
+
d = self.lp.objective_constant_term()
|
|
304
|
+
return A, b, c, x, constraint_types, variable_types, problem_type, base_ring, d
|
|
305
|
+
|
|
306
|
+
cpdef set_sense(self, int sense):
|
|
307
|
+
"""
|
|
308
|
+
Set the direction (maximization/minimization).
|
|
309
|
+
|
|
310
|
+
INPUT:
|
|
311
|
+
|
|
312
|
+
- ``sense`` -- integer:
|
|
313
|
+
|
|
314
|
+
* +1 => Maximization
|
|
315
|
+
* -1 => Minimization
|
|
316
|
+
|
|
317
|
+
EXAMPLES::
|
|
318
|
+
|
|
319
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
320
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
321
|
+
sage: p.is_maximization()
|
|
322
|
+
True
|
|
323
|
+
sage: p.set_sense(-1)
|
|
324
|
+
sage: p.is_maximization()
|
|
325
|
+
False
|
|
326
|
+
"""
|
|
327
|
+
A, b, c, x, constraint_types, variable_types, problem_type, ring, d = self._AbcxCVPRd()
|
|
328
|
+
if sense == +1:
|
|
329
|
+
problem_type = "max"
|
|
330
|
+
else:
|
|
331
|
+
problem_type = "min"
|
|
332
|
+
self.lp = InteractiveLPProblem(A, b, c, x,
|
|
333
|
+
constraint_types, variable_types,
|
|
334
|
+
problem_type, ring, objective_constant_term=d)
|
|
335
|
+
|
|
336
|
+
cpdef objective_coefficient(self, int variable, coeff=None):
|
|
337
|
+
"""
|
|
338
|
+
Set or get the coefficient of a variable in the objective
|
|
339
|
+
function
|
|
340
|
+
|
|
341
|
+
INPUT:
|
|
342
|
+
|
|
343
|
+
- ``variable`` -- integer; the variable's id
|
|
344
|
+
|
|
345
|
+
- ``coeff`` -- double; its coefficient
|
|
346
|
+
|
|
347
|
+
EXAMPLES::
|
|
348
|
+
|
|
349
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
350
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
351
|
+
sage: p.add_variable()
|
|
352
|
+
0
|
|
353
|
+
sage: p.objective_coefficient(0)
|
|
354
|
+
0
|
|
355
|
+
sage: p.objective_coefficient(0,2)
|
|
356
|
+
sage: p.objective_coefficient(0)
|
|
357
|
+
2
|
|
358
|
+
"""
|
|
359
|
+
if coeff is None:
|
|
360
|
+
return self.lp.objective_coefficients()[variable]
|
|
361
|
+
else:
|
|
362
|
+
A, b, c, x, constraint_types, variable_types, problem_type, ring, d = self._AbcxCVPRd()
|
|
363
|
+
c = list(c)
|
|
364
|
+
c[variable] = coeff
|
|
365
|
+
self.lp = InteractiveLPProblem(A, b, c, x,
|
|
366
|
+
constraint_types, variable_types,
|
|
367
|
+
problem_type, ring, objective_constant_term=d)
|
|
368
|
+
|
|
369
|
+
cpdef objective_constant_term(self, d=None):
|
|
370
|
+
"""
|
|
371
|
+
Set or get the constant term in the objective function.
|
|
372
|
+
|
|
373
|
+
INPUT:
|
|
374
|
+
|
|
375
|
+
- ``d`` -- double; its coefficient. If ``None`` (default), return the
|
|
376
|
+
current value.
|
|
377
|
+
|
|
378
|
+
EXAMPLES::
|
|
379
|
+
|
|
380
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
381
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
382
|
+
sage: p.objective_constant_term()
|
|
383
|
+
0
|
|
384
|
+
sage: p.objective_constant_term(42)
|
|
385
|
+
sage: p.objective_constant_term()
|
|
386
|
+
42
|
|
387
|
+
"""
|
|
388
|
+
if d is None:
|
|
389
|
+
return self.lp.objective_constant_term()
|
|
390
|
+
else:
|
|
391
|
+
A, b, c, x, constraint_types, variable_types, problem_type, ring, _ = self._AbcxCVPRd()
|
|
392
|
+
self.lp = InteractiveLPProblem(A, b, c, x,
|
|
393
|
+
constraint_types, variable_types,
|
|
394
|
+
problem_type, ring, objective_constant_term=d)
|
|
395
|
+
|
|
396
|
+
cpdef set_objective(self, list coeff, d=0):
|
|
397
|
+
"""
|
|
398
|
+
Set the objective function.
|
|
399
|
+
|
|
400
|
+
INPUT:
|
|
401
|
+
|
|
402
|
+
- ``coeff`` -- list of real values, whose i-th element is the
|
|
403
|
+
coefficient of the i-th variable in the objective function
|
|
404
|
+
|
|
405
|
+
- ``d`` -- real; the constant term in the linear function (set to `0`
|
|
406
|
+
by default)
|
|
407
|
+
|
|
408
|
+
EXAMPLES::
|
|
409
|
+
|
|
410
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
411
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
412
|
+
sage: p.add_variables(5)
|
|
413
|
+
4
|
|
414
|
+
sage: p.set_objective([1, 1, 2, 1, 3])
|
|
415
|
+
sage: [p.objective_coefficient(x) for x in range(5)]
|
|
416
|
+
[1, 1, 2, 1, 3]
|
|
417
|
+
|
|
418
|
+
Constants in the objective function are respected::
|
|
419
|
+
|
|
420
|
+
sage: p = MixedIntegerLinearProgram(solver='InteractiveLP')
|
|
421
|
+
sage: x,y = p[0], p[1]
|
|
422
|
+
sage: p.add_constraint(2*x + 3*y, max = 6)
|
|
423
|
+
sage: p.add_constraint(3*x + 2*y, max = 6)
|
|
424
|
+
sage: p.set_objective(x + y + 7)
|
|
425
|
+
sage: p.solve()
|
|
426
|
+
47/5
|
|
427
|
+
|
|
428
|
+
TESTS:
|
|
429
|
+
|
|
430
|
+
Constants also work the right way for min::
|
|
431
|
+
|
|
432
|
+
sage: p = MixedIntegerLinearProgram(solver='InteractiveLP', maximization=False)
|
|
433
|
+
sage: x,y = p[0], p[1]
|
|
434
|
+
sage: p.add_constraint(2*x + 3*y, max = 6)
|
|
435
|
+
sage: p.add_constraint(3*x + 2*y, max = 6)
|
|
436
|
+
sage: p.set_objective(-x - y - 7)
|
|
437
|
+
sage: p.solve()
|
|
438
|
+
-47/5
|
|
439
|
+
"""
|
|
440
|
+
A, b, _, x, constraint_types, variable_types, problem_type, ring, _ = self._AbcxCVPRd()
|
|
441
|
+
c = coeff
|
|
442
|
+
self.lp = InteractiveLPProblem(A, b, c, x,
|
|
443
|
+
constraint_types, variable_types,
|
|
444
|
+
problem_type, ring, objective_constant_term=d)
|
|
445
|
+
|
|
446
|
+
cpdef set_verbosity(self, int level):
|
|
447
|
+
"""
|
|
448
|
+
Set the log (verbosity) level.
|
|
449
|
+
|
|
450
|
+
INPUT:
|
|
451
|
+
|
|
452
|
+
- ``level`` -- integer; from 0 (no verbosity) to 3
|
|
453
|
+
|
|
454
|
+
EXAMPLES::
|
|
455
|
+
|
|
456
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
457
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
458
|
+
sage: p.set_verbosity(2)
|
|
459
|
+
"""
|
|
460
|
+
self.verbosity = level
|
|
461
|
+
|
|
462
|
+
cpdef remove_constraint(self, int i):
|
|
463
|
+
r"""
|
|
464
|
+
Remove a constraint.
|
|
465
|
+
|
|
466
|
+
INPUT:
|
|
467
|
+
|
|
468
|
+
- ``i`` -- index of the constraint to remove
|
|
469
|
+
|
|
470
|
+
EXAMPLES::
|
|
471
|
+
|
|
472
|
+
sage: p = MixedIntegerLinearProgram(solver='InteractiveLP')
|
|
473
|
+
sage: v = p.new_variable(nonnegative=True)
|
|
474
|
+
sage: x,y = v[0], v[1]
|
|
475
|
+
sage: p.add_constraint(2*x + 3*y, max = 6)
|
|
476
|
+
sage: p.add_constraint(3*x + 2*y, max = 6)
|
|
477
|
+
sage: p.set_objective(x + y + 7)
|
|
478
|
+
sage: p.solve()
|
|
479
|
+
47/5
|
|
480
|
+
sage: p.remove_constraint(0)
|
|
481
|
+
sage: p.solve()
|
|
482
|
+
10
|
|
483
|
+
sage: p.get_values([x,y])
|
|
484
|
+
[0, 3]
|
|
485
|
+
"""
|
|
486
|
+
A, b, c, x, constraint_types, variable_types, problem_type, ring, d = self._AbcxCVPRd()
|
|
487
|
+
A = A.delete_rows((i,))
|
|
488
|
+
b = list(b)
|
|
489
|
+
del b[i]
|
|
490
|
+
constraint_types = list(constraint_types)
|
|
491
|
+
del constraint_types[i]
|
|
492
|
+
self.lp = InteractiveLPProblem(A, b, c, x,
|
|
493
|
+
constraint_types, variable_types,
|
|
494
|
+
problem_type, ring, objective_constant_term=d)
|
|
495
|
+
|
|
496
|
+
cpdef add_linear_constraint(self, coefficients, lower_bound, upper_bound, name=None):
|
|
497
|
+
"""
|
|
498
|
+
Add a linear constraint.
|
|
499
|
+
|
|
500
|
+
INPUT:
|
|
501
|
+
|
|
502
|
+
- ``coefficients`` -- an iterable of pairs ``(i, v)``. In each
|
|
503
|
+
pair, ``i`` is a variable index (integer) and ``v`` is a
|
|
504
|
+
value (element of :meth:`base_ring`).
|
|
505
|
+
|
|
506
|
+
- ``lower_bound`` -- element of :meth:`base_ring` or
|
|
507
|
+
``None``; the lower bound
|
|
508
|
+
|
|
509
|
+
- ``upper_bound`` -- element of :meth:`base_ring` or
|
|
510
|
+
``None``; the upper bound
|
|
511
|
+
|
|
512
|
+
- ``name`` -- string or ``None``; optional name for this row
|
|
513
|
+
|
|
514
|
+
EXAMPLES::
|
|
515
|
+
|
|
516
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
517
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
518
|
+
sage: p.add_variables(5)
|
|
519
|
+
4
|
|
520
|
+
sage: p.add_linear_constraint( zip(range(5), range(5)), 2, 2)
|
|
521
|
+
sage: p.row(0)
|
|
522
|
+
([1, 2, 3, 4], [1, 2, 3, 4])
|
|
523
|
+
sage: p.row_bounds(0)
|
|
524
|
+
(2, 2)
|
|
525
|
+
sage: p.add_linear_constraint( zip(range(5), range(5)), 1, 1, name='foo')
|
|
526
|
+
sage: p.row_name(1)
|
|
527
|
+
'foo'
|
|
528
|
+
"""
|
|
529
|
+
A, b, c, x, constraint_types, variable_types, problem_type, ring, d = self._AbcxCVPRd()
|
|
530
|
+
if lower_bound is None:
|
|
531
|
+
if upper_bound is None:
|
|
532
|
+
raise ValueError("At least one of lower_bound and upper_bound must be provided")
|
|
533
|
+
else:
|
|
534
|
+
constraint_types = constraint_types + ("<=",)
|
|
535
|
+
b = tuple(b) + (upper_bound,)
|
|
536
|
+
else:
|
|
537
|
+
if upper_bound is None:
|
|
538
|
+
constraint_types = constraint_types + (">=",)
|
|
539
|
+
b = tuple(b) + (lower_bound,)
|
|
540
|
+
elif lower_bound == upper_bound:
|
|
541
|
+
constraint_types = constraint_types + ("==",)
|
|
542
|
+
b = tuple(b) + (lower_bound,)
|
|
543
|
+
else:
|
|
544
|
+
raise NotImplementedError("Ranged constraints are not supported")
|
|
545
|
+
|
|
546
|
+
row = vector(ring, self.ncols())
|
|
547
|
+
for (i, v) in coefficients:
|
|
548
|
+
row[i] = v
|
|
549
|
+
A = A.stack(row)
|
|
550
|
+
|
|
551
|
+
self.row_names.append(name)
|
|
552
|
+
|
|
553
|
+
self.lp = InteractiveLPProblem(A, b, c, x,
|
|
554
|
+
constraint_types, variable_types,
|
|
555
|
+
problem_type, ring, objective_constant_term=d)
|
|
556
|
+
|
|
557
|
+
cpdef add_col(self, indices, coeffs):
|
|
558
|
+
"""
|
|
559
|
+
Add a column.
|
|
560
|
+
|
|
561
|
+
INPUT:
|
|
562
|
+
|
|
563
|
+
- ``indices`` -- list of integers; this list contains the
|
|
564
|
+
indices of the constraints in which the variable's
|
|
565
|
+
coefficient is nonzero
|
|
566
|
+
|
|
567
|
+
- ``coeffs`` -- list of real values; associates a coefficient
|
|
568
|
+
to the variable in each of the constraints in which it
|
|
569
|
+
appears. Namely, the i-th entry of ``coeffs`` corresponds to
|
|
570
|
+
the coefficient of the variable in the constraint
|
|
571
|
+
represented by the i-th entry in ``indices``.
|
|
572
|
+
|
|
573
|
+
.. NOTE::
|
|
574
|
+
|
|
575
|
+
``indices`` and ``coeffs`` are expected to be of the same length.
|
|
576
|
+
|
|
577
|
+
EXAMPLES::
|
|
578
|
+
|
|
579
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
580
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
581
|
+
sage: p.ncols()
|
|
582
|
+
0
|
|
583
|
+
sage: p.nrows()
|
|
584
|
+
0
|
|
585
|
+
sage: p.add_linear_constraints(5, 0, None)
|
|
586
|
+
sage: p.add_col(list(range(5)), list(range(5)))
|
|
587
|
+
sage: p.nrows()
|
|
588
|
+
5
|
|
589
|
+
"""
|
|
590
|
+
self.add_variable(coefficients=zip(indices, coeffs))
|
|
591
|
+
|
|
592
|
+
cpdef int solve(self) except -1:
|
|
593
|
+
"""
|
|
594
|
+
Solve the problem.
|
|
595
|
+
|
|
596
|
+
.. NOTE::
|
|
597
|
+
|
|
598
|
+
This method raises ``MIPSolverException`` exceptions when
|
|
599
|
+
the solution cannot be computed for any reason (none
|
|
600
|
+
exists, or the LP solver was not able to find it, etc...)
|
|
601
|
+
|
|
602
|
+
EXAMPLES::
|
|
603
|
+
|
|
604
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
605
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
606
|
+
sage: p.add_linear_constraints(5, 0, None)
|
|
607
|
+
sage: p.add_col(list(range(5)), list(range(5)))
|
|
608
|
+
sage: p.solve()
|
|
609
|
+
0
|
|
610
|
+
sage: p.objective_coefficient(0,1)
|
|
611
|
+
sage: p.solve()
|
|
612
|
+
Traceback (most recent call last):
|
|
613
|
+
...
|
|
614
|
+
MIPSolverException: ...
|
|
615
|
+
"""
|
|
616
|
+
## FIXME: standard_form should allow to pass slack names (which we would take from row_names).
|
|
617
|
+
## FIXME: Perhaps also pass the problem name as objective name
|
|
618
|
+
lp_std_form, transformation = self.lp.standard_form(transformation=True)
|
|
619
|
+
self.lp_std_form, self.std_form_transformation = lp_std_form, transformation
|
|
620
|
+
output = lp_std_form.run_revised_simplex_method()
|
|
621
|
+
## FIXME: Display output as a side effect if verbosity is high enough
|
|
622
|
+
d = self.final_dictionary = lp_std_form.final_revised_dictionary()
|
|
623
|
+
if d.is_optimal():
|
|
624
|
+
if lp_std_form.auxiliary_variable() in d.basic_variables():
|
|
625
|
+
raise MIPSolverException("InteractiveLP: Problem has no feasible solution")
|
|
626
|
+
else:
|
|
627
|
+
return 0
|
|
628
|
+
else:
|
|
629
|
+
raise MIPSolverException("InteractiveLP: Problem is unbounded")
|
|
630
|
+
|
|
631
|
+
cpdef get_objective_value(self):
|
|
632
|
+
"""
|
|
633
|
+
Return the value of the objective function.
|
|
634
|
+
|
|
635
|
+
.. NOTE::
|
|
636
|
+
|
|
637
|
+
Behavior is undefined unless ``solve`` has been called before.
|
|
638
|
+
|
|
639
|
+
EXAMPLES::
|
|
640
|
+
|
|
641
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
642
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
643
|
+
sage: p.add_variables(2)
|
|
644
|
+
1
|
|
645
|
+
sage: p.add_linear_constraint([(0,1), (1,2)], None, 3)
|
|
646
|
+
sage: p.set_objective([2, 5])
|
|
647
|
+
sage: p.solve()
|
|
648
|
+
0
|
|
649
|
+
sage: p.get_objective_value()
|
|
650
|
+
15/2
|
|
651
|
+
sage: p.get_variable_value(0)
|
|
652
|
+
0
|
|
653
|
+
sage: p.get_variable_value(1)
|
|
654
|
+
3/2
|
|
655
|
+
"""
|
|
656
|
+
d = self.final_dictionary
|
|
657
|
+
v = d.objective_value()
|
|
658
|
+
if self.lp_std_form.is_negative():
|
|
659
|
+
v = - v
|
|
660
|
+
return v
|
|
661
|
+
|
|
662
|
+
cpdef get_variable_value(self, int variable):
|
|
663
|
+
"""
|
|
664
|
+
Return the value of a variable given by the solver.
|
|
665
|
+
|
|
666
|
+
.. NOTE::
|
|
667
|
+
|
|
668
|
+
Behavior is undefined unless ``solve`` has been called before.
|
|
669
|
+
|
|
670
|
+
EXAMPLES::
|
|
671
|
+
|
|
672
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
673
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
674
|
+
sage: p.add_variables(2)
|
|
675
|
+
1
|
|
676
|
+
sage: p.add_linear_constraint([(0,1), (1, 2)], None, 3)
|
|
677
|
+
sage: p.set_objective([2, 5])
|
|
678
|
+
sage: p.solve()
|
|
679
|
+
0
|
|
680
|
+
sage: p.get_objective_value()
|
|
681
|
+
15/2
|
|
682
|
+
sage: p.get_variable_value(0)
|
|
683
|
+
0
|
|
684
|
+
sage: p.get_variable_value(1)
|
|
685
|
+
3/2
|
|
686
|
+
"""
|
|
687
|
+
solution = self.std_form_transformation(self.final_dictionary.basic_solution())
|
|
688
|
+
return solution[variable]
|
|
689
|
+
|
|
690
|
+
cpdef int ncols(self) noexcept:
|
|
691
|
+
"""
|
|
692
|
+
Return the number of columns/variables.
|
|
693
|
+
|
|
694
|
+
EXAMPLES::
|
|
695
|
+
|
|
696
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
697
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
698
|
+
sage: p.ncols()
|
|
699
|
+
0
|
|
700
|
+
sage: p.add_variables(2)
|
|
701
|
+
1
|
|
702
|
+
sage: p.ncols()
|
|
703
|
+
2
|
|
704
|
+
"""
|
|
705
|
+
return self.lp.n_variables()
|
|
706
|
+
|
|
707
|
+
cpdef int nrows(self) noexcept:
|
|
708
|
+
"""
|
|
709
|
+
Return the number of rows/constraints.
|
|
710
|
+
|
|
711
|
+
EXAMPLES::
|
|
712
|
+
|
|
713
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
714
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
715
|
+
sage: p.nrows()
|
|
716
|
+
0
|
|
717
|
+
sage: p.add_linear_constraints(2, 0, None)
|
|
718
|
+
sage: p.nrows()
|
|
719
|
+
2
|
|
720
|
+
"""
|
|
721
|
+
return self.lp.n_constraints()
|
|
722
|
+
|
|
723
|
+
cpdef bint is_maximization(self) noexcept:
|
|
724
|
+
"""
|
|
725
|
+
Test whether the problem is a maximization
|
|
726
|
+
|
|
727
|
+
EXAMPLES::
|
|
728
|
+
|
|
729
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
730
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
731
|
+
sage: p.is_maximization()
|
|
732
|
+
True
|
|
733
|
+
sage: p.set_sense(-1)
|
|
734
|
+
sage: p.is_maximization()
|
|
735
|
+
False
|
|
736
|
+
"""
|
|
737
|
+
return self.lp.problem_type() == "max"
|
|
738
|
+
|
|
739
|
+
cpdef problem_name(self, name=None):
|
|
740
|
+
"""
|
|
741
|
+
Return or define the problem's name.
|
|
742
|
+
|
|
743
|
+
INPUT:
|
|
744
|
+
|
|
745
|
+
- ``name`` -- string; the problem's name. When set to
|
|
746
|
+
``None`` (default), the method returns the problem's name.
|
|
747
|
+
|
|
748
|
+
EXAMPLES::
|
|
749
|
+
|
|
750
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
751
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
752
|
+
sage: p.problem_name("There_once_was_a_french_fry")
|
|
753
|
+
sage: print(p.problem_name())
|
|
754
|
+
There_once_was_a_french_fry
|
|
755
|
+
"""
|
|
756
|
+
if name is None:
|
|
757
|
+
if self.prob_name is not None:
|
|
758
|
+
return self.prob_name
|
|
759
|
+
else:
|
|
760
|
+
return ""
|
|
761
|
+
else:
|
|
762
|
+
self.prob_name = str(name)
|
|
763
|
+
|
|
764
|
+
cpdef row(self, int i):
|
|
765
|
+
"""
|
|
766
|
+
Return a row.
|
|
767
|
+
|
|
768
|
+
INPUT:
|
|
769
|
+
|
|
770
|
+
- ``index`` -- integer; the constraint's id
|
|
771
|
+
|
|
772
|
+
OUTPUT:
|
|
773
|
+
|
|
774
|
+
A pair ``(indices, coeffs)`` where ``indices`` lists the
|
|
775
|
+
entries whose coefficient is nonzero, and to which ``coeffs``
|
|
776
|
+
associates their coefficient on the model of the
|
|
777
|
+
``add_linear_constraint`` method.
|
|
778
|
+
|
|
779
|
+
EXAMPLES::
|
|
780
|
+
|
|
781
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
782
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
783
|
+
sage: p.add_variables(5)
|
|
784
|
+
4
|
|
785
|
+
sage: p.add_linear_constraint(zip(range(5), range(5)), 0, None)
|
|
786
|
+
sage: p.row(0)
|
|
787
|
+
([1, 2, 3, 4], [1, 2, 3, 4])
|
|
788
|
+
"""
|
|
789
|
+
A, b, c, x = self.lp.Abcx()
|
|
790
|
+
indices = []
|
|
791
|
+
coeffs = []
|
|
792
|
+
for j in range(self.ncols()):
|
|
793
|
+
if A[i][j] != 0:
|
|
794
|
+
indices.append(j)
|
|
795
|
+
coeffs.append(A[i][j])
|
|
796
|
+
return (indices, coeffs)
|
|
797
|
+
|
|
798
|
+
cpdef row_bounds(self, int index):
|
|
799
|
+
"""
|
|
800
|
+
Return the bounds of a specific constraint.
|
|
801
|
+
|
|
802
|
+
INPUT:
|
|
803
|
+
|
|
804
|
+
- ``index`` -- integer; the constraint's id
|
|
805
|
+
|
|
806
|
+
OUTPUT:
|
|
807
|
+
|
|
808
|
+
A pair ``(lower_bound, upper_bound)``. Each of them can be set
|
|
809
|
+
to ``None`` if the constraint is not bounded in the
|
|
810
|
+
corresponding direction, and is a real value otherwise.
|
|
811
|
+
|
|
812
|
+
EXAMPLES::
|
|
813
|
+
|
|
814
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
815
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
816
|
+
sage: p.add_variables(5)
|
|
817
|
+
4
|
|
818
|
+
sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2)
|
|
819
|
+
sage: p.row_bounds(0)
|
|
820
|
+
(2, 2)
|
|
821
|
+
"""
|
|
822
|
+
A, b, c, x = self.lp.Abcx()
|
|
823
|
+
constraint_types = self.lp.constraint_types()
|
|
824
|
+
if constraint_types[index] == '>=':
|
|
825
|
+
return (b[index], None)
|
|
826
|
+
elif constraint_types[index] == '<=':
|
|
827
|
+
return (None, b[index])
|
|
828
|
+
elif constraint_types[index] == '==':
|
|
829
|
+
return (b[index], b[index])
|
|
830
|
+
else:
|
|
831
|
+
raise ValueError("Bad constraint_type")
|
|
832
|
+
|
|
833
|
+
cpdef col_bounds(self, int index):
|
|
834
|
+
"""
|
|
835
|
+
Return the bounds of a specific variable.
|
|
836
|
+
|
|
837
|
+
INPUT:
|
|
838
|
+
|
|
839
|
+
- ``index`` -- integer; the variable's id
|
|
840
|
+
|
|
841
|
+
OUTPUT:
|
|
842
|
+
|
|
843
|
+
A pair ``(lower_bound, upper_bound)``. Each of them can be set
|
|
844
|
+
to ``None`` if the variable is not bounded in the
|
|
845
|
+
corresponding direction, and is a real value otherwise.
|
|
846
|
+
|
|
847
|
+
EXAMPLES::
|
|
848
|
+
|
|
849
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
850
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
851
|
+
sage: p.add_variable(lower_bound=None)
|
|
852
|
+
0
|
|
853
|
+
sage: p.col_bounds(0)
|
|
854
|
+
(None, None)
|
|
855
|
+
sage: p.variable_lower_bound(0, 0)
|
|
856
|
+
sage: p.col_bounds(0)
|
|
857
|
+
(0, None)
|
|
858
|
+
"""
|
|
859
|
+
t = self.lp.variable_types()[index]
|
|
860
|
+
if t == ">=":
|
|
861
|
+
return (0, None)
|
|
862
|
+
elif t == "<=":
|
|
863
|
+
return (None, 0)
|
|
864
|
+
elif t == "":
|
|
865
|
+
return (None, None)
|
|
866
|
+
else:
|
|
867
|
+
raise ValueError("Bad _variable_types")
|
|
868
|
+
|
|
869
|
+
cpdef bint is_variable_binary(self, int index) noexcept:
|
|
870
|
+
"""
|
|
871
|
+
Test whether the given variable is of binary type.
|
|
872
|
+
|
|
873
|
+
INPUT:
|
|
874
|
+
|
|
875
|
+
- ``index`` -- integer; the variable's id
|
|
876
|
+
|
|
877
|
+
EXAMPLES::
|
|
878
|
+
|
|
879
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
880
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
881
|
+
sage: p.ncols()
|
|
882
|
+
0
|
|
883
|
+
sage: p.add_variable()
|
|
884
|
+
0
|
|
885
|
+
sage: p.is_variable_binary(0)
|
|
886
|
+
False
|
|
887
|
+
"""
|
|
888
|
+
return False
|
|
889
|
+
|
|
890
|
+
cpdef bint is_variable_integer(self, int index) noexcept:
|
|
891
|
+
"""
|
|
892
|
+
Test whether the given variable is of integer type.
|
|
893
|
+
|
|
894
|
+
INPUT:
|
|
895
|
+
|
|
896
|
+
- ``index`` -- integer; the variable's id
|
|
897
|
+
|
|
898
|
+
EXAMPLES::
|
|
899
|
+
|
|
900
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
901
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
902
|
+
sage: p.ncols()
|
|
903
|
+
0
|
|
904
|
+
sage: p.add_variable()
|
|
905
|
+
0
|
|
906
|
+
sage: p.is_variable_integer(0)
|
|
907
|
+
False
|
|
908
|
+
"""
|
|
909
|
+
return False
|
|
910
|
+
|
|
911
|
+
cpdef bint is_variable_continuous(self, int index) noexcept:
|
|
912
|
+
"""
|
|
913
|
+
Test whether the given variable is of continuous/real type.
|
|
914
|
+
|
|
915
|
+
INPUT:
|
|
916
|
+
|
|
917
|
+
- ``index`` -- integer; the variable's id
|
|
918
|
+
|
|
919
|
+
EXAMPLES::
|
|
920
|
+
|
|
921
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
922
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
923
|
+
sage: p.ncols()
|
|
924
|
+
0
|
|
925
|
+
sage: p.add_variable()
|
|
926
|
+
0
|
|
927
|
+
sage: p.is_variable_continuous(0)
|
|
928
|
+
True
|
|
929
|
+
"""
|
|
930
|
+
return True
|
|
931
|
+
|
|
932
|
+
cpdef row_name(self, int index):
|
|
933
|
+
"""
|
|
934
|
+
Return the ``index``-th row name.
|
|
935
|
+
|
|
936
|
+
INPUT:
|
|
937
|
+
|
|
938
|
+
- ``index`` -- integer; the row's id
|
|
939
|
+
|
|
940
|
+
EXAMPLES::
|
|
941
|
+
|
|
942
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
943
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
944
|
+
sage: p.add_linear_constraints(1, 2, None, names=['Empty constraint 1'])
|
|
945
|
+
sage: p.row_name(0)
|
|
946
|
+
'Empty constraint 1'
|
|
947
|
+
"""
|
|
948
|
+
return self.row_names[index]
|
|
949
|
+
|
|
950
|
+
cpdef col_name(self, int index):
|
|
951
|
+
"""
|
|
952
|
+
Return the ``index``-th column name.
|
|
953
|
+
|
|
954
|
+
INPUT:
|
|
955
|
+
|
|
956
|
+
- ``index`` -- integer; the column id
|
|
957
|
+
|
|
958
|
+
- ``name`` -- (``char *``) its name; when set to ``NULL``
|
|
959
|
+
(default), the method returns the current name
|
|
960
|
+
|
|
961
|
+
EXAMPLES::
|
|
962
|
+
|
|
963
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
964
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
965
|
+
sage: p.add_variable(name='I_am_a_variable')
|
|
966
|
+
0
|
|
967
|
+
sage: p.col_name(0)
|
|
968
|
+
'I_am_a_variable'
|
|
969
|
+
"""
|
|
970
|
+
return str(self.lp.decision_variables()[index])
|
|
971
|
+
|
|
972
|
+
cpdef variable_upper_bound(self, int index, value=False):
|
|
973
|
+
"""
|
|
974
|
+
Return or define the upper bound on a variable.
|
|
975
|
+
|
|
976
|
+
INPUT:
|
|
977
|
+
|
|
978
|
+
- ``index`` -- integer; the variable's id
|
|
979
|
+
|
|
980
|
+
- ``value`` -- real value, or ``None`` to mean that the
|
|
981
|
+
variable has not upper bound. When set to ``False``
|
|
982
|
+
(default), the method returns the current value.
|
|
983
|
+
|
|
984
|
+
EXAMPLES::
|
|
985
|
+
|
|
986
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
987
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
988
|
+
sage: p.add_variable(lower_bound=None)
|
|
989
|
+
0
|
|
990
|
+
sage: p.col_bounds(0)
|
|
991
|
+
(None, None)
|
|
992
|
+
sage: p.variable_upper_bound(0) is None
|
|
993
|
+
True
|
|
994
|
+
sage: p.variable_upper_bound(0, 0)
|
|
995
|
+
sage: p.col_bounds(0)
|
|
996
|
+
(None, 0)
|
|
997
|
+
sage: p.variable_upper_bound(0)
|
|
998
|
+
0
|
|
999
|
+
sage: p.variable_upper_bound(0, None)
|
|
1000
|
+
sage: p.variable_upper_bound(0) is None
|
|
1001
|
+
True
|
|
1002
|
+
"""
|
|
1003
|
+
bounds = self.col_bounds(index)
|
|
1004
|
+
if value is False:
|
|
1005
|
+
return bounds[1]
|
|
1006
|
+
else:
|
|
1007
|
+
if value != bounds[1]:
|
|
1008
|
+
bounds = (bounds[0], value)
|
|
1009
|
+
A, b, c, x, constraint_types, variable_types, problem_type, ring, d = self._AbcxCVPRd()
|
|
1010
|
+
variable_types = list(variable_types)
|
|
1011
|
+
variable_types[index] = self._variable_type_from_bounds(*bounds)
|
|
1012
|
+
self.lp = InteractiveLPProblem(A, b, c, x,
|
|
1013
|
+
constraint_types, variable_types,
|
|
1014
|
+
problem_type, ring, objective_constant_term=d)
|
|
1015
|
+
|
|
1016
|
+
cpdef variable_lower_bound(self, int index, value=False):
|
|
1017
|
+
"""
|
|
1018
|
+
Return or define the lower bound on a variable.
|
|
1019
|
+
|
|
1020
|
+
INPUT:
|
|
1021
|
+
|
|
1022
|
+
- ``index`` -- integer; the variable's id
|
|
1023
|
+
|
|
1024
|
+
- ``value`` -- real value, or ``None`` to mean that the
|
|
1025
|
+
variable has no lower bound. When set to ``False``
|
|
1026
|
+
(default), the method returns the current value.
|
|
1027
|
+
|
|
1028
|
+
EXAMPLES::
|
|
1029
|
+
|
|
1030
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1031
|
+
sage: p = get_solver(solver = "InteractiveLP")
|
|
1032
|
+
sage: p.add_variable(lower_bound=None)
|
|
1033
|
+
0
|
|
1034
|
+
sage: p.col_bounds(0)
|
|
1035
|
+
(None, None)
|
|
1036
|
+
sage: p.variable_lower_bound(0) is None
|
|
1037
|
+
True
|
|
1038
|
+
sage: p.variable_lower_bound(0, 0)
|
|
1039
|
+
sage: p.col_bounds(0)
|
|
1040
|
+
(0, None)
|
|
1041
|
+
sage: p.variable_lower_bound(0)
|
|
1042
|
+
0
|
|
1043
|
+
sage: p.variable_lower_bound(0, None)
|
|
1044
|
+
sage: p.variable_lower_bound(0) is None
|
|
1045
|
+
True
|
|
1046
|
+
"""
|
|
1047
|
+
bounds = self.col_bounds(index)
|
|
1048
|
+
if value is False:
|
|
1049
|
+
return bounds[0]
|
|
1050
|
+
else:
|
|
1051
|
+
if value != bounds[0]:
|
|
1052
|
+
bounds = (value, bounds[1])
|
|
1053
|
+
A, b, c, x, constraint_types, variable_types, problem_type, ring, d = self._AbcxCVPRd()
|
|
1054
|
+
variable_types = list(variable_types)
|
|
1055
|
+
variable_types[index] = self._variable_type_from_bounds(*bounds)
|
|
1056
|
+
self.lp = InteractiveLPProblem(A, b, c, x,
|
|
1057
|
+
constraint_types, variable_types,
|
|
1058
|
+
problem_type, ring, objective_constant_term=d)
|
|
1059
|
+
|
|
1060
|
+
cpdef bint is_variable_basic(self, int index) noexcept:
|
|
1061
|
+
"""
|
|
1062
|
+
Test whether the given variable is basic.
|
|
1063
|
+
|
|
1064
|
+
This assumes that the problem has been solved with the simplex method
|
|
1065
|
+
and a basis is available. Otherwise an exception will be raised.
|
|
1066
|
+
|
|
1067
|
+
INPUT:
|
|
1068
|
+
|
|
1069
|
+
- ``index`` -- integer; the variable's id
|
|
1070
|
+
|
|
1071
|
+
EXAMPLES::
|
|
1072
|
+
|
|
1073
|
+
sage: p = MixedIntegerLinearProgram(maximization=True,\
|
|
1074
|
+
....: solver='InteractiveLP')
|
|
1075
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
1076
|
+
sage: p.add_constraint(-x[0] + x[1] <= 2)
|
|
1077
|
+
sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17)
|
|
1078
|
+
sage: p.set_objective(11/2 * x[0] - 3 * x[1])
|
|
1079
|
+
sage: b = p.get_backend()
|
|
1080
|
+
sage: # Backend-specific commands to instruct solver to use simplex method here
|
|
1081
|
+
sage: b.solve()
|
|
1082
|
+
0
|
|
1083
|
+
sage: b.is_variable_basic(0)
|
|
1084
|
+
True
|
|
1085
|
+
sage: b.is_variable_basic(1)
|
|
1086
|
+
False
|
|
1087
|
+
"""
|
|
1088
|
+
return self.lp_std_form.decision_variables()[index] in self.final_dictionary.basic_variables()
|
|
1089
|
+
|
|
1090
|
+
cpdef bint is_variable_nonbasic_at_lower_bound(self, int index) noexcept:
|
|
1091
|
+
"""
|
|
1092
|
+
Test whether the given variable is nonbasic at lower bound.
|
|
1093
|
+
|
|
1094
|
+
This assumes that the problem has been solved with the simplex method
|
|
1095
|
+
and a basis is available. Otherwise an exception will be raised.
|
|
1096
|
+
|
|
1097
|
+
INPUT:
|
|
1098
|
+
|
|
1099
|
+
- ``index`` -- integer; the variable's id
|
|
1100
|
+
|
|
1101
|
+
EXAMPLES::
|
|
1102
|
+
|
|
1103
|
+
sage: p = MixedIntegerLinearProgram(maximization=True,\
|
|
1104
|
+
....: solver='InteractiveLP')
|
|
1105
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
1106
|
+
sage: p.add_constraint(-x[0] + x[1] <= 2)
|
|
1107
|
+
sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17)
|
|
1108
|
+
sage: p.set_objective(11/2 * x[0] - 3 * x[1])
|
|
1109
|
+
sage: b = p.get_backend()
|
|
1110
|
+
sage: # Backend-specific commands to instruct solver to use simplex method here
|
|
1111
|
+
sage: b.solve()
|
|
1112
|
+
0
|
|
1113
|
+
sage: b.is_variable_nonbasic_at_lower_bound(0)
|
|
1114
|
+
False
|
|
1115
|
+
sage: b.is_variable_nonbasic_at_lower_bound(1)
|
|
1116
|
+
True
|
|
1117
|
+
"""
|
|
1118
|
+
return self.lp_std_form.decision_variables()[index] in self.final_dictionary.nonbasic_variables()
|
|
1119
|
+
|
|
1120
|
+
cpdef bint is_slack_variable_basic(self, int index) noexcept:
|
|
1121
|
+
"""
|
|
1122
|
+
Test whether the slack variable of the given row is basic.
|
|
1123
|
+
|
|
1124
|
+
This assumes that the problem has been solved with the simplex method
|
|
1125
|
+
and a basis is available. Otherwise an exception will be raised.
|
|
1126
|
+
|
|
1127
|
+
INPUT:
|
|
1128
|
+
|
|
1129
|
+
- ``index`` -- integer; the variable's id
|
|
1130
|
+
|
|
1131
|
+
EXAMPLES::
|
|
1132
|
+
|
|
1133
|
+
sage: p = MixedIntegerLinearProgram(maximization=True,\
|
|
1134
|
+
....: solver='InteractiveLP')
|
|
1135
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
1136
|
+
sage: p.add_constraint(-x[0] + x[1] <= 2)
|
|
1137
|
+
sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17)
|
|
1138
|
+
sage: p.set_objective(11/2 * x[0] - 3 * x[1])
|
|
1139
|
+
sage: b = p.get_backend()
|
|
1140
|
+
sage: # Backend-specific commands to instruct solver to use simplex method here
|
|
1141
|
+
sage: b.solve()
|
|
1142
|
+
0
|
|
1143
|
+
sage: b.is_slack_variable_basic(0)
|
|
1144
|
+
True
|
|
1145
|
+
sage: b.is_slack_variable_basic(1)
|
|
1146
|
+
False
|
|
1147
|
+
"""
|
|
1148
|
+
return self.lp_std_form.slack_variables()[index] in self.final_dictionary.basic_variables()
|
|
1149
|
+
|
|
1150
|
+
cpdef bint is_slack_variable_nonbasic_at_lower_bound(self, int index) noexcept:
|
|
1151
|
+
"""
|
|
1152
|
+
Test whether the given variable is nonbasic at lower bound.
|
|
1153
|
+
|
|
1154
|
+
This assumes that the problem has been solved with the simplex method
|
|
1155
|
+
and a basis is available. Otherwise an exception will be raised.
|
|
1156
|
+
|
|
1157
|
+
INPUT:
|
|
1158
|
+
|
|
1159
|
+
- ``index`` -- integer; the variable's id
|
|
1160
|
+
|
|
1161
|
+
EXAMPLES::
|
|
1162
|
+
|
|
1163
|
+
sage: p = MixedIntegerLinearProgram(maximization=True,\
|
|
1164
|
+
....: solver='InteractiveLP')
|
|
1165
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
1166
|
+
sage: p.add_constraint(-x[0] + x[1] <= 2)
|
|
1167
|
+
sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17)
|
|
1168
|
+
sage: p.set_objective(11/2 * x[0] - 3 * x[1])
|
|
1169
|
+
sage: b = p.get_backend()
|
|
1170
|
+
sage: # Backend-specific commands to instruct solver to use simplex method here
|
|
1171
|
+
sage: b.solve()
|
|
1172
|
+
0
|
|
1173
|
+
sage: b.is_slack_variable_nonbasic_at_lower_bound(0)
|
|
1174
|
+
False
|
|
1175
|
+
sage: b.is_slack_variable_nonbasic_at_lower_bound(1)
|
|
1176
|
+
True
|
|
1177
|
+
"""
|
|
1178
|
+
return self.lp_std_form.slack_variables()[index] in self.final_dictionary.nonbasic_variables()
|
|
1179
|
+
|
|
1180
|
+
cpdef dictionary(self):
|
|
1181
|
+
# Proposed addition to the general interface,
|
|
1182
|
+
# which would for other solvers return backend dictionaries (#18804)
|
|
1183
|
+
"""
|
|
1184
|
+
Return a dictionary representing the current basis.
|
|
1185
|
+
|
|
1186
|
+
EXAMPLES::
|
|
1187
|
+
|
|
1188
|
+
sage: p = MixedIntegerLinearProgram(maximization=True,\
|
|
1189
|
+
....: solver='InteractiveLP')
|
|
1190
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
1191
|
+
sage: p.add_constraint(-x[0] + x[1] <= 2)
|
|
1192
|
+
sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17)
|
|
1193
|
+
sage: p.set_objective(11/2 * x[0] - 3 * x[1])
|
|
1194
|
+
sage: b = p.get_backend()
|
|
1195
|
+
sage: # Backend-specific commands to instruct solver to use simplex method here
|
|
1196
|
+
sage: b.solve()
|
|
1197
|
+
0
|
|
1198
|
+
sage: d = b.dictionary(); d
|
|
1199
|
+
LP problem dictionary ...
|
|
1200
|
+
sage: set(d.basic_variables())
|
|
1201
|
+
{x1, x3}
|
|
1202
|
+
sage: d.basic_solution()
|
|
1203
|
+
(17/8, 0)
|
|
1204
|
+
|
|
1205
|
+
TESTS:
|
|
1206
|
+
|
|
1207
|
+
Compare with a dictionary obtained in another way::
|
|
1208
|
+
|
|
1209
|
+
sage: lp, basis = p.interactive_lp_problem()
|
|
1210
|
+
sage: lp.dictionary(*basis).basic_solution()
|
|
1211
|
+
(17/8, 0)
|
|
1212
|
+
"""
|
|
1213
|
+
return self.final_dictionary
|
|
1214
|
+
|
|
1215
|
+
cpdef interactive_lp_problem(self):
|
|
1216
|
+
"""
|
|
1217
|
+
Return the :class:`InteractiveLPProblem` object associated with this backend.
|
|
1218
|
+
|
|
1219
|
+
EXAMPLES::
|
|
1220
|
+
|
|
1221
|
+
sage: p = MixedIntegerLinearProgram(maximization=True,\
|
|
1222
|
+
....: solver='InteractiveLP')
|
|
1223
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
1224
|
+
sage: p.add_constraint(-x[0] + x[1] <= 2)
|
|
1225
|
+
sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17)
|
|
1226
|
+
sage: p.set_objective(11/2 * x[0] - 3 * x[1])
|
|
1227
|
+
sage: b = p.get_backend()
|
|
1228
|
+
sage: b.interactive_lp_problem()
|
|
1229
|
+
LP problem ...
|
|
1230
|
+
"""
|
|
1231
|
+
return self.lp
|