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