Module Qcert.NNRC.Optim.NNRCRewriteUtil
Require Import String.
Require Import List.
Require Import Arith.
Require Import Program.
Require Import Peano_dec.
Require Import EquivDec.
Require Import Utils.
Require Import DataRuntime.
Require Import cNNRCRuntime.
Require Import NNRCRuntime.
Section NNRCRewriteUtil.
Context {
fruntime:
foreign_runtime}.
Lemma not_in_over_app {
A} (
x:
A) (
l1 l2:
list A) :
~
In x (
l1++
l2) -> ~
In x l1 /\ ~
In x l2.
Proof.
unfold not;
intros.
split;
intros.
apply H.
apply in_or_app;
left;
assumption.
apply H.
apply in_or_app;
right;
assumption.
Qed.
Lemma really_fresh_is_really_fresh {
sep} {
oldvar} (
avoid:
list var) (
e:
nnrc) (
x:
var) :
x =
really_fresh_in sep oldvar avoid e ->
(~
In x avoid) /\ (~
In x (
nnrc_free_vars e)) /\ (~
In x (
nnrc_bound_vars e)).
Proof.
Lemma split_really_fresh_app (
x:
var)
l1 l2 l3 l4 :
~
False /\
~
In x (
l1 ++
l2) /\
~
In x (
l3 ++
l4) ->
((~
In x l1) /\ (~
In x l2)) /\
((~
In x l3) /\ (~
In x l4)).
Proof.
intros.
elim H;
clear H;
intros;
clear H;
elim H0;
clear H0;
intros.
split.
apply not_in_over_app;
assumption.
apply not_in_over_app;
assumption.
Qed.
Lemma split_really_fresh_app2 (
x:
var)
l1 l2 l3 l4 :
~
False /\
~
In x (
l1 ++
l2) /\
~
In x (
l3 ++
l4) ->
(~
False /\ (~
In x l1) /\ (~
In x l3)) /\
(~
False /\ (~
In x l2) /\ (~
In x l4)).
Proof.
intros.
elim H;
clear H;
intros;
clear H;
elim H0;
clear H0;
intros.
assert (~
In x l1 /\ ~
In x l2)
by (
apply not_in_over_app;
assumption).
assert (~
In x l3 /\ ~
In x l4)
by (
apply not_in_over_app;
assumption).
clear H0 H;
elim H1;
clear H1;
intros;
elim H2;
clear H2;
intros.
split;
split;
auto.
Qed.
Lemma dupl_var_ignored {
h:
list (
string*
string)} {
cenv}
(
d1 d2:
data) (
env:
bindings) (
v:
var) (
e:
nnrc):
nnrc_core_eval h cenv ((
v,
d1) :: (
v,
d2) ::
env)
e =
nnrc_core_eval h cenv ((
v,
d1)::
env)
e.
Proof.
Lemma not_or p1 p2:
~(
p1 \/
p2) -> ~
p1 /\ ~
p2.
Proof.
intros.
split;
unfold not in *;
intros.
elim H;
left;
assumption.
elim H;
right;
assumption.
Qed.
Lemma remove_in l (
x v:
var):
v<>
x -> ~
In x (
remove equiv_dec v l) ->
~
In x l.
Proof.
intros.
induction l;
unfold not in *;
intros.
simpl in H1;
assumption.
simpl in *.
destruct (
equiv_dec v a).
-
rewrite e in *;
clear e.
elim H1;
intros.
apply (
H H2).
apply (
IHl H0 H2).
-
simpl in *.
assert (
a <>
x /\ ~
In x (
remove equiv_dec v l)).
apply not_or;
assumption.
elim H2;
intros.
apply IHl;
try auto.
elim H1;
intros.
congruence.
assumption.
Qed.
Lemma split_really_fresh_app3 (
v x:
var)
l1 l2 l3 l4 :
~
False /\
~
In x (
l1 ++
remove equiv_dec v l2) /\
~ (
v =
x \/
In x (
l3 ++
l4)) ->
(
v <>
x) /\ (~
False /\ (~
In x l1) /\ (~
In x l3)) /\
(~
False /\ (~
In x l2) /\ (~
In x l4)).
Proof.
intros.
elim H;
clear H;
intros.
clear H;
elim H0;
clear H0;
intros.
assert (
v<>
x /\ ~(
In x (
l3 ++
l4))).
apply not_or;
assumption.
elim H1;
clear H0 H1;
intros.
split;
try assumption.
assert (~
In x l1 /\ ~
In x (
remove equiv_dec v l2))
by (
apply not_in_over_app;
assumption).
assert (~
In x l3 /\ ~
In x l4)
by (
apply not_in_over_app;
assumption).
elim H2;
clear H2 H1 H;
intros.
elim H3;
clear H3;
intros.
split;
split;
auto.
split;
try assumption.
apply (
remove_in l2 x v).
assumption.
assumption.
Qed.
Lemma nnrc_subst_rename {
sep} {
oldvar} (
e1 e2:
nnrc) (
x1 x2:
var) :
x2 =
really_fresh_in sep oldvar nil e2 ->
nnrc_core_eq (
NNRCLet x1 e1 e2) (
NNRCLet x2 e1 (
nnrc_subst e2 x1 (
NNRCVar x2))).
Proof.
unfold nnrc_core_eq;
simpl;
intros ? ? ? ? ?
_.
generalize (
really_fresh_is_really_fresh nil e2 x2 H);
intros.
clear H.
destruct (
nnrc_core_eval h cenv env e1);
try reflexivity.
revert env;
nnrc_cases (
induction e2)
Case;
intros;
simpl.
-
Case "
NNRCGetConstant"%
string.
reflexivity.
-
Case "
NNRCVar"%
string.
simpl in * .
match_destr;
unfold Equivalence.equiv in *;
subst;
match_destr;
try congruence;
simpl;
try congruence;
match_destr;
unfold Equivalence.equiv in *;
try congruence.
intuition.
-
Case "
NNRCConst"%
string.
reflexivity.
-
Case "
NNRCBinop"%
string.
simpl in *.
generalize (
split_really_fresh_app2 x2 _ _ _ _ H1);
clear H1;
intros.
elim H;
clear H;
intros.
specialize (
IHe2_1 H);
specialize (
IHe2_2 H1);
clear H H1.
rewrite IHe2_1;
rewrite IHe2_2;
reflexivity.
-
Case "
NNRCUnop"%
string.
specialize (
IHe2 H1).
rewrite IHe2;
reflexivity.
-
Case "
NNRCLet"%
string.
simpl in *.
generalize (
split_really_fresh_app3 v x2 _ _ _ _ H1);
clear H1;
intros.
elim H;
clear H;
intros;
simpl in *.
elim H1;
clear H1;
intros;
simpl in *.
specialize (
IHe2_1 H1).
specialize (
IHe2_2 H2).
rewrite IHe2_1;
clear IHe2_1.
destruct (
nnrc_core_eval h cenv ((
x2,
d) ::
env) (
nnrc_subst e2_1 x1 (
NNRCVar x2)));
try reflexivity.
match_destr;
unfold Equivalence.equiv in *;
subst;
simpl.
+
rewrite dupl_var_ignored.
generalize (@
nnrc_core_eval_swap_neq _ h cenv nil x1 d0 x2 d env e2_2 H);
intros.
rewrite app_nil_l in H3.
rewrite app_nil_l in H3.
unfold var in *.
rewrite H3;
clear H3.
clear H H1 IHe2_2.
elim H2 ;
clear H2;
intros;
clear H.
elim H1;
clear H1;
intros;
clear H1.
generalize (@
nnrc_core_eval_remove_free_env _ h cenv nil x2 d ((
x1,
d0) ::
env)
e2_2 H);
intros.
rewrite app_nil_l in H1.
rewrite app_nil_l in H1.
unfold var in *.
rewrite H1;
reflexivity.
+
generalize (@
nnrc_core_eval_swap_neq _ h cenv nil v d0 x1 d env e2_2);
intros.
assert (
v <>
x1)
by auto.
specialize (
H3 H4);
clear H4.
rewrite app_nil_l in H3.
rewrite app_nil_l in H3.
unfold var in *.
rewrite H3;
clear H3.
generalize (@
nnrc_core_eval_swap_neq _ h cenv nil v d0 x2 d env (
nnrc_subst e2_2 x1 (
NNRCVar x2))
H);
intros.
rewrite app_nil_l in H3.
rewrite app_nil_l in H3.
rewrite H3;
clear H3.
rewrite (
IHe2_2 ((
v,
d0) ::
env)).
reflexivity.
-
Case "
NNRCFor"%
string.
simpl in *.
generalize (
split_really_fresh_app3 v x2 _ _ _ _ H1);
clear H1;
intros.
elim H;
clear H;
intros;
simpl in *.
elim H1;
clear H1;
intros;
simpl in *.
specialize (
IHe2_1 H1).
specialize (
IHe2_2 H2).
rewrite IHe2_1;
clear IHe2_1.
destruct (
nnrc_core_eval h cenv ((
x2,
d) ::
env) (
nnrc_subst e2_1 x1 (
NNRCVar x2)));
try reflexivity.
destruct (
equiv_dec v x1);
try reflexivity.
+
rewrite e in *;
clear e.
destruct d0;
try reflexivity;
simpl.
induction l;
try reflexivity;
simpl.
rewrite dupl_var_ignored.
generalize (@
nnrc_core_eval_swap_neq _ h cenv nil x1 a x2 d env e2_2 H);
intros.
rewrite app_nil_l in H3.
rewrite app_nil_l in H3.
unfold var in *.
rewrite H3;
clear H3.
clear H H1 IHe2_2.
elim H2 ;
clear H2;
intros;
clear H.
elim H1;
clear H1;
intros;
clear H1.
generalize (@
nnrc_core_eval_remove_free_env _ h cenv nil x2 d ((
x1,
a) ::
env)
e2_2 H);
intros.
rewrite app_nil_l in H1.
unfold var in *.
rewrite app_nil_l in H1.
rewrite H1.
destruct (
nnrc_core_eval h cenv ((
x1,
a)::
env)
e2_2);
try reflexivity.
unfold lift in *;
simpl in *.
destruct (
lift_map (
fun d1 :
data =>
nnrc_core_eval h cenv ((
x1,
d1) :: (
x1,
d) ::
env)
e2_2)
l);
destruct (
lift_map (
fun d1 :
data =>
nnrc_core_eval h cenv ((
x1,
d1) :: (
x2,
d) ::
env)
e2_2)
l);
congruence.
+
destruct d0;
try reflexivity;
simpl.
induction l;
try reflexivity;
simpl.
generalize (@
nnrc_core_eval_swap_neq _ h cenv nil v a x1 d env e2_2);
intros.
assert (
v <>
x1)
by auto.
specialize (
H3 H4);
clear H4.
rewrite app_nil_l in H3.
rewrite app_nil_l in H3.
unfold var in *.
rewrite H3;
clear H3.
generalize (@
nnrc_core_eval_swap_neq _ h cenv nil v a x2 d env (
nnrc_subst e2_2 x1 (
NNRCVar x2))
H);
intros.
rewrite app_nil_l in H3.
rewrite app_nil_l in H3.
rewrite H3;
clear H3.
rewrite (
IHe2_2 ((
v,
a) ::
env)).
destruct (
nnrc_core_eval h cenv ((
x2,
d) :: (
v,
a) ::
env) (
nnrc_subst e2_2 x1 (
NNRCVar x2)));
try reflexivity.
unfold lift in *;
simpl in *.
destruct (
lift_map (
fun d1 :
data =>
nnrc_core_eval h cenv ((
v,
d1) :: (
x1,
d) ::
env)
e2_2)
l);
destruct (
lift_map (
fun d1 :
data =>
nnrc_core_eval h cenv ((
v,
d1) :: (
x2,
d) ::
env) (
nnrc_subst e2_2 x1 (
NNRCVar x2)))
l);
congruence.
-
Case "
NNRCIf"%
string.
simpl in *.
generalize (
split_really_fresh_app2 x2 _ _ _ _ H1);
clear H1;
intros.
elim H;
clear H;
intros.
generalize (
split_really_fresh_app2 x2 _ _ _ _ H1);
clear H1;
intros.
elim H1;
clear H1;
intros.
specialize (
IHe2_1 H);
specialize (
IHe2_2 H1);
specialize (
IHe2_3 H2);
clear H H1 H2.
rewrite IHe2_1;
rewrite IHe2_2;
rewrite IHe2_3.
reflexivity.
-
Case "
NNRCEither"%
string.
simpl in H1.
repeat rewrite nin_app_or in H1.
destruct H1 as [
_[[?[??]]?]].
apply not_or in H3.
destruct H3.
apply not_or in H4.
destruct H4.
repeat rewrite nin_app_or in H5.
destruct H5 as [?[??]].
rewrite IHe2_1 by (
simpl;
intuition).
rewrite <-
remove_in_neq in H1,
H2 by congruence.
match_destr.
match_destr.
+
match_destr;
unfold equiv,
complement in *;
subst.
*
generalize (@
nnrc_core_eval_remove_duplicate_env _ h cenv nil x1 d0 nil);
simpl;
intros re1;
rewrite re1.
generalize (@
nnrc_core_eval_remove_free_env _ h cenv ((
x1,
d0)::
nil));
simpl;
intros re2;
rewrite re2 by trivial.
trivial.
*
generalize (@
nnrc_core_eval_swap_neq _ h cenv nil v d0);
simpl;
intros re1;
repeat rewrite re1 by trivial.
rewrite IHe2_2;
trivial.
simpl;
intuition.
+
match_destr;
unfold equiv,
complement in *;
subst.
*
generalize (@
nnrc_core_eval_remove_duplicate_env _ h cenv nil x1 d0 nil);
simpl;
intros re1;
rewrite re1.
generalize (@
nnrc_core_eval_remove_free_env _ h cenv ((
x1,
d0)::
nil));
simpl;
intros re2;
rewrite re2 by trivial.
trivial.
*
generalize (@
nnrc_core_eval_swap_neq _ h cenv nil v0 d0);
simpl;
intros re1;
repeat rewrite re1 by trivial.
rewrite IHe2_3;
trivial.
simpl;
intuition.
-
Case "
NNRCGroupBy"%
string.
reflexivity.
Qed.
Inductive var_use :=
|
NotUsed
|
UsedOnce
|
UsedMany.
Definition use_sum u1 u2 :=
match (
u1,
u2)
with
| (
UsedMany,
_) =>
UsedMany
| (
_,
UsedMany) =>
UsedMany
| (
UsedOnce,
UsedOnce) =>
UsedMany
| (
UsedOnce,
NotUsed) =>
UsedOnce
| (
NotUsed,
UsedOnce) =>
UsedOnce
| (
NotUsed,
NotUsed) =>
NotUsed
end.
Lemma use_sum_once u1 u2:
use_sum u1 u2 =
UsedOnce <->
((
u1 =
UsedOnce) /\ (
u2 =
NotUsed)) \/
((
u1 =
NotUsed) /\ (
u2 =
UsedOnce)).
Proof.
split;
intros.
-
destruct u1;
destruct u2;
unfold use_sum in H;
simpl in H;
try congruence.
right;
split;
reflexivity.
left;
split;
reflexivity.
-
elim H;
intros;
elim H0;
intros;
rewrite H1;
rewrite H2;
reflexivity.
Qed.
Lemma use_sum_not u1 u2:
use_sum u1 u2 =
NotUsed <->
(
u1 =
NotUsed) /\ (
u2 =
NotUsed).
Proof.
split;
intros.
-
destruct u1;
destruct u2;
unfold use_sum in H;
simpl in H;
try congruence.
split;
reflexivity.
-
elim H;
intros;
rewrite H0;
rewrite H1;
reflexivity.
Qed.
Definition use_alt u1 u2 :=
match (
u1,
u2)
with
| (
UsedOnce,
UsedOnce) =>
UsedOnce
| (
NotUsed,
NotUsed) =>
NotUsed
|
_ =>
UsedMany
end.
Lemma use_alt_once u1 u2:
use_alt u1 u2 =
UsedOnce <->
((
u1 =
UsedOnce) /\ (
u2 =
UsedOnce)).
Proof.
split;
intros.
-
destruct u1;
destruct u2;
unfold use_alt in H;
simpl in H;
try congruence.
split;
reflexivity.
-
elim H;
intros;
elim H0;
rewrite H0;
rewrite H1;
reflexivity.
Qed.
Lemma use_alt_not u1 u2:
use_alt u1 u2 =
NotUsed <->
((
u1 =
NotUsed) /\ (
u2 =
NotUsed)).
Proof.
split;
intros.
-
destruct u1;
destruct u2;
unfold use_alt in H;
simpl in H;
try congruence.
split;
reflexivity.
-
elim H;
intros;
elim H0;
rewrite H0;
rewrite H1;
reflexivity.
Qed.
Definition use_exp u1 u2 :=
match (
u1,
u2)
with
| (
UsedMany,
_) =>
UsedMany
| (
_,
UsedMany) =>
UsedMany
| (
_,
UsedOnce) =>
UsedMany
| (
UsedOnce,
NotUsed) =>
UsedOnce
| (
NotUsed,
NotUsed) =>
NotUsed
end.
Lemma use_exp_once u1 u2:
use_exp u1 u2 =
UsedOnce <-> (
u1 =
UsedOnce) /\ (
u2 =
NotUsed).
Proof.
split;
intros.
-
destruct u1;
destruct u2;
unfold use_exp in H;
simpl in H;
try congruence.
split;
reflexivity.
-
elim H;
intros;
rewrite H0;
rewrite H1;
reflexivity.
Qed.
Lemma use_exp_not x y :
(
use_exp x y) =
NotUsed <->
(
x =
NotUsed /\
y =
NotUsed).
Proof.
unfold use_exp.
match_destr;
try match_destr;
intuition;
discriminate.
Qed.
Fixpoint use_count (
x:
var) (
e:
nnrc) :
var_use :=
match e with
|
NNRCGetConstant x' =>
NotUsed
|
NNRCVar x' => (
if x ==
x'
then UsedOnce else NotUsed)
|
NNRCConst _ =>
NotUsed
|
NNRCBinop _ e1 e2 =>
use_sum (
use_count x e1) (
use_count x e2)
|
NNRCUnop _ e1 =>
use_count x e1
|
NNRCLet x'
e1 e2 =>
if (
x ==
x')
then use_count x e1
else use_sum (
use_count x e1) (
use_count x e2)
|
NNRCFor x'
e1 e2 =>
use_exp (
use_count x e1) (
if x ==
x'
then NotUsed else (
use_count x e2))
|
NNRCIf e1 e2 e3 =>
use_sum (
use_count x e1) (
use_alt (
use_count x e2) (
use_count x e3))
|
NNRCEither ed xl el xr er =>
use_sum
(
use_count x ed)
(
use_alt
(
if x ==
xl then NotUsed else use_count x el)
(
if x ==
xr then NotUsed else use_count x er))
|
NNRCGroupBy _ _ e1 =>
use_count x e1
end.
Lemma NotUsed_nfree v e :
use_count v e =
NotUsed <-> ~
In v (
nnrc_free_vars e).
Proof.
Lemma not_used_ignored {
h:
list(
string*
string)} {
cenv}
(
d:
data) (
env:
bindings) (
v:
var) (
e:
nnrc) :
(
use_count v e) =
NotUsed ->
nnrc_core_eval h cenv ((
v,
d)::
env)
e =
nnrc_core_eval h cenv env e.
Proof.
Fixpoint nnrc_var_must_be_evaluated (
e:
nnrc) (
x:
var) :
Prop :=
match e with
|
NNRCGetConstant _ =>
False
|
NNRCVar v =>
v =
x
|
NNRCConst _ =>
False
|
NNRCBinop _ e1 e2 =>
nnrc_var_must_be_evaluated e1 x
\/
nnrc_var_must_be_evaluated e2 x
|
NNRCUnop u e1 =>
nnrc_var_must_be_evaluated e1 x
|
NNRCLet v e1 e2 =>
nnrc_var_must_be_evaluated e1 x
\/ (
v <>
x /\
nnrc_var_must_be_evaluated e2 x)
|
NNRCFor v e1 e2 =>
nnrc_var_must_be_evaluated e1 x
|
NNRCIf e1 e2 e3 =>
nnrc_var_must_be_evaluated e1 x
|
NNRCEither e1 v2 e2 v3 e3 =>
nnrc_var_must_be_evaluated e1 x
|
NNRCGroupBy g sl e1 =>
nnrc_var_must_be_evaluated e1 x
end.
Lemma nnrc_var_must_be_evaluated_dec (
e:
nnrc) (
x:
var) :
{
nnrc_var_must_be_evaluated e x} + {~
nnrc_var_must_be_evaluated e x}.
Proof.
induction e;
simpl;
eauto 3.
-
destruct (
v ==
x);
eauto.
-
destruct IHe1; [
tauto | ].
destruct IHe2; [
eauto | ].
right;
tauto.
-
destruct IHe1; [
tauto | ].
destruct (
x ==
v);
unfold equiv,
complement in *.
+
right.
subst;
intuition.
+
destruct IHe2.
*
left.
intuition.
*
right;
intuition.
Defined.
Lemma nnrc_must_use_preserves_failure {
h:
brand_relation_t}
cenv e1 x e2 env :
disjoint (
nnrc_bound_vars e2) (
nnrc_free_vars e1) ->
nnrc_var_must_be_evaluated e2 x ->
@
nnrc_eval _ h cenv env e1 =
None ->
@
nnrc_eval _ h cenv env (
nnrc_subst e2 x e1) =
None.
Proof.
Lemma let_inline_disjoint_arrow_must_use x e1 e2 :
disjoint (
nnrc_bound_vars e2) (
nnrc_free_vars e1) ->
nnrc_var_must_be_evaluated e2 x ->
nnrc_eq
(
NNRCLet x e1 e2)
(
nnrc_subst e2 x e1).
Proof.
End NNRCRewriteUtil.