Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/numerical/backends/gurobi_backend.pyx
8815 views
1
"""
2
Gurobi Backend
3
4
AUTHORS:
5
6
- Nathann Cohen (2011-10): initial implementation
7
8
TESTS:
9
10
Bug from :trac:`12833`::
11
12
sage: g = DiGraph('IESK@XgAbCgH??KG??')
13
sage: g.feedback_edge_set(value_only = True, constraint_generation = False)
14
7
15
sage: g.feedback_edge_set(value_only = True, constraint_generation = False, solver = "Gurobi") # optional - Gurobi
16
7
17
18
Methods
19
-------
20
"""
21
22
##############################################################################
23
# Copyright (C) 2010 Nathann Cohen <[email protected]>
24
# Distributed under the terms of the GNU General Public License (GPL)
25
# The full text of the GPL is available at:
26
# http://www.gnu.org/licenses/
27
##############################################################################
28
29
from sage.numerical.mip import MIPSolverException
30
31
cdef class GurobiBackend(GenericBackend):
32
def __init__(self, maximization = True):
33
"""
34
Constructor
35
36
EXAMPLE::
37
38
sage: p = MixedIntegerLinearProgram(solver="Gurobi") # optional - Gurobi
39
"""
40
cdef int error
41
42
# Initializing the master Environment. This one is kept to be
43
# deallocated on __dealloc__
44
error = GRBloadenv(&self.env_master, NULL)
45
46
if self.env_master == NULL:
47
raise RuntimeError("Could not initialize Gurobi environment")
48
49
check(self.env_master, error)
50
51
# Initializing the model
52
error = GRBnewmodel(self.env_master, &self.model, NULL, 0, NULL, NULL, NULL, NULL, NULL)
53
54
self.env = GRBgetenv (self.model)
55
56
if error:
57
raise RuntimeError("Could not initialize Gurobi model")
58
59
if maximization:
60
error = GRBsetintattr(self.model, "ModelSense", -1)
61
else:
62
error = GRBsetintattr(self.model, "ModelSense", +1)
63
64
check(self.env, error)
65
66
self.set_sense(1 if maximization else -1)
67
68
self.set_verbosity(0)
69
self.obj_constant_term = 0.0
70
71
cpdef int add_variable(self, lower_bound=0.0, upper_bound=None, binary=False, continuous=False, integer=False, obj=0.0, name=None) except -1:
72
"""
73
Add a variable.
74
75
This amounts to adding a new column to the matrix. By default,
76
the variable is both positive, real and the coefficient in the
77
objective function is 0.0.
78
79
INPUT:
80
81
- ``lower_bound`` - the lower bound of the variable (default: 0)
82
83
- ``upper_bound`` - the upper bound of the variable (default: ``None``)
84
85
- ``binary`` - ``True`` if the variable is binary (default: ``False``).
86
87
- ``continuous`` - ``True`` if the variable is binary (default: ``True``).
88
89
- ``integer`` - ``True`` if the variable is binary (default: ``False``).
90
91
- ``obj`` - (optional) coefficient of this variable in the objective function (default: 0.0)
92
93
- ``name`` - an optional name for the newly added variable (default: ``None``).
94
95
OUTPUT: The index of the newly created variable
96
97
EXAMPLE::
98
99
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
100
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
101
sage: p.ncols() # optional - Gurobi
102
0
103
sage: p.add_variable() # optional - Gurobi
104
0
105
sage: p.ncols() # optional - Gurobi
106
1
107
sage: p.add_variable(binary=True) # optional - Gurobi
108
1
109
sage: p.add_variable(lower_bound=-2.0, integer=True) # optional - Gurobi
110
2
111
sage: p.add_variable(continuous=True, integer=True) # optional - Gurobi
112
Traceback (most recent call last):
113
...
114
ValueError: ...
115
sage: p.add_variable(name='x',obj=1.0) # optional - Gurobi
116
3
117
sage: p.col_name(3) # optional - Gurobi
118
'x'
119
sage: p.objective_coefficient(3) # optional - Gurobi
120
1.0
121
"""
122
# Checking the input
123
cdef char vtype = int(bool(binary)) + int(bool(continuous)) + int(bool(integer))
124
if vtype == 0:
125
continuous = True
126
elif vtype != 1:
127
raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.")
128
129
cdef int error
130
131
if binary:
132
vtype = GRB_BINARY
133
elif continuous:
134
vtype = GRB_CONTINUOUS
135
elif integer:
136
vtype = GRB_INTEGER
137
138
cdef char * c_name = ""
139
140
if name is None:
141
name = "x_"+str(self.ncols())
142
143
c_name = name
144
145
if upper_bound is None:
146
upper_bound = GRB_INFINITY
147
if lower_bound is None:
148
lower_bound = -GRB_INFINITY
149
150
151
error = GRBaddvar(self.model, 0, NULL, NULL, obj, <double> lower_bound, <double> upper_bound, vtype, c_name)
152
153
check(self.env,error)
154
155
check(self.env,GRBupdatemodel(self.model))
156
157
return self.ncols()-1
158
159
cpdef int add_variables(self, int number, lower_bound=0.0, upper_bound=None, binary=False, continuous=False, integer=False, obj=0.0, names=None) except -1:
160
"""
161
Add ``number`` new variables.
162
163
This amounts to adding new columns to the matrix. By default,
164
the variables are both positive, real and theor coefficient in
165
the objective function is 0.0.
166
167
INPUT:
168
169
- ``n`` - the number of new variables (must be > 0)
170
171
- ``lower_bound`` - the lower bound of the variable (default: 0)
172
173
- ``upper_bound`` - the upper bound of the variable (default: ``None``)
174
175
- ``binary`` - ``True`` if the variable is binary (default: ``False``).
176
177
- ``continuous`` - ``True`` if the variable is binary (default: ``True``).
178
179
- ``integer`` - ``True`` if the variable is binary (default: ``False``).
180
181
- ``obj`` - (optional) coefficient of all variables in the objective function (default: 0.0)
182
183
- ``names`` - optional list of names (default: ``None``)
184
185
OUTPUT: The index of the variable created last.
186
187
EXAMPLE::
188
189
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
190
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
191
sage: p.ncols() # optional - Gurobi
192
0
193
sage: p.add_variables(5) # optional - Gurobi
194
4
195
sage: p.ncols() # optional - Gurobi
196
5
197
sage: p.add_variables(2, lower_bound=-2.0, integer=True, names=['a','b']) # optional - Gurobi
198
6
199
"""
200
cdef int i
201
cdef int value
202
for i in range(number):
203
value = self.add_variable(lower_bound = lower_bound,
204
upper_bound = upper_bound,
205
binary = binary,
206
continuous = continuous,
207
integer = integer,
208
obj = obj,
209
name = None if names is None else names[i])
210
return value
211
212
cpdef set_variable_type(self, int variable, int vtype):
213
"""
214
Set the type of a variable
215
216
INPUT:
217
218
- ``variable`` (integer) -- the variable's id
219
220
- ``vtype`` (integer) :
221
222
* 1 Integer
223
* 0 Binary
224
* -1 Real
225
226
EXAMPLE::
227
228
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
229
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
230
sage: p.ncols() # optional - Gurobi
231
0
232
sage: p.add_variable() # optional - Gurobi
233
0
234
sage: p.set_variable_type(0,1) # optional - Gurobi
235
sage: p.is_variable_integer(0) # optional - Gurobi
236
True
237
"""
238
cdef int error
239
240
if vtype == 1:
241
error = GRBsetcharattrelement(self.model, "VType", variable, 'I')
242
elif vtype == 0:
243
error = GRBsetcharattrelement(self.model, "VType", variable, 'B')
244
else:
245
error = GRBsetcharattrelement(self.model, "VType", variable, 'C')
246
check(self.env, error)
247
248
check(self.env,GRBupdatemodel(self.model))
249
250
cpdef set_sense(self, int sense):
251
"""
252
Set the direction (maximization/minimization).
253
254
INPUT:
255
256
- ``sense`` (integer) :
257
258
* +1 => Maximization
259
* -1 => Minimization
260
261
EXAMPLE::
262
263
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
264
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
265
sage: p.is_maximization() # optional - Gurobi
266
True
267
sage: p.set_sense(-1) # optional - Gurobi
268
sage: p.is_maximization() # optional - Gurobi
269
False
270
"""
271
cdef int error
272
273
if sense == 1:
274
error = GRBsetintattr(self.model, "ModelSense", -1)
275
else:
276
error = GRBsetintattr(self.model, "ModelSense", +1)
277
278
check(self.env, error)
279
check(self.env,GRBupdatemodel(self.model))
280
281
cpdef objective_coefficient(self, int variable, coeff=None):
282
"""
283
Set or get the coefficient of a variable in the objective function
284
285
INPUT:
286
287
- ``variable`` (integer) -- the variable's id
288
289
- ``coeff`` (double) -- its coefficient or ``None`` for
290
reading (default: ``None``)
291
292
EXAMPLE::
293
294
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
295
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
296
sage: p.add_variable() # optional - Gurobi
297
0
298
sage: p.objective_coefficient(0) == 0 # optional - Gurobi
299
True
300
sage: p.objective_coefficient(0,2) # optional - Gurobi
301
sage: p.objective_coefficient(0) # optional - Gurobi
302
2.0
303
"""
304
cdef int error
305
cdef double value[1]
306
307
if coeff:
308
error = GRBsetdblattrelement(self.model, "Obj", variable, coeff)
309
check(self.env, error)
310
check(self.env,GRBupdatemodel(self.model))
311
else:
312
error = GRBgetdblattrelement(self.model, "Obj", variable, value)
313
check(self.env, error)
314
return value[0]
315
316
cpdef problem_name(self, char * name = NULL):
317
"""
318
Return or define the problem's name
319
320
INPUT:
321
322
- ``name`` (``char *``) -- the problem's name. When set to
323
``NULL`` (default), the method returns the problem's name.
324
325
EXAMPLE::
326
327
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
328
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
329
sage: p.problem_name("There once was a french fry") # optional - Gurobi
330
sage: print p.problem_name() # optional - Gurobi
331
There once was a french fry
332
333
TESTS::
334
335
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
336
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
337
sage: print p.problem_name() # optional - Gurobi
338
"""
339
cdef int error
340
cdef char * pp_name[1]
341
342
if name:
343
error = GRBsetstrattr(self.model, "ModelName", name)
344
check(self.env, error)
345
check(self.env,GRBupdatemodel(self.model))
346
347
else:
348
check(self.env,GRBgetstrattr(self.model, "ModelName", <char **> pp_name))
349
if pp_name[0] == NULL:
350
value = ""
351
else:
352
value = str(pp_name[0])
353
354
return value
355
356
cpdef set_objective(self, list coeff, d = 0.0):
357
"""
358
Set the objective function.
359
360
INPUT:
361
362
- ``coeff`` - a list of real values, whose ith element is the
363
coefficient of the ith variable in the objective function.
364
365
- ``d`` (double) -- the constant term in the linear function (set to `0` by default)
366
367
EXAMPLE::
368
369
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
370
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
371
sage: p.add_variables(5) # optional - Gurobi
372
4
373
sage: p.set_objective([1, 1, 2, 1, 3]) # optional - Gurobi
374
sage: map(lambda x :p.objective_coefficient(x), range(5)) # optional - Gurobi
375
[1.0, 1.0, 2.0, 1.0, 3.0]
376
377
Constants in the objective function are respected::
378
379
sage: p = MixedIntegerLinearProgram(solver='Gurobi')# optional - Gurobi
380
sage: x,y = p[0], p[1] # optional - Gurobi
381
sage: p.add_constraint(2*x + 3*y, max = 6) # optional - Gurobi
382
sage: p.add_constraint(3*x + 2*y, max = 6) # optional - Gurobi
383
sage: p.set_objective(x + y + 7) # optional - Gurobi
384
sage: p.set_integer(x); p.set_integer(y) # optional - Gurobi
385
sage: p.solve() # optional - Gurobi
386
9.0
387
"""
388
cdef int i = 0
389
cdef double value
390
cdef int error
391
392
for value in coeff:
393
error = GRBsetdblattrelement (self.model, "Obj", i, value)
394
check(self.env,error)
395
i += 1
396
397
check(self.env,GRBupdatemodel(self.model))
398
399
self.obj_constant_term = d
400
401
cpdef set_verbosity(self, int level):
402
"""
403
Set the verbosity level
404
405
INPUT:
406
407
- ``level`` (integer) -- From 0 (no verbosity) to 3.
408
409
EXAMPLE::
410
411
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
412
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
413
sage: p.set_verbosity(2) # optional - Gurobi
414
415
"""
416
cdef int error
417
if level:
418
error = GRBsetintparam(self.env, "OutputFlag", 1)
419
else:
420
error = GRBsetintparam(self.env, "OutputFlag", 0)
421
422
check(self.env, error)
423
424
cpdef remove_constraint(self, int i):
425
r"""
426
Remove a constraint from self.
427
428
INPUT:
429
430
- ``i`` -- index of the constraint to remove
431
432
EXAMPLE::
433
434
sage: p = MixedIntegerLinearProgram(solver='Gurobi')# optional - Gurobi
435
sage: x,y = p[0], p[1] # optional - Gurobi
436
sage: p.add_constraint(2*x + 3*y, max = 6) # optional - Gurobi
437
sage: p.add_constraint(3*x + 2*y, max = 6) # optional - Gurobi
438
sage: p.set_objective(x + y + 7) # optional - Gurobi
439
sage: p.set_integer(x); p.set_integer(y) # optional - Gurobi
440
sage: p.solve() # optional - Gurobi
441
9.0
442
sage: p.remove_constraint(0) # optional - Gurobi
443
sage: p.solve() # optional - Gurobi
444
10.0
445
sage: p.get_values([x,y]) # optional - Gurobi
446
[0.0, 3.0]
447
"""
448
cdef int ind[1]
449
ind[0] = i
450
cdef int error
451
error = GRBdelconstrs (self.model, 1, ind )
452
check(self.env, error)
453
454
error = GRBupdatemodel(self.model)
455
check(self.env,error)
456
457
cpdef add_linear_constraint(self, coefficients, lower_bound, upper_bound, name=None):
458
"""
459
Add a linear constraint.
460
461
INPUT:
462
463
- ``coefficients`` an iterable with ``(c,v)`` pairs where ``c``
464
is a variable index (integer) and ``v`` is a value (real
465
value).
466
467
- ``lower_bound`` - a lower bound, either a real value or ``None``
468
469
- ``upper_bound`` - an upper bound, either a real value or ``None``
470
471
- ``name`` - an optional name for this row (default: ``None``)
472
473
EXAMPLE::
474
475
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
476
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
477
sage: p.add_variables(5) # optional - Gurobi
478
4
479
sage: p.add_linear_constraint( zip(range(5), range(5)), 2.0, 2.0) # optional - Gurobi
480
sage: p.row(0) # optional - Gurobi
481
([0, 1, 2, 3, 4], [0.0, 1.0, 2.0, 3.0, 4.0])
482
sage: p.row_bounds(0) # optional - Gurobi
483
(2.0, 2.0)
484
sage: p.add_linear_constraint( zip(range(5), range(5)), 1.0, 1.0, name='foo') # optional - Gurobi
485
sage: p.row_name(1) # optional - Gurobi
486
'foo'
487
"""
488
489
if lower_bound is None and upper_bound is None:
490
raise ValueError("At least one of 'upper_bound' or 'lower_bound' must be set.")
491
492
cdef int * row_i
493
cdef double * row_values
494
495
row_i = <int *> sage_malloc((len(coefficients)) * sizeof(int))
496
row_values = <double *> sage_malloc((len(coefficients)) * sizeof(double))
497
498
499
for i,(c,v) in enumerate(coefficients):
500
row_i[i] = c
501
row_values[i] = v
502
503
if name is None:
504
name = ""
505
506
if upper_bound is not None and lower_bound is None:
507
error = GRBaddconstr(self.model, len(coefficients), row_i, row_values, GRB_LESS_EQUAL, <double> upper_bound, name)
508
509
elif lower_bound is not None and upper_bound is None:
510
error = GRBaddconstr(self.model, len(coefficients), row_i, row_values, GRB_GREATER_EQUAL, <double> lower_bound, name)
511
512
elif upper_bound is not None and lower_bound is not None:
513
if lower_bound == upper_bound:
514
error = GRBaddconstr(self.model, len(coefficients), row_i, row_values, GRB_EQUAL, <double> lower_bound, name)
515
516
else:
517
error = GRBaddrangeconstr(self.model, len(coefficients), row_i, row_values, <double> lower_bound, <double> upper_bound, name)
518
519
check(self.env,error)
520
521
error = GRBupdatemodel(self.model)
522
523
check(self.env,error)
524
525
sage_free(row_i)
526
sage_free(row_values)
527
528
cpdef row(self, int index):
529
r"""
530
Return a row
531
532
INPUT:
533
534
- ``index`` (integer) -- the constraint's id.
535
536
OUTPUT:
537
538
A pair ``(indices, coeffs)`` where ``indices`` lists the
539
entries whose coefficient is nonzero, and to which ``coeffs``
540
associates their coefficient on the model of the
541
``add_linear_constraint`` method.
542
543
EXAMPLE::
544
545
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
546
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
547
sage: p.add_variables(5) # optional - Gurobi
548
4
549
sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2) # optional - Gurobi
550
sage: p.row(0) # optional - Gurobi
551
([0, 1, 2, 3, 4], [0.0, 1.0, 2.0, 3.0, 4.0])
552
sage: p.row_bounds(0) # optional - Gurobi
553
(2.0, 2.0)
554
"""
555
cdef int error
556
cdef int fake[1]
557
558
cdef int length[1]
559
error = GRBgetconstrs(self.model, length, NULL, NULL, NULL, index, 1 )
560
check(self.env,error)
561
562
cdef int * p_indices = <int *> sage_malloc(length[0] * sizeof(int))
563
cdef double * p_values = <double *> sage_malloc(length[0] * sizeof(double))
564
565
error = GRBgetconstrs(self.model, length, <int *> fake, p_indices, p_values, index, 1 )
566
check(self.env,error)
567
568
cdef list indices = []
569
cdef list values = []
570
571
cdef int i
572
for i in range(length[0]):
573
indices.append(p_indices[i])
574
values.append(p_values[i])
575
576
sage_free(p_indices)
577
sage_free(p_values)
578
579
return indices, values
580
581
582
cpdef row_bounds(self, int index):
583
"""
584
Return the bounds of a specific constraint.
585
586
INPUT:
587
588
- ``index`` (integer) -- the constraint's id.
589
590
OUTPUT:
591
592
A pair ``(lower_bound, upper_bound)``. Each of them can be set
593
to ``None`` if the constraint is not bounded in the
594
corresponding direction, and is a real value otherwise.
595
596
EXAMPLE::
597
598
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
599
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
600
sage: p.add_variables(5) # optional - Gurobi
601
4
602
sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2) # optional - Gurobi
603
sage: p.row(0) # optional - Gurobi
604
([0, 1, 2, 3, 4], [0.0, 1.0, 2.0, 3.0, 4.0])
605
sage: p.row_bounds(0) # optional - Gurobi
606
(2.0, 2.0)
607
"""
608
cdef double d[1]
609
cdef char sense[1]
610
cdef int error
611
612
error = GRBgetcharattrelement(self.model, "Sense", index, <char *> sense)
613
check(self.env, error)
614
615
error = GRBgetdblattrelement(self.model, "RHS", index, <double *> d)
616
check(self.env, error)
617
618
if sense[0] == '>':
619
return (d[0], None)
620
elif sense[0] == '<':
621
return (None, d[0])
622
else:
623
return (d[0],d[0])
624
625
cpdef col_bounds(self, int index):
626
"""
627
Return the bounds of a specific variable.
628
629
INPUT:
630
631
- ``index`` (integer) -- the variable's id.
632
633
OUTPUT:
634
635
A pair ``(lower_bound, upper_bound)``. Each of them can be set
636
to ``None`` if the variable is not bounded in the
637
corresponding direction, and is a real value otherwise.
638
639
EXAMPLE::
640
641
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
642
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
643
sage: p.add_variable() # optional - Gurobi
644
0
645
sage: p.col_bounds(0) # optional - Gurobi
646
(0.0, None)
647
sage: p.variable_upper_bound(0, 5) # optional - Gurobi
648
sage: p.col_bounds(0) # optional - Gurobi
649
(0.0, 5.0)
650
"""
651
652
cdef double lb[1], ub[1]
653
654
error = GRBgetdblattrelement(self.model, "LB", index, <double *> lb)
655
check(self.env, error)
656
657
error = GRBgetdblattrelement(self.model, "UB", index, <double *> ub)
658
check(self.env, error)
659
660
return (None if lb[0] <= -2147483647 else lb[0],
661
None if ub[0] >= 2147483647 else ub[0])
662
663
cpdef int solve(self) except -1:
664
"""
665
Solve the problem.
666
667
.. NOTE::
668
669
This method raises ``MIPSolverException`` exceptions when
670
the solution can not be computed for any reason (none
671
exists, or the LP solver was not able to find it, etc...)
672
673
EXAMPLE::
674
675
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
676
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
677
sage: p.add_variables(5) # optional - Gurobi
678
4
679
sage: p.add_linear_constraint([(0,1), (1, 1)], 1.2, 1.7) # optional - Gurobi
680
sage: p.set_variable_type(0, 1) # optional - Gurobi
681
sage: p.set_variable_type(1, 1) # optional - Gurobi
682
sage: p.solve() # optional - Gurobi
683
Traceback (most recent call last):
684
...
685
MIPSolverException: 'Gurobi: The problem is infeasible'
686
"""
687
cdef int error
688
global mip_status
689
690
check(self.env, GRBoptimize(self.model))
691
692
cdef int status[1]
693
check(self.env, GRBgetintattr(self.model, "Status", <int *> status))
694
695
# Has there been a problem ?
696
if status[0] != GRB_OPTIMAL:
697
raise MIPSolverException("Gurobi: "+mip_status.get(status[0], "unknown error during call to GRBoptimize : "+str(status[0])))
698
699
700
cpdef get_objective_value(self):
701
"""
702
Returns the value of the objective function.
703
704
.. NOTE::
705
706
Behaviour is undefined unless ``solve`` has been called before.
707
708
EXAMPLE::
709
710
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
711
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
712
sage: p.add_variables(2) # optional - Gurobi
713
1
714
sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3) # optional - Gurobi
715
sage: p.set_objective([2, 5]) # optional - Gurobi
716
sage: p.solve() # optional - Gurobi
717
0
718
sage: p.get_objective_value() # optional - Gurobi
719
7.5
720
sage: p.get_variable_value(0) # optional - Gurobi
721
0.0
722
sage: p.get_variable_value(1) # optional - Gurobi
723
1.5
724
"""
725
cdef double p_value[1]
726
727
check(self.env,GRBgetdblattr(self.model, "ObjVal", <double* >p_value))
728
729
return p_value[0] + self.obj_constant_term
730
731
cpdef get_variable_value(self, int variable):
732
"""
733
Returns the value of a variable given by the solver.
734
735
.. NOTE::
736
737
Behaviour is undefined unless ``solve`` has been called before.
738
739
EXAMPLE::
740
741
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
742
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
743
sage: p.add_variables(2) # optional - Gurobi
744
1
745
sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3) # optional - Gurobi
746
sage: p.set_objective([2, 5]) # optional - Gurobi
747
sage: p.solve() # optional - Gurobi
748
0
749
sage: p.get_objective_value() # optional - Gurobi
750
7.5
751
sage: p.get_variable_value(0) # optional - Gurobi
752
0.0
753
sage: p.get_variable_value(1) # optional - Gurobi
754
1.5
755
"""
756
757
cdef double value[1]
758
check(self.env,GRBgetdblattrelement(self.model, "X", variable, value))
759
return round(value[0]) if self.is_variable_binary(variable) else value[0]
760
761
cpdef int ncols(self):
762
"""
763
Return the number of columns/variables.
764
765
EXAMPLE::
766
767
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
768
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
769
sage: p.ncols() # optional - Gurobi
770
0
771
sage: p.add_variables(2) # optional - Gurobi
772
1
773
sage: p.ncols() # optional - Gurobi
774
2
775
"""
776
cdef int i[1]
777
check(self.env,GRBgetintattr(self.model, "NumVars", i))
778
return i[0]
779
780
cpdef int nrows(self):
781
"""
782
Return the number of rows/constraints.
783
784
EXAMPLE::
785
786
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
787
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
788
sage: p.nrows() # optional - Gurobi
789
0
790
sage: p.add_linear_constraint([], 2, None) # optional - Gurobi
791
sage: p.add_linear_constraint([], 2, None) # optional - Gurobi
792
sage: p.nrows() # optional - Gurobi
793
2
794
"""
795
cdef int i[1]
796
check(self.env,GRBgetintattr(self.model, "NumConstrs", i))
797
return i[0]
798
799
cpdef col_name(self, int index):
800
"""
801
Return the ``index`` th col name
802
803
INPUT:
804
805
- ``index`` (integer) -- the col's id
806
807
EXAMPLE::
808
809
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
810
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
811
sage: p.add_variable(name='I am a variable') # optional - Gurobi
812
0
813
sage: p.col_name(0) # optional - Gurobi
814
'I am a variable'
815
"""
816
cdef char * name[1]
817
check(self.env,GRBgetstrattrelement(self.model, "VarName", index, <char **> name))
818
if name[0] == NULL:
819
value = ""
820
else:
821
value = str(name[0])
822
return value
823
824
cpdef row_name(self, int index):
825
"""
826
Return the ``index`` th row name
827
828
INPUT:
829
830
- ``index`` (integer) -- the row's id
831
832
EXAMPLE::
833
834
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
835
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
836
sage: p.add_linear_constraint([], 2, None, name='Empty constraint 1') # optional - Gurobi
837
sage: p.row_name(0) # optional - Gurobi
838
'Empty constraint 1'
839
"""
840
cdef char * name[1]
841
check(self.env,GRBgetstrattrelement(self.model, "ConstrName", index, <char **> name))
842
if name[0] == NULL:
843
value = ""
844
else:
845
value = str(name[0])
846
return value
847
848
cpdef bint is_variable_binary(self, int index):
849
"""
850
Test whether the given variable is of binary type.
851
852
INPUT:
853
854
- ``index`` (integer) -- the variable's id
855
856
EXAMPLE::
857
858
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
859
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
860
sage: p.ncols() # optional - Gurobi
861
0
862
sage: p.add_variable() # optional - Gurobi
863
0
864
sage: p.set_variable_type(0,0) # optional - Gurobi
865
sage: p.is_variable_binary(0) # optional - Gurobi
866
True
867
"""
868
cdef char vtype[1]
869
check(self.env, GRBgetcharattrelement(self.model, "VType", index, <char *> vtype))
870
return vtype[0] == 'B'
871
872
873
cpdef bint is_variable_integer(self, int index):
874
"""
875
Test whether the given variable is of integer type.
876
877
INPUT:
878
879
- ``index`` (integer) -- the variable's id
880
881
EXAMPLE::
882
883
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
884
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
885
sage: p.ncols() # optional - Gurobi
886
0
887
sage: p.add_variable() # optional - Gurobi
888
0
889
sage: p.set_variable_type(0,1) # optional - Gurobi
890
sage: p.is_variable_integer(0) # optional - Gurobi
891
True
892
"""
893
cdef char vtype[1]
894
check(self.env, GRBgetcharattrelement(self.model, "VType", index, <char *> vtype))
895
return vtype[0] == 'I'
896
897
cpdef bint is_variable_continuous(self, int index):
898
"""
899
Test whether the given variable is of continuous/real type.
900
901
INPUT:
902
903
- ``index`` (integer) -- the variable's id
904
905
EXAMPLE::
906
907
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
908
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
909
sage: p.ncols() # optional - Gurobi
910
0
911
sage: p.add_variable() # optional - Gurobi
912
0
913
sage: p.is_variable_continuous(0) # optional - Gurobi
914
True
915
sage: p.set_variable_type(0,1) # optional - Gurobi
916
sage: p.is_variable_continuous(0) # optional - Gurobi
917
False
918
919
"""
920
cdef char vtype[1]
921
check(self.env, GRBgetcharattrelement(self.model, "VType", index, <char *> vtype))
922
return vtype[0] == 'C'
923
924
cpdef bint is_maximization(self):
925
"""
926
Test whether the problem is a maximization
927
928
EXAMPLE::
929
930
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
931
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
932
sage: p.is_maximization() # optional - Gurobi
933
True
934
sage: p.set_sense(-1) # optional - Gurobi
935
sage: p.is_maximization() # optional - Gurobi
936
False
937
"""
938
cdef int sense[1]
939
check(self.env,GRBgetintattr(self.model, "ModelSense", <int *> sense))
940
return sense[0] == -1
941
942
cpdef variable_upper_bound(self, int index, value = False):
943
"""
944
Return or define the upper bound on a variable
945
946
INPUT:
947
948
- ``index`` (integer) -- the variable's id
949
950
- ``value`` -- real value, or ``None`` to mean that the
951
variable has not upper bound. When set to ``False``
952
(default), the method returns the current value.
953
954
EXAMPLE::
955
956
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
957
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
958
sage: p.add_variable() # optional - Gurobi
959
0
960
sage: p.col_bounds(0) # optional - Gurobi
961
(0.0, None)
962
sage: p.variable_upper_bound(0, 5) # optional - Gurobi
963
sage: p.col_bounds(0) # optional - Gurobi
964
(0.0, 5.0)
965
"""
966
cdef double b[1]
967
968
if not value is False:
969
check(self.env, GRBsetdblattrelement(
970
self.model, "UB",
971
index,
972
value if value is not None else GRB_INFINITY))
973
974
check(self.env,GRBupdatemodel(self.model))
975
else:
976
error = GRBgetdblattrelement(self.model, "UB", index, <double *> b)
977
check(self.env, error)
978
return None if b[0] >= 2147483647 else b[0]
979
980
cpdef variable_lower_bound(self, int index, value = False):
981
"""
982
Return or define the lower bound on a variable
983
984
INPUT:
985
986
- ``index`` (integer) -- the variable's id
987
988
- ``value`` -- real value, or ``None`` to mean that the
989
variable has not lower bound. When set to ``False``
990
(default), the method returns the current value.
991
992
EXAMPLE::
993
994
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
995
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
996
sage: p.add_variable() # optional - Gurobi
997
0
998
sage: p.col_bounds(0) # optional - Gurobi
999
(0.0, None)
1000
sage: p.variable_lower_bound(0, 5) # optional - Gurobi
1001
sage: p.col_bounds(0) # optional - Gurobi
1002
(5.0, None)
1003
"""
1004
cdef double b[1]
1005
1006
1007
if not value is False:
1008
check(self.env, GRBsetdblattrelement(
1009
self.model, "LB",
1010
index,
1011
value if value is not None else -GRB_INFINITY))
1012
1013
check(self.env,GRBupdatemodel(self.model))
1014
1015
else:
1016
error = GRBgetdblattrelement(self.model, "LB", index, <double *> b)
1017
check(self.env, error)
1018
return None if b[0] <= -2147483647 else b[0]
1019
1020
cpdef write_lp(self, char * filename):
1021
"""
1022
Write the problem to a .lp file
1023
1024
INPUT:
1025
1026
- ``filename`` (string)
1027
1028
EXAMPLE::
1029
1030
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
1031
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
1032
sage: p.add_variables(2) # optional - Gurobi
1033
1
1034
sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3) # optional - Gurobi
1035
sage: p.set_objective([2, 5]) # optional - Gurobi
1036
sage: p.write_lp(os.path.join(SAGE_TMP, "lp_problem.lp")) # optional - Gurobi
1037
"""
1038
check(self.env, GRBwrite(self.model, filename))
1039
1040
cpdef write_mps(self, char * filename, int modern):
1041
"""
1042
Write the problem to a .mps file
1043
1044
INPUT:
1045
1046
- ``filename`` (string)
1047
1048
EXAMPLE::
1049
1050
sage: from sage.numerical.backends.generic_backend import get_solver # optional - Gurobi
1051
sage: p = get_solver(solver = "Gurobi") # optional - Gurobi
1052
sage: p.add_variables(2) # optional - Gurobi
1053
1
1054
sage: p.add_linear_constraint([[0, 1], [1, 2]], None, 3) # optional - Gurobi
1055
sage: p.set_objective([2, 5]) # optional - Gurobi
1056
sage: p.write_lp(os.path.join(SAGE_TMP, "lp_problem.lp")) # optional - Gurobi
1057
"""
1058
check(self.env, GRBwrite(self.model, filename))
1059
1060
cpdef solver_parameter(self, name, value = None):
1061
"""
1062
Returns or defines a solver parameter.
1063
1064
For a list of parameters and associated values, please refer to Gurobi's
1065
reference manual
1066
`<http://www.gurobi.com/documentation/5.5/reference-manual/node798>`_.
1067
1068
INPUT:
1069
1070
- ``name`` (string) -- the parameter
1071
1072
- ``value`` -- the parameter's value if it is to be defined,
1073
or ``None`` (default) to obtain its current value.
1074
1075
EXAMPLES::
1076
1077
sage: p = MixedIntegerLinearProgram(solver="Gurobi") # optional - Gurobi
1078
1079
An integer parameter::
1080
1081
sage: p.solver_parameter("VarBranch") # optional - Gurobi
1082
-1
1083
sage: p.solver_parameter("VarBranch", 1) # optional - Gurobi
1084
sage: p.solver_parameter("VarBranch") # optional - Gurobi
1085
1
1086
1087
A double parameter::
1088
1089
sage: p.solver_parameter("TimeLimit") # optional - Gurobi
1090
1e+100
1091
sage: p.solver_parameter("TimeLimit", 10) # optional - Gurobi
1092
sage: p.solver_parameter("TimeLimit") # optional - Gurobi
1093
10.0
1094
1095
A string parameter::
1096
1097
sage: p.solver_parameter("LogFile") # optional - Gurobi
1098
''
1099
sage: p.solver_parameter("LogFile", "/dev/null") # optional - Gurobi
1100
sage: p.solver_parameter("LogFile") # optional - Gurobi
1101
'/dev/null'
1102
1103
"""
1104
cdef int tmp_int[1]
1105
cdef double tmp_dbl[1]
1106
cdef char tmp_str[25500]
1107
cdef char * c_name
1108
c_name = tmp_str
1109
1110
if name == "timelimit":
1111
name = "TimeLimit"
1112
1113
try:
1114
t = parameters_type[name]
1115
except KeyError:
1116
raise ValueError("This parameter is not available. "+
1117
"Enabling it may not be so hard, though.")
1118
1119
if t == "int":
1120
if value is None:
1121
check(self.env, GRBgetintparam(self.env, name, tmp_int))
1122
return tmp_int[0]
1123
else:
1124
check(self.env, GRBsetintparam(self.env, name, value))
1125
elif t == "double":
1126
if value is None:
1127
check(self.env, GRBgetdblparam(self.env, name, tmp_dbl))
1128
return tmp_dbl[0]
1129
else:
1130
check(self.env, GRBsetdblparam(self.env, name, value))
1131
elif t == "string":
1132
if value is None:
1133
check(self.env, GRBgetstrparam(self.env, name, c_name))
1134
return str(c_name)
1135
else:
1136
check(self.env, GRBsetstrparam(self.env, name, value))
1137
else:
1138
raise RuntimeError("This should not happen.")
1139
1140
cpdef GurobiBackend copy(self):
1141
"""
1142
Returns a copy of self.
1143
1144
EXAMPLE::
1145
1146
sage: from sage.numerical.backends.generic_backend import get_solver # optional - GUROBI
1147
sage: p = MixedIntegerLinearProgram(solver = "GUROBI") # optional - GUROBI
1148
sage: b = p.new_variable() # optional - GUROBI
1149
sage: p.add_constraint(b[1] + b[2] <= 6) # optional - GUROBI
1150
sage: p.set_objective(b[1] + b[2]) # optional - GUROBI
1151
sage: copy(p).solve() # optional - GUROBI
1152
6.0
1153
"""
1154
cdef GurobiBackend p = GurobiBackend(maximization = self.is_maximization())
1155
p.model = GRBcopymodel(self.model)
1156
p.env = GRBgetenv(p.model)
1157
return p
1158
1159
def __dealloc__(self):
1160
"""
1161
Destructor
1162
"""
1163
GRBfreeenv(self.env)
1164
GRBfreeenv(self.env_master)
1165
GRBfreemodel(self.model)
1166
1167
cdef dict errors = {
1168
10001 : "GRB_ERROR_OUT_OF_MEMORY",
1169
10002 : "GRB_ERROR_NULL_ARGUMENT",
1170
10003 : "GRB_ERROR_INVALID_ARGUMENT",
1171
10004 : "GRB_ERROR_UNKNOWN_ATTRIBUTE",
1172
10005 : "GRB_ERROR_DATA_NOT_AVAILABLE",
1173
10006 : "GRB_ERROR_INDEX_OUT_OF_RANGE",
1174
10007 : "GRB_ERROR_UNKNOWN_PARAMETER",
1175
10008 : "GRB_ERROR_VALUE_OUT_OF_RANGE",
1176
10009 : "GRB_ERROR_NO_LICENSE",
1177
10010 : "GRB_ERROR_SIZE_LIMIT_EXCEEDED",
1178
10011 : "GRB_ERROR_CALLBACK",
1179
10012 : "GRB_ERROR_FILE_READ",
1180
10013 : "GRB_ERROR_FILE_WRITE",
1181
10014 : "GRB_ERROR_NUMERIC",
1182
10015 : "GRB_ERROR_IIS_NOT_INFEASIBLE",
1183
10016 : "GRB_ERROR_NOT_FOR_MIP",
1184
10017 : "GRB_ERROR_OPTIMIZATION_IN_PROGRESS",
1185
10018 : "GRB_ERROR_DUPLICATES",
1186
10019 : "GRB_ERROR_NODEFILE",
1187
10020 : "GRB_ERROR_Q_NOT_PSD",
1188
}
1189
1190
cdef dict mip_status = {
1191
GRB_INFEASIBLE: "The problem is infeasible",
1192
GRB_INF_OR_UNBD: "The problem is infeasible or unbounded",
1193
GRB_UNBOUNDED: "The problem is unbounded",
1194
GRB_ITERATION_LIMIT: "The iteration limit has been reached",
1195
GRB_NODE_LIMIT: "The node limit has been reached",
1196
GRB_TIME_LIMIT: "The time limit has been reached",
1197
GRB_SOLUTION_LIMIT: "The solution limit has been reached",
1198
}
1199
1200
cdef dict parameters_type = {
1201
"AggFill" : "int",
1202
"Aggregate" : "int",
1203
"BarConvTol" : "double",
1204
"BarCorrectors" : "int",
1205
"BarHomogeneous" : "int",
1206
"BarOrder" : "int",
1207
"BarQCPConvTol" : "double",
1208
"BarIterLimit" : "int",
1209
"BranchDir" : "int",
1210
"CliqueCuts" : "int",
1211
"CoverCuts" : "int",
1212
"Crossover" : "int",
1213
"CrossoverBasis" : "int",
1214
"Cutoff" : "double",
1215
"CutAggPasses" : "int",
1216
"CutPasses" : "int",
1217
"Cuts" : "int",
1218
"DisplayInterval" : "int",
1219
"DualReductions" : "int",
1220
"FeasibilityTol" : "double",
1221
"FeasRelaxBigM" : "double",
1222
"FlowCoverCuts" : "int",
1223
"FlowPathCuts" : "int",
1224
"GomoryPasses" : "int",
1225
"GUBCoverCuts" : "int",
1226
"Heuristics" : "double",
1227
"IISMethod" : "int",
1228
"ImpliedCuts" : "int",
1229
"ImproveStartGap" : "double",
1230
"ImproveStartNodes" : "double",
1231
"ImproveStartTime" : "double",
1232
"InfUnbdInfo" : "int",
1233
"InputFile" : "string",
1234
"IntFeasTol" : "double",
1235
"IterationLimit" : "double",
1236
"LogFile" : "string",
1237
"LogToConsole" : "int",
1238
"MarkowitzTol" : "double",
1239
"Method" : "int",
1240
"MinRelNodes" : "int",
1241
"MIPFocus" : "int",
1242
"MIPGap" : "double",
1243
"MIPGapAbs" : "double",
1244
"MIPSepCuts" : "int",
1245
"MIQCPMethod" : "int",
1246
"MIRCuts" : "int",
1247
"ModKCuts" : "int",
1248
"NetworkCuts" : "int",
1249
"NodefileDir" : "string",
1250
"NodefileStart" : "double",
1251
"NodeLimit" : "double",
1252
"NodeMethod" : "int",
1253
"NormAdjust" : "int",
1254
"ObjScale" : "double",
1255
"OptimalityTol" : "double",
1256
"OutputFlag" : "int",
1257
"PerturbValue" : "double",
1258
"PreCrush" : "int",
1259
"PreDepRow" : "int",
1260
"PreDual" : "int",
1261
"PrePasses" : "int",
1262
"PreQLinearize" : "int",
1263
"Presolve" : "int",
1264
"PreSparsify" : "int",
1265
"PSDTol" : "double",
1266
"PumpPasses" : "int",
1267
"QCPDual" : "int",
1268
"Quad" : "int",
1269
"ResultFile" : "string",
1270
"RINS" : "int",
1271
"ScaleFlag" : "int",
1272
"Seed" : "int",
1273
"Sifting" : "int",
1274
"SiftMethod" : "int",
1275
"SimplexPricing" : "int",
1276
"SolutionLimit" : "int",
1277
"SolutionNumber" : "int",
1278
"SubMIPCuts" : "int",
1279
"SubMIPNodes" : "int",
1280
"Symmetry" : "int",
1281
"Threads" : "int",
1282
"TimeLimit" : "double",
1283
"VarBranch" : "int",
1284
"ZeroHalfCuts" : "int",
1285
"ZeroObjNodes" : "int"
1286
}
1287
1288
cdef check(GRBenv * env, int error):
1289
if error:
1290
raise MIPSolverException("Gurobi: "+str(GRBgeterrormsg(env))+" ("+errors[error]+")")
1291
1292