Documentation

CslibFrontier.Computability.Complexity.Problems.TwoSAT.Membership

The complement of 2SAT in nondeterministic logarithmic space #

A nondeterministic counter program (Cslib.Complexity.TwoSAT.decider) accepts, on the encoding of a formula φ, exactly when φ ∉ TwoSAT (Cslib.Complexity.TwoSAT.accepts_decider_iff). It first guesses which of two reasons to look for:

These are all the reasons (Cslib.Complexity.notMem_TwoSAT_iff), by the theorem of Aspvall, Plass and Tarjan [APT79]. The walk stores its current literal as the position of an occurrence of its variable and a polarity. A step guesses a clause and one of its literals ℓ', checks that the clause has one or two literals and that its other literal, or ℓ' itself for a unit clause, is the negation of the current literal, which is the arc from the current literal to ℓ' of the implication graph, and moves to ℓ'. Variables are compared digit by digit through their positions (Cslib.Complexity.TwoSAT.cmpVarCode), so only positions, counters and flags are stored, all at most the length of the input. The strategy, guessing the two paths, is that of Papadimitriou, Theorem 16.3; the program, its register layout and the positional comparison of variables are this library's own.

Main definitions #

Main results #

References #

The decider of the complement of TwoSAT. Register 0 holds the choice, register 1 a scanning position, registers 2, 3 and 4 the occurrence of the starting variable, the occurrence of the current variable and the current polarity, registers 5, 6 and 7 the phase, the number of steps and the length of the input, registers 8 to 10 the literals of a guessed clause, registers 11 and 12 the next literal and the other one, and registers 13 to 15 cursors. Label 102 accepts and label 103 rejects.

