Skip to content

Commit

Permalink
add logs for CCG
Browse files Browse the repository at this point in the history
  • Loading branch information
hlefebvr committed Feb 20, 2025
1 parent 71afb17 commit 4411753
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ class idol::Optimizers::Robust::ColumnAndConstraintGeneration : public Algorithm
std::unique_ptr<OptimizerFactory> m_initial_scenario_by_maximization;

// Feasibility Separation
const bool m_with_feasibility_separation_loop_reset = false;
std::vector<std::unique_ptr<OptimizerFactory>> m_optimizer_feasibility_separation;
unsigned int m_index_feasibility_separation = 0;

// Optimality Separation
const bool m_with_optimality_separation_loop_reset = false;
std::vector<std::unique_ptr<OptimizerFactory>> m_optimizer_optimality_separation;
unsigned int m_index_optimality_separation = 0;
public:
Expand Down Expand Up @@ -115,15 +117,21 @@ class idol::Optimizers::Robust::ColumnAndConstraintGeneration : public Algorithm

void check_termination_criteria();

void log_iteration();
void log_banner();
void log_iteration(bool t_is_feasibility_separation,
const std::string& t_optimizer_name,
const SolutionStatus& t_status,
const SolutionReason& t_reason,
bool t_separation_outcome);
void log_iteration_separator();

void solve_adversarial_problem();
unsigned int solve_feasibility_adversarial_problem();
unsigned int solve_optimality_adversarial_problem();
unsigned int solve_optimality_adversarial_problem(const Point<Var>& t_upper_level_solution);
unsigned int solve_optimality_adversarial_problem(const idol::Point<idol::Var> &t_upper_level_solution, unsigned int t_coupling_constraint_index);

bool is_adjustable_robust_problem() const;
[[nodiscard]] bool is_adjustable_robust_problem() const;
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ idol::Optimizers::Bilevel::StrongDuality::StrongDuality(const Model& t_parent,
}

std::string idol::Optimizers::Bilevel::StrongDuality::name() const {
return "strong-duality reformulation";
return "strong-duality";
}

double idol::Optimizers::Bilevel::StrongDuality::get_var_primal(const idol::Var &t_var) const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <idol/bilevel/optimizers/BilevelOptimizerInterface.h>
#include <idol/bilevel/optimizers/PessimisticAsOptimistic/PessimisticAsOptimistic.h>
#include <idol/bilevel/modeling/write_to_file.h>
#include "idol/general/optimizers/logs.h"

idol::Optimizers::Robust::ColumnAndConstraintGeneration::ColumnAndConstraintGeneration(const idol::Model &t_parent,
const idol::Robust::Description &t_robust_description,
Expand Down Expand Up @@ -111,6 +112,8 @@ void idol::Optimizers::Robust::ColumnAndConstraintGeneration::hook_before_optimi
m_index_feasibility_separation = 0;
m_index_optimality_separation = 0;

log_banner();

}

