Set Bullet Behavior "Strict Subproofs".
Opaque upto.

(* Specifications: *)
Lemma body_initialize_writer : semax_body Vprog Gprog f_initialize_writer initialize_writer_spec.
Lemma body_start_write : semax_body Vprog Gprog f_start_write start_write_spec.
Lemma find_write_rest : forall d h, exists n, snd (find_write h d) = skipn n h.
Corollary prev_taken_In : forall h, prev_taken h = vint 1 \/ In (AE (prev_taken h) Empty) h.
Lemma write_val : forall h i v (Hh : apply_hist i (rev h) = Some v), v = Empty \/ v = fst (find_write h i).
Lemma find_write_read : forall i d h (Hread : apply_hist i (rev h) = Some Empty) (Hi : i <> Empty),
fst (find_read h d) = fst (find_write h i).
Lemma take_read : forall h v, apply_hist (vint 0) (rev h) = Some v ->
prev_taken h = if eq_dec v Empty then snd (last_two_reads h)
else fst (last_two_reads h).
Lemma find_write_In : forall d h, fst (find_write h d) = d \/ exists r, In (AE r (fst (find_write h d))) h.
Lemma make_shares_app : forall i l1 l2 shs, Zlength l1 + Zlength l2 <= Zlength shs ->
make_shares shs (l1 ++ l2) i =
make_shares shs l1 i ++ make_shares (sublist (Zlength l1) (Zlength shs) shs) l2 i.
Lemma make_shares_ext : forall i l l' shs (Hlen : Zlength l = Zlength l')
(Hi : forall j, 0 <= j < Zlength l -> Znth j l = i <-> Znth j l' = i),
make_shares shs l i = make_shares shs l' i.
Lemma body_main : semax_body Vprog Gprog f_main main_spec.
Lemma body_initialize_writer : semax_body Vprog Gprog f_initialize_writer initialize_writer_spec.
Lemma body_start_write : semax_body Vprog Gprog f_start_write start_write_spec.
Lemma find_write_rest : forall d h, exists n, snd (find_write h d) = skipn n h.
Corollary prev_taken_In : forall h, prev_taken h = vint 1 \/ In (AE (prev_taken h) Empty) h.
Lemma write_val : forall h i v (Hh : apply_hist i (rev h) = Some v), v = Empty \/ v = fst (find_write h i).
Lemma find_write_read : forall i d h (Hread : apply_hist i (rev h) = Some Empty) (Hi : i <> Empty),
fst (find_read h d) = fst (find_write h i).
Lemma take_read : forall h v, apply_hist (vint 0) (rev h) = Some v ->
prev_taken h = if eq_dec v Empty then snd (last_two_reads h)
else fst (last_two_reads h).
Lemma find_write_In : forall d h, fst (find_write h d) = d \/ exists r, In (AE r (fst (find_write h d))) h.
Lemma make_shares_app : forall i l1 l2 shs, Zlength l1 + Zlength l2 <= Zlength shs ->
make_shares shs (l1 ++ l2) i =
make_shares shs l1 i ++ make_shares (sublist (Zlength l1) (Zlength shs) shs) l2 i.
Lemma make_shares_out : forall b lgood lasts shs (Hb : ~In b lasts)
(Hlen1 : Zlength lgood = Zlength shs) (Hlen2 : Zlength lasts = Zlength shs),
make_shares shs (combine lgood lasts) b = map snd (filter fst (combine lgood shs)).
Lemma make_shares_ext : forall i d l l' lgood shs (Hlen : Zlength l = Zlength l')
(Hi : forall j, 0 <= j < Zlength l -> Znth j l d = i <-> Znth j l' d = i),
make_shares shs (combine lgood l) i = make_shares shs (combine lgood l') i.
Lemma make_shares_add : forall i i' d lasts lgood j shs (Hj : 0 <= j < Zlength lasts)
(Hi : Znth j lasts d = i) (Hgood : Znth j lgood false = true) (Hi' : i' <> i)
(Hlen : Zlength shs >= Zlength lasts),
exists shs1 shs2, make_shares shs (combine lgood lasts) i = shs1 ++ shs2 /\
make_shares shs (combine lgood (upd_Znth j lasts i')) i = shs1 ++ Znth j shs Tsh :: shs2.
Lemma make_shares_In : forall i lasts lgood x shs (Hx : 0 <= x < Zlength lasts)
(Hi : Znth x lasts 0 <> i) (Hgood : Znth x lgood false = true)
(Hlen : Zlength shs >= Zlength lasts),
In (Znth x shs Tsh) (make_shares shs (combine lgood lasts) i).
Lemma make_shares_sub : forall i lasts shs sh0 sh1 sh2 (Hlen : Zlength shs >= Zlength lasts)
(Hsh1 : sepalg_list.list_join sh0 shs sh1) (Hsh2 : sepalg_list.list_join sh0 (make_shares shs lasts i) sh2),
sepalg.join_sub sh2 sh1.
(* up *)
Lemma combine_nil : forall {A B} (l : list A), combine l (@nil B) = [].
Lemma make_shares_join : forall i d lasts lgood shs sh0 j sh1 sh2
(Hlen : Zlength shs >= Zlength lasts)
(Hsh1 : sepalg_list.list_join sh0 shs sh1)
(Hsh2 : sepalg_list.list_join sh0 (make_shares shs (combine lgood lasts) i) sh2)
(Hin : 0 <= j < Zlength shs) (Hj : Znth j lasts d = i),
exists sh', sepalg.join sh2 (Znth j shs Tsh) sh'.
Lemma data_at_buffer_cohere : forall sh1 sh2 v1 v2 p, readable_share sh1 ->
data_at sh1 tbuffer v1 p * data_at sh2 tbuffer v2 p |--
data_at sh1 tbuffer v1 p * data_at sh2 tbuffer v1 p.
Lemma make_shares_add' : forall i i' d lasts lgood j shs (Hj : 0 <= j < Zlength lasts)
(Hi : Znth j lasts d = i) (Hgood : Znth j lgood false = false)
(Hlen : Zlength shs >= Zlength lasts),
make_shares shs (combine lgood (upd_Znth j lasts i')) i = make_shares shs (combine lgood lasts) i.
Lemma make_shares_ext' : forall i d l l' lgood shs (Hlen : Zlength l = Zlength l')
(Hi : forall j, 0 <= j < Zlength l -> Znth j lgood false = true -> Znth j l d = i <-> Znth j l' d = i),
make_shares shs (combine lgood l) i = make_shares shs (combine lgood l') i.
(* The relationship between the last_taken array and the shares held by the writer is preserved by the action of the loop body. *)
Lemma upd_write_shares : forall bufs b b0 lgood lasts shs sh0 (Hb : 0 <= b < B) (Hb0 : 0 <= b0 < B)
(Hlasts : Forall (fun x : Z => 0 <= x < B) lasts) (Hshs : Zlength shs = N)
(Hread : Forall readable_share shs) (Hsh0 : sepalg_list.list_join sh0 shs Tsh)
(Hdiff : b <> b0) (Hout : ~ In b lasts) (Hout0 : ~ In b0 lasts) (Hlasts : Zlength lasts = N)
(Hlgood : Zlength lgood = N) i (Hh' : 0 <= i < N) good (Hgood : good = Znth i lgood false)
b' (Hb' : good = true -> -1 <= b' < B) sh (Hsh : sh = Znth i shs Tsh)
shi (Hshi : sepalg_list.list_join sh0
(map snd (filter fst (sublist (i + 1) N (combine lgood shs)))) shi)
bsh (Hbsh : sepalg_list.list_join shi
(map snd (if good then [(good, sh)] else [])) bsh)
h' (Hh' : Zlength h' = i) lasts' (Hlasts' : lasts' = map (fun i =>
if eq_dec (Znth i h' Vundef) Empty then b0 else Znth i lasts 0) (upto 3))
lasts'' (Hlasts'' : lasts'' = map (fun i =>
if eq_dec (Znth i (h' ++ [vint b']) Vundef) Empty then b0 else Znth i lasts 0) (upto 3)) vb,
(if good then EX v : _, data_at sh tbuffer (Vint v)
(Znth (if eq_dec b' (-1) then Znth i lasts 0 else b0) bufs Vundef)
else emp) *
(data_at shi tbuffer (Vint vb) (Znth b bufs Vundef) *
fold_right sepcon emp (upd_Znth b (map (fun a => EX sh2 : share,
!! (if eq_dec a b0 then sepalg_list.list_join sh0
(make_shares shs (combine lgood (sublist 0 i lasts')) a) sh2
else if eq_dec a b then sepalg_list.list_join sh0
(map snd (filter fst (sublist i N (combine lgood shs)))) sh2
else sepalg_list.list_join sh0
(make_shares shs (combine lgood lasts') a) sh2) &&
(EX v : _, data_at sh2 tbuffer (Vint v) (Znth a bufs Vundef))) (upto 5)) emp))
|-- fold_right sepcon emp (map (fun a => EX sh2 : share,
!! (if eq_dec a b0 then sepalg_list.list_join sh0
(make_shares shs (combine lgood (sublist 0 (i + 1) lasts'')) a) sh2
else if eq_dec a b then sepalg_list.list_join sh0
(map snd (filter fst (sublist (i + 1) N (combine lgood shs)))) sh2
else sepalg_list.list_join sh0
(make_shares shs (combine lgood lasts'') a) sh2) &&
(EX v : _, data_at sh2 tbuffer (Vint v) (Znth a bufs Vundef))) (upto 5)).
Lemma body_finish_write : semax_body Vprog Gprog f_finish_write finish_write_spec.