Instances For

    Registers #

    The registers other than the choice.

    • p : ℕ

      Register 1.

    • o₀ : ℕ

      Register 2.

    • cur : ℕ

      Register 3.

    • sgn : ℕ

      Register 4.

    • phase : ℕ

      Register 5.

    • steps : ℕ

      Register 6.

    • len : ℕ

      Register 7.

    • q₁ : ℕ

      Register 8.

    • q₂ : ℕ

      Register 9.

    • q₃ : ℕ

      Register 10.

    • o₁ : ℕ

      Register 11.

    • o₂ : ℕ

      Register 12.

    • t₁ : ℕ

      Register 13.

    • t₂ : ℕ

      Register 14.

    • t : ℕ

      Register 15.

    Instances For

      The registers, with the choice c.

      Instances For

        All registers other than the choice are at most B.

        Instances For
          theorem Cslib.Complexity.TwoSAT.St.forall_mem_regs {B : ℕ} {st : St} {c : ℕ} (h : Bounded B st) (hc : c ≤ B) (r : ℕ) :
          r ∈ st.regs c → r ≤ B
          @[simp]
          theorem Cslib.Complexity.TwoSAT.length_regs (st : St) (c : ℕ) :
          (st.regs c).length = 16
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_1 (st : St) (c : ℕ) :
          (st.regs c).getD 1 0 = st.p
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_1 (st : St) (c x : ℕ) :
          (st.regs c).set 1 x = { p := x, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_2 (st : St) (c : ℕ) :
          (st.regs c).getD 2 0 = st.o₀
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_2 (st : St) (c x : ℕ) :
          (st.regs c).set 2 x = { p := st.p, o₀ := x, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_3 (st : St) (c : ℕ) :
          (st.regs c).getD 3 0 = st.cur
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_3 (st : St) (c x : ℕ) :
          (st.regs c).set 3 x = { p := st.p, o₀ := st.o₀, cur := x, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_4 (st : St) (c : ℕ) :
          (st.regs c).getD 4 0 = st.sgn
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_4 (st : St) (c x : ℕ) :
          (st.regs c).set 4 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := x, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_5 (st : St) (c : ℕ) :
          (st.regs c).getD 5 0 = st.phase
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_5 (st : St) (c x : ℕ) :
          (st.regs c).set 5 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := x, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_6 (st : St) (c : ℕ) :
          (st.regs c).getD 6 0 = st.steps
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_6 (st : St) (c x : ℕ) :
          (st.regs c).set 6 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := x, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_7 (st : St) (c : ℕ) :
          (st.regs c).getD 7 0 = st.len
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_7 (st : St) (c x : ℕ) :
          (st.regs c).set 7 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := x, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_8 (st : St) (c : ℕ) :
          (st.regs c).getD 8 0 = st.q₁
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_8 (st : St) (c x : ℕ) :
          (st.regs c).set 8 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := x, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_9 (st : St) (c : ℕ) :
          (st.regs c).getD 9 0 = st.q₂
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_9 (st : St) (c x : ℕ) :
          (st.regs c).set 9 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := x, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_10 (st : St) (c : ℕ) :
          (st.regs c).getD 10 0 = st.q₃
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_10 (st : St) (c x : ℕ) :
          (st.regs c).set 10 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := x, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_11 (st : St) (c : ℕ) :
          (st.regs c).getD 11 0 = st.o₁
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_11 (st : St) (c x : ℕ) :
          (st.regs c).set 11 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := x, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_12 (st : St) (c : ℕ) :
          (st.regs c).getD 12 0 = st.o₂
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_12 (st : St) (c x : ℕ) :
          (st.regs c).set 12 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := x, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_13 (st : St) (c : ℕ) :
          (st.regs c).getD 13 0 = st.t₁
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_13 (st : St) (c x : ℕ) :
          (st.regs c).set 13 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := x, t₂ := st.t₂, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_14 (st : St) (c : ℕ) :
          (st.regs c).getD 14 0 = st.t₂
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_14 (st : St) (c x : ℕ) :
          (st.regs c).set 14 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := x, t := st.t }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_15 (st : St) (c : ℕ) :
          (st.regs c).getD 15 0 = st.t
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.set_regs_15 (st : St) (c x : ℕ) :
          (st.regs c).set 15 x = { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := x }.regs c
          @[simp]
          theorem Cslib.Complexity.TwoSAT.St.getD_regs_0 (st : St) (c : ℕ) :
          (st.regs c).getD 0 0 = c

          Halting #

          What every halt guarantees: accepting only formulas outside TwoSAT.

          Instances For
            @[reducible, inline]

            The bound on the registers: the length of the input, plus one for the choice.

            Instances For
              theorem Cslib.Complexity.TwoSAT.ab_reject {φ : Logic.PL.CNF ℕ} {Q : Turing.CounterProgram.Config → Prop} {st : St} (hB : St.Bounded (bnd φ) st) (b : Bool) :
              decider.AllBranches (encCNF φ) (bnd φ) (Post φ) Q (103, st.regs b.toNat)

              Every branch from the rejecting halt.

              theorem Cslib.Complexity.TwoSAT.ab_accept {φ : Logic.PL.CNF ℕ} {Q : Turing.CounterProgram.Config → Prop} {st : St} (hB : St.Bounded (bnd φ) st) (b : Bool) (h : φ ∉ TwoSAT) :
              decider.AllBranches (encCNF φ) (bnd φ) (Post φ) Q (102, st.regs b.toNat)

              Every branch from the accepting halt, for a formula outside TwoSAT.

              theorem Cslib.Complexity.TwoSAT.ab_step_reject {φ : Logic.PL.CNF ℕ} {Q : Turing.CounterProgram.Config → Prop} {l : ℕ} {st : St} (hB : St.Bounded (bnd φ) st) (hh : decider.halted (l, st.regs 0) = false) (b : Bool) (hstep : ∀ (b : Bool), decider.step (encCNF φ) (l, st.regs b.toNat) = (103, st.regs b.toNat)) :
              decider.AllBranches (encCNF φ) (bnd φ) (Post φ) Q (l, st.regs b.toNat)

              A step to the rejecting halt.

              Code placement #

              A clause of width zero or more than two #

              theorem Cslib.Complexity.TwoSAT.le_bnd_of_infixAt {φ : Logic.PL.CNF ℕ} {p : ℕ} {u : List Bool} (h : InfixAt (encCNF φ) p u) (hu : u ≠ []) :
              p + u.length ≤ bnd φ

              A position within the input is at most the bound.

              theorem Cslib.Complexity.TwoSAT.reaches_width {φ : Logic.PL.CNF ℕ} {p : ℕ} {c : Logic.PL.Clause ℕ} (hc : LitsAt (encCNF φ) p c) {st : St} (hp : st.p = p) (hB : St.Bounded (bnd φ) st) (x : ℕ) (hx : x ≤ bnd φ) :
              ∃ (st' : St), St.Bounded (bnd φ) st' ∧ decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (10, st.regs x) (if List.length c = 0 ∨ 3 ≤ List.length c then 102 else 103, st'.regs x)

              The width of a clause: from label 10, the run accepts exactly when the clause at the scanning position is empty or has more than two literals.

              Every branch through the decider #

              theorem Cslib.Complexity.TwoSAT.ab_of_reaches {φ : Logic.PL.CNF ℕ} {Q : Turing.CounterProgram.Config → Prop} {l l' : ℕ} {st st' : St} {x : ℕ} (h : decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (l, st.regs x) (l', st'.regs x)) (hcont : ∀ (b : Bool), decider.AllBranches (encCNF φ) (bnd φ) (Post φ) Q (l', st'.regs b.toNat)) (b : Bool) :
              decider.AllBranches (encCNF φ) (bnd φ) (Post φ) Q (l, st.regs b.toNat)

              Every branch through deterministic code, then from its end.

              theorem Cslib.Complexity.TwoSAT.ab_choice {φ : Logic.PL.CNF ℕ} {Q : Turing.CounterProgram.Config → Prop} {l yes no : ℕ} {st : St} (hl : decider.instr l = Turing.CounterProgram.Instr.lt (Turing.CounterProgram.Expr.reg 0) (Turing.CounterProgram.Expr.const 1) yes no) (hB : St.Bounded (bnd φ) st) (hyes : ∀ (b : Bool), decider.AllBranches (encCNF φ) (bnd φ) (Post φ) Q (yes, st.regs b.toNat)) (hno : ∀ (b : Bool), decider.AllBranches (encCNF φ) (bnd φ) (Post φ) Q (no, st.regs b.toNat)) (b : Bool) :
              decider.AllBranches (encCNF φ) (bnd φ) (Post φ) Q (l, st.regs b.toNat)

              A step at a choice: yes for the choice 0 and no for the choice 1.

              theorem Cslib.Complexity.TwoSAT.LitsAt.getElem?_isSome {w : List Bool} {p : ℕ} {c : Logic.PL.Clause ℕ} (h : LitsAt w p c) :
              ∃ (b : Bool), w[p]? = some b

              The first bit of a clause is that of its first literal, or the end of the clause.

              theorem Cslib.Complexity.TwoSAT.readLabel_some (yes no e : ℕ) {o : Option Bool} (h : ∃ (b : Bool), o = some b) (hyn : yes = no) :

              The length of the bits of a clause.

              theorem Cslib.Complexity.TwoSAT.ab_modeA {φ : Logic.PL.CNF ℕ} (cs : Logic.PL.CNF ℕ) {p : ℕ} {st : St} :
              (∀ c ∈ cs, c ∈ φ) → ClausesAt (encCNF φ) p cs → st.p = p → St.Bounded (bnd φ) st → ∀ (b : Bool), decider.AllBranches (encCNF φ) (bnd φ) (Post φ) (fun (x : Turing.CounterProgram.Config) => False) (3, st.regs b.toNat)

              Every branch looking for a clause of width zero or more than two, from the clauses cs, halts, accepting only when it finds one.

              The walk #

              The position pos holds an occurrence of the literal (v, b) of the formula.

              Instances For

                The registers at the head of the walk: the starting occurrence of a variable x, the occurrence of the variable v of the current literal and its polarity, the number of steps within the length of the input, and the paths found so far: from x to the current literal in the first phase, and from x to ¬x and from ¬x to the current literal in the second.

                Instances For

                  The measure of the walk: the steps left, the first phase counting double.

                  Instances For
                    theorem Cslib.Complexity.TwoSAT.reaches_pick {φ : Logic.PL.CNF ℕ} {p : ℕ} {st : St} (hp : st.p = p) (hB : St.Bounded (bnd φ) st) :
                    decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (32, st.regs 0) (35, { p := st.p, o₀ := p, cur := p, sgn := 1, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs 0)

                    The chosen occurrence becomes the starting one and the current one, with polarity 1.

                    theorem Cslib.Complexity.TwoSAT.ab_startLit {φ : Logic.PL.CNF ℕ} {c : Logic.PL.Clause ℕ} (hcφ : c ∈ φ) (ls : Logic.PL.Clause ℕ) {p : ℕ} {st : St} :
                    (∀ l ∈ ls, l ∈ c) → LitsAt (encCNF φ) p ls → st.p = p → St.Bounded (bnd φ) st → st.phase = 0 → st.steps = 0 → st.len = (encCNF φ).length → ∀ (b : Bool), decider.AllBranches (encCNF φ) (bnd φ) (Post φ) (fun (s : Turing.CounterProgram.Config) => ∃ (st' : St) (b' : Bool), s = (35, st'.regs b'.toNat) ∧ LoopInv φ st') (27, st.regs b.toNat)

                    Every branch choosing the starting occurrence within a clause, from its literals ls, rejects or reaches the head of the walk.

                    theorem Cslib.Complexity.TwoSAT.ab_start {φ : Logic.PL.CNF ℕ} (cs : Logic.PL.CNF ℕ) {p : ℕ} {st : St} :
                    (∀ c ∈ cs, c ∈ φ) → ClausesAt (encCNF φ) p cs → st.p = p → St.Bounded (bnd φ) st → st.phase = 0 → st.steps = 0 → st.len = (encCNF φ).length → ∀ (b : Bool), decider.AllBranches (encCNF φ) (bnd φ) (Post φ) (fun (s : Turing.CounterProgram.Config) => ∃ (st' : St) (b' : Bool), s = (35, st'.regs b'.toNat) ∧ LoopInv φ st') (20, st.regs b.toNat)

                    Every branch choosing the starting occurrence, from the clauses cs, rejects or reaches the head of the walk.

                    theorem Cslib.Complexity.TwoSAT.reaches_check {φ : Logic.PL.CNF ℕ} {st : St} {v : ℕ} {b₁ : Bool} (hcur : InfixAt (encCNF φ) st.cur (literalBits v b₁)) (hsgn : st.sgn ≤ 1) {ℓ' m : Logic.PL.Literal ℕ} (ho₁ : InfixAt (encCNF φ) st.o₁ (literalBits ℓ'.1 ℓ'.2)) (ho₂ : InfixAt (encCNF φ) st.o₂ (literalBits m.1 m.2)) (hB : St.Bounded (bnd φ) st) :
                    ∃ (st' : St), St.Bounded (bnd φ) st' ∧ decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (79, st.regs 0) (if m = Std.Sat.Literal.negate (v, decide (st.sgn = 1)) then 35 else 103, st'.regs 0) ∧ (m = Std.Sat.Literal.negate (v, decide (st.sgn = 1)) → st'.o₀ = st.o₀ ∧ st'.phase = st.phase ∧ st'.steps = st.steps ∧ st'.len = st.len ∧ st'.cur = st.o₁ ∧ st'.sgn = ℓ'.2.toNat)

                    Checking an arc and moving along it, deterministically: from label 79, with the occurrences of literals ℓ' and m in registers 11 and 12, the run moves to ℓ' at the head of the walk when m is the negation of the current literal, and rejects otherwise.

                    theorem Cslib.Complexity.TwoSAT.ab_check {φ : Logic.PL.CNF ℕ} {st : St} {c : Logic.PL.Clause ℕ} (hcφ : c ∈ φ) {v : ℕ} {b₁ : Bool} (hcur : InfixAt (encCNF φ) st.cur (literalBits v b₁)) (hsgn : st.sgn ≤ 1) {ℓ' m : Logic.PL.Literal ℕ} (hℓ' : ℓ' ∈ c) (hm : m ∈ c) (hc : ∀ y ∈ c, y = m ∨ y = ℓ') (ho₁ : InfixAt (encCNF φ) st.o₁ (literalBits ℓ'.1 ℓ'.2)) (ho₂ : InfixAt (encCNF φ) st.o₂ (literalBits m.1 m.2)) (hB : St.Bounded (bnd φ) st) (b : Bool) :
                    decider.AllBranches (encCNF φ) (bnd φ) (Post φ) (fun (s : Turing.CounterProgram.Config) => ∃ (st' : St) (b' : Bool), s = (35, st'.regs b'.toNat) ∧ st'.o₀ = st.o₀ ∧ st'.phase = st.phase ∧ st'.steps = st.steps ∧ st'.len = st.len ∧ st'.cur = st.o₁ ∧ st'.sgn = ℓ'.2.toNat ∧ St.Bounded (bnd φ) st' ∧ φ.Implies (v, decide (st.sgn = 1)) ℓ') (79, st.regs b.toNat)

                    Every branch checking an arc and moving along it: from label 79, with the occurrences of literals ℓ' and m of a clause c in registers 11 and 12, every branch rejects or moves to ℓ' when m is the negation of the current literal, in which case the arc exists.

                    The registers at label 79: the walk unchanged, and the occurrences of two literals ℓ' and m of the clause c in registers 11 and 12, such that c has no other literal.

                    Instances For

                      The registers of the walk agree.

                      Instances For
                        theorem Cslib.Complexity.TwoSAT.reaches_inspect {φ : Logic.PL.CNF ℕ} {q : ℕ} {c : Logic.PL.Clause ℕ} (hc : LitsAt (encCNF φ) q c) {st : St} (hp : st.p = q) (hB : St.Bounded (bnd φ) st) :
                        ∃ (st' : St), St.Bounded (bnd φ) st' ∧ Same st st' ∧ ((c = [] ∨ 3 ≤ List.length c) ∧ decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (60, st.regs 0) (103, st'.regs 0) ∨ (∃ (m₁ : Logic.PL.Literal ℕ), c = [m₁] ∧ InfixAt (encCNF φ) st'.o₁ (literalBits m₁.1 m₁.2) ∧ InfixAt (encCNF φ) st'.o₂ (literalBits m₁.1 m₁.2) ∧ decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (60, st.regs 0) (79, st'.regs 0)) ∨ ∃ (m₁ : Logic.PL.Literal ℕ) (m₂ : Logic.PL.Literal ℕ), c = [m₁, m₂] ∧ InfixAt (encCNF φ) st'.q₁ (literalBits m₁.1 m₁.2) ∧ InfixAt (encCNF φ) st'.q₂ (literalBits m₂.1 m₂.2) ∧ decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (60, st.regs 0) (74, st'.regs 0))

                        Reading a guessed clause, deterministically, up to the guess of its literal ℓ': an empty clause or one with more than two literals is rejected, the literal of a unit clause is taken, and the two literals of a clause of width two are placed in registers 8 and 9.

                        The registers after the guess of ℓ' in a clause of width two.

                        Instances For
                          theorem Cslib.Complexity.TwoSAT.reaches_pair {φ : Logic.PL.CNF ℕ} {st : St} (hB : St.Bounded (bnd φ) st) (first : Bool) :
                          decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (if first = true then 75 else 77, st.regs 0) (79, (pairSt st first).regs 0)

                          The guess of ℓ' in a clause of width two: the first literal, or the second.

                          theorem Cslib.Complexity.TwoSAT.ab_inspect {φ : Logic.PL.CNF ℕ} {p : ℕ} {c : Logic.PL.Clause ℕ} (hc : LitsAt (encCNF φ) p c) {st : St} (hp : st.p = p) (hB : St.Bounded (bnd φ) st) (b : Bool) :
                          decider.AllBranches (encCNF φ) (bnd φ) (Post φ) (fun (s : Turing.CounterProgram.Config) => ∃ (st' : St) (b' : Bool), s = (79, st'.regs b'.toNat) ∧ Ready φ st st' c) (60, st.regs b.toNat)

                          Every branch reading a guessed clause rejects it when it is empty or has more than two literals, and otherwise guesses its literal ℓ', the other literal being m.

                          theorem Cslib.Complexity.TwoSAT.ab_scan {φ : Logic.PL.CNF ℕ} (cs : Logic.PL.CNF ℕ) {p : ℕ} {st : St} :
                          (∀ c ∈ cs, c ∈ φ) → ClausesAt (encCNF φ) p cs → st.p = p → St.Bounded (bnd φ) st → ∀ (b : Bool), decider.AllBranches (encCNF φ) (bnd φ) (Post φ) (fun (s : Turing.CounterProgram.Config) => ∃ (st' : St) (b' : Bool), ∃ c ∈ φ, s = (79, st'.regs b'.toNat) ∧ Ready φ st st' c) (53, st.regs b.toNat)

                          Every branch guessing a clause, from the clauses cs, rejects or reaches label 79 ready to check one of them.

                          The registers after the test of the number of steps.

                          Instances For
                            theorem Cslib.Complexity.TwoSAT.reaches_steps {φ : Logic.PL.CNF ℕ} {st : St} (hB : St.Bounded (bnd φ) st) (hlen : st.len = (encCNF φ).length) (hs : st.steps < st.len) :

                            The test of the number of steps, deterministically: from label 50, the run continues to guess a clause when fewer steps than the length of the input were taken.

                            theorem Cslib.Complexity.TwoSAT.stepSt_bounded {φ : Logic.PL.CNF ℕ} {st : St} (hB : St.Bounded (bnd φ) st) (hlen : st.len = (encCNF φ).length) (hs : st.steps < st.len) :
                            theorem Cslib.Complexity.TwoSAT.ab_walk {φ : Logic.PL.CNF ℕ} {st : St} (hinv : LoopInv φ st) (b : Bool) :
                            decider.AllBranches (encCNF φ) (bnd φ) (Post φ) (fun (s : Turing.CounterProgram.Config) => ∃ (st' : St) (b' : Bool), s = (35, st'.regs b'.toNat) ∧ LoopInv φ st' ∧ measure φ st' < measure φ st) (50, st.regs b.toNat)

                            Every branch of a step of the walk: from label 50, every branch rejects or comes back to the head of the walk one step further along an arc.

                            theorem Cslib.Complexity.TwoSAT.LoopInv.cursors {φ : Logic.PL.CNF ℕ} {st : St} (h : LoopInv φ st) {x y : ℕ} (hx : x ≤ bnd φ) (hy : y ≤ bnd φ) :
                            LoopInv φ { p := st.p, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := x, t₂ := y, t := st.t }

                            The invariant does not depend on the cursors.

                            def Cslib.Complexity.TwoSAT.headOut (st : St) (same : Prop) [Decidable same] (X Y : ℕ) :

                            Where the head of the walk goes: when the current literal is the end of the half, the walk switches to the second half, or accepts at the end of the second; otherwise it continues.

                            Instances For
                              theorem Cslib.Complexity.TwoSAT.reaches_head {φ : Logic.PL.CNF ℕ} {st : St} {x v : ℕ} {b₀ b₁ : Bool} (hO₀ : InfixAt (encCNF φ) st.o₀ (literalBits x b₀)) (hOc : InfixAt (encCNF φ) st.cur (literalBits v b₁)) (hsgn : st.sgn ≤ 1) (hph : st.phase ≤ 1) (hB : St.Bounded (bnd φ) st) :
                              ∃ (X : ℕ) (Y : ℕ), X ≤ bnd φ ∧ Y ≤ bnd φ ∧ decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (35, st.regs 0) ((headOut st (v = x) X Y).1, (headOut st (v = x) X Y).2.regs 0)

                              The head of the walk, deterministically: it compares the current variable v with the starting variable x, and the polarity with the phase.

                              theorem Cslib.Complexity.TwoSAT.ab_head {φ : Logic.PL.CNF ℕ} {st : St} (hinv : LoopInv φ st) (b : Bool) :
                              decider.AllBranches (encCNF φ) (bnd φ) (Post φ) (fun (s : Turing.CounterProgram.Config) => ∃ (st' : St) (b' : Bool), s = (35, st'.regs b'.toNat) ∧ LoopInv φ st' ∧ measure φ st' < measure φ st) (35, st.regs b.toNat)

                              Every branch from the head of the walk halts, accepting only when both paths are found, or comes back to it with a smaller measure.

                              theorem Cslib.Complexity.TwoSAT.ab_loop {φ : Logic.PL.CNF ℕ} (n : ℕ) (st : St) :
                              measure φ st = n → LoopInv φ st → ∀ (b : Bool), decider.AllBranches (encCNF φ) (bnd φ) (Post φ) (fun (x : Turing.CounterProgram.Config) => False) (35, st.regs b.toNat)

                              Every branch from the head of the walk halts, accepting only when both paths are found.

                              Every branch from the start #

                              theorem Cslib.Complexity.TwoSAT.reaches_count {φ : Logic.PL.CNF ℕ} (j : ℕ) :
                              j ≤ (encCNF φ).length → decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (0, { len := j }.regs 0) (2, { len := (encCNF φ).length }.regs 0)

                              The input is counted into register 7.

                              Every branch of the decider halts, accepting only formulas outside TwoSAT, with registers at most the length of the input plus one.

                              An accepting branch #

                              theorem Cslib.Complexity.TwoSAT.branches_of_reaches' {φ : Logic.PL.CNF ℕ} {l l' : ℕ} {st st' : St} {x : ℕ} (h : decider.Reaches (encCNF φ) (decider.Oblivious (bnd φ)) (l, st.regs x) (l', st'.regs x)) (hne : l ≠ l') (b b' : Bool) :

                              One branch through deterministic code, with any choices before and after.

                              theorem Cslib.Complexity.TwoSAT.branches_scan {φ : Logic.PL.CNF ℕ} {l₀ skip inspect : ℕ} (h₀ : decider.instr l₀ = Turing.CounterProgram.Instr.read (Turing.CounterProgram.Expr.reg 1) (l₀ + 1) (l₀ + 1) 103) (h₁ : decider.instr (l₀ + 1) = Turing.CounterProgram.Instr.lt (Turing.CounterProgram.Expr.reg 0) (Turing.CounterProgram.Expr.const 1) inspect skip) (hskip : decider.CodeAt skip (skipClauseCode skip 1 l₀)) (hne : l₀ ≠ l₀ + 1) (hsk : skip ≠ l₀) (cs : Logic.PL.CNF ℕ) {p : ℕ} {st : St} :
                              ClausesAt (encCNF φ) p cs → st.p = p → St.Bounded (bnd φ) st → ∀ (i : ℕ) (hi : i < List.length cs) (b b' : Bool), ∃ (q : ℕ), LitsAt (encCNF φ) q cs[i] ∧ q ≤ bnd φ ∧ Turing.CounterProgram.Branches (l₀, st.regs b.toNat) (inspect, { p := q, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs b'.toNat)

                              A branch guessing a clause of a scanning loop: the code at l₀ reads the scanning position, the choice at l₀ + 1 inspects the clause at inspect or skips it with the code at skip.

                              theorem Cslib.Complexity.TwoSAT.branches_lit {φ : Logic.PL.CNF ℕ} (ls : Logic.PL.Clause ℕ) {p : ℕ} {st : St} :
                              LitsAt (encCNF φ) p ls → st.p = p → St.Bounded (bnd φ) st → ∀ (j : ℕ) (hj : j < List.length ls) (b b' : Bool), ∃ (q : ℕ), InfixAt (encCNF φ) q (literalBits ls[j].1 ls[j].2) ∧ Turing.CounterProgram.Branches (27, st.regs b.toNat) (32, { p := q, o₀ := st.o₀, cur := st.cur, sgn := st.sgn, phase := st.phase, steps := st.steps, len := st.len, q₁ := st.q₁, q₂ := st.q₂, q₃ := st.q₃, o₁ := st.o₁, o₂ := st.o₂, t₁ := st.t₁, t₂ := st.t₂, t := st.t }.regs b'.toNat)

                              A branch guessing a literal of a clause, at label 27.

                              theorem Cslib.Complexity.TwoSAT.branches_arc {φ : Logic.PL.CNF ℕ} {st : St} {v : ℕ} {b₁ : Bool} (hcur : InfixAt (encCNF φ) st.cur (literalBits v b₁)) (hsgn : st.sgn ≤ 1) (hB : St.Bounded (bnd φ) st) (hlen : st.len = (encCNF φ).length) (hs : st.steps < st.len) (hw : ∀ c ∈ φ, 1 ≤ List.length c ∧ List.length c ≤ 2) {ℓ' : Logic.PL.Literal ℕ} (harc : φ.Implies (v, decide (st.sgn = 1)) ℓ') (b : Bool) :
                              ∃ (st' : St) (b' : Bool), Turing.CounterProgram.Branches (50, st.regs b.toNat) (35, st'.regs b'.toNat) ∧ st'.o₀ = st.o₀ ∧ st'.phase = st.phase ∧ st'.steps = st.steps + 1 ∧ st'.len = st.len ∧ Occ φ st'.cur ℓ'.1 ℓ'.2 ∧ st'.sgn = ℓ'.2.toNat ∧ St.Bounded (bnd φ) st'

                              A branch along an arc of the implication graph, from label 50 back to the head of the walk, for a formula whose clauses have one or two literals.

                              A formula has at most as many occurrences of literals as its encoding has bits.

                              An accepting branch for a variable x with a path from x to ¬x and one back, for a formula whose clauses have one or two literals.

                              The decider accepts exactly the formulas outside TwoSAT: some branch accepts exactly then.

                              theorem Cslib.Complexity.TwoSAT.exists_decidesInLogSpace_compl :
                              ∃ (k : ℕ) (State : Type) (_ : Finite State) (ntm : Turing.MultiTapeNTM k Bool State) (c : ℕ), ntm.DecidesInSpace encCNF TwoSATᶜ fun (φ : Logic.PL.CNF ℕ) => c * ((encCNF φ).length.log2 + 1)

                              The complement of TwoSAT is decided in nondeterministic logarithmic space: one nondeterministic machine decides it within space logarithmic in the length of the encoding, every branch halting.