From Velus Require Import Common.
From Coq Require Import List.
From Coq Require Import Permutation.
Import List.ListNotations.
Class ProgramUnit (
U:
Type) := {
name:
U ->
ident }.
Class ProgramStateUnit (
U T:
Type) :=
{
ProgramStateUnitProgramUnit :>
ProgramUnit U;
state_variables :
U ->
list (
ident *
T);
instance_variables :
U ->
list (
ident *
ident)
}.
Section Program.
Class Program (
U Prog:
Type) :=
{
units :
Prog ->
list U;
update :
Prog ->
list U ->
Prog;
units_of_update :
forall p us,
units (
update p us) =
us;
update_idempotent :
forall p us us',
update (
update p us)
us' =
update p us';
}.
Context {
U Prog:
Type}.
Context `{
ProgramUnit U} `{
Program U Prog}.
Definition find_unit (
f:
ident) (
p:
Prog) :
option (
U *
Prog):=
let fix find p :=
match p with
| [] =>
None
|
u ::
p =>
if ident_eq_dec (
name u)
f
then Some (
u,
p)
else find p
end
in
match find (
units p)
with
|
Some (
u,
us) =>
Some (
u,
update p us)
|
None =>
None
end.
Lemma find_unit_empty:
forall f p,
units p = [] ->
find_unit f p =
None.
Proof.
unfold find_unit;
intros * ->;
reflexivity.
Qed.
Definition ltsuffix_prog (
p p':
Prog) :=
ltsuffix (
units p) (
units p').
Lemma ltsuffix_prog_wf:
well_founded ltsuffix_prog.
Proof.
Lemma find_unit_ltsuffix_prog:
forall f p u p',
find_unit f p =
Some (
u,
p') ->
ltsuffix_prog p'
p.
Proof.
Lemma program_ind:
forall (
P:
Prog ->
Prop),
(
forall p,
(
forall f u p',
find_unit f p =
Some (
u,
p') ->
P p') ->
P p) ->
forall p,
P p.
Proof.
Definition equiv_program (
p p':
Prog) :=
forall us,
update p us =
update p'
us.
Lemma equiv_program_refl:
forall p,
equiv_program p p.
Proof.
intros ??; reflexivity.
Qed.
Lemma equiv_program_sym:
forall p p',
equiv_program p p' ->
equiv_program p'
p.
Proof.
intros * ??; auto.
Qed.
Lemma equiv_program_trans:
forall p p'
p'',
equiv_program p p' ->
equiv_program p'
p'' ->
equiv_program p p''.
Proof.
intros * ???; etransitivity; eauto.
Qed.
Global Add Parametric Relation:
Prog equiv_program
reflexivity proved by equiv_program_refl
symmetry proved by equiv_program_sym
transitivity proved by equiv_program_trans
as program_equiv_rel.
Lemma equiv_program_update:
forall p us,
equiv_program p (
update p us).
Proof.
Lemma find_unit_equiv_program:
forall p f u p',
find_unit f p =
Some (
u,
p') ->
equiv_program p p'.
Proof.
Lemma find_unit_now:
forall p u us,
units p =
u ::
us ->
find_unit (
name u)
p =
Some (
u,
update p us).
Proof.
intros *
Hunits.
unfold find_unit.
rewrite Hunits;
simpl.
destruct (
ident_eq_dec _ _);
try congruence.
Qed.
Lemma find_unit_later:
forall f p us p',
equiv_program p p' ->
units p =
us ++
units p' ->
Forall (
fun u =>
f <>
name u)
us ->
(
find_unit f p =
find_unit f p').
Proof.
Lemma find_unit_other:
forall f u p p',
equiv_program p p' ->
name u <>
f ->
units p =
u ::
units p' ->
(
find_unit f p =
find_unit f p').
Proof.
intros *
Eq Hnf E.
unfold find_unit;
rewrite E;
simpl.
destruct (
ident_eq_dec (
name u)
f);
try contradiction.
cases;
now rewrite Eq.
Qed.
Lemma find_unit_In:
forall p f u p',
find_unit f p =
Some (
u,
p') ->
name u =
f /\
In u (
units p).
Proof.
intro;
unfold find_unit.
induction (
units p)
as [|
u];
try discriminate.
intros *
Find.
destruct (
ident_eq_dec (
name u)
f).
-
inv Find;
intuition.
-
apply IHl in Find;
intuition.
Qed.
Lemma find_unit_Exists:
forall f p,
find_unit f p <>
None <->
Exists (
fun u =>
f = (
name u)) (
units p).
Proof.
Remark In_find_unit:
forall p u,
NoDup (
map name (
units p)) ->
In u (
units p) ->
exists p',
find_unit (
name u)
p =
Some (
u,
p').
Proof.
intros *
Nodup Hin;
unfold find_unit.
induction (
units p)
as [|
u'
p'];
try contradiction.
simpl in Nodup;
inversion_clear Nodup as [|??
Hnin].
inv Hin.
-
destruct (
ident_eq_dec (
name u) (
name u));
eauto;
contradiction.
-
destruct (
ident_eq_dec (
name u') (
name u));
eauto.
exfalso.
apply Hnin.
rewrite e;
apply in_map;
auto.
Qed.
Lemma find_unit_spec:
forall f p u p',
find_unit f p =
Some (
u,
p') ->
name u =
f
/\
exists us,
units p =
us ++
u ::
units p'
/\
Forall (
fun u =>
f <>
name u)
us.
Proof.
unfold find_unit;
intros *
Find.
induction (
units p)
as [|
u'];
try discriminate.
destruct (
ident_eq_dec (
name u')
f).
-
inv Find;
intuition.
exists nil;
simpl;
rewrite units_of_update;
intuition.
-
apply IHl in Find as (?&
us & -> &?).
intuition.
exists (
u' ::
us);
intuition.
Qed.
Lemma find_unit_None:
forall p f,
find_unit f p =
None <->
Forall (
fun u =>
f <>
name u) (
units p).
Proof.
Lemma find_unit_Some:
forall f p u p',
find_unit f p =
Some (
u,
p') <->
(
exists us,
units p =
u ::
us
/\
p' =
update p us
/\
name u =
f)
\/
(
exists u'
us,
units p =
u' ::
us
/\
name u' <>
f
/\
find_unit f (
update p us) =
Some (
u,
p')).
Proof.
unfold find_unit;
intros ??.
induction (
units p)
as [|
u'];
simpl.
-
split;
try discriminate.
intros [(?&?&?)|(?&?&?&?&?)];
discriminate.
-
intros.
destruct (
ident_eq_dec (
name u')
f);
simpl.
+
split.
*
intros E;
inv E;
intuition eauto.
*
intros [(?&
E &?&?)|(?&?&
E & ?&?)];
inv E;
auto;
contradiction.
+
split.
*
rewrite IHl;
setoid_rewrite units_of_update.
intros [(
us &
E &?&?)|(
u'' &
us &
E &?&?)];
inv E.
--
right;
exists u', (
u ::
us);
intuition.
destruct (
ident_eq_dec (
name u) (
name u));
try contradiction.
now rewrite update_idempotent.
--
right;
exists u', (
u'' ::
us);
intuition.
destruct (
ident_eq_dec (
name u'')
f);
try contradiction.
cases;
now rewrite update_idempotent in *.
*
intros [(
us &
E &?&?)|(
u'' &
us &
E &?&
Find)];
inv E.
--
contradiction.
--
rewrite units_of_update in Find.
cases;
now rewrite update_idempotent in Find.
Qed.
Lemma find_unit_app:
forall f p us us',
units p =
us ++
us' ->
find_unit f p =
match find_unit f (
update p us)
with
|
None =>
find_unit f (
update p us')
|
Some (
u,
p') =>
Some (
u,
update p (
units p' ++
us'))
end.
Proof.
Lemma find_unit_cons:
forall f p u us up',
units p =
u ::
us ->
find_unit f p =
up' <->
(
f =
name u /\
up' =
Some (
u,
update p us))
\/ (
f <>
name u /\
find_unit f (
update p us) =
up').
Proof.
Section Suffix.
Inductive suffix:
Prog ->
Prog ->
Prop :=
suffix_intro:
forall p p'
us,
equiv_program p p' ->
units p' =
us ++
units p ->
suffix p p'.
Lemma suffix_refl:
forall p,
suffix p p.
Proof.
Global Add Parametric Relation:
Prog suffix
reflexivity proved by suffix_refl
as suffix_rel.
Lemma suffix_cons:
forall u p p'
p'',
equiv_program p p'' ->
units p =
u ::
units p'' ->
suffix p p' ->
suffix p''
p'.
Proof.
intros *
E E'
Hsub;
inv Hsub.
econstructor.
-
symmetry in E;
transitivity p;
auto.
-
take (
units p' =
_)
and rewrite it.
rewrite E', <-
app_last_app;
eauto.
Qed.
Lemma find_unit_suffix:
forall p f u p',
find_unit f p =
Some (
u,
p') ->
suffix p'
p.
Proof.
End Suffix.
Section Ordered.
Variable Is_called_in:
ident ->
U ->
Prop.
Definition Ordered_program (
p:
Prog) :=
Forall' (
fun us u =>
(
forall f,
Is_called_in f u ->
f <>
name u
/\
exists u'
p',
find_unit f (
update p us) =
Some (
u',
p'))
/\
Forall (
fun u' =>
name u <>
name u')
us)
(
units p).
Lemma Ordered_program_append:
forall p us p',
equiv_program p p' ->
units p =
us ++
units p' ->
Ordered_program p ->
Forall' (
fun us u =>
Forall (
fun u' =>
name u <>
name u') (
us ++
units p'))
us
/\
Ordered_program p'.
Proof.
unfold Ordered_program;
intros *
E ->
Ord;
split.
-
induction us;
simpl.
+
constructor.
+
rewrite <-
app_comm_cons in Ord.
inversion_clear Ord as [|?? []
Ord'].
apply IHus in Ord'.
constructor;
auto.
-
apply Forall'
_app_r in Ord.
eapply Forall'
_impl;
eauto;
simpl;
intros * (
Spec &?);
split;
auto.
intros *
Called;
apply Spec in Called as (?&?&?&
Find);
intuition.
rewrite <-
E;
eauto.
Qed.
Corollary Ordered_program_append':
forall p us us',
units p =
us ++
us' ->
Ordered_program p ->
Forall' (
fun us u =>
Forall (
fun u' =>
name u <>
name u') (
us ++
us'))
us
/\
Ordered_program (
update p us').
Proof.
Lemma Ordered_program_find_unit:
forall p f u p',
Ordered_program p ->
find_unit f p =
Some (
u,
p') ->
Ordered_program (
update p (
u ::
units p')).
Proof.
Lemma not_Is_called_in_self:
forall p f u p',
Ordered_program p ->
find_unit f p =
Some (
u,
p') ->
~
Is_called_in f u.
Proof.
unfold find_unit;
induction 1
as [|
u' ? (
Spec & ?)];
try discriminate.
destruct (
ident_eq_dec (
name u')
f);
auto.
intros E Called;
inv E.
apply Spec in Called as [];
contradiction.
Qed.
Lemma find_unit_later_not_Is_called_in:
forall f'
us p p'
u'
p'',
Ordered_program p ->
units p =
us ++
units p' ->
find_unit f'
p' =
Some (
u',
p'') ->
Forall (
fun u => ~
Is_called_in (
name u)
u')
us.
Proof.
Corollary find_unit_other_not_Is_called_in:
forall f'
u p p'
u'
p'',
Ordered_program p ->
units p =
u ::
units p' ->
find_unit f'
p' =
Some (
u',
p'') ->
~
Is_called_in (
name u)
u'.
Proof.
Lemma find_unit_not_Is_called_in:
forall p f u p'
g,
Ordered_program p ->
find_unit g p =
None ->
find_unit f p =
Some (
u,
p') ->
~
Is_called_in g u.
Proof.
End Ordered.
End Program.
Section Transformation.
Class TransformUnit (
U U':
Type) `{
ProgramUnit U} `{
ProgramUnit U'} :=
{
transform_unit :
U ->
U';
transform_unit_conservative_name :
forall u,
name (
transform_unit u) =
name u
}.
Class TransformStateUnit (
U U':
Type) {
T:
Type}
`{
P:
ProgramStateUnit U T} `{
P':
ProgramStateUnit U'
T} :=
{
TransformStateUnitTransformUnit :>
TransformUnit U U';
transform_unit_conservative_state :
forall u,
Permutation (
state_variables (
transform_unit u)) (
state_variables u)
/\
Permutation (
instance_variables (
transform_unit u)) (
instance_variables u)
}.
Section Program.
Class TransformProgramWithoutUnits (
Prog Prog' :
Type) {
U:
Type} `{
Program U Prog} :=
{
transform_program_without_units :
Prog ->
Prog';
transform_program_without_units_update:
forall p us,
transform_program_without_units (
update p us)
=
transform_program_without_units p
}.
Context {
U U'
Prog Prog':
Type}
`{
TransformUnit U U'}
`{
ProgInst:
Program U Prog} `{
Program U'
Prog'}
`{@
TransformProgramWithoutUnits Prog Prog'
_ ProgInst}.
Definition transform_units (
p:
Prog) :
Prog' :=
update (
transform_program_without_units p) (
map transform_unit (
units p)).
Lemma find_unit_transform_units_backward:
forall f p tu tp',
find_unit f (
transform_units p) =
Some (
tu,
tp') ->
exists u p',
find_unit f p =
Some (
u,
p')
/\
tu =
transform_unit u
/\
tp' =
transform_units p'.
Proof.
Lemma find_unit_transform_units_forward:
forall f p u p',
find_unit f p =
Some (
u,
p') ->
find_unit f (
transform_units p) =
Some (
transform_unit u,
transform_units p').
Proof.
Lemma transform_units_Ordered_program:
forall p (
Is_called_in:
ident ->
U ->
Prop) (
Is_called_in':
ident ->
U' ->
Prop),
(
forall f u,
Is_called_in'
f (
transform_unit u) ->
Is_called_in f u) ->
Ordered_program Is_called_in p ->
Ordered_program Is_called_in' (
transform_units p).
Proof.
End Program.
End Transformation.
Global Hint Resolve suffix_refl suffix_cons :
program.
Global Hint Resolve find_unit_transform_units_backward find_unit_transform_units_forward
transform_units_Ordered_program :
program.