module UInt
import Base
import Nat
private union Binary {
bzero
dub_inc(Binary)
inc_dub(Binary)
}
private union UIntView {
UIntZero
UIntSucc(Binary)
}
export UIntZero
export UIntSucc
opaque recursive toNat(Binary) -> Nat {
toNat(bzero) = ℕ0
toNat(dub_inc(x)) = ℕ2 * suc(toNat(x))
toNat(inc_dub(x)) = suc(ℕ2 * toNat(x))
}
assert toNat(bzero) = ℕ0
assert toNat(inc_dub(bzero)) = ℕ1
assert toNat(dub_inc(bzero)) = ℕ2
assert toNat(inc_dub(inc_dub(bzero))) = ℕ3
assert toNat(dub_inc(inc_dub(bzero))) = ℕ4
opaque recursive operator< (Binary, Binary) -> bool {
operator < (bzero, y) =
switch y {
case bzero { false }
case dub_inc(y') { true }
case inc_dub(y') { true }
}
operator < (dub_inc(x'), y) =
switch y {
case bzero { false }
case dub_inc(y') { x' < y' }
case inc_dub(y') { x' < y' }
}
operator < (inc_dub(x'), y) =
switch y {
case bzero { false }
case dub_inc(y') { x' < y' or x' = y' }
case inc_dub(y') { x' < y' }
}
}
fun operator ≤ (x:Binary, y:Binary) {
x < y or x = y
}
fun operator > (x:Binary, y:Binary) {
y < x
}
fun operator ≥ (x:Binary, y:Binary) {
y ≤ x
}
private recursive dub(Binary) -> Binary {
dub(bzero) = bzero
dub(dub_inc(x)) = dub_inc(inc_dub(x))
dub(inc_dub(x)) = dub_inc(dub(x))
}
private recursive inc(Binary) -> Binary {
inc(bzero) = inc_dub(bzero)
inc(dub_inc(x)) = inc_dub(inc(x))
inc(inc_dub(x)) = dub_inc(x)
}
private fun pred(x:Binary) {
switch x {
case bzero { bzero }
case dub_inc(x') { inc_dub(x') }
case inc_dub(x') { dub(x') }
}
}
private fun uint_view(x:Binary) {
if x = bzero then UIntZero else UIntSucc(pred(x))
}
private fun uint_unview(v:UIntView) {
switch v {
case UIntZero { bzero }
case UIntSucc(p) { inc(p) }
}
}
lemma dub_inc_is_dub_inc: all x:Binary. dub(inc(x)) = dub_inc(x)
proof
induction Binary
case bzero {
evaluate
}
case dub_inc(x) assume IH {
expand inc | dub
replace IH
.
}
case inc_dub(x) assume IH {
evaluate
}
end
lemma uint_view_inc: all x:Binary. uint_view(inc(x)) = UIntSucc(x)
proof
induction Binary
case bzero {
evaluate
}
case dub_inc(x) assume IH {
suffices uint_view(inc(dub_inc(x))) = UIntSucc(dub_inc(x)) by .
expand uint_view | inc | pred
replace dub_inc_is_dub_inc[x]
.
}
case inc_dub(x) assume IH {
evaluate
}
end
lemma uint_view_unview: all v:UIntView. uint_view(uint_unview(v)) = v
proof
arbitrary v:UIntView
switch v {
case UIntZero { evaluate }
case UIntSucc(p) {
expand uint_unview
uint_view_inc[p]
}
}
end
view UInt {
source Binary
target UIntView
into uint_view
out uint_unview
roundtrip uint_view_unview
}
opaque fun div2(b : UInt) {
switch b {
case bzero { bzero }
case dub_inc(x) { inc(x) }
case inc_dub(x) { x }
}
}
private recursive cnt_dubs(Binary) -> Binary {
cnt_dubs(bzero) = bzero
cnt_dubs(dub_inc(x)) = inc(cnt_dubs(x))
cnt_dubs(inc_dub(x)) = inc(cnt_dubs(x))
}
opaque fun log(b : UInt) {
cnt_dubs(pred(b))
}
opaque recursive operator+(Binary, Binary) -> Binary {
operator+(bzero, y) = y
operator+(dub_inc(x), y) =
switch y {
case bzero { dub_inc(x) }
case dub_inc(y') { dub_inc(inc(x + y')) }
case inc_dub(y') { inc(dub_inc(x + y')) }
}
operator+(inc_dub(x), y) =
switch y {
case bzero { inc_dub(x) }
case dub_inc(y') { inc(dub_inc(x + y')) }
case inc_dub(y') { inc(inc_dub(x + y')) }
}
}
opaque recursive operator ∸ (Binary, Binary) -> Binary {
operator∸(bzero, y) = bzero
operator∸(dub_inc(x), y) =
switch y {
case bzero { dub_inc(x) }
case dub_inc(y') { dub(x ∸ y') }
case inc_dub(y') {
if x < y' then bzero
else inc_dub(x ∸ y')
}
}
operator∸(inc_dub(x), y) =
switch y {
case bzero { inc_dub(x) }
case dub_inc(y') {
if x < y' then bzero else pred(dub(x ∸ y'))
}
case inc_dub(y') { dub(x ∸ y') }
}
}
opaque recursive operator *(Binary, Binary) -> Binary {
operator*(bzero, y) = bzero
operator*(dub_inc(x), y) =
switch y {
case bzero { bzero }
case dub_inc(y') {
dub(dub_inc(x + y' + x * y'))
}
case inc_dub(y') {
dub_inc(x + dub(y' + x*y'))
}
}
operator*(inc_dub(x), y) =
switch y {
case bzero { bzero }
case dub_inc(y') {
dub_inc(dub(x) + y' + dub(x * y'))
}
case inc_dub(y') {
inc_dub(x + y' + dub(x * y'))
}
}
}
fun sqr(a : UInt) { a * a }
private recursive expt(Binary, Binary) -> Binary {
expt(bzero, a) = inc_dub(bzero)
expt(dub_inc(p), a) = sqr(a * expt(p, a))
expt(inc_dub(p), a) = a * sqr(expt(p, a))
}
opaque fun operator ^(a : UInt, b : UInt) {
expt(b, a)
}
opaque recursive fromNat(Nat) -> UInt {
fromNat(0) = bzero
fromNat(suc(n)) = inc(fromNat(n))
}
fun max(x : UInt, y : UInt) {
if x < y then y
else x
}
fun min(x : UInt, y : UInt) {
if x < y then x
else y
}