static depth findMinWidth(const NGHolder &h, NFAVertex src) { if (isLeafNode(src, h)) { return depth::unreachable(); } typedef boost::filtered_graph<NFAGraph, SpecialEdgeFilter> StartGraph; StartGraph g(h.g, SpecialEdgeFilter(&h)); assert(hasCorrectlyNumberedVertices(h)); const size_t num = num_vertices(h); vector<depth> distance(num, depth::unreachable()); distance.at(g[src].index) = depth(0); auto index_map = get(&NFAGraphVertexProps::index, g); // Since we are interested in the single-source shortest paths on a graph // with the same weight on every edge, using BFS will be faster than // Dijkstra here. breadth_first_search( g, src, visitor(make_bfs_visitor(record_distances( make_iterator_property_map(distance.begin(), index_map), boost::on_tree_edge()))).vertex_index_map(index_map)); DEBUG_PRINTF("d[accept]=%s, d[acceptEod]=%s\n", distance.at(NODE_ACCEPT).str().c_str(), distance.at(NODE_ACCEPT_EOD).str().c_str()); depth d = min(distance.at(NODE_ACCEPT), distance.at(NODE_ACCEPT_EOD)); if (d.is_unreachable()) { return d; } assert(d.is_finite()); assert(d > depth(0)); return d - depth(1); }
depth findMaxWidth(const NGHolder &h, u32 top) { return findMaxWidth(h, SpecialEdgeFilter(h, top)); }
depth findMaxWidth(const NGHolder &h) { return findMaxWidth(h, SpecialEdgeFilter(h)); }
static depth findMaxWidth(const NGHolder &h, NFAVertex src) { if (isLeafNode(src, h.g)) { return depth::unreachable(); } if (hasReachableCycle(h, src)) { // There's a cycle reachable from this src, so we have inf width. return depth::infinity(); } typedef boost::filtered_graph<NFAGraph, SpecialEdgeFilter> NodeFilteredGraph; NodeFilteredGraph g(h.g, SpecialEdgeFilter(&h)); assert(hasCorrectlyNumberedVertices(h)); const size_t num = num_vertices(h); vector<int> distance(num); vector<boost::default_color_type> colors(num); auto index_map = get(&NFAGraphVertexProps::index, g); // DAG shortest paths with negative edge weights. dag_shortest_paths( g, src, distance_map(make_iterator_property_map(distance.begin(), index_map)) .weight_map(boost::make_constant_property<NFAEdge>(-1)) .vertex_index_map(index_map) .color_map(make_iterator_property_map(colors.begin(), index_map))); depth acceptDepth, acceptEodDepth; if (colors.at(NODE_ACCEPT) == boost::white_color) { acceptDepth = depth::unreachable(); } else { acceptDepth = -1 * distance.at(NODE_ACCEPT); } if (colors.at(NODE_ACCEPT_EOD) == boost::white_color) { acceptEodDepth = depth::unreachable(); } else { acceptEodDepth = -1 * distance.at(NODE_ACCEPT_EOD); } depth d; if (acceptDepth.is_unreachable()) { d = acceptEodDepth; } else if (acceptEodDepth.is_unreachable()) { d = acceptDepth; } else { d = max(acceptDepth, acceptEodDepth); } if (d.is_unreachable()) { // If we're actually reachable, we'll have a min width, so we can // return infinity in this case. if (findMinWidth(h, src).is_reachable()) { return depth::infinity(); } return d; } // Invert sign and subtract one for start transition. assert(d.is_finite() && d > depth(0)); return d - depth(1); }