def test_ipopt_solver(model_name): current_dir = pathlib.Path(__file__).parent osil_file = current_dir / 'models' / (model_name + '.osil') pyomo_model = read_pyomo_model(osil_file) problem = problem_from_pyomo_model(pyomo_model) atol = rtol = 1e-4 galini = Galini() galini.update_configuration({ 'galini': { 'constraint_violation_tol': 1e-2, }, 'logging': { 'stdout': True, }, 'branch_and_cut': { 'tolerance': atol, 'relative_tolerance': rtol, 'root_node_feasible_solution_search_timelimit': 0, 'cuts': { 'maxiter': 100, } }, 'cuts_generator': { 'generators': ['outer_approximation'], }, 'ipopt': { 'ipopt': { 'acceptable_constr_viol_tol': 1e-3 }, }, }) set_timelimit(30) start_timelimit() solver = BranchAndBoundSolver(galini) solver.before_solve(pyomo_model, problem) solution = solver.solve(problem) assert solution.status.is_success() sol_file = current_dir / 'solutions' / (model_name + '.sol') expected_solution = read_solution(sol_file) expected_objective = expected_solution['objective'] assert solution.objective is not None assert is_close(expected_objective, solution.objective.value, atol=atol, rtol=rtol) expected_variables = expected_solution['variables'] for var_sol in solution.variables: assert is_close( expected_variables[var_sol.name], var_sol.value, atol=atol, rtol=rtol, )
def test_ipopt_solver(model_name): current_dir = pathlib.Path(__file__).parent osil_file = current_dir / 'models' / (model_name + '.osil') pyomo_model = read_pyomo_model(osil_file) problem = problem_from_pyomo_model(pyomo_model) galini = Galini() galini.update_configuration({ 'galini': { 'constraint_violation_tol': 1e-2, }, 'ipopt': { 'ipopt': { 'acceptable_constr_viol_tol': 1e-3 }, }, }) solver = IpoptNLPSolver(galini) solution = solver.solve(problem) assert solution.status.is_success() sol_file = current_dir / 'solutions' / (model_name + '.sol') expected_solution = read_solution(sol_file) expected_objective = expected_solution['objective'] assert solution.objective is not None assert np.isclose(expected_objective, solution.objective.value) if False: expected_variables = expected_solution['variables'] assert len(expected_variables) == len(solution.variables) for variable, expected in zip(solution.variables, expected_variables): assert np.isclose(expected, variable.value)
def test_outer_approximation_cuts(problem): galini = Galini() galini.update_configuration( {'logging': { 'level': 'DEBUG', 'stdout': False, }}) config = galini.get_configuration_group( 'cuts_generator.outer_approximation') generator = OuterApproximationCutsGenerator(galini, config) bounds, mono, cvx = propagate_special_structure(problem) cvx_relaxation = ConvexRelaxation(problem, bounds, mono, cvx) relaxed_problem = RelaxedProblem(cvx_relaxation, problem).relaxed linear_relaxation = LinearRelaxation(relaxed_problem, bounds, mono, cvx) linear_problem = RelaxedProblem(linear_relaxation, relaxed_problem).relaxed solution = Solution(FakeStatus(FakeStatusEnum.Success), [OptimalObjective('_objvar', 8.00)], [ OptimalVariable('x[0]', 4.0), OptimalVariable('x[1]', 2.0), OptimalVariable('_aux_0', 12.0), OptimalVariable('_aux_1', 0.0), OptimalVariable('_objvar', 8.0), OptimalVariable('_aux_bilinear_x[0]_x[0]', 12.0), OptimalVariable('_aux_bilinear_x[1]_x[1]', 0.0), ]) cuts = generator.generate( run_id=0, problem=problem, relaxed_problem=relaxed_problem, linear_problem=linear_problem, mip_solution=solution, tree=None, node=None, ) assert len(cuts) == 2 objective_cuts = [c for c in cuts if c.is_objective] constraint_cuts = [c for c in cuts if not c.is_objective] assert len(objective_cuts) == 0 assert len(constraint_cuts) == 2 _cut_map = [ _check_g0, _check_g1, ] for i, cut in enumerate(constraint_cuts): _cut_map[i](cut)
def test_cut_selection_strategy(problem, cut_selection_strategy, expected_solution): galini = Galini() relaxation = _linear_relaxation(problem) run_id = 'test_run_sdp' galini.update_configuration({ 'branch_and_cut': { 'cuts': { 'use_lp_cut_phase': True, 'use_milp_cut_phase': True, }, }, 'cuts_generator': { 'generators': ['sdp'], 'sdp': { 'domain_eps': 1e-3, 'thres_sdp_viol': -1e-15, 'min_sdp_cuts_per_round': 0, 'max_sdp_cuts_per_round': 5e3, 'dim': 3, 'big_m': 10e3, 'thres_min_opt_sel': 0, 'selection_size': 4, 'cut_sel_strategy': cut_selection_strategy, }, } }) config = galini._config sdp_cuts_gen = SdpCutsGenerator(galini, config.cuts_generator.sdp) algo = BranchAndCutAlgorithm(galini, FakeSolver(), telemetry=None) relaxed_problem = relaxation.relax(problem) algo._cuts_generators_manager.before_start_at_root(run_id, problem, None) nbs_cuts = [] mip_sols = [] if cut_selection_strategy == "RANDOM": np.random.seed(0) for iteration in range(5): set_timelimit(60) mip_solution = algo._mip_solver.solve(relaxed_problem) assert mip_solution.status.is_success() mip_sols.append(mip_solution.objective.value) # Generate new cuts new_cuts = algo._cuts_generators_manager.generate( run_id, problem, None, relaxed_problem, mip_solution, None, None) # Add cuts as constraints nbs_cuts.append(len(list(new_cuts))) for cut in new_cuts: new_cons = Constraint(cut.name, cut.expr, cut.lower_bound, cut.upper_bound) relaxation._relax_constraint(problem, relaxed_problem, new_cons) assert np.allclose(mip_sols, expected_solution)
def galini(): galini_ = Galini() galini_.update_configuration({ 'cuts_generator': { 'generators': ['triangle'], 'triangle': { 'domain_eps': 1e-3, 'thres_triangle_viol': 1e-7, 'max_tri_cuts_per_round': 10e3, 'selection_size': 2, 'min_tri_cuts_per_round': 0, }, } }) return galini_
def derivative_check(model_name, model, order): galini = Galini() galini.update_configuration({ 'galini': { 'constraint_violation_tol': 1e-2, }, 'ipopt': { 'ipopt': { 'acceptable_constr_viol_tol': 1e-3, 'derivative_test': order, 'max_iter': 1, }, 'logging': { 'level': 'J_ITERSUMMARY', } }, 'logging': { 'stdout': True, 'level': 'DEBUG', } }) solver = IpoptNLPSolver(galini) solver = IpoptNLPSolver(galini) # setup Ipopt journalist output_str = io.StringIO() app = IpoptApplication() journalist = app.journalist() journalist.delete_all_journals() journalist.add_journal( PythonJournal('Default', EJournalLevel.J_ITERSUMMARY, output_str)) solver.solve(model, ipopt_application=app) output = output_str.getvalue() output_str.close() check_ok = 'No errors detected by derivative checker.' in output if not check_ok: print(output) assert check_ok
def execute_with_model(self, model, args): galini = Galini() if args.config: galini.update_configuration(args.config) solution = galini.solve( model, args.algorithm, known_optimal_objective=args.known_optimal_objective) status_table = OutputTable('Solution', [{ 'id': 'status', 'name': 'Status', 'type': 't' }]) if solution is None: status_table.add_row({'status': 'unboundedOrInfeasible'}) print_output_table([status_table], args) return status_table.add_row({'status': solution.status.description()}) obj_table = OutputTable('Objectives', [ { 'id': 'name', 'name': 'Objective', 'type': 't' }, { 'id': 'value', 'name': 'Value', 'type': 'f' }, ]) obj_table.add_row({ 'name': 'objective', 'value': solution.objective, }) var_table = OutputTable('Variables', [ { 'id': 'name', 'name': 'Variable', 'type': 't' }, { 'id': 'value', 'name': 'Value', 'type': 'f' }, ]) for var in solution.variables: var_table.add_row({ 'name': var.name, 'value': var.value, }) counter_table = OutputTable('Counters', [ { 'id': 'name', 'name': 'Name', 'type': 't' }, { 'id': 'value', 'name': 'Value', 'type': 'f' }, ]) for counter in galini.telemetry.counters_values(): counter_table.add_row(counter) print_output_table([status_table, obj_table, var_table, counter_table], args)
def test_cut_selection_strategy(problem, cut_selection_strategy, expected_solution): galini = Galini() relaxed_problem, relax_data = _linear_relaxation(problem) galini.update_configuration({ 'cuts_generator': { 'generators': ['sdp'], 'sdp': { 'domain_eps': 1e-3, 'thres_sdp_viol': -1e-15, 'min_sdp_cuts_per_round': 0, 'max_sdp_cuts_per_round': 5e3, 'dim': 3, 'big_m': 10e3, 'thres_min_opt_sel': 0, 'selection_size': 4, 'cut_sel_strategy': cut_selection_strategy, }, } }) storage = FakeStorage(relaxation_data=relax_data) node = FakeNode(storage) galini.timelimit.start_now() config = galini._config sdp_cuts_gen = SdpCutsGenerator(galini, config.cuts_generator.sdp) sdp_cuts_gen.before_start_at_root(problem, relaxed_problem) nbs_cuts = [] mip_sols = [] if cut_selection_strategy == "RANDOM": np.random.seed(0) mip_solver = _instantiate_mip_solver() _update_solver_options(mip_solver) relaxed_problem._cuts = pe.ConstraintList() for iteration in range(5): mip_res = mip_solver.solve(relaxed_problem) mip_solution = load_solution_from_model(mip_res, relaxed_problem) assert mip_solution.status.is_success() mip_sols.append(mip_solution.objective) # Generate new cuts new_cuts = sdp_cuts_gen.generate(problem, relaxed_problem, mip_solution, None, node) # Add cuts as constraints nbs_cuts.append(len(list(new_cuts))) for cut in new_cuts: relaxed_cut = relax_inequality(relaxed_problem, cut, RelaxationSide.BOTH, storage.relaxation_data) relaxed_problem._cuts.add(relaxed_cut) update_relaxation_data(relaxed_problem, storage.relaxation_data) rebuild_relaxations(relaxed_problem, storage.relaxation_data, use_linear_relaxation=True) assert np.allclose(mip_sols, expected_solution)
def test_sdp_cuts_after_branching(problem): galini = Galini() # Test when branched on x0 in [0.5, 1] x0 = problem.x[0] x0.setlb(0.5) relaxed_problem, relax_data = _linear_relaxation(problem) storage = FakeStorage(relaxation_data=relax_data) node = FakeNode(storage) galini.update_configuration({ 'cuts_generator': { 'sdp': { 'domain_eps': 1e-3, 'thres_sdp_viol': -1e-15, 'min_sdp_cuts_per_round': 0, 'max_sdp_cuts_per_round': 5e3, 'dim': 3, 'big_m': 10e3, 'thres_min_opt_sel': 0, 'selection_size': 4, 'cut_sel_strategy': "COMB_ONE_CON" }, } }) galini.timelimit.start_now() config = galini._config sdp_cuts_gen = SdpCutsGenerator(galini, config.cuts_generator.sdp) sdp_cuts_gen.before_start_at_root(problem, relaxed_problem) mip_sols = [] relaxed_problem._cuts = pe.ConstraintList() mip_solver = _instantiate_mip_solver() _update_solver_options(mip_solver) for iteration in range(5): mip_res = mip_solver.solve(relaxed_problem) mip_solution = load_solution_from_model(mip_res, relaxed_problem) assert mip_solution.status.is_success() mip_sols.append(mip_solution.objective) # Generate new cuts new_cuts = sdp_cuts_gen.generate(problem, relaxed_problem, mip_solution, None, node) # Add cuts as constraints for cut in new_cuts: relaxed_cut = relax_inequality(relaxed_problem, cut, RelaxationSide.BOTH, storage.relaxation_data) relaxed_problem._cuts.add(relaxed_cut) update_relaxation_data(relaxed_problem, storage.relaxation_data) rebuild_relaxations(relaxed_problem, storage.relaxation_data, use_linear_relaxation=True) assert np.allclose(mip_sols, [ -187.53571428571428, -178.17645682147835, -175.10310263115286, -175.0895610878696, -175.03389759123812 ])
def test_sdp_cuts_after_branching(problem): galini = Galini() galini.update_configuration({ 'cuts_generator': { 'generators': ['sdp'], 'sdp': { 'selection_size': 2, }, } }) run_id = 'test_run_sdp' relaxation = _linear_relaxation(problem) # Test when branched on x0 in [0.5, 1] x0 = problem.variable_view(problem.variables[0]) x0.set_lower_bound(0.5) galini.update_configuration({ 'branch_and_cut': { 'cuts': { 'use_lp_cut_phase': True, 'use_milp_cut_phase': True, }, }, 'cuts_generator': { 'sdp': { 'domain_eps': 1e-3, 'thres_sdp_viol': -1e-15, 'min_sdp_cuts_per_round': 0, 'max_sdp_cuts_per_round': 5e3, 'dim': 3, 'big_m': 10e3, 'thres_min_opt_sel': 0, 'selection_size': 4, 'cut_sel_strategy': "COMB_ONE_CON" }, } }) config = galini._config sdp_cuts_gen = SdpCutsGenerator(galini, config.cuts_generator.sdp) algo = BranchAndCutAlgorithm(galini, FakeSolver(), telemetry=None) relaxed_problem = relaxation.relax(problem) algo._cuts_generators_manager.before_start_at_root(run_id, problem, None) mip_sols = [] mip_solution = None for iteration in range(5): set_timelimit(60) mip_solution = algo._mip_solver.solve(relaxed_problem) assert mip_solution.status.is_success() mip_sols.append(mip_solution.objective.value) # Generate new cuts new_cuts = algo._cuts_generators_manager.generate( run_id, problem, None, relaxed_problem, mip_solution, None, None) # Add cuts as constraints for cut in new_cuts: new_cons = Constraint(cut.name, cut.expr, cut.lower_bound, cut.upper_bound) relaxation._relax_constraint(problem, relaxed_problem, new_cons) assert np.allclose(mip_sols, [ -187.53571428571428, -178.17645682147835, -175.10310263115286, -175.0895610878696, -175.03389759123812 ]) feas_solution = algo._nlp_solver.solve(relaxed_problem) assert (feas_solution.objective.value >= mip_sols[-1]) sdp_cuts_gen.after_end_at_node(run_id, problem, None, mip_solution) sdp_cuts_gen.after_end_at_root(run_id, problem, None, mip_solution)
def execute_with_problem(self, model, problem, args): galini = Galini() if args.config: galini.update_configuration(args.config) solver_cls = galini.get_solver(args.solver.lower()) if solver_cls is None: available = ', '.join(solvers_reg.keys()) print('Solver {} not available. Available solvers: {}'.format( args.solver, available)) sys.exit(1) apply_logging_config(galini.get_configuration_group('logging')) solver = solver_cls(galini) galini_group = galini.get_configuration_group('galini') timelimit = galini_group.get('timelimit') elapsed_counter = galini.telemetry.create_gauge('elapsed_time', 0.0) set_timelimit(timelimit) start_timelimit() start_time = current_time() solver.before_solve(model, problem) solution = solver.solve( problem, known_optimal_objective=args.known_optimal_objective) elapsed_counter.set_value(seconds_elapsed_since(start_time)) if solution is None: raise RuntimeError('Solver did not return a solution') obj_table = OutputTable('Objectives', [ { 'id': 'name', 'name': 'Objective', 'type': 't' }, { 'id': 'value', 'name': 'Value', 'type': 'f' }, ]) value = solution.objective.value if not problem.objective.original_sense.is_minimization(): if value is not None: value = -value obj_table.add_row({ 'name': solution.objective.name, 'value': value, }) var_table = OutputTable('Variables', [ { 'id': 'name', 'name': 'Variable', 'type': 't' }, { 'id': 'value', 'name': 'Value', 'type': 'f' }, ]) for var in solution.variables: var_table.add_row({ 'name': var.name, 'value': var.value, }) counter_table = OutputTable('Counters', [ { 'id': 'name', 'name': 'Name', 'type': 't' }, { 'id': 'value', 'name': 'Value', 'type': 'f' }, ]) for counter in galini.telemetry.counters_values(): counter_table.add_row(counter) print_output_table([obj_table, var_table, counter_table], args)
def user_config(): user_config_path = Path(__file__).parent / 'user_config.toml' galini = Galini() galini.update_configuration(str(user_config_path)) return galini._config
m.x = pe.Var(bounds=(0, None)) m.y = pe.Var(bounds=(0, None)) m.z = pe.Var(bounds=(0, None)) m.obj = pe.Objective(expr=m.x, sense=pe.maximize) m.lin = pe.Constraint(expr=m.x + m.y + m.z == 1) m.soc = pe.Constraint(expr=m.x**2 + m.y**2 <= m.z**2) m.rot = pe.Constraint(expr=m.x**2 <= m.y * m.z) return m if __name__ == '__main__': from galini.galini import Galini galini = Galini() galini.update_configuration({ 'galini': { 'timelimit': 100, }, 'logging': { 'stdout': True, }, }) model = get_pyomo_model() solution = galini.solve(model) print(solution)