Loading...
Searching...
No Matches
OsiIdolCglSolverInterface.h
1//
2// Created by Henri on 26/03/2026.
3//
4
5#ifndef IDOL_OSIIDOLCGLSOLVERINTERFACE_H
6#define IDOL_OSIIDOLCGLSOLVERINTERFACE_H
7
8#ifdef IDOL_USE_CGL
9#include <OsiSolverInterface.hpp>
10#include <OsiCuts.hpp>
11
12#define THROW_CALLED { throw Exception("Function " + std::string(__FUNCTION__) + " was called by Cgl."); }
13
14template<class NodeInfoT>
15class idol::CglCutCallback<NodeInfoT>::Strategy::OsiIdolCglSolverInterface : public OsiSolverInterface {
16 Strategy& m_parent;
17 std::unique_ptr<CoinPackedMatrix> m_matrix;
18 std::vector<double> m_col_lower;
19 std::vector<double> m_col_upper;
20 std::vector<char> m_row_sense;
21 std::vector<double> m_rhs;
22 std::vector<double> m_row_lower;
23 std::vector<double> m_row_upper;
24 std::vector<double> m_current_solution;
25 std::vector<double> m_row_activity;
26public:
27 OsiIdolCglSolverInterface(Strategy& parent) : m_parent(parent) {
28
29 }
30
31 void update_current_solution() {
32 m_row_activity.clear();
33 const auto& model = m_parent.original_model();
34 const unsigned int n_cols = model.vars().size();
35 m_current_solution = std::vector<double>(n_cols);
36 const auto& current_solution = m_parent.node().info().primal_solution();
37 for (unsigned int index = 0 ; index < n_cols ; ++index) {
38 const auto& var = model.get_var_by_index(index);
39 m_current_solution[index] = current_solution.get(var);
40 }
41 }
42
43 void initialSolve() override THROW_CALLED
44 void resolve() override THROW_CALLED
45 void branchAndBound() override THROW_CALLED
46 bool isAbandoned() const override THROW_CALLED
47 bool isProvenOptimal() const override THROW_CALLED
48 bool isProvenPrimalInfeasible() const override THROW_CALLED
49 bool isProvenDualInfeasible() const override THROW_CALLED
50 CoinWarmStart* getEmptyWarmStart() const override THROW_CALLED
51 CoinWarmStart* getWarmStart() const override THROW_CALLED
52 bool setWarmStart(const CoinWarmStart* warmstart) override THROW_CALLED
53 int getNumCols() const override { return m_parent.original_model().vars().size(); }
54 int getNumRows() const override { return m_parent.original_model().ctrs().size(); }
55 CoinBigIndex getNumElements() const override THROW_CALLED
56
57 const double* getColLower() const override {
58
59 if (m_col_lower.empty()) {
60 auto& me = const_cast<OsiIdolCglSolverInterface&>(*this);
61 const auto& model = m_parent.original_model();
62 const auto n_cols = model.vars().size();
63 me.m_col_lower = std::vector<double>(n_cols);
64 for (unsigned int index = 0 ; index < n_cols ; ++index) {
65 const auto& var = model.get_var_by_index(index);
66 me.m_col_lower[index] = model.get_var_lb(var);
67 }
68 }
69
70 assert(m_col_lower.size() == m_parent.original_model().vars().size());
71 return m_col_lower.data();
72 }
73
74 const double* getColUpper() const override {
75
76 if (m_col_upper.empty()) {
77 auto& me = const_cast<OsiIdolCglSolverInterface&>(*this);
78 const auto& model = m_parent.original_model();
79 const auto n_cols = model.vars().size();
80 me.m_col_upper = std::vector<double>(n_cols);
81 for (unsigned int index = 0 ; index < n_cols; ++index) {
82 const auto& var = model.get_var_by_index(index);
83 me.m_col_upper[index] = model.get_var_ub(var);
84 }
85 }
86
87 assert(m_col_upper.size() == m_parent.original_model().vars().size());
88 return m_col_upper.data();
89 }
90
91 const char* getRowSense() const override {
92
93 if (m_row_sense.empty()) {
94 auto& me = const_cast<OsiIdolCglSolverInterface&>(*this);
95 const auto& model = m_parent.original_model();
96 const auto n_rows = model.ctrs().size();
97 me.m_row_sense = std::vector<char>(n_rows);
98 for (unsigned int index = 0 ; index < n_rows ; ++index) {
99 const auto ctr = model.get_ctr_by_index(index);
100 const auto type = model.get_ctr_type(ctr);
101 switch (type) {
102 case LessOrEqual:
103 me.m_row_sense[index] = 'L';
104 break;
105 case GreaterOrEqual:
106 me.m_row_sense[index] = 'G';
107 break;
108 case Equal:
109 me.m_row_sense[index] = 'E';
110 break;
111 default:
112 throw Exception("Constraint type out of bounds.");
113 }
114 }
115 }
116
117 assert(m_row_sense.size() == m_parent.original_model().ctrs().size());
118 return m_row_sense.data();
119 }
120
121 const double* getRightHandSide() const override {
122
123 if (m_rhs.empty()) {
124 auto& me = const_cast<OsiIdolCglSolverInterface&>(*this);
125 const auto& model = m_parent.original_model();
126 const auto n_rows = model.ctrs().size();
127 me.m_rhs = std::vector<double>(n_rows);
128 for (unsigned int index = 0 ; index < n_rows ; ++index) {
129 const auto ctr = model.get_ctr_by_index(index);
130 me.m_rhs[index] = model.get_ctr_rhs(ctr);
131 }
132 }
133
134 assert(m_rhs.size() == m_parent.original_model().ctrs().size());
135 return m_rhs.data();
136 }
137
138 const double* getRowRange() const override THROW_CALLED
139
140 const double* getRowLower() const override {
141
142 if (m_row_lower.empty()) {
143 auto& me = const_cast<OsiIdolCglSolverInterface&>(*this);
144 const auto& model = m_parent.original_model();
145 const unsigned int n_rows = model.ctrs().size();
146 me.m_row_lower = std::vector<double>(n_rows);
147 for (int i = 0 ; i < n_rows ; ++i) {
148 const auto ctr = model.get_ctr_by_index(i);
149 const auto rhs = model.get_ctr_rhs(ctr);
150 const auto type = model.get_ctr_type(ctr);
151 switch (type) {
152 case LessOrEqual:
153 me.m_row_lower[i] = -Inf;
154 break;
155 case GreaterOrEqual:
156 me.m_row_lower[i] = rhs;
157 break;
158 case Equal:
159 me.m_row_lower[i] = rhs;
160 break;
161 default:
162 throw Exception("Constraint type out of bounds.");
163 }
164 }
165 }
166
167 assert(m_row_lower.size() == m_parent.original_model().ctrs().size());
168 return m_row_lower.data();
169 }
170
171 const double* getRowUpper() const override {
172
173 if (m_row_upper.empty()) {
174 auto& me = const_cast<OsiIdolCglSolverInterface&>(*this);
175 const auto& model = m_parent.original_model();
176 const unsigned int n_rows = model.ctrs().size();
177 me.m_row_upper = std::vector<double>(n_rows);
178 for (int i = 0 ; i < n_rows ; ++i) {
179 const auto ctr = model.get_ctr_by_index(i);
180 const auto rhs = model.get_ctr_rhs(ctr);
181 const auto type = model.get_ctr_type(ctr);
182 switch (type) {
183 case idol::LessOrEqual:
184 me.m_row_upper[i] = rhs;
185 break;
186 case idol::GreaterOrEqual:
187 me.m_row_upper[i] = Inf;
188 break;
189 case idol::Equal:
190 me.m_row_upper[i] = rhs;
191 break;
192 default:
193 throw Exception("Constraint type out of bounds.");
194 }
195 }
196 }
197
198 assert(m_row_upper.size() == m_parent.original_model().ctrs().size());
199 return m_row_upper.data();
200 }
201
202 const double* getObjCoefficients() const override THROW_CALLED
203 double getObjSense() const override THROW_CALLED
204
205 bool isContinuous(int colIndex) const override {
206 const auto& model = m_parent.original_model();
207 assert(colIndex < model.vars().size());
208 const auto& var = model.get_var_by_index(colIndex);
209 return model.get_var_type(var) == Continuous;
210 }
211
212 const CoinPackedMatrix* getMatrixByRow() const override {
213
214 if (!m_matrix) {
215
216 const auto& model = m_parent.original_model();
217 const auto n_rows = model.ctrs().size();
218 const auto n_cols = model.vars().size();
219
220 /*
221 auto* me = const_cast<OsiIdolCglSolverInterface*>(this);
222 me->m_matrix.reset(new CoinPackedMatrix(false, n_rows, n_cols));
223
224 for (int i = 0 ; i < n_rows ; ++i) {
225 const auto ctr = model.get_ctr_by_index(i);
226 const auto &row = model.get_ctr_row(ctr);
227
228 CoinPackedVector row_vector;
229 for (const auto &[var, constant]: row) {
230 const int index = (int) model.get_var_index(var);
231 row_vector.insert(index, constant);
232 }
233
234 me->m_matrix->appendRow(row_vector);
235 }
236 */
237
238 // First pass: count total nonzeros
239 CoinBigIndex nnz = 0;
240 std::vector<int> row_lengths(n_rows);
241
242 for (int i = 0; i < n_rows; ++i) {
243 const auto ctr = model.get_ctr_by_index(i);
244 const auto& row = model.get_ctr_row(ctr);
245
246 row_lengths[i] = row.size();
247 nnz += row_lengths[i];
248 }
249
250 // Allocate storage
251 std::vector<double> elem(nnz);
252 std::vector<int> ind(nnz);
253 std::vector<CoinBigIndex> start(n_rows);
254
255 // Fill data
256 CoinBigIndex pos = 0;
257
258 for (int i = 0; i < n_rows; ++i) {
259 start[i] = pos;
260
261 const auto ctr = model.get_ctr_by_index(i);
262 const auto& row = model.get_ctr_row(ctr);
263
264 for (const auto& [var, constant] : row) {
265 const int index = (int) model.get_var_index(var);
266 assert(index >= 0 && index < n_cols);
267
268 ind[pos] = index;
269 elem[pos] = constant;
270 ++pos;
271 }
272 }
273
274 auto* me = const_cast<OsiIdolCglSolverInterface*>(this);
275 me->m_matrix.reset(new CoinPackedMatrix(
276 false,
277 n_cols,
278 n_rows,
279 nnz,
280 elem.data(),
281 ind.data(),
282 start.data(),
283 row_lengths.data()
284 ));
285
286 }
287
288 assert(m_matrix->getNumCols() == m_parent.original_model().vars().size());
289 assert(m_matrix->getNumRows() == m_parent.original_model().ctrs().size());
290
291 return m_matrix.get();
292 }
293
294 const CoinPackedMatrix* getMatrixByCol() const override THROW_CALLED
295
296 double getInfinity() const override { return Inf; }
297
298 const double* getColSolution() const override {
299 assert(m_current_solution.size() == m_parent.original_model().vars().size());
300 return m_current_solution.data();
301 }
302
303 const double* getRowPrice() const override THROW_CALLED
304 const double* getReducedCost() const override THROW_CALLED
305
306 const double* getRowActivity() const override {
307
308 if (m_row_activity.empty()) {
309 auto& me = const_cast<OsiIdolCglSolverInterface&>(*this);
310 const auto& model = m_parent.original_model();
311 const unsigned int n_rows = model.ctrs().size();
312 me.m_row_activity = std::vector<double>(n_rows);
313 const auto& current_solution = m_parent.node().info().primal_solution();
314 for (unsigned int index = 0 ; index < n_rows ; ++index) {
315 const auto& ctr = model.get_ctr_by_index(index);
316 const auto& row = model.get_ctr_row(ctr);
317 me.m_row_activity[index] = evaluate(row, current_solution);
318 }
319 }
320
321 assert(m_row_activity.size() == m_parent.original_model().ctrs().size());
322 return m_row_activity.data();
323 }
324
325 std::vector<double*> getDualRays(int maxNumRays, bool fullRay) const override THROW_CALLED
326 std::vector<double*> getPrimalRays(int maxNumRays) const override THROW_CALLED
327 void setObjCoeff(int elementIndex, double elementValue) override THROW_CALLED
328 void setColLower(int elementIndex, double elementValue) override THROW_CALLED
329 void setColUpper(int elementIndex, double elementValue) override THROW_CALLED
330 void setRowLower(int elementIndex, double elementValue) override THROW_CALLED
331 void setRowUpper(int elementIndex, double elementValue) override THROW_CALLED
332 void setColSolution(const double* colsol) override THROW_CALLED
333 void setRowPrice(const double* rowprice) override THROW_CALLED
334 void setContinuous(int index) override THROW_CALLED
335 void setInteger(int index) override THROW_CALLED
336 void addCol(const CoinPackedVectorBase& vec, const double collb, const double colub, const double obj) override THROW_CALLED
337 void addRow(const CoinPackedVectorBase& vec, const double rowlb, const double rowub) override THROW_CALLED
338 void deleteRows(const int num, const int* rowIndices) override THROW_CALLED
339 void loadProblem(const CoinPackedMatrix& matrix, const double* collb, const double* colub, const double* obj, const double* rowlb, const double* rowub) override THROW_CALLED
340 void assignProblem(CoinPackedMatrix*& matrix, double*& collb, double*& colub, double*& obj, double*& rowlb, double*& rowub) override THROW_CALLED
341 void loadProblem(const CoinPackedMatrix& matrix, const double* collb, const double* colub, const double* obj, const char* rowsen, const double* rowrhs, const double* rowrng) override THROW_CALLED
342 void assignProblem(CoinPackedMatrix*& matrix, double*& collb, double*& colub, double*& obj, char*& rowsen, double*& rowrhs, double*& rowrng) override THROW_CALLED
343 void loadProblem(const int numcols, const int numrows, const CoinBigIndex* start, const int* index, const double* value, const double* collb, const double* colub, const double* obj, const double* rowlb, const double* rowub) override THROW_CALLED
344 void loadProblem(const int numcols, const int numrows, const CoinBigIndex* start, const int* index, const double* value, const double* collb, const double* colub, const double* obj, const char* rowsen, const double* rowrhs, const double* rowrng) override THROW_CALLED
345 void writeMps(const char* filename, const char* extension, double objSense) const override THROW_CALLED
346 OsiSolverInterface* clone(bool copyData) const override THROW_CALLED
347 bool isIterationLimitReached() const override THROW_CALLED
348 double getObjValue() const override THROW_CALLED
349 int getIterationCount() const override THROW_CALLED
350 void setObjSense(double s) override THROW_CALLED
351 void setRowType(int index, char sense, double rightHandSide, double range) override THROW_CALLED
352 void deleteCols(const int num, const int* colIndices) override THROW_CALLED
353 void addRow(const CoinPackedVectorBase& vec, const char rowsen, const double rowrhs, const double rowrng) override THROW_CALLED
354
355protected:
356 void applyRowCut(const OsiRowCut& rc) override THROW_CALLED
357 void applyColCut(const OsiColCut& cc) override THROW_CALLED
358};
359
360#endif
361#endif //IDOL_OSIIDOLCGLSOLVERINTERFACE_H