Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cpp/include/cuopt/mathematical_optimization/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@
/* @brief Block bounded-variable-elimination step of cuOpt's internal MIP presolve */
#define CUOPT_MIP_HYPER_BLOCK_BVE "mip_hyper_block_bve"

/* @brief Indicator-strengthening step that runs before Papilo presolve on MIPs */
#define CUOPT_MIP_HYPER_PRESOLVE_INDICATOR_STRENGTHENING \
"mip_hyper_presolve_indicator_strengthening"

/* @brief QCQP (barrier) scaling hyper-parameters */
#define CUOPT_QCQP_HYPER_RUIZ_EQUILIBRATION "qcqp_hyper_ruiz_equilibration"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ class mip_solver_settings_t {
* no-op when no certified reduction exists.
*/
bool block_bve{true};
/**
* @brief Enable the indicator-strengthening step of presolve (MIP only).
*
* Runs before Papilo and only when the higher-level presolve is enabled. It appends implied
* indicator rows and lifts capacity rows by the indicator that bounds all of their members.
*/
bool indicator_strengthening{true};
/**
* @brief Determinism mode for MIP solver.
*
Expand Down
1 change: 1 addition & 0 deletions cpp/src/math_optimization/solver_settings.cu
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ solver_settings_t<i_t, f_t>::solver_settings_t() : pdlp_settings(), mip_settings
// Recursive sub-MIP (RINS) hyper-parameters (hidden from default --help: name contains "hyper_")
{CUOPT_MIP_HYPER_SUBMIP_ENABLE_CPUFJ, &mip_settings.submip_params.enable_cpufj, true, "run CPU FJ over the sub-MIP"},
{CUOPT_MIP_HYPER_BLOCK_BVE, &mip_settings.block_bve, true, "eliminate blocks of binaries in cuOpt's MIP presolve (needs " CUOPT_MIP_PROBING ")"},
{CUOPT_MIP_HYPER_PRESOLVE_INDICATOR_STRENGTHENING, &mip_settings.indicator_strengthening, true, "append implied indicator rows and lift capacity rows before Papilo presolve"},
// PDLP scaling hyper-parameter (hidden from default --help: name contains "hyper_")
{CUOPT_PDLP_HYPER_ENABLE_CURTIS_REID_SCALING, &pdlp_settings.hyper_params.do_curtis_reid_scaling, true, "Curtis-Reid prescaling, run before Ruiz/Pock-Chambolle scaling"},
};
Expand Down
1 change: 1 addition & 0 deletions cpp/src/mip_heuristics/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set(MIP_LP_NECESSARY_FILES
${CMAKE_CURRENT_SOURCE_DIR}/presolve/single_lock_dual_aggregation.cpp
${CMAKE_CURRENT_SOURCE_DIR}/presolve/gf2_presolve.cpp
${CMAKE_CURRENT_SOURCE_DIR}/presolve/bhw_coeff_reduce.cpp
${CMAKE_CURRENT_SOURCE_DIR}/presolve/indicator_strengthening.cpp
${CMAKE_CURRENT_SOURCE_DIR}/solution/solution.cu
${CMAKE_CURRENT_SOURCE_DIR}/presolve/conflict_graph/clique_table.cu
)
Expand Down
425 changes: 425 additions & 0 deletions cpp/src/mip_heuristics/presolve/indicator_strengthening.cpp

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions cpp/src/mip_heuristics/presolve/indicator_strengthening.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* clang-format off */
/*
* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
/* clang-format on */

#pragma once

#if !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow" // ignore boost error for pip wheel build
#pragma GCC diagnostic ignored "-Wnarrowing"
#endif
#include <papilo/Config.hpp>
#include <papilo/core/Problem.hpp>
#if !defined(__clang__)
#pragma GCC diagnostic pop
#endif

