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.
Files changed (209) hide show
  1. passagemath_polyhedra/__init__.py +3 -0
  2. passagemath_polyhedra-10.6.37.dist-info/METADATA +367 -0
  3. passagemath_polyhedra-10.6.37.dist-info/METADATA.bak +369 -0
  4. passagemath_polyhedra-10.6.37.dist-info/RECORD +209 -0
  5. passagemath_polyhedra-10.6.37.dist-info/WHEEL +5 -0
  6. passagemath_polyhedra-10.6.37.dist-info/top_level.txt +3 -0
  7. passagemath_polyhedra.libs/libgcc_s-0cd532bd.so.1 +0 -0
  8. passagemath_polyhedra.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
  9. passagemath_polyhedra.libs/libgomp-8949ffbe.so.1.0.0 +0 -0
  10. passagemath_polyhedra.libs/libstdc++-5d72f927.so.6.0.33 +0 -0
  11. sage/all__sagemath_polyhedra.py +50 -0
  12. sage/game_theory/all.py +8 -0
  13. sage/game_theory/catalog.py +6 -0
  14. sage/game_theory/catalog_normal_form_games.py +923 -0
  15. sage/game_theory/cooperative_game.py +844 -0
  16. sage/game_theory/matching_game.py +1181 -0
  17. sage/game_theory/normal_form_game.py +2697 -0
  18. sage/game_theory/parser.py +275 -0
  19. sage/geometry/all__sagemath_polyhedra.py +22 -0
  20. sage/geometry/cone.py +6940 -0
  21. sage/geometry/cone_catalog.py +847 -0
  22. sage/geometry/cone_critical_angles.py +1027 -0
  23. sage/geometry/convex_set.py +1119 -0
  24. sage/geometry/fan.py +3743 -0
  25. sage/geometry/fan_isomorphism.py +389 -0
  26. sage/geometry/fan_morphism.py +1884 -0
  27. sage/geometry/hasse_diagram.py +202 -0
  28. sage/geometry/hyperplane_arrangement/affine_subspace.py +390 -0
  29. sage/geometry/hyperplane_arrangement/all.py +1 -0
  30. sage/geometry/hyperplane_arrangement/arrangement.py +3905 -0
  31. sage/geometry/hyperplane_arrangement/check_freeness.py +145 -0
  32. sage/geometry/hyperplane_arrangement/hyperplane.py +773 -0
  33. sage/geometry/hyperplane_arrangement/library.py +825 -0
  34. sage/geometry/hyperplane_arrangement/ordered_arrangement.py +642 -0
  35. sage/geometry/hyperplane_arrangement/plot.py +520 -0
  36. sage/geometry/integral_points.py +35 -0
  37. sage/geometry/integral_points_generic_dense.cpython-314-x86_64-linux-musl.so +0 -0
  38. sage/geometry/integral_points_generic_dense.pyx +7 -0
  39. sage/geometry/lattice_polytope.py +5894 -0
  40. sage/geometry/linear_expression.py +773 -0
  41. sage/geometry/newton_polygon.py +767 -0
  42. sage/geometry/point_collection.cpython-314-x86_64-linux-musl.so +0 -0
  43. sage/geometry/point_collection.pyx +1008 -0
  44. sage/geometry/polyhedral_complex.py +2616 -0
  45. sage/geometry/polyhedron/all.py +8 -0
  46. sage/geometry/polyhedron/backend_cdd.py +460 -0
  47. sage/geometry/polyhedron/backend_cdd_rdf.py +231 -0
  48. sage/geometry/polyhedron/backend_field.py +347 -0
  49. sage/geometry/polyhedron/backend_normaliz.py +2503 -0
  50. sage/geometry/polyhedron/backend_number_field.py +168 -0
  51. sage/geometry/polyhedron/backend_polymake.py +765 -0
  52. sage/geometry/polyhedron/backend_ppl.py +582 -0
  53. sage/geometry/polyhedron/base.py +1206 -0
  54. sage/geometry/polyhedron/base0.py +1444 -0
  55. sage/geometry/polyhedron/base1.py +886 -0
  56. sage/geometry/polyhedron/base2.py +812 -0
  57. sage/geometry/polyhedron/base3.py +1845 -0
  58. sage/geometry/polyhedron/base4.py +1262 -0
  59. sage/geometry/polyhedron/base5.py +2700 -0
  60. sage/geometry/polyhedron/base6.py +1741 -0
  61. sage/geometry/polyhedron/base7.py +997 -0
  62. sage/geometry/polyhedron/base_QQ.py +1258 -0
  63. sage/geometry/polyhedron/base_RDF.py +98 -0
  64. sage/geometry/polyhedron/base_ZZ.py +934 -0
  65. sage/geometry/polyhedron/base_mutable.py +215 -0
  66. sage/geometry/polyhedron/base_number_field.py +122 -0
  67. sage/geometry/polyhedron/cdd_file_format.py +155 -0
  68. sage/geometry/polyhedron/combinatorial_polyhedron/all.py +1 -0
  69. sage/geometry/polyhedron/combinatorial_polyhedron/base.cpython-314-x86_64-linux-musl.so +0 -0
  70. sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +76 -0
  71. sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +3859 -0
  72. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.cpython-314-x86_64-linux-musl.so +0 -0
  73. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +39 -0
  74. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +1038 -0
  75. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.cpython-314-x86_64-linux-musl.so +0 -0
  76. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pxd +9 -0
  77. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +501 -0
  78. sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +207 -0
  79. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.cpython-314-x86_64-linux-musl.so +0 -0
  80. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +102 -0
  81. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +2274 -0
  82. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.cpython-314-x86_64-linux-musl.so +0 -0
  83. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +370 -0
  84. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +84 -0
  85. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.cpython-314-x86_64-linux-musl.so +0 -0
  86. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +31 -0
  87. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +587 -0
  88. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.cpython-314-x86_64-linux-musl.so +0 -0
  89. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +52 -0
  90. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +560 -0
  91. sage/geometry/polyhedron/constructor.py +773 -0
  92. sage/geometry/polyhedron/double_description.py +753 -0
  93. sage/geometry/polyhedron/double_description_inhomogeneous.py +564 -0
  94. sage/geometry/polyhedron/face.py +1060 -0
  95. sage/geometry/polyhedron/generating_function.py +1810 -0
  96. sage/geometry/polyhedron/lattice_euclidean_group_element.py +178 -0
  97. sage/geometry/polyhedron/library.py +3502 -0
  98. sage/geometry/polyhedron/misc.py +121 -0
  99. sage/geometry/polyhedron/modules/all.py +1 -0
  100. sage/geometry/polyhedron/modules/formal_polyhedra_module.py +155 -0
  101. sage/geometry/polyhedron/palp_database.py +447 -0
  102. sage/geometry/polyhedron/parent.py +1279 -0
  103. sage/geometry/polyhedron/plot.py +1986 -0
  104. sage/geometry/polyhedron/ppl_lattice_polygon.py +556 -0
  105. sage/geometry/polyhedron/ppl_lattice_polytope.py +1257 -0
  106. sage/geometry/polyhedron/representation.py +1723 -0
  107. sage/geometry/pseudolines.py +515 -0
  108. sage/geometry/relative_interior.py +445 -0
  109. sage/geometry/toric_plotter.py +1103 -0
  110. sage/geometry/triangulation/all.py +2 -0
  111. sage/geometry/triangulation/base.cpython-314-x86_64-linux-musl.so +0 -0
  112. sage/geometry/triangulation/base.pyx +963 -0
  113. sage/geometry/triangulation/data.h +147 -0
  114. sage/geometry/triangulation/data.pxd +4 -0
  115. sage/geometry/triangulation/element.py +914 -0
  116. sage/geometry/triangulation/functions.h +10 -0
  117. sage/geometry/triangulation/functions.pxd +4 -0
  118. sage/geometry/triangulation/point_configuration.py +2256 -0
  119. sage/geometry/triangulation/triangulations.h +49 -0
  120. sage/geometry/triangulation/triangulations.pxd +7 -0
  121. sage/geometry/voronoi_diagram.py +319 -0
  122. sage/interfaces/all__sagemath_polyhedra.py +1 -0
  123. sage/interfaces/polymake.py +2028 -0
  124. sage/numerical/all.py +13 -0
  125. sage/numerical/all__sagemath_polyhedra.py +11 -0
  126. sage/numerical/backends/all.py +1 -0
  127. sage/numerical/backends/all__sagemath_polyhedra.py +1 -0
  128. sage/numerical/backends/cvxopt_backend.cpython-314-x86_64-linux-musl.so +0 -0
  129. sage/numerical/backends/cvxopt_backend.pyx +1006 -0
  130. sage/numerical/backends/cvxopt_backend_test.py +19 -0
  131. sage/numerical/backends/cvxopt_sdp_backend.cpython-314-x86_64-linux-musl.so +0 -0
  132. sage/numerical/backends/cvxopt_sdp_backend.pyx +382 -0
  133. sage/numerical/backends/cvxpy_backend.cpython-314-x86_64-linux-musl.so +0 -0
  134. sage/numerical/backends/cvxpy_backend.pxd +41 -0
  135. sage/numerical/backends/cvxpy_backend.pyx +934 -0
  136. sage/numerical/backends/cvxpy_backend_test.py +13 -0
  137. sage/numerical/backends/generic_backend_test.py +24 -0
  138. sage/numerical/backends/interactivelp_backend.cpython-314-x86_64-linux-musl.so +0 -0
  139. sage/numerical/backends/interactivelp_backend.pxd +36 -0
  140. sage/numerical/backends/interactivelp_backend.pyx +1231 -0
  141. sage/numerical/backends/interactivelp_backend_test.py +12 -0
  142. sage/numerical/backends/logging_backend.py +391 -0
  143. sage/numerical/backends/matrix_sdp_backend.cpython-314-x86_64-linux-musl.so +0 -0
  144. sage/numerical/backends/matrix_sdp_backend.pxd +15 -0
  145. sage/numerical/backends/matrix_sdp_backend.pyx +478 -0
  146. sage/numerical/backends/ppl_backend.cpython-314-x86_64-linux-musl.so +0 -0
  147. sage/numerical/backends/ppl_backend.pyx +1126 -0
  148. sage/numerical/backends/ppl_backend_test.py +13 -0
  149. sage/numerical/backends/scip_backend.cpython-314-x86_64-linux-musl.so +0 -0
  150. sage/numerical/backends/scip_backend.pxd +22 -0
  151. sage/numerical/backends/scip_backend.pyx +1289 -0
  152. sage/numerical/backends/scip_backend_test.py +13 -0
  153. sage/numerical/interactive_simplex_method.py +5338 -0
  154. sage/numerical/knapsack.py +665 -0
  155. sage/numerical/linear_functions.cpython-314-x86_64-linux-musl.so +0 -0
  156. sage/numerical/linear_functions.pxd +31 -0
  157. sage/numerical/linear_functions.pyx +1648 -0
  158. sage/numerical/linear_tensor.py +470 -0
  159. sage/numerical/linear_tensor_constraints.py +448 -0
  160. sage/numerical/linear_tensor_element.cpython-314-x86_64-linux-musl.so +0 -0
  161. sage/numerical/linear_tensor_element.pxd +6 -0
  162. sage/numerical/linear_tensor_element.pyx +459 -0
  163. sage/numerical/mip.cpython-314-x86_64-linux-musl.so +0 -0
  164. sage/numerical/mip.pxd +40 -0
  165. sage/numerical/mip.pyx +3667 -0
  166. sage/numerical/sdp.cpython-314-x86_64-linux-musl.so +0 -0
  167. sage/numerical/sdp.pxd +39 -0
  168. sage/numerical/sdp.pyx +1433 -0
  169. sage/rings/all__sagemath_polyhedra.py +3 -0
  170. sage/rings/polynomial/all__sagemath_polyhedra.py +10 -0
  171. sage/rings/polynomial/omega.py +982 -0
  172. sage/schemes/all__sagemath_polyhedra.py +2 -0
  173. sage/schemes/toric/all.py +10 -0
  174. sage/schemes/toric/chow_group.py +1248 -0
  175. sage/schemes/toric/divisor.py +2082 -0
  176. sage/schemes/toric/divisor_class.cpython-314-x86_64-linux-musl.so +0 -0
  177. sage/schemes/toric/divisor_class.pyx +322 -0
  178. sage/schemes/toric/fano_variety.py +1606 -0
  179. sage/schemes/toric/homset.py +650 -0
  180. sage/schemes/toric/ideal.py +451 -0
  181. sage/schemes/toric/library.py +1322 -0
  182. sage/schemes/toric/morphism.py +1958 -0
  183. sage/schemes/toric/points.py +1032 -0
  184. sage/schemes/toric/sheaf/all.py +1 -0
  185. sage/schemes/toric/sheaf/constructor.py +302 -0
  186. sage/schemes/toric/sheaf/klyachko.py +921 -0
  187. sage/schemes/toric/toric_subscheme.py +905 -0
  188. sage/schemes/toric/variety.py +3460 -0
  189. sage/schemes/toric/weierstrass.py +1078 -0
  190. sage/schemes/toric/weierstrass_covering.py +457 -0
  191. sage/schemes/toric/weierstrass_higher.py +288 -0
  192. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.info +10 -0
  193. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v03 +0 -0
  194. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v04 +0 -0
  195. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v05 +1 -0
  196. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v06 +1 -0
  197. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.info +22 -0
  198. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v04 +0 -0
  199. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v05 +0 -0
  200. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v06 +0 -0
  201. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v07 +0 -0
  202. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v08 +0 -0
  203. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v09 +0 -0
  204. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v10 +0 -0
  205. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v11 +1 -0
  206. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v12 +1 -0
  207. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v13 +1 -0
  208. sage_wheels/share/reflexive_polytopes/reflexive_polytopes_2d +80 -0
  209. sage_wheels/share/reflexive_polytopes/reflexive_polytopes_3d +37977 -0
