Skip to content

Commit

Permalink
Trac #17320: Memory leaks with LP Solvers are back
Browse files Browse the repository at this point in the history
3 years ago a memory leak in lp solvers was fixed in ticket
[http://trac.sagemath.org/ticket/11917 11917]. It seems that the
problems are back in Sage 6.3. The code

{{{
while True:
    P = MixedIntegerLinearProgram(solver="Coin")
}}}

consumes several GB of memory within a few seconds! The same happens
with solver="gurobi", but not with solver="glpk".

Simon King confirmed the leak at [https://groups.google.com/d/msg/sage-
support/dqgmyhMIQdw/qARZHXTt2z8J sage-support], including some analysis
and details.

URL: http://trac.sagemath.org/17320
Reported by: pmueller
Ticket author(s): Nils Bruin, Nathann Cohen
Reviewer(s): Nils Bruin, Nathann Cohen
  • Loading branch information
Release Manager authored and vbraun committed Nov 19, 2014
2 parents b5f0535 + 5480f4e commit 1fc9ab6
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 17 deletions.
33 changes: 23 additions & 10 deletions src/sage/numerical/backends/coin_backend.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ cdef class CoinBackend(GenericBackend):
Destructor function
"""
del self.si
del self.model

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:
r"""
Expand Down Expand Up @@ -328,7 +329,8 @@ cdef class CoinBackend(GenericBackend):
Constants in the objective function are respected::
sage: p = MixedIntegerLinearProgram(solver='Coin') # optional - Coin
sage: x,y = p[0], p[1] # optional - Coin
sage: v = p.new_variable(nonnegative=True) # optional - Coin
sage: x,y = v[0], v[1] # optional - Coin
sage: p.add_constraint(2*x + 3*y, max = 6) # optional - Coin
sage: p.add_constraint(3*x + 2*y, max = 6) # optional - Coin
sage: p.set_objective(x + y + 7) # optional - Coin
Expand Down Expand Up @@ -372,7 +374,8 @@ cdef class CoinBackend(GenericBackend):
EXAMPLE::
sage: p = MixedIntegerLinearProgram(solver='Coin') # optional - Coin
sage: x,y = p[0], p[1] # optional - Coin
sage: v = p.new_variable(nonnegative=True) # optional - Coin
sage: x,y = v[0], v[1] # optional - Coin
sage: p.add_constraint(2*x + 3*y, max = 6) # optional - Coin
sage: p.add_constraint(3*x + 2*y, max = 6) # optional - Coin
sage: p.set_objective(x + y + 7) # optional - Coin
Expand Down Expand Up @@ -412,7 +415,8 @@ cdef class CoinBackend(GenericBackend):
EXAMPLE::
sage: p = MixedIntegerLinearProgram(solver='Coin') # optional - Coin
sage: x,y = p[0], p[1] # optional - Coin
sage: v = p.new_variable(nonnegative=True) # optional - Coin
sage: x,y = v[0], v[1] # optional - Coin
sage: p.add_constraint(2*x + 3*y, max = 6) # optional - Coin
sage: p.add_constraint(3*x + 2*y, max = 6) # optional - Coin
sage: p.set_objective(x + y + 7) # optional - Coin
Expand Down Expand Up @@ -743,8 +747,16 @@ cdef class CoinBackend(GenericBackend):
cdef OsiSolverInterface * si = self.si

cdef CbcModel * model
cdef int old_logLevel = self.model.logLevel()

model = new CbcModel(si[0])
model.setLogLevel(self.model.logLevel())
del self.model
self.model = model

#we immediately commit to the new model so that the user has access
#to it even when something goes wrong.

model.setLogLevel(old_logLevel)

# multithreading
import multiprocessing
Expand All @@ -767,8 +779,7 @@ cdef class CoinBackend(GenericBackend):
elif not model.solver().isProvenOptimal():
raise MIPSolverException("CBC : Unknown error")

del self.model
self.model = model
return 0

cpdef get_objective_value(self):
r"""
Expand Down Expand Up @@ -822,7 +833,7 @@ cdef class CoinBackend(GenericBackend):
sage: p.get_variable_value(1) # optional - Coin
1.5
sage: p = MixedIntegerLinearProgram("Coin") # optional - Coin
sage: x = p.new_variable(dim=1) # optional - Coin
sage: x = p.new_variable(nonnegative=True) # optional - Coin
sage: p.set_min(x[0], 0.0) # optional - Coin
sage: p.get_values(x) # optional - Coin
{0: 0.0}
Expand Down Expand Up @@ -997,7 +1008,8 @@ cdef class CoinBackend(GenericBackend):
:trac:`14581`::
sage: P = MixedIntegerLinearProgram(solver="Coin") # optional - Coin
sage: x = P["x"] # optional - Coin
sage: v = P.new_variable(nonnegative=True) # optional - Coin
sage: x = v["x"] # optional - Coin
sage: P.set_max(x, 0) # optional - Coin
sage: P.get_max(x) # optional - Coin
0.0
Expand Down Expand Up @@ -1040,7 +1052,8 @@ cdef class CoinBackend(GenericBackend):
:trac:`14581`::
sage: P = MixedIntegerLinearProgram(solver="Coin") # optional - Coin
sage: x = P["x"] # optional - Coin
sage: v = P.new_variable(nonnegative=True) # optional - Coin
sage: x = v["x"] # optional - Coin
sage: P.set_min(x, 5) # optional - Coin
sage: P.set_min(x, 0) # optional - Coin
sage: P.get_min(x) # optional - Coin
Expand Down Expand Up @@ -1175,7 +1188,7 @@ cdef class CoinBackend(GenericBackend):
sage: from sage.numerical.backends.generic_backend import get_solver
sage: p = MixedIntegerLinearProgram(solver = "Coin") # optional - Coin
sage: b = p.new_variable() # optional - Coin
sage: b = p.new_variable(nonnegative=True) # optional - Coin
sage: p.add_constraint(b[1] + b[2] <= 6) # optional - Coin
sage: p.set_objective(b[1] + b[2]) # optional - Coin
sage: copy(p).solve() # optional - Coin
Expand Down
2 changes: 1 addition & 1 deletion src/sage/numerical/backends/gurobi_backend.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ cdef extern from "gurobi_c.h":
int GRBaddrangeconstr(GRBmodel *model, int numnz, int *cind, double *cval, double lower, double upper, char *constrnames)


void GRBfreemodel(GRBmodel *model)
int GRBfreemodel(GRBmodel *model)
void GRBfreeenv(GRBenv *env)
int GRBupdatemodel(GRBmodel *model)
int GRBoptimize(GRBmodel *model)
Expand Down
13 changes: 7 additions & 6 deletions src/sage/numerical/backends/gurobi_backend.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ cdef class GurobiBackend(GenericBackend):
# Initializing the model
error = GRBnewmodel(self.env_master, &self.model, NULL, 0, NULL, NULL, NULL, NULL, NULL)

self.env = GRBgetenv (self.model)
self.env = GRBgetenv(self.model)

if error:
raise RuntimeError("Could not initialize Gurobi model")
Expand Down Expand Up @@ -377,7 +377,8 @@ cdef class GurobiBackend(GenericBackend):
Constants in the objective function are respected::
sage: p = MixedIntegerLinearProgram(solver='Gurobi')# optional - Gurobi
sage: x,y = p[0], p[1] # optional - Gurobi
sage: v = p.new_variable(nonnegative=True) # optional - Gurobi
sage: x,y = v[0], v[1] # optional - Gurobi
sage: p.add_constraint(2*x + 3*y, max = 6) # optional - Gurobi
sage: p.add_constraint(3*x + 2*y, max = 6) # optional - Gurobi
sage: p.set_objective(x + y + 7) # optional - Gurobi
Expand Down Expand Up @@ -432,7 +433,8 @@ cdef class GurobiBackend(GenericBackend):
EXAMPLE::
sage: p = MixedIntegerLinearProgram(solver='Gurobi')# optional - Gurobi
sage: x,y = p[0], p[1] # optional - Gurobi
sage: v = p.new_variable(nonnegative=True) # optional - Gurobi
sage: x,y = v[0], v[1] # optional - Gurobi
sage: p.add_constraint(2*x + 3*y, max = 6) # optional - Gurobi
sage: p.add_constraint(3*x + 2*y, max = 6) # optional - Gurobi
sage: p.set_objective(x + y + 7) # optional - Gurobi
Expand Down Expand Up @@ -1148,7 +1150,7 @@ cdef class GurobiBackend(GenericBackend):
sage: from sage.numerical.backends.generic_backend import get_solver # optional - GUROBI
sage: p = MixedIntegerLinearProgram(solver = "GUROBI") # optional - GUROBI
sage: b = p.new_variable() # optional - GUROBI
sage: b = p.new_variable(nonnegative=True) # optional - GUROBI
sage: p.add_constraint(b[1] + b[2] <= 6) # optional - GUROBI
sage: p.set_objective(b[1] + b[2]) # optional - GUROBI
sage: copy(p).solve() # optional - GUROBI
Expand All @@ -1163,9 +1165,8 @@ cdef class GurobiBackend(GenericBackend):
"""
Destructor
"""
GRBfreeenv(self.env)
GRBfreeenv(self.env_master)
GRBfreemodel(self.model)
GRBfreeenv(self.env_master)

cdef dict errors = {
10001 : "GRB_ERROR_OUT_OF_MEMORY",
Expand Down

0 comments on commit 1fc9ab6

Please sign in to comment.