Skip to content

Commit

Permalink
Merge branch 'benchmark' into OA_convexification
Browse files Browse the repository at this point in the history
  • Loading branch information
ZedongPeng committed Oct 29, 2023
2 parents d9dd088 + dec70eb commit 6f41799
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 76 deletions.
1 change: 1 addition & 0 deletions pyomo/contrib/mindtpy/algorithm_base_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -2387,6 +2387,7 @@ def handle_fp_subproblem_optimal(self, fp_nlp):
fp_nlp.MindtPy_utils.variable_list,
self.working_model.MindtPy_utils.variable_list,
self.config,
ignore_integrality=True
)
add_orthogonality_cuts(self.working_model, self.mip, self.config)

Expand Down
76 changes: 38 additions & 38 deletions pyomo/contrib/mindtpy/single_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from pyomo.opt import TerminationCondition as tc
from pyomo.core import minimize, value
from pyomo.core.expr import identify_variables
import math

cplex, cplex_available = attempt_import('cplex')

Expand All @@ -41,7 +42,6 @@ def copy_lazy_var_list_values(
config,
skip_stale=False,
skip_fixed=True,
ignore_integrality=False,
):
"""This function copies variable values from one list to another.
Expand Down Expand Up @@ -71,43 +71,43 @@ def copy_lazy_var_list_values(
if skip_fixed and v_to.is_fixed():
continue # Skip fixed variables.
v_val = self.get_values(opt._pyomo_var_to_solver_var_map[v_from])
try:
# We don't want to trigger the reset of the global stale
# indicator, so we will set this variable to be "stale",
# knowing that set_value will switch it back to "not
# stale"
v_to.stale = True
# NOTE: PEP 2180 changes the var behavior so that domain
# / bounds violations no longer generate exceptions (and
# instead log warnings). This means that the following
# will always succeed and the ValueError should never be
# raised.
v_to.set_value(v_val, skip_validation=True)
except ValueError as e:
# Snap the value to the bounds
config.logger.error(e)
if (
v_to.has_lb()
and v_val < v_to.lb
and v_to.lb - v_val <= config.variable_tolerance
):
v_to.set_value(v_to.lb, skip_validation=True)
elif (
v_to.has_ub()
and v_val > v_to.ub
and v_val - v_to.ub <= config.variable_tolerance
):
v_to.set_value(v_to.ub, skip_validation=True)
# ... or the nearest integer
elif v_to.is_integer():
rounded_val = int(round(v_val))
if (
ignore_integrality
or abs(v_val - rounded_val) <= config.integer_tolerance
) and rounded_val in v_to.domain:
v_to.set_value(rounded_val, skip_validation=True)
else:
raise
rounded_val = int(round(v_val))
# We don't want to trigger the reset of the global stale
# indicator, so we will set this variable to be "stale",
# knowing that set_value will switch it back to "not
# stale"
v_to.stale = True
# NOTE: PEP 2180 changes the var behavior so that domain
# / bounds violations no longer generate exceptions (and
# instead log warnings). This means that the following
# will always succeed and the ValueError should never be
# raised.
if v_val in v_to.domain \
and not ((v_to.has_lb() and v_val < v_to.lb)) \
and not ((v_to.has_ub() and v_val > v_to.ub)):
v_to.set_value(v_val)
# Snap the value to the bounds
# TODO: check the performance of
# v_to.lb - v_val <= config.variable_tolerance
elif (
v_to.has_lb()
and v_val < v_to.lb
# and v_to.lb - v_val <= config.variable_tolerance
):
v_to.set_value(v_to.lb)
elif (
v_to.has_ub()
and v_val > v_to.ub
# and v_val - v_to.ub <= config.variable_tolerance
):
v_to.set_value(v_to.ub)
# ... or the nearest integer
elif v_to.is_integer() and math.fabs(v_val - rounded_val) <= config.integer_tolerance: # and rounded_val in v_to.domain:
v_to.set_value(rounded_val)
elif abs(v_val) <= config.zero_tolerance and 0 in v_to.domain:
v_to.set_value(0)
else:
raise ValueError('copy_lazy_var_list_values failed.')

def add_lazy_oa_cuts(
self,
Expand Down
83 changes: 45 additions & 38 deletions pyomo/contrib/mindtpy/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -684,41 +684,42 @@ def copy_var_list_values_from_solution_pool(
Whether to ignore the integrality of integer variables, by default False.
"""
for v_from, v_to in zip(from_list, to_list):
try:
if config.mip_solver == 'cplex_persistent':
var_val = solver_model.solution.pool.get_values(
solution_name, var_map[v_from]
)
elif config.mip_solver == 'gurobi_persistent':
solver_model.setParam(gurobipy.GRB.Param.SolutionNumber, solution_name)
var_val = var_map[v_from].Xn
# We don't want to trigger the reset of the global stale
# indicator, so we will set this variable to be "stale",
# knowing that set_value will switch it back to "not
# stale"
v_to.stale = True
# NOTE: PEP 2180 changes the var behavior so that domain /
# bounds violations no longer generate exceptions (and
# instead log warnings). This means that the following will
# always succeed and the ValueError should never be raised.
if config.mip_solver == 'cplex_persistent':
var_val = solver_model.solution.pool.get_values(
solution_name, var_map[v_from]
)
elif config.mip_solver == 'gurobi_persistent':
solver_model.setParam(gurobipy.GRB.Param.SolutionNumber, solution_name)
var_val = var_map[v_from].Xn
# We don't want to trigger the reset of the global stale
# indicator, so we will set this variable to be "stale",
# knowing that set_value will switch it back to "not
# stale"
v_to.stale = True
rounded_val = int(round(var_val))
# NOTE: PEP 2180 changes the var behavior so that domain /
# bounds violations no longer generate exceptions (and
# instead log warnings). This means that the following will
# always succeed and the ValueError should never be raised.
if var_val in v_to.domain \
and not ((v_to.has_lb() and var_val < v_to.lb)) \
and not ((v_to.has_ub() and var_val > v_to.ub)):
v_to.set_value(var_val, skip_validation=True)
except ValueError as e:
config.logger.error(e)
rounded_val = int(round(var_val))
# Check to see if this is just a tolerance issue
if ignore_integrality and v_to.is_integer():
v_to.set_value(var_val, skip_validation=True)
elif v_to.is_integer() and (
abs(var_val - rounded_val) <= config.integer_tolerance
):
v_to.set_value(rounded_val, skip_validation=True)
elif abs(var_val) <= config.zero_tolerance and 0 in v_to.domain:
v_to.set_value(0, skip_validation=True)
else:
config.logger.error(
'Unknown validation domain error setting variable %s' % (v_to.name,)
)
raise
elif v_to.has_lb() and var_val < v_to.lb:
v_to.set_value(v_to.lb)
elif v_to.has_ub() and var_val > v_to.ub:
v_to.set_value(v_to.ub)
# Check to see if this is just a tolerance issue
elif ignore_integrality and v_to.is_integer():
v_to.set_value(var_val, skip_validation=True)
elif v_to.is_integer() and (
abs(var_val - rounded_val) <= config.integer_tolerance
):
v_to.set_value(rounded_val, skip_validation=True)
elif abs(var_val) <= config.zero_tolerance and 0 in v_to.domain:
v_to.set_value(0, skip_validation=True)
else:
raise ValueError("copy_var_list_values_from_solution_pool failed.")


