lean4-htt/library/data/bitvec.lean

171 lines
5 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2015 Joe Hendrix. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joe Hendrix, Sebastian Ullrich
Basic operations on bitvectors.
This is a work-in-progress, and contains additions to other theories.
-/
import data.vector
@[reducible] def bitvec (n : ) := vector bool n
namespace bitvec
open nat
open vector
local infix `++ₜ`:65 := vector.append
-- Create a zero bitvector
@[reducible] protected def zero (n : ) : bitvec n := repeat ff n
-- Create a bitvector with the constant one.
@[reducible] protected def one : Π (n : ), bitvec n
| 0 := []
| (succ n) := repeat ff n ++ₜ [tt]
protected def cong {a b : } (h : a = b) : bitvec a → bitvec b
| ⟨x, p⟩ := ⟨x, h ▸ p⟩
-- bitvec specific version of vector.append
def append {m n} : bitvec m → bitvec n → bitvec (m + n) := vector.append
section shift
variable {n : }
def shl (x : bitvec n) (i : ) : bitvec n :=
bitvec.cong (by simp) $
dropn i x ++ₜ repeat ff (min n i)
local attribute [ematch] nat.add_sub_assoc sub_le le_of_not_ge sub_eq_zero_of_le
def fill_shr (x : bitvec n) (i : ) (fill : bool) : bitvec n :=
bitvec.cong (by async { begin [smt] by_cases (i ≤ n), eblast end }) $
repeat fill (min n i) ++ₜ taken (n-i) x
-- unsigned shift right
def ushr (x : bitvec n) (i : ) : bitvec n :=
fill_shr x i ff
-- signed shift right
def sshr : Π {m : }, bitvec m → → bitvec m
| 0 _ _ := []
| (succ m) x i := head x :: fill_shr (tail x) i (head x)
end shift
section bitwise
variable {n : }
def not : bitvec n → bitvec n := map bnot
def and : bitvec n → bitvec n → bitvec n := map₂ band
def or : bitvec n → bitvec n → bitvec n := map₂ bor
def xor : bitvec n → bitvec n → bitvec n := map₂ bxor
end bitwise
section arith
variable {n : }
protected def xor3 (x y c : bool) := bxor (bxor x y) c
protected def carry (x y c : bool) :=
x && y || x && c || y && c
protected def neg (x : bitvec n) : bitvec n :=
let f := λ y c, (y || c, bxor y c) in
prod.snd (map_accumr f x ff)
-- Add with carry (no overflow)
def adc (x y : bitvec n) (c : bool) : bitvec (n+1) :=
let f := λ x y c, (bitvec.carry x y c, bitvec.xor3 x y c) in
let ⟨c, z⟩ := vector.map_accumr₂ f x y c in
c :: z
protected def add (x y : bitvec n) : bitvec n := tail (adc x y ff)
protected def borrow (x y b : bool) :=
bnot x && y || bnot x && b || y && b
-- Subtract with borrow
def sbb (x y : bitvec n) (b : bool) : bool × bitvec n :=
let f := λ x y c, (bitvec.borrow x y c, bitvec.xor3 x y c) in
vector.map_accumr₂ f x y b
protected def sub (x y : bitvec n) : bitvec n := prod.snd (sbb x y ff)
instance : has_zero (bitvec n) := ⟨bitvec.zero n⟩
instance : has_one (bitvec n) := ⟨bitvec.one n⟩
instance : has_add (bitvec n) := ⟨bitvec.add⟩
instance : has_sub (bitvec n) := ⟨bitvec.sub⟩
instance : has_neg (bitvec n) := ⟨bitvec.neg⟩
protected def mul (x y : bitvec n) : bitvec n :=
let f := λ r b, cond b (r + r + y) (r + r) in
list.foldl f 0 (to_list x)
instance : has_mul (bitvec n) := ⟨bitvec.mul⟩
end arith
section comparison
variable {n : }
def uborrow (x y : bitvec n) : bool := prod.fst (sbb x y ff)
def ult (x y : bitvec n) : Prop := uborrow x y
def ugt (x y : bitvec n) : Prop := ult y x
def ule (x y : bitvec n) : Prop := ¬ (ult y x)
def uge (x y : bitvec n) : Prop := ule y x
def sborrow : Π {n : }, bitvec n → bitvec n → bool
| 0 _ _ := ff
| (succ n) x y :=
match (head x, head y) with
| (tt, ff) := tt
| (ff, tt) := ff
| _ := uborrow (tail x) (tail y)
end
def slt (x y : bitvec n) : Prop := sborrow x y
def sgt (x y : bitvec n) : Prop := slt y x
def sle (x y : bitvec n) : Prop := ¬ (slt y x)
def sge (x y : bitvec n) : Prop := sle y x
end comparison
section conversion
variable {α : Type}
protected def of_nat : Π (n : ), nat → bitvec n
| 0 x := nil
| (succ n) x := of_nat n (x / 2) ++ₜ [to_bool (x % 2 = 1)]
protected def of_int : Π (n : ), int → bitvec (succ n)
| n (int.of_nat m) := ff :: bitvec.of_nat n m
| n (int.neg_succ_of_nat m) := tt :: not (bitvec.of_nat n m)
def bits_to_nat (v : list bool) : nat :=
list.foldl (λ r b, r + r + cond b 1 0) 0 v
protected def to_nat {n : nat} (v : bitvec n) : nat :=
bits_to_nat (to_list v)
protected def to_int : Π {n : nat}, bitvec n → int
| 0 _ := 0
| (succ n) v :=
cond (head v)
(int.neg_succ_of_nat $ bitvec.to_nat $ not $ tail v)
(int.of_nat $ bitvec.to_nat $ tail v)
end conversion
private def to_string {n : nat} : bitvec n → string
| ⟨bs, p⟩ :=
"0b" ++ (bs^.reverse^.for (λ b, if b then #"1" else #"0"))
instance (n : nat) : has_to_string (bitvec n) :=
⟨to_string⟩
end bitvec
instance {n} {x y : bitvec n} : decidable (bitvec.ult x y) := bool.decidable_eq _ _
instance {n} {x y : bitvec n} : decidable (bitvec.ugt x y) := bool.decidable_eq _ _