From 8c194c93b2995f4561de03a3189d12cc2c61f5a6 Mon Sep 17 00:00:00 2001 From: Francesco Ceccon Date: Thu, 10 Dec 2020 15:48:38 +0000 Subject: [PATCH] feat: branch and perform obbt only on quadratic vars --- galini/branch_and_cut/bound_reduction.py | 16 ++++++++++------ galini/branch_and_cut/branching.py | 6 ++++++ galini/branch_and_cut/node_storage.py | 2 +- galini/relaxations/expressions.py | 11 ++++------- galini/relaxations/multivariate.py | 8 ++++---- galini/relaxations/relax.py | 3 ++- 6 files changed, 27 insertions(+), 19 deletions(-) diff --git a/galini/branch_and_cut/bound_reduction.py b/galini/branch_and_cut/bound_reduction.py index 54a2c6c..2484e62 100644 --- a/galini/branch_and_cut/bound_reduction.py +++ b/galini/branch_and_cut/bound_reduction.py @@ -18,6 +18,7 @@ import numpy as np import pyomo.environ as pe from coramin.relaxations.iterators import relaxation_data_objects +from galini.branch_and_cut.branching import BILINEAR_RELAXATIONS_TYPES from galini.math import is_close from galini.pyomo import safe_set_bounds from galini.pyomo.util import update_solver_options @@ -72,13 +73,14 @@ def perform_obbt_on_model(solver, model, linear_model, upper_bound, timelimit, r # collect variables in nonlinear constraints nonlinear_variables = ComponentSet() for relaxation in relaxation_data_objects(linear_model, active=True, descend_into=True): - for var in relaxation.get_rhs_vars(): - # Coramin will complain about variables that are fixed - if not var.has_lb() or not var.has_ub(): - nonlinear_variables.add(var) - else: - if not np.abs(var.ub - var.lb) < mc.epsilon: + if not isinstance(relaxation, BILINEAR_RELAXATIONS_TYPES): + for var in relaxation.get_rhs_vars(): + # Coramin will complain about variables that are fixed + if not var.has_lb() or not var.has_ub(): nonlinear_variables.add(var) + else: + if not np.abs(var.ub - var.lb) < mc.epsilon: + nonlinear_variables.add(var) time_left = timelimit - seconds_elapsed_since(obbt_start_time) nonlinear_variables = list(nonlinear_variables) @@ -140,6 +142,8 @@ def perform_obbt_on_model(solver, model, linear_model, upper_bound, timelimit, r for var, new_lb, new_ub in zip(nonlinear_variables, *result): original_var = model.find_component(var.getname(fully_qualified=True)) + if original_var is None: + continue new_lb = best_lower_bound(var, new_lb, var.lb, eps) new_ub = best_upper_bound(var, new_ub, var.ub, eps) if np.abs(new_ub - new_lb) < eps: diff --git a/galini/branch_and_cut/branching.py b/galini/branch_and_cut/branching.py index 6b402c3..83412f1 100644 --- a/galini/branch_and_cut/branching.py +++ b/galini/branch_and_cut/branching.py @@ -16,6 +16,7 @@ import numpy as np import pyomo.environ as pe +from coramin.relaxations.mccormick import PWMcCormickRelaxation from galini.branch_and_bound.branching import BranchingPoint from galini.branch_and_bound.strategy import BranchingStrategy @@ -24,6 +25,9 @@ from galini.math import is_close, is_inf +BILINEAR_RELAXATIONS_TYPES = (PWMcCormickRelaxation,) + + class BranchAndCutBranchingStrategy(BranchingStrategy): def __init__(self, algorithm): pass @@ -162,6 +166,8 @@ def compute_nonlinear_infeasiblity_components(linear_problem, mip_solution): } for relaxation in linear_problem.galini_nonlinear_relaxations: + if not isinstance(relaxation, BILINEAR_RELAXATIONS_TYPES): + continue rhs_vars = relaxation.get_rhs_vars() if len(rhs_vars) > 2: diff --git a/galini/branch_and_cut/node_storage.py b/galini/branch_and_cut/node_storage.py index b225502..5e45014 100644 --- a/galini/branch_and_cut/node_storage.py +++ b/galini/branch_and_cut/node_storage.py @@ -19,9 +19,9 @@ from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr from galini.branch_and_bound.branching import branch_at_point -from galini.relaxations.relax import RelaxationData from galini.cuts.pool import CutNodeStorage, CutPool from galini.pyomo import safe_setlb, safe_setub +from galini.relaxations.relax import RelaxationData class BranchingDecision: diff --git a/galini/relaxations/expressions.py b/galini/relaxations/expressions.py index e99293c..fb0c1fc 100644 --- a/galini/relaxations/expressions.py +++ b/galini/relaxations/expressions.py @@ -15,14 +15,11 @@ """Functions to relax nonlinear pyomo expresions.""" import networkx as nx - -from suspect.pyomo.quadratic import QuadraticExpression -import pyomo.environ as pe -from suspect.convexity.rules.quadratic import QuadraticRule -from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr -from coramin.utils.coramin_enums import RelaxationSide, FunctionShape +from coramin.utils.coramin_enums import RelaxationSide from galini.relaxations.multivariate import FactorableConvexExpressionRelaxation -from coramin.relaxations.auto_relax import replace_sub_expression_with_aux_var +from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr +from suspect.convexity.rules.quadratic import QuadraticRule +from suspect.pyomo.quadratic import QuadraticExpression _convexity_rule = QuadraticRule() diff --git a/galini/relaxations/multivariate.py b/galini/relaxations/multivariate.py index 3474655..b631faf 100644 --- a/galini/relaxations/multivariate.py +++ b/galini/relaxations/multivariate.py @@ -14,13 +14,13 @@ """Relaxation that replaces a convex function with an auxiliary variable.""" -from coramin.utils.coramin_enums import RelaxationSide, FunctionShape +import math + +import pyomo.environ as pe from coramin.relaxations.custom_block import declare_custom_block from coramin.relaxations.relaxations_base import BaseRelaxationData, ComponentWeakRef +from coramin.utils.coramin_enums import RelaxationSide from pyomo.core.expr.visitor import identify_variables -import math -import pyomo.environ as pe -from coramin.relaxations._utils import _get_bnds_list @declare_custom_block(name='FactorableConvexExpressionRelaxation') diff --git a/galini/relaxations/relax.py b/galini/relaxations/relax.py index 1a9239e..876e80d 100644 --- a/galini/relaxations/relax.py +++ b/galini/relaxations/relax.py @@ -21,6 +21,7 @@ _relax_root_to_leaf_SumExpression, _relax_expr, ) +from coramin.relaxations import PWXSquaredRelaxation, PWUnivariateRelaxation from coramin.utils.coramin_enums import RelaxationSide from pyomo.core.expr.numvalue import polynomial_degree from suspect.pyomo.quadratic import QuadraticExpression @@ -164,7 +165,7 @@ def relax(model, data, use_linear_relaxation=True): assert obj.is_minimizing() - relaxation_side = RelaxationSide.UNDER + # relaxation_side = RelaxationSide.UNDER relaxation_side = RelaxationSide.BOTH new_body = relax_expression(model, obj.expr, relaxation_side, data)