/*++ Copyright (c) 2013 Microsoft Corporation Module Name: spanning_tree_def.h Abstract: Author: Anh-Dung Phan (t-anphan) 2013-11-06 Notes: --*/ #pragma once #include "smt/spanning_tree.h" namespace smt { template thread_spanning_tree::thread_spanning_tree(graph & g) : m_graph(g) { } template void thread_spanning_tree::initialize(svector const & tree) { m_tree = tree; unsigned num_nodes = m_graph.get_num_nodes(); m_pred.resize(num_nodes); m_depth.resize(num_nodes); m_thread.resize(num_nodes); node_id root = num_nodes - 1; m_pred[root] = -1; m_depth[root] = 0; m_thread[root] = 0; // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree for (int i = 0; i < root; ++i) { m_pred[i] = root; m_depth[i] = 1; m_thread[i] = i + 1; } TRACE("network_flow", { tout << pp_vector("Predecessors", m_pred) << pp_vector("Threads", m_thread); tout << pp_vector("Depths", m_depth) << pp_vector("Tree", m_tree); }); } template typename thread_spanning_tree::node_id thread_spanning_tree::get_common_ancestor(node_id u, node_id v) { while (u != v) { if (m_depth[u] > m_depth[v]) u = m_pred[u]; else v = m_pred[v]; } return u; } template void thread_spanning_tree::get_path(node_id start, node_id end, svector & path, bool_vector & against) { node_id join = get_common_ancestor(start, end); path.reset(); while (start != join) { edge_id e_id = m_tree[start]; path.push_back(e_id); against.push_back(is_forward_edge(e_id)); start = m_pred[start]; } while (end != join) { edge_id e_id = m_tree[end]; path.push_back(e_id); against.push_back(!is_forward_edge(e_id)); end = m_pred[end]; } } template bool thread_spanning_tree::is_forward_edge(edge_id e_id) const { node_id start = m_graph.get_source(e_id); node_id end = m_graph.get_target(e_id); SASSERT(m_pred[start] == end || m_pred[end] == start); return m_pred[start] == end; } template void thread_spanning_tree::get_descendants(node_id start, svector & descendants) { descendants.reset(); descendants.push_back(start); node_id u = m_thread[start]; while (m_depth[u] > m_depth[start]) { descendants.push_back(u); u = m_thread[u]; } } template bool thread_spanning_tree::in_subtree_t2(node_id child) { if (m_depth[child] < m_depth[m_root_t2]) { return false; } return is_ancestor_of(m_root_t2, child); } template bool thread_spanning_tree::is_ancestor_of(node_id ancestor, node_id child) { for (node_id n = child; n != -1; n = m_pred[n]) { if (n == ancestor) { return true; } } return false; } /** \brief add entering_edge, remove leaving_edge from spanning tree. Old tree: New tree: root root / \ / \ x y x y / \ / \ / \ / \ u s u s | / / v w v w / \ \ / \ \ z p z p \ \ / q q */ template void thread_spanning_tree::update(edge_id enter_id, edge_id leave_id) { node_id p = m_graph.get_source(enter_id); node_id q = m_graph.get_target(enter_id); node_id u = m_graph.get_source(leave_id); node_id v = m_graph.get_target(leave_id); if (m_pred[u] == v) { std::swap(u, v); } SASSERT(m_pred[v] == u); if (is_ancestor_of(v, p)) { std::swap(p, q); } SASSERT(is_ancestor_of(v, q)); TRACE("network_flow", { tout << "update_spanning_tree: (" << p << ", " << q << ") enters, ("; tout << u << ", " << v << ") leaves\n"; }); // Old threads: alpha -> v -*-> f(v) -> beta | p -*-> f(p) -> gamma // New threads: alpha -> beta | p -*-> f(p) -> v -*-> f(v) -> gamma node_id f_p = get_final(p); node_id f_v = get_final(v); node_id alpha = find_rev_thread(v); node_id beta = m_thread[f_v]; node_id gamma = m_thread[f_p]; if (v != gamma) { m_thread[alpha] = beta; m_thread[f_p] = v; m_thread[f_v] = gamma; } node_id old_pred = m_pred[q]; // Update stem nodes from q to v if (q != v) { for (node_id n = q; n != v; ) { SASSERT(old_pred != u); // the last processed node_id is v SASSERT(-1 != m_pred[old_pred]); int next_old_pred = m_pred[old_pred]; swap_order(n, old_pred); m_tree[old_pred] = m_tree[n]; n = old_pred; old_pred = next_old_pred; } } m_pred[q] = p; m_tree[q] = enter_id; m_root_t2 = q; node_id after_final_q = (v == gamma) ? beta : gamma; fix_depth(q, after_final_q); SASSERT(!in_subtree_t2(p)); SASSERT(in_subtree_t2(q)); SASSERT(!in_subtree_t2(u)); SASSERT(in_subtree_t2(v)); TRACE("network_flow", { tout << pp_vector("Predecessors", m_pred) << pp_vector("Threads", m_thread); tout << pp_vector("Depths", m_depth) << pp_vector("Tree", m_tree); }); } /** swap v and q in tree. - fixup m_thread - fixup m_pred Case 1: final(q) == final(v) ------- Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> next New thread: prev -> q -*-> final(q) -> v -*-> alpha -> next Case 2: final(q) != final(v) ------- Old thread: prev -> v -*-> alpha -> q -*-> final(q) -> beta -*-> final(v) -> next New thread: prev -> q -*-> final(q) -> v -*-> alpha -> beta -*-> final(v) -> next */ template void thread_spanning_tree::swap_order(node_id q, node_id v) { SASSERT(q != v); SASSERT(m_pred[q] == v); SASSERT(is_preorder_traversal(v, get_final(v))); node_id prev = find_rev_thread(v); node_id f_q = get_final(q); node_id f_v = get_final(v); node_id next = m_thread[f_v]; node_id alpha = find_rev_thread(q); if (f_q == f_v) { SASSERT(f_q != v && alpha != next); m_thread[f_q] = v; m_thread[alpha] = next; f_q = alpha; } else { node_id beta = m_thread[f_q]; SASSERT(f_q != v && alpha != beta); m_thread[f_q] = v; m_thread[alpha] = beta; f_q = f_v; } SASSERT(prev != q); m_thread[prev] = q; m_pred[v] = q; // Notes: f_q has to be used since m_depth hasn't been updated yet. SASSERT(is_preorder_traversal(q, f_q)); } /** \brief Check invariants of main data-structures. Spanning tree of m_graph + root is represented using: svector m_states; edge_id |-> edge_state svector m_pred; node_id |-> node svector m_depth; node_id |-> int svector m_thread; node_id |-> node Tree is determined by m_pred: - m_pred[root] == -1 - m_pred[n] = m != n for each node_id n, acyclic until reaching root. - m_depth[m_pred[n]] + 1 == m_depth[n] for each n != root m_thread is a linked list traversing all nodes. Furthermore, the nodes linked in m_thread follows a depth-first traversal order. */ template bool thread_spanning_tree::check_well_formed() { node_id root = m_pred.size()-1; // Check that m_thread traverses each node. // This gets checked using union-find as well. bool_vector found(m_thread.size(), false); found[root] = true; for (node_id x = m_thread[root]; x != root; x = m_thread[x]) { SASSERT(x != m_thread[x]); found[x] = true; } for (unsigned i = 0; i < found.size(); ++i) { SASSERT(found[i]); } // m_pred is acyclic, and points to root. SASSERT(m_pred[root] == -1); SASSERT(m_depth[root] == 0); for (node_id i = 0; i < root; ++i) { SASSERT(m_depth[m_pred[i]] < m_depth[i]); } // m_depth[x] denotes distance from x to the root node for (node_id x = m_thread[root]; x != root; x = m_thread[x]) { SASSERT(m_depth[x] > 0); SASSERT(m_depth[x] == m_depth[m_pred[x]] + 1); } // m_thread forms a spanning tree over [0..root] // Union-find structure svector roots(m_pred.size(), -1); for (node_id x = m_thread[root]; x != root; x = m_thread[x]) { node_id y = m_pred[x]; // We are now going to check the edge between x and y SASSERT(find(roots, x) != find(roots, y)); merge(roots, x, y); } // All nodes belong to the same spanning tree for (unsigned i = 0; i < roots.size(); ++i) { SASSERT(roots[i] + roots.size() == 0 || roots[i] >= 0); } for (unsigned i = 0; i < m_tree.size(); ++i) { node_id src = m_graph.get_source(m_tree[i]); node_id tgt = m_graph.get_target(m_tree[i]); SASSERT(m_pred[src] == tgt || m_pred[tgt] == src); } return true; } static unsigned find(svector& roots, unsigned x) { unsigned old_x = x; while (roots[x] >= 0) { x = roots[x]; } SASSERT(roots[x] < 0); if (old_x != x) { roots[old_x] = x; } return x; } static void merge(svector& roots, unsigned x, unsigned y) { x = find(roots, x); y = find(roots, y); SASSERT(roots[x] < 0 && roots[y] < 0); if (x == y) { return; } if (roots[x] > roots[y]) { std::swap(x, y); } SASSERT(roots[x] <= roots[y]); roots[x] += roots[y]; roots[y] = x; } /** \brief find node_id that points to 'n' in m_thread */ template typename thread_spanning_tree::node_id thread_spanning_tree::find_rev_thread(node_id n) const { node_id ancestor = m_pred[n]; SASSERT(ancestor != -1); while (m_thread[ancestor] != n) { ancestor = m_thread[ancestor]; } return ancestor; } template void thread_spanning_tree::fix_depth(node_id start, node_id after_end) { while (start != after_end) { SASSERT(m_pred[start] != -1); m_depth[start] = m_depth[m_pred[start]]+1; start = m_thread[start]; } } template typename thread_spanning_tree::node_id thread_spanning_tree::get_final(int start) { int n = start; while (m_depth[m_thread[n]] > m_depth[start]) { n = m_thread[n]; } return n; } template bool thread_spanning_tree::is_preorder_traversal(node_id start, node_id end) { // get children of start uint_set children; children.insert(start); node_id root = m_pred.size()-1; for (int i = 0; i < root; ++i) { for (int j = 0; j < root; ++j) { if (children.contains(m_pred[j])) { children.insert(j); } } } // visit children using m_thread children.remove(start); do { start = m_thread[start]; SASSERT(children.contains(start)); children.remove(start); } while (start != end); SASSERT(children.empty()); return true; } // Basic spanning tree template basic_spanning_tree::basic_spanning_tree(graph & g) : thread_spanning_tree(g) { } template void basic_spanning_tree::initialize(svector const & tree) { m_tree_graph = alloc(graph); m_tree = tree; unsigned num_nodes = m_graph.get_num_nodes(); for (unsigned i = 0; i < num_nodes; ++i) { m_tree_graph->init_var(i); } vector const & es = m_graph.get_all_edges(); svector::const_iterator it = m_tree.begin(), end = m_tree.end(); for(; it != end; ++it) { edge const & e = es[*it]; m_tree_graph->add_edge(e.get_source(), e.get_target(), e.get_weight(), explanation()); } node_id root = num_nodes - 1; m_tree_graph->bfs_undirected(root, m_pred, m_depth); m_tree_graph->dfs_undirected(root, m_thread); } template void basic_spanning_tree::update(edge_id enter_id, edge_id leave_id) { if (m_tree_graph) dealloc(m_tree_graph); m_tree_graph = alloc(graph); unsigned num_nodes = m_graph.get_num_nodes(); for (unsigned i = 0; i < num_nodes; ++i) { m_tree_graph->init_var(i); } vector const & es = m_graph.get_all_edges(); svector::const_iterator it = m_tree.begin(), end = m_tree.end(); for(; it != end; ++it) { edge const & e = es[*it]; if (leave_id != *it) { m_tree_graph->add_edge(e.get_source(), e.get_target(), e.get_weight(), explanation()); } } edge const & e = es[enter_id]; m_tree_graph->add_edge(e.get_source(), e.get_target(), e.get_weight(), explanation()); node_id root = num_nodes - 1; m_tree_graph->bfs_undirected(root, m_pred, m_depth); m_tree_graph->dfs_undirected(root, m_thread); vector const & tree_edges = m_tree_graph->get_all_edges(); for (unsigned i = 0; i < tree_edges.size(); ++i) { edge const & e = tree_edges[i]; dl_var src = e.get_source(); dl_var tgt = e.get_target(); edge_id id; VERIFY(m_graph.get_edge_id(src, tgt, id)); SASSERT(tgt == m_pred[src] || src == m_pred[tgt]); if (tgt == m_pred[src]) { m_tree[src] = id; } else { m_tree[tgt] = id; } } node_id p = m_graph.get_source(enter_id); node_id q = m_graph.get_target(enter_id); m_root_t2 = p == m_pred[q] ? q : p; } }