Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various bug fixes #126

Merged
merged 17 commits into from
Aug 21, 2017
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion optlang/glpk_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
glp_get_mat_row, glp_get_row_ub, glp_get_row_type, glp_get_row_lb, glp_get_row_name, glp_get_obj_coef, \
glp_get_obj_dir, glp_scale_prob, GLP_SF_AUTO, glp_get_num_int, glp_get_num_bin, glp_mip_col_val, \
glp_mip_obj_val, glp_mip_status, GLP_ETMLIM, glp_adv_basis, glp_read_lp, glp_mip_row_val, \
get_col_primals, get_col_duals, get_row_primals, get_row_duals
get_col_primals, get_col_duals, get_row_primals, get_row_duals, glp_delete_prob



Expand Down Expand Up @@ -579,6 +579,9 @@ def __setstate__(self, repr_dict):
if repr_dict['glpk_status'] == 'optimal':
self.optimize() # since the start is an optimal solution, nothing will happen here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might also need to delete self._variables/constraints/objective here since the Python GC does not resolve cyclical dependencies automatically for objects that have a del method for some older Python versions I think...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that __del__ is only being called when the object is garbage collected (which it isn't in this case if it has a __del__ method) :(

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, good catch. Maybe wrap glp_prob into its own class with a __del__ method, use the wrapped object as Model.problem and rather reference Model instead of Model.problem in the objective?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would probably work, but perhaps a better solution would be to use weakrefs for the references to Models in Variables, Constraints and Objectives?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! That is a great idea!

def __del__(self):
glp_delete_prob(self.problem)

@property
def objective(self):
return self._objective
Expand Down
42 changes: 27 additions & 15 deletions optlang/gurobi_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import os
import six
from functools import partial
from optlang import interface
from optlang.util import inheritdocstring, TemporaryFilename
from optlang.expression_parsing import parse_optimization_expression
Expand Down Expand Up @@ -325,9 +326,10 @@ def __init__(self, expression, sloppy=False, *args, **kwargs):
@property
def value(self):
if getattr(self, "problem", None) is not None:
gurobi_problem = self.problem.problem
try:
return self.problem.problem.getAttr("ObjVal") + getattr(self.problem, "_objective_offset", 0)
except gurobipy.GurobiError: # TODO: let this check the actual error message
return gurobi_problem.getAttr("ObjVal") + getattr(self.problem, "_objective_offset", 0)
except (gurobipy.GurobiError, AttributeError): # TODO: let this check the actual error message
return None
else:
return None
Expand Down Expand Up @@ -359,8 +361,9 @@ def _get_expression(self):
if self.problem is not None and self._expression_expired and len(self.problem._variables) > 0:
grb_obj = self.problem.problem.getObjective()
terms = []
variables = self.problem._variables
for i in range(grb_obj.size()):
terms.append(grb_obj.getCoeff(i) * self.problem.variables[grb_obj.getVar(i).getAttr('VarName')])
terms.append(grb_obj.getCoeff(i) * variables[grb_obj.getVar(i).getAttr('VarName')])
expression = symbolics.add(terms)
# TODO implement quadratic objectives
self._expression = expression + getattr(self.problem, "_objective_offset", 0)
Expand Down Expand Up @@ -427,20 +430,29 @@ def timeout(self, value):
self.problem.problem.params.TimeLimit = value
self._timeout = value

def _get_feasibility(self):
return getattr(self.problem.problem.params, "FeasibilityTol")

def _set_feasibility(self, value):
return setattr(self.problem.problem.params, "FeasibilityTol", value)

def _get_optimality(self):
return getattr(self.problem.problem.params, "OptimalityTol")

def _set_optimality(self, value):
return setattr(self.problem.problem.params, "OptimalityTol", value)

def _get_integrality(self):
return getattr(self.problem.problem.params, "IntFeasTol")

def _set_integrality(self, value):
return setattr(self.problem.problem.params, "IntFeasTol", value)

def _tolerance_functions(self):
return {
"feasibility": (
lambda: self.problem.problem.params.FeasibilityTol,
lambda x: setattr(self.problem.problem.params, "FeasibilityTol", x)
),
"optimality": (
lambda: self.problem.problem.params.OptimalityTol,
lambda x: setattr(self.problem.problem.params, "OptimalityTol", x)
),
"integrality": (
lambda: self.problem.problem.params.IntFeasTol,
lambda x: setattr(self.problem.problem.params, "IntFeasTol", x)
)
"feasibility": (self._get_feasibility, self._set_feasibility),
"optimality": (self._get_optimality, self._set_optimality),
"integrality": (self._get_integrality, self._set_integrality)
}


Expand Down