passagemath-polyhedra 10.6.31rc3__cp314-cp314-musllinux_1_2_aarch64.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.

Potentially problematic release.


This version of passagemath-polyhedra might be problematic. Click here for more details.

Files changed (208) hide show
  1. passagemath_polyhedra-10.6.31rc3.dist-info/METADATA +367 -0
  2. passagemath_polyhedra-10.6.31rc3.dist-info/METADATA.bak +369 -0
  3. passagemath_polyhedra-10.6.31rc3.dist-info/RECORD +208 -0
  4. passagemath_polyhedra-10.6.31rc3.dist-info/WHEEL +5 -0
  5. passagemath_polyhedra-10.6.31rc3.dist-info/top_level.txt +2 -0
  6. passagemath_polyhedra.libs/libgcc_s-2d945d6c.so.1 +0 -0
  7. passagemath_polyhedra.libs/libgmp-28992bcb.so.10.5.0 +0 -0
  8. passagemath_polyhedra.libs/libgomp-1ede7ee7.so.1.0.0 +0 -0
  9. passagemath_polyhedra.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
  10. sage/all__sagemath_polyhedra.py +50 -0
  11. sage/game_theory/all.py +8 -0
  12. sage/game_theory/catalog.py +6 -0
  13. sage/game_theory/catalog_normal_form_games.py +923 -0
  14. sage/game_theory/cooperative_game.py +844 -0
  15. sage/game_theory/matching_game.py +1181 -0
  16. sage/game_theory/normal_form_game.py +2697 -0
  17. sage/game_theory/parser.py +275 -0
  18. sage/geometry/all__sagemath_polyhedra.py +22 -0
  19. sage/geometry/cone.py +6940 -0
  20. sage/geometry/cone_catalog.py +847 -0
  21. sage/geometry/cone_critical_angles.py +1027 -0
  22. sage/geometry/convex_set.py +1119 -0
  23. sage/geometry/fan.py +3743 -0
  24. sage/geometry/fan_isomorphism.py +389 -0
  25. sage/geometry/fan_morphism.py +1884 -0
  26. sage/geometry/hasse_diagram.py +202 -0
  27. sage/geometry/hyperplane_arrangement/affine_subspace.py +390 -0
  28. sage/geometry/hyperplane_arrangement/all.py +1 -0
  29. sage/geometry/hyperplane_arrangement/arrangement.py +3895 -0
  30. sage/geometry/hyperplane_arrangement/check_freeness.py +145 -0
  31. sage/geometry/hyperplane_arrangement/hyperplane.py +773 -0
  32. sage/geometry/hyperplane_arrangement/library.py +825 -0
  33. sage/geometry/hyperplane_arrangement/ordered_arrangement.py +642 -0
  34. sage/geometry/hyperplane_arrangement/plot.py +520 -0
  35. sage/geometry/integral_points.py +35 -0
  36. sage/geometry/integral_points_generic_dense.cpython-314-aarch64-linux-musl.so +0 -0
  37. sage/geometry/integral_points_generic_dense.pyx +7 -0
  38. sage/geometry/lattice_polytope.py +5894 -0
  39. sage/geometry/linear_expression.py +773 -0
  40. sage/geometry/newton_polygon.py +767 -0
  41. sage/geometry/point_collection.cpython-314-aarch64-linux-musl.so +0 -0
  42. sage/geometry/point_collection.pyx +1008 -0
  43. sage/geometry/polyhedral_complex.py +2616 -0
  44. sage/geometry/polyhedron/all.py +8 -0
  45. sage/geometry/polyhedron/backend_cdd.py +460 -0
  46. sage/geometry/polyhedron/backend_cdd_rdf.py +231 -0
  47. sage/geometry/polyhedron/backend_field.py +347 -0
  48. sage/geometry/polyhedron/backend_normaliz.py +2503 -0
  49. sage/geometry/polyhedron/backend_number_field.py +168 -0
  50. sage/geometry/polyhedron/backend_polymake.py +765 -0
  51. sage/geometry/polyhedron/backend_ppl.py +582 -0
  52. sage/geometry/polyhedron/base.py +1206 -0
  53. sage/geometry/polyhedron/base0.py +1444 -0
  54. sage/geometry/polyhedron/base1.py +886 -0
  55. sage/geometry/polyhedron/base2.py +812 -0
  56. sage/geometry/polyhedron/base3.py +1845 -0
  57. sage/geometry/polyhedron/base4.py +1262 -0
  58. sage/geometry/polyhedron/base5.py +2700 -0
  59. sage/geometry/polyhedron/base6.py +1741 -0
  60. sage/geometry/polyhedron/base7.py +997 -0
  61. sage/geometry/polyhedron/base_QQ.py +1258 -0
  62. sage/geometry/polyhedron/base_RDF.py +98 -0
  63. sage/geometry/polyhedron/base_ZZ.py +934 -0
  64. sage/geometry/polyhedron/base_mutable.py +215 -0
  65. sage/geometry/polyhedron/base_number_field.py +122 -0
  66. sage/geometry/polyhedron/cdd_file_format.py +155 -0
  67. sage/geometry/polyhedron/combinatorial_polyhedron/all.py +1 -0
  68. sage/geometry/polyhedron/combinatorial_polyhedron/base.cpython-314-aarch64-linux-musl.so +0 -0
  69. sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +76 -0
  70. sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +3859 -0
  71. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.cpython-314-aarch64-linux-musl.so +0 -0
  72. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +39 -0
  73. sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +1038 -0
  74. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.cpython-314-aarch64-linux-musl.so +0 -0
  75. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pxd +9 -0
  76. sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +501 -0
  77. sage/geometry/polyhedron/combinatorial_polyhedron/face_data_structure.pxd +207 -0
  78. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.cpython-314-aarch64-linux-musl.so +0 -0
  79. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +102 -0
  80. sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +2274 -0
  81. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.cpython-314-aarch64-linux-musl.so +0 -0
  82. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +370 -0
  83. sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +84 -0
  84. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.cpython-314-aarch64-linux-musl.so +0 -0
  85. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +31 -0
  86. sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +587 -0
  87. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.cpython-314-aarch64-linux-musl.so +0 -0
  88. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +52 -0
  89. sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +560 -0
  90. sage/geometry/polyhedron/constructor.py +773 -0
  91. sage/geometry/polyhedron/double_description.py +753 -0
  92. sage/geometry/polyhedron/double_description_inhomogeneous.py +564 -0
  93. sage/geometry/polyhedron/face.py +1060 -0
  94. sage/geometry/polyhedron/generating_function.py +1810 -0
  95. sage/geometry/polyhedron/lattice_euclidean_group_element.py +178 -0
  96. sage/geometry/polyhedron/library.py +3502 -0
  97. sage/geometry/polyhedron/misc.py +121 -0
  98. sage/geometry/polyhedron/modules/all.py +1 -0
  99. sage/geometry/polyhedron/modules/formal_polyhedra_module.py +155 -0
  100. sage/geometry/polyhedron/palp_database.py +447 -0
  101. sage/geometry/polyhedron/parent.py +1279 -0
  102. sage/geometry/polyhedron/plot.py +1986 -0
  103. sage/geometry/polyhedron/ppl_lattice_polygon.py +556 -0
  104. sage/geometry/polyhedron/ppl_lattice_polytope.py +1257 -0
  105. sage/geometry/polyhedron/representation.py +1723 -0
  106. sage/geometry/pseudolines.py +515 -0
  107. sage/geometry/relative_interior.py +445 -0
  108. sage/geometry/toric_plotter.py +1103 -0
  109. sage/geometry/triangulation/all.py +2 -0
  110. sage/geometry/triangulation/base.cpython-314-aarch64-linux-musl.so +0 -0
  111. sage/geometry/triangulation/base.pyx +963 -0
  112. sage/geometry/triangulation/data.h +147 -0
  113. sage/geometry/triangulation/data.pxd +4 -0
  114. sage/geometry/triangulation/element.py +914 -0
  115. sage/geometry/triangulation/functions.h +10 -0
  116. sage/geometry/triangulation/functions.pxd +4 -0
  117. sage/geometry/triangulation/point_configuration.py +2256 -0
  118. sage/geometry/triangulation/triangulations.h +49 -0
  119. sage/geometry/triangulation/triangulations.pxd +7 -0
  120. sage/geometry/voronoi_diagram.py +319 -0
  121. sage/interfaces/all__sagemath_polyhedra.py +1 -0
  122. sage/interfaces/polymake.py +2028 -0
  123. sage/numerical/all.py +13 -0
  124. sage/numerical/all__sagemath_polyhedra.py +11 -0
  125. sage/numerical/backends/all.py +1 -0
  126. sage/numerical/backends/all__sagemath_polyhedra.py +1 -0
  127. sage/numerical/backends/cvxopt_backend.cpython-314-aarch64-linux-musl.so +0 -0
  128. sage/numerical/backends/cvxopt_backend.pyx +1006 -0
  129. sage/numerical/backends/cvxopt_backend_test.py +19 -0
  130. sage/numerical/backends/cvxopt_sdp_backend.cpython-314-aarch64-linux-musl.so +0 -0
  131. sage/numerical/backends/cvxopt_sdp_backend.pyx +382 -0
  132. sage/numerical/backends/cvxpy_backend.cpython-314-aarch64-linux-musl.so +0 -0
  133. sage/numerical/backends/cvxpy_backend.pxd +41 -0
  134. sage/numerical/backends/cvxpy_backend.pyx +934 -0
  135. sage/numerical/backends/cvxpy_backend_test.py +13 -0
  136. sage/numerical/backends/generic_backend_test.py +24 -0
  137. sage/numerical/backends/interactivelp_backend.cpython-314-aarch64-linux-musl.so +0 -0
  138. sage/numerical/backends/interactivelp_backend.pxd +36 -0
  139. sage/numerical/backends/interactivelp_backend.pyx +1231 -0
  140. sage/numerical/backends/interactivelp_backend_test.py +12 -0
  141. sage/numerical/backends/logging_backend.py +391 -0
  142. sage/numerical/backends/matrix_sdp_backend.cpython-314-aarch64-linux-musl.so +0 -0
  143. sage/numerical/backends/matrix_sdp_backend.pxd +15 -0
  144. sage/numerical/backends/matrix_sdp_backend.pyx +478 -0
  145. sage/numerical/backends/ppl_backend.cpython-314-aarch64-linux-musl.so +0 -0
  146. sage/numerical/backends/ppl_backend.pyx +1126 -0
  147. sage/numerical/backends/ppl_backend_test.py +13 -0
  148. sage/numerical/backends/scip_backend.cpython-314-aarch64-linux-musl.so +0 -0
  149. sage/numerical/backends/scip_backend.pxd +22 -0
  150. sage/numerical/backends/scip_backend.pyx +1289 -0
  151. sage/numerical/backends/scip_backend_test.py +13 -0
  152. sage/numerical/interactive_simplex_method.py +5338 -0
  153. sage/numerical/knapsack.py +665 -0
  154. sage/numerical/linear_functions.cpython-314-aarch64-linux-musl.so +0 -0
  155. sage/numerical/linear_functions.pxd +31 -0
  156. sage/numerical/linear_functions.pyx +1648 -0
  157. sage/numerical/linear_tensor.py +470 -0
  158. sage/numerical/linear_tensor_constraints.py +448 -0
  159. sage/numerical/linear_tensor_element.cpython-314-aarch64-linux-musl.so +0 -0
  160. sage/numerical/linear_tensor_element.pxd +6 -0
  161. sage/numerical/linear_tensor_element.pyx +459 -0
  162. sage/numerical/mip.cpython-314-aarch64-linux-musl.so +0 -0
  163. sage/numerical/mip.pxd +40 -0
  164. sage/numerical/mip.pyx +3667 -0
  165. sage/numerical/sdp.cpython-314-aarch64-linux-musl.so +0 -0
  166. sage/numerical/sdp.pxd +39 -0
  167. sage/numerical/sdp.pyx +1433 -0
  168. sage/rings/all__sagemath_polyhedra.py +3 -0
  169. sage/rings/polynomial/all__sagemath_polyhedra.py +10 -0
  170. sage/rings/polynomial/omega.py +982 -0
  171. sage/schemes/all__sagemath_polyhedra.py +2 -0
  172. sage/schemes/toric/all.py +10 -0
  173. sage/schemes/toric/chow_group.py +1248 -0
  174. sage/schemes/toric/divisor.py +2082 -0
  175. sage/schemes/toric/divisor_class.cpython-314-aarch64-linux-musl.so +0 -0
  176. sage/schemes/toric/divisor_class.pyx +322 -0
  177. sage/schemes/toric/fano_variety.py +1606 -0
  178. sage/schemes/toric/homset.py +650 -0
  179. sage/schemes/toric/ideal.py +451 -0
  180. sage/schemes/toric/library.py +1322 -0
  181. sage/schemes/toric/morphism.py +1958 -0
  182. sage/schemes/toric/points.py +1032 -0
  183. sage/schemes/toric/sheaf/all.py +1 -0
  184. sage/schemes/toric/sheaf/constructor.py +302 -0
  185. sage/schemes/toric/sheaf/klyachko.py +921 -0
  186. sage/schemes/toric/toric_subscheme.py +905 -0
  187. sage/schemes/toric/variety.py +3460 -0
  188. sage/schemes/toric/weierstrass.py +1078 -0
  189. sage/schemes/toric/weierstrass_covering.py +457 -0
  190. sage/schemes/toric/weierstrass_higher.py +288 -0
  191. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.info +10 -0
  192. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v03 +0 -0
  193. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v04 +0 -0
  194. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v05 +1 -0
  195. sage_wheels/share/reflexive_polytopes/Full2d/zzdb.v06 +1 -0
  196. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.info +22 -0
  197. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v04 +0 -0
  198. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v05 +0 -0
  199. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v06 +0 -0
  200. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v07 +0 -0
  201. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v08 +0 -0
  202. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v09 +0 -0
  203. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v10 +0 -0
  204. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v11 +1 -0
  205. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v12 +1 -0
  206. sage_wheels/share/reflexive_polytopes/Full3d/zzdb.v13 +1 -0
  207. sage_wheels/share/reflexive_polytopes/reflexive_polytopes_2d +80 -0
  208. sage_wheels/share/reflexive_polytopes/reflexive_polytopes_3d +37977 -0
