@bramas/simulant-lean 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENCE.txt +515 -0
- package/Simulant/Builtins.lean +24 -0
- package/Simulant/Equivariance.lean +149 -0
- package/Simulant/Exec.lean +150 -0
- package/Simulant/Invariants.lean +89 -0
- package/Simulant/Lemmas.lean +146 -0
- package/Simulant/Library/BlackHole.lean +54 -0
- package/Simulant/Library/CrashAtNode.lean +46 -0
- package/Simulant/Library/CrashStop.lean +38 -0
- package/Simulant/Library/Pebbles.lean +51 -0
- package/Simulant/Library/PersistentReflection.lean +40 -0
- package/Simulant/Library/Visited.lean +41 -0
- package/Simulant/Library.lean +6 -0
- package/Simulant/LibraryLemmas/BlackHole.lean +52 -0
- package/Simulant/ND.lean +88 -0
- package/Simulant/NonVacuity.lean +133 -0
- package/Simulant/Ring.lean +130 -0
- package/Simulant/Round.lean +249 -0
- package/Simulant.lean +9 -0
- package/lakefile.toml +13 -0
- package/lean-toolchain +1 -0
- package/package.json +23 -3
- package/README.md +0 -3
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import Simulant.Round
|
|
2
|
+
|
|
3
|
+
/-!
|
|
4
|
+
# Executions, tasks and non-vacuity (plan, Sections 3.9, 3.10 and 5.2)
|
|
5
|
+
|
|
6
|
+
Every execution permitted by the round is considered (no fairness on the
|
|
7
|
+
adversary's choices), except that a semi-synchronous round only admits
|
|
8
|
+
scheduler-fair executions: every agent that acts forever is activated
|
|
9
|
+
infinitely often.
|
|
10
|
+
-/
|
|
11
|
+
|
|
12
|
+
namespace Simulant
|
|
13
|
+
|
|
14
|
+
inductive Verdict where
|
|
15
|
+
| success | failure | inProgress
|
|
16
|
+
deriving DecidableEq, Repr
|
|
17
|
+
|
|
18
|
+
inductive Goal where
|
|
19
|
+
| eventually | eventuallyAlways | safety
|
|
20
|
+
deriving DecidableEq, Repr
|
|
21
|
+
|
|
22
|
+
variable {σ : Sig}
|
|
23
|
+
|
|
24
|
+
structure Execution (σ : Sig) where
|
|
25
|
+
config : Nat → Config σ
|
|
26
|
+
witness : Nat → Witness
|
|
27
|
+
active : Nat → List (Fin σ.k)
|
|
28
|
+
|
|
29
|
+
def Satisfies (goal : Goal) (verdict : Config σ → Verdict) (e : Execution σ) : Prop :=
|
|
30
|
+
match goal with
|
|
31
|
+
| .safety => ∀ n, verdict (e.config n) ≠ .failure
|
|
32
|
+
| .eventually => ∃ n, verdict (e.config n) = .success ∧ ∀ j, j ≤ n → verdict (e.config j) ≠ .failure
|
|
33
|
+
| .eventuallyAlways =>
|
|
34
|
+
(∀ n, verdict (e.config n) ≠ .failure) ∧ ∃ n, ∀ j, n ≤ j → verdict (e.config j) = .success
|
|
35
|
+
|
|
36
|
+
namespace Model
|
|
37
|
+
|
|
38
|
+
variable [FlagSet σ.F] (m : Model σ) (act0 : σ.A) (init : ND (Config σ))
|
|
39
|
+
|
|
40
|
+
/-- Starts in an initial configuration and follows the round. -/
|
|
41
|
+
def Valid (e : Execution σ) : Prop :=
|
|
42
|
+
ND.Can init (e.config 0) ∧
|
|
43
|
+
∀ n, (e.witness n, (e.active n, e.config (n + 1))) ∈ m.roundA act0 (e.config n)
|
|
44
|
+
|
|
45
|
+
/-- Every agent that acts forever is activated infinitely often. -/
|
|
46
|
+
def Fair (e : Execution σ) : Prop :=
|
|
47
|
+
∀ a : Fin σ.k, (∀ n, FlagSet.acts (e.config n).agents[a].flags ≠ .never) →
|
|
48
|
+
∀ n, ∃ j, n ≤ j ∧ a ∈ e.active j
|
|
49
|
+
|
|
50
|
+
def Admissible (e : Execution σ) : Prop :=
|
|
51
|
+
m.Valid act0 init e ∧ (m.round = .ssync → Fair e)
|
|
52
|
+
|
|
53
|
+
/-- The correctness statement: every admissible execution satisfies the goal. -/
|
|
54
|
+
def Correct (verdict : Config σ → Verdict) (goal : Goal) : Prop :=
|
|
55
|
+
∀ e, m.Admissible act0 init e → Satisfies goal verdict e
|
|
56
|
+
|
|
57
|
+
inductive Reachable : Config σ → Prop where
|
|
58
|
+
| init {C} : ND.Can init C → Reachable C
|
|
59
|
+
| step {C C' w a} : Reachable C → (w, (a, C')) ∈ m.roundA act0 C → Reachable C'
|
|
60
|
+
|
|
61
|
+
/-! Non-vacuity: the model is not empty, so a correctness theorem is not vacuous. -/
|
|
62
|
+
|
|
63
|
+
omit [FlagSet σ.F] in
|
|
64
|
+
/-- (The model is an argument only so that `m.HasInitial init` reads like the other statements.) -/
|
|
65
|
+
def HasInitial (_m : Model σ) (init : ND (Config σ)) : Prop := ∃ C, ND.Can init C
|
|
66
|
+
|
|
67
|
+
def Total : Prop := ∀ C, Reachable m act0 init C → ∃ w a C', (w, (a, C')) ∈ m.roundA act0 C
|
|
68
|
+
|
|
69
|
+
def HasExecution : Prop := ∃ e, m.Admissible act0 init e
|
|
70
|
+
|
|
71
|
+
end Model
|
|
72
|
+
|
|
73
|
+
/-! ## Lassos
|
|
74
|
+
|
|
75
|
+
A finite lasso found by the explorer, checked by evaluation, gives an
|
|
76
|
+
admissible execution (for a synchronous round). -/
|
|
77
|
+
|
|
78
|
+
structure Lasso (σ : Sig) where
|
|
79
|
+
start : Config σ
|
|
80
|
+
/-- Each step: witness, activated agents, next configuration. -/
|
|
81
|
+
steps : List (Witness × List (Fin σ.k) × Config σ)
|
|
82
|
+
/-- The last configuration equals the configuration at this position (0 is `start`). -/
|
|
83
|
+
loop : Nat
|
|
84
|
+
|
|
85
|
+
namespace Lasso
|
|
86
|
+
|
|
87
|
+
def configs (l : Lasso σ) : List (Config σ) := l.start :: l.steps.map (·.2.2)
|
|
88
|
+
|
|
89
|
+
/-- The position in the lasso after `n` steps. -/
|
|
90
|
+
def pos (l : Lasso σ) : Nat → Nat
|
|
91
|
+
| 0 => 0
|
|
92
|
+
| n + 1 => if l.pos n + 1 = l.steps.length then l.loop else l.pos n + 1
|
|
93
|
+
|
|
94
|
+
theorem pos_lt (l : Lasso σ) (h : l.loop < l.steps.length) : ∀ n, l.pos n < l.steps.length := by
|
|
95
|
+
intro n
|
|
96
|
+
induction n with
|
|
97
|
+
| zero => simp [pos]; omega
|
|
98
|
+
| succ n ih => simp only [pos]; split <;> omega
|
|
99
|
+
|
|
100
|
+
theorem length_configs (l : Lasso σ) : l.configs.length = l.steps.length + 1 := by
|
|
101
|
+
simp [configs]
|
|
102
|
+
|
|
103
|
+
def toExecution (l : Lasso σ) (h : l.loop < l.steps.length) : Execution σ where
|
|
104
|
+
config n := l.configs[l.pos n]'(by have := l.pos_lt h n; rw [length_configs]; omega)
|
|
105
|
+
witness n := (l.steps[l.pos n]'(l.pos_lt h n)).1
|
|
106
|
+
active n := (l.steps[l.pos n]'(l.pos_lt h n)).2.1
|
|
107
|
+
|
|
108
|
+
variable [FlagSet σ.F]
|
|
109
|
+
|
|
110
|
+
/-- Every step of the lasso is a step of the round, and it closes on itself. -/
|
|
111
|
+
def Valid (m : Model σ) (act0 : σ.A) (l : Lasso σ) : Prop :=
|
|
112
|
+
l.loop < l.steps.length ∧
|
|
113
|
+
(∀ i (h : i < l.steps.length),
|
|
114
|
+
l.steps[i] ∈ m.roundA act0 (l.configs[i]'(by rw [length_configs]; omega))) ∧
|
|
115
|
+
l.configs[l.steps.length]? = l.configs[l.loop]?
|
|
116
|
+
|
|
117
|
+
omit [FlagSet σ.F] in
|
|
118
|
+
theorem config_succ (l : Lasso σ) (h : l.loop < l.steps.length)
|
|
119
|
+
(hclose : l.configs[l.steps.length]? = l.configs[l.loop]?) (n : Nat) :
|
|
120
|
+
(l.toExecution h).config (n + 1) =
|
|
121
|
+
(l.steps[l.pos n]'(l.pos_lt h n)).2.2 := by
|
|
122
|
+
have hp := l.pos_lt h n
|
|
123
|
+
simp only [toExecution, pos]
|
|
124
|
+
split
|
|
125
|
+
· rename_i heq
|
|
126
|
+
have h1 : l.configs[l.pos n + 1]? = some (l.steps[l.pos n]'hp).2.2 := by
|
|
127
|
+
simp [configs, hp]
|
|
128
|
+
rw [heq] at h1
|
|
129
|
+
rw [hclose] at h1
|
|
130
|
+
exact Option.some.inj ((List.getElem?_eq_getElem _).symm.trans h1)
|
|
131
|
+
· simp [configs]
|
|
132
|
+
|
|
133
|
+
theorem toExecution_valid (m : Model σ) (act0 : σ.A) (init : ND (Config σ)) (l : Lasso σ)
|
|
134
|
+
(hv : l.Valid m act0) (hinit : ND.Can init l.start) :
|
|
135
|
+
m.Valid act0 init (l.toExecution hv.1) := by
|
|
136
|
+
obtain ⟨hlt, hsteps, hclose⟩ := hv
|
|
137
|
+
refine ⟨by simpa [toExecution, pos, configs] using hinit, fun n => ?_⟩
|
|
138
|
+
have hp := l.pos_lt hlt n
|
|
139
|
+
rw [config_succ l hlt hclose n]
|
|
140
|
+
have := hsteps (l.pos n) hp
|
|
141
|
+
simpa [toExecution] using this
|
|
142
|
+
|
|
143
|
+
/-- For a synchronous round, a valid lasso is an admissible execution. -/
|
|
144
|
+
theorem hasExecution (m : Model σ) (act0 : σ.A) (init : ND (Config σ)) (l : Lasso σ)
|
|
145
|
+
(hround : m.round = .fsync) (hv : l.Valid m act0) (hinit : ND.Can init l.start) :
|
|
146
|
+
m.HasExecution act0 init :=
|
|
147
|
+
⟨l.toExecution hv.1, toExecution_valid m act0 init l hv hinit, fun h => by rw [hround] at h; cases h⟩
|
|
148
|
+
|
|
149
|
+
end Lasso
|
|
150
|
+
end Simulant
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import Simulant.NonVacuity
|
|
2
|
+
|
|
3
|
+
/-!
|
|
4
|
+
# Invariants of public states
|
|
5
|
+
|
|
6
|
+
The public state of an agent changes only through the algorithm's step:
|
|
7
|
+
components never write it, and agents that do not decide keep it. So a
|
|
8
|
+
property of public states that the step preserves holds of every agent in
|
|
9
|
+
every reachable configuration, whatever the components.
|
|
10
|
+
-/
|
|
11
|
+
|
|
12
|
+
namespace Simulant
|
|
13
|
+
|
|
14
|
+
variable {σ : Sig} [FlagSet σ.F]
|
|
15
|
+
|
|
16
|
+
omit [FlagSet σ.F] in
|
|
17
|
+
theorem Decision.idle_pub (a : Agent σ) (act : σ.A) : (Decision.idle a act).pub = a.pub := rfl
|
|
18
|
+
|
|
19
|
+
theorem Config.apply_pub (C : Config σ) (e : Effect σ) (i : Fin σ.k) : (C.apply e).agents[i].pub = C.agents[i].pub := by
|
|
20
|
+
rw [Config.apply_agent]
|
|
21
|
+
|
|
22
|
+
theorem moveAll_pub (ts : TState) (C : Config σ) (ds : Fin σ.k → Decision σ) (i : Fin σ.k) :
|
|
23
|
+
(moveAll ts C ds).agents[i].pub =
|
|
24
|
+
if ((ds i).decided && FlagSet.acts C.agents[i].flags != .never) = true then (ds i).pub else C.agents[i].pub := by
|
|
25
|
+
simp only [moveAll, Fin.getElem_fin, Vector.getElem_ofFn]
|
|
26
|
+
split <;> rfl
|
|
27
|
+
|
|
28
|
+
namespace Model
|
|
29
|
+
|
|
30
|
+
variable (m : Model σ) (act0 : σ.A) (P : σ.P → Prop)
|
|
31
|
+
|
|
32
|
+
theorem options_pub (ts : TState) (C : Config σ) (i : Fin σ.k)
|
|
33
|
+
(hstep : ∀ mem pub v, P pub → P (m.step mem pub v).pub) (hC : P C.agents[i].pub)
|
|
34
|
+
{d : Decision σ} (hd : ND.Can (m.options act0 ts C i) d) : P d.pub := by
|
|
35
|
+
unfold Model.options at hd
|
|
36
|
+
dsimp only at hd
|
|
37
|
+
split at hd
|
|
38
|
+
· obtain ⟨_, -, rfl⟩ := ND.can_map.1 hd
|
|
39
|
+
exact hC
|
|
40
|
+
· obtain ⟨f, -, hd⟩ := ND.can_bind.1 hd
|
|
41
|
+
obtain ⟨v, -, hd⟩ := ND.can_bind.1 hd
|
|
42
|
+
rw [ND.can_pure.1 hd]
|
|
43
|
+
exact hstep _ _ _ hC
|
|
44
|
+
|
|
45
|
+
theorem decideAll_pub (ts : TState) (C : Config σ)
|
|
46
|
+
(hstep : ∀ mem pub v, P pub → P (m.step mem pub v).pub) (hC : ∀ i : Fin σ.k, P C.agents[i].pub) :
|
|
47
|
+
∀ (active : List (Fin σ.k)) (init : Fin σ.k → Decision σ), (∀ j, P (init j).pub) →
|
|
48
|
+
∀ ds, ND.Can (active.foldlM (fun ds i => do
|
|
49
|
+
let d ← m.options act0 ts C i
|
|
50
|
+
pure fun j => if j = i then d else ds j) init) ds → ∀ j, P (ds j).pub
|
|
51
|
+
| [], init, hinit, ds, hds => by
|
|
52
|
+
rw [List.foldlM_nil, ND.can_pure] at hds
|
|
53
|
+
subst hds
|
|
54
|
+
exact hinit
|
|
55
|
+
| i :: rest, init, hinit, ds, hds => by
|
|
56
|
+
rw [List.foldlM_cons] at hds
|
|
57
|
+
obtain ⟨acc, hacc, hds⟩ := ND.can_bind.1 hds
|
|
58
|
+
obtain ⟨d, hd, rfl⟩ := ND.can_map.1 hacc
|
|
59
|
+
refine decideAll_pub ts C hstep hC rest _ ?_ ds hds
|
|
60
|
+
intro j
|
|
61
|
+
by_cases h : j = i
|
|
62
|
+
· simp only [h, ite_true]; exact m.options_pub act0 P ts C i hstep (hC i) hd
|
|
63
|
+
· simp only [h, ite_false]; exact hinit j
|
|
64
|
+
|
|
65
|
+
/-- A property of public states preserved by the step holds of every agent after a round. -/
|
|
66
|
+
theorem step_pub {C C' : Config σ} {w : Witness} (hstep : ∀ mem pub v, P pub → P (m.step mem pub v).pub)
|
|
67
|
+
(h : m.Step act0 C w C') (hC : ∀ i : Fin σ.k, P C.agents[i].pub) : ∀ i : Fin σ.k, P C'.agents[i].pub := by
|
|
68
|
+
obtain ⟨_, h⟩ := h
|
|
69
|
+
simp only [Model.roundA, ND.mem_bind, ND.mem_pure] at h
|
|
70
|
+
obtain ⟨_, ts, _, -, ⟨_, e1, _, -, ⟨_, act, _, -, ⟨_, ds, _, hd, ⟨_, e2, _, -, ⟨_, e3, _, -, ⟨-, heq⟩, -⟩, -⟩, -⟩, -⟩, -⟩, -⟩ := h
|
|
71
|
+
obtain ⟨-, rfl⟩ := Prod.mk.inj heq
|
|
72
|
+
have h1 : ∀ i : Fin σ.k, P (C.apply e1).agents[i].pub := by intro i; rw [Config.apply_pub]; exact hC i
|
|
73
|
+
have hds := m.decideAll_pub act0 P ts (C.apply e1) hstep h1 act _ (fun j => by rw [Decision.idle_pub]; exact h1 j) ds ⟨_, hd⟩
|
|
74
|
+
intro i
|
|
75
|
+
rw [Config.apply_pub, moveAll_pub, Config.apply_pub]
|
|
76
|
+
split
|
|
77
|
+
· exact hds i
|
|
78
|
+
· exact h1 i
|
|
79
|
+
|
|
80
|
+
/-- ... and so of every agent in every reachable configuration. -/
|
|
81
|
+
theorem reachable_pub (init : ND (Config σ)) (hstep : ∀ mem pub v, P pub → P (m.step mem pub v).pub)
|
|
82
|
+
(hinit : ∀ C, ND.Can init C → ∀ i : Fin σ.k, P C.agents[i].pub) {C : Config σ}
|
|
83
|
+
(h : m.Reachable act0 init C) : ∀ i : Fin σ.k, P C.agents[i].pub := by
|
|
84
|
+
induction h with
|
|
85
|
+
| init hC => exact hinit _ hC
|
|
86
|
+
| step _ hs ih => exact m.step_pub act0 P hstep ⟨_, hs⟩ ih
|
|
87
|
+
|
|
88
|
+
end Model
|
|
89
|
+
end Simulant
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import Simulant.Exec
|
|
2
|
+
|
|
3
|
+
/-!
|
|
4
|
+
# Library lemmas about the round, for any components (plan, Section 4)
|
|
5
|
+
-/
|
|
6
|
+
|
|
7
|
+
namespace Simulant
|
|
8
|
+
|
|
9
|
+
variable {σ : Sig} [FlagSet σ.F]
|
|
10
|
+
|
|
11
|
+
theorem mem_chooseIfMany {site : String} {l : List α} {w : Witness} {x : α}
|
|
12
|
+
(h : (w, x) ∈ chooseIfMany site l) : x ∈ l := by
|
|
13
|
+
unfold chooseIfMany at h
|
|
14
|
+
split at h
|
|
15
|
+
· simp only [ND.mem_pure] at h; rw [h.2]; exact List.mem_singleton_self _
|
|
16
|
+
· exact ND.can_choose.1 ⟨w, h⟩
|
|
17
|
+
|
|
18
|
+
@[simp] theorem Config.apply_world (C : Config σ) (e : Effect σ) : (C.apply e).world = e.world C.world := rfl
|
|
19
|
+
|
|
20
|
+
@[simp] theorem Config.apply_agent (C : Config σ) (e : Effect σ) (i : Fin σ.k) :
|
|
21
|
+
(C.apply e).agents[i] = { C.agents[i] with flags := FlagSet.merge C.agents[i].flags (e.raise i) } := by
|
|
22
|
+
simp [Config.apply]
|
|
23
|
+
|
|
24
|
+
theorem moveAll_never (ts : TState) (C : Config σ) (ds : Fin σ.k → Decision σ) (i : Fin σ.k)
|
|
25
|
+
(h : FlagSet.acts C.agents[i].flags = .never) : (moveAll ts C ds).agents[i] = C.agents[i] := by
|
|
26
|
+
simp only [Fin.getElem_fin] at h
|
|
27
|
+
simp [moveAll, h]
|
|
28
|
+
|
|
29
|
+
@[simp] theorem moveAll_world (ts : TState) (C : Config σ) (ds : Fin σ.k → Decision σ) :
|
|
30
|
+
(moveAll ts C ds).world = C.world := rfl
|
|
31
|
+
|
|
32
|
+
variable [LawfulFlagSet σ.F]
|
|
33
|
+
|
|
34
|
+
theorem apply_never (C : Config σ) (e : Effect σ) (i : Fin σ.k)
|
|
35
|
+
(h : FlagSet.acts C.agents[i].flags = .never) : FlagSet.acts (C.apply e).agents[i].flags = .never := by
|
|
36
|
+
rw [Config.apply_agent]
|
|
37
|
+
exact LawfulFlagSet.acts_merge_never _ _ h
|
|
38
|
+
|
|
39
|
+
/-- An agent that never acts (crashed, dead) neither moves nor acts again, whatever the components. -/
|
|
40
|
+
theorem never_stays (m : Model σ) (act0 : σ.A) {C C' : Config σ} {w : Witness} (h : m.Step act0 C w C')
|
|
41
|
+
(i : Fin σ.k) (hn : FlagSet.acts C.agents[i].flags = .never) :
|
|
42
|
+
C'.agents[i].pos = C.agents[i].pos ∧ FlagSet.acts C'.agents[i].flags = .never := by
|
|
43
|
+
obtain ⟨_, h⟩ := h
|
|
44
|
+
simp only [Model.roundA, ND.mem_bind, ND.mem_pure] at h
|
|
45
|
+
obtain ⟨_, ts, _, -, ⟨_, e1, _, -, ⟨_, _, _, -, ⟨_, ds, _, -, ⟨_, e2, _, -, ⟨_, e3, _, -, ⟨-, heq⟩, -⟩, -⟩, -⟩, -⟩, -⟩, -⟩ := h
|
|
46
|
+
obtain ⟨-, rfl⟩ := Prod.mk.inj heq
|
|
47
|
+
have h1 := apply_never C e1 i hn
|
|
48
|
+
have h2 := apply_never _ e2 i h1
|
|
49
|
+
have hm := moveAll_never ts ((C.apply e1).apply e2) ds i h2
|
|
50
|
+
refine ⟨?_, ?_⟩
|
|
51
|
+
· simp only [Config.apply_agent] at hm ⊢
|
|
52
|
+
rw [hm]
|
|
53
|
+
· apply apply_never
|
|
54
|
+
rw [hm]
|
|
55
|
+
exact h2
|
|
56
|
+
|
|
57
|
+
end Simulant
|
|
58
|
+
|
|
59
|
+
/-! ## World parts that the round preserves
|
|
60
|
+
|
|
61
|
+
An observation `g` of the world (typically: a component's part) is
|
|
62
|
+
preserved by the round when every component preserves it. Components
|
|
63
|
+
built from `Hooks` preserve every part they do not own (`toComponent_preserves`). -/
|
|
64
|
+
|
|
65
|
+
namespace Simulant
|
|
66
|
+
|
|
67
|
+
variable {σ : Sig} [FlagSet σ.F] {T : Type}
|
|
68
|
+
|
|
69
|
+
/-- Every effect the component's hooks can produce preserves `g`. -/
|
|
70
|
+
def Component.Preserves (c : Component σ) (g : σ.W → T) : Prop :=
|
|
71
|
+
(∀ ts C e, ND.Can (c.beforeLook ts C) e → ∀ w, g (e.world w) = g w) ∧
|
|
72
|
+
(∀ ts C ds e, ND.Can (c.beforeMove ts C ds) e → ∀ w, g (e.world w) = g w) ∧
|
|
73
|
+
(∀ ts C e, ND.Can (c.afterMove ts C) e → ∀ w, g (e.world w) = g w)
|
|
74
|
+
|
|
75
|
+
omit [FlagSet σ.F] in
|
|
76
|
+
theorem Component.Preserves.comp {c : Component σ} {g : σ.W → T} (h : c.Preserves g) (f : T → U) :
|
|
77
|
+
c.Preserves (fun w => f (g w)) := by
|
|
78
|
+
obtain ⟨h1, h2, h3⟩ := h
|
|
79
|
+
exact ⟨fun ts C e he w => congrArg f (h1 ts C e he w), fun ts C ds e he w => congrArg f (h2 ts C ds e he w),
|
|
80
|
+
fun ts C e he w => congrArg f (h3 ts C e he w)⟩
|
|
81
|
+
|
|
82
|
+
theorem ND.can_map {m : ND α} {f : α → β} {b : β} :
|
|
83
|
+
ND.Can (do let a ← m; pure (f a)) b ↔ ∃ a, ND.Can m a ∧ b = f a := by
|
|
84
|
+
rw [ND.can_bind]
|
|
85
|
+
exact exists_congr fun _ => and_congr_right fun _ => ND.can_pure
|
|
86
|
+
|
|
87
|
+
theorem parallel_preserves {g : σ.W → T} (C : Config σ) :
|
|
88
|
+
∀ (hooks : List (Config σ → ND (Effect σ))),
|
|
89
|
+
(∀ hk ∈ hooks, ∀ e, ND.Can (hk C) e → ∀ w, g (e.world w) = g w) →
|
|
90
|
+
∀ e, ND.Can (parallel hooks C) e → ∀ w, g (e.world w) = g w
|
|
91
|
+
| [], _, e, he, w => by
|
|
92
|
+
simp only [parallel, ND.can_pure] at he
|
|
93
|
+
subst he
|
|
94
|
+
rfl
|
|
95
|
+
| hk :: hs, h, e, he, w => by
|
|
96
|
+
simp only [parallel, ND.can_bind, ND.can_pure] at he
|
|
97
|
+
obtain ⟨e1, h1, r, hr, rfl⟩ := he
|
|
98
|
+
have ih := parallel_preserves C hs (fun hk' hm => h hk' (List.mem_cons_of_mem _ hm)) r hr
|
|
99
|
+
show g (r.world (e1.world w)) = g w
|
|
100
|
+
rw [ih, h hk (List.mem_cons_self) e1 h1 w]
|
|
101
|
+
|
|
102
|
+
/-- If every component preserves `g`, so does the round. -/
|
|
103
|
+
theorem Model.step_preserves (m : Model σ) (act0 : σ.A) {g : σ.W → T}
|
|
104
|
+
(h : ∀ c ∈ m.components, c.Preserves g) {C C' : Config σ} {w : Witness}
|
|
105
|
+
(hs : m.Step act0 C w C') : g C'.world = g C.world := by
|
|
106
|
+
obtain ⟨_, hs⟩ := hs
|
|
107
|
+
simp only [Model.roundA, ND.mem_bind, ND.mem_pure] at hs
|
|
108
|
+
obtain ⟨_, ts, _, -, ⟨_, e1, _, h1, ⟨_, _, _, -, ⟨_, ds, _, -, ⟨_, e2, _, h2, ⟨_, e3, _, h3, ⟨-, heq⟩, -⟩, -⟩, -⟩, -⟩, -⟩, -⟩ := hs
|
|
109
|
+
obtain ⟨-, rfl⟩ := Prod.mk.inj heq
|
|
110
|
+
have p1 := parallel_preserves C _ (by
|
|
111
|
+
intro hk hm e he; simp only [List.mem_map] at hm; obtain ⟨c, hc, rfl⟩ := hm; exact (h c hc).1 ts C e he) e1 ⟨_, h1⟩
|
|
112
|
+
have p2 := parallel_preserves _ _ (by
|
|
113
|
+
intro hk hm e he; simp only [List.mem_map] at hm; obtain ⟨c, hc, rfl⟩ := hm; exact (h c hc).2.1 ts _ ds e he) e2 ⟨_, h2⟩
|
|
114
|
+
have p3 := parallel_preserves _ _ (by
|
|
115
|
+
intro hk hm e he; simp only [List.mem_map] at hm; obtain ⟨c, hc, rfl⟩ := hm; exact (h c hc).2.2 ts _ e he) e3 ⟨_, h3⟩
|
|
116
|
+
simp only [Config.apply_world, moveAll_world]
|
|
117
|
+
rw [p3, p2, p1]
|
|
118
|
+
|
|
119
|
+
omit [FlagSet σ.F] in
|
|
120
|
+
/-- A component preserves every part of the world that its own lens does not touch. -/
|
|
121
|
+
theorem Hooks.toComponent_preserves (h : Hooks σ Wc) (L : Lens σ.W Wc) (g : σ.W → T)
|
|
122
|
+
(hg : ∀ w x, g (L.set w x) = g w) : (h.toComponent L).Preserves g := by
|
|
123
|
+
refine ⟨fun ts C e he w => ?_, fun ts C ds e he w => ?_, fun ts C e he w => ?_⟩ <;>
|
|
124
|
+
· obtain ⟨e, -, rfl⟩ := ND.can_map.1 he
|
|
125
|
+
exact hg _ _
|
|
126
|
+
|
|
127
|
+
omit [FlagSet σ.F] in
|
|
128
|
+
/-- A component preserves an observation of its own part that each of its own effects preserves. -/
|
|
129
|
+
theorem Hooks.toComponent_preserves_own (h : Hooks σ Wc) (L : Lens σ.W Wc) [LawfulLens L] (g : Wc → T)
|
|
130
|
+
(hown : (∀ ts C e, ND.Can (h.beforeLook ts C) e → ∀ x, g (e.world x) = g x) ∧
|
|
131
|
+
(∀ ts C ds e, ND.Can (h.beforeMove ts C ds) e → ∀ x, g (e.world x) = g x) ∧
|
|
132
|
+
(∀ ts C e, ND.Can (h.afterMove ts C) e → ∀ x, g (e.world x) = g x)) :
|
|
133
|
+
(h.toComponent L).Preserves (fun w => g (L.get w)) := by
|
|
134
|
+
obtain ⟨h1, h2, h3⟩ := hown
|
|
135
|
+
refine ⟨fun ts C e he w => ?_, fun ts C ds e he w => ?_, fun ts C e he w => ?_⟩
|
|
136
|
+
· obtain ⟨e', he', rfl⟩ := ND.can_map.1 he
|
|
137
|
+
simp only [OwnEffect.lift, LawfulLens.get_set]
|
|
138
|
+
exact h1 ts C e' he' _
|
|
139
|
+
· obtain ⟨e', he', rfl⟩ := ND.can_map.1 he
|
|
140
|
+
simp only [OwnEffect.lift, LawfulLens.get_set]
|
|
141
|
+
exact h2 ts C ds e' he' _
|
|
142
|
+
· obtain ⟨e', he', rfl⟩ := ND.can_map.1 he
|
|
143
|
+
simp only [OwnEffect.lift, LawfulLens.get_set]
|
|
144
|
+
exact h3 ts C e' he' _
|
|
145
|
+
|
|
146
|
+
end Simulant
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import Simulant
|
|
2
|
+
|
|
3
|
+
/-! Generated from the IR of component `BlackHole` by packages/lean-gen. Do not edit. -/
|
|
4
|
+
|
|
5
|
+
set_option linter.unusedVariables false
|
|
6
|
+
|
|
7
|
+
namespace Simulant.Library.BlackHole
|
|
8
|
+
open Simulant
|
|
9
|
+
|
|
10
|
+
inductive HolePolicy where
|
|
11
|
+
| none
|
|
12
|
+
| initiallyPresent
|
|
13
|
+
| mayEmerge
|
|
14
|
+
deriving DecidableEq, Repr, Inhabited
|
|
15
|
+
|
|
16
|
+
structure World (N : Nat) where
|
|
17
|
+
site : Fin N
|
|
18
|
+
active : Bool
|
|
19
|
+
deriving DecidableEq, Repr
|
|
20
|
+
|
|
21
|
+
/-- The flags declared by `BlackHole`, with the laws of a composition's flags. -/
|
|
22
|
+
class Flags (F : Type) [FlagSet F] where
|
|
23
|
+
dead : F → Bool
|
|
24
|
+
raise_dead : F
|
|
25
|
+
dead_raise : dead raise_dead = true
|
|
26
|
+
dead_merge : ∀ a b : F, dead (FlagSet.merge a b) = (dead a || dead b)
|
|
27
|
+
dead_none : dead (FlagSet.none : F) = false
|
|
28
|
+
|
|
29
|
+
class Actions (A : Type) where
|
|
30
|
+
|
|
31
|
+
/-- What the composition gives the component: lenses on the state it owns. -/
|
|
32
|
+
structure Ctx (σ : Sig) where
|
|
33
|
+
world : Lens σ.W (World σ.N)
|
|
34
|
+
|
|
35
|
+
def initWorld {N : Nat} [NeZero N] (policy : HolePolicy) (site : Fin N) : ND (World N) := do
|
|
36
|
+
let site ← (pure site)
|
|
37
|
+
let active ← (pure (policy == HolePolicy.initiallyPresent))
|
|
38
|
+
pure { site := site, active := active }
|
|
39
|
+
|
|
40
|
+
section
|
|
41
|
+
variable {σ : Sig} [FlagSet σ.F] [Flags σ.F] [Actions σ.A]
|
|
42
|
+
|
|
43
|
+
/-- The hooks, on the part of the world the component owns. -/
|
|
44
|
+
def hooks (policy : HolePolicy) (L : Ctx σ) : Hooks σ (World σ.N) where
|
|
45
|
+
beforeLook := fun ts C => pure ⟨id, fun _ => FlagSet.none⟩
|
|
46
|
+
beforeMove := fun ts C ds => pure ⟨id, fun _ => FlagSet.none⟩
|
|
47
|
+
afterMove := fun ts C => (do let active ← (if ((policy == HolePolicy.mayEmerge) && (!((L.world.get C.world).active))) then (ND.choose "BlackHole.active" ([false, true] : List (Bool))) else (pure ((L.world.get C.world).active))); (pure ({ world := fun x => { x with active := active }, raise := fun a => (if (fun (a : Fin σ.k) => ((FlagSet.present C.agents[a].flags) && active && ((C.agents[a].pos) == ((L.world.get C.world).site)))) a then (Flags.raise_dead : σ.F) else FlagSet.none) } : OwnEffect σ (World σ.N))))
|
|
48
|
+
|
|
49
|
+
def component (policy : HolePolicy) (L : Ctx σ) : Component σ :=
|
|
50
|
+
(hooks policy L).toComponent L.world
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end Simulant.Library.BlackHole
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import Simulant
|
|
2
|
+
|
|
3
|
+
/-! Generated from the IR of component `CrashAtNode` by packages/lean-gen. Do not edit. -/
|
|
4
|
+
|
|
5
|
+
set_option linter.unusedVariables false
|
|
6
|
+
|
|
7
|
+
namespace Simulant.Library.CrashAtNode
|
|
8
|
+
open Simulant
|
|
9
|
+
|
|
10
|
+
structure World (N : Nat) where
|
|
11
|
+
crashNode : Fin N
|
|
12
|
+
deriving DecidableEq, Repr
|
|
13
|
+
|
|
14
|
+
/-- The flags declared by `CrashAtNode`, with the laws of a composition's flags. -/
|
|
15
|
+
class Flags (F : Type) [FlagSet F] where
|
|
16
|
+
crashed : F → Bool
|
|
17
|
+
raise_crashed : F
|
|
18
|
+
crashed_raise : crashed raise_crashed = true
|
|
19
|
+
crashed_merge : ∀ a b : F, crashed (FlagSet.merge a b) = (crashed a || crashed b)
|
|
20
|
+
crashed_none : crashed (FlagSet.none : F) = false
|
|
21
|
+
|
|
22
|
+
class Actions (A : Type) where
|
|
23
|
+
|
|
24
|
+
/-- What the composition gives the component: lenses on the state it owns. -/
|
|
25
|
+
structure Ctx (σ : Sig) where
|
|
26
|
+
world : Lens σ.W (World σ.N)
|
|
27
|
+
|
|
28
|
+
def initWorld {N : Nat} [NeZero N] (crashNode : Fin N) : ND (World N) := do
|
|
29
|
+
let crashNode ← (pure crashNode)
|
|
30
|
+
pure { crashNode := crashNode }
|
|
31
|
+
|
|
32
|
+
section
|
|
33
|
+
variable {σ : Sig} [FlagSet σ.F] [Flags σ.F] [Actions σ.A]
|
|
34
|
+
|
|
35
|
+
/-- The hooks, on the part of the world the component owns. -/
|
|
36
|
+
def hooks (L : Ctx σ) : Hooks σ (World σ.N) where
|
|
37
|
+
beforeLook := fun ts C => pure ⟨id, fun _ => FlagSet.none⟩
|
|
38
|
+
beforeMove := fun ts C ds => (do let S ← (ND.choose "CrashAtNode.S" (B.subsets ((List.finRange σ.k).filter (fun (a : Fin σ.k) => ((FlagSet.correct C.agents[a].flags) && ((C.agents[a].pos) == ((L.world.get C.world).crashNode))))))); (pure ({ world := id, raise := fun a => (if (S).contains a then (Flags.raise_crashed : σ.F) else FlagSet.none) } : OwnEffect σ (World σ.N))))
|
|
39
|
+
afterMove := fun ts C => pure ⟨id, fun _ => FlagSet.none⟩
|
|
40
|
+
|
|
41
|
+
def component (L : Ctx σ) : Component σ :=
|
|
42
|
+
(hooks L).toComponent L.world
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end Simulant.Library.CrashAtNode
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import Simulant
|
|
2
|
+
|
|
3
|
+
/-! Generated from the IR of component `CrashStop` by packages/lean-gen. Do not edit. -/
|
|
4
|
+
|
|
5
|
+
set_option linter.unusedVariables false
|
|
6
|
+
|
|
7
|
+
namespace Simulant.Library.CrashStop
|
|
8
|
+
open Simulant
|
|
9
|
+
|
|
10
|
+
/-- The flags declared by `CrashStop`, with the laws of a composition's flags. -/
|
|
11
|
+
class Flags (F : Type) [FlagSet F] where
|
|
12
|
+
crashed : F → Bool
|
|
13
|
+
raise_crashed : F
|
|
14
|
+
crashed_raise : crashed raise_crashed = true
|
|
15
|
+
crashed_merge : ∀ a b : F, crashed (FlagSet.merge a b) = (crashed a || crashed b)
|
|
16
|
+
crashed_none : crashed (FlagSet.none : F) = false
|
|
17
|
+
|
|
18
|
+
class Actions (A : Type) where
|
|
19
|
+
|
|
20
|
+
/-- What the composition gives the component: lenses on the state it owns. -/
|
|
21
|
+
structure Ctx (σ : Sig) where
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
section
|
|
25
|
+
variable {σ : Sig} [FlagSet σ.F] [Flags σ.F] [Actions σ.A]
|
|
26
|
+
|
|
27
|
+
/-- The hooks, on the part of the world the component owns. -/
|
|
28
|
+
def hooks (f : Nat) (L : Ctx σ) : Hooks σ Unit where
|
|
29
|
+
beforeLook := fun ts C => (do let S ← (ND.chooseSuch "CrashStop.S" (B.subsets ((List.finRange σ.k).filter (fun (x0 : Fin σ.k) => (FlagSet.correct C.agents[x0].flags)))) (fun (S : List (Fin σ.k)) => (decide ((((List.finRange σ.k).countP (fun (x1 : Fin σ.k) => (Flags.crashed C.agents[x1].flags))) + S.length) ≤ f)))); (pure ({ world := id, raise := fun a => (if (S).contains a then (Flags.raise_crashed : σ.F) else FlagSet.none) } : OwnEffect σ Unit)))
|
|
30
|
+
beforeMove := fun ts C ds => pure ⟨id, fun _ => FlagSet.none⟩
|
|
31
|
+
afterMove := fun ts C => pure ⟨id, fun _ => FlagSet.none⟩
|
|
32
|
+
|
|
33
|
+
def component (f : Nat) (L : Ctx σ) : Component σ :=
|
|
34
|
+
(hooks f L).toComponent (Lens.unit σ.W)
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end Simulant.Library.CrashStop
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Simulant
|
|
2
|
+
|
|
3
|
+
/-! Generated from the IR of component `Pebbles` by packages/lean-gen. Do not edit. -/
|
|
4
|
+
|
|
5
|
+
set_option linter.unusedVariables false
|
|
6
|
+
|
|
7
|
+
namespace Simulant.Library.Pebbles
|
|
8
|
+
open Simulant
|
|
9
|
+
|
|
10
|
+
inductive PebbleAction where
|
|
11
|
+
| none
|
|
12
|
+
| drop
|
|
13
|
+
| pick
|
|
14
|
+
deriving DecidableEq, Repr, Inhabited
|
|
15
|
+
|
|
16
|
+
structure World (N : Nat) where
|
|
17
|
+
pebbles : List (Fin N)
|
|
18
|
+
deriving DecidableEq, Repr
|
|
19
|
+
|
|
20
|
+
/-- The flags declared by `Pebbles`, with the laws of a composition's flags. -/
|
|
21
|
+
class Flags (F : Type) [FlagSet F] where
|
|
22
|
+
|
|
23
|
+
class Actions (A : Type) where
|
|
24
|
+
pebble : A → PebbleAction
|
|
25
|
+
|
|
26
|
+
/-- What the composition gives the component: lenses on the state it owns. -/
|
|
27
|
+
structure Ctx (σ : Sig) where
|
|
28
|
+
world : Lens σ.W (World σ.N)
|
|
29
|
+
|
|
30
|
+
def initWorld {N : Nat} [NeZero N] : ND (World N) := do
|
|
31
|
+
let pebbles ← (pure ([] : List (Fin N)))
|
|
32
|
+
pure { pebbles := pebbles }
|
|
33
|
+
|
|
34
|
+
section
|
|
35
|
+
variable {σ : Sig} [FlagSet σ.F] [Flags σ.F] [Actions σ.A]
|
|
36
|
+
|
|
37
|
+
def sensor_pebblesHere (L : Ctx σ) (ts : TState) (C : Config σ) (me : Fin σ.k) (frame : Bool) : ND (Nat) :=
|
|
38
|
+
(pure (((L.world.get C.world).pebbles).countP (fun (x0 : Fin σ.N) => (x0 == (C.agents[me].pos)))))
|
|
39
|
+
|
|
40
|
+
/-- The hooks, on the part of the world the component owns. -/
|
|
41
|
+
def hooks (L : Ctx σ) : Hooks σ (World σ.N) where
|
|
42
|
+
beforeLook := fun ts C => pure ⟨id, fun _ => FlagSet.none⟩
|
|
43
|
+
beforeMove := fun ts C ds => (pure (let picks := (((List.finRange σ.k).filter (fun (a : Fin σ.k) => (((ds a).decided) && ((Actions.pebble (ds a).act) == PebbleAction.pick)))).map (fun (x0 : Fin σ.k) => C.agents[x0].pos)); (let drops := (((List.finRange σ.k).filter (fun (a : Fin σ.k) => (((ds a).decided) && ((Actions.pebble (ds a).act) == PebbleAction.drop)))).map (fun (x0 : Fin σ.k) => C.agents[x0].pos)); ({ world := fun x => { x with pebbles := ((B.diff ((L.world.get C.world).pebbles) picks) ++ drops) }, raise := fun a => FlagSet.none } : OwnEffect σ (World σ.N)))))
|
|
44
|
+
afterMove := fun ts C => pure ⟨id, fun _ => FlagSet.none⟩
|
|
45
|
+
|
|
46
|
+
def component (L : Ctx σ) : Component σ :=
|
|
47
|
+
(hooks L).toComponent L.world
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end Simulant.Library.Pebbles
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import Simulant
|
|
2
|
+
|
|
3
|
+
/-! Generated from the IR of component `PersistentReflection` by packages/lean-gen. Do not edit. -/
|
|
4
|
+
|
|
5
|
+
set_option linter.unusedVariables false
|
|
6
|
+
|
|
7
|
+
namespace Simulant.Library.PersistentReflection
|
|
8
|
+
open Simulant
|
|
9
|
+
|
|
10
|
+
structure Fields (N : Nat) where
|
|
11
|
+
mirrored : Bool
|
|
12
|
+
deriving DecidableEq, Repr
|
|
13
|
+
|
|
14
|
+
/-- The flags declared by `PersistentReflection`, with the laws of a composition's flags. -/
|
|
15
|
+
class Flags (F : Type) [FlagSet F] where
|
|
16
|
+
|
|
17
|
+
class Actions (A : Type) where
|
|
18
|
+
|
|
19
|
+
/-- What the composition gives the component: lenses on the state it owns. -/
|
|
20
|
+
structure Ctx (σ : Sig) where
|
|
21
|
+
fields : Lens σ.X (Fields σ.N)
|
|
22
|
+
|
|
23
|
+
def init_mirrored {N : Nat} [NeZero N] (i : Nat) : ND (Bool) :=
|
|
24
|
+
(ND.choose "PersistentReflection.mirrored" ([false, true]))
|
|
25
|
+
|
|
26
|
+
section
|
|
27
|
+
variable {σ : Sig} [FlagSet σ.F] [Flags σ.F] [Actions σ.A]
|
|
28
|
+
|
|
29
|
+
/-- The hooks, on the part of the world the component owns. -/
|
|
30
|
+
def hooks (L : Ctx σ) : Hooks σ Unit where
|
|
31
|
+
beforeLook := fun ts C => pure ⟨id, fun _ => FlagSet.none⟩
|
|
32
|
+
beforeMove := fun ts C ds => pure ⟨id, fun _ => FlagSet.none⟩
|
|
33
|
+
afterMove := fun ts C => pure ⟨id, fun _ => FlagSet.none⟩
|
|
34
|
+
|
|
35
|
+
def component (L : Ctx σ) : Component σ :=
|
|
36
|
+
(hooks L).toComponent (Lens.unit σ.W)
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end Simulant.Library.PersistentReflection
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import Simulant
|
|
2
|
+
|
|
3
|
+
/-! Generated from the IR of component `Visited` by packages/lean-gen. Do not edit. -/
|
|
4
|
+
|
|
5
|
+
set_option linter.unusedVariables false
|
|
6
|
+
|
|
7
|
+
namespace Simulant.Library.Visited
|
|
8
|
+
open Simulant
|
|
9
|
+
|
|
10
|
+
structure World (N : Nat) where
|
|
11
|
+
visited : List (Fin N)
|
|
12
|
+
deriving DecidableEq, Repr
|
|
13
|
+
|
|
14
|
+
/-- The flags declared by `Visited`, with the laws of a composition's flags. -/
|
|
15
|
+
class Flags (F : Type) [FlagSet F] where
|
|
16
|
+
|
|
17
|
+
class Actions (A : Type) where
|
|
18
|
+
|
|
19
|
+
/-- What the composition gives the component: lenses on the state it owns. -/
|
|
20
|
+
structure Ctx (σ : Sig) where
|
|
21
|
+
world : Lens σ.W (World σ.N)
|
|
22
|
+
|
|
23
|
+
def initWorld {N : Nat} [NeZero N] : ND (World N) := do
|
|
24
|
+
let visited ← (pure ([] : List (Fin N)))
|
|
25
|
+
pure { visited := visited }
|
|
26
|
+
|
|
27
|
+
section
|
|
28
|
+
variable {σ : Sig} [FlagSet σ.F] [Flags σ.F] [Actions σ.A]
|
|
29
|
+
|
|
30
|
+
/-- The hooks, on the part of the world the component owns. -/
|
|
31
|
+
def hooks (L : Ctx σ) : Hooks σ (World σ.N) where
|
|
32
|
+
beforeLook := fun ts C => (pure ({ world := fun x => { x with visited := (((L.world.get C.world).visited) ++ (((List.finRange σ.k).filter (fun (x0 : Fin σ.k) => (FlagSet.present C.agents[x0].flags))).map (fun (x0 : Fin σ.k) => C.agents[x0].pos))).eraseDups }, raise := fun a => FlagSet.none } : OwnEffect σ (World σ.N)))
|
|
33
|
+
beforeMove := fun ts C ds => pure ⟨id, fun _ => FlagSet.none⟩
|
|
34
|
+
afterMove := fun ts C => (pure ({ world := fun x => { x with visited := (((L.world.get C.world).visited) ++ (((List.finRange σ.k).filter (fun (x0 : Fin σ.k) => (FlagSet.present C.agents[x0].flags))).map (fun (x0 : Fin σ.k) => C.agents[x0].pos))).eraseDups }, raise := fun a => FlagSet.none } : OwnEffect σ (World σ.N)))
|
|
35
|
+
|
|
36
|
+
def component (L : Ctx σ) : Component σ :=
|
|
37
|
+
(hooks L).toComponent L.world
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end Simulant.Library.Visited
|