Skip to content

Commit

Permalink
Merge branch 'Cplex-qp' into devel
Browse files Browse the repository at this point in the history
# Conflicts:
#	optlang/cplex_interface.py
  • Loading branch information
phantomas1234 committed Feb 1, 2016
2 parents f4524fe + 9b6377e commit 82c7d4a
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 92 deletions.
115 changes: 64 additions & 51 deletions optlang/cplex_interface.py
Expand Up @@ -35,6 +35,7 @@
from sympy.core.singleton import S
import cplex
from optlang import interface
from optlang.util import inheritdocstring
Zero = S.Zero
One = S.One

Expand Down Expand Up @@ -146,8 +147,8 @@ def _constraint_lb_and_ub_to_cplex_sense_rhs_and_range_value(lb, ub):
return sense, rhs, range_value


@six.add_metaclass(inheritdocstring)
class Variable(interface.Variable):
"""CPLEX variable interface."""

def __init__(self, name, *args, **kwargs):
super(Variable, self).__init__(name, **kwargs)
Expand Down Expand Up @@ -195,8 +196,8 @@ def dual(self):
return None


@six.add_metaclass(inheritdocstring)
class Constraint(interface.Constraint):
"""CPLEX solver interface"""

_INDICATOR_CONSTRAINT_SUPPORT = True

Expand Down Expand Up @@ -243,7 +244,9 @@ def problem(self, value):
@property
def primal(self):
if self.problem is not None:
return self.problem.problem.solution.get_activity_levels(self.name)
primal_from_solver = self.problem.problem.solution.get_activity_levels(self.name)
#return self._round_primal_to_bounds(primal_from_solver) # Test assertions fail
return primal_from_solver
else:
return None

Expand All @@ -254,46 +257,55 @@ def dual(self):
else:
return None

# TODO: Refactor to use properties
def __setattr__(self, name, value):
try:
old_name = self.name # TODO: This is a hack
except AttributeError:
pass
super(Constraint, self).__setattr__(name, value)
if getattr(self, 'problem', None):
@interface.Constraint.name.setter
def name(self, value):
if getattr(self, 'problem', None) is not None:
if self.indicator_variable is not None:
raise NotImplementedError(
"Unfortunately, the CPLEX python bindings don't support changing an indicator constraint's name"
)
else:
# TODO: the following needs to deal with quadratic constraints
self.problem.problem.linear_constraints.set_names(self.name, value)
self._name = value

if name == 'name':
if self.indicator_variable is not None:
raise NotImplementedError("Unfortunately, the CPLEX python bindings don't support changing an indicator constraint's name")
else:
# TODO: the following needs to deal with quadratic constraints
self.problem.problem.linear_constraints.set_names(old_name, value)

elif name == 'lb' or name == 'ub':
if self.indicator_variable is not None:
raise NotImplementedError("Unfortunately, the CPLEX python bindings don't support changing an indicator constraint's bounds")
if name == 'lb':
if self.ub is not None and value > self.ub:
raise ValueError(
"Lower bound %f is larger than upper bound %f in constraint %s" %
(value, self.ub, self)
)
sense, rhs, range_value = _constraint_lb_and_ub_to_cplex_sense_rhs_and_range_value(value, self.ub)
elif name == 'ub':
if self.lb is not None and value < self.lb:
raise ValueError(
"Upper bound %f is less than lower bound %f in constraint %s" %
(value, self.lb, self)
)
sense, rhs, range_value = _constraint_lb_and_ub_to_cplex_sense_rhs_and_range_value(self.lb, value)
if self.is_Linear:
self.problem.problem.linear_constraints.set_rhs(self.name, rhs)
self.problem.problem.linear_constraints.set_senses(self.name, sense)
self.problem.problem.linear_constraints.set_range_values(self.name, range_value)

