Documentation

GeneralizationLinter.Helpers.Digraph

Directed Graphs #

Small directed graph module providing the core graph-theoretic mechanisms used by the generalization linter.


Main definitions


References

structure GeneralizationLinter.Digraph (V : Type u) [BEq V] [Hashable V] :

Directed graph with vertices of type V, implemented through an adjacency list adj.

  • adj : Std.HashMap V (Array V)

    Adjacency list of the directed graph.

    Given a vertex a, adj[a] is the array of immediate successors of a.

    Default: {}


    Example

    1 → 2 ─┐
    ↓   ↑  │    5
    3   4 ←┘
    

    For the graph shown above (where the 5 is an isolated vertex), we'd have:

    • adj[1] = [2, 3]
    • adj[2] = [4]
    • adj[3] = []
    • adj[4] = [2]
    • adj[5] = []

    Implementation Notes

    Storing the successors as an Array instead of a List is more efficient for our purposes. Conceptually, either one would work.

Instances For

    Returns an array of the vertices of G in some order.

    Equations
    Instances For
      def GeneralizationLinter.Digraph.contains {V : Type u} [BEq V] [Hashable V] (G : Digraph V) (v : V) :

      Returns true iff G contains the vertex v.

      Equations
      Instances For
        def GeneralizationLinter.Digraph.succs {V : Type u} [BEq V] [Hashable V] (G : Digraph V) (v : V) :

        Returns the immediate successors of v in G.

        Warning: If v is not in G, this will silently return the empty array.

        Equations
        Instances For

          Inserts vertex v into G, and returns updated G.

          Equations
          Instances For
            def GeneralizationLinter.Digraph.insertEdge {V : Type u} [BEq V] [Hashable V] (G : Digraph V) (s t : V) :

            Inserts edge s → t into G, and returns updated G. (s stands for "source vertex" and t stands for "target vertex" of the edge to be inserted.)

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For

              Reachability #

              partial def GeneralizationLinter.Digraph.dfs {V : Type u} [BEq V] [Hashable V] (G : Digraph V) (v : V) (acc : Array V) (vis : Std.HashSet V) :

              Depth-first search to compute transitive closure of v under G.

              • acc is an array that will eventually contain all vertices reachable from v, including v itself. If G is acyclic, this list will be returned in postorder.
              • vis is the set of visited vertices. It will eventually also contain all vertices reachable from v, including v itself.

              Returns the set of vertices of G reachable from v.

              Equations
              Instances For

                Returns map from vertices to the set of vertices that each can reach.

                Equations
                Instances For
                  Equations
                  Instances For

                    Returns transpose of G.

                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For

                      Condensation #

                      Strongly-connected components of G, computed with Kosaraju–Sharir's algorithm.

                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For
                        Instances For

                          Condense digraph G into DAG of SCCs of G and return the result as a Condensation structure.

                          Equations
                          • One or more equations did not get rendered due to their size.
                          Instances For

                            Returns indices of SCCs containing the vertices vs.

                            Equations
                            Instances For

                              Least Upper Bounds #

                              Establishes how minCommonAncestors should handle inputs that are unexpectedly not vertices of the given condensation.

                              • failClosed : AbsencePolicy

                                Return an empty array. (Default.)

                              • failOpenGuarded : AbsencePolicy

                                Filter out bad inputs and proceed as usual.

                              Instances For
                                Equations
                                • One or more equations did not get rendered due to their size.
                                Instances For

                                  Idea: Given the set of classes that a theorem uses, find the minimal common ancestor of that set in the class DAG, i.e., the weakest common ancestor of the elements of the set (i.e., their meet), if a unique one exists. The class DAG is not a lattice, however, so the meet is not guaranteed to exist. In those cases, an antichain of incomparable answers is returned.


                                  Implementation notes

                                  The set of used classes is given as an array (requirements) of smaller sets. Currently, these smaller sets are usually singletons, except for used classes that are not universe polymorphic. In those cases, the corresponding smaller set consists of the used class with the specific universe level, and the universe-polymorphic version of the used class.

                                  The idea is that the array of smaller sets communicates the requirements as a general AND of ORs. Let's call each smaller set a set of witnesses. The question then becomes:

                                  Find a class that is a common ancestor to at least one witness of each requirement (i.e., a common ancestor of at least one transversal of the sets of witnesses).

                                  The answer is returned as an array of arrays. Any element of any of the inner arrays is a class which satisfies, on its own, all the given requirements. The structure within which the classes are given encodes the relationships between all of these classes:

                                  • All classes within each inner array are mutually equipotent. Each inner array therefore represents a single SCC of the class graph pre-condensation (or, equivalently, a single vertex in the class DAG, i.e., in the condensation of the class graph).
                                  • The SCCs listed in the outer array are pairwise unreachable in the class graph. Alternatively, roughly speaking, the outer array represents the antichain of vertices of the class DAG which satisfy the requirements. More precisely, each of these vertices is a bona-fide minimal common ancestor; it's just that minimality doesn't generally imply uniqueness in our case, since the class DAG is not a lattice.

                                  Examples

                                  • Unique minimal common ancestor: Sometimes, there is exactly one minimal common ancestor.

                                    minCommonAncestors #[{Monoid}, {CommSemigroup}] = #[#[CommMonoid]]
                                    
                                  • No common ancestors: Quite often, there may not exist any class which satisfies all the given requirements.

                                    minCommonAncestors #[{Inv}, {SDiff}] = #[]
                                    
                                  • Minimal common ancestors of single classes: Within an SCC of the class graph (pre-condensation), all classes are pairwise equipotent. This means that any element of the SCC is a minimal common ancestor of any other element or subset of the SCC. Note that the vast majority of the SCCs of the class graph (pre-condensation) are singletons.

                                    minCommonAncestors #[{Nonempty}] = #[#[Inhabited, Nonempty]]
                                    minCommonAncestors #[{Monoid}] = #[#[Monoid]]
                                    
                                  • Multiple non-equipotent minimal common ancestors: Rarely, requirements may have multiple non-equipotent minimal common ancestors.

                                    minCommonAncestors #[{Add}, {Mul}] = #[
                                      #[FirstOrder.Language.Structure]
                                      #[Lean.Grind.Semiring],
                                      #[Distrib],
                                    ]
                                    
                                  Equations
                                  • One or more equations did not get rendered due to their size.
                                  Instances For

                                    Given the condensation of a graph and two vertices s and t of the graph (pre-condensation), returns whether s reaches t in the graph (pre-condensation).

                                    Equations
                                    Instances For
                                      def GeneralizationLinter.Digraph.Condensation.coalesceWith {α : Type u_1} [Inhabited α] (fuse : ααα) (connected : ααBool) (xs : Array α) :

                                      Given an array xs and methods

                                      • fuse to merge two elements of the array and
                                      • connected to query whether two elements of the array should be merged,

                                      returns an array in which no two elements should be merged anymore.

                                      We require the following preconditions:

                                      • connected must be a symmetric relation.
                                      • For any a b c : α, connected a c implies connected (fuse a b) c.

                                      Examples:

                                      coalesceWith (·.append ·) (fun x y : List Nat => x.any y.contains)
                                        #[[1], [1, 2], [3], [2, 4], [5, 6]] = #[[1, 1, 2, 2, 4], [3], [5, 6]]
                                      coalesceWith (·.union ·) (fun x y : HashSet Nat => !(x.inter y).isEmpty)
                                        #[{1}, {1, 2}, {3}, {2, 4}, {5, 6}] = #[{1, 2, 4}, {3}, {5, 6}]
                                      
                                      Equations
                                      Instances For

                                        Partitions used into subsets whose down-sets are disconnected according to conn.


                                        Example

                                        Roughly speaking, in our use-case, if partitionByDesc was called on {Semigroup, MulOneClass, IsPreorder, IsTotal}, it would return [{Semigroup, MulOneClass}, {IsPreorder}, {IsTotal}]. Refer to the examples documented for sharesDataDesc for more information.

                                        Equations
                                        • One or more equations did not get rendered due to their size.
                                        Instances For