Skip to content

Commit

Permalink
Refactor batch getters of problem values (#101)
Browse files Browse the repository at this point in the history
Added Model._get_primal_values, _get_constraint_values, _get_shadow_prices, _get_reduced_costs for very efficient retrieval of values
  • Loading branch information
matthiaskoenig authored and KristianJensen committed Apr 8, 2017
1 parent 84b432e commit e3ca986
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 53 deletions.
31 changes: 15 additions & 16 deletions optlang/cplex_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,40 +723,39 @@ def _set_objective_direction(self, direction):

@property
def primal_values(self):
# round primals
primal_values = [variable._round_primal_to_bounds(primal)
for variable, primal in zip(self.variables, self._get_primal_values())]
return collections.OrderedDict(
zip(self._get_variables_names(), primal_values)
)

def _get_primal_values(self):
try:
primal_values = collections.OrderedDict(
(variable.name, variable._round_primal_to_bounds(primal))
for variable, primal in zip(self.variables, self.problem.solution.get_values())
)
primal_values = self.problem.solution.get_values()
except CplexSolverError as err:
raise SolverError(str(err))
return primal_values

@property
def reduced_costs(self):
def _get_reduced_costs(self):
if self.is_integer:
raise ValueError("Dual values are not well-defined for integer problems")
try:
return collections.OrderedDict(
zip((variable.name for variable in self.variables), self.problem.solution.get_reduced_costs()))
return self.problem.solution.get_reduced_costs()
except CplexSolverError as err:
raise SolverError(str(err))

@property
def constraint_values(self):
def _get_constraint_values(self):
try:
return collections.OrderedDict(
zip((constraint.name for constraint in self.constraints), self.problem.solution.get_activity_levels()))
return self.problem.solution.get_activity_levels()
except CplexSolverError as err:
raise SolverError(str(err))

@property
def shadow_prices(self):
def _get_shadow_prices(self):
if self.is_integer:
raise ValueError("Dual values are not well-defined for integer problems")
try:
return collections.OrderedDict(
zip((constraint.name for constraint in self.constraints), self.problem.solution.get_dual_values()))
return self.problem.solution.get_dual_values()
except CplexSolverError as err:
raise SolverError(str(err))

Expand Down
59 changes: 26 additions & 33 deletions optlang/glpk_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
glp_set_mat_row, glp_set_col_bnds, glp_set_row_bnds, GLP_FR, GLP_UP, GLP_LO, GLP_FX, GLP_DB, glp_del_rows, \
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
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



Expand Down Expand Up @@ -590,45 +591,37 @@ def objective(self, value):

@property
def primal_values(self):
primal_values = collections.OrderedDict()
is_mip = self._glpk_is_mip()
for index, variable in enumerate(self.variables):
if is_mip:
value = glp_mip_col_val(self.problem, index + 1)
else:
value = glp_get_col_prim(self.problem, index + 1)
primal_values[variable.name] = variable._round_primal_to_bounds(value)
return primal_values
# round primals
primal_values = [variable._round_primal_to_bounds(primal)
for variable, primal in zip(self.variables, self._get_primal_values())]
return collections.OrderedDict(
zip(self._get_variables_names(), primal_values)
)

@property
def reduced_costs(self):
def _get_primal_values(self):
if self._glpk_is_mip():
# no vector function (element wise)
return [glp_mip_col_val(self.problem, index + 1)
for index in range(len(self.variables))]
else:
return get_col_primals(self.problem)

def _get_reduced_costs(self):
if self.is_integer:
raise ValueError("Dual values are not well-defined for integer problems")
reduced_costs = collections.OrderedDict(
(var.name, glp_get_col_dual(self.problem, index + 1)) for index, var in enumerate(self.variables)
)
return reduced_costs
return get_col_duals(self.problem)

@property
def constraint_values(self):
dual_values = collections.OrderedDict()
is_mip = self._glpk_is_mip()
for index, constraint in enumerate(self.constraints):
if is_mip:
value = glp_mip_row_val(self.problem, index + 1)
else:
value = glp_get_row_prim(self.problem, index + 1)
dual_values[constraint.name] = value
return dual_values
def _get_constraint_values(self):
if self._glpk_is_mip():
# no vector function (element wise)
return [glp_mip_row_val(self.problem, index + 1) for index in range(len(self.constraints))]
else:
return get_row_primals(self.problem)

@property
def shadow_prices(self):
def _get_shadow_prices(self):
if self.is_integer:
raise ValueError("Dual values are not well-defined for integer problems")
shadow_prices = collections.OrderedDict(
(constraint.name, glp_get_row_dual(self.problem, index + 1)) for index, constraint in enumerate(self.constraints)
)
return shadow_prices
return get_row_duals(self.problem)

def to_lp(self):
self.update()
Expand Down
72 changes: 68 additions & 4 deletions optlang/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -1202,16 +1202,37 @@ def status(self):
"""The solver status of the model."""
return self._status

def _get_variables_names(self):
"""The names of model variables.
Returns
-------
list
"""
return [variable.name for variable in self.variables]

@property
def primal_values(self):
"""The primal values of model variables.
The primal values are rounded to the bounds.
Returns
-------
collections.OrderedDict
"""
return collections.OrderedDict(
zip(self._get_variables_names(), self._get_primal_values())
)

def _get_primal_values(self):
"""The primal values of model variables.
Returns
-------
list
"""
# Fallback, if nothing faster is available
return collections.OrderedDict([(variable.name, variable.primal) for variable in self.variables])
return [variable.primal for variable in self.variables]

@property
def reduced_costs(self):
Expand All @@ -1221,8 +1242,28 @@ def reduced_costs(self):
-------
collections.OrderedDict
"""
return collections.OrderedDict(
zip(self._get_variables_names(), self._get_reduced_costs())
)

def _get_reduced_costs(self):
"""The reduced costs/dual values of all variables.
Returns
-------
list
"""
# Fallback, if nothing faster is available
return collections.OrderedDict([(variable.name, variable.dual) for variable in self.variables])
return [variable.dual for variable in self.variables]

def _get_constraint_names(self):
"""The names of model constraints.
Returns
-------
list
"""
return [constraint.name for constraint in self.constraints]

@property
def constraint_values(self):
Expand All @@ -1232,19 +1273,42 @@ def constraint_values(self):
-------
collections.OrderedDict
"""
return collections.OrderedDict(
zip(self._get_constraint_names(), self._get_constraint_values())
)

def _get_constraint_values(self):
"""The primal values of all constraints.
Returns
-------
list
"""
# Fallback, if nothing faster is available
return collections.OrderedDict([(constraint.name, constraint.primal) for constraint in self.constraints])
return [constraint.primal for constraint in self.constraints]

@property
def shadow_prices(self):
"""The shadow prices of model (dual values of all constraints).
Returns
-------
collections.OrderedDict
"""
return collections.OrderedDict(
zip(self._get_constraint_names(), self._get_shadow_prices())
)


def _get_shadow_prices(self):
"""The shadow prices of model (dual values of all constraints).
Returns
-------
collections.OrderedDict
"""
# Fallback, if nothing faster is available
return collections.OrderedDict([(constraint.name, constraint.dual) for constraint in self.constraints])
return [constraint.dual for constraint in self.constraints]

@property
def is_integer(self):
Expand Down

0 comments on commit e3ca986

Please sign in to comment.