elif name == 'expression':
pass
@interface.Constraint.lb.setter
def lb(self, value):
if getattr(self, 'problem', None) is not None:
if self.indicator_variable is not None:
raise NotImplementedError(
"Unfortunately, the CPLEX python bindings don't support changing an indicator constraint's bounds"
)
if self.ub is not None and value > self.ub:
raise ValueError(
"Lower bound %f is larger than upper bound %f in constraint %s" %
(value, self.ub, self)
)
sense, rhs, range_value = _constraint_lb_and_ub_to_cplex_sense_rhs_and_range_value(value, self.ub)
if self.is_Linear:
self.problem.problem.linear_constraints.set_rhs(self.name, rhs)
self.problem.problem.linear_constraints.set_senses(self.name, sense)
self.problem.problem.linear_constraints.set_range_values(self.name, range_value)
self._lb = value

@interface.Constraint.ub.setter
def ub(self, value):
if getattr(self, 'problem', None) is not None:
if self.indicator_variable is not None:
raise NotImplementedError(
"Unfortunately, the CPLEX python bindings don't support changing an indicator constraint's bounds"
)
if self.lb is not None and value < self.lb:
raise ValueError(
"Upper bound %f is less than lower bound %f in constraint %s" %
(value, self.lb, self)
)
sense, rhs, range_value = _constraint_lb_and_ub_to_cplex_sense_rhs_and_range_value(self.lb, value)
if self.is_Linear:
self.problem.problem.linear_constraints.set_rhs(self.name, rhs)
self.problem.problem.linear_constraints.set_senses(self.name, sense)
self.problem.problem.linear_constraints.set_range_values(self.name, range_value)
self._ub = value

def __iadd__(self, other):
# if self.problem is not None:
Expand All @@ -308,6 +320,7 @@ def __iadd__(self, other):
return self


@six.add_metaclass(inheritdocstring)
class Objective(interface.Objective):
def __init__(self, *args, **kwargs):
super(Objective, self).__init__(*args, **kwargs)
Expand All @@ -316,17 +329,16 @@ def __init__(self, *args, **kwargs):
def value(self):
return self.problem.problem.solution.get_objective_value()

def __setattr__(self, name, value):

if getattr(self, 'problem', None):
if name == 'direction':
self.problem.problem.objective.set_sense(
{'min': self.problem.problem.objective.sense.minimize, 'max': self.problem.problem.objective.sense.maximize}[value])
super(Objective, self).__setattr__(name, value)
else:
super(Objective, self).__setattr__(name, value)
@interface.Objective.direction.setter
def direction(self, value):
if getattr(self, 'problem', None) is not None:
self.problem.problem.objective.set_sense(
{'min': self.problem.problem.objective.sense.minimize,
'max': self.problem.problem.objective.sense.maximize}[value])
super(Objective, self).__setattr__("direction", value)


@six.add_metaclass(inheritdocstring)
class Configuration(interface.MathematicalProgrammingConfiguration):

def __init__(self, lp_method='primal', tolerance=1e-9, presolve=False, verbosity=0, timeout=None,
Expand Down Expand Up @@ -500,6 +512,7 @@ def qp_method(self, value):
self._qp_method = value


@six.add_metaclass(inheritdocstring)
class Model(interface.Model):
def __init__(self, problem=None, *args, **kwargs):

Expand Down
74 changes: 39 additions & 35 deletions optlang/glpk_interface.py
Expand Up @@ -28,6 +28,8 @@
from sympy.core.add import _unevaluated_Add
from sympy.core.mul import _unevaluated_Mul

from optlang.util import inheritdocstring

import logging
log = logging.getLogger(__name__)

Expand Down Expand Up @@ -67,8 +69,8 @@
)


@six.add_metaclass(inheritdocstring)
class Variable(interface.Variable):
"""..."""

def __init__(self, name, index=None, *args, **kwargs):
super(Variable, self).__init__(name, **kwargs)
Expand Down Expand Up @@ -126,19 +128,15 @@ def dual(self):
else:
return None

def __setattr__(self, name, value):
try:
old_name = self.name # TODO: This is a hack
except AttributeError:
pass
super(Variable, self).__setattr__(name, value)
if getattr(self, 'problem', None):
if name == 'name':
glp_set_col_name(self.problem.problem, glp_find_col(self.problem.problem, old_name), str(value))
@interface.Variable.name.setter
def name(self, value):
if getattr(self, 'problem', None) is not None:
glp_set_col_name(self.problem.problem, glp_find_col(self.problem.problem, self.name), str(value))
self._name = value


