Skip to content

Commit

Permalink
fix baron convexification
Browse files Browse the repository at this point in the history
  • Loading branch information
Zedong Peng committed Oct 26, 2023
1 parent e14eb96 commit 64881ad
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 24 deletions.
6 changes: 5 additions & 1 deletion pyomo/contrib/mindtpy/algorithm_base_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver
from pyomo.common.collections import ComponentMap, Bunch, ComponentSet
from pyomo.common.errors import InfeasibleConstraintException
from pyomo.contrib.mindtpy.cut_generation import add_no_good_cuts
from pyomo.contrib.mindtpy.cut_generation import add_no_good_cuts, add_baron_cuts
from operator import itemgetter
from pyomo.common.errors import DeveloperError
from pyomo.solvers.plugins.solvers.gurobi_direct import gurobipy
Expand Down Expand Up @@ -2203,6 +2203,7 @@ def load_solution(self):
if self.working_model.component("_int_to_binary_reform") is not None:
self.working_model._int_to_binary_reform.deactivate()
# exclude fixed variables here. This is consistent with the definition of variable_list.
self.working_model.del_component('baroncuts')
working_model_variable_list = list(
get_vars_from_components(
block=self.working_model,
Expand Down Expand Up @@ -2772,6 +2773,9 @@ def solve(self, model, **kwds):

# Reformulate the objective function.
self.objective_reformulation()
if config.use_baron_convexification:
add_baron_cuts(self.working_model)
config.logger.info("Use the baron to tighten the bounds of variables and add initial cuts")

# Save model initial values.
self.initial_var_values = list(v.value for v in MindtPy.variable_list)
Expand Down
6 changes: 6 additions & 0 deletions pyomo/contrib/mindtpy/config_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,12 @@ def _add_common_configs(CONFIG):
domain=bool,
),
)
CONFIG.declare("use_baron_convexification", ConfigValue(
default=False,
domain=bool,
description="use baron to provide the convex relations for nonconvex MINLPs.",
doc="use baron to provide the convex relations for nonconvex MINLPs."
))


def _add_subsolver_configs(CONFIG):
Expand Down
50 changes: 30 additions & 20 deletions pyomo/contrib/mindtpy/cut_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

"""Cut generation."""
from math import copysign
from pyomo.core import minimize, value
from pyomo.core import minimize, value, RangeSet, Var, ConstraintList, Objective, Set
from pyomo.core.base.var import _GeneralVarData
import pyomo.core.expr as EXPR
from pyomo.contrib.gdpopt.util import time_code
from pyomo.contrib.mcpp.pyomo_mcpp import McCormick as mc, MCPP_Error
Expand Down Expand Up @@ -503,38 +504,46 @@ def add_baron_cuts(model):
output_filename, symbol_map = model.baronwrite(
"root_relaxation_baron.bar", format="bar")
var_ids = symbol_map.byObject
print(var_ids)
# dolocal: Local search option for upper bounding. 0: no local search is done during upper bounding. 1: BARON automatically decides when to apply local search based on analyzing the results of previous local searches
os.system("sed -i '1 a dolocal:0; ' root_relaxation_baron.bar")
# NumLoc: Number of local searches done in preprocessing. If NumLoc is set to −1, local searches in preprocessing will be done until proof of globality or MaxTime is reached. If NumLoc is set to −2, BARON decides the number of local searches in preprocessing based on problem and NLP solver characteristics.
os.system("sed -i '1 a numloc:0; ' root_relaxation_baron.bar")
os.system("sed -i '1 a maxtime:10000; ' root_relaxation_baron.bar")
# Option to control log output. 0: all log output is suppressed. 1: print log output.
os.system("sed -i '1 a prlevel:0; ' root_relaxation_baron.bar")
os.system("sed -i '1 a ppdo:0; ' root_relaxation_baron.bar")
os.system("sed -i '1 a pscdo:0; ' root_relaxation_baron.bar")
# os.system('''sed -i '1 a CplexLibName: "/opt/ibm/ILOG/CPLEX_Studio129/cplex/bin/x86-64_linux/libcplex1290.so"; ' root_relaxation_baron.bar''')
os.system('''sed -i '1 a CplexLibName: "/package/cplex/22.1/cplex/bin/x86-64_linux/libcplex12100.dylib"; ' root_relaxation_baron.bar''')

