Require Import Coqlib Utf8 ToString PrintPos FastArith.
Require Import Util AdomLib.
Require Import Integers.
Require Psatz.
Inductive zitv :
Type :=
|
ZITV:
Zfast ->
Zfast ->
zitv.
Instance ZitvToString :
ToString zitv :=
{
to_string i :=
let '
ZITV min max :=
i in
("[" ++
to_string min ++ "," ++
to_string max ++ "]")%
string
}.
Instance leb_zitv :
leb_op zitv :=
fun (
i1 i2:
zitv) =>
let '
ZITV min1 max1 :=
i1 in
let '
ZITV min2 max2 :=
i2 in
Zfastleb min2 min1 &&
Zfastleb max1 max2.
Lemma leb_eq:
∀
i:
zitv,
i ⊑
i =
true.
Proof.
destruct i as [[][]];
unfold leb.
simpl.
fastunwrap.
rewrite !
Z.leb_refl.
auto.
Qed.
Instance join_zitv :
join_op zitv zitv :=
fun i1 i2 =>
let '
ZITV min1 max1 :=
i1 in
let '
ZITV min2 max2 :=
i2 in
match Zfastcompare min1 min2,
Zfastcompare max1 max2 with
| (
Lt |
Eq), (
Eq |
Gt) =>
i1
| (
Eq |
Gt),
Lt |
Gt,
Eq =>
i2
|
Lt,
Lt =>
ZITV min1 max2
|
Gt,
Gt =>
ZITV min2 max1
end.
Lemma join_eq:
∀
x:
zitv,
x ⊔
x =
x.
Proof.
Instance meet_zitv :
meet_op zitv (
zitv+⊥) :=
fun i1 i2 =>
let '
ZITV min1 max1 :=
i1 in
let '
ZITV min2 max2 :=
i2 in
match Zfastcompare min1 min2,
Zfastcompare max1 max2 with
| (
Eq |
Gt), (
Lt |
Eq) =>
NotBot i1
| (
Lt |
Eq),
Gt |
Lt,
Eq =>
NotBot i2
|
Gt,
Gt =>
if Zfastleb min1 max2 then NotBot (
ZITV min1 max2)
else Bot
|
Lt,
Lt =>
if Zfastleb min2 max1 then NotBot (
ZITV min2 max1)
else Bot
end.
Definition widening_hints :
list Zfast :=
(-
Z.shiftl 1 63 :
Zfast) ::
(-
Z.shiftl 1 31 :
Zfast) ::
(-
Z.shiftl 1 15 :
Zfast) ::
(-
Z.shiftl 1 7 :
Zfast) ::
(
F0:
Zfast) :: (
F1:
Zfast) ::
(
Z.shiftl 1 7 - 1 :
Zfast) ::
(
Z.shiftl 1 8 - 1 :
Zfast) ::
(
Z.shiftl 1 15 - 1 :
Zfast) ::
(
Z.shiftl 1 16 - 1 :
Zfast) ::
(
Z.shiftl 1 31 - 1 :
Zfast) ::
(
Z.shiftl 1 32 - 1 :
Zfast) ::
(
Z.shiftl 1 63 - 1 :
Zfast) ::
nil.
Definition widening_hints_rev :
list Zfast :=
List.rev_append widening_hints nil.
Definition next_larger z :=
List.find (
Zfastleb z)
widening_hints.
Lemma next_larger_larger:
∀
n m,
next_larger n =
Some m ->
n <=
m.
Proof.
Definition next_smaller z :=
List.find (
fun x =>
Zfastleb x z)
widening_hints_rev.
Lemma next_smaller_smaller:
∀
n m,
next_smaller n =
Some m ->
m <=
n.
Proof.
Definition widen_zitv i1 i2 :=
let '
ZITV min1 max1 :=
i1 in
let '
ZITV min2 max2 :=
i2 in
let lemin :=
Zfastleb min1 min2 in
let lemax :=
Zfastleb max2 max1 in
if lemin &&
lemax then Just i1
else
let min :=
if lemin then Some min1
else next_smaller min2
in
let max :=
if lemax then Some max1
else next_larger max2
in
match min,
max with
|
Some min,
Some max =>
Just (
ZITV min max)
|
_,
_ =>
All
end.
Lemma widen_eq:
∀
x:
zitv,
widen_zitv x x =
Just x.
Proof.
Instance gamma_zitv :
gamma_op zitv Z :=
fun i v =>
let '
ZITV m M :=
i in m <=
v <=
M.
Instance leb_zitv_correct :
leb_op_correct zitv Z.
Proof.
intros [[?][?]] [[?][?]].
unfold leb.
simpl.
fastunwrap.
destruct (
Z.leb_spec x1 x), (
Z.leb_spec x0 x2);
try discriminate.
intros;
Psatz.lia.
Qed.
Instance join_zitv_correct :
join_op_correct zitv zitv Z.
Proof.
intros [[?][?]] [[?][?]] ? [[? ?]|[? ?]];
unfold join;
simpl;
fastunwrap;
destruct (
Z.compare_spec x x1), (
Z.compare_spec x0 x2);
split;
simpl in *;
Psatz.lia.
Qed.
Lemma widen_incr:
∀
ab1 ab2, γ
ab1 ⊆ γ (
widen_zitv ab1 ab2).
Proof.
Instance meet_zitv_correct:
meet_op_correct zitv (
zitv+⊥)
Z.
Proof.
intros [[
mx] [
Mx]] [[
my] [
My]]
z Hz;
simpl in *;
unfold meet;
simpl;
fastunwrap.
destruct Hz as [[][]];
fastunwrap.
destruct (
Zcompare_spec mx my), (
Zcompare_spec Mx My);
try (
split;
simpl;
Psatz.lia).
destruct (
Z.leb_spec my Mx);
try (
split;
simpl;
Psatz.lia).
Psatz.lia.
destruct (
Z.leb_spec mx My);
try (
split;
simpl;
Psatz.lia).
Psatz.lia.
Qed.
Definition forward_neg (
x:
zitv+⊤) :
zitv+⊤ :=
match x with
|
Just (
ZITV mx Mx) =>
Just (
ZITV (
Zfastopp Mx) (
Zfastopp mx))
|
All =>
All
end.
Lemma forward_neg_correct:
∀
x x_ab,
x ∈ γ
x_ab -> (-
x) ∈ γ (
forward_neg x_ab) .
Proof.
intros x [|[[mx] [Mx]]] Hx; simpl in *; intuition.
Qed.
Definition forward_mult (
x y:
zitv+⊤) :
zitv+⊤+⊥ :=
match x,
y with
|
Just (
ZITV mx Mx),
Just (
ZITV my My) =>
let b1 :=
Zfastmul mx my in let b2 :=
Zfastmul mx My in
let b3 :=
Zfastmul Mx my in let b4 :=
Zfastmul Mx My in
NotBot (
Just (
ZITV (
Zfastmin (
Zfastmin b1 b4) (
Zfastmin b3 b2))
(
Zfastmax (
Zfastmax b1 b4) (
Zfastmax b3 b2))))
|
All,
Just (
ZITV m M) |
Just (
ZITV m M),
All =>
if (
Zfasteqb m F0 &&
Zfasteqb M F0)
then NotBot (
Just (
ZITV F0 F0))
else NotBot All
|
All,
All =>
NotBot All
end.
Lemma Mult_interval_correct_min_max :
forall a b c d x y :
Z,
a <=
x <=
b ->
c <=
y <=
d ->
Zmin (
Zmin (
a*
c) (
b*
d)) (
Zmin (
b*
c) (
a*
d)) <=
x *
y
<=
Zmax (
Zmax (
a*
c) (
b*
d)) (
Zmax (
b*
c) (
a*
d)).
Proof.
Lemma forward_mult_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
(
x *
y)%
Z ∈ γ (
forward_mult x_ab y_ab).
Proof.
intros x [|[[
mx] [
Mx]]]
Hx y [|[[
my] [
My]]]
Hy;
simpl in Hx,
Hy.
-
tauto.
-
destruct my,
My;
simpl;
try tauto.
Psatz.nia.
-
destruct mx,
Mx;
simpl;
try tauto.
Psatz.nia.
-
destruct mx,
Mx;
unfold forward_mult;
fastunwrap;
apply Mult_interval_correct_min_max;
auto.
Qed.
Definition forward_div_pos (
x:
zitv+⊤) (
my My:
Zfast) :
zitv+⊤ :=
match x with
|
Just (
ZITV mx Mx) =>
Just (
ZITV (
Zfastquot mx (
if Zfastleb F0 mx then My else my))
(
Zfastquot Mx (
if Zfastleb F0 Mx then my else My)))
|
All =>
All
end.
Lemma Zquot_le_compat_l_neg:
∀
p q r :
Z,
p < 0 -> 0 <
q <=
r ->
p ÷
q <=
p ÷
r.
Proof.
Lemma forward_div_pos_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y my My, 0 <
my /\
my <=
y <=
My ->
(
x ÷
y) ∈ γ (
forward_div_pos x_ab my My).
Proof.
Definition forward_div_neg (
x:
zitv+⊤) (
my My:
Zfast) :
zitv+⊤ :=
forward_neg (
forward_div_pos x (
Zfastopp My) (
Zfastopp my)).
Lemma forward_div_neg_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y my My,
My < 0 /\
my <=
y <=
My ->
(
x ÷
y) ∈ γ (
forward_div_neg x_ab my My).
Proof.
Definition forward_div (
x y:
zitv+⊤) :
zitv+⊤+⊥ :=
if y ⊑
Just (
ZITV F0 F0)
then Bot
else if x ⊑
Just (
ZITV F0 F0)
then NotBot (
Just (
ZITV F0 F0))
else match y with
|
All =>
NotBot All
|
Just (
ZITV my My) =>
let p :=
if Zfastleb My F0 then Bot
else NotBot (
forward_div_pos x (
Zfastmax F1 my)
My)
in
let n :=
if Zfastleb F0 my then Bot
else NotBot (
forward_div_neg x my (
Zfastmin Fm1 My))
in p ⊔
n
end.
Lemma forward_div_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
y ≠ 0 ->
(
x ÷
y) ∈ γ (
forward_div x_ab y_ab).
Proof.
Definition forward_mod_pos_pos (
x:
zitv+⊤) (
my My:
Zfast) :
zitv+⊤+⊥ :=
match x with
|
All =>
NotBot (
Just (
ZITV F0 (
Zfastsub My F1)))
|
Just (
ZITV mx Mx) =>
if Zfastleb F0 Mx then
if (
if Zfasteqb mx Mx then Zfasteqb my My else false)
then
let m :=
Zfastmod mx my in
NotBot (
Just (
ZITV m m))
else
NotBot (
Just (
ZITV (
if Zfastleb my Mx then F0 else Zfastmax F0 mx)
(
Zfastmin (
Zfastsub My F1)
Mx)))
else Bot
end.
Lemma forward_mod_pos_pos_correct:
∀
x x_ab,
x ∈ γ
x_ab -> 0 <=
x ->
∀
y my My, 0 <
my /\
my <=
y <=
My ->
(
Z.rem x y) ∈ γ (
forward_mod_pos_pos x_ab my My).
Proof.
intros x x_ab Hx Hxpos [|
y|]
my My Hy;
unfold forward_mod_pos_pos;
fastunwrap;
try (
exfalso;
Psatz.lia).
assert (0 <=
Z.rem x (
Zpos y) <=
My - 1).
{
pose proof (
Zquot.Zrem_lt_pos_pos x (
Z.pos y)).
Psatz.lia. }
destruct x_ab as [|[[
mx] [
Mx]]].
assumption.
fastunwrap.
simpl.
pose proof (
Zle_cases 0
Mx).
destruct (0 <=?
Mx); [|
simpl in *;
Psatz.lia].
case_eq (
if mx =?
Mx then my =?
My else false).
+
case Z.eqb_spec. 2:
intros;
eq_some_inv.
intros ->.
case Z.eqb_spec. 2:
intros;
eq_some_inv.
intros ->.
intros _.
simpl in *.
assert (
x =
Mx)
by Psatz.lia.
subst Mx.
assert (
Zpos y =
My)
by Psatz.lia.
subst My.
rewrite !
Z.rem_mod_nonneg by Psatz.lia.
Psatz.lia.
+
intros _.
simpl in Hx.
split.
-
pose proof (
Zle_cases my Mx).
destruct (
my <=?
Mx);
simpl.
Psatz.lia.
apply Z.max_case_strong.
Psatz.lia.
rewrite Z.rem_small.
Psatz.lia.
split.
auto.
Psatz.lia.
-
apply Z.min_case_strong.
simpl in *.
Psatz.lia.
intro.
pose proof (
Z.rem_le x (
Zpos y)).
simpl in *.
Psatz.lia.
Qed.
Definition forward_mod_pos (
x:
zitv+⊤) (
my My:
Zfast) :
zitv+⊤+⊥ :=
forward_mod_pos_pos x my My ⊔
fmap forward_neg (
forward_mod_pos_pos (
forward_neg x)
my My).
Lemma forward_mod_pos_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y my My, 0 <
my /\
my <=
y <=
My ->
(
Z.rem x y) ∈ γ (
forward_mod_pos x_ab my My).
Proof.
Definition forward_mod_neg (
x:
zitv+⊤) (
my My:
Zfast) :
zitv+⊤+⊥ :=
forward_mod_pos x (
Zfastopp My) (
Zfastopp my).
Lemma forward_mod_neg_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y my My,
My < 0 /\
my <=
y <=
My ->
(
Z.rem x y) ∈ γ (
forward_mod_neg x_ab my My).
Proof.
intros x x_ab Hx [| |
y]
my My Hy;
try (
exfalso;
Psatz.lia).
rewrite <-
Z.rem_opp_r'.
eapply forward_mod_pos_correct.
auto.
fastunwrap.
Psatz.lia.
Qed.
Definition forward_mod (
x y:
zitv+⊤) :
zitv+⊤+⊥ :=
if y ⊑
Just (
ZITV F0 F0)
then Bot
else match y with
|
All =>
match x with
|
All =>
NotBot All
|
Just (
ZITV mx Mx) =>
let M :=
Zfast_of_Nfast (
Nfastmax (
Zfastabs mx) (
Zfastabs Mx))
in
NotBot (
Just (
ZITV (
Zfastopp M)
M))
end
|
Just (
ZITV my My) =>
let p :=
if Zfastleb My F0 then Bot
else forward_mod_pos x (
Zfastmax F1 my)
My
in
let n :=
if Zfastleb F0 my then Bot
else forward_mod_neg x my (
Zfastmin Fm1 My)
in p ⊔
n
end.
Lemma forward_mod_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
y ≠ 0 ->
(
Z.rem x y) ∈ γ (
forward_mod x_ab y_ab).
Proof.
Definition forward_lnot (
x:
zitv+⊤) :
zitv+⊤ :=
match x with
|
Just (
ZITV mx Mx) =>
Just (
ZITV (
Zfastsub Fm1 Mx) (
Zfastsub Fm1 mx))
|
All =>
All
end.
Lemma forward_lnot_correct:
∀
x x_ab,
x ∈ γ
x_ab -> (
Z.lnot x) ∈ γ (
forward_lnot x_ab) .
Proof.
intros x [|[[
mx] [
Mx]]]
Hx.
auto.
unfold forward_lnot,
Z.lnot.
fastunwrap.
simpl Z.of_N.
split;
destruct Hx;
fastunwrap;
omega.
Qed.
Lemma le_common_bits :
∀
m p M, (
m <=
p <=
M)%
N ->
∀
i, (
N.size (
N.lxor m M) <=
i)%
N ->
N.testbit m i =
N.testbit p i /\
N.testbit p i =
N.testbit M i.
Proof.
Definition forward_and_pos (
mx Mx my My:
Nfast) :
Nfast *
Nfast :=
let cx :=
N.size (
Nfastlxor mx Mx)
in
let cy :=
N.size (
Nfastlxor my My)
in
let c :=
Nfastmax cx cy in
let onesc :=
Nfastones c in
let high:
Nfast :=
Nfastldiff (
Nfastland mx my)
onesc in
(
high,
Nfastlor high (
Nfastmin (
Nfastland Mx onesc) (
Nfastland My onesc))).
Lemma forward_and_pos_correct:
∀
mx x Mx, (
mx <=
x <=
Mx)%
N ->
∀
my y My, (
my <=
y <=
My)%
N ->
∀
r R,
forward_and_pos mx Mx my My = (
r,
R) ->
(
r <=
N.land x y <=
R)%
N.
Proof.
unfold forward_and_pos;
intros.
rewrite Nfastldiff_Nldiff,
Nfastones_Nones in H1.
fastunwrap.
inv H1.
fastunwrap.
set (
mask:=(
N.ones (
N.max (
N.size (
N.lxor mx Mx)) (
N.size (
N.lxor my My))))).
assert (
N.ldiff (
N.land mx my)
mask =
N.ldiff (
N.land x y)
mask).
{
apply N.bits_inj;
intro.
rewrite !
N.ldiff_spec, !
N.land_spec.
destruct (
N.le_gt_cases (
N.max (
N.size (
N.lxor mx Mx)) (
N.size (
N.lxor my My)))
n).
-
f_equal.
f_equal;
(
eapply proj1,
le_common_bits; [
eauto|];
revert H1;
apply N.max_case_strong;
intros;
Psatz.lia).
-
unfold mask;
rewrite N.ones_spec_low by trivial.
repeat (
destruct N.testbit;
try reflexivity). }
assert (∀
a b c,
a <=
b ->
a <=
c ->
b-
a <=
c-
a ->
a <=
b <=
c)%
N by (
intros;
Psatz.lia).
apply H2;
clear H2.
-
apply N.ldiff_le,
N.bits_inj_0;
intro.
rewrite H1, !
N.ldiff_spec, !
N.land_spec;
simpl.
repeat (
destruct N.testbit;
try reflexivity).
-
apply N.ldiff_le,
N.bits_inj_0;
intro.
simpl.
rewrite !
N.ldiff_spec,
N.lor_spec,
N.ldiff_spec;
simpl.
repeat (
destruct N.testbit;
try reflexivity).
-
rewrite H1, !
N.sub_nocarry_ldiff.
+
assert (
N.land (
N.land x y)
mask <=
N.min (
N.land Mx mask) (
N.land My mask))%
N.
{
apply N.le_trans with (
N.min (
N.land x mask) (
N.land y mask)).
apply N.min_glb;
zify;
apply Int.Ztestbit_le;
trivial;
intros i Hi;
rewrite !
Z2N.inj_testbit, !
N.land_spec in *
by trivial;
repeat (
destruct N.testbit;
try (
simpl;
congruence)).
apply N.min_le_compat.
-
assert (
N.ldiff x mask =
N.ldiff Mx mask).
{
apply N.bits_inj;
intro.
rewrite !
N.ldiff_spec.
destruct (
N.le_gt_cases (
N.max (
N.size (
N.lxor mx Mx)) (
N.size (
N.lxor my My)))
n).
-
f_equal.
eapply proj2,
le_common_bits.
eauto.
revert H2;
apply N.max_case_strong;
intros;
Psatz.lia.
-
unfold mask;
rewrite N.ones_spec_low by trivial.
repeat (
destruct N.testbit;
try reflexivity). }
apply proj2 in H.
rewrite <-
N.lor_ldiff_and with (
a:=
x) (
b:=
mask)
in H.
rewrite <-
N.lor_ldiff_and with (
a:=
Mx) (
b:=
mask)
in H.
rewrite <- !
N.lxor_lor, <- !
N.add_nocarry_lxor in H;
try now (
apply N.bits_inj_0;
intro;
rewrite !
N.land_spec,
N.ldiff_spec;
repeat (
destruct N.testbit;
try reflexivity)).
Psatz.lia.
-
assert (
N.ldiff y mask =
N.ldiff My mask).
{
apply N.bits_inj;
intro.
rewrite !
N.ldiff_spec.
destruct (
N.le_gt_cases (
N.max (
N.size (
N.lxor mx Mx)) (
N.size (
N.lxor my My)))
n).
-
f_equal.
eapply proj2,
le_common_bits.
eauto.
revert H2;
apply N.max_case_strong;
intros;
Psatz.lia.
-
unfold mask;
rewrite N.ones_spec_low by trivial.
repeat (
destruct N.testbit;
try reflexivity). }
apply proj2 in H0.
rewrite <-
N.lor_ldiff_and with (
a:=
y) (
b:=
mask)
in H0.
rewrite <-
N.lor_ldiff_and with (
a:=
My) (
b:=
mask)
in H0.
rewrite <- !
N.lxor_lor, <- !
N.add_nocarry_lxor in H0;
try now (
apply N.bits_inj_0;
intro;
rewrite !
N.land_spec,
N.ldiff_spec;
repeat (
destruct N.testbit;
try reflexivity)).
Psatz.lia. }
match goal with H:(?
a <= ?
b)%
N |- (?
a' <= ?
b')%
N =>
replace a'
with a; [
replace b'
with b|]
end.
trivial.
*
apply N.min_case;
apply N.bits_inj;
intro;
simpl;
rewrite !
N.ldiff_spec,
N.lor_spec,
N.ldiff_spec, !
N.land_spec;
repeat (
destruct N.testbit;
try reflexivity).
*
apply N.bits_inj;
intro;
simpl;
rewrite !
N.ldiff_spec, !
N.land_spec;
repeat (
destruct N.testbit;
try reflexivity).
+
apply N.bits_inj;
intro;
simpl;
rewrite !
N.ldiff_spec, !
N.lor_spec,
N.ldiff_spec;
repeat (
destruct N.testbit;
try reflexivity).
+
apply N.bits_inj_0;
intro;
simpl;
rewrite !
N.ldiff_spec;
repeat (
destruct N.testbit;
try reflexivity).
Qed.
Definition forward_or_pos (
mx Mx my My:
Nfast) :
Nfast *
Nfast :=
let N :=
Nfastones (
Nfastmax (
N.size Mx) (
N.size My))
in
let (
m,
M) :=
forward_and_pos (
Nfastldiff N Mx) (
Nfastldiff N mx)
(
Nfastldiff N My) (
Nfastldiff N my)
in
(
Nfastldiff N M,
Nfastldiff N m)%
N.
Lemma forward_or_pos_correct:
∀
mx x Mx, (
mx <=
x <=
Mx)%
N ->
∀
my y My, (
my <=
y <=
My)%
N ->
∀
r R,
forward_or_pos mx Mx my My = (
r,
R) ->
(
r <=
N.lor x y <=
R)%
N.
Proof.
intros.
unfold forward_or_pos in H1.
rewrite !
Nfastldiff_Nldiff,
Nfastones_Nones in H1.
fastunwrap.
set (
N :=
N.ones (
N.max (
N.size Mx) (
N.size My)))
in *.
assert (∀
x y,
x <=
y ->
N.size x <=
N.size y)%
N.
{
intros.
destruct x0,
y0;
auto.
rewrite !
N.size_log2 by discriminate.
apply ->
N.succ_le_mono.
apply N.log2_le_mono,
H2. }
assert (∀
n,
N.size n <=
N.max (
N.size Mx) (
N.size My) ->
N.ldiff n N = 0)%
N.
{
intros.
apply N.bits_inj_0.
intros.
rewrite N.ldiff_spec.
destruct (
N.leb_spec (
N.size n)
n0).
-
apply (
N.pow_le_mono_r 2)
in H4. 2:
Psatz.lia.
pose proof (
N.size_gt n).
assert (
n < 2^
n0)%
N by Psatz.lia.
apply N.div_small in H6.
pose proof N.testbit_spec'
n n0.
rewrite H6 in H7.
destruct N.testbit.
discriminate.
auto.
-
unfold N.
rewrite N.ones_spec_low.
destruct N.testbit;
auto.
Psatz.lia. }
destruct (
forward_and_pos (
N.ldiff N Mx) (
N.ldiff N mx)
(
N.ldiff N My) (
N.ldiff N my))
eqn:
EQ.
rewrite !
Nfastldiff_Nldiff in H1.
inv H1.
pose proof EQ.
apply forward_and_pos_correct with (
x:=
N.ldiff N x) (
y:=
N.ldiff N y)
in H1.
-
rewrite <- !
N.sub_nocarry_ldiff.
replace (
N.lor x y)
with (
N.ldiff N (
N.land (
N.ldiff N x) (
N.ldiff N y))).
rewrite <-
N.sub_nocarry_ldiff.
fastunwrap.
Psatz.lia.
+
apply N.bits_inj_0.
intros.
rewrite N.ldiff_spec,
N.land_spec, !
N.ldiff_spec.
destruct N.testbit,
N.testbit,
N.testbit;
auto.
+
apply N.bits_inj.
intro.
rewrite N.ldiff_spec,
N.land_spec,
N.lor_spec, !
N.ldiff_spec.
destruct (
N.leb_spec (
N.max (
N.size Mx) (
N.size My))
n1);
unfold N.
2:
rewrite N.ones_spec_low by auto;
destruct N.testbit,
N.testbit;
now auto.
rewrite N.ones_spec_high by auto.
symmetry.
apply orb_false_intro.
*
apply N.max_lub_l, (
N.pow_le_mono_r 2)
in H4. 2:
Psatz.lia.
pose proof (
N.size_gt Mx).
assert (
x < 2 ^
n1)%
N by Psatz.lia.
apply N.div_small in H6.
apply N.b2n_inj.
rewrite N.testbit_spec',
H6.
auto.
*
apply N.max_lub_r, (
N.pow_le_mono_r 2)
in H4. 2:
Psatz.lia.
pose proof (
N.size_gt My).
assert (
y < 2 ^
n1)%
N by Psatz.lia.
apply N.div_small in H6.
apply N.b2n_inj.
rewrite N.testbit_spec',
H6.
auto.
+
clear H1.
inv EQ.
fastunwrap.
apply N.bits_inj_0.
intros.
rewrite !
N.ldiff_spec,
N.land_spec, !
N.ldiff_spec.
destruct (
N.testbit N n).
apply andb_false_r.
auto.
+
clear H1.
inv EQ.
fastunwrap.
apply N.bits_inj_0.
intros.
apply N.min_case;
rewrite !
N.ldiff_spec,
N.lor_spec, !
N.land_spec,
N.ldiff_spec,
N.land_spec,
!
N.ldiff_spec;
destruct (
N.testbit N n);
auto using andb_false_r.
-
rewrite <- !
N.sub_nocarry_ldiff;
try (
apply H3;
etransitivity; [|
apply N.le_max_l];
apply H2);
Psatz.lia.
-
rewrite <- !
N.sub_nocarry_ldiff;
try (
apply H3;
etransitivity; [|
apply N.le_max_r];
apply H2);
Psatz.lia.
Qed.
Definition forward_diff_pos (
mx Mx my My:
Nfast) :
Nfast *
Nfast :=
let N :=
Nfastones (
Nfastmax (
N.size Mx) (
N.size My))
in
forward_and_pos mx Mx (
Nfastldiff N My) (
Nfastldiff N my).
Lemma forward_diff_pos_correct:
∀
mx x Mx, (
mx <=
x <=
Mx)%
N ->
∀
my y My, (
my <=
y <=
My)%
N ->
∀
r R,
forward_diff_pos mx Mx my My = (
r,
R) ->
(
r <=
N.ldiff x y <=
R)%
N.
Proof.
Definition positive_part (
i:
zitv+⊤) :
zitv+⊤+⊥ :=
match i with
|
Just (
ZITV x y) =>
if Zfastleb F0 y then NotBot (
Just (
ZITV (
Zfastmax F0 x)
y))
else Bot
|
All =>
NotBot All
end.
Lemma positive_part_correct:
∀
i n,
n ∈ γ
i -> 0 <=
n ->
n ∈ γ (
positive_part i).
Proof.
destruct i as [|[[] []]];
simpl;
intros.
auto.
fastunwrap.
simpl.
destruct (
Z.leb_spec 0
x0).
split;
simpl in *;
Psatz.lia.
Psatz.lia.
Qed.
Definition pos_bind fJJ fJA fAJ x y :
zitv+⊤+⊥ :=
do x <-
positive_part x;
do y <-
positive_part y;
match x,
y return zitv+⊤+⊥
with
|
Just (
ZITV mx Mx),
Just (
ZITV my My) =>
let '(
m,
M) :=
fJJ (
Nfast_of_Zfast mx) (
Nfast_of_Zfast Mx)
(
Nfast_of_Zfast my) (
Nfast_of_Zfast My)
in
NotBot (
Just (
ZITV (
Zfast_of_Nfast m) (
Zfast_of_Nfast M)))
|
Just (
ZITV mx Mx),
All =>
match fJA (
Nfast_of_Zfast mx) (
Nfast_of_Zfast Mx)
with
|
None =>
NotBot All
|
Some (
m,
M) =>
NotBot (
Just (
ZITV (
Zfast_of_Nfast m) (
Zfast_of_Nfast M)))
end
|
All,
Just (
ZITV my My) =>
match fAJ (
Nfast_of_Zfast my) (
Nfast_of_Zfast My)
with
|
None =>
NotBot All
|
Some (
m,
M) =>
NotBot (
Just (
ZITV (
Zfast_of_Nfast m) (
Zfast_of_Nfast M)))
end
|
All,
All =>
NotBot All
end.
Lemma pos_bind_spec:
∀
x_ab x,
Z.of_N x ∈ γ
x_ab ->
∀
y_ab y,
Z.of_N y ∈ γ
y_ab ->
∀ (
fJJ:
Nfast ->
Nfast ->
Nfast ->
Nfast ->
Nfast *
Nfast)
(
fAJ fJA:
Nfast ->
Nfast ->
option (
Nfast *
Nfast))
f,
(∀
mx x Mx, (
mx <=
x <=
Mx)%
N ->
∀
my y My, (
my <=
y <=
My)%
N ->
∀
r R,
fJJ mx Mx my My = (
r,
R) ->
(
r <=
f x y <=
R)%
N) ->
(∀
mx x Mx, (
mx <=
x <=
Mx)%
N ->
∀
y r R,
fJA mx Mx =
Some (
r,
R) ->
(
r <=
f x y <=
R)%
N) ->
(∀
x my y My, (
my <=
y <=
My)%
N ->
∀
r R,
fAJ my My =
Some (
r,
R) ->
(
r <=
f x y <=
R)%
N) ->
Z.of_N (
f x y) ∈ γ (
pos_bind fJJ fJA fAJ x_ab y_ab).
Proof.
Definition forward_land (
x y:
zitv+⊤) :
zitv+⊤+⊥ :=
pos_bind forward_and_pos (
fun _ M =>
Some (
F0,
M))
(
fun _ M =>
Some (
F0,
M))
x y ⊔
pos_bind forward_diff_pos (
fun _ M =>
Some (
F0,
M))
(
fun _ _ =>
None)
x (
forward_lnot y) ⊔
pos_bind forward_diff_pos (
fun _ M =>
Some (
F0,
M))
(
fun _ _ =>
None)
y (
forward_lnot x) ⊔
fmap forward_lnot
(
pos_bind forward_or_pos (
fun _ _ =>
None) (
fun _ _ =>
None)
(
forward_lnot x) (
forward_lnot y)).
Lemma forward_land_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
Z.land x y ∈ γ (
forward_land x_ab y_ab).
Proof.
intros.
unfold forward_land.
assert (∀
x, ∃
x',
x =
Z.of_N x' \/
x =
Z.lnot (
Z.of_N x')).
{
intro.
unfold Z.lnot.
destruct x0.
-
exists 0%
N.
eauto.
-
eexists (
Npos _).
simpl.
eauto.
-
eexists (
Npos p - 1)%
N.
zify.
omega. }
destruct (
H1 x)
as [
x' []], (
H1 y)
as [
y' []];
subst.
-
replace (
Z.land (
Z.of_N x') (
Z.of_N y'))
with (
Z.of_N (
N.land x'
y'))
by (
destruct x',
y';
reflexivity).
apply join_correct.
left.
apply join_correct.
left.
apply join_correct.
left.
apply pos_bind_spec;
auto.
+
apply forward_and_pos_correct.
+
intros.
inv H3.
split.
simpl.
Psatz.lia.
transitivity x;
try (
simpl;
Psatz.lia).
zify.
apply Int.Ztestbit_le.
auto.
intros i Hi.
rewrite !
Z2N.inj_testbit,
N.land_spec,
Bool.andb_true_iff by auto.
now intuition.
+
intros.
inv H3.
split.
simpl.
Psatz.lia.
transitivity y;
try (
simpl;
Psatz.lia).
zify.
apply Int.Ztestbit_le.
auto.
intros i Hi.
rewrite !
Z2N.inj_testbit,
N.land_spec,
Bool.andb_true_iff by auto.
now intuition.
-
assert (γ (
forward_lnot y_ab) (
Z.of_N y')).
{
rewrite <-
Z.lnot_involutive with (
Z.of_N y').
auto using forward_lnot_correct. }
replace (
Z.land (
Z.of_N x') (
Z.lnot (
Z.of_N y')))
with (
Z.of_N (
N.ldiff x'
y'))
by (
destruct x',
y';
try reflexivity;
simpl;
replace (
Pos.pred_N (
p0 + 1))
with (
Npos p0); [
reflexivity|];
rewrite Pos.add_1_r,
Pos.pred_N_succ;
reflexivity).
apply join_correct.
left.
apply join_correct.
left.
apply join_correct.
right.
apply pos_bind_spec;
auto.
+
apply forward_diff_pos_correct.
+
intros.
inv H4.
split.
simpl.
Psatz.lia.
transitivity x;
try (
simpl;
Psatz.lia).
zify.
apply Int.Ztestbit_le.
auto.
intros i Hi.
rewrite !
Z2N.inj_testbit,
N.ldiff_spec,
Bool.andb_true_iff by auto.
now intuition.
+
discriminate.
-
assert (γ (
forward_lnot x_ab) (
Z.of_N x')).
{
rewrite <-
Z.lnot_involutive with (
Z.of_N x').
auto using forward_lnot_correct. }
replace (
Z.land (
Z.lnot (
Z.of_N x')) (
Z.of_N y'))
with (
Z.of_N (
N.ldiff y'
x'))
by (
destruct x',
y';
try reflexivity;
simpl;
replace (
Pos.pred_N (
p + 1))
with (
Npos p); [
reflexivity|];
rewrite Pos.add_1_r,
Pos.pred_N_succ;
reflexivity).
apply join_correct.
left.
apply join_correct.
right.
apply pos_bind_spec;
auto.
+
apply forward_diff_pos_correct.
+
intros.
inv H4.
split.
simpl.
Psatz.lia.
transitivity x;
try (
simpl;
Psatz.lia).
zify.
apply Int.Ztestbit_le.
auto.
intros i Hi.
rewrite !
Z2N.inj_testbit,
N.ldiff_spec,
Bool.andb_true_iff by auto.
now intuition.
+
discriminate.
-
assert (γ (
forward_lnot x_ab) (
Z.of_N x')).
{
rewrite <-
Z.lnot_involutive with (
Z.of_N x').
auto using forward_lnot_correct. }
assert (γ (
forward_lnot y_ab) (
Z.of_N y')).
{
rewrite <-
Z.lnot_involutive with (
Z.of_N y').
auto using forward_lnot_correct. }
replace (
Z.land (
Z.lnot (
Z.of_N x')) (
Z.lnot (
Z.of_N y')))
with (
Z.lnot (
Z.of_N (
N.lor x'
y')))
by (
rewrite <-
Z.lnot_lor;
destruct x',
y';
reflexivity).
apply join_correct.
right.
eapply botbind_spec.
intros.
apply forward_lnot_correct,
H4.
apply pos_bind_spec;
auto.
+
apply forward_or_pos_correct.
+
discriminate.
+
discriminate.
Qed.
Definition forward_lor (
x y:
zitv+⊤) :
zitv+⊤+⊥ :=
fmap forward_lnot (
forward_land (
forward_lnot x) (
forward_lnot y)).
Lemma forward_lor_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
Z.lor x y ∈ γ (
forward_lor x_ab y_ab).
Proof.
Definition forward_lxor (
x y:
zitv+⊤) :
zitv+⊤+⊥ :=
do A <-
forward_land x (
forward_lnot y);
do B <-
forward_land (
forward_lnot x)
y;
forward_lor A B.
Lemma forward_lxor_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
Z.lxor x y ∈ γ (
forward_lxor x_ab y_ab).
Proof.
Definition forward_shl (
x y:
zitv+⊤) :
zitv+⊤+⊥ :=
match x with
|
All =>
NotBot All
|
Just (
ZITV mx Mx) =>
if (
Zfastleb F0 mx &&
Zfastleb Mx F0)%
bool then NotBot (
Just (
ZITV F0 F0))
else
match y with
|
All =>
NotBot All
|
Just (
ZITV my My) =>
if (
Zfastleb (
Zfastopp F64)
my &&
Zfastleb My F64)%
bool then
NotBot (
Just (
ZITV (
Zfastshl mx (
if Zfastleb F0 mx then my else My))
(
Zfastshl Mx (
if Zfastleb F0 Mx then My else my))))
else
NotBot All
end
end.
Lemma forward_shl_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
Z.shiftl x y ∈ γ (
forward_shl x_ab y_ab).
Proof.
intros.
destruct x_ab as [|[]];
unfold forward_shl.
tauto.
fastunwrap.
simpl.
destruct ((0 <=?
z) && (
z0 <=? 0))%
bool eqn:
EQ.
-
rewrite Bool.andb_true_iff in EQ.
destruct (
Z.leb_spec 0
z).
destruct (
Z.leb_spec z0 0).
destruct H.
replace x with 0
by Psatz.lia.
rewrite Z.shiftl_0_l.
split;
reflexivity.
destruct EQ.
congruence.
destruct EQ.
congruence.
-
clear EQ.
destruct y_ab as [|[]].
tauto.
simpl in *.
fastunwrap.
destruct ((-64 <=?
z1) && (
z2 <=? 64))%
bool. 2:
simpl;
easy.
simpl in *.
assert (
forall a b c, 0 <=
a ->
b <=
c ->
Z.shiftl a b <=
Z.shiftl a c). {
intros.
destruct (
Z.nonpos_pos_cases b), (
Z.nonpos_pos_cases c);
try Psatz.lia.
-
rewrite !
Z.shiftl_div_pow2 by Psatz.lia.
apply Z.div_le_compat_l.
auto.
split.
apply Z.pow_pos_nonneg;
Psatz.lia.
apply Z.pow_le_mono_r;
Psatz.lia.
-
rewrite Z.shiftl_div_pow2,
Z.shiftl_mul_pow2 by Psatz.lia.
transitivity a.
assert (
a / 2 ^ (-
b) <=
a / 1).
apply Z.div_le_compat_l.
auto.
pose proof (
Z.pow_pos_nonneg 2 (-
b)).
Psatz.lia.
rewrite Zdiv_1_r in H5.
auto.
assert (
a * 1 <=
a * 2 ^
c).
apply Zmult_le_compat_l.
pose proof (
Z.pow_pos_nonneg 2
c).
Psatz.lia.
auto.
rewrite Zmult_1_r in H5.
auto.
-
rewrite !
Z.shiftl_mul_pow2 by Psatz.lia.
apply Zmult_le_compat_l.
apply Z.pow_le_mono_r;
Psatz.lia.
auto.
}
assert (
forall a b c,
a < 0 ->
b <=
c ->
Z.shiftl a c <=
Z.shiftl a b). {
intros.
destruct (
Z.nonpos_pos_cases b), (
Z.nonpos_pos_cases c);
try Psatz.lia.
-
specialize (
H1 (
Z.lnot a)
b c).
replace (
Z.shiftl (
Z.lnot a)
b)
with (
Z.lnot (
Z.shiftl a b))
in H1.
replace (
Z.shiftl (
Z.lnot a)
c)
with (
Z.lnot (
Z.shiftl a c))
in H1.
unfold Z.lnot in H1.
omega.
apply Z.bits_inj'.
intros.
rewrite Z.lnot_spec, !
Z.shiftl_spec,
Z.lnot_spec by Psatz.lia.
reflexivity.
apply Z.bits_inj'.
intros.
rewrite Z.lnot_spec, !
Z.shiftl_spec,
Z.lnot_spec by Psatz.lia.
reflexivity.
-
rewrite Z.shiftl_mul_pow2,
Z.shiftl_div_pow2 by Psatz.lia.
transitivity a.
assert ((-
a) * 1 <= (-
a) * 2 ^
c).
apply Zmult_le_compat_l.
pose proof (
Z.pow_pos_nonneg 2
c).
Psatz.lia.
Psatz.lia.
rewrite !
Z.mul_opp_l in H6.
Psatz.lia.
rewrite <-
Z.div_mul with (
a:=
a) (
b:=2^(-
b))
at 1.
apply Z.div_le_mono.
apply Z.pow_pos_nonneg;
Psatz.lia.
assert ((-
a) * 1 <= (-
a) * 2 ^ (-
b)).
apply Zmult_le_compat_l.
pose proof (
Z.pow_pos_nonneg 2 (-
b)).
Psatz.lia.
Psatz.lia.
rewrite !
Z.mul_opp_l in H6.
Psatz.lia.
pose proof (
Z.pow_pos_nonneg 2 (-
b)).
Psatz.lia.
-
rewrite !
Z.shiftl_mul_pow2 by Psatz.lia.
assert ((-
a)*2^
b <= (-
a)*2^
c).
apply Zmult_le_compat_l.
apply Z.pow_le_mono_r;
Psatz.lia.
Psatz.lia.
rewrite !
Z.mul_opp_l in H6.
Psatz.lia.
}
assert (
forall a b c,
a <=
b ->
Z.shiftl a c <=
Z.shiftl b c). {
intros.
destruct (
Z.nonpos_pos_cases c).
-
rewrite !
Z.shiftl_div_pow2 by Psatz.lia.
apply Z.div_le_mono.
apply Z.pow_pos_nonneg;
Psatz.lia.
auto.
-
rewrite !
Z.shiftl_mul_pow2 by Psatz.lia.
apply Zmult_le_compat_r.
auto.
pose proof (
Z.pow_pos_nonneg 2
c).
Psatz.lia.
}
destruct H0,
H.
split; [
pose proof (
Zle_cases 0
z)|
pose proof (
Zle_cases 0
z0)];
destruct Z.leb.
+
etransitivity.
apply H1;
eauto.
apply H3;
eauto.
+
etransitivity.
apply H2.
Psatz.lia.
eauto.
apply H3;
eauto.
+
etransitivity.
apply H3;
eauto.
apply H1;
eauto.
+
etransitivity.
apply H3;
eauto.
apply H2.
Psatz.lia.
eauto.
Qed.
Definition forward_shr (
x y:
zitv+⊤) :
zitv+⊤+⊥ :=
forward_shl x (
forward_neg y).
Lemma forward_shr_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
Z.shiftr x y ∈ γ (
forward_shr x_ab y_ab).
Proof.
Definition backward_cmp_l (
c:
comparison) (
x y:
zitv+⊤) :
zitv+⊤+⊥ :=
match c with
|
Ceq =>
match x,
y with
|
Just (
ZITV mx Mx),
Just (
ZITV my My) =>
if Zfastleb my Mx &&
Zfastleb mx My then NotBot y else Bot
|
_,
_ =>
NotBot y
end
|
Cne =>
match y with
|
Just (
ZITV my My) =>
if Zfastleb My my then
match x with
|
Just (
ZITV mx Mx) =>
if Zfastleb mx my &&
Zfastleb my mx then
if Zfastleb Mx my &&
Zfastleb my Mx then Bot
else NotBot (
Just (
ZITV (
Zfastadd mx F1)
Mx))
else
if Zfastleb Mx my &&
Zfastleb my Mx then
NotBot (
Just (
ZITV mx (
Zfastsub Mx F1)))
else NotBot All
|
All =>
NotBot All
end
else NotBot All
|
All =>
NotBot All
end
|
Cle =>
match x,
y with
|
Just (
ZITV mx _),
Just (
ZITV _ My) =>
if Zfastleb mx My then NotBot (
Just (
ZITV mx My))
else Bot
|
_,
_ =>
NotBot All
end
|
Cge =>
match x,
y with
|
Just (
ZITV _ Mx),
Just (
ZITV my _) =>
if Zfastleb my Mx then NotBot (
Just (
ZITV my Mx))
else Bot
|
_,
_ =>
NotBot All
end
|
Clt =>
match x,
y with
|
Just (
ZITV mx _),
Just (
ZITV _ My) =>
let Mx' :=
Zfastsub My F1 in
if Zfastleb mx Mx'
then NotBot (
Just (
ZITV mx Mx'))
else Bot
|
_,
_ =>
NotBot All
end
|
Cgt =>
match x,
y with
|
Just (
ZITV _ Mx),
Just (
ZITV my _) =>
let mx' :=
Zfastadd my F1 in
if Zfastleb mx'
Mx then NotBot (
Just (
ZITV mx'
Mx))
else Bot
|
_,
_ =>
NotBot All
end
end.
Definition Zcmp (
c:
comparison) (
z1 z2:
Z) :
bool :=
match c,
z1 ?=
z2 with
|
Ceq,
Eq |
Clt,
Lt |
Cgt,
Gt
|
Cle, (
Lt|
Eq) |
Cge, (
Gt|
Eq)
|
Cne, (
Lt|
Gt) =>
true
|
_,
_ =>
false
end.
Lemma backward_cmp_l_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
∀
c,
Zcmp c x y =
true ->
x ∈ γ (
backward_cmp_l c x_ab y_ab).
Proof.
intros x x_ab Hx y y_ab Hy []
Hc;
simpl in Hc;
destruct (
Zcompare_spec x y);
try discriminate;
subst;
clear Hc;
unfold backward_cmp_l;
destruct x_ab as [|[]],
y_ab as [|[]];
fastunwrap;
repeat match goal with
| |-
context [?
a <=? ?
b] =>
destruct (
Z.leb_spec a b)
end;
simpl in *;
try exact I;
try Psatz.lia.
Qed.
Definition backward_mul_pos (
res x:
zitv+⊤) (
my My:
Zfast) :
zitv+⊤+⊥ :=
match res with
|
Just (
ZITV mres Mres) =>
let mx :=
Zfastopp (
Zfastdiv (
Zfastopp mres)
(
if Zfastleb F0 mres then My else my))
in
let Mx :=
Zfastdiv Mres (
if Zfastleb F0 Mres then my else My)
in
Just (
ZITV mx Mx) ⊓
x
|
All =>
NotBot x
end.
Lemma backward_mul_pos_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y my My, 0 <
my /\
my <=
y <=
My ->
∀
res_ab, (
x *
y)%
Z ∈ γ
res_ab ->
x ∈ γ (
backward_mul_pos res_ab x_ab my My).
Proof.
Definition backward_mul_neg (
res x:
zitv+⊤) (
my My:
Zfast) :
zitv+⊤+⊥ :=
backward_mul_pos (
forward_neg res)
x (
Zfastopp My) (
Zfastopp my).
Lemma backward_mul_neg_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y my My,
My < 0 /\
my <=
y <=
My ->
∀
res_ab, (
x *
y)%
Z ∈ γ
res_ab ->
x ∈ γ (
backward_mul_neg res_ab x_ab my My).
Proof.
Definition backward_mul_0 (
res:
zitv+⊤) :
zitv+⊤+⊥ :=
if Just (
ZITV F0 F0) ⊑
res then NotBot All else Bot.
Lemma backward_mul_0_correct:
∀
x,
∀
y, 0 <=
y <= 0 ->
∀
res_ab, (
x *
y)%
Z ∈ γ
res_ab ->
x ∈ γ (
backward_mul_0 res_ab).
Proof.
intros. replace y with 0 in * by Psatz.lia.
destruct res_ab as [|[[[]] [[]]]]; simpl in *;
try reflexivity;
Psatz.lia.
Qed.
Definition backward_mul_l (
res x y:
zitv+⊤) :
zitv+⊤+⊥ :=
match y with
|
All =>
NotBot All
|
Just (
ZITV my My) =>
let p :=
if Zfastleb My F0 then Bot
else backward_mul_pos res x (
Zfastmax F1 my)
My
in
let n :=
if Zfastleb F0 my then Bot
else backward_mul_neg res x my (
Zfastmin Fm1 My)
in
let z :=
if Zfastleb my F0 &&
Zfastleb F0 My then backward_mul_0 res
else Bot
in
p ⊔
n ⊔
z
end.
Lemma backward_mul_l_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
∀
res_ab, (
x *
y)%
Z ∈ γ
res_ab ->
x ∈ γ (
backward_mul_l res_ab x_ab y_ab).
Proof.
Definition backward_or (
res x y:
zitv+⊤) : (
zitv+⊤ *
zitv+⊤)+⊥ :=
match res with
|
Just (
ZITV 0 0) =>
do x' <-
x ⊓
res;
do y' <-
y ⊓
res;
NotBot (
x',
y')
|
_ =>
NotBot (
x,
y)
end.
Lemma backward_or_correct:
∀
x x_ab,
x ∈ γ
x_ab ->
∀
y y_ab,
y ∈ γ
y_ab ->
∀
res_ab, (
Z.lor x y) ∈ γ
res_ab ->
(
x,
y) ∈ γ (
backward_or res_ab x_ab y_ab).
Proof.
unfold backward_or.
intros x x_ab H y y_ab H0 res_ab H1.
destruct res_ab as [ | [[[]] [
h]] ];
try (
split;
eauto).
destruct h;
try (
split;
eauto).
assert (
Z.lor x y = 0)
as Hz.
destruct H1;
fastunwrap;
Psatz.lia.
clear H1.
apply Z.lor_eq_0_iff in Hz.
destruct Hz.
subst x y.
assert (γ (
Just (
ZITV 0 0)) 0)
as K0.
split;
discriminate.
apply botbind_spec with 0.
intros x'
Hx'.
apply botbind_spec with 0.
intros y'
Hy'.
split;
eauto.
apply meet_correct;
split;
auto.
apply meet_correct;
split;
auto.
Qed.