@@ -171,6 +171,8 @@ Int FactorHiGHSSolver::buildNEstructure(const HighsSparseMatrix& A,
171171 // temporary storage of indices
172172 std::vector<Int> temp_index (A.num_row_ );
173173
174+ Clock clock;
175+
174176 for (Int row = 0 ; row < A.num_row_ ; ++row) {
175177 // go along the entries of the row, and then down each column.
176178 // this builds the lower triangular part of the row-th column of AAt.
@@ -216,6 +218,98 @@ Int FactorHiGHSSolver::buildNEstructure(const HighsSparseMatrix& A,
216218 }
217219 }
218220
221+ printf (" time 1: %f\n " , clock.stop ());
222+
223+ return kStatusOk ;
224+ }
225+
226+ Int FactorHiGHSSolver::buildNEstructure_2 (const HighsSparseMatrix& A,
227+ int64_t nz_limit) {
228+ // Build lower triangular structure of AAt.
229+ // This approach uses a column-wise copy of A, a partial row-wise copy and a
230+ // vector of corresponding indices.
231+
232+ // NB: A must have sorted columns for this to work
233+
234+ // create partial row-wise representation
235+ // for now, using the full row-wise matrix
236+ {
237+ HighsSparseMatrix At = A;
238+ At.ensureRowwise ();
239+ ptrNE_rw_ = std::move (At.start_ );
240+ idxNE_rw_ = std::move (At.index_ );
241+ }
242+
243+ {
244+ std::vector<Int> temp = ptrNE_rw_;
245+ corr_NE_.assign (A.numNz (), 0 );
246+
247+ // build array or corresponding indices
248+ for (Int col = 0 ; col < A.num_col_ ; ++col) {
249+ for (Int el = A.start_ [col]; el < A.start_ [col + 1 ]; ++el) {
250+ Int row = A.index_ [el];
251+
252+ corr_NE_[temp[row]] = el;
253+ temp[row]++;
254+ }
255+ }
256+ }
257+
258+ std::vector<Int> ptrNE (A.num_row_ + 1 );
259+ std::vector<Int> rowsNE;
260+
261+ // keep track if given entry is nonzero, in column considered
262+ std::vector<bool > is_nz (A.num_row_ , false );
263+
264+ // temporary storage of indices
265+ std::vector<Int> temp_index (A.num_row_ );
266+
267+ Clock clock;
268+
269+ for (Int row = 0 ; row < A.num_row_ ; ++row) {
270+ // go along the entries of the row, and then down each column.
271+ // this builds the lower triangular part of the row-th column of AAt.
272+
273+ Int nz_in_col = 0 ;
274+
275+ for (Int el = ptrNE_rw_[row]; el < ptrNE_rw_[row + 1 ]; ++el) {
276+ Int col = idxNE_rw_[el];
277+ Int corr = corr_NE_[el];
278+
279+ // for each nonzero in the row, go down corresponding column, starting
280+ // from current position
281+ for (Int colEl = corr; colEl < A.start_ [col + 1 ]; ++colEl) {
282+ Int row2 = A.index_ [colEl];
283+
284+ // row2 is guaranteed to be larger or equal than row
285+ // (provided that the columns of A are sorted)
286+
287+ // save information that there is nonzero in position (row2,row).
288+ if (!is_nz[row2]) {
289+ is_nz[row2] = true ;
290+ temp_index[nz_in_col] = row2;
291+ ++nz_in_col;
292+ }
293+ }
294+ }
295+ // intersection of row with rows below finished.
296+
297+ // if the total number of nonzeros exceeds the maximum, return error
298+ if ((int64_t )ptrNE[row] + (int64_t )nz_in_col >= nz_limit) return kStatusOoM ;
299+
300+ // update pointers
301+ ptrNE[row + 1 ] = ptrNE[row] + nz_in_col;
302+
303+ // now assign indices
304+ for (Int i = 0 ; i < nz_in_col; ++i) {
305+ Int index = temp_index[i];
306+ rowsNE.push_back (index);
307+ is_nz[index] = false ;
308+ }
309+ }
310+
311+ printf (" time 2: %f\n " , clock.stop ());
312+
219313 return kStatusOk ;
220314}
221315
@@ -418,6 +512,8 @@ Int FactorHiGHSSolver::analyseNE(Symbolic& S, int64_t nz_limit) {
418512 if (Int status = buildNEstructure (model_.A (), nz_limit)) return status;
419513 if (info_) info_->matrix_structure_time = clock.stop ();
420514
515+ buildNEstructure_2 (model_.A (), nz_limit);
516+
421517 // create vector of signs of pivots
422518 std::vector<Int> pivot_signs (model_.A ().num_row_ , 1 );
423519
0 commit comments