5#ifndef IDOL_IMPL_PSEUDOCOST_H
6#define IDOL_IMPL_PSEUDOCOST_H
9#include "VariableBranching.h"
10#include "NodeScoreFunction.h"
12namespace idol::BranchingRules {
13 template<
class NodeInfoT>
class PseudoCost;
16template<
class NodeInfoT>
19 std::unique_ptr<NodeScoreFunction> m_scoring_function;
21 struct PseudoCostData {
22 double objective_gains_by_upper_boundings = 0;
23 double objective_gains_by_lower_boundings = 0;
24 unsigned int n_entries_for_upper_bounds = 0;
25 unsigned int n_entries_for_lower_bounds = 0;
27 PseudoCostData& operator+=(
const PseudoCostData& t_rhs);
30 Map<Var, PseudoCostData> m_pseudo_cost_data;
32 double compute_upper_bounding_score(
const Var& t_var,
const PseudoCostData& t_data,
const Node<NodeInfoT>& t_node)
const;
34 double compute_lower_bounding_score(
const Var& t_var,
const PseudoCostData& t_data,
const Node<NodeInfoT>& t_node)
const;
36 double compute_average_lower_bounding_score(
const Node<NodeInfoT>& t_node)
const;
38 double compute_average_upper_bounding_score(
const Node<NodeInfoT>& t_node)
const;
42 std::list<std::pair<Var, double>> scoring_function(
const std::list<Var> &t_var,
const Node<NodeInfoT> &t_node)
override;
48template<
class NodeInfoT>
53 objective_gains_by_upper_boundings += t_rhs.objective_gains_by_upper_boundings;
54 objective_gains_by_lower_boundings += t_rhs.objective_gains_by_lower_boundings;
55 n_entries_for_upper_bounds += t_rhs.n_entries_for_upper_bounds;
56 n_entries_for_lower_bounds += t_rhs.n_entries_for_lower_bounds;
61template<
class NodeInfoT>
66 if (t_node.level() == 0) {
71 const auto& parent = t_node.parent();
72 const auto& parent_solution = parent.info().primal_solution();
73 const double parent_objective_value = parent_solution.objective_value();
76 for (
const auto &branching_decision : t_node.info().variable_branching_decisions()) {
78 const auto &var = branching_decision.variable;
79 const double bound = branching_decision.bound;
80 const bool is_upper_bound = branching_decision.type == LessOrEqual;
81 const double node_objective_value = t_node.info().objective_value();
83 const double parent_var_primal_value = parent_solution.get(var);
85 double objective_gain_per_unit_change = 0;
86 if (!equals(bound, parent_var_primal_value, 1e-5)) {
87 objective_gain_per_unit_change =
88 (node_objective_value - parent_objective_value) / std::abs(bound - parent_var_primal_value);
94 data.n_entries_for_upper_bounds = 1;
95 data.objective_gains_by_upper_boundings = objective_gain_per_unit_change;
97 data.n_entries_for_lower_bounds = 1;
98 data.objective_gains_by_lower_boundings = objective_gain_per_unit_change;
101 auto [it, success] = m_pseudo_cost_data.emplace(var, data);
111template<
class NodeInfoT>
114 : VariableBranching<NodeInfoT>(t_parent, std::move(t_branching_candidates)),
115 m_scoring_function(new NodeScoreFunctions::Linear())
118template<
class NodeInfoT>
119std::list<std::pair<idol::Var, double>>
121 const Node<NodeInfoT> &t_node) {
123 std::list<std::pair<idol::Var, double>> result;
125 const double average_upper_bound_score = compute_average_upper_bounding_score(t_node);
126 const double average_lower_bound_score = compute_average_lower_bounding_score(t_node);
127 const auto end = m_pseudo_cost_data.end();
129 for (
const auto& var : t_variables) {
131 const auto it = m_pseudo_cost_data.find(var);
133 const auto upper_bounding_score = it != end && it->second.n_entries_for_upper_bounds > 0 ? compute_upper_bounding_score(it->first, it->second, t_node) : average_upper_bound_score;
134 const auto lower_bounding_score = it != end && it->second.n_entries_for_lower_bounds > 0 ? compute_lower_bounding_score(it->first, it->second, t_node) : average_lower_bound_score;
136 const double pseudo_cost = (*m_scoring_function)(upper_bounding_score,lower_bounding_score);
138 result.emplace_back(var, pseudo_cost);
145template<
class NodeInfoT>
147 const PseudoCostData& t_data,
150 const double sum_of_objective_gains_per_unit_change = t_data.objective_gains_by_lower_boundings;
151 const unsigned int n_entries = t_data.n_entries_for_lower_bounds;
152 const double var_value = t_node.info().primal_solution().get(t_var);
154 return (std::ceil(var_value) - var_value) * sum_of_objective_gains_per_unit_change / (double) n_entries;
157template<
class NodeInfoT>
159 const PseudoCostData& t_data,
162 const double sum_of_objective_gains_per_unit_change = t_data.objective_gains_by_upper_boundings;
163 const unsigned int n_entries = t_data.n_entries_for_upper_bounds;
164 const double var_value = t_node.info().primal_solution().get(t_var);
166 return (var_value - std::floor(var_value)) * sum_of_objective_gains_per_unit_change / (double) n_entries;
169template<
class NodeInfoT>
176 for (
const auto& [var, data] : m_pseudo_cost_data) {
178 if (data.n_entries_for_upper_bounds == 0) {
182 sum += compute_upper_bounding_score(var, data, t_node);
190 return sum / (double) n;
193template<
class NodeInfoT>
200 for (
const auto& [var, data] : m_pseudo_cost_data) {
202 if (data.n_entries_for_lower_bounds == 0) {
206 sum += compute_lower_bounding_score(var, data, t_node);
214 return sum / (double) n;