1919#include < cuopt/logger.hpp>
2020#include < mip/mip_constants.hpp>
2121#include < mip/presolve/third_party_presolve.hpp>
22+ #include < utilities/timer.hpp>
2223
24+ #pragma GCC diagnostic push
25+ #pragma GCC diagnostic ignored "-Wstringop-overflow" // ignore boost error for pip wheel build
2326#include < papilo/core/Presolve.hpp>
2427#include < papilo/core/ProblemBuilder.hpp>
28+ #pragma GCC diagnostic pop
2529
2630namespace cuopt ::linear_programming::detail {
2731
@@ -124,18 +128,32 @@ papilo::Problem<f_t> build_papilo_problem(const optimization_problem_t<i_t, f_t>
124128 builder.setRowRhsAll (h_constr_ub);
125129 }
126130
131+ std::vector<papilo::RowFlags> h_row_flags (h_constr_lb.size ());
132+ std::vector<std::tuple<i_t , i_t , f_t >> h_entries;
127133 // Add constraints row by row
128134 for (size_t i = 0 ; i < h_constr_lb.size (); ++i) {
129135 // Get row entries
130136 i_t row_start = h_offsets[i];
131137 i_t row_end = h_offsets[i + 1 ];
132138 i_t num_entries = row_end - row_start;
133- builder.addRowEntries (
134- i, num_entries, h_variables.data () + row_start, h_coefficients.data () + row_start);
135- builder.setRowLhsInf (i, h_constr_lb[i] == -std::numeric_limits<f_t >::infinity ());
136- builder.setRowRhsInf (i, h_constr_ub[i] == std::numeric_limits<f_t >::infinity ());
137- if (h_constr_lb[i] == -std::numeric_limits<f_t >::infinity ()) { builder.setRowLhs (i, 0 ); }
138- if (h_constr_ub[i] == std::numeric_limits<f_t >::infinity ()) { builder.setRowRhs (i, 0 ); }
139+ for (size_t j = 0 ; j < num_entries; ++j) {
140+ h_entries.push_back (
141+ std::make_tuple (i, h_variables[row_start + j], h_coefficients[row_start + j]));
142+ }
143+
144+ if (h_constr_lb[i] == -std::numeric_limits<f_t >::infinity ()) {
145+ h_row_flags[i].set (papilo::RowFlag::kLhsInf );
146+ } else {
147+ h_row_flags[i].unset (papilo::RowFlag::kLhsInf );
148+ }
149+ if (h_constr_ub[i] == std::numeric_limits<f_t >::infinity ()) {
150+ h_row_flags[i].set (papilo::RowFlag::kRhsInf );
151+ } else {
152+ h_row_flags[i].unset (papilo::RowFlag::kRhsInf );
153+ }
154+
155+ if (h_constr_lb[i] == -std::numeric_limits<f_t >::infinity ()) { h_constr_lb[i] = 0 ; }
156+ if (h_constr_ub[i] == std::numeric_limits<f_t >::infinity ()) { h_constr_ub[i] = 0 ; }
139157 }
140158
141159 for (size_t i = 0 ; i < h_var_lb.size (); ++i) {
@@ -144,7 +162,24 @@ papilo::Problem<f_t> build_papilo_problem(const optimization_problem_t<i_t, f_t>
144162 if (h_var_lb[i] == -std::numeric_limits<f_t >::infinity ()) { builder.setColLb (i, 0 ); }
145163 if (h_var_ub[i] == std::numeric_limits<f_t >::infinity ()) { builder.setColUb (i, 0 ); }
146164 }
147- return builder.build ();
165+
166+ auto problem = builder.build ();
167+
168+ if (h_entries.size ()) {
169+ auto constexpr const sorted_entries = true ;
170+ auto csr_storage = papilo::SparseStorage<f_t >(h_entries, num_rows, num_cols, sorted_entries);
171+ problem.setConstraintMatrix (csr_storage, h_constr_lb, h_constr_ub, h_row_flags);
172+
173+ papilo::ConstraintMatrix<f_t >& matrix = problem.getConstraintMatrix ();
174+ for (int i = 0 ; i < problem.getNRows (); ++i) {
175+ papilo::RowFlags rowFlag = matrix.getRowFlags ()[i];
176+ if (!rowFlag.test (papilo::RowFlag::kRhsInf ) && !rowFlag.test (papilo::RowFlag::kLhsInf ) &&
177+ matrix.getLeftHandSides ()[i] == matrix.getRightHandSides ()[i])
178+ matrix.getRowFlags ()[i].set (papilo::RowFlag::kEquation );
179+ }
180+ }
181+
182+ return problem;
148183}
149184
150185template <typename i_t , typename f_t >
@@ -299,14 +334,16 @@ void set_presolve_methods(papilo::Presolve<f_t>& presolver, problem_category_t c
299334 presolver.addPresolveMethod (uptr (new papilo::Substitution<f_t >()));
300335}
301336
302- template <typename f_t >
337+ template <typename i_t , typename f_t >
303338void set_presolve_options (papilo::Presolve<f_t >& presolver,
304339 problem_category_t category,
305340 f_t absolute_tolerance,
306341 f_t relative_tolerance,
307- double time_limit)
342+ double time_limit,
343+ i_t num_cpu_threads)
308344{
309- presolver.getPresolveOptions ().tlim = time_limit;
345+ presolver.getPresolveOptions ().tlim = time_limit;
346+ presolver.getPresolveOptions ().threads = num_cpu_threads; // user setting or 0 (automatic)
310347}
311348
312349template <typename i_t , typename f_t >
@@ -315,7 +352,8 @@ std::pair<optimization_problem_t<i_t, f_t>, bool> third_party_presolve_t<i_t, f_
315352 problem_category_t category,
316353 f_t absolute_tolerance,
317354 f_t relative_tolerance,
318- double time_limit)
355+ double time_limit,
356+ i_t num_cpu_threads)
319357{
320358 cuopt_expects (
321359 presolve_calls_ == 0 , error_type_t ::ValidationError, " Presolve can only be called once" );
@@ -330,8 +368,8 @@ std::pair<optimization_problem_t<i_t, f_t>, bool> third_party_presolve_t<i_t, f_
330368
331369 papilo::Presolve<f_t > presolver;
332370 set_presolve_methods<f_t >(presolver, category);
333- set_presolve_options<f_t >(
334- presolver, category, absolute_tolerance, relative_tolerance, time_limit);
371+ set_presolve_options<i_t , f_t >(
372+ presolver, category, absolute_tolerance, relative_tolerance, time_limit, num_cpu_threads );
335373
336374 // Disable papilo logs
337375 presolver.setVerbosityLevel (papilo::VerbosityLevel::kQuiet );
0 commit comments