@@ -379,6 +379,101 @@ void FactorHiGHSSolver::getReg(std::vector<double>& reg) {
379379 return FH_.getRegularisation (reg);
380380}
381381
382+ Int FactorHiGHSSolver::chooseOrdering (const std::vector<Int>& rows,
383+ const std::vector<Int>& ptr,
384+ const std::vector<Int>& signs,
385+ Symbolic& S) {
386+ // Run analyse phase.
387+ // - If ordering is "amd", "metis", "rcm" run only the ordering requested.
388+ // - If ordering is "choose", run "amd", "metis", and choose the best.
389+
390+ Clock clock;
391+
392+ // select which fill-reducing orderings should be tried
393+ std::vector<std::string> orderings_to_try;
394+ if (options_.ordering != kHighsChooseString )
395+ orderings_to_try.push_back (options_.ordering );
396+ else {
397+ orderings_to_try.push_back (" amd" );
398+ orderings_to_try.push_back (" metis" );
399+ // rcm is much worse in general, so no point in trying for now
400+ }
401+
402+ std::vector<Symbolic> symbolics (orderings_to_try.size (), S);
403+ std::vector<bool > status (orderings_to_try.size (), 0 );
404+ Int num_success = 0 ;
405+
406+ for (Int i = 0 ; i < orderings_to_try.size (); ++i) {
407+ clock.start ();
408+ status[i] =
409+ FH_.analyse (symbolics[i], rows, ptr, signs, orderings_to_try[i]);
410+ if (info_) info_->analyse_AS_time += clock.stop ();
411+
412+ if (status[i] && log_.debug (2 )) {
413+ log_.print (" Failed symbolic:" );
414+ symbolics[i].print (log_, true );
415+ }
416+
417+ if (!status[i]) ++num_success;
418+ }
419+
420+ if (orderings_to_try.size () < 2 ) {
421+ S = std::move (symbolics[0 ]);
422+
423+ } else if (orderings_to_try.size () == 2 ) {
424+ // if there's only one success, obvious choice
425+ if (status[0 ] && !status[1 ])
426+ S = std::move (symbolics[1 ]);
427+ else if (!status[0 ] && status[1 ])
428+ S = std::move (symbolics[0 ]);
429+
430+ else if (num_success > 1 ) {
431+ // need to choose the better ordering
432+
433+ const double flops_0 = symbolics[0 ].flops ();
434+ const double flops_1 = symbolics[1 ].flops ();
435+ const double sn_avg_0 = symbolics[0 ].size () / symbolics[0 ].sn ();
436+ const double sn_avg_1 = symbolics[1 ].size () / symbolics[1 ].sn ();
437+ const double bytes_0 = symbolics[0 ].storage ();
438+ const double bytes_1 = symbolics[1 ].storage ();
439+
440+ Int chosen = -1 ;
441+
442+ // selection rule:
443+ // - if flops have a clear winner (+/- 20%), then choose it.
444+ // - otherwise, choose the one with larger supernodes.
445+
446+ if (flops_0 > kFlopsOrderingThresh * flops_1)
447+ chosen = 1 ;
448+ else if (flops_1 > kFlopsOrderingThresh * flops_0)
449+ chosen = 0 ;
450+ else if (sn_avg_0 > sn_avg_1)
451+ chosen = 0 ;
452+ else
453+ chosen = 1 ;
454+
455+ // fix selection if one or more require too much memory
456+ const double bytes_thresh = kLargeStorageGB * 1024 * 1024 * 1024 ;
457+ if (bytes_0 > bytes_thresh || bytes_1 > bytes_thresh) {
458+ if (bytes_0 > bytes_1)
459+ chosen = 1 ;
460+ else
461+ chosen = 0 ;
462+ }
463+
464+ assert (chosen == 0 || chosen == 1 );
465+
466+ S = std::move (symbolics[chosen]);
467+ }
468+
469+ } else {
470+ // only two orderings tried for now
471+ assert (0 == 1 );
472+ }
473+
474+ return num_success > 0 ? kStatusOk : kStatusErrorAnalyse ;
475+ }
476+
382477Int FactorHiGHSSolver::analyseAS (Symbolic& S) {
383478 // Perform analyse phase of augmented system and return symbolic factorisation
384479 // in object S and the status.
@@ -399,19 +494,7 @@ Int FactorHiGHSSolver::analyseAS(Symbolic& S) {
399494
400495 log_.printDevInfo (" Performing AS analyse phase\n " );
401496
402- std::string ordering = options_.ordering ;
403- if (ordering == kHighsChooseString ) ordering = kHipoMetisString ;
404-
405- clock.start ();
406- Int status = FH_.analyse (S, rowsLower, ptrLower, pivot_signs, ordering);
407- if (info_) info_->analyse_AS_time = clock.stop ();
408-
409- if (status && log_.debug (2 )) {
410- log_.print (" Failed augmented system:" );
411- S.print (log_, true );
412- }
413-
414- return status ? kStatusErrorAnalyse : kStatusOk ;
497+ return chooseOrdering (rowsLower, ptrLower, pivot_signs, S);
415498}
416499
417500void FactorHiGHSSolver::freeNEmemory () {
@@ -441,19 +524,7 @@ Int FactorHiGHSSolver::analyseNE(Symbolic& S, Int64 nz_limit) {
441524
442525 log_.printDevInfo (" Performing NE analyse phase\n " );
443526
444- std::string ordering = options_.ordering ;
445- if (ordering == kHighsChooseString ) ordering = kHipoMetisString ;
446-
447- clock.start ();
448- Int status = FH_.analyse (S, rowsNE_, ptrNE_, pivot_signs, ordering);
449- if (info_) info_->analyse_NE_time = clock.stop ();
450-
451- if (status && log_.debug (2 )) {
452- log_.print (" Failed normal equations:" );
453- S.print (log_, true );
454- }
455-
456- return status ? kStatusErrorAnalyse : kStatusOk ;
527+ return chooseOrdering (rowsNE_, ptrNE_, pivot_signs, S);
457528}
458529
459530Int FactorHiGHSSolver::chooseNla () {
@@ -518,11 +589,6 @@ Int FactorHiGHSSolver::chooseNla() {
518589 status = kStatusErrorAnalyse ;
519590
520591 log_.printe (" Both NE and AS failed analyse phase\n " );
521- if ((symb_AS.fillin () > kLargeFillin || symb_NE.fillin () > kLargeFillin ) &&
522- options_.ordering == " metis" && !options_.metis_no2hop )
523- log_.print (
524- " Large fill-in in factorisation. Consider setting the "
525- " hipo_metis_no2hop option to true\n " );
526592 } else {
527593 // Total number of operations, given by dense flops and sparse indexing
528594 // operations, weighted with an empirical factor
0 commit comments