From af27bc3cc3995d9dbc3eb30bacc245b222f5ac3c Mon Sep 17 00:00:00 2001 From: fwesselm Date: Tue, 7 Jan 2025 15:27:35 +0100 Subject: [PATCH 01/19] Do not iterate over a HighsMatrixSlice while modifying the matrix (via HPresolve::addToMatrix) --- src/presolve/HPresolve.cpp | 67 +++++++++++++++++++++++++------------- src/presolve/HPresolve.h | 3 ++ 2 files changed, 47 insertions(+), 23 deletions(-) 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; From 7e9a1463c2946656bc2550c7467f6b1a4705cae4 Mon Sep 17 00:00:00 2001 From: fwesselm Date: Tue, 7 Jan 2025 16:27:54 +0100 Subject: [PATCH 02/19] Add test --- check/TestPresolve.cpp | 10 + check/instances/issue-2095.mps | 836 +++++++++++++++++++++++++++++++++ 2 files changed, 846 insertions(+) create mode 100644 check/instances/issue-2095.mps 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 From 01361bc574f00ecc14ff7d972bb60f785ae6c78e Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 11:49:33 +0000 Subject: [PATCH 03/19] cov --- CMakeLists.txt | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc485c9471..90eda6bea4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -473,6 +473,82 @@ elseif (DEBUG_MEMORY STREQUAL "Leak") -fno-omit-frame-pointer ") endif() +# HiGHS coverage update in progress + +# For the moment keep above coverage part in case we are testing at CI. +# option(CI_COV "CI extended tests" ON) + +# Coverage part +# 'make coverage' to start the coverage process +option(HIGHS_COVERAGE "Activate the code coverage compilation" OFF) + +if(HIGHS_COVERAGE) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 --coverage") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 --coverage") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O0 --coverage") + endif() + + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage -Xclang -coverage-cfg-checksum -Xclang -coverage-no-function-names-in-data -Xclang -coverage-version='408*'") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage -Xclang -coverage-cfg-checksum -Xclang -coverage-no-function-names-in-data -Xclang -coverage-version='408*'") + endif() +endif() + +if(HIGHS_COVERAGE) + if(NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") + message(FATAL_ERROR "Warning: to enable coverage, you must compile in DEBUG mode") + endif() +endif() + +if(HIGHS_COVERAGE) + if(WIN32) + message(FATAL_ERROR "Error: code coverage analysis is only available under Linux for now.") + endif() + + find_program(GCOV_PATH gcov) + find_program(LCOV_PATH lcov) + find_program(GENHTML_PATH genhtml) + + if(NOT GCOV_PATH) + message(FATAL_ERROR "gcov not found! Please install lcov and gcov. Aborting...") + endif() + + if(NOT LCOV_PATH) + message(FATAL_ERROR "lcov not found! Please install lcov and gcov. Aborting...") + endif() + + if(NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Please install lcov and gcov. Aborting...") + endif() + + # Capturing lcov counters and generating report + # if(NOT CI) + add_custom_target(coverage + COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters + COMMAND ${LCOV_PATH} --capture --initial --directory ${CMAKE_BINARY_DIR}/bin --output-file ${CMAKE_BINARY_DIR}/coverage.info + COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR} ${CMAKE_CTEST_COMMAND} -LE "(LONG|FAIL)" || true + COMMAND ${LCOV_PATH} --capture --directory ${CMAKE_BINARY_DIR}/bin --directory ${CMAKE_BINARY_DIR}/src --directory ${CMAKE_BINARY_DIR}/app --directory ${CMAKE_BINARY_DIR}/check --output-file ${CMAKE_BINARY_DIR}/coverage.info + COMMAND ${LCOV_PATH} --remove "*/usr/include/*" --output-file ${CMAKE_BINARY_DIR}/coverage.info.cleaned + COMMAND ${GENHTML_PATH} -o ${CMAKE_BINARY_DIR}/coverage ${CMAKE_BINARY_DIR}/coverage.info.cleaned + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/coverage.info.cleaned + VERBATIM + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Resetting code coverage counters to zero. + Processing code coverage counters and generating report. + You can zip the directory ${CMAKE_BINARY_DIR}/coverage and upload the content to a web server.") + # else() + # add_custom_target(ci_cov + # COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters + # COMMAND ${LCOV_PATH} --capture --initial --directory ${CMAKE_BINARY_DIR}/bin --output-file ${CMAKE_BINARY_DIR}/coverage.info + # COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR} ${CMAKE_CTEST_COMMAND} -LE "(LONG|FAIL)" || true + # COMMAND ${LCOV_PATH} --capture --directory ${CMAKE_BINARY_DIR}/bin --directory ${CMAKE_BINARY_DIR}/src --directory ${CMAKE_BINARY_DIR}/app --directory ${CMAKE_BINARY_DIR}/check --output-file ${CMAKE_BINARY_DIR}/coverage.info + # VERBATIM + # WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + # COMMENT "Resetting code coverage counters to zero.") + # endif() +endif() + if(NOT FAST_BUILD) # For the moment keep above coverage part in case we are testing at CI. option(CI "CI extended tests" ON) From dcf7f0aad9729212355244b939582676abe482ae Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 17:52:00 +0000 Subject: [PATCH 04/19] clean up --- .github/workflows/code-coverage.yml | 51 ++++++++++++++ .gitignore | 1 + CMakeLists.txt | 102 +++++++++++----------------- check/CMakeLists.txt | 38 ++++++----- cmake/cpp-highs.cmake | 26 +++---- 5 files changed, 127 insertions(+), 91 deletions(-) create mode 100644 .github/workflows/code-coverage.yml diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml new file mode 100644 index 0000000000..e4f073ca67 --- /dev/null +++ b/.github/workflows/code-coverage.yml @@ -0,0 +1,51 @@ +name: code-coverage + +on: [push, pull_request] + +jobs: + debug: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + + steps: + - uses: actions/checkout@v4 + + - name: install + run: sudo apt-get update && sudo apt-get install lcov + + - name: Create Build Environment + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure CMake + shell: bash + working-directory: ${{runner.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Debug -DHIGHS_COVERAGE=ON -DALL_TESTS=ON -DBUILD_SHARED_LIBS=OFF + + - name: Build + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + cmake --build . --parallel --config Debug + + - name: Test + working-directory: ${{runner.workspace}}/build + shell: bash + run: ctest --parallel --timeout 300 --output-on-failure + + - name: Generate report with lcov + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + lcov -d . -c -o cov.info --ignore-errors empty + lcov --remove cov.info "/usr/include/*" -o cov.info + lcov --remove cov.info "/usr/include/*" -o cov.info + lcov --remove cov.info "extern/pdqsort/*" -o cov.info + lcov --remove cov.info "extern/zstr/*" -o cov.info + lcov --remove cov.info "app/cxxopts*" -o cov.info + lcov --remove cov.info "/usr/lib/*" -o cov.info + lcov --list cov.info + + + diff --git a/.gitignore b/.gitignore index 096bc893e1..c36222e48d 100644 --- a/.gitignore +++ b/.gitignore @@ -230,6 +230,7 @@ pip-log.txt # Unit test / coverage reports .coverage +cov.info .tox #Translations diff --git a/CMakeLists.txt b/CMakeLists.txt index 90eda6bea4..3409278e60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,8 @@ if (PYTHON_BUILD_SETUP) set(ZLIB OFF) endif() +option(HIGHS_COVERAGE "Activate the code coverage compilation" OFF) + # Address | Thread | Leak # Linux atm # Only Debug is theted atm @@ -328,16 +330,18 @@ if(NOT FAST_BUILD) endif() include(CheckCXXCompilerFlag) -if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ppc64|powerpc64)" AND NOT APPLE) - check_cxx_compiler_flag("-mpopcntd" COMPILER_SUPPORTS_POPCNTD) - if(COMPILER_SUPPORTS_POPCNTD) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcntd") - endif() -else() - check_cxx_compiler_flag("-mpopcnt" COMPILER_SUPPORTS_POPCNT) - if(COMPILER_SUPPORTS_POPCNT) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcnt") - endif() +if (NOT HIGHS_COVERAGE) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ppc64|powerpc64)" AND NOT APPLE) + check_cxx_compiler_flag("-mpopcntd" COMPILER_SUPPORTS_POPCNTD) + if(COMPILER_SUPPORTS_POPCNTD) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcntd") + endif() + else() + check_cxx_compiler_flag("-mpopcnt" COMPILER_SUPPORTS_POPCNT) + if(COMPILER_SUPPORTS_POPCNT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcnt") + endif() + endif() endif() option(DEBUGSOL "check the debug solution" OFF) @@ -474,37 +478,24 @@ elseif (DEBUG_MEMORY STREQUAL "Leak") endif() # HiGHS coverage update in progress - -# For the moment keep above coverage part in case we are testing at CI. -# option(CI_COV "CI extended tests" ON) - -# Coverage part -# 'make coverage' to start the coverage process -option(HIGHS_COVERAGE "Activate the code coverage compilation" OFF) - -if(HIGHS_COVERAGE) - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 --coverage") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 --coverage") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O0 --coverage") +if(FAST_BUILD AND HIGHS_COVERAGE) + if(WIN32) + message(FATAL_ERROR "Error: code coverage analysis is only available under Linux for now.") endif() - if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage -Xclang -coverage-cfg-checksum -Xclang -coverage-no-function-names-in-data -Xclang -coverage-version='408*'") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage -Xclang -coverage-cfg-checksum -Xclang -coverage-no-function-names-in-data -Xclang -coverage-version='408*'") + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(FATAL_ERROR "Warning: to enable coverage, you must compile in Debug mode") endif() -endif() -if(HIGHS_COVERAGE) - if(NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") - message(FATAL_ERROR "Warning: to enable coverage, you must compile in DEBUG mode") - endif() -endif() + # Disable IPO + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) + message(STATUS "Building in coverage mode") -if(HIGHS_COVERAGE) - if(WIN32) - message(FATAL_ERROR "Error: code coverage analysis is only available under Linux for now.") - endif() + # Enable coverage flags + add_compile_options(-O0) + add_compile_options(--coverage) + add_link_options(-O0) + add_link_options(--coverage) # Ensure coverage data is linked correctly find_program(GCOV_PATH gcov) find_program(LCOV_PATH lcov) @@ -522,31 +513,18 @@ if(HIGHS_COVERAGE) message(FATAL_ERROR "genhtml not found! Please install lcov and gcov. Aborting...") endif() - # Capturing lcov counters and generating report - # if(NOT CI) - add_custom_target(coverage - COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters - COMMAND ${LCOV_PATH} --capture --initial --directory ${CMAKE_BINARY_DIR}/bin --output-file ${CMAKE_BINARY_DIR}/coverage.info - COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR} ${CMAKE_CTEST_COMMAND} -LE "(LONG|FAIL)" || true - COMMAND ${LCOV_PATH} --capture --directory ${CMAKE_BINARY_DIR}/bin --directory ${CMAKE_BINARY_DIR}/src --directory ${CMAKE_BINARY_DIR}/app --directory ${CMAKE_BINARY_DIR}/check --output-file ${CMAKE_BINARY_DIR}/coverage.info - COMMAND ${LCOV_PATH} --remove "*/usr/include/*" --output-file ${CMAKE_BINARY_DIR}/coverage.info.cleaned - COMMAND ${GENHTML_PATH} -o ${CMAKE_BINARY_DIR}/coverage ${CMAKE_BINARY_DIR}/coverage.info.cleaned - COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/coverage.info.cleaned - VERBATIM - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT "Resetting code coverage counters to zero. - Processing code coverage counters and generating report. - You can zip the directory ${CMAKE_BINARY_DIR}/coverage and upload the content to a web server.") - # else() - # add_custom_target(ci_cov - # COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters - # COMMAND ${LCOV_PATH} --capture --initial --directory ${CMAKE_BINARY_DIR}/bin --output-file ${CMAKE_BINARY_DIR}/coverage.info - # COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR} ${CMAKE_CTEST_COMMAND} -LE "(LONG|FAIL)" || true - # COMMAND ${LCOV_PATH} --capture --directory ${CMAKE_BINARY_DIR}/bin --directory ${CMAKE_BINARY_DIR}/src --directory ${CMAKE_BINARY_DIR}/app --directory ${CMAKE_BINARY_DIR}/check --output-file ${CMAKE_BINARY_DIR}/coverage.info - # VERBATIM - # WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - # COMMENT "Resetting code coverage counters to zero.") - # endif() + # add_custom_target(coverage + # COMMAND ${LCOV_PATH} -d bin -c -o cov.info --ignore-errors empty + # COMMAND ${LCOV_PATH} --remove "*/usr/include/*" -o ${CMAKE_BINARY_DIR}/cov.info.cleaned + # COMMAND ${LCOV_PATH} --remove "*/usr/lib/*" -o ${CMAKE_BINARY_DIR}/cov.info.cleaned + # COMMAND ${LCOV_PATH} --remove "extern/pdqsort/*" -o ${CMAKE_BINARY_DIR}/cov.info.cleaned + # COMMAND ${LCOV_PATH} --remove "extern/zstr/*" -o ${CMAKE_BINARY_DIR}/cov.info.cleaned + # COMMAND ${LCOV_PATH} --remove "app/cxxopts*" -o ${CMAKE_BINARY_DIR}/cov.info.cleaned + # COMMAND ${GENHTML_PATH} ${CMAKE_BINARY_DIR}/cov.info.cleaned -o ${CMAKE_BINARY_DIR}/cov_report + # VERBATIM + # WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + # COMMENT "Generating code coverage report v2025.") + endif() if(NOT FAST_BUILD) @@ -571,7 +549,7 @@ if(NOT FAST_BUILD) endif() if(HIGHS_COVERAGE) - if(NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") message(FATAL_ERROR "Warning: to enable coverage, you must compile in DEBUG mode") endif() endif() diff --git a/check/CMakeLists.txt b/check/CMakeLists.txt index b1076e1825..4ba1f995eb 100644 --- a/check/CMakeLists.txt +++ b/check/CMakeLists.txt @@ -129,25 +129,29 @@ if ((NOT FAST_BUILD OR ALL_TESTS) AND NOT (BUILD_EXTRA_UNIT_ONLY)) add_test(NAME capi_unit_tests COMMAND capi_unit_tests) # Check whether test executable builds OK. - add_test(NAME unit-test-build - COMMAND ${CMAKE_COMMAND} - --build ${HIGHS_BINARY_DIR} - --target unit_tests - # --config ${CMAKE_BUILD_TYPE} - ) - + if (NOT HIGHS_COVERAGE) + add_test(NAME unit-test-build + COMMAND ${CMAKE_COMMAND} + --build ${HIGHS_BINARY_DIR} + --target unit_tests + # --config ${CMAKE_BUILD_TYPE} + ) - # Avoid that several build jobs try to concurretly build. - set_tests_properties(unit-test-build - PROPERTIES - RESOURCE_LOCK unittestbin) + # Avoid that several build jobs try to concurretly build. + set_tests_properties(unit-test-build + PROPERTIES + RESOURCE_LOCK unittestbin) - # create a binary running all the tests in the executable - add_test(NAME unit_tests_all COMMAND unit_tests --success) - set_tests_properties(unit_tests_all - PROPERTIES - DEPENDS unit-test-build) - set_tests_properties(unit_tests_all PROPERTIES TIMEOUT 10000) + # create a binary running all the tests in the executable + add_test(NAME unit_tests_all COMMAND unit_tests --success) + set_tests_properties(unit_tests_all + PROPERTIES + DEPENDS unit-test-build) + set_tests_properties(unit_tests_all PROPERTIES TIMEOUT 10000) + else() + add_test(NAME unit_tests_all COMMAND unit_tests --success) + set_tests_properties(unit_tests_all PROPERTIES TIMEOUT 10000) + endif() # An individual test can be added with the command below but the approach # above with a single add_test for all the unit tests automatically detects all diff --git a/cmake/cpp-highs.cmake b/cmake/cpp-highs.cmake index 88a529a6f3..3e25a3e601 100644 --- a/cmake/cpp-highs.cmake +++ b/cmake/cpp-highs.cmake @@ -57,18 +57,20 @@ install(TARGETS highs PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/highs) # Add library targets to the build-tree export set -export(TARGETS highs - NAMESPACE ${PROJECT_NAMESPACE}::highs - FILE "${HIGHS_BINARY_DIR}/highs-targets.cmake") - -install(EXPORT ${lower}-targets - NAMESPACE ${PROJECT_NAMESPACE}:: - FILE highs-targets.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${lower}) -# install(FILES "${HIGHS_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/highs-config.cmake" -# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/highs) -# install(FILES "${HIGHS_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/highs.pc" -# DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +if (NOT HIGHS_COVERAGE) + export(TARGETS highs + NAMESPACE ${PROJECT_NAMESPACE}::highs + FILE "${HIGHS_BINARY_DIR}/highs-targets.cmake") + + install(EXPORT ${lower}-targets + NAMESPACE ${PROJECT_NAMESPACE}:: + FILE highs-targets.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${lower}) + # install(FILES "${HIGHS_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/highs-config.cmake" + # DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/highs) + # install(FILES "${HIGHS_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/highs.pc" + # DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() include(CMakePackageConfigHelpers) From 2c83d4287bb74ed6a8aba5c0d3db7549a363898b Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 18:42:51 +0000 Subject: [PATCH 05/19] atomic flag for gcov --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3409278e60..5893656b11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -494,6 +494,8 @@ if(FAST_BUILD AND HIGHS_COVERAGE) # Enable coverage flags add_compile_options(-O0) add_compile_options(--coverage) + add_compile_options(-fprofile-update=atomic) + add_link_options(-O0) add_link_options(--coverage) # Ensure coverage data is linked correctly From 379b0cca2b1029120d10f95de0527b6ce78a8097 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 19:22:51 +0000 Subject: [PATCH 06/19] clean up report --- .github/workflows/code-coverage.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index e4f073ca67..238a650710 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -40,11 +40,12 @@ jobs: run: | lcov -d . -c -o cov.info --ignore-errors empty lcov --remove cov.info "/usr/include/*" -o cov.info - lcov --remove cov.info "/usr/include/*" -o cov.info + lcov --remove cov.info "/usr/lib/*" -o cov.info lcov --remove cov.info "extern/pdqsort/*" -o cov.info lcov --remove cov.info "extern/zstr/*" -o cov.info + lcov --remove cov.info "extern/catch*" -o cov.info lcov --remove cov.info "app/cxxopts*" -o cov.info - lcov --remove cov.info "/usr/lib/*" -o cov.info + lcov --remove cov.info "src/test*" -o cov.info lcov --list cov.info From d98756c40e4e0a627d05556b3c4c246c5052ef44 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 19:40:31 +0000 Subject: [PATCH 07/19] python workflow runner version downgrade, test new on another branch. specify g++ over clang --- .github/workflows/build-python-package.yml | 8 ++++---- .github/workflows/code-coverage.yml | 9 +++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index 0b6c32f2fe..b308628b0d 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -78,12 +78,12 @@ jobs: # ubuntu 22 has a latest version of cmake, but setup-python # does not seem to provide all necessary modules to find python # from cmake. works on my machine, test the wheels manually - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - # strategy: - # matrix: - # python: [3.12] + strategy: + matrix: + python: [3.10] - name: Install correct python version uses: actions/setup-python@v5 diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 238a650710..f26f1bb002 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -21,7 +21,7 @@ jobs: - name: Configure CMake shell: bash working-directory: ${{runner.workspace}}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Debug -DHIGHS_COVERAGE=ON -DALL_TESTS=ON -DBUILD_SHARED_LIBS=OFF + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Debug -DHIGHS_COVERAGE=ON -DALL_TESTS=ON -DBUILD_SHARED_LIBS=OFF -D CMAKE_C_COMPILER=gcc -D CMAKE_CXX_COMPILER=g++ - name: Build working-directory: ${{runner.workspace}}/build @@ -48,5 +48,10 @@ jobs: lcov --remove cov.info "src/test*" -o cov.info lcov --list cov.info - + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: ERGO-Code/HiGHS + From 8cb0334f9635c4fe84c03ca0ca3b83733d406331 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 20:00:59 +0000 Subject: [PATCH 08/19] typo python linux wheel update' --- .github/workflows/build-python-package.yml | 7 ++----- .github/workflows/code-coverage.yml | 5 +++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index b308628b0d..10bd81539a 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -81,14 +81,11 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - strategy: - matrix: - python: [3.10] - name: Install correct python version uses: actions/setup-python@v5 - # with: - # python-version: ${{ matrix.python }} + with: + python-version: 3.10 - name: Build wheel run: | diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index f26f1bb002..649e078490 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -53,5 +53,10 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} slug: ERGO-Code/HiGHS + fail_ci_if_error: true # optional (default = false) + files: ${{runner.workspace}}/build/cov.info # optional + # name: codecov-umbrella # optional + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true # optional (default = false) From 3d413c67f0a1bbfd1bc55d2841eb7ec21c192a28 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 20:14:12 +0000 Subject: [PATCH 09/19] python version: --- .github/workflows/build-python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index 10bd81539a..33bd47786f 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -85,7 +85,7 @@ jobs: - name: Install correct python version uses: actions/setup-python@v5 with: - python-version: 3.10 + python-version: '3.10' - name: Build wheel run: | From 780cd347547cf5e0b174eae56b6e1f27d3de6e46 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 20:16:15 +0000 Subject: [PATCH 10/19] coverage fix duplicate tag --- .github/workflows/code-coverage.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 649e078490..2b9b5807d0 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -56,7 +56,6 @@ jobs: fail_ci_if_error: true # optional (default = false) files: ${{runner.workspace}}/build/cov.info # optional # name: codecov-umbrella # optional - token: ${{ secrets.CODECOV_TOKEN }} verbose: true # optional (default = false) From 6157752daab754e67fc466eeabc8b55891ddbe2d Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 20:52:30 +0000 Subject: [PATCH 11/19] try secret again --- .github/workflows/code-coverage.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 2b9b5807d0..277bd96587 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -57,5 +57,3 @@ jobs: files: ${{runner.workspace}}/build/cov.info # optional # name: codecov-umbrella # optional verbose: true # optional (default = false) - - From f3290dfd6919f3a46361214f53f50448b816db3b Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 21:11:43 +0000 Subject: [PATCH 12/19] Coverage locally for now. --- .github/workflows/code-coverage.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 277bd96587..7d643204cc 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -48,12 +48,14 @@ jobs: lcov --remove cov.info "src/test*" -o cov.info lcov --list cov.info - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - slug: ERGO-Code/HiGHS - fail_ci_if_error: true # optional (default = false) - files: ${{runner.workspace}}/build/cov.info # optional - # name: codecov-umbrella # optional - verbose: true # optional (default = false) + # Made it past the first token issue. + # May need some more time to porpagate on the codecov side. + # - name: Upload coverage reports to Codecov + # uses: codecov/codecov-action@v5 + # with: + # token: ${{ secrets.CODECOV_TOKEN }} + # slug: ERGO-Code/HiGHS + # fail_ci_if_error: true # optional (default = false) + # files: ${{runner.workspace}}/build/cov.info # optional + # # name: codecov-umbrella # optional + # verbose: true # optional (default = false) From df7ca0ae21bad5029c3f32c1a1c9fb24e9f72fd4 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 21:13:36 +0000 Subject: [PATCH 13/19] publish wheels to pypi on release re-enable --- .github/workflows/build-wheels-push.yml | 78 ++++++++++++------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/.github/workflows/build-wheels-push.yml b/.github/workflows/build-wheels-push.yml index 899d865c9a..b38ebd2280 100644 --- a/.github/workflows/build-wheels-push.yml +++ b/.github/workflows/build-wheels-push.yml @@ -1,12 +1,12 @@ name: build-wheels-push -on: [] +# on: [] # on: push -# on: -# release: -# types: -# - published +on: + release: + types: + - published concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -82,51 +82,22 @@ jobs: name: cibw-wheels-${{ matrix.python }}-${{ matrix.buildplat[1] }} path: wheelhouse/*.whl - upload_testpypi: - name: >- - Publish highspy to TestPyPI - runs-on: ubuntu-latest - needs: [build_wheels, build_sdist] - # needs: [build_sdist] - - # upload to PyPI on every tag starting with 'v' - # if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') - - environment: - name: testpypi - url: https://test.pypi.org/p/highspy - - permissions: - id-token: write # IMPORTANT: mandatory for trusted publishing - steps: - - uses: actions/download-artifact@v4 - with: - pattern: cibw-* - path: dist - merge-multiple: true - - - name: Download all - uses: pypa/gh-action-pypi-publish@release/v1 - with: - repository-url: https://test.pypi.org/legacy/ - verbose: true - - # upload_pypi: + # upload_testpypi: # name: >- - # Publish highspy to PyPI + # Publish highspy to TestPyPI # runs-on: ubuntu-latest # needs: [build_wheels, build_sdist] + # # needs: [build_sdist] # # upload to PyPI on every tag starting with 'v' # # if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') # environment: - # name: pypi - # url: https://pypi.org/p/highspy + # name: testpypi + # url: https://test.pypi.org/p/highspy # permissions: # id-token: write # IMPORTANT: mandatory for trusted publishing - # steps: # - uses: actions/download-artifact@v4 # with: @@ -136,3 +107,32 @@ jobs: # - name: Download all # uses: pypa/gh-action-pypi-publish@release/v1 + # with: + # repository-url: https://test.pypi.org/legacy/ + # verbose: true + + upload_pypi: + name: >- + Publish highspy to PyPI + runs-on: ubuntu-latest + needs: [build_wheels, build_sdist] + + # upload to PyPI on every tag starting with 'v' + # if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + + environment: + name: pypi + url: https://pypi.org/p/highspy + + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + + steps: + - uses: actions/download-artifact@v4 + with: + pattern: cibw-* + path: dist + merge-multiple: true + + - name: Download all + uses: pypa/gh-action-pypi-publish@release/v1 From dee9dc1c8c8e6732e86c63480cb0f368bdfae3cd Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Wed, 8 Jan 2025 21:21:26 +0000 Subject: [PATCH 14/19] update condition for legacy coverage --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5893656b11..7da1d94a62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -494,7 +494,7 @@ if(FAST_BUILD AND HIGHS_COVERAGE) # Enable coverage flags add_compile_options(-O0) add_compile_options(--coverage) - add_compile_options(-fprofile-update=atomic) + # add_compile_options(-fprofile-update=atomic) add_link_options(-O0) add_link_options(--coverage) # Ensure coverage data is linked correctly @@ -551,7 +551,7 @@ if(NOT FAST_BUILD) endif() if(HIGHS_COVERAGE) - if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") message(FATAL_ERROR "Warning: to enable coverage, you must compile in DEBUG mode") endif() endif() From f1d72f3cdd117dd92396589d360a301a97cf8b10 Mon Sep 17 00:00:00 2001 From: JAJHall Date: Thu, 9 Jan 2025 08:24:51 +0000 Subject: [PATCH 15/19] Updated FEATURES.md and docs/src/options/definitions.md --- FEATURES.md | 5 +++++ app/RunHighs.cpp | 2 +- docs/src/options/definitions.md | 30 +++++++++++++++++++++++++++++- src/lp_data/HighsOptions.h | 28 ++++++++++++++-------------- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index e3c62da2c9..bc7bf6d82c 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -10,4 +10,9 @@ Added basis solve methods to highspy Added methods to get primal/dual ray and dual unboundedness direction to highspy +When a presolved LP has model status kUnknown, rather than returning this to the user, it performs postsolve and then uses the basis to solve the original LP + +Fixed bug in presolve when pointers stored in HighsMatrixSlice get invalidated when the coefficient matrix is reallocated (e.g. when non-zeros are added in HPresolve::addToMatrix) + +Primal and dual residual tolerances - applied following IPM or PDLP solution - now documented as options diff --git a/app/RunHighs.cpp b/app/RunHighs.cpp index 8813755b4c..f238bc1adc 100644 --- a/app/RunHighs.cpp +++ b/app/RunHighs.cpp @@ -46,7 +46,7 @@ int main(int argc, char** argv) { // call this first so that printHighsVersionCopyright uses reporting // settings defined in any options file. highs.passOptions(loaded_options); - // highs.writeOptions("Options.md"); + highs.writeOptions("Options.md"); // Load the model from model_file HighsStatus read_status = highs.readModel(model_file); diff --git a/docs/src/options/definitions.md b/docs/src/options/definitions.md index f4e932523c..92ac80c889 100644 --- a/docs/src/options/definitions.md +++ b/docs/src/options/definitions.md @@ -73,6 +73,18 @@ - Range: [1e-12, inf] - Default: 1e-08 +## primal\_residual\_tolerance +- Primal residual tolerance +- Type: double +- Range: [1e-10, inf] +- Default: 1e-07 + +## dual\_residual\_tolerance +- Dual residual tolerance +- Type: double +- Range: [1e-10, inf] +- Default: 1e-07 + ## objective\_bound - Objective bound for termination of the dual simplex solver - Type: double @@ -198,6 +210,16 @@ - Type: boolean - Default: "false" +## write\_presolved\_model\_file +- Write presolved model file +- Type: string +- Default: "" + +## write\_presolved\_model\_to\_file +- Write the presolved model to a file +- Type: boolean +- Default: "false" + ## mip\_detect\_symmetry - Whether MIP symmetry should be detected - Type: boolean @@ -220,6 +242,12 @@ - Range: {0, 2147483647} - Default: 2147483647 +## mip\_max\_start\_nodes +- MIP solver max number of nodes when completing a partial MIP start +- Type: integer +- Range: {0, 2147483647} +- Default: 500 + ## mip\_improving\_solution\_save - Whether improving MIP solutions should be saved - Type: boolean @@ -354,7 +382,7 @@ - Default: 4000 ## blend\_multi\_objectives -- Blend multiple objectives or apply lexicographically +- Blend multiple objectives or apply lexicographically: Default = true - Type: boolean - Default: "true" diff --git a/src/lp_data/HighsOptions.h b/src/lp_data/HighsOptions.h index eb315b8bcd..842f432b00 100644 --- a/src/lp_data/HighsOptions.h +++ b/src/lp_data/HighsOptions.h @@ -299,6 +299,8 @@ struct HighsOptionsStruct { double primal_feasibility_tolerance; double dual_feasibility_tolerance; double ipm_optimality_tolerance; + double primal_residual_tolerance; + double dual_residual_tolerance; double objective_bound; double objective_target; HighsInt threads; @@ -390,8 +392,6 @@ struct HighsOptionsStruct { bool less_infeasible_DSE_choose_row; bool use_original_HFactor_logic; bool run_centring; - double primal_residual_tolerance; - double dual_residual_tolerance; HighsInt max_centring_steps; double centring_ratio_tolerance; @@ -452,6 +452,8 @@ struct HighsOptionsStruct { primal_feasibility_tolerance(0.0), dual_feasibility_tolerance(0.0), ipm_optimality_tolerance(0.0), + primal_residual_tolerance(0.0), + dual_residual_tolerance(0.0), objective_bound(0.0), objective_target(0.0), threads(0), @@ -528,8 +530,6 @@ struct HighsOptionsStruct { less_infeasible_DSE_choose_row(false), use_original_HFactor_logic(false), run_centring(false), - primal_residual_tolerance(0.0), - dual_residual_tolerance(0.0), max_centring_steps(0), centring_ratio_tolerance(0.0), icrash(false), @@ -707,6 +707,16 @@ class HighsOptions : public HighsOptionsStruct { &ipm_optimality_tolerance, 1e-12, 1e-8, kHighsInf); records.push_back(record_double); + record_double = new OptionRecordDouble( + "primal_residual_tolerance", "Primal residual tolerance", advanced, + &primal_residual_tolerance, 1e-10, 1e-7, kHighsInf); + records.push_back(record_double); + + record_double = new OptionRecordDouble( + "dual_residual_tolerance", "Dual residual tolerance", advanced, + &dual_residual_tolerance, 1e-10, 1e-7, kHighsInf); + records.push_back(record_double); + record_double = new OptionRecordDouble( "objective_bound", "Objective bound for termination of the dual simplex solver", advanced, @@ -1399,16 +1409,6 @@ class HighsOptions : public HighsOptionsStruct { advanced, ¢ring_ratio_tolerance, 0, 100, kHighsInf); records.push_back(record_double); - record_double = new OptionRecordDouble( - "primal_residual_tolerance", "Primal residual tolerance", advanced, - &primal_residual_tolerance, 1e-10, 1e-7, kHighsInf); - records.push_back(record_double); - - record_double = new OptionRecordDouble( - "dual_residual_tolerance", "Dual residual tolerance", advanced, - &dual_residual_tolerance, 1e-10, 1e-7, kHighsInf); - records.push_back(record_double); - // Set up the log_options aliases log_options.clear(); log_options.log_stream = From d865e6a5eb99c8064da5f04b4033d40ffdebeefd Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Tue, 7 Jan 2025 18:29:38 +0530 Subject: [PATCH 16/19] BUG: Localize everything to prevent highspy errors Closes scipy-gh-22257 --- src/highs_bindings.cpp | 90 +++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/highs_bindings.cpp b/src/highs_bindings.cpp index c9b6c42269..07e54ec244 100644 --- a/src/highs_bindings.cpp +++ b/src/highs_bindings.cpp @@ -886,27 +886,27 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { // parent scope, which should be skipped for newer C++11-style strongly typed // enums." // [1]: https://pybind11.readthedocs.io/en/stable/classes.html - py::enum_(m, "ObjSense") + py::enum_(m, "ObjSense", py::module_local()) .value("kMinimize", ObjSense::kMinimize) .value("kMaximize", ObjSense::kMaximize); - py::enum_(m, "MatrixFormat") + py::enum_(m, "MatrixFormat", py::module_local()) .value("kColwise", MatrixFormat::kColwise) .value("kRowwise", MatrixFormat::kRowwise) .value("kRowwisePartitioned", MatrixFormat::kRowwisePartitioned); - py::enum_(m, "HessianFormat") + py::enum_(m, "HessianFormat", py::module_local()) .value("kTriangular", HessianFormat::kTriangular) .value("kSquare", HessianFormat::kSquare); - py::enum_(m, "SolutionStatus") + py::enum_(m, "SolutionStatus", py::module_local()) .value("kSolutionStatusNone", SolutionStatus::kSolutionStatusNone) .value("kSolutionStatusInfeasible", SolutionStatus::kSolutionStatusInfeasible) .value("kSolutionStatusFeasible", SolutionStatus::kSolutionStatusFeasible) .export_values(); - py::enum_(m, "BasisValidity") + py::enum_(m, "BasisValidity", py::module_local()) .value("kBasisValidityInvalid", BasisValidity::kBasisValidityInvalid) .value("kBasisValidityValid", BasisValidity::kBasisValidityValid) .export_values(); - py::enum_(m, "HighsModelStatus") + py::enum_(m, "HighsModelStatus", py::module_local()) .value("kNotset", HighsModelStatus::kNotset) .value("kLoadError", HighsModelStatus::kLoadError) .value("kModelError", HighsModelStatus::kModelError) @@ -926,7 +926,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kSolutionLimit", HighsModelStatus::kSolutionLimit) .value("kInterrupt", HighsModelStatus::kInterrupt) .value("kMemoryLimit", HighsModelStatus::kMemoryLimit); - py::enum_(m, "HighsPresolveStatus") + py::enum_(m, "HighsPresolveStatus", py::module_local()) .value("kNotPresolved", HighsPresolveStatus::kNotPresolved) .value("kNotReduced", HighsPresolveStatus::kNotReduced) .value("kInfeasible", HighsPresolveStatus::kInfeasible) @@ -937,37 +937,37 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kTimeout", HighsPresolveStatus::kTimeout) .value("kNullError", HighsPresolveStatus::kNullError) .value("kOptionsError", HighsPresolveStatus::kOptionsError); - py::enum_(m, "HighsBasisStatus") + py::enum_(m, "HighsBasisStatus", py::module_local()) .value("kLower", HighsBasisStatus::kLower) .value("kBasic", HighsBasisStatus::kBasic) .value("kUpper", HighsBasisStatus::kUpper) .value("kZero", HighsBasisStatus::kZero) .value("kNonbasic", HighsBasisStatus::kNonbasic); - py::enum_(m, "HighsVarType") + py::enum_(m, "HighsVarType", py::module_local()) .value("kContinuous", HighsVarType::kContinuous) .value("kInteger", HighsVarType::kInteger) .value("kSemiContinuous", HighsVarType::kSemiContinuous) .value("kSemiInteger", HighsVarType::kSemiInteger); - py::enum_(m, "HighsOptionType") + py::enum_(m, "HighsOptionType", py::module_local()) .value("kBool", HighsOptionType::kBool) .value("kInt", HighsOptionType::kInt) .value("kDouble", HighsOptionType::kDouble) .value("kString", HighsOptionType::kString); - py::enum_(m, "HighsInfoType") + py::enum_(m, "HighsInfoType", py::module_local()) .value("kInt64", HighsInfoType::kInt64) .value("kInt", HighsInfoType::kInt) .value("kDouble", HighsInfoType::kDouble); - py::enum_(m, "HighsStatus") + py::enum_(m, "HighsStatus", py::module_local()) .value("kError", HighsStatus::kError) .value("kOk", HighsStatus::kOk) .value("kWarning", HighsStatus::kWarning); - py::enum_(m, "HighsLogType") + py::enum_(m, "HighsLogType", py::module_local()) .value("kInfo", HighsLogType::kInfo) .value("kDetailed", HighsLogType::kDetailed) .value("kVerbose", HighsLogType::kVerbose) .value("kWarning", HighsLogType::kWarning) .value("kError", HighsLogType::kError); - py::enum_(m, "IisStrategy") + py::enum_(m, "IisStrategy", py::module_local()) .value("kIisStrategyMin", IisStrategy::kIisStrategyMin) .value("kIisStrategyFromLpRowPriority", IisStrategy::kIisStrategyFromLpRowPriority) @@ -975,7 +975,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { IisStrategy::kIisStrategyFromLpColPriority) .value("kIisStrategyMax", IisStrategy::kIisStrategyMax) .export_values(); - py::enum_(m, "IisBoundStatus") + py::enum_(m, "IisBoundStatus", py::module_local()) .value("kIisBoundStatusDropped", IisBoundStatus::kIisBoundStatusDropped) .value("kIisBoundStatusNull", IisBoundStatus::kIisBoundStatusNull) .value("kIisBoundStatusFree", IisBoundStatus::kIisBoundStatusFree) @@ -983,7 +983,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kIisBoundStatusUpper", IisBoundStatus::kIisBoundStatusUpper) .value("kIisBoundStatusBoxed", IisBoundStatus::kIisBoundStatusBoxed) .export_values(); - py::enum_(m, "HighsDebugLevel") + py::enum_(m, "HighsDebugLevel", py::module_local()) .value("kHighsDebugLevelNone", HighsDebugLevel::kHighsDebugLevelNone) .value("kHighsDebugLevelCheap", HighsDebugLevel::kHighsDebugLevelCheap) .value("kHighsDebugLevelCostly", HighsDebugLevel::kHighsDebugLevelCostly) @@ -992,7 +992,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kHighsDebugLevelMax", HighsDebugLevel::kHighsDebugLevelMax) .export_values(); // Classes - py::class_(m, "HighsSparseMatrix") + py::class_(m, "HighsSparseMatrix", py::module_local()) .def(py::init<>()) .def_readwrite("format_", &HighsSparseMatrix::format_) .def_readwrite("num_col_", &HighsSparseMatrix::num_col_) @@ -1001,9 +1001,9 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("p_end_", &HighsSparseMatrix::p_end_) .def_readwrite("index_", &HighsSparseMatrix::index_) .def_readwrite("value_", &HighsSparseMatrix::value_); - py::class_(m, "HighsLpMods"); - py::class_(m, "HighsScale"); - py::class_(m, "HighsLp") + py::class_(m, "HighsLpMods", py::module_local()); + py::class_(m, "HighsScale", py::module_local()); + py::class_(m, "HighsLp", py::module_local()) .def(py::init<>()) .def_readwrite("num_col_", &HighsLp::num_col_) .def_readwrite("num_row_", &HighsLp::num_row_) @@ -1023,18 +1023,18 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("is_scaled_", &HighsLp::is_scaled_) .def_readwrite("is_moved_", &HighsLp::is_moved_) .def_readwrite("mods_", &HighsLp::mods_); - py::class_(m, "HighsHessian") + py::class_(m, "HighsHessian", py::module_local()) .def(py::init<>()) .def_readwrite("dim_", &HighsHessian::dim_) .def_readwrite("format_", &HighsHessian::format_) .def_readwrite("start_", &HighsHessian::start_) .def_readwrite("index_", &HighsHessian::index_) .def_readwrite("value_", &HighsHessian::value_); - py::class_(m, "HighsModel") + py::class_(m, "HighsModel", py::module_local()) .def(py::init<>()) .def_readwrite("lp_", &HighsModel::lp_) .def_readwrite("hessian_", &HighsModel::hessian_); - py::class_(m, "HighsInfo") + py::class_(m, "HighsInfo", py::module_local()) .def(py::init<>()) .def_readwrite("valid", &HighsInfo::valid) .def_readwrite("mip_node_count", &HighsInfo::mip_node_count) @@ -1073,7 +1073,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { &HighsInfo::sum_complementarity_violations) .def_readwrite("primal_dual_integral", &HighsInfo::primal_dual_integral); - py::class_(m, "HighsOptions") + py::class_(m, "HighsOptions", py::module_local()) .def(py::init<>()) .def_readwrite("presolve", &HighsOptions::presolve) .def_readwrite("solver", &HighsOptions::solver) @@ -1161,7 +1161,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { &HighsOptions::mip_heuristic_effort) .def_readwrite("mip_min_logging_interval", &HighsOptions::mip_min_logging_interval); - py::class_(m, "_Highs") + py::class_(m, "_Highs", py::module_local()) .def(py::init<>()) .def("version", &Highs::version) .def("versionMajor", &Highs::versionMajor) @@ -1356,7 +1356,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def("stopCallbackInt", static_cast( &Highs::stopCallback)); - py::class_(m, "HighsIis") + py::class_(m, "HighsIis", py::module_local()) .def(py::init<>()) .def("invalidate", &HighsIis::invalidate) .def_readwrite("valid", &HighsIis::valid_) @@ -1367,7 +1367,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("row_bound", &HighsIis::row_bound_) .def_readwrite("info", &HighsIis::info_); // structs - py::class_(m, "HighsSolution") + py::class_(m, "HighsSolution", py::module_local()) .def(py::init<>()) .def_readwrite("value_valid", &HighsSolution::value_valid) .def_readwrite("dual_valid", &HighsSolution::dual_valid) @@ -1375,11 +1375,11 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("col_dual", &HighsSolution::col_dual) .def_readwrite("row_value", &HighsSolution::row_value) .def_readwrite("row_dual", &HighsSolution::row_dual); - py::class_(m, "HighsObjectiveSolution") + py::class_(m, "HighsObjectiveSolution", py::module_local()) .def(py::init<>()) .def_readwrite("objective", &HighsObjectiveSolution::objective) .def_readwrite("col_value", &HighsObjectiveSolution::col_value); - py::class_(m, "HighsBasis") + py::class_(m, "HighsBasis", py::module_local()) .def(py::init<>()) .def_readwrite("valid", &HighsBasis::valid) .def_readwrite("alien", &HighsBasis::alien) @@ -1389,13 +1389,13 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("debug_origin_name", &HighsBasis::debug_origin_name) .def_readwrite("col_status", &HighsBasis::col_status) .def_readwrite("row_status", &HighsBasis::row_status); - py::class_(m, "HighsRangingRecord") + py::class_(m, "HighsRangingRecord", py::module_local()) .def(py::init<>()) .def_readwrite("value_", &HighsRangingRecord::value_) .def_readwrite("objective_", &HighsRangingRecord::objective_) .def_readwrite("in_var_", &HighsRangingRecord::in_var_) .def_readwrite("ou_var_", &HighsRangingRecord::ou_var_); - py::class_(m, "HighsRanging") + py::class_(m, "HighsRanging", py::module_local()) .def(py::init<>()) .def_readwrite("valid", &HighsRanging::valid) .def_readwrite("col_cost_up", &HighsRanging::col_cost_up) @@ -1404,7 +1404,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("col_bound_dn", &HighsRanging::col_bound_dn) .def_readwrite("row_bound_up", &HighsRanging::row_bound_up) .def_readwrite("row_bound_dn", &HighsRanging::row_bound_dn); - py::class_(m, "HighsIisInfo") + py::class_(m, "HighsIisInfo", py::module_local()) .def(py::init<>()) .def_readwrite("simplex_time", &HighsIisInfo::simplex_time) .def_readwrite("simplex_iterations", &HighsIisInfo::simplex_iterations); @@ -1428,7 +1428,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { py::module_ simplex_constants = m.def_submodule("simplex_constants", "Submodule for simplex constants"); - py::enum_(simplex_constants, "SimplexStrategy") + py::enum_(simplex_constants, "SimplexStrategy", py::module_local()) .value("kSimplexStrategyMin", SimplexStrategy::kSimplexStrategyMin) .value("kSimplexStrategyChoose", SimplexStrategy::kSimplexStrategyChoose) .value("kSimplexStrategyDual", SimplexStrategy::kSimplexStrategyDual) @@ -1443,7 +1443,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kSimplexStrategyNum", SimplexStrategy::kSimplexStrategyNum) .export_values(); py::enum_(simplex_constants, - "SimplexUnscaledSolutionStrategy") + "SimplexUnscaledSolutionStrategy", py::module_local()) .value( "kSimplexUnscaledSolutionStrategyMin", SimplexUnscaledSolutionStrategy::kSimplexUnscaledSolutionStrategyMin) @@ -1463,7 +1463,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { "kSimplexUnscaledSolutionStrategyNum", SimplexUnscaledSolutionStrategy::kSimplexUnscaledSolutionStrategyNum) .export_values(); - py::enum_(simplex_constants, "SimplexSolvePhase") + py::enum_(simplex_constants, "SimplexSolvePhase", py::module_local()) .value("kSolvePhaseMin", SimplexSolvePhase::kSolvePhaseMin) .value("kSolvePhaseError", SimplexSolvePhase::kSolvePhaseError) .value("kSolvePhaseExit", SimplexSolvePhase::kSolvePhaseExit) @@ -1479,7 +1479,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kSolvePhaseMax", SimplexSolvePhase::kSolvePhaseMax) .export_values(); py::enum_(simplex_constants, - "SimplexEdgeWeightStrategy") + "SimplexEdgeWeightStrategy", py::module_local()) .value("kSimplexEdgeWeightStrategyMin", SimplexEdgeWeightStrategy::kSimplexEdgeWeightStrategyMin) .value("kSimplexEdgeWeightStrategyChoose", @@ -1493,7 +1493,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kSimplexEdgeWeightStrategyMax", SimplexEdgeWeightStrategy::kSimplexEdgeWeightStrategyMax) .export_values(); - py::enum_(simplex_constants, "SimplexPriceStrategy") + py::enum_(simplex_constants, "SimplexPriceStrategy", py::module_local()) .value("kSimplexPriceStrategyMin", SimplexPriceStrategy::kSimplexPriceStrategyMin) .value("kSimplexPriceStrategyCol", @@ -1508,7 +1508,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { SimplexPriceStrategy::kSimplexPriceStrategyMax) .export_values(); py::enum_( - simplex_constants, "SimplexPivotalRowRefinementStrategy") + simplex_constants, "SimplexPivotalRowRefinementStrategy", py::module_local()) .value("kSimplexInfeasibilityProofRefinementMin", SimplexPivotalRowRefinementStrategy:: kSimplexInfeasibilityProofRefinementMin) @@ -1526,7 +1526,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { kSimplexInfeasibilityProofRefinementMax) .export_values(); py::enum_(simplex_constants, - "SimplexPrimalCorrectionStrategy") + "SimplexPrimalCorrectionStrategy", py::module_local()) .value( "kSimplexPrimalCorrectionStrategyNone", SimplexPrimalCorrectionStrategy::kSimplexPrimalCorrectionStrategyNone) @@ -1537,7 +1537,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { SimplexPrimalCorrectionStrategy:: kSimplexPrimalCorrectionStrategyAlways) .export_values(); - py::enum_(simplex_constants, "SimplexNlaOperation") + py::enum_(simplex_constants, "SimplexNlaOperation", py::module_local()) .value("kSimplexNlaNull", SimplexNlaOperation::kSimplexNlaNull) .value("kSimplexNlaBtranFull", SimplexNlaOperation::kSimplexNlaBtranFull) .value("kSimplexNlaPriceFull", SimplexNlaOperation::kSimplexNlaPriceFull) @@ -1554,14 +1554,14 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kNumSimplexNlaOperation", SimplexNlaOperation::kNumSimplexNlaOperation) .export_values(); - py::enum_(simplex_constants, "EdgeWeightMode") + py::enum_(simplex_constants, "EdgeWeightMode", py::module_local()) .value("kDantzig", EdgeWeightMode::kDantzig) .value("kDevex", EdgeWeightMode::kDevex) .value("kSteepestEdge", EdgeWeightMode::kSteepestEdge) .value("kCount", EdgeWeightMode::kCount); py::module_ callbacks = m.def_submodule("cb", "Callback interface submodule"); // Types for interface - py::enum_(callbacks, "HighsCallbackType") + py::enum_(callbacks, "HighsCallbackType", py::module_local()) .value("kCallbackMin", HighsCallbackType::kCallbackMin) .value("kCallbackLogging", HighsCallbackType::kCallbackLogging) .value("kCallbackSimplexInterrupt", @@ -1580,12 +1580,12 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kNumCallbackType", HighsCallbackType::kNumCallbackType) .export_values(); // Classes - py::class_>(m, "readonly_ptr_wrapper_double") + py::class_>(m, "readonly_ptr_wrapper_double", py::module_local()) .def(py::init()) .def("__getitem__", &readonly_ptr_wrapper::operator[]) .def("__bool__", &readonly_ptr_wrapper::is_valid) .def("to_array", &readonly_ptr_wrapper::to_array); - py::class_(callbacks, "HighsCallbackDataOut") + py::class_(callbacks, "HighsCallbackDataOut", py::module_local()) .def(py::init<>()) .def_readwrite("log_type", &HighsCallbackDataOut::log_type) .def_readwrite("running_time", &HighsCallbackDataOut::running_time) @@ -1607,7 +1607,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { [](const HighsCallbackDataOut& self) -> readonly_ptr_wrapper { return readonly_ptr_wrapper(self.mip_solution); }); - py::class_(callbacks, "HighsCallbackDataIn") + py::class_(callbacks, "HighsCallbackDataIn", py::module_local()) .def(py::init<>()) .def_readwrite("user_interrupt", &HighsCallbackDataIn::user_interrupt); } From b559b8219f2308c875bc1ac0b237765488d82438 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Thu, 9 Jan 2025 17:48:04 +0530 Subject: [PATCH 17/19] MAINT: Localize HighsLinearObjective --- src/highs_bindings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/highs_bindings.cpp b/src/highs_bindings.cpp index 07e54ec244..d4c7ad0ebe 100644 --- a/src/highs_bindings.cpp +++ b/src/highs_bindings.cpp @@ -1408,7 +1408,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def(py::init<>()) .def_readwrite("simplex_time", &HighsIisInfo::simplex_time) .def_readwrite("simplex_iterations", &HighsIisInfo::simplex_iterations); - py::class_(m, "HighsLinearObjective") + py::class_(m, "HighsLinearObjective", py::module_local()) .def(py::init<>()) .def_readwrite("weight", &HighsLinearObjective::weight) .def_readwrite("offset", &HighsLinearObjective::offset) From c462546210111b8c1709aac4044013c7a80a8eb0 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Thu, 9 Jan 2025 14:37:40 +0000 Subject: [PATCH 18/19] missing flag for atomic --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7da1d94a62..6ef2d28cdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -494,7 +494,7 @@ if(FAST_BUILD AND HIGHS_COVERAGE) # Enable coverage flags add_compile_options(-O0) add_compile_options(--coverage) - # add_compile_options(-fprofile-update=atomic) + add_compile_options(-fprofile-update=atomic) add_link_options(-O0) add_link_options(--coverage) # Ensure coverage data is linked correctly From 5d6197a2b5241219c97d7114f0857846949735d2 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Thu, 9 Jan 2025 15:03:49 +0000 Subject: [PATCH 19/19] genhtml --- .github/workflows/code-coverage.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 7d643204cc..e4540f2173 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -34,7 +34,7 @@ jobs: shell: bash run: ctest --parallel --timeout 300 --output-on-failure - - name: Generate report with lcov + - name: Generate Report working-directory: ${{runner.workspace}}/build shell: bash run: | @@ -48,6 +48,12 @@ jobs: lcov --remove cov.info "src/test*" -o cov.info lcov --list cov.info + - name: Genhtml Results Summary + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + genhtml -o coverage cov.info + # Made it past the first token issue. # May need some more time to porpagate on the codecov side. # - name: Upload coverage reports to Codecov