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,1126 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-polyhedra
|
|
2
|
+
# sage.doctest: needs pplpy
|
|
3
|
+
"""
|
|
4
|
+
PPL Backend
|
|
5
|
+
|
|
6
|
+
AUTHORS:
|
|
7
|
+
|
|
8
|
+
- Risan (2012-02): initial implementation
|
|
9
|
+
|
|
10
|
+
- Jeroen Demeyer (2014-08-04) allow rational coefficients for
|
|
11
|
+
constraints and objective function (:issue:`16755`)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
# ****************************************************************************
|
|
15
|
+
# Copyright (C) 2010 Risan <ptrrsn.1@gmail.com>
|
|
16
|
+
# Copyright (C) 2014 Jeroen Demeyer <jdemeyer@cage.ugent.be>
|
|
17
|
+
#
|
|
18
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
19
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
20
|
+
# the License, or (at your option) any later version.
|
|
21
|
+
# https://www.gnu.org/licenses/
|
|
22
|
+
# ****************************************************************************
|
|
23
|
+
|
|
24
|
+
from sage.numerical.mip import MIPSolverException
|
|
25
|
+
from ppl import MIP_Problem, Variable, Variables_Set, Linear_Expression
|
|
26
|
+
from sage.rings.integer cimport Integer
|
|
27
|
+
from sage.rings.rational cimport Rational
|
|
28
|
+
from sage.numerical.backends.generic_backend cimport GenericBackend
|
|
29
|
+
from copy import copy
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
cdef class PPLBackend(GenericBackend):
|
|
33
|
+
"""
|
|
34
|
+
MIP Backend that uses the exact MIP solver from the Parma Polyhedra Library.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
cdef object mip
|
|
38
|
+
cdef list Matrix
|
|
39
|
+
cdef list row_lower_bound
|
|
40
|
+
cdef list row_upper_bound
|
|
41
|
+
cdef list col_lower_bound
|
|
42
|
+
cdef list col_upper_bound
|
|
43
|
+
cdef list objective_function
|
|
44
|
+
cdef list row_name_var
|
|
45
|
+
cdef list col_name_var
|
|
46
|
+
cdef int is_maximize
|
|
47
|
+
cdef str name
|
|
48
|
+
cdef object integer_variables
|
|
49
|
+
|
|
50
|
+
# Common denominator for objective function in self.mip (not for the constant term)
|
|
51
|
+
cdef Integer obj_denominator
|
|
52
|
+
|
|
53
|
+
def __cinit__(self, maximization=True, base_ring=None):
|
|
54
|
+
"""
|
|
55
|
+
Constructor.
|
|
56
|
+
|
|
57
|
+
EXAMPLES::
|
|
58
|
+
|
|
59
|
+
sage: p = MixedIntegerLinearProgram(solver = "PPL")
|
|
60
|
+
|
|
61
|
+
TESTS:
|
|
62
|
+
|
|
63
|
+
Raise an error if a ``base_ring`` is requested that is not supported::
|
|
64
|
+
|
|
65
|
+
sage: p = MixedIntegerLinearProgram(solver='PPL', base_ring=AA) # needs sage.rings.number_field
|
|
66
|
+
Traceback (most recent call last):
|
|
67
|
+
...
|
|
68
|
+
TypeError: The PPL backend only supports rational data.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
if base_ring is not None:
|
|
72
|
+
from sage.rings.rational_field import QQ
|
|
73
|
+
if base_ring is not QQ:
|
|
74
|
+
raise TypeError('The PPL backend only supports rational data.')
|
|
75
|
+
|
|
76
|
+
self.Matrix = []
|
|
77
|
+
self.row_lower_bound = []
|
|
78
|
+
self.row_upper_bound = []
|
|
79
|
+
self.col_lower_bound = []
|
|
80
|
+
self.col_upper_bound = []
|
|
81
|
+
self.objective_function = []
|
|
82
|
+
self.row_name_var = []
|
|
83
|
+
self.col_name_var = []
|
|
84
|
+
self.name = ''
|
|
85
|
+
self.obj_constant_term = Rational(0)
|
|
86
|
+
self.obj_denominator = Integer(1)
|
|
87
|
+
self.integer_variables = set()
|
|
88
|
+
|
|
89
|
+
if maximization:
|
|
90
|
+
self.set_sense(+1)
|
|
91
|
+
else:
|
|
92
|
+
self.set_sense(-1)
|
|
93
|
+
|
|
94
|
+
cpdef base_ring(self):
|
|
95
|
+
from sage.rings.rational_field import QQ
|
|
96
|
+
return QQ
|
|
97
|
+
|
|
98
|
+
cpdef zero(self):
|
|
99
|
+
return self.base_ring()(0)
|
|
100
|
+
|
|
101
|
+
cpdef __copy__(self):
|
|
102
|
+
"""
|
|
103
|
+
Return a copy of ``self``.
|
|
104
|
+
|
|
105
|
+
EXAMPLES::
|
|
106
|
+
|
|
107
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
108
|
+
sage: p = MixedIntegerLinearProgram(solver = "PPL")
|
|
109
|
+
sage: b = p.new_variable()
|
|
110
|
+
sage: p.add_constraint(b[1] + b[2] <= 6)
|
|
111
|
+
sage: p.set_objective(b[1] + b[2])
|
|
112
|
+
sage: cp = copy(p.get_backend())
|
|
113
|
+
sage: cp.solve()
|
|
114
|
+
0
|
|
115
|
+
sage: cp.get_objective_value()
|
|
116
|
+
6
|
|
117
|
+
"""
|
|
118
|
+
cdef PPLBackend cp = type(self)()
|
|
119
|
+
cp.Matrix = [row[:] for row in self.Matrix]
|
|
120
|
+
cp.row_lower_bound = self.row_lower_bound[:]
|
|
121
|
+
cp.row_upper_bound = self.row_upper_bound[:]
|
|
122
|
+
cp.col_lower_bound = self.col_lower_bound[:]
|
|
123
|
+
cp.col_upper_bound = self.col_upper_bound[:]
|
|
124
|
+
cp.objective_function = self.objective_function[:]
|
|
125
|
+
cp.row_name_var = self.row_name_var[:]
|
|
126
|
+
cp.col_name_var = self.col_name_var[:]
|
|
127
|
+
cp.name = self.name
|
|
128
|
+
cp.obj_constant_term = self.obj_constant_term
|
|
129
|
+
cp.obj_denominator = self.obj_denominator
|
|
130
|
+
cp.integer_variables = copy(self.integer_variables)
|
|
131
|
+
cp.is_maximize = self.is_maximize
|
|
132
|
+
return cp
|
|
133
|
+
|
|
134
|
+
def init_mip(self):
|
|
135
|
+
"""
|
|
136
|
+
Converting the matrix form of the MIP Problem to PPL MIP_Problem.
|
|
137
|
+
|
|
138
|
+
EXAMPLES::
|
|
139
|
+
|
|
140
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
141
|
+
sage: p = get_solver(solver='PPL')
|
|
142
|
+
sage: p.base_ring()
|
|
143
|
+
Rational Field
|
|
144
|
+
sage: type(p.zero())
|
|
145
|
+
<class 'sage.rings.rational.Rational'>
|
|
146
|
+
sage: p.init_mip()
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
self.mip = MIP_Problem()
|
|
150
|
+
|
|
151
|
+
# Common denominator (for objective function and every constraint)
|
|
152
|
+
cdef Integer denom, newdenom
|
|
153
|
+
|
|
154
|
+
self.mip.add_space_dimensions_and_embed(len(self.objective_function))
|
|
155
|
+
|
|
156
|
+
# Integrality
|
|
157
|
+
|
|
158
|
+
ivar = Variables_Set()
|
|
159
|
+
for i in self.integer_variables:
|
|
160
|
+
ivar.insert(Variable(i))
|
|
161
|
+
self.mip.add_to_integer_space_dimensions(ivar)
|
|
162
|
+
|
|
163
|
+
# Objective function
|
|
164
|
+
mip_obj = Linear_Expression(0)
|
|
165
|
+
denom = Integer(1)
|
|
166
|
+
for i in range(len(self.objective_function)):
|
|
167
|
+
coeff = self.objective_function[i] * denom
|
|
168
|
+
newdenom = coeff.denominator()
|
|
169
|
+
if newdenom != 1:
|
|
170
|
+
assert newdenom >= 2
|
|
171
|
+
denom *= newdenom
|
|
172
|
+
mip_obj *= newdenom
|
|
173
|
+
coeff *= newdenom
|
|
174
|
+
mip_obj = mip_obj + Linear_Expression(coeff * Variable(i))
|
|
175
|
+
self.mip.set_objective_function(mip_obj)
|
|
176
|
+
self.obj_denominator = denom
|
|
177
|
+
|
|
178
|
+
# Constraints
|
|
179
|
+
for i in range(len(self.Matrix)):
|
|
180
|
+
l = Linear_Expression(0)
|
|
181
|
+
denom = Integer(1)
|
|
182
|
+
for j in range(len(self.Matrix[i])):
|
|
183
|
+
coeff = self.Matrix[i][j] * denom
|
|
184
|
+
newdenom = coeff.denominator()
|
|
185
|
+
if newdenom != 1:
|
|
186
|
+
assert newdenom >= 2
|
|
187
|
+
denom *= newdenom
|
|
188
|
+
l *= newdenom
|
|
189
|
+
coeff *= newdenom
|
|
190
|
+
l = l + Linear_Expression(coeff * Variable(j))
|
|
191
|
+
self._add_rational_constraint(l, denom, self.row_lower_bound[i], self.row_upper_bound[i])
|
|
192
|
+
|
|
193
|
+
assert len(self.col_lower_bound) == len(self.col_upper_bound)
|
|
194
|
+
for i in range(len(self.col_lower_bound)):
|
|
195
|
+
self._add_rational_constraint(Variable(i), 1, self.col_lower_bound[i], self.col_upper_bound[i])
|
|
196
|
+
|
|
197
|
+
if self.is_maximize == 1:
|
|
198
|
+
self.mip.set_optimization_mode('maximization')
|
|
199
|
+
else:
|
|
200
|
+
self.mip.set_optimization_mode('minimization')
|
|
201
|
+
|
|
202
|
+
def _add_rational_constraint(self, e, denom, lower, upper):
|
|
203
|
+
"""
|
|
204
|
+
Helper function for adding constraints: add the constraint
|
|
205
|
+
``lower <= e/denom <= upper``.
|
|
206
|
+
|
|
207
|
+
INPUT:
|
|
208
|
+
|
|
209
|
+
- ``e`` -- a linear expression (type ``Linear_Expression``)
|
|
210
|
+
|
|
211
|
+
- ``denom`` -- positive integer
|
|
212
|
+
|
|
213
|
+
- ``lower``, ``upper`` -- a rational number or ``None``, where
|
|
214
|
+
``None`` means that there is no constraint
|
|
215
|
+
|
|
216
|
+
TESTS:
|
|
217
|
+
|
|
218
|
+
Create a linear system with only equalities as constraints::
|
|
219
|
+
|
|
220
|
+
sage: p = MixedIntegerLinearProgram(solver='PPL')
|
|
221
|
+
sage: x = p.new_variable(nonnegative=False)
|
|
222
|
+
sage: n = 40
|
|
223
|
+
sage: v = random_vector(QQ, n)
|
|
224
|
+
sage: M = random_matrix(QQ, 2*n, n)
|
|
225
|
+
sage: for j in range(2*n): # indirect doctest
|
|
226
|
+
....: lhs = p.sum(M[j,i]*x[i] for i in range(n))
|
|
227
|
+
....: rhs = M.row(j).inner_product(v)
|
|
228
|
+
....: p.add_constraint(lhs == rhs)
|
|
229
|
+
sage: p.solve() # long time
|
|
230
|
+
0
|
|
231
|
+
"""
|
|
232
|
+
if lower == upper:
|
|
233
|
+
if lower is not None:
|
|
234
|
+
rhs = Rational(lower * denom)
|
|
235
|
+
self.mip.add_constraint(e * rhs.denominator() == rhs.numerator())
|
|
236
|
+
else:
|
|
237
|
+
if lower is not None:
|
|
238
|
+
rhs = Rational(lower * denom)
|
|
239
|
+
self.mip.add_constraint(e * rhs.denominator() >= rhs.numerator())
|
|
240
|
+
if upper is not None:
|
|
241
|
+
rhs = Rational(upper * denom)
|
|
242
|
+
self.mip.add_constraint(e * rhs.denominator() <= rhs.numerator())
|
|
243
|
+
|
|
244
|
+
cpdef int add_variable(self, lower_bound=0, upper_bound=None, binary=False, continuous=False, integer=False, obj=0, name=None) except -1:
|
|
245
|
+
"""
|
|
246
|
+
Add a variable.
|
|
247
|
+
|
|
248
|
+
This amounts to adding a new column to the matrix. By default,
|
|
249
|
+
the variable is both positive and real.
|
|
250
|
+
|
|
251
|
+
It has not been implemented for selecting the variable type yet.
|
|
252
|
+
|
|
253
|
+
INPUT:
|
|
254
|
+
|
|
255
|
+
- ``lower_bound`` -- the lower bound of the variable (default: 0)
|
|
256
|
+
|
|
257
|
+
- ``upper_bound`` -- the upper bound of the variable (default: ``None``)
|
|
258
|
+
|
|
259
|
+
- ``binary`` -- ``True`` if the variable is binary (default: ``False``)
|
|
260
|
+
|
|
261
|
+
- ``continuous`` -- ``True`` if the variable is continuous (default: ``True``)
|
|
262
|
+
|
|
263
|
+
- ``integer`` -- ``True`` if the variable is integral (default: ``False``)
|
|
264
|
+
|
|
265
|
+
- ``obj`` -- (optional) coefficient of this variable in the objective function (default: 0)
|
|
266
|
+
|
|
267
|
+
- ``name`` -- an optional name for the newly added variable (default: ``None``)
|
|
268
|
+
|
|
269
|
+
OUTPUT: the index of the newly created variable
|
|
270
|
+
|
|
271
|
+
EXAMPLES::
|
|
272
|
+
|
|
273
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
274
|
+
sage: p = get_solver(solver = "PPL")
|
|
275
|
+
sage: p.ncols()
|
|
276
|
+
0
|
|
277
|
+
sage: p.add_variable()
|
|
278
|
+
0
|
|
279
|
+
sage: p.ncols()
|
|
280
|
+
1
|
|
281
|
+
sage: p.add_variable(lower_bound=-2)
|
|
282
|
+
1
|
|
283
|
+
sage: p.add_variable(name='x',obj=2/3)
|
|
284
|
+
2
|
|
285
|
+
sage: p.col_name(2)
|
|
286
|
+
'x'
|
|
287
|
+
sage: p.objective_coefficient(2)
|
|
288
|
+
2/3
|
|
289
|
+
sage: p.add_variable(integer=True)
|
|
290
|
+
3
|
|
291
|
+
"""
|
|
292
|
+
cdef int vtype = int(bool(binary)) + int(bool(continuous)) + int(bool(integer))
|
|
293
|
+
if vtype == 0:
|
|
294
|
+
continuous = True
|
|
295
|
+
elif vtype != 1:
|
|
296
|
+
raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.")
|
|
297
|
+
|
|
298
|
+
for i in range(len(self.Matrix)):
|
|
299
|
+
self.Matrix[i].append(0)
|
|
300
|
+
self.col_lower_bound.append(lower_bound)
|
|
301
|
+
self.col_upper_bound.append(upper_bound)
|
|
302
|
+
self.objective_function.append(obj)
|
|
303
|
+
self.col_name_var.append(name)
|
|
304
|
+
|
|
305
|
+
n = len(self.objective_function) - 1
|
|
306
|
+
if binary:
|
|
307
|
+
self.set_variable_type(n,0)
|
|
308
|
+
elif integer:
|
|
309
|
+
self.set_variable_type(n,1)
|
|
310
|
+
|
|
311
|
+
return n
|
|
312
|
+
|
|
313
|
+
cpdef int add_variables(self, int n, lower_bound=0, upper_bound=None, binary=False, continuous=True, integer=False, obj=0, names=None) except -1:
|
|
314
|
+
"""
|
|
315
|
+
Add ``n`` variables.
|
|
316
|
+
|
|
317
|
+
This amounts to adding new columns to the matrix. By default,
|
|
318
|
+
the variables are both positive and real.
|
|
319
|
+
|
|
320
|
+
It has not been implemented for selecting the variable type yet.
|
|
321
|
+
|
|
322
|
+
INPUT:
|
|
323
|
+
|
|
324
|
+
- ``n`` -- the number of new variables (must be > 0)
|
|
325
|
+
|
|
326
|
+
- ``lower_bound`` -- the lower bound of the variable (default: 0)
|
|
327
|
+
|
|
328
|
+
- ``upper_bound`` -- the upper bound of the variable (default: ``None``)
|
|
329
|
+
|
|
330
|
+
- ``binary`` -- ``True`` if the variable is binary (default: ``False``)
|
|
331
|
+
|
|
332
|
+
- ``continuous`` -- ``True`` if the variable is continuous (default: ``True``)
|
|
333
|
+
|
|
334
|
+
- ``integer`` -- ``True`` if the variable is integral (default: ``False``)
|
|
335
|
+
|
|
336
|
+
- ``obj`` -- coefficient of all variables in the objective function (default: 0)
|
|
337
|
+
|
|
338
|
+
- ``names`` -- list of names (default: ``None``)
|
|
339
|
+
|
|
340
|
+
OUTPUT: the index of the variable created last
|
|
341
|
+
|
|
342
|
+
EXAMPLES::
|
|
343
|
+
|
|
344
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
345
|
+
sage: p = get_solver(solver = "PPL")
|
|
346
|
+
sage: p.ncols()
|
|
347
|
+
0
|
|
348
|
+
sage: p.add_variables(5)
|
|
349
|
+
4
|
|
350
|
+
sage: p.ncols()
|
|
351
|
+
5
|
|
352
|
+
sage: p.add_variables(2, lower_bound=-2.0, obj=42.0, names=['a','b'])
|
|
353
|
+
6
|
|
354
|
+
|
|
355
|
+
TESTS:
|
|
356
|
+
|
|
357
|
+
Check that arguments are used::
|
|
358
|
+
|
|
359
|
+
sage: p.col_bounds(5) # tol 1e-8
|
|
360
|
+
(-2.0, None)
|
|
361
|
+
sage: p.col_name(5)
|
|
362
|
+
'a'
|
|
363
|
+
sage: p.objective_coefficient(5) # tol 1e-8
|
|
364
|
+
42.0
|
|
365
|
+
"""
|
|
366
|
+
if binary or integer:
|
|
367
|
+
raise NotImplementedError("The PPL backend in Sage only supports continuous variables")
|
|
368
|
+
for k in range(n):
|
|
369
|
+
for i in range(len(self.Matrix)):
|
|
370
|
+
self.Matrix[i].append(0)
|
|
371
|
+
self.col_lower_bound.append(lower_bound)
|
|
372
|
+
self.col_upper_bound.append(upper_bound)
|
|
373
|
+
self.objective_function.append(obj)
|
|
374
|
+
if names is not None:
|
|
375
|
+
self.col_name_var.append(names[k])
|
|
376
|
+
else:
|
|
377
|
+
self.col_name_var.append(None)
|
|
378
|
+
return len(self.objective_function) - 1
|
|
379
|
+
|
|
380
|
+
cpdef set_variable_type(self, int variable, int vtype):
|
|
381
|
+
"""
|
|
382
|
+
Set the type of a variable.
|
|
383
|
+
|
|
384
|
+
INPUT:
|
|
385
|
+
|
|
386
|
+
- ``variable`` -- integer; the variable's id
|
|
387
|
+
|
|
388
|
+
- ``vtype`` -- integer:
|
|
389
|
+
|
|
390
|
+
* 1 Integer
|
|
391
|
+
* 0 Binary
|
|
392
|
+
* -1 Continuous
|
|
393
|
+
|
|
394
|
+
EXAMPLES::
|
|
395
|
+
|
|
396
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
397
|
+
sage: p = get_solver(solver = "PPL")
|
|
398
|
+
sage: p.add_variables(5)
|
|
399
|
+
4
|
|
400
|
+
sage: p.set_variable_type(0,1)
|
|
401
|
+
sage: p.is_variable_integer(0)
|
|
402
|
+
True
|
|
403
|
+
sage: p.set_variable_type(3,0)
|
|
404
|
+
sage: p.is_variable_integer(3) or p.is_variable_binary(3)
|
|
405
|
+
True
|
|
406
|
+
sage: p.col_bounds(3) # tol 1e-6
|
|
407
|
+
(0, 1)
|
|
408
|
+
sage: p.set_variable_type(3, -1)
|
|
409
|
+
sage: p.is_variable_continuous(3)
|
|
410
|
+
True
|
|
411
|
+
|
|
412
|
+
TESTS:
|
|
413
|
+
|
|
414
|
+
Test that an exception is raised when an invalid type is passed::
|
|
415
|
+
|
|
416
|
+
sage: p.set_variable_type(3, -2)
|
|
417
|
+
Traceback (most recent call last):
|
|
418
|
+
...
|
|
419
|
+
ValueError: ...
|
|
420
|
+
"""
|
|
421
|
+
if vtype == -1:
|
|
422
|
+
if variable in self.integer_variables:
|
|
423
|
+
self.integer_variables.remove(variable)
|
|
424
|
+
elif vtype == 0:
|
|
425
|
+
self.integer_variables.add(variable)
|
|
426
|
+
self.variable_lower_bound(variable, 0)
|
|
427
|
+
self.variable_upper_bound(variable, 1)
|
|
428
|
+
elif vtype == 1:
|
|
429
|
+
self.integer_variables.add(variable)
|
|
430
|
+
else:
|
|
431
|
+
raise ValueError("Invalid variable type: {}".format(vtype))
|
|
432
|
+
|
|
433
|
+
cpdef set_sense(self, int sense):
|
|
434
|
+
"""
|
|
435
|
+
Set the direction (maximization/minimization).
|
|
436
|
+
|
|
437
|
+
INPUT:
|
|
438
|
+
|
|
439
|
+
- ``sense`` -- integer:
|
|
440
|
+
|
|
441
|
+
* +1 => Maximization
|
|
442
|
+
* -1 => Minimization
|
|
443
|
+
|
|
444
|
+
EXAMPLES::
|
|
445
|
+
|
|
446
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
447
|
+
sage: p = get_solver(solver = "PPL")
|
|
448
|
+
sage: p.is_maximization()
|
|
449
|
+
True
|
|
450
|
+
sage: p.set_sense(-1)
|
|
451
|
+
sage: p.is_maximization()
|
|
452
|
+
False
|
|
453
|
+
"""
|
|
454
|
+
if sense == 1:
|
|
455
|
+
self.is_maximize = 1
|
|
456
|
+
else:
|
|
457
|
+
self.is_maximize = 0
|
|
458
|
+
|
|
459
|
+
cpdef objective_coefficient(self, int variable, coeff=None):
|
|
460
|
+
"""
|
|
461
|
+
Set or get the coefficient of a variable in the objective
|
|
462
|
+
function
|
|
463
|
+
|
|
464
|
+
INPUT:
|
|
465
|
+
|
|
466
|
+
- ``variable`` -- integer; the variable's id
|
|
467
|
+
|
|
468
|
+
- ``coeff`` -- integer; its coefficient
|
|
469
|
+
|
|
470
|
+
EXAMPLES::
|
|
471
|
+
|
|
472
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
473
|
+
sage: p = get_solver(solver = "PPL")
|
|
474
|
+
sage: p.add_variable()
|
|
475
|
+
0
|
|
476
|
+
sage: p.objective_coefficient(0)
|
|
477
|
+
0
|
|
478
|
+
sage: p.objective_coefficient(0,2)
|
|
479
|
+
sage: p.objective_coefficient(0)
|
|
480
|
+
2
|
|
481
|
+
"""
|
|
482
|
+
if coeff is not None:
|
|
483
|
+
self.objective_function[variable] = coeff
|
|
484
|
+
else:
|
|
485
|
+
return self.objective_function[variable]
|
|
486
|
+
|
|
487
|
+
cpdef set_objective(self, list coeff, d=0):
|
|
488
|
+
"""
|
|
489
|
+
Set the objective function.
|
|
490
|
+
|
|
491
|
+
INPUT:
|
|
492
|
+
|
|
493
|
+
- ``coeff`` -- list of real values, whose i-th element is the
|
|
494
|
+
coefficient of the i-th variable in the objective function
|
|
495
|
+
|
|
496
|
+
EXAMPLES::
|
|
497
|
+
|
|
498
|
+
sage: p = MixedIntegerLinearProgram(solver='PPL')
|
|
499
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
500
|
+
sage: p.add_constraint(x[0]*5 + x[1]/11 <= 6)
|
|
501
|
+
sage: p.set_objective(x[0])
|
|
502
|
+
sage: p.solve()
|
|
503
|
+
6/5
|
|
504
|
+
sage: p.set_objective(x[0]/2 + 1)
|
|
505
|
+
sage: p.show()
|
|
506
|
+
Maximization:
|
|
507
|
+
1/2 x_0 + 1
|
|
508
|
+
<BLANKLINE>
|
|
509
|
+
Constraints:
|
|
510
|
+
constraint_0: 5 x_0 + 1/11 x_1 <= 6
|
|
511
|
+
Variables:
|
|
512
|
+
x_0 is a continuous variable (min=0, max=+oo)
|
|
513
|
+
x_1 is a continuous variable (min=0, max=+oo)
|
|
514
|
+
sage: p.solve()
|
|
515
|
+
8/5
|
|
516
|
+
|
|
517
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
518
|
+
sage: p = get_solver(solver = "PPL")
|
|
519
|
+
sage: p.add_variables(5)
|
|
520
|
+
4
|
|
521
|
+
sage: p.set_objective([1, 1, 2, 1, 3])
|
|
522
|
+
sage: [p.objective_coefficient(x) for x in range(5)]
|
|
523
|
+
[1, 1, 2, 1, 3]
|
|
524
|
+
"""
|
|
525
|
+
for i in range(len(coeff)):
|
|
526
|
+
self.objective_function[i] = coeff[i]
|
|
527
|
+
self.obj_constant_term = Rational(d)
|
|
528
|
+
|
|
529
|
+
cpdef set_verbosity(self, int level):
|
|
530
|
+
"""
|
|
531
|
+
Set the log (verbosity) level. Not Implemented.
|
|
532
|
+
|
|
533
|
+
EXAMPLES::
|
|
534
|
+
|
|
535
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
536
|
+
sage: p = get_solver(solver = "PPL")
|
|
537
|
+
sage: p.set_verbosity(0)
|
|
538
|
+
"""
|
|
539
|
+
|
|
540
|
+
cpdef add_linear_constraint(self, coefficients, lower_bound, upper_bound, name=None):
|
|
541
|
+
"""
|
|
542
|
+
Add a linear constraint.
|
|
543
|
+
|
|
544
|
+
INPUT:
|
|
545
|
+
|
|
546
|
+
- ``coefficients`` -- an iterable with ``(c,v)`` pairs where ``c``
|
|
547
|
+
is a variable index (integer) and ``v`` is a value (real
|
|
548
|
+
value).
|
|
549
|
+
|
|
550
|
+
- ``lower_bound`` -- a lower bound, either a real value or ``None``
|
|
551
|
+
|
|
552
|
+
- ``upper_bound`` -- an upper bound, either a real value or ``None``
|
|
553
|
+
|
|
554
|
+
- ``name`` -- an optional name for this row (default: ``None``)
|
|
555
|
+
|
|
556
|
+
EXAMPLES::
|
|
557
|
+
|
|
558
|
+
sage: p = MixedIntegerLinearProgram(solver='PPL')
|
|
559
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
560
|
+
sage: p.add_constraint(x[0]/2 + x[1]/3 <= 2/5)
|
|
561
|
+
sage: p.set_objective(x[1])
|
|
562
|
+
sage: p.solve()
|
|
563
|
+
6/5
|
|
564
|
+
sage: p.add_constraint(x[0] - x[1] >= 1/10)
|
|
565
|
+
sage: p.solve()
|
|
566
|
+
21/50
|
|
567
|
+
sage: p.set_max(x[0], 1/2)
|
|
568
|
+
sage: p.set_min(x[1], 3/8)
|
|
569
|
+
sage: p.solve()
|
|
570
|
+
2/5
|
|
571
|
+
|
|
572
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
573
|
+
sage: p = get_solver(solver = "PPL")
|
|
574
|
+
sage: p.add_variables(5)
|
|
575
|
+
4
|
|
576
|
+
sage: p.add_linear_constraint(zip(range(5), range(5)), 2.0, 2.0)
|
|
577
|
+
sage: p.row(0)
|
|
578
|
+
([1, 2, 3, 4], [1, 2, 3, 4])
|
|
579
|
+
sage: p.row_bounds(0)
|
|
580
|
+
(2.00000000000000, 2.00000000000000)
|
|
581
|
+
sage: p.add_linear_constraint( zip(range(5), range(5)), 1.0, 1.0, name='foo')
|
|
582
|
+
sage: p.row_name(-1)
|
|
583
|
+
'foo'
|
|
584
|
+
"""
|
|
585
|
+
last = len(self.Matrix)
|
|
586
|
+
self.Matrix.append([])
|
|
587
|
+
for i in range(len(self.objective_function)):
|
|
588
|
+
self.Matrix[last].append(0)
|
|
589
|
+
for a in coefficients:
|
|
590
|
+
self.Matrix[last][a[0]] = a[1]
|
|
591
|
+
|
|
592
|
+
self.row_lower_bound.append(lower_bound)
|
|
593
|
+
self.row_upper_bound.append(upper_bound)
|
|
594
|
+
self.row_name_var.append(name)
|
|
595
|
+
|
|
596
|
+
cpdef add_col(self, indices, coeffs):
|
|
597
|
+
"""
|
|
598
|
+
Add a column.
|
|
599
|
+
|
|
600
|
+
INPUT:
|
|
601
|
+
|
|
602
|
+
- ``indices`` -- list of integers; this list contains the
|
|
603
|
+
indices of the constraints in which the variable's
|
|
604
|
+
coefficient is nonzero
|
|
605
|
+
|
|
606
|
+
- ``coeffs`` -- list of real values; associates a coefficient
|
|
607
|
+
to the variable in each of the constraints in which it
|
|
608
|
+
appears. Namely, the i-th entry of ``coeffs`` corresponds to
|
|
609
|
+
the coefficient of the variable in the constraint
|
|
610
|
+
represented by the i-th entry in ``indices``.
|
|
611
|
+
|
|
612
|
+
.. NOTE::
|
|
613
|
+
|
|
614
|
+
``indices`` and ``coeffs`` are expected to be of the same
|
|
615
|
+
length.
|
|
616
|
+
|
|
617
|
+
EXAMPLES::
|
|
618
|
+
|
|
619
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
620
|
+
sage: p = get_solver(solver = "PPL")
|
|
621
|
+
sage: p.ncols()
|
|
622
|
+
0
|
|
623
|
+
sage: p.nrows()
|
|
624
|
+
0
|
|
625
|
+
sage: p.add_linear_constraints(5, 0, None)
|
|
626
|
+
sage: p.add_col(list(range(5)), list(range(5)))
|
|
627
|
+
sage: p.nrows()
|
|
628
|
+
5
|
|
629
|
+
"""
|
|
630
|
+
for i in range(len(self.Matrix)):
|
|
631
|
+
self.Matrix[i].append(0)
|
|
632
|
+
for i in range(len(indices)):
|
|
633
|
+
self.Matrix[indices[i]][len(self.Matrix[indices[i]]) - 1] = coeffs[i]
|
|
634
|
+
|
|
635
|
+
self.col_lower_bound.append(None)
|
|
636
|
+
self.col_upper_bound.append(None)
|
|
637
|
+
self.objective_function.append(0)
|
|
638
|
+
self.col_name_var.append(None)
|
|
639
|
+
|
|
640
|
+
cpdef add_linear_constraints(self, int number, lower_bound, upper_bound, names=None):
|
|
641
|
+
"""
|
|
642
|
+
Add constraints.
|
|
643
|
+
|
|
644
|
+
INPUT:
|
|
645
|
+
|
|
646
|
+
- ``number`` -- integer; the number of constraints to add
|
|
647
|
+
|
|
648
|
+
- ``lower_bound`` -- a lower bound, either a real value or ``None``
|
|
649
|
+
|
|
650
|
+
- ``upper_bound`` -- an upper bound, either a real value or ``None``
|
|
651
|
+
|
|
652
|
+
- ``names`` -- an optional list of names (default: ``None``)
|
|
653
|
+
|
|
654
|
+
EXAMPLES::
|
|
655
|
+
|
|
656
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
657
|
+
sage: p = get_solver(solver = "PPL")
|
|
658
|
+
sage: p.add_variables(5)
|
|
659
|
+
4
|
|
660
|
+
sage: p.add_linear_constraints(5, None, 2)
|
|
661
|
+
sage: p.row(4)
|
|
662
|
+
([], [])
|
|
663
|
+
sage: p.row_bounds(4)
|
|
664
|
+
(None, 2)
|
|
665
|
+
"""
|
|
666
|
+
for i in range(number):
|
|
667
|
+
self.Matrix.append([])
|
|
668
|
+
for j in range(len(self.objective_function)):
|
|
669
|
+
self.Matrix[i].append(0)
|
|
670
|
+
self.row_lower_bound.append(lower_bound)
|
|
671
|
+
self.row_upper_bound.append(upper_bound)
|
|
672
|
+
if names is not None:
|
|
673
|
+
self.row_name_var.append(names[i])
|
|
674
|
+
else:
|
|
675
|
+
self.row_name_var.append(None)
|
|
676
|
+
|
|
677
|
+
cpdef int solve(self) except -1:
|
|
678
|
+
# integer example copied from cplex_backend.pyx
|
|
679
|
+
"""
|
|
680
|
+
Solve the problem.
|
|
681
|
+
|
|
682
|
+
.. NOTE::
|
|
683
|
+
|
|
684
|
+
This method raises ``MIPSolverException`` exceptions when
|
|
685
|
+
the solution cannot be computed for any reason (none
|
|
686
|
+
exists, or the solver was not able to find it, etc...)
|
|
687
|
+
|
|
688
|
+
EXAMPLES:
|
|
689
|
+
|
|
690
|
+
A linear optimization problem::
|
|
691
|
+
|
|
692
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
693
|
+
sage: p = get_solver(solver = "PPL")
|
|
694
|
+
sage: p.add_linear_constraints(5, 0, None)
|
|
695
|
+
sage: p.add_col(list(range(5)), list(range(5)))
|
|
696
|
+
sage: p.solve()
|
|
697
|
+
0
|
|
698
|
+
|
|
699
|
+
An unbounded problem::
|
|
700
|
+
|
|
701
|
+
sage: p.objective_coefficient(0,1)
|
|
702
|
+
sage: p.solve()
|
|
703
|
+
Traceback (most recent call last):
|
|
704
|
+
...
|
|
705
|
+
MIPSolverException: ...
|
|
706
|
+
|
|
707
|
+
An integer optimization problem::
|
|
708
|
+
|
|
709
|
+
sage: p = MixedIntegerLinearProgram(solver='PPL')
|
|
710
|
+
sage: x = p.new_variable(integer=True, nonnegative=True)
|
|
711
|
+
sage: p.add_constraint(2*x[0] + 3*x[1], max = 6)
|
|
712
|
+
sage: p.add_constraint(3*x[0] + 2*x[1], max = 6)
|
|
713
|
+
sage: p.set_objective(x[0] + x[1] + 7)
|
|
714
|
+
sage: p.solve()
|
|
715
|
+
9
|
|
716
|
+
"""
|
|
717
|
+
self.init_mip()
|
|
718
|
+
|
|
719
|
+
ans = self.mip.solve()
|
|
720
|
+
|
|
721
|
+
if ans['status'] == 'optimized':
|
|
722
|
+
pass
|
|
723
|
+
elif ans['status'] == 'unbounded':
|
|
724
|
+
raise MIPSolverException("PPL : Solution is unbounded")
|
|
725
|
+
elif ans['status'] == 'unfeasible':
|
|
726
|
+
raise MIPSolverException("PPL : There is no feasible solution")
|
|
727
|
+
|
|
728
|
+
return 0
|
|
729
|
+
|
|
730
|
+
cpdef get_objective_value(self):
|
|
731
|
+
"""
|
|
732
|
+
Return the exact value of the objective function.
|
|
733
|
+
|
|
734
|
+
.. NOTE::
|
|
735
|
+
|
|
736
|
+
Behaviour is undefined unless ``solve`` has been called before.
|
|
737
|
+
|
|
738
|
+
EXAMPLES::
|
|
739
|
+
|
|
740
|
+
sage: p = MixedIntegerLinearProgram(solver='PPL')
|
|
741
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
742
|
+
sage: p.add_constraint(5/13*x[0] + x[1]/2 == 8/7)
|
|
743
|
+
sage: p.set_objective(5/13*x[0] + x[1]/2)
|
|
744
|
+
sage: p.solve()
|
|
745
|
+
8/7
|
|
746
|
+
|
|
747
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
748
|
+
sage: p = get_solver(solver = "PPL")
|
|
749
|
+
sage: p.add_variables(2)
|
|
750
|
+
1
|
|
751
|
+
sage: p.add_linear_constraint([(0,1), (1,2)], None, 3)
|
|
752
|
+
sage: p.set_objective([2, 5])
|
|
753
|
+
sage: p.solve()
|
|
754
|
+
0
|
|
755
|
+
sage: p.get_objective_value()
|
|
756
|
+
15/2
|
|
757
|
+
sage: p.get_variable_value(0)
|
|
758
|
+
0
|
|
759
|
+
sage: p.get_variable_value(1)
|
|
760
|
+
3/2
|
|
761
|
+
"""
|
|
762
|
+
ans = Rational(self.mip.optimal_value())
|
|
763
|
+
return ans / self.obj_denominator + self.obj_constant_term
|
|
764
|
+
|
|
765
|
+
cpdef get_variable_value(self, int variable):
|
|
766
|
+
"""
|
|
767
|
+
Return the value of a variable given by the solver.
|
|
768
|
+
|
|
769
|
+
.. NOTE::
|
|
770
|
+
|
|
771
|
+
Behaviour is undefined unless ``solve`` has been called before.
|
|
772
|
+
|
|
773
|
+
EXAMPLES::
|
|
774
|
+
|
|
775
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
776
|
+
sage: p = get_solver(solver = "PPL")
|
|
777
|
+
sage: p.add_variables(2)
|
|
778
|
+
1
|
|
779
|
+
sage: p.add_linear_constraint([(0,1), (1, 2)], None, 3)
|
|
780
|
+
sage: p.set_objective([2, 5])
|
|
781
|
+
sage: p.solve()
|
|
782
|
+
0
|
|
783
|
+
sage: p.get_objective_value()
|
|
784
|
+
15/2
|
|
785
|
+
sage: p.get_variable_value(0)
|
|
786
|
+
0
|
|
787
|
+
sage: p.get_variable_value(1)
|
|
788
|
+
3/2
|
|
789
|
+
"""
|
|
790
|
+
g = self.mip.optimizing_point()
|
|
791
|
+
return Integer(g.coefficient(Variable(variable))) / Integer(g.divisor())
|
|
792
|
+
|
|
793
|
+
cpdef int ncols(self) noexcept:
|
|
794
|
+
"""
|
|
795
|
+
Return the number of columns/variables.
|
|
796
|
+
|
|
797
|
+
EXAMPLES::
|
|
798
|
+
|
|
799
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
800
|
+
sage: p = get_solver(solver = "PPL")
|
|
801
|
+
sage: p.ncols()
|
|
802
|
+
0
|
|
803
|
+
sage: p.add_variables(2)
|
|
804
|
+
1
|
|
805
|
+
sage: p.ncols()
|
|
806
|
+
2
|
|
807
|
+
"""
|
|
808
|
+
return len(self.objective_function)
|
|
809
|
+
|
|
810
|
+
cpdef int nrows(self) noexcept:
|
|
811
|
+
"""
|
|
812
|
+
Return the number of rows/constraints.
|
|
813
|
+
|
|
814
|
+
EXAMPLES::
|
|
815
|
+
|
|
816
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
817
|
+
sage: p = get_solver(solver = "PPL")
|
|
818
|
+
sage: p.nrows()
|
|
819
|
+
0
|
|
820
|
+
sage: p.add_linear_constraints(2, 2.0, None)
|
|
821
|
+
sage: p.nrows()
|
|
822
|
+
2
|
|
823
|
+
"""
|
|
824
|
+
return len(self.Matrix)
|
|
825
|
+
|
|
826
|
+
cpdef bint is_maximization(self) noexcept:
|
|
827
|
+
"""
|
|
828
|
+
Test whether the problem is a maximization
|
|
829
|
+
|
|
830
|
+
EXAMPLES::
|
|
831
|
+
|
|
832
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
833
|
+
sage: p = get_solver(solver = "PPL")
|
|
834
|
+
sage: p.is_maximization()
|
|
835
|
+
True
|
|
836
|
+
sage: p.set_sense(-1)
|
|
837
|
+
sage: p.is_maximization()
|
|
838
|
+
False
|
|
839
|
+
"""
|
|
840
|
+
if self.is_maximize == 1:
|
|
841
|
+
return 1
|
|
842
|
+
else:
|
|
843
|
+
return 0
|
|
844
|
+
|
|
845
|
+
cpdef problem_name(self, name=None):
|
|
846
|
+
"""
|
|
847
|
+
Return or define the problem's name.
|
|
848
|
+
|
|
849
|
+
INPUT:
|
|
850
|
+
|
|
851
|
+
- ``name`` -- string; the problem's name. When set to
|
|
852
|
+
``None`` (default), the method returns the problem's name.
|
|
853
|
+
|
|
854
|
+
EXAMPLES::
|
|
855
|
+
|
|
856
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
857
|
+
sage: p = get_solver(solver = "PPL")
|
|
858
|
+
sage: p.problem_name("There once was a french fry")
|
|
859
|
+
sage: print(p.problem_name())
|
|
860
|
+
There once was a french fry
|
|
861
|
+
"""
|
|
862
|
+
if name is None:
|
|
863
|
+
return self.name
|
|
864
|
+
self.name = name
|
|
865
|
+
|
|
866
|
+
cpdef row(self, int i):
|
|
867
|
+
"""
|
|
868
|
+
Return a row.
|
|
869
|
+
|
|
870
|
+
INPUT:
|
|
871
|
+
|
|
872
|
+
- ``index`` -- integer; the constraint's id
|
|
873
|
+
|
|
874
|
+
OUTPUT:
|
|
875
|
+
|
|
876
|
+
A pair ``(indices, coeffs)`` where ``indices`` lists the
|
|
877
|
+
entries whose coefficient is nonzero, and to which ``coeffs``
|
|
878
|
+
associates their coefficient on the model of the
|
|
879
|
+
``add_linear_constraint`` method.
|
|
880
|
+
|
|
881
|
+
EXAMPLES::
|
|
882
|
+
|
|
883
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
884
|
+
sage: p = get_solver(solver = "PPL")
|
|
885
|
+
sage: p.add_variables(5)
|
|
886
|
+
4
|
|
887
|
+
sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2)
|
|
888
|
+
sage: p.row(0)
|
|
889
|
+
([1, 2, 3, 4], [1, 2, 3, 4])
|
|
890
|
+
sage: p.row_bounds(0)
|
|
891
|
+
(2, 2)
|
|
892
|
+
"""
|
|
893
|
+
idx = []
|
|
894
|
+
coef = []
|
|
895
|
+
for j in range(len(self.Matrix[i])):
|
|
896
|
+
if self.Matrix[i][j] != 0:
|
|
897
|
+
idx.append(j)
|
|
898
|
+
coef.append(self.Matrix[i][j])
|
|
899
|
+
return (idx, coef)
|
|
900
|
+
|
|
901
|
+
cpdef row_bounds(self, int index):
|
|
902
|
+
"""
|
|
903
|
+
Return the bounds of a specific constraint.
|
|
904
|
+
|
|
905
|
+
INPUT:
|
|
906
|
+
|
|
907
|
+
- ``index`` -- integer; the constraint's id
|
|
908
|
+
|
|
909
|
+
OUTPUT:
|
|
910
|
+
|
|
911
|
+
A pair ``(lower_bound, upper_bound)``. Each of them can be set
|
|
912
|
+
to ``None`` if the constraint is not bounded in the
|
|
913
|
+
corresponding direction, and is a real value otherwise.
|
|
914
|
+
|
|
915
|
+
EXAMPLES::
|
|
916
|
+
|
|
917
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
918
|
+
sage: p = get_solver(solver = "PPL")
|
|
919
|
+
sage: p.add_variables(5)
|
|
920
|
+
4
|
|
921
|
+
sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2)
|
|
922
|
+
sage: p.row(0)
|
|
923
|
+
([1, 2, 3, 4], [1, 2, 3, 4])
|
|
924
|
+
sage: p.row_bounds(0)
|
|
925
|
+
(2, 2)
|
|
926
|
+
"""
|
|
927
|
+
return (self.row_lower_bound[index], self.row_upper_bound[index])
|
|
928
|
+
|
|
929
|
+
cpdef col_bounds(self, int index):
|
|
930
|
+
"""
|
|
931
|
+
Return the bounds of a specific variable.
|
|
932
|
+
|
|
933
|
+
INPUT:
|
|
934
|
+
|
|
935
|
+
- ``index`` -- integer; the variable's id
|
|
936
|
+
|
|
937
|
+
OUTPUT:
|
|
938
|
+
|
|
939
|
+
A pair ``(lower_bound, upper_bound)``. Each of them can be set
|
|
940
|
+
to ``None`` if the variable is not bounded in the
|
|
941
|
+
corresponding direction, and is a real value otherwise.
|
|
942
|
+
|
|
943
|
+
EXAMPLES::
|
|
944
|
+
|
|
945
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
946
|
+
sage: p = get_solver(solver = "PPL")
|
|
947
|
+
sage: p.add_variable()
|
|
948
|
+
0
|
|
949
|
+
sage: p.col_bounds(0)
|
|
950
|
+
(0, None)
|
|
951
|
+
sage: p.variable_upper_bound(0, 5)
|
|
952
|
+
sage: p.col_bounds(0)
|
|
953
|
+
(0, 5)
|
|
954
|
+
"""
|
|
955
|
+
return (self.col_lower_bound[index], self.col_upper_bound[index])
|
|
956
|
+
|
|
957
|
+
cpdef bint is_variable_binary(self, int index) noexcept:
|
|
958
|
+
"""
|
|
959
|
+
Test whether the given variable is of binary type.
|
|
960
|
+
|
|
961
|
+
INPUT:
|
|
962
|
+
|
|
963
|
+
- ``index`` -- integer; the variable's id
|
|
964
|
+
|
|
965
|
+
EXAMPLES::
|
|
966
|
+
|
|
967
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
968
|
+
sage: p = get_solver(solver = "PPL")
|
|
969
|
+
sage: p.ncols()
|
|
970
|
+
0
|
|
971
|
+
sage: p.add_variable()
|
|
972
|
+
0
|
|
973
|
+
sage: p.is_variable_binary(0)
|
|
974
|
+
False
|
|
975
|
+
"""
|
|
976
|
+
return index in self.integer_variables and self.col_bounds(index) == (0, 1)
|
|
977
|
+
|
|
978
|
+
cpdef bint is_variable_integer(self, int index) noexcept:
|
|
979
|
+
"""
|
|
980
|
+
Test whether the given variable is of integer type.
|
|
981
|
+
|
|
982
|
+
INPUT:
|
|
983
|
+
|
|
984
|
+
- ``index`` -- integer; the variable's id
|
|
985
|
+
|
|
986
|
+
EXAMPLES::
|
|
987
|
+
|
|
988
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
989
|
+
sage: p = get_solver(solver = "PPL")
|
|
990
|
+
sage: p.ncols()
|
|
991
|
+
0
|
|
992
|
+
sage: p.add_variable()
|
|
993
|
+
0
|
|
994
|
+
sage: p.is_variable_integer(0)
|
|
995
|
+
False
|
|
996
|
+
"""
|
|
997
|
+
return index in self.integer_variables and self.col_bounds(index) != (0, 1)
|
|
998
|
+
|
|
999
|
+
cpdef bint is_variable_continuous(self, int index) noexcept:
|
|
1000
|
+
"""
|
|
1001
|
+
Test whether the given variable is of continuous/real type.
|
|
1002
|
+
|
|
1003
|
+
INPUT:
|
|
1004
|
+
|
|
1005
|
+
- ``index`` -- integer; the variable's id
|
|
1006
|
+
|
|
1007
|
+
EXAMPLES::
|
|
1008
|
+
|
|
1009
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1010
|
+
sage: p = get_solver(solver = "PPL")
|
|
1011
|
+
sage: p.ncols()
|
|
1012
|
+
0
|
|
1013
|
+
sage: p.add_variable()
|
|
1014
|
+
0
|
|
1015
|
+
sage: p.is_variable_continuous(0)
|
|
1016
|
+
True
|
|
1017
|
+
"""
|
|
1018
|
+
return index not in self.integer_variables
|
|
1019
|
+
|
|
1020
|
+
cpdef row_name(self, int index):
|
|
1021
|
+
"""
|
|
1022
|
+
Return the ``index``-th row name.
|
|
1023
|
+
|
|
1024
|
+
INPUT:
|
|
1025
|
+
|
|
1026
|
+
- ``index`` -- integer; the row's id
|
|
1027
|
+
|
|
1028
|
+
EXAMPLES::
|
|
1029
|
+
|
|
1030
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1031
|
+
sage: p = get_solver(solver = "PPL")
|
|
1032
|
+
sage: p.add_linear_constraints(1, 2, None, names=["Empty constraint 1"])
|
|
1033
|
+
sage: p.row_name(0)
|
|
1034
|
+
'Empty constraint 1'
|
|
1035
|
+
"""
|
|
1036
|
+
if self.row_name_var[index] is not None:
|
|
1037
|
+
return self.row_name_var[index]
|
|
1038
|
+
return "constraint_" + repr(index)
|
|
1039
|
+
|
|
1040
|
+
cpdef col_name(self, int index):
|
|
1041
|
+
"""
|
|
1042
|
+
Return the ``index``-th col name.
|
|
1043
|
+
|
|
1044
|
+
INPUT:
|
|
1045
|
+
|
|
1046
|
+
- ``index`` -- integer; the col's id
|
|
1047
|
+
|
|
1048
|
+
- ``name`` -- (``char *``) its name; when set to ``NULL``
|
|
1049
|
+
(default), the method returns the current name
|
|
1050
|
+
|
|
1051
|
+
EXAMPLES::
|
|
1052
|
+
|
|
1053
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1054
|
+
sage: p = get_solver(solver = "PPL")
|
|
1055
|
+
sage: p.add_variable(name="I am a variable")
|
|
1056
|
+
0
|
|
1057
|
+
sage: p.col_name(0)
|
|
1058
|
+
'I am a variable'
|
|
1059
|
+
"""
|
|
1060
|
+
if self.col_name_var[index] is not None:
|
|
1061
|
+
return self.col_name_var[index]
|
|
1062
|
+
return "x_" + repr(index)
|
|
1063
|
+
|
|
1064
|
+
cpdef variable_upper_bound(self, int index, value=False):
|
|
1065
|
+
"""
|
|
1066
|
+
Return or define the upper bound on a variable.
|
|
1067
|
+
|
|
1068
|
+
INPUT:
|
|
1069
|
+
|
|
1070
|
+
- ``index`` -- integer; the variable's id
|
|
1071
|
+
|
|
1072
|
+
- ``value`` -- real value, or ``None`` to mean that the
|
|
1073
|
+
variable has not upper bound. When set to ``False``
|
|
1074
|
+
(default), the method returns the current value.
|
|
1075
|
+
|
|
1076
|
+
EXAMPLES::
|
|
1077
|
+
|
|
1078
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1079
|
+
sage: p = get_solver(solver = "PPL")
|
|
1080
|
+
sage: p.add_variable()
|
|
1081
|
+
0
|
|
1082
|
+
sage: p.col_bounds(0)
|
|
1083
|
+
(0, None)
|
|
1084
|
+
sage: p.variable_upper_bound(0, 5)
|
|
1085
|
+
sage: p.col_bounds(0)
|
|
1086
|
+
(0, 5)
|
|
1087
|
+
sage: p.variable_upper_bound(0, None)
|
|
1088
|
+
sage: p.col_bounds(0)
|
|
1089
|
+
(0, None)
|
|
1090
|
+
"""
|
|
1091
|
+
if value is not False:
|
|
1092
|
+
self.col_upper_bound[index] = value
|
|
1093
|
+
else:
|
|
1094
|
+
return self.col_upper_bound[index]
|
|
1095
|
+
|
|
1096
|
+
cpdef variable_lower_bound(self, int index, value=False):
|
|
1097
|
+
"""
|
|
1098
|
+
Return or define the lower bound on a variable.
|
|
1099
|
+
|
|
1100
|
+
INPUT:
|
|
1101
|
+
|
|
1102
|
+
- ``index`` -- integer; the variable's id
|
|
1103
|
+
|
|
1104
|
+
- ``value`` -- real value, or ``None`` to mean that the
|
|
1105
|
+
variable has not lower bound. When set to ``False``
|
|
1106
|
+
(default), the method returns the current value.
|
|
1107
|
+
|
|
1108
|
+
EXAMPLES::
|
|
1109
|
+
|
|
1110
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1111
|
+
sage: p = get_solver(solver = "PPL")
|
|
1112
|
+
sage: p.add_variable()
|
|
1113
|
+
0
|
|
1114
|
+
sage: p.col_bounds(0)
|
|
1115
|
+
(0, None)
|
|
1116
|
+
sage: p.variable_lower_bound(0, 5)
|
|
1117
|
+
sage: p.col_bounds(0)
|
|
1118
|
+
(5, None)
|
|
1119
|
+
sage: p.variable_lower_bound(0, None)
|
|
1120
|
+
sage: p.col_bounds(0)
|
|
1121
|
+
(None, None)
|
|
1122
|
+
"""
|
|
1123
|
+
if value is not False:
|
|
1124
|
+
self.col_lower_bound[index] = value
|
|
1125
|
+
else:
|
|
1126
|
+
return self.col_lower_bound[index]
|