Require Import Coqlib Util Utf8 IdealExpr AbIdealEnv AdomLib Integers FastArith.
Require Import IdealIntervals ZIntervals.
Fixpoint simplify_bool_expr_aux (
e:
iexpr) :
iexpr *
bool :=
match e with
|
IEvar _ _ |
IEconst _ |
IEZitv _ => (
e,
false)
|
IEunop op e => (
IEunop op (
simplify_expr e),
false)
|
IEbinop (
IOcmp Ceq) (
e as e1) (
IEconst (
INz z)
as e2)
|
IEbinop (
IOcmp Ceq) (
IEconst (
INz z)
as e1) (
e as e2) =>
if Zfasteqb z F0 then
let '(
e',
b) :=
simplify_bool_expr_aux e in
(
e',
negb b)
else (
IEbinop (
IOcmp Ceq) (
simplify_expr e1) (
simplify_expr e2),
false)
|
IEbinop (
IOcmp Cne) (
e as e1) (
IEconst (
INz z)
as e2)
|
IEbinop (
IOcmp Cne) (
IEconst (
INz z)
as e1) (
e as e2) =>
if Zfasteqb z F0 then simplify_bool_expr_aux e
else (
IEbinop (
IOcmp Cne) (
simplify_expr e1) (
simplify_expr e2),
false)
|
IEbinop (
IOcmp c)
e1 e2 =>
(
IEbinop (
IOcmp c) (
simplify_expr e1) (
simplify_expr e2),
false)
|
IEbinop (
IOcmpf c)
e1 e2 =>
(
IEbinop (
IOcmpf c) (
simplify_expr e1) (
simplify_expr e2),
false)
|
IEbinop op e1 e2 =>
(
IEbinop op (
simplify_expr e1) (
simplify_expr e2),
false)
end
with simplify_expr (
e:
iexpr) :
iexpr :=
let e0 :=
IEconst (
INz F0)
in
match e with
|
IEvar _ _ |
IEconst _ |
IEZitv _ =>
e
|
IEunop op e =>
IEunop op (
simplify_expr e)
|
IEbinop (
IOcmp Ceq as op) (
e as e1) (
IEconst (
INz z)
as e2)
|
IEbinop (
IOcmp Ceq as op) (
IEconst (
INz z)
as e1) (
e as e2) =>
if Zfasteqb z F0 then
match simplify_bool_expr_aux e with
| (
e',
true) =>
IEbinop (
IOcmp Cne)
e'
e0
| (
e',
false) =>
IEbinop (
IOcmp Ceq)
e'
e0
end
else IEbinop op (
simplify_expr e1) (
simplify_expr e2)
|
IEbinop (
IOcmp Cne as op) (
e as e1) (
IEconst (
INz z)
as e2)
|
IEbinop (
IOcmp Cne as op) (
IEconst (
INz z)
as e1) (
e as e2) =>
if Zfasteqb z F0 then
match simplify_bool_expr_aux e with
| (
e',
false) =>
IEbinop (
IOcmp Cne)
e'
e0
| (
e',
true) =>
IEbinop (
IOcmp Ceq)
e'
e0
end
else IEbinop op (
simplify_expr e1) (
simplify_expr e2)
|
IEbinop op e1 e2 =>
IEbinop op (
simplify_expr e1) (
simplify_expr e2)
end.
Lemma simplify_expr_correct_aux:
forall e,
(
forall ρ
n,
eval_iexpr ρ
e (
INz n) ->
forall e'
b,
simplify_bool_expr_aux e = (
e',
b) ->
exists n',
eval_iexpr ρ
e' (
INz n') /\
xorb (
Zcmp Ceq n 0) (
Zcmp Ceq n' 0) =
b)
/\
(
forall ρ
n,
eval_iexpr ρ
e n ->
eval_iexpr ρ (
simplify_expr e)
n).
Proof.
induction e;
simpl;
split;
intros;
inv H.
-
inv H0.
eexists.
split.
constructor;
eauto.
apply xorb_nilpotent.
-
constructor;
auto.
-
inv H0.
eexists.
split.
constructor;
eauto.
apply xorb_nilpotent.
-
constructor.
-
inv H0.
eexists.
split.
constructor;
eauto.
apply xorb_nilpotent.
-
constructor;
auto.
-
destruct IHe as [
IHe IHe'].
inv H0.
eexists.
split.
econstructor;
eauto.
apply xorb_nilpotent.
-
destruct IHe as [
IHe IHe'].
econstructor;
eauto.
-
destruct IHe1 as [
IHe1 IHe1'].
destruct IHe2 as [
IHe2 IHe2'].
inv H7;
try now (
inv H0;
eexists;
split;
[
econstructor;
eauto;
econstructor|
apply xorb_nilpotent]).
assert (
forall A B (
a a':
A) (
b b':
B),
(
a,
b) = (
a',
b') ->
a =
a' /\
b =
b')
by (
split;
congruence).
destruct (
simplify_bool_expr_aux e1)
as (
e1',
b1),
(
simplify_bool_expr_aux e2)
as (
e2',
b2).
edestruct IHe1 as ([
n'1] &
EVAL1 &
Hn'1);
eauto.
clear IHe1.
edestruct IHe2 as ([
n'2] &
EVAL2 &
Hn'2);
eauto.
clear IHe2.
specialize (
IHe1'
_ _ H4).
specialize (
IHe2'
_ _ H6).
assert (
forall n,
eval_iexpr ρ (
IEconst (
INz 0)) (
INz n) ->
n = 0).
{
intros.
clear -
H1.
inv H1.
auto. }
destruct c;
(
try now (
apply H in H0;
destruct H0;
subst;
eexists;
split;
[
econstructor; [
apply IHe1'|
apply IHe2'|
econstructor]|
apply xorb_nilpotent]));
destruct e1 as [|[|[[]]]| | |],
e2 as [|[|[[]]]| | |];
fastunwrap;
simpl Z.eqb in H0;
cbv iota in H0;
apply H in H0;
destruct H0;
subst;
(
try now (
eexists;
split; [
econstructor; [
apply IHe1'|
apply IHe2'|
econstructor]|
apply xorb_nilpotent]));
unfold Zcmp in *;
(
try (
apply H1 in H4;
inv H4;
rewrite (
Z.compare_antisym i2 0)));
(
try (
apply H1 in H6;
inv H6));
(
eexists;
split; [
now eauto|];
symmetry;
simpl;
destruct Z.compare,
Z.compare;
auto).
-
destruct IHe1 as [
IHe1 IHe1'].
destruct IHe2 as [
IHe2 IHe2'].
assert (
eval_iexpr ρ (
IEbinop i (
simplify_expr e1) (
simplify_expr e2))
n)
by (
econstructor;
eauto).
assert (
forall n,
eval_iexpr ρ (
IEconst (
INz 0)) (
INz n) ->
n = 0).
{
intros.
inv H0.
auto. }
destruct H6;
auto.
destruct (
simplify_bool_expr_aux e1)
as (
e1',
b1),
(
simplify_bool_expr_aux e2)
as (
e2',
b2).
edestruct IHe1 as ([
n'1] &
EVAL1 &
Hn'1);
eauto.
clear IHe1.
edestruct IHe2 as ([
n'2] &
EVAL2 &
Hn'2);
eauto.
clear IHe2.
specialize (
IHe1'
_ _ H3).
specialize (
IHe2'
_ _ H5).
assert (
eval_iexpr ρ (
IEconst (
INz 0)) (
INz 0)).
{
econstructor. }
destruct c;
auto.
+
assert (
eval_iexpr ρ (
IEbinop (
IOcmp Ceq)
e1' (
IEconst (
INz 0)))
(
INz (
if Zcmp Ceq n'1 0
then F1 else F0))).
{
econstructor;
eauto. }
assert (
eval_iexpr ρ (
IEbinop (
IOcmp Ceq)
e2' (
IEconst (
INz 0)))
(
INz (
if Zcmp Ceq n'2 0
then F1 else F0))).
{
econstructor;
eauto. }
assert (
eval_iexpr ρ (
IEbinop (
IOcmp Cne)
e1' (
IEconst (
INz 0)))
(
INz (
if Zcmp Ceq n'1 0
then F0 else F1))).
{
econstructor;
eauto.
replace (
if Zcmp Ceq n'1 0
return Zfast then F0 else F1)
with (
if Zcmp Cne n'1 0
return Zfast then F1 else F0)
by (
unfold Zcmp;
destruct Z.compare;
auto).
constructor. }
assert (
eval_iexpr ρ (
IEbinop (
IOcmp Cne)
e2' (
IEconst (
INz 0)))
(
INz (
if Zcmp Ceq n'2 0
then F0 else F1))).
{
econstructor;
eauto.
replace (
if Zcmp Ceq n'2 0
return Zfast then F0 else F1)
with (
if Zcmp Cne n'2 0
return Zfast then F1 else F0)
by (
unfold Zcmp;
destruct Z.compare;
auto).
constructor. }
destruct e1 as [|[|[[]]]| | |],
e2 as [|[|[[]]]| | |];
auto;
fastunwrap;
simpl Z.eqb;
cbv iota;
(
try (
apply H0 in H3;
inv H3;
replace (
Zcmp Ceq 0
i2)
with (
Zcmp Ceq i2 0)
by (
unfold Zcmp;
rewrite Z.compare_antisym;
destruct Z.compare;
auto)));
(
try (
apply H0 in H5;
inv H5));
destruct (
Zcmp Ceq n'1 0), (
Zcmp Ceq n'2 0);
(
try destruct (
Zcmp Ceq i1 0));
(
try destruct (
Zcmp Ceq i2 0));
eauto.
+
assert (
eval_iexpr ρ (
IEbinop (
IOcmp Ceq)
e1' (
IEconst (
INz 0)))
(
INz (
if Zcmp Ceq n'1 0
then F1 else F0))).
{
econstructor;
eauto. }
assert (
eval_iexpr ρ (
IEbinop (
IOcmp Ceq)
e2' (
IEconst (
INz 0)))
(
INz (
if Zcmp Ceq n'2 0
then F1 else F0))).
{
econstructor;
eauto. }
assert (
eval_iexpr ρ (
IEbinop (
IOcmp Cne)
e1' (
IEconst (
INz 0)))
(
INz (
if Zcmp Ceq n'1 0
then F0 else F1))).
{
econstructor;
eauto.
replace (
if Zcmp Ceq n'1 0
return Zfast then F0 else F1)
with (
if Zcmp Cne n'1 0
return Zfast then F1 else F0)
by (
unfold Zcmp;
destruct Z.compare;
auto).
constructor. }
assert (
eval_iexpr ρ (
IEbinop (
IOcmp Cne)
e2' (
IEconst (
INz 0)))
(
INz (
if Zcmp Ceq n'2 0
then F0 else F1))).
{
econstructor;
eauto.
replace (
if Zcmp Ceq n'2 0
return Zfast then F0 else F1)
with (
if Zcmp Cne n'2 0
return Zfast then F1 else F0)
by (
unfold Zcmp;
destruct Z.compare;
auto).
constructor. }
destruct e1 as [|[|[[]]]| | |],
e2 as [|[|[[]]]| | |];
auto;
simpl Zunwrap in *;
(
try (
apply H0 in H3;
inv H3;
replace (
Zcmp Cne 0
i2)
with (
Zcmp Cne i2 0)
by (
unfold Zcmp;
rewrite Z.compare_antisym;
destruct Z.compare;
auto)));
(
try (
apply H0 in H5;
inv H5));
unfold Zcmp in *;
destruct (
n'1 ?= 0), (
n'2 ?= 0);
(
try destruct (
i1 ?= 0));
(
try destruct (
i2 ?= 0));
eauto.
Qed.
Lemma simplify_expr_correct:
forall e ρ
n,
eval_iexpr ρ
e n ->
eval_iexpr ρ (
simplify_expr e)
n.
Proof.
Definition is_bool_expr (
e:
iexpr) (
c:
query_chan) :
bool :=
match e with
|
IEbinop (
IOcmp _ |
IOcmpf _)
_ _ =>
true
|
IEvar _ _ =>
c.(
get_itv)
e ⊑
NotBot (
Just (
Az (
ZITV F0 F1)))
|
IEconst (
INz z) =>
Zfasteqb z F0 ||
Zfasteqb z F1
|
_ =>
false
end.
Lemma is_bool_expr_correct:
forall e ρ
n c,
eval_iexpr ρ
e (
INz n) -> ρ ∈ γ
c ->
is_bool_expr e c =
true ->
n = 0 \/
n = 1.
Proof.
intros.
destruct e;
try discriminate.
-
simpl in H1.
destruct n as [
n].
apply (
leb_correct (
get_itv c (
IEvar i v)))
with (
a:=
INz n)
in H1.
simpl in *.
assert (
n=0 \/
n=1)
by omega.
clear -
H2.
intuition congruence.
eapply get_itv_correct;
eauto.
-
simpl in H1.
inv H.
destruct n as [[|[]|]];
try discriminate;
auto.
-
inv H.
inv H1.
inv H8;
try discriminate.
destruct Zcmp;
auto.
destruct Floats.Float.cmp;
auto.
Qed.
Definition simplify_bool_expr (
e:
iexpr) (
c:
query_chan) :
iexpr *
bool :=
let '(
e,
b) :=
simplify_bool_expr_aux e in
if is_bool_expr e c then (
e,
b)
else (
IEbinop (
IOcmp (
if b then Ceq else Cne))
e (
IEconst (
INz F0)),
false).
Lemma simplify_bool_expr_correct:
∀
e ρ
n,
eval_iexpr ρ
e (
INz n) ->
∀
c, ρ ∈ γ
c ->
∀
e'
b,
simplify_bool_expr e c = (
e',
b) ->
eval_iexpr ρ
e' (
INz (
if xorb (
n =? 0)
b then F0 else F1)).
Proof.
Section assume_unfold.
Context {
A:
Type} {
J:
join_op A (
A+⊥)} (
assume:
iexpr ->
bool ->
A *
query_chan ->
A+⊥).
Definition trivial_ite_assume (
e:
ite_iexpr) (
b:
bool) (
ab:
A) :
A+⊥ :=
match e,
b with
|
Leaf (
IEconst (
INz z)),
false =>
if Zfasteqb z F1 then Bot else NotBot ab
|
Leaf (
IEconst (
INz z)),
true =>
if Zfasteqb z F0 then Bot else NotBot ab
|
_,
_ =>
NotBot ab
end.
Fixpoint ite_assume (
fuel:
nat) (
e:
ite_iexpr) (
b:
bool) (
ab:
A *
query_chan) :
A+⊥ :=
match fuel with
|
O =>
ret (
fst ab)
|
S fuel =>
match e with
|
Leaf e =>
let '(
e,
b') :=
simplify_bool_expr e (
snd ab)
in
let b :=
xorb b b'
in
do ab' <-
assume e b ab;
match e with
|
IEvar _ x =>
match (
snd ab).(
get_eq_expr)
x with
|
None =>
ret ab'
|
Some e' =>
ite_assume fuel e'
b (
ab',
snd ab)
end
|
_ =>
ret ab'
end
|
Ite c et ef =>
let abtrue :=
do abtrue <-
trivial_ite_assume et b (
fst ab);
do abtrue <-
trivial_ite_assume (
Leaf c)
true abtrue;
do abtrue <-
ite_assume fuel (
Leaf c)
true (
abtrue,
snd ab);
ite_assume fuel et b (
abtrue,
snd ab)
in
let abfalse :=
do abfalse <-
trivial_ite_assume ef b (
fst ab);
do abfalse <-
trivial_ite_assume (
Leaf c)
false abfalse;
do abfalse <-
ite_assume fuel (
Leaf c)
false (
abfalse,
snd ab);
ite_assume fuel ef b (
abfalse,
snd ab)
in
match abtrue,
abfalse with
|
Bot,
x |
x,
Bot =>
x
|
NotBot ab1,
NotBot ab2 =>
ab1 ⊔
ab2
end
end
end.
Definition ite_assume_fuel := 20%
nat.
Global Opaque ite_assume_fuel.
Definition assume_unfold e :=
ite_assume ite_assume_fuel (
Leaf e).
Context (γ
A:
gamma_op A (
var ->
ideal_num))
(ρ:
var ->
ideal_num)
(
join_correct_ρ:
forall x y:
A, ρ ∈ (γ
x ∪ γ
y) -> ρ ∈ γ ((
x ⊔
y):
_+⊥))
(
assume_sound_ρ:
forall e (
b:
bool)
x,
ρ ∈ γ
x ->
eval_iexpr ρ
e (
INz (
if b then F1 else F0)) ->
ρ ∈ γ (
assume e b x)).
Lemma trivial_ite_assume_correct:
forall e (
b:
bool)
x,
ρ ∈ γ
x ->
eval_ite_iexpr ρ
e (
INz (
if b then F1 else F0)) ->
ρ ∈ γ (
trivial_ite_assume e b x).
Proof.
destruct e; auto. destruct i; auto. destruct b, i as [|[[|[]|]]]; auto.
intros. inv H0. inv H2. intros. inv H0. inv H2.
Qed.
Lemma ite_assume_correct:
forall fuel e (
b:
bool)
ab,
ρ ∈ γ
ab ->
eval_ite_iexpr ρ
e (
INz (
if b then F1 else F0)) ->
ρ ∈ γ (
ite_assume fuel e b ab).
Proof.
induction fuel.
simpl;
intros.
apply H.
destruct e;
simpl;
intros;
inv H0.
-
pose proof (
simplify_bool_expr_correct i _ _ H2 (
snd ab) (
proj2 H)).
destruct (
simplify_bool_expr i (
snd ab)).
specialize (
H0 _ _ eq_refl).
replace (
xorb (
Zunwrap (
if b return Zfast then F1 else F0) =? 0)
b0)
with (
negb (
xorb b b0))
in H0
by (
destruct b,
b0;
easy).
rewrite if_negb in H0.
eapply botbind_spec,
assume_sound_ρ;
eauto.
inv H0;
auto.
pose proof (
get_eq_expr_correct (
proj2 H)
id).
destruct (
get_eq_expr (
snd ab)
id);
auto.
specialize (
H0 _ eq_refl).
intros.
apply IHfuel.
split.
auto.
apply H.
congruence.
-
destruct H.
apply trivial_ite_assume_correct with (
e:=
e2) (
b:=
b)
in H;
auto.
apply eval_Leaf in H5.
eapply botbind_spec in H.
2:
intros;
eapply botbind_spec,
trivial_ite_assume_correct with (
b:=
false),
H5. 3:
eauto.
2:
intros;
eapply botbind_spec, (
IHfuel (
Leaf i)
false),
H5. 3:
instantiate (1:=(
_,
_));
split;
eauto.
2:
intros;
apply (
IHfuel e2),
H6. 2:
instantiate (1:=(
_,
_));
split;
eauto.
simpl in *.
destruct (
bind (
M:=
botlift)), (
bind (
M:=
botlift));
auto.
destruct H.
-
destruct H.
apply trivial_ite_assume_correct with (
e:=
e1) (
b:=
b)
in H;
auto.
apply eval_Leaf in H5.
eapply botbind_spec in H.
2:
intros;
eapply botbind_spec,
trivial_ite_assume_correct with (
b:=
true),
H5. 3:
eauto.
2:
intros. 2:
eapply botbind_spec, (
IHfuel (
Leaf i)
true),
H5. 3:
instantiate (1:=(
_,
_));
split;
eauto.
2:
intros;
apply (
IHfuel e1),
H6. 2:
instantiate (1:=(
_,
_));
split;
eauto.
simpl in *.
destruct (
bind (
M:=
botlift)), (
bind (
M:=
botlift));
auto.
destruct H.
Qed.
Lemma assume_unfold_correct:
forall e (
b:
bool)
ab,
ρ ∈ γ
ab ->
eval_iexpr ρ
e (
INz (
if b then F1 else F0)) ->
ρ ∈ γ (
assume_unfold e b ab).
Proof.
End assume_unfold.