@@ -10,6 +10,7 @@ open EcSubst
1010
1111open EcMatching.Position
1212open EcCoreGoal
13+ open EcCoreFol
1314open EcLowGoal
1415open EcLowPhlGoal
1516
@@ -442,6 +443,89 @@ module Core = struct
442443 | `Right -> f_equivS (snd es.es_ml) mt (es_pr es) es.es_sl s (es_po es) in
443444 FApi. xmutate1 tc (`RndSem pos) [concl]
444445
446+ (* -------------------------------------------------------------------- *)
447+ let t_equiv_coupling_r side g tc =
448+ (* process the following pRHL goal, where g is a coupling of g1 and g2 *)
449+ (* {phi} c1; x <$ g1 ~ c2; y <$ g2 {psi} *)
450+ let env = FApi. tc1_env tc in
451+ let es = tc1_as_equivS tc in
452+ let ml = fst es.es_ml in
453+ let mr = fst es.es_mr in
454+ let (lvL, muL), sl' = tc1_last_rnd tc es.es_sl in
455+ let (lvR, muR), sr' = tc1_last_rnd tc es.es_sr in
456+ let tyL = proj_distr_ty env (e_ty muL) in
457+ let tyR = proj_distr_ty env (e_ty muR) in
458+ let muL = (EcFol. ss_inv_of_expr ml muL).inv in
459+ let muR = (EcFol. ss_inv_of_expr mr muR).inv in
460+ let g = g.inv in
461+
462+ let goal =
463+ match side with
464+ | None ->
465+ (* Goal: {phi} c1 ~ c2 {iscoupling g muL muR /\ (forall a b, (a, b) \in supp(g) => psi[x -> a, y -> b])} *)
466+ (* Generate two free variables a and b and the pair (a, b) *)
467+ let a_id = EcIdent. create " a" in
468+ let b_id = EcIdent. create " b" in
469+ let a = f_local a_id tyL in
470+ let b = f_local b_id tyR in
471+ let ab = f_tuple [a; b] in
472+
473+ (* Generate the coupling distribution type: (tyL * tyR) distr *)
474+ let coupling_ty = ttuple [tyL; tyR] in
475+ let g_app = f_app_simpl g [] (tdistr coupling_ty) in
476+
477+ let iscoupling_op = EcPath. extend EcCoreLib. p_top [" Distr" ; " iscoupling" ] in
478+ let iscoupling_ty = tfun (tdistr tyL) (tfun (tdistr tyR) (tfun (tdistr coupling_ty) tbool)) in
479+ let iscoupling_pred = f_app (f_op iscoupling_op [tyL; tyR] iscoupling_ty) [muL; muR; g_app] tbool in
480+
481+ (* Substitute in the postcondition *)
482+ let post = (es_po es) in
483+ let post_subst = subst_form_lv_left env lvL {ml= ml;mr= mr;inv= a} post in
484+ let post_subst = subst_form_lv_right env lvR {ml= ml;mr= mr;inv= b} post_subst in
485+
486+ let goal = map_ts_inv1 (f_imp (f_in_supp ab g_app)) post_subst in
487+ let goal = map_ts_inv1 (f_forall_simpl [(a_id, GTty tyL); (b_id, GTty tyR)]) goal in
488+ map_ts_inv1 (f_and iscoupling_pred) goal
489+ | Some side ->
490+ (* Goal (left): {phi} c1 ~ c2 {dmap d1 g = d2 /\
491+ forall a b, a \in supp(d1) -> b = g(a) -> psi[x -> a, y -> b]} *)
492+ (* Goal (right): {phi} c1 ~ c2 {d1 = dmap d2 g /\
493+ forall a b, b \in supp(d2) -> a = g(b) -> psi[x -> a, y -> b]} *)
494+ let dmap_op = EcPath. extend EcCoreLib. p_top [" Distr" ; " dmap" ] in
495+ let dmap_eq =
496+ match side with
497+ | `Left ->
498+ let dmap_ty = tfun (tdistr tyL) (tfun (tfun tyL tyR) (tdistr tyR)) in
499+ let dmap_pred = f_app (f_op dmap_op [tyL; tyR] dmap_ty) [muL ; g] (tdistr tyR) in
500+ f_eq dmap_pred muR
501+ | `Right ->
502+ let dmap_ty = tfun (tdistr tyR) (tfun (tfun tyR tyL) (tdistr tyL)) in
503+ let dmap_pred = f_app (f_op dmap_op [tyR; tyL] dmap_ty) [muR ; g] (tdistr tyL) in
504+ f_eq muL dmap_pred in
505+
506+ let a_id = EcIdent. create " a" in
507+ let b_id = EcIdent. create " b" in
508+ let a = f_local a_id tyL in
509+ let b = f_local b_id tyR in
510+ let post = es_po es in
511+ let post_subst = subst_form_lv_left env lvL {ml= ml;mr= mr;inv= a} post in
512+ let post_subst = subst_form_lv_right env lvR {ml= ml;mr= mr;inv= b} post_subst in
513+
514+ let goal =
515+ match side with
516+ | `Left -> map_ts_inv1
517+ (f_imp (f_in_supp a muL))
518+ (map_ts_inv1 (f_imp (f_eq (f_app_simpl g [a] tyR) b)) post_subst)
519+ | `Right -> map_ts_inv1
520+ (f_imp (f_in_supp b muR))
521+ (map_ts_inv1 (f_imp (f_eq a (f_app_simpl g [b] tyL))) post_subst) in
522+
523+ let goal = map_ts_inv1 (f_forall_simpl [(a_id, GTty tyL); (b_id, GTty tyR)]) goal in
524+ map_ts_inv1 (f_and dmap_eq) goal
525+ in
526+ let goal = f_equivS (snd es.es_ml) (snd es.es_mr) (es_pr es) sl' sr' goal in
527+
528+ FApi. xmutate1 tc `Rnd [goal]
445529end (* Core *)
446530
447531(* -------------------------------------------------------------------- *)
@@ -666,32 +750,32 @@ let process_rnd side pos tac_info tc =
666750 t_bdhoare_rnd tac_info tc
667751
668752 | _ , _ , _ when is_equivS concl ->
669- let process_form f ty1 ty2 =
670- TTC. tc1_process_prhl_form tc (tfun ty1 ty2) f in
671-
672- let bij_info =
673- match tac_info with
674- | PNoRndParams -> None , None
675- | PSingleRndParam f -> Some (process_form f), None
676- | PTwoRndParams (f , finv ) -> Some (process_form f), Some (process_form finv)
677- | _ -> tc_error !! tc " invalid arguments"
678- in
753+ let process_form f ty1 ty2 =
754+ TTC. tc1_process_prhl_form tc (tfun ty1 ty2) f in
755+
756+ let bij_info =
757+ match tac_info with
758+ | PNoRndParams -> None , None
759+ | PSingleRndParam f -> Some (process_form f), None
760+ | PTwoRndParams (f , finv ) -> Some (process_form f), Some (process_form finv)
761+ | _ -> tc_error !! tc " invalid arguments"
762+ in
679763
680- let pos = pos |> Option. map (function
681- | Single (b , p ) ->
682- let p =
683- if Option. is_some side then
684- EcProofTyping. tc1_process_codepos1 tc (side, p)
685- else EcTyping. trans_codepos1 (FApi. tc1_env tc) p
686- in Single (b, p)
687- | Double ((b1 , p1 ), (b2 , p2 )) ->
688- let p1 = EcProofTyping. tc1_process_codepos1 tc (Some `Left , p1) in
689- let p2 = EcProofTyping. tc1_process_codepos1 tc (Some `Right , p2) in
690- Double ((b1, p1), (b2, p2))
691- )
692- in
693-
694- t_equiv_rnd side ?pos bij_info tc
764+ let pos = pos |> Option. map (function
765+ | Single (b , p ) ->
766+ let p =
767+ if Option. is_some side then
768+ EcProofTyping. tc1_process_codepos1 tc (side, p)
769+ else EcTyping. trans_codepos1 (FApi. tc1_env tc) p
770+ in Single (b, p)
771+ | Double ((b1 , p1 ), (b2 , p2 )) ->
772+ let p1 = EcProofTyping. tc1_process_codepos1 tc (Some `Left , p1) in
773+ let p2 = EcProofTyping. tc1_process_codepos1 tc (Some `Right , p2) in
774+ Double ((b1, p1), (b2, p2))
775+ )
776+ in
777+
778+ t_equiv_rnd side ?pos bij_info tc
695779
696780 | _ -> tc_error !! tc " invalid arguments"
697781
@@ -713,3 +797,24 @@ let process_rndsem ~reduce side pos tc =
713797 | Some side when is_equivS concl ->
714798 t_equiv_rndsem reduce side pos tc
715799 | _ -> tc_error !! tc " invalid arguments"
800+
801+ let process_coupling side g tc =
802+ let concl = FApi. tc1_goal tc in
803+
804+ if not (is_equivS concl) then
805+ tc_error !! tc " coupling can only be used on pRHL goals"
806+ else
807+ let env = FApi. tc1_env tc in
808+ let es = tc1_as_equivS tc in
809+ let (_, muL), _ = tc1_last_rnd tc es.es_sl in
810+ let (_, muR), _ = tc1_last_rnd tc es.es_sr in
811+ let tyL = proj_distr_ty env (e_ty muL) in
812+ let tyR = proj_distr_ty env (e_ty muR) in
813+
814+ let coupling_ty =
815+ match side with
816+ | None -> tdistr (ttuple [tyL; tyR])
817+ | Some `Left -> tfun tyL tyR
818+ | Some `Right -> tfun tyR tyL in
819+ let g_form = TTC. tc1_process_prhl_form tc coupling_ty g in
820+ Core. t_equiv_coupling_r side g_form tc
0 commit comments