From 20a385c2ea4d1b87aae468b8828b52ccd6ebd34d Mon Sep 17 00:00:00 2001
From: Bradley Meyer
+The rank_spanning_branchings() function finds, in order by branching
+weight, the spanning branchings in a directed graph with weighted edges.
+If the order of a directed graph is N, a spanning branching is an
+acyclic subgraph of
+that graph with N-1 edges such that no vertex has indegree larger than
+one. The weight of the branching is the sum of the weights of the edges
+in the branching.
+This function uses the Camerini et al. algorithm
+[74]
+to compute the
+branchings in order by branching weight. Once the routine finds a branching,
+the routine calls a user-supplied
+BranchingProcessor
+to process the branching and then
+moves on to find the next branching. The
+user-supplied
+BranchingProcessor
+must take as input
+a filtered view of the parent graph
+that gives the branching.
+
+The Camerini et al. algorithm starts with a directed graph that has
+a single root vertex (that is, a vertex that has indegree equal to zero
+and outdegree not equal to zero). The procedure RANK
+finds from the procedure BEST the spanning
+branching A with the largest
+branching weight, denoted d(A).
+The
+BranchingProcessor
+is invoked on A, and if it returns true, the procedure continues.
+The procedure NEXT is then invoked to find
+the edge e such that when e is removed from G,
+BEST will find the next largest branching.
+NEXT also returns δ
+such that d(A)-δ is the weight of the next largest branching.
+
+RANK keeps a priority queue of tuples with elements (weight, edge,
+branching, Y, Z). The element
+branching is a set of edges giving a branching. Y is a set of
+edges that must be included in a branching.
+Z is a set of edges that must be excluded from a branching. After
+each evaluation of NEXT,
+the appropriate tuple is inserted into Q.
+The priority queue ranks tuples by the weight entry.
+Once the maximum weight branching is found, RANK finds subsequent
+branchings by popping a tuple off the top of Q and running
+BEST. Possible descendants are then evaluated with NEXT.
+
+The procedure BEST is the Chu-Liu/Edmond's algorithm
+[75,
+76]
+in the form adopted by
+Tarjan [77] and
+Camerini et al.
+[78].
+The procedure begins by
+constructing a subgraph H of G. To construct H,
+the procedure loops over each edge in Y and removes from the graph
+every other edge with the same target. This ensures that the edges in
+Y will be part of the branching found in this invocation of
+BEST. The procedure then removes the edges in Z from the
+graph; thus, the edges in Z will not be part of the branching.
+BEST finds the largest edge into each vertex. When a cycle forms,
+the cycle is condensed to a new vertex (such that the graph becomes
+HC) and the weight of
+edges into the cycle (that is, into the new vertex)
+are modified. The modification is such that, if v is a vertex
+in the cycle and is the invertex for edge e whose source is outside
+the cycle, the weight of e is modified
+by adding the weight of the least costly edge within the cycle and
+subtracting the weight of the cycle edge into v.
+This proceeds until all
+vertices have been examined. The condensed graph is then expanded to give the
+best branching given the constraints Y and Z.
+
+The procedure NEXT constructs the constrained graph H as
+in BEST. It examines each edge in the branching to determine
+whether swapping an edge not in the input branching for an edge in the
+branching results in a smaller
+weight difference. Only those alternative
+edges for which the target of the
+branching edge (to be replaced) is not an ancestor of the source of the
+alternative edge in the branching are allowed as possible
+swapped edges (as determined by procedure SEEK). The implementation
+of rank_spanning_branchings() does not in fact use a separate
+SEEK routine but rather simply an ordered iteration over the
+priority queue containing in edges to the vertex under
+examination. Cycles are handled as in BEST. NEXT
+returns the edge e that when removed from the input graph to
+BEST will
+give the next best branching and the weight difference between the current
+best branching and the next best descendent.
+
+boost/graph/rank_spanning_branchings.hpp
+
+
+
+
+BranchingProcessor is used in the rank_spanning_branchings()
+function to process the current branching. It is a functor that is called with
+a filtered view of the parent graph.
+The processor must return a boolean. If the return value is
+true, rank_spanning_branchings()
+continues and seeks the next branching.
+If the return value is false, rank_spanning_branchings() stops.
+
+The following functor is an example
+BranchingProcessor that prints out the edges in a branching.
+
Generating random spanning trees more quickly than the cover time.
ACM Symposium on the Theory of Computing, pp. 296-303, 1996.
+
The K Best Spanning Arborescences of a Network
+Networks 10: 91-110, 1980.
+
+
On the Shortest Arborescence of a Directed Graph
+Science Sinica 14: 1396-1400, 1965.
+
+
Optimum Branchings
+J. Res. Nat. Bur. Standards 71B: 233-240, 1967.
+
+
Finding Optimum Branchings
+Networks 7: 25-35, 1977.
+
+
A Note on Finding Optimum Branchings
+Networks 9: 309-312, 1979.
+
diff --git a/doc/rank_spanning_branchings.html b/doc/rank_spanning_branchings.html
new file mode 100644
index 00000000..11453a07
--- /dev/null
+++ b/doc/rank_spanning_branchings.html
@@ -0,0 +1,381 @@
+
+
+
+
+
+
+
+
+
+rank_spanning_branchings
+
+
+
+template <class Graph, class BranchingProcessor, class P, class T, class R>
+void
+rank_spanning_branchings(Graph& g, BranchingProcessor bp,
+ const bgl_named_params<P, T, R>& params = all defaults);
+
+
+
+RANK(G, BranchingProcessor())
+ A := BEST(G, Ø, Ø)
+ if (!BranchingProcessor(A)) return
+ (e,δ) := NEXT(G, A, Ø, Ø)
+ INSERT( Q, (d(A) - δ, e, A, Ø, Ø) )
+ while (Q != Ø)
+ (w, e, A, Y, Z) := POP(Q)
+ Y' := Y U e
+ Z' := Z U e
+ A' := BEST(G, Y, Z')
+ if (!BranchingProcessor(A')) return
+ (e',δ) := NEXT(G, A, Y', Z)
+ INSERT( Q, (d(A) - δ, e', A, Y', Z))
+ (e',δ) := NEXT(G, A', Y, Z')
+ INSERT( Q, (w - δ, e', A', Y, Z'))
+ end while
+ return
+
+
+
+BEST(G, Y, Z)
+ H := GYZ
+ B := Ø
+ Γ := (V,Ø)
+ while there exists an exposed vertex v ≠ root in H with respect to B
+ let wH be the weighting function of H
+ let Q be a priority queue of in edges of v ordered by wH
+ b := TOP(Q)
+ B := B U b
+ β(v) := b
+ if B contains a cycle C of H then
+ H := HC
+ let u be the vertex of HC corresponding to C
+ add u to Γ
+ for each vertex v' in C
+ make v' a child of u in Γ
+ end for
+ B := B - C
+ end if
+ end while
+ while Γ contains non-isolated vertices
+ find path in Γ with vertices v1, v2, ... vk such that v1 is any non-isolated root of Γ and vk = t(β(v1))
+ for h = 1, k - 1
+ β(vh+1) := β(vh)
+ remove from Γ vertex vh and all edges directed out of vh
+ end for
+ end while
+ A := {β(v):v ≠ root is a vertex of G}
+ return A
+
+
+
+NEXT(G, A, Y, Z)
+ H := GYZ
+ B := Ø
+ δ := ∞
+ while there exists an exposed vertex v ≠ root in H with respect to B
+ let wH be the weighting function of H
+ let Q be a priority queue of in edges of v ordered by wH
+ b := TOP(Q) (ties among edges must be solved in favor of edges in A)
+ B := B U b
+ if b ∈ A - Y
+ w' := SEEK(b, Q, A, H)
+ if wH(b) - w' < δ
+ e := b
+ δ := wH(b) - w'
+ end if
+ end if
+ if B contains a cycle C of H
+ H := HC
+ B := B - C
+ end if
+ end while
+ return (e, δ)
+
+
+
+SEEK(b, Q, A, H )
+ for f in Q (ordered iteration by wH)
+ if f != b and target of b is not an ancestor of source of f in A
+ return wH(f)
+ end if
+ end for
+ return -∞
+
+
+Where Defined
+
+
+BranchingProcessor
+
+
+
+struct print_branching
+{
+
+ print_branching() {}
+
+ template<class BranchingGraph>
+ bool operator()( const BranchingGraph& bg )
+ {
+ std::cout << "Branching:";
+ BGL_FORALL_EDGES_T( e, bg, BranchingGraph )
+ {
+ std::cout << " (" << source( e, bg ) << "," << target( e, bg ) << ")";
+ }
+ std::cout << std::endl;
+ return true;
+ }
+};
+
+It returns true, so rank_spanning_branchings() would always continue
+on to find the next branching.
+
+This example +BranchingProcessor could be called on a Graph g as +
+rank_spanning_branchings( g, print_branching() ); ++This would print out all spanning branchings in the graph in descending order +by branching weight. + + +
+ A directed graph. The graph type must be a model of + VertexAndEdgeListGraph. + The graph should + have a single root vertex, that is, a single vertex that has indegree + equal to zero and an edge directed to at least one other vertex. + No other vertex should have indegree equal to zero. + A graph with at least one spanning branching + can always be constructed from a general + directed graph by adding a vertex (the root vertex) and then adding edges + with weight zero directed from the root vertex to every other vertex.+ + + IN: BranchingProcessor bp +
+
+ A functor that models BranchingProcessor to process the edges in a branching.+ +
+
+The weight or ``length'' of + each edge in the graph. + The WeightMap type must be a model + of Readable + Property Map. If no edge weight comparison function is supplied, + its value type must be Less Than + Comparable. The key type of this map needs to be the graph's + edge descriptor type.+ +IN: vertex_index_map(VertexIndexMap i_map) +
+ Default: get(edge_weight, g)
+
+ This maps each vertex to an integer in the range [0, + num_vertices(g)). + The type VertexIndexMap + must be a model of Readable Property + Map. The value type of the map must be an integer type. The + vertex descriptor type of the graph needs to be usable as the key + type of the map.+ +IN: distance_compare(CompareFunction cmp) +
+ Default: get(vertex_index, g) + Note: if you use this default, make sure your graph has + an internal vertex_index property. For example, + adjacenty_list with VertexList=listS does + not have an internal vertex_index property. +
+
+ This function is used to compare edge weights to determine which + edges to include + in the next best branching. It is also used to compare the weights of + branchings. The weight of a branching is the sum of weights of its edges. + The CompareFunction type must be a model of Binary + Predicate and have argument types that match the value type of + the WeightMap property map.+ +
+ + Default: + std::less<W> with W=typename + property_traits<WeightMap>::value_type
+
+The time complexity is O(kE log V), where k is the number +of spanning branchings found. + +
+The files example/rank-branching1.cpp +and +example/rank-branching2.cpp +contain examples of using the Camerini et al. algorithm. + +
+The development of rank_spanning_branchings() was inspired by +the C++ implementation of +Edmond's algorithm by Ali Tofigh and Erik Sjölund. +
+ +| Copyright © 2015 | +Clemson University, Bradley S. Meyer (mbradle@clemson.edu) + |
& params
+ )
+ {
+
+ detail::rank_spanning_branchings_dispatch2(
+ g,
+ bp,
+ choose_param(
+ get_param( params, vertex_index_t()), get( vertex_index, g )
+ ),
+ choose_param(
+ get_param( params, edge_weight_t()), get( edge_weight, g )
+ ),
+ compare
+ );
+
+ }
+
+ template & params
+ )
+ {
+
+ typedef
+ typename
+ property_traits<
+ typename property_map & params
+ )
+ {
+
+ detail::rank_spanning_branchings_dispatch1(
+ g,
+ bp,
+ get_param( params, distance_compare_t() ),
+ params
+ );
+
+ }
+
+ template