Skip to content

Commit bf6be13

Browse files
author
Release Manager
committed
gh-40488: Improve MIP print formatting, etc. Just some minor improvements in mixed linear integer programming logic. In particular, previously, the line after `Maximization:` or `Minutization:` is always printed even if cothe coefficients are zero. Now in that case it is no longer printed. Besides, if it is printed, the trailing space is no longer there. Also add documentation for how to add a linear program already in standard form. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [ ] The description explains in detail what this PR is about. - [ ] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [ ] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - #12345: short description why this is a dependency --> <!-- - #34567: ... --> URL: #40488 Reported by: user202729 Reviewer(s): David Coudert
2 parents d346f69 + c33377b commit bf6be13

File tree

2 files changed

+59
-46
lines changed

2 files changed

+59
-46
lines changed

src/sage/combinat/matrices/dancing_links.pyx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,9 +1017,6 @@ cdef class dancing_linksWrapper:
10171017
the `i`-th row is in the solution::
10181018
10191019
sage: p.show() # needs sage.numerical.mip
1020-
Maximization:
1021-
<BLANKLINE>
1022-
<BLANKLINE>
10231020
Constraints:...
10241021
one 1 in 0-th column: 1.0 <= x_0 + x_1 <= 1.0
10251022
one 1 in 1-th column: 1.0 <= x_0 + x_2 <= 1.0

