diff options
Diffstat (limited to 'mathcomp/odd_order/PFsection3.v')
| -rw-r--r-- | mathcomp/odd_order/PFsection3.v | 1854 |
1 files changed, 1854 insertions, 0 deletions
diff --git a/mathcomp/odd_order/PFsection3.v b/mathcomp/odd_order/PFsection3.v new file mode 100644 index 0000000..063aacc --- /dev/null +++ b/mathcomp/odd_order/PFsection3.v @@ -0,0 +1,1854 @@ +(* (c) Copyright Microsoft Corporation and Inria. All rights reserved. *) +Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. +Require Import fintype tuple finfun bigop prime ssralg matrix poly finset. +Require Import fingroup morphism perm automorphism quotient action finalg zmodp. +Require Import gfunctor center gproduct cyclic pgroup abelian frobenius. +Require Import mxalgebra mxrepresentation vector falgebra fieldext galois. +Require Import ssrnum rat algC algnum classfun character. +Require Import integral_char inertia vcharacter. +Require Import PFsection1 PFsection2. + +(******************************************************************************) +(* This file covers Peterfalvi, Section 3: TI-Subsets with Cyclic Normalizers *) +(******************************************************************************) +(* Given a direct product decomposition defW : W1 \x W2 = W, we define here: *) +(* cyclicTIset defW == the set complement of W1 and W2 in W; this *) +(* (locally) V definition is usually Let-bound to V. *) +(* := W :\: (W1 :|: W2). *) +(* cyclicTI_hypothesis G defW <-> W is a cyclic of odd order that is the *) +(* normaliser in G of its non-empty TI subset *) +(* V = cyclicTIset defW = W :\: (W1 :|: W2). *) +(* -> This is Peterfalvi, Hypothesis (3.1), or Feit-Thompson (13.1). *) +(* cyclicTIirr defW i j == the irreducible character of W coinciding with *) +(* (locally) w_ i j chi_i and 'chi_j on W1 and W2, respectively. *) +(* This notation is usually Let-bound to w_ i j. *) +(* := 'chi_(dprod_Iirr defW (i, j)). *) +(* cfCyclicTIset defW i j == the virtual character of 'Z[irr W, V] coinciding *) +(* (locally) alpha_ i j with 1 - chi_i and 1 - 'chi_j on W1 and W2, *) +(* respectively. This definition is denoted by *) +(* alpha_ i j in this file, and is only used in the *) +(* proof if Peterfalvi (13.9) in the sequel. *) +(* := cfDprod defW (1 - 'chi_i) (1 - 'chi_j). *) +(* = 1 - w_ i 0 - w_ 0 j + w_ i j. *) +(* cfCyclicTIsetBase defW := the tuple of all the alpha_ i j, for i, j != 0. *) +(* (locally) cfWVbase This is a basis of 'CF(W, V); this definition is *) +(* not used outside this file. *) +(* For ctiW : cyclicTI_hypothesis defW G we also define *) +(* cyclicTIiso ctiW == a linear isometry from 'CF(W) to 'CF(G) that *) +(* (locally) sigma that extends induction on 'CF(W, V), maps the *) +(* w_ i j to virtual characters, and w_ 0 0 to 1. *) +(* This definition is usually Let-bound to sigma, *) +(* and only depends extensionally on W, V and G. *) +(* (locally) eta_ i j := sigma (w_ i j), as in sections 13 and 14 of *) +(* tha Peterfalv text. *) +(* cyclicTI_NC ctiW phi == the number of eta_ i j constituents of phi. *) +(* (locally) NC phi := #|[set ij | '[phi, eta_ ij .1 ij.2] != 0]|. *) +(* The construction of sigma involves a large combinatorial proof, for which *) +(* it is worthwhile to use reflection techniques to automate mundane and *) +(* repetitive arguments. We isolate the necessary boilerplate in a separate *) +(* CyclicTIisoReflexion module. *) +(******************************************************************************) + +Set Implicit Arguments. +Unset Strict Implicit. +Unset Printing Implicit Defensive. + +Import GroupScope GRing.Theory Num.Theory. +Local Open Scope ring_scope. + +Section Definitions. + +Variables (gT : finGroupType) (G W W1 W2 : {set gT}). + +Definition cyclicTIset of W1 \x W2 = W := W :\: (W1 :|: W2). + +Definition cyclicTI_hypothesis (defW : W1 \x W2 = W) := + [/\ cyclic W, odd #|W| & normedTI (cyclicTIset defW) G W]. + +End Definitions. + +(* These is defined as a Notation which clients can bind with a Section Let *) +(* that can be folded easily. *) +Notation cyclicTIirr defW i j := 'chi_(dprod_Iirr defW (i, j)). + +Module CyclicTIisoReflexion. + +(******************************************************************************) +(* Support for carrying out the combinatorial parts of the proof of Theorem *) +(* (3.5) by reflection. Specifically, we need to show that in a rectangular *) +(* array of virtual characters of norm 3, of even dimensions, and such that *) +(* the dot product of two entries is 1 if they are on the same row or column, *) +(* the entries of each column contain a "pivot" normal virtual character *) +(* orthogonal to all other columns. The proof never needs to consider more *) +(* than a 4 x 2 rectangle, but frequently renumbers lines, columns and *) +(* orthonormal components in order to do so. *) +(* We want to use reflection to automate this renumbering; we also want to *) +(* automate the evaluation of the dot product constaints for partially *) +(* described entries of the matrix. *) +(* To do so we define a "theory" data structure to store a reifed form of *) +(* such partial descriptions: a set of "clauses", each consisting in an index *) +(* (i, j) into the array, and a collection of "literals" (k, v) representing *) +(* constraints '[b_(i, j), x`_k] = v%:~R, with v = 0, 1 or -1. A clause with *) +(* exactly three nonzero literals defines b_(i, j) exactly. *) +(* We define special notation for the concrete instances that appear in *) +(* reflected proofs; for example *) +(* |= & b11 = -x1 + x2 + x3 & x1, ~x2 in b12 & ? in b31 *) +(* denotes the "theory" of arrays whose two left entries decomposes into *) +(* x1 + x2 + x3 for some orthonormal x1, x2, and x3, such that the second top *) +(* entry has x1 is a signed component but is orthogonal to x2, and which have *) +(* an (unconstrained) first entry in the third column. (The concrete encoding *) +(* shifts indices to start at 0.) *) +(* The "models" in which such theories are interpreted supply the dimensions *) +(* of the array, which must be even, nonequal and at least 2, the function *) +(* mapping indices to array entries, which must be virtual characters with *) +(* the requisite norms and dot products, and an orthonormal sequence of *) +(* virtual characters that will be used to interpret the xij; a model coerces *) +(* to any of these three components. *) +(* We are primarily interested in two predicates: *) +(* sat m th <=> the interpretation of th in m is well-defined (no out of *) +(* bound indices) and valid (all constraints true). *) +(* unsat th <-> forall m, ~ sat m th *) +(* While the main theorem of this section, column_pivot, can be seen as an *) +(* instance of "sat", all the principal combinatorial lemmas use "unsat", *) +(* whose universal quantifier allows symmetry reductions. We present the set *) +(* of lemmas implementing reflection-assisted proofs of "unsat th" as a small *) +(* domain-specific proof language consisting of the following tactics: *) +(* consider bij ::= add a clause for bij, which must not appear in th, *) +(* changing the goal to unsat th & ? in bij. *) +(* bij must be within a 4 x 2 bounding box, and th *) +(* must be symmetric if bij "breaks" the 2 x 2 box. *) +(* fill bij ::= add an x(k.+1) literal to the bij clause in th, *) +(* where x1, ..., xk are all the normal characters *) +(* appearing in th, and the clause for bij exists and *) +(* contains assumptions for all of x1, ..., xk, at *) +(* two of which are nonzero. *) +(* uwlog Dcl: cl [by tac] ::= add the clause cl to th, replacing an existing *) +(* clause for the same matrix entry. This produces a *) +(* side goal of unsat th, but with an additional *) +(* assumption Dcl : unsat th+cl, which can be resolved *) +(* with the optional "by tac". *) +(* uhave lit in bij as T(ij, kl) ::= adds the literal lit (one of xk, -xk, or *) +(* ~xk) to an existing clause for bij in th, using the *) +(* reflection lemma T(ij, kl) to rule out the other *) +(* possibilities for xk. Here T can be either O *) +(* (general dot product evaluation) or L (specific *) +(* line/column constraints following from (3.5.2)). *) +(* uhave lit, lit' in bij as T(ij, kl) ::= adds both lit and lit'. *) +(* uhave lit | lit' in bij as T(ij, kl) ::= produces two subgoals, where lit *) +(* (resp. lit') is added to the ... in bij clause in *) +(* th, using T(ij, kl) to eliminate the third literal. *) +(* (lit and lit' must constrain the same component). *) +(* uhave lit | lit' | lit'' in bij ::= produces three subgoals, where lit *) +(* (resp. lit', lit'') is added to the bij clause in *) +(* th; lit, lit', lit'' should be a permutation of xk, *) +(* -xk, and ~xk for some k. *) +(* uwlog Ebij: lit | lit' in bij as T(ij, kl) ::= adds lit to the bij clause *) +(* in th, but produces a side goal where lit' has been *) +(* added instead, with an additional assumption *) +(* Ebij: th + (lit in bij); T(ij, kl) is used to rule *) +(* out the third value. *) +(* counter to T(ij, kl) ::= use T(ij, kl) to conclude that unsat th. *) +(* uexact Hth' ::= use Hth' : unsat th', where th' is a subset of th *) +(* (with the same order of literals) to conclude. *) +(* symmetric to Hth' ::= use Hth' : unsat th', where th' is a permutation *) +(* of a subset of th (preserving columns, and with at *) +(* most one row exchange) to conclude. *) +(******************************************************************************) + +Import ssrint. + +(* Clause left-hand side, a reference to a value of beta; in the reference *) +(* model m, (i, j) stands for beta_ (inord i.+1) (inord j.+1). *) +Definition ref := (nat * nat)%type. +Implicit Type ij : ref. +Definition Ref b_ij : ref := edivn (b_ij - 11) 10. (* Ref 21 = (1, 0). *) +Notation "''b' ij" := (Ref ij) (at level 0, ij at level 0, format "''b' ij"). +Notation b11 := 'b11. Notation b12 := 'b12. +Notation b21 := 'b21. Notation b22 := 'b22. +Notation b31 := 'b31. Notation b32 := 'b32. +Notation b41 := 'b41. Notation b42 := 'b42. + +Definition bbox := (nat * nat)%type. (* bounding box for refs. *) +Implicit Type bb : bbox. +Identity Coercion pair_of_bbox : bbox >-> prod. + +Definition sub_bbox bb1 bb2 := (bb1.1 <= bb2.1)%N && (bb1.2 <= bb2.2)%N. +Definition wf_ref bb := [pred ij : ref | (ij.1 < bb.1)%N && (ij.2 < bb.2)%N]. +Definition dot_ref ij1 ij2 := ((ij1.1 == ij2.1).+1 * (ij1.2 == ij2.2).+1 - 1)%N. + +Lemma bbox_refl bb : sub_bbox bb bb. Proof. exact/andP. Qed. + +(* Clause right-hand side litteral, denoting the projection of the left-hand *) +(* side on an irreducible character of G: in a valid model m, (k, v) stands *) +(* for the component m`_k *~ v = (model_xi m)`_k, and for the projection *) +(* constraint '[m i j, m`_k] == v%:~R. *) +Definition lit := (nat * int)%type. (* +x1 = (0,1) ~x2 = (1,0) -x3 = (2, -1) *) +Implicit Types (kv : lit) (kvs : seq lit). +Definition Lit k1 v : lit := if (0 + k1)%N is k.+1 then (k, v) else (k1, v). +Notation "+x k" := (Lit k 1) (at level 0, k at level 0, format "+x k"). +Notation "-x k" := (Lit k (-1)) (at level 0, k at level 0, format "-x k"). +Notation "~x k" := (Lit k 0) (at level 0, k at level 0, format "~x k"). +Notation x1 := +x1. Notation x2 := +x2. +Notation x3 := +x3. Notation x4 := +x4. +Notation x5 := +x5. Notation x6 := +x6. +Notation x7 := +x7. Notation x8 := +x8. + +Definition AndLit kvs kv := kv :: kvs. +Definition AddLit := AndLit. +Notation "(*dummy*)" := (Prop Prop) (at level 0) : defclause_scope. +Arguments Scope AddLit [defclause_scope _]. +Infix "+" := AddLit : defclause_scope. +Definition SubLit kvs kv := AddLit kvs (kv.1, - kv.2). +Arguments Scope SubLit [defclause_scope _]. +Infix "-" := SubLit : defclause_scope. +Coercion LastLit kv := [:: kv]. + +Fixpoint norm_cl kvs : nat := + (if kvs is (_, v) :: kvs1 then `|v| ^ 2 + norm_cl kvs1 else 0)%N. + +Definition clause := (ref * seq lit)%type. +Implicit Type cl : clause. +Definition Clause ij kvs : clause := (ij, kvs). +Notation "& kv1 , .. , kvn 'in' ij" := + (Clause ij (AndLit .. (AndLit nil kv1) .. kvn)) + (at level 200, ij, kv1, kvn at level 0, + format "& kv1 , .. , kvn 'in' ij"). +Notation "& ? 'in' ij" := (Clause ij nil) + (at level 200, ij at level 0, format "& ? 'in' ij"). +Definition DefClause := Clause. +Arguments Scope DefClause [_ defclause_scope]. +Notation "& ij = kvs" := (DefClause ij kvs) + (at level 200, ij at level 0, format "& ij = kvs"). + +Definition theory := seq clause. +Implicit Type th : theory. +Definition AddClause th cl : theory := cl :: th. +Notation "|= cl1 .. cln" := (AddClause .. (AddClause nil cl1) .. cln) + (at level 8, cl1, cln at level 200, + format "|= '[hv' cl1 '/' .. '/' cln ']'"). + +(* Transpose (W1 / W2 symmetry). *) + +Definition tr (ij : nat * nat) : ref := (ij.2, ij.1). +Definition tr_th th : theory := [seq (tr cl.1, cl.2) | cl <- th]. + +Lemma trK : involutive tr. Proof. by case. Qed. +Lemma tr_thK : involutive tr_th. Proof. by apply: mapK => [[[i j] kvs]]. Qed. + +(* Index range of a theory. *) + +Fixpoint th_bbox th : bbox := + if th is (i, j, _) :: th1 then + let: (ri, rj) := th_bbox th1 in (maxn i.+1 ri, maxn j.+1 rj) + else (0, 0)%N. + +Lemma th_bboxP th bb : + reflect {in th, forall cl, cl.1 \in wf_ref bb} (sub_bbox (th_bbox th) bb). +Proof. +pose in_bb := [pred cl : clause | cl.1 \in wf_ref bb]. +suffices ->: sub_bbox (th_bbox th) bb = all in_bb th by apply: allP. +elim: th => [|[[i j] _] th] //=; case: (th_bbox th) => ri rj /=. +by rewrite /sub_bbox /= !geq_max andbACA => ->. +Qed. +Implicit Arguments th_bboxP [th bb]. + +Fixpoint th_dim th : nat := + if th is (_, kvs) :: th1 then + foldr (fun kv => maxn kv.1.+1) (th_dim th1) kvs + else 0%N. + +Lemma th_dimP th bk : + reflect {in th, forall cl, {in cl.2, forall kv, kv.1 < bk}}%N + (th_dim th <= bk)%N. +Proof. +pose in_bk := [pred cl : clause | all (fun kv => kv.1 < bk)%N cl.2]. +suffices ->: (th_dim th <= bk)%N = all in_bk th. + by apply: (iffP allP) => bk_th cl /bk_th/allP. +elim: th => // [[_ kvs] th /= <-]; elim: kvs => //= kv kvs. +by rewrite -andbA geq_max => ->. +Qed. +Implicit Arguments th_dimP [th bk]. + +(* Theory and clause lookup. *) + +CoInductive get_spec T (P : T -> Prop) (Q : Prop) : option T -> Prop := + | GetSome x of P x : get_spec P Q (Some x) + | GetNone of Q : get_spec P Q None. + +Fixpoint get_cl ij (th : theory) : option clause := + if th is cl :: th1 then if cl.1 == ij then Some cl else get_cl ij th1 + else None. + +Lemma get_clP ij (th : theory) : + get_spec (fun cl : clause => cl \in th /\ cl.1 = ij) True (get_cl ij th). +Proof. +elim: th => /= [|cl th IHth]; first by right. +case: eqP => [Dij | _]; first by left; rewrite ?mem_head. +by case: IHth => [cl1 [th_cl1 Dij]|]; constructor; rewrite // mem_behead. +Qed. + +Fixpoint get_lit (k0 : nat) kvs : option int := + if kvs is (k, v) :: kvs1 then if k == k0 then Some v else get_lit k0 kvs1 + else None. + +Lemma get_litP k0 kvs : + get_spec (fun v => (k0, v) \in kvs) (k0 \notin unzip1 kvs) (get_lit k0 kvs). +Proof. +elim: kvs => [|[k v] kvs IHkvs /=]; [by right | rewrite inE eq_sym]. +have [-> | k'0] := altP eqP; first by left; rewrite ?mem_head. +by have [v0 kvs_k0v | kvs'k0] := IHkvs; constructor; rewrite // mem_behead. +Qed. + +(* Theory extension. *) + +Fixpoint set_cl cl2 th : wrapped theory := + if th is cl :: th1 then + let: Wrap th2 := set_cl cl2 th1 in + if cl.1 == cl2.1 then Wrap (AddClause th2 cl2) else Wrap (AddClause th2 cl) + else Wrap nil. + +Definition ext_cl th cl k v := + let: (ij, kvs) := cl in set_cl (Clause ij (AndLit kvs (Lit k.+1 v))) th. + +Definition wf_ext_cl cl k rk := (k \notin unzip1 cl.2) && (k < rk)%N. + +Definition wf_fill k kvs := (size kvs == k) && (norm_cl kvs < 3)%N. + +Lemma ext_clP cl1 th k v (cl1k := (cl1.1, (k, v) :: cl1.2)) : + cl1 \in th -> + exists2 th1, ext_cl th cl1 k v = Wrap th1 + & cl1k \in th1 + /\ th1 =i [pred cl | if cl.1 == cl1.1 then cl == cl1k else cl \in th]. +Proof. +case: cl1 => ij kvs /= in cl1k * => th_cl1; set th1p := [pred cl | _]. +pose th1 := [seq if cl.1 == ij then cl1k else cl | cl <- th]. +exists th1; first by elim: (th) @th1 => //= cl th' ->; rewrite -2!fun_if. +suffices Dth1: th1 =i th1p by rewrite Dth1 !inE !eqxx. +move=> cl; rewrite inE; apply/mapP/idP=> [[{cl}cl th_cl ->] | ]. + by case cl_ij: (cl.1 == ij); rewrite ?eqxx ?cl_ij. +case: ifP => [_ /eqP-> | cl'ij th_cl]; last by exists cl; rewrite ?cl'ij. +by exists (ij, kvs); rewrite ?eqxx. +Qed. + +(* Satisfiability tests. *) + +Definition sat_test (rO : rel clause) ij12 th := + if get_cl (Ref ij12.1) th is Some cl1 then + oapp (rO cl1) true (get_cl (Ref ij12.2) th) + else true. + +(* This reflects the application of (3.5.1) for an arbitrary pair of entries. *) +Definition Otest cl1 cl2 := + let: (ij1, kvs1) := cl1 in let: (ij2, kvs2) := cl2 in + let fix loop s1 s2 kvs2 := + if kvs2 is (k, v2) :: kvs2 then + if get_lit k kvs1 is Some v1 then loop (v1 * v2 + s1) s2 kvs2 else + loop s1 s2.+1 kvs2 + else (s1, if norm_cl kvs1 == 3 then 0%N else s2) in + let: (s1, s2) := loop 0 0%N kvs2 in + (norm_cl kvs2 == 3) ==> (`|s1 - dot_ref ij1 ij2| <= s2)%N. + +(* Matching up to a permutation of the rows, columns, and base vectors. *) + +Definition sub_match th1 th2 := + let match_cl cl1 cl2 := + if cl2.1 == cl1.1 then subseq cl1.2 cl2.2 else false in + all [pred cl1 | has (match_cl cl1) th2] th1. + +Definition wf_consider ij th (ri := (th_bbox th).1) := + (ij.1 < 2 + ((2 < ri) || sub_match th (tr_th th)).*2)%N && (ij.2 < 2)%N. + +CoInductive sym := Sym (si : seq nat) (sj : seq nat) (sk : seq nat). + +Definition sym_match s th1 th2 := + let: Sym si sj sk := s in let: (ri, rj, rk) := (th_bbox th1, th_dim th1) in + let is_sym r s := uniq s && all (gtn r) s in + let match_cl cl2 := + let: (i2, j2, kvs2) := cl2 in let ij := (nth ri si i2, nth rj sj j2) in + let match_lit kvs1 kv := (nth rk sk kv.1, kv.2) \in kvs1 in + let match_cl1 cl1 := + let: (ij1, kvs1) := cl1 in (ij1 == ij) && all (match_lit kvs1) kvs2 in + uniq (unzip1 kvs2) && has match_cl1 th1 in + [&& is_sym ri si, is_sym rj sj, is_sym rk sk & all match_cl th2]. + +(* Try to compute the base vector permutation for a given row and column *) +(* permutation. We assume each base vector is determined by the entries of *) +(* which it is a proper constituent, and that there are at most two columns. *) +Definition find_sym_k th1 th2 (si sj : seq nat) := + let store_lit c kv ksig := + let: (k, v) := kv in if v == 0 then ksig else let cv := (c, v) in + let fix insert_in (cvs : seq (nat * int)) := + if cvs is cv' :: cvs' then + if (c < cv'.1)%N then cv :: cvs else cv' :: insert_in cvs' + else [:: cv] in + set_nth nil ksig k (insert_in (nth nil ksig k)) in + let fix read_lit ksig1 ksig2 := + if ksig1 is cvs :: ksig1' then + let k := index cvs ksig2 in + k :: read_lit ksig1' (set_nth nil ksig2 k nil) + else nil in + let fix store2 ksig1 ksig2 cls1 := + if cls1 is (i1, j1, kvs1) :: cls1' then + if get_cl (nth 0 si i1, nth 0 sj j1)%N th2 is Some (_, kvs2) then + let st_kvs := foldr (store_lit (i1.*2 + j1)%N) in (* assume j1 <= 1 *) + store2 (st_kvs ksig1 kvs1) (st_kvs ksig2 kvs2) cls1' + else None + else + let sk := read_lit ksig1 ksig2 in + if all (gtn (size ksig2)) sk then Some (Sym si sj sk) else None in + store2 nil nil th1. + +(* Try to find a symmetry that maps th1 to th2, assuming the same number of *) +(* rows and columns, and considering at most one row exchange. *) +Definition find_sym th1 th2 := + let: (ri, rj) := th_bbox th2 in let si := iota 0 ri in let sj := iota 0 rj in + if find_sym_k th1 th2 si sj is Some _ as s then s else + let fix loop m := + if m is i.+1 then + let fix inner_loop m' := + if m' is i'.+1 then + let si' := (set_nth 0 (set_nth 0 si i i') i' i)%N in + if find_sym_k th1 th2 si' sj is Some _ as s then s else inner_loop i' + else None in + if inner_loop i is Some _ as s then s else loop i + else None in + loop ri. + +Section Interpretation. + +Variables (gT : finGroupType) (G : {group gT}). + +Definition is_Lmodel bb b := + [/\ [/\ odd bb.1.+1, odd bb.2.+1, bb.1 > 1, bb.2 > 1 & bb.1 != bb.2]%N, + forall ij, b ij \in 'Z[irr G] + & {in wf_ref bb &, forall ij1 ij2, '[b ij1, b ij2] = (dot_ref ij1 ij2)%:R}]. + +Definition is_Rmodel X := orthonormal X /\ {subset X <= 'Z[irr G]}. + +Inductive model := Model bb f X of is_Lmodel bb f & is_Rmodel X. + +Coercion model_bbox m := let: Model d _ _ _ _ := m in d. +Definition model_entry m := let: Model _ f _ _ _ := m in f. +Coercion model_entry : model >-> Funclass. +Coercion model_basis m := let: Model _ _ X _ _ := m in X. +Lemma LmodelP (m : model) : is_Lmodel m m. Proof. by case: m. Qed. +Lemma RmodelP (m : model) : is_Rmodel m. Proof. by case: m. Qed. + +Fact nil_RmodelP : is_Rmodel nil. Proof. by []. Qed. + +Definition eval_cl (m : model) kvs := \sum_(kv <- kvs) m`_kv.1 *~ kv.2. + +Definition sat_lit (m : model) ij kv := '[m ij, m`_kv.1] == kv.2%:~R. +Definition sat_cl m cl := uniq (unzip1 cl.2) && all (sat_lit m cl.1) cl.2. + +Definition sat (m : model) th := + [&& sub_bbox (th_bbox th) m, th_dim th <= size m & all (sat_cl m) th]%N. +Definition unsat th := forall m, ~ sat m th. + +Lemma satP (m : model) th : + reflect {in th, forall cl, + [/\ cl.1 \in wf_ref m, uniq (unzip1 cl.2) + & {in cl.2, forall kv, kv.1 < size m /\ sat_lit m cl.1 kv}%N]} + (sat m th). +Proof. +apply: (iffP and3P) => [[/th_bboxP thbP /th_dimP thdP /allP thP] cl th_cl |thP]. + have /andP[-> clP] := thP _ th_cl; split=> // [|kv cl_kv]; first exact: thbP. + by rewrite (thdP _ th_cl) ?(allP clP). +split; first by apply/th_bboxP=> cl /thP[]. + by apply/th_dimP=> cl /thP[_ _ clP] kv /clP[]. +by apply/allP=> cl /thP[_ Ucl clP]; rewrite /sat_cl Ucl; apply/allP=> kv /clP[]. +Qed. +Implicit Arguments satP [m th]. + +(* Reflexion of the dot product. *) + +Lemma norm_clP m th cl : + sat m th -> cl \in th -> + let norm := norm_cl cl.2 in let beta := m cl.1 in + [/\ (norm <= 3)%N, norm == 3 -> beta = eval_cl m cl.2 + & (norm < 3)%N -> size cl.2 == size m -> + exists2 dk, dk \in dirr_constt beta & orthogonal (dchi dk) m]. +Proof. +case: cl => ij kvs /satP thP /thP[wf_ij Uks clP] norm beta. +have [[_ ZmL Dm] [o1m ZmR]] := (LmodelP m, RmodelP m). +set ks := unzip1 kvs in Uks; pose Aij := [seq m`_k | k <- ks]. +have lt_ks k: k \in ks -> (k < size m)%N by case/mapP=> kv /clP[ltk _] ->. +have sAm: {subset Aij <= (m : seq _)} + by move=> _ /mapP[k /lt_ks ltk ->]; rewrite mem_nth. +have o1Aij: orthonormal Aij. + have [Um _] := orthonormalP o1m; apply: sub_orthonormal o1m => //. + rewrite map_inj_in_uniq // => k1 k2 /lt_ks ltk1 /lt_ks ltk2 /eqP. + by apply: contraTeq; rewrite nth_uniq. +have [X AijX [Y [defXY oXY oYij]]] := orthogonal_split Aij beta. +have{AijX} defX: X = \sum_(xi <- Aij) '[beta, xi] *: xi. + have [_ -> ->] := orthonormal_span o1Aij AijX; apply: eq_big_seq => xi CFxi. + by rewrite defXY cfdotDl (orthoPl oYij) ?addr0. +have ->: eval_cl m kvs = X. + rewrite {}defX !big_map; apply: eq_big_seq => kv /clP[_ /eqP->]. + by rewrite scaler_int. +rewrite -leC_nat -ltC_nat -eqC_nat /=. +have <-: '[beta] = 3%:R by rewrite Dm // /dot_ref !eqxx. +have <-: '[X] = norm%:R. + rewrite {}defX {}/norm cfnorm_sum_orthonormal // {o1Aij oYij sAm}/Aij. + transitivity (\sum_(kv <- kvs) `|kv.2%:~R| ^+ 2 : algC). + by rewrite !big_map; apply: eq_big_seq => kv /clP[_ /eqP->]. + rewrite unlock /=; elim: (kvs) => //= [[k v] kvs' ->]. + by rewrite -intr_norm -natrX -natrD. +rewrite defXY cfnormDd //; split; first by rewrite ler_paddr ?cfnorm_ge0. + by rewrite eq_sym addrC -subr_eq0 addrK cfnorm_eq0 => /eqP->; rewrite addr0. +have{ZmL} Zbeta: beta \in 'Z[irr G] by apply: ZmL. +have Z_X: X \in 'Z[irr G]. + rewrite defX big_seq rpred_sum // => xi /sAm/ZmR Zxi. + by rewrite rpredZ_Cint ?Cint_cfdot_vchar. +rewrite -ltr_subl_addl subrr cnorm_dconstt; last first. + by rewrite -[Y](addKr X) -defXY addrC rpredB. +have [-> | [dk Ydk] _ /eqP sz_kvs] := set_0Vmem (dirr_constt Y). + by rewrite big_set0 ltrr. +have Dks: ks =i iota 0 (size m). + have: {subset ks <= iota 0 (size m)} by move=> k /lt_ks; rewrite mem_iota. + by case/leq_size_perm=> //; rewrite size_iota size_map sz_kvs. +suffices o_dk_m: orthogonal (dchi dk) m. + exists dk; rewrite // dirr_consttE defX cfdotDl cfdot_suml. + rewrite big1_seq ?add0r -?dirr_consttE // => xi /sAm CFxi. + by rewrite cfdotC cfdotZr (orthoPl o_dk_m) // mulr0 conjC0. +apply/orthoPl=> _ /(nthP 0)[k ltk <-]; have [Um o_m] := orthonormalP o1m. +have Z1k: m`_k \in dirr G by rewrite dirrE ZmR ?o_m ?eqxx ?mem_nth. +apply: contraTeq Ydk => /eqP; rewrite dirr_consttE cfdot_dirr ?dirr_dchi //. +have oYm: '[Y, m`_k] = 0 by rewrite (orthoPl oYij) ?map_f // Dks mem_iota. +by do 2?case: eqP => [-> | _]; rewrite // ?cfdotNr oYm ?oppr0 ltrr. +Qed. + +Lemma norm_cl_eq3 m th cl : + sat m th -> cl \in th -> norm_cl cl.2 == 3 -> m cl.1 = eval_cl m cl.2. +Proof. by move=> m_th /(norm_clP m_th)[]. Qed. + +Lemma norm_lit m th cl kv : + sat m th -> cl \in th -> kv \in cl.2 -> (`|kv.2| <= 1)%N. +Proof. +move=> m_th /(norm_clP m_th)[cl_le3 _ _]. +elim: cl.2 => //= [[k v] kvs IHkvs] in cl_le3 * => /predU1P[-> | /IHkvs->//]. + by apply: contraLR cl_le3; rewrite -ltnNge -leq_sqr => /subnKC <-. +exact: leq_trans (leq_addl _ _) cl_le3. +Qed. + +(* Decision procedure framework (in which we will define O and L). *) + +Definition is_sat_test (tO : pred theory) := forall m th, sat m th -> tO th. + +Lemma sat_testP (rO : rel clause) ij12 : + (forall m th cl1 cl2, sat m th -> cl1 \in th -> cl2 \in th -> rO cl1 cl2) -> + is_sat_test (sat_test rO ij12). +Proof. +rewrite /sat_test => O m th /O O_th; case: get_clP => // cl1 [th_cl1 _]. +by case: get_clP => // cl2 [th_cl2 _]; apply: O_th. +Qed. + +(* Case analysis on the value of a specific projection. *) + +Definition lit_vals : seq int := [:: 0; 1; -1]. + +Lemma sat_cases (m : model) th k cl : + sat m th -> cl \in th -> wf_ext_cl cl k (size m) -> + exists2 v, v \in lit_vals & sat m (unwrap (ext_cl th cl k v)). +Proof. +case: cl => ij kvs /satP thP th_cl /andP[cl'k ltkm]. +have [[_ ZmL _] [o1m ZmR]] := (LmodelP m, RmodelP m). +have [m_ij Uij clP] := thP _ th_cl. +have /CintP[v Dv]: '[m ij, m`_k] \in Cint. + by rewrite Cint_cfdot_vchar ?ZmL ?ZmR ?mem_nth. +have [/= th1 Dthx [th1_cl Dth1]] := ext_clP k v th_cl. +suffices{Dthx} m_th1: sat m th1. + exists v; last by rewrite /ext_cl Dthx. + by case: (v) (norm_lit m_th1 th1_cl (mem_head _ _)); do 2?case. +apply/satP=> cl1; rewrite Dth1 inE; case: ifP => [_ /eqP-> | _ /thP] //=. +by rewrite cl'k; split=> // kv /predU1P[-> | /clP//]; rewrite /sat_lit Dv. +Qed. +Implicit Arguments sat_cases [m th cl]. + +Definition unsat_cases_hyp th0 kvs tO cl := + let: (k, _) := head (2, 0) kvs in let thk_ := ext_cl th0 cl k in + let th's := [seq unwrap (thk_ v) | v <- lit_vals & v \notin unzip2 kvs] in + let add hyp kv := + let: (_, v) := kv in let: Wrap th := thk_ v in hyp /\ unsat th in + foldl add (wf_ext_cl cl k (th_dim th0) && all (predC tO) th's) kvs. + +Lemma unsat_cases th ij kvs tO : + is_sat_test tO -> oapp (unsat_cases_hyp th kvs tO) False (get_cl ij th) -> + unsat th. +Proof. +case: get_clP => //= cl [th_cl _] O; rewrite /unsat_cases_hyp. +case: head => k _; set thk_ := ext_cl th cl k; set add := fun _ _ => _. +set wf_kvs := _ && _; rewrite -[kvs]revK foldl_rev => Ukvs m m_th. +have{Ukvs}: all (fun kv => ~~ sat m (unwrap (thk_ kv.2))) (rev kvs) && wf_kvs. + elim: rev Ukvs => // [[_ v] /= kvs' IH]; case Dthk: (thk_ v) => [thv] [/IH]. + by rewrite -andbA => -> Uthk; rewrite andbT; apply/negP; apply: Uthk. +case/and3P=> /allP Uthkvs /andP[cl'k ltkr] /allP Uthkv's. +have [|{cl'k ltkr} v lit_v m_thv] := sat_cases k m_th th_cl. + by rewrite /wf_ext_cl cl'k (leq_trans ltkr) //; have [] := and3P m_th. +have /idPn[] := O _ _ m_thv; apply: Uthkv's; apply: map_f. +rewrite mem_filter lit_v andbT -mem_rev -map_rev. +by apply: contraL m_thv => /mapP[kv /Uthkvs m'thkv ->]. +Qed. + +(* Dot product reflection. *) + +Lemma O ij12 : is_sat_test (sat_test Otest ij12). +Proof. +apply: sat_testP => m th [ij1 kvs1] [ij2 kvs2] /= m_th th_cl1 th_cl2. +set cl1eq := _ == 3; set cl2eq := _ == 3; have [_ _ Dm] := LmodelP m. +pose goal s1 s2 := cl2eq ==> (`|s1 - (dot_ref ij1 ij2)%:~R| <= s2%:R :> algC). +set kvs := kvs2; set s1 := 0; set s2 := {2}0%N; have thP := satP m_th. +have{thP} [[wf_cl1 _ cl1P] [wf_cl2 _ cl2P]] := (thP _ th_cl1, thP _ th_cl2). +have: goal (s1%:~R + '[m ij1, eval_cl m kvs]) (if cl1eq then 0%N else s2). + apply/implyP=> /(norm_cl_eq3 m_th th_cl2) <-. + by rewrite if_same Dm // addrK normr0. +have /allP: {subset kvs <= kvs2} by []. +rewrite cfdot_sumr unlock; elim: kvs s1 s2 => [|[k v2] kvs IHkvs] s1 s2 /=. + by rewrite addr0 /goal -rmorphB pmulrn -!CintrE. +case/andP=> kvs2_v /IHkvs{IHkvs}IHkvs; have{cl2P} [ltk _] := cl2P _ kvs2_v. +have [v1 /cl1P[_ /eqP/=Dv1] | kvs1'k] := get_litP. + rewrite addrA => gl12; apply: IHkvs; congr (goal (_ + _) _): gl12. + by rewrite raddfMz addrC /= Dv1 -mulrzA -rmorphD. +move=> gl12; apply: IHkvs; case: ifP gl12 => [/(norm_cl_eq3 m_th th_cl1)->|_]. + rewrite cfdot_suml big1_seq ?add0r //= => kv1 kvs1_kv1. + have [[ltk1 _] [/orthonormalP[Um oom] _]] := (cl1P _ kvs1_kv1, RmodelP m). + rewrite -!scaler_int cfdotZl cfdotZr oom ?mem_nth ?nth_uniq // mulrb. + by rewrite ifN ?mulr0 //; apply: contraNneq kvs1'k => <-; apply: map_f. +rewrite /goal -(ler_add2r 1) -mulrSr; case: (cl2eq) => //; apply: ler_trans. +set s := '[_, _]; rewrite -[_ + _](addrK s) (ler_trans (ler_norm_sub _ _)) //. +rewrite 2![_ + s]addrAC addrA ler_add2l {}/s -scaler_int cfdotZr rmorph_int. +have [|v1 _] := sat_cases k m_th th_cl1; first exact/andP. +have [th1 -> /= [th1_cl1 _] m_th1] := ext_clP k v1 th_cl1. +have [_ _ /(_ _ (mem_head _ _))[_ /eqP->]] := satP m_th1 _ th1_cl1. +have ubv1: (`|v1| <= 1)%N := norm_lit m_th1 th1_cl1 (mem_head _ _). +have ubv2: (`|v2| <= 1)%N := norm_lit m_th th_cl2 kvs2_v. +by rewrite -rmorphM -intr_norm lern1 abszM /= (leq_mul ubv2 ubv1). +Qed. + +(* "Without loss" cut rules. *) + +Lemma unsat_wlog cl th : + (let: Wrap th1 := set_cl cl th in (unsat th1 -> unsat th) /\ unsat th1) -> + unsat th. +Proof. by case: set_cl => th1 [Uth /Uth]. Qed. + +Lemma unsat_wlog_cases th1 th2 : + (unsat th1 -> unsat th2) -> unsat th1 -> (true /\ unsat th1) /\ unsat th2. +Proof. by move=> Uth2 Uth1; split; last exact: Uth2. Qed. + +(* Extend the orthonormal basis *) + +Lemma sat_fill m th cl (k := th_dim th) : + sat m th -> cl \in th -> wf_fill k cl.2 -> + exists mr : {CFk | is_Rmodel CFk}, + sat (Model (LmodelP m) (svalP mr)) (unwrap (ext_cl th cl k 1)). +Proof. +move=> m_th th_cl /andP[/eqP sz_kvs n3cl]. +wlog sz_m: m m_th / size m = k. + have lekm: (k <= size m)%N by have [] := and3P m_th. + have mrP: is_Rmodel (take k m). + have [] := RmodelP m; rewrite -{1 2}(cat_take_drop k m) orthonormal_cat /=. + by case/andP=> o1mr _ /allP; rewrite all_cat => /andP[/allP]. + move/(_ (Model (LmodelP m) mrP)); apply; rewrite ?size_takel //. + congr (_ && _): m_th; rewrite lekm size_takel ?leqnn //=. + apply: eq_in_all => cl1 /th_dimP lt_cl1; congr (_ && _). + by apply: eq_in_all => kv1 /lt_cl1 lt_kv1; rewrite /sat_lit nth_take ?lt_kv1. +have [_ _ [//||dk cl_dk o_dk_m]] := norm_clP m_th th_cl. + by rewrite sz_kvs sz_m. +have CFkP: is_Rmodel (rcons m (dchi dk)). + have [o1m /allP Zm] := RmodelP m. + split; last by apply/allP; rewrite all_rcons /= dchi_vchar. + rewrite -cats1 orthonormal_cat o1m orthogonal_sym o_dk_m. + by rewrite /orthonormal /= cfnorm_dchi eqxx. +exists (exist _ _ CFkP); set mk := Model _ _. +have{m_th} mk_th: sat mk th. + congr (_ && _): m_th; rewrite size_rcons sz_m leqnn ltnW //=. + apply: eq_in_all => cl1 /th_dimP lt_cl1; congr (_ && _). + apply: eq_in_all => kv1 /lt_cl1 lt_kv1; congr ('[_, _] == _). + by rewrite nth_rcons sz_m lt_kv1. +have [|{mk_th}v ub_v m_th] := sat_cases k mk_th th_cl. + rewrite /wf_ext_cl size_rcons sz_m (contraFN _ (ltnn k)) //=. + by case/mapP=> kv kv_cl {1}->; rewrite (th_dimP _ _ th_cl). +suffices: 0 < v by case/or4P: ub_v m_th => // /eqP->. +case: (ext_clP k v th_cl) m_th => th1 -> [th1_cl1 _] /and3P[_ _]. +case/allP/(_ _ th1_cl1)/and3P=> _ /eqP/=. +by rewrite nth_rcons sz_m ltnn eqxx CintrE => <- _; rewrite -dirr_consttE. +Qed. + +Lemma unsat_fill ij th : + let fill_cl cl := + if (th_dim th).+1 %/ 1 is k.+1 then + let: Wrap thk := ext_cl th cl k 1 in wf_fill k cl.2 /\ unsat thk + else True in + oapp fill_cl False (get_cl ij th) -> unsat th. +Proof. +rewrite divn1; case: get_clP => //= cl [th_cl _]. +case Dthk: ext_cl => [th1] [wf_thk Uth1] m m_th. +by have [mk] := sat_fill m_th th_cl wf_thk; rewrite Dthk => /Uth1. +Qed. + +(* Matching an assumption exactly. *) + +Lemma sat_exact m th1 th2 : sub_match th1 th2 -> sat m th2 -> sat m th1. +Proof. +move/allP=> s_th12 /satP th2P; apply/satP => cl1 /s_th12/hasP[cl2 th_cl2]. +case: eqP => // <- s_cl12; have [wf_ij2 Ucl2 cl2P] := th2P _ th_cl2. +split=> // [|kv /(mem_subseq s_cl12)/cl2P//]. +by rewrite (subseq_uniq _ Ucl2) ?map_subseq. +Qed. + +Lemma unsat_exact th1 th2 : sub_match th1 th2 -> unsat th1 -> unsat th2. +Proof. by move=> sth21 Uth1 m /(sat_exact sth21)/Uth1. Qed. + +(* Transpose (W1 / W2 symmetry). *) + +Fact tr_Lmodel_subproof (m : model) : is_Lmodel (tr m) (fun ij => m (tr ij)). +Proof. +case: m => /= d f _ [[odd_d1 odd_d2 d1gt1 d2gt1 neq_d12] Zf fP] _. +split=> // [|[j1 i1] [j2 i2]]; first by rewrite eq_sym. +by rewrite ![_ \in _]andbC /= => wf_ij1 wf_ij2; rewrite fP // /dot_ref mulnC. +Qed. + +Definition tr_model m := Model (tr_Lmodel_subproof m) (RmodelP m). + +Lemma sat_tr m th : sat m th -> sat (tr_model m) (tr_th th). +Proof. +move/satP=> thP; apply/satP=> _ /mapP[[[i j] kvs] /thP[m_ij Uks kvsP] ->]. +by rewrite inE /= andbC. +Qed. + +(* Extend the theory (add a new empty clause). *) + +Lemma unsat_consider ij th : + wf_consider ij th -> unsat (AddClause th (& ? in ij)) -> unsat th. +Proof. +case: ij => i j; case/andP; set sym_t := sub_match _ _ => lti ltj Uthij m m_th. +wlog le_m21: m m_th / sym_t -> (m.2 <= m.1)%N. + move=> IH; apply: (IH m m_th) => sym_th. + rewrite leqNgt; apply/negP=> /leqW le_m1_m2. + by have /(sat_exact sym_th)/IH[] := sat_tr m_th. +apply: (Uthij m); congr (_ && _): (m_th) => /=; case: (th_bbox th) => ri rj /=. +have [[odd_m1 _ m1gt1 m2gt1 neq_m12] _ _] := LmodelP m. +rewrite /sub_bbox !geq_max (leq_trans ltj) ?(leq_trans lti) //; case: orP => //. +rewrite -(ltnS 4) (odd_geq _ odd_m1) ltnS. +case=> [/leq_trans-> // | /le_m21]; first by have [/andP[]] := and3P m_th. +by rewrite leq_eqVlt eq_sym (negPf neq_m12); apply: leq_trans. +Qed. + +(* Matching up to a permutation of the rows, columns, and base vectors. *) + +Lemma unsat_match s th1 th2 : sym_match s th1 th2 -> unsat th2 -> unsat th1. +Proof. +pose I_ si mi := si ++ filter [predC si] (iota 0 mi). +have SsP mi si ri (Ii := I_ si mi): + uniq si && all (gtn ri) si -> (ri <= mi)%N -> + [/\ {in Ii, forall i, i < mi}%N, uniq Ii & size Ii = mi]. +- case/andP=> Usi /allP/=ltsi le_ri_mi; have uIm := iota_uniq 0 mi. + have uIi: uniq Ii by rewrite cat_uniq Usi -all_predC filter_all filter_uniq. + have defIi: Ii =i iota 0 mi. + move=> i; rewrite mem_cat mem_filter orb_andr orbN mem_iota. + by apply: orb_idl => /ltsi/leq_trans->. + split=> // [i|]; first by rewrite defIi mem_iota. + by rewrite (perm_eq_size (uniq_perm_eq _ _ defIi)) ?size_iota. +have lt_nth ri si i: (nth ri si i < ri)%N -> (i < size si)%N. + by rewrite !ltnNge; apply: contra => le_si; rewrite nth_default. +case: s => [si sj sk] /= sym12 Uth2 m m_th1; case/and3P: (m_th1) sym12. +case: th_bbox (th_bboxP (bbox_refl (th_bbox th1))) => ri rj rijP. +case/andP=> /= leri lerj lerk _ /and4P[Ssi Ssj /andP[Usk /allP/=lesrk] sym12]. +have{Ssi} /SsP/(_ leri)[ltIi uIi szIi] := Ssi. +have{Ssj SsP} /SsP/(_ lerj)[ltIj uIj szIj] := Ssj. +pose smL ij := m (nth ri (I_ si m.1) ij.1, nth rj (I_ sj m.2) ij.2)%N. +pose smR := [seq m`_k | k <- sk]. +have [[lb_m ZmL Dm] [o1m ZmR]] := (LmodelP m, RmodelP m). +have{lb_m} smLP: is_Lmodel m smL. + split=> // [ij | ij1 ij2 /andP[lti1 ltj1] /andP[lti2 ltj2]]; first exact: ZmL. + by rewrite Dm ?inE /dot_ref/= ?nth_uniq ?ltIi ?ltIj ?mem_nth ?szIi ?szIj. +have{lesrk} ubk k: k \in sk -> (k < size m)%N by move=> /lesrk/leq_trans->. +have smRP: is_Rmodel smR. + have ssmR: {subset smR <= (m : seq _)}. + by move=> _ /mapP[k s_k ->]; rewrite mem_nth ?ubk. + split=> [|xi /ssmR/ZmR//]; have [Um _] := orthonormalP o1m. + apply: sub_orthonormal o1m; rewrite ?map_inj_in_uniq //. + by apply: can_in_inj (index^~ m) _ => k s_k; rewrite /= index_uniq ?ubk. +apply: (Uth2 (Model smLP smRP)); apply/satP=> [][[i2 j2] kvs2] /(allP sym12). +case/andP=> -> /hasP[[[i1 j1] kvs1] th1_cl1 /andP[/eqP[Di1 Dj1] /allP s_kv12]]. +have:= rijP _ th1_cl1; rewrite Di1 Dj1 => /andP[/lt_nth lti1 /lt_nth ltj1]. +rewrite !inE -szIi -szIj !size_cat !(leq_trans _ (leq_addr _ _)) //. +split=> // kv /s_kv12 kvs1_kv1; rewrite size_map /sat_lit /=. +have /lt_nth ltk := th_dimP (leqnn _) _ th1_cl1 _ kvs1_kv1; split=> //. +rewrite (nth_map (th_dim th1)) // /smL !nth_cat lti1 ltj1 -Di1 -Dj1. +by have [_ _ /(_ _ kvs1_kv1)[]] := satP m_th1 _ th1_cl1. +Qed. + +Lemma unsat_sym th1 th2 : + (if find_sym th1 th2 is Some s then sym_match s th2 th1 else false) -> + unsat th1 -> unsat th2. +Proof. by case: find_sym => // s; apply: unsat_match. Qed. + +End Interpretation. + +Implicit Arguments satP [gT G m th]. +Implicit Arguments unsat [gT G]. +Implicit Arguments sat_cases [gT G m th cl]. +Implicit Arguments unsat_cases [gT G th tO]. +Implicit Arguments unsat_wlog [gT G]. +Implicit Arguments unsat_fill [gT G]. +Implicit Arguments unsat_consider [gT G]. +Implicit Arguments unsat_match [gT G th1 th2]. + +(* The domain-specific tactic language. *) + +Tactic Notation "consider" constr(ij) := + apply: (unsat_consider ij); first exact isT. + +(* Note that "split" here would be significantly less efficient, because it *) +(* would evaluate the reflected assumption four times. *) +Tactic Notation "fill" constr(ij) := + apply: (unsat_fill ij); apply: (conj isT _). + +Tactic Notation "uwlog" simple_intropattern(IH) ":" constr(cl) := + apply: (unsat_wlog cl); split=> [IH | ]. + +Tactic Notation "uwlog" simple_intropattern(IH) ":" constr(cl) + "by" tactic4(tac) := + apply: (unsat_wlog cl); split=> [IH | ]; first by [tac]. + +Tactic Notation "uhave" constr(kv) "in" constr(ij) + "as" constr(T) constr(ij12) := + apply: (unsat_cases ij [:: kv] (T ij12)); apply: (conj isT _). + +Tactic Notation "uhave" constr(kv1) "," constr(kv2) "in" constr(ij) + "as" constr(T) constr(ij12) := + uhave kv1 in ij as T ij12; uhave kv2 in ij as T ij12. + +Tactic Notation "uhave" constr(kv1) "|" constr(kv2) "in" constr(ij) + "as" constr(T) constr(ij12) := + apply: (unsat_cases ij [:: kv1; kv2] (T ij12)); apply: (conj (conj isT _) _). + +Tactic Notation "uhave" constr(kv1) "|" constr(kv2) "|" constr(kv3) + "in" constr(ij) := + apply: (unsat_cases ij [:: kv1; kv2; kv3] (fun _ _ _ => isT)); + apply: (conj (conj (conj isT _) _) _). + +Tactic Notation "uwlog" simple_intropattern(IH) ":" + constr(kv1) "|" constr(kv2) "in" constr(ij) + "as" constr(T) constr(ij12) := + apply: (unsat_cases ij [:: kv1; kv2] (T ij12)); + apply: unsat_wlog_cases => [IH | ]. + +Tactic Notation "counter" "to" constr(T) constr(ij12) := by move=> ? /(T ij12). + +Tactic Notation "uexact" constr(IH) := apply: unsat_exact IH; exact isT. + +Tactic Notation "symmetric" "to" constr(IH) := apply: unsat_sym (IH); exact isT. + +End CyclicTIisoReflexion. + +Section Three. + +Variables (gT : finGroupType) (G W W1 W2 : {group gT}). +Hypothesis defW : W1 \x W2 = W. + +Let V := cyclicTIset defW. +Let w_ i j := cyclicTIirr defW i j. +Let w1 := #|W1|. +Let w2 := #|W2|. + +Lemma cyclicTIirrC (xdefW : W2 \x W1 = W) i j : + cyclicTIirr xdefW j i = w_ i j. +Proof. by rewrite (dprod_IirrC xdefW defW). Qed. + +Lemma cycTIirrP chi : chi \in irr W -> {i : Iirr W1 & {j | chi = w_ i j}}. +Proof. +case/irrP/sig_eqW=> k ->{chi}. +by have /codomP/sig_eqW[[i j] ->] := dprod_Iirr_onto defW k; exists i, j. +Qed. + +Lemma cycTIirr_aut u i j : w_ (aut_Iirr u i) (aut_Iirr u j) = cfAut u (w_ i j). +Proof. by rewrite /w_ !dprod_IirrE cfAutDprod !aut_IirrE. Qed. + +Let sW1W : W1 \subset W. Proof. by have /mulG_sub[] := dprodW defW. Qed. +Let sW2W : W2 \subset W. Proof. by have /mulG_sub[] := dprodW defW. Qed. + +Lemma card_cycTIset : #|V| = (w1.-1 * w2.-1)%N. +Proof. +have [_ _ _ tiW12] := dprodP defW. +rewrite cardsD (setIidPr _) ?subUset ?sW1W // cardsU {}tiW12 cards1. +rewrite -(dprod_card defW) -addnBA // -!subn1 -/w1 -/w2 subnDA. +by rewrite mulnBl mulnBr mul1n muln1. +Qed. + +Definition cfCyclicTIset i j := cfDprod defW (1 - 'chi_i) (1 - 'chi_j). +Local Notation alpha_ := cfCyclicTIset. + +Lemma cycTIirr00 : w_ 0 0 = 1. Proof. by rewrite /w_ dprod_Iirr0 irr0. Qed. +Local Notation w_00 := cycTIirr00. + +Lemma cycTIirr_split i j : w_ i j = w_ i 0 * w_ 0 j. +Proof. by rewrite /w_ !dprod_IirrE !irr0 cfDprod_split. Qed. + +Lemma cfker_cycTIl j : W1 \subset cfker (w_ 0 j). +Proof. by rewrite /w_ dprod_IirrE irr0 cfDprod_cfun1l cfker_sdprod. Qed. + +Lemma cfker_cycTIr i : W2 \subset cfker (w_ i 0). +Proof. by rewrite /w_ dprod_IirrE irr0 cfDprod_cfun1r cfker_sdprod. Qed. + +Let cfdot_w i1 j1 i2 j2 : '[w_ i1 j1, w_ i2 j2] = ((i1 == i2) && (j1 == j2))%:R. +Proof. exact: cfdot_dprod_irr. Qed. + +Lemma cfCycTI_E i j : alpha_ i j = 1 - w_ i 0 - w_ 0 j + w_ i j. +Proof. +rewrite -w_00 -[w_ i j]opprK /w_ !dprod_IirrE !irr0 -addrA -opprD -!mulrBl. +by rewrite -mulrBr -!rmorphB. +Qed. +Local Notation alphaE := cfCycTI_E. + +Lemma cfCycTI_vchar i j : alpha_ i j \in 'Z[irr W]. +Proof. by rewrite alphaE rpredD ?rpredB ?rpred1 ?irr_vchar. Qed. + +Definition cfCyclicTIsetBase := + [seq alpha_ ij.1 ij.2 | ij in setX [set~ 0] [set~ 0]]. +Local Notation cfWVbase := cfCyclicTIsetBase. + +Let cfdot_alpha_w i1 j1 i2 j2 : + i2 != 0 -> j2 != 0 -> '[alpha_ i1 j1, w_ i2 j2] = [&& i1 == i2 & j1 == j2]%:R. +Proof. +move=> nzi2 nzj2; rewrite alphaE -w_00 !cfdotDl !cfdotNl !cfdot_w. +by rewrite !(eq_sym 0) (negPf nzi2) (negPf nzj2) /= andbF !subr0 add0r. +Qed. + +Let cfdot_alpha_1 i j : i != 0 -> j != 0 -> '[alpha_ i j, 1] = 1. +Proof. +move=> nzi nzj; rewrite alphaE -w_00 !cfdotDl !cfdotNl !cfdot_w. +by rewrite !eqxx andbT /= (negPf nzi) (negPf nzj) addr0 !subr0. +Qed. + +Let cfnorm_alpha i j : i != 0 -> j != 0 -> '[alpha_ i j] = 4%:R. +Proof. +move=> nzi nzj; rewrite -[4]/(size [:: 1; - w_ i 0; - w_ 0 j; w_ i j]). +rewrite -cfnorm_orthonormal 3?big_cons ?big_seq1 ?addrA -?alphaE //. +rewrite /orthonormal -w_00 /= !cfdotNl !cfdotNr !opprK !oppr_eq0 !cfnorm_irr. +by rewrite !cfdot_w !eqxx /= !(eq_sym 0) (negPf nzi) (negPf nzj) !eqxx. +Qed. + +Lemma cfCycTIbase_free : free cfWVbase. +Proof. +apply/freeP=> s /= s_alpha_0 ij; case def_ij: (enum_val ij) => [i j]. +have /andP[nzi nzj]: (i != 0) && (j != 0). + by rewrite -!in_setC1 -in_setX -def_ij enum_valP. +have:= congr1 (cfdotr (w_ i j)) s_alpha_0; rewrite raddf_sum raddf0 => <-. +rewrite (bigD1 ij) //= nth_image def_ij cfdotZl cfdot_alpha_w // !eqxx mulr1. +rewrite big1 ?addr0 // => ij1; rewrite nth_image -(inj_eq enum_val_inj) def_ij. +case: (enum_val ij1) => i1 j1 /= => ne_ij1_ij. +by rewrite cfdotZl cfdot_alpha_w // mulr_natr mulrb ifN. +Qed. + +(* Further results on alpha_ depend on the assumption that W is cyclic. *) + +Hypothesis ctiW : cyclicTI_hypothesis G defW. + +Let cycW : cyclic W. Proof. by case: ctiW. Qed. +Let oddW : odd #|W|. Proof. by case: ctiW. Qed. +Let tiV : normedTI V G W. Proof. by case: ctiW. Qed. +Let ntV : V != set0. Proof. by case/andP: tiV. Qed. + +Lemma cyclicTIhyp_sym (xdefW : W2 \x W1 = W) : cyclicTI_hypothesis G xdefW. +Proof. by split; rewrite // /cyclicTIset setUC. Qed. + +Let cycW1 : cyclic W1. Proof. exact: cyclicS cycW. Qed. +Let cycW2 : cyclic W2. Proof. exact: cyclicS cycW. Qed. +Let coW12 : coprime w1 w2. Proof. by rewrite -(cyclic_dprod defW). Qed. + +Let Wlin k : 'chi[W]_k \is a linear_char. Proof. exact/irr_cyclic_lin. Qed. +Let W1lin i : 'chi[W1]_i \is a linear_char. Proof. exact/irr_cyclic_lin. Qed. +Let W2lin i : 'chi[W2]_i \is a linear_char. Proof. exact/irr_cyclic_lin. Qed. +Let w_lin i j : w_ i j \is a linear_char. Proof. exact: Wlin. Qed. + +Let nirrW1 : #|Iirr W1| = w1. Proof. exact: card_Iirr_cyclic. Qed. +Let nirrW2 : #|Iirr W2| = w2. Proof. exact: card_Iirr_cyclic. Qed. +Let NirrW1 : Nirr W1 = w1. Proof. by rewrite -nirrW1 card_ord. Qed. +Let NirrW2 : Nirr W2 = w2. Proof. by rewrite -nirrW2 card_ord. Qed. + +Lemma cycTI_nontrivial : W1 :!=: 1%g /\ W2 :!=: 1%g. +Proof. +apply/andP; rewrite -!cardG_gt1 -!(subn_gt0 1) !subn1 -muln_gt0. +by rewrite -card_cycTIset card_gt0. +Qed. + +Let ntW1 : W1 :!=: 1%g. Proof. by case: cycTI_nontrivial. Qed. +Let ntW2 : W2 :!=: 1%g. Proof. by case: cycTI_nontrivial. Qed. +Let oddW1 : odd w1. Proof. exact: oddSg oddW. Qed. +Let oddW2 : odd w2. Proof. exact: oddSg oddW. Qed. +Let w1gt2 : (2 < w1)%N. Proof. by rewrite odd_gt2 ?cardG_gt1. Qed. +Let w2gt2 : (2 < w2)%N. Proof. by rewrite odd_gt2 ?cardG_gt1. Qed. + +Let neq_w12 : w1 != w2. +Proof. +by apply: contraTneq coW12 => ->; rewrite /coprime gcdnn -(subnKC w2gt2). +Qed. + +Let cWW : abelian W. Proof. exact: cyclic_abelian. Qed. +Let nsVW : V <| W. Proof. by rewrite -sub_abelian_normal ?subsetDl. Qed. +Let sWG : W \subset G. Proof. by have [_ /subsetIP[]] := normedTI_P tiV. Qed. +Let sVG : V \subset G^#. Proof. by rewrite setDSS ?subsetU ?sub1G. Qed. + +Let alpha1 i j : alpha_ i j 1%g = 0. +Proof. by rewrite cfDprod1 !cfunE cfun11 lin_char1 // subrr mul0r. Qed. + +(* This first part of Peterfalvi (3.4) will be used in (4.10) and (13.9). *) +Lemma cfCycTI_on i j : alpha_ i j \in 'CF(W, V). +Proof. +apply/cfun_onP=> x; rewrite !inE negb_and negbK orbC. +case/or3P => [/cfun0->// | W1x | W2x]. + by rewrite -[x]mulg1 cfDprodE // !cfunE cfun11 lin_char1 ?subrr ?mulr0. +by rewrite -[x]mul1g cfDprodE // !cfunE cfun11 lin_char1 ?subrr ?mul0r. +Qed. + +(* This is Peterfalvi (3.4). *) +Lemma cfCycTIbase_basis : basis_of 'CF(W, V) cfWVbase. +Proof. +rewrite basisEfree cfCycTIbase_free /=. +have ->: \dim 'CF(W, V) = #|V| by rewrite dim_cfun_on_abelian ?subsetDl. +rewrite size_tuple cardsX !cardsC1 nirrW1 nirrW2 -card_cycTIset leqnn andbT. +by apply/span_subvP=> _ /imageP[[i j] _ ->]; apply: cfCycTI_on. +Qed. +Local Notation cfWVbasis := cfCycTIbase_basis. + +Section CyclicTIisoBasis. + +Import CyclicTIisoReflexion ssrint. + +Local Notation unsat := (@unsat gT G). +Local Notation O := (@O gT G). +Local Notation "#1" := (inord 1). + +(* This is the combinatorial core of Peterfalvi (3.5.2). *) +(* Peterfalvi uses evaluation at 1%g to conclude after the second step; since *) +(* this is not covered by our model, we have used the dot product constraints *) +(* between b12 and b11, b21 instead. *) +Let unsat_J : unsat |= & x1 in b11 & -x1 in b21. +Proof. +uwlog b11x1: (& b11 = x1 + x2 + x3) by do 2!fill b11. +uwlog b21x1: (& b21 = -x1 + x2 + x3) by uhave x2, x3 in b21 as O(21, 11). +consider b12; uhave -x2 | x2 | ~x2 in b12. +- by uhave x1 in b12 as O(12, 11); counter to O(12, 21). +- uhave x1 | ~x1 in b12 as O(12, 21). + by uhave ~x3 in b12 as O(12, 21); counter to O(12, 11). + by uhave ~x3 in b12 as O(12, 11); counter to O(12, 21). +uhave x3 | ~x3 in b12 as O(12, 11). + by uhave x1 in b12 as O(12, 21); counter to O(12, 11). +by uhave x1 in b12 as O(12, 11); counter to O(12, 21). +Qed. + +Let unsat_II: unsat |= & x1, x2 in b11 & x1, x2 in b21. +Proof. by fill b11; uhave -x3 in b21 as O(21, 11); symmetric to unsat_J. Qed. + +(* This reflects the application of (3.5.2), but only to rule out nonzero *) +(* components of the first entry that conflict with positive components of *) +(* the second entry; Otest covers all the other uses of (3.5.2) in the proof. *) +Let Ltest (cl1 cl2 : clause) := + let: (i1, j1, kvs1) := cl1 in let: (i2, j2, kvs2) := cl2 in + let fix loop mm kvs2' := + if kvs2' is (k, v2) :: kvs2'' then + let v1 := odflt 0 (get_lit k kvs1) in + if (v2 != 1) || (v1 == 0) then loop mm kvs2'' else + if (v1 != 1) || mm then false else loop true kvs2'' + else true in + (i1 == i2) (+) (j1 == j2) ==> loop false kvs2. + +Let L ij12 : is_sat_test G (sat_test Ltest ij12). +Proof. +apply: sat_testP => m th [[i1 j1] kvs1] [[i2 j2] kvs2] m_th th_cl1 th_cl2. +wlog eq_j: m th i1 i2 j1 j2 m_th th_cl1 th_cl2 / j1 == j2. + move=> IH; case eq_j: (j1 == j2); first exact: IH m_th th_cl1 th_cl2 eq_j. + case eq_i: (i1 == i2); last by rewrite /= eq_i eq_j. + have /(_ (_, _, _)) mem_trt: _ \in tr_th th := map_f _ _. + by rewrite /= addbC; apply: IH (sat_tr m_th) _ _ eq_i; rewrite ?mem_trt. +apply/implyP; rewrite eq_j addbT => neq_i. +rewrite -[f in f _ kvs2]/(idfun _); set f := idfun _; rewrite /= in f *. +have [/= _ Ukvs2 kvsP] := satP m_th _ th_cl2. +move: Ukvs2; set kvs2' := kvs2; set mm := false. +have /allP: {subset kvs2' <= kvs2} by []. +pose lit12 k := (k, 1) \in kvs1 /\ (k, 1) \in kvs2. +have: mm -> {k | lit12 k & k \notin unzip1 kvs2'} by []. +elim: kvs2' mm => [|[k v2] kvs2' IH] //= mm mmP /andP[kvs2k /IH{IH}IHkvs]. +case/andP=> kvs2'k /IHkvs{IHkvs}IHkvs; case: ifP => [_ | /norP[]]. + by apply/IHkvs=> /mmP[kv kvs12kv /norP[]]; exists kv. +have [v1 /= kvs1k | //] := get_litP; case: eqP => // -> in kvs2k * => _ nz_v1. +case Dbb: (th_bbox th) (th_bboxP (bbox_refl (th_bbox th))) => [ri rj] rijP. +have [/andP[/=lti1r ltj1r] /andP[/=lti2r _]] := (rijP _ th_cl1, rijP _ th_cl2). +have rkP := th_dimP (leqnn _) _ th_cl1; have /= ltkr := rkP _ kvs1k. +have symP := unsat_match (Sym [:: i2; i1] [:: j1] _) _ _ m m_th. +rewrite /= Dbb lti1r lti2r ltj1r inE eq_sym neq_i /= in symP. +have [Dv1 | v1_neq1] /= := altP eqP; first rewrite Dv1 in kvs1k. + case: ifP => [/mmP[k0 [kvs1k0 kvs2k0]] | _]; last by apply: IHkvs; exists k. + case/norP=> k'k0; have [/=] := symP [:: k0; k] _ _ unsat_II. + rewrite inE k'k0 ltkr (rkP _ kvs1k0) /= andbT; apply/andP; split; apply/hasP. + by exists (i1, j1, kvs1) => //=; rewrite eqxx kvs1k kvs1k0. + by exists (i2, j2, kvs2) => //=; rewrite (eqP eq_j) eqxx kvs2k kvs2k0. +have{nz_v1 v1_neq1} Dv1: v1 = -1; last rewrite Dv1 in kvs1k. + by case: (v1) nz_v1 v1_neq1 (norm_lit m_th th_cl1 kvs1k) => [[|[]] | []]. +have[] := symP [:: k] _ _ unsat_J; rewrite /= ltkr !andbT /=; apply/andP; split. + by apply/hasP; exists (i1, j1, kvs1); rewrite //= eqxx kvs1k. +by apply/hasP; exists (i2, j2, kvs2); rewrite //= (eqP eq_j) eqxx kvs2k. +Qed. + +(* This is the combinatorial core of Peterfalvi (3.5.4). *) +(* We have made a few simplifications to the combinatorial analysis in the *) +(* text: we omit the (unused) step (3.5.4.4) entirely, which lets us inline *) +(* step (3.5.4.1) in the proof of (3.5.4.2); we clear the assumptions on b31 *) +(* and b32 before the final step (3.5.4.5), exposing a hidden symmetry. *) +Let unsat_Ii : unsat |= & x1 in b11 & x1 in b21 & ~x1 in b31. +Proof. +uwlog Db11: (& b11 = x1 + x2 + x3) by do 2!fill b11. +uwlog Db21: (& b21 = x1 + x4 + x5). + by uhave ~x2, ~x3 in b21 as L(21, 11); do 2!fill b21; uexact Db21. +uwlog Db31: (& b31 = x2 + x4 + x6). + uwlog b31x2: x2 | ~x2 in b31 as L(31, 11). + by uhave x3 in b31 as O(31, 11); symmetric to b31x2. + uwlog b31x4: x4 | ~x4 in b31 as L(31, 21). + by uhave x5 in b31 as O(31, 21); symmetric to b31x4. + uhave ~x3 in b31 as O(31, 11); uhave ~x5 in b31 as L(31, 21). + by fill b31; uexact Db31. +consider b41; uwlog b41x1: x1 | ~x1 in b41 as L(41, 11). + uwlog Db41: (& b41 = x3 + x5 + x6) => [|{b41x1}]. + uhave ~x2 | x2 in b41 as L(41, 11); last symmetric to b41x1. + uhave ~x4 | x4 in b41 as L(41, 21); last symmetric to b41x1. + uhave x3 in b41 as O(41, 11); uhave x5 in b41 as O(41, 21). + by uhave x6 in b41 as O(41, 31); uexact Db41. + consider b12; uwlog b12x1: x1 | ~x1 in b12 as L(12, 11). + uhave ~x2 | x2 in b12 as L(12, 11); last symmetric to b12x1. + by uhave x3 in b12 as O(12, 11); symmetric to b12x1. + uwlog b12x4: -x4 | ~x4 in b12 as O(12, 21). + by uhave -x5 in b12 as O(12, 21); symmetric to b12x4. + uhave ~x2, ~x3 in b12 as L(12, 11); uhave ~x5 in b12 as O(12, 21). + by uhave x6 in b12 as O(12, 31); counter to O(12, 41). +uwlog Db41: (& b41 = x1 + x6 + x7). + uhave ~x2, ~x3 in b41 as L(41, 11); uhave ~x4, ~x5 in b41 as L(41, 21). + by uhave x6 in b41 as O(41, 31); fill b41; uexact Db41. +consider b32; uwlog Db32: (& b32 = x6 - x7 + x8). + uwlog b32x6: x6 | ~x6 in b32 as L(32, 31). + uhave ~x2 | x2 in b32 as L(32, 31); last symmetric to b32x6. + by uhave x4 in b32 as O(32, 31); symmetric to b32x6. + uhave ~x2, ~x4 in b32 as L(32, 31). + uhave -x7 | ~x7 in b32 as O(32, 41). + uhave ~x1 in b32 as O(32, 41); uhave ~x3 in b32 as O(32, 11). + by uhave ~x5 in b32 as O(32, 21); fill b32; uexact Db32. + uhave -x1 in b32 as O(32, 41). + by uhave x3 in b32 as O(32, 11); counter to O(32, 21). +consider b42; uwlog Db42: (& b42 = x6 - x4 + x5). + uhave ~x6 | x6 in b42 as L(42, 41). + uhave ~x7 | x7 in b42 as L(42, 41); last counter to O(42, 32). + uhave x1 in b42 as O(42, 41); uhave x8 in b42 as O(42, 32). + uhave ~x2 | -x2 in b42 as O(42, 11); last counter to O(42, 21). + by uhave -x3 in b42 as O(42, 11); counter to O(42, 21). + uwlog b42x4: -x4 | ~x4 in b42 as O(42, 31). + by uhave -x2 in b42 as O(42, 31); symmetric to b42x4. + by uhave ~x1 in b42 as L(42, 41); uhave x5 in b42 as O(42, 21); uexact Db42. +uwlog Db32: (& ? in b32); first uexact Db32. +uwlog Db41: (& ? in b41); first uexact Db41. +consider b12; uwlog b12x5: x5 | ~x5 in b12 as L(12, 42). + uhave ~x6 | x6 in b12 as L(12, 42); last by consider b22; symmetric to b12x5. + uhave -x4 in b12 as O(12, 42); uhave x1 in b12 as O(12, 21). + by uhave ~x2 in b12 as L(12, 11); counter to O(12, 31). +uhave ~x6 in b12 as L(12, 42); uhave ~x4 in b12 as O(12, 42). +uhave ~x2 in b12 as O(12, 31). +by uhave -x1 in b12 as O(12, 21); counter to L(12, 11). +Qed. + +Let unsat_C : unsat |= & x1 in b11 & x1 in b21 & x1 in b12. +Proof. +consider b31; uwlog Db21: (& b21 = x1 + x2 + x3) by do 2!fill b21. +uwlog Db12: (& b12 = x1 - x2 + x4). + uwlog b21x2: -x2 | ~x2 in b12 as O(12, 21). + by uhave -x3 in b12 as O(12, 21); symmetric to b21x2. + by uhave ~x3 in b12 as O(12, 21); fill b12; uexact Db12. +uwlog Db31: (& b31 = x1 - x4 + x5). + uhave x1 | ~x1 in b31 as L(31, 21); last uexact unsat_Ii. + uhave ~x2, ~x3 in b31 as L(31, 21). + by uhave -x4 in b31 as O(31, 12); fill b31; uexact Db31. +consider b41; uhave x1 | ~x1 in b41 as L(41, 21); last symmetric to unsat_Ii. +uhave ~x5 in b41 as L(41, 31); uhave ~x4 in b41 as O(41, 31). +by uhave ~x2 in b41 as L(41, 21); counter to O(41, 12). +Qed. + +(* This refinement of Peterfalvi (3.5.4) is the essential part of (3.5.5). *) +Let column_pivot (m : model G) (j0 : 'I_m.2.+1) : + exists dk, forall (i : 'I_m.1.+1) (j : 'I_m.2.+1), + j0 != 0 -> i != 0 -> j != 0 -> '[m (i.-1, j.-1), dchi dk] = (j == j0)%:R. +Proof. +pose t_i (i0 i1 : nat) := [eta id with i0 |-> i1, i1 |-> i0]. +pose t_ij i0 i1 ij : ref := (t_i i0 i1 ij.1, ij.2). +have t_iK i0 i1: involutive (t_i i0 i1). + move=> i /=; have [-> | i0'i] := altP (i =P i0). + by rewrite eqxx; case: eqP. + by have [-> | /negPf->] := altP (i =P i1); rewrite ?eqxx // ifN. +have lt_t_i i0 i1 ri i: (i0 <= i1 < ri)%N -> (t_i i0 i1 i < ri)%N = (i < ri)%N. + case/andP=> le_i01 lti1 /=. + by do 2?case: eqP => [-> | _] //; rewrite ?(leq_trans _ lti1). +have t_mP i0 i1 (m0 : model G): + (i0 <= i1 < m0.1)%N -> is_Lmodel m0 (m0 \o t_ij i0 i1). +- have [lbm0 Zm0 Dm0] := LmodelP m0; split=> //= ij1 ij2 wf_ij1 wf_ij2. + by rewrite Dm0 /dot_ref ?(can_eq (t_iK _ _)) // !inE ?lt_t_i. +pose t_m i0 i1 m0 lti01 := Model (t_mP i0 i1 m0 lti01) (RmodelP m0). +without loss suffices{j0 lt_t_i} IHm: m / + exists dk, {in wf_ref m, forall ij, '[m ij, dchi dk] = (ij.2 == 0%N)%:R}. +- have [_ | nzj0] := altP eqP; first by exists (dirr1 G). + have ltj0: (j0.-1 < m.2)%N by rewrite prednK ?lt0n ?leq_ord. + have{IHm} [dk Ddk] := IHm (tr_model (t_m 0%N j0.-1 (tr_model m) ltj0)). + exists dk => i j _ nzi nzj; rewrite -[j.-1](t_iK 0%N j0.-1). + rewrite (Ddk (_, _)) ?inE ?lt_t_i // ?prednK ?lt0n ?leq_ord //. + by rewrite (inv_eq (t_iK _ _)) -eqSS !prednK ?lt0n. +pose cl11 := & b11 = x1 + x2 + x3. +without loss m_th: m / sat m |= cl11 & ? in b21. + move=> IHm; suffices{IHm}: sat m |= & ? in b11 & ? in b21. + have fill_b11 := sat_fill _ (mem_nth cl11 (_ : 1 < _))%N. + by do 3![case/fill_b11=> // ?]; apply: IHm. + have [[_ _ m1gt2 /ltnW m2gt0 _] _ _] := LmodelP m. + by rewrite /sat /= -!andbA /= m2gt0 -(subnKC m1gt2). +without loss{m_th} m_th: m / sat m |= & x1 in b11 & x1 in b21. + pose sat123P := @allP _ (fun k => sat_lit m _ (k, _)) (rev (iota 0 3)). + have [m123 | ] := altP (sat123P b21 0). + suffices: sat m |= cl11 & ~x1, ~x2, ~x3 in b21 by move/(O(21, 11)). + by rewrite /sat /= {1}/sat_cl /= !m123. + case/allPn=> k k012 /negP nz_m21 IHm; rewrite -[sat_lit _ _ _]andbT in nz_m21. + have ltk3: (k < 3)%N by rewrite mem_rev mem_iota in k012. + have [[/andP[/allP/=n1m _] Zm] [_ /= m_gt2 _]] := (RmodelP m, and3P m_th). + have ltk := leq_trans ltk3 m_gt2. + have{n1m Zm} mkP: is_Rmodel [:: m`_k]. + by split=> [|_ /predU1P[->|//]]; rewrite /orthonormal /= ?n1m ?Zm ?mem_nth. + pose mk := Model (LmodelP m) mkP; apply: {IHm}(IHm mk). + have{m_th} [v lit_v m_th] := sat_cases k m_th (mem_head _ _) ltk. + suffices: sat mk |= & x1 in b11 & (Lit 1 v) in b21. + by case/or4P: lit_v m_th => // /eqP-> => [/and4P[] | | _ /(L(21,11))]. + have [m_bb _ m_b21 /sat123P m_b11 _] := and5P m_th. + by apply/and5P; split; rewrite // /sat_cl /= [sat_lit _ _ _]m_b11. +have /dIrrP[dk Ddk]: m`_0 \in dirr G. + have [[/andP[/allP n1m _] Zm] [_ m_gt0 _]] := (RmodelP m, and3P m_th). + by rewrite dirrE Zm ?[_ == 1]n1m ?mem_nth. +exists dk => [][i j] /andP[/= lti ltj]; apply/eqP. +suffices{dk Ddk}: sat_cl m (& (Lit 1 (j == 0))%N in (i, j)). + by rewrite /sat_cl /= andbT /sat_lit Ddk. +without loss{i lti} ->: m i ltj m_th / i = 0%N. + have [bb21_m m_gt0 m11_x1 m21_x1 _] := and5P m_th. + move=> IHi; suffices{IHi} m_i1_x1: sat_lit m (i, 0)%N x1 && true. + apply: (IHi (t_m 0%N i m lti) 0%N); rewrite /sat /sat_cl //= bb21_m m_gt0. + by rewrite /= m_i1_x1 /sat_lit /= andbT /t_ij /=; case: ifP. + case i_gt1: (1 < i)%N; last by case: (i) i_gt1 => [|[|[]]]. + have itv_i: (1 < i < m.1)%N by [apply/andP]; pose m2 := t_m 2 i m itv_i. + have m2_th: sat m2 |= & x1 in b11 & x1 in b21 & ? in b31. + rewrite /sat m_gt0 -andbA (leq_trans _ lti) ?(leq_trans _ ltj) /sat_cl //=. + by rewrite /sat_lit /= -(subnKC i_gt1); have [_ _] := and3P m_th. + have [v] := sat_cases _ m2_th (mem_head _ _) m_gt0; rewrite !inE. + by case/or3P=> /eqP-> => [/unsat_Ii | /and4P[] | /(L(31,11))]. +have [-> | nzj] := posnP j; first by case/and5P: m_th. +without loss{ltj nzj} ->: m j m_th / j = 1%N. + have itv_j: (0 < j < m.2)%N by rewrite nzj. + move/(_ (tr_model (t_m _ j (tr_model m) itv_j)) _ _ (erefl _)) => /=. + by rewrite /sat /sat_cl /sat_lit /= -(prednK nzj) => ->. +have{m_th}[/= _ m_gt0 m_x1] := and3P m_th. +have{m_x1} m_th: sat m |= & x1 in b11 & x1 in b21 & ? in b12. + by rewrite /sat m_gt0 /sub_bbox; have [[_ _ -> ->]] := LmodelP m. +have [v] := sat_cases 0%N m_th (mem_head _ _) m_gt0; rewrite !inE. +by case/or3P=> /eqP-> => [/and4P[] | /unsat_C | /(L(12,11))]. +Qed. + +(* This is Peterfalvi (3.5). *) +(* We have inlined part of the proof of (3.5.5) in this main proof, replacing *) +(* some combinatorial arguments with direct computation of the dot product, *) +(* this avoids the duplicate case analysis required to exploit (3.5.5) as it *) +(* is stated in the text. *) +Lemma cyclicTIiso_basis_exists : + exists xi_ : Iirr W1 -> Iirr W2 -> 'CF(G), + [/\ xi_ 0 0 = 1, forall i j, xi_ i j \in 'Z[irr G], + forall i j, i != 0 -> j != 0 -> + 'Ind (alpha_ i j) = 1 - xi_ i 0 - xi_ 0 j + xi_ i j + & forall i1 j1 i2 j2, '[xi_ i1 j1, xi_ i2 j2] = ((i1, j1) == (i2, j2))%:R]. +Proof. +(* Instantiate the abstract theory vertically and horizontally. *) +pose beta i j : 'CF(G) := 'Ind[G] (alpha_ i j) - 1. +have Zbeta i j: beta i j \in 'Z[irr G]. + by rewrite rpredB ?rpred1 ?cfInd_vchar ?cfCycTI_vchar. +have o_alphaG_1 i j: i != 0 -> j != 0 -> '['Ind[G] (alpha_ i j), 1] = 1. + by move=> nz_i nz_j; rewrite -cfdot_Res_r rmorph1 cfdot_alpha_1. +have o_beta_1 i j: i != 0 -> j != 0 -> '[beta i j, 1] = 0. + by move=> nzi nzj; rewrite cfdotBl o_alphaG_1 // cfnorm1 subrr. +have o_beta i1 j1 i2 j2 : i1 != 0 -> j1 != 0 -> i2 != 0 -> j2 != 0 -> + '[beta i1 j1, beta i2 j2] = ((i1 == i2).+1 * (j1 == j2).+1 - 1)%:R. +- move=> nzi1 nzj1 nzi2 nzj2; rewrite mulSnr addnS mulnSr /=. + rewrite cfdotBr o_beta_1 // subr0 cfdotBl (cfdotC 1) o_alphaG_1 //. + rewrite (normedTI_isometry tiV) ?cfCycTI_on // rmorph1 addrC. + rewrite (alphaE i2) cfdotDr !cfdotBr cfdot_alpha_1 // -!addrA addKr addrA. + rewrite addrC cfdot_alpha_w // subn1 -addnA !natrD mulnb; congr (_ + _). + rewrite alphaE -w_00 !(cfdotBl, cfdotDl) !cfdot_w !eqxx !(eq_sym 0). + rewrite (negPf nzi1) (negPf nzj1) (negPf nzi2) (negPf nzj2) /= !andbF !andbT. + by rewrite !addr0 !subr0 !opprB !subr0. +pose beta_fun := [fun ij => beta (inord ij.1.+1) (inord ij.2.+1)]. +have beta_modelP: is_Lmodel ((Nirr W1).-1, (Nirr W2).-1) beta_fun. + split=> [ | //= | ij1 ij2 /=/andP[lti1 ltj1] /andP[lti2 ltj2]]. + by rewrite -!(ltnS 2) -eqSS NirrW1 NirrW2. + by rewrite o_beta -?val_eqE /= ?inordK. +pose beta_model := Model beta_modelP (nil_RmodelP G). +have betaE i j: i != 0 -> j != 0 -> beta i j = beta_fun (i.-1, j.-1). + by move=> nzi nzj /=; rewrite !prednK ?lt0n ?inord_val. +have /fin_all_exists [dXi0 betaXi0] i0: exists dX, i0 != 0 -> + forall i j, i != 0 -> j != 0 -> '[beta i j, dchi dX] = (i == i0)%:R. +- have [/= dX DdX] := @column_pivot (tr_model beta_model) i0. + by exists dX => nzi0 i j nzi nzj; rewrite betaE ?DdX. +have /fin_all_exists [dX0j betaX0j] j0: exists dX, j0 != 0 -> + forall i j, i != 0 -> j != 0 -> '[beta i j, dchi dX] = (j == j0)%:R. +- have [dX DdX] := @column_pivot beta_model j0. + by exists dX => nzj0 i j nzi nzj; rewrite betaE ?DdX. +pose Xi0 j := dchi (dXi0 j); pose X0j i := dchi (dX0j i). +(* Construct the orthonormal family xi_ i j. *) +pose xi_ i j := if i == 0 then if j == 0 then 1 else - X0j j else + if j == 0 then - Xi0 i else beta i j - Xi0 i - X0j j. +exists xi_; split=> [| i j | i j nzi nzj | i1 j1 i2 j2]. +- by rewrite /xi_ !eqxx. +- rewrite /xi_; do 2!case: ifP => _; rewrite ?rpred1 ?rpredN ?dchi_vchar //. + by rewrite 2?rpredB ?dchi_vchar. +- by rewrite /xi_ /= !ifN // addrCA subrK addrACA subrK addrA addrK. +have o_dchi i j dk1 dk2 (phi := beta i j): + '[phi, dchi dk1] = 1 -> '[phi, dchi dk2] = 0 -> '[dchi dk1, dchi dk2] = 0. +- move=> phi1 phi0; have /eqP: 1 != 0 :> algC := oner_neq0 _. + rewrite -phi1 cfdot_dchi; do 2!case: eqP => [->|_]; rewrite ?subrr //. + by rewrite dchi_ndirrE cfdotNr phi0 oppr0. +have [nzi01 nzj01] := (Iirr1_neq0 ntW1, Iirr1_neq0 ntW2). +have X0j_1 j: j != 0 -> '[X0j j, 1] = 0. + by move=> nzj; rewrite -dchi1 (o_dchi #1 j) ?betaX0j ?eqxx ?dchi1 ?o_beta_1. +have Xi0_1 i: i != 0 -> '[Xi0 i, 1] = 0. + by move=> nzi; rewrite -dchi1 (o_dchi i #1) ?betaXi0 ?eqxx ?dchi1 ?o_beta_1. +have Xi0_X0j i j: i != 0 -> j != 0 -> '[Xi0 i, X0j j] = 0. + move=> nzi nzj; pose j' := conjC_Iirr j. + apply: (o_dchi i j'); rewrite (betaX0j, betaXi0) ?conjC_Iirr_eq0 ?eqxx //. + by rewrite -(inj_eq irr_inj) conjC_IirrE mulrb ifN ?odd_eq_conj_irr1 ?irr_eq1. +have X0j_X0j j j0: j != 0 -> j0 != 0 -> '[X0j j, X0j j0] = (j == j0)%:R. + move=> nzj nzj0; case: (altP eqP) => [-> | j0'j]; first exact: cfnorm_dchi. + by apply: (o_dchi #1 j); rewrite ?betaX0j ?eqxx ?(negPf j0'j). +have Xi0_Xi0 i i0: i != 0 -> i0 != 0 -> '[Xi0 i, Xi0 i0] = (i == i0)%:R. + move=> nzi nzi0; case: (altP eqP) => [-> | i0'i]; first exact: cfnorm_dchi. + by apply: (o_dchi i #1); rewrite ?betaXi0 ?eqxx ?(negPf i0'i). +have oxi_00 i j: '[xi_ i j, xi_ 0 0] = ((i == 0) && (j == 0))%:R. + rewrite /xi_; case: ifPn => [_ | nzi]. + by case: ifPn => [_ | nzj]; rewrite ?cfnorm1 // cfdotNl X0j_1 ?oppr0. + case: ifPn => [_ | nzj]; first by rewrite cfdotNl Xi0_1 ?oppr0. + by rewrite 2!cfdotBl o_beta_1 ?X0j_1 ?Xi0_1 ?subr0. +have oxi_0j i j j0: '[xi_ i j, xi_ 0 j0] = ((i == 0) && (j == j0))%:R. + rewrite /xi_; have [-> | nzj0] := altP (j0 =P 0); first exact: oxi_00. + rewrite cfdotNr; case: ifPn => [_ | nzi]. + have [-> | nzj] := altP eqP; last by rewrite cfdotNl opprK X0j_X0j. + by rewrite cfdotC X0j_1 // conjC0 oppr0 mulrb ifN_eqC. + have [_ | nzj] := ifPn; first by rewrite cfdotNl Xi0_X0j ?oppr0. + by rewrite 2!cfdotBl Xi0_X0j // subr0 betaX0j ?X0j_X0j // subrr oppr0. +have{oxi_00} oxi_i0 i j i0: '[xi_ i j, xi_ i0 0] = ((i == i0) && (j == 0))%:R. + rewrite /xi_; have [-> | nzi0] := altP (i0 =P 0); first exact: oxi_00. + rewrite cfdotNr andbC; have [_ | nzj] := boolP (j == 0). + have [-> | nzi] := altP eqP; last by rewrite cfdotNl opprK Xi0_Xi0. + by rewrite cfdotC Xi0_1 // conjC0 oppr0 mulrb ifN_eqC. + have [_ | nzi] := ifPn; first by rewrite cfdotNl opprK cfdotC Xi0_X0j ?conjC0. + rewrite 2!cfdotBl betaXi0 ?Xi0_Xi0 // subrr add0r opprK. + by rewrite cfdotC Xi0_X0j // conjC0. +have [-> | nzi2] := altP (i2 =P 0); first exact: oxi_0j. +have [-> | nzj2] := altP (j2 =P 0); first exact: oxi_i0. +rewrite cfdotC eq_sym; apply: canLR conjCK _; rewrite rmorph_nat. +have [-> | nzi1] := altP (i1 =P 0); first exact: oxi_0j. +have [-> | nzj1] := altP (j1 =P 0); first exact: oxi_i0. +have ->: xi_ i1 j1 = beta i1 j1 + xi_ i1 0 + xi_ 0 j1 by rewrite /xi_ !ifN. +rewrite 2!cfdotDr oxi_i0 oxi_0j andbC /xi_ (negPf nzi2) (negPf nzj2) !addr0. +rewrite eq_sym xpair_eqE cfdotC 2!cfdotBr o_beta // betaXi0 ?betaX0j //. +by rewrite -!CintrE /= rmorph_int; do 2!case: (_ == _). +Qed. + +End CyclicTIisoBasis. + +(* This is PeterFalvi, Theorem (3.2)(a, b, c). *) +Theorem cyclicTIiso_exists : + {sigma : 'Hom(cfun_vectType W, cfun_vectType G) | + [/\ {in 'Z[irr W], isometry sigma, to 'Z[irr G]}, sigma 1 = 1 + & {in 'CF(W, V), forall phi : 'CF(W), sigma phi = 'Ind[G] phi}]}. +Proof. +pose sigmaVP f := ('CF(W, V) <= lker (linfun f - linfun 'Ind[G]))%VS. +pose sigmaP f := [&& orthonormal (map f (irr W)), f 1 == 1 & sigmaVP f]. +pose sigma_base f := [seq (dchi (f k) : 'CF(G)) | k : Iirr W]. +pose sigma_spec f := sigmaP (sval (linear_of_free (irr W) (sigma_base f))). +suffices /sigW[f /and3P[]]: exists f : {ffun _}, sigma_spec f. + case: linear_of_free => /=sigma Dsigma o1sigma /eqP sigma1 /eqlfun_inP sigmaV. + exists (linfun sigma); split=> [|| phi /sigmaV]; try by rewrite !lfunE. + do [rewrite size_map !size_tuple => /(_ (irr_free W) (card_ord _))] in Dsigma. + have [inj_sigma dot_sigma] := orthonormalP o1sigma. + rewrite -(map_tnth_enum (irr W)) -map_comp in Dsigma inj_sigma. + move/eq_in_map in Dsigma; move/injectiveP in inj_sigma. + split=> [|_ /zchar_tuple_expansion[z Zz ->]]. + apply: isometry_in_zchar=> _ _ /irrP[k1 ->] /irrP[k2 ->] /=. + by rewrite !lfunE dot_sigma ?map_f ?mem_irr // cfdot_irr (inj_eq inj_sigma). + rewrite linear_sum rpred_sum // => k _; rewrite linearZ rpredZ_Cint //=. + by rewrite -tnth_nth lfunE [sigma _]Dsigma ?mem_enum ?dchi_vchar. +have [xi_ [xi00 Zxi Dxi o1xi]] := cyclicTIiso_basis_exists. +pose f := [ffun k => dirr_dIirr (prod_curry xi_) (inv_dprod_Iirr defW k)]. +exists f; apply/and3P; case: linear_of_free => /= sigma Dsigma. +have{f Dsigma} Deta i j: sigma (w_ i j) = xi_ i j. + rewrite /w_ -tnth_map /= (tnth_nth 0) /=. + rewrite Dsigma ?irr_free //; last by rewrite !size_tuple card_ord. + rewrite nth_mktuple ffunE dprod_IirrK dirr_dIirrE // => {i j} [[i j]] /=. + by rewrite dirrE Zxi o1xi !eqxx. +have sigma1: sigma 1 = 1 by rewrite -w_00 Deta. +rewrite sigma1 /sigmaVP -(span_basis cfWVbasis); split=> //. + rewrite map_orthonormal ?irr_orthonormal //; apply: isometry_in_zchar. + move=> _ _ /cycTIirrP[i1 [j1 ->]] /cycTIirrP[i2 [j2 ->]] /=. + by rewrite !Deta o1xi cfdot_w. +apply/span_subvP=> _ /imageP[[i j] /setXP[nzi nzj] ->]; rewrite !inE in nzi nzj. +rewrite memv_ker !lfun_simp /= subr_eq0 Dxi //. +by rewrite alphaE linearD !linearB sigma1 !Deta. +Qed. + +Fact cyclicTIiso_key : unit. Proof. by []. Qed. +Definition cyclicTIiso := + locked_with cyclicTIiso_key (lfun_linear (sval cyclicTIiso_exists)). +Local Notation sigma := cyclicTIiso. +Let im_sigma := map sigma (irr W). +Let eta_ i j := sigma (w_ i j). + +Lemma cycTI_Zisometry : {in 'Z[irr W], isometry sigma, to 'Z[irr G]}. +Proof. by rewrite [sigma]unlock; case: cyclicTIiso_exists => ? []. Qed. + +Let Isigma : {in 'Z[irr W] &, isometry sigma}. +Proof. by case: cycTI_Zisometry. Qed. +Let Zsigma : {in 'Z[irr W], forall phi, sigma phi \in 'Z[irr G]}. +Proof. by case: cycTI_Zisometry. Qed. + +Lemma cycTIisometry : isometry sigma. +Proof. +move=> phi psi; have [[a ->] [b ->]] := (cfun_irr_sum phi, cfun_irr_sum psi). +rewrite !linear_sum !cfdot_suml; apply: eq_bigr => i _. +rewrite !cfdot_sumr; apply: eq_bigr => j _. +by rewrite !linearZ !cfdotZl !cfdotZr /= Isigma ?irr_vchar. +Qed. + +Lemma cycTIiso_vchar i j : eta_ i j \in 'Z[irr G]. +Proof. by rewrite Zsigma ?irr_vchar. Qed. + +Lemma cfdot_cycTIiso i1 i2 j1 j2 : + '[eta_ i1 j1, eta_ i2 j2] = ((i1 == i2) && (j1 == j2))%:R. +Proof. by rewrite cycTIisometry. Qed. + +Lemma cfnorm_cycTIiso i j : '[eta_ i j] = 1. +Proof. by rewrite cycTIisometry cfnorm_irr. Qed. + +Lemma cycTIiso_dirr i j : eta_ i j \in dirr G. +Proof. by rewrite dirrE cycTIiso_vchar /= cfnorm_cycTIiso. Qed. + +Lemma cycTIiso_orthonormal : orthonormal im_sigma. +Proof. by rewrite map_orthonormal ?irr_orthonormal. Qed. + +Lemma cycTIiso_eqE i1 i2 j1 j2 : + (eta_ i1 j1 == eta_ i2 j2) = ((i1 == i2) && (j1 == j2)). +Proof. +have /inj_in_eq-> := Zisometry_inj Isigma; try exact: irr_vchar. +by rewrite (inj_eq irr_inj) (inj_eq (dprod_Iirr_inj _)). +Qed. + +Lemma cycTIiso_neqN i1 i2 j1 j2 : (eta_ i1 j1 == - eta_ i2 j2) = false. +Proof. +rewrite -addr_eq0; apply/eqP=> /(congr1 (cfdot (eta_ i1 j1)))/eqP. +by rewrite cfdot0r cfdotDr !cfdot_cycTIiso !eqxx -mulrS pnatr_eq0. +Qed. + +Lemma cycTIiso1 : sigma 1 = 1. +Proof. by rewrite [sigma]unlock; case: cyclicTIiso_exists => ? []. Qed. + +Lemma cycTIiso_Ind : {in 'CF(W, V), forall phi, sigma phi = 'Ind[G, W] phi}. +Proof. by rewrite [sigma]unlock; case: cyclicTIiso_exists => ? []. Qed. + +Let sigma_Res_V : + [/\ forall phi, {in V, sigma phi =1 phi} + & forall psi : 'CF(G), orthogonal psi im_sigma -> {in V, psi =1 \0}]. +Proof. +have sigW i j : '[sigma 'chi_i, sigma 'chi_j] = (i == j)%:R. + by rewrite cycTIisometry cfdot_irr. +have [j | sigmaV sigma'V] := equiv_restrict_compl_ortho sWG nsVW cfWVbasis sigW. + rewrite /= -/cfWVbase -(eq_bigr _ (fun _ _ => linearZ _ _)) /= -linear_sum. + rewrite -cfun_sum_cfdot cycTIiso_Ind //. + by rewrite (basis_mem cfWVbasis) ?mem_nth ?size_image. +split=> [phi v Vv | psi /orthoPl o_psi_sigma]. + rewrite [phi]cfun_sum_cfdot linear_sum !sum_cfunE. + by apply: eq_bigr => k _; rewrite linearZ !cfunE sigmaV. +by apply: sigma'V => k; rewrite o_psi_sigma ?map_f ?mem_irr. +Qed. + +(* This is Peterfalvi, Theorem (3.2)(d). *) +Theorem cycTIiso_restrict phi : {in V, sigma phi =1 phi}. +Proof. by case: sigma_Res_V. Qed. + +(* This is Peterfalvi, Theorem (3.2)(e). *) +Theorem ortho_cycTIiso_vanish (psi : 'CF(G)) : + orthogonal psi im_sigma -> {in V, forall x, psi x = 0}. +Proof. by case: sigma_Res_V psi. Qed. + +(* This is PeterFalvi (3.7). *) +Lemma cycTIiso_cfdot_exchange (psi : 'CF(G)) i1 i2 j1 j2 : + {in V, forall x, psi x = 0} -> + '[psi, eta_ i1 j1] + '[psi, eta_ i2 j2] + = '[psi, eta_ i1 j2] + '[psi, eta_ i2 j1]. +Proof. +move=> psiV_0; pose phi : 'CF(W) := w_ i1 j1 + w_ i2 j2 - w_ i1 j2 - w_ i2 j1. +have Vphi: phi \in 'CF(W, V). + apply/cfun_onP=> g; rewrite inE negb_and negbK !inE orbC. + case/or3P=> [/cfun0-> // | W1g | W2g]; apply/eqP; rewrite !cfunE subr_eq0. + by rewrite addrC -[g]mulg1 /w_ !dprod_IirrE !cfDprodE ?lin_char1 ?addKr. + by rewrite -[g]mul1g /w_ !dprod_IirrE !cfDprodE ?lin_char1 ?addrK. +suffices: '[psi, 'Ind[G] phi] == 0. + rewrite -!cycTIiso_Ind // !linearB !linearD !cfdotBr !cfdotDr. + by rewrite -addrA -opprD subr_eq0 => /eqP. +rewrite (cfdotEr _ (cfInd_on sWG Vphi)) big1 ?mulr0 //. +by move=> _ /imset2P[x y Vx Gy ->]; rewrite cfunJ ?psiV_0 ?mul0r. +Qed. + +(* This is NC as defined in PeterFalvi (3.6). *) +Definition cyclicTI_NC phi := #|[set ij | '[phi, eta_ ij.1 ij.2] != 0]|. +Local Notation NC := cyclicTI_NC. + +Lemma cycTI_NC_opp (phi : 'CF(G)) : (NC (- phi)%R = NC phi)%N. +Proof. by apply: eq_card=> [[i j]]; rewrite !inE cfdotNl oppr_eq0. Qed. + +Lemma cycTI_NC_sign (phi : 'CF(G)) n : (NC ((-1) ^+ n *: phi)%R = NC phi)%N. +Proof. +elim: n=> [|n IH]; rewrite ?(expr0,scale1r) //. +by rewrite exprS -scalerA scaleN1r cycTI_NC_opp. +Qed. + +Lemma cycTI_NC_iso i j : NC (eta_ i j) = 1%N. +Proof. +rewrite -(cards1 (i, j)); apply: eq_card => [[i1 j1]]; rewrite !inE /=. +rewrite cfdot_cycTIiso //= pnatr_eq0 (can_eq oddb _ false) eqbF_neg negbK. +by rewrite -xpair_eqE eq_sym. +Qed. + +Lemma cycTI_NC_irr i : (NC 'chi_i <= 1)%N. +Proof. +apply: wlog_neg; rewrite -ltnNge => /ltnW/card_gt0P[[i1 j1]]. +rewrite inE cfdot_dirr ?(irr_dirr, cycTIiso_dirr) //=. +case: ('chi_i =P _) => [-> | _]; first by rewrite cycTI_NC_opp cycTI_NC_iso. +by case: ('chi_i =P _)=> [-> | _]; rewrite (cycTI_NC_iso, eqxx). +Qed. + +Lemma cycTI_NC_dirr f : f \in dirr G -> (NC f <= 1)%N. +Proof. by case/dirrP=> b [i ->]; rewrite cycTI_NC_sign cycTI_NC_irr. Qed. + +Lemma cycTI_NC_dchi di : (NC (dchi di) <= 1)%N. +Proof. by rewrite cycTI_NC_dirr ?dirr_dchi. Qed. + +Lemma cycTI_NC_0 : NC 0 = 0%N. +Proof. by apply: eq_card0 => ij; rewrite !inE cfdot0l eqxx. Qed. + +Lemma cycTI_NC_add n1 n2 phi1 phi2 : + (NC phi1 <= n1 -> NC phi2 <= n2 -> NC (phi1 + phi2)%R <= n1 + n2)%N. +Proof. +move=> ub1 ub2; apply: leq_trans {ub1 ub2}(leq_add ub1 ub2). +rewrite -cardsUI -[NC _]addn0 leq_add // subset_leq_card //. +apply/subsetP=> [[i j]]; rewrite !inE /= -negb_and cfdotDl. +by apply: contra => /andP[/eqP-> /eqP->]; rewrite addr0. +Qed. + +Lemma cycTI_NC_sub n1 n2 phi1 phi2 : + (NC phi1 <= n1 -> NC phi2 <= n2 -> NC (phi1 - phi2)%R <= n1 + n2)%N. +Proof. by move=> ub1 ub2; rewrite cycTI_NC_add ?cycTI_NC_opp. Qed. + +Lemma cycTI_NC_scale_nz a phi : a != 0 -> NC (a *: phi) = NC phi. +Proof. +move=> nz_a; apply: eq_card => ij. +by rewrite !inE cfdotZl mulf_eq0 negb_or nz_a. +Qed. + +Lemma cycTI_NC_scale a phi n : (NC phi <= n -> NC (a *: phi) <= n)%N. +Proof. +have [-> _ | /cycTI_NC_scale_nz-> //] := eqVneq a 0. +by rewrite scale0r cycTI_NC_0. +Qed. + +Lemma cycTI_NC_norm phi n : + phi \in 'Z[irr G] -> '[phi] <= n%:R -> (NC phi <= n)%N. +Proof. +move=> Zphi ub_phi; apply: leq_trans (_ : #|dirr_constt phi| <= n)%N. + rewrite {1}[phi]cfun_sum_dconstt // -sum1_card. + elim/big_rec2: _ => [|/= i n1 phi1 _]; first by rewrite cycTI_NC_0. + by apply: cycTI_NC_add; rewrite cycTI_NC_scale ?cycTI_NC_dchi. +rewrite -leC_nat (ler_trans _ ub_phi) ?cnorm_dconstt // -sumr_const. +apply: ler_sum => i phi_i; rewrite sqr_Cint_ge1 ?Cint_Cnat ?Cnat_dirr //. +by rewrite gtr_eqF -?dirr_consttE. +Qed. + +(* This is PeterFalvi (3.8). *) +Lemma small_cycTI_NC phi i0 j0 (a0 := '[phi, eta_ i0 j0]) : + {in V, forall x, phi x = 0} -> (NC phi < 2 * minn w1 w2)%N -> a0 != 0 -> + (forall i j, '[phi, eta_ i j] = (j == j0)%:R * a0) + \/ (forall i j, '[phi, eta_ i j] = (i == i0)%:R * a0). +Proof. +pose a i j := '[phi, eta_ i j]; pose A := [set ij | a ij.1 ij.2 != 0]. +rewrite -[NC phi]/#|A| ltnNge => phiV_0 ubA nz_a0. +have{phiV_0} Da i2 j2 i1 j1 : a i1 j1 = a i1 j2 + a i2 j1 - a i2 j2. + by rewrite cycTIiso_cfdot_exchange ?addrK. +have ubA2: ~~ (w2 + w1 <= #|A| + 2)%N. + rewrite addnC addn2 -ltnS (contra _ ubA) //; apply: (@leq_trans _ _.+3). + rewrite odd_geq /= ?odd_add ?oddW1 ?oddW2 // mul2n -addn_min_max -addnn. + by rewrite uphalf_double leq_add2l gtn_min !leq_max !ltnn orbF -neq_ltn. +(* This is step (3.8.1). *) +have Za i1 i2 j1 j2 : a i1 j2 == 0 -> a i2 j1 == 0 -> a i1 j1 == 0. + have [-> // | /negPf i2'1 /eqP Za12 /eqP Za21] := eqVneq i1 i2. + apply: contraR ubA2 => nz_a11. + pose L := [set (if a i1 j == 0 then i2 else i1, j) | j : Iirr W2]. + pose C := [set (i, if a i j1 == 0 then j2 else j1) | i : Iirr W1]. + have [<- <-]: #|L| = w2 /\ #|C| = w1 by rewrite !card_imset // => ? ? []. + have <-: #|[set (i1, j1); (i2, j2)]| = 2 by rewrite cards2 xpair_eqE i2'1. + rewrite -cardsUI leq_add ?subset_leq_card //; last first. + apply/subsetP=> _ /setIP[/imsetP[j _ ->] /imsetP[i _ []]]. + by case: ifP => _ <- ->; rewrite !inE ?Za21 ?(negPf nz_a11) !eqxx ?orbT. + apply/subsetP=> ij /setUP[] /imsetP[] => [j | i] _ {ij}->; rewrite inE. + by case: ifPn => // /eqP Za1j; rewrite (Da i1 j1) Za21 Za1j !add0r oppr_eq0. + by case: ifPn => // /eqP Zai1; rewrite (Da i1 j1) Za12 Zai1 !add0r oppr_eq0. +pose L i := [set ij | ij.1 == i] :&: A; pose C j := [set ij | ij.2 == j] :&: A. +have{ubA2} ubLC i j: (#|L i| + #|C j| != w2 + w1)%N. + apply: contraNneq ubA2 => <-; rewrite addnS leqW // -cardsUI -setIUl -setIIl. + rewrite -(card1 (i, j)) leq_add ?subset_leq_card ?subsetIr //. + by apply/subsetP=> ij /setIP[]; rewrite !inE. +have lbA L1 L2: L1 :&: L2 =i set0 -> (#|L1 :&: A| + #|L2 :&: A| <= #|A|)%N. + rewrite -cardsUI -setIUl -setIIl => /setP->. + by rewrite set0I cards0 addn0 subset_leq_card ?subsetIr. +have oL i1: ~~ [exists j, a i1 j == 0] -> #|L i1| = w2. + rewrite negb_exists => /forallP nz_a1. + transitivity #|predX (pred1 i1) (Iirr W2)|; last by rewrite cardX card1 mul1n. + by apply/eq_card=> ij; rewrite !inE andbT andb_idr // => /eqP->. +have oC i1 j1 j2 : a i1 j1 != 0 -> a i1 j2 == 0 -> #|C j1| = w1. + move=> nz_a11 /(Za i1)/contra/(_ nz_a11) nz_a1. + transitivity #|predX (Iirr W1) (pred1 j1)|; last by rewrite cardX card1 muln1. + by apply/eq_card=> ij; rewrite !inE andb_idr // => /eqP->. +(* This is step (3.8.2). *) +have [/existsP[j1 Za01] | /oL oL0] := boolP [exists j, a i0 j == 0]. + have j0'1 : j1 != j0 by apply: contraTneq Za01 => ->. + have oC0: #|C j0| = w1 by apply: oC nz_a0 Za01. + suffices Za0 i j: j != j0 -> a i j = 0. + left=> i j; rewrite -/(a i j) mulr_natl mulrb; have [->|/Za0//] := altP eqP. + by rewrite (Da i0 j1) !(Za0 _ j1) // subr0 add0r. + move=> j0'j; apply: contraNeq (ubLC i j0) => nz_aij; rewrite oC0 oL //. + apply: contra ubA => /existsP[_ /Za/contra/(_ nz_aij) nz_a_j]. + rewrite minn_mulr geq_min mul2n -addnn -{2}oC0 -(oC i0 j j1) ?lbA // => ij. + by rewrite !inE; apply/andP=> [[/eqP-> /idPn]]. +(* This is step (3.8.3). *) +suffices Za0 i j: i != i0 -> a i j = 0. + right=> i j; rewrite -/(a i j) mulr_natl mulrb; have [->|/Za0//] := altP eqP. + have /card_gt0P[i1 i0'i]: (0 < #|predC1 i0|)%N. + by rewrite cardC1 nirrW1 -(subnKC w1gt2). + by rewrite (Da i1 j0) !(Za0 i1) // subr0 addr0. +move=> i0'i; suffices /existsP[j1 Zai1]: [exists j, a i j == 0]. + by apply: contraNeq (ubLC i0 j) => /oC/(_ Zai1)->; rewrite oL0. +apply: contraR ubA; rewrite minn_mulr geq_min orbC mul2n -addnn => /oL{1}<-. +by rewrite -oL0 lbA // => ij; rewrite !inE; apply/andP=> [[/eqP-> /idPn]]. +Qed. + +(* A weaker version of PeterFalvi (3.8). *) +Lemma cycTI_NC_minn (phi : 'CF(G)) : + {in V, forall x, phi x = 0} -> (0 < NC phi < 2 * minn w1 w2)%N -> + (minn w1 w2 <= NC phi)%N. +Proof. +move=> phiV_0 /andP[/card_gt0P[[i0 j0]]]; rewrite inE /= => nz_a0 ubNC. +pose L := [seq (i0, j) | j : Iirr W2]; pose C := [seq (i, j0) | i : Iirr W1]. +have [oL oC]: #|L| = w2 /\ #|C| = w1 by rewrite !card_image // => i j []. +have [Da | Da] := small_cycTI_NC phiV_0 ubNC nz_a0. + rewrite geq_min -oC subset_leq_card //. + by apply/subsetP=> _ /codomP[i ->]; rewrite !inE /= Da eqxx mul1r. +rewrite geq_min orbC -oL subset_leq_card //. +by apply/subsetP=> _ /codomP[j ->]; rewrite !inE /= Da eqxx mul1r. +Qed. + +(* Another consequence of (3.8), used in (4.8), (10.5), (10.10) and (11.8). *) +Lemma eq_signed_sub_cTIiso phi e i j1 j2 : + let rho := (-1) ^+ e *: (eta_ i j1 - eta_ i j2) in + phi \in 'Z[irr G] -> '[phi] = 2%:R -> j1 != j2 -> + {in V, phi =1 rho} -> phi = rho. +Proof. +set rho := _ - _; move: phi => phi0 /= Zphi0 n2phi0 neq_j12 eq_phi_rho. +pose phi := (-1) ^+ e *: phi0; pose psi := phi - rho. +have{eq_phi_rho} psiV0 z: z \in V -> psi z = 0. + by move=> Vz; rewrite !cfunE eq_phi_rho // !cfunE signrMK subrr. +have{Zphi0} Zphi: phi \in 'Z[irr G] by rewrite rpredZsign. +have{n2phi0} n2phi: '[phi] = 2%:R by rewrite cfnorm_sign. +have Zrho: rho \in 'Z[irr G] by rewrite rpredB ?cycTIiso_vchar. +have n2rho: '[rho] = 2%:R. + by rewrite cfnormBd !cfdot_cycTIiso ?eqxx ?(negPf neq_j12) ?andbF. +have [oIphi _ Dphi] := dirr_small_norm Zphi n2phi isT. +have [oIrho _ Drho] := dirr_small_norm Zrho n2rho isT. +set Iphi := dirr_constt _ in oIphi Dphi. +set Irho := dirr_constt _ in oIrho Drho. +suffices /eqP eqIrho: Irho == Iphi by rewrite Drho eqIrho -Dphi signrZK. +have psi_phi'_lt0 di: di \in Irho :\: Iphi -> '[psi, dchi di] < 0. + case/setDP=> rho_di phi'di; rewrite cfdotBl subr_lt0. + move: rho_di; rewrite dirr_consttE; apply: ler_lt_trans. + rewrite real_lerNgt -?dirr_consttE ?real0 ?Creal_Cint //. + by rewrite Cint_cfdot_vchar ?dchi_vchar. +have NCpsi: (NC psi < 2 * minn w1 w2)%N. + suffices NCpsi4: (NC psi <= 2 + 2)%N. + by rewrite (leq_ltn_trans NCpsi4) // !addnn mul2n ltn_double leq_min w1gt2. + by rewrite cycTI_NC_sub // cycTI_NC_norm ?n2phi ?n2rho. +pose rhoId := dirr_dIirr (fun sk => (-1) ^+ (sk.1 : bool) *: eta_ i sk.2). +have rhoIdE s k: dchi (rhoId (s, k)) = (-1) ^+ s *: eta_ i k. + by apply: dirr_dIirrE => sk; rewrite rpredZsign cycTIiso_dirr. +rewrite eqEcard oIrho oIphi andbT -setD_eq0; apply/set0Pn=> [[dk1 phi'dk1]]. +have [[rho_dk1 _] psi_k1_lt0] := (setDP phi'dk1, psi_phi'_lt0 _ phi'dk1). +have dot_dk1: '[rho, dchi dk1] = 1. + rewrite Drho cfdot_suml (big_setD1 dk1) //= cfnorm_dchi big1 ?addr0 //. + move=> dk2 /setD1P[/negPf dk1'2 /dirr_constt_oppl]; rewrite cfdot_dchi dk1'2. + by case: eqP => [-> /negP[] | _ _]; rewrite ?subrr ?ndirrK. +have dot_dk2: 0 < '[rho, rho - dchi dk1]. + by rewrite cfdotBr dot_dk1 n2rho addrK ltr01. +have{dot_dk1 dot_dk2} [s [k Dk1 rho_k2]]: + exists s, exists2 k, rhoId (s, k.1) = dk1 & rhoId (~~ s, k.2) \in Irho. +- move/cfdot_add_dirr_eq1: dot_dk1. + rewrite dirr_dchi rpredN !cycTIiso_dirr //. + case=> // Dk1; [exists false, (j1, j2) | exists true, (j2, j1)]; + try apply: dirr_inj; rewrite ?dirr_consttE rhoIdE scaler_sign //=. + + by rewrite addrC Dk1 addKr in dot_dk2. + by rewrite Dk1 addrK in dot_dk2. +rewrite -Dk1 rhoIdE cfdotZr rmorph_sign in psi_k1_lt0. +have psi_k1_neq0: '[psi, eta_ i k.1] != 0. + by rewrite -(can_eq (signrMK s)) mulr0 ltr_eqF. +set dk2 := rhoId _ in rho_k2. +have NCk2'_le1 (dI : {set _}): + dk2 \in dI -> #|dI| = 2%N -> (NC (\sum_(dk in dI :\ dk2) dchi dk)%R <= 1)%N. +- rewrite (cardsD1 dk2) => -> /eqP/cards1P[dk ->]. + by rewrite big_set1 cycTI_NC_dirr ?dirr_dchi. +suffices /psi_phi'_lt0/ltr_geF/idP[]: dk2 \in Irho :\: Iphi. + rewrite rhoIdE cfdotZr signrN rmorphN mulNr oppr_ge0 rmorph_sign. + have := small_cycTI_NC psiV0 NCpsi psi_k1_neq0. + by case=> // ->; rewrite mulrCA nmulr_lle0 ?ler0n. +have: (1 + 1 < NC psi)%N. + apply (@leq_trans (minn w1 w2)); first by rewrite leq_min w1gt2. + apply: cycTI_NC_minn => //; rewrite NCpsi /NC. + by rewrite (cardsD1 (i, k.1)) inE /= psi_k1_neq0. +rewrite inE rho_k2 andbT ltnNge; apply: contra => phi_k2. +rewrite /psi Drho (big_setD1 dk2) //= Dphi (big_setD1 dk2) //=. +by rewrite addrAC opprD addNKr addrC cycTI_NC_sub ?NCk2'_le1. +Qed. + +(* This is PeterFalvi (3.9)(a). *) +Lemma eq_in_cycTIiso (i : Iirr W) (phi : 'CF(G)) : + phi \in dirr G -> {in V, phi =1 'chi_i} -> phi = sigma 'chi_i. +Proof. +move=> Dphi; rewrite -(inv_dprod_IirrK defW i). +case: (inv_dprod_Iirr _)=> /= i1 j1 EphiC. +pose psi : 'CF(G) := eta_ i1 j1 - phi. +have ZpsiV: {in V, forall g, psi g = 0}=> [g GiV|]. + by rewrite /psi !cfunE cycTIiso_restrict // -(EphiC _ GiV) subrr. +pose a i j := '[psi, eta_ i j]; pose S := [set ij | a ij.1 ij.2 != 0]. +case: (boolP ((i1, j1) \in S))=> [I1J1iS|]; last first. + rewrite inE negbK /a cfdotBl cfdot_cycTIiso !eqxx /=. + rewrite cfdot_dirr ?(irr_dirr, cycTIiso_dirr) //. + case: (boolP (phi == _))=> [|_]. + by rewrite opprK -(natrD _ 1 1) pnatr_eq0. + case: (boolP (phi == _))=> [/eqP //|]. + by rewrite subr0 oner_eq0. +have SPos : (0 < #|S|)%N by rewrite (cardD1 (i1,j1)) I1J1iS. +have SLt: (#|S| <= 2)%N. + by rewrite -[2]add1n cycTI_NC_sub // !cycTI_NC_dirr // cycTIiso_dirr. +have: (0 < #|S| < 2 * minn w1 w2)%N. + rewrite SPos; apply: leq_ltn_trans SLt _. + by rewrite -{1}[2%N]muln1 ltn_mul2l /= leq_min ![(1 < _)%N]ltnW. +move/(cycTI_NC_minn ZpsiV); rewrite leqNgt; case/negP. +by apply: leq_ltn_trans SLt _; rewrite leq_min w1gt2. +Qed. + +(* This is the second part of Peterfalvi (3.9)(a). *) +Lemma cfAut_cycTIiso u phi : cfAut u (sigma phi) = sigma (cfAut u phi). +Proof. +rewrite [phi]cfun_sum_cfdot !raddf_sum; apply: eq_bigr => ij _. +rewrite /= !(linearZ, cfAutZ) /= -aut_IirrE; congr (_ *: _) => {phi}. +apply: eq_in_cycTIiso => [|x Vx /=]. + by have /cycTIirrP[i [j ->]] := mem_irr ij; rewrite dirr_aut cycTIiso_dirr. +by rewrite cfunE cycTIiso_restrict // aut_IirrE cfunE. +Qed. + +Section AutCyclicTI. + +Variable iw : Iirr W. +Let w := 'chi_iw. +Let a := #[w]%CF. + +Let Zsigw : sigma w \in 'Z[irr G]. +Proof. by have [_ -> //] := cycTI_Zisometry; apply: irr_vchar. Qed. + +Let lin_w: w \is a linear_char := Wlin iw. + +(* This is Peterfalvi (3.9)(b). *) +Lemma cycTIiso_aut_exists k : + coprime k a -> + [/\ exists u, sigma (w ^+ k) = cfAut u (sigma w) + & forall x, coprime #[x] a -> sigma (w ^+ k) x = sigma w x]. +Proof. +case/(make_pi_cfAut G)=> u Du_a Du_a'. +suffices Dwk: sigma (w ^+ k) = cfAut u (sigma w). + by split=> [|x co_x_a]; [exists u | rewrite Dwk Du_a']. +rewrite cfAut_cycTIiso; congr (sigma _); apply/cfun_inP=> x Wx. +have Wxbar: coset _ x \in (W / cfker w)%G by rewrite mem_quotient. +rewrite exp_cfunE // cfunE -cfQuoEker //. +rewrite -lin_charX ?cfQuo_lin_char ?cfker_normal // -Du_a ?cfunE //. + by rewrite char_vchar ?cfQuo_char ?irr_char. +by rewrite [a]cforder_lin_char // dvdn_exponent. +Qed. + +(* This is Peterfalvi (3.9)(c). *) +Lemma Cint_cycTIiso_coprime x : coprime #[x] a -> sigma w x \in Cint. +Proof. +move=> co_x_a; apply: Cint_rat_Aint (Aint_vchar _ Zsigw). +have [Qb galQb [QbC AutQbC [w_b genQb memQb]]] := group_num_field_exists <[x]>. +have{memQb} [wx Dwx]: exists wx, sigma w x = QbC wx. + have /memQb Qbx := dvdnn #[x]. + have [sw1 /Qbx[wx1 Dwx1] [sw2 /Qbx[wx2 Dwx2] ->]] := vcharP _ Zsigw. + by exists (wx1 - wx2); rewrite rmorphB !cfunE Dwx1 Dwx2. +suffices: wx \in fixedField 'Gal({:Qb} / 1). + rewrite Dwx (galois_fixedField galQb) ?subvf // => /vlineP[z ->]. + by rewrite -in_algE fmorph_eq_rat fmorph_rat Crat_rat. +apply/fixedFieldP=> [|v_b _]; first exact: memvf. +have [v Dv] := AutQbC v_b; apply: (fmorph_inj QbC); rewrite Dv -Dwx. +have [u uQb uQb'] := dvd_restrict_cfAut (W / cfker w) #[x] v. +transitivity (sigma (cfAut u w) x); first by rewrite -cfAut_cycTIiso cfunE -uQb. +congr (sigma _ _); apply/cfun_inP=> y Wy; rewrite cfunE -cfQuoEker //. +rewrite uQb' ?char_vchar ?cfQuo_char ?irr_char // coprime_sym. +apply: coprime_dvdr co_x_a; rewrite [a]cforder_lin_char //. +by rewrite dvdn_exponent ?mem_quotient. +Qed. + +End AutCyclicTI. + +End Three. + +Implicit Arguments ortho_cycTIiso_vanish [gT G W W1 W2 defW psi]. + +Section ThreeSymmetry. + +Variables (gT : finGroupType) (G W W1 W2 : {group gT}). +Implicit Types (defW : W1 \x W2 = W) (xdefW : W2 \x W1 = W). +Local Notation sigma_ := (@cyclicTIiso gT G W _ _). +Local Notation w_ defW i j := (cyclicTIirr defW i j). + +Lemma cycTIisoC defW xdefW ctiW xctiW i j : + @sigma_ defW ctiW (w_ defW i j) = @sigma_ xdefW xctiW (w_ xdefW j i). +Proof. +apply: eq_in_cycTIiso; first exact: cycTIiso_dirr. +by rewrite /cyclicTIset setUC cyclicTIirrC; apply: cycTIiso_restrict. +Qed. + +Lemma cycTIiso_irrelC defW xdefW ctiW xctiW : + @sigma_ defW ctiW = @sigma_ xdefW xctiW. +Proof. +suffices: sigma_ ctiW =1 sigma_ xctiW by rewrite ![sigma_ _]unlock => /lfunP->. +move=> phi; have [z_ ->] := cfun_irr_sum phi; rewrite !linear_sum. +apply/eq_bigr=> ij _; have [i [j ->]] := cycTIirrP defW (mem_irr ij). +by rewrite !linearZ /= {1}cycTIisoC cyclicTIirrC. +Qed. + +Lemma cycTIiso_irrel defW defW' ctiW ctiW' : + @sigma_ defW ctiW = @sigma_ defW' ctiW'. +Proof. +have xdefW: W2 \x W1 = W by rewrite dprodC. +by rewrite !(cycTIiso_irrelC _ (cyclicTIhyp_sym ctiW xdefW)). +Qed. + +End ThreeSymmetry. |
