Skip to content

Eliminate empty rows that does not have an activity change#89

Open
nguidotti wants to merge 3 commits into
scipopt:mainfrom
nguidotti:fix-empty-rows
Open

Eliminate empty rows that does not have an activity change#89
nguidotti wants to merge 3 commits into
scipopt:mainfrom
nguidotti:fix-empty-rows

Conversation

@nguidotti

Copy link
Copy Markdown

When running Papilo presolve, I encounter the following assertion failure in the DualInfer reduction:

src/papilo/presolvers/DualInfer.hpp:211: papilo::PresolveStatus papilo::DualInfer<REAL>::execute(const papilo::Problem<REAL>&, const papilo::ProblemUpdate<REAL>&, const papilo::Num<REAL>&, papilo::Reductions<REAL>&, const papilo::Timer&, int&) [with REAL = double]: Assertion `consMatrix.getRowSizes()[i] > 0' failed.

Since the input matrix does not have empty rows, it was introduced during one of the previous presolve reductions (sparsify, substitution or probing):

[substitution] live-empty row 28: size 0 lhsInf true rhsInf false eq false lhs -0.04893420343679652 rhs -3.799497838990599e-18
[substitution] live-empty row 30: size 0 lhsInf true rhsInf false eq false lhs -0.01475780480417465 rhs 3.799497838990599e-18
[substitution] TOTAL live-empty (non-redundant, size<=0) rows: 2 (DualInfer will assert on the first)
[probing] live-empty row 24: size 0 lhsInf false rhsInf false eq true lhs 8.45853285232799e-18 rhs 8.45853285232799e-18
[probing] TOTAL live-empty (non-redundant, size<=0) rows: 1 (DualInfer will assert on the first)
[DualInfer] LIVE-EMPTY ROW at execute(): row 24 size 0 redundant false lhsInf false rhsInf false eq true lhs 8.45853285232799e-18 rhs 8.45853285232799e-18 | nrows 142 ncols 61

As a fix, I added a loop in flush() that mark empty rows as redundant, so they can be eliminated in consMatrix.deleteRowsAndCols(redundant_rows, …).

@alexhoen

alexhoen commented Jul 7, 2026

Copy link
Copy Markdown
Member

Hi Niclas,

Thanks for providing the fix.

Would it be possible to share an instance with me so I can debug the issue?

Thanks in advance.

Best regards,
Alexande

@nguidotti

nguidotti commented Jul 7, 2026

Copy link
Copy Markdown
Author

Hello @alexhoen,

It was the milo-v12-6-r2-40-1 from the MIPLIB2017 dataset. However, I encounter this assertion failure when running a recursive RINS. I will try to generate a MPS with the offending sub-MIP.

@alexhoen

alexhoen commented Jul 7, 2026

Copy link
Copy Markdown
Member

Hi @nguidotti,

Unfortunately, this will probably be difficult to reproduce because the row/column ordering differs depending on whether PaPILO is accessed via the API or through an MPS file. This can lead to a different execution path where the issue does not occur. It is still worth trying, but it may be a challenging and too time-consuming task.

Normally, trivialPresolving in Presolve (trivialRowPresolve()) should handle these empty rows between presolver calls. The main question I'd like to debug is how this managed to slip through the trivialPresolving step.

Thanks for your analysis and the effort you've put into investigating this!

@nguidotti

nguidotti commented Jul 8, 2026

Copy link
Copy Markdown
Author

Here is the file: dual-infer-assertion-failure.mps.zip.

Note that for recursive RINS, I am limiting the number of threads to 1. This was encounter in NVIDIA/cuopt#1482.

The full log is

❯ cuopt/cpp/build/cuopt_cli --time-limit 600 --num-cpu-threads=2 dual-infer-assertion-failure.mps
Setting CUDA_MODULE_LOADING to EAGER
Setting parameter num_cpu_threads to 2
Setting parameter time_limit to 6.000000e+02
Reading file dual-infer-assertion-failure.mps
Read file dual-infer-assertion-failure.mps in 0.01 seconds
cuOpt version: 26.8.0, git hash: aef95152, host arch: x86_64, device archs: 89-real
CPU: Intel(R) Core(TM) Ultra 7 165H, threads (physical/logical): 16/22, RAM: 1.55 GiB
CUDA 13.2, device: NVIDIA RTX 3500 Ada Generation Laptop GPU (ID 0), VRAM: 11.60 GiB
CUDA device UUID: f2c35ecc-1759-35d4-87dd-e354d447c9c2

Solving a problem with 637 constraints, 888 variables (97 integers), and 2925 nonzeros
Problem scaling:
Objective coefficents range:          [2e+02, 4e+03]
Constraint matrix coefficients range: [4e-04, 2e+02]
Constraint rhs / bounds range:        [3e-19, 3e+00]
Variable bounds range:                [1e-18, 8e+00]
Warning: input problem contains a large range of coefficients: consider reformulating to avoid numerical difficulties.

MIP row scaling completed

Running Papilo presolve (git hash 741a2b9c)
cuopt_cli: /home/nguidotti/cuopt-dev/cuopt/cpp/build/_deps/papilo-src/src/papilo/presolvers/DualInfer.hpp:195: papilo::PresolveStatus papilo::DualInfer<REAL>::execute(const papilo::Problem<REAL>&, const papilo::ProblemUpdate<REAL>&, const papilo::Num<REAL>&, papilo::Reductions<REAL>&, const papilo::Timer&, int&) [with REAL = double]: Assertion `consMatrix.getRowSizes()[i] > 0' failed.
zsh: IOT instruction  cuopt/cpp/build/cuopt_cli --time-limit 600 --num-cpu-threads=2 

@nguidotti

nguidotti commented Jul 8, 2026

Copy link
Copy Markdown
Author

I am also hitting this error:

cuopt_cli: /cuopt-dev/cuopt/cpp/build/_deps/papilo-src/src/papilo/core/SingleRow.hpp:469: void papilo::update_activity_after_coeffchange(REAL, REAL, ColFlags, REAL, REAL, RowActivity<REAL>&, int, const int*, const REAL*, const VariableDomains<REAL>&, Num<REAL>, ACTIVITYCHANGE&&) [with REAL = double; ACTIVITYCHANGE = ConstraintMatrix<double>::sparsify(const papilo::Num<double>&, int, const double&, int, papilo::Vec<int>&, papilo::Vec<double>&, const papilo::VariableDomains<double>&, papilo::Vec<int>&, papilo::Vec<papilo::RowActivity<double> >&, papilo::Vec<int>&, papilo::Vec<int>&, papilo::Vec<int>&, int)::<lambda(int, int, double, double)>::<lambda(ActivityChange, RowActivity<double>&)>&; ColFlags = Flags<ColFlag>]: Assertion `oldcolcoef != newcolcoef' failed.

I changed update_activity_after_coeffchange to have an early return if this happens in 0cfea20.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants