Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/numerical/mip.pyx
8815 views
1
r"""
2
Mixed integer linear programming
3
4
A linear program (`LP <http://en.wikipedia.org/wiki/Linear_programming>`_)
5
is an `optimization problem <http://en.wikipedia.org/wiki/Optimization_%28mathematics%29>`_
6
in the following form
7
8
.. MATH::
9
\max \{ c^T x \;|\; A x \leq b, x \geq 0 \}
10
11
with given `A \in \mathbb{R}^{m,n}`, `b \in \mathbb{R}^m`,
12
`c \in \mathbb{R}^n` and unknown `x \in \mathbb{R}^{n}`.
13
If some or all variables in the vector `x` are restricted over
14
the integers `\mathbb{Z}`, the problem is called mixed integer
15
linear program (`MILP <http://en.wikipedia.org/wiki/Mixed_integer_linear_programming>`_).
16
A wide variety of problems in optimization
17
can be formulated in this standard form. Then, solvers are
18
able to calculate a solution.
19
20
Imagine you want to solve the following linear system of three equations:
21
22
- `w_0 + w_1 + w_2 - 14 w_3 = 0`
23
- `w_1 + 2 w_2 - 8 w_3 = 0`
24
- `2 w_2 - 3 w_3 = 0`
25
26
and this additional inequality:
27
28
- `w_0 - w_1 - w_2 \geq 0`
29
30
where all `w_i \in \mathbb{Z}`. You know that the trivial solution is
31
`w_i = 0 \; \forall i`, but what is the first non-trivial one with
32
`w_3 \geq 1`?
33
34
A mixed integer linear program can give you an answer:
35
36
#. You have to create an instance of :class:`MixedIntegerLinearProgram` and
37
-- in our case -- specify that it is a minimization.
38
#. Create a variable vector ``w`` via ``w = p.new_variable(integer=True)`` and
39
tell the system that it is over the integers.
40
#. Add those three equations as equality constraints via
41
:meth:`add_constraint <sage.numerical.mip.MixedIntegerLinearProgram.add_constraint>`.
42
#. Also add the inequality constraint.
43
#. Add an inequality constraint `w_3 \geq 1` to exclude the trivial solution.
44
#. By default, all variables have a minimum of `0`. We remove that constraint
45
via ``p.set_min(variable, None)``, see :meth:`set_min <sage.numerical.mip.MixedIntegerLinearProgram.set_min>`.
46
#. Specify the objective function via :meth:`set_objective <sage.numerical.mip.MixedIntegerLinearProgram.set_objective>`.
47
In our case that is just `w_3`. If it
48
is a pure constraint satisfaction problem, specify it as ``None``.
49
#. To check if everything is set up correctly, you can print the problem via
50
:meth:`show <sage.numerical.mip.MixedIntegerLinearProgram.show>`.
51
#. :meth:`Solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>` it and print the solution.
52
53
The following example shows all these steps::
54
55
sage: p = MixedIntegerLinearProgram(maximization=False, solver = "GLPK")
56
sage: w = p.new_variable(integer=True)
57
sage: p.add_constraint(w[0] + w[1] + w[2] - 14*w[3] == 0)
58
sage: p.add_constraint(w[1] + 2*w[2] - 8*w[3] == 0)
59
sage: p.add_constraint(2*w[2] - 3*w[3] == 0)
60
sage: p.add_constraint(w[0] - w[1] - w[2] >= 0)
61
sage: p.add_constraint(w[3] >= 1)
62
sage: _ = [ p.set_min(w[i], None) for i in range(1,4) ]
63
sage: p.set_objective(w[3])
64
sage: p.show()
65
Minimization:
66
x_3
67
Constraints:
68
0.0 <= x_0 + x_1 + x_2 - 14.0 x_3 <= 0.0
69
0.0 <= x_1 + 2.0 x_2 - 8.0 x_3 <= 0.0
70
0.0 <= 2.0 x_2 - 3.0 x_3 <= 0.0
71
- x_0 + x_1 + x_2 <= 0.0
72
- x_3 <= -1.0
73
Variables:
74
x_0 is an integer variable (min=0.0, max=+oo)
75
x_1 is an integer variable (min=-oo, max=+oo)
76
x_2 is an integer variable (min=-oo, max=+oo)
77
x_3 is an integer variable (min=-oo, max=+oo)
78
sage: print 'Objective Value:', p.solve()
79
Objective Value: 2.0
80
sage: for i, v in p.get_values(w).iteritems():\
81
print 'w_%s = %s' % (i, int(round(v)))
82
w_0 = 15
83
w_1 = 10
84
w_2 = 3
85
w_3 = 2
86
87
Different backends compute with different base fields, for example::
88
89
sage: p = MixedIntegerLinearProgram(solver = 'GLPK')
90
sage: p.base_ring()
91
Real Double Field
92
sage: x = p.new_variable()
93
sage: 0.5 + 3/2*x[1]
94
0.5 + 1.5*x_0
95
96
sage: p = MixedIntegerLinearProgram(solver = 'ppl')
97
sage: p.base_ring()
98
Rational Field
99
sage: x = p.new_variable()
100
sage: 0.5 + 3/2*x[1]
101
1/2 + 3/2*x_0
102
103
AUTHORS:
104
105
- Risan (2012/02): added extension for exact computation
106
107
Index of functions and methods
108
------------------------------
109
110
Below are listed the methods of :class:`MixedIntegerLinearProgram`. This module
111
also implements the :class:`MIPSolverException` exception, as well as the
112
:class:`MIPVariable` class.
113
114
.. csv-table::
115
:class: contentstable
116
:widths: 30, 70
117
:delim: |
118
119
:meth:`~MixedIntegerLinearProgram.add_constraint` | Adds a constraint to the ``MixedIntegerLinearProgram``
120
:meth:`~MixedIntegerLinearProgram.base_ring` | Return the base ring
121
:meth:`~MixedIntegerLinearProgram.constraints` | Returns a list of constraints, as 3-tuples
122
:meth:`~MixedIntegerLinearProgram.get_backend` | Returns the backend instance used
123
:meth:`~MixedIntegerLinearProgram.get_max` | Returns the maximum value of a variable
124
:meth:`~MixedIntegerLinearProgram.get_min` | Returns the minimum value of a variable
125
:meth:`~MixedIntegerLinearProgram.get_values` | Return values found by the previous call to ``solve()``
126
:meth:`~MixedIntegerLinearProgram.is_binary` | Tests whether the variable ``e`` is binary
127
:meth:`~MixedIntegerLinearProgram.is_integer` | Tests whether the variable is an integer
128
:meth:`~MixedIntegerLinearProgram.is_real` | Tests whether the variable is real
129
:meth:`~MixedIntegerLinearProgram.linear_constraints_parent` | Return the parent for all linear constraints
130
:meth:`~MixedIntegerLinearProgram.linear_function` | Construct a new linear function
131
:meth:`~MixedIntegerLinearProgram.linear_functions_parent` | Return the parent for all linear functions
132
:meth:`~MixedIntegerLinearProgram.new_variable` | Returns an instance of ``MIPVariable`` associated
133
:meth:`~MixedIntegerLinearProgram.number_of_constraints` | Returns the number of constraints assigned so far
134
:meth:`~MixedIntegerLinearProgram.number_of_variables` | Returns the number of variables used so far
135
:meth:`~MixedIntegerLinearProgram.polyhedron` | Returns the polyhedron defined by the Linear Program
136
:meth:`~MixedIntegerLinearProgram.remove_constraint` | Removes a constraint from self
137
:meth:`~MixedIntegerLinearProgram.remove_constraints` | Remove several constraints
138
:meth:`~MixedIntegerLinearProgram.set_binary` | Sets a variable or a ``MIPVariable`` as binary
139
:meth:`~MixedIntegerLinearProgram.set_integer` | Sets a variable or a ``MIPVariable`` as integer
140
:meth:`~MixedIntegerLinearProgram.set_max` | Sets the maximum value of a variable
141
:meth:`~MixedIntegerLinearProgram.set_min` | Sets the minimum value of a variable
142
:meth:`~MixedIntegerLinearProgram.set_objective` | Sets the objective of the ``MixedIntegerLinearProgram``
143
:meth:`~MixedIntegerLinearProgram.set_problem_name` | Sets the name of the ``MixedIntegerLinearProgram``
144
:meth:`~MixedIntegerLinearProgram.set_real` | Sets a variable or a ``MIPVariable`` as real
145
:meth:`~MixedIntegerLinearProgram.show` | Displays the ``MixedIntegerLinearProgram`` in a human-readable
146
:meth:`~MixedIntegerLinearProgram.solve` | Solves the ``MixedIntegerLinearProgram``
147
:meth:`~MixedIntegerLinearProgram.solver_parameter` | Return or define a solver parameter
148
:meth:`~MixedIntegerLinearProgram.sum` | Efficiently computes the sum of a sequence of LinearFunction elements
149
:meth:`~MixedIntegerLinearProgram.write_lp` | Write the linear program as a LP file
150
:meth:`~MixedIntegerLinearProgram.write_mps` | Write the linear program as a MPS file
151
152
Classes and methods
153
-------------------
154
"""
155
156
#*****************************************************************************
157
# Copyright (C) 2012 Nathann Cohen <[email protected]>
158
#
159
# Distributed under the terms of the GNU General Public License (GPL)
160
# as published by the Free Software Foundation; either version 2 of
161
# the License, or (at your option) any later version.
162
# http://www.gnu.org/licenses/
163
#*****************************************************************************
164
165
include "sage/ext/stdsage.pxi"
166
include "sage/ext/interrupt.pxi"
167
include "sage/ext/cdefs.pxi"
168
169
from sage.structure.sage_object cimport SageObject
170
from sage.misc.cachefunc import cached_method
171
from sage.numerical.linear_functions import is_LinearFunction, is_LinearConstraint
172
173
174
cdef class MixedIntegerLinearProgram(SageObject):
175
r"""
176
The ``MixedIntegerLinearProgram`` class is the link between Sage, linear
177
programming (LP) and mixed integer programming (MIP) solvers.
178
179
See the Wikipedia article on `linear programming
180
<http://en.wikipedia.org/wiki/Linear_programming>`_ for further information
181
on linear programming and the documentation of the :mod:`MILP module
182
<sage.numerical.mip>` for its use in Sage.
183
184
A mixed integer program consists of variables, linear constraints on these
185
variables, and an objective function which is to be maximised or minimised
186
under these constraints. An instance of ``MixedIntegerLinearProgram`` also
187
requires the information on the direction of the optimization.
188
189
INPUT:
190
191
- ``solver`` -- the following solvers should be available through this class:
192
193
- GLPK (``solver="GLPK"``). See the `GLPK
194
<http://www.gnu.org/software/glpk/>`_ web site.
195
196
- COIN Branch and Cut (``solver="Coin"``). See the `COIN-OR
197
<http://www.coin-or.org>`_ web site.
198
199
- CPLEX (``solver="CPLEX"``). See the `CPLEX
200
<http://www.ilog.com/products/cplex/>`_ web site.
201
202
- Gurobi (``solver="Gurobi"``). See the `Gurobi <http://www.gurobi.com/>`_
203
web site.
204
205
- PPL (``solver="PPL"``). See the 'PPL<http://bugseng.com/products/ppl>'_
206
web site.
207
208
- If ``solver=None`` (default), the default solver is used (see
209
``default_mip_solver`` method.
210
211
- ``maximization``
212
213
- When set to ``True`` (default), the ``MixedIntegerLinearProgram``
214
is defined as a maximization.
215
216
- When set to ``False``, the ``MixedIntegerLinearProgram`` is
217
defined as a minimization.
218
219
- ``constraint_generation`` -- whether to require the returned solver to
220
support constraint generation (excludes Coin). ``False by default``.
221
222
.. SEEALSO::
223
224
- :func:`default_mip_solver` -- Returns/Sets the default MIP solver.
225
226
EXAMPLES:
227
228
Computation of a maximum stable set in Petersen's graph::
229
230
sage: g = graphs.PetersenGraph()
231
sage: p = MixedIntegerLinearProgram(maximization=True)
232
sage: b = p.new_variable()
233
sage: p.set_objective(sum([b[v] for v in g]))
234
sage: for (u,v) in g.edges(labels=None):
235
... p.add_constraint(b[u] + b[v], max=1)
236
sage: p.set_binary(b)
237
sage: p.solve(objective_only=True)
238
4.0
239
"""
240
241
def __init__(self, solver=None, maximization=True,
242
constraint_generation=False, check_redundant=False):
243
r"""
244
Constructor for the ``MixedIntegerLinearProgram`` class.
245
246
INPUT:
247
248
- ``solver`` -- the following solvers should be available through this class:
249
250
- GLPK (``solver="GLPK"``). See the `GLPK
251
<http://www.gnu.org/software/glpk/>`_ web site.
252
253
- COIN Branch and Cut (``solver="Coin"``). See the `COIN-OR
254
<http://www.coin-or.org>`_ web site.
255
256
- CPLEX (``solver="CPLEX"``). See the `CPLEX
257
<http://www.ilog.com/products/cplex/>`_ web site. An interface to
258
CPLEX is not yet implemented.
259
260
- Gurobi (``solver="Gurobi"``). See the `Gurobi
261
<http://www.gurobi.com/>`_ web site.
262
263
- PPL (``solver="PPL"``). See the `PPL
264
<http://bugseng.com/products/ppl>`_ web site.
265
266
-If ``solver=None`` (default), the default solver is used (see
267
``default_mip_solver`` method.
268
269
- ``maximization``
270
271
- When set to ``True`` (default), the ``MixedIntegerLinearProgram``
272
is defined as a maximization.
273
- When set to ``False``, the ``MixedIntegerLinearProgram`` is
274
defined as a minimization.
275
276
- ``constraint_generation`` -- whether to require the returned solver to
277
support constraint generation (excludes Coin). ``False by default``.
278
279
- ``check_redundant`` -- whether to check that constraints added to the
280
program are redundant with constraints already in the program.
281
Only obvious redundancies are checked: to be considered redundant,
282
either a constraint is equal to another constraint in the program,
283
or it is a constant multiple of the other. To make this search
284
effective and efficient, constraints are normalized; thus, the
285
constraint `-x_1 < 0` will be stored as `x_1 > 0`.
286
287
.. SEEALSO::
288
289
- :meth:`default_mip_solver` -- Returns/Sets the default MIP solver.
290
291
EXAMPLE::
292
293
sage: p = MixedIntegerLinearProgram(maximization=True)
294
295
TESTS:
296
297
Checks that the objects are deallocated without invoking the cyclic garbage
298
collector (cf. :trac:`12616`)::
299
300
sage: del p
301
sage: def just_create_variables():
302
... p = MixedIntegerLinearProgram()
303
... b = p.new_variable()
304
... p.add_constraint(b[3]+b[6] <= 2)
305
... p.solve()
306
sage: C = sage.numerical.mip.MixedIntegerLinearProgram
307
sage: import gc
308
sage: _ = gc.collect() # avoid side effects of other doc tests
309
sage: sum([1 for x in gc.get_objects() if isinstance(x,C)])
310
0
311
312
We now disable the cyclic garbage collector. Since :trac:`12616` avoids
313
a reference cycle, the mixed integer linear program created in
314
``just_create_variables()`` is removed even without the cyclic garbage
315
collection::
316
317
sage: gc.disable()
318
sage: just_create_variables()
319
sage: sum([1 for x in gc.get_objects() if isinstance(x,C)])
320
0
321
sage: gc.enable()
322
"""
323
self.__BINARY = 0
324
self.__REAL = -1
325
self.__INTEGER = 1
326
327
from sage.numerical.backends.generic_backend import get_solver
328
self._backend = get_solver(solver=solver,
329
constraint_generation=constraint_generation)
330
if not maximization:
331
self._backend.set_sense(-1)
332
333
# Associates an index to the variables
334
self._variables = {}
335
336
# Check for redundant constraints
337
self._check_redundant = check_redundant
338
if check_redundant:
339
self._constraints = list()
340
341
def linear_functions_parent(self):
342
"""
343
Return the parent for all linear functions
344
345
EXAMPLES::
346
347
sage: p = MixedIntegerLinearProgram()
348
sage: p.linear_functions_parent()
349
Linear functions over Real Double Field
350
"""
351
if self._linear_functions_parent is None:
352
base_ring = self._backend.base_ring()
353
from sage.numerical.linear_functions import LinearFunctionsParent
354
self._linear_functions_parent = LinearFunctionsParent(base_ring)
355
return self._linear_functions_parent
356
357
def linear_constraints_parent(self):
358
"""
359
Return the parent for all linear constraints
360
361
See :mod:`~sage.numerical.linear_functions` for more
362
details.
363
364
EXAMPLES::
365
366
sage: p = MixedIntegerLinearProgram()
367
sage: p.linear_constraints_parent()
368
Linear constraints over Real Double Field
369
"""
370
if self._linear_constraints_parent is None:
371
from sage.numerical.linear_functions import LinearConstraintsParent
372
LF = self.linear_functions_parent()
373
self._linear_constraints_parent = LinearConstraintsParent(LF)
374
return self._linear_constraints_parent
375
376
def __call__(self, x):
377
"""
378
Construct a new linear function
379
380
EXAMPLES::
381
382
sage: p = MixedIntegerLinearProgram()
383
sage: p.linear_function({1:3, 4:5})
384
3*x_1 + 5*x_4
385
386
This is equivalent to::
387
388
sage: p({1:3, 4:5})
389
3*x_1 + 5*x_4
390
"""
391
parent = self.linear_functions_parent()
392
return parent(x)
393
394
linear_function = __call__
395
396
def _repr_(self):
397
r"""
398
Returns a short description of the ``MixedIntegerLinearProgram``.
399
400
EXAMPLE::
401
402
sage: p = MixedIntegerLinearProgram()
403
sage: v = p.new_variable()
404
sage: p.add_constraint(v[1] + v[2], max=2)
405
sage: print p
406
Mixed Integer Program ( maximization, 2 variables, 1 constraints )
407
"""
408
cdef GenericBackend b = self._backend
409
410
return ("Mixed Integer Program "+
411
412
( "\"" +self._backend.problem_name()+ "\""
413
if (str(self._backend.problem_name()) != "") else "")+
414
415
" ( " + ("maximization" if b.is_maximization() else "minimization" ) +
416
417
", " + str(b.ncols()) + " variables, " +
418
str(b.nrows()) + " constraints )")
419
420
def __copy__(self):
421
r"""
422
Returns a copy of the current ``MixedIntegerLinearProgram`` instance.
423
424
EXAMPLE::
425
426
sage: p = MixedIntegerLinearProgram()
427
sage: p.add_constraint(p[0] + p[1], max = 10)
428
sage: q = copy(p)
429
sage: q.number_of_constraints()
430
1
431
"""
432
cdef MixedIntegerLinearProgram p = \
433
MixedIntegerLinearProgram(solver="GLPK")
434
from copy import copy
435
try:
436
p._variables = copy(self._variables)
437
except AttributeError:
438
pass
439
440
try:
441
p._default_mipvariable = self._default_mipvariable
442
except AttributeError:
443
pass
444
445
try:
446
p._check_redundant = self._check_redundant
447
p._constraints = copy(self._constraints)
448
except AttributeError:
449
pass
450
451
p._backend = (<GenericBackend> self._backend).copy()
452
return p
453
454
def __getitem__(self, v):
455
r"""
456
Returns the symbolic variable corresponding to the key
457
from a default dictionary.
458
459
It returns the element asked, and otherwise creates it.
460
If necessary, it also creates the default dictionary.
461
462
This method lets the user define LinearProgram without having to
463
define independent dictionaries when it is not necessary for him.
464
465
EXAMPLE::
466
467
sage: p = MixedIntegerLinearProgram()
468
sage: p.set_objective(p['x'] + p['z'])
469
sage: p['x']
470
x_0
471
"""
472
473
try:
474
return self._default_mipvariable[v]
475
except TypeError:
476
self._default_mipvariable = self.new_variable()
477
return self._default_mipvariable[v]
478
479
def base_ring(self):
480
"""
481
Return the base ring.
482
483
OUTPUT:
484
485
A ring. The coefficients that the chosen solver supports.
486
487
EXAMPLES::
488
489
sage: p = MixedIntegerLinearProgram(solver='GLPK')
490
sage: p.base_ring()
491
Real Double Field
492
sage: p = MixedIntegerLinearProgram(solver='ppl')
493
sage: p.base_ring()
494
Rational Field
495
"""
496
return self._backend.base_ring()
497
498
def set_problem_name(self,name):
499
r"""
500
Sets the name of the ``MixedIntegerLinearProgram``.
501
502
INPUT:
503
504
- ``name`` -- A string representing the name of the
505
``MixedIntegerLinearProgram``.
506
507
EXAMPLE::
508
509
sage: p=MixedIntegerLinearProgram()
510
sage: p.set_problem_name("Test program")
511
sage: p
512
Mixed Integer Program "Test program" ( maximization, 0 variables, 0 constraints )
513
"""
514
self._backend.problem_name(name)
515
516
def new_variable(self, real=False, binary=False, integer=False, dim=1,name=""):
517
r"""
518
Returns an instance of ``MIPVariable`` associated
519
to the current instance of ``MixedIntegerLinearProgram``.
520
521
A new variable ``x`` is defined by::
522
523
sage: p = MixedIntegerLinearProgram()
524
sage: x = p.new_variable()
525
526
It behaves exactly as a usual dictionary would. It can use any key
527
argument you may like, as ``x[5]`` or ``x["b"]``, and has methods
528
``items()`` and ``keys()``.
529
530
Any of its fields exists, and is uniquely defined.
531
532
By default, all ``x[i]`` are assumed to be non-negative
533
reals. They can be defined as binary through the parameter
534
``binary=True`` (or integer with ``integer=True``). Lower and
535
upper bounds can be defined or re-defined (for instance when you want
536
some variables to be negative) using ``MixedIntegerLinearProgram`` methods
537
``set_min`` and ``set_max``.
538
539
INPUT:
540
541
- ``dim`` (integer) -- Defines the dimension of the dictionary.
542
If ``x`` has dimension `2`, its fields will be of the form
543
``x[key1][key2]``.
544
545
- ``binary, integer, real`` (boolean) -- Set one of these arguments
546
to ``True`` to ensure that the variable gets the corresponding
547
type. The default type is ``real``.
548
549
- ``name`` (string) -- Associates a name to the variable. This is
550
only useful when exporting the linear program to a file using
551
``write_mps`` or ``write_lp``, and has no other effect.
552
553
EXAMPLE::
554
555
sage: p = MixedIntegerLinearProgram()
556
557
To define two dictionaries of variables, the first being
558
of real type, and the second of integer type ::
559
560
sage: x = p.new_variable(real=True)
561
sage: y = p.new_variable(dim=2, integer=True)
562
sage: p.add_constraint(x[2] + y[3][5], max=2)
563
sage: p.is_integer(x[2])
564
False
565
sage: p.is_integer(y[3][5])
566
True
567
568
An exception is raised when two types are supplied ::
569
570
sage: z = p.new_variable(real = True, integer = True)
571
Traceback (most recent call last):
572
...
573
ValueError: Exactly one of the available types has to be True
574
"""
575
if sum([real, binary, integer]) >= 2:
576
raise ValueError("Exactly one of the available types has to be True")
577
578
if binary:
579
vtype = self.__BINARY
580
elif integer:
581
vtype = self.__INTEGER
582
else:
583
vtype = self.__REAL
584
585
v=MIPVariable(self, vtype, dim=dim,name=name)
586
return v
587
588
cpdef int number_of_constraints(self):
589
r"""
590
Returns the number of constraints assigned so far.
591
592
EXAMPLE::
593
594
sage: p = MixedIntegerLinearProgram()
595
sage: p.add_constraint(p[0] - p[2], min = 1, max = 4)
596
sage: p.add_constraint(p[0] - 2*p[1], min = 1)
597
sage: p.number_of_constraints()
598
2
599
"""
600
return self._backend.nrows()
601
602
cpdef int number_of_variables(self):
603
r"""
604
Returns the number of variables used so far.
605
606
Note that this is backend-dependent, i.e. we count solver's
607
variables rather than user's variables. An example of the latter
608
can be seen below: Gurobi converts double inequalities,
609
i.e. inequalities like `m <= c^T x <= M`, with `m<M`, into
610
equations, by adding extra variables: `c^T x + y = M`, `0 <= y
611
<= M-m`.
612
613
EXAMPLE::
614
615
sage: p = MixedIntegerLinearProgram()
616
sage: p.add_constraint(p[0] - p[2], max = 4)
617
sage: p.number_of_variables()
618
2
619
sage: p.add_constraint(p[0] - 2*p[1], min = 1)
620
sage: p.number_of_variables()
621
3
622
sage: p = MixedIntegerLinearProgram(solver="glpk")
623
sage: p.add_constraint(p[0] - p[2], min = 1, max = 4)
624
sage: p.number_of_variables()
625
2
626
sage: p = MixedIntegerLinearProgram(solver="gurobi") # optional - Gurobi
627
sage: p.add_constraint(p[0] - p[2], min = 1, max = 4) # optional - Gurobi
628
sage: p.number_of_variables() # optional - Gurobi
629
3
630
"""
631
return self._backend.ncols()
632
633
def constraints(self, indices = None):
634
r"""
635
Returns a list of constraints, as 3-tuples.
636
637
INPUT:
638
639
- ``indices`` -- select which constraint(s) to return
640
641
- If ``indices = None``, the method returns the list of all the
642
constraints.
643
644
- If ``indices`` is an integer `i`, the method returns constraint
645
`i`.
646
647
- If ``indices`` is a list of integers, the method returns the list
648
of the corresponding constraints.
649
650
OUTPUT:
651
652
Each constraint is returned as a triple ``lower_bound, (indices,
653
coefficients), upper_bound``. For each of those entries, the
654
corresponding linear function is the one associating to variable
655
``indices[i]`` the coefficient ``coefficients[i]``, and `0` to all the
656
others.
657
658
``lower_bound`` and ``upper_bound`` are numerical values.
659
660
EXAMPLE:
661
662
First, let us define a small LP::
663
664
sage: p = MixedIntegerLinearProgram()
665
sage: p.add_constraint(p[0] - p[2], min = 1, max = 4)
666
sage: p.add_constraint(p[0] - 2*p[1], min = 1)
667
668
To obtain the list of all constraints::
669
670
sage: p.constraints() # not tested
671
[(1.0, ([1, 0], [-1.0, 1.0]), 4.0), (1.0, ([2, 0], [-2.0, 1.0]), None)]
672
673
Or constraint `0` only::
674
675
sage: p.constraints(0) # not tested
676
(1.0, ([1, 0], [-1.0, 1.0]), 4.0)
677
678
A list of constraints containing only `1`::
679
680
sage: p.constraints([1]) # not tested
681
[(1.0, ([2, 0], [-2.0, 1.0]), None)]
682
683
TESTS:
684
685
As the ordering of the variables in each constraint depends on the
686
solver used, we define a short function reordering it before it is
687
printed. The output would look the same without this function applied::
688
689
sage: def reorder_constraint((lb,(ind,coef),ub)):
690
... d = dict(zip(ind, coef))
691
... ind.sort()
692
... return (lb, (ind, [d[i] for i in ind]), ub)
693
694
Running the examples from above, reordering applied::
695
696
sage: p = MixedIntegerLinearProgram(solver = "GLPK")
697
sage: p.add_constraint(p[0] - p[2], min = 1, max = 4)
698
sage: p.add_constraint(p[0] - 2*p[1], min = 1)
699
sage: sorted(map(reorder_constraint,p.constraints()))
700
[(1.0, ([0, 1], [1.0, -1.0]), 4.0), (1.0, ([0, 2], [1.0, -2.0]), None)]
701
sage: reorder_constraint(p.constraints(0))
702
(1.0, ([0, 1], [1.0, -1.0]), 4.0)
703
sage: sorted(map(reorder_constraint,p.constraints([1])))
704
[(1.0, ([0, 2], [1.0, -2.0]), None)]
705
706
"""
707
from sage.rings.integer import Integer as Integer
708
cdef int i
709
cdef str s
710
cdef GenericBackend b = self._backend
711
712
result = list()
713
714
# If indices == None, we actually want to return all constraints
715
if indices == None:
716
indices = range(b.nrows())
717
718
# Only one constraint
719
if isinstance(indices, int) or isinstance(indices, Integer):
720
lb, ub = b.row_bounds(indices)
721
return (lb, b.row(indices), ub)
722
723
# List of constraints
724
elif isinstance(indices, list):
725
for i in indices:
726
lb, ub = b.row_bounds(i)
727
result.append((lb, b.row(i), ub))
728
729
return result
730
731
# Weird Input
732
else:
733
raise ValueError, "constraints() requires a list of integers, though it will accommodate None or an integer."
734
735
def polyhedron(self, **kwds):
736
r"""
737
Returns the polyhedron defined by the Linear Program.
738
739
INPUT:
740
741
All arguments given to this method are forwarded to the constructor of
742
the :func:`Polyhedron` class.
743
744
OUTPUT:
745
746
A :func:`Polyhedron` object whose `i`-th variable represents the `i`-th
747
variable of ``self``.
748
749
.. warning::
750
751
The polyhedron is built from the variables stored by the LP solver
752
(i.e. the output of :meth:`show`). While they usually match the ones
753
created explicitely when defining the LP, a solver like Gurobi has
754
been known to introduce additional variables to store constraints of
755
the type ``lower_bound <= linear_function <= upper bound``. You
756
should be fine if you did not install Gurobi or if you do not use it
757
as a solver, but keep an eye on the number of variables in the
758
polyhedron, or on the output of :meth:`show`. Just in case.
759
760
EXAMPLES:
761
762
A LP on two variables::
763
764
sage: p = MixedIntegerLinearProgram()
765
sage: p.add_constraint(2*p['x'] + p['y'] <= 1)
766
sage: p.add_constraint(3*p['y'] + p['x'] <= 2)
767
sage: P = p.polyhedron(); P
768
A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices
769
770
3-D Polyhedron::
771
772
sage: p = MixedIntegerLinearProgram()
773
sage: p.add_constraint(2*p['x'] + p['y'] + 3*p['z'] <= 1)
774
sage: p.add_constraint(2*p['y'] + p['z'] + 3*p['x'] <= 1)
775
sage: p.add_constraint(2*p['z'] + p['x'] + 3*p['y'] <= 1)
776
sage: P = p.polyhedron(); P
777
A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices
778
779
An empty polyhedron::
780
781
sage: p = MixedIntegerLinearProgram()
782
sage: p.add_constraint(2*p['x'] + p['y'] + 3*p['z'] <= 1)
783
sage: p.add_constraint(2*p['y'] + p['z'] + 3*p['x'] <= 1)
784
sage: p.add_constraint(2*p['z'] + p['x'] + 3*p['y'] >= 2)
785
sage: P = p.polyhedron(); P
786
The empty polyhedron in QQ^3
787
788
An unbounded polyhedron::
789
790
sage: p = MixedIntegerLinearProgram()
791
sage: p.add_constraint(2*p['x'] + p['y'] - p['z'] <= 1)
792
sage: P = p.polyhedron(); P
793
A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices and 3 rays
794
795
A square (see :trac:`14395`) ::
796
797
sage: p = MixedIntegerLinearProgram()
798
sage: x,y = p['x'], p['y']
799
sage: p.set_min(x,None)
800
sage: p.set_min(y,None)
801
sage: p.add_constraint( x <= 1 )
802
sage: p.add_constraint( x >= -1 )
803
sage: p.add_constraint( y <= 1 )
804
sage: p.add_constraint( y >= -1 )
805
sage: p.polyhedron()
806
A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices
807
808
"""
809
from sage.geometry.polyhedron.constructor import Polyhedron
810
from copy import copy
811
812
cdef GenericBackend b = self._backend
813
cdef int i
814
815
inequalities = []
816
equalities = []
817
nvar = self.number_of_variables()
818
819
# Constraints
820
for lb, (indices, values), ub in self.constraints():
821
822
coeffs = dict(zip(indices, values))
823
824
# Equalities
825
if (not lb is None) and lb == ub:
826
linear_function = []
827
linear_function = [coeffs.get(i,0) for i in range(nvar)]
828
linear_function.insert(0,-lb)
829
equalities.append(linear_function)
830
continue
831
832
# Lower Bound
833
if not lb is None:
834
linear_function = []
835
linear_function = [coeffs.get(i,0) for i in range(nvar)]
836
linear_function.insert(0,-lb)
837
inequalities.append(linear_function)
838
839
# Upper Bound
840
if not ub is None:
841
linear_function = []
842
linear_function = [-coeffs.get(i,0) for i in range(nvar)]
843
linear_function.insert(0,ub)
844
inequalities.append(linear_function)
845
846
zero = [0] * nvar
847
848
# Variable bounds
849
for 0<= i < nvar:
850
lb, ub = b.col_bounds(i)
851
852
# Fixed variable
853
if (not lb is None) and lb == ub:
854
linear_function = copy(zero)
855
linear_function[i] = 1
856
linear_function.insert(0,-lb)
857
equalities.append(linear_function)
858
continue
859
860
# Lower bound
861
if not lb is None:
862
linear_function = copy(zero)
863
linear_function[i] = 1
864
linear_function.insert(0,-lb)
865
inequalities.append(linear_function)
866
867
# Upper bound
868
if not ub is None:
869
linear_function = copy(zero)
870
linear_function[i] = -1
871
linear_function.insert(0,ub)
872
inequalities.append(linear_function)
873
874
return Polyhedron(ieqs = inequalities, eqns = equalities)
875
876
def show(self):
877
r"""
878
Displays the ``MixedIntegerLinearProgram`` in a human-readable
879
way.
880
881
EXAMPLES:
882
883
When constraints and variables have names ::
884
885
sage: p = MixedIntegerLinearProgram(solver = "GLPK")
886
sage: x = p.new_variable(name="Hey")
887
sage: p.set_objective(x[1] + x[2])
888
sage: p.add_constraint(-3*x[1] + 2*x[2], max=2, name="Constraint_1")
889
sage: p.show()
890
Maximization:
891
Hey[1] + Hey[2]
892
Constraints:
893
Constraint_1: -3.0 Hey[1] + 2.0 Hey[2] <= 2.0
894
Variables:
895
Hey[1] is a continuous variable (min=0.0, max=+oo)
896
Hey[2] is a continuous variable (min=0.0, max=+oo)
897
898
Without any names ::
899
900
sage: p = MixedIntegerLinearProgram(solver = "GLPK")
901
sage: x = p.new_variable()
902
sage: p.set_objective(x[1] + x[2])
903
sage: p.add_constraint(-3*x[1] + 2*x[2], max=2)
904
sage: p.show()
905
Maximization:
906
x_0 + x_1
907
Constraints:
908
-3.0 x_0 + 2.0 x_1 <= 2.0
909
Variables:
910
x_0 is a continuous variable (min=0.0, max=+oo)
911
x_1 is a continuous variable (min=0.0, max=+oo)
912
913
With `\QQ` coefficients::
914
915
sage: p = MixedIntegerLinearProgram(solver= 'ppl')
916
sage: x = p.new_variable()
917
sage: p.set_objective(x[1] + 1/2*x[2])
918
sage: p.add_constraint(-3/5*x[1] + 2/7*x[2], max=2/5)
919
sage: p.show()
920
Maximization:
921
x_0 + 1/2 x_1
922
Constraints:
923
constraint_0: -3/5 x_0 + 2/7 x_1 <= 2/5
924
Variables:
925
x_0 is a continuous variable (min=0, max=+oo)
926
x_1 is a continuous variable (min=0, max=+oo)
927
"""
928
929
cdef int i, j
930
cdef GenericBackend b = self._backend
931
932
# inv_variables associates a MIPVariable object to an id
933
inv_variables = {}
934
935
for (v, id) in self._variables.iteritems():
936
inv_variables[id]=v
937
938
# varid_name associates variables id to names
939
varid_name = {}
940
941
for 0<= i < b.ncols():
942
s = b.col_name(i)
943
varid_name[i] = ("x_"+str(i)) if s == "" else s
944
945
##### Sense and objective function
946
947
print ("Maximization:" if b.is_maximization() else "Minimization:")
948
print " ",
949
950
first = True
951
for 0<= i< b.ncols():
952
c = b.objective_coefficient(i)
953
if c == 0:
954
continue
955
956
print (("+ " if (not first and c>0) else "") +
957
("" if c == 1 else ("- " if c == -1 else str(c)+" "))+varid_name[i]
958
),
959
first = False
960
961
if b.obj_constant_term > self._backend.zero(): print "+", b.obj_constant_term
962
elif b.obj_constant_term < self._backend.zero(): print "-", -b.obj_constant_term
963
964
print
965
966
##### Constraints
967
print "Constraints:"
968
969
for 0<= i < b.nrows():
970
971
indices, values = b.row(i)
972
973
lb, ub = b.row_bounds(i)
974
975
print " ",
976
977
978
# Constraint's name
979
if b.row_name(i):
980
print b.row_name(i)+":",
981
982
# Lower bound
983
if lb is not None:
984
print str(lb)+" <=",
985
986
first = True
987
988
for j,c in sorted(zip(indices, values)):
989
990
if c == 0:
991
continue
992
993
print (("+ " if (not first and c>0) else "") +
994
("" if c == 1 else ("- " if c == -1 else (str(c) + " " if first and c < 0 else ("- " + str(abs(c)) + " " if c < 0 else str(c) + " "))))+varid_name[j]
995
),
996
first = False
997
998
# Upper bound
999
print ("<= "+str(ub) if ub!=None else "")
1000
1001
1002
##### Variables
1003
print "Variables:"
1004
1005
for 0<= i < b.ncols():
1006
print " " + varid_name[i] + " is",
1007
1008
if b.is_variable_integer(i):
1009
print "an integer variable",
1010
elif b.is_variable_binary(i):
1011
print "a boolean variable",
1012
else:
1013
print "a continuous variable",
1014
1015
lb, ub = b.col_bounds(i)
1016
1017
print "(min=" + ( str(lb) if lb != None else "-oo" )+",",
1018
print "max=" + ( str(ub) if ub != None else "+oo" )+")"
1019
1020
1021
def write_mps(self,filename,modern=True):
1022
r"""
1023
Write the linear program as a MPS file.
1024
1025
This function export the problem as a MPS file.
1026
1027
INPUT:
1028
1029
- ``filename`` -- The file in which you want the problem
1030
to be written.
1031
1032
- ``modern`` -- Lets you choose between Fixed MPS and Free MPS
1033
1034
- ``True`` -- Outputs the problem in Free MPS
1035
- ``False`` -- Outputs the problem in Fixed MPS
1036
1037
EXAMPLE::
1038
1039
sage: p = MixedIntegerLinearProgram(solver="GLPK")
1040
sage: x = p.new_variable()
1041
sage: p.set_objective(x[1] + x[2])
1042
sage: p.add_constraint(-3*x[1] + 2*x[2], max=2,name="OneConstraint")
1043
sage: p.write_mps(os.path.join(SAGE_TMP, "lp_problem.mps"))
1044
Writing problem data to ...
1045
17 records were written
1046
1047
For information about the MPS file format :
1048
http://en.wikipedia.org/wiki/MPS_%28format%29
1049
"""
1050
self._backend.write_mps(filename, modern)
1051
1052
def write_lp(self,filename):
1053
r"""
1054
Write the linear program as a LP file.
1055
1056
This function export the problem as a LP file.
1057
1058
INPUT:
1059
1060
- ``filename`` -- The file in which you want the problem
1061
to be written.
1062
1063
EXAMPLE::
1064
1065
sage: p = MixedIntegerLinearProgram(solver="GLPK")
1066
sage: x = p.new_variable()
1067
sage: p.set_objective(x[1] + x[2])
1068
sage: p.add_constraint(-3*x[1] + 2*x[2], max=2)
1069
sage: p.write_lp(os.path.join(SAGE_TMP, "lp_problem.lp"))
1070
Writing problem data to ...
1071
9 lines were written
1072
1073
For more information about the LP file format :
1074
http://lpsolve.sourceforge.net/5.5/lp-format.htm
1075
"""
1076
1077
self._backend.write_lp(filename)
1078
1079
def get_values(self, *lists):
1080
r"""
1081
Return values found by the previous call to ``solve()``.
1082
1083
INPUT:
1084
1085
- Any instance of ``MIPVariable`` (or one of its elements),
1086
or lists of them.
1087
1088
OUTPUT:
1089
1090
- Each instance of ``MIPVariable`` is replaced by a dictionary
1091
containing the numerical values found for each
1092
corresponding variable in the instance.
1093
- Each element of an instance of a ``MIPVariable`` is replaced
1094
by its corresponding numerical value.
1095
1096
.. NOTE::
1097
1098
While a variable may be declared as binary or integer, its value as
1099
returned by the solver is of type ``float``.
1100
1101
EXAMPLE::
1102
1103
sage: p = MixedIntegerLinearProgram()
1104
sage: x = p.new_variable()
1105
sage: y = p.new_variable(dim=2)
1106
sage: p.set_objective(x[3] + 3*y[2][9] + x[5])
1107
sage: p.add_constraint(x[3] + y[2][9] + 2*x[5], max=2)
1108
sage: p.solve()
1109
6.0
1110
1111
To return the optimal value of ``y[2][9]``::
1112
1113
sage: p.get_values(y[2][9])
1114
2.0
1115
1116
To get a dictionary identical to ``x`` containing optimal
1117
values for the corresponding variables ::
1118
1119
sage: x_sol = p.get_values(x)
1120
sage: x_sol.keys()
1121
[3, 5]
1122
1123
Obviously, it also works with variables of higher dimension::
1124
1125
sage: y_sol = p.get_values(y)
1126
1127
We could also have tried ::
1128
1129
sage: [x_sol, y_sol] = p.get_values(x, y)
1130
1131
Or::
1132
1133
sage: [x_sol, y_sol] = p.get_values([x, y])
1134
"""
1135
val = []
1136
for l in lists:
1137
if isinstance(l, MIPVariable):
1138
if l.depth() == 1:
1139
c = {}
1140
for (k,v) in l.items():
1141
#c[k] = self._values[v] if self._values.has_key(v) else None
1142
c[k] = self._backend.get_variable_value(self._variables[v])
1143
val.append(c)
1144
else:
1145
c = {}
1146
for (k,v) in l.items():
1147
c[k] = self.get_values(v)
1148
val.append(c)
1149
elif isinstance(l, list):
1150
if len(l) == 1:
1151
val.append([self.get_values(l[0])])
1152
else:
1153
c = []
1154
[c.append(self.get_values(ll)) for ll in l]
1155
val.append(c)
1156
elif self._variables.has_key(l):
1157
#val.append(self._values[l])
1158
val.append(self._backend.get_variable_value(self._variables[l]))
1159
1160
if len(lists) == 1:
1161
return val[0]
1162
else:
1163
return val
1164
1165
def set_objective(self,obj):
1166
r"""
1167
Sets the objective of the ``MixedIntegerLinearProgram``.
1168
1169
INPUT:
1170
1171
- ``obj`` -- A linear function to be optimized.
1172
( can also be set to ``None`` or ``0`` when just
1173
looking for a feasible solution )
1174
1175
EXAMPLE:
1176
1177
Let's solve the following linear program::
1178
1179
Maximize:
1180
x + 5 * y
1181
Constraints:
1182
x + 0.2 y <= 4
1183
1.5 * x + 3 * y <= 4
1184
Variables:
1185
x is Real (min = 0, max = None)
1186
y is Real (min = 0, max = None)
1187
1188
This linear program can be solved as follows::
1189
1190
sage: p = MixedIntegerLinearProgram(maximization=True)
1191
sage: x = p.new_variable()
1192
sage: p.set_objective(x[1] + 5*x[2])
1193
sage: p.add_constraint(x[1] + 2/10*x[2], max=4)
1194
sage: p.add_constraint(1.5*x[1]+3*x[2], max=4)
1195
sage: round(p.solve(),5)
1196
6.66667
1197
sage: p.set_objective(None)
1198
sage: _ = p.solve()
1199
"""
1200
cdef list values = []
1201
1202
# If the objective is None, or a constant, we want to remember
1203
# that the objective function has been defined ( the user did not
1204
# forget it ). In some LP problems, you just want a feasible solution
1205
# and do not care about any function being optimal.
1206
1207
cdef int i
1208
1209
if obj is not None:
1210
f = obj.dict()
1211
else:
1212
f = {-1 : 0}
1213
1214
d = f.pop(-1,self._backend.zero())
1215
1216
for i in range(self._backend.ncols()):
1217
values.append(f.get(i,self._backend.zero()))
1218
1219
self._backend.set_objective(values, d)
1220
1221
def add_constraint(self, linear_function, max=None, min=None, name=None):
1222
r"""
1223
Adds a constraint to the ``MixedIntegerLinearProgram``.
1224
1225
INPUT:
1226
1227
- ``linear_function`` -- Two different types of arguments are possible:
1228
- A linear function. In this case, arguments ``min`` or ``max``
1229
have to be specified.
1230
- A linear constraint of the form ``A <= B``, ``A >= B``,
1231
``A <= B <= C``, ``A >= B >= C`` or ``A == B``. In this
1232
case, arguments ``min`` and ``max`` will be ignored.
1233
- ``max`` -- An upper bound on the constraint (set to ``None``
1234
by default). This must be a numerical value.
1235
- ``min`` -- A lower bound on the constraint. This must be a
1236
numerical value.
1237
- ``name`` -- A name for the constraint.
1238
1239
To set a lower and/or upper bound on the variables use the methods
1240
``set_min`` and/or ``set_max`` of ``MixedIntegerLinearProgram``.
1241
1242
EXAMPLE:
1243
1244
Consider the following linear program::
1245
1246
Maximize:
1247
x + 5 * y
1248
Constraints:
1249
x + 0.2 y <= 4
1250
1.5 * x + 3 * y <= 4
1251
Variables:
1252
x is Real (min = 0, max = None)
1253
y is Real (min = 0, max = None)
1254
1255
It can be solved as follows::
1256
1257
sage: p = MixedIntegerLinearProgram(maximization=True)
1258
sage: x = p.new_variable()
1259
sage: p.set_objective(x[1] + 5*x[2])
1260
sage: p.add_constraint(x[1] + 0.2*x[2], max=4)
1261
sage: p.add_constraint(1.5*x[1] + 3*x[2], max=4)
1262
sage: round(p.solve(),6)
1263
6.666667
1264
1265
There are two different ways to add the constraint
1266
``x[5] + 3*x[7] <= x[6] + 3`` to a ``MixedIntegerLinearProgram``.
1267
1268
The first one consists in giving ``add_constraint`` this
1269
very expression::
1270
1271
sage: p.add_constraint( x[5] + 3*x[7] <= x[6] + 3 )
1272
1273
The second (slightly more efficient) one is to use the
1274
arguments ``min`` or ``max``, which can only be numerical
1275
values::
1276
1277
sage: p.add_constraint( x[5] + 3*x[7] - x[6], max = 3 )
1278
1279
One can also define double-bounds or equality using symbols
1280
``<=``, ``>=`` and ``==``::
1281
1282
sage: p.add_constraint( x[5] + 3*x[7] == x[6] + 3 )
1283
sage: p.add_constraint( x[5] + 3*x[7] <= x[6] + 3 <= x[8] + 27 )
1284
1285
The previous program can be rewritten::
1286
1287
sage: p = MixedIntegerLinearProgram(maximization=True)
1288
sage: x = p.new_variable()
1289
sage: p.set_objective(x[1] + 5*x[2])
1290
sage: p.add_constraint(x[1] + 0.2*x[2] <= 4)
1291
sage: p.add_constraint(1.5*x[1] + 3*x[2] <= 4)
1292
sage: round(p.solve(), 5)
1293
6.66667
1294
1295
TESTS:
1296
1297
Complex constraints::
1298
1299
sage: p = MixedIntegerLinearProgram(solver = "GLPK")
1300
sage: b = p.new_variable()
1301
sage: p.add_constraint( b[8] - b[15] <= 3*b[8] + 9)
1302
sage: p.show()
1303
Maximization:
1304
<BLANKLINE>
1305
Constraints:
1306
-2.0 x_0 - x_1 <= 9.0
1307
Variables:
1308
x_0 is a continuous variable (min=0.0, max=+oo)
1309
x_1 is a continuous variable (min=0.0, max=+oo)
1310
1311
Empty constraint::
1312
1313
sage: p=MixedIntegerLinearProgram()
1314
sage: p.add_constraint(sum([]),min=2)
1315
1316
Min/Max are numerical ::
1317
1318
sage: v = p.new_variable()
1319
sage: p.add_constraint(v[3] + v[5], min = v[6])
1320
Traceback (most recent call last):
1321
...
1322
ValueError: min and max arguments are required to be numerical
1323
sage: p.add_constraint(v[3] + v[5], max = v[6])
1324
Traceback (most recent call last):
1325
...
1326
ValueError: min and max arguments are required to be numerical
1327
1328
Do not add redundant elements (notice only one copy of each constraint is added)::
1329
1330
sage: lp = MixedIntegerLinearProgram(solver = "GLPK", check_redundant=True)
1331
sage: for each in xrange(10): lp.add_constraint(lp[0]-lp[1],min=1)
1332
sage: lp.show()
1333
Maximization:
1334
<BLANKLINE>
1335
Constraints:
1336
1.0 <= x_0 - x_1
1337
Variables:
1338
x_0 is a continuous variable (min=0.0, max=+oo)
1339
x_1 is a continuous variable (min=0.0, max=+oo)
1340
1341
We check for constant multiples of constraints as well::
1342
1343
sage: for each in xrange(10): lp.add_constraint(2*lp[0]-2*lp[1],min=2)
1344
sage: lp.show()
1345
Maximization:
1346
<BLANKLINE>
1347
Constraints:
1348
1.0 <= x_0 - x_1
1349
Variables:
1350
x_0 is a continuous variable (min=0.0, max=+oo)
1351
x_1 is a continuous variable (min=0.0, max=+oo)
1352
1353
But if the constant multiple is negative, we should add it anyway (once)::
1354
1355
sage: for each in xrange(10): lp.add_constraint(-2*lp[0]+2*lp[1],min=-2)
1356
sage: lp.show()
1357
Maximization:
1358
<BLANKLINE>
1359
Constraints:
1360
1.0 <= x_0 - x_1
1361
x_0 - x_1 <= 1.0
1362
Variables:
1363
x_0 is a continuous variable (min=0.0, max=+oo)
1364
x_1 is a continuous variable (min=0.0, max=+oo)
1365
1366
TESTS:
1367
1368
Catch ``True`` / ``False`` as INPUT (:trac:`13646`)::
1369
1370
sage: p = MixedIntegerLinearProgram()
1371
sage: x = p.new_variable()
1372
sage: p.add_constraint(True)
1373
Traceback (most recent call last):
1374
...
1375
ValueError: argument must be a linear function or constraint, got True
1376
"""
1377
if linear_function is 0:
1378
return
1379
1380
# Raising an exception when min/max are not as expected
1381
from sage.rings.all import RR
1382
if ((min is not None and min not in RR)
1383
or (max is not None and max not in RR)):
1384
raise ValueError("min and max arguments are required to be numerical")
1385
1386
if is_LinearFunction(linear_function):
1387
f = linear_function.dict()
1388
constant_coefficient = f.get(-1,0)
1389
1390
# We do not want to ignore the constant coefficient
1391
max = (max - constant_coefficient) if max != None else None
1392
min = (min - constant_coefficient) if min != None else None
1393
1394
indices = []
1395
values = []
1396
1397
if self._check_redundant:
1398
b = self._backend
1399
from __builtin__ import min as min_function
1400
i = min_function([v for (v,coeff) in f.iteritems() if coeff != 0])
1401
c = f[i]
1402
C = [(v,coeff/c) for (v,coeff) in f.iteritems() if v != -1]
1403
if c > 0:
1404
min = min/c if min != None else None
1405
max = max/c if max != None else None
1406
else:
1407
tempmin = max/c if max != None else None
1408
tempmax = min/c if min != None else None
1409
min, max = tempmin, tempmax
1410
if (tuple(C),min,max) in self._constraints:
1411
return None
1412
else:
1413
self._constraints.append((tuple(C),min,max))
1414
else:
1415
C = [(v,coeff) for (v,coeff) in f.iteritems() if v != -1]
1416
1417
if min == None and max == None:
1418
raise ValueError("Both max and min are set to None ? Weird!")
1419
1420
self._backend.add_linear_constraint(C, min, max, name)
1421
1422
elif is_LinearConstraint(linear_function):
1423
constraint = linear_function
1424
for lhs, rhs in constraint.equations():
1425
self.add_constraint(lhs-rhs, min=0, max=0, name=name)
1426
for lhs, rhs in constraint.inequalities():
1427
self.add_constraint(lhs-rhs, max=0, name=name)
1428
else:
1429
raise ValueError('argument must be a linear function or constraint, got '+str(linear_function))
1430
1431
def remove_constraint(self, int i):
1432
r"""
1433
Removes a constraint from self.
1434
1435
INPUT:
1436
1437
- ``i`` -- Index of the constraint to remove.
1438
1439
EXAMPLE::
1440
1441
sage: p = MixedIntegerLinearProgram()
1442
sage: x, y = p[0], p[1]
1443
sage: p.add_constraint(x + y, max = 10)
1444
sage: p.add_constraint(x - y, max = 0)
1445
sage: p.add_constraint(x, max = 4)
1446
sage: p.show()
1447
Maximization:
1448
<BLANKLINE>
1449
Constraints:
1450
x_0 + x_1 <= 10.0
1451
x_0 - x_1 <= 0.0
1452
x_0 <= 4.0
1453
...
1454
sage: p.remove_constraint(1)
1455
sage: p.show()
1456
Maximization:
1457
<BLANKLINE>
1458
Constraints:
1459
x_0 + x_1 <= 10.0
1460
x_0 <= 4.0
1461
...
1462
sage: p.number_of_constraints()
1463
2
1464
"""
1465
if self._check_redundant: self._constraints.pop(i)
1466
self._backend.remove_constraint(i)
1467
1468
def remove_constraints(self, constraints):
1469
r"""
1470
Remove several constraints.
1471
1472
INPUT:
1473
1474
- ``constraints`` -- an iterable containing the indices of the rows to remove.
1475
1476
EXAMPLE::
1477
1478
sage: p = MixedIntegerLinearProgram()
1479
sage: x, y = p[0], p[1]
1480
sage: p.add_constraint(x + y, max = 10)
1481
sage: p.add_constraint(x - y, max = 0)
1482
sage: p.add_constraint(x, max = 4)
1483
sage: p.show()
1484
Maximization:
1485
<BLANKLINE>
1486
Constraints:
1487
x_0 + x_1 <= 10.0
1488
x_0 - x_1 <= 0.0
1489
x_0 <= 4.0
1490
...
1491
sage: p.remove_constraints([0, 1])
1492
sage: p.show()
1493
Maximization:
1494
<BLANKLINE>
1495
Constraints:
1496
x_0 <= 4.0
1497
...
1498
sage: p.number_of_constraints()
1499
1
1500
1501
When checking for redundant constraints, make sure you remove only
1502
the constraints that were actually added. Problems could arise if
1503
you have a function that builds lps non-interactively, but it fails
1504
to check whether adding a constraint actually increases the number of
1505
constraints. The function might later try to remove constraints that
1506
are not actually there::
1507
1508
sage: p = MixedIntegerLinearProgram(check_redundant=True)
1509
sage: x, y = p[0], p[1]
1510
sage: p.add_constraint(x + y, max = 10)
1511
sage: for each in xrange(10): p.add_constraint(x - y, max = 10)
1512
sage: p.add_constraint(x, max = 4)
1513
sage: p.number_of_constraints()
1514
3
1515
sage: p.remove_constraints(range(1,9))
1516
Traceback (most recent call last):
1517
...
1518
IndexError: pop index out of range
1519
sage: p.remove_constraint(1)
1520
sage: p.number_of_constraints()
1521
2
1522
1523
We should now be able to add the old constraint back in::
1524
1525
sage: for each in xrange(10): p.add_constraint(x - y, max = 10)
1526
sage: p.number_of_constraints()
1527
3
1528
"""
1529
if self._check_redundant:
1530
for i in sorted(constraints,reverse=True):
1531
self._constraints.pop(i)
1532
self._backend.remove_constraints(constraints)
1533
1534
def set_binary(self, ee):
1535
r"""
1536
Sets a variable or a ``MIPVariable`` as binary.
1537
1538
INPUT:
1539
1540
- ``ee`` -- An instance of ``MIPVariable`` or one of
1541
its elements.
1542
1543
EXAMPLE::
1544
1545
sage: p = MixedIntegerLinearProgram()
1546
sage: x = p.new_variable()
1547
1548
With the following instruction, all the variables
1549
from x will be binary::
1550
1551
sage: p.set_binary(x)
1552
sage: p.set_objective(x[0] + x[1])
1553
sage: p.add_constraint(-3*x[0] + 2*x[1], max=2)
1554
1555
It is still possible, though, to set one of these
1556
variables as real while keeping the others as they are::
1557
1558
sage: p.set_real(x[3])
1559
"""
1560
cdef MIPVariable e
1561
e = <MIPVariable> ee
1562
1563
if isinstance(e, MIPVariable):
1564
e._vtype = self.__BINARY
1565
if e.depth() == 1:
1566
for v in e.values():
1567
self._backend.set_variable_type(self._variables[v],self.__BINARY)
1568
else:
1569
for v in e.keys():
1570
self.set_binary(e[v])
1571
elif self._variables.has_key(e):
1572
self._backend.set_variable_type(self._variables[e],self.__BINARY)
1573
else:
1574
raise ValueError("e must be an instance of MIPVariable or one of its elements.")
1575
1576
def is_binary(self, e):
1577
r"""
1578
Tests whether the variable ``e`` is binary. Variables are real by
1579
default.
1580
1581
INPUT:
1582
1583
- ``e`` -- A variable (not a ``MIPVariable``, but one of its elements.)
1584
1585
OUTPUT:
1586
1587
``True`` if the variable ``e`` is binary; ``False`` otherwise.
1588
1589
EXAMPLE::
1590
1591
sage: p = MixedIntegerLinearProgram()
1592
sage: v = p.new_variable()
1593
sage: p.set_objective(v[1])
1594
sage: p.is_binary(v[1])
1595
False
1596
sage: p.set_binary(v[1])
1597
sage: p.is_binary(v[1])
1598
True
1599
"""
1600
1601
return self._backend.is_variable_binary(self._variables[e])
1602
1603
def set_integer(self, ee):
1604
r"""
1605
Sets a variable or a ``MIPVariable`` as integer.
1606
1607
INPUT:
1608
1609
- ``ee`` -- An instance of ``MIPVariable`` or one of
1610
its elements.
1611
1612
EXAMPLE::
1613
1614
sage: p = MixedIntegerLinearProgram()
1615
sage: x = p.new_variable()
1616
1617
With the following instruction, all the variables
1618
from x will be integers::
1619
1620
sage: p.set_integer(x)
1621
sage: p.set_objective(x[0] + x[1])
1622
sage: p.add_constraint(-3*x[0] + 2*x[1], max=2)
1623
1624
It is still possible, though, to set one of these
1625
variables as real while keeping the others as they are::
1626
1627
sage: p.set_real(x[3])
1628
"""
1629
cdef MIPVariable e
1630
e = <MIPVariable> ee
1631
1632
if isinstance(e, MIPVariable):
1633
e._vtype = self.__INTEGER
1634
if e.depth() == 1:
1635
for v in e.values():
1636
self._backend.set_variable_type(self._variables[v],self.__INTEGER)
1637
else:
1638
for v in e.keys():
1639
self.set_integer(e[v])
1640
elif self._variables.has_key(e):
1641
self._backend.set_variable_type(self._variables[e],self.__INTEGER)
1642
else:
1643
raise ValueError("e must be an instance of MIPVariable or one of its elements.")
1644
1645
def is_integer(self, e):
1646
r"""
1647
Tests whether the variable is an integer. Variables are real by
1648
default.
1649
1650
INPUT:
1651
1652
- ``e`` -- A variable (not a ``MIPVariable``, but one of its elements.)
1653
1654
OUTPUT:
1655
1656
``True`` if the variable ``e`` is an integer; ``False`` otherwise.
1657
1658
EXAMPLE::
1659
1660
sage: p = MixedIntegerLinearProgram()
1661
sage: v = p.new_variable()
1662
sage: p.set_objective(v[1])
1663
sage: p.is_integer(v[1])
1664
False
1665
sage: p.set_integer(v[1])
1666
sage: p.is_integer(v[1])
1667
True
1668
"""
1669
return self._backend.is_variable_integer(self._variables[e])
1670
1671
def set_real(self,ee):
1672
r"""
1673
Sets a variable or a ``MIPVariable`` as real.
1674
1675
INPUT:
1676
1677
- ``ee`` -- An instance of ``MIPVariable`` or one of
1678
its elements.
1679
1680
EXAMPLE::
1681
1682
sage: p = MixedIntegerLinearProgram()
1683
sage: x = p.new_variable()
1684
1685
With the following instruction, all the variables
1686
from x will be real (they are by default, though)::
1687
1688
sage: p.set_real(x)
1689
sage: p.set_objective(x[0] + x[1])
1690
sage: p.add_constraint(-3*x[0] + 2*x[1], max=2)
1691
1692
It is still possible, though, to set one of these
1693
variables as binary while keeping the others as they are::
1694
1695
sage: p.set_binary(x[3])
1696
"""
1697
1698
cdef MIPVariable e
1699
e = <MIPVariable> ee
1700
1701
if isinstance(e, MIPVariable):
1702
e._vtype = self.__REAL
1703
if e.depth() == 1:
1704
for v in e.values():
1705
self._backend.set_variable_type(self._variables[v],self.__REAL)
1706
else:
1707
for v in e.keys():
1708
self.set_real(e[v])
1709
elif self._variables.has_key(e):
1710
self._backend.set_variable_type(self._variables[e],self.__REAL)
1711
else:
1712
raise ValueError("e must be an instance of MIPVariable or one of its elements.")
1713
1714
def is_real(self, e):
1715
r"""
1716
Tests whether the variable is real. Variables are real by default.
1717
1718
INPUT:
1719
1720
- ``e`` -- A variable (not a ``MIPVariable``, but one of its elements.)
1721
1722
OUTPUT:
1723
1724
``True`` if the variable is real; ``False`` otherwise.
1725
1726
EXAMPLE::
1727
1728
sage: p = MixedIntegerLinearProgram()
1729
sage: v = p.new_variable()
1730
sage: p.set_objective(v[1])
1731
sage: p.is_real(v[1])
1732
True
1733
sage: p.set_binary(v[1])
1734
sage: p.is_real(v[1])
1735
False
1736
sage: p.set_real(v[1])
1737
sage: p.is_real(v[1])
1738
True
1739
"""
1740
return self._backend.is_variable_continuous(self._variables[e])
1741
1742
def solve(self, solver=None, log=None, objective_only=False):
1743
r"""
1744
Solves the ``MixedIntegerLinearProgram``.
1745
1746
INPUT:
1747
1748
- ``solver`` -- DEPRECATED -- the solver now has to be set
1749
when calling the class' constructor
1750
1751
- ``log`` -- integer (default: ``None``) The verbosity level. Indicates
1752
whether progress should be printed during computation. The solver is
1753
initialized to report no progress.
1754
1755
- ``objective_only`` -- Boolean variable.
1756
1757
- When set to ``True``, only the objective function is returned.
1758
- When set to ``False`` (default), the optimal numerical values
1759
are stored (takes computational time).
1760
1761
OUTPUT:
1762
1763
The optimal value taken by the objective function.
1764
1765
EXAMPLES:
1766
1767
Consider the following linear program::
1768
1769
Maximize:
1770
x + 5 * y
1771
Constraints:
1772
x + 0.2 y <= 4
1773
1.5 * x + 3 * y <= 4
1774
Variables:
1775
x is Real (min = 0, max = None)
1776
y is Real (min = 0, max = None)
1777
1778
This linear program can be solved as follows::
1779
1780
sage: p = MixedIntegerLinearProgram(maximization=True)
1781
sage: x = p.new_variable()
1782
sage: p.set_objective(x[1] + 5*x[2])
1783
sage: p.add_constraint(x[1] + 0.2*x[2], max=4)
1784
sage: p.add_constraint(1.5*x[1] + 3*x[2], max=4)
1785
sage: round(p.solve(),6)
1786
6.666667
1787
sage: x = p.get_values(x)
1788
sage: round(x[1],6)
1789
0.0
1790
sage: round(x[2],6)
1791
1.333333
1792
1793
Computation of a maximum stable set in Petersen's graph::
1794
1795
sage: g = graphs.PetersenGraph()
1796
sage: p = MixedIntegerLinearProgram(maximization=True)
1797
sage: b = p.new_variable()
1798
sage: p.set_objective(sum([b[v] for v in g]))
1799
sage: for (u,v) in g.edges(labels=None):
1800
... p.add_constraint(b[u] + b[v], max=1)
1801
sage: p.set_binary(b)
1802
sage: p.solve(objective_only=True)
1803
4.0
1804
1805
Constraints in the objective function are respected::
1806
1807
sage: p = MixedIntegerLinearProgram()
1808
sage: x, y = p[0], p[1]
1809
sage: p.add_constraint(2*x + 3*y, max = 6)
1810
sage: p.add_constraint(3*x + 2*y, max = 6)
1811
sage: p.set_objective(x + y + 7)
1812
sage: p.set_integer(x); p.set_integer(y)
1813
sage: p.solve()
1814
9.0
1815
"""
1816
if solver != None:
1817
raise ValueError("Solver argument deprecated. This parameter now has to be set when calling the class' constructor")
1818
1819
if log != None: self._backend.set_verbosity(log)
1820
1821
self._backend.solve()
1822
1823
return self._backend.get_objective_value()
1824
1825
def set_min(self, v, min):
1826
r"""
1827
Sets the minimum value of a variable.
1828
1829
INPUT:
1830
1831
- ``v`` -- a variable (not a ``MIPVariable``, but one of its
1832
elements).
1833
- ``min`` -- the minimum value the variable can take.
1834
When ``min=None``, the variable has no lower bound.
1835
1836
EXAMPLE::
1837
1838
sage: p = MixedIntegerLinearProgram()
1839
sage: v = p.new_variable()
1840
sage: p.set_objective(v[1])
1841
sage: p.get_min(v[1])
1842
0.0
1843
sage: p.set_min(v[1],6)
1844
sage: p.get_min(v[1])
1845
6.0
1846
sage: p.set_min(v[1], None)
1847
sage: p.get_min(v[1])
1848
1849
"""
1850
self._backend.variable_lower_bound(self._variables[v], min)
1851
1852
def set_max(self, v, max):
1853
r"""
1854
Sets the maximum value of a variable.
1855
1856
INPUT
1857
1858
- ``v`` -- a variable (not a ``MIPVariable``, but one of its
1859
elements).
1860
- ``max`` -- the maximum value the variable can take.
1861
When ``max=None``, the variable has no upper bound.
1862
1863
EXAMPLE::
1864
1865
sage: p = MixedIntegerLinearProgram()
1866
sage: v = p.new_variable()
1867
sage: p.set_objective(v[1])
1868
sage: p.get_max(v[1])
1869
sage: p.set_max(v[1],6)
1870
sage: p.get_max(v[1])
1871
6.0
1872
"""
1873
self._backend.variable_upper_bound(self._variables[v], max)
1874
1875
def get_min(self, v):
1876
r"""
1877
Returns the minimum value of a variable.
1878
1879
INPUT:
1880
1881
- ``v`` -- a variable (not a ``MIPVariable``, but one of its elements).
1882
1883
OUTPUT:
1884
1885
Minimum value of the variable, or ``None`` if
1886
the variable has no lower bound.
1887
1888
EXAMPLE::
1889
1890
sage: p = MixedIntegerLinearProgram()
1891
sage: v = p.new_variable()
1892
sage: p.set_objective(v[1])
1893
sage: p.get_min(v[1])
1894
0.0
1895
sage: p.set_min(v[1],6)
1896
sage: p.get_min(v[1])
1897
6.0
1898
sage: p.set_min(v[1], None)
1899
sage: p.get_min(v[1])
1900
"""
1901
return self._backend.variable_lower_bound(self._variables[v])
1902
1903
def get_max(self, v):
1904
r"""
1905
Returns the maximum value of a variable.
1906
1907
INPUT:
1908
1909
- ``v`` -- a variable (not a ``MIPVariable``, but one of its elements).
1910
1911
OUTPUT:
1912
1913
Maximum value of the variable, or ``None`` if
1914
the variable has no upper bound.
1915
1916
EXAMPLE::
1917
1918
sage: p = MixedIntegerLinearProgram()
1919
sage: v = p.new_variable()
1920
sage: p.set_objective(v[1])
1921
sage: p.get_max(v[1])
1922
sage: p.set_max(v[1],6)
1923
sage: p.get_max(v[1])
1924
6.0
1925
"""
1926
return self._backend.variable_upper_bound(self._variables[v])
1927
1928
def solver_parameter(self, name, value = None):
1929
"""
1930
Return or define a solver parameter
1931
1932
The solver parameters are by essence solver-specific, which
1933
means their meaning heavily depends on the solver used.
1934
1935
(If you do not know which solver you are using, then you use
1936
use GLPK).
1937
1938
Aliases:
1939
1940
Very common parameters have aliases making them
1941
solver-independent. For example, the following::
1942
1943
sage: p = MixedIntegerLinearProgram(solver = "GLPK")
1944
sage: p.solver_parameter("timelimit", 60)
1945
1946
Sets the solver to stop its computations after 60 seconds, and
1947
works with GLPK, CPLEX and Gurobi.
1948
1949
- ``"timelimit"`` -- defines the maximum time spent on a
1950
computation. Measured in seconds.
1951
1952
Solver-specific parameters:
1953
1954
- GLPK : We have implemented very close to comprehensive coverage of
1955
the GLPK solver parameters for the simplex and integer
1956
optimization methods. For details, see the documentation of
1957
:meth:`GLPKBackend.solver_parameter
1958
<sage.numerical.backends.glpk_backend.GLPKBackend.solver_parameter>`.
1959
1960
- CPLEX's parameters are identified by a string. Their
1961
list is available `on ILOG's website
1962
<http://publib.boulder.ibm.com/infocenter/odmeinfo/v3r4/index.jsp?topic=/ilog.odms.ide.odme.help/Content/Optimization/Documentation/ODME/_pubskel/ODME_pubskels/startall_ODME34_Eclipse1590.html>`_.
1963
1964
The command ::
1965
1966
sage: p = MixedIntegerLinearProgram(solver = "CPLEX") # optional - CPLEX
1967
sage: p.solver_parameter("CPX_PARAM_TILIM", 60) # optional - CPLEX
1968
1969
works as intended.
1970
1971
- Gurobi's parameters should all be available through this
1972
method. Their list is available on Gurobi's website
1973
`<http://www.gurobi.com/documentation/5.5/reference-manual/node798>`_.
1974
1975
INPUT:
1976
1977
- ``name`` (string) -- the parameter
1978
1979
- ``value`` -- the parameter's value if it is to be defined,
1980
or ``None`` (default) to obtain its current value.
1981
1982
EXAMPLE::
1983
1984
sage: p = MixedIntegerLinearProgram(solver = "GLPK")
1985
sage: p.solver_parameter("timelimit", 60)
1986
sage: p.solver_parameter("timelimit")
1987
60.0
1988
"""
1989
if value is None:
1990
return self._backend.solver_parameter(name)
1991
else:
1992
self._backend.solver_parameter(name, value)
1993
1994
cpdef sum(self, L):
1995
r"""
1996
Efficiently computes the sum of a sequence of
1997
:class:`~sage.numerical.linear_functions.LinearFunction` elements
1998
1999
INPUT:
2000
2001
- ``mip`` -- the :class:`MixedIntegerLinearProgram` parent.
2002
2003
- ``L`` -- list of :class:`~sage.numerical.linear_functions.LinearFunction` instances.
2004
2005
.. NOTE::
2006
2007
The use of the regular ``sum`` function is not recommended
2008
as it is much less efficient than this one
2009
2010
EXAMPLES::
2011
2012
sage: p = MixedIntegerLinearProgram()
2013
sage: v = p.new_variable()
2014
2015
The following command::
2016
2017
sage: s = p.sum([v[i] for i in xrange(90)])
2018
2019
is much more efficient than::
2020
2021
sage: s = sum([v[i] for i in xrange(90)])
2022
"""
2023
d = {}
2024
for v in L:
2025
for id,coeff in v.iteritems():
2026
d[id] = coeff + d.get(id,0)
2027
return self.linear_functions_parent()(d)
2028
2029
2030
def get_backend(self):
2031
r"""
2032
Returns the backend instance used.
2033
2034
This might be useful when acces to additional functions provided by
2035
the backend is needed.
2036
2037
EXAMPLE:
2038
2039
This example uses the simplex algorthm and prints information::
2040
2041
sage: p = MixedIntegerLinearProgram(solver="GLPK")
2042
sage: x, y = p[0], p[1]
2043
sage: p.add_constraint(2*x + 3*y, max = 6)
2044
sage: p.add_constraint(3*x + 2*y, max = 6)
2045
sage: p.set_objective(x + y + 7)
2046
sage: b = p.get_backend()
2047
sage: b.solver_parameter("simplex_or_intopt", "simplex_only")
2048
sage: b.solver_parameter("verbosity_simplex", "GLP_MSG_ALL")
2049
sage: p.solve() # tol 0.00001
2050
GLPK Simplex Optimizer, v4.44
2051
2 rows, 2 columns, 4 non-zeros
2052
* 0: obj = 7.000000000e+00 infeas = 0.000e+00 (0)
2053
* 2: obj = 9.400000000e+00 infeas = 0.000e+00 (0)
2054
OPTIMAL SOLUTION FOUND
2055
9.4
2056
"""
2057
return self._backend
2058
2059
class MIPSolverException(RuntimeError):
2060
r"""
2061
Exception raised when the solver fails.
2062
"""
2063
2064
def __init__(self, value):
2065
r"""
2066
Constructor for ``MIPSolverException``.
2067
2068
``MIPSolverException`` is the exception raised when the solver fails.
2069
2070
EXAMPLE::
2071
2072
sage: from sage.numerical.mip import MIPSolverException
2073
sage: MIPSolverException("Error")
2074
MIPSolverException()
2075
2076
TESTS:
2077
2078
No continuous solution::
2079
2080
sage: p=MixedIntegerLinearProgram(solver="GLPK")
2081
sage: v=p.new_variable()
2082
sage: p.add_constraint(v[0],max=5.5)
2083
sage: p.add_constraint(v[0],min=7.6)
2084
sage: p.set_objective(v[0])
2085
2086
Tests of GLPK's Exceptions::
2087
2088
sage: p.solve()
2089
Traceback (most recent call last):
2090
...
2091
MIPSolverException: 'GLPK : Solution is undefined'
2092
2093
No integer solution::
2094
2095
sage: p=MixedIntegerLinearProgram(solver="GLPK")
2096
sage: v=p.new_variable()
2097
sage: p.add_constraint(v[0],max=5.6)
2098
sage: p.add_constraint(v[0],min=5.2)
2099
sage: p.set_objective(v[0])
2100
sage: p.set_integer(v)
2101
2102
Tests of GLPK's Exceptions::
2103
2104
sage: p.solve()
2105
Traceback (most recent call last):
2106
...
2107
MIPSolverException: 'GLPK : Solution is undefined'
2108
"""
2109
self.value = value
2110
2111
def __str__(self):
2112
r"""
2113
Returns the value of the instance of ``MIPSolverException``.
2114
2115
EXAMPLE::
2116
2117
sage: from sage.numerical.mip import MIPSolverException
2118
sage: e = MIPSolverException("Error")
2119
sage: print e
2120
'Error'
2121
"""
2122
return repr(self.value)
2123
2124
cdef class MIPVariable(SageObject):
2125
r"""
2126
``MIPVariable`` is a variable used by the class
2127
``MixedIntegerLinearProgram``.
2128
"""
2129
2130
def __cinit__(self, p, vtype, dim=1, name=""):
2131
r"""
2132
Constructor for ``MIPVariable``.
2133
2134
INPUT:
2135
2136
- ``p`` -- the instance of ``MixedIntegerLinearProgram`` to which the
2137
variable is to be linked.
2138
2139
- ``vtype`` (integer) -- Defines the type of the variables
2140
(default is ``REAL``).
2141
2142
- ``dim`` -- the integer defining the definition of the variable.
2143
2144
- ``name`` -- A name for the ``MIPVariable``.
2145
2146
For more informations, see the method
2147
``MixedIntegerLinearProgram.new_variable``.
2148
2149
EXAMPLE::
2150
2151
sage: p=MixedIntegerLinearProgram()
2152
sage: v=p.new_variable()
2153
"""
2154
self._dim = dim
2155
self._dict = {}
2156
self._p = p
2157
self._vtype = vtype
2158
2159
self._hasname = (len(name) >0)
2160
2161
# create a temporary char *
2162
cdef char *name_c = name
2163
# and copy it over
2164
self._name = <char*>sage_malloc(len(name)+1)
2165
strcpy(self._name, name_c)
2166
2167
def __dealloc__(self):
2168
if self._name:
2169
sage_free(self._name)
2170
2171
def __getitem__(self, i):
2172
r"""
2173
Returns the symbolic variable corresponding to the key.
2174
2175
Returns the element asked, otherwise creates it.
2176
(When depth>1, recursively creates the variables).
2177
2178
EXAMPLE::
2179
2180
sage: p = MixedIntegerLinearProgram()
2181
sage: v = p.new_variable()
2182
sage: p.set_objective(v[0] + v[1])
2183
sage: v[0]
2184
x_0
2185
"""
2186
cdef MIPVariable s = self
2187
2188
cdef int j
2189
2190
if self._dict.has_key(i):
2191
return self._dict[i]
2192
elif self._dim == 1:
2193
zero = self._p._backend.zero()
2194
j = self._p._backend.add_variable(zero , None, False, True, False, zero,
2195
(str(self._name) + "[" + str(i) + "]")
2196
if self._hasname else None)
2197
2198
v = self._p.linear_function({j : 1})
2199
self._p._variables[v] = j
2200
self._p._backend.set_variable_type(j,self._vtype)
2201
self._dict[i] = v
2202
2203
return v
2204
2205
else:
2206
self._dict[i] = MIPVariable(
2207
self._p,
2208
self._vtype,
2209
dim=self._dim-1,
2210
name = ("" if not self._hasname
2211
else (str(self._name) + "[" + str(i) + "]")))
2212
2213
return self._dict[i]
2214
2215
def _repr_(self):
2216
r"""
2217
Returns a representation of self.
2218
2219
EXAMPLE::
2220
2221
sage: p=MixedIntegerLinearProgram()
2222
sage: v=p.new_variable(dim=3)
2223
sage: v
2224
MIPVariable of dimension 3.
2225
sage: v[2][5][9]
2226
x_0
2227
sage: v
2228
MIPVariable of dimension 3.
2229
"""
2230
return "MIPVariable of dimension " + str(self._dim) + "."
2231
2232
def keys(self):
2233
r"""
2234
Returns the keys already defined in the dictionary.
2235
2236
EXAMPLE::
2237
2238
sage: p = MixedIntegerLinearProgram()
2239
sage: v = p.new_variable()
2240
sage: p.set_objective(v[0] + v[1])
2241
sage: v.keys()
2242
[0, 1]
2243
"""
2244
return self._dict.keys()
2245
2246
def items(self):
2247
r"""
2248
Returns the pairs (keys,value) contained in the dictionary.
2249
2250
EXAMPLE::
2251
2252
sage: p = MixedIntegerLinearProgram()
2253
sage: v = p.new_variable()
2254
sage: p.set_objective(v[0] + v[1])
2255
sage: v.items()
2256
[(0, x_0), (1, x_1)]
2257
"""
2258
return self._dict.items()
2259
2260
def depth(self):
2261
r"""
2262
Returns the current variable's depth.
2263
2264
EXAMPLE::
2265
2266
sage: p = MixedIntegerLinearProgram()
2267
sage: v = p.new_variable()
2268
sage: p.set_objective(v[0] + v[1])
2269
sage: v.depth()
2270
1
2271
"""
2272
return self._dim
2273
2274
def values(self):
2275
r"""
2276
Returns the symbolic variables associated to the current dictionary.
2277
2278
EXAMPLE::
2279
2280
sage: p = MixedIntegerLinearProgram()
2281
sage: v = p.new_variable()
2282
sage: p.set_objective(v[0] + v[1])
2283
sage: v.values()
2284
[x_0, x_1]
2285
"""
2286
return self._dict.values()
2287
2288
def Sum(x):
2289
"""
2290
Only for legacy support, use :meth:`MixedIntegerLinearProgram.sum` instead.
2291
2292
EXAMPLES::
2293
2294
sage: from sage.numerical.mip import Sum
2295
sage: Sum([])
2296
doctest:...: DeprecationWarning: use MixedIntegerLinearProgram.sum() instead
2297
See http://trac.sagemath.org/13646 for details.
2298
2299
sage: p = MixedIntegerLinearProgram()
2300
sage: x = p.new_variable()
2301
sage: Sum([ x[0]+x[1], x[1]+x[2], x[2]+x[3] ]) # deprecation is only shown once
2302
x_0 + 2*x_1 + 2*x_2 + x_3
2303
"""
2304
from sage.misc.superseded import deprecation
2305
deprecation(13646, 'use MixedIntegerLinearProgram.sum() instead')
2306
if not x:
2307
return None
2308
parent = x[0].parent()
2309
return parent.sum(x)
2310
2311