Documentation

LeanPool.IsoGraph.Canon.Orbits

Orbit closure #

dfsChildren skips a child that is marked in orb.mark, the set of children in the orbit of the already-processed ones under the automorphisms fixing the node's path. This file proves the one fact that makes the skip legitimate: everything the closure marks is reachable from a seed by the generators, in the form

Instantiated with P w := "the subtree below the child w is dominated" and combined with Autos.reach_child_auto, this says that skipping a marked child loses no leaf key.

Orbit closure #

def IsoGraph.Canon.MarkP (P : Prop) (mark : Array Bool) :

mark only ever flags points satisfying P.

Equations
Instances For
    def IsoGraph.Canon.StackP (P : Prop) (stack : Array ) :

    Every entry of the frontier satisfies P.

    Equations
    Instances For
      theorem IsoGraph.Canon.markP_set {P : Prop} {mark : Array Bool} {w : } (hm : MarkP P mark) (hw : P w) :
      MarkP P (mark.set! w true)
      theorem IsoGraph.Canon.stackP_push {P : Prop} {stack : Array } {w : } (hs : StackP P stack) (hw : P w) :
      StackP P (stack.push w)
      theorem IsoGraph.Canon.stackP_pop {P : Prop} {stack : Array } (hs : StackP P stack) :
      StackP P stack.pop
      theorem IsoGraph.Canon.closure_foldl_P {P : Prop} {v : } (hv : P v) (l : List (Array )) (ms : Array Bool × Array ) :
      (∀ gl, P g[v]!)MarkP P ms.1StackP P ms.2MarkP P (List.foldl (fun (ms : Array Bool × Array ) (g : Array ) => have w := g[v]!; if (!ms.1[w]!) = true then (ms.1.set! w true, ms.2.push w) else ms) ms l).1 StackP P (List.foldl (fun (ms : Array Bool × Array ) (g : Array ) => have w := g[v]!; if (!ms.1[w]!) = true then (ms.1.set! w true, ms.2.push w) else ms) ms l).2
      theorem IsoGraph.Canon.closureStep_P {P : Prop} {gens : Array (Array )} {mark : Array Bool} {stack : Array } {v : } (hgen : ggens, ∀ (w : ), P wP g[w]!) (hm : MarkP P mark) (hs : StackP P stack) (hv : P v) :
      MarkP P (closureStep gens mark stack v).1 StackP P (closureStep gens mark stack v).2

      One closure step keeps the invariant. If P is closed under the generators, marking the images of a point satisfying P only ever marks points satisfying P.

      theorem IsoGraph.Canon.closureLoop_P {P : Prop} {gens : Array (Array )} (hgen : ggens, ∀ (w : ), P wP g[w]!) (fuel : ) (mark : Array Bool) (stack : Array ) :
      MarkP P markStackP P stackMarkP P (closureLoop gens fuel mark stack)

      The closure loop keeps the invariant.

      theorem IsoGraph.Canon.markP_seed_foldl {P : Prop} (l : List ) (mark : Array Bool) :
      (∀ vl, P v)MarkP P markMarkP P (List.foldl (fun (mark : Array Bool) (v : ) => mark.set! v true) mark l)
      theorem IsoGraph.Canon.orbitClosure_P {P : Prop} {n : } {gens : Array (Array )} {seed : Array } (hgen : ggens, ∀ (w : ), P wP g[w]!) (hseed : vseed, P v) :
      MarkP P (orbitClosure n gens seed)

      Orbit closure is sound. Everything orbitClosure marks satisfies any predicate that holds on the seeds and is closed under the generators. Instantiated with "the subtree below this child is dominated", this is exactly what makes orbit pruning legitimate.