Documentation

SSA.Experimental.Bits.Fast.FiniteStateMachine

structure FSM (arity : Type) :

FSM n represents a function BitStream → ⋯ → BitStreamBitStream, where n is the number of BitStream arguments, as a finite state machine.

  • α : Type

    The arity of the (finite) type α determines how many bits the internal carry state of this FSM has

  • i : Fintype self
  • dec_eq : DecidableEq self
  • initCarry : selfBool

    initCarry is the value of the initial internal carry state. It maps each α to a bit, thus it is morally a bitvector where the width is the arity of α

  • nextBitCirc : Option selfCircuit (self arity)

    nextBitCirc is a family of Boolean circuits, which may refer to the current input bits and the current state bits as free variables in the circuit.

    nextBitCirc none computes the current output bit. nextBitCirc (some a), computes the one bit of the new state that corresponds to a : α.

Instances For
    @[reducible, inline]
    abbrev FSM.State {arity : Type} (p : FSM arity) :

    The state of FSM p is given by a function from p.α to Bool.

    Note that p.α is assumed to be a finite type, so p.State is morally a finite bitvector whose width is given by the arity of p.α

    Equations
    • p.State = (pBool)
    Instances For
      def FSM.nextBit {arity : Type} (p : FSM arity) :
      p.State(arityBool)p.State × Bool

      p.nextBit state in computes both the next state bits and the output bit, where state are the current state bits, and in are the current input bits.

      Equations
      • p.nextBit carry inputBits = (fun (a : p) => (p.nextBitCirc (some a)).eval (Sum.elim carry inputBits), (p.nextBitCirc none).eval (Sum.elim carry inputBits))
      Instances For
        def FSM.carry {arity : Type} (p : FSM arity) (x : arityBitStream) :
        p.State

        p.carry in i computes the internal carry state at step i, given input streams in

        Equations
        • p.carry x 0 = p.initCarry
        • p.carry x n.succ = (p.nextBit (p.carry x n) fun (i : arity) => x i n).1
        Instances For
          def FSM.eval {arity : Type} (p : FSM arity) (x : arityBitStream) :

          eval p morally gives the function BitStream → ... → BitStream represented by FSM p

          Equations
          • p.eval x n = (p.nextBit (p.carry x n) fun (i : arity) => x i n).2
          Instances For
            def FSM.eval' {arity : Type} (p : FSM arity) (x : arityBitStream) :

            eval' is an alternative definition of eval

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              def FSM.changeInitCarry {arity : Type} (p : FSM arity) (c : pBool) :
              FSM arity

              p.changeInitCarry c yields an FSM with c as the initial state

              Equations
              • p.changeInitCarry c = FSM.mk p c p.nextBitCirc
              Instances For
                theorem FSM.carry_changeInitCarry_succ {arity : Type} (p : FSM arity) (c : pBool) (x : arityBitStream) (n : ) :
                (p.changeInitCarry c).carry x (n + 1) = (p.changeInitCarry (p.nextBit c fun (a : arity) => x a 0).1).carry (fun (a : arity) (i : ) => x a (i + 1)) n
                theorem FSM.eval_changeInitCarry_succ {arity : Type} (p : FSM arity) (c : pBool) (x : arityBitStream) (n : ) :
                (p.changeInitCarry c).eval x (n + 1) = (p.changeInitCarry (p.nextBit c fun (a : arity) => x a 0).1).eval (fun (a : arity) (i : ) => x a (i + 1)) n
                theorem FSM.eval_eq_carry {arity : Type} (p : FSM arity) (x : arityBitStream) (n : ) :
                p.eval x n = (p.nextBit (p.carry x n) fun (i : arity) => x i n).2

                unfolds the definition of eval

                theorem FSM.eval_eq_eval' {arity : Type} (p : FSM arity) {x : arityBitStream} :
                p.eval x = p.eval' x
                def FSM.changeVars {arity : Type} (p : FSM arity) {arity2 : Type} (changeVars : arityarity2) :
                FSM arity2

                p.changeVars f changes the arity of an FSM. The function f determines how the new input bits map to the input expected by p

                Equations
                • p.changeVars changeVars = FSM.mk p p.initCarry fun (a : Option p) => (p.nextBitCirc a).map (Sum.map id changeVars)
                Instances For
                  def FSM.compose {arity : Type} (p : FSM arity) [Fintype arity] [DecidableEq arity] (new_arity : Type) (q_arity : arityType) (vars : (a : arity) → q_arity anew_arity) (q : (a : arity) → FSM (q_arity a)) :
                  FSM new_arity

                  Given an FSM p of arity n, a family of n FSMs qᵢ of posibly different arities mᵢ, and given yet another arity m such that mᵢ ≤ m for all i, we can compose p with qᵢ yielding a single FSM of arity m, such that each FSM qᵢ computes the ith bit that is fed to the FSM p.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    theorem FSM.carry_compose {arity : Type} (p : FSM arity) [Fintype arity] [DecidableEq arity] (new_arity : Type) (q_arity : arityType) (vars : (a : arity) → q_arity anew_arity) (q : (a : arity) → FSM (q_arity a)) (x : new_arityBitStream) (n : ) :
                    (p.compose new_arity q_arity vars q).carry x n = let z := p.carry (fun (a : arity) => (q a).eval fun (i : q_arity a) => x (vars a i)) n; Sum.elim z fun (a : (a : arity) × (q a)) => (q a.fst).carry (fun (t : q_arity a.fst) => x (vars a.fst t)) n a.snd
                    theorem FSM.eval_compose {arity : Type} (p : FSM arity) [Fintype arity] [DecidableEq arity] (new_arity : Type) (q_arity : arityType) (vars : (a : arity) → q_arity anew_arity) (q : (a : arity) → FSM (q_arity a)) (x : new_arityBitStream) :
                    (p.compose new_arity q_arity vars q).eval x = p.eval fun (a : arity) => (q a).eval fun (i : q_arity a) => x (vars a i)

                    Evaluating a composed fsm is equivalent to composing the evaluations of the constituent FSMs

                    Equations
                    Instances For
                      @[simp]
                      theorem FSM.eval_and (x : BoolBitStream) :
                      FSM.and.eval x = x true &&& x false
                      Equations
                      Instances For
                        @[simp]
                        theorem FSM.eval_or (x : BoolBitStream) :
                        FSM.or.eval x = x true ||| x false
                        Equations
                        Instances For
                          @[simp]
                          theorem FSM.eval_xor (x : BoolBitStream) :
                          FSM.xor.eval x = x true ^^^ x false
                          Equations
                          • One or more equations did not get rendered due to their size.
                          Instances For
                            theorem FSM.carry_add_succ (x : BoolBitStream) (n : ) :
                            FSM.add.carry x (n + 1) = fun (x_1 : FSM.add) => ((x true).addAux (x false) n).2

                            The internal carry state of the add FSM agrees with the carry bit of addition as implemented on bitstreams

                            @[simp]
                            theorem FSM.carry_zero {arity : Type} (p : FSM arity) (x : arityBitStream) :
                            p.carry x 0 = p.initCarry
                            @[simp]
                            theorem FSM.initCarry_add :
                            FSM.add.initCarry = fun (x : FSM.add) => false
                            @[simp]
                            theorem FSM.eval_add (x : BoolBitStream) :
                            FSM.add.eval x = x true + x false

                            We don't really need subtraction or negation FSMs, given that we can reduce both those operations to just addition and bitwise complement

                            Equations
                            • One or more equations did not get rendered due to their size.
                            Instances For
                              theorem FSM.carry_sub (x : BoolBitStream) (n : ) :
                              FSM.sub.carry x (n + 1) = fun (x_1 : FSM.sub) => ((x true).subAux (x false) n).2
                              @[simp]
                              theorem FSM.eval_sub (x : BoolBitStream) :
                              FSM.sub.eval x = x true - x false
                              Equations
                              • One or more equations did not get rendered due to their size.
                              Instances For
                                theorem FSM.carry_neg (x : UnitBitStream) (n : ) :
                                FSM.neg.carry x (n + 1) = fun (x_1 : FSM.neg) => ((x ()).negAux n).2
                                @[simp]
                                theorem FSM.eval_neg (x : UnitBitStream) :
                                FSM.neg.eval x = -x ()
                                Equations
                                Instances For
                                  @[simp]
                                  theorem FSM.eval_not (x : UnitBitStream) :
                                  FSM.not.eval x = ~~~x ()
                                  def FSM.zero :
                                  FSM (Fin 0)
                                  Equations
                                  Instances For
                                    @[simp]
                                    theorem FSM.eval_zero (x : Fin 0BitStream) :
                                    def FSM.one :
                                    FSM (Fin 0)
                                    Equations
                                    Instances For
                                      @[simp]
                                      theorem FSM.carry_one (x : Fin 0BitStream) (n : ) :
                                      FSM.one.carry x (n + 1) = fun (x : FSM.one) => false
                                      @[simp]
                                      theorem FSM.eval_one (x : Fin 0BitStream) :
                                      def FSM.negOne :
                                      FSM (Fin 0)
                                      Equations
                                      Instances For
                                        @[simp]
                                        def FSM.ls (b : Bool) :
                                        Equations
                                        Instances For
                                          theorem FSM.carry_ls (b : Bool) (x : UnitBitStream) (n : ) :
                                          (FSM.ls b).carry x (n + 1) = fun (x_1 : (FSM.ls b)) => x () n
                                          @[simp]
                                          theorem FSM.eval_ls (b : Bool) (x : UnitBitStream) :
                                          (FSM.ls b).eval x = BitStream.concat b (x ())
                                          def FSM.var (n : ) :
                                          FSM (Fin (n + 1))
                                          Equations
                                          Instances For
                                            @[simp]
                                            theorem FSM.eval_var (n : ) (x : Fin (n + 1)BitStream) :
                                            (FSM.var n).eval x = x (Fin.last n)
                                            Equations
                                            • One or more equations did not get rendered due to their size.
                                            Instances For
                                              theorem FSM.carry_incr (x : UnitBitStream) (n : ) :
                                              FSM.incr.carry x (n + 1) = fun (x_1 : FSM.incr) => ((x ()).incrAux n).2
                                              @[simp]
                                              theorem FSM.eval_incr (x : UnitBitStream) :
                                              FSM.incr.eval x = (x ()).incr
                                              Equations
                                              • One or more equations did not get rendered due to their size.
                                              Instances For
                                                theorem FSM.carry_decr (x : UnitBitStream) (n : ) :
                                                FSM.decr.carry x (n + 1) = fun (x_1 : FSM.decr) => ((x ()).decrAux n).2
                                                @[simp]
                                                theorem FSM.eval_decr (x : UnitBitStream) :
                                                FSM.decr.eval x = (x ()).decr
                                                theorem FSM.evalAux_eq_zero_of_set {arity : Type} (p : FSM arity) (R : Set (pBool)) (hR : ∀ (x : arityBool) (s : p.State), (p.nextBit s x).1 Rs R) (hi : p.initCarryR) (hr1 : ∀ (x : arityBool) (s : p.State), (p.nextBit s x).2 = trues R) (x : arityBitStream) (n : ) :
                                                p.eval x n = false p.carry x nR
                                                theorem FSM.eval_eq_zero_of_set {arity : Type} (p : FSM arity) (R : Set (pBool)) (hR : ∀ (x : arityBool) (s : p.State), (p.nextBit s x).1 Rs R) (hi : p.initCarryR) (hr1 : ∀ (x : arityBool) (s : p.State), (p.nextBit s x).2 = trues R) :
                                                p.eval = fun (x : arityBitStream) (x : ) => false
                                                Equations
                                                Instances For
                                                  @[simp]
                                                  theorem FSM.eval_repeatBit {x : UnitBitStream} :
                                                  FSM.repeatBit.eval x = (x ()).repeatBit
                                                  structure FSMSolution (t : Term) extends FSM :
                                                  Instances For
                                                    theorem FSMSolution.good {t : Term} (self : FSMSolution t) :
                                                    t.evalFin = self.eval
                                                    def composeUnary (p : FSM Unit) {t : Term} (q : FSMSolution t) :
                                                    FSM (Fin t.arity)
                                                    Equations
                                                    Instances For
                                                      def composeBinary (p : FSM Bool) {t₁ : Term} {t₂ : Term} (q₁ : FSMSolution t₁) (q₂ : FSMSolution t₂) :
                                                      FSM (Fin (max t₁.arity t₂.arity))
                                                      Equations
                                                      • One or more equations did not get rendered due to their size.
                                                      Instances For
                                                        def composeBinary' (p : FSM Bool) {n : } {m : } (q₁ : FSM (Fin n)) (q₂ : FSM (Fin m)) :
                                                        FSM (Fin (max n m))
                                                        Equations
                                                        • One or more equations did not get rendered due to their size.
                                                        Instances For
                                                          @[simp]
                                                          theorem composeUnary_eval (p : FSM Unit) {t : Term} (q : FSMSolution t) (x : Fin t.arityBitStream) :
                                                          (composeUnary p q).eval x = p.eval fun (x_1 : Unit) => t.evalFin x
                                                          @[simp]
                                                          theorem composeBinary_eval (p : FSM Bool) {t₁ : Term} {t₂ : Term} (q₁ : FSMSolution t₁) (q₂ : FSMSolution t₂) (x : Fin (max t₁.arity t₂.arity)BitStream) :
                                                          (composeBinary p q₁ q₂).eval x = p.eval fun (b : Bool) => bif b then t₁.evalFin fun (i : Fin t₁.arity) => x (Fin.castLE i) else t₂.evalFin fun (i : Fin t₂.arity) => x (Fin.castLE i)
                                                          instance instFintypeCond_sSA {α : Type} {β : Type} [Fintype α] [Fintype β] (b : Bool) :
                                                          Fintype (bif b then α else β)
                                                          Equations
                                                          • One or more equations did not get rendered due to their size.
                                                          Equations
                                                          Instances For

                                                            FSM that implement bitwise-and. Since we use 0 as the good state, we keep the invariant that if both inputs are good and our state is 0, then we produce a 0. If not, we produce an infinite sequence of 1.

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

                                                              FSM that implement bitwise-or. Since we use 0 as the good state, we keep the invariant that if either inputs is 0 then our state is 0. If not, we produce a 1.

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

                                                                FSM that implement logical not. we keep the invariant that if the input ever fails and becomes a 1, then we produce a 0. IF not, we produce an infinite sequence of 1.

                                                                EDIT: Aha, this doesn't work! We need NFA to DFA here (as the presburger book does), where we must produce an infinite sequence of0 iff the input can ever become a 1. But here, since we phrase things directly in terms of producing sequences, it's a bit less clear what we should do :)

                                                                inductive Result :
                                                                Instances For
                                                                  Equations
                                                                  def card_compl {α : Type} [Fintype α] [DecidableEq α] (c : Circuit α) :
                                                                  Equations
                                                                  Instances For
                                                                    theorem decideIfZeroAux_wf {α : Type} [Fintype α] [DecidableEq α] {c : Circuit α} {c' : Circuit α} (h : ¬c' c) :
                                                                    @[irreducible]
                                                                    def decideIfZerosAux {arity : Type} [DecidableEq arity] (p : FSM arity) (c : Circuit p) :
                                                                    Equations
                                                                    • One or more equations did not get rendered due to their size.
                                                                    Instances For
                                                                      def decideIfZeros {arity : Type} [DecidableEq arity] (p : FSM arity) :
                                                                      Equations
                                                                      Instances For
                                                                        @[irreducible]
                                                                        theorem decideIfZerosAux_correct {arity : Type} [DecidableEq arity] (p : FSM arity) (c : Circuit p) (hc : ∀ (s : pBool), c.eval s = true∃ (m : ) (y : arityBitStream), (p.changeInitCarry s).eval y m = true) (hc₂ : ∀ (x : arityBool) (s : pBool), (p.nextBit s x).2 = truec.eval s = true) :
                                                                        decideIfZerosAux p c = true ∀ (n : ) (x : arityBitStream), p.eval x n = false
                                                                        theorem decideIfZeros_correct {arity : Type} [DecidableEq arity] (p : FSM arity) :
                                                                        decideIfZeros p = true ∀ (n : ) (x : arityBitStream), p.eval x n = false
                                                                        inductive Predicate :
                                                                        Type

                                                                        The fragment of predicate logic that we support in bv_automata. Currently, we support equality, conjunction, disjunction, and negation. This can be expanded to also support arithmetic constraints such as unsigned-less-than.

                                                                        Instances For
                                                                          def Predicate.denote {α : } :

                                                                          denote a reflected predicate into a `prop.

                                                                          Equations
                                                                          • (Predicate.eq t1 t2).denote = (t1.eval = t2.eval)
                                                                          • (p.and q).denote = (p.denote q.denote)
                                                                          • (p.or q).denote = (p.denote q.denote)
                                                                          Instances For
                                                                            def Predicate.toFSM {k : } :
                                                                            Predicate kFSM (Fin k)

                                                                            Convert a predicate into a proposition

                                                                            Equations
                                                                            Instances For
                                                                              theorem Predicate.toFsm_correct {k : } (p : Predicate k) :
                                                                              decideIfZeros p.toFSM = true p.denote