INLINE_IF_HEADER_ONLY void MorseDecomposition:: assign ( Digraph const& digraph, Components const& components ) { data_ . reset ( new MorseDecomposition_ ); data_ -> components_ = components; uint64_t C = components . size (); uint64_t R = components . recurrentComponents () . size (); std::vector<std::vector<uint64_t>> reachability ( R ); std::vector<uint64_t> recurrent_indices; for ( uint64_t i = 0; i < C; ++ i ) { if ( components . isRecurrent ( i ) ) { recurrent_indices . push_back ( i ); } } // Proceed in cohorts of 64 recurrent components. There are ceil(R/64) cohorts uint64_t num_cohorts = R / 64; if ( R % 64 != 0 ) ++ num_cohorts; // Round up for ceiling std::vector<uint64_t> reach_info ( C, 0 ); for ( uint64_t cohort = 0; cohort < num_cohorts; ++ cohort ) { if ( cohort > 0 ) std::fill ( reach_info.begin(), reach_info.end(), 0); uint64_t source = 64LL*cohort; // Give each recurrent component in the cohort a unique bit signature // e.g. the 5th component gets 000...00010000 for ( uint64_t i = 0; i < 64; ++ i, ++ source ) { if ( source == R ) break; reach_info [ recurrent_indices [ source ] ] = (1LL << i); } // Propagate reachability information by bitwise-oring bit signatures uint64_t parent_comp = 0; for ( auto const& component : components ) { for ( uint64_t u : component ) { std::vector<uint64_t> const& children = digraph . adjacencies ( u ); for ( uint64_t v : children ) { uint64_t child_comp = components . whichComponent ( v ); reach_info [ child_comp ] |= reach_info [ parent_comp ]; } } ++ parent_comp; } for ( uint64_t i = 0; i < R; ++ i ) { uint64_t code = reach_info [ recurrent_indices [ i ] ]; uint64_t ancestor = 64*cohort; while ( code != 0 ) { if ( code & 1 ) reachability[ancestor].push_back(i); code >>= 1; ++ ancestor; } } } data_ -> poset_ = Poset(reachability); _canonicalize (); }
INLINE_IF_HEADER_ONLY void MorseDecomposition:: assign ( Digraph const& digraph, Components const& components ) { data_ . reset ( new MorseDecomposition_ ); data_ -> poset_ = Poset (); data_ -> components_ = components; uint64_t C = components . size (); uint64_t R = components . recurrentComponents () . size (); std::vector<uint64_t> recurrent_indices; for ( uint64_t i = 0; i < C; ++ i ) { if ( components . isRecurrent ( i ) ) { recurrent_indices . push_back ( i ); data_ -> poset_ . add_vertex (); } } // Proceed in cohorts of 64 uint64_t num_cohorts = R / 64; if ( R % 64 != 0 ) ++ num_cohorts; std::vector<uint64_t> reach_info ( C, 0 ); for ( uint64_t cohort = 0; cohort < num_cohorts; ++ cohort ) { if ( cohort > 0 ) std::fill ( reach_info.begin(), reach_info.end(), 0); uint64_t source = 64LL*cohort; for ( uint64_t i = 0; i < 64; ++ i, ++ source ) { if ( source == R ) break; reach_info [ recurrent_indices [ source ] ] = (1LL << i); } uint64_t parent_comp = 0; for ( auto const& component : components ) { for ( uint64_t u : component ) { std::vector<uint64_t> const& children = digraph . adjacencies ( u ); for ( uint64_t v : children ) { uint64_t child_comp = components . whichComponent ( v ); reach_info [ child_comp ] |= reach_info [ parent_comp ]; } } ++ parent_comp; } for ( uint64_t i = 0; i < R; ++ i ) { uint64_t code = reach_info [ recurrent_indices [ i ] ]; uint64_t ancestor = 64*cohort; while ( code != 0 ) { if ( code & 1 ) data_ -> poset_ . add_edge ( ancestor, i ); code >>= 1; ++ ancestor; } } } data_ -> poset_ . reduction (); _canonicalize (); }