namespace cuopt::mathematical_optimization::mip {

// Adds an implied indicator row y <= sum_{g in D} z_g for every implication row
Comment thread
nguidotti marked this conversation as resolved.
// y <= sum_{j in S} x_j whose members are bounded by indicators x_j <= z_g, and lifts every
// capacity row sum_{i in S} x_i - s <= K whose members share an indicator z into sum_{i in S} x_i -
// s <= K z. Both need an integral indicator, so this is for MIPs only.
template <typename i_t, typename f_t>
void strengthen_indicators(papilo::Problem<f_t>& problem);

} // namespace cuopt::mathematical_optimization::mip
18 changes: 13 additions & 5 deletions cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <mip_heuristics/mip_constants.hpp>
#include <mip_heuristics/presolve/bhw_coeff_reduce.hpp>
#include <mip_heuristics/presolve/gf2_presolve.hpp>
#include <mip_heuristics/presolve/indicator_strengthening.hpp>
#include <mip_heuristics/presolve/single_lock_dual_aggregation.hpp>
#include <mip_heuristics/presolve/third_party_presolve.hpp>
#include <utilities/logger.hpp>
Expand Down Expand Up @@ -747,8 +748,8 @@ void set_presolve_methods(

if (category == problem_category_t::MIP) {
// cuOpt custom GF2 presolver
maybe_add(uptr(new cuopt::mathematical_optimization::mip::GF2Presolve<f_t>()));
maybe_add(uptr(new cuopt::mathematical_optimization::mip::BHWCoeffReduce<f_t>()));
maybe_add(uptr(new GF2Presolve<f_t>()));
maybe_add(uptr(new BHWCoeffReduce<f_t>()));
}
// fast presolvers
maybe_add(uptr(new papilo::SingletonCols<f_t>()));
Expand Down Expand Up @@ -927,14 +928,21 @@ third_party_presolve_status_t third_party_presolve_t<i_t, f_t>::apply_papilo(

// Capture original dimensions before papilo.apply() mutates papilo_problem
// in place into its reduced form.
const i_t original_n_vars = static_cast<i_t>(papilo_problem.getNCols());
const i_t original_n_cons = static_cast<i_t>(papilo_problem.getNRows());
const i_t original_nnz = static_cast<i_t>(papilo_problem.getConstraintMatrix().getNnz());
const i_t original_n_vars = papilo_problem.getNCols();
const i_t original_n_cons = papilo_problem.getNRows();
const i_t original_nnz = papilo_problem.getConstraintMatrix().getNnz();

CUOPT_LOG_DEBUG("Original problem: %d constraints, %d variables, %d nonzeros",
original_n_cons,
original_n_vars,
original_nnz);

if (category == problem_category_t::MIP && indicator_strengthening_ &&
(!reduction_allowlist_.has_value() ||
reduction_allowlist_->count("indicatorstrengthening") > 0)) {
strengthen_indicators<i_t, f_t>(papilo_problem);
}

CUOPT_LOG_INFO("\nRunning Papilo presolve (git hash %s)", PAPILO_GITHASH);
if (category == problem_category_t::MIP) { dual_postsolve = false; }
papilo::Presolve<f_t> papilo_presolver;
Expand Down
3 changes: 3 additions & 0 deletions cpp/src/mip_heuristics/presolve/third_party_presolve.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ class third_party_presolve_t {
reduction_allowlist_ = std::move(allowlist);
}

void set_indicator_strengthening(bool enabled) { indicator_strengthening_ = enabled; }

// Apply the presolve on an simplex::user_problem in-place. Used in sub MIP and (in the future)
// restarts.
third_party_presolve_status_t apply_to_subproblem(
Expand Down Expand Up @@ -225,6 +227,7 @@ class third_party_presolve_t {
f_t original_objective_scaling_factor_{1};

std::optional<std::unordered_set<std::string>> reduction_allowlist_{};
bool indicator_strengthening_{true};
};

// Just for testing the conversion: user_problem -> Papilo problem -> user_problem.
Expand Down
3 changes: 2 additions & 1 deletion cpp/src/mip_heuristics/solve.cu
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,8 @@ mip_solution_t<i_t, f_t> solve_mip_helper(
? std::numeric_limits<double>::infinity()
: timer.remaining_time();

presolver = std::make_unique<mip::third_party_presolve_t<i_t, f_t>>();
presolver = std::make_unique<mip::third_party_presolve_t<i_t, f_t>>();
presolver->set_indicator_strengthening(settings.indicator_strengthening);
auto result = presolver->apply_presolve_from_op_problem(
op_problem,
cuopt::mathematical_optimization::problem_category_t::MIP,
Expand Down
1 change: 1 addition & 0 deletions cpp/tests/internal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ ConfigureTest(NUMOPT_INTERNAL_TEST
${CUOPT_TEST_DIR}/mip/block_bve_test.cu
${CUOPT_TEST_DIR}/mip/bhw_coeff_reduce_test.cpp
${CUOPT_TEST_DIR}/mip/gf2_presolve_test.cpp
${CUOPT_TEST_DIR}/mip/indicator_strengthening_test.cpp
${CUOPT_TEST_DIR}/mip/arc_flow_test.cu
${CUOPT_TEST_DIR}/mip/single_lock_dual_aggregation_test.cpp
${CUOPT_TEST_DIR}/mip/termination_test.cu
Expand Down
Loading
Loading