@@ -6133,16 +6133,30 @@ HPresolve::Result HPresolve::equalityRowAddition(
61336133 HighsPostsolveStack& postsolve_stack, HighsInt stayrow, HighsInt removerow,
61346134 double scale, const HighsMatrixSlice<RowStorageFormat>& vector) {
61356135 postsolve_stack.equalityRowAddition (removerow, stayrow, scale, vector);
6136+ // As exposed by #2095, adding to the matrix in the loop can corrupt
6137+ // vector, so possiblt accumulate the addiitons and perform then
6138+ // when vector is no longer needed
6139+ std::vector<std::pair<HighsInt, double >> add_index_value;
6140+ const bool add_to_matrix_after = true ;
61366141 for (const auto & rowNz : vector) {
61376142 assert (rowNz.index () >= 0 );
61386143 HighsInt pos = findNonzero (removerow, rowNz.index ());
6139- if (pos != -1 )
6144+ if (pos != -1 ) {
61406145 unlink (pos); // all common nonzeros are cancelled, as the rows are
61416146 // parallel
6142- else // might introduce a singleton
6143- addToMatrix (removerow, rowNz.index (), scale * rowNz.value ());
6147+ } else { // might introduce a singleton
6148+ if (add_to_matrix_after) {
6149+ add_index_value.push_back (std::make_pair (rowNz.index (), rowNz.value ()));
6150+ } else {
6151+ addToMatrix (removerow, rowNz.index (), scale * rowNz.value ());
6152+ }
6153+ }
6154+ }
6155+ if (add_to_matrix_after) {
6156+ for (HighsInt iX = 0 ; iX < HighsInt (add_index_value.size ()); iX++)
6157+ addToMatrix (removerow, add_index_value[iX].first ,
6158+ scale * add_index_value[iX].second );
61446159 }
6145-
61466160 if (model->row_upper_ [removerow] != kHighsInf )
61476161 model->row_upper_ [removerow] =
61486162 double (model->row_upper_ [removerow] +
0 commit comments