sage/numerical/sdp.pyx ADDED
@@ -0,0 +1,1433 @@
1
+ # sage_setup: distribution = sagemath-polyhedra
2
+ r"""
3
+ Semidefinite Programming
4
+
5
+ A semidefinite program (:wikipedia:`SDP <Semidefinite_programming>`)
6
+ is an optimization problem (:wikipedia:`Optimization_(mathematics)>`)
7
+ of the following form
8
+
9
+ .. MATH::
10
+
11
+ \min \sum_{i,j=1}^n C_{ij}X_{ij} & \qquad \text{(Dual problem)}\\
12
+ \text{Subject to:} & \sum_{i,j=1}^n A_{ijk}X_{ij} = b_k, \qquad k=1\dots m\\
13
+ &X \succeq 0
14
+
15
+ where the `X_{ij}`, `1 \leq i,j \leq n` are `n^2` variables satisfying the symmetry
16
+ conditions `x_{ij} = x_{ji}` for all `i,j`, the `C_{ij}=C_{ji}`, `A_{ijk}=A_{kji}` and `b_k`
17
+ are real coefficients, and `X` is positive semidefinite, i.e., all the eigenvalues of `X` are nonnegative.
18
+ The closely related dual problem of this one is the following, where we denote by
19
+ `A_k` the matrix `(A_{kij})` and by `C` the matrix `(C_{ij})`,
20
+
21
+ .. MATH::
22
+
23
+ \max \sum_k b_k x_k & \qquad \text{(Primal problem)}\\
24
+ \text{Subject to:} & \sum_k x_k A_k \preceq C.
25
+
26
+ Here `(x_1,...,x_m)` is a vector of scalar variables.
27
+ A wide variety of problems in optimization can be formulated in one of these two standard
28
+ forms. Then, solvers are able to calculate an approximation to a solution.
29
+ Here we refer to the latter problem as primal, and to the former problem as dual.
30
+ The optimal value of the dual is always at least the
31
+ optimal value of the primal, and usually (although not always) they are equal.
32
+
33
+ For instance, suppose you want to maximize `x_1 - x_0` subject to
34
+
35
+ .. MATH::
36
+
37
+ \left( \begin{array}{cc} 1 & 2 \\ 2 & 3 \end{array} \right) x_0 +
38
+ \left( \begin{array}{cc} 3 & 4 \\ 4 & 5 \end{array} \right) x_1 \preceq
39
+ \left( \begin{array}{cc} 5 & 6 \\ 6 & 7 \end{array} \right),\quad
40
+ \left( \begin{array}{cc} 1 & 1 \\ 1 & 1 \end{array} \right) x_0 +
41
+ \left( \begin{array}{cc} 2 & 2 \\ 2 & 2 \end{array} \right) x_1 \preceq
42
+ \left( \begin{array}{cc} 3 & 3 \\ 3 & 3 \end{array} \right),
43
+ \quad x_0\geq 0, x_1\geq 0.
44
+
45
+ An SDP can give you an answer to the problem above. Here is how it's done:
46
+
47
+ #. You have to create an instance of :class:`SemidefiniteProgram`.
48
+ #. Create a dictionary `x` of integer variables via :meth:`~SemidefiniteProgram.new_variable`,
49
+ for example doing ``x = p.new_variable()`` if ``p`` is the name of the SDP instance.
50
+ #. Add those two matrix inequalities as inequality constraints via
51
+ :meth:`~SemidefiniteProgram.add_constraint`.
52
+ #. Add another matrix inequality to specify nonnegativity of `x`.
53
+ #. Specify the objective function via :meth:`~SemidefiniteProgram.set_objective`.
54
+ In our case it is `x_1 - x_0`. If it
55
+ is a pure constraint satisfaction problem, specify it as ``None``.
56
+ #. To check if everything is set up correctly, you can print the problem via
57
+ :meth:`show <sage.numerical.sdp.SemidefiniteProgram.show>`.
58
+ #. :meth:`Solve <sage.numerical.sdp.SemidefiniteProgram.solve>` it and print the solution.
59
+
60
+ The following example shows all these steps::
61
+
62
+ sage: p = SemidefiniteProgram()
63
+ sage: x = p.new_variable()
64
+ sage: p.set_objective(x[1] - x[0])
65
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
66
+ sage: a2 = matrix([[3, 4.], [4., 5.]])
67
+ sage: a3 = matrix([[5, 6.], [6., 7.]])
68
+ sage: b1 = matrix([[1, 1.], [1., 1.]])
69
+ sage: b2 = matrix([[2, 2.], [2., 2.]])
70
+ sage: b3 = matrix([[3, 3.], [3., 3.]])
71
+ sage: c1 = matrix([[1.0, 0],[0,0]],sparse=True)
72
+ sage: c2 = matrix([[0.0, 0],[0,1]],sparse=True)
73
+ sage: p.add_constraint(a1*x[0] + a2*x[1] <= a3)
74
+ sage: p.add_constraint(b1*x[0] + b2*x[1] <= b3)
75
+ sage: p.add_constraint(c1*x[0] + c2*x[1] >= matrix.zero(2,2,sparse=True))
76
+
77
+ sage: # needs cvxopt
78
+ sage: p.solver_parameter("show_progress", True)
79
+ sage: opt = p.solve()
80
+ pcost dcost gap pres dres k/t
81
+ 0: ...
82
+ ...
83
+ Optimal solution found.
84
+ sage: print('Objective Value: {}'.format(N(opt,3)))
85
+ Objective Value: 1.0
86
+ sage: [N(x, 3) for x in sorted(p.get_values(x).values())]
87
+ [3.0e-8, 1.0]
88
+ sage: p.show()
89
+ Maximization:
90
+ x_0 - x_1
91
+ Constraints:
92
+ constraint_0: [3.0 4.0][4.0 5.0]x_0 + [1.0 2.0][2.0 3.0]x_1 <= [5.0 6.0][6.0 7.0]
93
+ constraint_1: [2.0 2.0][2.0 2.0]x_0 + [1.0 1.0][1.0 1.0]x_1 <= [3.0 3.0][3.0 3.0]
94
+ constraint_2: [ 0.0 0.0][ 0.0 -1.0]x_0 + [-1.0 0.0][ 0.0 0.0]x_1 <= [0 0][0 0]
95
+ Variables:
96
+ x_0, x_1
97
+
98
+ Most solvers, e.g. the default Sage SDP solver CVXOPT, solve simultaneously the pair
99
+ of primal and dual problems. Thus we can get the optimizer `X` of the dual problem
100
+ as follows, as diagonal blocks, one per each constraint, via :meth:`~SemidefiniteProgram.dual_variable`.
101
+ E.g.::
102
+
103
+ sage: p.dual_variable(1) # rel tol 2e-03 # needs cvxopt
104
+ [ 85555.0 -85555.0]
105
+ [-85555.0 85555.0]
106
+
107
+ We can see that the optimal value of the dual is equal (up to numerical noise) to `opt`.::
108
+
109
+ sage: opt - ((p.dual_variable(0)*a3).trace() # tol 8e-08 # needs cvxopt
110
+ ....: + (p.dual_variable(1)*b3).trace())
111
+ 0.0
112
+
113
+ Dual variable blocks at optimality are orthogonal to "slack variables", that is,
114
+ matrices `C-\sum_k x_k A_k`, cf. (Primal problem) above, available via
115
+ :meth:`~SemidefiniteProgram.slack`. E.g.::
116
+
117
+ sage: (p.slack(0)*p.dual_variable(0)).trace() # tol 2e-07 # needs cvxopt
118
+ 0.0
119
+
120
+
121
+ More interesting example, the :func:`Lovasz theta <sage.graphs.lovasz_theta.lovasz_theta>` of the 7-gon::
122
+
123
+ sage: # needs sage.graphs
124
+ sage: c = graphs.CycleGraph(7)
125
+ sage: c2 = c.distance_graph(2).adjacency_matrix()
126
+ sage: c3 = c.distance_graph(3).adjacency_matrix()
127
+ sage: p.<y> = SemidefiniteProgram()
128
+ sage: p.add_constraint((1/7)*matrix.identity(7)>=-y[0]*c2-y[1]*c3)
129
+ sage: p.set_objective(y[0]*(c2**2).trace()+y[1]*(c3**2).trace())
130
+ sage: x = p.solve(); x + 1 # needs cvxopt
131
+ 3.31766...
132
+
133
+ Unlike in the previous example, the slack variable is very far from 0::
134
+
135
+ sage: p.slack(0).trace() # tol 1e-14 # needs cvxopt sage.graphs
136
+ 1.0
137
+
138
+ The default CVXOPT backend computes with the Real Double Field, for example::
139
+
140
+ sage: # needs cvxopt
141
+ sage: p = SemidefiniteProgram(solver='cvxopt')
142
+ sage: p.base_ring()
143
+ Real Double Field
144
+ sage: x = p.new_variable()
145
+ sage: 0.5 + 3/2*x[1]
146
+ 0.5 + 1.5*x_0
147
+
148
+ For representing an SDP with exact data, there is another backend::
149
+
150
+ sage: from sage.numerical.backends.matrix_sdp_backend import MatrixSDPBackend
151
+ sage: p = SemidefiniteProgram(solver=MatrixSDPBackend, base_ring=QQ)
152
+ sage: p.base_ring()
153
+ Rational Field
154
+ sage: x = p.new_variable()
155
+ sage: 1/2 + 3/2 * x[1]
156
+ 1/2 + 3/2*x_0
157
+
158
+
159
+ Linear Variables and Expressions
160
+ --------------------------------
161
+
162
+
163
+ To make your code more readable, you can construct
164
+ :class:`SDPVariable` objects that can be arbitrarily named and
165
+ indexed. Internally, this is then translated back to the `x_i`
166
+ variables. For example::
167
+
168
+ sage: sdp.<a,b> = SemidefiniteProgram()
169
+ sage: a
170
+ SDPVariable
171
+ sage: 5 + a[1] + 2*b[3]
172
+ 5 + x_0 + 2*x_1
173
+
174
+ Indices can be any object, not necessarily integers. Multi-indices are
175
+ also allowed::
176
+
177
+ sage: a[4, 'string', QQ]
178
+ x_2
179
+ sage: a[4, 'string', QQ] - 7*b[2]
180
+ x_2 - 7*x_3
181
+ sage: sdp.show()
182
+ Maximization:
183
+ <BLANKLINE>
184
+ Constraints:
185
+ Variables:
186
+ a[1], b[3], a[(4, 'string', Rational Field)], b[2]
187
+
188
+ Index of functions and methods
189
+ ------------------------------
190
+
191
+ Below are listed the methods of :class:`SemidefiniteProgram`. This module
192
+ also implements the :class:`SDPSolverException` exception, as well as the
193
+ :class:`SDPVariable` class.
194
+
195
+ .. csv-table::
196
+ :class: contentstable
197
+ :widths: 30, 70
198
+ :delim: |
199
+
200
+ :meth:`~SemidefiniteProgram.add_constraint` | Add a constraint to the ``SemidefiniteProgram``
201
+ :meth:`~SemidefiniteProgram.base_ring` | Return the base ring
202
+ :meth:`~SemidefiniteProgram.dual_variable` | Return optimal dual variable block
203
+ :meth:`~SemidefiniteProgram.get_backend` | Return the backend instance used
204
+ :meth:`~SemidefiniteProgram.get_values` | Return values found by the previous call to ``solve()``
205
+ :meth:`~SemidefiniteProgram.linear_constraints_parent` | Return the parent for all linear constraints
206
+ :meth:`~SemidefiniteProgram.linear_function` | Construct a new linear function
207
+ :meth:`~SemidefiniteProgram.linear_functions_parent` | Return the parent for all linear functions
208
+ :meth:`~SemidefiniteProgram.new_variable` | Return an instance of ``SDPVariable`` associated to the ``SemidefiniteProgram``
209
+ :meth:`~SemidefiniteProgram.number_of_constraints` | Return the number of constraints assigned so far
210
+ :meth:`~SemidefiniteProgram.number_of_variables` | Return the number of variables used so far
211
+ :meth:`~SemidefiniteProgram.set_objective` | Set the objective of the ``SemidefiniteProgram``
212
+ :meth:`~SemidefiniteProgram.set_problem_name` | Set the name of the ``SemidefiniteProgram``
213
+ :meth:`~SemidefiniteProgram.slack` | Return the slack variable block at the optimum
214
+ :meth:`~SemidefiniteProgram.show` | Display the ``SemidefiniteProgram`` in a human-readable way
215
+ :meth:`~SemidefiniteProgram.solve` | Solve the ``SemidefiniteProgram``
216
+ :meth:`~SemidefiniteProgram.solver_parameter` | Return or define a solver parameter
217
+ :meth:`~SemidefiniteProgram.sum` | Efficiently compute the sum of a sequence of LinearFunction elements
218
+
219
+ AUTHORS:
220
+
221
+ - Ingolfur Edvardsson (2014/08): added extension for exact computation
222
+
223
+ - Dima Pasechnik (2014-) : supervision, minor fixes, duality
224
+ """
225
+ # ****************************************************************************
226
+ # Copyright (C) 2014 Ingolfur Edvardsson <ingolfured@gmail.com>
227
+ #
228
+ # This program is free software: you can redistribute it and/or modify
229
+ # it under the terms of the GNU General Public License as published by
230
+ # the Free Software Foundation, either version 2 of the License, or
231
+ # (at your option) any later version.
232
+ # https://www.gnu.org/licenses/
233
+ # ****************************************************************************
234
+
235
+ from sage.structure.parent cimport Parent
236
+ from sage.structure.element cimport Element
237
+ from sage.numerical.linear_functions import LinearFunction, LinearConstraint
238
+ from sage.matrix.constructor import matrix
239
+ from sage.structure.element import Matrix
240
+
241
+
242
+ cdef class SemidefiniteProgram(SageObject):
243
+ r"""
244
+ The ``SemidefiniteProgram`` class is the link between Sage, semidefinite
245
+ programming (SDP) and semidefinite programming solvers.
246
+
247
+ A Semidefinite Programming (SDP) consists of variables, linear
248
+ constraints on these variables, and an objective function which is to be
249
+ maximised or minimised under these constraints.
250
+
251
+ See the :wikipedia:`Semidefinite_programming` for further information on semidefinite
252
+ programming, and the :mod:`SDP module <sage.numerical.sdp>` for its use in
253
+ Sage.
254
+
255
+ INPUT:
256
+
257
+ - ``solver`` -- selects a solver:
258
+
259
+ - CVXOPT (``solver="CVXOPT"``). See the `CVXOPT <http://www.cvxopt.org/>`_
260
+ website.
261
+
262
+ - If ``solver=None`` (default), the default solver is used (see
263
+ :func:`default_sdp_solver`)
264
+
265
+ - ``maximization``
266
+
267
+ - When set to ``True`` (default), the ``SemidefiniteProgram``
268
+ is defined as a maximization.
269
+
270
+ - When set to ``False``, the ``SemidefiniteProgram`` is
271
+ defined as a minimization.
272
+
273
+
274
+ .. SEEALSO::
275
+
276
+ - :func:`default_sdp_solver` -- returns/sets the default SDP solver
277
+
278
+ EXAMPLES:
279
+
280
+ Computation of a basic Semidefinite Program::
281
+
282
+ sage: p = SemidefiniteProgram(maximization=False)
283
+ sage: x = p.new_variable()
284
+ sage: p.set_objective(x[0] - x[1])
285
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
286
+ sage: a2 = matrix([[3, 4.], [4., 5.]])
287
+ sage: a3 = matrix([[5, 6.], [6., 7.]])
288
+ sage: b1 = matrix([[1, 1.], [1., 1.]])
289
+ sage: b2 = matrix([[2, 2.], [2., 2.]])
290
+ sage: b3 = matrix([[3, 3.], [3., 3.]])
291
+ sage: p.add_constraint(a1*x[0] + a2*x[1] <= a3)
292
+ sage: p.add_constraint(b1*x[0] + b2*x[1] <= b3)
293
+ sage: N(p.solve(), 2) # needs cvxopt
294
+ -3.0
295
+ """
296
+
297
+ def __init__(self, solver=None, maximization=True,
298
+ names=tuple(), **kwds):
299
+ r"""
300
+ Constructor for the ``SemidefiniteProgram`` class.
301
+
302
+ INPUT:
303
+
304
+ - ``solver`` -- the following solvers should be available through this class:
305
+
306
+ - CVXOPT (``solver="CVXOPT"``). See the `CVXOPT <http://www.cvxopt.org/>`_
307
+ web site.
308
+
309
+ - If ``solver=None`` (default), the default solver is used (see
310
+ ``default_sdp_solver`` method.
311
+
312
+ - ``maximization``
313
+
314
+ - When set to ``True`` (default), the ``SemidefiniteProgram``
315
+ is defined as a maximization.
316
+ - When set to ``False``, the ``SemidefiniteProgram`` is
317
+ defined as a minimization.
318
+
319
+ - ``names`` -- list/tuple/iterable of string. Default names of
320
+ the SDP variables. Used to enable the ``sdp.<x> =
321
+ SemidefiniteProgram()`` syntax.
322
+
323
+ - other keyword arguments are passed to the solver.
324
+
325
+ .. SEEALSO::
326
+
327
+ - :meth:`default_sdp_solver` -- returns/Sets the default SDP solver
328
+
329
+ EXAMPLES::
330
+
331
+ sage: p = SemidefiniteProgram(maximization=True)
332
+ """
333
+ self._first_variable_names = list(names)
334
+ from sage.numerical.backends.generic_sdp_backend import get_solver
335
+ self._backend = get_solver(solver=solver, **kwds)
336
+ if not maximization:
337
+ self._backend.set_sense(-1)
338
+
339
+ # Associates an index to the variables
340
+ self._variables = {}
341
+
342
+ def linear_functions_parent(self):
343
+ """
344
+ Return the parent for all linear functions.
345
+
346
+ EXAMPLES::
347
+
348
+ sage: p = SemidefiniteProgram()
349
+ sage: p.linear_functions_parent()
350
+ Linear functions over Real Double Field
351
+ """
352
+ if self._linear_functions_parent is None:
353
+ base_ring = self._backend.base_ring()
354
+ from sage.numerical.linear_functions import LinearFunctionsParent
355
+ self._linear_functions_parent = LinearFunctionsParent(base_ring)
356
+ return self._linear_functions_parent
357
+
358
+ def linear_constraints_parent(self):
359
+ """
360
+ Return the parent for all linear constraints.
361
+
362
+ See :mod:`~sage.numerical.linear_functions` for more
363
+ details.
364
+
365
+ EXAMPLES::
366
+
367
+ sage: p = SemidefiniteProgram()
368
+ sage: p.linear_constraints_parent()
369
+ Linear constraints over Real Double Field
370
+ """
371
+ if self._linear_constraints_parent is None:
372
+ from sage.numerical.linear_functions import LinearConstraintsParent
373
+ LF = self.linear_functions_parent()
374
+ self._linear_constraints_parent = LinearConstraintsParent(LF)
375
+ return self._linear_constraints_parent
376
+
377
+ def __call__(self, x):
378
+ """
379
+ Construct a new linear function.
380
+
381
+ EXAMPLES::
382
+
383
+ sage: p = SemidefiniteProgram()
384
+ sage: p.linear_function({0:1})
385
+ x_0
386
+ """
387
+ parent = self.linear_functions_parent()
388
+ return parent(x)
389
+
390
+ linear_function = __call__
391
+
392
+ def _repr_(self):
393
+ r"""
394
+ Return a short description of the ``SemidefiniteProgram``.
395
+
396
+ EXAMPLES::
397
+
398
+ sage: p = SemidefiniteProgram()
399
+ sage: x = p.new_variable()
400
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
401
+ sage: a2 = matrix([[3, 4.], [4., 5.]])
402
+ sage: a3 = matrix([[5, 6.], [6., 7.]])
403
+ sage: b1 = matrix([[1, 1.], [1., 1.]])
404
+ sage: b2 = matrix([[2, 2.], [2., 2.]])
405
+ sage: b3 = matrix([[3, 3.], [3., 3.]])
406
+ sage: p.add_constraint(a1*x[0] + a2*x[1] <= a3)
407
+ sage: p.add_constraint(b1*x[0] + b2*x[1] <= b3)
408
+ sage: p.add_constraint(b1*x[0] + b2*x[1] <= a1)
409
+ sage: print(p)
410
+ Semidefinite Program ( maximization, 2 variables, 3 constraints )
411
+ """
412
+ cdef GenericSDPBackend b = self._backend
413
+
414
+ return ("Semidefinite Program " +
415
+
416
+ ( "\"" +self._backend.problem_name()+ "\""
417
+ if (str(self._backend.problem_name()) != "") else "")+
418
+
419
+ " ( " + ("maximization" if b.is_maximization() else "minimization" ) +
420
+
421
+ ", " + str(b.ncols()) + " variables, " +
422
+ str(b.nrows()) + " constraints )")
423
+
424
+ def __getitem__(self, v):
425
+ r"""
426
+ Return the symbolic variable corresponding to the key
427
+ from a default dictionary.
428
+
429
+ It returns the element asked, and otherwise creates it.
430
+ If necessary, it also creates the default dictionary.
431
+
432
+ This method lets the user define LinearProgram without having to
433
+ define independent dictionaries when it is not necessary for him.
434
+
435
+ EXAMPLES::
436
+
437
+ sage: p = SemidefiniteProgram()
438
+ sage: p.set_objective(p['x'] + p['z'])
439
+ sage: p['x']
440
+ x_0
441
+ """
442
+
443
+ try:
444
+ return self._default_sdpvariable[v]
445
+ except TypeError:
446
+ self._default_sdpvariable = self.new_variable()
447
+ return self._default_sdpvariable[v]
448
+
449
+ def base_ring(self):
450
+ """
451
+ Return the base ring.
452
+
453
+ OUTPUT: a ring. The coefficients that the chosen solver supports
454
+
455
+ EXAMPLES::
456
+
457
+ sage: p = SemidefiniteProgram(solver='cvxopt')
458
+ sage: p.base_ring()
459
+ Real Double Field
460
+ """
461
+ return self._backend.base_ring()
462
+
463
+ def set_problem_name(self, name):
464
+ r"""
465
+ Set the name of the ``SemidefiniteProgram``.
466
+
467
+ INPUT:
468
+
469
+ - ``name`` -- string representing the name of the
470
+ ``SemidefiniteProgram``
471
+
472
+ EXAMPLES::
473
+
474
+ sage: p = SemidefiniteProgram()
475
+ sage: p.set_problem_name("Test program")
476
+ sage: p
477
+ Semidefinite Program "Test program" ( maximization, 0 variables, 0 constraints )
478
+ """
479
+ self._backend.problem_name(name)
480
+
481
+ def new_variable(self, name=""):
482
+ r"""
483
+ Return an instance of :class:`SDPVariable` associated
484
+ to the current instance of :class:`SemidefiniteProgram`.
485
+
486
+ A new variable ``x`` is defined by::
487
+
488
+ sage: p = SemidefiniteProgram()
489
+ sage: x = p.new_variable()
490
+
491
+ It behaves exactly as an usual dictionary would. It can use any key
492
+ argument you may like, as ``x[5]`` or ``x["b"]``, and has methods
493
+ ``items()`` and ``keys()``.
494
+
495
+ INPUT:
496
+
497
+ - ``dim`` -- integer; defines the dimension of the dictionary
498
+ If ``x`` has dimension `2`, its fields will be of the form
499
+ ``x[key1][key2]``. Deprecated.
500
+
501
+ - ``name`` -- string; associates a name to the variable
502
+
503
+ EXAMPLES::
504
+
505
+ sage: p = SemidefiniteProgram()
506
+ sage: x = p.new_variable()
507
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
508
+ sage: p.add_constraint(a1*x[0] + a1*x[3] <= 0)
509
+ sage: p.show()
510
+ Maximization:
511
+ <BLANKLINE>
512
+ Constraints:
513
+ constraint_0: [1.0 2.0][2.0 3.0]x_0 + [1.0 2.0][2.0 3.0]x_1 <= [0 0][0 0]
514
+ Variables:
515
+ x_0, x_1
516
+ """
517
+ if not name and self._first_variable_names:
518
+ name = self._first_variable_names.pop(0)
519
+
520
+ return sdp_variable_parent(self,
521
+ name=name)
522
+
523
+ def _first_ngens(self, n):
524
+ """
525
+ Construct the first `n` SDPVariables.
526
+
527
+ This method is used for the generator syntax (see below). You
528
+ probably should not use it for anything else.
529
+
530
+ INPUT:
531
+
532
+ - ``n`` -- integer; the number of variables to construct
533
+
534
+ OUTPUT:
535
+
536
+ A tuple of not necessarily positive :class:`SDPVariable`
537
+ instances.
538
+
539
+ EXAMPLES::
540
+
541
+ sage: sdp.<a,b> = SemidefiniteProgram()
542
+ sage: a[0] + b[2]
543
+ x_0 + x_1
544
+ sage: sdp.show()
545
+ Maximization:
546
+ <BLANKLINE>
547
+ Constraints:
548
+ Variables:
549
+ a[0], b[2]
550
+ """
551
+ return tuple(self.new_variable() for i in range(n))
552
+
553
+ def gen(self, i):
554
+ """
555
+ Return the linear variable `x_i`.
556
+
557
+ EXAMPLES::
558
+
559
+ sage: sdp = SemidefiniteProgram()
560
+ sage: sdp.gen(0)
561
+ x_0
562
+ sage: [sdp.gen(i) for i in range(10)]
563
+ [x_0, x_1, x_2, x_3, x_4, x_5, x_6, x_7, x_8, x_9]
564
+ """
565
+ return self.linear_functions_parent().gen(i)
566
+
567
+ cpdef int number_of_constraints(self) noexcept:
568
+ r"""
569
+ Return the number of constraints assigned so far.
570
+
571
+ EXAMPLES::
572
+
573
+ sage: p = SemidefiniteProgram(solver = "cvxopt")
574
+ sage: x = p.new_variable()
575
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
576
+ sage: a2 = matrix([[3, 4.], [4., 5.]])
577
+ sage: a3 = matrix([[5, 6.], [6., 7.]])
578
+ sage: b1 = matrix([[1, 1.], [1., 1.]])
579
+ sage: b2 = matrix([[2, 2.], [2., 2.]])
580
+ sage: b3 = matrix([[3, 3.], [3., 3.]])
581
+ sage: p.add_constraint(a1*x[0] + a2*x[1] <= a3)
582
+ sage: p.add_constraint(b1*x[0] + b2*x[1] <= b3)
583
+ sage: p.add_constraint(b1*x[0] + a2*x[1] <= b3)
584
+ sage: p.number_of_constraints()
585
+ 3
586
+ """
587
+ return self._backend.nrows()
588
+
589
+ cpdef int number_of_variables(self) noexcept:
590
+ r"""
591
+ Return the number of variables used so far.
592
+
593
+ EXAMPLES::
594
+
595
+ sage: p = SemidefiniteProgram()
596
+ sage: a = matrix([[1, 2.], [2., 3.]])
597
+ sage: p.add_constraint(a*p[0] - a*p[2] <= 2*a*p[4] )
598
+ sage: p.number_of_variables()
599
+ 3
600
+ """
601
+ return self._backend.ncols()
602
+
603
+ def show(self):
604
+ r"""
605
+ Display the :class:`SemidefiniteProgram` in a human-readable way.
606
+
607
+ EXAMPLES:
608
+
609
+ When constraints and variables have names ::
610
+
611
+ sage: p = SemidefiniteProgram()
612
+ sage: x = p.new_variable(name='hihi')
613
+ sage: a1 = matrix([[1,2],[2,3]])
614
+ sage: a2 = matrix([[2,3],[3,4]])
615
+ sage: a3 = matrix([[3,4],[4,5]])
616
+ sage: p.set_objective(x[0] - x[1])
617
+ sage: p.add_constraint(a1*x[0] + a2*x[1]<= a3)
618
+ sage: p.show()
619
+ Maximization:
620
+ hihi[0] - hihi[1]
621
+ Constraints:
622
+ constraint_0: [1.0 2.0][2.0 3.0]hihi[0] + [2.0 3.0][3.0 4.0]hihi[1] <= [3.0 4.0][4.0 5.0]
623
+ Variables:
624
+ hihi[0], hihi[1]
625
+ """
626
+ cdef int i, j
627
+ cdef GenericSDPBackend b = self._backend
628
+
629
+ # inv_variables associates a SDPVariable object to an id
630
+ inv_variables = {}
631
+ for (v, id) in self._variables.iteritems():
632
+ inv_variables[id] = v
633
+
634
+ # varid_name associates variables id to names
635
+ varid_name = {}
636
+ for 0<= i < b.ncols():
637
+ s = b.col_name(i)
638
+ varid_name[i] = s if s else 'x_'+str(i)
639
+
640
+ ##### Sense and objective function
641
+ print("Maximization:" if b.is_maximization() else "Minimization:")
642
+ print(" ", end=" ")
643
+ first = True
644
+ for 0<= i< b.ncols():
645
+ c = b.objective_coefficient(i)
646
+ if c == 0:
647
+ continue
648
+ print((("+ " if (not first and c>0) else "") +
649
+ ("" if c == 1 else ("- " if c == -1 else str(c)+" ")) + varid_name[i]
650
+ ), end=" ")
651
+ first = False
652
+ if b.obj_constant_term > self._backend.zero():
653
+ print("+ {}".format(b.obj_constant_term))
654
+ elif b.obj_constant_term < self._backend.zero():
655
+ print("- {}".format(-b.obj_constant_term))
656
+ print("\n")
657
+
658
+ ##### Constraints
659
+ print("Constraints:")
660
+ for i in range(b.nrows()):
661
+ indices, values = b.row(i)
662
+ print(" ", end=" ")
663
+ # Constraint's name
664
+ if b.row_name(i):
665
+ print(b.row_name(i)+":", end=" ")
666
+ first = True
667
+ l = sorted(zip(indices,values))
668
+ l.reverse()
669
+ if l[-1][0] == -1:
670
+ _, last_value = l.pop()
671
+ else:
672
+ last_value = matrix.zero( l[0][1].dimensions()[0],l[0][1].dimensions()[1] )
673
+ l.reverse()
674
+ for j, c in l:
675
+ if c == 0:
676
+ continue
677
+ print((("+ " if (not first) else "") +
678
+ ( str(repr(c).replace('\n',"") ) )+varid_name[j]),
679
+ end=" ")
680
+ first = False
681
+ print(("<= "), end=" ")
682
+ print(repr(-last_value).replace('\n',""))
683
+
684
+ ##### Variables
685
+ print("Variables:")
686
+ print(" ", end=" ")
687
+ for 0<= i < b.ncols()-1:
688
+ print(str(varid_name[i]) + ", ", end=" ")
689
+ print(str(varid_name[b.ncols()-1]))
690
+
691
+ def get_values(self, *lists):
692
+ r"""
693
+ Return values found by the previous call to ``solve()``.
694
+
695
+ INPUT:
696
+
697
+ - Any instance of :class:`SDPVariable` (or one of its elements),
698
+ or lists of them.
699
+
700
+ OUTPUT:
701
+
702
+ - Each instance of :class:`SDPVariable` is replaced by a dictionary
703
+ containing the numerical values found for each
704
+ corresponding variable in the instance.
705
+ - Each element of an instance of a :class:`SDPVariable` is replaced
706
+ by its corresponding numerical value.
707
+
708
+ EXAMPLES::
709
+
710
+ sage: p = SemidefiniteProgram(solver = "cvxopt", maximization = False)
711
+ sage: x = p.new_variable()
712
+ sage: p.set_objective(x[3] - x[5])
713
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
714
+ sage: a2 = matrix([[3, 4.], [4., 5.]])
715
+ sage: a3 = matrix([[5, 6.], [6., 7.]])
716
+ sage: b1 = matrix([[1, 1.], [1., 1.]])
717
+ sage: b2 = matrix([[2, 2.], [2., 2.]])
718
+ sage: b3 = matrix([[3, 3.], [3., 3.]])
719
+ sage: p.add_constraint(a1*x[3] + a2*x[5] <= a3)
720
+ sage: p.add_constraint(b1*x[3] + b2*x[5] <= b3)
721
+ sage: N(p.solve(), 3) # needs cvxopt
722
+ -3.0
723
+
724
+ To return the optimal value of ``x[3]``::
725
+
726
+ sage: N(p.get_values(x[3]),3) # needs cvxopt
727
+ -1.0
728
+
729
+ To get a dictionary identical to ``x`` containing optimal
730
+ values for the corresponding variables ::
731
+
732
+ sage: x_sol = p.get_values(x) # needs cvxopt
733
+ sage: sorted(x_sol) # needs cvxopt
734
+ [3, 5]
735
+ """
736
+ val = []
737
+ for l in lists:
738
+ if isinstance(l, SDPVariable):
739
+ c = {}
740
+ for k, v in l.items():
741
+ c[k] = self._backend.get_variable_value(self._variables[v])
742
+ val.append(c)
743
+ elif isinstance(l, list):
744
+ if len(l) == 1:
745
+ val.append([self.get_values(l[0])])
746
+ else:
747
+ c = []
748
+ [c.append(self.get_values(ll)) for ll in l]
749
+ val.append(c)
750
+ elif l in self._variables:
751
+ #val.append(self._values[l])
752
+ val.append(self._backend.get_variable_value(self._variables[l]))
753
+
754
+ if len(lists) == 1:
755
+ return val[0]
756
+ else:
757
+ return val
758
+
759
+ def set_objective(self, obj):
760
+ r"""
761
+ Set the objective of the :class:`SemidefiniteProgram`.
762
+
763
+ INPUT:
764
+
765
+ - ``obj`` -- a semidefinite function to be optimized
766
+ (can also be set to ``None`` or ``0`` when just
767
+ looking for a feasible solution)
768
+
769
+ EXAMPLES:
770
+
771
+ Let's solve the following semidefinite program:
772
+
773
+ .. MATH::
774
+
775
+ \begin{aligned}
776
+ \text{maximize} &\qquad x + 5y \qquad \\
777
+ \text{subject to} &\qquad \left( \begin{array}{cc} 1 & 2 \\ 2 & 3 \end{array} \right) x +
778
+ \left( \begin{array}{cc} 1 & 1 \\ 1 & 1 \end{array} \right) y \preceq
779
+ \left( \begin{array}{cc} 1 & -1 \\ -1 & 1 \end{array} \right)
780
+ \end{aligned}
781
+
782
+ This SDP can be solved as follows::
783
+
784
+ sage: p = SemidefiniteProgram(maximization=True)
785
+ sage: x = p.new_variable()
786
+ sage: p.set_objective(x[1] + 5*x[2])
787
+ sage: a1 = matrix([[1,2],[2,3]])
788
+ sage: a2 = matrix([[1,1],[1,1]])
789
+ sage: a3 = matrix([[1,-1],[-1,1]])
790
+ sage: p.add_constraint(a1*x[1] + a2*x[2] <= a3)
791
+ sage: N(p.solve(), digits=3) # needs cvxopt
792
+ 16.2
793
+ sage: p.set_objective(None)
794
+ sage: _ = p.solve() # needs cvxopt
795
+ """
796
+ cdef list values = []
797
+
798
+ # If the objective is None, or a constant, we want to remember
799
+ # that the objective function has been defined ( the user did not
800
+ # forget it ). In some SDO problems, you just want a feasible solution
801
+ # and do not care about any function being optimal.
802
+ cdef int i
803
+
804
+ if obj is not None:
805
+ f = obj.dict()
806
+ else:
807
+ f = {-1: 0}
808
+ d = f.pop(-1, self._backend.zero())
809
+
810
+ for i in range(self._backend.ncols()):
811
+ values.append(f.get(i,self._backend.zero()))
812
+ self._backend.set_objective(values, d)
813
+
814
+ def add_constraint(self, linear_function, name=None):
815
+ r"""
816
+ Add a constraint to the ``SemidefiniteProgram``.
817
+
818
+ INPUT:
819
+
820
+ - ``linear_function`` -- two different types of arguments are possible:
821
+
822
+ - A linear function. In this case, arguments ``min`` or ``max``
823
+ have to be specified.
824
+ - A linear constraint of the form ``A <= B``, ``A >= B``,
825
+ ``A <= B <= C``, ``A >= B >= C`` or ``A == B``. In this
826
+ case, arguments ``min`` and ``max`` will be ignored.
827
+
828
+ - ``name`` -- a name for the constraint
829
+
830
+ EXAMPLES:
831
+
832
+ Let's solve the following semidefinite program:
833
+
834
+ .. MATH::
835
+
836
+ \begin{aligned}
837
+ \text{maximize} &\qquad x + 5y \qquad \\
838
+ \text{subject to} &\qquad \left( \begin{array}{cc} 1 & 2 \\ 2 & 3 \end{array} \right) x +
839
+ \left( \begin{array}{cc} 1 & 1 \\ 1 & 1 \end{array} \right) y \preceq
840
+ \left( \begin{array}{cc} 1 & -1 \\ -1 & 1 \end{array} \right)
841
+ \end{aligned}
842
+
843
+ This SDP can be solved as follows::
844
+
845
+ sage: p = SemidefiniteProgram(maximization=True)
846
+ sage: x = p.new_variable()
847
+ sage: p.set_objective(x[1] + 5*x[2])
848
+ sage: a1 = matrix([[1,2],[2,3]])
849
+ sage: a2 = matrix([[1,1],[1,1]])
850
+ sage: a3 = matrix([[1,-1],[-1,1]])
851
+ sage: p.add_constraint(a1*x[1] + a2*x[2] <= a3)
852
+ sage: N(p.solve(), digits=3) # needs cvxopt
853
+ 16.2
854
+
855
+ One can also define double-bounds or equality using the symbol
856
+ ``>=`` or ``==``::
857
+
858
+ sage: p = SemidefiniteProgram(maximization=True)
859
+ sage: x = p.new_variable()
860
+ sage: p.set_objective(x[1] + 5*x[2])
861
+ sage: a1 = matrix([[1,2],[2,3]])
862
+ sage: a2 = matrix([[1,1],[1,1]])
863
+ sage: a3 = matrix([[1,-1],[-1,1]])
864
+ sage: p.add_constraint(a3 >= a1*x[1] + a2*x[2])
865
+ sage: N(p.solve(), digits=3) # needs cvxopt
866
+ 16.2
867
+
868
+ TESTS:
869
+
870
+ Complex constraints::
871
+
872
+ sage: p = SemidefiniteProgram()
873
+ sage: b = p.new_variable()
874
+ sage: a1 = matrix([[1,2],[2,3]])
875
+ sage: a2 = matrix([[1,-2],[-2,4]])
876
+ sage: p.add_constraint(a1*b[8] - a1*b[15] <= a2*b[8])
877
+ sage: p.show()
878
+ Maximization:
879
+ <BLANKLINE>
880
+ Constraints:
881
+ constraint_0: [ 0.0 4.0][ 4.0 -1.0]x_0 + [-1.0 -2.0][-2.0 -3.0]x_1 <= [0 0][0 0]
882
+ Variables:
883
+ x_0, x_1
884
+
885
+ Empty constraint::
886
+
887
+ sage: p = SemidefiniteProgram()
888
+ sage: p.add_constraint(sum([]))
889
+ """
890
+ if linear_function is 0:
891
+ return
892
+
893
+ from sage.numerical.linear_tensor_constraints import LinearTensorConstraint
894
+ from sage.numerical.linear_tensor import LinearTensor
895
+
896
+ if isinstance(linear_function, (LinearTensorConstraint,
897
+ LinearConstraint)):
898
+ c = linear_function
899
+ if c.is_equation():
900
+ self.add_constraint(c.lhs()-c.rhs(), name=name)
901
+ self.add_constraint(-c.lhs()+c.rhs(), name=name)
902
+ else:
903
+ self.add_constraint(c.lhs()-c.rhs(), name=name)
904
+
905
+ elif isinstance(linear_function, (LinearFunction, LinearTensor)):
906
+ l = sorted(linear_function.dict().items())
907
+ self._backend.add_linear_constraint(l, name)
908
+
909
+ else:
910
+ raise ValueError('argument must be a linear function or constraint, got '+str(linear_function))
911
+
912
+ def solve(self, objective_only=False):
913
+ r"""
914
+ Solve the :class:`SemidefiniteProgram`.
915
+
916
+ INPUT:
917
+
918
+ - ``objective_only`` -- boolean:
919
+
920
+ - when set to ``True``, only the objective function is returned
921
+ - when set to ``False`` (default), the optimal numerical values
922
+ are stored (takes computational time)
923
+
924
+ OUTPUT: the optimal value taken by the objective function
925
+
926
+ TESTS:
927
+
928
+ The SDP from the header of this module::
929
+
930
+ sage: p = SemidefiniteProgram(maximization=False)
931
+ sage: x = p.new_variable()
932
+ sage: p.set_objective(x[0] - x[1])
933
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
934
+ sage: a2 = matrix([[3, 4.], [4., 2.]])
935
+ sage: a3 = matrix([[5, 6.], [6., 7.]])
936
+ sage: b1 = matrix([[1, 1.], [1., 1.]])
937
+ sage: b2 = matrix([[2, 2.], [2., 1.]])
938
+ sage: b3 = matrix([[3, 3.], [3., 3.]])
939
+ sage: p.add_constraint(a1*x[0] + a2*x[1] <= a3)
940
+ sage: p.add_constraint(b1*x[0] + b2*x[1] <= b3)
941
+
942
+ sage: # needs cvxopt
943
+ sage: N(p.solve(), 4)
944
+ -11.
945
+ sage: x = p.get_values(x)
946
+ sage: N(x[0],4)
947
+ -8.0
948
+ sage: N(x[1],4)
949
+ 3.0
950
+ """
951
+ self._backend.solve()
952
+ return self._backend.get_objective_value()
953
+
954
+ cpdef dual_variable(self, int i, sparse=False):
955
+ """
956
+ The `i`-th dual variable.
957
+
958
+ Available after ``self.solve()`` is called, otherwise the result is
959
+ undefined.
960
+
961
+ INPUT:
962
+
963
+ - ``index`` -- integer; the constraint's id
964
+
965
+ OUTPUT: the matrix of the `i`-th dual variable
966
+
967
+ EXAMPLES:
968
+
969
+ Dual objective value is the same as the primal one::
970
+
971
+ sage: p = SemidefiniteProgram(maximization=False)
972
+ sage: x = p.new_variable()
973
+ sage: p.set_objective(x[0] - x[1])
974
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
975
+ sage: a2 = matrix([[3, 4.], [4., 5.]])
976
+ sage: a3 = matrix([[5, 6.], [6., 7.]])
977
+ sage: b1 = matrix([[1, 1.], [1., 1.]])
978
+ sage: b2 = matrix([[2, 2.], [2., 2.]])
979
+ sage: b3 = matrix([[3, 3.], [3., 3.]])
980
+ sage: p.add_constraint(a1*x[0] + a2*x[1] <= a3)
981
+ sage: p.add_constraint(b1*x[0] + b2*x[1] <= b3)
982
+
983
+ sage: # needs cvxopt
984
+ sage: p.solve() # tol 1e-08
985
+ -3.0
986
+ sage: x = p.get_values(x).values()
987
+ sage: -(a3*p.dual_variable(0)).trace() - (b3*p.dual_variable(1)).trace() # tol 1e-07
988
+ -3.0
989
+
990
+ Dual variable is orthogonal to the slack ::
991
+
992
+ sage: # needs cvxopt
993
+ sage: g = sum((p.slack(j)*p.dual_variable(j)).trace() for j in range(2)); g # tol 1.2e-08
994
+ 0.0
995
+
996
+ TESTS::
997
+
998
+ sage: p.dual_variable(7) # needs cvxopt
999
+ Traceback (most recent call last):
1000
+ ...
1001
+ IndexError: list index out of range
1002
+ """
1003
+ return self._backend.dual_variable(i, sparse=sparse)
1004
+
1005
+ cpdef slack(self, int i, sparse=False):
1006
+ """
1007
+ Slack of the `i`-th constraint.
1008
+
1009
+ Available after ``self.solve()`` is called, otherwise the result is
1010
+ undefined.
1011
+
1012
+ INPUT:
1013
+
1014
+ - ``index`` -- integer; the constraint's id
1015
+
1016
+ OUTPUT: the matrix of the slack of the `i`-th constraint
1017
+
1018
+ EXAMPLES::
1019
+
1020
+ sage: p = SemidefiniteProgram(maximization = False)
1021
+ sage: x = p.new_variable()
1022
+ sage: p.set_objective(x[0] - x[1])
1023
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
1024
+ sage: a2 = matrix([[3, 4.], [4., 5.]])
1025
+ sage: a3 = matrix([[5, 6.], [6., 7.]])
1026
+ sage: b1 = matrix([[1, 1.], [1., 1.]])
1027
+ sage: b2 = matrix([[2, 2.], [2., 2.]])
1028
+ sage: b3 = matrix([[3, 3.], [3., 3.]])
1029
+ sage: p.add_constraint(a1*x[0] + a2*x[1] <= a3)
1030
+ sage: p.add_constraint(b1*x[0] + b2*x[1] <= b3)
1031
+
1032
+ sage: # needs cvxopt
1033
+ sage: p.solve() # tol 1e-08
1034
+ -3.0
1035
+ sage: B1 = p.slack(1); B1 # tol 1e-08
1036
+ [0.0 0.0]
1037
+ [0.0 0.0]
1038
+ sage: B1.is_positive_definite()
1039
+ True
1040
+ sage: x = sorted(p.get_values(x).values())
1041
+ sage: x[0]*b1 + x[1]*b2 - b3 + B1 # tol 1e-09
1042
+ [0.0 0.0]
1043
+ [0.0 0.0]
1044
+
1045
+ TESTS::
1046
+
1047
+ sage: p.slack(7) # needs cvxopt
1048
+ Traceback (most recent call last):
1049
+ ...
1050
+ IndexError: list index out of range
1051
+ """
1052
+ return self._backend.slack(i, sparse=sparse)
1053
+
1054
+ def solver_parameter(self, name, value=None):
1055
+ """
1056
+ Return or define a solver parameter.
1057
+
1058
+ The solver parameters are by essence solver-specific, which
1059
+ means their meaning heavily depends on the solver used.
1060
+
1061
+ (If you do not know which solver you are using, then you are
1062
+ using CVXOPT).
1063
+
1064
+ INPUT:
1065
+
1066
+ - ``name`` -- string; the parameter
1067
+
1068
+ - ``value`` -- the parameter's value if it is to be defined,
1069
+ or ``None`` (default) to obtain its current value
1070
+
1071
+ EXAMPLES::
1072
+
1073
+ sage: # needs cvxopt
1074
+ sage: p.<x> = SemidefiniteProgram(solver='cvxopt',
1075
+ ....: maximization=False)
1076
+ sage: p.solver_parameter("show_progress", True)
1077
+ sage: p.solver_parameter("show_progress")
1078
+ True
1079
+ sage: p.set_objective(x[0] - x[1])
1080
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
1081
+ sage: a2 = matrix([[3, 4.], [4., 2.]])
1082
+ sage: a3 = matrix([[5, 6.], [6., 7.]])
1083
+ sage: b1 = matrix([[1, 1.], [1., 1.]])
1084
+ sage: b2 = matrix([[2, 2.], [2., 1.]])
1085
+ sage: b3 = matrix([[3, 3.], [3., 3.]])
1086
+ sage: p.add_constraint(a1*x[0] + a2*x[1] <= a3)
1087
+ sage: p.add_constraint(b1*x[0] + b2*x[1] <= b3)
1088
+ sage: N(p.solve(), 4)
1089
+ pcost dcost gap pres dres k/t
1090
+ 0: 1...
1091
+ ...
1092
+ Optimal solution found.
1093
+ -11.
1094
+ """
1095
+ if value is None:
1096
+ return self._backend.solver_parameter(name)
1097
+ else:
1098
+ self._backend.solver_parameter(name, value)
1099
+
1100
+ cpdef sum(self, L):
1101
+ r"""
1102
+ Efficiently compute the sum of a sequence of
1103
+ :class:`~sage.numerical.linear_functions.LinearFunction` elements.
1104
+
1105
+ INPUT:
1106
+
1107
+ - ``L`` -- list of
1108
+ :class:`~sage.numerical.linear_functions.LinearFunction` instances
1109
+
1110
+ .. NOTE::
1111
+
1112
+ The use of the regular ``sum`` function is not recommended
1113
+ as it is much less efficient than this one.
1114
+
1115
+ EXAMPLES::
1116
+
1117
+ sage: p = SemidefiniteProgram()
1118
+ sage: v = p.new_variable()
1119
+
1120
+ The following command::
1121
+
1122
+ sage: s = p.sum(v[i] for i in range(90))
1123
+
1124
+ is much more efficient than::
1125
+
1126
+ sage: s = sum(v[i] for i in range(90))
1127
+ """
1128
+ d = {}
1129
+ for v in L:
1130
+ for id, coeff in v.iteritems():
1131
+ d[id] = coeff + d.get(id, 0)
1132
+ return self.linear_functions_parent()(d)
1133
+
1134
+ def get_backend(self):
1135
+ r"""
1136
+ Return the backend instance used.
1137
+
1138
+ This might be useful when access to additional functions provided by
1139
+ the backend is needed.
1140
+
1141
+ EXAMPLES:
1142
+
1143
+ This example prints a matrix coefficient::
1144
+
1145
+ sage: p = SemidefiniteProgram(solver='cvxopt')
1146
+ sage: x = p.new_variable()
1147
+ sage: a1 = matrix([[1, 2.], [2., 3.]])
1148
+ sage: a2 = matrix([[3, 4.], [4., 5.]])
1149
+ sage: p.add_constraint(a1*x[0] + a2*x[1] <= a1)
1150
+ sage: b = p.get_backend()
1151
+ sage: b.get_matrix()[0][0]
1152
+ (
1153
+ [-1.0 -2.0]
1154
+ -1, [-2.0 -3.0]
1155
+ )
1156
+ """
1157
+ return self._backend
1158
+
1159
+
1160
+ class SDPSolverException(RuntimeError):
1161
+ r"""
1162
+ Exception raised when the solver fails.
1163
+
1164
+ ``SDPSolverException`` is the exception raised when the solver fails.
1165
+
1166
+ EXAMPLES::
1167
+
1168
+ sage: from sage.numerical.sdp import SDPSolverException
1169
+ sage: SDPSolverException("Error")
1170
+ SDPSolverException('Error'...)
1171
+
1172
+ TESTS:
1173
+
1174
+ No solution::
1175
+
1176
+ sage: # needs cvxopt
1177
+ sage: p = SemidefiniteProgram(solver='cvxopt')
1178
+ sage: x = p.new_variable()
1179
+ sage: p.set_objective(x[0])
1180
+ sage: a = matrix([[1,2],[2,4]])
1181
+ sage: b = matrix([[1,9],[9,4]])
1182
+ sage: p.add_constraint(a*x[0] == b)
1183
+ sage: p.solve()
1184
+ Traceback (most recent call last):
1185
+ ...
1186
+ SDPSolverException: ...
1187
+
1188
+ The value of the exception::
1189
+
1190
+ sage: from sage.numerical.sdp import SDPSolverException
1191
+ sage: e = SDPSolverException("Error")
1192
+ sage: print(e)
1193
+ Error
1194
+ """
1195
+ pass
1196
+
1197
+
1198
+ cdef class SDPVariable(Element):
1199
+ r"""
1200
+ ``SDPVariable`` is a variable used by the class
1201
+ ``SemidefiniteProgram``.
1202
+
1203
+ .. warning::
1204
+
1205
+ You should not instantiate this class directly. Instead, use
1206
+ :meth:`SemidefiniteProgram.new_variable`.
1207
+ """
1208
+
1209
+ def __init__(self, parent, sdp, name):
1210
+ r"""
1211
+ Constructor for ``SDPVariable``.
1212
+
1213
+ INPUT:
1214
+
1215
+ - ``parent`` -- :class:`SDPVariableParent`; the parent of the
1216
+ SDP variable
1217
+
1218
+ - ``sdp`` -- :class:`SemidefiniteProgram`; the
1219
+ underlying linear program
1220
+
1221
+ - ``name`` -- a name for the ``SDPVariable``
1222
+
1223
+ - ``lower_bound``, ``upper_bound`` -- lower bound and upper
1224
+ bound on the variable. Set to ``None`` to indicate that the
1225
+ variable is unbounded.
1226
+
1227
+ For more informations, see the method
1228
+ ``SemidefiniteProgram.new_variable``.
1229
+
1230
+ EXAMPLES::
1231
+
1232
+ sage: p = SemidefiniteProgram()
1233
+ sage: p.new_variable()
1234
+ SDPVariable
1235
+ """
1236
+ super().__init__(parent)
1237
+ self._dict = {}
1238
+ self._p = sdp
1239
+ self._name = name
1240
+
1241
+ def __getitem__(self, i):
1242
+ r"""
1243
+ Return the symbolic variable corresponding to the key.
1244
+
1245
+ Returns the element asked, otherwise creates it.
1246
+
1247
+ EXAMPLES::
1248
+
1249
+ sage: p = SemidefiniteProgram()
1250
+ sage: v = p.new_variable()
1251
+ sage: p.set_objective(v[0] + v[1])
1252
+ sage: v[0]
1253
+ x_0
1254
+ """
1255
+ cdef int j
1256
+ if i in self._dict:
1257
+ return self._dict[i]
1258
+ zero = self._p._backend.zero()
1259
+ name = self._name + "[" + str(i) + "]" if self._name else None
1260
+ j = self._p._backend.add_variable( obj=zero, name=name)
1261
+ v = self._p.linear_function({j: 1})
1262
+ self._p._variables[v] = j
1263
+ self._dict[i] = v
1264
+ return v
1265
+
1266
+ def _repr_(self):
1267
+ r"""
1268
+ Return a representation of ``self``.
1269
+
1270
+ EXAMPLES::
1271
+
1272
+ sage: p = SemidefiniteProgram()
1273
+ sage: v = p.new_variable()
1274
+ sage: v
1275
+ SDPVariable
1276
+ """
1277
+ return "SDPVariable"
1278
+
1279
+ def keys(self):
1280
+ r"""
1281
+ Return the keys already defined in the dictionary.
1282
+
1283
+ EXAMPLES::
1284
+
1285
+ sage: p = SemidefiniteProgram()
1286
+ sage: v = p.new_variable()
1287
+ sage: p.set_objective(v[0] + v[1])
1288
+ sage: sorted(v.keys())
1289
+ [0, 1]
1290
+ """
1291
+ return self._dict.keys()
1292
+
1293
+ def items(self):
1294
+ r"""
1295
+ Return the pairs (keys,value) contained in the dictionary.
1296
+
1297
+ EXAMPLES::
1298
+
1299
+ sage: p = SemidefiniteProgram()
1300
+ sage: v = p.new_variable()
1301
+ sage: p.set_objective(v[0] + v[1])
1302
+ sage: sorted(v.items())
1303
+ [(0, x_0), (1, x_1)]
1304
+ """
1305
+ return self._dict.items()
1306
+
1307
+ def values(self):
1308
+ r"""
1309
+ Return the symbolic variables associated to the current dictionary.
1310
+
1311
+ EXAMPLES::
1312
+
1313
+ sage: p = SemidefiniteProgram()
1314
+ sage: v = p.new_variable()
1315
+ sage: p.set_objective(v[0] + v[1])
1316
+ sage: sorted(v.values(), key=str)
1317
+ [x_0, x_1]
1318
+ """
1319
+ return self._dict.values()
1320
+
1321
+ cdef _matrix_rmul_impl(self, m):
1322
+ """
1323
+ Implement the action of a matrix multiplying from the right.
1324
+ """
1325
+ result = dict()
1326
+ for i, row in enumerate(m.rows()):
1327
+ x = self[i]
1328
+ x_index, = x.dict().keys()
1329
+ result[x_index] = row
1330
+ from sage.modules.free_module import FreeModule
1331
+ V = FreeModule(self._p.base_ring(), m.ncols())
1332
+ T = self._p.linear_functions_parent().tensor(V)
1333
+ return T(result)
1334
+
1335
+ cdef _matrix_lmul_impl(self, m):
1336
+ """
1337
+ Implement the action of a matrix multiplying from the left.
1338
+ """
1339
+ result = dict()
1340
+ for i, col in enumerate(m.columns()):
1341
+ x = self[i]
1342
+ x_index, = x.dict().keys()
1343
+ result[x_index] = col
1344
+ from sage.modules.free_module import FreeModule
1345
+ V = FreeModule(self._p.base_ring(), m.nrows())
1346
+ T = self._p.linear_functions_parent().tensor(V)
1347
+ return T(result)
1348
+
1349
+ cpdef _acted_upon_(self, mat, bint self_on_left):
1350
+ """
1351
+ Act with matrices on SDPVariables.
1352
+
1353
+ EXAMPLES::
1354
+
1355
+ sage: p = SemidefiniteProgram()
1356
+ sage: v = p.new_variable()
1357
+ sage: m = matrix([[1,2], [3,4]])
1358
+ sage: v * m
1359
+ (1.0, 2.0)*x_0 + (3.0, 4.0)*x_1
1360
+ sage: m * v
1361
+ (1.0, 3.0)*x_0 + (2.0, 4.0)*x_1
1362
+ """
1363
+ from sage.structure.element import Matrix
1364
+ if isinstance(mat, Matrix):
1365
+ return self._matrix_rmul_impl(mat) if self_on_left else self._matrix_lmul_impl(mat)
1366
+
1367
+
1368
+ cdef class SDPVariableParent(Parent):
1369
+ """
1370
+ Parent for :class:`SDPVariable`.
1371
+
1372
+ .. warning::
1373
+
1374
+ This class is for internal use. You should not instantiate it
1375
+ yourself. Use :meth:`SemidefiniteProgram.new_variable`
1376
+ to generate sdp variables.
1377
+ """
1378
+
1379
+ Element = SDPVariable
1380
+
1381
+ def _repr_(self):
1382
+ r"""
1383
+ Return representation of ``self``.
1384
+
1385
+ OUTPUT: string
1386
+
1387
+ EXAMPLES::
1388
+
1389
+ sage: sdp.<v> = SemidefiniteProgram()
1390
+ sage: v.parent()
1391
+ Parent of SDPVariables
1392
+ """
1393
+ return 'Parent of SDPVariables'
1394
+
1395
+ def _an_element_(self):
1396
+ """
1397
+ Construct a SDP variable.
1398
+
1399
+ OUTPUT:
1400
+
1401
+ This is required for the coercion framework. We raise a
1402
+ :exc:`TypeError` to abort search for any coercion to another
1403
+ parent for binary operations. The only interesting operations
1404
+ involving :class:`SDPVariable` elements are actions by
1405
+ matrices.
1406
+
1407
+ EXAMPLES::
1408
+
1409
+ sage: sdp.<x> = SemidefiniteProgram()
1410
+ sage: parent = x.parent()
1411
+ sage: parent.an_element() # indirect doctest
1412
+ Traceback (most recent call last):
1413
+ ...
1414
+ TypeError: disallow coercion
1415
+ """
1416
+ raise TypeError('disallow coercion')
1417
+
1418
+ def _element_constructor_(self, sdp, name=""):
1419
+ """
1420
+ The Element constructor.
1421
+
1422
+ INPUT/OUTPUT: see :meth:`SDPVariable.__init__`
1423
+
1424
+ EXAMPLES::
1425
+
1426
+ sage: sdp = SemidefiniteProgram()
1427
+ sage: sdp.new_variable() # indirect doctest
1428
+ SDPVariable
1429
+ """
1430
+ return self.element_class(self, sdp, name)
1431
+
1432
+
1433
+ sdp_variable_parent = SDPVariableParent()