class GurobiPersistent4MindtPy(GurobiPersistent):
Expand Down Expand Up @@ -980,14 +981,20 @@ def copy_var_list_values(from_list, to_list, config,
continue # Skip fixed variables.
var_val = value(v_from, exception=False)
rounded_val = int(round(var_val))
if var_val in v_to.domain:
if var_val in v_to.domain \
and not ((v_to.has_lb() and var_val < v_to.lb)) \
and not ((v_to.has_ub() and var_val > v_to.ub)):
v_to.set_value(value(v_from, exception=False))
elif v_to.has_lb() and var_val < v_to.lb:
v_to.set_value(v_to.lb)
elif v_to.has_ub() and var_val > v_to.ub:
v_to.set_value(v_to.ub)
elif ignore_integrality and v_to.is_integer():
v_to.set_value(value(v_from, exception=False), skip_validation=True)
elif abs(var_val) <= config.zero_tolerance and 0 in v_to.domain:
v_to.set_value(0)
elif v_to.is_integer() and (math.fabs(var_val - rounded_val) <=
config.integer_tolerance):
v_to.set_value(rounded_val)
elif abs(var_val) <= config.zero_tolerance and 0 in v_to.domain:
v_to.set_value(0)
else:
raise
raise ValueError("copy_var_list_values failed.")

0 comments on commit 6f41799

Please sign in to comment.