summaryrefslogtreecommitdiff
path: root/Verification/Specifications.lean
blob: 392c4384d73bfd23283ca1975e5100f3dcf81452 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import «AvlVerification»

namespace Primitives

namespace Result

def map {A B: Type} (x: Result A) (f: A -> B): Result B := match x with
| .ok y => .ok (f y)
| .fail e => .fail e
| .div => .div

@[inline]
def isok {A: Type} : Result A -> Bool
| .ok _ => true
| .fail _ => false
| .div => false

@[inline]
def get? {A: Type}: (r: Result A) -> isok r -> A
| .ok x, _ => x

end Result

end Primitives

namespace avl_verification

@[simp]
def Ordering.toLeanOrdering (o: avl_verification.Ordering): _root_.Ordering := match o with 
| .Less => .lt
| .Equal => .eq
| .Greater => .gt

def Ordering.ofLeanOrdering (o: _root_.Ordering): avl_verification.Ordering := match o with
| .lt => .Less
| .eq => .Equal
| .gt => .Greater

@[simp]
def Ordering.toDualOrdering (o: avl_verification.Ordering): avl_verification.Ordering := match o with 
| .Less => .Greater
| .Equal => .Equal
| .Greater => .Less

@[simp]
theorem Ordering.toLeanOrdering.injEq (x y: avl_verification.Ordering): (x.toLeanOrdering = y.toLeanOrdering) = (x = y) := by
  apply propext
  cases x <;> cases y <;> simp

@[simp]
theorem ite_eq_lt_distrib (c : Prop) [Decidable c] (a b : Ordering) :
    ((if c then a else b) = .Less) = if c then a = .Less else b = .Less := by
  by_cases c <;> simp [*]

@[simp]
theorem ite_eq_eq_distrib (c : Prop) [Decidable c] (a b : Ordering) :
    ((if c then a else b) = .Equal) = if c then a = .Equal else b = .Equal := by
  by_cases c <;> simp [*]

@[simp]
theorem ite_eq_gt_distrib (c : Prop) [Decidable c] (a b : Ordering) :
    ((if c then a else b) = .Greater) = if c then a = .Greater else b = .Greater := by
  by_cases c <;> simp [*]

end avl_verification

namespace Specifications

open Primitives
open Result

variable {T: Type} (H: outParam (avl_verification.Ord T))

@[simp]
def _root_.Ordering.toDualOrdering (o: _root_.Ordering): _root_.Ordering := match o with 
| .lt => .gt
| .eq => .eq
| .gt => .lt


@[simp]
theorem toDualOrderingOfToLeanOrdering (o: avl_verification.Ordering): o.toDualOrdering.toLeanOrdering = o.toLeanOrdering.toDualOrdering := by
  cases o <;> simp

@[simp]
theorem toDualOrderingIdempotency (o: _root_.Ordering): o.toDualOrdering.toDualOrdering = o := by 
  cases o <;> simp

-- TODO: reason about raw bundling vs. refined bundling.
-- raw bundling: hypothesis with Rust extracted objects.
-- refined bundling: lifted hypothesis with Lean native objects.
class OrdSpec [Ord T] where
  infallible:  a b,  (o: avl_verification.Ordering), H.cmp a b = .ok o  compare a b = o.toLeanOrdering
  
class OrdSpecSymmetry [O: Ord T] extends OrdSpec H where
  symmetry:  a b, O.compare a b = (O.opposite.compare a b).toDualOrdering

-- Must be R decidableRel and an equivalence relationship?
class OrdSpecRel [O: Ord T] (R: outParam (T -> T -> Prop)) extends OrdSpec H where
  equivalence:  a b, H.cmp a b = .ok .Equal -> R a b

class OrdSpecLinearOrderEq [O: Ord T] extends OrdSpecSymmetry H, OrdSpecRel H Eq

theorem infallible [Ord T] [OrdSpec H]:  a b,  o, H.cmp a b = .ok o := fun a b => by 
  obtain  o,  H, _   := OrdSpec.infallible a b
  exact  o, H 

instance: Coe (avl_verification.Ordering) (_root_.Ordering) where
  coe a := a.toLeanOrdering

theorem rustCmpEq [Ord T] [O: OrdSpec H]: H.cmp a b = .ok o <-> compare a b = o.toLeanOrdering := by
  apply Iff.intro
  . intro Hcmp
    obtain  o',  Hcmp', Hcompare   := O.infallible a b
    rw [Hcmp', ok.injEq] at Hcmp
    simp [Hcompare, Hcmp', Hcmp]
  . intro Hcompare
    obtain  o',  Hcmp', Hcompare'   := O.infallible a b
    rw [Hcompare', avl_verification.Ordering.toLeanOrdering.injEq] at Hcompare
    simp [Hcompare.symm, Hcmp']


theorem oppositeOfOpposite {x y: _root_.Ordering}: x.toDualOrdering = y  x = y.toDualOrdering := by
  cases x <;> cases y <;> simp
theorem oppositeRustOrder [Ord T] [Spec: OrdSpecSymmetry H] {a b}: H.cmp b a = .ok o  H.cmp a b = .ok o.toDualOrdering := by
  rw [rustCmpEq, Spec.symmetry, compare, Ord.opposite, oppositeOfOpposite, rustCmpEq, toDualOrderingOfToLeanOrdering]

theorem ltOfRustOrder 
  [LO: LinearOrder T]
  [Spec: OrdSpec H]: 
   a b, H.cmp a b = .ok .Less -> a < b := by
  intros a b
  intro Hcmp
  -- why the typeclass search doesn't work here?
  refine' (@compare_lt_iff_lt T LO).1 _
  obtain  o,  Hcmp', Hcompare   := Spec.infallible a b 
  simp only [Hcmp', ok.injEq] at Hcmp
  simp [Hcompare, Hcmp, avl_verification.Ordering.toLeanOrdering]

theorem gtOfRustOrder 
  [LinearOrder T]
  [Spec: OrdSpecSymmetry H]: 
   a b, H.cmp a b = .ok .Greater -> b < a := by
  intros a b
  intro Hcmp
  refine' @ltOfRustOrder _ H _ Spec.toOrdSpec _ _ _
  rewrite [oppositeRustOrder]
  simp [Hcmp]

end Specifications