@@ -34,7 +34,8 @@ static papilo::PostsolveStorage<double> post_solve_storage_;
34
34
static bool maximize_ = false ;
35
35
36
36
template <typename i_t , typename f_t >
37
- papilo::Problem<f_t > build_papilo_problem (const optimization_problem_t <i_t , f_t >& op_problem)
37
+ papilo::Problem<f_t > build_papilo_problem (const optimization_problem_t <i_t , f_t >& op_problem,
38
+ problem_category_t category)
38
39
{
39
40
// Build papilo problem from optimization problem
40
41
papilo::ProblemBuilder<f_t > builder;
@@ -167,7 +168,11 @@ papilo::Problem<f_t> build_papilo_problem(const optimization_problem_t<i_t, f_t>
167
168
168
169
if (h_entries.size ()) {
169
170
auto constexpr const sorted_entries = true ;
170
- auto csr_storage = papilo::SparseStorage<f_t >(h_entries, num_rows, num_cols, sorted_entries);
171
+ // MIP reductions like clique merging and substituition require more fillin
172
+ const double spare_ratio = category == problem_category_t ::MIP ? 4.0 : 2.0 ;
173
+ const int min_inter_row_space = category == problem_category_t ::MIP ? 30 : 4 ;
174
+ auto csr_storage = papilo::SparseStorage<f_t >(
175
+ h_entries, num_rows, num_cols, sorted_entries, spare_ratio, min_inter_row_space);
171
176
problem.setConstraintMatrix (csr_storage, h_constr_lb, h_constr_ub, h_row_flags);
172
177
173
178
papilo::ConstraintMatrix<f_t >& matrix = problem.getConstraintMatrix ();
@@ -304,14 +309,16 @@ void check_postsolve_status(const papilo::PostsolveStatus& status)
304
309
}
305
310
306
311
template <typename f_t >
307
- void set_presolve_methods (papilo::Presolve<f_t >& presolver, problem_category_t category)
312
+ void set_presolve_methods (papilo::Presolve<f_t >& presolver,
313
+ problem_category_t category,
314
+ bool dual_postsolve)
308
315
{
309
316
using uptr = std::unique_ptr<papilo::PresolveMethod<f_t >>;
310
317
311
- // cuopt custom presolvers
312
- if (category == problem_category_t ::MIP)
318
+ if (category == problem_category_t ::MIP) {
319
+ // cuOpt custom GF2 presolver
313
320
presolver.addPresolveMethod (uptr (new cuopt::linear_programming::detail::GF2Presolve<f_t >()));
314
-
321
+ }
315
322
// fast presolvers
316
323
presolver.addPresolveMethod (uptr (new papilo::SingletonCols<f_t >()));
317
324
presolver.addPresolveMethod (uptr (new papilo::CoefficientStrengthening<f_t >()));
@@ -326,16 +333,21 @@ void set_presolve_methods(papilo::Presolve<f_t>& presolver, problem_category_t c
326
333
presolver.addPresolveMethod (uptr (new papilo::SingletonStuffing<f_t >()));
327
334
presolver.addPresolveMethod (uptr (new papilo::DualFix<f_t >()));
328
335
presolver.addPresolveMethod (uptr (new papilo::SimplifyInequalities<f_t >()));
336
+ presolver.addPresolveMethod (uptr (new papilo::CliqueMerging<f_t >()));
329
337
330
338
// exhaustive presolvers
331
339
presolver.addPresolveMethod (uptr (new papilo::ImplIntDetection<f_t >()));
332
340
presolver.addPresolveMethod (uptr (new papilo::DominatedCols<f_t >()));
333
341
presolver.addPresolveMethod (uptr (new papilo::Probing<f_t >()));
334
342
335
- presolver.addPresolveMethod (uptr (new papilo::DualInfer<f_t >));
336
- presolver.addPresolveMethod (uptr (new papilo::SimpleSubstitution<f_t >()));
337
- presolver.addPresolveMethod (uptr (new papilo::Sparsify<f_t >()));
338
- presolver.addPresolveMethod (uptr (new papilo::Substitution<f_t >()));
343
+ if (!dual_postsolve) {
344
+ presolver.addPresolveMethod (uptr (new papilo::DualInfer<f_t >()));
345
+ presolver.addPresolveMethod (uptr (new papilo::SimpleSubstitution<f_t >()));
346
+ presolver.addPresolveMethod (uptr (new papilo::Sparsify<f_t >()));
347
+ presolver.addPresolveMethod (uptr (new papilo::Substitution<f_t >()));
348
+ } else {
349
+ CUOPT_LOG_INFO (" Disabling the presolver methods that do not support dual postsolve" );
350
+ }
339
351
}
340
352
341
353
template <typename i_t , typename f_t >
@@ -351,26 +363,51 @@ void set_presolve_options(papilo::Presolve<f_t>& presolver,
351
363
presolver.getPresolveOptions ().feastol = 1e-5 ;
352
364
}
353
365
366
+ template <typename f_t >
367
+ void set_presolve_parameters (papilo::Presolve<f_t >& presolver,
368
+ problem_category_t category,
369
+ int nrows,
370
+ int ncols)
371
+ {
372
+ // It looks like a copy. But this copy has the pointers to relevant variables in papilo
373
+ auto params = presolver.getParameters ();
374
+ if (category == problem_category_t ::MIP) {
375
+ // Papilo has work unit measurements for probing. Because of this when the first batch fails to
376
+ // produce any reductions, the algorithm stops. To avoid stopping the algorithm, we set a
377
+ // minimum badge size to a huge value. The time limit makes sure that we exit if it takes too
378
+ // long
379
+ int min_badgesize = std::max (ncols / 2 , 32 );
380
+ params.setParameter (" probing.minbadgesize" , min_badgesize);
381
+ params.setParameter (" cliquemerging.enabled" , true );
382
+ params.setParameter (" cliquemerging.maxcalls" , 50 );
383
+ }
384
+ }
385
+
354
386
template <typename i_t , typename f_t >
355
387
std::pair<optimization_problem_t <i_t , f_t >, bool > third_party_presolve_t <i_t , f_t >::apply(
356
388
optimization_problem_t <i_t , f_t > const & op_problem,
357
389
problem_category_t category,
390
+ bool dual_postsolve,
358
391
f_t absolute_tolerance,
359
392
f_t relative_tolerance,
360
393
double time_limit,
361
394
i_t num_cpu_threads)
362
395
{
363
- papilo::Problem<f_t > papilo_problem = build_papilo_problem (op_problem);
396
+ papilo::Problem<f_t > papilo_problem = build_papilo_problem (op_problem, category );
364
397
365
398
CUOPT_LOG_INFO (" Unpresolved problem:: %d constraints, %d variables, %d nonzeros" ,
366
399
papilo_problem.getNRows (),
367
400
papilo_problem.getNCols (),
368
401
papilo_problem.getConstraintMatrix ().getNnz ());
369
402
403
+ CUOPT_LOG_INFO (" Calling Papilo presolver" );
404
+ if (category == problem_category_t ::MIP) { dual_postsolve = false ; }
370
405
papilo::Presolve<f_t > presolver;
371
- set_presolve_methods<f_t >(presolver, category);
406
+ set_presolve_methods<f_t >(presolver, category, dual_postsolve );
372
407
set_presolve_options<i_t , f_t >(
373
408
presolver, category, absolute_tolerance, relative_tolerance, time_limit, num_cpu_threads);
409
+ set_presolve_parameters<f_t >(
410
+ presolver, category, op_problem.get_n_constraints (), op_problem.get_n_variables ());
374
411
375
412
// Disable papilo logs
376
413
presolver.setVerbosityLevel (papilo::VerbosityLevel::kQuiet );
@@ -423,9 +460,12 @@ void third_party_presolve_t<i_t, f_t>::undo(rmm::device_uvector<f_t>& primal_sol
423
460
check_postsolve_status (status);
424
461
425
462
primal_solution.resize (full_sol.primal .size (), stream_view);
426
- dual_solution.resize (full_sol.primal .size (), stream_view);
427
- reduced_costs.resize (full_sol.primal .size (), stream_view);
463
+ dual_solution.resize (full_sol.dual .size (), stream_view);
464
+ reduced_costs.resize (full_sol.reducedCosts .size (), stream_view);
428
465
raft::copy (primal_solution.data (), full_sol.primal .data (), full_sol.primal .size (), stream_view);
466
+ raft::copy (dual_solution.data (), full_sol.dual .data (), full_sol.dual .size (), stream_view);
467
+ raft::copy (
468
+ reduced_costs.data (), full_sol.reducedCosts .data (), full_sol.reducedCosts .size (), stream_view);
429
469
}
430
470
431
471
#if MIP_INSTANTIATE_FLOAT
0 commit comments