Documentation

Pdl.BuildTree

From winning strategies to model graphs, part 1: BuildTree and PreState (Section 6.3) #

Builder Strategy Tree #

inductive BuildTree :

Winning Strategy Tree for Builder. At each step, we consider

  • ALL rules R that prover may choose, followed immediately by
  • ONE of the children then chosen by Builder

The type is actually similar to Tableau, as it also uses a history, but it does allow open leaves. For choosing a local tableau end node the mutual RuleChoice is needed to avoid the error "nested inductive datatypes parameters cannot contain local variables". Instead of the .lpr constructor here we have .fpr because we only make a RuleTree when Builder wins and thus we can never reach an lpr where Prover would win, but do allow free repeats. As in Tableau note that the history is stored in reverse.

Instances For
    inductive BuildChoice :
    Instances For
      def BuildTree.size {H : History} {X : Sequent} :
      BuildTree H X

      Manual replacement for sizeOf (bt : BuildTree) so we also count the next parts.

      Equations
      Instances For
        def BuildChoice.size {H : History} {X : Sequent} {YS : List Sequent} :
        BuildChoice H X YS
        Equations
        Instances For
          theorem BuildTree.size_lt_loc (H : History) (X : Sequent) (nbas : ¬X.basic) (next : (lt : OpenLocalTableau X) → BuildChoice H X (endNodesOf lt)) (ltX : OpenLocalTableau X) (someLT : OpenLocalTableau.all X []) :
          (next ltX).6.size < (loc nbas someLT next).size
          theorem BuildTree.size_lt_pdl (H : History) (X : Sequent) (bas : X.basic) (someR : PdlRule.all X []) (next : (Y : Sequent) → PdlRule X YBuildTree (X :: H) Y) (Y : Sequent) (r : PdlRule X Y) :
          (next Y r).size < (pdl bas someR next).size
          @[simp]
          theorem BuildChoice.fst_eq {H : History} {X : Sequent} {YS : List Sequent} {bc : BuildChoice H X YS} :
          bc.1 = H
          @[simp]
          theorem BuildChoice.snd_eq {H : History} {X : Sequent} {YS : List Sequent} {bc : BuildChoice H X YS} :
          bc.2 = X
          @[simp]
          theorem BuildChoice.thrd_eq {H : History} {X : Sequent} {YS : List Sequent} {bc : BuildChoice H X YS} :
          bc.3 = YS
          theorem BuildChoice.frth_mem {H : History} {X : Sequent} {YS : List Sequent} {bc : BuildChoice H X YS} :
          bc.4 YS

          The node picked by Builder is one of the given ones.

          Equations
          • One or more equations did not get rendered due to their size.
          def BuildTree.getFreeRepeat {H : History} {X : Sequent} {bt : BuildTree H X} (h : bt.isFreeRepeat) :
          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            def FreeRepeat.of_rep_free {H : History} {X : Sequent} (rp : rep H X) (free : ¬X.isLoaded = true) :

            Given the proof rep H X and that X is free, find a FreeRepeat value / data.

            (Previously here we tried to go from rep H X and ¬Nonempty (LoadedPathRepeat H X) to FreeRepeat which does not work as there might still be loaded non-lpr repeats.)

            Equations
            Instances For
              @[irreducible]
              def buildTree (s : Strategy tableauGame Builder) {H : History} {X : Sequent} {p : ProverPos H X} (h : winning s H, X, Sum.inl p) :

              Given a winning Builder strategy, compute its BuildTree. NEW: note the Sum.inl p here. This ensure we start tree building from a Prover position, i.e.

              • not allowing BuilderPos.lpr here (easy, was forbidden already anyway as prover wins there.)
              • not allowing BuilderPos.ltab because we cannot use BuildTree.loc for a single fixed local tab.
              Equations
              Instances For

                Matches #

                inductive Match {H : History} {X : Sequent} :
                BuildTree H XType

                A match is a path inside a BuildTree. Analogous to PathIn for Tableau. In Game Theory this could be called a "rollout", but note that it stays within the given Builder strategy tree and it is not tracking all intermediate game positions.

                Instances For
                  def instDecidableEqMatch.decEq {H✝ : History} {X✝ : Sequent} {a✝ : BuildTree H✝ X✝} (x✝ x✝¹ : Match a✝) :
                  Decidable (x✝ = x✝¹)
                  Equations
                  Instances For
                    def Match.length {H : History} {X : Sequent} {bt : BuildTree H X} :
                    Match bt

                    Inspired by PathIn.length. Counting the steps made by a Match in a BuildTree. Note that such a step is a combination of a prover and a builder move.

                    Equations
                    Instances For
                      def Match.btAt {H : History} {X : Sequent} {bt : BuildTree H X} :
                      Match bt(H' : History) × (Y : Sequent) × BuildTree H' Y
                      Equations
                      Instances For
                        def Match.endSeq {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) :

                        The sequent reached at the end of a match.

                        Equations
                        Instances For
                          @[irreducible]
                          def Match.all {H : History} {X : Sequent} (bt : BuildTree H X) :
                          List (Match bt)
                          Equations
                          Instances For
                            theorem Match.all_spec {H : History} {X : Sequent} {bt : BuildTree H X} {m : Match bt} :
                            m all bt
                            def Match.isOpenLeaf {H : History} {X : Sequent} {bt : BuildTree H X} {m : Match bt} :
                            Equations
                            Instances For
                              instance instDecidableIsOpenLeaf {a✝ : History} {a✝¹ : Sequent} {bt : BuildTree a✝ a✝¹} {m : Match bt} :
                              Equations
                              • One or more equations did not get rendered due to their size.
                              def Match.isFreeRepeat {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) :
                              Equations
                              Instances For
                                Equations
                                • One or more equations did not get rendered due to their size.

                                Get the FreeRepeat (rewind-index and same-sequent proof) of a Match.

                                Equations
                                Instances For
                                  def Match.append {H : History} {X : Sequent} {bt : BuildTree H X} (m1 : Match bt) (m2 : Match m1.btAt.snd.snd) :
                                  Equations
                                  Instances For
                                    theorem Match.btAt_append {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) (c : Match m.btAt.snd.snd) :
                                    (m.append c).btAt = c.btAt

                                    Appending matches: the node reached is the one reached by the second match.

                                    theorem Match.endSeq_append {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) (c : Match m.btAt.snd.snd) :

                                    Appending matches: the sequent reached is the one reached by the second match.

                                    def Match.rewind {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) (k : Fin (m.length + 1)) :

                                    Rewind a Match, i.e. go back up inside bt by k steps. The + 1 is there because going back 0 steps does nothing.

                                    Equations
                                    Instances For
                                      @[simp]
                                      theorem Match.rewind_zero {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) :
                                      m.rewind 0 = m

                                      Rewinding 0 steps does nothing.

                                      theorem Match.rewind_length_lt_length_of_pos {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) (k : Fin (m.length + 1)) (k_pos : 0 < k) :

                                      Inspired by PathIn.rewind_length_lt_length_of_gt_zero.

                                      def Match.companionOf {X : Sequent} {bt : BuildTree [] X} (m : Match bt) (h : m.isFreeRepeat) :

                                      Roll back to the companion. Only possibe if we started with H=[] so we know the root. The + 1 is there because the FreeRepeat values are indices of the history starting with 0, but Match.rewind 0 would do nothing. (Same as the .succ in companionOf for PathIn.)

                                      Equations
                                      Instances For
                                        def Match.toHistory {H : History} {X : Sequent} {bt : BuildTree H X} :
                                        Match btHistory

                                        The sequents visited by a Match, in reverse order and not including the last one. Analogous to PathIn.toHistory.

                                        Equations
                                        Instances For
                                          @[simp]
                                          theorem Match.toHistory_length {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) :
                                          theorem Match.toHistory_append_eq_btAt_fst {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) :

                                          The history reached by a Match consists of the sequents visited, then the old history.

                                          @[simp]
                                          theorem Match.rewind_last {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) :
                                          theorem Match.btAt_rewind_eq_toHistory_get {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) (k : Fin (m.length + 1)) :

                                          Rewinding a Match by k steps gives the k-th element of the history, where the end sequent of the match itself is counted as the 0-th element. Inspired by PathIn.nodeAt_rewind_eq_toHistory_get.

                                          def Match.companion {X : Sequent} {bt : BuildTree [] X} (m n : Match bt) :

                                          The repeat ♥ companion relation on Match.

                                          Equations
                                          Instances For

                                            The sequent at the companion is setEqTo the sequent at the repeat. Analogous to nodeAt_companionOf_setEq.

                                            theorem Match.companionOf_length_lt {X : Sequent} {bt : BuildTree [] X} (m : Match bt) (h : m.isFreeRepeat) :

                                            Going to the companion of a free repeat gives a strictly shorter Match.

                                            Collecting Sequents for Pre-states #

                                            As possible worlds for the model graph we want to define maximal paths inside the build tree that do not contain (M), (L+) or (L-) steps.

                                            We collect the sequents along such paths directly by induction on the BuildTree.

                                            @[irreducible]

                                            Collect pre-states in the whole BuildTree. The local pre-states come from paths in a local tableau, and PDL pre-states each consist of just a single node.

                                            Equations
                                            Instances For
                                              theorem BuildTree.collect_contains_root {X : Sequent} (bt : BuildTree [] X) :
                                              πbt.collect, X π
                                              theorem BuildTree.collect_contains_root_of_not_freeRepeat {H : History} {X : Sequent} (bt : BuildTree H X) (h : ¬bt.isFreeRepeat) :
                                              πbt.collect, X π

                                              Any BuildTree that is not a free repeat collects at least one list containing its root. Generalisation of BuildTree.collect_contains_root to non-empty histories.

                                              Pre-states (Def 6.13) #

                                              def PreState {H : History} {X : Sequent} (bt : BuildTree H X) :

                                              A pre-state is a list of sequents collected from a BuildTree.

                                              Equations
                                              Instances For
                                                @[irreducible]
                                                theorem PreState.nonempty {H : History} {X : Sequent} {bt : BuildTree H X} {π : PreState bt} :
                                                π []

                                                Collecting Formulas in Pre-state Sequents #

                                                Λ(π) gets all formulas for a pre-state but keep the information what is loaded. Returns the WhateverFormula type so that lemmas like 6.15 and 6.18 are sayable.

                                                Equations
                                                Instances For
                                                  def PreState.forms {H : History} {X : Sequent} {bt : BuildTree H X} (π : PreState bt) :

                                                  Λ⁻(π) gets all formulas from a pre-state π, via unloading if needed.

                                                  Equations
                                                  Instances For

                                                    Characterizing three different ways in which a formula can be in PreState.forms.

                                                    @[irreducible]
                                                    theorem PreState.forms_saturated {H : History} {X : Sequent} {bt : BuildTree H X} {π : PreState bt} :
                                                    @[irreducible]
                                                    @[irreducible]
                                                    theorem PreState.forms_last_basic {H : History} {X : Sequent} {bt : BuildTree H X} {π : PreState bt} :
                                                    ((↑π).getLast ).basic

                                                    PreStates to Matches and back again #

                                                    To prove the existence lemmas we first make some helper definitions and lemmas that allow us to switch between PreStates & Matches.

                                                    theorem Match.collect_btAt_subset {H : History} {X : Sequent} {bt : BuildTree H X} (m : Match bt) (π : List Sequent) :
                                                    π m.btAt.snd.snd.collectπ bt.collect

                                                    The result of BuildTree.collect in any sub-BuildTree reached by a Match is also part of BuildTree.collect applied to the bigger BuildTree.

                                                    @[irreducible]
                                                    theorem Match.existsPreState {X : Sequent} {bt : BuildTree [] X} (m : Match bt) :
                                                    ∃ (π : PreState bt), Zπ, m.btAt.snd.fst.setEqTo Z

                                                    For any Match there exists a PreState containing a sequent setEqTo the end nof the Match.

                                                    def Match.fitsPreState {X : Sequent} {bt : BuildTree [] X} (m : Match bt) (π : List Sequent) :

                                                    The Boolean predicate used by Match.toPreState: does the given list of sequents contain a sequent that is setEqTo the end of the given Match?

                                                    Equations
                                                    Instances For
                                                      theorem Match.fitsPreState_iff {X : Sequent} {bt : BuildTree [] X} {m : Match bt} {π : List Sequent} :
                                                      m.fitsPreState π = true Zπ, m.btAt.snd.fst.setEqTo Z
                                                      theorem Match.exists_fitsPreState {X : Sequent} {bt : BuildTree [] X} (m : Match bt) :
                                                      πbt.collect, m.fitsPreState π = true

                                                      Reformulation of Match.existsPreState using Match.fitsPreState.

                                                      Thanks to Match.existsPreState the search for a fitting pre-state succeeds.

                                                      def Match.toPreState {X : Sequent} {bt : BuildTree [] X} (m : Match bt) :

                                                      Pick a PreState for a given Match, using Match.existsPreState and List.find?.

                                                      Equations
                                                      Instances For
                                                        theorem Match.toPreState_spec {X : Sequent} {bt : BuildTree [] X} (m : Match bt) :
                                                        Zm.toPreState, m.btAt.snd.fst.setEqTo Z

                                                        The result of Match.toPreState indeed contains a sequent setEqTo the end of the Match.

                                                        @[irreducible]
                                                        def BuildTree.toMatchAux {H : History} {X : Sequent} (bt : BuildTree H X) (p : List Sequent) :

                                                        Search for the node in bt at which the list p of sequents is collected, and return the Match leading to that node. Auxiliary function for PreState.toMatch, defined for all lists p of sequents. If p is not collected anywhere, then we return Match.nil as a dummy value.

                                                        Equations
                                                        Instances For
                                                          @[irreducible]

                                                          A collected list of sequents is still collected in the sub-BuildTree found for it.

                                                          @[irreducible]
                                                          theorem BuildTree.toMatchAux_head? {H : History} {X : Sequent} (bt : BuildTree H X) (p : List Sequent) :

                                                          A collected list of sequents starts with the sequent of the node where it is collected.

                                                          def PreState.toMatch {H : History} {X : Sequent} {bt : BuildTree H X} (π : PreState bt) :

                                                          Every pre-state comes from a Match: this is the Match that leads to the node of the BuildTree at which the pre-state π was collected. (Defined for any history, not only for H = [].)

                                                          Equations
                                                          Instances For
                                                            theorem PreState.toMatch_mem_collect {H : History} {X : Sequent} {bt : BuildTree H X} (π : PreState bt) :

                                                            Specification of PreState.toMatch, part one: the pre-state is collected already in the sub-BuildTree reached by the match.

                                                            theorem PreState.toMatch_head {H : History} {X : Sequent} {bt : BuildTree H X} (π : PreState bt) :
                                                            (↑π).head = π.toMatch.btAt.snd.fst

                                                            Specification of PreState.toMatch, part two: the pre-state starts with the sequent at the node reached by the match.

                                                            theorem PreState.toMatch_endSeq {H : History} {X : Sequent} {bt : BuildTree H X} (π : PreState bt) :
                                                            π.toMatch.endSeq = (↑π).head

                                                            Specification of PreState.toMatch, part three: the sequent at the node reached by the match is the head of the pre-state. (Reformulation of PreState.toMatch_head.)

                                                            @[irreducible]
                                                            theorem PreState.exists_match_endSeq_eq_last {H : History} {X : Sequent} {bt : BuildTree H X} (π : PreState bt) :
                                                            ∃ (m : Match bt), m.endSeq = (↑π).getLast

                                                            Not only the first sequent of a pre-state is reached by a Match (this is PreState.toMatch), also the last sequent of a pre-state is reached by some Match.

                                                            theorem PreState.exists_endMatch {H : History} {X : Sequent} {bt : BuildTree H X} (π : PreState bt) :
                                                            ∃ (c : Match π.toMatch.btAt.snd.snd), π.toMatch.endSeq = (↑π).head (π.toMatch.append c).endSeq = (↑π).getLast

                                                            Both ends of a pre-state are reached by matches, and the match reaching the last sequent extends the one reaching the first sequent: the continuation c is a Match inside the sub-BuildTree at which π was collected, and appending it to π.toMatch gives a Match in the whole tree that ends at the last sequent of π.

                                                            theorem PreState.setEqTo_mem_toMatch_toPreState {X : Sequent} {bt : BuildTree [] X} (π : PreState bt) :
                                                            Zπ.toMatch.toPreState, ((↑π).head ).setEqTo Z

                                                            Weak round-trip that always holds: going from a pre-state to a match and back gives a pre-state that contains a sequent set-equal to the first sequent of π.

                                                            theorem PreState.toMatch_toPreState {X : Sequent} {bt : BuildTree [] X} (π : PreState bt) (uniq : ρbt.collect, (∃ Zρ, ((↑π).head ).setEqTo Z)ρ = π) :

                                                            Round-trip: under the assumption that π is the only collected list that contains a sequent set-equal to the sequent at the node where π is collected, going to the match and back gives π again.

                                                            theorem PreState.toMatch_toPreState_openLeaf {X : Sequent} (bas : X.basic) (noRule : PdlRule.all X = []) (π : PreState (BuildTree.openLeaf bas noRule)) :

                                                            Example where the uniq assumption of PreState.toMatch_toPreState is satisfied: an open leaf collects only one pre-state, so there the round-trip does hold.

                                                            Properties of Formula (Sets? Lists?) obtained from Pre-States #

                                                            @[irreducible]
                                                            theorem PreState.mem_bothSides_getLast_of_basic {H : History} {X : Sequent} {bt : BuildTree H X} {π : PreState bt} {φ : Formula} (φ_basic : φ.basic = true) (φ_in : φ π.forms) :
                                                            φ ((↑π).getLast ).bothSides

                                                            Every basic formula of a pre-state already occurs in the last (basic) sequent of that pre-state. Note that bothSides is used here, so this also covers formulas from the loaded part of a sequent.

                                                            theorem PreState.formsCases {a✝ : History} {a✝¹ : Sequent} {bt : BuildTree a✝ a✝¹} {φ : Formula} {π : PreState bt} (φ_in : φ π.forms) :
                                                            φ.basic = true φ ((↑π).getLast ).bothSides ¬φ.basic = true

                                                            Lemma 6.14, weakened version. The original statement says that φ is principal in a rule applied later on. We do not have the rule applications available along a pre-state, so instead we make the case distinction on whether φ is basic, and give the actual content for the first case: any basic formula of a pre-state occurs already in its last sequent. (We also use Sequent.bothSides instead of to include the loaded formula.)

                                                            Lemma 6.15 free case. #

                                                            The helper lemmas needed for it are in Pdl/Sequent.lean, Pdl/LocalRules.lean and Pdl/LocalTableauPaths.lean.

                                                            @[irreducible]
                                                            theorem PreState.freeUnfoldDiaMem_of_nonAtom {H : History} {X : Sequent} {bt : BuildTree H X} {π : PreState bt} {α : Program} {φ : Formula} :

                                                            Lemma 6.15 free case. (Generalised from bt : BuildTree [] X to an arbitrary history H, as needed for the recursion into sub-BuildTrees.)

                                                            Lemma 6.15 loaded cases. #

                                                            The helper lemmas needed for these are in Pdl/Sequent.lean, Pdl/LocalRules.lean and Pdl/LocalTableauPaths.lean.

                                                            @[irreducible]

                                                            Generic version of the loaded case of Lemma 6.15: a non-atomic loaded diamond in a pre-state must have been unfolded by a LoadRule somewhere in the pre-state. The two versions below are the special cases for AnyFormula.loaded and AnyFormula.normal. (Generalised from bt : BuildTree [] X to an arbitrary history H, as needed for the recursion into sub-BuildTrees.)

                                                            Lemma 6.15 loaded case with more than one loaded box

                                                            Lemma 6.15 loaded case with only one loaded box.

                                                            Lemma 6.16: pre-states are saturated and locally consistent, their last node is basic.