Documentation

SSA.Experimental.Bits.Fast.BitStream

theorem Int.bmod_eq_of_ge_and_le (z : ) (m : ) (hlower_bound : m / 2 z) (hupper_bound : z < m / 2) :
z.bmod m = z
theorem Int.bmod_ofNat_eq_of_lt (n : ) (m : ) (h : n < (m + 1) / 2) :
(↑n).bmod m = (n % m)
theorem Int.emod_eq_of_neg {a : } {b : } (H1 : a < 0) (H2 : 0 a + b.natAbs) :
a % b = b.natAbs + a

Reflection #

We have a decision procedure which operates on BitStream operations, but we'd like

Equations
Instances For

    Preliminaries #

    Equations
    • x.head = x 0
    Instances For
      Equations
      • x✝.tail x = x✝ (x + 1)
      Instances For

        Append a single bit to the least significant end of a bitvector. That is, the new bit is the least significant bit.

        Equations
        Instances For
          @[reducible, inline]
          abbrev BitStream.map (f : BoolBool) :

          map f maps a (unary) function over a bitstreams

          Equations
          Instances For
            @[reducible, inline]

            map₂ f maps a binary function over two bitstreams

            Equations
            Instances For
              def BitStream.corec {β : Type u_1} (f : ββ × Bool) (b : β) :
              Equations
              Instances For
                def BitStream.mapAccum₂ {α : Type u_1} (f : αBoolBoolα × Bool) (init : α) (x : BitStream) (y : BitStream) :

                mapAccum₂ ("binary map accumulate") maps a binary function f over two streams, while accumulating some state

                Equations
                • One or more equations did not get rendered due to their size.
                Instances For
                  theorem BitStream.ext_iff {x : BitStream} {y : BitStream} :
                  x = y ∀ (i : ), x i = y i
                  theorem BitStream.ext {x : BitStream} {y : BitStream} (h : ∀ (i : ), x i = y i) :
                  x = y
                  theorem BitStream.compose_first {α : Type u₁} (i : ) (a : α) (f : αα × Bool) :
                  (f ((Prod.fst f)^[i] a)).1 = (Prod.fst f)^[i] (f a).1

                  The field projection .1 distributes over function composition, so we can compute the first field of the result of the composition by repeatedly composing the first projection.

                  theorem BitStream.corec_eq_corec {α : Type u_1} {β : Type u_2} {a : α} {b : β} {f : αα × Bool} {g : ββ × Bool} (R : αβProp) (thing : R a b) (h : ∀ (a : α) (b : β), R a blet x := f a; let y := g b; R x.1 y.1 x.2 = y.2) :

                  Coinduction principle for corec. To show that corec f a = corec g b, we must show that:

                  • The relation R a b is inhabited ["base case"]
                  • Given that R a b holds, then R (f a) (g b) holds [coinductive case]

                  OfNat #

                  Zero-extend a natural number to an infinite bitstream

                  Equations
                  Instances For
                    Equations

                    Conversions to and from BitVec #

                    @[reducible, inline]
                    abbrev BitStream.ofBitVec {w : } (x : BitVec w) :

                    Sign-extend a finite bitvector x to the infinite stream (x.msb)^ω ⋅ x

                    Equations
                    Instances For

                      x.toBitVec w returns the first w bits of bitstream x

                      Equations
                      Instances For

                        EqualUpTo w x y holds iff x and y are equal in the first w bits

                        Equations
                        Instances For

                          printPrefix x n returns a string with the first n digits of the bitstream x

                          Equations
                          • x.printPrefix 0 = "0b"
                          • x.printPrefix i.succ = x.tail.printPrefix i ++ if x.head = true then "1" else "0"
                          Instances For

                            Bitwise Operations #

                            @[simp]
                            theorem BitStream.not_eq (x : BitStream) (i : ) :
                            (~~~x) i = !x i
                            @[simp]
                            theorem BitStream.and_eq (x : BitStream) (y : BitStream) (i : ) :
                            (x &&& y) i = (x i && y i)
                            @[simp]
                            theorem BitStream.or_eq (x : BitStream) (y : BitStream) (i : ) :
                            (x ||| y) i = (x i || y i)
                            @[simp]
                            theorem BitStream.xor_eq (x : BitStream) (y : BitStream) (i : ) :
                            (x ^^^ y) i = (x i ^^ y i)

                            Addition, Subtraction, Negation #

                            Equations
                            Instances For
                              Equations
                              • x.add y n = (x.addAux y n).1
                              Instances For
                                Equations
                                • x.subAux y 0 = (x 0 ^^ y 0, !x 0 && y 0)
                                • x.subAux y i.succ = (x (i + 1) ^^ (y (i + 1) ^^ (x.subAux y i).2), !x (i + 1) && y (i + 1) || !(x (i + 1) ^^ y (i + 1)) && (x.subAux y i).2)
                                Instances For
                                  Equations
                                  • x.sub y n = (x.subAux y n).1
                                  Instances For
                                    Equations
                                    • x.negAux 0 = (x 0, !x 0)
                                    • x.negAux i.succ = (!x (i + 1) ^^ (x.negAux i).2, !x (i + 1) && (x.negAux i).2)
                                    Instances For
                                      Equations
                                      • x.neg n = (x.negAux n).1
                                      Instances For
                                        Equations
                                        • x.incrAux 0 = (!x 0, x 0)
                                        • x.incrAux i.succ = (x (i + 1) ^^ (x.incrAux i).2, x (i + 1) && (x.incrAux i).2)
                                        Instances For
                                          Equations
                                          • x.incr n = (x.incrAux n).1
                                          Instances For
                                            Equations
                                            • x.decrAux 0 = (!x 0, !x 0)
                                            • x.decrAux i.succ = (x (i + 1) ^^ (x.decrAux i).2, !x (i + 1) && (x.decrAux i).2)
                                            Instances For
                                              Equations
                                              • x.decr n = (x.decrAux n).1
                                              Instances For
                                                Equations
                                                • x.carry y n = (x.addAux y n).1
                                                Instances For

                                                  repeatBit xs will repeat the first bit of xs which is true. That is, it will be all-zeros iff xs is all-zeroes, otherwise, there's some number k so that after dropping the k least significant bits, repeatBit xs is all-ones.

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

                                                    TODO: We should define addition and carry in terms of mapAccum. For example: def add := mapAccum₂ BitVec.adcb false and

                                                    def carry : BitStreamBitStreamBitStream :=
                                                      mapAccum₂ (fun c x₀ y₀ =>
                                                        let c' := Bool.atLeastTwo c x₀ y₀
                                                        (c', c')
                                                      ) false
                                                    

                                                    Following the same pattern as for ofBitVec_and, _or, etc., we would expect an equality like: ofBitVec (x + y) = (ofBitVec x) + (ofBitVec y) However, this is not actually true, since the left hand side does addition on the bitvector level, thus forgets the extra carry bit, while rhe rhs does addition on streams, thus could have a bit set in the w+1th position.

                                                    Crucially, our decision procedure works by considering which equalities hold for all widths,

                                                    Will subAux overflow/carry when computing a - b?

                                                    Equations
                                                    • a.subCarries? b 0 = (!a 0 && b 0 || !(a 0 ^^ b 0) && false)
                                                    • a.subCarries? b i_1.succ = (!a i_1.succ && b i_1.succ || !(a i_1.succ ^^ b i_1.succ) && a.subCarries? b i_1)
                                                    Instances For
                                                      theorem BitStream.neg_or_add {a : BitStream} {b : BitStream} (i : ) :
                                                      (b.negAux i).2 = false (a.addAux b.neg i).2 = false

                                                      For any i : ℕ, either the ith bit of -b will not overflow, or the ith bit of (a + -b) will not overflow.

                                                      theorem BitStream.subCarries?_correct {a : BitStream} {b : BitStream} (i : ) :
                                                      a.subCarries? b i = ((b.negAux i).2 == (a.addAux b.neg i).2)

                                                      Whether a - b will overflow is equivalent to -b overflows = (a + - b) overflows.

                                                      theorem BitStream.subAux_inductive_lemma {a : BitStream} {b : BitStream} (i : ) :
                                                      a.subAux b i = ((a.addAux b.neg i).1, a.subCarries? b i)
                                                      @[simp]
                                                      theorem BitStream.ofBitVec_getLsbD {w : } {x : BitVec w} (n : ) (h : n < w) :
                                                      BitStream.ofBitVec x n = x.getLsbD n
                                                      Equations
                                                      • BitStream.congr_trans = { trans := }
                                                      theorem BitStream.add_congr {w : } {a : BitStream} {b : BitStream} {c : BitStream} {d : BitStream} (e1 : BitStream.EqualUpTo w a b) (e2 : BitStream.EqualUpTo w c d) :
                                                      BitStream.EqualUpTo w (a + c) (b + d)
                                                      theorem BitStream.and_congr {w : } {a : BitStream} {b : BitStream} {c : BitStream} {d : BitStream} (e1 : BitStream.EqualUpTo w a b) (e2 : BitStream.EqualUpTo w c d) :
                                                      theorem BitStream.or_congr {w : } {a : BitStream} {b : BitStream} {c : BitStream} {d : BitStream} (e1 : BitStream.EqualUpTo w a b) (e2 : BitStream.EqualUpTo w c d) :
                                                      theorem BitStream.xor_congr {w : } {a : BitStream} {b : BitStream} {c : BitStream} {d : BitStream} (e1 : BitStream.EqualUpTo w a b) (e2 : BitStream.EqualUpTo w c d) :
                                                      theorem BitStream.negAux_eq_not_addAux {a : BitStream} :
                                                      a.negAux = (~~~a).addAux 1
                                                      theorem BitStream.incr_congr {w : } {a : BitStream} {b : BitStream} (h : BitStream.EqualUpTo w a b) :
                                                      BitStream.EqualUpTo w a.incr b.incr
                                                      theorem BitStream.sub_congr {w : } {a : BitStream} {b : BitStream} {c : BitStream} {d : BitStream} (e1 : BitStream.EqualUpTo w a b) (e2 : BitStream.EqualUpTo w c d) :
                                                      BitStream.EqualUpTo w (a - c) (b - d)

                                                      OfInt #

                                                      Using OfInt we can convert an Int into the infinite bitstream that represents that particular constant

                                                      Sign-extend an integer to its representation as a 2-adic number (morally, an infinite width 2s complement representation)

                                                      Equations
                                                      Instances For
                                                        @[reducible, inline]
                                                        Equations
                                                        Instances For
                                                          @[reducible, inline]
                                                          Equations
                                                          Instances For
                                                            @[reducible, inline]
                                                            Equations
                                                            Instances For
                                                              @[simp]
                                                              theorem BitStream.one_eq (i : ) :