Set Bullet Behavior "Strict Subproofs".
Opaque upto.
(* The complement of make_shares. *)
Fixpoint make_shares_inv shs (lasts : list Z) i {struct lasts} : list share :=
match lasts with
| [] => []
| b :: rest => if eq_dec b i then hd Share.bot shs :: make_shares_inv (tl shs) rest i
else make_shares_inv (tl shs) rest i
end.

(* 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 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 Ews)
(Hdiff : b <> b0) (Hout : ~ In b lasts) (Hout0 : ~ In b0 lasts) (Hlasts : Zlength lasts = N)
bsh' v' (Hv' : -1 <= v' < B) h' (Hh' : 0 <= Zlength h' < N)
(Hbsh' : sepalg_list.list_join sh0 (sublist (Zlength h' + 1) N shs) bsh')
bsh (Hbsh : sepalg.join bsh' (Znth (Zlength h') shs) bsh),
(if eq_dec v' (-1) then
EX v0 : Z, data_at (Znth (Zlength h') shs) tbuffer (vint v0) (Znth (Znth (Zlength h') lasts) bufs)
else !! (v' = b0) && (EX v'0 : Z, data_at (Znth (Zlength h') shs) tbuffer (vint v'0) (Znth b0 bufs))) *
((EX v0 : Z, data_at bsh' tbuffer (vint v0) (Znth b bufs)) *
fold_right sepcon emp (upd_Znth b (map (fun a => EX sh : share, !! (if eq_dec a b0 then
sepalg_list.list_join sh0 (make_shares shs (sublist 0 (Zlength h')
(map (fun i : Z => if eq_dec (Znth i h') Empty then b0 else Znth i lasts) (upto (Z.to_nat N)))) a) sh
else if eq_dec a b then sepalg_list.list_join sh0 (sublist (Zlength h') N shs) sh
else sepalg_list.list_join sh0 (make_shares shs
(map (fun i : Z => if eq_dec (Znth i h') Empty then b0 else Znth i lasts) (upto (Z.to_nat N))) a) sh) &&
(EX v0 : Z, data_at sh tbuffer (vint v0) (Znth a bufs))) (upto (Z.to_nat B))) emp))
|-- fold_right sepcon emp (map (fun a => EX sh : share, !! (if eq_dec a b0 then
sepalg_list.list_join sh0 (make_shares shs (sublist 0 (Zlength h' + 1)
(map (fun i : Z => if eq_dec (Znth i (h' ++ [vint v'])) Empty then b0 else Znth i lasts) (upto (Z.to_nat N)))) a) sh
else if eq_dec a b then sepalg_list.list_join sh0 (sublist (Zlength h' + 1) N shs) sh
else sepalg_list.list_join sh0 (make_shares shs
(map (fun i : Z => if eq_dec (Znth i (h' ++ [vint v'])) Empty then b0 else Znth i lasts) (upto (Z.to_nat N))) a) sh) &&
(EX v0 : Z, data_at sh tbuffer (vint v0) (Znth a bufs))) (upto (Z.to_nat B))).