src/sage/numerical/mip.pyx

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ A mixed integer linear program can give you an answer:
6565
The following example shows all these steps::
6666
6767
sage: p = MixedIntegerLinearProgram(maximization=False, solver='GLPK')
68-
sage: w = p.new_variable(integer=True, nonnegative=True)
68+
sage: w = p.new_variable(integer=True, nonnegative=True, name='w')
6969
sage: p.add_constraint(w[0] + w[1] + w[2] - 14*w[3] == 0)
7070
sage: p.add_constraint(w[1] + 2*w[2] - 8*w[3] == 0)
7171
sage: p.add_constraint(2*w[2] - 3*w[3] == 0)
@@ -74,18 +74,18 @@ The following example shows all these steps::
7474
sage: p.set_objective(w[3])
7575
sage: p.show()
7676
Minimization:
77-
x_3
77+
w[3]
7878
Constraints:
79-
0.0 <= x_0 + x_1 + x_2 - 14.0 x_3 <= 0.0
80-
0.0 <= x_1 + 2.0 x_2 - 8.0 x_3 <= 0.0
81-
0.0 <= 2.0 x_2 - 3.0 x_3 <= 0.0
82-
- x_0 + x_1 + x_2 <= 0.0
83-
- x_3 <= -1.0
79+
0.0 <= w[0] + w[1] + w[2] - 14.0 w[3] <= 0.0
80+
0.0 <= w[1] + 2.0 w[2] - 8.0 w[3] <= 0.0
81+
0.0 <= 2.0 w[2] - 3.0 w[3] <= 0.0
82+
- w[0] + w[1] + w[2] <= 0.0
83+
- w[3] <= -1.0
8484
Variables:
85-
x_0 is an integer variable (min=0.0, max=+oo)
86-
x_1 is an integer variable (min=0.0, max=+oo)
87-
x_2 is an integer variable (min=0.0, max=+oo)
88-
x_3 is an integer variable (min=0.0, max=+oo)
85+
w[0] = x_0 is an integer variable (min=0.0, max=+oo)
86+
w[1] = x_1 is an integer variable (min=0.0, max=+oo)
87+
w[2] = x_2 is an integer variable (min=0.0, max=+oo)
88+
w[3] = x_3 is an integer variable (min=0.0, max=+oo)
8989
sage: print('Objective Value: {}'.format(p.solve()))
9090
Objective Value: 2.0
9191
sage: for i, v in sorted(p.get_values(w, convert=ZZ, tolerance=1e-3).items()):
@@ -95,6 +95,34 @@ The following example shows all these steps::
9595
w_2 = 3
9696
w_3 = 2
9797
98+
If your problem is already in the standard form, for example::
99+
100+
sage: A = matrix([[1, 2], [3, 5]])
101+
sage: b = vector([7, 11])
102+
sage: c = vector([5, 9])
103+
104+
You can add the constraint by treating the variable dictionary as a vector::
105+
106+
sage: p = MixedIntegerLinearProgram(maximization=True, solver='GLPK')
107+
sage: w = p.new_variable(integer=True, name='w')
108+
sage: p.add_constraint(A * w <= b)
109+
sage: p.set_objective((c.row() * w)[0])
110+
sage: p.show()
111+
Maximization:
112+
5.0 w[0] + 9.0 w[1]
113+
Constraints:
114+
w[0] + 2.0 w[1] <= 7.0
115+
3.0 w[0] + 5.0 w[1] <= 11.0
116+
Variables:
117+
w[0] = x_0 is an integer variable (min=-oo, max=+oo)
118+
w[1] = x_1 is an integer variable (min=-oo, max=+oo)
119+
sage: print('Objective Value: {}'.format(p.solve()))
120+
Objective Value: 25.0
121+
sage: for i, v in sorted(p.get_values(w, convert=ZZ, tolerance=1e-3).items()):
122+
....: print(f'w_{i} = {v}')
123+
w_0 = -13
124+
w_1 = 10
125+
98126
Different backends compute with different base fields, for example::
99127
100128
sage: p = MixedIntegerLinearProgram(solver='GLPK')
@@ -144,8 +172,6 @@ also allowed::
144172
sage: a[4, 'string', QQ] - 7*b[2]
145173
x_2 - 7*x_3
146174
sage: mip.show()
147-
Maximization:
148-
<BLANKLINE>
149175
Constraints:
150176
Variables:
151177
a[1] = x_0 is a continuous variable (min=-oo, max=+oo)
@@ -778,8 +804,6 @@ cdef class MixedIntegerLinearProgram(SageObject):
778804
sage: p.add_constraint(x[0] + x[3] <= 8)
779805
sage: p.add_constraint(y[0] >= y[1])
780806
sage: p.show()
781-
Maximization:
782-
<BLANKLINE>
783807
Constraints:
784808
x_0 + x_1 <= 8.0
785809
- x_2 + x_3 <= 0.0
@@ -795,8 +819,6 @@ cdef class MixedIntegerLinearProgram(SageObject):
795819
sage: mip.<x, y, z> = MixedIntegerLinearProgram(solver='GLPK')
796820
sage: mip.add_constraint(x[0] + y[1] + z[2] <= 10)
797821
sage: mip.show()
798-
Maximization:
799-
<BLANKLINE>
800822
Constraints:
801823
x[0] + y[1] + z[2] <= 10.0
802824
Variables:
@@ -860,8 +882,6 @@ cdef class MixedIntegerLinearProgram(SageObject):
860882
sage: a[0] + b[2]
861883
x_0 + x_1
862884
sage: mip.show()
863-
Maximization:
864-
<BLANKLINE>
865885
Constraints:
866886
Variables:
867887
a[0] = x_0 is a continuous variable (min=-oo, max=+oo)
@@ -1251,23 +1271,24 @@ cdef class MixedIntegerLinearProgram(SageObject):
12511271
varid_explainer[i] = varid_name[i] = default_name
12521272

12531273
##### Sense and objective function
1254-
print("Maximization:" if b.is_maximization() else "Minimization:")
1255-
print(" ", end=" ")
1274+
formula_parts = []
12561275
first = True
12571276
for 0<= i< b.ncols():
12581277
c = b.objective_coefficient(i)
12591278
if c == 0:
12601279
continue
1261-
print((("+ " if (not first and c>0) else "") +
1262-
("" if c == 1 else ("- " if c == -1 else str(c)+" "))+varid_name[i]
1263-
), end=" ")
1280+
formula_parts.append(("+ " if (not first and c>0) else "") +
1281+
("" if c == 1 else ("- " if c == -1 else str(c)+" "))+varid_name[i]
1282+
)
12641283
first = False
12651284
d = b.objective_constant_term()
12661285
if d > self._backend.zero():
1267-
print("+ {} ".format(d))
1286+
formula_parts.append("+ {}".format(d))
12681287
elif d < self._backend.zero():
1269-
print("- {} ".format(-d))
1270-
print("\n")
1288+
formula_parts.append("- {}".format(-d))
1289+
if formula_parts:
1290+
print("Maximization:" if b.is_maximization() else "Minimization:")
1291+
print(" " + " ".join(formula_parts))
12711292

