From e9525346e36552686c6f9266c7388791bb27cb0b Mon Sep 17 00:00:00 2001 From: fwesselm Date: Wed, 11 Dec 2024 15:55:52 +0100 Subject: [PATCH 1/7] Fix detection of implied integral (already integer-constrained) variables and implicit (continuous) integer variables --- subprojects/highs/src/presolve/HPresolve.cpp | 24 +++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/subprojects/highs/src/presolve/HPresolve.cpp b/subprojects/highs/src/presolve/HPresolve.cpp index 5360c9e..d6dd158 100644 --- a/subprojects/highs/src/presolve/HPresolve.cpp +++ b/subprojects/highs/src/presolve/HPresolve.cpp @@ -223,6 +223,7 @@ void HPresolve::dualImpliedFreeGetRhsAndRowType( } bool HPresolve::isImpliedIntegral(HighsInt col) { + // check if the integer constraint on a variable is implied by the model bool runDualDetection = true; assert(model->integrality_[col] == HighsVarType::kInteger); @@ -263,10 +264,15 @@ bool HPresolve::isImpliedIntegral(HighsInt col) { if (!runDualDetection) return false; + bool impliedIntegral = true; for (const HighsSliceNonzero& nz : getColumnVector(col)) { double scale = 1.0 / nz.value(); - if (!rowCoefficientsIntegral(nz.index(), scale)) return false; + // if row coefficients are not integral, variable is not (implied) integral + bool rowIntegral = rowCoefficientsIntegral(nz.index(), scale); + impliedIntegral = impliedIntegral && rowIntegral; + if (!rowIntegral) continue; if (model->row_upper_[nz.index()] != kHighsInf) { + // scale, round down and unscale right-hand side again double rUpper = std::abs(nz.value()) * std::floor(model->row_upper_[nz.index()] * std::abs(scale) + @@ -276,24 +282,26 @@ bool HPresolve::isImpliedIntegral(HighsInt col) { model->row_upper_[nz.index()] = rUpper; markChangedRow(nz.index()); } - } else { - assert(model->row_lower_[nz.index()] != -kHighsInf); + } + if (model->row_lower_[nz.index()] != -kHighsInf) { + // scale, round up and unscale left-hand side again double rLower = std::abs(nz.value()) * - std::ceil(model->row_upper_[nz.index()] * std::abs(scale) - + std::ceil(model->row_lower_[nz.index()] * std::abs(scale) - primal_feastol); if (std::abs(model->row_lower_[nz.index()] - rLower) > options->small_matrix_value) { - model->row_upper_[nz.index()] = rLower; + model->row_lower_[nz.index()] = rLower; markChangedRow(nz.index()); } } } - return true; + return impliedIntegral; } bool HPresolve::isImpliedInteger(HighsInt col) { + // check if a non-integer variable is implied integer bool runDualDetection = true; assert(model->integrality_[col] == HighsVarType::kContinuous); @@ -345,11 +353,11 @@ bool HPresolve::isImpliedInteger(HighsInt col) { for (const HighsSliceNonzero& nz : getColumnVector(col)) { double scale = 1.0 / nz.value(); if (model->row_upper_[nz.index()] != kHighsInf && - fractionality(model->row_upper_[nz.index()]) > primal_feastol) + fractionality(model->row_upper_[nz.index()] * scale) > primal_feastol) return false; if (model->row_lower_[nz.index()] != -kHighsInf && - fractionality(model->row_lower_[nz.index()]) > primal_feastol) + fractionality(model->row_lower_[nz.index()] * scale) > primal_feastol) return false; if (!rowCoefficientsIntegral(nz.index(), scale)) return false; -- 2.53.0 From 7f75cc45101d393b4247e0eec00c59dc2c46f58e Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Mon, 13 Jan 2025 16:57:56 +0000 Subject: [PATCH 2/7] free gpu memory, localtermination wip --- subprojects/highs/src/pdlp/CupdlpWrapper.cpp | 55 +++++++++++++------ .../highs/src/pdlp/cupdlp/cupdlp_linalg.c | 13 +++++ 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/subprojects/highs/src/pdlp/CupdlpWrapper.cpp b/subprojects/highs/src/pdlp/CupdlpWrapper.cpp index 31fa31e..8d905da 100644 --- a/subprojects/highs/src/pdlp/CupdlpWrapper.cpp +++ b/subprojects/highs/src/pdlp/CupdlpWrapper.cpp @@ -66,8 +66,6 @@ HighsStatus solveLpCupdlp(const HighsOptions& options, HighsTimer& timer, 0.0; // true objVal = sig * c'x - offset, sig = 1 (min) or -1 (max) double sense_origin = 1; // 1 (min) or -1 (max) int* constraint_new_idx = NULL; - cupdlp_float* x_origin = cupdlp_NULL; - cupdlp_float* y_origin = cupdlp_NULL; void* model = NULL; void* presolvedmodel = NULL; @@ -159,8 +157,6 @@ HighsStatus solveLpCupdlp(const HighsOptions& options, HighsTimer& timer, // CUPDLP_CALL(LP_SolvePDHG(prob, ifChangeIntParam, intParam, // ifChangeFloatParam, floatParam, fp)); - cupdlp_init_double(x_origin, nCols_origin); - cupdlp_init_double(y_origin, nRows); // Resize the highs_solution so cuPDLP-c can use it internally highs_solution.col_value.resize(lp.num_col_); highs_solution.row_value.resize(lp.num_row_); @@ -208,19 +204,31 @@ HighsStatus solveLpCupdlp(const HighsOptions& options, HighsTimer& timer, analysePdlpSolution(options, lp, highs_solution); #endif - free(cost); - free(lower); - free(upper); - free(csc_beg); - free(csc_idx); - free(csc_val); - free(rhs); + // free(cost); + // free(lower); + // free(upper); + // free(csc_beg); + // free(csc_idx); + // free(csc_val); + // free(rhs); - free(x_origin); - free(y_origin); + // free(constraint_new_idx); - free(constraint_new_idx); + // Scaling +#ifdef CUPDLP_CPU + if (scaling->rowScale != nullptr) free(scaling->rowScale); + if (scaling->colScale != nullptr) free(scaling->colScale); + free(scaling); + +#else + // free problem + if (scaling) { + scaling_clear(scaling); + } +#endif + +#ifdef CUPDLP_CPU free(prob->cost); free(prob->lower); free(prob->upper); @@ -248,10 +256,23 @@ HighsStatus solveLpCupdlp(const HighsOptions& options, HighsTimer& timer, free(csc_cpu->colMatElem); free(csc_cpu); +#endif - if (scaling->rowScale != nullptr) free(scaling->rowScale); - if (scaling->colScale != nullptr) free(scaling->colScale); - free(scaling); + if (cost != NULL) cupdlp_free(cost); + if (csc_beg != NULL) cupdlp_free(csc_beg); + if (csc_idx != NULL) cupdlp_free(csc_idx); + if (csc_val != NULL) cupdlp_free(csc_val); + if (rhs != NULL) cupdlp_free(rhs); + if (lower != NULL) cupdlp_free(lower); + if (upper != NULL) cupdlp_free(upper); + if (constraint_new_idx != NULL) cupdlp_free(constraint_new_idx); + + // constraint type is std::vector + // if (constraint_type != NULL) cupdlp_free(constraint_type); + + // free memory + csc_clear(csc_cpu); + problem_clear(prob); return HighsStatus::kOk; } diff --git a/subprojects/highs/src/pdlp/cupdlp/cupdlp_linalg.c b/subprojects/highs/src/pdlp/cupdlp/cupdlp_linalg.c index 8d28043..bf3e2fe 100644 --- a/subprojects/highs/src/pdlp/cupdlp/cupdlp_linalg.c +++ b/subprojects/highs/src/pdlp/cupdlp/cupdlp_linalg.c @@ -801,3 +801,16 @@ void cupdlp_compute_interaction_and_movement(CUPDLPwork *w, cupdlp_sub(w->buffer3, iterates->aty->data, iterates->atyUpdate->data, nCols); cupdlp_dot(w, nCols, w->buffer2, w->buffer3, dInteraction); } + +double get_fabs_value(double* vec, int index) { +#ifdef CUPDLP_CPU + return vec[index]; +#else + double result = 0; + int status = -1; + get_gpu_vec_element(vec, index, &result, &status); + if (!status) + return 0; + return result; +#endif +} \ No newline at end of file -- 2.53.0 From 9efff0fc9ae0eb870ea8f6b5742ea9e17c90de52 Mon Sep 17 00:00:00 2001 From: Julian Hall Date: Thu, 11 Dec 2025 20:23:13 +0000 Subject: [PATCH 3/7] Modify version and URL for HiGHS release Updated version and URL in CITATION.cff --- subprojects/highs/CITATION.cff | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/subprojects/highs/CITATION.cff b/subprojects/highs/CITATION.cff index 0987d34..da14abc 100644 --- a/subprojects/highs/CITATION.cff +++ b/subprojects/highs/CITATION.cff @@ -6,14 +6,10 @@ authors: email: HighsOpt@gmail.com - given-names: Ivet family-names: Galabova -- given-names: Leona - family-names: Gottwald -- given-names: Michael - family-names: Feldmeier title: "HiGHS" -version: 1.2.2 +version: 1.12.0 date-released: 2022-04-18 -url: "https://github.com/ERGO-Code/HiGHS/releases/tag/v1.2.2" +url: "https://github.com/ERGO-Code/HiGHS/releases/tag/v1.12.0" preferred-citation: type: article authors: -- 2.53.0 From 7d971de3169912e449b2d2f8ab00f9f7be0968f0 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Fri, 19 Dec 2025 17:42:13 +0100 Subject: [PATCH 4/7] Fix use-after-close in writeSolution when ranging fails Add missing return statement after returnFromWriteSolution() call when getRangingInterface() returns an error, preventing fprintf() from writing to an already-closed file handle. --- subprojects/highs/src/lp_data/Highs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/highs/src/lp_data/Highs.cpp b/subprojects/highs/src/lp_data/Highs.cpp index c1c3254..a175f1c 100644 --- a/subprojects/highs/src/lp_data/Highs.cpp +++ b/subprojects/highs/src/lp_data/Highs.cpp @@ -3272,7 +3272,7 @@ HighsStatus Highs::writeSolution(const std::string& filename, interpretCallStatus(options_.log_options, this->getRangingInterface(), return_status, "getRangingInterface"); if (return_status == HighsStatus::kError) - returnFromWriteSolution(file, return_status); + return returnFromWriteSolution(file, return_status); fprintf(file, "\n# Ranging\n"); writeRangingFile(file, model_.lp_, info_.objective_function_value, basis_, solution_, ranging_, style); -- 2.53.0 From d7a19c9fad468ca4b8e094da67ea2d8cc3760e7f Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Mon, 22 Dec 2025 02:02:25 +0100 Subject: [PATCH 5/7] mip: Fix use-after-move in HighsLpRelaxation::loadModel Save lpmodel.num_col_ before passing lpmodel via std::move to lpsolver.passModel(). After the move, lpmodel is in a valid but unspecified state, making access to its members undefined behavior. Found by Coverity static analysis. --- subprojects/highs/src/mip/HighsLpRelaxation.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subprojects/highs/src/mip/HighsLpRelaxation.cpp b/subprojects/highs/src/mip/HighsLpRelaxation.cpp index 4288f99..58e0e4d 100644 --- a/subprojects/highs/src/mip/HighsLpRelaxation.cpp +++ b/subprojects/highs/src/mip/HighsLpRelaxation.cpp @@ -222,11 +222,12 @@ void HighsLpRelaxation::loadModel() { for (HighsInt i = 0; i != lpmodel.num_row_; ++i) lprows.push_back(LpRow::model(i)); lpmodel.integrality_.clear(); + HighsInt num_col = lpmodel.num_col_; lpsolver.clearSolver(); lpsolver.clearModel(); lpsolver.passModel(std::move(lpmodel)); - colLbBuffer.resize(lpmodel.num_col_); - colUbBuffer.resize(lpmodel.num_col_); + colLbBuffer.resize(num_col); + colUbBuffer.resize(num_col); } void HighsLpRelaxation::resetToGlobalDomain() { -- 2.53.0 From cba9eba8aed879bc6335d3f4d43a5cd9f891e854 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Wed, 14 Jan 2026 04:50:19 +0100 Subject: [PATCH 6/7] BUG: initialize save_value field to fix uninitialized memory use When a HighsSimplexBadBasisChangeRecord is created, save_value is not set until later in applyTabooRowOut/applyTabooVariableIn. Pushing the struct with an uninitialized field copies garbage memory. Found via Coverity static analysis --- subprojects/highs/src/simplex/SimplexStruct.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/highs/src/simplex/SimplexStruct.h b/subprojects/highs/src/simplex/SimplexStruct.h index eb49c8c..996dcc4 100644 --- a/subprojects/highs/src/simplex/SimplexStruct.h +++ b/subprojects/highs/src/simplex/SimplexStruct.h @@ -258,7 +258,7 @@ struct HighsSimplexBadBasisChangeRecord { HighsInt variable_out; HighsInt variable_in; BadBasisChangeReason reason; - double save_value; + double save_value = 0.0; }; #endif /* SIMPLEX_SIMPLEXSTRUCT_H_ */ -- 2.53.0 From ee47ee8895c789980a1e90d8e0c17f54a69b4440 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Wed, 28 Jan 2026 01:23:57 +0100 Subject: [PATCH 7/7] Initialize nowactiveatlower in ratiotest_textbook The nowactiveatlower field was only set inside the conditional blocks when a limiting constraint was found (alpha_i < result.alpha). If both loops completed without finding a limiting constraint, the field remained uninitialized. Uncovered by Coverity static analysis --- subprojects/highs/src/qpsolver/ratiotest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/subprojects/highs/src/qpsolver/ratiotest.cpp b/subprojects/highs/src/qpsolver/ratiotest.cpp index dd313c4..424f695 100644 --- a/subprojects/highs/src/qpsolver/ratiotest.cpp +++ b/subprojects/highs/src/qpsolver/ratiotest.cpp @@ -17,6 +17,7 @@ static RatiotestResult ratiotest_textbook(Runtime& rt, const QpVector& p, RatiotestResult result; result.limitingconstraint = -1; result.alpha = alphastart; + result.nowactiveatlower = false; // check ratio towards variable bounds for (HighsInt j = 0; j < p.num_nz; j++) { -- 2.53.0