aboutsummaryrefslogtreecommitdiffstats
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.