Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
Try doing some basic maths questions in the Lean Theorem Prover. Functions, real numbers, equivalence relations and groups. Click on README.md and then on "Open in CoCalc with one click".
Project: Xena
Views: 18536License: APACHE
/- Copyright (c) 2014 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Mario Carneiro Binary representation of integers using inductive types. Note: Unlike in Coq, where this representation is preferred because of the reliance on kernel reduction, in Lean this representation is discouraged in favor of the "Peano" natural numbers `nat`, and the purpose of this collection of theorems is to show the equivalence of the different approaches. -/ import data.vector data.bitvec /-- The type of positive binary numbers. 13 = 1101(base 2) = bit1 (bit0 (bit1 one)) -/ @[derive has_reflect, derive decidable_eq] inductive pos_num : Type | one : pos_num | bit1 : pos_num → pos_num | bit0 : pos_num → pos_num instance : has_one pos_num := ⟨pos_num.one⟩ instance : inhabited pos_num := ⟨1⟩ /-- The type of nonnegative binary numbers, using `pos_num`. 13 = 1101(base 2) = pos (bit1 (bit0 (bit1 one))) -/ @[derive has_reflect, derive decidable_eq] inductive num : Type | zero : num | pos : pos_num → num instance : has_zero num := ⟨num.zero⟩ instance : has_one num := ⟨num.pos 1⟩ instance : inhabited num := ⟨0⟩ /-- Representation of integers using trichotomy around zero. 13 = 1101(base 2) = pos (bit1 (bit0 (bit1 one))) -13 = -1101(base 2) = neg (bit1 (bit0 (bit1 one))) -/ @[derive has_reflect, derive decidable_eq] inductive znum : Type | zero : znum | pos : pos_num → znum | neg : pos_num → znum instance : has_zero znum := ⟨znum.zero⟩ instance : has_one znum := ⟨znum.pos 1⟩ instance : inhabited znum := ⟨0⟩ /-- See `snum`. -/ @[derive has_reflect, derive decidable_eq] inductive nzsnum : Type | msb : bool → nzsnum | bit : bool → nzsnum → nzsnum /-- Alternative representation of integers using a sign bit at the end. The convention on sign here is to have the argument to `msb` denote the sign of the MSB itself, with all higher bits set to the negation of this sign. The result is interpreted in two's complement. 13 = ..0001101(base 2) = nz (bit1 (bit0 (bit1 (msb tt)))) -13 = ..1110011(base 2) = nz (bit1 (bit1 (bit0 (msb ff)))) As with `num`, a special case must be added for zero, which has no msb, but by two's complement symmetry there is a second special case for -1. Here the `bool` field indicates the sign of the number. 0 = ..0000000(base 2) = zero ff -1 = ..1111111(base 2) = zero tt -/ @[derive has_reflect, derive decidable_eq] inductive snum : Type | zero : bool → snum | nz : nzsnum → snum instance : has_coe nzsnum snum := ⟨snum.nz⟩ instance : has_zero snum := ⟨snum.zero ff⟩ instance : has_one nzsnum := ⟨nzsnum.msb tt⟩ instance : has_one snum := ⟨snum.nz 1⟩ instance : inhabited nzsnum := ⟨1⟩ instance : inhabited snum := ⟨0⟩ namespace pos_num def bit (b : bool) : pos_num → pos_num := cond b bit1 bit0 def succ : pos_num → pos_num | 1 := bit0 one | (bit1 n) := bit0 (succ n) | (bit0 n) := bit1 n def is_one : pos_num → bool | 1 := tt | _ := ff protected def add : pos_num → pos_num → pos_num | 1 b := succ b | a 1 := succ a | (bit0 a) (bit0 b) := bit0 (add a b) | (bit1 a) (bit1 b) := bit0 (succ (add a b)) | (bit0 a) (bit1 b) := bit1 (add a b) | (bit1 a) (bit0 b) := bit1 (add a b) instance : has_add pos_num := ⟨pos_num.add⟩ def pred' : pos_num → num | 1 := 0 | (bit0 n) := num.pos (num.cases_on (pred' n) 1 bit1) | (bit1 n) := num.pos (bit0 n) def pred (a : pos_num) : pos_num := num.cases_on (pred' a) 1 id def size : pos_num → pos_num | 1 := 1 | (bit0 n) := succ (size n) | (bit1 n) := succ (size n) def nat_size : pos_num → nat | 1 := 1 | (bit0 n) := nat.succ (nat_size n) | (bit1 n) := nat.succ (nat_size n) protected def mul (a : pos_num) : pos_num → pos_num | 1 := a | (bit0 b) := bit0 (mul b) | (bit1 b) := bit0 (mul b) + a instance : has_mul pos_num := ⟨pos_num.mul⟩ def of_nat_succ : ℕ → pos_num | 0 := 1 | (nat.succ n) := succ (of_nat_succ n) def of_nat (n : ℕ) : pos_num := of_nat_succ (nat.pred n) open ordering def cmp : pos_num → pos_num → ordering | 1 1 := eq | _ 1 := gt | 1 _ := lt | (bit0 a) (bit0 b) := cmp a b | (bit0 a) (bit1 b) := ordering.cases_on (cmp a b) lt lt gt | (bit1 a) (bit0 b) := ordering.cases_on (cmp a b) lt gt gt | (bit1 a) (bit1 b) := cmp a b instance : has_lt pos_num := ⟨λa b, cmp a b = ordering.lt⟩ instance : has_le pos_num := ⟨λa b, ¬ b < a⟩ instance decidable_lt : @decidable_rel pos_num (<) | a b := by dsimp [(<)]; apply_instance instance decidable_le : @decidable_rel pos_num (≤) | a b := by dsimp [(≤)]; apply_instance end pos_num section variables {α : Type*} [has_zero α] [has_one α] [has_add α] def cast_pos_num : pos_num → α | 1 := 1 | (pos_num.bit0 a) := bit0 (cast_pos_num a) | (pos_num.bit1 a) := bit1 (cast_pos_num a) def cast_num : num → α | 0 := 0 | (num.pos p) := cast_pos_num p @[priority 10] instance pos_num_coe : has_coe pos_num α := ⟨cast_pos_num⟩ @[priority 10] instance num_nat_coe : has_coe num α := ⟨cast_num⟩ instance : has_repr pos_num := ⟨λ n, repr (n : ℕ)⟩ instance : has_repr num := ⟨λ n, repr (n : ℕ)⟩ end namespace num open pos_num def succ' : num → pos_num | 0 := 1 | (pos p) := succ p def succ (n : num) : num := pos (succ' n) protected def add : num → num → num | 0 a := a | b 0 := b | (pos a) (pos b) := pos (a + b) instance : has_add num := ⟨num.add⟩ protected def bit0 : num → num | 0 := 0 | (pos n) := pos (pos_num.bit0 n) protected def bit1 : num → num | 0 := 1 | (pos n) := pos (pos_num.bit1 n) def bit (b : bool) : num → num := cond b num.bit1 num.bit0 def size : num → num | 0 := 0 | (pos n) := pos (pos_num.size n) def nat_size : num → nat | 0 := 0 | (pos n) := pos_num.nat_size n protected def mul : num → num → num | 0 _ := 0 | _ 0 := 0 | (pos a) (pos b) := pos (a * b) instance : has_mul num := ⟨num.mul⟩ open ordering def cmp : num → num → ordering | 0 0 := eq | _ 0 := gt | 0 _ := lt | (pos a) (pos b) := pos_num.cmp a b instance : has_lt num := ⟨λa b, cmp a b = ordering.lt⟩ instance : has_le num := ⟨λa b, ¬ b < a⟩ instance decidable_lt : @decidable_rel num (<) | a b := by dsimp [(<)]; apply_instance instance decidable_le : @decidable_rel num (≤) | a b := by dsimp [(≤)]; apply_instance def to_znum : num → znum | 0 := 0 | (pos a) := znum.pos a def to_znum_neg : num → znum | 0 := 0 | (pos a) := znum.neg a def of_nat' : ℕ → num := nat.binary_rec 0 (λ b n, cond b num.bit1 num.bit0) end num namespace znum open pos_num def zneg : znum → znum | 0 := 0 | (pos a) := neg a | (neg a) := pos a instance : has_neg znum := ⟨zneg⟩ def abs : znum → num | 0 := 0 | (pos a) := num.pos a | (neg a) := num.pos a def succ : znum → znum | 0 := 1 | (pos a) := pos (pos_num.succ a) | (neg a) := (pos_num.pred' a).to_znum_neg def pred : znum → znum | 0 := neg 1 | (pos a) := (pos_num.pred' a).to_znum | (neg a) := neg (pos_num.succ a) protected def bit0 : znum → znum | 0 := 0 | (pos n) := pos (pos_num.bit0 n) | (neg n) := neg (pos_num.bit0 n) protected def bit1 : znum → znum | 0 := 1 | (pos n) := pos (pos_num.bit1 n) | (neg n) := neg (num.cases_on (pred' n) 1 pos_num.bit1) protected def bitm1 : znum → znum | 0 := neg 1 | (pos n) := pos (num.cases_on (pred' n) 1 pos_num.bit1) | (neg n) := neg (pos_num.bit1 n) def of_int' : ℤ → znum | (n : ℕ) := num.to_znum (num.of_nat' n) | -[1+ n] := num.to_znum_neg (num.of_nat' (n+1)) end znum namespace pos_num open znum def sub' : pos_num → pos_num → znum | a 1 := (pred' a).to_znum | 1 b := (pred' b).to_znum_neg | (bit0 a) (bit0 b) := (sub' a b).bit0 | (bit0 a) (bit1 b) := (sub' a b).bitm1 | (bit1 a) (bit0 b) := (sub' a b).bit1 | (bit1 a) (bit1 b) := (sub' a b).bit0 def of_znum' : znum → option pos_num | (znum.pos p) := some p | _ := none def of_znum : znum → pos_num | (znum.pos p) := p | _ := 1 protected def sub (a b : pos_num) : pos_num := match sub' a b with | (znum.pos p) := p | _ := 1 end instance : has_sub pos_num := ⟨pos_num.sub⟩ end pos_num namespace num def ppred : num → option num | 0 := none | (pos p) := some p.pred' def pred : num → num | 0 := 0 | (pos p) := p.pred' def div2 : num → num | 0 := 0 | 1 := 0 | (pos (pos_num.bit0 p)) := pos p | (pos (pos_num.bit1 p)) := pos p def of_znum' : znum → option num | 0 := some 0 | (znum.pos p) := some (pos p) | (znum.neg p) := none def of_znum : znum → num | (znum.pos p) := pos p | _ := 0 def sub' : num → num → znum | 0 0 := 0 | (pos a) 0 := znum.pos a | 0 (pos b) := znum.neg b | (pos a) (pos b) := a.sub' b def psub (a b : num) : option num := of_znum' (sub' a b) protected def sub (a b : num) : num := of_znum (sub' a b) instance : has_sub num := ⟨num.sub⟩ end num namespace znum open pos_num protected def add : znum → znum → znum | 0 a := a | b 0 := b | (pos a) (pos b) := pos (a + b) | (pos a) (neg b) := sub' a b | (neg a) (pos b) := sub' b a | (neg a) (neg b) := neg (a + b) instance : has_add znum := ⟨znum.add⟩ protected def mul : znum → znum → znum | 0 a := 0 | b 0 := 0 | (pos a) (pos b) := pos (a * b) | (pos a) (neg b) := neg (a * b) | (neg a) (pos b) := neg (a * b) | (neg a) (neg b) := pos (a * b) instance : has_mul znum := ⟨znum.mul⟩ open ordering def cmp : znum → znum → ordering | 0 0 := eq | (pos a) (pos b) := pos_num.cmp a b | (neg a) (neg b) := pos_num.cmp b a | (pos _) _ := gt | (neg _) _ := lt | _ (pos _) := lt | _ (neg _) := gt instance : has_lt znum := ⟨λa b, cmp a b = ordering.lt⟩ instance : has_le znum := ⟨λa b, ¬ b < a⟩ instance decidable_lt : @decidable_rel znum (<) | a b := by dsimp [(<)]; apply_instance instance decidable_le : @decidable_rel znum (≤) | a b := by dsimp [(≤)]; apply_instance end znum namespace pos_num def divmod_aux (d : pos_num) (q r : num) : num × num := match num.of_znum' (num.sub' r (num.pos d)) with | some r' := (num.bit1 q, r') | none := (num.bit0 q, r) end def divmod (d : pos_num) : pos_num → num × num | (bit0 n) := let (q, r₁) := divmod n in divmod_aux d q (num.bit0 r₁) | (bit1 n) := let (q, r₁) := divmod n in divmod_aux d q (num.bit1 r₁) | 1 := divmod_aux d 0 1 def div' (n d : pos_num) : num := (divmod d n).1 def mod' (n d : pos_num) : num := (divmod d n).2 def sqrt_aux1 (b : pos_num) (r n : num) : num × num := match num.of_znum' (n.sub' (r + num.pos b)) with | some n' := (r.div2 + num.pos b, n') | none := (r.div2, n) end def sqrt_aux : pos_num → num → num → num | b@(bit0 b') r n := let (r', n') := sqrt_aux1 b r n in sqrt_aux b' r' n' | b@(bit1 b') r n := let (r', n') := sqrt_aux1 b r n in sqrt_aux b' r' n' | 1 r n := (sqrt_aux1 1 r n).1 /- def sqrt_aux : ℕ → ℕ → ℕ → ℕ | b r n := if b0 : b = 0 then r else let b' := shiftr b 2 in have b' < b, from sqrt_aux_dec b0, match (n - (r + b : ℕ) : ℤ) with | (n' : ℕ) := sqrt_aux b' (div2 r + b) n' | _ := sqrt_aux b' (div2 r) n end /-- `sqrt n` is the square root of a natural number `n`. If `n` is not a perfect square, it returns the largest `k:ℕ` such that `k*k ≤ n`. -/ def sqrt (n : ℕ) : ℕ := match size n with | 0 := 0 | succ s := sqrt_aux (shiftl 1 (bit0 (div2 s))) 0 n end -/ end pos_num namespace num def div : num → num → num | 0 _ := 0 | _ 0 := 0 | (pos n) (pos d) := pos_num.div' n d def mod : num → num → num | 0 _ := 0 | n 0 := n | (pos n) (pos d) := pos_num.mod' n d instance : has_div num := ⟨num.div⟩ instance : has_mod num := ⟨num.mod⟩ def gcd_aux : nat → num → num → num | 0 a b := b | (nat.succ n) 0 b := b | (nat.succ n) a b := gcd_aux n (b % a) a def gcd (a b : num) : num := if a ≤ b then gcd_aux (a.nat_size + b.nat_size) a b else gcd_aux (b.nat_size + a.nat_size) b a end num namespace znum def div : znum → znum → znum | 0 _ := 0 | _ 0 := 0 | (pos n) (pos d) := num.to_znum (pos_num.div' n d) | (pos n) (neg d) := num.to_znum_neg (pos_num.div' n d) | (neg n) (pos d) := neg (pos_num.pred' n / num.pos d).succ' | (neg n) (neg d) := pos (pos_num.pred' n / num.pos d).succ' def mod : znum → znum → znum | 0 d := 0 | (pos n) d := num.to_znum (num.pos n % d.abs) | (neg n) d := d.abs.sub' (pos_num.pred' n % d.abs).succ instance : has_div znum := ⟨znum.div⟩ instance : has_mod znum := ⟨znum.mod⟩ def gcd (a b : znum) : num := a.abs.gcd b.abs end znum section variables {α : Type*} [has_zero α] [has_one α] [has_add α] [has_neg α] def cast_znum : znum → α | 0 := 0 | (znum.pos p) := p | (znum.neg p) := -p @[priority 10] instance znum_coe : has_coe znum α := ⟨cast_znum⟩ instance : has_repr znum := ⟨λ n, repr (n : ℤ)⟩ end /- The snum representation uses a bit string, essentially a list of 0 (ff) and 1 (tt) bits, and the negation of the MSB is sign-extended to all higher bits. -/ namespace nzsnum notation a :: b := bit a b def sign : nzsnum → bool | (msb b) := bnot b | (b :: p) := sign p @[pattern] def not : nzsnum → nzsnum | (msb b) := msb (bnot b) | (b :: p) := bnot b :: not p prefix ~ := not def bit0 : nzsnum → nzsnum := bit ff def bit1 : nzsnum → nzsnum := bit tt def head : nzsnum → bool | (msb b) := b | (b :: p) := b def tail : nzsnum → snum | (msb b) := snum.zero (bnot b) | (b :: p) := p end nzsnum namespace snum open nzsnum def sign : snum → bool | (zero z) := z | (nz p) := p.sign @[pattern] def not : snum → snum | (zero z) := zero (bnot z) | (nz p) := ~p prefix ~ := not @[pattern] def bit : bool → snum → snum | b (zero z) := if b = z then zero b else msb b | b (nz p) := p.bit b notation a :: b := bit a b def bit0 : snum → snum := bit ff def bit1 : snum → snum := bit tt theorem bit_zero (b) : b :: zero b = zero b := by cases b; refl theorem bit_one (b) : b :: zero (bnot b) = msb b := by cases b; refl end snum namespace nzsnum open snum def drec' {C : snum → Sort*} (z : Π b, C (snum.zero b)) (s : Π b p, C p → C (b :: p)) : Π p : nzsnum, C p | (msb b) := by rw ←bit_one; exact s b (snum.zero (bnot b)) (z (bnot b)) | (bit b p) := s b p (drec' p) end nzsnum namespace snum open nzsnum def head : snum → bool | (zero z) := z | (nz p) := p.head def tail : snum → snum | (zero z) := zero z | (nz p) := p.tail def drec' {C : snum → Sort*} (z : Π b, C (snum.zero b)) (s : Π b p, C p → C (b :: p)) : Π p, C p | (zero b) := z b | (nz p) := p.drec' z s def rec' {α} (z : bool → α) (s : bool → snum → α → α) : snum → α := drec' z s def bits : snum → Π n, vector bool n | p 0 := vector.nil | p (n+1) := head p :: bits (tail p) n def test_bit : nat → snum → bool | 0 p := head p | (n+1) p := test_bit n (tail p) def succ : snum → snum := rec' (λ b, cond b 0 1) (λb p succp, cond b (ff :: succp) (tt :: p)) def pred : snum → snum := rec' (λ b, cond b (~1) ~0) (λb p predp, cond b (ff :: p) (tt :: predp)) protected def neg (n : snum) : snum := succ ~n instance : has_neg snum := ⟨snum.neg⟩ -- First bit is 0 or 1 (tt), second bit is 0 or -1 (tt) def czadd : bool → bool → snum → snum | ff ff p := p | ff tt p := pred p | tt ff p := succ p | tt tt p := p def cadd : snum → snum → bool → snum := rec' (λ a p c, czadd c a p) $ λa p IH, rec' (λb c, czadd c b (a :: p)) $ λb q _ c, bitvec.xor3 a b c :: IH q (bitvec.carry a b c) protected def add (a b : snum) : snum := cadd a b ff instance : has_add snum := ⟨snum.add⟩ protected def sub (a b : snum) : snum := a + -b instance : has_sub snum := ⟨snum.sub⟩ protected def mul (a : snum) : snum → snum := rec' (λ b, cond b (-a) 0) $ λb q IH, cond b (bit0 IH + a) (bit0 IH) instance : has_mul snum := ⟨snum.mul⟩ end snum namespace int def of_snum : snum → ℤ := snum.rec' (λ a, cond a (-1) 0) (λa p IH, cond a (bit1 IH) (bit0 IH)) instance snum_coe : has_coe snum ℤ := ⟨of_snum⟩ end int instance : has_lt snum := ⟨λa b, (a : ℤ) < b⟩ instance : has_le snum := ⟨λa b, (a : ℤ) ≤ b⟩