idol
A C++ Framework for Optimization
Loading...
Searching...
No Matches
MibSCallbackI.h
1//
2// Created by henri on 22.10.24.
3//
4
5#ifndef IDOL_MIBSCALLBACKI_H
6#define IDOL_MIBSCALLBACKI_H
7
8#include <BlisHeuristic.h>
9#include <CglCutGenerator.hpp>
10#include "idol/mixed-integer/optimizers/callbacks/Callback.h"
11#include "idol/mixed-integer/modeling/constraints/TempCtr.h"
12#include "impl_MibSFromAPI.h"
13
14namespace idol {
15 class MibSCallbackI;
16}
17
19public:
20 class Heuristic;
21 class CutGenerator;
22private:
23 const impl::MibSFromAPI& m_parent;
24 Heuristic* m_heuristic;
25 CutGenerator* m_cut_generator;
26 bool m_is_heuristic_call = false;
27
28 void call(CallbackEvent t_event) {
29
30 if (m_is_heuristic_call) {
31 for (const auto &callback: m_parent.m_callbacks) {
32 execute(*callback, t_event);
33 }
34 } else {
35 std::cout << "Check if cuts were generated" << std::endl;
36 }
37
38 }
39public:
40 class Heuristic : public ::BlisHeuristic {
41 MibSCallbackI& m_parent;
42 std::list<PrimalPoint> m_solutions;
43 public:
44 explicit Heuristic(MibSCallbackI& t_parent) : m_parent(t_parent) {}
45
46 void submit_heuristic_solution(PrimalPoint t_solution) {
47 m_solutions.emplace_back(std::move(t_solution));
48 }
49
50 bool searchSolution(double &t_objective_value, double *t_new_solution) override {
51
52 m_parent.m_is_heuristic_call = true;
53 m_parent.call(InvalidSolution);
54
55 auto solution = m_solutions.end();
56
57 double current_best = m_parent.best_obj();
58 for (auto it = m_solutions.begin(), end = m_solutions.end(); it != end ; ++it) {
59 if (it->objective_value() < current_best) {
60 solution = it;
61 current_best = it->objective_value();
62 }
63 }
64
65 if (solution == m_solutions.end()) {
66 m_solutions.clear();
67 return false;
68 }
69
70 const auto& osi_solver = *m_parent.m_parent.m_osi_solver;
71 const unsigned int n_vars = osi_solver.getNumCols();
72 for (unsigned int i = 0; i < n_vars; ++i) {
73 t_new_solution[i] = solution->get(m_parent.m_parent.m_model.get_var_by_index(i));
74 }
75 t_objective_value = solution->objective_value();
76
77 m_solutions.clear();
78
79 return true;
80 }
81 };
82
83 class CutGenerator : public ::CglCutGenerator {
84 MibSCallbackI& m_parent;
85 std::list<TempCtr> m_cuts;
86 public:
87 explicit CutGenerator(MibSCallbackI& t_parent) : m_parent(t_parent) {}
88
89 void add_user_cut(TempCtr t_cut) {
90 m_cuts.emplace_back(std::move(t_cut));
91 }
92
93 void generateCuts(const OsiSolverInterface &si, OsiCuts &cs, const CglTreeInfo info) override {
94 m_parent.m_is_heuristic_call = false;
95
96 const double infinity = si.getInfinity();
97 const auto& model = m_parent.original_model();
98
99 for (const auto& cut : m_cuts) {
100
101 const auto& row = cut.lhs();
102 const double rhs = cut.rhs();
103
104 CoinPackedVector lhs;
105 for (const auto& [var, constant] : row) {
106 const unsigned int index = model.get_var_index(var);
107 lhs.insert(index, constant);
108 }
109
110 OsiRowCut osi_cut;
111 osi_cut.setRow(lhs);
112
113 switch (cut.type()) {
114 case CtrType::LessOrEqual:
115 osi_cut.setLb(-infinity);
116 osi_cut.setUb(rhs);
117 break;
118 case CtrType::Equal:
119 osi_cut.setLb(rhs);
120 osi_cut.setUb(rhs);
121 break;
122 case CtrType::GreaterOrEqual:
123 osi_cut.setLb(rhs);
124 osi_cut.setUb(infinity);
125 break;
126 }
127
128 cs.insert(osi_cut);
129 }
130
131 m_cuts.clear();
132
133 }
134
135 [[nodiscard]] CglCutGenerator *clone() const override {
136 return new CutGenerator(*this);
137 }
138 };
139
140 explicit MibSCallbackI(const impl::MibSFromAPI& t_parent) : m_parent(t_parent), m_heuristic(new Heuristic(*this)), m_cut_generator(new CutGenerator(*this)) {
141 m_heuristic->setHeurCallFrequency(1);
142 m_heuristic->setStrategy(BlisHeurStrategyPeriodic);
143 }
144
145 BlisHeuristic& heuristic() { return *m_heuristic; }
146
147 [[nodiscard]] const BlisHeuristic& heuristic() const { return *m_heuristic; }
148
149 CglCutGenerator& cut_generator() { return *m_cut_generator; }
150
151 [[nodiscard]] const CglCutGenerator& cut_generator() const { return *m_cut_generator; }
152protected:
153 [[nodiscard]] const Model &original_model() const override {
154 return m_parent.m_model;
155 }
156
157 void add_user_cut(const TempCtr &t_cut) override {
158 m_cut_generator->add_user_cut(t_cut);
159 }
160
161 void add_lazy_cut(const TempCtr &t_cut) override {
162 throw Exception("Not implemented.");
163 }
164
165 void submit_heuristic_solution(PrimalPoint t_solution) override {
166 m_heuristic->submit_heuristic_solution(std::move(t_solution));
167 }
168
169 [[nodiscard]] PrimalPoint primal_solution() const override {
170
171 auto& osi_solver = *m_parent.m_osi_solver;
172 const auto* solution = osi_solver.getColSolution();
173 const unsigned int n_vars = osi_solver.getNumCols();
174
175 PrimalPoint result;
176 result.set_reason(NotSpecified);
177
178 if (osi_solver.isProvenOptimal()) {
179
180 result.set_status(Optimal);
181
182 } else {
183
184 if (osi_solver.isProvenPrimalInfeasible()) {
185 result.set_status(Infeasible);
186 return result;
187 }
188
189 if (osi_solver.isProvenDualInfeasible()) {
190 result.set_status(Unbounded);
191 return result;
192 }
193
194 result.set_status(Fail);
195 return result;
196
197 }
198
199 for (unsigned int i = 0; i < n_vars; ++i) {
200 const auto& var = m_parent.m_model.get_var_by_index(i);
201 result.set(var, solution[i]);
202 }
203
204 result.set_objective_value(m_parent.m_model.get_obj_expr().affine().constant() + osi_solver.getObjValue());
205
206 return result;
207 }
208
209 [[nodiscard]] const Timer &time() const override {
210 return m_parent.m_model.optimizer().time();
211 }
212
213 [[nodiscard]] double best_obj() const override {
214 return m_parent.get_best_obj();
215 }
216
217 [[nodiscard]] double best_bound() const override {
218 return m_parent.get_best_bound();
219 }
220
221 void terminate() override {
222 throw Exception("Not available.");
223 }
224};
225
226#endif //IDOL_MIBSCALLBACKI_H