diff --git a/check/TestPresolve.cpp b/check/TestPresolve.cpp index 7d2e5d9604..505373c156 100644 --- a/check/TestPresolve.cpp +++ b/check/TestPresolve.cpp @@ -639,3 +639,13 @@ TEST_CASE("presolve-slacks", "[highs_test_presolve]") { REQUIRE(h.getPresolvedLp().num_col_ == 2); REQUIRE(h.getPresolvedLp().num_row_ == 2); } + +TEST_CASE("presolve-issue-2095", "[highs_test_presolve]") { + std::string model_file = + std::string(HIGHS_DIR) + "/check/instances/issue-2095.mps"; + Highs highs; + highs.setOptionValue("output_flag", dev_run); + highs.readModel(model_file); + REQUIRE(highs.presolve() == HighsStatus::kOk); + REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kReduced); +} diff --git a/check/instances/issue-2095.mps b/check/instances/issue-2095.mps new file mode 100644 index 0000000000..a05dc4ef22 --- /dev/null +++ b/check/instances/issue-2095.mps @@ -0,0 +1,836 @@ +NAME +ROWS + N Obj + E r0 + E r1 + E r2 + E r3 + E r4 + E r5 + E r6 + E r7 + E r8 + E r9 + E r10 + E r11 + E r12 + E r13 + E r14 + E r15 + E r16 + E r17 + E r18 + E r19 + E r20 + E r21 + E r22 + E r23 + E r24 + E r25 + E r26 + E r27 + E r28 +COLUMNS + MARK0000 'MARKER' 'INTORG' + c0 Obj 1 + c0 r0 1 + c1 Obj 1 + c1 r1 1 + c2 Obj 1 + c2 r2 1 + c3 Obj 1 + c3 r3 1 + c4 Obj 1 + c4 r5 1 + c5 Obj 1 + c5 r6 1 + c6 Obj 1 + c6 r7 1 + c7 Obj 1 + c7 r25 1 + c8 Obj 1 + c8 r26 1 + c9 Obj 1 + c9 r27 1 + c10 Obj 1 + c10 r28 1 + c11 Obj 1 + c11 r0 1 + c11 r1 1 + c11 r2 1 + c11 r3 1 + c12 Obj 1 + c12 r1 1 + c12 r2 1 + c12 r3 1 + c12 r4 1 + c13 Obj 1 + c13 r5 1 + c13 r6 1 + c13 r7 1 + c13 r8 1 + c14 Obj 1 + c14 r8 1 + c14 r9 1 + c14 r10 1 + c14 r11 1 + c15 Obj 1 + c15 r24 1 + c15 r25 1 + c15 r26 1 + c15 r27 1 + c16 Obj 1 + c16 r0 1 + c16 r1 1 + c16 r2 1 + c16 r3 1 + c16 r4 1 + c17 Obj 1 + c17 r4 1 + c17 r5 1 + c17 r6 1 + c17 r7 1 + c17 r8 1 + c18 Obj 1 + c18 r5 1 + c18 r6 1 + c18 r7 1 + c18 r8 1 + c18 r9 1 + c19 Obj 1 + c19 r8 1 + c19 r9 1 + c19 r10 1 + c19 r11 1 + c19 r12 1 + c20 Obj 1 + c20 r23 1 + c20 r24 1 + c20 r25 1 + c20 r26 1 + c20 r27 1 + c21 Obj 1 + c21 r4 1 + c21 r5 1 + c21 r6 1 + c21 r7 1 + c21 r8 1 + c21 r9 1 + c22 Obj 1 + c22 r5 1 + c22 r6 1 + c22 r7 1 + c22 r8 1 + c22 r9 1 + c22 r10 1 + c23 Obj 1 + c23 r8 1 + c23 r9 1 + c23 r10 1 + c23 r11 1 + c23 r12 1 + c23 r13 1 + c24 Obj 1 + c24 r22 1 + c24 r23 1 + c24 r24 1 + c24 r25 1 + c24 r26 1 + c24 r27 1 + c25 Obj 1 + c25 r4 1 + c25 r5 1 + c25 r6 1 + c25 r7 1 + c25 r8 1 + c25 r9 1 + c25 r10 1 + c26 Obj 1 + c26 r8 1 + c26 r9 1 + c26 r10 1 + c26 r11 1 + c26 r12 1 + c26 r13 1 + c26 r14 1 + c27 Obj 1 + c27 r21 1 + c27 r22 1 + c27 r23 1 + c27 r24 1 + c27 r25 1 + c27 r26 1 + c27 r27 1 + c28 Obj 1 + c28 r8 1 + c28 r9 1 + c28 r10 1 + c28 r11 1 + c28 r12 1 + c28 r13 1 + c28 r14 1 + c28 r15 1 + c29 Obj 1 + c29 r20 1 + c29 r21 1 + c29 r22 1 + c29 r23 1 + c29 r24 1 + c29 r25 1 + c29 r26 1 + c29 r27 1 + c30 Obj 1 + c30 r8 1 + c30 r9 1 + c30 r10 1 + c30 r11 1 + c30 r12 1 + c30 r13 1 + c30 r14 1 + c30 r15 1 + c30 r16 1 + c31 Obj 1 + c31 r19 1 + c31 r20 1 + c31 r21 1 + c31 r22 1 + c31 r23 1 + c31 r24 1 + c31 r25 1 + c31 r26 1 + c31 r27 1 + c32 Obj 1 + c32 r8 1 + c32 r9 1 + c32 r10 1 + c32 r11 1 + c32 r12 1 + c32 r13 1 + c32 r14 1 + c32 r15 1 + c32 r16 1 + c32 r17 1 + c33 Obj 1 + c33 r18 1 + c33 r19 1 + c33 r20 1 + c33 r21 1 + c33 r22 1 + c33 r23 1 + c33 r24 1 + c33 r25 1 + c33 r26 1 + c33 r27 1 + c34 Obj 1 + c34 r8 1 + c34 r9 1 + c34 r10 1 + c34 r11 1 + c34 r12 1 + c34 r13 1 + c34 r14 1 + c34 r15 1 + c34 r16 1 + c34 r17 1 + c34 r18 1 + c35 Obj 1 + c35 r17 1 + c35 r18 1 + c35 r19 1 + c35 r20 1 + c35 r21 1 + c35 r22 1 + c35 r23 1 + c35 r24 1 + c35 r25 1 + c35 r26 1 + c35 r27 1 + c36 Obj 1 + c36 r7 1 + c36 r8 1 + c36 r9 1 + c36 r10 1 + c36 r11 1 + c36 r12 1 + c36 r13 1 + c36 r14 1 + c36 r15 1 + c36 r16 1 + c36 r17 1 + c36 r18 1 + c37 Obj 1 + c37 r8 1 + c37 r9 1 + c37 r10 1 + c37 r11 1 + c37 r12 1 + c37 r13 1 + c37 r14 1 + c37 r15 1 + c37 r16 1 + c37 r17 1 + c37 r18 1 + c37 r19 1 + c38 Obj 1 + c38 r16 1 + c38 r17 1 + c38 r18 1 + c38 r19 1 + c38 r20 1 + c38 r21 1 + c38 r22 1 + c38 r23 1 + c38 r24 1 + c38 r25 1 + c38 r26 1 + c38 r27 1 + c39 Obj 1 + c39 r17 1 + c39 r18 1 + c39 r19 1 + c39 r20 1 + c39 r21 1 + c39 r22 1 + c39 r23 1 + c39 r24 1 + c39 r25 1 + c39 r26 1 + c39 r27 1 + c39 r28 1 + c40 Obj 1 + c40 r7 1 + c40 r8 1 + c40 r9 1 + c40 r10 1 + c40 r11 1 + c40 r12 1 + c40 r13 1 + c40 r14 1 + c40 r15 1 + c40 r16 1 + c40 r17 1 + c40 r18 1 + c40 r19 1 + c41 Obj 1 + c41 r8 1 + c41 r9 1 + c41 r10 1 + c41 r11 1 + c41 r12 1 + c41 r13 1 + c41 r14 1 + c41 r15 1 + c41 r16 1 + c41 r17 1 + c41 r18 1 + c41 r19 1 + c41 r20 1 + c42 Obj 1 + c42 r15 1 + c42 r16 1 + c42 r17 1 + c42 r18 1 + c42 r19 1 + c42 r20 1 + c42 r21 1 + c42 r22 1 + c42 r23 1 + c42 r24 1 + c42 r25 1 + c42 r26 1 + c42 r27 1 + c43 Obj 1 + c43 r16 1 + c43 r17 1 + c43 r18 1 + c43 r19 1 + c43 r20 1 + c43 r21 1 + c43 r22 1 + c43 r23 1 + c43 r24 1 + c43 r25 1 + c43 r26 1 + c43 r27 1 + c43 r28 1 + c44 Obj 1 + c44 r7 1 + c44 r8 1 + c44 r9 1 + c44 r10 1 + c44 r11 1 + c44 r12 1 + c44 r13 1 + c44 r14 1 + c44 r15 1 + c44 r16 1 + c44 r17 1 + c44 r18 1 + c44 r19 1 + c44 r20 1 + c45 Obj 1 + c45 r8 1 + c45 r9 1 + c45 r10 1 + c45 r11 1 + c45 r12 1 + c45 r13 1 + c45 r14 1 + c45 r15 1 + c45 r16 1 + c45 r17 1 + c45 r18 1 + c45 r19 1 + c45 r20 1 + c45 r21 1 + c46 Obj 1 + c46 r14 1 + c46 r15 1 + c46 r16 1 + c46 r17 1 + c46 r18 1 + c46 r19 1 + c46 r20 1 + c46 r21 1 + c46 r22 1 + c46 r23 1 + c46 r24 1 + c46 r25 1 + c46 r26 1 + c46 r27 1 + c47 Obj 1 + c47 r15 1 + c47 r16 1 + c47 r17 1 + c47 r18 1 + c47 r19 1 + c47 r20 1 + c47 r21 1 + c47 r22 1 + c47 r23 1 + c47 r24 1 + c47 r25 1 + c47 r26 1 + c47 r27 1 + c47 r28 1 + c48 Obj 1 + c48 r7 1 + c48 r8 1 + c48 r9 1 + c48 r10 1 + c48 r11 1 + c48 r12 1 + c48 r13 1 + c48 r14 1 + c48 r15 1 + c48 r16 1 + c48 r17 1 + c48 r18 1 + c48 r19 1 + c48 r20 1 + c48 r21 1 + c49 Obj 1 + c49 r8 1 + c49 r9 1 + c49 r10 1 + c49 r11 1 + c49 r12 1 + c49 r13 1 + c49 r14 1 + c49 r15 1 + c49 r16 1 + c49 r17 1 + c49 r18 1 + c49 r19 1 + c49 r20 1 + c49 r21 1 + c49 r22 1 + c50 Obj 1 + c50 r13 1 + c50 r14 1 + c50 r15 1 + c50 r16 1 + c50 r17 1 + c50 r18 1 + c50 r19 1 + c50 r20 1 + c50 r21 1 + c50 r22 1 + c50 r23 1 + c50 r24 1 + c50 r25 1 + c50 r26 1 + c50 r27 1 + c51 Obj 1 + c51 r14 1 + c51 r15 1 + c51 r16 1 + c51 r17 1 + c51 r18 1 + c51 r19 1 + c51 r20 1 + c51 r21 1 + c51 r22 1 + c51 r23 1 + c51 r24 1 + c51 r25 1 + c51 r26 1 + c51 r27 1 + c51 r28 1 + c52 Obj 1 + c52 r7 1 + c52 r8 1 + c52 r9 1 + c52 r10 1 + c52 r11 1 + c52 r12 1 + c52 r13 1 + c52 r14 1 + c52 r15 1 + c52 r16 1 + c52 r17 1 + c52 r18 1 + c52 r19 1 + c52 r20 1 + c52 r21 1 + c52 r22 1 + c53 Obj 1 + c53 r8 1 + c53 r9 1 + c53 r10 1 + c53 r11 1 + c53 r12 1 + c53 r13 1 + c53 r14 1 + c53 r15 1 + c53 r16 1 + c53 r17 1 + c53 r18 1 + c53 r19 1 + c53 r20 1 + c53 r21 1 + c53 r22 1 + c53 r23 1 + c54 Obj 1 + c54 r12 1 + c54 r13 1 + c54 r14 1 + c54 r15 1 + c54 r16 1 + c54 r17 1 + c54 r18 1 + c54 r19 1 + c54 r20 1 + c54 r21 1 + c54 r22 1 + c54 r23 1 + c54 r24 1 + c54 r25 1 + c54 r26 1 + c54 r27 1 + c55 Obj 1 + c55 r13 1 + c55 r14 1 + c55 r15 1 + c55 r16 1 + c55 r17 1 + c55 r18 1 + c55 r19 1 + c55 r20 1 + c55 r21 1 + c55 r22 1 + c55 r23 1 + c55 r24 1 + c55 r25 1 + c55 r26 1 + c55 r27 1 + c55 r28 1 + c56 Obj 1 + c56 r7 1 + c56 r8 1 + c56 r9 1 + c56 r10 1 + c56 r11 1 + c56 r12 1 + c56 r13 1 + c56 r14 1 + c56 r15 1 + c56 r16 1 + c56 r17 1 + c56 r18 1 + c56 r19 1 + c56 r20 1 + c56 r21 1 + c56 r22 1 + c56 r23 1 + c57 Obj 1 + c57 r8 1 + c57 r9 1 + c57 r10 1 + c57 r11 1 + c57 r12 1 + c57 r13 1 + c57 r14 1 + c57 r15 1 + c57 r16 1 + c57 r17 1 + c57 r18 1 + c57 r19 1 + c57 r20 1 + c57 r21 1 + c57 r22 1 + c57 r23 1 + c57 r24 1 + c58 Obj 1 + c58 r11 1 + c58 r12 1 + c58 r13 1 + c58 r14 1 + c58 r15 1 + c58 r16 1 + c58 r17 1 + c58 r18 1 + c58 r19 1 + c58 r20 1 + c58 r21 1 + c58 r22 1 + c58 r23 1 + c58 r24 1 + c58 r25 1 + c58 r26 1 + c58 r27 1 + c59 Obj 1 + c59 r12 1 + c59 r13 1 + c59 r14 1 + c59 r15 1 + c59 r16 1 + c59 r17 1 + c59 r18 1 + c59 r19 1 + c59 r20 1 + c59 r21 1 + c59 r22 1 + c59 r23 1 + c59 r24 1 + c59 r25 1 + c59 r26 1 + c59 r27 1 + c59 r28 1 + c60 Obj 1 + c60 r7 1 + c60 r8 1 + c60 r9 1 + c60 r10 1 + c60 r11 1 + c60 r12 1 + c60 r13 1 + c60 r14 1 + c60 r15 1 + c60 r16 1 + c60 r17 1 + c60 r18 1 + c60 r19 1 + c60 r20 1 + c60 r21 1 + c60 r22 1 + c60 r23 1 + c60 r24 1 + c61 Obj 1 + c61 r10 1 + c61 r11 1 + c61 r12 1 + c61 r13 1 + c61 r14 1 + c61 r15 1 + c61 r16 1 + c61 r17 1 + c61 r18 1 + c61 r19 1 + c61 r20 1 + c61 r21 1 + c61 r22 1 + c61 r23 1 + c61 r24 1 + c61 r25 1 + c61 r26 1 + c61 r27 1 + c62 Obj 1 + c62 r11 1 + c62 r12 1 + c62 r13 1 + c62 r14 1 + c62 r15 1 + c62 r16 1 + c62 r17 1 + c62 r18 1 + c62 r19 1 + c62 r20 1 + c62 r21 1 + c62 r22 1 + c62 r23 1 + c62 r24 1 + c62 r25 1 + c62 r26 1 + c62 r27 1 + c62 r28 1 + c63 Obj 1 + c63 r9 1 + c63 r10 1 + c63 r11 1 + c63 r12 1 + c63 r13 1 + c63 r14 1 + c63 r15 1 + c63 r16 1 + c63 r17 1 + c63 r18 1 + c63 r19 1 + c63 r20 1 + c63 r21 1 + c63 r22 1 + c63 r23 1 + c63 r24 1 + c63 r25 1 + c63 r26 1 + c63 r27 1 + c64 Obj 1 + c64 r10 1 + c64 r11 1 + c64 r12 1 + c64 r13 1 + c64 r14 1 + c64 r15 1 + c64 r16 1 + c64 r17 1 + c64 r18 1 + c64 r19 1 + c64 r20 1 + c64 r21 1 + c64 r22 1 + c64 r23 1 + c64 r24 1 + c64 r25 1 + c64 r26 1 + c64 r27 1 + c64 r28 1 + c65 Obj 1 + c65 r9 1 + c65 r10 1 + c65 r11 1 + c65 r12 1 + c65 r13 1 + c65 r14 1 + c65 r15 1 + c65 r16 1 + c65 r17 1 + c65 r18 1 + c65 r19 1 + c65 r20 1 + c65 r21 1 + c65 r22 1 + c65 r23 1 + c65 r24 1 + c65 r25 1 + c65 r26 1 + c65 r27 1 + c65 r28 1 + MARK0001 'MARKER' 'INTEND' +RHS + RHS_V r0 1 + RHS_V r1 1 + RHS_V r2 1 + RHS_V r3 1 + RHS_V r4 1 + RHS_V r5 1 + RHS_V r6 1 + RHS_V r7 1 + RHS_V r8 1 + RHS_V r9 1 + RHS_V r10 1 + RHS_V r11 1 + RHS_V r12 1 + RHS_V r13 1 + RHS_V r14 1 + RHS_V r15 1 + RHS_V r16 1 + RHS_V r17 1 + RHS_V r18 1 + RHS_V r19 1 + RHS_V r20 1 + RHS_V r21 1 + RHS_V r22 1 + RHS_V r23 1 + RHS_V r24 1 + RHS_V r25 1 + RHS_V r26 1 + RHS_V r27 1 + RHS_V r28 1 +BOUNDS + BV BOUND c0 + BV BOUND c1 + BV BOUND c2 + BV BOUND c3 + BV BOUND c4 + BV BOUND c5 + BV BOUND c6 + BV BOUND c7 + BV BOUND c8 + BV BOUND c9 + BV BOUND c10 + BV BOUND c11 + BV BOUND c12 + BV BOUND c13 + BV BOUND c14 + BV BOUND c15 + BV BOUND c16 + BV BOUND c17 + BV BOUND c18 + BV BOUND c19 + BV BOUND c20 + BV BOUND c21 + BV BOUND c22 + BV BOUND c23 + BV BOUND c24 + BV BOUND c25 + BV BOUND c26 + BV BOUND c27 + BV BOUND c28 + BV BOUND c29 + BV BOUND c30 + BV BOUND c31 + BV BOUND c32 + BV BOUND c33 + BV BOUND c34 + BV BOUND c35 + BV BOUND c36 + BV BOUND c37 + BV BOUND c38 + BV BOUND c39 + BV BOUND c40 + BV BOUND c41 + BV BOUND c42 + BV BOUND c43 + BV BOUND c44 + BV BOUND c45 + BV BOUND c46 + BV BOUND c47 + BV BOUND c48 + BV BOUND c49 + BV BOUND c50 + BV BOUND c51 + BV BOUND c52 + BV BOUND c53 + BV BOUND c54 + BV BOUND c55 + BV BOUND c56 + BV BOUND c57 + BV BOUND c58 + BV BOUND c59 + BV BOUND c60 + BV BOUND c61 + BV BOUND c62 + BV BOUND c63 + BV BOUND c64 + BV BOUND c65 +ENDATA diff --git a/src/presolve/HPresolve.cpp b/src/presolve/HPresolve.cpp index d7977a0ebb..38e56fc9f0 100644 --- a/src/presolve/HPresolve.cpp +++ b/src/presolve/HPresolve.cpp @@ -2052,14 +2052,17 @@ HPresolve::Result HPresolve::applyConflictGraphSubstitutions( return Result::kOk; } -void HPresolve::storeRow(HighsInt row) { - rowpositions.clear(); +void HPresolve::getRowPositions(HighsInt row, + std::vector& myrowpositions) const { + myrowpositions.clear(); - auto rowVec = getSortedRowVector(row); - for (auto iter = rowVec.begin(); iter != rowVec.end(); ++iter) - rowpositions.push_back(iter.position()); + auto rowvector = getSortedRowVector(row); + for (auto rowiter = rowvector.begin(); rowiter != rowvector.end(); ++rowiter) + myrowpositions.push_back(rowiter.position()); } +void HPresolve::storeRow(HighsInt row) { getRowPositions(row, rowpositions); } + HighsTripletPositionSlice HPresolve::getStoredRow() const { return HighsTripletPositionSlice(Acol.data(), Avalue.data(), rowpositions.data(), rowpositions.size()); @@ -3542,19 +3545,27 @@ HPresolve::Result HPresolve::rowPresolve(HighsPostsolveStack& postsolve_stack, auto strengthenCoefs = [&](HighsCDouble& rhs, HighsInt direction, double maxCoefValue) { - for (const HighsSliceNonzero& nonz : getStoredRow()) { - if (model->integrality_[nonz.index()] == HighsVarType::kContinuous) - continue; - - if (direction * nonz.value() > maxCoefValue + primal_feastol) { - double delta = direction * maxCoefValue - nonz.value(); - addToMatrix(row, nonz.index(), delta); - rhs += delta * model->col_upper_[nonz.index()]; - } else if (direction * nonz.value() < - -maxCoefValue - primal_feastol) { - double delta = -direction * maxCoefValue - nonz.value(); - addToMatrix(row, nonz.index(), delta); - rhs += delta * model->col_lower_[nonz.index()]; + // iterate over non-zero positions instead of iterating over the + // HighsMatrixSlice (provided by HPresolve::getStoredRow) because the + // latter contains pointers to Acol and Avalue that may be invalidated + // if these vectors are reallocated (see std::vector::push_back + // performed in HPresolve::addToMatrix). + for (HighsInt rowiter : rowpositions) { + // get column index and coefficient + HighsInt col = Acol[rowiter]; + double val = Avalue[rowiter]; + + // skip continuous variables + if (model->integrality_[col] == HighsVarType::kContinuous) continue; + + if (direction * val > maxCoefValue + primal_feastol) { + double delta = direction * maxCoefValue - val; + addToMatrix(row, col, delta); + rhs += delta * model->col_upper_[col]; + } else if (direction * val < -maxCoefValue - primal_feastol) { + double delta = -direction * maxCoefValue - val; + addToMatrix(row, col, delta); + rhs += delta * model->col_lower_[col]; } } }; @@ -6128,15 +6139,25 @@ HPresolve::Result HPresolve::detectParallelRowsAndCols( template HPresolve::Result HPresolve::equalityRowAddition( HighsPostsolveStack& postsolve_stack, HighsInt stayrow, HighsInt removerow, - double scale, const HighsMatrixSlice& vector) { - postsolve_stack.equalityRowAddition(removerow, stayrow, scale, vector); - for (const auto& rowNz : vector) { - HighsInt pos = findNonzero(removerow, rowNz.index()); + double scale, const HighsMatrixSlice& rowvector) { + // extract non-zero positions + std::vector stay_rowpositions; + getRowPositions(stayrow, stay_rowpositions); + + // update postsolve information + postsolve_stack.equalityRowAddition(removerow, stayrow, scale, rowvector); + + // iterate over non-zero positions instead of iterating over the + // HighsMatrixSlice because the latter contains pointers to Acol and Avalue + // that may be invalidated if these vectors are reallocated + // (see std::vector::push_back performed in HPresolve::addToMatrix). + for (HighsInt rowiter : stay_rowpositions) { + HighsInt pos = findNonzero(removerow, Acol[rowiter]); if (pos != -1) unlink(pos); // all common nonzeros are cancelled, as the rows are // parallel else // might introduce a singleton - addToMatrix(removerow, rowNz.index(), scale * rowNz.value()); + addToMatrix(removerow, Acol[rowiter], scale * Avalue[rowiter]); } if (model->row_upper_[removerow] != kHighsInf) diff --git a/src/presolve/HPresolve.h b/src/presolve/HPresolve.h index a64bbf07fb..9781e2567b 100644 --- a/src/presolve/HPresolve.h +++ b/src/presolve/HPresolve.h @@ -212,6 +212,9 @@ class HPresolve { void toCSR(std::vector& ARval, std::vector& ARindex, std::vector& ARstart); + void getRowPositions(HighsInt row, + std::vector& myrowpositions) const; + void storeRow(HighsInt row); HighsTripletPositionSlice getStoredRow() const;