(* Ltac flatten_emp_in_mpreds RR := match RR with | (SEPx (?R)) => match R with context [emp :: ?R'] => let n := constr:(length R - Datatypes.S (length R'))%nat in let n' := eval lazy beta zeta iota delta in n in erewrite(@flatten_emp_in_mpreds' n' R _ (eq_refl _)); [ | let RR := fresh "RR" in set (RR := R); unfold firstn, app, skipn; subst RR; cbv beta iota; apply eq_refl ] end end.  Ltac flatten_emp := match goal with | |- semax _ ?PQR _ _ => flatten_emp_in_SEP PQR | |-  ?PQR |-- _ => first [flatten_emp_in_SEP PQR | flatten_emp_in_mpreds PQR ] end.*)
Ltac flatten_emp_in_SEP PQR :=
match PQR with
| PROPx ?P (LOCALx ?Q (SEPx (?R))) =>
match R with context [emp :: ?R'] =>
let n := constr:((length R - Datatypes.S (length R'))%nat) in
let n' := eval lazy beta zeta iota delta in n in
erewrite(@flatten_emp_in_SEP' n' P Q R _ (eq_refl _));
[ |
let RR := fresh "RR" in set (RR := R);
unfold firstn, app, skipn; subst RR; cbv beta iota;
apply eq_refl
]
end
end.
Ltac flatten_emp :=
match goal with
| |- semax _ ?PQR _ _ => flatten_emp_in_SEP PQR
| |-  ?PQR |-- _ => flatten_emp_in_SEP PQR
end.
(*Thawing a freezer results in the sepcon product of the frozen items.*)
(*Tactic requires the resulting goal to be normalized manually.*)
Ltac thaw' name :=
rewrite (FRZL_ax name); unfold name, abbreviate; clear name.
(*add simplification of the list operations inside the freezer, flatten the sepcon, and eliminate the emp term*)
Ltac thaw name :=
thaw' name; simpl nat_of_Z; unfold my_delete_nth, my_nth, fold_right_sepcon;
repeat flatten_sepcon_in_SEP; repeat flatten_emp.
(************************ Ramification ************************)
Inductive split_FRZ_in_SEP: list mpred -> list mpred -> list mpred -> Prop :=
| split_FRZ_in_SEP_nil: split_FRZ_in_SEP nil nil nil
| split_FRZ_in_SEP_FRZ: forall R R' RF F, split_FRZ_in_SEP R R' RF -> split_FRZ_in_SEP (FRZ F :: R) R' (FRZ F :: RF)
| split_FRZ_in_SEP_FRZL: forall R R' RF F, split_FRZ_in_SEP R R' RF -> split_FRZ_in_SEP (FRZL F :: R) R' (FRZL F :: RF)
| split_FRZ_in_SEP_FRZR: forall R R' RF L G w, split_FRZ_in_SEP R R' RF -> split_FRZ_in_SEP (@FRZR L G w :: R) R' (@FRZR L G w :: RF)
| split_FRZ_in_SEP_other: forall R R' RF R0, split_FRZ_in_SEP R R' RF -> split_FRZ_in_SEP (R0 :: R) (R0 :: R') RF.
Ltac prove_split_FRZ_in_SEP :=
solve [
repeat first
[ simple apply split_FRZ_in_SEP_nil
| simple apply split_FRZ_in_SEP_FRZ
| simple apply split_FRZ_in_SEP_FRZL
| simple apply split_FRZ_in_SEP_FRZR
| simple apply split_FRZ_in_SEP_other]].

Lemma split_FRZ_in_SEP_spec: forall R R' RF,
split_FRZ_in_SEP R R' RF ->
fold_right_sepcon R = fold_right_sepcon R' * fold_right_sepcon RF.