void idol::Optimizers::Robust::ColumnAndConstraintGeneration::hook_optimize() {
Expand All @@ -129,9 +132,9 @@ void idol::Optimizers::Robust::ColumnAndConstraintGeneration::hook_optimize() {

solve_adversarial_problem();

check_termination_criteria();
log_iteration_separator();

log_iteration();
check_termination_criteria();

if (is_terminated()) {
break;
Expand Down Expand Up @@ -205,10 +208,6 @@ void idol::Optimizers::Robust::ColumnAndConstraintGeneration::add_initial_scenar
add_initial_scenario_by_min_or_max(*m_initial_scenario_by_maximization, -1.);
}

if (get_param_logs()) {
std::cout << "Initial scenario pool contains " << m_formulation->n_added_scenarios() << " scenarios." << std::endl;
}

}

void idol::Optimizers::Robust::ColumnAndConstraintGeneration::add_initial_scenario_by_min_or_max(const OptimizerFactory& t_optimizer, double t_coefficient) {
Expand Down Expand Up @@ -278,41 +277,123 @@ void idol::Optimizers::Robust::ColumnAndConstraintGeneration::check_termination_

}

void idol::Optimizers::Robust::ColumnAndConstraintGeneration::log_iteration() {
void idol::Optimizers::Robust::ColumnAndConstraintGeneration::log_banner() {

if (!get_param_logs()) {
return;
}

std::cout << time().count() << "s\t"
<< m_n_iterations << "\t"
<< get_best_bound() << "\t"
<< get_best_obj() << "\t"
<< get_relative_gap() << "\t"
<< get_absolute_gap() << std::endl;
center(std::cout, "", 182, '*') << std::endl;
center(std::cout, " Column-and-constraint Generation ", 182) << std::endl;
center(std::cout, "", 182, '*') << std::endl;

std::cout << std::setw(12) << "Time (s)" << "\t"
<< std::setw(5) << "# Iter." << "\t"
<< std::setw(5) << "# Scen." << "\t"
<< std::setw(12) << "LB" << "\t"
<< std::setw(12) << "UB" << "\t"
<< std::setw(12) << "Gap (%)" << "\t"
<< std::setw(12) << "Abs. Gap" << "\t"
<< std::setw(35) << "Master" << "\t"
<< std::setw(35) << "Separation" << "\t"
<< std::setw(8) << "Iter. status"
<< std::endl;
log_iteration_separator();
}

void idol::Optimizers::Robust::ColumnAndConstraintGeneration::log_iteration(
bool t_is_feasibility_separation,
const std::string& t_optimizer_name,
const SolutionStatus& t_status,
const SolutionReason& t_reason,
bool t_separation_outcome
) {

if (!get_param_logs()) {
return;
}

const auto& master = m_formulation->master();
std::stringstream master_status;
master_status << "<" << master.optimizer().name() << "," << master.get_status() << "," << master.get_reason() << ">";

std::stringstream separation_status;
separation_status << "<" << t_optimizer_name << "," << t_status << "," << t_reason << ">";

std::stringstream separation_outcome;
if (t_is_feasibility_separation) {
separation_outcome << "feasibility=";
if (t_separation_outcome) {
separation_outcome << (t_status == Optimal ? "yes" : "?");
} else {
separation_outcome << "no";
}
} else {
separation_outcome << "optimality=";
if (t_separation_outcome) {
separation_outcome << "yes";
} else {
separation_outcome << (t_status == Optimal ? "no" : "?");
}
}

std::cout << std::setw(12) << time().count() << "s\t"
<< std::setw(5) << m_n_iterations << "\t"
<< std::setw(5) << m_formulation->n_added_scenarios() << "\t"
<< std::setw(12) << get_best_bound() << "\t"
<< std::setw(12) << get_best_obj() << "\t"
<< std::setw(12) << get_relative_gap() << "\t"
<< std::setw(12) << get_absolute_gap() << "\t"
<< std::setw(35) << master_status.str() << "\t"
<< std::setw(35) << separation_status.str() << "\t"
<< std::setw(8) << separation_outcome.str()
<< std::endl;

}

void idol::Optimizers::Robust::ColumnAndConstraintGeneration::solve_adversarial_problem() {

if (m_with_feasibility_separation_loop_reset) {
m_index_feasibility_separation = 0;
}

if (m_with_optimality_separation_loop_reset) {
m_index_optimality_separation = 0;
}

const unsigned int n_feasibility_separation_optimizers = m_optimizer_feasibility_separation.size();
const unsigned int n_optimality_separation_optimizers = m_optimizer_optimality_separation.size();

unsigned int n_added_scenario;
for (;;) {

const bool is_last_optimizer = m_index_feasibility_separation + 1 == n_feasibility_separation_optimizers;
n_added_scenario = solve_feasibility_adversarial_problem();

do {
const unsigned int n_added_scenario = solve_feasibility_adversarial_problem();
if (n_added_scenario > 0) {
if (n_added_scenario > 0 || is_terminated()) {
return;
}
} while (m_index_feasibility_separation + 1 != n_feasibility_separation_optimizers);

if (is_last_optimizer) {
break;
}

const unsigned int n_optimality_separation_optimizers = m_optimizer_optimality_separation.size();
}

for (;;) {

const bool is_last_optimizer = m_index_optimality_separation + 1 == n_optimality_separation_optimizers;
n_added_scenario = solve_optimality_adversarial_problem();

do {
const unsigned int n_added_scenario = solve_optimality_adversarial_problem();
if (n_added_scenario > 0) {
if (n_added_scenario > 0 || is_terminated()) {
return;
}
} while (m_index_optimality_separation + 1 != n_optimality_separation_optimizers);

if (is_last_optimizer) {
break;
}

}

}

Expand All @@ -332,7 +413,6 @@ unsigned int idol::Optimizers::Robust::ColumnAndConstraintGeneration::solve_feas
high_point_relaxation.optimizer().set_param_time_limit(get_remaining_time());

// Solve adversarial problem
std::cout << "Solving feasibility adversarial problem with " << high_point_relaxation.optimizer().name() << std::endl;
high_point_relaxation.optimize();

// Analyze results
Expand All @@ -347,20 +427,23 @@ unsigned int idol::Optimizers::Robust::ColumnAndConstraintGeneration::solve_feas
set_status(Fail);
set_reason(high_point_relaxation.get_reason());
terminate();
return 1;
return 0;
}
}

if (is_last_optimizer && status != Optimal) { // if the last optimizer is not reporting optimal, it's a fail
set_status(Fail);
set_reason(high_point_relaxation.get_reason());
terminate();
return 1;
return 0;
}

const double objective_value = -high_point_relaxation.get_best_obj();
const bool is_feasible = objective_value <= Tolerance::Feasibility;

log_iteration(true, high_point_relaxation.optimizer().name(), status, high_point_relaxation.get_reason(), is_feasible);

if (objective_value >= Tolerance::Feasibility) {
if (!is_feasible) {
const auto scenario = save_primal(m_robust_description.uncertainty_set(), high_point_relaxation);
m_formulation->add_scenario_to_master(scenario);
return 1;
Expand Down Expand Up @@ -418,7 +501,6 @@ idol::Optimizers::Robust::ColumnAndConstraintGeneration::solve_optimality_advers
high_point_relaxation.optimizer().set_param_time_limit(get_remaining_time());

// Solve adversarial problem
std::cout << "Solving optimality adversarial problem with " << high_point_relaxation.optimizer().name() << std::endl;
high_point_relaxation.optimize();

// Analyze results
Expand Down Expand Up @@ -448,7 +530,7 @@ idol::Optimizers::Robust::ColumnAndConstraintGeneration::solve_optimality_advers
if (t_coupling_constraint_index == 0) {
const double LB = m_formulation->master().get_best_obj();
const double UB = -high_point_relaxation.get_best_obj();
add_scenario = absolute_gap(LB, UB) > Tolerance::MIPAbsoluteGap || relative_gap(LB, UB) > Tolerance::MIPRelativeGap;
add_scenario = UB > LB && (absolute_gap(LB, UB) > Tolerance::MIPAbsoluteGap || relative_gap(LB, UB) > Tolerance::MIPRelativeGap);
if (status == Optimal) {
set_best_obj(std::min(get_best_obj(), -high_point_relaxation.get_best_obj()));
}
Expand All @@ -457,6 +539,8 @@ idol::Optimizers::Robust::ColumnAndConstraintGeneration::solve_optimality_advers
throw Exception("Coupling constraints not yet implemented");
}

log_iteration(false, high_point_relaxation.optimizer().name(), status, high_point_relaxation.get_reason(), add_scenario);

if (add_scenario) {
const auto scenario = save_primal(m_robust_description.uncertainty_set(), high_point_relaxation);
m_formulation->add_scenario_to_master(scenario);
Expand All @@ -469,3 +553,13 @@ idol::Optimizers::Robust::ColumnAndConstraintGeneration::solve_optimality_advers

return 0;
}

void idol::Optimizers::Robust::ColumnAndConstraintGeneration::log_iteration_separator() {

if (!get_param_logs()) {
return;
}

center(std::cout, "-", 182, '-') << std::endl;

}

0 comments on commit 4411753

Please sign in to comment.