[m-rev.] for review: Fix digraph.tc and digraph.rtc.
Julien Fischer
jfischer at opturion.com
Wed Jan 11 00:11:30 AEDT 2023
On Tue, 10 Jan 2023, Peter Wang wrote:
> The implementation of digraph.rtc was incorrect (as demonstrated in the
> new test case), which meant that digraph.tc was also incorrect.
Ouch!
> library/digraph.m:
> Fix the implementation of rtc (reflexive transitive closure):
>
> - Following the algorithm used in digraph.cliques, it needs to
> traverse the graph G in *reverse* depth-first order.
>
> - To find the clique containing a vertex X, it needs to do a DFS on
> the *reversed* graph to find the vertices with a path to X.
> The vertices that were previously unvisited will be members of
> the same clique as X.
>
> - Previously it found the "followers" of the elements of the clique,
> and the followers of those followers, then added edges from the
> members of the current clique to those followers. However, that
> only includes vertices two steps removed from the clique.
> I have fixed it to add edges to *all* vertices reachable from
> members of the clique.
>
> Add straightforward implementations of tc and rtc for comparison.
>
> Add some comments.
...
> diff --git a/library/digraph.m b/library/digraph.m
> index 3dd0d35cc..7529bd1f9 100644
> --- a/library/digraph.m
> +++ b/library/digraph.m
> @@ -362,6 +365,24 @@
>
> :- implementation.
>
> +% Everything below here is not intended to be part of the public interface,
> +% and will not be included in the Mercury library reference manual.
> +
> +:- interface.
> +
> + % Straightforward implementation of tc for debugging.
> + %
> +:- pred slow_tc(digraph(T)::in, digraph(T)::out) is det.
> +
> + % Straightforward implementation of rtc for debugging.
> + %
> +:- pred slow_rtc(digraph(T)::in, digraph(T)::out) is det.
> +
> +%---------------------------------------------------------------------------%
> +%---------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> :- import_module bimap.
> :- import_module uint.
> :- import_module require.
> @@ -1048,14 +1069,24 @@ tc(G, Tc) :-
> % digraph.tc returns the transitive closure of a digraph.
> % We use this procedure:
> %
> - % - Compute the reflexive transitive closure.
> + % - Compute the reflexive transitive closure, which is
> + % the reflexive closure of the transitive closure of G:
> + % G* = (G+)=
What's that supposed to mean?
> + %
> % - Find the "fake reflexives", that is, the set of vertices x for which
> % (x,x) is not an edge in G+. This is done by noting that G+ = G . G*
> % (where '.' denotes composition). Therefore x is a fake reflexive
> % iff there is no y such that (x,y) is an edge in G and (y,x) is an edge
> % in G*.
> + %
> % - Remove those edges from the reflexive transitive closure
> % computed above.
> + %
> + % XXX Despite being "easier to debug", digraph.rtc was buggy for a long
> + % time, so implementing digraph.tc in terms of digraph.rtc was of no
> + % benefit. We should implement TC using a known efficient algorithm,
> + % then RTC can be implemented trivially on top of TC.
That's fine.
Julien.
More information about the reviews
mailing list