@@ -10,6 +10,7 @@ open EcSubst
1010
1111open EcMatching.Position
1212open EcCoreGoal
13+ open EcCoreFol
1314open EcLowGoal
1415open EcLowPhlGoal
1516
@@ -442,6 +443,84 @@ 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 = ss_inv_generalize_right (EcFol. ss_inv_of_expr ml muL) mr in
459+ let muR = ss_inv_generalize_left (EcFol. ss_inv_of_expr mr muR) ml in
460+
461+ let goal =
462+ match side with
463+ | None ->
464+ (* Goal: {phi} c1 ~ c2 {iscoupling g muL muR /\ (forall a b, (a, b) \in supp(g) => psi[x -> a, y -> b])} *)
465+ (* Generate two free variables a and b and the pair (a, b) *)
466+ let a_id = EcIdent. create " a" in
467+ let b_id = EcIdent. create " b" in
468+ let a = f_local a_id tyL in
469+ let b = f_local b_id tyR in
470+ let ab = f_tuple [a; b] in
471+
472+ (* Generate the coupling distribution type: (tyL * tyR) distr *)
473+ let coupling_ty = ttuple [tyL; tyR] in
474+ let g_app = map_ts_inv1 (fun g -> f_app_simpl g [] (tdistr coupling_ty)) g in
475+
476+ let iscoupling_op = EcPath. extend EcCoreLib. p_top [" Distr" ; " iscoupling" ] in
477+ let iscoupling_ty = tfun (tdistr tyL) (tfun (tdistr tyR) (tfun (tdistr coupling_ty) tbool)) in
478+ let iscoupling_pred = map_ts_inv (fun f_list ->
479+ f_app
480+ (f_op iscoupling_op [tyL; tyR] iscoupling_ty)
481+ f_list
482+ tbool)
483+ [muL; muR; g_app] in
484+
485+ (* Substitute in the postcondition *)
486+ let post = (es_po es) in
487+ let post_subst = subst_form_lv_left env lvL {ml= ml;mr= mr;inv= a} post in
488+ let post_subst = subst_form_lv_right env lvR {ml= ml;mr= mr;inv= b} post_subst in
489+
490+ let goal = map_ts_inv2 f_imp (map_ts_inv1 (f_in_supp ab) g_app) post_subst in
491+ let goal = map_ts_inv1 (f_forall_simpl [(a_id, GTty tyL); (b_id, GTty tyR)]) goal in
492+ map_ts_inv2 f_and iscoupling_pred goal
493+ | Some side ->
494+ (* Goal (left): {phi} c1 ~ c2 {dmap d1 g = d2 /\ forall a b, b = g(a) => psi[x -> a, y -> b]} *)
495+ (* Goal (right): {phi} c1 ~ c2 {dmap d1 g = d2 /\ forall a b, a = g(b) => psi[x -> a, y -> b]} *)
496+ let dmap_op = EcPath. extend EcCoreLib. p_top [" Distr" ; " dmap" ] in
497+ let dmap_ty = tfun (tdistr tyL) (tfun (tfun tyL tyR) (tdistr tyR)) in
498+ let dmap_pred = map_ts_inv2 f_eq
499+ (map_ts_inv (fun f_list ->
500+ f_app (f_op dmap_op [tyL; tyR] dmap_ty) f_list (tdistr tyR))
501+ [muL; g])
502+ muR in
503+
504+ let a_id = EcIdent. create " a" in
505+ let b_id = EcIdent. create " b" in
506+ let a = f_local a_id tyL in
507+ let b = f_local b_id tyR in
508+ let post = (es_po es) in
509+ let post_subst = subst_form_lv_left env lvL {ml= ml;mr= mr;inv= a} post in
510+ let post_subst = subst_form_lv_right env lvR {ml= ml;mr= mr;inv= b} post_subst in
511+
512+ let eq_condition =
513+ match side with
514+ | `Left -> map_ts_inv1 (fun g -> f_eq (f_app_simpl g [a] tyR) b) g
515+ | `Right -> map_ts_inv1 (fun g -> f_eq a (f_app_simpl g [b] tyL)) g in
516+
517+ let goal = map_ts_inv2 f_imp eq_condition post_subst in
518+ let goal = map_ts_inv1 (f_forall_simpl [(a_id, GTty tyL); (b_id, GTty tyR)]) goal in
519+ map_ts_inv2 f_and dmap_pred goal
520+ in
521+ let goal = f_equivS (snd es.es_ml) (snd es.es_mr) (es_pr es) sl' sr' goal in
522+
523+ FApi. xmutate1 tc `Rnd [goal]
445524end (* Core *)
446525
447526(* -------------------------------------------------------------------- *)
@@ -666,32 +745,32 @@ let process_rnd side pos tac_info tc =
666745 t_bdhoare_rnd tac_info tc
667746
668747 | _ , _ , _ 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
748+ let process_form f ty1 ty2 =
749+ TTC. tc1_process_prhl_form tc (tfun ty1 ty2) f in
750+
751+ let bij_info =
752+ match tac_info with
753+ | PNoRndParams -> None , None
754+ | PSingleRndParam f -> Some (process_form f), None
755+ | PTwoRndParams (f , finv ) -> Some (process_form f), Some (process_form finv)
756+ | _ -> tc_error !! tc " invalid arguments"
757+ in
679758
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
759+ let pos = pos |> Option. map (function
760+ | Single (b , p ) ->
761+ let p =
762+ if Option. is_some side then
763+ EcProofTyping. tc1_process_codepos1 tc (side, p)
764+ else EcTyping. trans_codepos1 (FApi. tc1_env tc) p
765+ in Single (b, p)
766+ | Double ((b1 , p1 ), (b2 , p2 )) ->
767+ let p1 = EcProofTyping. tc1_process_codepos1 tc (Some `Left , p1) in
768+ let p2 = EcProofTyping. tc1_process_codepos1 tc (Some `Right , p2) in
769+ Double ((b1, p1), (b2, p2))
770+ )
771+ in
772+
773+ t_equiv_rnd side ?pos bij_info tc
695774
696775 | _ -> tc_error !! tc " invalid arguments"
697776
@@ -713,3 +792,24 @@ let process_rndsem ~reduce side pos tc =
713792 | Some side when is_equivS concl ->
714793 t_equiv_rndsem reduce side pos tc
715794 | _ -> tc_error !! tc " invalid arguments"
795+
796+ let process_coupling side g tc =
797+ let concl = FApi. tc1_goal tc in
798+
799+ if not (is_equivS concl) then
800+ tc_error !! tc " coupling can only be used on pRHL goals"
801+ else
802+ let env = FApi. tc1_env tc in
803+ let es = tc1_as_equivS tc in
804+ let (_, muL), _ = tc1_last_rnd tc es.es_sl in
805+ let (_, muR), _ = tc1_last_rnd tc es.es_sr in
806+ let tyL = proj_distr_ty env (e_ty muL) in
807+ let tyR = proj_distr_ty env (e_ty muR) in
808+
809+ let coupling_ty =
810+ match side with
811+ | None -> tdistr (ttuple [tyL; tyR])
812+ | Some `Left -> tfun tyL tyR
813+ | Some `Right -> tfun tyR tyL in
814+ let g_form = TTC. tc1_process_prhl_form tc coupling_ty g in
815+ Core. t_equiv_coupling_r side g_form tc
0 commit comments