12721293
##### Constraints
12731294
print("Constraints:")
@@ -2001,8 +2022,6 @@ cdef class MixedIntegerLinearProgram(SageObject):
20012022
sage: b = p.new_variable(nonnegative=True)
20022023
sage: p.add_constraint(b[8] - b[15] <= 3*b[8] + 9)
20032024
sage: p.show()
2004-
Maximization:
2005-
<BLANKLINE>
20062025
Constraints:
20072026
-2.0 x_0 - x_1 <= 9.0
20082027
Variables:
@@ -2043,8 +2062,6 @@ cdef class MixedIntegerLinearProgram(SageObject):
20432062
sage: for each in range(10):
20442063
....: lp.add_constraint(lp[0]-lp[1], min=1)
20452064
sage: lp.show()
2046-
Maximization:
2047-
<BLANKLINE>
20482065
Constraints:
20492066
1.0 <= x_0 - x_1
20502067
Variables:
@@ -2056,8 +2073,6 @@ cdef class MixedIntegerLinearProgram(SageObject):
20562073
sage: for each in range(10):
20572074
....: lp.add_constraint(2*lp[0] - 2*lp[1], min=2)
20582075
sage: lp.show()
2059-
Maximization:
2060-
<BLANKLINE>
20612076
Constraints:
20622077
1.0 <= x_0 - x_1
20632078
Variables:
@@ -2069,8 +2084,6 @@ cdef class MixedIntegerLinearProgram(SageObject):
20692084
sage: for each in range(10):
20702085
....: lp.add_constraint(-2*lp[0] + 2*lp[1], min=-2)
20712086
sage: lp.show()
2072-
Maximization:
2073-
<BLANKLINE>
20742087
Constraints:
20752088
1.0 <= x_0 - x_1
20762089
-2.0 <= -2.0 x_0 + 2.0 x_1
@@ -2268,17 +2281,13 @@ cdef class MixedIntegerLinearProgram(SageObject):
22682281
sage: p.add_constraint(x - y, max=0)
22692282
sage: p.add_constraint(x, max=4)
22702283
sage: p.show()
2271-
Maximization:
2272-
<BLANKLINE>
22732284
Constraints:
22742285
x_0 + x_1 <= 10.0
22752286
x_0 - x_1 <= 0.0
22762287
x_0 <= 4.0
22772288
...
22782289
sage: p.remove_constraint(1)
22792290
sage: p.show()
2280-
Maximization:
2281-
<BLANKLINE>
22822291
Constraints:
22832292
x_0 + x_1 <= 10.0
22842293
x_0 <= 4.0
@@ -2306,17 +2315,13 @@ cdef class MixedIntegerLinearProgram(SageObject):
23062315
sage: p.add_constraint(x - y, max=0)
23072316
sage: p.add_constraint(x, max=4)
23082317
sage: p.show()
2309-
Maximization:
2310-
<BLANKLINE>
23112318
Constraints:
23122319
x_0 + x_1 <= 10.0
23132320
x_0 - x_1 <= 0.0
23142321
x_0 <= 4.0
23152322
...
23162323
sage: p.remove_constraints([0, 1])
23172324
sage: p.show()
2318-
Maximization:
2319-
<BLANKLINE>
23202325
Constraints:
23212326
x_0 <= 4.0
23222327
...
@@ -3627,8 +3632,19 @@ cdef class MIPVariable(FiniteFamily):
36273632
(1, 1/2)*x_0 + (2/3, 3/4)*x_1
36283633
sage: m * v
36293634
(1, 2/3)*x_0 + (1/2, 3/4)*x_1
3635+
3636+
sage: c = vector([1, 2])
3637+
sage: v * c
3638+
x_0 + 2*x_1
3639+
sage: c * v
3640+
x_0 + 2*x_1
36303641
"""
3642+
from sage.structure.element import Vector
3643+
if isinstance(left, Vector):
3644+
left, right = right, left
36313645
if isinstance(left, MIPVariable):
3646+
if isinstance(right, Vector):
3647+
return (<MIPVariable> left)._matrix_rmul_impl(right.column())[0]
36323648
if not isinstance(right, Matrix):
36333649
return NotImplemented
36343650
return (<MIPVariable> left)._matrix_rmul_impl(right)

0 commit comments

Comments
 (0)