Module infotheo.ecc_modern.summary_tanner
From mathcomp Require Import all_ssreflect ssralg ssrnum fingroup finalg zmodp.From mathcomp Require Import matrix lra ring.
From mathcomp Require Import Rstruct reals.
Require Import ssr_ext ssralg_ext f2 summary.
Require Import subgraph_partition tanner tanner_partition fdist channel.
Require Import checksum.
Technical lemmas about the summary operator
Set Implicit Arguments.
Set SsrOldRewriteGoalsOrder.
Unset Strict Implicit.
Import Prenex Implicits.
Local Open Scope vec_ext_scope.
Local Open Scope ring_scope.
Section dprojs_comb.
Variables (n : nat) (F : finFieldType).
Implicit Types d t : 'rV[F]_n.
Implicit Types s : {set 'I_n}.
Implicit Types A : finType.
Definition
dproj
d s t :=dproj not a defined object.
locked (\row_(j < n) if j \in s then t ``_ j else d ``_ j).
Lemma sub_vec_dproj d t s' s : s \subset s' -> (dproj d s' t) \# s = t \# s.
Proof.
Lemma dproj_out d t s i : i \notin s -> (dproj d s t) ``_ i = d ``_i.
Lemma dproj_in d t s i : i \in s -> (dproj d s t) ``_ i = t ``_i.
Lemma freeon_dproj d t s : freeon s d (dproj d s t).
Lemma dprojIdef d d' t s : dproj d s (dproj d' s t) = dproj d s t.
Proof.
Lemma dproj_freeon d s t : freeon s d t -> dproj d s t = t.
Proof.
Definition
dprojs
d A (g : A -> {set 'I_n}) t :=dprojs not a defined object.
locked [ffun a => dproj d (g a) t].
Lemma sub_vec_dprojs d t A (g : A -> {set 'I_n}) s a :
s \subset g a -> ((dprojs d g t) a) \# s = t \# s.
Proof.
Lemma freeon_dprojs d t A (g : A -> {set 'I_n}) a : freeon (g a) d ((dprojs d g t) a).
Proof.
Lemma dprojs_in d t A (g : A -> {set 'I_n}) n0 a :
n0 \in g a -> ((dprojs d g t) a) ``_ n0 = t ``_ n0.
Lemma dprojs_out d t A (g : A -> {set 'I_n}) n0 a :
n0 \notin g a -> ((dprojs d g t) a) ``_ n0 = d ``_n0.
Definition
comb
d A (f : {ffun A -> 'rV[F]_n}) (g : A -> {set 'I_n}) :=comb not a defined object.
locked (\row_(j < n) (if [pick a | j \in g a] is Some a then (f a) ``_ j else d ``_ j)).
Lemma comb_in d A (f : {ffun A -> 'rV[F]_n}) (g : A -> {set 'I_n}) n1 a :
[pick a | n1 \in g a] = Some a -> (comb d f g) ``_ n1 = (f a) ``_ n1.
Lemma comb_out d A (f : {ffun A -> 'rV[F]_n}) (g : A -> {set 'I_n}) n1 :
[pick a | n1 \in g a] = None-> (comb d f g) ``_ n1 = d ``_ n1.
Lemma comb_dprojs_not_in_partition d A (g : A -> {set 'I_n}) n0 t :
[forall a, n0 \notin g a] ->
(comb d (dprojs d g t) g) ``_ n0 = d ``_ n0.
Proof.
Lemma comb_dprojs d A (g : A -> {set 'I_n}) t :
(forall n0, t ``_ n0 = d ``_ n0 \/ exists a, n0 \in g a) ->
comb d (dprojs d g t) g = t.
Proof.
End dprojs_comb.
Section dproj_F2.
Variable n : nat.
Implicit Types d t : 'rV['F_2]_n.
Implicit Types s : {set 'I_n}.
Lemma checksubsum_dproj d t s s0 : (forall i, i \in s :\: s0 -> t ``_ i = d ``_ i) ->
\delta s (dproj d s0 t) = \delta s t.
Proof.
Lemma checksubsum_dprojD1 d n0 t s : t ``_ n0 = d ``_ n0 ->
\delta s (dproj d (s :\ n0) t) = \delta s t.
Proof.
Lemma checksubsum_dproj_freeon d s0 s t : freeon s0 d t ->
\delta s (dproj d s0 t) = \delta s t.
Proof.
move=> Ht.
rewrite checksubsum_dproj // => i; rewrite in_setD => /andP[H1 H2].
by rewrite (freeon_notin Ht).
Qed.
rewrite checksubsum_dproj // => i; rewrite in_setD => /andP[H1 H2].
by rewrite (freeon_notin Ht).
Qed.
End dproj_F2.
Section dprojs_subgraph.
Variables (m n : nat) (H : 'M['F_2]_(m, n)).
Hypothesis Hconnected : forall a b, connect (tanner_rel H) a b.
Local Notation "''V(' x ',' y ')'" := (Vgraph H x y).
Local Notation "''F(' x ',' y ')'" := (Fgraph H x y).
Local Notation "''V'" := (Vnext H).
Local Notation "''F'" := (Fnext H).
Implicit Types d t : 'rV['F_2]_n.
Definition
sgraph
n0 m0 := 'V(m0, n0) :\ n0.sgraph not a defined object.
Definition
dprojs_V
d n0 t : {ffun 'I_m -> 'rV_n} := dprojs d (sgraph n0) t.dprojs_V not a defined object.
Lemma pfamily_dprojs_V d n0 t : dprojs d (sgraph n0) t \in
pfamily d ('F n0) (fun m0 => [pred t | freeon (sgraph n0 m0) d t]).
Proof.
pose pT : predType _ := [predType of simpl_pred 'rV['F_2]_n].
apply/(@pfamilyP _ _ pT); split.
apply/supportP => m0 n0m0.
apply/rowP => n1.
rewrite dprojs_out //.
apply: contra n0m0.
rewrite FnextE; exact: mem_VgraphD1_Vnext.
move=> m0 m0n0; by rewrite inE (freeon_dprojs _ _ (sgraph n0)).
Qed.
apply/(@pfamilyP _ _ pT); split.
apply/supportP => m0 n0m0.
apply/rowP => n1.
rewrite dprojs_out //.
apply: contra n0m0.
rewrite FnextE; exact: mem_VgraphD1_Vnext.
move=> m0 m0n0; by rewrite inE (freeon_dprojs _ _ (sgraph n0)).
Qed.
Definition
comb_V
d n0 f := comb d f (sgraph n0).comb_V not a defined object.
Lemma comb_dprojs_V d i t : t ``_ i = d ``_ i -> comb_V d i (dprojs_V d i t) = t.
Proof.
move=> H0.
rewrite /comb_V /dprojs_V comb_dprojs // => n1.
case/boolP: (i == n1) => [/eqP <-|in1]; [by left | right].
move: (cover_Vgraph_part_vnode Hconnected i) => Hcover.
have : n1 \in cover (Vgraph_part_vnode H i) :\ i by rewrite Hcover !inE eq_sym in1.
rewrite in_setD1 eq_sym in1 /=.
case/bigcupP => /= s /imsetP[m1 Hm1 ->{s} Hn1]; by exists m1.
Qed.
rewrite /comb_V /dprojs_V comb_dprojs // => n1.
case/boolP: (i == n1) => [/eqP <-|in1]; [by left | right].
move: (cover_Vgraph_part_vnode Hconnected i) => Hcover.
have : n1 \in cover (Vgraph_part_vnode H i) :\ i by rewrite Hcover !inE eq_sym in1.
rewrite in_setD1 eq_sym in1 /=.
case/bigcupP => /= s /imsetP[m1 Hm1 ->{s} Hn1]; by exists m1.
Qed.
Lemma comb_dprojs_V_not_in_partition d n0 t n1 : (forall m0, n1 \notin sgraph n0 m0) ->
(comb_V d n0 (dprojs_V d n0 t)) ``_ n1 = d ``_ n1.
Proof.
move=> H0; rewrite /comb_V /dprojs_V comb_dprojs_not_in_partition //.
apply/forallP => m0; by rewrite H0.
Qed.
apply/forallP => m0; by rewrite H0.
Qed.
Lemma comb_V_support d (f : {ffun 'I_m -> 'rV_n}) n0 n1 (s : {set 'I_m}) :
d.-support f \subset s ->
~~ [exists m0, (m0 \in s) && (n1 \in 'V(m0, n0))] ->
(comb_V d n0 f) ``_ n1 = d ``_ n1.
Proof.
Lemma checksubsum_dprojs_V d n0 t m0 m1 :
m1 \in 'F(m0, n0) -> t ``_ n0 = d ``_ n0 ->
\delta ('V m1) ((dprojs_V d n0 t) m0) = \delta ('V m1) t.
Proof.
move=> Hm1 tn0dn0.
rewrite /dprojs_V /dprojs; unlock; rewrite ffunE. (* NB: really unlock? *)
rewrite checksubsum_dproj // => n2.
rewrite in_setD => /andP[].
rewrite in_setD1 negb_and negbK.
case/boolP : (n2 == n0) => [/eqP -> //|/= n2n0 Hn2 Hn2'].
move: (Fgraph_Vnext_Vgraph Hm1 Hn2' n2n0).
by rewrite (negbTE Hn2).
Qed.
rewrite /dprojs_V /dprojs; unlock; rewrite ffunE. (* NB: really unlock? *)
rewrite checksubsum_dproj // => n2.
rewrite in_setD => /andP[].
rewrite in_setD1 negb_and negbK.
case/boolP : (n2 == n0) => [/eqP -> //|/= n2n0 Hn2 Hn2'].
move: (Fgraph_Vnext_Vgraph Hm1 Hn2' n2n0).
by rewrite (negbTE Hn2).
Qed.
Lemma freeon_comb_dprojs_V d t n0 : freeon (setT :\ n0) d (comb_V d n0 (dprojs_V d n0 t)).
Proof.
End dprojs_subgraph.
Section dprojs_subgraph_acyclic.
Variables (m n : nat) (H : 'M['F_2]_(m, n)).
Hypothesis Hconnected : forall a b, connect (tanner_rel H) a b.
Local Notation "''V(' x ',' y ')'" := (Vgraph H x y).
Local Notation "''F(' x ',' y ')'" := (Fgraph H x y).
Local Notation "''V'" := (Vnext H).
Local Notation "''F'" := (Fnext H).
Implicit Types d : 'rV['F_2]_n.
Hypothesis Hacyclic : acyclic (tanner_rel H).
Lemma comb_V_in d (f : {ffun 'I_m -> 'rV_n}) n0 m0 n1 :
n1 \in 'V(m0, n0) :\ n0 -> (comb_V H d n0 f) ``_ n1 = (f m0) ``_ n1.
Proof.
move=> Hn1; rewrite /comb_V (@comb_in _ _ _ _ f _ _ m0) //.
case: pickP => [m1 Hm1 | ].
case/boolP : (m0 == m1) => [/eqP -> // | m0m1].
have {}Hm1 : n1 \in 'V(m1, n0).
move: Hm1; rewrite in_setD1; by case/andP.
move: Hn1; rewrite in_setD1; case/andP => n1n0 Hn1.
move: (disjoint_Vgraph Hacyclic n1n0 m0m1 Hn1); by rewrite Hm1.
move/(_ m0); by rewrite Hn1.
Qed.
case: pickP => [m1 Hm1 | ].
case/boolP : (m0 == m1) => [/eqP -> // | m0m1].
have {}Hm1 : n1 \in 'V(m1, n0).
move: Hm1; rewrite in_setD1; by case/andP.
move: Hn1; rewrite in_setD1; case/andP => n1n0 Hn1.
move: (disjoint_Vgraph Hacyclic n1n0 m0m1 Hn1); by rewrite Hm1.
move/(_ m0); by rewrite Hn1.
Qed.
Lemma dprojs_comb_V d n0 (g : 'I_n -> {set 'I_m}) (f : {ffun 'I_m -> 'rV_n}) :
f \in pfamily d (g n0) (fun i => freeon ('V(i, n0) :\ n0) d) ->
dprojs_V H d n0 (comb_V H d n0 f) = f.
Proof.
rewrite inE /= => /forallP => /= Hf.
apply/ffunP => /= m0.
apply/rowP => n1.
case/boolP : (n1 \in 'V( m0, n0) :\ n0) => Hn1.
rewrite dprojs_in //.
by rewrite (@comb_V_in _ _ _ m0) //.
rewrite dprojs_out //.
move: (Hf m0).
case: ifP => [_ | _ /eqP -> //].
rewrite inE.
by move/freeon_notin => ->.
Qed.
apply/ffunP => /= m0.
apply/rowP => n1.
case/boolP : (n1 \in 'V( m0, n0) :\ n0) => Hn1.
rewrite dprojs_in //.
by rewrite (@comb_V_in _ _ _ m0) //.
rewrite dprojs_out //.
move: (Hf m0).
case: ifP => [_ | _ /eqP -> //].
rewrite inE.
by move/freeon_notin => ->.
Qed.
Local Open Scope summary_scope.
Lemma rmul_rsum_commute0 (R := Rdefinitions.R) d n0 (B : finType) (t : 'rV[B]_n)
(W : forall m, 'rV_m -> 'rV_m -> R)
(F : 'I_m -> 'rV_n -> R)
(HF : forall m1 m0 (t' : 'rV_n), m1 \in 'F(m0, n0) -> t' ``_ n0 = d ``_ n0 -> F m1 ((dprojs_V H d n0 t') m0) = F m1 t') :
\prod_(m0 in 'F n0) (\sum_(t' = d [~'V(m0, n0) :\ n0])
W _ (t \# 'V(m0, n0) :\ n0) (t' \# 'V(m0, n0) :\ n0) * \prod_(m1 in 'F(m0, n0)) F m1 t') =
\sum_(t' = d [~ setT :\ n0]) (\prod_(m0 in 'F n0)
(W _ (t \# 'V(m0, n0) :\ n0) (t' \# 'V(m0, n0) :\ n0) * \prod_(m1 in 'F(m0, n0)) F m1 t')).
Proof.
rewrite (big_distr_big_dep d [pred x in 'F n0] (fun i => freeon ('V(i, n0) :\ n0) d)) [LHS]/=.
rewrite (reindex_onto (dprojs_V H d n0) (comb_V H d n0)); last first.
rewrite /= => f Hf; by apply: (@dprojs_comb_V d n0 (fun n => 'F n)).
rewrite [LHS]/=.
apply/esym/eq_big.
- move=> /= t'.
case Hlhs : (freeon _ _ t').
apply/esym.
rewrite comb_dprojs_V => //; last first.
by rewrite (freeon_notin Hlhs) // !inE eqxx.
by rewrite eqxx andbT pfamily_dprojs_V.
apply/esym/negbTE.
move/negbT : Hlhs; apply: contra.
case/andP => _ /eqP <-.
by rewrite freeon_comb_dprojs_V.
- move=> /= t' Ht'.
apply: eq_bigr => m0 Hm0.
congr (_ * _)%R.
+ by rewrite /dprojs_V sub_vec_dprojs.
+ apply: eq_bigr => m1 Hm1.
by rewrite HF // -(freeon_notin Ht') //= !inE eqxx.
Qed.
rewrite (reindex_onto (dprojs_V H d n0) (comb_V H d n0)); last first.
rewrite /= => f Hf; by apply: (@dprojs_comb_V d n0 (fun n => 'F n)).
rewrite [LHS]/=.
apply/esym/eq_big.
- move=> /= t'.
case Hlhs : (freeon _ _ t').
apply/esym.
rewrite comb_dprojs_V => //; last first.
by rewrite (freeon_notin Hlhs) // !inE eqxx.
by rewrite eqxx andbT pfamily_dprojs_V.
apply/esym/negbTE.
move/negbT : Hlhs; apply: contra.
case/andP => _ /eqP <-.
by rewrite freeon_comb_dprojs_V.
- move=> /= t' Ht'.
apply: eq_bigr => m0 Hm0.
congr (_ * _)%R.
+ by rewrite /dprojs_V sub_vec_dprojs.
+ apply: eq_bigr => m1 Hm1.
by rewrite HF // -(freeon_notin Ht') //= !inE eqxx.
Qed.
End dprojs_subgraph_acyclic.
Section dprojs_subsubgraph.
Variables (m n : nat).
Variable H : 'M['F_2]_(m, n).
Local Notation "'`V(' x ',' y ')'" := (Vgraph H x y).
Local Notation "'`F(' x ',' y ')'" := (Fgraph H x y).
Local Notation "''V'" := (Vnext H).
Local Notation "'`F'" := (Fnext H).
Implicit Types d : 'rV['F_2]_n.
Definition
ssgraph
m0 n0 n1 :=ssgraph not a defined object.
[set n2 | (n1 \in 'V m0 :\ n0) && [exists m1, (m1 \in `F n1 :\ m0) && (n2 \in `V(m1, n1))]].
Definition
dprojs_V2
d m0 n0 t : {ffun 'I_n -> 'rV_n} := dprojs d (ssgraph m0 n0) t.dprojs_V2 not a defined object.
Definition
comb_V2
d m0 n0 (f : {ffun 'I_n -> 'rV_n}) := comb d f (ssgraph m0 n0).comb_V2 not a defined object.
Lemma sub_vec_dprojs_V2 d m0 n0 t n1 m1 : n1 \in 'V m0 :\ n0 -> m1 \in `F n1 :\ m0 ->
(dprojs_V2 d m0 n0 t) n1 \# `V(m1, n1) :\ n1 = t \# `V(m1, n1) :\ n1.
Proof.
Lemma checksubsum_dprojs_V2 d m0 n0 (t' t : 'rV_n) n1 m1 m2
(Hn1 : n1 \in 'V m0 :\ n0) (Hm1 : m1 \in `F n1 :\ m0) (Hm2 : m2 \in `F(m1, n1)) :
dprojs_V2 d m0 n0 t \in pfamily t' ('V m0 :\ n0)
(fun n2 => [pred t'' | (dprojs_V H d n2 t'' \in pfamily d (`F n2 :\ m0)
(fun m2 => freeon (`V(m2, n2) :\ n2) d)) &&
(comb_V H d n2 (dprojs_V H d n2 t'') == t'')]) ->
\delta ('V m2) ((dprojs_V H d n1 ((dprojs_V2 d m0 n0 t) n1)) m1) =
\delta ('V m2) t.
Proof.
move=> H0; rewrite /checksubsum; congr (_ == _).
apply: eq_bigr => n2 n2m2.
rewrite /dprojs_V /dprojs_V2.
case/boolP : (n2 \in `V( m1, n1) :\ n1) => [Hn2|].
rewrite dprojs_in // dprojs_in //inE /ssgraph Hn1 /=.
apply/existsP; exists m1; rewrite Hm1.
by case/setD1P : Hn2.
move=> Hn2; rewrite dprojs_out //; move: Hn2.
rewrite in_setD1 negb_and negbK.
case/boolP : (n2 == n1) => [/eqP ?|/=]; last first.
by move/(Fgraph_Vnext_Vgraph Hm2 n2m2) => ->.
subst n2 => /=.
pose pT : predType _ := [predType of simpl_pred 'rV['F_2]_n].
case/(@pfamilyP _ _ pT): H0 => H0 /(_ _ Hn1).
rewrite inE => /andP[_].
move/eqP/rowP/(_ n1).
rewrite comb_dprojs_V_not_in_partition; last first.
by move=> m3; rewrite in_setD1 eqxx.
rewrite /dprojs_V2 dprojs_in // inE Hn1 /=.
apply/existsP; exists m1; by rewrite Hm1 /= root_in_Vgraph.
Qed.
apply: eq_bigr => n2 n2m2.
rewrite /dprojs_V /dprojs_V2.
case/boolP : (n2 \in `V( m1, n1) :\ n1) => [Hn2|].
rewrite dprojs_in // dprojs_in //inE /ssgraph Hn1 /=.
apply/existsP; exists m1; rewrite Hm1.
by case/setD1P : Hn2.
move=> Hn2; rewrite dprojs_out //; move: Hn2.
rewrite in_setD1 negb_and negbK.
case/boolP : (n2 == n1) => [/eqP ?|/=]; last first.
by move/(Fgraph_Vnext_Vgraph Hm2 n2m2) => ->.
subst n2 => /=.
pose pT : predType _ := [predType of simpl_pred 'rV['F_2]_n].
case/(@pfamilyP _ _ pT): H0 => H0 /(_ _ Hn1).
rewrite inE => /andP[_].
move/eqP/rowP/(_ n1).
rewrite comb_dprojs_V_not_in_partition; last first.
by move=> m3; rewrite in_setD1 eqxx.
rewrite /dprojs_V2 dprojs_in // inE Hn1 /=.
apply/existsP; exists m1; by rewrite Hm1 /= root_in_Vgraph.
Qed.
End dprojs_subsubgraph.
Section dprojs_subsubgraph_acyclic.
Variables (m n : nat).
Variable H : 'M['F_2]_(m, n).
Local Notation "'`V(' x ',' y ')'" := (Vgraph H x y).
Local Notation "'`F(' x ',' y ')'" := (Fgraph H x y).
Local Notation "''V'" := (Vnext H).
Local Notation "'`F'" := (Fnext H).
Implicit Types d : 'rV['F_2]_n.
Hypothesis Hacyclic : acyclic (tanner_rel H).
Lemma comb_dprojs_V2_in_partition d t m0 n0 n1 :
(exists n2, n1 \in ssgraph H m0 n0 n2) ->
(comb_V2 H d m0 n0 (dprojs_V2 H d m0 n0 t)) ``_ n1 = t ``_ n1.
Proof.
Lemma comb_dprojs_V2_not_in_subgraph d t n0 m0 (m0n0 : n0 \in 'V m0) n1 :
n1 \notin `V(m0, n0) -> (comb_V2 H d m0 n0 (dprojs_V2 H d m0 n0 t)) ``_ n1 = d ``_ n1.
Proof.
Lemma comb_dprojs_V2_Vnext d t n0 m0 (m0n0 : n0 \in 'V m0) :
(comb_V2 H d m0 n0 (dprojs_V2 H d m0 n0 t)) ``_ n0 = d ``_ n0.
Proof.
Lemma freeon_trans d m0 n0 (m0n0 : n0 \in 'V m0) d' t (Ht : freeon ('V m0 :\ n0) d d') :
freeon (`V(m0, n0) :\ n0) d t ->
freeon (`V(m0, n0) :\ n0) d' t.
Proof.
move=> Hlhs2.
apply/forallP => /= n1.
rewrite in_setD1 negb_and negbK.
apply/implyP => /orP[/eqP ->{n1}|].
rewrite -(freeon_notin Hlhs2) ?in_setD1 ?eqxx //.
by rewrite (freeon_notin Ht) // !inE eqxx.
move=> Hn1.
rewrite -(freeon_notin Hlhs2) ?in_setD1 ?(negbTE Hn1) ?andbF //.
rewrite (freeon_notin Ht) //.
apply: contra Hn1 => Hn1.
move/Fnext_Vnext_Vgraph : m0n0.
move/subsetP/(_ _ Hn1).
rewrite in_setD1.
by case/andP.
Qed.
apply/forallP => /= n1.
rewrite in_setD1 negb_and negbK.
apply/implyP => /orP[/eqP ->{n1}|].
rewrite -(freeon_notin Hlhs2) ?in_setD1 ?eqxx //.
by rewrite (freeon_notin Ht) // !inE eqxx.
move=> Hn1.
rewrite -(freeon_notin Hlhs2) ?in_setD1 ?(negbTE Hn1) ?andbF //.
rewrite (freeon_notin Ht) //.
apply: contra Hn1 => Hn1.
move/Fnext_Vnext_Vgraph : m0n0.
move/subsetP/(_ _ Hn1).
rewrite in_setD1.
by case/andP.
Qed.
Lemma comb_V2_freeon d m0 n0 (m0n0 : n0 \in 'V m0) t' t (Ht : freeon ('V m0 :\ n0) d t') :
comb_V2 H d m0 n0 (dprojs_V2 H d m0 n0 t) = t ->
freeon (`V(m0, n0) :\ n0) t' t.
Proof.
move=> <-.
apply: (freeon_trans m0n0 Ht).
apply/forallP => /= n1.
rewrite in_setD1 negb_and negbK.
apply/implyP => /orP[/eqP ->{n1}|].
by rewrite comb_dprojs_V2_Vnext // (freeon_notin Ht) // !inE eqxx.
move=> Hn1.
by rewrite comb_dprojs_V2_not_in_subgraph.
Qed.
apply: (freeon_trans m0n0 Ht).
apply/forallP => /= n1.
rewrite in_setD1 negb_and negbK.
apply/implyP => /orP[/eqP ->{n1}|].
by rewrite comb_dprojs_V2_Vnext // (freeon_notin Ht) // !inE eqxx.
move=> Hn1.
by rewrite comb_dprojs_V2_not_in_subgraph.
Qed.
Hypothesis Hconnected : forall a b, connect (tanner_rel H) a b.
Lemma dprojs_V2_pfamily d m0 n0 (m0n0 : n0 \in 'V m0) t d'
(d'td : dproj d' ('V m0 :\ n0) t = d) (d't : freeon (`V(m0, n0) :\ n0) d' t) :
dprojs_V2 H d m0 n0 t \in pfamily d ('V m0 :\ n0)
(fun n1 => [pred t0 | (dprojs_V H d n1 t0
\in pfamily d (`F n1 :\ m0) (fun m1 => freeon (`V(m1, n1) :\ n1) d)) &&
(comb_V H d n1 (dprojs_V H d n1 t0) == t0)]).
Proof.
pose pT : predType _ := [predType of simpl_pred 'rV['F_2]_n].
apply/(@pfamilyP _ _ pT); split.
apply/supportP => n1.
rewrite 2!inE /= negb_and negbK.
case/orP => [ /eqP ->{n1}| m0n1].
apply/rowP => n2 /=.
by rewrite /dprojs_V2 dprojs_out // inE /ssgraph 2!inE eqxx.
apply/rowP => n2 /=.
by rewrite /dprojs_V2 dprojs_out // inE /ssgraph in_setD1 (negbTE m0n1) andbF.
move=> /= n1 Hn1.
rewrite {1}/in_mem /=.
apply/andP; split.
apply/familyP => /= m1.
rewrite {1}/in_mem /=.
rewrite inE /= in_set1 /=.
case: ifPn.
case/andP => m1m0 m1n1.
apply/forallP => n2.
apply/implyP => Hn2.
by rewrite /dprojs_V2 dprojs_out.
rewrite negb_and negbK.
case/orP => [ | m1n1 /=].
move/eqP => -> {m1} /=.
rewrite /dprojs_V /dprojs_V2.
apply/eqP/rowP => n2.
case/boolP : (n2 \in `V( m0, n1) :\ n1) => K; last by rewrite dprojs_out.
rewrite dprojs_in //.
case/boolP : (n2 \in ssgraph H m0 n0 n1) => L; last first.
by rewrite dprojs_out.
rewrite dprojs_in //.
move: L; rewrite inE => /andP[L].
case/existsP => m1 /andP[Hm1 n2m1n1].
rewrite -d'td.
case/boolP : (n2 \in 'V m0 :\ n0) => n2m0n0; first by rewrite dproj_in.
rewrite dproj_out // (freeon_notin d't) //.
rewrite in_setD1 negb_and negbK.
rewrite /= in_setD1 negb_and negbK in n2m0n0.
case/orP : n2m0n0 => [->// | n2m0].
suff : n2 \notin `V(m0, n0) by move => ->; rewrite orbC.
apply/negP.
by apply: disjoint_Vgraph2 n2m1n1 n2m0.
apply/eqP/rowP => n2.
rewrite dprojs_out //.
apply/negP.
rewrite /= in_setD1.
case/andP => Hn2' Hn2.
move/negP : Hn2'; apply.
rewrite Vgraph_set1 in Hn2.
by rewrite in_set1 in Hn2.
by rewrite -FnextE.
rewrite comb_dprojs_V //.
case/boolP: [exists m1, (m1 \in `F n1 :\ m0) && (n1 \in `V( m1, n1))] => X.
rewrite /dprojs_V2 dprojs_in //; last by rewrite inE /ssgraph Hn1 X.
by rewrite -d'td dproj_in.
by rewrite /dprojs_V2 dprojs_out // inE /ssgraph Hn1.
Qed.
apply/(@pfamilyP _ _ pT); split.
apply/supportP => n1.
rewrite 2!inE /= negb_and negbK.
case/orP => [ /eqP ->{n1}| m0n1].
apply/rowP => n2 /=.
by rewrite /dprojs_V2 dprojs_out // inE /ssgraph 2!inE eqxx.
apply/rowP => n2 /=.
by rewrite /dprojs_V2 dprojs_out // inE /ssgraph in_setD1 (negbTE m0n1) andbF.
move=> /= n1 Hn1.
rewrite {1}/in_mem /=.
apply/andP; split.
apply/familyP => /= m1.
rewrite {1}/in_mem /=.
rewrite inE /= in_set1 /=.
case: ifPn.
case/andP => m1m0 m1n1.
apply/forallP => n2.
apply/implyP => Hn2.
by rewrite /dprojs_V2 dprojs_out.
rewrite negb_and negbK.
case/orP => [ | m1n1 /=].
move/eqP => -> {m1} /=.
rewrite /dprojs_V /dprojs_V2.
apply/eqP/rowP => n2.
case/boolP : (n2 \in `V( m0, n1) :\ n1) => K; last by rewrite dprojs_out.
rewrite dprojs_in //.
case/boolP : (n2 \in ssgraph H m0 n0 n1) => L; last first.
by rewrite dprojs_out.
rewrite dprojs_in //.
move: L; rewrite inE => /andP[L].
case/existsP => m1 /andP[Hm1 n2m1n1].
rewrite -d'td.
case/boolP : (n2 \in 'V m0 :\ n0) => n2m0n0; first by rewrite dproj_in.
rewrite dproj_out // (freeon_notin d't) //.
rewrite in_setD1 negb_and negbK.
rewrite /= in_setD1 negb_and negbK in n2m0n0.
case/orP : n2m0n0 => [->// | n2m0].
suff : n2 \notin `V(m0, n0) by move => ->; rewrite orbC.
apply/negP.
by apply: disjoint_Vgraph2 n2m1n1 n2m0.
apply/eqP/rowP => n2.
rewrite dprojs_out //.
apply/negP.
rewrite /= in_setD1.
case/andP => Hn2' Hn2.
move/negP : Hn2'; apply.
rewrite Vgraph_set1 in Hn2.
by rewrite in_set1 in Hn2.
by rewrite -FnextE.
rewrite comb_dprojs_V //.
case/boolP: [exists m1, (m1 \in `F n1 :\ m0) && (n1 \in `V( m1, n1))] => X.
rewrite /dprojs_V2 dprojs_in //; last by rewrite inE /ssgraph Hn1 X.
by rewrite -d'td dproj_in.
by rewrite /dprojs_V2 dprojs_out // inE /ssgraph Hn1.
Qed.
Lemma comb_dprojs_V2 d m0 n0 (m0n0 : n0 \in 'V m0) d' t
(d'td : dproj d' ('V m0 :\ n0) t = d) (d't : freeon (`V(m0, n0) :\ n0) d' t) :
comb_V2 H d m0 n0 (dprojs_V2 H d m0 n0 t) == t.
Proof.
apply/eqP/rowP => n1.
case/boolP : (n1 == n0) => [/eqP ?|n1n0].
subst n1.
rewrite comb_dprojs_V2_Vnext // -d'td dproj_out ?in_setD1 ?eqxx //.
move/rowP : d'td => /(_ n0).
by rewrite (freeon_notin d't) // in_setD1 eqxx.
case/boolP : [exists n2, n1 \in ssgraph H m0 n0 n2] => [/existsP[n2 Hn2]|].
rewrite comb_dprojs_V2_in_partition //; by exists n2.
rewrite negb_exists => H0.
rewrite comb_out; last first.
case: pickP => // => x.
by move/forallP : H0 => /(_ x) /negbTE ->.
rewrite -d'td.
case/boolP : (n1 \in 'V m0 :\ n0) => K.
by rewrite dproj_in.
rewrite dproj_out //.
move/forallP: d't => /(_ n1).
rewrite in_setD1 n1n0 /=.
have -> : n1 \notin `V(m0, n0).
apply/negP => n1m0n0.
rewrite in_setD1 negb_and negbK (negbTE n1n0) orFb in K.
case: (Vgraph_decompose m0n0 n1m0n0 n1n0 K) => n2 [] Hn2 [m1 [H0' H1']].
move/forallP in H0.
move: (H0 n2) => /=; rewrite /ssgraph Hn2 /= inE.
by rewrite negb_exists => /forallP/(_ m1); rewrite H0' /= H1'.
by rewrite implyTb => /eqP.
Qed.
case/boolP : (n1 == n0) => [/eqP ?|n1n0].
subst n1.
rewrite comb_dprojs_V2_Vnext // -d'td dproj_out ?in_setD1 ?eqxx //.
move/rowP : d'td => /(_ n0).
by rewrite (freeon_notin d't) // in_setD1 eqxx.
case/boolP : [exists n2, n1 \in ssgraph H m0 n0 n2] => [/existsP[n2 Hn2]|].
rewrite comb_dprojs_V2_in_partition //; by exists n2.
rewrite negb_exists => H0.
rewrite comb_out; last first.
case: pickP => // => x.
by move/forallP : H0 => /(_ x) /negbTE ->.
rewrite -d'td.
case/boolP : (n1 \in 'V m0 :\ n0) => K.
by rewrite dproj_in.
rewrite dproj_out //.
move/forallP: d't => /(_ n1).
rewrite in_setD1 n1n0 /=.
have -> : n1 \notin `V(m0, n0).
apply/negP => n1m0n0.
rewrite in_setD1 negb_and negbK (negbTE n1n0) orFb in K.
case: (Vgraph_decompose m0n0 n1m0n0 n1n0 K) => n2 [] Hn2 [m1 [H0' H1']].
move/forallP in H0.
move: (H0 n2) => /=; rewrite /ssgraph Hn2 /= inE.
by rewrite negb_exists => /forallP/(_ m1); rewrite H0' /= H1'.
by rewrite implyTb => /eqP.
Qed.
Hypothesis tannerH_simple : simple (tanner_rel H).
Lemma comb_dprojs_V2_Vnext_dangling d m0 n0 t n1 (n1m0 : n1 \in 'V m0) :
~~ [exists m1, (m1 \in `F n1 :\ m0)] ->
(comb_V2 H d m0 n0 (dprojs_V2 H d m0 n0 t)) ``_ n1 = d ``_ n1.
Proof.
move=> tmp.
rewrite /comb_V2 /dprojs_V2.
rewrite /comb; unlock; rewrite mxE. (* xxx *)
case: pickP => //.
move=> n1'; rewrite inE => /andP[Hn1' /existsP[m1' Hm1']].
case/boolP : (n1 \in ssgraph H m0 n0 n1') => [|L]; last first.
by rewrite dprojs_out.
rewrite dprojs_in; last first.
rewrite /ssgraph Hn1' /= inE.
apply/existsP; exists m1'; by rewrite Hm1'.
rewrite /ssgraph Hn1' /=.
case/andP: Hm1' => Hm1'.
rewrite 3!inE; case/orP => [/eqP ?|].
subst n1'.
move=> abs.
rewrite inE in abs.
exfalso.
move/negP : tmp; apply.
case/existsP : abs => m1 /andP[abs _].
apply/existsP; by exists m1.
rewrite inE.
case/andP => n1'm1' /connectP [] /= p.
case/shortenP => p' Hp' Hun p'p Hlast.
exfalso.
apply: (@Hacyclic [:: inl m0, inr n1', inl m1' & p'] isT).
apply: uniq_path_ucycle_extend_1 => //.
- by rewrite /= -VnextE; move: Hn1'; rewrite in_setD1 => /andP[].
- rewrite rcons_path Hp' /= -Hlast.
rewrite exceptE /= andbT -VnextE n1m0 /= eq_sym.
rewrite (path_except_neq _ Hp') // Hlast.
destruct p' => //=; by rewrite mem_last.
- rewrite rcons_uniq Hun andbT inE negb_or; apply/andP; split.
apply/eqP; case => m0m1'; by move: Hm1'; rewrite m0m1' in_setD1 eqxx.
apply/negP => Hx.
case/splitPr : Hx => p1 p2 in Hp' Hun p'p Hlast.
rewrite last_cat /= in Hlast.
apply: (@Hacyclic [:: inl m0, inr n1', inl m1' & p1] isT).
apply: uniq_path_ucycle_extend_1 => //.
+ by rewrite /= -VnextE; move: Hn1'; rewrite in_setD1 => /andP[].
+ move: Hp'; by rewrite -cat_rcons cat_path => /andP[].
+ rewrite rcons_uniq.
move: Hun; rewrite -cat_cons cat_uniq => /andP[-> /=].
by rewrite negb_or -andbA => /and3P[->].
Qed.
rewrite /comb_V2 /dprojs_V2.
rewrite /comb; unlock; rewrite mxE. (* xxx *)
case: pickP => //.
move=> n1'; rewrite inE => /andP[Hn1' /existsP[m1' Hm1']].
case/boolP : (n1 \in ssgraph H m0 n0 n1') => [|L]; last first.
by rewrite dprojs_out.
rewrite dprojs_in; last first.
rewrite /ssgraph Hn1' /= inE.
apply/existsP; exists m1'; by rewrite Hm1'.
rewrite /ssgraph Hn1' /=.
case/andP: Hm1' => Hm1'.
rewrite 3!inE; case/orP => [/eqP ?|].
subst n1'.
move=> abs.
rewrite inE in abs.
exfalso.
move/negP : tmp; apply.
case/existsP : abs => m1 /andP[abs _].
apply/existsP; by exists m1.
rewrite inE.
case/andP => n1'm1' /connectP [] /= p.
case/shortenP => p' Hp' Hun p'p Hlast.
exfalso.
apply: (@Hacyclic [:: inl m0, inr n1', inl m1' & p'] isT).
apply: uniq_path_ucycle_extend_1 => //.
- by rewrite /= -VnextE; move: Hn1'; rewrite in_setD1 => /andP[].
- rewrite rcons_path Hp' /= -Hlast.
rewrite exceptE /= andbT -VnextE n1m0 /= eq_sym.
rewrite (path_except_neq _ Hp') // Hlast.
destruct p' => //=; by rewrite mem_last.
- rewrite rcons_uniq Hun andbT inE negb_or; apply/andP; split.
apply/eqP; case => m0m1'; by move: Hm1'; rewrite m0m1' in_setD1 eqxx.
apply/negP => Hx.
case/splitPr : Hx => p1 p2 in Hp' Hun p'p Hlast.
rewrite last_cat /= in Hlast.
apply: (@Hacyclic [:: inl m0, inr n1', inl m1' & p1] isT).
apply: uniq_path_ucycle_extend_1 => //.
+ by rewrite /= -VnextE; move: Hn1'; rewrite in_setD1 => /andP[].
+ move: Hp'; by rewrite -cat_rcons cat_path => /andP[].
+ rewrite rcons_uniq.
move: Hun; rewrite -cat_cons cat_uniq => /andP[-> /=].
by rewrite negb_or -andbA => /and3P[->].
Qed.
Lemma dproj_prop d m0 n0 d' t (d'd : freeon ('V m0 :\ n0) d' d)
(Hpfamily : dprojs_V2 H d m0 n0 t
\in pfamily d ('V m0 :\ n0)
(fun n1 => [pred t0 |
(dprojs_V H d n1 t0
\in pfamily d (`F n1 :\ m0)
(fun m1 => freeon (`V(m1, n1) :\ n1) d)) &&
(comb_V H d n1 (dprojs_V H d n1 t0) == t0)]))
(Ht : comb_V2 H d m0 n0 (dprojs_V2 H d m0 n0 t) = t) :
dproj d' ('V m0 :\ n0) t == d.
Proof.
apply/eqP/rowP => n1.
case/boolP : (n1 \in 'V m0 :\ n0) => K; last first.
by rewrite dproj_out // (freeon_notin d'd).
rewrite dproj_in //.
move: K.
rewrite /= in_setD1.
case/andP => n1n0 Hn1.
pose pT : predType _ := [predType of simpl_pred 'rV['F_2]_n].
case/(@pfamilyP _ _ pT): Hpfamily => _ /(_ n1).
rewrite inE in_set1 n1n0 /= => /(_ Hn1).
rewrite {1}/in_mem /=.
case/andP => /pfamilyP[Hlhs11 Hlhs12].
rewrite /comb_V /dprojs_V /dprojs_V2.
move/eqP/(congr1 (fun x : 'rV_n => x ``_ n1)).
rewrite /comb; unlock => /=.
rewrite mxE.
case: pickP => [m1 Hm1 | _].
by rewrite in_setD1 eqxx in Hm1.
case/boolP : (n1 \in ssgraph H m0 n0 n1) => [L|L].
by rewrite dprojs_in.
rewrite dprojs_out //.
move: L.
rewrite /ssgraph inE negb_and in_setD1 Hn1 andbT negbK (negbTE n1n0) orFb.
move=> tmp _.
rewrite -{}Ht comb_dprojs_V2_Vnext_dangling //.
apply: contra tmp => /existsP[m1 Hm1].
apply/existsP; exists m1; rewrite Hm1 /=; exact: root_in_Vgraph.
Qed.
case/boolP : (n1 \in 'V m0 :\ n0) => K; last first.
by rewrite dproj_out // (freeon_notin d'd).
rewrite dproj_in //.
move: K.
rewrite /= in_setD1.
case/andP => n1n0 Hn1.
pose pT : predType _ := [predType of simpl_pred 'rV['F_2]_n].
case/(@pfamilyP _ _ pT): Hpfamily => _ /(_ n1).
rewrite inE in_set1 n1n0 /= => /(_ Hn1).
rewrite {1}/in_mem /=.
case/andP => /pfamilyP[Hlhs11 Hlhs12].
rewrite /comb_V /dprojs_V /dprojs_V2.
move/eqP/(congr1 (fun x : 'rV_n => x ``_ n1)).
rewrite /comb; unlock => /=.
rewrite mxE.
case: pickP => [m1 Hm1 | _].
by rewrite in_setD1 eqxx in Hm1.
case/boolP : (n1 \in ssgraph H m0 n0 n1) => [L|L].
by rewrite dprojs_in.
rewrite dprojs_out //.
move: L.
rewrite /ssgraph inE negb_and in_setD1 Hn1 andbT negbK (negbTE n1n0) orFb.
move=> tmp _.
rewrite -{}Ht comb_dprojs_V2_Vnext_dangling //.
apply: contra tmp => /existsP[m1 Hm1].
apply/existsP; exists m1; rewrite Hm1 /=; exact: root_in_Vgraph.
Qed.
Lemma dprojs_V2_in d m0 n0 t n1 (Hn1 : n1 \in 'V m0 :\ n0)
(Ht : comb_V2 H d m0 n0 (dprojs_V2 H d m0 n0 t) = t) :
((dprojs_V2 H d m0 n0 t) n1) ``_ n1 = t ``_ n1.
Proof.
case/boolP : [exists m1, (m1 \in `F n1 :\ m0)] => [/existsP[m1 K]|K].
rewrite /dprojs_V2 dprojs_in // inE /ssgraph Hn1 /=.
by apply/existsP; exists m1; rewrite K root_in_Vgraph.
rewrite dprojs_out /=; last first.
rewrite inE /ssgraph Hn1 /=.
apply: contra K => /existsP[x /andP[Hx _]].
by apply/existsP; exists x.
rewrite -Ht.
rewrite /comb_V2 /dprojs_V2 /= /comb; unlock; rewrite mxE. (* xxx *)
case: pickP => // n3.
rewrite inE => /andP[Hn3 /existsP[m1 /andP[Hm1 Hn1'']]].
rewrite negb_exists in K.
suff n31 : n3 = n1.
move/forallP : K => /(_ m1).
by rewrite -{1}n31 Hm1.
move: Hn1''.
rewrite inE in_set1 /= => /orP[/eqP //|].
rewrite 2!inE.
case/andP => m1n3 /connectP [] /= p.
case/shortenP => p' Hp' Hun pp' Hlast.
exfalso.
apply: (@Hacyclic [:: inl m0, inr n3, inl m1 & p'] isT).
apply: uniq_path_ucycle_extend_1 => //.
- by rewrite /= -VnextE; move: Hn3; rewrite in_setD1 => /andP[].
- rewrite rcons_path Hp' /= -Hlast exceptE /= andbT -VnextE.
move: Hn1; rewrite in_setD1 => /andP[_ -> /=].
rewrite eq_sym (path_except_neq _ Hp') // Hlast.
destruct p' => //=; by rewrite mem_last.
- rewrite rcons_uniq Hun andbT inE negb_or.
apply/andP; split.
apply/eqP; case => ?; subst m1.
by rewrite in_setD1 eqxx in Hm1.
apply/negP => Hx.
case/splitPr : Hx => p1 p2 in Hp' Hun pp' Hlast.
rewrite last_cat /= in Hlast.
apply: (@Hacyclic [:: inl m0, inr n3, inl m1 & p1] isT).
apply: uniq_path_ucycle_extend_1 => //.
+ by rewrite /= -VnextE; move: Hn3; rewrite in_setD1 => /andP[].
+ by move: Hp'; rewrite -cat_rcons cat_path => /andP[].
+ rewrite rcons_uniq.
move: Hun; rewrite -cat_cons cat_uniq => /andP[-> /=].
by rewrite negb_or -andbA => /andP[ ->].
Qed.
rewrite /dprojs_V2 dprojs_in // inE /ssgraph Hn1 /=.
by apply/existsP; exists m1; rewrite K root_in_Vgraph.
rewrite dprojs_out /=; last first.
rewrite inE /ssgraph Hn1 /=.
apply: contra K => /existsP[x /andP[Hx _]].
by apply/existsP; exists x.
rewrite -Ht.
rewrite /comb_V2 /dprojs_V2 /= /comb; unlock; rewrite mxE. (* xxx *)
case: pickP => // n3.
rewrite inE => /andP[Hn3 /existsP[m1 /andP[Hm1 Hn1'']]].
rewrite negb_exists in K.
suff n31 : n3 = n1.
move/forallP : K => /(_ m1).
by rewrite -{1}n31 Hm1.
move: Hn1''.
rewrite inE in_set1 /= => /orP[/eqP //|].
rewrite 2!inE.
case/andP => m1n3 /connectP [] /= p.
case/shortenP => p' Hp' Hun pp' Hlast.
exfalso.
apply: (@Hacyclic [:: inl m0, inr n3, inl m1 & p'] isT).
apply: uniq_path_ucycle_extend_1 => //.
- by rewrite /= -VnextE; move: Hn3; rewrite in_setD1 => /andP[].
- rewrite rcons_path Hp' /= -Hlast exceptE /= andbT -VnextE.
move: Hn1; rewrite in_setD1 => /andP[_ -> /=].
rewrite eq_sym (path_except_neq _ Hp') // Hlast.
destruct p' => //=; by rewrite mem_last.
- rewrite rcons_uniq Hun andbT inE negb_or.
apply/andP; split.
apply/eqP; case => ?; subst m1.
by rewrite in_setD1 eqxx in Hm1.
apply/negP => Hx.
case/splitPr : Hx => p1 p2 in Hp' Hun pp' Hlast.
rewrite last_cat /= in Hlast.
apply: (@Hacyclic [:: inl m0, inr n3, inl m1 & p1] isT).
apply: uniq_path_ucycle_extend_1 => //.
+ by rewrite /= -VnextE; move: Hn3; rewrite in_setD1 => /andP[].
+ by move: Hp'; rewrite -cat_rcons cat_path => /andP[].
+ rewrite rcons_uniq.
move: Hun; rewrite -cat_cons cat_uniq => /andP[-> /=].
by rewrite negb_or -andbA => /andP[ ->].
Qed.
Local Open Scope channel_scope.
Local Open Scope proba_scope.
Lemma rprod_rsum_commute d (B : finType) (x : 'rV_n) (W: `Ch('F_2, B)) m0 n0 (m0n0 : n0 \in 'V m0) :
let pr n1 t := (dprojs_V H d n1 t \in pfamily d (`F n1 :\ m0)
(fun m1 => freeon (`V(m1, n1) :\ n1) d)) &&
(comb_V H d n1 (dprojs_V H d n1 t) == t) in
let g := dprojs_V2 H d m0 n0 in
let g' := comb_V2 H d m0 n0 in
(\prod_(n1 in 'V m0 :\ n0)
(\sum_(t | pr n1 t)
W (t ``_ n1) (x ``_ n1) *
\prod_(m1 in `F n1 :\ m0)
(W ``(x \# `V(m1, n1) :\ n1 | ((dprojs_V H d n1 t) m1) \# `V(m1, n1) :\ n1) *
\prod_(m2 in `F(m1, n1)) (\delta ('V m2) ((dprojs_V H d n1 t) m1))%:R)) =
\sum_(t | (g t \in pfamily d ('V m0 :\ n0) pr) && (g' (g t) == t))
\prod_(n1 in 'V m0 :\ n0)
(W ((g t n1) ``_ n1) (x ``_ n1) *
\prod_(m1 in `F n1 :\ m0)
(W ``(x \# `V(m1, n1) :\ n1 | ((dprojs_V H d n1 (g t n1)) m1) \# `V(m1, n1) :\ n1) *
\prod_(m2 in `F(m1, n1)) (\delta ('V m2) ((dprojs_V H d n1 (g t n1)) m1))%:R)))%R.
Proof.
move=> pr g g'.
rewrite (big_distr_big_dep d) /=.
rewrite (reindex_onto (dprojs_V2 H d m0 n0) (comb_V2 H d m0 n0)) //.
move=> /= t' Ht'.
rewrite /dprojs_V2 /comb_V2.
apply/ffunP => /= n1.
apply/rowP => n2.
case/boolP : (n2 \in ssgraph H m0 n0 n1).
rewrite inE; case/andP => Hn1 /existsP [] m1 Hm1.
rewrite dprojs_in => /=; last first.
rewrite /ssgraph Hn1 /= inE.
apply/existsP; exists m1; by rewrite Hm1.
move H0 : [pick a | n2 \in ssgraph H m0 n0 a] => [n1'|]; last first.
case: pickP H0 => //.
move/(_ n1); rewrite inE Hn1 /= => /negbT; rewrite negb_exists => /forallP/(_ m1).
by rewrite Hm1.
have ? : n1' = n1.
case: pickP H0 => // x0.
rewrite inE => /andP[Hn1' H0].
move: H0 => /existsP[m1' /andP[Hm1' Hn2']].
case/andP : Hm1 => Hm1 Hn2 [<-].
by rewrite (Vgraph_id Hacyclic m0n0 Hn1 Hn1' Hm1 Hm1' Hn2 Hn2').
subst n1'.
by rewrite (@comb_in _ _ d _ t' (ssgraph H m0 n0) _ n1).
rewrite inE negb_and.
case/orP => [Hn1|].
rewrite dprojs_out /=; last by rewrite inE negb_and Hn1.
case/pfamilyP : Ht' => Ht' _.
move/supportP : Ht'.
by move/(_ n1 Hn1) => ->.
move=> tmp.
case/boolP : (n1 \in 'V m0 :\ n0) => Hn1; last first.
rewrite dprojs_out //; last by rewrite inE /ssgraph (negbTE Hn1).
case/pfamilyP : (Ht').
by move/supportP => /(_ _ Hn1) ->.
case/pfamilyP : (Ht') => _ /(_ _ Hn1).
rewrite {1}/in_mem /=.
case/andP => H1 /eqP <-.
rewrite dprojs_out //; last by rewrite inE /ssgraph Hn1.
rewrite (comb_V_support _ tmp) //; by case/pfamilyP : H1.
Qed.
rewrite (big_distr_big_dep d) /=.
rewrite (reindex_onto (dprojs_V2 H d m0 n0) (comb_V2 H d m0 n0)) //.
move=> /= t' Ht'.
rewrite /dprojs_V2 /comb_V2.
apply/ffunP => /= n1.
apply/rowP => n2.
case/boolP : (n2 \in ssgraph H m0 n0 n1).
rewrite inE; case/andP => Hn1 /existsP [] m1 Hm1.
rewrite dprojs_in => /=; last first.
rewrite /ssgraph Hn1 /= inE.
apply/existsP; exists m1; by rewrite Hm1.
move H0 : [pick a | n2 \in ssgraph H m0 n0 a] => [n1'|]; last first.
case: pickP H0 => //.
move/(_ n1); rewrite inE Hn1 /= => /negbT; rewrite negb_exists => /forallP/(_ m1).
by rewrite Hm1.
have ? : n1' = n1.
case: pickP H0 => // x0.
rewrite inE => /andP[Hn1' H0].
move: H0 => /existsP[m1' /andP[Hm1' Hn2']].
case/andP : Hm1 => Hm1 Hn2 [<-].
by rewrite (Vgraph_id Hacyclic m0n0 Hn1 Hn1' Hm1 Hm1' Hn2 Hn2').
subst n1'.
by rewrite (@comb_in _ _ d _ t' (ssgraph H m0 n0) _ n1).
rewrite inE negb_and.
case/orP => [Hn1|].
rewrite dprojs_out /=; last by rewrite inE negb_and Hn1.
case/pfamilyP : Ht' => Ht' _.
move/supportP : Ht'.
by move/(_ n1 Hn1) => ->.
move=> tmp.
case/boolP : (n1 \in 'V m0 :\ n0) => Hn1; last first.
rewrite dprojs_out //; last by rewrite inE /ssgraph (negbTE Hn1).
case/pfamilyP : (Ht').
by move/supportP => /(_ _ Hn1) ->.
case/pfamilyP : (Ht') => _ /(_ _ Hn1).
rewrite {1}/in_mem /=.
case/andP => H1 /eqP <-.
rewrite dprojs_out //; last by rewrite inE /ssgraph Hn1.
rewrite (comb_V_support _ tmp) //; by case/pfamilyP : H1.
Qed.
End dprojs_subsubgraph_acyclic.