From mininix Require Import nix.wp nix.notations.
From stdpp Require Import options.
Local Open Scope Z_scope.
Definition test αs :=
let: "x" := 1 in
with: EAttr αs in
with: EAttr {[ "y" := AttrN 2 ]} in
"x" =: "y".
Example test_wp μ αs :
no_recs αs →
wp μ (test αs) (.= false).
Proof.
intros Hαs. rewrite /test. apply LetAttr_no_recs_wp.
{ by apply no_recs_insert. }
rewrite /= !map_fmap_singleton /= right_id_L lookup_singleton lookup_singleton_ne //=.
apply LetAttr_no_recs_wp.
{ by apply no_recs_attr_subst. }
rewrite /= !map_fmap_singleton /= right_id_L.
rewrite (map_fmap_compose attr_expr) lookup_fmap union_kinded_abs.
rewrite !lookup_fmap.
apply LetAttr_no_recs_wp.
{ by apply no_recs_insert. }
rewrite /= map_fmap_singleton lookup_singleton lookup_singleton_ne //=.
rewrite union_kinded_with.
apply BinOp_wp.
apply Id_wp, Lit_wp; first done. eexists; split; [constructor|].
apply Id_wp, Lit_wp; first done.
eexists; split; [done|]. by apply Lit_wp.
Qed.
Definition neg := λ: "b", if: "b" then false else true.
Lemma neg_wp μ (Φ : expr → Prop) e :
wp SHALLOW e (λ e', ∃ b : bool, e' = b ∧ Φ (negb b)) →
wp μ (neg e) Φ.
Proof.
intros Hwp. apply β_wp. rewrite /= lookup_singleton /=.
apply If_wp, Id_wp. eapply wp_mono; [done|].
intros ? (b & -> & ?). exists b; split; [done|].
destruct b; by apply Lit_wp.
Qed.
(* rec { f = x: if x = 0 then true else !(f (x - 1)); }.f n *)
Definition even_rec_attr :=
EAttr {[ "f" := AttrR (λ: "x", if: "x" =: 0 then true else neg ("f" ("x" -: 1))) ]} .: "f".
Lemma even_rec_attr_wp e n :
0 ≤ n ≤ int_max →
wp SHALLOW e (.= n) →
wp SHALLOW (even_rec_attr e) (.= Z.even n).
Proof.
intros Hn Hwp. apply App_wp.
revert e Hwp. induction (Z.lt_wf 0 n) as [n _ IH]; intros e Hwp.
apply BinOp_wp. apply Attr_wp_shallow.
eexists; split; [by constructor|].
apply Lit_wp; [done|]. eexists; split; [by eexists|].
rewrite /=. apply Abs_wp, β_wp.
rewrite /= !lookup_singleton /= !lookup_singleton_ne //=.
rewrite !union_with_None_l !union_with_None_r.
rewrite /indirects map_imap_insert map_imap_empty lookup_insert.
rewrite -/even_rec_attr -/neg.
apply If_wp, BinOp_wp, Id_wp.
eapply wp_mono; [apply Hwp|]; intros ? ->.
eexists; split; [by constructor|].
apply Lit_wp; [done|]. eexists; split; [by eexists|]. simpl.
destruct (n =? 0) eqn:Hn0; (apply Lit_wp; [done|]; eexists; split; [done|]; simpl).
{ apply Lit_wp; [done|]. by apply Z.eqb_eq in Hn0 as ->. }
apply neg_wp, App_wp, Id_wp.
eapply wp_mono; [apply (IH (n-1))|]; [lia..| |].
2:{ intros e' He'. eapply wp_mono; [apply He'|].
intros ? ->. eexists; split; [done|].
by rewrite Z.negb_even Z.sub_1_r Z.odd_pred. }
eapply BinOp_wp, Id_wp. eapply wp_mono; [apply Hwp|]. intros ? ->.
eexists; split; [by constructor|]. apply Lit_wp; [done|].
eexists; split; [eexists _, _; split_and!; [done| |done]|].
- rewrite /= option_guard_True //. apply bool_decide_pack.
rewrite /int_min Z.shiftl_mul_pow2 //. lia.
- apply Lit_wp; [|done]. apply bool_decide_pack.
rewrite /int_min Z.shiftl_mul_pow2 //. lia.
Qed.
Lemma even_rec_attr_wp' n :
0 ≤ n ≤ int_max →
wp SHALLOW (even_rec_attr n) (.= Z.even n).
Proof.
intros ?. apply even_rec_attr_wp; [done|]. apply Lit_wp; [|done].
rewrite /= /int_ok. apply bool_decide_pack.
rewrite /int_min Z.shiftl_mul_pow2 //. lia.
Qed.
(* { "__functor " = r: x: if x == 0 then true else !(r (x - 1)); } n *)
Definition even_rec_functor :=
EAttr {[ "__functor" :=
AttrN (λ: "r" "x", if: "x" =: 0 then true else neg ("r" ("x" -: 1))) ]}.
Lemma even_rec_functor_wp e n :
0 ≤ n ≤ int_max →
wp SHALLOW e (.= n) →
wp SHALLOW (even_rec_functor e) (.= Z.even n).
Proof.
intros Hn Hwp. apply App_wp.
revert e Hwp. induction (Z.lt_wf 0 n) as [n _ IH]; intros e Hwp.
apply Attr_wp_shallow. rewrite map_fmap_singleton /=. eapply Functor_wp.
{ by apply no_recs_insert. }
{ done. }
apply App_wp. apply β_wp.
rewrite /= !lookup_singleton !lookup_singleton_ne //=. apply Abs_wp, β_wp.
rewrite /= !lookup_singleton /= !lookup_singleton_ne //=.
rewrite -/even_rec_functor -/neg.
apply If_wp, BinOp_wp, Id_wp.
eapply wp_mono; [apply Hwp|]; intros ? ->.
eexists; split; [by constructor|].
apply Lit_wp; [done|]. eexists; split; [by eexists|]. simpl.
destruct (n =? 0) eqn:Hn0; (apply Lit_wp; [done|]; eexists; split; [done|]; simpl).
{ apply Lit_wp; [done|]. by apply Z.eqb_eq in Hn0 as ->. }
apply neg_wp, App_wp, Id_wp.
eapply wp_mono; [apply (IH (n-1))|]; [lia..| |].
2:{ intros e' He'. eapply wp_mono; [apply He'|].
intros ? ->. eexists; split; [done|].
by rewrite Z.negb_even Z.sub_1_r Z.odd_pred. }
eapply BinOp_wp, Id_wp. eapply wp_mono; [apply Hwp|]. intros ? ->.
eexists; split; [by constructor|]. apply Lit_wp; [done|].
eexists; split; [eexists _, _; split_and!; [done| |done]|].
- rewrite /= option_guard_True //. apply bool_decide_pack.
rewrite /int_min Z.shiftl_mul_pow2 //. lia.
- apply Lit_wp; [|done]. apply bool_decide_pack.
rewrite /int_min Z.shiftl_mul_pow2 //. lia.
Qed.
Lemma even_rec_functor_wp' n :
0 ≤ n ≤ int_max →
wp SHALLOW (even_rec_functor n) (.= Z.even n).
Proof.
intros ?. apply even_rec_functor_wp; [done|]. apply Lit_wp; [|done].
rewrite /= /int_ok. apply bool_decide_pack.
rewrite /int_min Z.shiftl_mul_pow2 //. lia.
Qed.
(* ({ f ? (x: if x == 0 then true else !(f (x - 1))) }: f) {} n *)
Definition even_rec_default :=
(λattr:
{[ "f" := Some (λ: "x", if: "x" =: 0 then true else neg ("f" ("x" -: 1))) ]}, "f")
(EAttr ∅).
Lemma even_rec_default_wp e n :
0 ≤ n ≤ int_max →
wp SHALLOW e (.= n) →
wp SHALLOW (even_rec_default e) (.= Z.even n).
Proof.
intros Hn Hwp. apply App_wp.
eapply βMatch_wp; [done|repeat econstructor|]. simplify_map_eq.
rewrite -/even_rec_attr. by apply Id_wp, App_wp, even_rec_attr_wp.
Qed.
Lemma even_rec_default_wp' n :
0 ≤ n ≤ int_max →
wp SHALLOW (even_rec_default n) (.= Z.even n).
Proof.
intros ?. apply even_rec_default_wp; [done|]. apply Lit_wp; [|done].
rewrite /= /int_ok. apply bool_decide_pack.
rewrite /int_min Z.shiftl_mul_pow2 //. lia.
Qed.