14#ifndef OR_TOOLS_ORTOOLS_SET_COVER_SET_COVER_CFT_H
15#define OR_TOOLS_ORTOOLS_SET_COVER_SET_COVER_CFT_H
17#include <absl/algorithm/container.h>
18#include <absl/base/internal/pretty_function.h>
19#include <absl/status/status.h>
88 Solution(
const SubModel& model,
const std::vector<SubsetIndex>& core_subsets);
90 double cost()
const {
return cost_; }
91 const std::vector<FullSubsetIndex>&
subsets()
const {
return subsets_; }
93 subsets_.push_back(subset);
96 bool Empty()
const {
return subsets_.empty(); }
103 Cost cost_ = std::numeric_limits<Cost>::max();
104 std::vector<FullSubsetIndex> subsets_;
112 DCHECK_GE(numerator, -1e-6);
113 if (numerator < 1e-6) {
116 return numerator / denominator;
126 template <
typename SubModelT>
129 multipliers_(model.num_elements(), .0),
130 reduced_costs_(model.subset_costs().
begin(),
131 model.subset_costs().
end()) {}
138 template <
typename SubModelT,
typename Op>
139 void DualUpdate(
const SubModelT& model, Op multiplier_operator) {
140 multipliers_.
resize(model.num_elements());
141 reduced_costs_.resize(model.num_subsets());
144 for (ElementIndex i : model.ElementRange()) {
145 multiplier_operator(i, multipliers_[i]);
146 lower_bound_ += multipliers_[i];
147 DCHECK(std::isfinite(multipliers_[i]));
148 DCHECK_GE(multipliers_[i], .0);
150 lower_bound_ += ComputeReducedCosts(model, multipliers_, reduced_costs_);
155 template <
typename ModelT>
156 static Cost ComputeReducedCosts(
const ModelT& model,
160 Cost negative_sum = .0;
161 for (SubsetIndex j : model.SubsetRange()) {
163 for (ElementIndex i : model.columns()[j]) {
234 bool force =
false)
override;
243 std::vector<SubsetIndex> lagrangian_solution_;
250 BaseInt unfixed_run_extension_;
255 Cost last_min_lb_seen_;
256 Cost last_max_lb_seen_;
257 BaseInt step_size_update_countdown_;
258 BaseInt step_size_update_period_;
269 Cost cost_cutoff = std::numeric_limits<BaseInt>::max());
278 std::vector<SubsetIndex>& sol_subsets);
291 bool ExitCondition(
const SubgradientContext& context)
override {
293 context.best_solution.cost() - context.model.fixed_cost();
294 Cost lower_bound = context.best_lower_bound;
295 return upper_bound - .999 < lower_bound || --countdown_ <= 0;
302 bool force =
false)
override {
312 const Solution& init_solution = {});
319 const Solution& init_solution = {});
331class FullToCoreModel :
public SubModel {
333 struct UpdateTrigger {
355 class ColumnSelector {
357 const std::vector<FullSubsetIndex>& ComputeNewSelection(
359 const std::vector<FullSubsetIndex>& forced_columns,
370 std::vector<SubsetIndex> candidates_;
371 std::vector<SubsetIndex>::const_iterator first_unselected_;
375 std::vector<FullSubsetIndex> selection_;
387 const Solution& best_solution,
bool force)
override;
396 decltype(
auto)
IsFocusCol(FullSubsetIndex j) {
397 return is_focus_col_[
static_cast<SubsetIndex
>(j)];
399 decltype(
auto)
IsFocusRow(FullElementIndex i) {
400 return is_focus_row_[
static_cast<ElementIndex
>(i)];
403 Cost core_lower_bound,
Cost core_upper_bound);
413 full_model_->num_subsets(),
414 full_model_->num_elements());
423 const std::vector<FullSubsetIndex>& forced_columns = {});
426 const Model* full_model_;
444 Cost prev_best_lower_bound_;
452 ColumnSelector col_selector_;
void ComputeMultipliersDelta(const SubgradientContext &context, ElementCostVector &delta_mults) override
void RunHeuristic(const SubgradientContext &context, Solution &solution) override
bool ExitCondition(const SubgradientContext &context) override
bool UpdateCoreModel(SubgradientContext context, CoreModel &core_model, bool force=false) override
static constexpr Cost kTol
BoundCBs(const SubModel &model)
void DualUpdate(const SubModelT &model, Op multiplier_operator)
const SubsetCostVector & reduced_costs() const
const ElementCostVector & multipliers() const
DualState(const DualState &)=default
void ComputeAndSetFocus(Cost best_lower_bound, const Solution &best_solution)
FullToCoreModel()=default
std::vector< FullSubsetIndex > SelectNewCoreColumns(const std::vector< FullSubsetIndex > &forced_columns={})
bool UpdateCore(Cost best_lower_bound, const ElementCostVector &best_multipliers, const Solution &best_solution, bool force) override
void ResetPricingPeriod()
const DualState & best_dual_state() const
FilterModelView FixingFullModelView() const
Access the full model filtered by the current columns fixed.
void UpdatePricingPeriod(const DualState &full_dual_state, Cost core_lower_bound, Cost core_upper_bound)
void ResetColumnFixing(const std::vector< FullSubsetIndex > &columns_to_fix, const DualState &state) override
Cost FixMoreColumns(const std::vector< SubsetIndex > &columns_to_fix) override
Cost UpdateMultipliers(const ElementCostVector &core_multipliers)
bool FullToSubModelInvariantCheck()
decltype(auto) IsFocusCol(FullSubsetIndex j)
StrongModelView StrongTypedFullModelView() const
Access the full model with the strongly typed view.
decltype(auto) IsFocusRow(FullElementIndex i)
bool IsTimeToUpdate(Cost best_lower_bound, bool force)
bool ExitCondition(const SubgradientContext &context) override
void RunHeuristic(const SubgradientContext &context, Solution &solution) override
void ComputeMultipliersDelta(const SubgradientContext &context, ElementCostVector &delta_mults) override
bool UpdateCoreModel(SubgradientContext context, CoreModel &core_model, bool force=false) override
void set_step_size(Cost step_size)
void AddSubset(FullSubsetIndex subset, Cost cost)
const std::vector< FullSubsetIndex > & subsets() const
virtual void ComputeMultipliersDelta(const SubgradientContext &, ElementCostVector &delta_mults)=0
virtual void RunHeuristic(const SubgradientContext &, Solution &)=0
virtual bool ExitCondition(const SubgradientContext &)=0
virtual bool UpdateCoreModel(SubgradientContext context, CoreModel &core_model, bool force=false)=0
virtual ~SubgradientCBs()=default
void resize(size_type new_size)
PrimalDualState RunThreePhase(SubModel &model, const Solution &init_solution)
PrimalDualState RunCftHeuristic(SubModel &model, const Solution &init_solution)
Cost CoverGreedly(const SubModel &model, const DualState &dual_state, Cost cost_cutoff, BaseInt stop_size, std::vector< SubsetIndex > &sol_subsets)
Cost DivideIfGE0(Cost numerator, Cost denominator)
static constexpr BaseInt kMinCov
Coverage counter to decide the number of columns to keep in the core model.
Solution RunMultiplierBasedGreedy(const SubModel &model, const DualState &dual_state, Cost cost_cutoff)
void SubgradientOptimization(SubModel &model, SubgradientCBs &cbs, PrimalDualState &best_state)
util_intops::StrongVector< SubsetIndex, Cost > SubsetCostVector
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
util_intops::StrongVector< ElementIndex, Cost > ElementCostVector
ClosedInterval::Iterator end(ClosedInterval interval)
util_intops::StrongVector< ElementIndex, BaseInt > ElementToIntVector
util_intops::StrongVector< SubsetIndex, bool > SubsetBoolVector
util_intops::StrongVector< ElementIndex, bool > ElementBoolVector
double Cost
Basic non-strict type for cost. The speed penalty for using double is ~2%.
ClosedInterval::Iterator begin(ClosedInterval interval)
Utility aggregate to store and pass around both primal and dual states.
const ElementCostVector & best_multipliers
const Cost & best_lower_bound
Avoid copying unused reduced cost during subgradient.
const Solution & best_solution
const DualState & current_dual_state
const ElementCostVector & subgradient