def epigraph_reformulation(exp, slack_var_list, constraint_list, use_mcpp, sense): """Epigraph reformulation. Generate the epigraph reformuation for objective expressions. Parameters ---------- slack_var_list : VarList Slack vars for epigraph reformulation. constraint_list : ConstraintList Epigraph constraint list. use_mcpp : Bool Whether to use mcpp to tighten the bound of slack variables. exp : Expression The expression to reformualte. sense : objective sense The objective sense. """ slack_var = slack_var_list.add() if mcpp_available() and use_mcpp: mc_obj = McCormick(exp) slack_var.setub(mc_obj.upper()) slack_var.setlb(mc_obj.lower()) else: # Use Pyomo's contrib.fbbt package lb, ub = compute_bounds_on_expr(exp) if sense == minimize: slack_var.setlb(lb) else: slack_var.setub(ub) if sense == minimize: constraint_list.add(expr=slack_var >= exp) else: constraint_list.add(expr=slack_var <= exp)
def process_objective(solve_data, config, move_linear_objective=False): m = solve_data.working_model util_blk = getattr(m, solve_data.util_block_name) # Handle missing or multiple objectives active_objectives = list(m.component_data_objects( ctype=Objective, active=True, descend_into=True)) solve_data.results.problem.number_of_objectives = len(active_objectives) if len(active_objectives) == 0: config.logger.warning( 'Model has no active objectives. Adding dummy objective.') util_blk.dummy_objective = Objective(expr=1) main_obj = util_blk.dummy_objective elif len(active_objectives) > 1: raise ValueError('Model has multiple active objectives.') else: main_obj = active_objectives[0] solve_data.results.problem.sense = main_obj.sense solve_data.objective_sense = main_obj.sense # Move the objective to the constraints if it is nonlinear if main_obj.expr.polynomial_degree() not in (1, 0) \ or move_linear_objective: if move_linear_objective: config.logger.info("Moving objective to constraint set.") else: config.logger.info("Objective is nonlinear. Moving it to constraint set.") util_blk.objective_value = Var(domain=Reals, initialize=0) if mcpp_available(): mc_obj = McCormick(main_obj.expr) util_blk.objective_value.setub(mc_obj.upper()) util_blk.objective_value.setlb(mc_obj.lower()) if main_obj.sense == minimize: util_blk.objective_constr = Constraint( expr=util_blk.objective_value >= main_obj.expr) solve_data.results.problem.sense = ProblemSense.minimize else: util_blk.objective_constr = Constraint( expr=util_blk.objective_value <= main_obj.expr) solve_data.results.problem.sense = ProblemSense.maximize # Deactivate the original objective and add this new one. main_obj.deactivate() util_blk.objective = Objective( expr=util_blk.objective_value, sense=main_obj.sense) # Add the new variable and constraint to the working lists util_blk.variable_list.append(util_blk.objective_value) util_blk.constraint_list.append(util_blk.objective_constr)
def process_objective(solve_data, config): m = solve_data.working_model util_blk = getattr(m, solve_data.util_block_name) # Handle missing or multiple objectives objs = list(m.component_data_objects( ctype=Objective, active=True, descend_into=True)) num_objs = len(objs) solve_data.results.problem.number_of_objectives = num_objs if num_objs == 0: config.logger.warning( 'Model has no active objectives. Adding dummy objective.') util_blk.dummy_objective = Objective(expr=1) main_obj = util_blk.dummy_objective elif num_objs > 1: raise ValueError('Model has multiple active objectives.') else: main_obj = objs[0] solve_data.results.problem.sense = main_obj.sense solve_data.objective_sense = main_obj.sense # Move the objective to the constraints if it is nonlinear if main_obj.expr.polynomial_degree() not in (1, 0): config.logger.info("Objective is nonlinear. Moving it to constraint set.") util_blk.objective_value = Var(domain=Reals, initialize=0) if mcpp_available(): mc_obj = McCormick(main_obj.expr) util_blk.objective_value.setub(mc_obj.upper()) util_blk.objective_value.setlb(mc_obj.lower()) if main_obj.sense == minimize: util_blk.objective_constr = Constraint( expr=util_blk.objective_value >= main_obj.expr) solve_data.results.problem.sense = ProblemSense.minimize else: util_blk.objective_constr = Constraint( expr=util_blk.objective_value <= main_obj.expr) solve_data.results.problem.sense = ProblemSense.maximize # Deactivate the original objective and add this new one. main_obj.deactivate() util_blk.objective = Objective( expr=util_blk.objective_value, sense=main_obj.sense) # Add the new variable and constraint to the working lists util_blk.variable_list.append(util_blk.objective_value) util_blk.constraint_list.append(util_blk.objective_constr)
SolverFactory('gdpopt').solve( eight_process, strategy='LOA', init_strategy='custom_disjuncts', custom_init_disjuncts=initialize, mip_solver=mip_solver, nlp_solver=nlp_solver, call_after_subproblem_feasible=assert_correct_disjuncts_active) self.assertTrue(fabs(value(eight_process.profit.expr) - 68) <= 1E-2) @unittest.skipIf(not GLOA_solvers_available, "Required subsolvers %s are not available" % (GLOA_solvers, )) @unittest.skipIf(not mcpp_available(), "MC++ is not available") class TestGLOA(unittest.TestCase): """Tests for global logic-based outer approximation.""" def test_GDP_integer_vars(self): m = ConcreteModel() m.x = Var(bounds=(0, 10)) m.y = Var(domain=Integers, bounds=(0, 5)) m.d = Disjunction( expr=[[m.x >= m.y, m.y >= 3.5], [m.x >= m.y, m.y >= 2.5]]) m.o = Objective(expr=m.x) SolverFactory('gdpopt').solve(m, strategy='GLOA', mip_solver=mip_solver, nlp_solver=nlp_solver, minlp_solver=minlp_solver) self.assertAlmostEqual(value(m.o.expr), 3)
self.assertTrue(soln_disj.indicator_var.value == 1) SolverFactory('gdpopt').solve( eight_process, strategy='LOA', init_strategy='custom_disjuncts', custom_init_disjuncts=initialize, mip_solver=mip_solver, nlp_solver=nlp_solver, call_after_subproblem_feasible=assert_correct_disjuncts_active) self.assertTrue(fabs(value(eight_process.profit.expr) - 68) <= 1E-2) @unittest.skipIf(not GLOA_solvers_available, "Required subsolvers %s are not available" % (GLOA_solvers,)) @unittest.skipIf(not mcpp_available(), "MC++ is not available") class TestGLOA(unittest.TestCase): """Tests for global logic-based outer approximation.""" def test_GDP_integer_vars(self): m = ConcreteModel() m.x = Var(bounds=(0, 10)) m.y = Var(domain=Integers, bounds=(0, 5)) m.d = Disjunction(expr=[[ m.x >= m.y, m.y >= 3.5 ], [ m.x >= m.y, m.y >= 2.5 ]]) m.o = Objective(expr=m.x) SolverFactory('gdpopt').solve(
def process_objective(solve_data, config, move_linear_objective=False, use_mcpp=True, updata_var_con_list=True): """Process model objective function. Check that the model has only 1 valid objective. If the objective is nonlinear, move it into the constraints. If no objective function exists, emit a warning and create a dummy objective. Parameters ---------- solve_data (GDPoptSolveData): solver environment data class config (ConfigBlock): solver configuration options move_linear_objective (bool): if True, move even linear objective functions to the constraints """ m = solve_data.working_model util_blk = getattr(m, solve_data.util_block_name) # Handle missing or multiple objectives active_objectives = list(m.component_data_objects( ctype=Objective, active=True, descend_into=True)) solve_data.results.problem.number_of_objectives = len(active_objectives) if len(active_objectives) == 0: config.logger.warning( 'Model has no active objectives. Adding dummy objective.') util_blk.dummy_objective = Objective(expr=1) main_obj = util_blk.dummy_objective elif len(active_objectives) > 1: raise ValueError('Model has multiple active objectives.') else: main_obj = active_objectives[0] solve_data.results.problem.sense = ProblemSense.minimize if main_obj.sense == 1 else ProblemSense.maximize solve_data.objective_sense = main_obj.sense # Move the objective to the constraints if it is nonlinear if main_obj.expr.polynomial_degree() not in (1, 0) \ or move_linear_objective: if move_linear_objective: config.logger.info("Moving objective to constraint set.") else: config.logger.info( "Objective is nonlinear. Moving it to constraint set.") util_blk.objective_value = Var(domain=Reals, initialize=0) if mcpp_available() and use_mcpp: mc_obj = McCormick(main_obj.expr) util_blk.objective_value.setub(mc_obj.upper()) util_blk.objective_value.setlb(mc_obj.lower()) else: # Use Pyomo's contrib.fbbt package lb, ub = compute_bounds_on_expr(main_obj.expr) if solve_data.results.problem.sense == ProblemSense.minimize: util_blk.objective_value.setlb(lb) else: util_blk.objective_value.setub(ub) if main_obj.sense == minimize: util_blk.objective_constr = Constraint( expr=util_blk.objective_value >= main_obj.expr) else: util_blk.objective_constr = Constraint( expr=util_blk.objective_value <= main_obj.expr) # Deactivate the original objective and add this new one. main_obj.deactivate() util_blk.objective = Objective( expr=util_blk.objective_value, sense=main_obj.sense) # Add the new variable and constraint to the working lists if main_obj.expr.polynomial_degree() not in (1, 0) or (move_linear_objective and updata_var_con_list): util_blk.variable_list.append(util_blk.objective_value) util_blk.continuous_variable_list.append(util_blk.objective_value) util_blk.constraint_list.append(util_blk.objective_constr) util_blk.objective_list.append(util_blk.objective) if util_blk.objective_constr.body.polynomial_degree() in (0, 1): util_blk.linear_constraint_list.append(util_blk.objective_constr) else: util_blk.nonlinear_constraint_list.append( util_blk.objective_constr)
else: subsolvers_available = True model_list = [ EightProcessFlowsheet(convex=False), Nonconvex1(), Nonconvex2(), Nonconvex3(), Nonconvex4(), ] @unittest.skipIf(not subsolvers_available, 'Required subsolvers %s are not available' % (required_solvers, )) @unittest.skipIf(not pyomo_mcpp.mcpp_available(), 'MC++ is not available') class TestMindtPy(unittest.TestCase): """Tests for the MindtPy solver plugin.""" def test_GOA(self): """Test the global outer approximation decomposition algorithm.""" with SolverFactory('mindtpy') as opt: for model in model_list: results = opt.solve(model, strategy='GOA', mip_solver=required_solvers[1], nlp_solver=required_solvers[0], single_tree=True) self.assertIn(results.solver.termination_condition, [ TerminationCondition.optimal, TerminationCondition.feasible ])
else: subsolvers_available = True model_list = [EightProcessFlowsheet(convex=False), Nonconvex1(), Nonconvex2(), Nonconvex3(), Nonconvex4(), ] @unittest.skipIf(not subsolvers_available, 'Required subsolvers %s are not available' % (required_solvers,)) @unittest.skipIf(not pyomo_mcpp.mcpp_available(), 'MC++ is not available') class TestMindtPy(unittest.TestCase): """Tests for the MindtPy solver plugin.""" def test_GOA(self): """Test the global outer approximation decomposition algorithm.""" with SolverFactory('mindtpy') as opt: for model in model_list: results = opt.solve(model, strategy='GOA', mip_solver=required_solvers[1], nlp_solver=required_solvers[0], single_tree=True) self.assertIn(results.solver.termination_condition, [ TerminationCondition.optimal, TerminationCondition.feasible])