@six.add_metaclass(inheritdocstring)
class Constraint(interface.Constraint):
"""GLPK solver interface"""

_INDICATOR_CONSTRAINT_SUPPORT = False

Expand Down Expand Up @@ -183,6 +181,24 @@ def _set_coefficients_low_level(self, variables_coefficients_dict):
else:
raise Exception('_set_coefficients_low_level works only if a constraint is associated with a solver instance.')

@interface.Constraint.lb.setter
def lb(self, value):
self._lb = value
if self.problem is not None:
self.problem._glpk_set_row_bounds(self)

@interface.Constraint.ub.setter
def ub(self, value):
self._ub = value
if self.problem is not None:
self.problem._glpk_set_row_bounds(self)

@interface.OptimizationExpression.name.setter
def name(self, value):
if self.problem is not None:
glp_set_row_name(self.problem.problem, glp_find_row(self.problem.problem, self.name), str(value))
self._name = value

@property
def problem(self):
return self._problem
Expand Down Expand Up @@ -211,7 +227,9 @@ def index(self):
@property
def primal(self):
if self.problem is not None:
return glp_get_row_prim(self.problem.problem, self.index)
primal_from_solver = glp_get_row_prim(self.problem.problem, self.index)
#return self._round_primal_to_bounds(primal_from_solver) # Test assertions fail
return primal_from_solver
else:
return None

Expand All @@ -235,18 +253,6 @@ def problem(self, value):
else:
self._problem = value

def __setattr__(self, name, value):
try:
old_name = self.name # TODO: This is a hack
except AttributeError:
pass
super(Constraint, self).__setattr__(name, value)
if getattr(self, 'problem', None):
if name == 'name':
glp_set_row_name(self.problem.problem, glp_find_row(self.problem.problem, old_name), str(value))
elif name == 'lb' or name == 'ub':
self.problem._glpk_set_row_bounds(self)

def __iadd__(self, other):
# if self.problem is not None:
# self.problem._add_to_constraint(self.index, other)
Expand Down Expand Up @@ -284,6 +290,7 @@ def __idiv__(self, other):
return self


@six.add_metaclass(inheritdocstring)
class Objective(interface.Objective):
def __init__(self, *args, **kwargs):
super(Objective, self).__init__(*args, **kwargs)
Expand All @@ -310,15 +317,11 @@ def value(self):
else:
return glp_get_obj_val(self.problem.problem)

def __setattr__(self, name, value):

if getattr(self, 'problem', None):
if name == 'direction':
glp_set_obj_dir(self.problem.problem,
{'min': GLP_MIN, 'max': GLP_MAX}[value])
super(Objective, self).__setattr__(name, value)
else:
super(Objective, self).__setattr__(name, value)
@interface.Objective.direction.setter
def direction(self, value):
if getattr(self, 'problem', None) is not None:
glp_set_obj_dir(self.problem.problem, {'min': GLP_MIN, 'max': GLP_MAX}[value])
super(Objective, self).__setattr__("objective", value)

def __iadd__(self, other):
self.problem = None
Expand Down Expand Up @@ -349,8 +352,8 @@ def __idiv__(self, other):
return self


@six.add_metaclass(inheritdocstring)
class Configuration(interface.MathematicalProgrammingConfiguration):
"""docstring for Configuration"""

def __init__(self, presolve=False, verbosity=0, timeout=None, *args, **kwargs):
super(Configuration, self).__init__(*args, **kwargs)
Expand Down Expand Up @@ -433,8 +436,9 @@ def timeout(self, value):
self._set_timeout(value)
self._timeout = value


@six.add_metaclass(inheritdocstring)
class Model(interface.Model):
"""GLPK solver interface"""

def __init__(self, problem=None, *args, **kwargs):

Expand Down

0 comments on commit 82c7d4a

Please sign in to comment.