-
-
Notifications
You must be signed in to change notification settings - Fork 480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added method to find constraints value for MILP #38055
Open
verreld7
wants to merge
6
commits into
sagemath:develop
Choose a base branch
from
verreld7:mip_constraints_values
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+69
−0
Open
Changes from 4 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
ba5f109
Added the constraints_values method to mixed integer linear programming.
verreld7 079e3f3
Merge branch 'sagemath:develop' into mip_constraints_values
verreld7 6f38bb2
Fix issues based on review
verreld7 de09a2e
Merge branch 'develop' into mip_constraints_values
verreld7 df2d6bc
Update documentation
verreld7 b114d7a
Fix lint error
verreld7 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -215,7 +215,7 @@ also implements the :class:`MIPSolverException` exception, as well as the | |||||||||||||||
:meth:`~MixedIntegerLinearProgram.show` | Display the ``MixedIntegerLinearProgram`` in a human-readable | ||||||||||||||||
:meth:`~MixedIntegerLinearProgram.solve` | Solve the ``MixedIntegerLinearProgram`` | ||||||||||||||||
:meth:`~MixedIntegerLinearProgram.solver_parameter` | Return or define a solver parameter | ||||||||||||||||
:meth:`~MixedIntegerLinearProgram.sum` | Efficiently computes the sum of a sequence of LinearFunction elements | ||||||||||||||||
:meth:`~MixedIntegerLinearProgram.result` | Efficiently computes the result of a sequence of LinearFunction elements | ||||||||||||||||
:meth:`~MixedIntegerLinearProgram.write_lp` | Write the linear program as a LP file | ||||||||||||||||
:meth:`~MixedIntegerLinearProgram.write_mps` | Write the linear program as a MPS file | ||||||||||||||||
|
||||||||||||||||
|
@@ -319,7 +319,7 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
sage: g = graphs.PetersenGraph() | ||||||||||||||||
sage: p = MixedIntegerLinearProgram(maximization=True, solver='GLPK') | ||||||||||||||||
sage: b = p.new_variable(binary=True) | ||||||||||||||||
sage: p.set_objective(sum([b[v] for v in g])) | ||||||||||||||||
sage: p.set_objective(result([b[v] for v in g])) | ||||||||||||||||
sage: for (u,v) in g.edges(sort=False, labels=None): | ||||||||||||||||
....: p.add_constraint(b[u] + b[v], max=1) | ||||||||||||||||
sage: p.solve(objective_only=True) | ||||||||||||||||
|
@@ -336,9 +336,9 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
....: p = MixedIntegerLinearProgram(solver='GLPK') | ||||||||||||||||
....: box = p.new_variable(nonnegative=True, **{type: True}) | ||||||||||||||||
....: for b in range(k): | ||||||||||||||||
....: p.add_constraint(p.sum([items[i]*box[i,b] for i in range(len(items))]) <= maximum) | ||||||||||||||||
....: p.add_constraint(p.result([items[i]*box[i,b] for i in range(len(items))]) <= maximum) | ||||||||||||||||
....: for i in range(len(items)): | ||||||||||||||||
....: p.add_constraint(p.sum([box[i,b] for b in range(k)]) == 1) | ||||||||||||||||
....: p.add_constraint(p.result([box[i,b] for b in range(k)]) == 1) | ||||||||||||||||
....: p.set_objective(None) | ||||||||||||||||
....: _ = p.solve() | ||||||||||||||||
....: box = p.get_values(box) | ||||||||||||||||
|
@@ -417,7 +417,7 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
sage: C = sage.numerical.mip.MixedIntegerLinearProgram | ||||||||||||||||
sage: import gc | ||||||||||||||||
sage: _ = gc.collect() # avoid side effects of other doc tests | ||||||||||||||||
sage: sum([1 for x in gc.get_objects() if isinstance(x,C)]) | ||||||||||||||||
sage: result([1 for x in gc.get_objects() if isinstance(x,C)]) | ||||||||||||||||
0 | ||||||||||||||||
|
||||||||||||||||
We now disable the cyclic garbage collector. Since :issue:`12616` avoids | ||||||||||||||||
|
@@ -427,7 +427,7 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
|
||||||||||||||||
sage: gc.disable() | ||||||||||||||||
sage: just_create_variables() | ||||||||||||||||
sage: sum([1 for x in gc.get_objects() if isinstance(x,C)]) | ||||||||||||||||
sage: result([1 for x in gc.get_objects() if isinstance(x,C)]) | ||||||||||||||||
0 | ||||||||||||||||
sage: gc.enable() | ||||||||||||||||
""" | ||||||||||||||||
|
@@ -804,7 +804,7 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
y[1] = x_1 is a continuous variable (min=-oo, max=+oo) | ||||||||||||||||
z[2] = x_2 is a continuous variable (min=-oo, max=+oo) | ||||||||||||||||
""" | ||||||||||||||||
if sum([real, binary, integer]) > 1: | ||||||||||||||||
if result([real, binary, integer]) > 1: | ||||||||||||||||
raise ValueError("Exactly one of the available types has to be True") | ||||||||||||||||
|
||||||||||||||||
if binary: | ||||||||||||||||
|
@@ -1519,6 +1519,80 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
return self._backend_variable_value_ZZ(v, tolerance) | ||||||||||||||||
return self.base_ring()(self._backend_variable_value(v, tolerance)) | ||||||||||||||||
|
||||||||||||||||
def constraints_values(self, indices=None): | ||||||||||||||||
r""" | ||||||||||||||||
Return values of constraints according to the current values of variables. | ||||||||||||||||
|
||||||||||||||||
INPUT: | ||||||||||||||||
|
||||||||||||||||
- ``indices`` -- select which constraint(s) values to return | ||||||||||||||||
|
||||||||||||||||
- If ``indices = None``, the method returns the list of all the | ||||||||||||||||
constraints values. | ||||||||||||||||
|
||||||||||||||||
- If ``indices`` is an integer `i`, the method returns value of constraint | ||||||||||||||||
`i`. | ||||||||||||||||
|
||||||||||||||||
- If ``indices`` is a list of integers, the method returns the list | ||||||||||||||||
of the corresponding value of constraints. | ||||||||||||||||
|
||||||||||||||||
OUTPUT: | ||||||||||||||||
|
||||||||||||||||
A list of numbers according to the input. | ||||||||||||||||
|
||||||||||||||||
EXAMPLES:: | ||||||||||||||||
|
||||||||||||||||
sage: p = MixedIntegerLinearProgram(maximization=True, solver='GLPK') | ||||||||||||||||
sage: x = p.new_variable(nonnegative=True) | ||||||||||||||||
sage: p.set_objective(5*x[1] + 4*x[2]) | ||||||||||||||||
sage: p.add_constraint(6*x[1] + 4*x[2], max=24) | ||||||||||||||||
sage: p.add_constraint(x[1] + 2*x[2], max=6) | ||||||||||||||||
sage: p.add_constraint(-x[1] + x[2], max=1) | ||||||||||||||||
sage: p.add_constraint(x[2], max=2) | ||||||||||||||||
sage: p.solve() | ||||||||||||||||
21.0 | ||||||||||||||||
sage: p.get_values(x) | ||||||||||||||||
{1: 3.0, 2: 1.5} | ||||||||||||||||
sage: p.constraints_values() | ||||||||||||||||
[24.0, 6.0, -1.5, 1.5] | ||||||||||||||||
|
||||||||||||||||
TESTS:: | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
|
||||||||||||||||
Check if the integer input is outside the valid input range:: | ||||||||||||||||
|
||||||||||||||||
sage: p = MixedIntegerLinearProgram(maximization=True, solver='GLPK') | ||||||||||||||||
sage: x = p.new_variable(nonnegative=True) | ||||||||||||||||
sage: p.set_objective(3*x[1] + 4*x[2]) | ||||||||||||||||
sage: p.add_constraint(2*x[1] + x[2], max=20) | ||||||||||||||||
sage: p.add_constraint(4*x[1] + 3*x[2], max=6) | ||||||||||||||||
sage: p.solve() | ||||||||||||||||
8.0 | ||||||||||||||||
sage: p.constraints_values(1) | ||||||||||||||||
[6.0] | ||||||||||||||||
sage: p.constraints_values(2) | ||||||||||||||||
Traceback (most recent call last): | ||||||||||||||||
... | ||||||||||||||||
ValueError: invalid row index 2 | ||||||||||||||||
|
||||||||||||||||
""" | ||||||||||||||||
from sage.rings.integer_ring import ZZ | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
|
||||||||||||||||
# calculate value of constraint 'i' | ||||||||||||||||
def calculate_value(self, i): | ||||||||||||||||
s = 0 | ||||||||||||||||
cons = self.constraints(i)[1] | ||||||||||||||||
for index, coeff in zip(cons[0], cons[1]): | ||||||||||||||||
s += var_val[index] * coeff | ||||||||||||||||
return s | ||||||||||||||||
|
||||||||||||||||
var = [n for n in self._variables] | ||||||||||||||||
var_val = self.get_values([n for n in var]) | ||||||||||||||||
if indices is None: | ||||||||||||||||
indices = [n for n in range(self.number_of_constraints())] | ||||||||||||||||
elif indices in ZZ: | ||||||||||||||||
indices = [ZZ(indices)] | ||||||||||||||||
return [calculate_value(self, i) for i in indices] | ||||||||||||||||
|
||||||||||||||||
def get_values(self, *lists, convert=None, tolerance=None): | ||||||||||||||||
r""" | ||||||||||||||||
Return values found by the previous call to ``solve()``. | ||||||||||||||||
|
@@ -2014,14 +2088,14 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
Trivially true empty constraint: | ||||||||||||||||
|
||||||||||||||||
sage: p = MixedIntegerLinearProgram(solver='GLPK') | ||||||||||||||||
sage: p.add_constraint(sum([]), max=2) | ||||||||||||||||
sage: p.add_constraint(result([]), max=2) | ||||||||||||||||
sage: p.solve() | ||||||||||||||||
0.0 | ||||||||||||||||
|
||||||||||||||||
Infeasible empty constraint:: | ||||||||||||||||
|
||||||||||||||||
sage: p = MixedIntegerLinearProgram(solver='GLPK') | ||||||||||||||||
sage: p.add_constraint(sum([]), min=2) | ||||||||||||||||
sage: p.add_constraint(result([]), min=2) | ||||||||||||||||
sage: p.solve() | ||||||||||||||||
Traceback (most recent call last): | ||||||||||||||||
... | ||||||||||||||||
|
@@ -2615,7 +2689,7 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
sage: g = graphs.PetersenGraph() | ||||||||||||||||
sage: p = MixedIntegerLinearProgram(maximization=True, solver='GLPK') | ||||||||||||||||
sage: b = p.new_variable(nonnegative=True) | ||||||||||||||||
sage: p.set_objective(sum([b[v] for v in g])) | ||||||||||||||||
sage: p.set_objective(result([b[v] for v in g])) | ||||||||||||||||
sage: for (u,v) in g.edges(sort=False, labels=None): | ||||||||||||||||
....: p.add_constraint(b[u] + b[v], max=1) | ||||||||||||||||
sage: p.set_binary(b) | ||||||||||||||||
|
@@ -2862,9 +2936,10 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
else: | ||||||||||||||||
self._backend.solver_parameter(name, value) | ||||||||||||||||
|
||||||||||||||||
cpdef sum(self, L): | ||||||||||||||||
cpdef result(self, L): | ||||||||||||||||
r""" | ||||||||||||||||
Efficiently compute the sum of a sequence of | ||||||||||||||||
|
||||||||||||||||
Efficiently computes the result of a sequence of | ||||||||||||||||
:class:`~sage.numerical.linear_functions.LinearFunction` elements | ||||||||||||||||
|
||||||||||||||||
INPUT: | ||||||||||||||||
|
@@ -2876,7 +2951,7 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
|
||||||||||||||||
.. NOTE:: | ||||||||||||||||
|
||||||||||||||||
The use of the regular ``sum`` function is not recommended | ||||||||||||||||
The use of the regular ``result`` function is not recommended | ||||||||||||||||
as it is much less efficient than this one | ||||||||||||||||
|
||||||||||||||||
EXAMPLES:: | ||||||||||||||||
|
@@ -2886,11 +2961,11 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
|
||||||||||||||||
The following command:: | ||||||||||||||||
|
||||||||||||||||
sage: s = p.sum(v[i] for i in range(90)) | ||||||||||||||||
sage: s = p.result(v[i] for i in range(90)) | ||||||||||||||||
|
||||||||||||||||
is much more efficient than:: | ||||||||||||||||
|
||||||||||||||||
sage: s = sum(v[i] for i in range(90)) | ||||||||||||||||
sage: s = result(v[i] for i in range(90)) | ||||||||||||||||
""" | ||||||||||||||||
d = {} | ||||||||||||||||
for v in L: | ||||||||||||||||
|
@@ -2972,9 +3047,9 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
sage: p = MixedIntegerLinearProgram(solver='GLPK') | ||||||||||||||||
sage: p.solver_parameter("mip_gap_tolerance",100) | ||||||||||||||||
sage: b = p.new_variable(binary=True) | ||||||||||||||||
sage: p.set_objective(p.sum(b[v] for v in g)) | ||||||||||||||||
sage: p.set_objective(p.result(b[v] for v in g)) | ||||||||||||||||
sage: for v in g: | ||||||||||||||||
....: p.add_constraint(b[v] + p.sum(b[u] for u in g.neighbors(v)) <= 1) | ||||||||||||||||
....: p.add_constraint(b[v] + p.result(b[u] for u in g.neighbors(v)) <= 1) | ||||||||||||||||
sage: p.add_constraint(b[v] == 1) # Force an easy non-0 solution | ||||||||||||||||
sage: p.solve() # rel tol 100 | ||||||||||||||||
1.0 | ||||||||||||||||
|
@@ -3007,9 +3082,9 @@ cdef class MixedIntegerLinearProgram(SageObject): | |||||||||||||||
sage: p = MixedIntegerLinearProgram(solver='GLPK') | ||||||||||||||||
sage: p.solver_parameter("mip_gap_tolerance",100) | ||||||||||||||||
sage: b = p.new_variable(binary=True) | ||||||||||||||||
sage: p.set_objective(p.sum(b[v] for v in g)) | ||||||||||||||||
sage: p.set_objective(p.result(b[v] for v in g)) | ||||||||||||||||
sage: for v in g: | ||||||||||||||||
....: p.add_constraint(b[v] + p.sum(b[u] for u in g.neighbors(v)) <= 1) | ||||||||||||||||
....: p.add_constraint(b[v] + p.result(b[u] for u in g.neighbors(v)) <= 1) | ||||||||||||||||
sage: p.add_constraint(b[v] == 1) # Force an easy non-0 solution | ||||||||||||||||
sage: p.solve() # rel tol 100 | ||||||||||||||||
1.0 | ||||||||||||||||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.