Module Freezer : FREEZER.
Definition FRZ (p: mpred) := p.
Definition FRZL (ps:list mpred): mpred := fold_right sepcon emp ps.
Inductive FRZRw' (L1 G1: list mpred): Type :=
| FRZRw'_constr: forall F: mpred,
(fold_right sepcon emp G1) |-- fold_right sepcon emp L1 * F -> FRZRw' L1 G1.
Definition FRZRw := FRZRw'.
Definition FRZRw_constr:= FRZRw'_constr.
Definition FRZR (L1 G1: list mpred) {w: FRZRw L1 G1}: mpred :=
match w with
| FRZRw'_constr F _ => F
end.
Tactic Notation "freeze1_SEP" constr(n) :=
eapply (freeze1_SEP' (Z.to_nat n)); simpl.
Tactic Notation "freeze1_SEP" constr(n) constr(m) :=
(gather_SEP' (n::m::nil)); eapply (freeze1_SEP' (Z.to_nat 0)); simpl.
Tactic Notation "freeze1_SEP" constr(n) constr(m) constr(k)  :=
(gather_SEP' (n::m::k::nil)); eapply (freeze1_SEP' (Z.to_nat 0)); simpl.
Tactic Notation "freeze1_SEP" constr(n) constr(m) constr(k)  constr(p) :=
(gather_SEP' (n::m::k::p::nil)); eapply (freeze1_SEP' (Z.to_nat 0)); simpl.
Tactic Notation "freeze1_SEP" constr(n) constr(m) constr(k) constr(p) constr(q) :=
(gather_SEP' (n::m::k::p::q::nil)); eapply (freeze1_SEP' (Z.to_nat 0)); simpl.
(*******************freezing a list of mpreds ******************************)
Fixpoint delete_list {A: Type} (ns: list nat) (xs: list A) : list A :=
(* ns must already be sorted *)
match ns with
| nil => xs
| n::ns' => delete_nth n (delete_list ns' xs)
end.
Definition freezelist_nth (ns: list nat) (al: list mpred) : list mpred * list mpred :=
(map (fun i => my_nth i al emp) ns,
delete_list (SortNat.sort ns) al).
Function is_increasing (ns: list nat) (last: nat) {measure length ns}: bool  :=
match ns with
| nil => true
| a::nil => Nat.ltb a last
| a::b::ns' => andb (Nat.ltb a b) (is_increasing (b::ns') last)
end.
*)
Fixpoint my_nth {A} (n : nat) (l : list A) (default : A) {struct l} : A :=
match n with
| 0%nat => match l with
| [] => default
| x :: _ => x
end
| S m => match l with
| [] => default
| _ :: t => my_nth m t default
end
end.
(*Variant if l is monotonically decreasing Fixpoint new_freezelist_nth (l: list nat) (al: list mpred): (list mpred) * (list mpred) := match l with | nil => (nil,al) | (n::l') => let (xs, ys) := new_freezelist_nth l' (my_delete_nth n al) in (my_nth n al emp::xs, ys) end.*)

Lemma flatten_emp_in_SEP':
forall n P Q (R: list mpred) R',
nth_error R n = Some emp ->
R' = firstn n R ++ skipn (S n) R ->
PROPx P (LOCALx Q (SEPx R)) = PROPx P (LOCALx Q (SEPx R')).