os.system('''sed -i '1 a CplexLibName: "/package/cplex/22.1/cplex/bin/x86-64_linux/libcplex2210.so"; ' root_relaxation_baron.bar''')
os.system(special_baron_path + " root_relaxation_baron.bar")
print('111111')
cplex_model = cplex.Cplex("relax.lp")

timeb = time.time()
print("lp file generation time", timeb - timea)
# create additional variables in the pyomo model
var_names = cplex_model.variables.get_names()
num_bar_vars = sum("bar_var" in var for var in var_names)
model.bar_set = RangeSet(num_bar_vars)
num_bar_vars_list = []
# sometimes the index of bar_var is not continuous
# Therefore, we cannot use RangeSet
for var in var_names:
if "bar_var" in var:
num_bar_vars_list.append(int(var.split("bar_var")[1]))
# model.bar_set = RangeSet(num_bar_vars)
model.bar_set = Set(initialize=num_bar_vars_list)
model.bar_var = Var(model.bar_set)

# create a map from cplex var id to pyomo var name
varid_to_var = {}
bar_var_indices = []
cplex_var_names = cplex_model.variables.get_names()
for vid in var_ids:
name = symbol_map.byObject[vid]
var_data = symbol_map.bySymbol[name]()
varid_cplex = cplex_model.variables.get_indices(name)
varid_to_var[varid_cplex] = var_data

cplex_var_names = cplex_model.variables.get_names()
var_data = symbol_map.bySymbol[name]
if isinstance(symbol_map.bySymbol[name], _GeneralVarData):
# sometimes some variables only appear in baron file not in cplex
if name in cplex_var_names:
varid_cplex = cplex_model.variables.get_indices(name)
varid_to_var[varid_cplex] = var_data
for i in range(len(cplex_var_names)):
varname = cplex_var_names[i]
if "bar_var" in varname:
Expand Down Expand Up @@ -570,15 +579,16 @@ def add_baron_cuts(model):
if sense == 'E':
model.baroncuts.add(expr == rhs)
# change objective
next(model.component_data_objects(Objective, active=True)).deactivate()
# move nonlinear objective function to constraint
# next(model.component_data_objects(Objective, active=True)).deactivate()
# model.obj.deactivate()
coeff = cplex_model.objective.get_linear()
if cplex_model.objective.get_sense() == 1:
model.baron_obj = Objective(expr=sum(varid_to_var[i] * coeff[i] for i in range(
cplex_model.variables.get_num()) if i in varid_to_var.keys()), sense=minimize)
else:
model.baron_obj = Objective(expr=sum(varid_to_var[i] * coeff[i] for i in range(
cplex_model.variables.get_num()) if i in varid_to_var.keys()), sense=maximize)
# coeff = cplex_model.objective.get_linear()
# if cplex_model.objective.get_sense() == 1:
# model.baron_obj = Objective(expr=sum(varid_to_var[i] * coeff[i] for i in range(
# cplex_model.variables.get_num()) if i in varid_to_var.keys()), sense=minimize)
# else:
# model.baron_obj = Objective(expr=sum(varid_to_var[i] * coeff[i] for i in range(
# cplex_model.variables.get_num()) if i in varid_to_var.keys()), sense=maximize)

timec = time.time()
print("time to add the cuts to pyomo model", timec-timeb)
3 changes: 0 additions & 3 deletions pyomo/core/base/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -2046,9 +2046,6 @@ def solver_capability(x): return True
solver_capability,
io_options)
referenced_variable_ids = smap.byObject.keys()
print(smap.byObject)
print(smap.byObject.keys())
print(referenced_variable_ids)
smap_id = id(smap)
if not hasattr(self, 'solutions'):
# This is a bit of a hack. The write() method was moved
Expand Down

0 comments on commit 64881ad

Please sign in to comment.