lean4-htt/library/data/bitvec.lean
Leonardo de Moura b1bdc4690f feat(library/init/meta/simp_tactic): cleanup dunfold
Here are modifications:
- It fails if no definition is unfolded.
  See comment https://github.com/leanprover/lean/issues/1694#issuecomment-310956315
  at issue #1694

- Users can provide configuration parameters.

- `dunfold_occs` was deleted.
2017-06-30 20:49:20 -07:00

222 lines
6.4 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)
def fill_shr (x : bitvec n) (i : ) (fill : bool) : bitvec n :=
bitvec.cong
begin
by_cases (i ≤ n),
{ have h₁ := sub_le n i,
rw [min_eq_right h], rw [min_eq_left h₁, -nat.add_sub_assoc h, add_comm, nat.add_sub_cancel] },
{ have h₁ := le_of_not_ge h,
rw [min_eq_left h₁, sub_eq_zero_of_le h₁, min_zero_left, add_zero] }
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)
-- Subtract with borrow
def sbb (x y : bitvec n) (b : bool) : bool × bitvec n :=
let f := λ x y c, (bitvec.carry (bnot 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
(to_list x).foldl f 0
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 add_lsb (r : ) (b : bool) := r + r + cond b 1 0
def bits_to_nat (v : list bool) : nat :=
v.foldl add_lsb 0
protected def to_nat {n : nat} (v : bitvec n) : nat :=
bits_to_nat (to_list v)
lemma bits_to_nat_to_list {n : } (x : bitvec n)
: bitvec.to_nat x = bits_to_nat (vector.to_list x) := rfl
theorem to_nat_append {m : } (xs : bitvec m) (b : bool)
: bitvec.to_nat (xs ++ₜ[b]) = bitvec.to_nat xs * 2 + bitvec.to_nat [b] :=
begin
cases xs with xs P,
simp [bits_to_nat_to_list], clear P,
unfold bits_to_nat list.foldl,
-- the next 4 lines generalize the accumulator of foldl
let x := 0,
change _ = add_lsb x b + _,
generalize 0 y,
revert x, simp,
induction xs with x xs ; intro y,
{ simp, unfold list.foldl add_lsb, simp [nat.mul_succ] },
{ simp, apply ih_1 }
end
theorem bits_to_nat_to_bool (n : )
: bitvec.to_nat [to_bool (n % 2 = 1)] = n % 2 :=
begin
simp [bits_to_nat_to_list],
unfold bits_to_nat add_lsb list.foldl cond,
simp [cond_to_bool_mod_two],
end
lemma of_nat_succ {k n : }
: bitvec.of_nat (succ k) n = bitvec.of_nat k (n / 2) ++ₜ[to_bool (n % 2 = 1)] :=
rfl
theorem to_nat_of_nat {k n : }
: bitvec.to_nat (bitvec.of_nat k n) = n % 2^k :=
begin
revert n,
induction k with k ; intro n,
{ unfold pow, simp [nat.mod_one], refl },
{ have h : 0 < 2, { apply le_succ },
rw [ of_nat_succ
, to_nat_append
, ih_1
, bits_to_nat_to_bool
, mod_pow_succ h],
ac_refl, }
end
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 repr {n : nat} : bitvec n → string
| ⟨bs, p⟩ :=
"0b" ++ (bs.map (λ b : bool, if b then '1' else '0')).as_string
instance (n : nat) : has_repr (bitvec n) :=
⟨repr⟩
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 _ _