@@ -10,6 +10,7 @@ open EcSubst
1010
1111open EcMatching.Position
1212open EcCoreGoal
13+ open EcCoreFol
1314open EcLowGoal
1415open EcLowPhlGoal
1516
@@ -442,6 +443,80 @@ 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. form_of_expr muL in
459+ let muR = EcFol. form_of_expr muR 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_inv1 (fun g_app ->
479+ f_app
480+ (f_op iscoupling_op [tyL; tyR] iscoupling_ty)
481+ [muL; muR; g_app]
482+ tbool) g_app in
483+
484+ (* Substitute in the postcondition *)
485+ let post = (es_po es) in
486+ let post_subst = subst_form_lv_left env lvL {ml= ml;mr= mr;inv= a} post in
487+ let post_subst = subst_form_lv_right env lvR {ml= ml;mr= mr;inv= b} post_subst in
488+
489+ let goal = map_ts_inv2 f_imp (map_ts_inv1 (f_in_supp ab) g_app) post_subst in
490+ let goal = map_ts_inv1 (f_forall_simpl [(a_id, GTty tyL); (b_id, GTty tyR)]) goal in
491+ map_ts_inv2 f_and iscoupling_pred goal
492+ | Some side ->
493+ (* Goal (left): {phi} c1 ~ c2 {dmap d1 g = d2 /\ forall a b, b = g(a) => psi[x -> a, y -> b]} *)
494+ (* Goal (right): {phi} c1 ~ c2 {dmap d1 g = d2 /\ forall a b, a = g(b) => psi[x -> a, y -> b]} *)
495+ let dmap_op = EcPath. extend EcCoreLib. p_top [" Distr" ; " dmap" ] in
496+ let dmap_ty = tfun (tdistr tyL) (tfun (tfun tyL tyR) (tdistr tyR)) in
497+ let dmap_pred = map_ts_inv1
498+ (fun g -> f_eq (f_app (f_op dmap_op [tyL; tyR] dmap_ty) [muL; g] (tdistr tyR)) muR) g in
499+
500+ let a_id = EcIdent. create " a" in
501+ let b_id = EcIdent. create " b" in
502+ let a = f_local a_id tyL in
503+ let b = f_local b_id tyR in
504+ let post = (es_po es) in
505+ let post_subst = subst_form_lv_left env lvL {ml= ml;mr= mr;inv= a} post in
506+ let post_subst = subst_form_lv_right env lvR {ml= ml;mr= mr;inv= b} post_subst in
507+
508+ let eq_condition =
509+ match side with
510+ | `Left -> map_ts_inv1 (fun g -> f_eq (f_app_simpl g [a] tyR) b) g
511+ | `Right -> map_ts_inv1 (fun g -> f_eq a (f_app_simpl g [b] tyL)) g in
512+
513+ let goal = map_ts_inv2 f_imp eq_condition post_subst in
514+ let goal = map_ts_inv1 (f_forall_simpl [(a_id, GTty tyL); (b_id, GTty tyR)]) goal in
515+ map_ts_inv2 f_and dmap_pred goal
516+ in
517+ let goal = f_equivS (snd es.es_ml) (snd es.es_mr) (es_pr es) sl' sr' goal in
518+
519+ FApi. xmutate1 tc `Rnd [goal]
445520end (* Core *)
446521
447522(* -------------------------------------------------------------------- *)
@@ -666,32 +741,32 @@ let process_rnd side pos tac_info tc =
666741 t_bdhoare_rnd tac_info tc
667742
668743 | _ , _ , _ 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
744+ let process_form f ty1 ty2 =
745+ TTC. tc1_process_prhl_form tc (tfun ty1 ty2) f in
746+
747+ let bij_info =
748+ match tac_info with
749+ | PNoRndParams -> None , None
750+ | PSingleRndParam f -> Some (process_form f), None
751+ | PTwoRndParams (f , finv ) -> Some (process_form f), Some (process_form finv)
752+ | _ -> tc_error !! tc " invalid arguments"
753+ in
679754
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
755+ let pos = pos |> Option. map (function
756+ | Single (b , p ) ->
757+ let p =
758+ if Option. is_some side then
759+ EcProofTyping. tc1_process_codepos1 tc (side, p)
760+ else EcTyping. trans_codepos1 (FApi. tc1_env tc) p
761+ in Single (b, p)
762+ | Double ((b1 , p1 ), (b2 , p2 )) ->
763+ let p1 = EcProofTyping. tc1_process_codepos1 tc (Some `Left , p1) in
764+ let p2 = EcProofTyping. tc1_process_codepos1 tc (Some `Right , p2) in
765+ Double ((b1, p1), (b2, p2))
766+ )
767+ in
768+
769+ t_equiv_rnd side ?pos bij_info tc
695770
696771 | _ -> tc_error !! tc " invalid arguments"
697772
@@ -713,3 +788,24 @@ let process_rndsem ~reduce side pos tc =
713788 | Some side when is_equivS concl ->
714789 t_equiv_rndsem reduce side pos tc
715790 | _ -> tc_error !! tc " invalid arguments"
791+
792+ let process_coupling side g tc =
793+ let concl = FApi. tc1_goal tc in
794+
795+ if not (is_equivS concl) then
796+ tc_error !! tc " coupling can only be used on pRHL goals"
797+ else
798+ let env = FApi. tc1_env tc in
799+ let es = tc1_as_equivS tc in
800+ let (_, muL), _ = tc1_last_rnd tc es.es_sl in
801+ let (_, muR), _ = tc1_last_rnd tc es.es_sr in
802+ let tyL = proj_distr_ty env (e_ty muL) in
803+ let tyR = proj_distr_ty env (e_ty muR) in
804+
805+ let coupling_ty =
806+ match side with
807+ | None -> tdistr (ttuple [tyL; tyR])
808+ | Some `Left -> tfun tyL tyR
809+ | Some `Right -> tfun tyR tyL in
810+ let g_form = TTC. tc1_process_prhl_form tc coupling_ty g in
811+ Core. t_equiv_coupling_r side g_form tc
0 commit comments