@@ -0,0 +1,1648 @@
1
+ # sage_setup: distribution = sagemath-polyhedra
2
+ """
3
+ Linear Functions and Constraints
4
+
5
+ This module implements linear functions (see :class:`LinearFunction`)
6
+ in formal variables and chained (in)equalities between them (see
7
+ :class:`LinearConstraint`). By convention, these are always written as
8
+ either equalities or less-or-equal. For example::
9
+
10
+ sage: p = MixedIntegerLinearProgram()
11
+ sage: x = p.new_variable()
12
+ sage: f = 1 + x[1] + 2*x[2]; f # a linear function
13
+ 1 + x_0 + 2*x_1
14
+ sage: type(f)
15
+ <class 'sage.numerical.linear_functions.LinearFunction'>
16
+
17
+ sage: c = (0 <= f); c # a constraint
18
+ 0 <= 1 + x_0 + 2*x_1
19
+ sage: type(c)
20
+ <class 'sage.numerical.linear_functions.LinearConstraint'>
21
+
22
+ Note that you can use this module without any reference to linear
23
+ programming, it only implements linear functions over a base ring and
24
+ constraints. However, for ease of demonstration we will always
25
+ construct them out of linear programs (see
26
+ :mod:`~sage.numerical.mip`).
27
+
28
+ Constraints can be equations or (non-strict) inequalities. They can be
29
+ chained::
30
+
31
+ sage: p = MixedIntegerLinearProgram()
32
+ sage: x = p.new_variable()
33
+ sage: x[0] == x[1] == x[2] == x[3]
34
+ x_0 == x_1 == x_2 == x_3
35
+
36
+ sage: ieq_01234 = x[0] <= x[1] <= x[2] <= x[3] <= x[4]
37
+ sage: ieq_01234
38
+ x_0 <= x_1 <= x_2 <= x_3 <= x_4
39
+
40
+ If necessary, the direction of inequality is flipped to always write
41
+ inequalities as less or equal::
42
+
43
+ sage: x[5] >= ieq_01234
44
+ x_0 <= x_1 <= x_2 <= x_3 <= x_4 <= x_5
45
+
46
+ sage: (x[5] <= x[6]) >= ieq_01234
47
+ x_0 <= x_1 <= x_2 <= x_3 <= x_4 <= x_5 <= x_6
48
+ sage: (x[5] <= x[6]) <= ieq_01234
49
+ x_5 <= x_6 <= x_0 <= x_1 <= x_2 <= x_3 <= x_4
50
+
51
+ .. WARNING::
52
+
53
+ The implementation of chained inequalities uses a Python hack to
54
+ make it work, so it is not completely robust. In particular, while
55
+ constants are allowed, no two constants can appear next to
56
+ each other. The following does not work for example::
57
+
58
+ sage: x[0] <= 3 <= 4
59
+ True
60
+
61
+ If you really need this for some reason, you can explicitly convert
62
+ the constants to a :class:`LinearFunction`::
63
+
64
+ sage: from sage.numerical.linear_functions import LinearFunctionsParent
65
+ sage: LF = LinearFunctionsParent(QQ)
66
+ sage: x[1] <= LF(3) <= LF(4)
67
+ x_1 <= 3 <= 4
68
+
69
+ TESTS:
70
+
71
+ This was fixed in :issue:`24423`::
72
+
73
+ sage: p.<x> = MixedIntegerLinearProgram()
74
+ sage: from sage.numerical.linear_functions import LinearFunctionsParent
75
+ sage: LF = LinearFunctionsParent(QQ)
76
+ sage: 3 <= x[0] <= LF(4)
77
+ 3 <= x_0 <= 4
78
+
79
+ See :issue:`12091`::
80
+
81
+ sage: p = MixedIntegerLinearProgram()
82
+ sage: b = p.new_variable()
83
+ sage: b[0] <= b[1] <= 2
84
+ x_0 <= x_1 <= 2
85
+ sage: list(b[0] <= b[1] <= 2)
86
+ [x_0, x_1, 2]
87
+ sage: 1 >= b[1] >= 2*b[0]
88
+ 2*x_0 <= x_1 <= 1
89
+ sage: b[2] >= b[1] >= 2*b[0]
90
+ 2*x_0 <= x_1 <= x_2
91
+ """
92
+
93
+ # ****************************************************************************
94
+ # Copyright (C) 2012 Nathann Cohen <nathann.cohen@gmail.com>
95
+ # Copyright (C) 2012 Volker Braun <vbraun.name@gmail.com>
96
+ # Copyright (C) 2016 Jeroen Demeyer <jdemeyer@cage.ugent.be>
97
+ #
98
+ # This program is free software: you can redistribute it and/or modify
99
+ # it under the terms of the GNU General Public License as published by
100
+ # the Free Software Foundation, either version 2 of the License, or
101
+ # (at your option) any later version.
102
+ # https://www.gnu.org/licenses/
103
+ # ****************************************************************************
104
+
105
+ from cpython.object cimport Py_EQ, Py_GE, Py_LE, Py_GT, Py_LT
106
+
107
+ from sage.misc.fast_methods cimport hash_by_id
108
+ from sage.structure.parent cimport Parent
109
+ from sage.structure.element cimport ModuleElement, Element
110
+ from sage.misc.cachefunc import cached_function
111
+
112
+ #*****************************************************************************
113
+ #
114
+ # Utility functions to test that something is a linear function / constraint
115
+ #
116
+ #*****************************************************************************
117
+
118
+ cpdef is_LinearFunction(x):
119
+ """
120
+ Test whether ``x`` is a linear function.
121
+
122
+ INPUT:
123
+
124
+ - ``x`` -- anything
125
+
126
+ OUTPUT: boolean
127
+
128
+ EXAMPLES::
129
+
130
+ sage: p = MixedIntegerLinearProgram()
131
+ sage: x = p.new_variable()
132
+ sage: from sage.numerical.linear_functions import is_LinearFunction
133
+ sage: is_LinearFunction(x[0] - 2*x[2])
134
+ doctest:warning...
135
+ DeprecationWarning: The function is_LinearFunction is deprecated;
136
+ use 'isinstance(..., LinearFunction)' instead.
137
+ See https://github.com/sagemath/sage/issues/38184 for details.
138
+ True
139
+ sage: is_LinearFunction('a string')
140
+ False
141
+ """
142
+ from sage.misc.superseded import deprecation_cython
143
+ deprecation_cython(38184,
144
+ "The function is_LinearFunction is deprecated; "
145
+ "use 'isinstance(..., LinearFunction)' instead.")
146
+ return isinstance(x, LinearFunction)
147
+
148
+
149
+ def is_LinearConstraint(x):
150
+ """
151
+ Test whether ``x`` is a linear constraint.
152
+
153
+ INPUT:
154
+
155
+ - ``x`` -- anything
156
+
157
+ OUTPUT: boolean
158
+
159
+ EXAMPLES::
160
+
161
+ sage: p = MixedIntegerLinearProgram()
162
+ sage: x = p.new_variable()
163
+ sage: ieq = (x[0] <= x[1])
164
+ sage: from sage.numerical.linear_functions import is_LinearConstraint
165
+ sage: is_LinearConstraint(ieq)
166
+ doctest:warning...
167
+ DeprecationWarning: The function is_LinearConstraint is deprecated;
168
+ use 'isinstance(..., LinearConstraint)' instead.
169
+ See https://github.com/sagemath/sage/issues/38184 for details.
170
+ True
171
+ sage: is_LinearConstraint('a string')
172
+ False
173
+ """
174
+ from sage.misc.superseded import deprecation_cython
175
+ deprecation_cython(38184,
176
+ "The function is_LinearConstraint is deprecated; "
177
+ "use 'isinstance(..., LinearConstraint)' instead.")
178
+ return isinstance(x, LinearConstraint)
179
+
180
+
181
+ # ****************************************************************************
182
+ #
183
+ # Factory functions for the parents to ensure uniqueness
184
+ #
185
+ # ****************************************************************************
186
+
187
+ @cached_function
188
+ def LinearFunctionsParent(base_ring):
189
+ """
190
+ Return the parent for linear functions over ``base_ring``.
191
+
192
+ The output is cached, so only a single parent is ever constructed
193
+ for a given base ring.
194
+
195
+ INPUT:
196
+
197
+ - ``base_ring`` -- a ring; the coefficient ring for the linear
198
+ functions
199
+
200
+ OUTPUT: the parent of the linear functions over ``base_ring``
201
+
202
+ EXAMPLES::
203
+
204
+ sage: from sage.numerical.linear_functions import LinearFunctionsParent
205
+ sage: LinearFunctionsParent(QQ)
206
+ Linear functions over Rational Field
207
+ """
208
+ return LinearFunctionsParent_class(base_ring)
209
+
210
+
211
+ @cached_function
212
+ def LinearConstraintsParent(linear_functions_parent):
213
+ """
214
+ Return the parent for linear functions over ``base_ring``.
215
+
216
+ The output is cached, so only a single parent is ever constructed
217
+ for a given base ring.
218
+
219
+ INPUT:
220
+
221
+ - ``linear_functions_parent`` -- a
222
+ :class:`LinearFunctionsParent_class`; the type of linear
223
+ functions that the constraints are made out of
224
+
225
+ OUTPUT: the parent of the linear constraints with the given linear functions
226
+
227
+ EXAMPLES::
228
+
229
+ sage: from sage.numerical.linear_functions import (
230
+ ....: LinearFunctionsParent, LinearConstraintsParent)
231
+ sage: LF = LinearFunctionsParent(QQ)
232
+ sage: LinearConstraintsParent(LF)
233
+ Linear constraints over Rational Field
234
+ """
235
+ return LinearConstraintsParent_class(linear_functions_parent)
236
+
237
+
238
+ # ****************************************************************************
239
+ #
240
+ # Elements of linear functions or constraints
241
+ #
242
+ # ****************************************************************************
243
+
244
+ cdef chained_comparator_left = None
245
+ cdef chained_comparator_right = None
246
+ cdef LinearConstraint chained_comparator_replace = None
247
+
248
+ cdef class LinearFunctionOrConstraint(ModuleElement):
249
+ """
250
+ Base class for :class:`LinearFunction` and :class:`LinearConstraint`.
251
+
252
+ This class exists solely to implement chaining of inequalities
253
+ in constraints.
254
+ """
255
+ def __richcmp__(self, other, int op):
256
+ """
257
+ Create an inequality or equality object, possibly chaining
258
+ several together.
259
+
260
+ EXAMPLES::
261
+
262
+ sage: p.<x> = MixedIntegerLinearProgram()
263
+ sage: x[0].__le__(x[1])
264
+ x_0 <= x_1
265
+
266
+ ::
267
+
268
+ sage: p = MixedIntegerLinearProgram()
269
+ sage: LF = p.linear_functions_parent()
270
+ sage: from sage.numerical.linear_functions import LinearFunction
271
+ sage: LF({2 : 5, 3 : 2}) <= LF({2 : 3, 9 : 2})
272
+ 5*x_2 + 2*x_3 <= 3*x_2 + 2*x_9
273
+
274
+ sage: LF({2 : 5, 3 : 2}) >= LF({2 : 3, 9 : 2})
275
+ 3*x_2 + 2*x_9 <= 5*x_2 + 2*x_3
276
+
277
+ sage: LF({2 : 5, 3 : 2}) == LF({2 : 3, 9 : 2})
278
+ 5*x_2 + 2*x_3 == 3*x_2 + 2*x_9
279
+
280
+ We can chain multiple (in)equalities::
281
+
282
+ sage: p.<b> = MixedIntegerLinearProgram()
283
+ sage: b[0] == 1 == b[1] == 2 == b[2] == 3
284
+ x_0 == 1 == x_1 == 2 == x_2 == 3
285
+ sage: b[0] <= 1 <= b[1] <= 2 <= b[2] <= 3
286
+ x_0 <= 1 <= x_1 <= 2 <= x_2 <= 3
287
+ sage: b[0] <= b[1] <= b[2] <= b[3]
288
+ x_0 <= x_1 <= x_2 <= x_3
289
+
290
+ Other comparison operators are not allowed::
291
+
292
+ sage: b[0] < b[1]
293
+ Traceback (most recent call last):
294
+ ...
295
+ ValueError: strict < is not allowed, use <= instead
296
+ sage: b[0] > b[1]
297
+ Traceback (most recent call last):
298
+ ...
299
+ ValueError: strict > is not allowed, use >= instead
300
+ sage: b[0] != b[1]
301
+ Traceback (most recent call last):
302
+ ...
303
+ ValueError: inequality != is not allowed, use one of <=, ==, >=
304
+
305
+ Mixing operators is also not allowed::
306
+
307
+ sage: 1 <= b[1] >= 2
308
+ Traceback (most recent call last):
309
+ ...
310
+ ValueError: incorrectly chained inequality
311
+ sage: 1 >= b[1] <= 2
312
+ Traceback (most recent call last):
313
+ ...
314
+ ValueError: incorrectly chained inequality
315
+ sage: 1 == b[1] <= 2
316
+ Traceback (most recent call last):
317
+ ...
318
+ ValueError: cannot mix equations and inequalities
319
+ sage: 1 >= b[1] == 2
320
+ Traceback (most recent call last):
321
+ ...
322
+ ValueError: cannot mix equations and inequalities
323
+
324
+ TESTS::
325
+
326
+ sage: p.<x> = MixedIntegerLinearProgram()
327
+ sage: LF = p.linear_functions_parent()
328
+ sage: cm = sage.structure.element.get_coercion_model()
329
+ sage: cm.explain(10, LF(1), operator.le)
330
+ Coercion on left operand via
331
+ Coercion map:
332
+ From: Integer Ring
333
+ To: Linear functions over Real Double Field
334
+ Arithmetic performed after coercions.
335
+ Result lives in Linear functions over Real Double Field
336
+ Linear functions over Real Double Field
337
+
338
+ sage: operator.le(10, x[0])
339
+ 10 <= x_0
340
+ sage: x[0] <= 1
341
+ x_0 <= 1
342
+ sage: x[0] >= 1
343
+ 1 <= x_0
344
+ sage: 1 <= x[0]
345
+ 1 <= x_0
346
+ sage: 1 >= x[0]
347
+ x_0 <= 1
348
+
349
+ This works with non-Sage types too, see :issue:`14540`::
350
+
351
+ sage: p.<b> = MixedIntegerLinearProgram()
352
+ sage: int(1) <= b[0] <= int(2)
353
+ 1 <= x_0 <= 2
354
+ sage: int(1) >= b[0] >= int(2)
355
+ 2 <= x_0 <= 1
356
+ sage: int(1) == b[0] == int(2)
357
+ 1 == x_0 == 2
358
+ sage: float(0) <= b[0] <= int(1) <= b[1] <= float(2)
359
+ 0 <= x_0 <= 1 <= x_1 <= 2
360
+ """
361
+ # Store the chaining variables and set them to None for now in
362
+ # order to have a sane state for any conversions below or when
363
+ # an exception is raised.
364
+ global chained_comparator_left
365
+ global chained_comparator_right
366
+ global chained_comparator_replace
367
+
368
+ chain_left = chained_comparator_left
369
+ chain_right = chained_comparator_right
370
+ chain_replace = chained_comparator_replace
371
+
372
+ chained_comparator_left = None
373
+ chained_comparator_right = None
374
+ chained_comparator_replace = None
375
+
376
+ # Assign {self, other} to {py_left, py_right} such that
377
+ # py_left <= py_right.
378
+ cdef bint equality = False
379
+ if op == Py_LE:
380
+ py_left, py_right = self, other
381
+ elif op == Py_GE:
382
+ py_left, py_right = other, self
383
+ elif op == Py_EQ:
384
+ py_left, py_right = self, other
385
+ equality = True
386
+ elif op == Py_LT:
387
+ raise ValueError("strict < is not allowed, use <= instead")
388
+ elif op == Py_GT:
389
+ raise ValueError("strict > is not allowed, use >= instead")
390
+ else:
391
+ raise ValueError("inequality != is not allowed, use one of <=, ==, >=")
392
+
393
+ # Convert py_left and py_right to constraints left and right,
394
+ # possibly replacing them to implement the hack below.
395
+ cdef LinearConstraint left = None
396
+ cdef LinearConstraint right = None
397
+
398
+ # HACK to allow chained constraints: Python translates
399
+ # x <= y <= z into:
400
+ #
401
+ # temp = x <= y # calls x.__richcmp__(y)
402
+ # if temp: # calls temp.__bool__()
403
+ # return y <= z # calls y.__richcmp__(z)
404
+ # else:
405
+ # return temp
406
+ #
407
+ # or, if x <= y is not implemented (for example, if x is a
408
+ # non-Sage type):
409
+ #
410
+ # temp = y >= x # calls y.__richcmp__(x)
411
+ # if temp: # calls temp.__bool__()
412
+ # return y <= z # calls y.__richcmp__(z)
413
+ # else:
414
+ # return temp
415
+ #
416
+ # but we would like x <= y <= z as output. The trick to make it
417
+ # work is to store x and y in the first call to __richcmp__
418
+ # and temp in the call to __bool__. Then we can replace x
419
+ # or y by x <= y in the second call to __richcmp__.
420
+ if chain_replace is not None:
421
+ if chain_replace.equality != equality:
422
+ raise ValueError("cannot mix equations and inequalities")
423
+
424
+ # First, check for correctly-chained inequalities
425
+ # x <= y <= z or z <= y <= x.
426
+ if py_left is chain_right:
427
+ left = chain_replace
428
+ elif py_right is chain_left:
429
+ right = chain_replace
430
+ # Next, check for incorrectly chained inequalities like
431
+ # x <= y >= z. If we are dealing with inequalities, this
432
+ # is an error. For an equality, we fix the chaining by
433
+ # reversing one of the sides.
434
+ elif py_left is chain_left:
435
+ if not equality:
436
+ raise ValueError("incorrectly chained inequality")
437
+ chain_replace.constraints.reverse()
438
+ left = chain_replace
439
+ elif py_right is chain_right:
440
+ if not equality:
441
+ raise ValueError("incorrectly chained inequality")
442
+ left = chain_replace
443
+ py_right = py_left
444
+
445
+ # Figure out the correct parent to work with: if we did a
446
+ # replacement, its parent takes priority.
447
+ if left is not None:
448
+ LC = left._parent
449
+ elif right is not None:
450
+ LC = right._parent
451
+ else:
452
+ LC = (<LinearFunctionOrConstraint>self)._parent
453
+
454
+ # We want the parent to be a LinearConstraintsParent
455
+ if not isinstance(LC, LinearConstraintsParent_class):
456
+ LC = LinearConstraintsParent(LC)
457
+
458
+ if left is None:
459
+ try:
460
+ left = <LinearConstraint?>py_left
461
+ except TypeError:
462
+ left = <LinearConstraint>LC(py_left, equality=equality)
463
+ else:
464
+ if left._parent is not LC:
465
+ left = <LinearConstraint>LC(left.constraints, equality=left.equality)
466
+
467
+ if right is None:
468
+ try:
469
+ right = <LinearConstraint?>py_right
470
+ except TypeError:
471
+ right = <LinearConstraint>LC(py_right, equality=equality)
472
+ else:
473
+ if right._parent is not LC:
474
+ right = <LinearConstraint>LC(right.constraints, equality=right.equality)
475
+
476
+ # Finally, chain the (in)equalities
477
+ if left.equality != equality or right.equality != equality:
478
+ raise ValueError("cannot mix equations and inequalities")
479
+ ret = LC(left.constraints + right.constraints, equality=equality)
480
+
481
+ # Everything done, so we set the chaining variables
482
+ chained_comparator_left = py_left
483
+ chained_comparator_right = py_right
484
+ chained_comparator_replace = None
485
+
486
+ return ret
487
+
488
+ def __hash__(self):
489
+ r"""
490
+ Return a hash from the ``id()``.
491
+
492
+ EXAMPLES::
493
+
494
+ sage: p = MixedIntegerLinearProgram()
495
+ sage: LF = p.linear_functions_parent()
496
+ sage: f = LF({2 : 5, 3 : 2})
497
+ sage: hash(f) # indirect doctest; random
498
+ 103987752
499
+
500
+ Since we hash by ``id()``, linear functions and constraints are
501
+ only considered equal for sets and dicts if they are the same
502
+ object::
503
+
504
+ sage: f = LF.0
505
+ sage: set([f, f])
506
+ {x_0}
507
+ sage: set([f, f+0])
508
+ {x_0, x_0}
509
+ sage: len(set([f, f+1]))
510
+ 2
511
+ sage: d = {}
512
+ sage: d[f] = 123
513
+ sage: d[f+0] = 456
514
+ sage: list(d)
515
+ [x_0, x_0]
516
+ """
517
+ return hash_by_id(<void*>self)
518
+
519
+
520
+ #*****************************************************************************
521
+ #
522
+ # Parent of linear functions
523
+ #
524
+ #*****************************************************************************
525
+
526
+ cdef class LinearFunctionsParent_class(Parent):
527
+ r"""
528
+ The parent for all linear functions over a fixed base ring.
529
+
530
+ .. warning::
531
+
532
+ You should use :func:`LinearFunctionsParent` to construct
533
+ instances of this class.
534
+
535
+ INPUT/OUTPUT: see :func:`LinearFunctionsParent`
536
+
537
+ EXAMPLES::
538
+
539
+ sage: from sage.numerical.linear_functions import LinearFunctionsParent_class
540
+ sage: LinearFunctionsParent_class
541
+ <class 'sage.numerical.linear_functions.LinearFunctionsParent_class'>
542
+ """
543
+ def __cinit__(self):
544
+ """
545
+ Cython initializer.
546
+
547
+ TESTS::
548
+
549
+ sage: from sage.numerical.linear_functions import LinearFunctionsParent_class
550
+ sage: LF = LinearFunctionsParent_class.__new__(LinearFunctionsParent_class)
551
+ sage: LF._multiplication_symbol
552
+ '*'
553
+ """
554
+ # Do not use coercion framework for __richcmp__
555
+ self.flags |= Parent_richcmp_element_without_coercion
556
+ self._multiplication_symbol = '*'
557
+
558
+ def __init__(self, base_ring):
559
+ """
560
+ The Python constructor.
561
+
562
+ TESTS::
563
+
564
+ sage: from sage.numerical.linear_functions import LinearFunctionsParent
565
+ sage: LinearFunctionsParent(RDF)
566
+ Linear functions over Real Double Field
567
+ """
568
+ from sage.categories.modules_with_basis import ModulesWithBasis
569
+ Parent.__init__(self, base=base_ring, category=ModulesWithBasis(base_ring))
570
+
571
+ def set_multiplication_symbol(self, symbol='*'):
572
+ """
573
+ Set the multiplication symbol when pretty-printing linear functions.
574
+
575
+ INPUT:
576
+
577
+ - ``symbol`` -- string (default: ``'*'``); the multiplication
578
+ symbol to be used
579
+
580
+ EXAMPLES::
581
+
582
+ sage: p = MixedIntegerLinearProgram()
583
+ sage: x = p.new_variable()
584
+ sage: f = -1-2*x[0]-3*x[1]
585
+ sage: LF = f.parent()
586
+ sage: LF._get_multiplication_symbol()
587
+ '*'
588
+ sage: f
589
+ -1 - 2*x_0 - 3*x_1
590
+ sage: LF.set_multiplication_symbol(' ')
591
+ sage: f
592
+ -1 - 2 x_0 - 3 x_1
593
+ sage: LF.set_multiplication_symbol()
594
+ sage: f
595
+ -1 - 2*x_0 - 3*x_1
596
+ """
597
+ self._multiplication_symbol = symbol
598
+
599
+ def _get_multiplication_symbol(self):
600
+ """
601
+ Return the multiplication symbol.
602
+
603
+ OUTPUT: string. By default, this is ``'*'``
604
+
605
+ EXAMPLES::
606
+
607
+ sage: LF = MixedIntegerLinearProgram().linear_functions_parent()
608
+ sage: LF._get_multiplication_symbol()
609
+ '*'
610
+ """
611
+ return self._multiplication_symbol
612
+
613
+ def tensor(self, free_module):
614
+ """
615
+ Return the tensor product with ``free_module``.
616
+
617
+ INPUT:
618
+
619
+ - ``free_module`` -- vector space or matrix space over the
620
+ same base ring
621
+
622
+ OUTPUT:
623
+
624
+ Instance of
625
+ :class:`sage.numerical.linear_tensor.LinearTensorParent_class`.
626
+
627
+ EXAMPLES::
628
+
629
+ sage: LF = MixedIntegerLinearProgram().linear_functions_parent()
630
+ sage: LF.tensor(RDF^3)
631
+ Tensor product of Vector space of dimension 3 over Real Double Field
632
+ and Linear functions over Real Double Field
633
+ sage: LF.tensor(QQ^2)
634
+ Traceback (most recent call last):
635
+ ...
636
+ ValueError: base rings must match
637
+ """
638
+ from sage.numerical.linear_tensor import LinearTensorParent
639
+ return LinearTensorParent(free_module, self)
640
+
641
+ def gen(self, i):
642
+ """
643
+ Return the linear variable `x_i`.
644
+
645
+ INPUT:
646
+
647
+ - ``i`` -- nonnegative integer
648
+
649
+ OUTPUT: the linear function `x_i`
650
+
651
+ EXAMPLES::
652
+
653
+ sage: LF = MixedIntegerLinearProgram().linear_functions_parent()
654
+ sage: LF.gen(23)
655
+ x_23
656
+ """
657
+ return LinearFunction(self, {i: 1})
658
+
659
+ def _repr_(self):
660
+ """
661
+ Return as string representation.
662
+
663
+ EXAMPLES::
664
+
665
+ sage: MixedIntegerLinearProgram().linear_functions_parent()
666
+ Linear functions over Real Double Field
667
+ """
668
+ return 'Linear functions over ' + str(self.base_ring())
669
+
670
+ cpdef _element_constructor_(self, x):
671
+ """
672
+ Construct a :class:`LinearFunction` from ``x``.
673
+
674
+ EXAMPLES::
675
+
676
+ sage: p = MixedIntegerLinearProgram()
677
+ sage: LF = p.linear_functions_parent()
678
+ sage: LF._element_constructor_(123)
679
+ 123
680
+ sage: LF(123) # indirect doctest
681
+ 123
682
+ sage: type(_)
683
+ <class 'sage.numerical.linear_functions.LinearFunction'>
684
+
685
+ sage: p_QQ = MixedIntegerLinearProgram(solver='ppl')
686
+ sage: LF_QQ = p_QQ.linear_functions_parent()
687
+ sage: f = LF({-1:1/2, 2:3/4}); f
688
+ 0.5 + 0.75*x_2
689
+ sage: LF(f) is f
690
+ True
691
+ sage: LF_QQ(f)
692
+ 1/2 + 3/4*x_2
693
+ sage: LF_QQ(f) is f
694
+ False
695
+ """
696
+ if isinstance(x, LinearFunction):
697
+ return LinearFunction(self, (<LinearFunction>x)._f)
698
+ return LinearFunction(self, x)
699
+
700
+ cpdef _coerce_map_from_(self, R):
701
+ """
702
+ Allow coercion of scalars into linear functions.
703
+
704
+ INPUT:
705
+
706
+ - ``R`` -- a ring
707
+
708
+ OUTPUT: boolean; whether there is a coercion map
709
+
710
+ EXAMPLES::
711
+
712
+ sage: p = MixedIntegerLinearProgram()
713
+ sage: parent = p.linear_functions_parent()
714
+ sage: parent.coerce(int(2))
715
+ 2
716
+ sage: parent._coerce_map_from_(int)
717
+ True
718
+ """
719
+ from sage.structure.coerce import parent_is_real_numerical
720
+ if parent_is_real_numerical(R) or R is complex:
721
+ return True
722
+ return False
723
+
724
+ def _an_element_(self):
725
+ """
726
+ Return an element.
727
+
728
+ OUTPUT: a linear function
729
+
730
+ EXAMPLES::
731
+
732
+ sage: p = MixedIntegerLinearProgram().linear_functions_parent()
733
+ sage: p._an_element_()
734
+ 5*x_2 + 7*x_5
735
+ sage: p.an_element() # indirect doctest
736
+ 5*x_2 + 7*x_5
737
+ """
738
+ return self._element_constructor_({2:5, 5:7})
739
+
740
+
741
+ #*****************************************************************************
742
+ #
743
+ # Elements of linear functions
744
+ #
745
+ #*****************************************************************************
746
+
747
+ cdef class LinearFunction(LinearFunctionOrConstraint):
748
+ r"""
749
+ An elementary algebra to represent symbolic linear functions.
750
+
751
+ .. warning::
752
+
753
+ You should never instantiate :class:`LinearFunction`
754
+ manually. Use the element constructor in the parent
755
+ instead.
756
+
757
+ EXAMPLES:
758
+
759
+ For example, do this::
760
+
761
+ sage: p = MixedIntegerLinearProgram()
762
+ sage: parent = p.linear_functions_parent()
763
+ sage: parent({0 : 1, 3 : -8})
764
+ x_0 - 8*x_3
765
+
766
+ instead of this::
767
+
768
+ sage: from sage.numerical.linear_functions import LinearFunction
769
+ sage: LinearFunction(p.linear_functions_parent(), {0 : 1, 3 : -8})
770
+ x_0 - 8*x_3
771
+ """
772
+
773
+ def __init__(self, parent, f):
774
+ r"""
775
+ Constructor taking a dictionary or a numerical value as its argument.
776
+
777
+ A linear function is represented as a dictionary. The
778
+ values are the coefficient of the variable represented
779
+ by the keys ( which are integers ). The key ``-1``
780
+ corresponds to the constant term.
781
+
782
+ EXAMPLES:
783
+
784
+ With a dictionary::
785
+
786
+ sage: p = MixedIntegerLinearProgram()
787
+ sage: LF = p.linear_functions_parent()
788
+ sage: LF({0 : 1, 3 : -8})
789
+ x_0 - 8*x_3
790
+
791
+ Using the constructor with a numerical value::
792
+
793
+ sage: p = MixedIntegerLinearProgram()
794
+ sage: LF = p.linear_functions_parent()
795
+ sage: LF(25)
796
+ 25
797
+ """
798
+ ModuleElement.__init__(self, parent)
799
+ R = self.base_ring()
800
+ if isinstance(f, dict):
801
+ self._f = dict( (int(key), R(value)) for key, value in f.iteritems() )
802
+ else:
803
+ self._f = {-1: R(f)}
804
+
805
+ cpdef iteritems(self):
806
+ """
807
+ Iterate over the index, coefficient pairs.
808
+
809
+ OUTPUT:
810
+
811
+ An iterator over the ``(key, coefficient)`` pairs. The keys
812
+ are integers indexing the variables. The key ``-1``
813
+ corresponds to the constant term.
814
+
815
+ EXAMPLES::
816
+
817
+ sage: p = MixedIntegerLinearProgram(solver = 'ppl')
818
+ sage: x = p.new_variable()
819
+ sage: f = 0.5 + 3/2*x[1] + 0.6*x[3]
820
+ sage: for id, coeff in sorted(f.iteritems()):
821
+ ....: print('id = {} coeff = {}'.format(id, coeff))
822
+ id = -1 coeff = 1/2
823
+ id = 0 coeff = 3/2
824
+ id = 1 coeff = 3/5
825
+ """
826
+ return self._f.iteritems()
827
+
828
+ def dict(self):
829
+ r"""
830
+ Return the dictionary corresponding to the Linear Function.
831
+
832
+ OUTPUT:
833
+
834
+ The linear function is represented as a dictionary. The value
835
+ are the coefficient of the variable represented by the keys (
836
+ which are integers ). The key ``-1`` corresponds to the
837
+ constant term.
838
+
839
+ EXAMPLES::
840
+
841
+ sage: p = MixedIntegerLinearProgram()
842
+ sage: LF = p.linear_functions_parent()
843
+ sage: lf = LF({0 : 1, 3 : -8})
844
+ sage: lf.dict()
845
+ {0: 1.0, 3: -8.0}
846
+ """
847
+ return dict(self._f)
848
+
849
+ def coefficient(self, x):
850
+ r"""
851
+ Return one of the coefficients.
852
+
853
+ INPUT:
854
+
855
+ - ``x`` -- a linear variable or an integer; if an integer `i`
856
+ is passed, then `x_i` is used as linear variable
857
+
858
+ OUTPUT:
859
+
860
+ A base ring element. The coefficient of ``x`` in the linear
861
+ function. Pass ``-1`` for the constant term.
862
+
863
+ EXAMPLES::
864
+
865
+ sage: mip.<b> = MixedIntegerLinearProgram()
866
+ sage: lf = -8 * b[3] + b[0] - 5; lf
867
+ -5 - 8*x_0 + x_1
868
+ sage: lf.coefficient(b[3])
869
+ -8.0
870
+ sage: lf.coefficient(0) # x_0 is b[3]
871
+ -8.0
872
+ sage: lf.coefficient(4)
873
+ 0.0
874
+ sage: lf.coefficient(-1)
875
+ -5.0
876
+
877
+ TESTS::
878
+
879
+ sage: lf.coefficient(b[3] + b[4])
880
+ Traceback (most recent call last):
881
+ ...
882
+ ValueError: x is a sum, must be a single variable
883
+ sage: lf.coefficient(2*b[3])
884
+ Traceback (most recent call last):
885
+ ...
886
+ ValueError: x must have a unit coefficient
887
+ sage: mip.<q> = MixedIntegerLinearProgram(solver='ppl')
888
+ sage: lf.coefficient(q[0])
889
+ Traceback (most recent call last):
890
+ ...
891
+ ValueError: x is from a different linear functions module
892
+ """
893
+ if isinstance(x, LinearFunction):
894
+ if self.parent() != x.parent():
895
+ raise ValueError('x is from a different linear functions module')
896
+ if len((<LinearFunction>x)._f) != 1:
897
+ raise ValueError('x is a sum, must be a single variable')
898
+ i, = (<LinearFunction>x)._f.keys()
899
+ if (<LinearFunction>x)._f[i] != 1:
900
+ raise ValueError('x must have a unit coefficient')
901
+ else:
902
+ i = int(x)
903
+ try:
904
+ return self._f[i]
905
+ except KeyError:
906
+ return self.parent().base_ring().zero()
907
+
908
+ cpdef _add_(self, b):
909
+ r"""
910
+ Defining the ``+`` operator.
911
+
912
+ EXAMPLES::
913
+
914
+ sage: p = MixedIntegerLinearProgram()
915
+ sage: LF = p.linear_functions_parent()
916
+ sage: LF({0 : 1, 3 : -8}) + LF({2 : 5, 3 : 2}) - 16
917
+ -16 + x_0 + 5*x_2 - 6*x_3
918
+ """
919
+ e = dict(self._f)
920
+ for (id,coeff) in b.dict().iteritems():
921
+ e[id] = self._f.get(id,0) + coeff
922
+ P = self.parent()
923
+ return P(e)
924
+
925
+ cpdef _neg_(self):
926
+ r"""
927
+ Defining the - operator (opposite).
928
+
929
+ EXAMPLES::
930
+
931
+ sage: p = MixedIntegerLinearProgram()
932
+ sage: LF = p.linear_functions_parent()
933
+ sage: - LF({0 : 1, 3 : -8})
934
+ -1*x_0 + 8*x_3
935
+ """
936
+ P = self.parent()
937
+ return P({id: -coeff for id, coeff in self._f.iteritems()})
938
+
939
+ cpdef _sub_(self, b):
940
+ r"""
941
+ Defining the - operator (subtraction).
942
+
943
+ EXAMPLES::
944
+
945
+ sage: p = MixedIntegerLinearProgram()
946
+ sage: LF = p.linear_functions_parent()
947
+ sage: LF({2 : 5, 3 : 2}) - 3
948
+ -3 + 5*x_2 + 2*x_3
949
+ sage: LF({0 : 1, 3 : -8}) - LF({2 : 5, 3 : 2}) - 16
950
+ -16 + x_0 - 5*x_2 - 10*x_3
951
+ """
952
+ e = dict(self._f)
953
+ for id, coeff in b.dict().iteritems():
954
+ e[id] = self._f.get(id, 0) - coeff
955
+ P = self.parent()
956
+ return P(e)
957
+
958
+ cpdef _lmul_(self, Element b):
959
+ r"""
960
+ Multiplication by scalars.
961
+
962
+ EXAMPLES::
963
+
964
+ sage: p = MixedIntegerLinearProgram()
965
+ sage: LF = p.linear_functions_parent()
966
+ sage: LF({2 : 5, 3 : 2}) * 3
967
+ 15*x_2 + 6*x_3
968
+ sage: 3 * LF({2 : 5, 3 : 2})
969
+ 15*x_2 + 6*x_3
970
+ """
971
+ P = self.parent()
972
+ return P(dict([(id,b*coeff) for (id, coeff) in self._f.iteritems()]))
973
+
974
+ cpdef _acted_upon_(self, x, bint self_on_left):
975
+ """
976
+ Act with scalars that do not have a natural coercion into
977
+ ``self.base_ring()``
978
+
979
+ EXAMPLES:
980
+
981
+ Note that there is no coercion from ``RR`` to ``QQ``, but you
982
+ can explicitly convert them::
983
+
984
+ sage: 1/2 * 0.6
985
+ 0.300000000000000
986
+
987
+ If there were a coercion, then 0.6 would have been coerced into
988
+ 6/10 and the result would have been rational. This is
989
+ undesirable, which is why there cannot be a coercion on the
990
+ level of the coefficient rings.
991
+
992
+ By declaring an action of ``RR`` on the linear functions over
993
+ ``QQ`` we make the following possible::
994
+
995
+ sage: p = MixedIntegerLinearProgram(solver='ppl')
996
+ sage: p.base_ring()
997
+ Rational Field
998
+ sage: x = p.new_variable()
999
+ sage: x[0] * 0.6
1000
+ 3/5*x_0
1001
+
1002
+ sage: vf = (2 + x[0]) * vector(ZZ, [3,4]); vf
1003
+ (6, 8) + (3, 4)*x_0
1004
+ sage: vf.parent()
1005
+ Tensor product of Vector space of dimension 2 over Rational Field
1006
+ and Linear functions over Rational Field
1007
+
1008
+ sage: tf = x[0] * identity_matrix(2); tf
1009
+ [x_0 0 ]
1010
+ [0 x_0]
1011
+ sage: tf.parent()
1012
+ Tensor product of Full MatrixSpace of 2 by 2 dense matrices over
1013
+ Rational Field and Linear functions over Rational Field
1014
+ """
1015
+ R = self.base_ring()
1016
+ try:
1017
+ x_R = R(x)
1018
+ except TypeError:
1019
+ M = x.parent().base_extend(R)
1020
+ x_M = M(x)
1021
+ from sage.numerical.linear_tensor import LinearTensorParent
1022
+ P = LinearTensorParent(M, self.parent())
1023
+ tensor = dict()
1024
+ for k, v in self._f.items():
1025
+ tensor[k] = x_M * v
1026
+ return P(tensor)
1027
+ return self._rmul_(x_R)
1028
+
1029
+ def _coeff_formatter(self, coeff, constant_term=False):
1030
+ """
1031
+ Pretty-print multiplicative coefficient ``x``.
1032
+
1033
+ OUTPUT:
1034
+
1035
+ string, including a trailing space if the coefficient is not
1036
+ one. Empty string otherwise.
1037
+
1038
+ EXAMPLES::
1039
+
1040
+ sage: p = MixedIntegerLinearProgram()
1041
+ sage: LF = p.linear_functions_parent()
1042
+ sage: f = LF(1); type(f)
1043
+ <class 'sage.numerical.linear_functions.LinearFunction'>
1044
+ sage: f._coeff_formatter(1)
1045
+ ''
1046
+ sage: f._coeff_formatter(1, constant_term=True)
1047
+ '1'
1048
+ sage: f._coeff_formatter(RDF(12.0))
1049
+ '12*'
1050
+ sage: f._coeff_formatter(RDF(12.3))
1051
+ '12.3*'
1052
+
1053
+ sage: p = MixedIntegerLinearProgram(solver='ppl')
1054
+ sage: LF = p.linear_functions_parent()
1055
+ sage: f = LF(1)
1056
+ sage: f._coeff_formatter(13/45)
1057
+ '13/45*'
1058
+
1059
+ sage: # needs sage.rings.number_field
1060
+ sage: from sage.rings.number_field.number_field import QuadraticField
1061
+ sage: K.<sqrt5> = QuadraticField(5, 'sqrt5')
1062
+ sage: p = MixedIntegerLinearProgram(solver='interactivelp', base_ring=K)
1063
+ sage: LF = p.linear_functions_parent()
1064
+ sage: f = LF(1)
1065
+ sage: f._coeff_formatter(sqrt5)
1066
+ 'sqrt5*'
1067
+
1068
+ sage: # needs sage.rings.number_field
1069
+ sage: from sage.rings.qqbar import AA
1070
+ sage: sqrt5 = AA(5).sqrt()
1071
+ sage: p = MixedIntegerLinearProgram(solver='interactivelp', base_ring=AA)
1072
+ sage: LF = p.linear_functions_parent()
1073
+ sage: f = LF(1)
1074
+ sage: f._coeff_formatter(sqrt5)
1075
+ '2.236067977499790?*'
1076
+ """
1077
+ R = self.base_ring()
1078
+ if coeff == R.one() and not constant_term:
1079
+ return ''
1080
+ try:
1081
+ from sage.rings.integer_ring import ZZ
1082
+ coeff = ZZ(coeff)
1083
+ except (TypeError, ValueError):
1084
+ pass
1085
+ if constant_term:
1086
+ return str(coeff)
1087
+ else:
1088
+ return str(coeff) + self.parent()._multiplication_symbol
1089
+
1090
+ def _repr_(self):
1091
+ r"""
1092
+ Return a string version of the linear function.
1093
+
1094
+ EXAMPLES::
1095
+
1096
+ sage: p = MixedIntegerLinearProgram(solver='GLPK')
1097
+ sage: LF = p.linear_functions_parent()
1098
+ sage: LF({-1: -15, 2 : -5.1, 3 : 2/3})
1099
+ -15 - 5.1*x_2 + 0.6666666666666666*x_3
1100
+ sage: p = MixedIntegerLinearProgram(solver='ppl')
1101
+ sage: LF = p.linear_functions_parent()
1102
+ sage: LF({-1: -15, 2 : -5.1, 3 : 2/3})
1103
+ -15 - 51/10*x_2 + 2/3*x_3
1104
+ """
1105
+ cdef dict d = dict(self._f)
1106
+ cdef bint first = True
1107
+ t = ""
1108
+
1109
+ if -1 in d:
1110
+ coeff = d.pop(-1)
1111
+ if coeff:
1112
+ t = self._coeff_formatter(coeff, constant_term=True)
1113
+ first = False
1114
+
1115
+ cdef list l = sorted(d.items())
1116
+ for id, coeff in l:
1117
+ sign = coeff.sign()
1118
+ if sign == 0:
1119
+ continue
1120
+ if not first:
1121
+ if sign == -1:
1122
+ t += ' - '
1123
+ if sign == +1:
1124
+ t += ' + '
1125
+ t += self._coeff_formatter(abs(coeff)) + 'x_' + str(id)
1126
+ else:
1127
+ t += self._coeff_formatter(coeff) + 'x_' + str(id)
1128
+ first = False
1129
+
1130
+ if first:
1131
+ return '0'
1132
+ else:
1133
+ return t
1134
+
1135
+ cpdef is_zero(self):
1136
+ """
1137
+ Test whether ``self`` is zero.
1138
+
1139
+ OUTPUT: boolean
1140
+
1141
+ EXAMPLES::
1142
+
1143
+ sage: p = MixedIntegerLinearProgram()
1144
+ sage: x = p.new_variable()
1145
+ sage: (x[1] - x[1] + 0*x[2]).is_zero()
1146
+ True
1147
+ """
1148
+ for coeff in self._f.values():
1149
+ if not coeff.is_zero():
1150
+ return False
1151
+ return True
1152
+
1153
+ cpdef equals(LinearFunction left, LinearFunction right):
1154
+ """
1155
+ Logically compare ``left`` and ``right``.
1156
+
1157
+ OUTPUT: boolean
1158
+
1159
+ EXAMPLES::
1160
+
1161
+ sage: p = MixedIntegerLinearProgram()
1162
+ sage: x = p.new_variable()
1163
+ sage: (x[1] + 1).equals(3/3 + 1*x[1] + 0*x[2])
1164
+ True
1165
+ """
1166
+ return (left-right).is_zero()
1167
+
1168
+
1169
+ #*****************************************************************************
1170
+ #
1171
+ # Parent of linear constraints
1172
+ #
1173
+ #*****************************************************************************
1174
+
1175
+ cdef class LinearConstraintsParent_class(Parent):
1176
+ """
1177
+ Parent for :class:`LinearConstraint`.
1178
+
1179
+ .. warning::
1180
+
1181
+ This class has no reason to be instantiated by the user, and
1182
+ is meant to be used by instances of
1183
+ :class:`MixedIntegerLinearProgram`. Also, use the
1184
+ :func:`LinearConstraintsParent` factory function.
1185
+
1186
+ INPUT/OUTPUT: see :func:`LinearFunctionsParent`
1187
+
1188
+ EXAMPLES::
1189
+
1190
+ sage: p = MixedIntegerLinearProgram()
1191
+ sage: LC = p.linear_constraints_parent(); LC
1192
+ Linear constraints over Real Double Field
1193
+ sage: from sage.numerical.linear_functions import LinearConstraintsParent
1194
+ sage: LinearConstraintsParent(p.linear_functions_parent()) is LC
1195
+ True
1196
+ """
1197
+ def __cinit__(self, linear_functions_parent):
1198
+ """
1199
+ Cython initializer.
1200
+
1201
+ TESTS::
1202
+
1203
+ sage: from sage.numerical.linear_functions import LinearConstraintsParent_class
1204
+ sage: from sage.numerical.linear_functions import LinearFunctionsParent
1205
+ sage: LF = LinearFunctionsParent(RDF)
1206
+ sage: LinearConstraintsParent_class.__new__(LinearConstraintsParent_class, LF)
1207
+ Linear constraints over Real Double Field
1208
+ sage: LinearConstraintsParent_class.__new__(LinearConstraintsParent_class, None)
1209
+ Traceback (most recent call last):
1210
+ ...
1211
+ TypeError: Cannot convert NoneType to sage.numerical.linear_functions.LinearFunctionsParent_class
1212
+ """
1213
+ self._LF = <LinearFunctionsParent_class?>linear_functions_parent
1214
+ # Do not use coercion framework for __richcmp__
1215
+ self.flags |= Parent_richcmp_element_without_coercion
1216
+
1217
+ def __init__(self, linear_functions_parent):
1218
+ """
1219
+ The Python constructor.
1220
+
1221
+ INPUT/OUTPUT: see :func:`LinearFunctionsParent`
1222
+
1223
+ TESTS::
1224
+
1225
+ sage: from sage.numerical.linear_functions import LinearFunctionsParent
1226
+ sage: LF = LinearFunctionsParent(RDF)
1227
+ sage: from sage.numerical.linear_functions import LinearConstraintsParent
1228
+ sage: LinearConstraintsParent(LF)
1229
+ Linear constraints over Real Double Field
1230
+ sage: LinearConstraintsParent(None)
1231
+ Traceback (most recent call last):
1232
+ ...
1233
+ TypeError: Cannot convert NoneType to sage.numerical.linear_functions.LinearFunctionsParent_class
1234
+ """
1235
+ Parent.__init__(self)
1236
+
1237
+ def linear_functions_parent(self):
1238
+ """
1239
+ Return the parent for the linear functions.
1240
+
1241
+ EXAMPLES::
1242
+
1243
+ sage: LC = MixedIntegerLinearProgram().linear_constraints_parent()
1244
+ sage: LC.linear_functions_parent()
1245
+ Linear functions over Real Double Field
1246
+ """
1247
+ return self._LF
1248
+
1249
+ def _repr_(self):
1250
+ """
1251
+ Return a string representation.
1252
+
1253
+ OUTPUT: string
1254
+
1255
+ EXAMPLES::
1256
+
1257
+ sage: MixedIntegerLinearProgram().linear_constraints_parent()
1258
+ Linear constraints over Real Double Field
1259
+ """
1260
+ return 'Linear constraints over ' + str(self.linear_functions_parent().base_ring())
1261
+
1262
+ cpdef _element_constructor_(self, left, right=None, equality=False):
1263
+ """
1264
+ Construct a :class:`LinearConstraint`.
1265
+
1266
+ INPUT:
1267
+
1268
+ - ``left`` -- a :class:`LinearFunction`, or something that can
1269
+ be converted into one, a list/tuple of
1270
+ :class:`LinearFunction`, or an existing
1271
+ :class:`LinearConstraint`.
1272
+
1273
+ - ``right`` -- a :class:`LinearFunction` or ``None``
1274
+ (default)
1275
+
1276
+ - ``equality`` -- boolean (default: ``True``); whether to
1277
+ construct an equation or an inequality
1278
+
1279
+ OUTPUT: the :class:`LinearConstraint` constructed from the input data
1280
+
1281
+ EXAMPLES::
1282
+
1283
+ sage: p = MixedIntegerLinearProgram()
1284
+ sage: LC = p.linear_constraints_parent()
1285
+ sage: LC._element_constructor_(1, 2)
1286
+ 1 <= 2
1287
+
1288
+ sage: x = p.new_variable()
1289
+ sage: LC([x[0], x[1], x[2]])
1290
+ x_0 <= x_1 <= x_2
1291
+
1292
+ sage: LC([x[0], x[1], x[2]], equality=True)
1293
+ x_0 == x_1 == x_2
1294
+
1295
+ sage: type(_)
1296
+ <class 'sage.numerical.linear_functions.LinearConstraint'>
1297
+
1298
+ TESTS::
1299
+
1300
+ sage: inequality = LC([x[0], 1/2*x[1], 3/4*x[2]]); inequality
1301
+ x_0 <= 0.5*x_1 <= 0.75*x_2
1302
+ sage: LC(inequality) is inequality
1303
+ True
1304
+ sage: p_QQ = MixedIntegerLinearProgram(solver='ppl')
1305
+ sage: LC_QQ = p_QQ.linear_constraints_parent()
1306
+ sage: LC_QQ(inequality)
1307
+ x_0 <= 1/2*x_1 <= 3/4*x_2
1308
+ sage: LC_QQ(inequality) is inequality
1309
+ False
1310
+ """
1311
+ if right is None and isinstance(left, LinearConstraint):
1312
+ if (left.parent() is self) and (left.is_equation() == equality):
1313
+ return left
1314
+ else:
1315
+ return LinearConstraint(self, (<LinearConstraint>left).constraints,
1316
+ equality=equality)
1317
+ if right is None:
1318
+ if isinstance(left, (list,tuple)):
1319
+ return LinearConstraint(self, left, equality=equality)
1320
+ else:
1321
+ return LinearConstraint(self, [left], equality=equality)
1322
+ else:
1323
+ return LinearConstraint(self, [left, right], equality=equality)
1324
+
1325
+ cpdef _coerce_map_from_(self, R):
1326
+ """
1327
+ Allow coercion of scalars into linear functions.
1328
+
1329
+ EXAMPLES::
1330
+
1331
+ sage: p = MixedIntegerLinearProgram()
1332
+ sage: parent = p.linear_constraints_parent()
1333
+ sage: parent.coerce(int(2))
1334
+ trivial constraint starting with 2
1335
+ sage: parent._coerce_map_from_(int)
1336
+ True
1337
+ """
1338
+ return self.linear_functions_parent().has_coerce_map_from(R)
1339
+
1340
+ def _an_element_(self):
1341
+ """
1342
+ Return an element.
1343
+
1344
+ EXAMPLES::
1345
+
1346
+ sage: p = MixedIntegerLinearProgram().linear_functions_parent()
1347
+ sage: p._an_element_()
1348
+ 5*x_2 + 7*x_5
1349
+ sage: p.an_element() # indirect doctest
1350
+ 5*x_2 + 7*x_5
1351
+ """
1352
+ LF = self.linear_functions_parent()
1353
+ return self(0) <= LF.an_element()
1354
+
1355
+
1356
+ #*****************************************************************************
1357
+ #
1358
+ # Elements of linear constraints
1359
+ #
1360
+ #*****************************************************************************
1361
+
1362
+ cdef class LinearConstraint(LinearFunctionOrConstraint):
1363
+ """
1364
+ A class to represent formal Linear Constraints.
1365
+
1366
+ A Linear Constraint being an inequality between
1367
+ two linear functions, this class lets the user
1368
+ write ``LinearFunction1 <= LinearFunction2``
1369
+ to define the corresponding constraint, which
1370
+ can potentially involve several layers of such
1371
+ inequalities (``A <= B <= C``), or even equalities
1372
+ like ``A == B == C``.
1373
+
1374
+ Trivial constraints (meaning that they have only one term and no
1375
+ relation) are also allowed. They are required for the coercion
1376
+ system to work.
1377
+
1378
+ .. warning::
1379
+
1380
+ This class has no reason to be instantiated by the user, and
1381
+ is meant to be used by instances of
1382
+ :class:`MixedIntegerLinearProgram`.
1383
+
1384
+ INPUT:
1385
+
1386
+ - ``parent`` -- the parent; a :class:`LinearConstraintsParent_class`
1387
+
1388
+ - ``terms`` -- list/tuple/iterable of two or more linear
1389
+ functions (or things that can be converted into linear
1390
+ functions)
1391
+
1392
+ - ``equality`` -- boolean (default: ``False``); whether the terms
1393
+ are the entries of a chained less-or-equal (``<=``) inequality
1394
+ or a chained equality
1395
+
1396
+ EXAMPLES::
1397
+
1398
+ sage: p = MixedIntegerLinearProgram()
1399
+ sage: b = p.new_variable()
1400
+ sage: b[2]+2*b[3] <= b[8]-5
1401
+ x_0 + 2*x_1 <= -5 + x_2
1402
+ """
1403
+
1404
+ def __init__(self, parent, terms, equality=False):
1405
+ r"""
1406
+ Constructor for ``LinearConstraint``.
1407
+
1408
+ INPUT:
1409
+
1410
+ See :class:`LinearConstraint`.
1411
+
1412
+ EXAMPLES::
1413
+
1414
+ sage: p = MixedIntegerLinearProgram()
1415
+ sage: b = p.new_variable()
1416
+ sage: b[2]+2*b[3] <= b[8]-5
1417
+ x_0 + 2*x_1 <= -5 + x_2
1418
+ """
1419
+ assert len(terms) > 0
1420
+ super().__init__(parent)
1421
+ self.equality = equality
1422
+ LF = parent.linear_functions_parent()
1423
+ self.constraints = [ LF(term) for term in terms ]
1424
+
1425
+ cpdef equals(LinearConstraint left, LinearConstraint right):
1426
+ """
1427
+ Compare ``left`` and ``right``.
1428
+
1429
+ OUTPUT:
1430
+
1431
+ boolean; whether all terms of ``left`` and ``right`` are
1432
+ equal. Note that this is stronger than mathematical
1433
+ equivalence of the relations.
1434
+
1435
+ EXAMPLES::
1436
+
1437
+ sage: p = MixedIntegerLinearProgram()
1438
+ sage: x = p.new_variable()
1439
+ sage: (x[1] + 1 >= 2).equals(3/3 + 1*x[1] + 0*x[2] >= 8/4)
1440
+ True
1441
+ sage: (x[1] + 1 >= 2).equals(x[1] + 1-1 >= 1-1)
1442
+ False
1443
+ """
1444
+ if len(left.constraints) != len(right.constraints):
1445
+ return False
1446
+ if left.equality != right.equality:
1447
+ return False
1448
+ cdef LinearFunction l, r
1449
+ for i in range(len(left.constraints)):
1450
+ l = <LinearFunction>(left.constraints[i])
1451
+ r = <LinearFunction>(right.constraints[i])
1452
+ if not l.equals(r):
1453
+ return False
1454
+ return True
1455
+
1456
+ def is_equation(self):
1457
+ """
1458
+ Whether the constraint is a chained equation.
1459
+
1460
+ OUTPUT: boolean
1461
+
1462
+ EXAMPLES::
1463
+
1464
+ sage: p = MixedIntegerLinearProgram()
1465
+ sage: b = p.new_variable()
1466
+ sage: (b[0] == b[1]).is_equation()
1467
+ True
1468
+ sage: (b[0] <= b[1]).is_equation()
1469
+ False
1470
+ """
1471
+ return self.equality
1472
+
1473
+ def is_less_or_equal(self):
1474
+ """
1475
+ Whether the constraint is a chained less-or_equal inequality.
1476
+
1477
+ OUTPUT: boolean
1478
+
1479
+ EXAMPLES::
1480
+
1481
+ sage: p = MixedIntegerLinearProgram()
1482
+ sage: b = p.new_variable()
1483
+ sage: (b[0] == b[1]).is_less_or_equal()
1484
+ False
1485
+ sage: (b[0] <= b[1]).is_less_or_equal()
1486
+ True
1487
+ """
1488
+ return not self.equality
1489
+
1490
+ def is_trivial(self):
1491
+ """
1492
+ Test whether the constraint is trivial.
1493
+
1494
+ EXAMPLES::
1495
+
1496
+ sage: p = MixedIntegerLinearProgram()
1497
+ sage: LC = p.linear_constraints_parent()
1498
+ sage: ieq = LC(1,2); ieq
1499
+ 1 <= 2
1500
+ sage: ieq.is_trivial()
1501
+ False
1502
+
1503
+ sage: ieq = LC(1); ieq
1504
+ trivial constraint starting with 1
1505
+ sage: ieq.is_trivial()
1506
+ True
1507
+ """
1508
+ return len(self.constraints) < 2
1509
+
1510
+ def __iter__(self):
1511
+ """
1512
+ Iterate over the terms of the chained (in)-equality.
1513
+
1514
+ OUTPUT:
1515
+
1516
+ A generator yielding the individual terms of the constraint in
1517
+ left-to-right order.
1518
+
1519
+ EXAMPLES::
1520
+
1521
+ sage: p = MixedIntegerLinearProgram()
1522
+ sage: b = p.new_variable()
1523
+ sage: ieq = 1 <= b[0] <= b[2] <= 3 <= b[3]; ieq
1524
+ 1 <= x_0 <= x_1 <= 3 <= x_2
1525
+ sage: list(ieq)
1526
+ [1, x_0, x_1, 3, x_2]
1527
+ sage: for term in ieq:
1528
+ ....: print(term)
1529
+ 1
1530
+ x_0
1531
+ x_1
1532
+ 3
1533
+ x_2
1534
+ """
1535
+ for term in self.constraints:
1536
+ yield term
1537
+
1538
+ def equations(self):
1539
+ """
1540
+ Iterate over the unchained(!) equations.
1541
+
1542
+ OUTPUT:
1543
+
1544
+ An iterator over pairs ``(lhs, rhs)`` such that the individual
1545
+ equations are ``lhs == rhs``.
1546
+
1547
+ EXAMPLES::
1548
+
1549
+ sage: p = MixedIntegerLinearProgram()
1550
+ sage: b = p.new_variable()
1551
+ sage: eqns = 1 == b[0] == b[2] == 3 == b[3]; eqns
1552
+ 1 == x_0 == x_1 == 3 == x_2
1553
+ sage: for lhs, rhs in eqns.equations():
1554
+ ....: print(str(lhs) + ' == ' + str(rhs))
1555
+ 1 == x_0
1556
+ x_0 == x_1
1557
+ x_1 == 3
1558
+ 3 == x_2
1559
+ """
1560
+ if not self.is_equation() or self.is_trivial():
1561
+ return
1562
+ term_iter = iter(self)
1563
+ lhs = next(term_iter)
1564
+ rhs = next(term_iter)
1565
+ while True:
1566
+ yield (lhs, rhs)
1567
+ lhs = rhs
1568
+ try:
1569
+ rhs = next(term_iter)
1570
+ except StopIteration:
1571
+ return
1572
+
1573
+ def inequalities(self):
1574
+ """
1575
+ Iterate over the unchained(!) inequalities.
1576
+
1577
+ OUTPUT:
1578
+
1579
+ An iterator over pairs ``(lhs, rhs)`` such that the individual
1580
+ equations are ``lhs <= rhs``.
1581
+
1582
+ EXAMPLES::
1583
+
1584
+ sage: p = MixedIntegerLinearProgram()
1585
+ sage: b = p.new_variable()
1586
+ sage: ieq = 1 <= b[0] <= b[2] <= 3 <= b[3]; ieq
1587
+ 1 <= x_0 <= x_1 <= 3 <= x_2
1588
+
1589
+ sage: for lhs, rhs in ieq.inequalities():
1590
+ ....: print(str(lhs) + ' <= ' + str(rhs))
1591
+ 1 <= x_0
1592
+ x_0 <= x_1
1593
+ x_1 <= 3
1594
+ 3 <= x_2
1595
+ """
1596
+ if not self.is_less_or_equal() or self.is_trivial():
1597
+ return
1598
+ term_iter = iter(self)
1599
+ lhs = next(term_iter)
1600
+ rhs = next(term_iter)
1601
+ while True:
1602
+ yield (lhs, rhs)
1603
+ lhs = rhs
1604
+ try:
1605
+ rhs = next(term_iter)
1606
+ except StopIteration:
1607
+ return
1608
+
1609
+ def _repr_(self):
1610
+ r"""
1611
+ Return a string representation of the constraint.
1612
+
1613
+ OUTPUT: string
1614
+
1615
+ EXAMPLES::
1616
+
1617
+ sage: p = MixedIntegerLinearProgram()
1618
+ sage: b = p.new_variable()
1619
+ sage: b[3] <= b[8] + 9
1620
+ x_0 <= 9 + x_1
1621
+
1622
+ sage: LC = p.linear_constraints_parent()
1623
+ sage: LC(b[3], b[8] + 9)
1624
+ x_0 <= 9 + x_1
1625
+ sage: LC(b[3])
1626
+ trivial constraint starting with x_0
1627
+ """
1628
+ comparator = (' == ' if self.equality else ' <= ')
1629
+ result = comparator.join(map(str, self))
1630
+ if self.is_trivial():
1631
+ return 'trivial constraint starting with ' + result
1632
+ return result
1633
+
1634
+ def __bool__(self):
1635
+ """
1636
+ Part of the hack to allow chained (in)equalities.
1637
+
1638
+ EXAMPLES::
1639
+
1640
+ sage: p = MixedIntegerLinearProgram()
1641
+ sage: b = p.new_variable()
1642
+ sage: ieq = (b[3] <= b[8] + 9)
1643
+ sage: ieq <= ieq <= ieq
1644
+ x_0 <= 9 + x_1 <= x_0 <= 9 + x_1 <= x_0 <= 9 + x_1
1645
+ """
1646
+ global chained_comparator_replace
1647
+ chained_comparator_replace = self
1648
+ return True