FSM n
represents a function BitStream → ⋯ → BitStream → BitStream
,
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 : self.α → Bool
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 toa : α
.
Instances For
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
Instances For
p.changeInitCarry c
yields an FSM with c
as the initial state
Instances For
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
Instances For
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 i
th bit that is fed to the FSM p
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Evaluating a composed fsm is equivalent to composing the evaluations of the constituent FSMs
We don't really need subtraction or negation FSMs, given that we can reduce both those operations to just addition and bitwise complement
Instances For
Equations
Instances For
Equations
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- termEvalEqFSM (Term.var n) = { toFSM := FSM.var n, good := ⋯ }
- termEvalEqFSM Term.zero = { toFSM := FSM.zero, good := termEvalEqFSM.proof_17 }
- termEvalEqFSM Term.one = { toFSM := FSM.one, good := termEvalEqFSM.proof_18 }
- termEvalEqFSM Term.negOne = { toFSM := FSM.negOne, good := termEvalEqFSM.proof_19 }
- termEvalEqFSM (t₁.and t₂) = { toFSM := composeBinary FSM.and (termEvalEqFSM t₁) (termEvalEqFSM t₂), good := ⋯ }
- termEvalEqFSM (t₁.or t₂) = { toFSM := composeBinary FSM.or (termEvalEqFSM t₁) (termEvalEqFSM t₂), good := ⋯ }
- termEvalEqFSM (t₁.xor t₂) = { toFSM := composeBinary FSM.xor (termEvalEqFSM t₁) (termEvalEqFSM t₂), good := ⋯ }
- termEvalEqFSM (Term.ls b t) = { toFSM := id (composeUnary (FSM.ls b) (termEvalEqFSM t)), good := ⋯ }
- termEvalEqFSM t.not = { toFSM := id (composeUnary FSM.not (termEvalEqFSM t)), good := ⋯ }
- termEvalEqFSM (t₁.add t₂) = { toFSM := composeBinary FSM.add (termEvalEqFSM t₁) (termEvalEqFSM t₂), good := ⋯ }
- termEvalEqFSM (t₁.sub t₂) = { toFSM := composeBinary FSM.sub (termEvalEqFSM t₁) (termEvalEqFSM t₂), good := ⋯ }
- termEvalEqFSM t.neg = { toFSM := id (composeUnary FSM.neg (termEvalEqFSM t)), good := ⋯ }
- termEvalEqFSM t.incr = { toFSM := id (composeUnary FSM.incr (termEvalEqFSM t)), good := ⋯ }
- termEvalEqFSM t.decr = { toFSM := id (composeUnary FSM.decr (termEvalEqFSM t)), good := ⋯ }
- termEvalEqFSM t.repeatBit = { toFSM := id (composeUnary FSM.repeatBit (termEvalEqFSM t)), good := ⋯ }
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
.
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
.
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 :)
- Alternatively, we need to be able to decide
eventually always zero
. - Alternatively, we push negations inside, and decide
⬝ ≠ ⬝
and⬝ ≰ ⬝
.
Equations
Equations
- card_compl c = (Finset.filter (fun (a : α → Bool) => c.eval a = false) Finset.univ).card
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- decideIfZeros p = decideIfZerosAux p (p.nextBitCirc none).fst
Instances For
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.
- eq: (t1 t2 : Term) → Predicate (max t1.arity t2.arity)
- and: {n m : ℕ} → Predicate n → Predicate m → Predicate (max n m)
- or: {n m : ℕ} → Predicate n → Predicate m → Predicate (max n m)
Instances For
Convert a predicate into a proposition
Equations
- (Predicate.eq t1 t2).toFSM = (termEvalEqFSM (t1.xor t2).repeatBit).toFSM
- (p.and q).toFSM = composeBinary' FSM.and p.toFSM q.toFSM
- (p.or q).toFSM = composeBinary' FSM.or p.toFSM q.toFSM