void ComputeLongestPathLength1( const DFA& dfa , typename DFA::state_id_t RootState , valvec<LenType>& lens ) { typedef typename DFA::state_id_t state_id_t; typedef typename DFA::transition_t transition_t; valvec<unsigned char> color(dfa.total_states(), 0); valvec<state_id_t> stack; valvec<state_id_t> index(dfa.total_states()+1, 0); valvec<state_id_t> backlink; state_id_t InverseRoot = DFA::null_state; // for reduce memory usage, use indexed adjacent difference structure // first pass traverse dfa from RootState: // caculate the number of incoming transitions of each state // index[state_id] = number of incoming transitions of state_id stack.push_back(RootState); color[RootState] = 1; while (!stack.empty()) { state_id_t parent = stack.back(); stack.pop_back(); dfa.for_each_dest(parent, [&](state_id_t, const transition_t& t) { state_id_t child = t; if (color[child] < 1) { color[child] = 1; stack.push_back(child); } index[child+1]++; }); if (!dfa.has_children(parent)) { assert(DFA::null_state == InverseRoot); if (DFA::null_state != InverseRoot) { throw std::logic_error("ComputeLongestPathLength: more than one InverseRoot"); } InverseRoot = parent; } } assert(DFA::null_state != InverseRoot); if (DFA::null_state == InverseRoot) { throw std::logic_error("ComputeLongestPathLength: not found InverseRoot"); } if (!dfa.is_term(InverseRoot)) { throw std::logic_error("ComputeLongestPathLength: InverseRoot is not final state"); } if (0 != index[RootState]) { throw std::logic_error("ComputeLongestPathLength: found back link to RootState"); } for (size_t i = 2; i < index.size(); ++i) index[i] += index[i-1]; // second pass traverse dfa from RootState: // backlink[index[s] ... index[s+1]) is the backlinks of state s stack.push_back(RootState); color[RootState] = 2; backlink.resize_no_init(index.back()); { valvec<state_id_t> index2 = index; while (!stack.empty()) { state_id_t parent = stack.back(); stack.pop_back(); dfa.for_each_dest(parent, [&](state_id_t, const transition_t& t) { state_id_t child = t; if (color[child] < 2) { color[child] = 2; stack.push_back(child); } backlink[index2[child]++] = parent; }); } } // traverse the inversed graph structure of dfa // compute longest_path_length of state s from RootState lens.resize(dfa.total_states(), 0); stack.push_back(InverseRoot); color[InverseRoot] = 3; while (!stack.empty()) { state_id_t parent = stack.back(); switch (color[parent]) { default: assert(0); throw std::runtime_error("ComputeLongestPathLength: unexpected 1"); case 3: { size_t beg = index[parent+0]; size_t end = index[parent+1]; color[parent] = 4; for (size_t i = beg; i < end; ++i) { state_id_t child = backlink[i]; switch (color[child]) { default: assert(0); throw std::runtime_error("ComputeLongestPathLength: unexpected 2"); break; case 2: // not touched stack.push_back(child); color[child] = 3; break; case 3: // forward edge break; case 4: // back edge if (child == parent) throw std::logic_error("ComputeLongestPathLength: found a self-loop"); else throw std::logic_error("ComputeLongestPathLength: found a non-self-loop"); case 5: // cross edge break; } } break; } case 4: { size_t beg = index[parent+0]; size_t end = index[parent+1]; for (size_t i = beg; i < end; ++i) { state_id_t child = backlink[i]; assert(5 == color[child]); lens[parent] = std::max(lens[parent], lens[child] + 1); } color[parent] = 5; stack.pop_back(); break; } case 5: break; } } }
void ComputeLongestPathLength2( const DFA& dfa , typename DFA::state_id_t RootState , valvec<LenType>& lens ) { typedef typename DFA::state_id_t state_id_t; typedef typename DFA::transition_t trans_t; valvec<unsigned char> color(dfa.total_states(), 2); valvec<state_id_t> stack, topological; lens.resize(dfa.total_states(), 0); stack.push_back(RootState); color[RootState] = 3; while (!stack.empty()) { state_id_t parent = stack.back(); switch (color[parent]) { default: assert(0); throw std::runtime_error("ComputeLongestPathLength: unexpected 1"); case 3: color[parent] = 4; dfa.for_each_dest(parent, [&](state_id_t p, const trans_t& t) { state_id_t child = t; switch (color[child]) { default: assert(0); throw std::runtime_error("ComputeLongestPathLength: unexpected 2"); break; case 2: // not touched stack.push_back(child); color[child] = 3; break; case 3: // forward edge break; case 4: // back edge if (child == p) throw std::logic_error("ComputeLongestPathLength: found a self-loop"); else throw std::logic_error("ComputeLongestPathLength: found a non-self-loop"); case 5: // cross edge break; } }); break; case 4: topological.push_back(parent); color[parent] = 5; stack.pop_back(); break; case 5: break; } } for (size_t i = topological.size(); i > 0; --i) { state_id_t parent = topological[i-1]; dfa.for_each_dest(parent, [&](state_id_t p, const trans_t& t) { state_id_t child = t; assert(5 == color[child]); lens[child] = std::max(lens[p] + 1, lens[child]); }); } }