Repository navigation
Expand file tree
/
Copy pathEnums.lean
More file actions
152 lines (111 loc) · 4.43 KB
/
Copy pathEnums.lean
File metadata and controls
152 lines (111 loc) · 4.43 KB
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
151
152
import Verified.Reflect.Command
/-! The nineteenth program of the verified compiler: enumerations. An enumeration with a `Flat`
instance is the word that the instance gives each constructor. A `match` on one becomes a chain of
tests of that word, and `==`, `!=`, `decide`, and `if` compare words. The programs use
enumerations as parameters, results, a structure field, a loop state's field, and array
elements, with one instance written with `ctorIdx` and one with `match`. -/
namespace Verified.Examples.Enums
open LeanExe.Pipeline
inductive Op where
| add | sub | mul | neg
deriving Inhabited, DecidableEq
instance : Flat Op UInt64 := ⟨fun op => op.ctorIdx.toUInt64⟩
inductive Phase where
| solid | liquid | gas
deriving Inhabited, DecidableEq
instance : Flat Phase UInt64 := ⟨fun | .solid => 0 | .liquid => 1 | .gas => 2⟩
structure Calc where
value : UInt64
steps : UInt64
last : Op
deriving Inhabited
instance : Flat Calc (UInt64 × UInt64 × Op) := ⟨fun c => (c.value, c.steps, c.last)⟩
def apply (op : Op) (a b : UInt64) : UInt64 :=
match op with
| .add => a + b
| .sub => a - b
| .mul => a * b
| .neg => 0 - a
def phaseOf (t : Float) : Phase :=
if t < 273.15 then .solid else if t < 373.15 then .liquid else .gas
def isGas (p : Phase) : Bool := p == .gas
/-- A heat capacity, with a wildcard that binds the phase and an `if` on its equality. -/
def heat (p : Phase) : Float :=
match p with
| .solid => 2.1
| q => if q = .gas then 2.0 else 4.2
def ofWord (w : UInt64) : Op :=
if w == 0 then .add else if w == 1 then .sub else if w == 2 then .mul else .neg
def step (c : Calc) (op : Op) (x : UInt64) : Calc :=
{ value := apply op c.value x, steps := c.steps + 1, last := op }
def same (a b : Op) : Bool := decide (a = b)
def differ (a b : Op) : Bool := a != b
/-- The calculator after the operations of `ops` with the operands of `xs`. -/
def run (ops : Array Op) (xs : Array UInt64) : Calc :=
LeanExe.loop ops.size.toUInt64 ⟨0, 0, .add⟩ fun i c => step c ops[i.toNat]! xs[i.toNat]!
def phases (ts : Array Float) : Array Phase :=
LeanExe.build ts.size.toUInt64 fun i => phaseOf ts[i.toNat]!
def countGas (ps : Array Phase) : UInt64 :=
LeanExe.loop ps.size.toUInt64 0 fun i acc => if ps[i.toNat]! == .gas then acc + 1 else acc
/-- Element `i` melted, in place: a `match` on an array element. -/
def melt (ps : Array Phase) (i : UInt64) : Array Phase :=
ps.set! i.toNat (match ps[i.toNat]! with
| .solid => .liquid
| p => p)
def lastOp (c : Calc) : Op := c.last
def notSame (a b : Op) : Bool := decide (a ≠ b)
def wordsDiffer (x y : UInt64) : Bool := decide (x ≠ y)
def ifDiffer (a b : Op) (x : UInt64) : UInt64 := if a ≠ b then x else 0
/-- A `let` of a loop over a literal count in an alternative whose result is an enumeration. -/
def cool (p : Phase) (k : UInt64) : Phase :=
match p with
| .solid =>
let n := LeanExe.loop 30000 k fun _ a => a + 1
if n < 5 then .liquid else .gas
| q => q
/-- A match on a call. -/
def phaseHeat (t : Float) : Float :=
match phaseOf t with
| .gas => 2.0
| _ => 4.0
/-- A match on a structure field. -/
def undo (c : Calc) : UInt64 :=
match c.last with
| .add => c.value - 1
| .sub => c.value + 1
| _ => c.value
/-- Nested matches. -/
def combine (a b : Op) : UInt64 :=
match a with
| .add =>
match b with
| .add => 1
| _ => 2
| _ => 3
inductive Only where
| only
deriving Inhabited, DecidableEq
instance : Flat Only UInt64 := ⟨fun _ => 0⟩
def onlyWord (u : Only) : UInt64 :=
match u with
| .only => 7
/-- An enumeration in a pair. -/
def tagged (a : Op) (x : UInt64) : Op × UInt64 := (a, x + 1)
/-- `Flat.flat` in the program. -/
def opCode (a : Op) : UInt64 := Flat.flat a + 100
/-- An enumeration whose words are not its constructor indices. -/
inductive Level where
| low | high
deriving Inhabited, DecidableEq
instance : Flat Level UInt64 := ⟨fun | .low => 0 | .high => 200⟩
def raise (l : Level) : Level :=
match l with
| .low => .high
| .high => .high
def isHigh (l : Level) : Bool := l == .high
/-- The first phase, the default `solid` for an empty array. -/
def firstPhase (ps : Array Phase) : Phase := ps[(0 : UInt64).toNat]!
verified_compile compiled := [apply, phaseOf, isGas, heat, ofWord, step, same, differ, run, phases,
countGas, melt, lastOp, notSame, wordsDiffer, ifDiffer, cool, phaseHeat, undo, combine, onlyWord,
tagged, opCode, raise, isHigh, firstPhase]
end Verified.Examples.Enums