@@ -10,6 +10,7 @@ open EcSubst
1010
1111open EcMatching.Position
1212open EcCoreGoal
13+ open EcCoreFol
1314open EcLowGoal
1415open EcLowPhlGoal
1516
@@ -442,6 +443,87 @@ 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, a \in supp(d1) -> b = g(a) => psi[x -> a, y -> b]} *)
495+ (* Goal (right): {phi} c1 ~ c2 {d1 = dmap d2 g /\ forall a b, b \in supp(d2) -> a = g(b) => psi[x -> a, y -> b]} *)
496+ let dmap_op = EcPath. extend EcCoreLib. p_top [" Distr" ; " dmap" ] in
497+ let dmap_eq =
498+ match side with
499+ | `Left ->
500+ let dmap_ty = tfun (tdistr tyL) (tfun (tfun tyL tyR) (tdistr tyR)) in
501+ let dmap_pred = map_ts_inv (fun f_list -> f_app (f_op dmap_op [tyL; tyR] dmap_ty) f_list (tdistr tyR)) in
502+ map_ts_inv2 f_eq (dmap_pred [muL ; g]) muR
503+ | `Right ->
504+ let dmap_ty = tfun (tdistr tyR) (tfun (tfun tyR tyL) (tdistr tyL)) in
505+ let dmap_pred = map_ts_inv (fun f_list -> f_app (f_op dmap_op [tyR; tyL] dmap_ty) f_list (tdistr tyL)) in
506+ map_ts_inv2 f_eq muL (dmap_pred [muR ; g]) in
507+
508+ let a_id = EcIdent. create " a" in
509+ let b_id = EcIdent. create " b" in
510+ let a = f_local a_id tyL in
511+ let b = f_local b_id tyR in
512+ let post = (es_po es) in
513+ let post_subst = subst_form_lv_left env lvL {ml= ml;mr= mr;inv= a} post in
514+ let post_subst = subst_form_lv_right env lvR {ml= ml;mr= mr;inv= b} post_subst in
515+
516+ let goal =
517+ match side with
518+ | `Left -> map_ts_inv2 f_imp (map_ts_inv1 (f_in_supp a) muL) (map_ts_inv2 f_imp (map_ts_inv1 (fun g -> f_eq (f_app_simpl g [a] tyR) b) g) post_subst)
519+ | `Right -> map_ts_inv2 f_imp (map_ts_inv1 (f_in_supp b) muR) (map_ts_inv2 f_imp (map_ts_inv1 (fun g -> f_eq a (f_app_simpl g [b] tyL)) g) post_subst) in
520+
521+ let goal = map_ts_inv1 (f_forall_simpl [(a_id, GTty tyL); (b_id, GTty tyR)]) goal in
522+ map_ts_inv2 f_and dmap_eq goal
523+ in
524+ let goal = f_equivS (snd es.es_ml) (snd es.es_mr) (es_pr es) sl' sr' goal in
525+
526+ FApi. xmutate1 tc `Rnd [goal]
445527end (* Core *)
446528
447529(* -------------------------------------------------------------------- *)
@@ -666,32 +748,32 @@ let process_rnd side pos tac_info tc =
666748 t_bdhoare_rnd tac_info tc
667749
668750 | _ , _ , _ 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
751+ let process_form f ty1 ty2 =
752+ TTC. tc1_process_prhl_form tc (tfun ty1 ty2) f in
753+
754+ let bij_info =
755+ match tac_info with
756+ | PNoRndParams -> None , None
757+ | PSingleRndParam f -> Some (process_form f), None
758+ | PTwoRndParams (f , finv ) -> Some (process_form f), Some (process_form finv)
759+ | _ -> tc_error !! tc " invalid arguments"
760+ in
679761
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
762+ let pos = pos |> Option. map (function
763+ | Single (b , p ) ->
764+ let p =
765+ if Option. is_some side then
766+ EcProofTyping. tc1_process_codepos1 tc (side, p)
767+ else EcTyping. trans_codepos1 (FApi. tc1_env tc) p
768+ in Single (b, p)
769+ | Double ((b1 , p1 ), (b2 , p2 )) ->
770+ let p1 = EcProofTyping. tc1_process_codepos1 tc (Some `Left , p1) in
771+ let p2 = EcProofTyping. tc1_process_codepos1 tc (Some `Right , p2) in
772+ Double ((b1, p1), (b2, p2))
773+ )
774+ in
775+
776+ t_equiv_rnd side ?pos bij_info tc
695777
696778 | _ -> tc_error !! tc " invalid arguments"
697779
@@ -713,3 +795,24 @@ let process_rndsem ~reduce side pos tc =
713795 | Some side when is_equivS concl ->
714796 t_equiv_rndsem reduce side pos tc
715797 | _ -> tc_error !! tc " invalid arguments"
798+
799+ let process_coupling side g tc =
800+ let concl = FApi. tc1_goal tc in
801+
802+ if not (is_equivS concl) then
803+ tc_error !! tc " coupling can only be used on pRHL goals"
804+ else
805+ let env = FApi. tc1_env tc in
806+ let es = tc1_as_equivS tc in
807+ let (_, muL), _ = tc1_last_rnd tc es.es_sl in
808+ let (_, muR), _ = tc1_last_rnd tc es.es_sr in
809+ let tyL = proj_distr_ty env (e_ty muL) in
810+ let tyR = proj_distr_ty env (e_ty muR) in
811+
812+ let coupling_ty =
813+ match side with
814+ | None -> tdistr (ttuple [tyL; tyR])
815+ | Some `Left -> tfun tyL tyR
816+ | Some `Right -> tfun tyR tyL in
817+ let g_form = TTC. tc1_process_prhl_form tc coupling_ty g in
818+ Core. t_equiv_coupling_r side g_form tc
0 commit comments