@@ -442,6 +442,137 @@ module Core = struct
442442 | `Right -> f_equivS (snd es.es_ml) mt (es_pr es) es.es_sl s (es_po es) in
443443 FApi. xmutate1 tc (`RndSem pos) [concl]
444444
445+ (* -------------------------------------------------------------------- *)
446+ let t_equiv_coupling_r side g tc =
447+ (* process the following pRHL goal, where g is a coupling of g1 and g2 *)
448+ (* {phi} x <$ g1 ~ y <$ g2 {psi} *)
449+ let env = FApi. tc1_env tc in
450+ let es = tc1_as_equivS tc in
451+ let (lvL, muL), sl' = tc1_last_rnd tc es.es_sl in
452+ let (lvR, muR), sr' = tc1_last_rnd tc es.es_sr in
453+ let tyL = proj_distr_ty env (e_ty muL) in
454+ let tyR = proj_distr_ty env (e_ty muR) in
455+ let muL = EcFol. form_of_expr (EcMemory. memory es.es_ml) muL in
456+ let muR = EcFol. form_of_expr (EcMemory. memory es.es_mr) muR in
457+
458+ let goal =
459+ match side with
460+ | None ->
461+ (* Goal: iscoupling g muL muR => forall a b, (a, b) \in supp(g) => psi[x -> a, y -> b] *)
462+ (* Generate two free variables a and b and the pair (a, b) *)
463+ let a_id = EcIdent. create " a" in
464+ let b_id = EcIdent. create " b" in
465+ let a = f_local a_id tyL in
466+ let b = f_local b_id tyR in
467+ let ab = f_tuple [a; b] in
468+
469+ (* Generate the coupling distribution type: (tyL * tyR) distr *)
470+ let coupling_ty = ttuple [tyL; tyR] in
471+ let g_app = f_app_simpl g [] (tdistr coupling_ty) in
472+
473+ let iscoupling_op = EcPath. extend EcCoreLib. p_top [" Distr" ; " iscoupling" ] in
474+ let iscoupling_ty = tfun (tdistr tyL) (tfun (tdistr tyR) (tfun (tdistr coupling_ty) tbool)) in
475+ let iscoupling_pred = f_app (f_op iscoupling_op [tyL; tyR] iscoupling_ty)
476+ [muL; muR; g_app] tbool in
477+
478+ (* Substitute in the postcondition *)
479+ let post = es.es_po in
480+ let post_subst = subst_form_lv env (EcMemory. memory es.es_ml) lvL a post in
481+ let post_subst = subst_form_lv env (EcMemory. memory es.es_mr) lvR b post_subst in
482+
483+ let goal = f_imp (f_in_supp ab g_app) post_subst in
484+ let goal = f_forall_simpl [(a_id, GTty tyL); (b_id, GTty tyR)] goal in
485+ f_and iscoupling_pred goal
486+ | Some side ->
487+ (* Goal: dmap d1 g = d2 /\ forall a b, b = g(a) => psi[x -> a, y -> b] *)
488+ let dmap_op = EcPath. extend EcCoreLib. p_top [" Distr" ; " dmap" ] in
489+ let dmap_ty = tfun (tdistr tyL) (tfun (tfun tyL tyR) (tdistr tyR)) in
490+ let dmap_pred = f_eq (f_app (f_op dmap_op [tyL; tyR] dmap_ty) [muL; g] (tdistr tyR)) muR in
491+
492+ let a_id = EcIdent. create " a" in
493+ let b_id = EcIdent. create " b" in
494+ let a = f_local a_id tyL in
495+ let b = f_local b_id tyR in
496+ let post = es.es_po in
497+ let post_subst = subst_form_lv env (EcMemory. memory es.es_ml) lvL a post in
498+ let post_subst = subst_form_lv env (EcMemory. memory es.es_mr) lvR b post_subst in
499+
500+ let eq_condition =
501+ match side with
502+ | `Left -> f_eq (f_app_simpl g [a] tyR) b
503+ | `Right -> f_eq a (f_app_simpl g [b] tyL) in
504+
505+ let goal = f_imp eq_condition post_subst in
506+ let goal = f_forall_simpl [(a_id, GTty tyL); (b_id, GTty tyR)] goal in
507+ f_and dmap_pred goal
508+ in
509+ let goal = f_equivS_r { es with es_sl= sl'; es_sr= sr'; es_po= goal; } in
510+
511+ FApi. xmutate1 tc `Rnd [goal]
512+
513+ (* -------------------------------------------------------------------- *)
514+ let t_equiv_map_rnd_r f tc =
515+ let env = FApi. tc1_env tc in
516+ let es = tc1_as_equivS tc in
517+ let (lvL, muL), sl' = tc1_last_rnd tc es.es_sl in
518+ let (lvR, muR), sr' = tc1_last_rnd tc es.es_sr in
519+ let tyL = proj_distr_ty env (e_ty muL) in
520+ let tyR = proj_distr_ty env (e_ty muR) in
521+ let muL = EcFol. form_of_expr (EcMemory. memory es.es_ml) muL in
522+ let muR = EcFol. form_of_expr (EcMemory. memory es.es_mr) muR in
523+
524+ (* Generate free variables a and b *)
525+ let a_id = EcIdent. create " a" in
526+ let b_id = EcIdent. create " b" in
527+ let a = f_local a_id tyL in
528+ let b = f_local b_id tyR in
529+
530+ (* Apply function f to a *)
531+ let f_app = f_app_simpl f [a] tyR in
532+
533+ (* Substitute in the postcondition: psi[x <- a, y <- f(a)] *)
534+ let post = es.es_po in
535+ let post_subst = subst_form_lv env (EcMemory. memory es.es_ml) lvL a post in
536+ let post_subst = subst_form_lv env (EcMemory. memory es.es_mr) lvR f_app post_subst in
537+
538+ (* Forall a, psi[x <- a, y <- f(a)] *)
539+ let goal = f_forall_simpl [(a_id, GTty tyL)] post_subst in
540+
541+ (* Create the probability constraint: *)
542+ (* sum_{a' : tyL} mu1_g1[a'] * (if f(a') = b then 1 else 0) = mu1_g2[b] *)
543+ let a'_id = EcIdent. create " a'" in
544+ let a' = f_local a'_id tyL in
545+
546+ let f_app_sum = f_app_simpl f [a'] tyR in
547+ let eq_condition = f_eq f_app_sum b in
548+ let prob_muL = f_app_simpl muL [a'] treal in (* mu1 muL a' *)
549+ let b2r_op = EcPath. extend EcCoreLib. p_top [" Real" ; " b2r" ] in
550+ let b2r_ty = tfun tbool treal in
551+ let b2r_app = f_op b2r_op [] b2r_ty in
552+ let b2r_condition = f_app_simpl b2r_app [eq_condition] treal in
553+
554+ let summand = f_real_mul prob_muL b2r_condition in
555+ let sum_func = f_lambda [(a'_id, GTty tyL)] summand in
556+
557+ let bigreal_path = EcPath. extend EcCoreLib. p_top [" StdBigop" ; " Bigreal" ; " BRA" ] in
558+ let big_op = EcPath. extend bigreal_path [" big" ] in
559+ let predt_op = EcPath. extend EcCoreLib. p_top [" Logic" ; " predT" ] in
560+ let predt_ty = tfun tyL tbool in
561+ let predt_app = f_op predt_op [tyL] predt_ty in
562+ let big_ty = tfun (tfun tyL tbool) (tfun (tfun tyL treal) treal) in
563+ let big_app = f_op big_op [tyL] big_ty in
564+ let sum_expr = f_app_simpl big_app [predt_app; sum_func] treal in
565+
566+ (* The probability constraint: sum = mu1_g2[b] *)
567+ let prob_muR_b = f_app_simpl muR [b] treal in (* mu1 muR b *)
568+ let prob_constraint = f_eq sum_expr prob_muR_b in
569+
570+ (* forall b, constraint -> goal *)
571+ let goal = f_imp prob_constraint goal in
572+ let goal = f_forall_simpl [(b_id, GTty tyR)] goal in
573+ let goal = f_equivS_r { es with es_sl= sl'; es_sr= sr'; es_po= goal; } in
574+
575+ FApi. xmutate1 tc `Rnd [goal]
445576end (* Core *)
446577
447578(* -------------------------------------------------------------------- *)
@@ -666,32 +797,32 @@ let process_rnd side pos tac_info tc =
666797 t_bdhoare_rnd tac_info tc
667798
668799 | _ , _ , _ 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
800+ let process_form f ty1 ty2 =
801+ TTC. tc1_process_prhl_form tc (tfun ty1 ty2) f in
802+
803+ let bij_info =
804+ match tac_info with
805+ | PNoRndParams -> None , None
806+ | PSingleRndParam f -> Some (process_form f), None
807+ | PTwoRndParams (f , finv ) -> Some (process_form f), Some (process_form finv)
808+ | _ -> tc_error !! tc " invalid arguments"
809+ in
679810
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
811+ let pos = pos |> Option. map (function
812+ | Single (b , p ) ->
813+ let p =
814+ if Option. is_some side then
815+ EcProofTyping. tc1_process_codepos1 tc (side, p)
816+ else EcTyping. trans_codepos1 (FApi. tc1_env tc) p
817+ in Single (b, p)
818+ | Double ((b1 , p1 ), (b2 , p2 )) ->
819+ let p1 = EcProofTyping. tc1_process_codepos1 tc (Some `Left , p1) in
820+ let p2 = EcProofTyping. tc1_process_codepos1 tc (Some `Right , p2) in
821+ Double ((b1, p1), (b2, p2))
822+ )
823+ in
824+
825+ t_equiv_rnd side ?pos bij_info tc
695826
696827 | _ -> tc_error !! tc " invalid arguments"
697828
@@ -713,3 +844,41 @@ let process_rndsem ~reduce side pos tc =
713844 | Some side when is_equivS concl ->
714845 t_equiv_rndsem reduce side pos tc
715846 | _ -> tc_error !! tc " invalid arguments"
847+
848+ (* -------------------------------------------------------------------- *)
849+ let process_rndp f tc =
850+ let concl = FApi. tc1_goal tc in
851+
852+ if not (is_equivS concl) then
853+ tc_error !! tc " rndp can only be used on pRHL goals"
854+ else
855+ let env = FApi. tc1_env tc in
856+ let es = tc1_as_equivS tc in
857+ let (_, muL), _ = tc1_last_rnd tc es.es_sl in
858+ let (_, muR), _ = tc1_last_rnd tc es.es_sr in
859+ let tyL = proj_distr_ty env (e_ty muL) in
860+ let tyR = proj_distr_ty env (e_ty muR) in
861+ let func_ty = tfun tyL tyR in
862+ let f_form = TTC. tc1_process_prhl_form tc func_ty f in
863+ Core. t_equiv_map_rnd_r f_form tc
864+
865+ let process_coupling side g tc =
866+ let concl = FApi. tc1_goal tc in
867+
868+ if not (is_equivS concl) then
869+ tc_error !! tc " coupling can only be used on pRHL goals"
870+ else
871+ let env = FApi. tc1_env tc in
872+ let es = tc1_as_equivS tc in
873+ let (_, muL), _ = tc1_last_rnd tc es.es_sl in
874+ let (_, muR), _ = tc1_last_rnd tc es.es_sr in
875+ let tyL = proj_distr_ty env (e_ty muL) in
876+ let tyR = proj_distr_ty env (e_ty muR) in
877+
878+ let coupling_ty =
879+ match side with
880+ | None -> tdistr (ttuple [tyL; tyR])
881+ | Some `Left -> tfun tyL tyR
882+ | Some `Right -> tfun tyR tyL in
883+ let g_form = TTC. tc1_process_prhl_form tc coupling_ty g in
884+ Core. t_equiv_coupling_r side g_form tc
0 commit comments