Documentation

LeanPool.IsoGraph.Canon.Search

The search tree, and what the search is looking for #

IsoGraph.Canon.Equivariance proves that the ingredients of the search — refinement, individualisation, the certificate — are equivariant, and that every leaf the search records is an honest one. This file is about the search tree:

The bridge from the algorithm to the specification — that the search's winner really is the largest key, i.e. that none of the three pruning rules ever discards it — is dfsNode_dom of IsoGraph/Canon/Optimal.lean; the two are joined in IsoGraph/Canon/Correct.lean.

The comparison used to pick the winner #

lexCmpU64 is compare on the underlying lists, so it is a linear order: antisymmetric (LawfulEqCmp), total (OrientedCmp) and transitive (TransCmp).

theorem IsoGraph.Canon.lexCmpFrom_eq_compare (a b : Array UInt64) (fuel i : ) :
i + fuel = min a.size b.sizelexCmpFrom a b fuel i = compare (List.drop i a.toList) (List.drop i b.toList)

The search's comparison is compare on the underlying lists.

The key a leaf is judged by: its node-invariant path first, its certificate second. Packing the two as a List (List UInt64) makes lexicographic compare on the pair — exactly the comparison leafUpdate performs — available with all of Std's order lemmas.

Equations
Instances For
    theorem IsoGraph.Canon.compare_leafKey (i c i' c' : Array UInt64) :
    compare (leafKey i c) (leafKey i' c') = match lexCmpU64 i i' with | Ordering.eq => lexCmpU64 c c' | o => o

    compare on keys is the two-stage comparison of leafUpdate.

    theorem IsoGraph.Canon.leafKey_inj {i c i' c' : Array UInt64} (h : leafKey i c = leafKey i' c') :
    i = i' c = c'

    The search tree #

    Reach n f invPath p k says that the tree rooted at the refined partition p — the unpruned tree, in which every vertex of the target cell is individualised in turn — has a leaf with key k. This is the search's specification: canonical is supposed to return the largest such key (BestKey), and that is manifestly an isomorphism invariant (bestKey_transfer).

    The child of p obtained by individualising v and re-refining, with the trace of the refinement. This is exactly the step dfsChildren takes.

    Equations
    Instances For
      def IsoGraph.Canon.childInv (G : Graph) (invPath : Array UInt64) (p : Part) (v : ) :

      The node invariant of that child, appended to the path invariant.

      Equations
      Instances For
        inductive IsoGraph.Canon.Reach (n : ) (f : Bool) :

        The leaves of the unpruned search tree below p, described by their keys.

        Instances For

          The tree is equivariant #

          theorem IsoGraph.Canon.child_equiv {n : } {σ : } {f : Bool} {p q : Part} ( : IsPerm n σ) (hp : Part.WF n p) (hq : Part.WF n q) (h : PartEquiv n σ p q) {v : } (hv : v < n) :
          PartEquiv n σ (child (Graph.ofOracle n f) p (σ v)).1 (child (Graph.ofOracle n fun (a b : ) => f (σ a) (σ b)) q v).1 (child (Graph.ofOracle n f) p (σ v)).2 = (child (Graph.ofOracle n fun (a b : ) => f (σ a) (σ b)) q v).2
          theorem IsoGraph.Canon.childInv_equiv {n : } {σ : } {f : Bool} {p q : Part} ( : IsPerm n σ) (hp : Part.WF n p) (hq : Part.WF n q) (h : PartEquiv n σ p q) (invPath : Array UInt64) {v : } (hv : v < n) :
          childInv (Graph.ofOracle n f) invPath p (σ v) = childInv (Graph.ofOracle n fun (a b : ) => f (σ a) (σ b)) invPath q v
          theorem IsoGraph.Canon.reach_transfer {n : } {σ : } {f : Bool} ( : IsPerm n σ) {invPath : Array UInt64} {q : Part} {k : List (List UInt64)} (hr : Reach n (fun (a b : ) => f (σ a) (σ b)) invPath q k) {p : Part} :
          Part.WF n pPart.WF n qPartEquiv n σ p qReach n f invPath p k

          Leaves transport along a renaming. If p is q renamed by σ, every leaf of the tree below q in the renamed graph has a leaf below p in the original one with the same key.

          theorem IsoGraph.Canon.reach_transfer' {n : } {σ : } {f : Bool} ( : IsPerm n σ) {invPath : Array UInt64} {p : Part} {k : List (List UInt64)} (hr : Reach n f invPath p k) {q : Part} :
          Part.WF n pPart.WF n qPartEquiv n σ p qReach n (fun (a b : ) => f (σ a) (σ b)) invPath q k

          The converse direction: a leaf below p gives one below q, again with the same key. The vertex to individualise is pulled back through σ.

          The specification, and its invariance #

          def IsoGraph.Canon.rootPart (n : ) (f : Bool) :

          The root of the search: the initially refined partition and its one-entry invariant path.

          Equations
          Instances For
            def IsoGraph.Canon.Leafkey (n : ) (f : Bool) (k : List (List UInt64)) :

            k is the key of a leaf of the whole (unpruned) search tree.

            Equations
            Instances For
              def IsoGraph.Canon.BestKey (n : ) (f : Bool) (k : List (List UInt64)) :

              The specification of canonical: the largest key of any leaf.

              Equations
              Instances For
                theorem IsoGraph.Canon.bestKey_unique {n : } {f : Bool} {k k' : List (List UInt64)} (h : BestKey n f k) (h' : BestKey n f k') :
                k = k'
                theorem IsoGraph.Canon.leafkey_transfer {n : } {σ : } {f : Bool} ( : IsPerm n σ) (k : List (List UInt64)) :
                Leafkey n (fun (a b : ) => f (σ a) (σ b)) k Leafkey n f k

                The specification is an isomorphism invariant. Renaming the graph does not change the set of leaf keys, hence not the largest one.

                theorem IsoGraph.Canon.bestKey_transfer {n : } {σ : } {f : Bool} ( : IsPerm n σ) (k : List (List UInt64)) :
                BestKey n (fun (a b : ) => f (σ a) (σ b)) k BestKey n f k

                The target cell really is a cell #

                theorem IsoGraph.Canon.cenTargetFrom_cst {n : } {p : Part} (hp : Part.WF n p) (fuel i : ) :
                (i < np.cst[i]! = i)∀ (c : ), cenTargetFrom p.cen n fuel i = some cp.cst[c]! = c
                theorem IsoGraph.Canon.targetCell_cst {n : } {p : Part} (hp : Part.WF n p) {c : } (h : p.targetCell n = some c) :
                p.cst[c]! = c

                The target cell is a cell start.

                theorem IsoGraph.Canon.mem_extract_cell {n : } {p : Part} (hp : Part.WF n p) {c v : } (hc : c < n) (hcst : p.cst[c]! = c) (h : v (p.lab.extract c p.cen[c]!).toList) :

                The children dfsChildren enumerates are exactly the vertices of the target cell.

                The winner is a leaf of the tree #

                The induction is parametric in a predicate P on keys: if everything reachable below the current node satisfies P, and everything the state already holds satisfies P, then so does everything the state holds afterwards. Taking P to be "is a leaf key of the whole tree" at the root gives canonical_leafkey.

                def IsoGraph.Canon.StP (P : List (List UInt64)Prop) (st : St) :

                Every leaf the state holds satisfies P.

                Equations
                Instances For
                  theorem IsoGraph.Canon.pruneNode_P {P : List (List UInt64)Prop} {invPath : Array UInt64} {st st' : St} (h : pruneNode invPath st = some st') (hst : StP P st) :
                  StP P st'
                  theorem IsoGraph.Canon.StP.addAuto {P : List (List UInt64)Prop} {st : St} (h : StP P st) (g : Array ) :
                  StP P (st.addAuto g)
                  theorem IsoGraph.Canon.StP.unwind {P : List (List UInt64)Prop} {st : St} (h : StP P st) (path : Array ) :
                  StP P (Canon.unwind path st)
                  theorem IsoGraph.Canon.leafUpdate_P {P : List (List UInt64)Prop} {G : Graph} {path : Array } {invPath : Array UInt64} {lab : Array } {st : St} (hl : P (leafKey invPath (certOf G lab))) (hst : StP P st) :
                  StP P (leafUpdate G path invPath lab st)
                  theorem IsoGraph.Canon.dfsNode_reach (n : ) (f : Bool) (P : List (List UInt64)Prop) (fuel : ) (path : Array ) (invPath : Array UInt64) (p : Part) (st : St) :
                  Part.WF n p(∀ (k : List (List UInt64)), Reach n f invPath p kP k)StP P stStP P (dfsNode (Graph.ofOracle n f) fuel path invPath p st)

                  The search only ever holds leaves of the tree below the current node.

                  The winner is a leaf of the whole tree #

                  def IsoGraph.Canon.canonSt (n : ) (f : Bool) :

                  The final state of the search on Graph.ofOracle n f.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    theorem IsoGraph.Canon.canonical_eq (n : ) (f : Bool) :
                    canonical (Graph.ofOracle n f) = match (canonSt n f).best with | none => { lab := Array.range n, cert := certOf (Graph.ofOracle n f) (Array.range n), autos := #[], nodes := (canonSt n f).nodes } | some b => { lab := b.lab, cert := b.cert, autos := (canonSt n f).autos, nodes := (canonSt n f).nodes }
                    theorem IsoGraph.Canon.canonSt_leafkey (n : ) (f : Bool) :
                    StP (Leafkey n f) (canonSt n f)

                    Soundness of the search. Whatever leaf the search ends up holding really is a leaf of the (unpruned) tree.

                    Leaves extend the invariant path of the node they hang below #

                    theorem IsoGraph.Canon.reach_extends {n : } {f : Bool} {invPath : Array UInt64} {p : Part} {k : List (List UInt64)} (h : Reach n f invPath p k) :
                    ∃ (tail : List UInt64) (c : List UInt64), k = [invPath.toList ++ tail, c]

                    If a node's invariant path is already worse than the incumbent's, so is every leaf below it.

                    Invariant pruning is sound #

                    k is beaten by the leaf the state currently holds.

                    Equations
                    Instances For
                      theorem IsoGraph.Canon.pruneNode_none {n : } {f : Bool} {invPath : Array UInt64} {p : Part} {st : St} (h : pruneNode invPath st = none) {k : List (List UInt64)} (hk : Reach n f invPath p k) :
                      Beaten st k

                      When pruneNode discards the subtree, every leaf below the node is beaten.