PySCIPOpt
Python Interface to the SCIP Optimization Suite
lp.pxi
Go to the documentation of this file.
1 ##@file lp.pxi
2 #@brief Base class of the LP Plugin
3 cdef class LP:
4  cdef SCIP_LPI* lpi
5  cdef readonly str name
6 
7  def __init__(self, name="LP", sense="minimize"):
8  """
9  Keyword arguments:
10  name -- the name of the problem (default 'LP')
11  sense -- objective sense (default minimize)
12  """
13  self.name = name
14  n = str_conversion(name)
15  if sense == "minimize":
16  PY_SCIP_CALL(SCIPlpiCreate(&(self.lpi), NULL, n, SCIP_OBJSENSE_MINIMIZE))
17  elif sense == "maximize":
18  PY_SCIP_CALL(SCIPlpiCreate(&(self.lpi), NULL, n, SCIP_OBJSENSE_MAXIMIZE))
19  else:
20  raise Warning("unrecognized objective sense")
21 
22  def __dealloc__(self):
23  PY_SCIP_CALL(SCIPlpiFree(&(self.lpi)))
24 
25  def __repr__(self):
26  return self.name
27 
28  def writeLP(self, filename):
29  """Writes LP to a file.
30 
31  Keyword arguments:
32  filename -- the name of the file to be used
33  """
34  PY_SCIP_CALL(SCIPlpiWriteLP(self.lpi, filename))
35 
36  def readLP(self, filename):
37  """Reads LP from a file.
38 
39  Keyword arguments:
40  filename -- the name of the file to be used
41  """
42  PY_SCIP_CALL(SCIPlpiReadLP(self.lpi, filename))
43 
44  def infinity(self):
45  """Returns infinity value of the LP.
46  """
47  return SCIPlpiInfinity(self.lpi)
48 
49  def isInfinity(self, val):
50  """Checks if a given value is equal to the infinity value of the LP.
51 
52  Keyword arguments:
53  val -- value that should be checked
54  """
55  return SCIPlpiIsInfinity(self.lpi, val)
56 
57  def addCol(self, entries, obj = 0.0, lb = 0.0, ub = None):
58  """Adds a single column to the LP.
59 
60  Keyword arguments:
61  entries -- list of tuples, each tuple consists of a row index and a coefficient
62  obj -- objective coefficient (default 0.0)
63  lb -- lower bound (default 0.0)
64  ub -- upper bound (default infinity)
65  """
66  nnonz = len(entries)
67 
68  cdef SCIP_Real* c_coefs = <SCIP_Real*> malloc(nnonz * sizeof(SCIP_Real))
69  cdef int* c_inds = <int*>malloc(nnonz * sizeof(int))
70  cdef SCIP_Real c_obj
71  cdef SCIP_Real c_lb
72  cdef SCIP_Real c_ub
73  cdef int c_beg
74 
75  c_obj = obj
76  c_lb = lb
77  c_ub = ub if ub != None else self.infinity()
78  c_beg = 0
79 
80  for i,entry in enumerate(entries):
81  c_inds[i] = entry[0]
82  c_coefs[i] = entry[1]
83 
84  PY_SCIP_CALL(SCIPlpiAddCols(self.lpi, 1, &c_obj, &c_lb, &c_ub, NULL, nnonz, &c_beg, c_inds, c_coefs))
85 
86  free(c_coefs)
87  free(c_inds)
88 
89  def addCols(self, entrieslist, objs = None, lbs = None, ubs = None):
90  """Adds multiple columns to the LP.
91 
92  Keyword arguments:
93  entrieslist -- list containing lists of tuples, each tuple contains a coefficient and a row index
94  objs -- objective coefficient (default 0.0)
95  lbs -- lower bounds (default 0.0)
96  ubs -- upper bounds (default infinity)
97  """
98 
99  ncols = len(entrieslist)
100  nnonz = sum(len(entries) for entries in entrieslist)
101 
102  cdef SCIP_Real* c_objs = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
103  cdef SCIP_Real* c_lbs = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
104  cdef SCIP_Real* c_ubs = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
105  cdef SCIP_Real* c_coefs
106  cdef int* c_inds
107  cdef int* c_beg
108 
109 
110  if nnonz > 0:
111  c_coefs = <SCIP_Real*> malloc(nnonz * sizeof(SCIP_Real))
112  c_inds = <int*>malloc(nnonz * sizeof(int))
113  c_beg = <int*>malloc(ncols * sizeof(int))
114 
115  tmp = 0
116  for i,entries in enumerate(entrieslist):
117  c_objs[i] = objs[i] if objs != None else 0.0
118  c_lbs[i] = lbs[i] if lbs != None else 0.0
119  c_ubs[i] = ubs[i] if ubs != None else self.infinity()
120  c_beg[i] = tmp
121 
122  for entry in entries:
123  c_inds[tmp] = entry[0]
124  c_coefs[tmp] = entry[1]
125  tmp += 1
126 
127  PY_SCIP_CALL(SCIPlpiAddCols(self.lpi, ncols, c_objs, c_lbs, c_ubs, NULL, nnonz, c_beg, c_inds, c_coefs))
128 
129  free(c_beg)
130  free(c_inds)
131  free(c_coefs)
132  else:
133  for i in range(len(entrieslist)):
134  c_objs[i] = objs[i] if objs != None else 0.0
135  c_lbs[i] = lbs[i] if lbs != None else 0.0
136  c_ubs[i] = ubs[i] if ubs != None else self.infinity()
137 
138  PY_SCIP_CALL(SCIPlpiAddCols(self.lpi, ncols, c_objs, c_lbs, c_ubs, NULL, 0, NULL, NULL, NULL))
139 
140  free(c_ubs)
141  free(c_lbs)
142  free(c_objs)
143 
144  def delCols(self, firstcol, lastcol):
145  """Deletes a range of columns from the LP.
146 
147  Keyword arguments:
148  firstcol -- first column to delete
149  lastcol -- last column to delete
150  """
151  PY_SCIP_CALL(SCIPlpiDelCols(self.lpi, firstcol, lastcol))
152 
153  def addRow(self, entries, lhs=0.0, rhs=None):
154  """Adds a single row to the LP.
155 
156  Keyword arguments:
157  entries -- list of tuples, each tuple contains a coefficient and a column index
158  lhs -- left-hand side of the row (default 0.0)
159  rhs -- right-hand side of the row (default infinity)
160  """
161  beg = 0
162  nnonz = len(entries)
163 
164  cdef SCIP_Real* c_coefs = <SCIP_Real*> malloc(nnonz * sizeof(SCIP_Real))
165  cdef int* c_inds = <int*>malloc(nnonz * sizeof(int))
166  cdef SCIP_Real c_lhs
167  cdef SCIP_Real c_rhs
168  cdef int c_beg
169 
170  c_lhs = lhs
171  c_rhs = rhs if rhs != None else self.infinity()
172  c_beg = 0
173 
174  for i,entry in enumerate(entries):
175  c_inds[i] = entry[0]
176  c_coefs[i] = entry[1]
177 
178  PY_SCIP_CALL(SCIPlpiAddRows(self.lpi, 1, &c_lhs, &c_rhs, NULL, nnonz, &c_beg, c_inds, c_coefs))
179 
180  free(c_coefs)
181  free(c_inds)
182 
183  def addRows(self, entrieslist, lhss = None, rhss = None):
184  """Adds multiple rows to the LP.
185 
186  Keyword arguments:
187  entrieslist -- list containing lists of tuples, each tuple contains a coefficient and a column index
188  lhss -- left-hand side of the row (default 0.0)
189  rhss -- right-hand side of the row (default infinity)
190  """
191  nrows = len(entrieslist)
192  nnonz = sum(len(entries) for entries in entrieslist)
193 
194  cdef SCIP_Real* c_lhss = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
195  cdef SCIP_Real* c_rhss = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
196  cdef SCIP_Real* c_coefs = <SCIP_Real*> malloc(nnonz * sizeof(SCIP_Real))
197  cdef int* c_inds = <int*>malloc(nnonz * sizeof(int))
198  cdef int* c_beg = <int*>malloc(nrows * sizeof(int))
199 
200  tmp = 0
201  for i,entries in enumerate(entrieslist):
202  c_lhss[i] = lhss[i] if lhss != None else 0.0
203  c_rhss[i] = rhss[i] if rhss != None else self.infinity()
204  c_beg[i] = tmp
205 
206  for entry in entries:
207  c_inds[tmp] = entry[0]
208  c_coefs[tmp] = entry[1]
209  tmp += 1
210 
211  PY_SCIP_CALL(SCIPlpiAddRows(self.lpi, nrows, c_lhss, c_rhss, NULL, nnonz, c_beg, c_inds, c_coefs))
212 
213  free(c_beg)
214  free(c_inds)
215  free(c_coefs)
216  free(c_lhss)
217  free(c_rhss)
218 
219  def delRows(self, firstrow, lastrow):
220  """Deletes a range of rows from the LP.
221 
222  Keyword arguments:
223  firstrow -- first row to delete
224  lastrow -- last row to delete
225  """
226  PY_SCIP_CALL(SCIPlpiDelRows(self.lpi, firstrow, lastrow))
227 
228  def getBounds(self, firstcol = 0, lastcol = None):
229  """Returns all lower and upper bounds for a range of columns.
230 
231  Keyword arguments:
232  firstcol -- first column (default 0)
233  lastcol -- last column (default ncols - 1)
234  """
235  lastcol = lastcol if lastcol != None else self.ncols() - 1
236 
237  if firstcol > lastcol:
238  return None
239 
240  ncols = lastcol - firstcol + 1
241  cdef SCIP_Real* c_lbs = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
242  cdef SCIP_Real* c_ubs = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
243  PY_SCIP_CALL(SCIPlpiGetBounds(self.lpi, firstcol, lastcol, c_lbs, c_ubs))
244 
245  lbs = []
246  ubs = []
247 
248  for i in range(ncols):
249  lbs.append(c_lbs[i])
250  ubs.append(c_ubs[i])
251 
252  free(c_ubs)
253  free(c_lbs)
254 
255  return lbs, ubs
256 
257  def getSides(self, firstrow = 0, lastrow = None):
258  """Returns all left- and right-hand sides for a range of rows.
259 
260  Keyword arguments:
261  firstrow -- first row (default 0)
262  lastrow -- last row (default nrows - 1)
263  """
264  lastrow = lastrow if lastrow != None else self.nrows() - 1
265 
266  if firstrow > lastrow:
267  return None
268 
269  nrows = lastrow - firstrow + 1
270  cdef SCIP_Real* c_lhss = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
271  cdef SCIP_Real* c_rhss = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
272  PY_SCIP_CALL(SCIPlpiGetSides(self.lpi, firstrow, lastrow, c_lhss, c_rhss))
273 
274  lhss = []
275  rhss = []
276 
277  for i in range(firstrow, lastrow + 1):
278  lhss.append(c_lhss[i])
279  rhss.append(c_rhss[i])
280 
281  free(c_rhss)
282  free(c_lhss)
283 
284  return lhss, rhss
285 
286  def chgObj(self, col, obj):
287  """Changes objective coefficient of a single column.
288 
289  Keyword arguments:
290  col -- column to change
291  obj -- new objective coefficient
292  """
293  cdef int c_col = col
294  cdef SCIP_Real c_obj = obj
295  PY_SCIP_CALL(SCIPlpiChgObj(self.lpi, 1, &c_col, &c_obj))
296 
297  def chgCoef(self, row, col, newval):
298  """Changes a single coefficient in the LP.
299 
300  Keyword arguments:
301  row -- row to change
302  col -- column to change
303  newval -- new coefficient
304  """
305  PY_SCIP_CALL(SCIPlpiChgCoef(self.lpi, row, col, newval))
306 
307  def chgBound(self, col, lb, ub):
308  """Changes the lower and upper bound of a single column.
309 
310  Keyword arguments:
311  col -- column to change
312  lb -- new lower bound
313  ub -- new upper bound
314  """
315  cdef int c_col = col
316  cdef SCIP_Real c_lb = lb
317  cdef SCIP_Real c_ub = ub
318  PY_SCIP_CALL(SCIPlpiChgBounds(self.lpi, 1, &c_col, &c_lb, &c_ub))
319 
320  def chgSide(self, row, lhs, rhs):
321  """Changes the left- and right-hand side of a single row.
322 
323  Keyword arguments:
324  row -- row to change
325  lhs -- new left-hand side
326  rhs -- new right-hand side
327  """
328  cdef int c_row = row
329  cdef SCIP_Real c_lhs = lhs
330  cdef SCIP_Real c_rhs = rhs
331  PY_SCIP_CALL(SCIPlpiChgSides(self.lpi, 1, &c_row, &c_lhs, &c_rhs))
332 
333  def clear(self):
334  """Clears the whole LP."""
335  PY_SCIP_CALL(SCIPlpiClear(self.lpi))
336 
337  def nrows(self):
338  """Returns the number of rows."""
339  cdef int nrows
340  PY_SCIP_CALL(SCIPlpiGetNRows(self.lpi, &nrows))
341  return nrows
342 
343  def ncols(self):
344  """Returns the number of columns."""
345  cdef int ncols
346  PY_SCIP_CALL(SCIPlpiGetNCols(self.lpi, &ncols))
347  return ncols
348 
349  def solve(self, dual=True):
350  """Solves the current LP.
351 
352  Keyword arguments:
353  dual -- use the dual or primal Simplex method (default: dual)
354  """
355  if dual:
356  PY_SCIP_CALL(SCIPlpiSolveDual(self.lpi))
357  else:
358  PY_SCIP_CALL(SCIPlpiSolvePrimal(self.lpi))
359 
360  cdef SCIP_Real objval
361  PY_SCIP_CALL(SCIPlpiGetObjval(self.lpi, &objval))
362  return objval
363 
364  def getPrimal(self):
365  """Returns the primal solution of the last LP solve."""
366  ncols = self.ncols()
367  cdef SCIP_Real* c_primalsol = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
368  PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, NULL, c_primalsol, NULL, NULL, NULL))
369  primalsol = [0.0] * ncols
370  for i in range(ncols):
371  primalsol[i] = c_primalsol[i]
372  free(c_primalsol)
373 
374  return primalsol
375 
376  def isPrimalFeasible(self):
377  """Returns True iff LP is proven to be primal feasible."""
378  return SCIPlpiIsPrimalFeasible(self.lpi)
379 
380  def getDual(self):
381  """Returns the dual solution of the last LP solve."""
382  nrows = self.nrows()
383  cdef SCIP_Real* c_dualsol = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
384  PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, NULL, NULL, c_dualsol, NULL, NULL))
385  dualsol = [0.0] * nrows
386  for i in range(nrows):
387  dualsol[i] = c_dualsol[i]
388  free(c_dualsol)
389 
390  return dualsol
391 
392  def isDualFeasible(self):
393  """Returns True iff LP is proven to be dual feasible."""
394  return SCIPlpiIsDualFeasible(self.lpi)
395 
396  def getPrimalRay(self):
397  """Returns a primal ray if possible, None otherwise."""
398  if not SCIPlpiHasPrimalRay(self.lpi):
399  return None
400  ncols = self.ncols()
401  cdef SCIP_Real* c_ray = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
402  PY_SCIP_CALL(SCIPlpiGetPrimalRay(self.lpi, c_ray))
403  ray = [0.0] * ncols
404  for i in range(ncols):
405  ray[i] = c_ray[i]
406  free(c_ray)
407 
408  return ray
409 
410  def getDualRay(self):
411  """Returns a dual ray if possible, None otherwise."""
412  if not SCIPlpiHasDualRay(self.lpi):
413  return None
414  nrows = self.nrows()
415  cdef SCIP_Real* c_ray = <SCIP_Real*> malloc(nrows * sizeof(SCIP_Real))
416  PY_SCIP_CALL(SCIPlpiGetDualfarkas(self.lpi, c_ray))
417  ray = [0.0] * nrows
418  for i in range(nrows):
419  ray[i] = c_ray[i]
420  free(c_ray)
421 
422  return ray
423 
424  def getNIterations(self):
425  """Returns the number of LP iterations of the last LP solve."""
426  cdef int niters
427  PY_SCIP_CALL(SCIPlpiGetIterations(self.lpi, &niters))
428  return niters
429 
430  def getRedcost(self):
431  """Returns the reduced cost vector of the last LP solve."""
432  ncols = self.ncols()
433 
434  cdef SCIP_Real* c_redcost = <SCIP_Real*> malloc(ncols * sizeof(SCIP_Real))
435  PY_SCIP_CALL(SCIPlpiGetSol(self.lpi, NULL, NULL, NULL, NULL, c_redcost))
436 
437  redcost = []
438  for i in range(ncols):
439  redcost[i].append(c_redcost[i])
440 
441  free(c_redcost)
442  return redcost
443 
444  def getBasisInds(self):
445  """Returns the indices of the basic columns and rows; index i >= 0 corresponds to column i, index i < 0 to row -i-1"""
446  nrows = self.nrows()
447  cdef int* c_binds = <int*> malloc(nrows * sizeof(int))
448 
449  PY_SCIP_CALL(SCIPlpiGetBasisInd(self.lpi, c_binds))
450 
451  binds = []
452  for i in range(nrows):
453  binds.append(c_binds[i])
454 
455  free(c_binds)
456  return binds
SCIP_RETCODE SCIPlpiReadLP(SCIP_LPI *lpi, const char *fname)
SCIP_RETCODE SCIPlpiGetObjval(SCIP_LPI *lpi, SCIP_Real *objval)
SCIP_Bool SCIPlpiIsDualFeasible(SCIP_LPI *lpi)
SCIP_Bool SCIPlpiHasPrimalRay(SCIP_LPI *lpi)
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
SCIP_RETCODE SCIPlpiGetBounds(SCIP_LPI *lpi, int firstcol, int lastcol, SCIP_Real *lbs, SCIP_Real *ubs)
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
SCIP_RETCODE SCIPlpiGetBasisInd(SCIP_LPI *lpi, int *bind)
SCIP_RETCODE SCIPlpiAddRows(SCIP_LPI *lpi, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
SCIP_RETCODE SCIPlpiGetDualfarkas(SCIP_LPI *lpi, SCIP_Real *dualfarkas)
SCIP_RETCODE SCIPlpiDelRows(SCIP_LPI *lpi, int firstrow, int lastrow)
SCIP_RETCODE SCIPlpiClear(SCIP_LPI *lpi)
SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
SCIP_RETCODE SCIPlpiAddCols(SCIP_LPI *lpi, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
SCIP_Bool SCIPlpiHasDualRay(SCIP_LPI *lpi)
SCIP_RETCODE SCIPlpiGetIterations(SCIP_LPI *lpi, int *iterations)
SCIP_RETCODE SCIPlpiGetSides(SCIP_LPI *lpi, int firstrow, int lastrow, SCIP_Real *lhss, SCIP_Real *rhss)
SCIP_RETCODE SCIPlpiDelCols(SCIP_LPI *lpi, int firstcol, int lastcol)
SCIP_Bool SCIPlpiIsInfinity(SCIP_LPI *lpi, SCIP_Real val)
SCIP_Bool SCIPlpiIsPrimalFeasible(SCIP_LPI *lpi)
SCIP_RETCODE SCIPlpiChgBounds(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *lb, const SCIP_Real *ub)
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
SCIP_RETCODE SCIPlpiGetPrimalRay(SCIP_LPI *lpi, SCIP_Real *ray)
SCIP_RETCODE SCIPlpiWriteLP(SCIP_LPI *lpi, const char *fname)
SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
SCIP_RETCODE SCIPlpiChgObj(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *obj)
SCIP_RETCODE SCIPlpiChgCoef(SCIP_LPI *lpi, int row, int col, SCIP_Real newval)