Section full_decoder.
Implicit Type (lt : list ((list bool) *  list bool)).
Definition size_cards lt := fold_right (fun c x => length (fst c) + length (snd c) + x) 0 lt.
Variables (c h l : pos n) (Hch : c <> h) (Hcl : c <> l) (Hhl : h <> l).
Variables (p : nat)   (* jumps here when decoding worked correctly *)
(q : nat)   (* jumps here when decoding produced an error *)
.
Let decoder_error := PUSH c Zero :: POP c q q :: nil.
(* Code that implements a decoder for tile indices - ll is a list of tiles (th,tl)  - when c starts with a valid tile index in ll encoded as 00001 (with n 0s to represent b) then the corresponding tile is stacked into h and l. The code ends up at s  - otherwise, h and l are left unchanged and the code ends up at q *)
Fixpoint decoder s i lt :=
match lt with
| nil           => decoder_error
| (th,tl) :: lt => POP c (3+length (tile h l th tl)+i) q ::
tile h l th tl ++
PUSH c Zero ::
POP c s s ::
decoder s (3+length (tile h l th tl)+i) lt
end.
Fixpoint length_decoder lt :=
match lt with
| nil => 2
| (th,tl) :: lt => 3+length th+length tl+length_decoder lt
end.
Fact decoder_length s i lt : length (decoder s i lt) = length_decoder lt.
Fact length_decoder_size lt : length_decoder lt = 2+3*length lt+size_cards lt.
Fact decoder_spec_ok s i ll th tl lr lc v st :
v#>c = list_repeat Zero (length ll) ++ One :: lc
-> st = (s,v[lc/c][(th++v#>h)/h][(tl++v#>l)/l])
-> (i,decoder s i (ll++(th,tl)::lr)) // (i,v) ->> st.
(* There is no trailing 1 *)
Fact decoder_spec_nok_1 s i ll v k :
v#>c = list_repeat Zero k
-> exists r, (i,decoder s i ll) // (i,v) ->> (q,v[(list_repeat Zero r)/c]).
(* There might be a trailing 1 but the list of 0s is too long *)
Fact decoder_spec_nok_2 s i ll lc v k :
v#>c = list_repeat Zero k ++ lc
-> length ll <= k
-> exists r, (i,decoder s i ll) // (i,v) ->> (q,v[(list_repeat Zero r ++ lc)/c]).
(* A full decoder of a list of boolean into a list a valid tile indices, stacking the tiles in h/l in the list on the run.  The following list of indices [5,3,0,2] is encoded as 000001 0001 1 001 A valid list of booleans is an encoding of [n1,...,n_p] where each n_i is stricly less than length mm  If the encoding on the list of indices is incorrect in any way: - either not a list of indices - or some index is to big then the full decoder ends up at q.  The empty list is not a valid list of tile indices  *)
Definition full_decoder i ll :=
POP c (4+i) p ::
PUSH c One ::
PUSH h Zero ::
POP h (5+i) q ::
PUSH c Zero ::
decoder i (5+i) ll.
Definition length_full_decoder ll := 5 + length_decoder ll.
Fact full_decoder_length i ll : length (full_decoder i ll) = length_full_decoder ll.
Local Fact full_dec_start_spec_1 i lt v :
v#>c <> nil
-> (i,full_decoder i lt) // (i,v) ->> (5+i,v).
Local Fact full_dec_spec_rec i ln lc lt v :
v#>c = list_nat_bool ln ++ lc
-> Forall (fun x => x < length lt) ln
-> let (hh,ll) := tile_concat ln lt
in (i,full_decoder i lt) // (i,v) ->> (i,v[lc/c][(hh++v#>h)/h][(ll++v#>l)/l]).
(* Correctness lemma for the full decoder when then input actually encodes a valid list of tiles *)
Local Fact full_dec_spec_rec1 i ln lc lt v :
v#>c = list_nat_bool ln ++ lc
-> Exists (fun x => length lt <= x) ln
-> exists w, (i,full_decoder i lt) // (i,v) ->> (q,w)
/\ forall z, z <> c -> z <> h -> z <> l -> v#>z = w#>z.
Local Fact full_dec_spec_rec2 i k lt v :
v#>c = list_repeat Zero (S k)
-> exists w, (i,full_decoder i lt) // (i,v) ->> (q,w)
/\ forall z, z <> c -> z <> h -> z <> l -> v#>z = w#>z.
(* Correctness lemma for the full decoder when then input encodes an invalid list of tiles *)

Theorem full_decoder_ko_spec i ln lc lt v :
v#>c = list_nat_bool ln ++ lc
-> (Exists (fun x => length lt <= x) ln
\/  Forall (fun x => x < length lt) ln
/\ exists k, lc = list_repeat Zero (S k))
->  exists w, (i,full_decoder i lt) // (i,v) ->> (q,w)
/\ forall z, z <> c -> z <> h -> z <> l -> v#>z = w#>z.