mathcomp-1.5/0000755000175000017500000000000012307636117012161 5ustar garesgaresmathcomp-1.5/INSTALL0000644000175000017500000000274212307636117013217 0ustar garesgaresINSTALLATION PROCEDURE FOR THE MATHEMATICAL COMPONENTS LIBRARY -------------------------------------------------------------- Summary: - Requirements - Building the Mathematical Components library REQUIREMENTS ============ - Coq version 8.4 & Ssreflect 1.4 or 1.5 BUILDING SSREFLECT ================================================== - We suppose that the Coq system has been installed as well as the Ssreflect plugin. - Your COQBIN environment variable must be point to directory where Coq's binaries are (remember to add a final / to the path). - Your PATH environment variable value must make Coq binaries (coqtop, coq_makefile,...) accessible. E.g. export PATH="$COQBIN:$PATH" - Download and unpack the archive of the mathematical components library in a directory whose name does not contain spaces (like " Documents and Settings" ...). - Go to the root of the directory created by the previous unpack and type `make && make install`. - Note for Mac OSX users: If you encounter a "stack overflow" error message, then set the following environment variable and try again: OCAMLOPT=ocamlopt.opt - Note for Mac OSX users and Windows users: If you encounter a linking error it may be caused by an old version of OCaml that does not support dynamic loding of plugins on you platform. Edit the Make file and uncomment the lines marked for static linking. In this way a statically linked binary bin/ssrcoq will be produced. It is up to you to copy it inside $COQBIN. mathcomp-1.5/AUTHORS0000644000175000017500000000177612307636117013244 0ustar garesgaresAndrea Asperti University of Bologna - Microsoft Inria Joint Centre Jeremy Avigad Carnegie Mellon University - Microsoft Inria Joint Centre Yves Bertot Inria Sophia Antipolis - Microsoft Inria Joint Centre Cyril Cohen LIX cole Polytechnique - Microsoft Inria Joint Centre Franois Garillot Microsoft Inria Joint Centre Georges Gonthier Microsoft Research Cambridge - Microsoft Inria Joint Centre Stphane Le Roux Microsoft Inria Joint Centre Assia Mahboubi Inria Saclay - Microsoft Inria Joint Centre Sidi Ould Biha Inria Sophia Antipolis - Microsoft Inria Joint Centre Ioana Pasca Inria Sophia Antipolis - Microsoft Inria Joint Centre Laurence Rideau Inria Sophia Antipolis - Microsoft Inria Joint Centre Alexey Solovyev University of Pittsburgh Enrico Tassi Inria Saclay - Microsoft Inria Joint Centre Laurent Thry Inria Sophia Antipolis - Microsoft Inria Joint Centre Russell O'Connor Mc Master University - Microsoft Inria Joint Centre mathcomp-1.5/README0000644000175000017500000000336112307636117013044 0ustar garesgares THE MATHAMTICAL COMPONENTS LIBRARY THE COQ SYSTEM ------------------------------------------ INSTALLATION ============ See the file INSTALL for installation procedure. DOCUMENTATION ============= The documentation of the ssreflect tactics, a brief description of the libraries contained in the theories/ directory of the archive, and a detailed list of the changes made in the last release is available as an Inria Research Report at http://hal.inria.fr/inria-00258384 TUTORIAL ======== A brief tutorial of the ssreflect extension can be found in the doc/ directory. The doc/tutorial.v file contains the code of the examples presented in this document. This tutorial is also available as an Inria Technical Report at http://hal.inria.fr/inria-00407778 This online version may be updated between two successive releases of ssreflect. AVAILABILITY ============ Ssreflect and the Mathematical Components library are available at: http://www.msr-inria.inria.fr/Projects/math-components THE DISCUSSION LIST =================== The ssreflect list is meant to be a standard way to discuss questions about the ssreflect extension and the mathematical components library. To subscribe to ssreflect@msr-inria.inria.fr please send an email to sympa@msr-inria.inria.fr, whose title is "subscribe ssreflect". LICENSING ========= This program is free software; you can redistribute it and/or modify it under the terms of the CeCILL B FREE SOFTWARE LICENSE. You should have received a copy of the CeCILL B License with this Kit, in the file named "CeCILL-B". If not, visit http://www.cecill.info mathcomp-1.5/Make0000644000175000017500000000256112307636117012765 0ustar garesgares-R theories MathComp theories/abelian.v theories/action.v theories/algC.v theories/algebraics_fundamentals.v theories/algnum.v theories/alt.v theories/automorphism.v theories/bigop.v theories/binomial.v theories/center.v theories/character.v theories/classfun.v theories/closed_field.v theories/commutator.v theories/countalg.v theories/cyclic.v theories/cyclotomic.v theories/div.v theories/extraspecial.v theories/extremal.v theories/falgebra.v theories/fieldext.v theories/finalg.v theories/finfun.v theories/fingraph.v theories/fingroup.v theories/finmodule.v theories/finset.v theories/frobenius.v theories/galois.v theories/generic_quotient.v theories/gfunctor.v theories/gproduct.v theories/gseries.v theories/hall.v theories/inertia.v theories/intdiv.v theories/integral_char.v theories/interval.v theories/jordanholder.v theories/matrix.v theories/maximal.v theories/morphism.v theories/mxabelem.v theories/mxalgebra.v theories/mxpoly.v theories/mxrepresentation.v theories/nilpotent.v theories/path.v theories/perm.v theories/pgroup.v theories/polydiv.v theories/poly.v theories/polyXY.v theories/presentation.v theories/prime.v theories/primitive_action.v theories/quotient.v theories/rat.v theories/ring_quotient.v theories/separable.v theories/ssralg.v theories/ssrint.v theories/ssrnum.v theories/sylow.v theories/tuple.v theories/vcharacter.v theories/vector.v theories/zmodp.v mathcomp-1.5/CeCILL-B0000644000175000017500000005262312307636117013266 0ustar garesgaresCeCILL-B FREE SOFTWARE LICENSE AGREEMENT Notice This Agreement is a Free Software license agreement that is the result of discussions between its authors in order to ensure compliance with the two main principles guiding its drafting: * firstly, compliance with the principles governing the distribution of Free Software: access to source code, broad rights granted to users, * secondly, the election of a governing law, French law, with which it is conformant, both as regards the law of torts and intellectual property law, and the protection that it offers to both authors and holders of the economic rights over software. The authors of the CeCILL-B (for Ce[a] C[nrs] I[nria] L[ogiciel] L[ibre]) license are: Commissariat l'Energie Atomique - CEA, a public scientific, technical and industrial research establishment, having its principal place of business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France. Centre National de la Recherche Scientifique - CNRS, a public scientific and technological establishment, having its principal place of business at 3 rue Michel-Ange, 75794 Paris cedex 16, France. Institut National de Recherche en Informatique et en Automatique - INRIA, a public scientific and technological establishment, having its principal place of business at Domaine de Voluceau, Rocquencourt, BP 105, 78153 Le Chesnay cedex, France. Preamble This Agreement is an open source software license intended to give users significant freedom to modify and redistribute the software licensed hereunder. The exercising of this freedom is conditional upon a strong obligation of giving credits for everybody that distributes a software incorporating a software ruled by the current license so as all contributions to be properly identified and acknowledged. In consideration of access to the source code and the rights to copy, modify and redistribute granted by the license, users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive licensors only have limited liability. In this respect, the risks associated with loading, using, modifying and/or developing or reproducing the software by the user are brought to the user's attention, given its Free Software status, which may make it complicated to use, with the result that its use is reserved for developers and experienced professionals having in-depth computer knowledge. Users are therefore encouraged to load and test the suitability of the software as regards their requirements in conditions enabling the security of their systems and/or data to be ensured and, more generally, to use and operate it in the same conditions of security. This Agreement may be freely reproduced and published, provided it is not altered, and that no provisions are either added or removed herefrom. This Agreement may apply to any or all software for which the holder of the economic rights decides to submit the use thereof to its provisions. Article 1 - DEFINITIONS For the purpose of this Agreement, when the following expressions commence with a capital letter, they shall have the following meaning: Agreement: means this license agreement, and its possible subsequent versions and annexes. Software: means the software in its Object Code and/or Source Code form and, where applicable, its documentation, "as is" when the Licensee accepts the Agreement. Initial Software: means the Software in its Source Code and possibly its Object Code form and, where applicable, its documentation, "as is" when it is first distributed under the terms and conditions of the Agreement. Modified Software: means the Software modified by at least one Contribution. Source Code: means all the Software's instructions and program lines to which access is required so as to modify the Software. Object Code: means the binary files originating from the compilation of the Source Code. Holder: means the holder(s) of the economic rights over the Initial Software. Licensee: means the Software user(s) having accepted the Agreement. Contributor: means a Licensee having made at least one Contribution. Licensor: means the Holder, or any other individual or legal entity, who distributes the Software under the Agreement. Contribution: means any or all modifications, corrections, translations, adaptations and/or new functions integrated into the Software by any or all Contributors, as well as any or all Internal Modules. Module: means a set of sources files including their documentation that enables supplementary functions or services in addition to those offered by the Software. External Module: means any or all Modules, not derived from the Software, so that this Module and the Software run in separate address spaces, with one calling the other when they are run. Internal Module: means any or all Module, connected to the Software so that they both execute in the same address space. Parties: mean both the Licensee and the Licensor. These expressions may be used both in singular and plural form. Article 2 - PURPOSE The purpose of the Agreement is the grant by the Licensor to the Licensee of a non-exclusive, transferable and worldwide license for the Software as set forth in Article 5 hereinafter for the whole term of the protection granted by the rights over said Software. Article 3 - ACCEPTANCE 3.1 The Licensee shall be deemed as having accepted the terms and conditions of this Agreement upon the occurrence of the first of the following events: * (i) loading the Software by any or all means, notably, by downloading from a remote server, or by loading from a physical medium; * (ii) the first time the Licensee exercises any of the rights granted hereunder. 3.2 One copy of the Agreement, containing a notice relating to the characteristics of the Software, to the limited warranty, and to the fact that its use is restricted to experienced users has been provided to the Licensee prior to its acceptance as set forth in Article 3.1 hereinabove, and the Licensee hereby acknowledges that it has read and understood it. Article 4 - EFFECTIVE DATE AND TERM 4.1 EFFECTIVE DATE The Agreement shall become effective on the date when it is accepted by the Licensee as set forth in Article 3.1. 4.2 TERM The Agreement shall remain in force for the entire legal term of protection of the economic rights over the Software. Article 5 - SCOPE OF RIGHTS GRANTED The Licensor hereby grants to the Licensee, who accepts, the following rights over the Software for any or all use, and for the term of the Agreement, on the basis of the terms and conditions set forth hereinafter. Besides, if the Licensor owns or comes to own one or more patents protecting all or part of the functions of the Software or of its components, the Licensor undertakes not to enforce the rights granted by these patents against successive Licensees using, exploiting or modifying the Software. If these patents are transferred, the Licensor undertakes to have the transferees subscribe to the obligations set forth in this paragraph. 5.1 RIGHT OF USE The Licensee is authorized to use the Software, without any limitation as to its fields of application, with it being hereinafter specified that this comprises: 1. permanent or temporary reproduction of all or part of the Software by any or all means and in any or all form. 2. loading, displaying, running, or storing the Software on any or all medium. 3. entitlement to observe, study or test its operation so as to determine the ideas and principles behind any or all constituent elements of said Software. This shall apply when the Licensee carries out any or all loading, displaying, running, transmission or storage operation as regards the Software, that it is entitled to carry out hereunder. 5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS The right to make Contributions includes the right to translate, adapt, arrange, or make any or all modifications to the Software, and the right to reproduce the resulting software. The Licensee is authorized to make any or all Contributions to the Software provided that it includes an explicit notice that it is the author of said Contribution and indicates the date of the creation thereof. 5.3 RIGHT OF DISTRIBUTION In particular, the right of distribution includes the right to publish, transmit and communicate the Software to the general public on any or all medium, and by any or all means, and the right to market, either in consideration of a fee, or free of charge, one or more copies of the Software by any means. The Licensee is further authorized to distribute copies of the modified or unmodified Software to third parties according to the terms and conditions set forth hereinafter. 5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION The Licensee is authorized to distribute true copies of the Software in Source Code or Object Code form, provided that said distribution complies with all the provisions of the Agreement and is accompanied by: 1. a copy of the Agreement, 2. a notice relating to the limitation of both the Licensor's warranty and liability as set forth in Articles 8 and 9, and that, in the event that only the Object Code of the Software is redistributed, the Licensee allows effective access to the full Source Code of the Software at a minimum during the entire period of its distribution of the Software, it being understood that the additional cost of acquiring the Source Code shall not exceed the cost of transferring the data. 5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE If the Licensee makes any Contribution to the Software, the resulting Modified Software may be distributed under a license agreement other than this Agreement subject to compliance with the provisions of Article 5.3.4. 5.3.3 DISTRIBUTION OF EXTERNAL MODULES When the Licensee has developed an External Module, the terms and conditions of this Agreement do not apply to said External Module, that may be distributed under a separate license agreement. 5.3.4 CREDITS Any Licensee who may distribute a Modified Software hereby expressly agrees to: 1. indicate in the related documentation that it is based on the Software licensed hereunder, and reproduce the intellectual property notice for the Software, 2. ensure that written indications of the Software intended use, intellectual property notice and license hereunder are included in easily accessible format from the Modified Software interface, 3. mention, on a freely accessible website describing the Modified Software, at least throughout the distribution term thereof, that it is based on the Software licensed hereunder, and reproduce the Software intellectual property notice, 4. where it is distributed to a third party that may distribute a Modified Software without having to make its source code available, make its best efforts to ensure that said third party agrees to comply with the obligations set forth in this Article . If the Software, whether or not modified, is distributed with an External Module designed for use in connection with the Software, the Licensee shall submit said External Module to the foregoing obligations. 5.3.5 COMPATIBILITY WITH THE CeCILL AND CeCILL-C LICENSES Where a Modified Software contains a Contribution subject to the CeCILL license, the provisions set forth in Article 5.3.4 shall be optional. A Modified Software may be distributed under the CeCILL-C license. In such a case the provisions set forth in Article 5.3.4 shall be optional. Article 6 - INTELLECTUAL PROPERTY 6.1 OVER THE INITIAL SOFTWARE The Holder owns the economic rights over the Initial Software. Any or all use of the Initial Software is subject to compliance with the terms and conditions under which the Holder has elected to distribute its work and no one shall be entitled to modify the terms and conditions for the distribution of said Initial Software. The Holder undertakes that the Initial Software will remain ruled at least by this Agreement, for the duration set forth in Article 4.2. 6.2 OVER THE CONTRIBUTIONS The Licensee who develops a Contribution is the owner of the intellectual property rights over this Contribution as defined by applicable law. 6.3 OVER THE EXTERNAL MODULES The Licensee who develops an External Module is the owner of the intellectual property rights over this External Module as defined by applicable law and is free to choose the type of agreement that shall govern its distribution. 6.4 JOINT PROVISIONS The Licensee expressly undertakes: 1. not to remove, or modify, in any manner, the intellectual property notices attached to the Software; 2. to reproduce said notices, in an identical manner, in the copies of the Software modified or not. The Licensee undertakes not to directly or indirectly infringe the intellectual property rights of the Holder and/or Contributors on the Software and to take, where applicable, vis--vis its staff, any and all measures required to ensure respect of said intellectual property rights of the Holder and/or Contributors. Article 7 - RELATED SERVICES 7.1 Under no circumstances shall the Agreement oblige the Licensor to provide technical assistance or maintenance services for the Software. However, the Licensor is entitled to offer this type of services. The terms and conditions of such technical assistance, and/or such maintenance, shall be set forth in a separate instrument. Only the Licensor offering said maintenance and/or technical assistance services shall incur liability therefor. 7.2 Similarly, any Licensor is entitled to offer to its licensees, under its sole responsibility, a warranty, that shall only be binding upon itself, for the redistribution of the Software and/or the Modified Software, under terms and conditions that it is free to decide. Said warranty, and the financial terms and conditions of its application, shall be subject of a separate instrument executed between the Licensor and the Licensee. Article 8 - LIABILITY 8.1 Subject to the provisions of Article 8.2, the Licensee shall be entitled to claim compensation for any direct loss it may have suffered from the Software as a result of a fault on the part of the relevant Licensor, subject to providing evidence thereof. 8.2 The Licensor's liability is limited to the commitments made under this Agreement and shall not be incurred as a result of in particular: (i) loss due the Licensee's total or partial failure to fulfill its obligations, (ii) direct or consequential loss that is suffered by the Licensee due to the use or performance of the Software, and (iii) more generally, any consequential loss. In particular the Parties expressly agree that any or all pecuniary or business loss (i.e. loss of data, loss of profits, operating loss, loss of customers or orders, opportunity cost, any disturbance to business activities) or any or all legal proceedings instituted against the Licensee by a third party, shall constitute consequential loss and shall not provide entitlement to any or all compensation from the Licensor. Article 9 - WARRANTY 9.1 The Licensee acknowledges that the scientific and technical state-of-the-art when the Software was distributed did not enable all possible uses to be tested and verified, nor for the presence of possible defects to be detected. In this respect, the Licensee's attention has been drawn to the risks associated with loading, using, modifying and/or developing and reproducing the Software which are reserved for experienced users. The Licensee shall be responsible for verifying, by any or all means, the suitability of the product for its requirements, its good working order, and for ensuring that it shall not cause damage to either persons or properties. 9.2 The Licensor hereby represents, in good faith, that it is entitled to grant all the rights over the Software (including in particular the rights set forth in Article 5). 9.3 The Licensee acknowledges that the Software is supplied "as is" by the Licensor without any other express or tacit warranty, other than that provided for in Article 9.2 and, in particular, without any warranty as to its commercial value, its secured, safe, innovative or relevant nature. Specifically, the Licensor does not warrant that the Software is free from any error, that it will operate without interruption, that it will be compatible with the Licensee's own equipment and software configuration, nor that it will meet the Licensee's requirements. 9.4 The Licensor does not either expressly or tacitly warrant that the Software does not infringe any third party intellectual property right relating to a patent, software or any other property right. Therefore, the Licensor disclaims any and all liability towards the Licensee arising out of any or all proceedings for infringement that may be instituted in respect of the use, modification and redistribution of the Software. Nevertheless, should such proceedings be instituted against the Licensee, the Licensor shall provide it with technical and legal assistance for its defense. Such technical and legal assistance shall be decided on a case-by-case basis between the relevant Licensor and the Licensee pursuant to a memorandum of understanding. The Licensor disclaims any and all liability as regards the Licensee's use of the name of the Software. No warranty is given as regards the existence of prior rights over the name of the Software or as regards the existence of a trademark. Article 10 - TERMINATION 10.1 In the event of a breach by the Licensee of its obligations hereunder, the Licensor may automatically terminate this Agreement thirty (30) days after notice has been sent to the Licensee and has remained ineffective. 10.2 A Licensee whose Agreement is terminated shall no longer be authorized to use, modify or distribute the Software. However, any licenses that it may have granted prior to termination of the Agreement shall remain valid subject to their having been granted in compliance with the terms and conditions hereof. Article 11 - MISCELLANEOUS 11.1 EXCUSABLE EVENTS Neither Party shall be liable for any or all delay, or failure to perform the Agreement, that may be attributable to an event of force majeure, an act of God or an outside cause, such as defective functioning or interruptions of the electricity or telecommunications networks, network paralysis following a virus attack, intervention by government authorities, natural disasters, water damage, earthquakes, fire, explosions, strikes and labor unrest, war, etc. 11.2 Any failure by either Party, on one or more occasions, to invoke one or more of the provisions hereof, shall under no circumstances be interpreted as being a waiver by the interested Party of its right to invoke said provision(s) subsequently. 11.3 The Agreement cancels and replaces any or all previous agreements, whether written or oral, between the Parties and having the same purpose, and constitutes the entirety of the agreement between said Parties concerning said purpose. No supplement or modification to the terms and conditions hereof shall be effective as between the Parties unless it is made in writing and signed by their duly authorized representatives. 11.4 In the event that one or more of the provisions hereof were to conflict with a current or future applicable act or legislative text, said act or legislative text shall prevail, and the Parties shall make the necessary amendments so as to comply with said act or legislative text. All other provisions shall remain effective. Similarly, invalidity of a provision of the Agreement, for any reason whatsoever, shall not cause the Agreement as a whole to be invalid. 11.5 LANGUAGE The Agreement is drafted in both French and English and both versions are deemed authentic. Article 12 - NEW VERSIONS OF THE AGREEMENT 12.1 Any person is authorized to duplicate and distribute copies of this Agreement. 12.2 So as to ensure coherence, the wording of this Agreement is protected and may only be modified by the authors of the License, who reserve the right to periodically publish updates or new versions of the Agreement, each with a separate number. These subsequent versions may address new issues encountered by Free Software. 12.3 Any Software distributed under a given version of the Agreement may only be subsequently distributed under the same version of the Agreement or a subsequent version. Article 13 - GOVERNING LAW AND JURISDICTION 13.1 The Agreement is governed by French law. The Parties agree to endeavor to seek an amicable solution to any disagreements or disputes that may arise during the performance of the Agreement. 13.2 Failing an amicable solution within two (2) months as from their occurrence, and unless emergency proceedings are necessary, the disagreements or disputes shall be referred to the Paris Courts having jurisdiction, by the more diligent Party. Version 1.0 dated 2006-09-05. mathcomp-1.5/extra/0000755000175000017500000000000012307636117013304 5ustar garesgaresmathcomp-1.5/extra/builddoc_lib.sh0000644000175000017500000000676312307636117016267 0ustar garesgares mangle_sources() { # pre processing, mainly comments for f in $@; do sed -r -e ' # We remove comments inside proofs /^Proof.$/,/^Qed./s/\(\*[^*](([^(]|\([^*]){1,}?[^^])\*+\)//g; ' $f | sed -r -e ' # read the whole file into the pattern space # :a is the label, N glues the current line; b branches # to a if not EOF :a; N; $!ba; # remove all starred lines s/\(\*{5,}?\)//g; # remove *)\n(* s/\*+\)\n\(\*+/\n/g; # double star not too short comments, that are left # as singly starred comments, like (*a.3*) s/\n\(\*+(([^(]|\([^*]){5,}?[^^])\*+\)/\n(**\ \1\ **)/g; # restore hide s/\(\*+[ ]*begin hide[ ]*\*+\)/\(\* begin hide \*\)/g; s/\(\*+[ ]*end hide[ ]*\*+\)/\(\* end hide \*\)/g; ' | sed -r -e ' # since ranges apply to lines only we create lines s/\(\*\*/\n(**\n/g; s/\*\*\)/\n**)\n/g; ' | sed -r -e ' # quote sharp, percent and dollar on comment blocks # hiding underscore /\(\*\*/,/\*\*\)/s/#/##/g; /\(\*\*/,/\*\*\)/s/%/%%/g; /\(\*\*/,/\*\*\)/s/\$/$$/g; /\(\*\*/,/\*\*\)/s/\[/#[#/g; /\(\*\*/,/\*\*\)/s/]/#]#/g; /\(\*\*/,/\*\*\)/s/\_/#\_#/g; # the lexer glues sharp with other symbols /\(\*\*/,/\*\*\)/s/([^A-Za-z0-9 ])#\[#/\1 #[#/g; /\(\*\*/,/\*\*\)/s/([^A-Za-z0-9 ])#]#/\1 #]#/g; ' | sed -r -e ' # we glue comment lines back together :a; N; $!ba; s/\n\(\*\*\n/(**/g; s/\n\*\*\)\n/**)/g; ' > $f.tmp mv $f.tmp $f done } build_doc() { rm -rf html mkdir html coqdoc -t "$TITLE" -g --utf8 $COQOPTS $COQDOCOPTS \ --parse-comments \ --multi-index $@ -d html # graph coqdep -noglob $COQOPTS $@ > depend sed -i -e 's/ [^ ]*\.cmxs//g' -e 's/ [^ ]*\.cm.//g' depend ocamlc -o $MAKEDOT/makedot -pp camlp5o $MAKEDOT/dependtodot.ml $MAKEDOT/makedot depend mv *.dot theories.dot || true $MANGLEDOT theories.dot dot -Tpng -o html/depend.png -Tcmapx -o html/depend.map theories.dot dot -Tsvg -o html/depend.svg theories.dot # post processing for f in html/*.html; do sed -r -i -e ' # read the whole file into the pattern space # :a is the label, N glues the current line; b branches # to a if not EOF :a; N; $!ba; #Add the favicon s/^<\/head>/\n<\/head>/mg; # add the Joint Center logo s/]*?)>/(Joint Center)/g; # extra blank line s/\n/
/g; # weird underscore s/ /_/g; # putting back underscore s/#\_#/\_/g; # abundance of
s/\n //g; ' $f done mv html/index.html html/index_lib.html cat >html/index.html < $TITLE

(Joint Center) $TITLE Documentation


EOT cat html/depend.map >> html/index.html cat >>html/index.html <
Library index
EOT } mathcomp-1.5/extra/coqdoc.css0000644000175000017500000001144112307636117015267 0ustar garesgaresody { padding: 0px 0px; margin: 0px 0px; background-color: white } #page { display: block; padding: 0px; margin: 0px; padding-bottom: 10px; } #header { display: block; position: relative; padding: 0; margin: 0; vertical-align: middle; border-bottom-style: solid; border-width: thin } #header h1 { padding: 0; margin: 0;} /* Contents */ #main{ display: block; padding: 10px; font-family: sans-serif; font-size: 100%; line-height: 100% } #main h1 { line-height: 95% } /* allow for multi-line headers */ #main a.idref:visited {color : #416DFF; text-decoration : none; } #main a.idref:link {color : #416DFF; text-decoration : none; } #main a.idref:hover {text-decoration : none; } #main a.idref:active {text-decoration : none; } #main a.modref:visited {color : #416DFF; text-decoration : none; } #main a.modref:link {color : #416DFF; text-decoration : none; } #main a.modref:hover {text-decoration : none; } #main a.modref:active {text-decoration : none; } #main .keyword { color : #cf1d1d } #main { color: black } .section { background-color: rgb(60%,60%,100%); padding-top: 13px; padding-bottom: 13px; padding-left: 3px; margin-top: 5px; margin-bottom: 5px; font-size : 110% } h2.section { background-color: rgb(80%,80%,100%); padding-left: 3px; padding-top: 12px; padding-bottom: 10px; font-size : 110% } h3.section { background-color: rgb(90%,90%,100%); padding-left: 3px; padding-top: 7px; padding-bottom: 7px; font-size : 110% } h4.section { /* background-color: rgb(80%,80%,80%); max-width: 20em; padding-left: 5px; padding-top: 5px; padding-bottom: 5px; */ background-color: white; padding-left: 0px; padding-top: 0px; padding-bottom: 0px; font-size : 100%; font-style : bold; text-decoration : underline; } #main .doc { margin: 0px; font-family: courier; font-size: 100%; line-height: 125%; max-width: 50em; color: black; padding: 10px; background-color: #90bdff; border-style: plain; white-space: pre; } .inlinecode { display: inline; /* font-size: 125%; */ color: #666666; font-family: monospace } .doc .inlinecode { display: inline; font-size: 120%; color: rgb(30%,30%,70%); font-family: monospace } .doc .inlinecode .id { color: rgb(30%,30%,70%); } .doc .code { display: inline; font-size: 120%; color: rgb(30%,30%,70%); font-family: monospace } .comment { display: inline; font-family: monospace; color: #cf1d1d } .code { display: block; /* padding-left: 15px; */ font-size: 110%; font-family: monospace; } /* Pied de page */ #footer { font-size: 65%; font-family: sans-serif; } .id { display: inline; } .id[type="constructor"] { color: rgb(60%,0%,0%); } .id[type="var"] { color: rgb(40%,0%,40%); } .id[type="variable"] { color: rgb(40%,0%,40%); } .id[type="definition"] { color: rgb(0%,40%,0%); } .id[type="abbreviation"] { color: rgb(0%,40%,0%); } .id[type="lemma"] { color: rgb(0%,40%,0%); } .id[type="instance"] { color: rgb(0%,40%,0%); } .id[type="projection"] { color: rgb(0%,40%,0%); } .id[type="method"] { color: rgb(0%,40%,0%); } .id[type="inductive"] { color: rgb(0%,0%,80%); } .id[type="record"] { color: rgb(0%,0%,80%); } .id[type="class"] { color: rgb(0%,0%,80%); } .id[type="keyword"] { color : #cf1d1d; /* color: black; */ } .inlinecode .id { color: rgb(0%,0%,0%); } /* TOC */ #toc h2 { padding: 10px; background-color: rgb(60%,60%,100%); } #toc li { padding-bottom: 8px; } /* Index */ #index { margin: 0; padding: 0; width: 100%; } #index #frontispiece { margin: 1em auto; padding: 1em; width: 60%; } .booktitle { font-size : 140% } .authors { font-size : 90%; line-height: 115%; } .moreauthors { font-size : 60% } #index #entrance { text-align: center; } #index #entrance .spacer { margin: 0 30px 0 30px; } #index #footer { position: absolute; bottom: 0; text-align: bottom; } mathcomp-1.5/extra/jc.png0000644000175000017500000000367012307636117014414 0ustar garesgaresPNG  IHDR&&=bKGD pHYs  tIME/ZtEXtCommentCreated with The GIMPd%nIDATX{W?gf߻+Ky,lW$-V(6@[RM6bZC6ICVH|jM*%"@%(lfXXvǽ{y3[V.LL>{~mhI5 A.PԚɚZZ*P15B\,WB]]UY p1b,(/]h@߽`#WH]Q1(P J,Z`%3Bop,p]>j5jcmfVa6de|c5eC-`-Pxc'tS+P\5u1vFѹs=2{-$2,`>N%hx*?YCTU6)hZ pr4,y#}|4Իˁv?8?F&^)`fqƑV\ |:۠u~ AvKJ+*o4J7(/v8=TMuDÚG9!|<`m 0x7@4(GC2 5yr+·jOՌZN\(q.n9; @L 2 &=1kf"oj&^ɑ]/kE^YhÉ=A9PnZSKfİ[Qt(y~Ao;W<8y |]EC WU<~8}cџ*0~!-$\a43%y+mAhi`Dfl_oTirp<_yO}!}*"T ϬaEPU P0|L&/ ?X6t^lWb \k܊I!=D \$[--L$1$B^NX Mш}Od`kS0bQJYlp,I-/@1‘DL'x9 lz[ 4B[:#H wгi=G,GƬ)zG @]D>S",p%TL]x]:~W/!4@mBI 8PƇWT8f=EshȆlY\ɿ{ oгx{P:bKO+fƚeDFߊ=͓$7FdbD.F$ "[]" |x::l -> let rec listdvr l = match l with [] -> "" |y::l -> "," ^ y ^ (listdvr l) in "[" ^ x ^ (listdvr l) ^ "]" ;; let rec visit ht hte x s = Hashtbl.add ht x x; try let le=Hashtbl.find hte x in let rec visit_edge ls le = match le with [] -> ls |b::l -> try let _ =Hashtbl.find ht b in (visit_edge (ls@[vedge ^ (vnoder b) ^ ")"]) l) with Not_found -> (visit_edge (ls@[vedge ^ (visit ht hte b s) ^ ")"]) l) in s ^ (vnode x) ^ (listdv (visit_edge [] le)) ^ "))" with Not_found -> s ^ (vnode x) ^ "[]))" ;; (* cloture transitive *) let rec merge_list a b = match a with [] -> b |x::a -> if (List.mem x b) then (merge_list a b) else x::(merge_list a b) ;; let ht_graph g = let ht =Hashtbl.create 50 in let rec fill g = match g with [] -> () |(a,lb)::g -> Hashtbl.add ht a lb; fill g in fill g; ht ;; let trans_clos1 g = let ht =ht_graph g in List.map (fun (a,lb) -> (a,(let l = ref lb in let rec addlb lb = match lb with [] -> () |b::lb -> (try l:=(merge_list (Hashtbl.find ht b) !l) with Not_found -> ()); addlb lb in addlb lb; !l))) g ;; let rec transitive_closure g = let g1=trans_clos1 g in if g1=g then g else (transitive_closure g1) ;; (* let g=["A",["B"]; "B",["C"]; "C",["D"]; "D",["E"]; "E",["A"]];; transitive_closure g;; *) (* enlever les arcs de transitivite *) let remove_trans g = let ht = ht_graph (transitive_closure g) in List.map (fun (a,lb) -> (a,(let l=ref [] in (let rec sel l2 = match l2 with [] -> () |b::l2 -> (let r=ref false in (let rec testlb l3 = match l3 with [] -> () |c::l3 -> if (not (b=a)) &&(not(b=c)) && (not (a=c)) && (try (List.mem b (Hashtbl.find ht c)) with Not_found -> false) then r:=true else (); testlb l3 in testlb lb); if (!r=false) then l:=b::!l else ()); sel l2 in sel lb); !l))) g ;; (* let g1=["Le", ["C";"Lt";"B"; "Plus"]; "Lt", ["A";"Plus"]];; let g=["A",["B";"C";"D";"E"]; "B",["C"]; "C",["D"]; "D",["E"]];; remove_trans g;; *) let dot g name file= let chan_out = open_out (file^".dot") in output_string chan_out "digraph "; output_string chan_out name; output_string chan_out " {\n"; output_string chan_out " bgcolor=transparent;\n"; output_string chan_out " splines=true;\n"; output_string chan_out " nodesep=1;\n"; output_string chan_out " node [fontsize=18, shape=rect, color=\"#dbc3b6\", style=filled];\n"; List.iter (fun (x,y) -> output_string chan_out " "; output_string chan_out (wstring x); output_string chan_out " [URL=\"./"; output_string chan_out x; output_string chan_out ".html\"]\n"; List.iter (fun y -> output_string chan_out " "; output_string chan_out (wstring x); output_string chan_out " -> "; output_string chan_out (wstring y); output_string chan_out ";\n") y) g; flush chan_out; output_string chan_out "}"; close_out chan_out ;; (* example: a complete 5-graph, let g=["A",["B";"C";"D";"E"]; "B",["A";"C";"D";"E"]; "C",["A";"B";"D";"E"]; "D",["A";"B";"C";"E"]; "E",["A";"B";"C";"D"]];; daVinci g "g2";; the file is then g2.daVinci *) (***********************************************************************) open Genlex;; (* change OP april 28 *) (* this parsing produce a pair where the first member is a paire (file,Directory) and the second is a list of pairs (file,Directory). from this we can compute the files graph dependency and also the directory graph dependency *) let lexer = make_lexer [":";".";"/";"-"];; let rec parse_dep = parser [< a=parse_name; 'Kwd ".";'Ident b; _=parse_until_colon; _=parse_name ;'Kwd "."; 'Ident d;n=parse_rem >] -> (a,n) and parse_rem = parser [< a=parse_name;'Kwd ".";'Ident b;n=parse_rem >] -> a::n | [<>]->[] and parse_until_colon = parser [< 'Kwd ":" >] -> () | [< 'Kwd _; _=parse_until_colon >] -> () | [< 'Int _; _=parse_until_colon >] -> () | [< 'Ident _; _=parse_until_colon >] -> () and parse_name = parser [<'Kwd "/";a=parse_ident; b=parse_name_rem a "" >]-> a::b |[]-> a::b and parse_name2 k = parser []-> d::b and parse_name_rem a b= parser [<'Kwd "/";c=parse_name2 a >]-> c | [<>]->[] and parse_ident = parser [<'Ident a; b=parse_ident_rem a "" >]-> a ^ b |[<'Int a; b=parse_ident_rem (string_of_int a) "" >]-> (string_of_int a) ^ b and parse_ident2 k = parser [<'Ident d; b=parse_ident_rem d k >]-> d ^ b |[<'Int d; b=parse_ident_rem (string_of_int d) k >]-> (string_of_int d) ^ b and parse_ident_rem a b= parser [<'Kwd "-";c=parse_ident2 a >]-> "-" ^ c | [<>]-> "" ;; (* parse_name(lexer(Stream.of_string "u/sanglier/0/croap/pottier/Coq/Dist/contrib/Rocq/ALGEBRA/CATEGORY_THEORY/NT/YONEDA_LEMMA/NatFun.vo: "));; parse_ident(lexer(Stream.of_string "ARITH-OMEGA-ggg-2.vo:"));; PROBLEME *) (* reads the depend file *) let read_depend file= let st =open_in file in let lr =ref [] in let rec other() = (try let d=parse_dep(lexer(Stream.of_string (input_line st))) in lr:=d::(!lr); other() with _ ->[]) in (let _ = other() in ()); !lr;; (* graph of a directory (given by a path) *) let rec is_prefix p q = match p with [] -> true |a::p -> match q with [] -> false |b::q -> if a=b then (is_prefix p q) else false ;; let rec after_prefix p q = match p with [] ->(match q with [] -> "unknown" |a::_ -> a) |a::p -> match q with [] -> "unknown" |b::q -> (after_prefix p q) ;; let rec proj_graph p g = match g with [] -> [] |(q,l)::g -> if (is_prefix p q) then let rec proj_edges l = match l with [] -> [] |r::l -> if (is_prefix p r) then (after_prefix p r)::(proj_edges l) else (proj_edges l) in ((after_prefix p q),(proj_edges l)) ::(proj_graph p g) else (proj_graph p g) ;; let rec start_path p = match p with [] ->[] |a::p -> match p with [] ->[] |b::q -> a::(start_path p) ;; (* the list of all the paths and subpaths in g *) let all_path g = let ht =Hashtbl.create 50 in let add_path p = Hashtbl.remove ht p;Hashtbl.add ht p true in let rec add_subpath p = match p with [] ->() |_ -> add_path p; add_subpath (start_path p) in let rec all_path g = match g with [] -> () |(q,l)::g -> add_subpath (start_path q); let rec all_pathl l = match l with [] -> () |a::l -> add_subpath (start_path a); all_pathl l in all_pathl l; all_path g in all_path g; let lp=ref [] in Hashtbl.iter (fun x y -> lp:=x::!lp) ht; !lp ;; (* let g=read_depend "depend";; proj_graph ["theories"] g;; *) let rec endpath p = match p with [] ->"" |a::p -> match p with [] ->a |_ -> endpath p ;; let rec fpath p = match p with [] ->"" |a::p -> a ^ "/" ^ (fpath p) ;; let rec spath p = match p with [] -> "" |a::p -> match p with [] ->a |b::q -> a ^ "/" ^ (spath p) ;; (* creates graphs for all paths *) let dependtodot file= let g =(read_depend file) in let lp1 = all_path g in let lp = (if lp1=[] then [[]] else lp1) in let rec ddv lp = match lp with [] -> () |p::lp -> let name = (let f = (endpath p) in if f="" then file else f) in let filep = (let f = (spath p) in if f="" then file else f) in dot (remove_trans (proj_graph p g)) name filep; ddv lp in ddv lp ;; let _ = if (Array.length Sys.argv) == 2 then dependtodot Sys.argv.(1) else print_string "makedot depend"; print_newline() mathcomp-1.5/theories/0000755000175000017500000000000012307636117014003 5ustar garesgaresmathcomp-1.5/theories/fingraph.v0000644000175000017500000006421712307636117016002 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path fintype. (******************************************************************************) (* This file develops the theory of finite graphs represented by an "edge" *) (* relation over a finType T; this mainly amounts to the theory of the *) (* transitive closure of such relations. *) (* For g : T -> seq T, e : rel T and f : T -> T we define: *) (* grel g == the adjacency relation y \in g x of the graph g. *) (* rgraph e == the graph (x |-> enum (e x)) of the relation e. *) (* dfs g n v x == the list of points traversed by a depth-first search of *) (* the g, at depth n, starting from x, and avoiding v. *) (* dfs_path g v x y <-> there is a path from x to y in g \ v. *) (* connect e == the transitive closure of e (computed by dfs). *) (* connect_sym e <-> connect e is symmetric, hence an equivalence relation. *) (* root e x == a representative of connect e x, which is the component *) (* of x in the transitive closure of e. *) (* roots e == the codomain predicate of root e. *) (* n_comp e a == the number of e-connected components of a, when a is *) (* e-closed and connect e is symmetric. *) (* equivalence classes of connect e if connect_sym e holds. *) (* closed e a == the collective predicate a is e-invariant. *) (* closure e a == the e-closure of a (the image of a under connect e). *) (* rel_adjunction h e e' a <-> in the e-closed domain a, h is the left part *) (* of an adjunction from e to another relation e'. *) (* fconnect f == connect (frel f), i.e., "connected under f iteration". *) (* froot f x == root (frel f) x, the root of the orbit of x under f. *) (* froots f == roots (frel f) == orbit representatives for f. *) (* orbit f x == lists the f-orbit of x. *) (* findex f x y == index of y in the f-orbit of x. *) (* order f x == size (cardinal) of the f-orbit of x. *) (* order_set f n == elements of f-order n. *) (* finv f == the inverse of f, if f is injective. *) (* := finv f x := iter (order x).-1 f x. *) (* fcard f a == number of orbits of f in a, provided a is f-invariant *) (* f is one-to-one. *) (* fclosed f a == the collective predicate a is f-invariant. *) (* fclosure f a == the closure of a under f iteration. *) (* fun_adjunction == rel_adjunction (frel f). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Definition grel (T : eqType) (g : T -> seq T) := [rel x y | y \in g x]. (* Decidable connectivity in finite types. *) Section Connect. Variable T : finType. Section Dfs. Variable g : T -> seq T. Implicit Type v w a : seq T. Fixpoint dfs n v x := if x \in v then v else if n is n'.+1 then foldl (dfs n') (x :: v) (g x) else v. Lemma subset_dfs n v a : v \subset foldl (dfs n) v a. Proof. elim: n a v => [|n IHn]; first by elim=> //= *; rewrite if_same. elim=> //= x a IHa v; apply: subset_trans {IHa}(IHa _); case: ifP => // _. by apply: subset_trans (IHn _ _); apply/subsetP=> y; exact: predU1r. Qed. Inductive dfs_path v x y : Prop := DfsPath p of path (grel g) x p & y = last x p & [disjoint x :: p & v]. Lemma dfs_pathP n x y v : #|T| <= #|v| + n -> y \notin v -> reflect (dfs_path v x y) (y \in dfs n v x). Proof. have dfs_id w z: z \notin w -> dfs_path w z z. by exists [::]; rewrite ?disjoint_has //= orbF. elim: n => [|n IHn] /= in x y v * => le_v'_n not_vy. rewrite addn0 (geq_leqif (subset_leqif_card (subset_predT _))) in le_v'_n. by rewrite predT_subset in not_vy. have [v_x | not_vx] := ifPn. by rewrite (negPf not_vy); right=> [] [p _ _]; rewrite disjoint_has /= v_x. set v1 := x :: v; set a := g x; have sub_dfs := subsetP (subset_dfs n _ _). have [-> | neq_yx] := eqVneq y x. by rewrite sub_dfs ?mem_head //; left; exact: dfs_id. apply: (@equivP (exists2 x1, x1 \in a & dfs_path v1 x1 y)); last first. split=> {IHn} [[x1 a_x1 [p g_p p_y]] | [p /shortenP[]]]. rewrite disjoint_has has_sym /= has_sym /= => /norP[_ not_pv]. by exists (x1 :: p); rewrite /= ?a_x1 // disjoint_has negb_or not_vx. case=> [_ _ _ eq_yx | x1 p1 /=]; first by case/eqP: neq_yx. case/andP=> a_x1 g_p1 /andP[not_p1x _] /subsetP p_p1 p1y not_pv. exists x1 => //; exists p1 => //. rewrite disjoint_sym disjoint_cons not_p1x disjoint_sym. by move: not_pv; rewrite disjoint_cons => /andP[_ /disjoint_trans->]. have{neq_yx not_vy}: y \notin v1 by exact/norP. have{le_v'_n not_vx}: #|T| <= #|v1| + n by rewrite cardU1 not_vx addSnnS. elim: {x v}a v1 => [|x a IHa] v /= le_v'_n not_vy. by rewrite (negPf not_vy); right=> [] []. set v2 := dfs n v x; have v2v: v \subset v2 := subset_dfs n v [:: x]. have [v2y | not_v2y] := boolP (y \in v2). by rewrite sub_dfs //; left; exists x; [exact: mem_head | exact: IHn]. apply: {IHa}(equivP (IHa _ _ not_v2y)). by rewrite (leq_trans le_v'_n) // leq_add2r subset_leq_card. split=> [] [x1 a_x1 [p g_p p_y not_pv]]. exists x1; [exact: predU1r | exists p => //]. by rewrite disjoint_sym (disjoint_trans v2v) // disjoint_sym. suffices not_p1v2: [disjoint x1 :: p & v2]. case/predU1P: a_x1 => [def_x1 | ]; last by exists x1; last exists p. case/pred0Pn: not_p1v2; exists x; rewrite /= def_x1 mem_head /=. suffices not_vx: x \notin v by apply/IHn; last exact: dfs_id. by move: not_pv; rewrite disjoint_cons def_x1 => /andP[]. apply: contraR not_v2y => /pred0Pn[x2 /andP[/= p_x2 v2x2]]. case/splitPl: p_x2 p_y g_p not_pv => p0 p2 p0x2. rewrite last_cat cat_path -cat_cons lastI cat_rcons {}p0x2 => p2y /andP[_ g_p2]. rewrite disjoint_cat disjoint_cons => /and3P[{p0}_ not_vx2 not_p2v]. have{not_vx2 v2x2} [p1 g_p1 p1_x2 not_p1v] := IHn _ _ v le_v'_n not_vx2 v2x2. apply/IHn=> //; exists (p1 ++ p2); rewrite ?cat_path ?last_cat -?p1_x2 ?g_p1 //. by rewrite -cat_cons disjoint_cat not_p1v. Qed. Lemma dfsP x y : reflect (exists2 p, path (grel g) x p & y = last x p) (y \in dfs #|T| [::] x). Proof. apply: (iffP (dfs_pathP _ _ _)); rewrite ?card0 // => [] [p]; exists p => //. by rewrite disjoint_sym disjoint0. Qed. End Dfs. Variable e : rel T. Definition rgraph x := enum (e x). Lemma rgraphK : grel rgraph =2 e. Proof. by move=> x y; rewrite /= mem_enum. Qed. Definition connect : rel T := fun x y => y \in dfs rgraph #|T| [::] x. Canonical connect_app_pred x := ApplicativePred (connect x). Lemma connectP x y : reflect (exists2 p, path e x p & y = last x p) (connect x y). Proof. apply: (equivP (dfsP _ x y)). by split=> [] [p e_p ->]; exists p => //; rewrite (eq_path rgraphK) in e_p *. Qed. Lemma connect_trans : transitive connect. Proof. move=> x y z /connectP[p e_p ->] /connectP[q e_q ->]; apply/connectP. by exists (p ++ q); rewrite ?cat_path ?e_p ?last_cat. Qed. Lemma connect0 x : connect x x. Proof. by apply/connectP; exists [::]. Qed. Lemma eq_connect0 x y : x = y -> connect x y. Proof. move->; exact: connect0. Qed. Lemma connect1 x y : e x y -> connect x y. Proof. by move=> e_xy; apply/connectP; exists [:: y]; rewrite /= ?e_xy. Qed. Lemma path_connect x p : path e x p -> subpred (mem (x :: p)) (connect x). Proof. move=> e_p y p_y; case/splitPl: p / p_y e_p => p q <-. by rewrite cat_path => /andP[e_p _]; apply/connectP; exists p. Qed. Definition root x := odflt x (pick (connect x)). Definition roots : pred T := fun x => root x == x. Canonical roots_pred := ApplicativePred roots. Definition n_comp_mem (m_a : mem_pred T) := #|predI roots m_a|. Lemma connect_root x : connect x (root x). Proof. by rewrite /root; case: pickP; rewrite ?connect0. Qed. Definition connect_sym := symmetric connect. Hypothesis sym_e : connect_sym. Lemma same_connect : left_transitive connect. Proof. exact: sym_left_transitive connect_trans. Qed. Lemma same_connect_r : right_transitive connect. Proof. exact: sym_right_transitive connect_trans. Qed. Lemma same_connect1 x y : e x y -> connect x =1 connect y. Proof. by move/connect1; exact: same_connect. Qed. Lemma same_connect1r x y : e x y -> connect^~ x =1 connect^~ y. Proof. by move/connect1; exact: same_connect_r. Qed. Lemma rootP x y : reflect (root x = root y) (connect x y). Proof. apply: (iffP idP) => e_xy. by rewrite /root -(eq_pick (same_connect e_xy)); case: pickP e_xy => // ->. by apply: (connect_trans (connect_root x)); rewrite e_xy sym_e connect_root. Qed. Lemma root_root x : root (root x) = root x. Proof. exact/esym/rootP/connect_root. Qed. Lemma roots_root x : roots (root x). Proof. exact/eqP/root_root. Qed. Lemma root_connect x y : (root x == root y) = connect x y. Proof. exact: sameP eqP (rootP x y). Qed. Definition closed_mem m_a := forall x y, e x y -> in_mem x m_a = in_mem y m_a. Definition closure_mem m_a : pred T := fun x => ~~ disjoint (mem (connect x)) m_a. End Connect. Hint Resolve connect0. Notation n_comp e a := (n_comp_mem e (mem a)). Notation closed e a := (closed_mem e (mem a)). Notation closure e a := (closure_mem e (mem a)). Prenex Implicits connect root roots. Implicit Arguments dfsP [T g x y]. Implicit Arguments connectP [T e x y]. Implicit Arguments rootP [T e x y]. Notation fconnect f := (connect (coerced_frel f)). Notation froot f := (root (coerced_frel f)). Notation froots f := (roots (coerced_frel f)). Notation fcard_mem f := (n_comp_mem (coerced_frel f)). Notation fcard f a := (fcard_mem f (mem a)). Notation fclosed f a := (closed (coerced_frel f) a). Notation fclosure f a := (closure (coerced_frel f) a). Section EqConnect. Variable T : finType. Implicit Types (e : rel T) (a : pred T). Lemma connect_sub e e' : subrel e (connect e') -> subrel (connect e) (connect e'). Proof. move=> e'e x _ /connectP[p e_p ->]; elim: p x e_p => //= y p IHp x /andP[exy]. by move/IHp; apply: connect_trans; exact: e'e. Qed. Lemma relU_sym e e' : connect_sym e -> connect_sym e' -> connect_sym (relU e e'). Proof. move=> sym_e sym_e'; apply: symmetric_from_pre => x _ /connectP[p e_p ->]. elim: p x e_p => //= y p IHp x /andP[e_xy /IHp{IHp}/connect_trans]; apply. case/orP: e_xy => /connect1; rewrite (sym_e, sym_e'); by apply: connect_sub y x => x y e_xy; rewrite connect1 //= e_xy ?orbT. Qed. Lemma eq_connect e e' : e =2 e' -> connect e =2 connect e'. Proof. move=> eq_e x y; apply/connectP/connectP=> [] [p e_p ->]; by exists p; rewrite // (eq_path eq_e) in e_p *. Qed. Lemma eq_n_comp e e' : connect e =2 connect e' -> n_comp_mem e =1 n_comp_mem e'. Proof. move=> eq_e [a]; apply: eq_card => x /=. by rewrite !inE /= /roots /root /= (eq_pick (eq_e x)). Qed. Lemma eq_n_comp_r {e} a a' : a =i a' -> n_comp e a = n_comp e a'. Proof. by move=> eq_a; apply: eq_card => x; rewrite inE /= eq_a. Qed. Lemma n_compC a e : n_comp e T = n_comp e a + n_comp e [predC a]. Proof. rewrite /n_comp_mem (eq_card (fun _ => andbT _)) -(cardID a); congr (_ + _). by apply: eq_card => x; rewrite !inE andbC. Qed. Lemma eq_root e e' : e =2 e' -> root e =1 root e'. Proof. by move=> eq_e x; rewrite /root (eq_pick (eq_connect eq_e x)). Qed. Lemma eq_roots e e' : e =2 e' -> roots e =1 roots e'. Proof. by move=> eq_e x; rewrite /roots (eq_root eq_e). Qed. End EqConnect. Section Closure. Variables (T : finType) (e : rel T). Hypothesis sym_e : connect_sym e. Implicit Type a : pred T. Lemma same_connect_rev : connect e =2 connect (fun x y => e y x). Proof. suff crev e': subrel (connect (fun x : T => e'^~ x)) (fun x => (connect e')^~x). by move=> x y; rewrite sym_e; apply/idP/idP; exact: crev. move=> x y /connectP[p e_p p_y]; apply/connectP. exists (rev (belast x p)); first by rewrite p_y rev_path. by rewrite -(last_cons x) -rev_rcons p_y -lastI rev_cons last_rcons. Qed. Lemma intro_closed a : (forall x y, e x y -> x \in a -> y \in a) -> closed e a. Proof. move=> cl_a x y e_xy; apply/idP/idP=> [|a_y]; first exact: cl_a. have{x e_xy} /connectP[p e_p ->]: connect e y x by rewrite sym_e connect1. by elim: p y a_y e_p => //= y p IHp x a_x /andP[/cl_a/(_ a_x)]; exact: IHp. Qed. Lemma closed_connect a : closed e a -> forall x y, connect e x y -> (x \in a) = (y \in a). Proof. move=> cl_a x _ /connectP[p e_p ->]. by elim: p x e_p => //= y p IHp x /andP[/cl_a->]; exact: IHp. Qed. Lemma connect_closed x : closed e (connect e x). Proof. by move=> y z /connect1/same_connect_r; exact. Qed. Lemma predC_closed a : closed e a -> closed e [predC a]. Proof. by move=> cl_a x y /cl_a; rewrite !inE => ->. Qed. Lemma closure_closed a : closed e (closure e a). Proof. apply: intro_closed => x y /connect1 e_xy; congr (~~ _). by apply: eq_disjoint; exact: same_connect. Qed. Lemma mem_closure a : {subset a <= closure e a}. Proof. by move=> x a_x; apply/existsP; exists x; rewrite !inE connect0. Qed. Lemma subset_closure a : a \subset closure e a. Proof. by apply/subsetP; exact: mem_closure. Qed. Lemma n_comp_closure2 x y : n_comp e (closure e (pred2 x y)) = (~~ connect e x y).+1. Proof. rewrite -(root_connect sym_e) -card2; apply: eq_card => z. apply/idP/idP=> [/andP[/eqP {2}<- /pred0Pn[t /andP[/= ezt exyt]]] |]. by case/pred2P: exyt => <-; rewrite (rootP sym_e ezt) !inE eqxx ?orbT. by case/pred2P=> ->; rewrite !inE roots_root //; apply/existsP; [exists x | exists y]; rewrite !inE eqxx ?orbT sym_e connect_root. Qed. Lemma n_comp_connect x : n_comp e (connect e x) = 1. Proof. rewrite -(card1 (root e x)); apply: eq_card => y. apply/andP/eqP => [[/eqP r_y /rootP-> //] | ->] /=. by rewrite inE connect_root roots_root. Qed. End Closure. Section Orbit. Variables (T : finType) (f : T -> T). Definition order x := #|fconnect f x|. Definition orbit x := traject f x (order x). Definition findex x y := index y (orbit x). Definition finv x := iter (order x).-1 f x. Lemma fconnect_iter n x : fconnect f x (iter n f x). Proof. apply/connectP. by exists (traject f (f x) n); [ exact: fpath_traject | rewrite last_traject ]. Qed. Lemma fconnect1 x : fconnect f x (f x). Proof. exact: (fconnect_iter 1). Qed. Lemma fconnect_finv x : fconnect f x (finv x). Proof. exact: fconnect_iter. Qed. Lemma orderSpred x : (order x).-1.+1 = order x. Proof. by rewrite /order (cardD1 x) [_ x _]connect0. Qed. Lemma size_orbit x : size (orbit x) = order x. Proof. exact: size_traject. Qed. Lemma looping_order x : looping f x (order x). Proof. apply: contraFT (ltnn (order x)); rewrite -looping_uniq => /card_uniqP. rewrite size_traject => <-; apply: subset_leq_card. by apply/subsetP=> _ /trajectP[i _ ->]; exact: fconnect_iter. Qed. Lemma fconnect_orbit x y : fconnect f x y = (y \in orbit x). Proof. apply/idP/idP=> [/connectP[_ /fpathP[m ->] ->] | /trajectP[i _ ->]]. by rewrite last_traject; exact/loopingP/looping_order. exact: fconnect_iter. Qed. Lemma orbit_uniq x : uniq (orbit x). Proof. rewrite /orbit -orderSpred looping_uniq; set n := (order x).-1. apply: contraFN (ltnn n) => /trajectP[i lt_i_n eq_fnx_fix]. rewrite {1}/n orderSpred /order -(size_traject f x n). apply: (leq_trans (subset_leq_card _) (card_size _)); apply/subsetP=> z. rewrite inE fconnect_orbit => /trajectP[j le_jn ->{z}]. rewrite -orderSpred -/n ltnS leq_eqVlt in le_jn. by apply/trajectP; case/predU1P: le_jn => [->|]; [exists i | exists j]. Qed. Lemma findex_max x y : fconnect f x y -> findex x y < order x. Proof. by rewrite [_ y]fconnect_orbit -index_mem size_orbit. Qed. Lemma findex_iter x i : i < order x -> findex x (iter i f x) = i. Proof. move=> lt_ix; rewrite -(nth_traject f lt_ix) /findex index_uniq ?orbit_uniq //. by rewrite size_orbit. Qed. Lemma iter_findex x y : fconnect f x y -> iter (findex x y) f x = y. Proof. rewrite [_ y]fconnect_orbit => fxy; pose i := index y (orbit x). have lt_ix: i < order x by rewrite -size_orbit index_mem. by rewrite -(nth_traject f lt_ix) nth_index. Qed. Lemma findex0 x : findex x x = 0. Proof. by rewrite /findex /orbit -orderSpred /= eqxx. Qed. Lemma fconnect_invariant (T' : eqType) (k : T -> T') : invariant f k =1 xpredT -> forall x y, fconnect f x y -> k x = k y. Proof. move=> eq_k_f x y /iter_findex <-; elim: {y}(findex x y) => //= n ->. by rewrite (eqP (eq_k_f _)). Qed. Section Loop. Variable p : seq T. Hypotheses (f_p : fcycle f p) (Up : uniq p). Variable x : T. Hypothesis p_x : x \in p. (* This lemma does not depend on Up : (uniq p) *) Lemma fconnect_cycle y : fconnect f x y = (y \in p). Proof. have [i q def_p] := rot_to p_x; rewrite -(mem_rot i p) def_p. have{i def_p} /andP[/eqP q_x f_q]: (f (last x q) == x) && fpath f x q. by have:= f_p; rewrite -(rot_cycle i) def_p (cycle_path x). apply/idP/idP=> [/connectP[_ /fpathP[j ->] ->] | ]; last exact: path_connect. case/fpathP: f_q q_x => n ->; rewrite !last_traject -iterS => def_x. by apply: (@loopingP _ f x n.+1); rewrite /looping def_x /= mem_head. Qed. Lemma order_cycle : order x = size p. Proof. by rewrite -(card_uniqP Up); exact (eq_card fconnect_cycle). Qed. Lemma orbit_rot_cycle : {i : nat | orbit x = rot i p}. Proof. have [i q def_p] := rot_to p_x; exists i. rewrite /orbit order_cycle -(size_rot i) def_p. suffices /fpathP[j ->]: fpath f x q by rewrite /= size_traject. by move: f_p; rewrite -(rot_cycle i) def_p (cycle_path x); case/andP. Qed. End Loop. Hypothesis injf : injective f. Lemma f_finv : cancel finv f. Proof. move=> x; move: (looping_order x) (orbit_uniq x). rewrite /looping /orbit -orderSpred looping_uniq /= /looping; set n := _.-1. case/predU1P=> // /trajectP[i lt_i_n]; rewrite -iterSr => /= /injf ->. by case/trajectP; exists i. Qed. Lemma finv_f : cancel f finv. Proof. exact (inj_can_sym f_finv injf). Qed. Lemma fin_inj_bij : bijective f. Proof. exists finv; [ exact finv_f | exact f_finv ]. Qed. Lemma finv_bij : bijective finv. Proof. exists f; [ exact f_finv | exact finv_f ]. Qed. Lemma finv_inj : injective finv. Proof. exact (can_inj f_finv). Qed. Lemma fconnect_sym x y : fconnect f x y = fconnect f y x. Proof. suff{x y} Sf x y: fconnect f x y -> fconnect f y x by apply/idP/idP; auto. case/connectP=> p f_p -> {y}; elim: p x f_p => //= y p IHp x. rewrite -{2}(finv_f x) => /andP[/eqP-> /IHp/connect_trans-> //]. exact: fconnect_finv. Qed. Let symf := fconnect_sym. Lemma iter_order x : iter (order x) f x = x. Proof. by rewrite -orderSpred iterS; exact (f_finv x). Qed. Lemma iter_finv n x : n <= order x -> iter n finv x = iter (order x - n) f x. Proof. rewrite -{2}[x]iter_order => /subnKC {1}<-; move: (_ - n) => m. by rewrite iter_add; elim: n => // n {2}<-; rewrite iterSr /= finv_f. Qed. Lemma cycle_orbit x : fcycle f (orbit x). Proof. rewrite /orbit -orderSpred (cycle_path x) /= last_traject -/(finv x). by rewrite fpath_traject f_finv andbT /=. Qed. Lemma fpath_finv x p : fpath finv x p = fpath f (last x p) (rev (belast x p)). Proof. elim: p x => //= y p IHp x; rewrite rev_cons rcons_path -{}IHp andbC /=. rewrite (canF_eq finv_f) eq_sym; congr (_ && (_ == _)). by case: p => //= z p; rewrite rev_cons last_rcons. Qed. Lemma same_fconnect_finv : fconnect finv =2 fconnect f. Proof. move=> x y; rewrite (same_connect_rev symf); apply: {x y}eq_connect => x y /=. by rewrite (canF_eq finv_f) eq_sym. Qed. Lemma fcard_finv : fcard_mem finv =1 fcard_mem f. Proof. exact: eq_n_comp same_fconnect_finv. Qed. Definition order_set n : pred T := [pred x | order x == n]. Lemma fcard_order_set n (a : pred T) : a \subset order_set n -> fclosed f a -> fcard f a * n = #|a|. Proof. move=> a_n cl_a; rewrite /n_comp_mem; set b := [predI froots f & a]. symmetry; transitivity #|preim (froot f) b|. apply: eq_card => x; rewrite !inE (roots_root fconnect_sym). by rewrite -(closed_connect cl_a (connect_root _ x)). have{cl_a a_n} (x): b x -> froot f x = x /\ order x = n. by case/andP=> /eqP-> /(subsetP a_n)/eqnP->. elim: {a b}#|b| {1 3 4}b (eqxx #|b|) => [|m IHm] b def_m f_b. by rewrite eq_card0 // => x; exact: (pred0P def_m). have [x b_x | b0] := pickP b; last by rewrite (eq_card0 b0) in def_m. have [r_x ox_n] := f_b x b_x; rewrite (cardD1 x) [x \in b]b_x eqSS in def_m. rewrite mulSn -{1}ox_n -(IHm _ def_m) => [|_ /andP[_ /f_b //]]. rewrite -(cardID (fconnect f x)); congr (_ + _); apply: eq_card => y. by apply: andb_idl => /= fxy; rewrite !inE -(rootP symf fxy) r_x. by congr (~~ _ && _); rewrite /= /in_mem /= symf -(root_connect symf) r_x. Qed. Lemma fclosed1 (a : pred T) : fclosed f a -> forall x, (x \in a) = (f x \in a). Proof. by move=> cl_a x; exact: cl_a (eqxx _). Qed. Lemma same_fconnect1 x : fconnect f x =1 fconnect f (f x). Proof. by apply: same_connect1 => /=. Qed. Lemma same_fconnect1_r x y : fconnect f x y = fconnect f x (f y). Proof. by apply: same_connect1r x => /=. Qed. End Orbit. Prenex Implicits order orbit findex finv order_set. Section FconnectId. Variable T : finType. Lemma fconnect_id (x : T) : fconnect id x =1 xpred1 x. Proof. by move=> y; rewrite (@fconnect_cycle _ _ [:: x]) //= ?inE ?eqxx. Qed. Lemma order_id (x : T) : order id x = 1. Proof. by rewrite /order (eq_card (fconnect_id x)) card1. Qed. Lemma orbit_id (x : T) : orbit id x = [:: x]. Proof. by rewrite /orbit order_id. Qed. Lemma froots_id (x : T) : froots id x. Proof. by rewrite /roots -fconnect_id connect_root. Qed. Lemma froot_id (x : T) : froot id x = x. Proof. by apply/eqP; exact: froots_id. Qed. Lemma fcard_id (a : pred T) : fcard id a = #|a|. Proof. by apply: eq_card => x; rewrite inE froots_id. Qed. End FconnectId. Section FconnectEq. Variables (T : finType) (f f' : T -> T). Lemma finv_eq_can : cancel f f' -> finv f =1 f'. Proof. move=> fK; exact: (bij_can_eq (fin_inj_bij (can_inj fK)) (finv_f (can_inj fK))). Qed. Hypothesis eq_f : f =1 f'. Let eq_rf := eq_frel eq_f. Lemma eq_fconnect : fconnect f =2 fconnect f'. Proof. exact: eq_connect eq_rf. Qed. Lemma eq_fcard : fcard_mem f =1 fcard_mem f'. Proof. exact: eq_n_comp eq_fconnect. Qed. Lemma eq_finv : finv f =1 finv f'. Proof. by move=> x; rewrite /finv /order (eq_card (eq_fconnect x)) (eq_iter eq_f). Qed. Lemma eq_froot : froot f =1 froot f'. Proof. exact: eq_root eq_rf. Qed. Lemma eq_froots : froots f =1 froots f'. Proof. exact: eq_roots eq_rf. Qed. End FconnectEq. Section FinvEq. Variables (T : finType) (f : T -> T). Hypothesis injf : injective f. Lemma finv_inv : finv (finv f) =1 f. Proof. exact: (finv_eq_can (f_finv injf)). Qed. Lemma order_finv : order (finv f) =1 order f. Proof. by move=> x; exact: eq_card (same_fconnect_finv injf x). Qed. Lemma order_set_finv n : order_set (finv f) n =i order_set f n. Proof. by move=> x; rewrite !inE order_finv. Qed. End FinvEq. Section RelAdjunction. Variables (T T' : finType) (h : T' -> T) (e : rel T) (e' : rel T'). Hypotheses (sym_e : connect_sym e) (sym_e' : connect_sym e'). Record rel_adjunction_mem m_a := RelAdjunction { rel_unit x : in_mem x m_a -> {x' : T' | connect e x (h x')}; rel_functor x' y' : in_mem (h x') m_a -> connect e' x' y' = connect e (h x') (h y') }. Variable a : pred T. Hypothesis cl_a : closed e a. Local Notation rel_adjunction := (rel_adjunction_mem (mem a)). Lemma intro_adjunction (h' : forall x, x \in a -> T') : (forall x a_x, [/\ connect e x (h (h' x a_x)) & forall y a_y, e x y -> connect e' (h' x a_x) (h' y a_y)]) -> (forall x' a_x, [/\ connect e' x' (h' (h x') a_x) & forall y', e' x' y' -> connect e (h x') (h y')]) -> rel_adjunction. Proof. move=> Aee' Ae'e; split=> [y a_y | x' z' a_x]. by exists (h' y a_y); case/Aee': (a_y). apply/idP/idP=> [/connectP[p e'p ->{z'}] | /connectP[p e_p p_z']]. elim: p x' a_x e'p => //= y' p IHp x' a_x. case: (Ae'e x' a_x) => _ Ae'x /andP[/Ae'x e_xy /IHp e_yz] {Ae'x}. by apply: connect_trans (e_yz _); rewrite // -(closed_connect cl_a e_xy). case: (Ae'e x' a_x) => /connect_trans-> //. elim: p {x'}(h x') p_z' a_x e_p => /= [|y p IHp] x p_z' a_x. by rewrite -p_z' in a_x *; case: (Ae'e _ a_x); rewrite sym_e'. case/andP=> e_xy /(IHp _ p_z') e'yz; have a_y: y \in a by rewrite -(cl_a e_xy). by apply: connect_trans (e'yz a_y); case: (Aee' _ a_x) => _ ->. Qed. Lemma strict_adjunction : injective h -> a \subset codom h -> rel_base h e e' [predC a] -> rel_adjunction. Proof. move=> /= injh h_a a_ee'; pose h' x Hx := iinv (subsetP h_a x Hx). apply: (@intro_adjunction h') => [x a_x | x' a_x]. rewrite f_iinv connect0; split=> // y a_y e_xy. by rewrite connect1 // -a_ee' !f_iinv ?negbK. rewrite [h' _ _]iinv_f //; split=> // y' e'xy. by rewrite connect1 // a_ee' ?negbK. Qed. Let ccl_a := closed_connect cl_a. Lemma adjunction_closed : rel_adjunction -> closed e' [preim h of a]. Proof. case=> _ Ae'e; apply: intro_closed => // x' y' /connect1 e'xy a_x. by rewrite Ae'e // in e'xy; rewrite !inE -(ccl_a e'xy). Qed. Lemma adjunction_n_comp : rel_adjunction -> n_comp e a = n_comp e' [preim h of a]. Proof. case=> Aee' Ae'e. have inj_h: {in predI (roots e') [preim h of a] &, injective (root e \o h)}. move=> x' y' /andP[/eqP r_x' /= a_x'] /andP[/eqP r_y' _] /(rootP sym_e). by rewrite -Ae'e // => /(rootP sym_e'); rewrite r_x' r_y'. rewrite /n_comp_mem -(card_in_image inj_h); apply: eq_card => x. apply/andP/imageP=> [[/eqP rx a_x] | [x' /andP[/eqP r_x' a_x'] ->]]; last first. by rewrite /= -(ccl_a (connect_root _ _)) roots_root. have [y' e_xy]:= Aee' x a_x; pose x' := root e' y'. have ay': h y' \in a by rewrite -(ccl_a e_xy). have e_yx: connect e (h y') (h x') by rewrite -Ae'e ?connect_root. exists x'; first by rewrite inE /= -(ccl_a e_yx) ?roots_root. by rewrite /= -(rootP sym_e e_yx) -(rootP sym_e e_xy). Qed. End RelAdjunction. Notation rel_adjunction h e e' a := (rel_adjunction_mem h e e' (mem a)). Notation "@ 'rel_adjunction' T T' h e e' a" := (@rel_adjunction_mem T T' h e e' (mem a)) (at level 10, T, T', h, e, e', a at level 8, only parsing) : type_scope. Notation fun_adjunction h f f' a := (rel_adjunction h (frel f) (frel f') a). Notation "@ 'fun_adjunction' T T' h f f' a" := (@rel_adjunction T T' h (frel f) (frel f') a) (at level 10, T, T', h, f, f', a at level 8, only parsing) : type_scope. Implicit Arguments intro_adjunction [T T' h e e' a]. Implicit Arguments adjunction_n_comp [T T' e e' a]. Unset Implicit Arguments. mathcomp-1.5/theories/alt.v0000644000175000017500000005727212307636117014767 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div fintype tuple. Require Import tuple bigop prime finset fingroup morphism perm automorphism. Require Import quotient action cyclic pgroup gseries sylow primitive_action. (******************************************************************************) (* Definitions of the symmetric and alternate groups, and some properties. *) (* 'Sym_T == The symmetric group over type T (which must have a finType *) (* structure). *) (* := [set: {perm T}] *) (* 'Alt_T == The alternating group over type T. *) (******************************************************************************) Unset Printing Implicit Defensive. Set Implicit Arguments. Unset Strict Implicit. Import GroupScope. Definition bool_groupMixin := FinGroup.Mixin addbA addFb addbb. Canonical bool_baseGroup := Eval hnf in BaseFinGroupType bool bool_groupMixin. Canonical boolGroup := Eval hnf in FinGroupType addbb. Section SymAltDef. Variable T : finType. Implicit Types (s : {perm T}) (x y z : T). (** Definitions of the alternate groups and some Properties **) Definition Sym of phant T : {set {perm T}} := setT. Canonical Sym_group phT := Eval hnf in [group of Sym phT]. Notation Local "'Sym_T" := (Sym (Phant T)) (at level 0). Canonical sign_morph := @Morphism _ _ 'Sym_T _ (in2W (@odd_permM _)). Definition Alt of phant T := 'ker (@odd_perm T). Canonical Alt_group phT := Eval hnf in [group of Alt phT]. Notation Local "'Alt_T" := (Alt (Phant T)) (at level 0). Lemma Alt_even p : (p \in 'Alt_T) = ~~ p. Proof. by rewrite !inE /=; case: odd_perm. Qed. Lemma Alt_subset : 'Alt_T \subset 'Sym_T. Proof. exact: subsetT. Qed. Lemma Alt_normal : 'Alt_T <| 'Sym_T. Proof. exact: ker_normal. Qed. Lemma Alt_norm : 'Sym_T \subset 'N('Alt_T). Proof. by case/andP: Alt_normal. Qed. Let n := #|T|. Lemma Alt_index : 1 < n -> #|'Sym_T : 'Alt_T| = 2. Proof. move=> lt1n; rewrite -card_quotient ?Alt_norm //=. have : ('Sym_T / 'Alt_T) \isog (@odd_perm T @* 'Sym_T) by apply: first_isog. case/isogP=> g /injmP/card_in_imset <-. rewrite /morphim setIid=> ->; rewrite -card_bool; apply: eq_card => b. apply/imsetP; case: b => /=; last first. by exists (1 : {perm T}); [rewrite setIid inE | rewrite odd_perm1]. case: (pickP T) lt1n => [x1 _ | d0]; last by rewrite /n eq_card0. rewrite /n (cardD1 x1) ltnS lt0n => /existsP[x2 /=]. by rewrite eq_sym andbT -odd_tperm; exists (tperm x1 x2); rewrite ?inE. Qed. Lemma card_Sym : #|'Sym_T| = n`!. Proof. rewrite -[n]cardsE -card_perm; apply: eq_card => p. by apply/idP/subsetP=> [? ?|]; rewrite !inE. Qed. Lemma card_Alt : 1 < n -> (2 * #|'Alt_T|)%N = n`!. Proof. by move/Alt_index <-; rewrite mulnC (Lagrange Alt_subset) card_Sym. Qed. Lemma Sym_trans : [transitive^n 'Sym_T, on setT | 'P]. Proof. apply/imsetP; pose t1 := [tuple of enum T]. have dt1: t1 \in n.-dtuple(setT) by rewrite inE enum_uniq; apply/subsetP. exists t1 => //; apply/setP=> t; apply/idP/imsetP=> [|[a _ ->{t}]]; last first. by apply: n_act_dtuple => //; apply/astabsP=> x; rewrite !inE. case/dtuple_onP=> injt _; have injf := inj_comp injt enum_rank_inj. exists (perm injf); first by rewrite inE. apply: eq_from_tnth => i; rewrite tnth_map /= [aperm _ _]permE; congr tnth. by rewrite (tnth_nth (enum_default i)) enum_valK. Qed. Lemma Alt_trans : [transitive^n.-2 'Alt_T, on setT | 'P]. Proof. case n_m2: n Sym_trans => [|[|m]] /= tr_m2; try exact: ntransitive0. have tr_m := ntransitive_weak (leqW (leqnSn m)) tr_m2. case/imsetP: tr_m2; case/tupleP=> x; case/tupleP=> y t. rewrite !dtuple_on_add 2![x \in _]inE inE negb_or /= -!andbA. case/and4P=> nxy ntx nty dt _; apply/imsetP; exists t => //; apply/setP=> u. apply/idP/imsetP=> [|[a _ ->{u}]]; last first. by apply: n_act_dtuple => //; apply/astabsP=> z; rewrite !inE. case/(atransP2 tr_m dt)=> /= a _ ->{u}. case odd_a: (odd_perm a); last by exists a => //; rewrite !inE /= odd_a. exists (tperm x y * a); first by rewrite !inE /= odd_permM odd_tperm nxy odd_a. apply/val_inj/eq_in_map => z tz; rewrite actM /= /aperm; congr (a _). by case: tpermP ntx nty => // <-; rewrite tz. Qed. Lemma aperm_faithful (A : {group {perm T}}) : [faithful A, on setT | 'P]. Proof. by apply/faithfulP=> /= p _ np1; apply/eqP/perm_act1P=> y; rewrite np1 ?inE. Qed. End SymAltDef. Notation "''Sym_' T" := (Sym (Phant T)) (at level 8, T at level 2, format "''Sym_' T") : group_scope. Notation "''Sym_' T" := (Sym_group (Phant T)) : Group_scope. Notation "''Alt_' T" := (Alt (Phant T)) (at level 8, T at level 2, format "''Alt_' T") : group_scope. Notation "''Alt_' T" := (Alt_group (Phant T)) : Group_scope. Lemma trivial_Alt_2 (T : finType) : #|T| <= 2 -> 'Alt_T = 1. Proof. rewrite leq_eqVlt => /predU1P[] oT. by apply: card_le1_trivg; rewrite -leq_double -mul2n card_Alt oT. suffices Sym1: 'Sym_T = 1 by apply/trivgP; rewrite -Sym1 subsetT. by apply: card1_trivg; rewrite card_Sym; case: #|T| oT; do 2?case. Qed. Lemma simple_Alt_3 (T : finType) : #|T| = 3 -> simple 'Alt_T. Proof. move=> T3; have{T3} oA: #|'Alt_T| = 3. by apply: double_inj; rewrite -mul2n card_Alt T3. apply/simpleP; split=> [|K]; [by rewrite trivg_card1 oA | case/andP=> sKH _]. have:= cardSg sKH; rewrite oA dvdn_divisors // !inE orbC /= -oA. case/pred2P=> eqK; [right | left]; apply/eqP. by rewrite eqEcard sKH eqK leqnn. by rewrite eq_sym eqEcard sub1G eqK cards1. Qed. Lemma not_simple_Alt_4 (T : finType) : #|T| = 4 -> ~~ simple 'Alt_T. Proof. move=> oT; set A := 'Alt_T. have oA: #|A| = 12 by apply: double_inj; rewrite -mul2n card_Alt oT. suffices [p]: exists p, [/\ prime p, 1 < #|A|`_p < #|A| & #|'Syl_p(A)| == 1%N]. case=> p_pr pA_int; rewrite /A; case/normal_sylowP=> P; case/pHallP. rewrite /= -/A => sPA pP nPA; apply/simpleP=> [] [_]; rewrite -pP in pA_int. by case/(_ P)=> // defP; rewrite defP oA ?cards1 in pA_int. have: #|'Syl_3(A)| \in filter [pred d | d %% 3 == 1%N] (divisors 12). by rewrite mem_filter -dvdn_divisors //= -oA card_Syl_dvd ?card_Syl_mod. rewrite /= oA mem_seq2 orbC. case/predU1P=> [oQ3|]; [exists 2 | exists 3]; split; rewrite ?p_part //. pose A3 := [set x : {perm T} | #[x] == 3]; suffices oA3: #|A :&: A3| = 8. have sQ2 P: P \in 'Syl_2(A) -> P :=: A :\: A3. rewrite inE pHallE oA p_part -natTrecE /= => /andP[sPA /eqP oP]. apply/eqP; rewrite eqEcard -(leq_add2l 8) -{1}oA3 cardsID oA oP. rewrite andbT subsetD sPA; apply/exists_inP=> -[x] /= Px. by rewrite inE => /eqP ox; have:= order_dvdG Px; rewrite oP ox. have [/= P sylP] := Sylow_exists 2 [group of A]. rewrite -(([set P] =P 'Syl_2(A)) _) ?cards1 // eqEsubset sub1set inE sylP. by apply/subsetP=> Q sylQ; rewrite inE -val_eqE /= !sQ2 // inE. rewrite -[8]/(4 * 2)%N -{}oQ3 -sum1_card -sum_nat_const. rewrite (partition_big (fun x => <[x]>%G) (mem 'Syl_3(A))) => [|x]; last first. by case/setIP=> Ax; rewrite /= !inE pHallE p_part cycle_subG Ax oA. apply: eq_bigr => Q; rewrite inE /= inE pHallE oA p_part -?natTrecE //=. case/andP=> sQA /eqP oQ; have:= oQ. rewrite (cardsD1 1) group1 -sum1_card => [[/= <-]]; apply: eq_bigl => x. rewrite setIC -val_eqE /= 2!inE in_setD1 -andbA -{4}[x]expg1 -order_dvdn dvdn1. apply/and3P/andP=> [[/eqP-> _ /eqP <-] | [ntx Qx]]; first by rewrite cycle_id. have:= order_dvdG Qx; rewrite oQ dvdn_divisors // mem_seq2 (negPf ntx) /=. by rewrite eqEcard cycle_subG Qx (subsetP sQA) // oQ /order => /eqP->. Qed. Lemma simple_Alt5_base (T : finType) : #|T| = 5 -> simple 'Alt_T. Proof. move=> oT. have F1: #|'Alt_T| = 60 by apply: double_inj; rewrite -mul2n card_Alt oT. have FF (H : {group {perm T}}): H <| 'Alt_T -> H :<>: 1 -> 20 %| #|H|. - move=> Hh1 Hh3. have [x _]: exists x, x \in T by apply/existsP/eqP; rewrite oT. have F2 := Alt_trans T; rewrite oT /= in F2. have F3: [transitive 'Alt_T, on setT | 'P] by exact: ntransitive1 F2. have F4: [primitive 'Alt_T, on setT | 'P] by exact: ntransitive_primitive F2. case: (prim_trans_norm F4 Hh1) => F5. case: Hh3; apply/trivgP; exact: subset_trans F5 (aperm_faithful _). have F6: 5 %| #|H| by rewrite -oT -cardsT (atrans_dvd F5). have F7: 4 %| #|H|. have F7: #|[set~ x]| = 4 by rewrite cardsC1 oT. case: (pickP (mem [set~ x])) => [y Hy | ?]; last by rewrite eq_card0 in F7. pose K := 'C_H[x | 'P]%G. have F8 : K \subset H by apply: subsetIl. pose Gx := 'C_('Alt_T)[x | 'P]%G. have F9: [transitive^2 Gx, on [set~ x] | 'P]. by rewrite -[[set~ x]]setTI -setDE stab_ntransitive ?inE. have F10: [transitive Gx, on [set~ x] | 'P]. exact: ntransitive1 F9. have F11: [primitive Gx, on [set~ x] | 'P]. exact: ntransitive_primitive F9. have F12: K \subset Gx by apply: setSI; exact: normal_sub. have F13: K <| Gx by rewrite /(K <| _) F12 normsIG // normal_norm. case: (prim_trans_norm F11 F13) => Ksub; last first. apply: dvdn_trans (cardSg F8); rewrite -F7; exact: atrans_dvd Ksub. have F14: [faithful Gx, on [set~ x] | 'P]. apply/subsetP=> g; do 2![case/setIP] => Altg cgx cgx'. apply: (subsetP (aperm_faithful 'Alt_T)). rewrite inE Altg /=; apply/astabP=> z _. case: (z =P x) => [->|]; first exact: (astab1P cgx). by move/eqP=> nxz; rewrite (astabP cgx') ?inE //. have Hreg g (z : T): g \in H -> g z = z -> g = 1. have F15 h: h \in H -> h x = x -> h = 1. move=> Hh Hhx; have: h \in K by rewrite inE Hh; apply/astab1P. by rewrite (trivGP (subset_trans Ksub F14)) => /set1P. move=> Hg Hgz; have:= in_setT x; rewrite -(atransP F3 z) ?inE //. case/imsetP=> g1 Hg1 Hg2; apply: (conjg_inj g1); rewrite conj1g. apply: F15; last by rewrite Hg2 -permM mulKVg permM Hgz. by case/normalP: Hh1 => _ nH1; rewrite -(nH1 _ Hg1) memJ_conjg. clear K F8 F12 F13 Ksub F14. case: (Cauchy _ F6) => // h Hh /eqP Horder. have diff_hnx_x n: 0 < n -> n < 5 -> x != (h ^+ n) x. move=> Hn1 Hn2; rewrite eq_sym; apply/negP => HH. have: #[h ^+ n] = 5. rewrite orderXgcd // (eqP Horder). by move: Hn1 Hn2 {HH}; do 5 (case: n => [|n] //). have Hhd2: h ^+ n \in H by rewrite groupX. by rewrite (Hreg _ _ Hhd2 (eqP HH)) order1. pose S1 := [tuple x; h x; (h ^+ 3) x]. have DnS1: S1 \in 3.-dtuple(setT). rewrite inE memtE subset_all /= !inE /= !negb_or -!andbA /= andbT. rewrite -{1}[h]expg1 !diff_hnx_x // expgSr permM. by rewrite (inj_eq (@perm_inj _ _)) diff_hnx_x. pose S2 := [tuple x; h x; (h ^+ 2) x]. have DnS2: S2 \in 3.-dtuple(setT). rewrite inE memtE subset_all /= !inE /= !negb_or -!andbA /= andbT. rewrite -{1}[h]expg1 !diff_hnx_x // expgSr permM. by rewrite (inj_eq (@perm_inj _ _)) diff_hnx_x. case: (atransP2 F2 DnS1 DnS2) => g Hg [/=]. rewrite /aperm => Hgx Hghx Hgh3x. have h_g_com: h * g = g * h. suff HH: (g * h * g^-1) * h^-1 = 1 by rewrite -[h * g]mul1g -HH !gnorm. apply: (Hreg _ x); last first. by rewrite !permM -Hgx Hghx -!permM mulKVg mulgV perm1. rewrite groupM // ?groupV // (conjgCV g) mulgK -mem_conjg. by case/normalP: Hh1 => _ ->. have: (g * (h ^+ 2) * g ^-1) x = (h ^+ 3) x. rewrite !permM -Hgx. have ->: h (h x) = (h ^+ 2) x by rewrite /= permM. by rewrite {1}Hgh3x -!permM /= mulgV mulg1 -expgSr. rewrite commuteX // mulgK {1}[expgn]lock expgS permM -lock. by move/perm_inj=> eqxhx; case/eqP: (diff_hnx_x 1%N isT isT); rewrite expg1. by rewrite (@Gauss_dvd 4 5) // F7. apply/simpleP; split => [|H Hnorm]; first by rewrite trivg_card1 F1. case Hcard1: (#|H| == 1%N); move/eqP: Hcard1 => Hcard1. by left; apply: card1_trivg; rewrite Hcard1. right; case Hcard60: (#|H| == 60%N); move/eqP: Hcard60 => Hcard60. by apply/eqP; rewrite eqEcard Hcard60 F1 andbT; case/andP: Hnorm. have Hcard20: #|H| = 20; last clear Hcard1 Hcard60. have Hdiv: 20 %| #|H| by apply: FF => // HH; case Hcard1; rewrite HH cards1. case H20: (#|H| == 20); first by apply/eqP. case: Hcard60; case/andP: Hnorm; move/cardSg; rewrite F1 => Hdiv1 _. by case/dvdnP: Hdiv H20 Hdiv1 => n ->; move: n; do 4!case=> //. have prime_5: prime 5 by []. have nSyl5: #|'Syl_5(H)| = 1%N. move: (card_Syl_dvd 5 H) (card_Syl_mod H prime_5). rewrite Hcard20; case: (card _) => // n Hdiv. move: (dvdn_leq (isT: (0 < 20)%N) Hdiv). by move: (n) Hdiv; do 20 (case => //). case: (Sylow_exists 5 H) => S; case/pHallP=> sSH oS. have{oS} oS: #|S| = 5 by rewrite oS p_part Hcard20. suff: 20 %| #|S| by rewrite oS. apply FF => [|S1]; last by rewrite S1 cards1 in oS. apply: char_normal_trans Hnorm; apply: lone_subgroup_char => // Q sQH isoQS. rewrite subEproper; apply/norP=> [[nQS _]]; move: nSyl5. rewrite (cardsD1 S) (cardsD1 Q) 4!{1}inE nQS !pHallE sQH sSH Hcard20 p_part. by rewrite (card_isog isoQS) oS. Qed. Section Restrict. Variables (T : finType) (x : T). Notation T' := {y | y != x}. Lemma rfd_funP (p : {perm T}) (u : T') : let p1 := if p x == x then p else 1 in p1 (val u) != x. Proof. case: (p x =P x) => /= [pxx|_]; last by rewrite perm1 (valP u). by rewrite -{2}pxx (inj_eq (@perm_inj _ p)); exact: (valP u). Qed. Definition rfd_fun p := [fun u => Sub ((_ : {perm T}) _) (rfd_funP p u) : T']. Lemma rfdP p : injective (rfd_fun p). Proof. apply: can_inj (rfd_fun p^-1) _ => u; apply: val_inj => /=. rewrite -(inj_eq (@perm_inj _ p)) permKV eq_sym. by case: eqP => _; rewrite !(perm1, permK). Qed. Definition rfd p := perm (@rfdP p). Hypothesis card_T : 2 < #|T|. Lemma rfd_morph : {in 'C_('Sym_T)[x | 'P] &, {morph rfd : y z / y * z}}. Proof. move=> p q; rewrite !setIA !setIid; move/astab1P=> p_x; move/astab1P=> q_x. apply/permP=> u; apply: val_inj. by rewrite permE /= !permM !permE /= [p x]p_x [q x]q_x eqxx permM /=. Qed. Canonical rfd_morphism := Morphism rfd_morph. Definition rgd_fun (p : {perm T'}) := [fun x1 => if insub x1 is Some u then sval (p u) else x]. Lemma rgdP p : injective (rgd_fun p). Proof. apply: can_inj (rgd_fun p^-1) _ => y /=. case: (insubP _ y) => [u _ val_u|]; first by rewrite valK permK. by rewrite negbK; move/eqP->; rewrite insubF //= eqxx. Qed. Definition rgd p := perm (@rgdP p). Lemma rfd_odd (p : {perm T}) : p x = x -> rfd p = p :> bool. Proof. have rfd1: rfd 1 = 1. by apply/permP => u; apply: val_inj; rewrite permE /= if_same !perm1. have HP0 (t : {perm T}): #|[set x | t x != x]| = 0 -> rfd t = t :> bool. - move=> Ht; suff ->: t = 1 by rewrite rfd1 !odd_perm1. apply/permP => z; rewrite perm1; apply/eqP/wlog_neg => nonfix_z. by rewrite (cardD1 z) inE nonfix_z in Ht. elim: #|_| {-2}p (leqnn #|[set x | p x != x]|) => {p}[|n Hrec] p Hp Hpx. by apply: HP0; move: Hp; case: card. case Ex: (pred0b (mem [set x | p x != x])); first by apply: HP0; move/eqnP: Ex. case/pred0Pn: Ex => x1; rewrite /= inE => Hx1. have nx1x: x1 != x by apply/eqP => HH; rewrite HH Hpx eqxx in Hx1. have npxx1: p x != x1 by apply/eqP => HH; rewrite -HH !Hpx eqxx in Hx1. have npx1x: p x1 != x. by apply/eqP; rewrite -Hpx; move/perm_inj => HH; case/eqP: nx1x. pose p1 := p * tperm x1 (p x1). have Hp1: p1 x = x. by rewrite /p1 permM; case tpermP => // [<-|]; [rewrite Hpx | move/perm_inj]. have Hcp1: #|[set x | p1 x != x]| <= n. have F1 y: p y = y -> p1 y = y. move=> Hy; rewrite /p1 permM Hy. case tpermP => //; first by move => <-. by move=> Hpx1; apply: (@perm_inj _ p); rewrite -Hpx1. have F2: p1 x1 = x1 by rewrite /p1 permM tpermR. have F3: [set x | p1 x != x] \subset [predD1 [set x | p x != x] & x1]. apply/subsetP => z; rewrite !inE permM. case tpermP => HH1 HH2. - rewrite eq_sym HH1 andbb; apply/eqP=> dx1. by rewrite dx1 HH1 dx1 eqxx in HH2. - by rewrite (perm_inj HH1) eqxx in HH2. by move->; rewrite andbT; apply/eqP => HH3; rewrite HH3 in HH2. apply: (leq_trans (subset_leq_card F3)). by move: Hp; rewrite (cardD1 x1) inE Hx1. have ->: p = p1 * tperm x1 (p x1) by rewrite -mulgA tperm2 mulg1. rewrite odd_permM odd_tperm eq_sym Hx1 morphM; last 2 first. - by rewrite 2!inE; exact/astab1P. - by rewrite 2!inE; apply/astab1P; rewrite -{1}Hpx /= /aperm -permM. rewrite odd_permM Hrec //=; congr (_ (+) _). pose x2 : T' := Sub x1 nx1x; pose px2 : T' := Sub (p x1) npx1x. suff ->: rfd (tperm x1 (p x1)) = tperm x2 px2. by rewrite odd_tperm -val_eqE eq_sym. apply/permP => z; apply/val_eqP; rewrite permE /= tpermD // eqxx. case: (tpermP x2) => [->|->|HH1 HH2]; rewrite /x2 ?tpermL ?tpermR 1?tpermD //. by apply/eqP=> HH3; case: HH1; apply: val_inj. by apply/eqP => HH3; case: HH2; apply: val_inj. Qed. Lemma rfd_iso : 'C_('Alt_T)[x | 'P] \isog 'Alt_T'. Proof. have rgd_x p: rgd p x = x by rewrite permE /= insubF //= eqxx. have rfd_rgd p: rfd (rgd p) = p. apply/permP => [[z Hz]]; apply/val_eqP; rewrite !permE. rewrite /= [rgd _ _]permE /= insubF eq_refl // permE /=. by rewrite (@insubT _ (xpredC1 x) _ _ Hz). have sSd: 'C_('Alt_T)[x | 'P] \subset 'dom rfd. by apply/subsetP=> p; rewrite !inE /=; case/andP. apply/isogP; exists [morphism of restrm sSd rfd] => /=; last first. rewrite morphim_restrm setIid; apply/setP=> z; apply/morphimP/idP=> [[p _]|]. case/setIP; rewrite Alt_even => Hp; move/astab1P=> Hp1 ->. by rewrite Alt_even rfd_odd. have dz': rgd z x == x by rewrite rgd_x. move=> kz; exists (rgd z); last by rewrite /= rfd_rgd. by rewrite 2!inE (sameP astab1P eqP). rewrite 4!inE /= (sameP astab1P eqP) dz' -rfd_odd; last exact/eqP. by rewrite rfd_rgd mker // ?set11. apply/injmP=> x1 y1 /=. case/setIP=> Hax1; move/astab1P; rewrite /= /aperm => Hx1. case/setIP=> Hay1; move/astab1P; rewrite /= /aperm => Hy1 Hr. apply/permP => z. case (z =P x) => [->|]; [by rewrite Hx1 | move/eqP => nzx]. move: (congr1 (fun q : {perm T'} => q (Sub z nzx)) Hr). by rewrite !permE => [[]]; rewrite Hx1 Hy1 !eqxx. Qed. End Restrict. Lemma simple_Alt5 (T : finType) : #|T| >= 5 -> simple 'Alt_T. Proof. suff F1 n: #|T| = n + 5 -> simple 'Alt_T by move/subnK/esym/F1. elim: n T => [| n Hrec T Hde]; first exact: simple_Alt5_base. have oT: 5 < #|T| by rewrite Hde addnC. apply/simpleP; split=> [|H Hnorm]; last have [Hh1 nH] := andP Hnorm. rewrite trivg_card1 -[#|_|]half_double -mul2n card_Alt Hde addnC //. by rewrite addSn factS mulnC -(prednK (fact_gt0 _)). case E1: (pred0b T); first by rewrite /pred0b in E1; rewrite (eqP E1) in oT. case/pred0Pn: E1 => x _; have Hx := in_setT x. have F2: [transitive^4 'Alt_T, on setT | 'P]. by apply: ntransitive_weak (Alt_trans T); rewrite -(subnKC oT). have F3 := ntransitive1 (isT: 0 < 4) F2. have F4 := ntransitive_primitive (isT: 1 < 4) F2. case Hcard1: (#|H| == 1%N); move/eqP: Hcard1 => Hcard1. by left; apply: card1_trivg; rewrite Hcard1. right; case: (prim_trans_norm F4 Hnorm) => F5. by rewrite (trivGP (subset_trans F5 (aperm_faithful _))) cards1 in Hcard1. case E1: (pred0b (predD1 T x)). rewrite /pred0b in E1; move: oT. by rewrite (cardD1 x) (eqP E1); case: (T x). case/pred0Pn: E1 => y Hdy; case/andP: (Hdy) => diff_x_y Hy. pose K := 'C_H[x | 'P]%G. have F8: K \subset H by apply: subsetIl. pose Gx := 'C_('Alt_T)[x | 'P]. have F9: [transitive^3 Gx, on [set~ x] | 'P]. by rewrite -[[set~ x]]setTI -setDE stab_ntransitive ?inE. have F10: [transitive Gx, on [set~ x] | 'P]. by apply: ntransitive1 F9. have F11: [primitive Gx, on [set~ x] | 'P]. by apply: ntransitive_primitive F9. have F12: K \subset Gx by rewrite setSI // normal_sub. have F13: K <| Gx by apply/andP; rewrite normsIG. have:= prim_trans_norm F11; case/(_ K) => //= => Ksub; last first. have F14: Gx * H = 'Alt_T by exact/(subgroup_transitiveP _ _ F3). have: simple Gx. by rewrite (isog_simple (rfd_iso x)) Hrec //= card_sig cardC1 Hde. case/simpleP=> _ simGx; case/simGx: F13 => /= HH2. case Ez: (pred0b (predD1 (predD1 T x) y)). move: oT; rewrite /pred0b in Ez. by rewrite (cardD1 x) (cardD1 y) (eqP Ez) inE /= inE /= diff_x_y. case/pred0Pn: Ez => z; case/andP => diff_y_z Hdz. have [diff_x_z Hz] := andP Hdz. have: z \in [set~ x] by rewrite !inE. rewrite -(atransP Ksub y) ?inE //; case/imsetP => g. rewrite /= HH2 inE; move/eqP=> -> HH4. by case/negP: diff_y_z; rewrite HH4 act1. by rewrite /= -F14 -[Gx]HH2 (mulSGid F8). have F14: [faithful Gx, on [set~ x] | 'P]. apply: subset_trans (aperm_faithful 'Sym_T); rewrite subsetI subsetT. apply/subsetP=> g; do 2![case/setIP]=> _ cgx cgx'; apply/astabP=> z _ /=. case: (z =P x) => [->|]; first exact: (astab1P cgx). by move/eqP=> zx; rewrite [_ g](astabP cgx') ?inE. have Hreg g z: g \in H -> g z = z -> g = 1. have F15 h: h \in H -> h x = x -> h = 1. move=> Hh Hhx; have: h \in K by rewrite inE Hh; apply/astab1P. by rewrite [K](trivGP (subset_trans Ksub F14)) => /set1P. move=> Hg Hgz; have:= in_setT x; rewrite -(atransP F3 z) ?inE //. case/imsetP=> g1 Hg1 Hg2; apply: (conjg_inj g1); rewrite conj1g. apply: F15; last by rewrite Hg2 -permM mulKVg permM Hgz. by rewrite memJ_norm ?(subsetP nH). clear K F8 F12 F13 Ksub F14. have Hcard: 5 < #|H|. apply: (leq_trans oT); apply dvdn_leq; first by exact: cardG_gt0. by rewrite -cardsT (atrans_dvd F5). case Eh: (pred0b [predD1 H & 1]). by move: Hcard; rewrite /pred0b in Eh; rewrite (cardD1 1) group1 (eqP Eh). case/pred0Pn: Eh => h; case/andP => diff_1_h /= Hh. case Eg: (pred0b (predD1 (predD1 [predD1 H & 1] h) h^-1)). move: Hcard; rewrite ltnNge; case/negP. rewrite (cardD1 1) group1 (cardD1 h) (cardD1 h^-1) (eqnP Eg). by do 2!case: (_ \in _). case/pred0Pn: Eg => g; case/andP => diff_h1_g; case/andP => diff_h_g. case/andP => diff_1_g /= Hg. case diff_hx_x: (h x == x). by case/negP: diff_1_h; apply/eqP; apply: (Hreg _ _ Hh (eqP diff_hx_x)). case diff_gx_x: (g x == x). case/negP: diff_1_g; apply/eqP; apply: (Hreg _ _ Hg (eqP diff_gx_x)). case diff_gx_hx: (g x == h x). case/negP: diff_h_g; apply/eqP; symmetry; apply: (mulIg g^-1); rewrite gsimp. apply: (Hreg _ x); first by rewrite groupM // groupV. by rewrite permM -(eqP diff_gx_hx) -permM mulgV perm1. case diff_hgx_x: ((h * g) x == x). case/negP: diff_h1_g; apply/eqP; apply: (mulgI h); rewrite !gsimp. by apply: (Hreg _ x); [exact: groupM | apply/eqP]. case diff_hgx_hx: ((h * g) x == h x). case/negP: diff_1_g; apply/eqP. by apply: (Hreg _ (h x)) => //; apply/eqP; rewrite -permM. case diff_hgx_gx: ((h * g) x == g x). case/eqP: diff_hx_x; apply: (@perm_inj _ g) => //. by apply/eqP; rewrite -permM. case Ez: (pred0b (predD1 (predD1 (predD1 (predD1 T x) (h x)) (g x)) ((h * g) x))). - move: oT; rewrite /pred0b in Ez. rewrite (cardD1 x) (cardD1 (h x)) (cardD1 (g x)) (cardD1 ((h * g) x)). by rewrite (eqP Ez); do 3!case: (_ x \in _). case/pred0Pn: Ez => z. case/and5P=> diff_hgx_z diff_gx_z diff_hx_z diff_x_z /= Hz. pose S1 := [tuple x; h x; g x; z]. have DnS1: S1 \in 4.-dtuple(setT). rewrite inE memtE subset_all -!andbA !negb_or /= !inE !andbT. rewrite -!(eq_sym z) diff_gx_z diff_x_z diff_hx_z. by rewrite !(eq_sym x) diff_hx_x diff_gx_x eq_sym diff_gx_hx. pose S2 := [tuple x; h x; g x; (h * g) x]. have DnS2: S2 \in 4.-dtuple(setT). rewrite inE memtE subset_all -!andbA !negb_or /= !inE !andbT !(eq_sym x). rewrite diff_hx_x diff_gx_x diff_hgx_x. by rewrite !(eq_sym (h x)) diff_gx_hx diff_hgx_hx eq_sym diff_hgx_gx. case: (atransP2 F2 DnS1 DnS2) => k Hk [/=]. rewrite /aperm => Hkx Hkhx Hkgx Hkhgx. have h_k_com: h * k = k * h. suff HH: (k * h * k^-1) * h^-1 = 1 by rewrite -[h * k]mul1g -HH !gnorm. apply: (Hreg _ x); last first. by rewrite !permM -Hkx Hkhx -!permM mulKVg mulgV perm1. by rewrite groupM // ?groupV // (conjgCV k) mulgK -mem_conjg (normsP nH). have g_k_com: g * k = k * g. suff HH: (k * g * k^-1) * g^-1 = 1 by rewrite -[g * k]mul1g -HH !gnorm. apply: (Hreg _ x); last first. by rewrite !permM -Hkx Hkgx -!permM mulKVg mulgV perm1. by rewrite groupM // ?groupV // (conjgCV k) mulgK -mem_conjg (normsP nH). have HH: (k * (h * g) * k ^-1) x = z. by rewrite 2!permM -Hkx Hkhgx -permM mulgV perm1. case/negP: diff_hgx_z. rewrite -HH !mulgA -h_k_com -!mulgA [k * _]mulgA. by rewrite -g_k_com -!mulgA mulgV mulg1. Qed. mathcomp-1.5/theories/maximal.v0000644000175000017500000022376012307636117015634 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq choice div fintype. Require Import finfun bigop finset prime binomial fingroup morphism perm. Require Import automorphism quotient action commutator gproduct gfunctor. Require Import ssralg finalg zmodp cyclic pgroup center gseries. Require Import nilpotent sylow abelian finmodule. (******************************************************************************) (* This file establishes basic properties of several important classes of *) (* maximal subgroups: maximal, max and min normal, simple, characteristically *) (* simple subgroups, the Frattini and Fitting subgroups, the Thompson *) (* critical subgroup, special and extra-special groups, and self-centralising *) (* normal (SCN) subgroups. In detail, we define: *) (* charsimple G == G is characteristically simple (it has no nontrivial *) (* characteristic subgroups, and is nontrivial) *) (* 'Phi(G) == the Frattini subgroup of G, i.e., the intersection of *) (* all its maximal proper subgroups. *) (* 'F(G) == the Fitting subgroup of G, i.e., the largest normal *) (* nilpotent subgroup of G (defined as the (direct) *) (* product of all the p-cores of G). *) (* critical C G == C is a critical subgroup of G: C is characteristic *) (* (but not functorial) in G, the center of C contains *) (* both its Frattini subgroup and the commutator [G, C], *) (* and is equal to the centraliser of C in G. The *) (* Thompson_critical theorem provides critical subgroups *) (* for p-groups; we also show that in this case the *) (* centraliser of C in Aut G is a p-group as well. *) (* special G == G is a special group: its center, Frattini, and *) (* derived sugroups coincide (we follow Aschbacher in *) (* not considering nontrivial elementary abelian groups *) (* as special); we show that a p-group factors under *) (* coprime action into special groups (Aschbacher 24.7). *) (* extraspecial G == G is a special group whose center has prime order *) (* (hence G is non-abelian). *) (* 'SCN(G) == the set of self-centralising normal abelian subgroups *) (* of G (the A <| G such that 'C_G(A) = A). *) (* 'SCN_n(G) == the subset of 'SCN(G) containing all groups with rank *) (* at least n (i.e., A \in 'SCN(G) and 'm(A) >= n). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section Defs. Variable gT : finGroupType. Implicit Types (A B D : {set gT}) (G : {group gT}). Definition charsimple A := [min A of G | G :!=: 1 & G \char A]. Definition Frattini A := \bigcap_(G : {group gT} | maximal_eq G A) G. Canonical Frattini_group A : {group gT} := Eval hnf in [group of Frattini A]. Definition Fitting A := \big[dprod/1]_(p <- primes #|A|) 'O_p(A). Lemma Fitting_group_set G : group_set (Fitting G). Proof. suffices [F ->]: exists F : {group gT}, Fitting G = F by exact: groupP. rewrite /Fitting; elim: primes (primes_uniq #|G|) => [_|p r IHr] /=. by exists [1 gT]%G; rewrite big_nil. case/andP=> rp /IHr[F defF]; rewrite big_cons defF. suffices{IHr} /and3P[p'F sFG nFG]: p^'.-group F && (F <| G). have nFGp: 'O_p(G) \subset 'N(F) := subset_trans (pcore_sub p G) nFG. have pGp: p.-group('O_p(G)) := pcore_pgroup p G. have{pGp} tiGpF: 'O_p(G) :&: F = 1 by rewrite coprime_TIg ?(pnat_coprime pGp). exists ('O_p(G) <*> F)%G; rewrite dprodEY // (sameP commG1P trivgP) -tiGpF. by rewrite subsetI commg_subl commg_subr (subset_trans sFG) // gFnorm. move/bigdprodWY: defF => <- {F}; elim: r rp => [_|q r IHr] /=. by rewrite big_nil gen0 pgroup1 normal1. rewrite inE eq_sym big_cons -joingE -joing_idr => /norP[qp /IHr {IHr}]. set F := <<_>> => /andP[p'F nsFG]; rewrite norm_joinEl /= -/F; last first. exact: subset_trans (pcore_sub q G) (normal_norm nsFG). by rewrite pgroupM p'F normalM ?pcore_normal //= (pi_pgroup (pcore_pgroup q G)). Qed. Canonical Fitting_group G := group (Fitting_group_set G). Definition critical A B := [/\ A \char B, Frattini A \subset 'Z(A), [~: B, A] \subset 'Z(A) & 'C_B(A) = 'Z(A)]. Definition special A := Frattini A = 'Z(A) /\ A^`(1) = 'Z(A). Definition extraspecial A := special A /\ prime #|'Z(A)|. Definition SCN B := [set A : {group gT} | A <| B & 'C_B(A) == A]. Definition SCN_at n B := [set A in SCN B | n <= 'r(A)]. End Defs. Arguments Scope charsimple [_ group_scope]. Arguments Scope Frattini [_ group_scope]. Arguments Scope Fitting [_ group_scope]. Arguments Scope critical [_ group_scope group_scope]. Arguments Scope special [_ group_scope]. Arguments Scope extraspecial [_ group_scope]. Arguments Scope SCN [_ group_scope]. Arguments Scope SCN_at [_ nat_scope group_scope]. Prenex Implicits maximal simple charsimple critical special extraspecial. Notation "''Phi' ( A )" := (Frattini A) (at level 8, format "''Phi' ( A )") : group_scope. Notation "''Phi' ( G )" := (Frattini_group G) : Group_scope. Notation "''F' ( G )" := (Fitting G) (at level 8, format "''F' ( G )") : group_scope. Notation "''F' ( G )" := (Fitting_group G) : Group_scope. Notation "''SCN' ( B )" := (SCN B) (at level 8, format "''SCN' ( B )") : group_scope. Notation "''SCN_' n ( B )" := (SCN_at n B) (at level 8, n at level 2, format "''SCN_' n ( B )") : group_scope. Section PMax. Variables (gT : finGroupType) (p : nat) (P M : {group gT}). Hypothesis pP : p.-group P. Lemma p_maximal_normal : maximal M P -> M <| P. Proof. case/maxgroupP=> /andP[sMP sPM] maxM; rewrite /normal sMP. have:= subsetIl P 'N(M); rewrite subEproper. case/predU1P=> [/setIidPl-> // | /maxM/= SNM]; case/negP: sPM. rewrite (nilpotent_sub_norm (pgroup_nil pP) sMP) //. by rewrite SNM // subsetI sMP normG. Qed. Lemma p_maximal_index : maximal M P -> #|P : M| = p. Proof. move=> maxM; have nM := p_maximal_normal maxM. rewrite -card_quotient ?normal_norm //. rewrite -(quotient_maximal _ nM) ?normal_refl // trivg_quotient in maxM. case/maxgroupP: maxM; rewrite properEneq eq_sym sub1G andbT /=. case/(pgroup_pdiv (quotient_pgroup M pP)) => p_pr /Cauchy[] // xq. rewrite /order -cycle_subG subEproper => /predU1P[-> // | sxPq oxq_p _]. by move/(_ _ sxPq (sub1G _)) => xq1; rewrite -oxq_p xq1 cards1 in p_pr. Qed. Lemma p_index_maximal : M \subset P -> prime #|P : M| -> maximal M P. Proof. move=> sMP /primeP[lt1PM pr_PM]. apply/maxgroupP; rewrite properEcard sMP -(Lagrange sMP). rewrite -{1}(muln1 #|M|) ltn_pmul2l //; split=> // H sHP sMH. apply/eqP; rewrite eq_sym eqEcard sMH. case/orP: (pr_PM _ (indexSg sMH (proper_sub sHP))) => /eqP iM. by rewrite -(Lagrange sMH) iM muln1 /=. by have:= proper_card sHP; rewrite -(Lagrange sMH) iM Lagrange ?ltnn. Qed. End PMax. Section Frattini. Variables gT : finGroupType. Implicit Type G M : {group gT}. Lemma Phi_sub G : 'Phi(G) \subset G. Proof. by rewrite bigcap_inf // /maximal_eq eqxx. Qed. Lemma Phi_sub_max G M : maximal M G -> 'Phi(G) \subset M. Proof. by move=> maxM; rewrite bigcap_inf // /maximal_eq predU1r. Qed. Lemma Phi_proper G : G :!=: 1 -> 'Phi(G) \proper G. Proof. move/eqP; case/maximal_exists: (sub1G G) => [<- //| [M maxM _] _]. exact: sub_proper_trans (Phi_sub_max maxM) (maxgroupp maxM). Qed. Lemma Phi_nongen G X : 'Phi(G) <*> X = G -> <> = G. Proof. move=> defG; have: <> \subset G by rewrite -{1}defG genS ?subsetUr. case/maximal_exists=> //= [[M maxM]]; rewrite gen_subG => sXM. case/andP: (maxgroupp maxM) => _ /negP[]. by rewrite -defG gen_subG subUset Phi_sub_max. Qed. Lemma Frattini_continuous (rT : finGroupType) G (f : {morphism G >-> rT}) : f @* 'Phi(G) \subset 'Phi(f @* G). Proof. apply/bigcapsP=> M maxM; rewrite sub_morphim_pre ?Phi_sub // bigcap_inf //. have {2}<-: f @*^-1 (f @* G) = G by rewrite morphimGK ?subsetIl. by rewrite morphpre_maximal_eq ?maxM //; case/maximal_eqP: maxM. Qed. End Frattini. Canonical Frattini_igFun := [igFun by Phi_sub & Frattini_continuous]. Canonical Frattini_gFun := [gFun by Frattini_continuous]. Section Frattini0. Variable gT : finGroupType. Implicit Types (rT : finGroupType) (D G : {group gT}). Lemma Phi_char G : 'Phi(G) \char G. Proof. exact: gFchar. Qed. Lemma Phi_normal G : 'Phi(G) <| G. Proof. exact: gFnormal. Qed. Lemma injm_Phi rT D G (f : {morphism D >-> rT}) : 'injm f -> G \subset D -> f @* 'Phi(G) = 'Phi(f @* G). Proof. exact: injmF. Qed. Lemma isog_Phi rT G (H : {group rT}) : G \isog H -> 'Phi(G) \isog 'Phi(H). Proof. exact: gFisog. Qed. Lemma PhiJ G x : 'Phi(G :^ x) = 'Phi(G) :^ x. Proof. rewrite -{1}(setIid G) -(setIidPr (Phi_sub G)) -!morphim_conj. by rewrite injm_Phi ?injm_conj. Qed. End Frattini0. Section Frattini2. Variables gT : finGroupType. Implicit Type G : {group gT}. Lemma Phi_quotient_id G : 'Phi (G / 'Phi(G)) = 1. Proof. apply/trivgP; rewrite -cosetpreSK cosetpre1 /=; apply/bigcapsP=> M maxM. have nPhi := Phi_normal G; have nPhiM: 'Phi(G) <| M. by apply: normalS nPhi; [exact: bigcap_inf | case/maximal_eqP: maxM]. by rewrite sub_cosetpre_quo ?bigcap_inf // quotient_maximal_eq. Qed. Lemma Phi_quotient_cyclic G : cyclic (G / 'Phi(G)) -> cyclic G. Proof. case/cyclicP=> /= Px; case: (cosetP Px) => x nPx ->{Px} defG. apply/cyclicP; exists x; symmetry; apply: Phi_nongen. rewrite -joing_idr norm_joinEr -?quotientK ?cycle_subG //. by rewrite /quotient morphim_cycle //= -defG quotientGK ?Phi_normal. Qed. Variables (p : nat) (P : {group gT}). Lemma trivg_Phi : p.-group P -> ('Phi(P) == 1) = p.-abelem P. Proof. move=> pP; case: (eqsVneq P 1) => [P1 | ntP]. by rewrite P1 abelem1 -subG1 -P1 Phi_sub. have [p_pr _ _] := pgroup_pdiv pP ntP. apply/eqP/idP=> [trPhi | abP]. apply/abelemP=> //; split=> [|x Px]. apply/commG1P/trivgP; rewrite -trPhi. apply/bigcapsP=> M /predU1P[-> | maxM]; first exact: der1_subG. have /andP[_ nMP]: M <| P := p_maximal_normal pP maxM. rewrite der1_min // cyclic_abelian // prime_cyclic // card_quotient //. by rewrite (p_maximal_index pP). apply/set1gP; rewrite -trPhi; apply/bigcapP=> M. case/predU1P=> [-> | maxM]; first exact: groupX. have /andP[_ nMP] := p_maximal_normal pP maxM. have nMx : x \in 'N(M) by exact: subsetP Px. apply: coset_idr; rewrite ?groupX ?morphX //=; apply/eqP. rewrite -(p_maximal_index pP maxM) -card_quotient // -order_dvdn cardSg //=. by rewrite cycle_subG mem_quotient. apply/trivgP/subsetP=> x Phi_x; rewrite -cycle_subG. have Px: x \in P by exact: (subsetP (Phi_sub P)). have sxP: <[x]> \subset P by rewrite cycle_subG. case/splitsP: (abelem_splits abP sxP) => K /complP[tiKx defP]. have [-> | nt_x] := eqVneq x 1; first by rewrite cycle1. have oxp := abelem_order_p abP Px nt_x. rewrite /= -tiKx subsetI subxx cycle_subG. apply: (bigcapP Phi_x); apply/orP; right. apply: p_index_maximal; rewrite -?divgS -defP ?mulG_subr //. by rewrite (TI_cardMg tiKx) mulnK // [#|_|]oxp. Qed. End Frattini2. Section Frattini3. Variables (gT : finGroupType) (p : nat) (P : {group gT}). Hypothesis pP : p.-group P. Lemma Phi_quotient_abelem : p.-abelem (P / 'Phi(P)). Proof. by rewrite -trivg_Phi ?morphim_pgroup //= Phi_quotient_id. Qed. Lemma Phi_joing : 'Phi(P) = P^`(1) <*> 'Mho^1(P). Proof. have [sPhiP nPhiP] := andP (Phi_normal P). apply/eqP; rewrite eqEsubset join_subG. case: (eqsVneq P 1) => [-> | ntP] in sPhiP *. by rewrite /= (trivgP sPhiP) sub1G der_subS Mho_sub. have [p_pr _ _] := pgroup_pdiv pP ntP. have [abP x1P] := abelemP p_pr Phi_quotient_abelem. apply/andP; split. have nMP: P \subset 'N(P^`(1) <*> 'Mho^1(P)) by rewrite normsY // !gFnorm. rewrite -quotient_sub1 ?(subset_trans sPhiP) //=. suffices <-: 'Phi(P / (P^`(1) <*> 'Mho^1(P))) = 1 by exact: morphimF. apply/eqP; rewrite (trivg_Phi (morphim_pgroup _ pP)) /= -quotientE. apply/abelemP=> //; rewrite [abelian _]quotient_cents2 ?joing_subl //. split=> // _ /morphimP[x Nx Px ->] /=. rewrite -morphX //= coset_id // (MhoE 1 pP) joing_idr expn1. by rewrite mem_gen //; apply/setUP; right; exact: mem_imset. rewrite -quotient_cents2 // [_ \subset 'C(_)]abP (MhoE 1 pP) gen_subG /=. apply/subsetP=> _ /imsetP[x Px ->]; rewrite expn1. have nPhi_x: x \in 'N('Phi(P)) by exact: (subsetP nPhiP). by rewrite coset_idr ?groupX ?morphX ?x1P ?mem_morphim. Qed. Lemma Phi_Mho : abelian P -> 'Phi(P) = 'Mho^1(P). Proof. by move=> cPP; rewrite Phi_joing (derG1P cPP) joing1G. Qed. End Frattini3. Section Frattini4. Variables (p : nat) (gT : finGroupType). Implicit Types (rT : finGroupType) (P G H K D : {group gT}). Lemma PhiS G H : p.-group H -> G \subset H -> 'Phi(G) \subset 'Phi(H). Proof. move=> pH sGH; rewrite (Phi_joing pH) (Phi_joing (pgroupS sGH pH)). by rewrite genS // setUSS ?dergS ?MhoS. Qed. Lemma morphim_Phi rT P D (f : {morphism D >-> rT}) : p.-group P -> P \subset D -> f @* 'Phi(P) = 'Phi(f @* P). Proof. move=> pP sPD; rewrite !(@Phi_joing _ p) ?morphim_pgroup //. rewrite morphim_gen ?(subset_trans _ sPD) ?subUset ?der_subS ?Mho_sub //. by rewrite morphimU -joingE morphimR ?morphim_Mho. Qed. Lemma quotient_Phi P H : p.-group P -> P \subset 'N(H) -> 'Phi(P) / H = 'Phi(P / H). Proof. exact: morphim_Phi. Qed. (* This is Aschbacher (23.2) *) Lemma Phi_min G H : p.-group G -> G \subset 'N(H) -> p.-abelem (G / H) -> 'Phi(G) \subset H. Proof. move=> pG nHG; rewrite -trivg_Phi ?quotient_pgroup // -subG1 /=. by rewrite -(quotient_Phi pG) ?quotient_sub1 // (subset_trans (Phi_sub _)). Qed. Lemma Phi_cprod G H K : p.-group G -> H \* K = G -> 'Phi(H) \* 'Phi(K) = 'Phi(G). Proof. move=> pG defG; have [_ /mulG_sub[sHG sKG] cHK] := cprodP defG. rewrite cprodEY /=; last by rewrite (centSS (Phi_sub _) (Phi_sub _)). rewrite !(Phi_joing (pgroupS _ pG)) //=. have /cprodP[_ <- /cent_joinEr <-] := der_cprod 1 defG. have /cprodP[_ <- /cent_joinEr <-] := Mho_cprod 1 defG. by rewrite !joingA /= -!(joingA H^`(1)) (joingC K^`(1)). Qed. Lemma Phi_mulg H K : p.-group H -> p.-group K -> K \subset 'C(H) -> 'Phi(H * K) = 'Phi(H) * 'Phi(K). Proof. move=> pH pK cHK; have defHK := cprodEY cHK. have [|_ -> _] := cprodP (Phi_cprod _ defHK); rewrite /= cent_joinEr //. by apply: pnat_dvd (dvdn_cardMg H K) _; rewrite pnat_mul; exact/andP. Qed. Lemma charsimpleP G : reflect (G :!=: 1 /\ forall K, K :!=: 1 -> K \char G -> K :=: G) (charsimple G). Proof. apply: (iffP mingroupP); rewrite char_refl andbT => [[ntG simG]]. by split=> // K ntK chK; apply: simG; rewrite ?ntK // char_sub. split=> // K /andP[ntK chK] _; exact: simG. Qed. End Frattini4. Section Fitting. Variable gT : finGroupType. Implicit Types (p : nat) (G H : {group gT}). Lemma Fitting_normal G : 'F(G) <| G. Proof. rewrite -['F(G)](bigdprodWY (erefl 'F(G))). elim/big_rec: _ => [|p H _ nsHG]; first by rewrite gen0 normal1. by rewrite -[<<_>>]joing_idr normalY ?pcore_normal. Qed. Lemma Fitting_sub G : 'F(G) \subset G. Proof. by rewrite normal_sub ?Fitting_normal. Qed. Lemma Fitting_nil G : nilpotent 'F(G). Proof. apply: (bigdprod_nil (erefl 'F(G))) => p _. exact: pgroup_nil (pcore_pgroup p G). Qed. Lemma Fitting_max G H : H <| G -> nilpotent H -> H \subset 'F(G). Proof. move=> nsHG nilH; rewrite -(Sylow_gen H) gen_subG. apply/bigcupsP=> P /SylowP[p _ SylP]. case Gp: (p \in \pi(G)); last first. rewrite card1_trivg ?sub1G // (card_Hall SylP). rewrite part_p'nat // (pnat_dvd (cardSg (normal_sub nsHG))) //. by rewrite /pnat cardG_gt0 all_predC has_pred1 Gp. move/nilpotent_Hall_pcore: SylP => ->{P} //. rewrite -(bigdprodWY (erefl 'F(G))) sub_gen //. rewrite -(filter_pi_of (ltnSn _)) big_filter big_mkord. have le_pG: p < #|G|.+1. by rewrite ltnS dvdn_leq //; move: Gp; rewrite mem_primes => /and3P[]. apply: (bigcup_max (Ordinal le_pG)) => //=. apply: pcore_max (pcore_pgroup _ _) _. exact: char_normal_trans (pcore_char p H) nsHG. Qed. Lemma pcore_Fitting pi G : 'O_pi('F(G)) \subset 'O_pi(G). Proof. rewrite pcore_max ?pcore_pgroup //. exact: char_normal_trans (pcore_char _ _) (Fitting_normal _). Qed. Lemma p_core_Fitting p G : 'O_p('F(G)) = 'O_p(G). Proof. apply/eqP; rewrite eqEsubset pcore_Fitting pcore_max ?pcore_pgroup //. apply: normalS (normal_sub (Fitting_normal _)) (pcore_normal _ _). exact: Fitting_max (pcore_normal _ _) (pgroup_nil (pcore_pgroup _ _)). Qed. Lemma nilpotent_Fitting G : nilpotent G -> 'F(G) = G. Proof. by move=> nilG; apply/eqP; rewrite eqEsubset Fitting_sub Fitting_max. Qed. Lemma Fitting_eq_pcore p G : 'O_p^'(G) = 1 -> 'F(G) = 'O_p(G). Proof. move=> p'G1; have /dprodP[_ /= <- _ _] := nilpotent_pcoreC p (Fitting_nil G). by rewrite p_core_Fitting ['O_p^'(_)](trivgP _) ?mulg1 // -p'G1 pcore_Fitting. Qed. Lemma FittingEgen G : 'F(G) = <<\bigcup_(p < #|G|.+1 | (p : nat) \in \pi(G)) 'O_p(G)>>. Proof. apply/eqP; rewrite eqEsubset gen_subG /=. rewrite -{1}(bigdprodWY (erefl 'F(G))) (big_nth 0) big_mkord genS. by apply/bigcupsP=> p _; rewrite -p_core_Fitting pcore_sub. apply/bigcupsP=> [[i /= lti]] _; set p := nth _ _ i. have pi_p: p \in \pi(G) by rewrite mem_nth. have p_dv_G: p %| #|G| by rewrite mem_primes in pi_p; case/and3P: pi_p. have lepG: p < #|G|.+1 by rewrite ltnS dvdn_leq. by rewrite (bigcup_max (Ordinal lepG)). Qed. End Fitting. Section FittingFun. Implicit Types gT rT : finGroupType. Lemma morphim_Fitting : GFunctor.pcontinuous Fitting. Proof. move=> gT rT G D f; apply: Fitting_max. by rewrite morphim_normal ?Fitting_normal. by rewrite morphim_nil ?Fitting_nil. Qed. Lemma FittingS gT (G H : {group gT}) : H \subset G -> H :&: 'F(G) \subset 'F(H). Proof. move=> sHG; rewrite -{2}(setIidPl sHG). do 2!rewrite -(morphim_idm (subsetIl H _)) morphimIdom; exact: morphim_Fitting. Qed. Lemma FittingJ gT (G : {group gT}) x : 'F(G :^ x) = 'F(G) :^ x. Proof. rewrite !FittingEgen -genJ /= cardJg; symmetry; congr <<_>>. rewrite (big_morph (conjugate^~ x) (fun A B => conjUg A B x) (imset0 _)). by apply: eq_bigr => p _; rewrite pcoreJ. Qed. End FittingFun. Canonical Fitting_igFun := [igFun by Fitting_sub & morphim_Fitting]. Canonical Fitting_gFun := [gFun by morphim_Fitting]. Canonical Fitting_pgFun := [pgFun by morphim_Fitting]. Section IsoFitting. Variables (gT rT : finGroupType) (G D : {group gT}) (f : {morphism D >-> rT}). Lemma Fitting_char : 'F(G) \char G. Proof. exact: gFchar. Qed. Lemma injm_Fitting : 'injm f -> G \subset D -> f @* 'F(G) = 'F(f @* G). Proof. exact: injmF. Qed. Lemma isog_Fitting (H : {group rT}) : G \isog H -> 'F(G) \isog 'F(H). Proof. exact: gFisog. Qed. End IsoFitting. Section CharSimple. Variable gT : finGroupType. Implicit Types (rT : finGroupType) (G H K L : {group gT}) (p : nat). Lemma minnormal_charsimple G H : minnormal H G -> charsimple H. Proof. case/mingroupP=> /andP[ntH nHG] minH. apply/charsimpleP; split=> // K ntK chK. by apply: minH; rewrite ?ntK (char_sub chK, char_norm_trans chK). Qed. Lemma maxnormal_charsimple G H L : G <| L -> maxnormal H G L -> charsimple (G / H). Proof. case/andP=> sGL nGL /maxgroupP[/andP[/andP[sHG not_sGH] nHL] maxH]. have nHG: G \subset 'N(H) := subset_trans sGL nHL. apply/charsimpleP; rewrite -subG1 quotient_sub1 //; split=> // HK ntHK chHK. case/(inv_quotientN _): (char_normal chHK) => [|K defHK sHK]; first exact/andP. case/andP; rewrite subEproper defHK => /predU1P[-> // | ltKG] nKG. have nHK: H <| K by rewrite /normal sHK (subset_trans (proper_sub ltKG)). case/negP: ntHK; rewrite defHK -subG1 quotient_sub1 ?normal_norm //. rewrite (maxH K) // ltKG -(quotientGK nHK) -defHK norm_quotient_pre //. by rewrite (char_norm_trans chHK) ?quotient_norms. Qed. Lemma abelem_split_dprod rT p (A B : {group rT}) : p.-abelem A -> B \subset A -> exists C : {group rT}, B \x C = A. Proof. move=> abelA sBA; have [_ cAA _]:= and3P abelA. case/splitsP: (abelem_splits abelA sBA) => C /complP[tiBC defA]. by exists C; rewrite dprodE // (centSS _ sBA cAA) // -defA mulG_subr. Qed. Lemma p_abelem_split1 rT p (A : {group rT}) x : p.-abelem A -> x \in A -> exists B : {group rT}, [/\ B \subset A, #|B| = #|A| %/ #[x] & <[x]> \x B = A]. Proof. move=> abelA Ax; have sxA: <[x]> \subset A by rewrite cycle_subG. have [B defA] := abelem_split_dprod abelA sxA. have [_ defxB _ ti_xB] := dprodP defA. have sBA: B \subset A by rewrite -defxB mulG_subr. by exists B; split; rewrite // -defxB (TI_cardMg ti_xB) mulKn ?order_gt0. Qed. Lemma abelem_charsimple p G : p.-abelem G -> G :!=: 1 -> charsimple G. Proof. move=> abelG ntG; apply/charsimpleP; split=> // K ntK /charP[sKG chK]. case/eqVproper: sKG => // /properP[sKG [x Gx notKx]]. have ox := abelem_order_p abelG Gx (group1_contra notKx). have [A [sAG oA defA]] := p_abelem_split1 abelG Gx. case/trivgPn: ntK => y Ky nty; have Gy := subsetP sKG y Ky. have{nty} oy := abelem_order_p abelG Gy nty. have [B [sBG oB defB]] := p_abelem_split1 abelG Gy. have: isog A B; last case/isogP=> fAB injAB defAB. rewrite (isog_abelem_card _ (abelemS sAG abelG)) (abelemS sBG) //=. by rewrite oA oB ox oy. have: isog <[x]> <[y]>; last case/isogP=> fxy injxy /= defxy. by rewrite isog_cyclic_card ?cycle_cyclic // [#|_|]oy -ox eqxx. have cfxA: fAB @* A \subset 'C(fxy @* <[x]>). by rewrite defAB defxy; case/dprodP: defB. have injf: 'injm (dprodm defA cfxA). by rewrite injm_dprodm injAB injxy defAB defxy; apply/eqP; case/dprodP: defB. case/negP: notKx; rewrite -cycle_subG -(injmSK injf) ?cycle_subG //=. rewrite morphim_dprodml // defxy cycle_subG /= chK //. have [_ {4}<- _ _] := dprodP defB; have [_ {3}<- _ _] := dprodP defA. by rewrite morphim_dprodm // defAB defxy. Qed. Lemma charsimple_dprod G : charsimple G -> exists H : {group gT}, [/\ H \subset G, simple H & exists2 I : {set {perm gT}}, I \subset Aut G & \big[dprod/1]_(f in I) f @: H = G]. Proof. case/charsimpleP=> ntG simG. have [H minH sHG]: {H : {group gT} | minnormal H G & H \subset G}. by apply: mingroup_exists; rewrite ntG normG. case/mingroupP: minH => /andP[ntH nHG] minH. pose Iok (I : {set {perm gT}}) := (I \subset Aut G) && [exists (M : {group gT} | M <| G), \big[dprod/1]_(f in I) f @: H == M]. have defH: (1 : {perm gT}) @: H = H. apply/eqP; rewrite eqEcard card_imset ?leqnn; last exact: perm_inj. by rewrite andbT; apply/subsetP=> _ /imsetP[x Hx ->]; rewrite perm1. have [|I] := @maxset_exists _ Iok 1. rewrite /Iok sub1G; apply/existsP; exists H. by rewrite /normal sHG nHG (big_pred1 1) => [|f]; rewrite ?defH /= ?inE. case/maxsetP=> /andP[Aut_I /exists_eq_inP[M /andP[sMG nMG] defM]] maxI. rewrite sub1set=> ntI; case/eqVproper: sMG => [defG | /andP[sMG not_sGM]]. exists H; split=> //; last by exists I; rewrite ?defM. apply/mingroupP; rewrite ntH normG; split=> // N /andP[ntN nNH] sNH. apply: minH => //; rewrite ntN /= -defG. move: defM; rewrite (bigD1 1) //= defH; case/dprodP=> [[_ K _ ->] <- cHK _]. by rewrite mul_subG // cents_norm // (subset_trans cHK) ?centS. have defG: <<\bigcup_(f in Aut G) f @: H>> = G. have sXG: \bigcup_(f in Aut G) f @: H \subset G. by apply/bigcupsP=> f Af; rewrite -(im_autm Af) morphimEdom imsetS. apply: simG. apply: contra ntH; rewrite -!subG1; apply: subset_trans. by rewrite sub_gen // (bigcup_max 1) ?group1 ?defH. rewrite /characteristic gen_subG sXG; apply/forall_inP=> f Af. rewrite -(autmE Af) -morphimEsub ?gen_subG ?morphim_gen // genS //. rewrite morphimEsub //= autmE. apply/subsetP=> _ /imsetP[_ /bigcupP[g Ag /imsetP[x Hx ->]] ->]. apply/bigcupP; exists (g * f); first exact: groupM. by apply/imsetP; exists x; rewrite // permM. have [f Af sfHM]: exists2 f, f \in Aut G & ~~ (f @: H \subset M). move: not_sGM; rewrite -{1}defG gen_subG; case/subsetPn=> x. by case/bigcupP=> f Af fHx Mx; exists f => //; apply/subsetPn; exists x. case If: (f \in I). by case/negP: sfHM; rewrite -(bigdprodWY defM) sub_gen // (bigcup_max f). case/idP: (If); rewrite -(maxI ([set f] :|: I)) ?subsetUr ?inE ?eqxx //. rewrite {maxI}/Iok subUset sub1set Af {}Aut_I; apply/existsP. have sfHG: autm Af @* H \subset G by rewrite -{4}(im_autm Af) morphimS. have{minH nHG} /mingroupP[/andP[ntfH nfHG] minfH]: minnormal (autm Af @* H) G. apply/mingroupP; rewrite andbC -{1}(im_autm Af) morphim_norms //=. rewrite -subG1 sub_morphim_pre // -kerE ker_autm subG1. split=> // N /andP[ntN nNG] sNfH. have sNG: N \subset G := subset_trans sNfH sfHG. apply/eqP; rewrite eqEsubset sNfH sub_morphim_pre //=. rewrite -(morphim_invmE (injm_autm Af)) [_ @* N]minH //=. rewrite -subG1 sub_morphim_pre /= ?im_autm // morphpre_invm morphim1 subG1. by rewrite ntN -{1}(im_invm (injm_autm Af)) /= {2}im_autm morphim_norms. by rewrite sub_morphim_pre /= ?im_autm // morphpre_invm. have{minfH sfHM} tifHM: autm Af @* H :&: M = 1. apply/eqP/idPn=> ntMfH; case/setIidPl: sfHM. rewrite -(autmE Af) -morphimEsub //. by apply: minfH; rewrite ?subsetIl // ntMfH normsI. have cfHM: M \subset 'C(autm Af @* H). rewrite centsC (sameP commG1P trivgP) -tifHM subsetI commg_subl commg_subr. by rewrite (subset_trans sMG) // (subset_trans sfHG). exists (autm Af @* H <*> M)%G; rewrite /normal /= join_subG sMG sfHG normsY //=. rewrite (bigD1 f) ?inE ?eqxx // (eq_bigl (mem I)) /= => [|g]; last first. by rewrite /= !inE andbC; case: eqP => // ->. by rewrite defM -(autmE Af) -morphimEsub // dprodE // cent_joinEr ?eqxx. Qed. Lemma simple_sol_prime G : solvable G -> simple G -> prime #|G|. Proof. move=> solG /simpleP[ntG simG]. have{solG} cGG: abelian G. apply/commG1P; case/simG: (der_normal 1 G) => // /eqP/idPn[]. by rewrite proper_neq // (sol_der1_proper solG). case: (trivgVpdiv G) ntG => [-> | [p p_pr]]; first by rewrite eqxx. case/Cauchy=> // x Gx oxp _; move: p_pr; rewrite -oxp orderE. have: <[x]> <| G by rewrite -sub_abelian_normal ?cycle_subG. by case/simG=> -> //; rewrite cards1. Qed. Lemma charsimple_solvable G : charsimple G -> solvable G -> is_abelem G. Proof. case/charsimple_dprod=> H [sHG simH [I Aut_I defG]] solG. have p_pr: prime #|H| by exact: simple_sol_prime (solvableS sHG solG) simH. set p := #|H| in p_pr; apply/is_abelemP; exists p => //. elim/big_rec: _ (G) defG => [_ <-|f B If IH_B M defM]; first exact: abelem1. have [Af [[_ K _ defB] _ _ _]] := (subsetP Aut_I f If, dprodP defM). rewrite (dprod_abelem p defM) defB IH_B // andbT -(autmE Af) -morphimEsub //=. rewrite morphim_abelem ?abelemE // exponent_dvdn. by rewrite cyclic_abelian ?prime_cyclic. Qed. Lemma minnormal_solvable L G H : minnormal H L -> H \subset G -> solvable G -> [/\ L \subset 'N(H), H :!=: 1 & is_abelem H]. Proof. move=> minH sHG solG; have /andP[ntH nHL] := mingroupp minH. split=> //; apply: (charsimple_solvable (minnormal_charsimple minH)). exact: solvableS solG. Qed. Lemma solvable_norm_abelem L G : solvable G -> G <| L -> G :!=: 1 -> exists H : {group gT}, [/\ H \subset G, H <| L, H :!=: 1 & is_abelem H]. Proof. move=> solG /andP[sGL nGL] ntG. have [H minH sHG]: {H : {group gT} | minnormal H L & H \subset G}. by apply: mingroup_exists; rewrite ntG. have [nHL ntH abH] := minnormal_solvable minH sHG solG. by exists H; split; rewrite // /normal (subset_trans sHG). Qed. Lemma trivg_Fitting G : solvable G -> ('F(G) == 1) = (G :==: 1). Proof. move=> solG; apply/idP/idP=> [F1|]; last first. by rewrite -!subG1; apply: subset_trans; exact: Fitting_sub. apply/idPn=> /(solvable_norm_abelem solG (normal_refl _))[M [_ nsMG ntM]]. case/is_abelemP=> p _ /and3P[pM _ _]; case/negP: ntM. by rewrite -subG1 -(eqP F1) Fitting_max ?(pgroup_nil pM). Qed. Lemma Fitting_pcore pi G : 'F('O_pi(G)) = 'O_pi('F(G)). Proof. apply/eqP; rewrite eqEsubset. rewrite (subset_trans _ (pcoreS _ (Fitting_sub _))); last first. rewrite subsetI Fitting_sub Fitting_max ?Fitting_nil //. by rewrite (char_normal_trans (Fitting_char _)) ?pcore_normal. rewrite (subset_trans _ (FittingS (pcore_sub _ _))) // subsetI pcore_sub. rewrite pcore_max ?pcore_pgroup //. by rewrite (char_normal_trans (pcore_char _ _)) ?Fitting_normal. Qed. End CharSimple. Section SolvablePrimeFactor. Variables (gT : finGroupType) (G : {group gT}). Lemma index_maxnormal_sol_prime (H : {group gT}) : solvable G -> maxnormal H G G -> prime #|G : H|. Proof. move=> solG maxH; have nsHG := maxnormal_normal maxH. rewrite -card_quotient ?normal_norm // simple_sol_prime ?quotient_sol //. by rewrite quotient_simple. Qed. Lemma sol_prime_factor_exists : solvable G -> G :!=: 1 -> {H : {group gT} | H <| G & prime #|G : H| }. Proof. move=> solG /ex_maxnormal_ntrivg[H maxH]. by exists H; [exact: maxnormal_normal | exact: index_maxnormal_sol_prime]. Qed. End SolvablePrimeFactor. Section Special. Variables (gT : finGroupType) (p : nat) (A G : {group gT}). (* This is Aschbacher (23.7) *) Lemma center_special_abelem : p.-group G -> special G -> p.-abelem 'Z(G). Proof. move=> pG [defPhi defG']. have [-> | ntG] := eqsVneq G 1; first by rewrite center1 abelem1. have [p_pr _ _] := pgroup_pdiv pG ntG. have fM: {in 'Z(G) &, {morph expgn^~ p : x y / x * y}}. by move=> x y /setIP[_ /centP cxG] /setIP[/cxG cxy _]; exact: expgMn. rewrite abelemE //= center_abelian; apply/exponentP=> /= z Zz. apply: (@kerP _ _ _ (Morphism fM)) => //; apply: subsetP z Zz. rewrite -{1}defG' gen_subG; apply/subsetP=> _ /imset2P[x y Gx Gy ->]. have Zxy: [~ x, y] \in 'Z(G) by rewrite -defG' mem_commg. have Zxp: x ^+ p \in 'Z(G). rewrite -defPhi (Phi_joing pG) (MhoE 1 pG) joing_idr mem_gen // !inE. by rewrite expn1 orbC (mem_imset (expgn^~ p)). rewrite mem_morphpre /= ?defG' ?Zxy // inE -commXg; last first. by red; case/setIP: Zxy => _ /centP->. by apply/commgP; red; case/setIP: Zxp => _ /centP->. Qed. Lemma exponent_special : p.-group G -> special G -> exponent G %| p ^ 2. Proof. move=> pG spG; have [defPhi _] := spG. have /and3P[_ _ expZ] := center_special_abelem pG spG. apply/exponentP=> x Gx; rewrite expgM (exponentP expZ) // -defPhi. by rewrite (Phi_joing pG) mem_gen // inE orbC (Mho_p_elt 1) ?(mem_p_elt pG). Qed. (* Aschbacher 24.7 (replaces Gorenstein 5.3.7) *) Theorem abelian_charsimple_special : p.-group G -> coprime #|G| #|A| -> [~: G, A] = G -> \bigcup_(H : {group gT} | (H \char G) && abelian H) H \subset 'C(A) -> special G /\ 'C_G(A) = 'Z(G). Proof. move=> pG coGA defG /bigcupsP cChaA. have cZA: 'Z(G) \subset 'C_G(A). by rewrite subsetI center_sub cChaA // center_char center_abelian. have cChaG (H : {group gT}): H \char G -> abelian H -> H \subset 'Z(G). move=> chH abH; rewrite subsetI char_sub //= centsC -defG. rewrite comm_norm_cent_cent ?(char_norm chH) -?commg_subl ?defG //. by rewrite centsC cChaA ?chH. have cZ2GG: [~: 'Z_2(G), G, G] = 1. by apply/commG1P; rewrite (subset_trans (ucn_comm 1 G)) // ucn1 subsetIr. have{cZ2GG} cG'Z: 'Z_2(G) \subset 'C(G^`(1)). by rewrite centsC; apply/commG1P; rewrite three_subgroup // (commGC G). have{cG'Z} sZ2G'_Z: 'Z_2(G) :&: G^`(1) \subset 'Z(G). apply: cChaG; first by rewrite charI ?ucn_char ?der_char. by rewrite /abelian subIset // (subset_trans cG'Z) // centS ?subsetIr. have{sZ2G'_Z} sG'Z: G^`(1) \subset 'Z(G). rewrite der1_min ?gFnorm //; apply/derG1P. have /TI_center_nil: nilpotent (G / 'Z(G)) := quotient_nil _ (pgroup_nil pG). apply; first exact: gFnormal; rewrite /= setIC -ucn1 -ucn_central. rewrite -quotient_der ?gFnorm // -quotientGI ?ucn_subS ?quotientS1 //=. by rewrite ucn1. have sCG': 'C_G(A) \subset G^`(1). rewrite -quotient_sub1 //; last by rewrite subIset // char_norm ?der_char. rewrite (subset_trans (quotient_subcent _ G A)) //= -[G in G / _]defG. have nGA: A \subset 'N(G) by rewrite -commg_subl defG. rewrite quotientR ?(char_norm_trans (der_char _ _)) ?normG //. rewrite coprime_abel_cent_TI ?quotient_norms ?coprime_morph //. exact: sub_der1_abelian. have defZ: 'Z(G) = G^`(1) by apply/eqP; rewrite eqEsubset (subset_trans cZA). split; last by apply/eqP; rewrite eqEsubset cZA defZ sCG'. split=> //; apply/eqP; rewrite eqEsubset defZ (Phi_joing pG) joing_subl. have:= pG; rewrite -pnat_exponent => /p_natP[n expGpn]. rewrite join_subG subxx andbT /= -defZ -(subnn n.-1). elim: {2}n.-1 => [|m IHm]. rewrite (MhoE _ pG) gen_subG; apply/subsetP=> _ /imsetP[x Gx ->]. rewrite subn0 -subn1 -add1n -maxnE maxnC maxnE expnD. by rewrite expgM -expGpn expg_exponent ?groupX ?group1. rewrite cChaG ?Mho_char //= (MhoE _ pG) /abelian cent_gen gen_subG. apply/centsP=> _ /imsetP[x Gx ->] _ /imsetP[y Gy ->]. move: sG'Z; rewrite subsetI centsC => /andP[_ /centsP cGG']. apply/commgP; rewrite {1}expnSr expgM. rewrite commXg -?commgX; try by apply: cGG'; rewrite ?mem_commg ?groupX. apply/commgP; rewrite subsetI Mho_sub centsC in IHm. apply: (centsP IHm); first by rewrite groupX. rewrite -add1n -(addn1 m) subnDA -maxnE maxnC maxnE. rewrite -expgM -expnSr -addSn expnD expgM groupX //=. by rewrite Mho_p_elt ?(mem_p_elt pG). Qed. End Special. Section Extraspecial. Variables (p : nat) (gT rT : finGroupType). Implicit Types D E F G H K M R S T U : {group gT}. Section Basic. Variable S : {group gT}. Hypotheses (pS : p.-group S) (esS : extraspecial S). Let pZ : p.-group 'Z(S) := pgroupS (center_sub S) pS. Lemma extraspecial_prime : prime p. Proof. by case: esS => _ /prime_gt1; rewrite cardG_gt1; case/(pgroup_pdiv pZ). Qed. Lemma card_center_extraspecial : #|'Z(S)| = p. Proof. by apply/eqP; apply: (pgroupP pZ); case: esS. Qed. Lemma min_card_extraspecial : #|S| >= p ^ 3. Proof. have p_gt1 := prime_gt1 extraspecial_prime. rewrite leqNgt (card_pgroup pS) ltn_exp2l // ltnS. case: esS => [[_ defS']]; apply: contraL => /(p2group_abelian pS)/derG1P S'1. by rewrite -defS' S'1 cards1. Qed. End Basic. Lemma card_p3group_extraspecial E : prime p -> #|E| = (p ^ 3)%N -> #|'Z(E)| = p -> extraspecial E. Proof. move=> p_pr oEp3 oZp; have p_gt0 := prime_gt0 p_pr. have pE: p.-group E by rewrite /pgroup oEp3 pnat_exp pnat_id. have pEq: p.-group (E / 'Z(E))%g by rewrite quotient_pgroup. have /andP[sZE nZE] := center_normal E. have oEq: #|E / 'Z(E)|%g = (p ^ 2)%N. by rewrite card_quotient -?divgS // oEp3 oZp expnS mulKn. have cEEq: abelian (E / 'Z(E))%g by exact: card_p2group_abelian oEq. have not_cEE: ~~ abelian E. have: #|'Z(E)| < #|E| by rewrite oEp3 oZp (ltn_exp2l 1) ?prime_gt1. by apply: contraL => cEE; rewrite -leqNgt subset_leq_card // subsetI subxx. have defE': E^`(1) = 'Z(E). apply/eqP; rewrite eqEsubset der1_min //=; apply: contraR not_cEE => not_sE'Z. apply/commG1P/(TI_center_nil (pgroup_nil pE) (der_normal 1 _)). by rewrite setIC prime_TIg ?oZp. split; [split=> // | by rewrite oZp]; apply/eqP. rewrite eqEsubset andbC -{1}defE' {1}(Phi_joing pE) joing_subl. rewrite -quotient_sub1 ?(subset_trans (Phi_sub _)) //. rewrite subG1 /= (quotient_Phi pE) //= (trivg_Phi pEq); apply/abelemP=> //. split=> // Zx EqZx; apply/eqP; rewrite -order_dvdn /order. rewrite (card_pgroup (mem_p_elt pEq EqZx)) (@dvdn_exp2l _ _ 1) //. rewrite leqNgt -pfactor_dvdn // -oEq; apply: contra not_cEE => sEqZx. rewrite cyclic_center_factor_abelian //; apply/cyclicP. exists Zx; apply/eqP; rewrite eq_sym eqEcard cycle_subG EqZx -orderE. exact: dvdn_leq sEqZx. Qed. Lemma p3group_extraspecial G : p.-group G -> ~~ abelian G -> logn p #|G| <= 3 -> extraspecial G. Proof. move=> pG not_cGG; have /andP[sZG nZG] := center_normal G. have ntG: G :!=: 1 by apply: contraNneq not_cGG => ->; exact: abelian1. have ntZ: 'Z(G) != 1 by rewrite (center_nil_eq1 (pgroup_nil pG)). have [p_pr _ [n oG]] := pgroup_pdiv pG ntG; rewrite oG pfactorK //. have [_ _ [m oZ]] := pgroup_pdiv (pgroupS sZG pG) ntZ. have lt_m1_n: m.+1 < n. suffices: 1 < logn p #|(G / 'Z(G))|. rewrite card_quotient // -divgS // logn_div ?cardSg //. by rewrite oG oZ !pfactorK // ltn_subRL addn1. rewrite ltnNge; apply: contra not_cGG => cycGs. apply: cyclic_center_factor_abelian; rewrite (dvdn_prime_cyclic p_pr) //. by rewrite (card_pgroup (quotient_pgroup _ pG)) (dvdn_exp2l _ cycGs). rewrite -{lt_m1_n}(subnKC lt_m1_n) !addSn !ltnS leqn0 in oG *. case: m => // in oZ oG * => /eqP n2; rewrite {n}n2 in oG. exact: card_p3group_extraspecial oZ. Qed. Lemma extraspecial_nonabelian G : extraspecial G -> ~~ abelian G. Proof. case=> [[_ defG'] oZ]; rewrite /abelian (sameP commG1P eqP). by rewrite -derg1 defG' -cardG_gt1 prime_gt1. Qed. Lemma exponent_2extraspecial G : 2.-group G -> extraspecial G -> exponent G = 4. Proof. move=> p2G esG; have [spG _] := esG. case/dvdn_pfactor: (exponent_special p2G spG) => // k. rewrite leq_eqVlt ltnS => /predU1P[-> // | lek1] expG. case/negP: (extraspecial_nonabelian esG). by rewrite (@abelem_abelian _ 2) ?exponent2_abelem // expG pfactor_dvdn. Qed. Lemma injm_special D G (f : {morphism D >-> rT}) : 'injm f -> G \subset D -> special G -> special (f @* G). Proof. move=> injf sGD [defPhiG defG']. by rewrite /special -morphim_der // -injm_Phi // defPhiG defG' injm_center. Qed. Lemma injm_extraspecial D G (f : {morphism D >-> rT}) : 'injm f -> G \subset D -> extraspecial G -> extraspecial (f @* G). Proof. move=> injf sGD [spG ZG_pr]; split; first exact: injm_special spG. by rewrite -injm_center // card_injm // subIset ?sGD. Qed. Lemma isog_special G (R : {group rT}) : G \isog R -> special G -> special R. Proof. by case/isogP=> f injf <-; exact: injm_special. Qed. Lemma isog_extraspecial G (R : {group rT}) : G \isog R -> extraspecial G -> extraspecial R. Proof. by case/isogP=> f injf <-; exact: injm_extraspecial. Qed. Lemma cprod_extraspecial G H K : p.-group G -> H \* K = G -> H :&: K = 'Z(H) -> extraspecial H -> extraspecial K -> extraspecial G. Proof. move=> pG defG ziHK [[PhiH defH'] ZH_pr] [[PhiK defK'] ZK_pr]. have [_ defHK cHK]:= cprodP defG. have sZHK: 'Z(H) \subset 'Z(K). by rewrite subsetI -{1}ziHK subsetIr subIset // centsC cHK. have{sZHK} defZH: 'Z(H) = 'Z(K). by apply/eqP; rewrite eqEcard sZHK leq_eqVlt eq_sym -dvdn_prime2 ?cardSg. have defZ: 'Z(G) = 'Z(K). by case/cprodP: (center_cprod defG) => /= _ <- _; rewrite defZH mulGid. split; first split; rewrite defZ //. by have /cprodP[_ <- _] := Phi_cprod pG defG; rewrite PhiH PhiK defZH mulGid. by have /cprodP[_ <- _] := der_cprod 1 defG; rewrite defH' defK' defZH mulGid. Qed. (* Lemmas bundling Aschbacher (23.10) with (19.1), (19.2), (19.12) and (20.8) *) Section ExtraspecialFormspace. Variable G : {group gT}. Hypotheses (pG : p.-group G) (esG : extraspecial G). Let p_pr := extraspecial_prime pG esG. Let oZ := card_center_extraspecial pG esG. Let p_gt1 := prime_gt1 p_pr. Let p_gt0 := prime_gt0 p_pr. (* This encasulates Aschbacher (23.10)(1). *) Lemma cent1_extraspecial_maximal x : x \in G -> x \notin 'Z(G) -> maximal 'C_G[x] G. Proof. move=> Gx notZx; pose f y := [~ x, y]; have [[_ defG'] prZ] := esG. have{defG'} fZ y: y \in G -> f y \in 'Z(G). by move=> Gy; rewrite -defG' mem_commg. have fM: {in G &, {morph f : y z / y * z}}%g. move=> y z Gy Gz; rewrite {1}/f commgMJ conjgCV -conjgM (conjg_fixP _) //. rewrite (sameP commgP cent1P); apply: subsetP (fZ y Gy). by rewrite subIset // orbC -cent_set1 centS // sub1set !(groupM, groupV). pose fm := Morphism fM. have fmG: fm @* G = 'Z(G). have sfmG: fm @* G \subset 'Z(G). by apply/subsetP=> _ /morphimP[z _ Gz ->]; exact: fZ. apply/eqP; rewrite eqEsubset sfmG; apply: contraR notZx => /(prime_TIg prZ). rewrite (setIidPr _) // => fmG1; rewrite inE Gx; apply/centP=> y Gy. by apply/commgP; rewrite -in_set1 -[[set _]]fmG1; exact: mem_morphim. have ->: 'C_G[x] = 'ker fm. apply/setP=> z; rewrite inE (sameP cent1P commgP) !inE. by rewrite -invg_comm eq_invg_mul mulg1. rewrite p_index_maximal ?subsetIl // -card_quotient ?ker_norm //. by rewrite (card_isog (first_isog fm)) /= fmG. Qed. (* This is the tranposition of the hyperplane dimension theorem (Aschbacher *) (* (19.1)) to subgroups of an extraspecial group. *) Lemma subcent1_extraspecial_maximal U x : U \subset G -> x \in G :\: 'C(U) -> maximal 'C_U[x] U. Proof. move=> sUG /setDP[Gx not_cUx]; apply/maxgroupP; split=> [|H ltHU sCxH]. by rewrite /proper subsetIl subsetI subxx sub_cent1. case/andP: ltHU => sHU not_sHU; have sHG := subset_trans sHU sUG. apply/eqP; rewrite eqEsubset sCxH subsetI sHU /= andbT. apply: contraR not_sHU => not_sHCx. have maxCx: maximal 'C_G[x] G. rewrite cent1_extraspecial_maximal //; apply: contra not_cUx. by rewrite inE Gx; exact: subsetP (centS sUG) _. have nsCx := p_maximal_normal pG maxCx. rewrite -(setIidPl sUG) -(mulg_normal_maximal nsCx maxCx sHG) ?subsetI ?sHG //. by rewrite -group_modr //= setIA (setIidPl sUG) mul_subG. Qed. (* This is the tranposition of the orthogonal subspace dimension theorem *) (* (Aschbacher (19.2)) to subgroups of an extraspecial group. *) Lemma card_subcent_extraspecial U : U \subset G -> #|'C_G(U)| = (#|'Z(G) :&: U| * #|G : U|)%N. Proof. move=> sUG; rewrite setIAC (setIidPr sUG). elim: {U}_.+1 {-2}U (ltnSn #|U|) sUG => // m IHm U leUm sUG. have [cUG | not_cUG]:= orP (orbN (G \subset 'C(U))). by rewrite !(setIidPl _) ?Lagrange // centsC. have{not_cUG} [x Gx not_cUx] := subsetPn not_cUG. pose W := 'C_U[x]; have sCW_G: 'C_G(W) \subset G := subsetIl G _. have maxW: maximal W U by rewrite subcent1_extraspecial_maximal // inE not_cUx. have nsWU: W <| U := p_maximal_normal (pgroupS sUG pG) maxW. have ltWU: W \proper U by exact: maxgroupp maxW. have [sWU [u Uu notWu]] := properP ltWU; have sWG := subset_trans sWU sUG. have defU: W * <[u]> = U by rewrite (mulg_normal_maximal nsWU) ?cycle_subG. have iCW_CU: #|'C_G(W) : 'C_G(U)| = p. rewrite -defU centM cent_cycle setIA /=; rewrite inE Uu cent1C in notWu. apply: p_maximal_index (pgroupS sCW_G pG) _. apply: subcent1_extraspecial_maximal sCW_G _. rewrite inE andbC (subsetP sUG) //= -sub_cent1. by apply/subsetPn; exists x; rewrite // inE Gx -sub_cent1 subsetIr. apply/eqP; rewrite -(eqn_pmul2r p_gt0) -{1}iCW_CU Lagrange ?setIS ?centS //. rewrite IHm ?(leq_trans (proper_card ltWU)) // -setIA -mulnA. rewrite -(Lagrange_index sUG sWU) (p_maximal_index (pgroupS sUG pG)) //=. by rewrite -cent_set1 (setIidPr (centS _)) ?sub1set. Qed. (* This is the tranposition of the proof that a singular vector is contained *) (* in a hyperbolic plane (Aschbacher (19.12)) to subgroups of an extraspecial *) (* group. *) Lemma split1_extraspecial x : x \in G :\: 'Z(G) -> {E : {group gT} & {R : {group gT} | [/\ #|E| = (p ^ 3)%N /\ #|R| = #|G| %/ p ^ 2, E \* R = G /\ E :&: R = 'Z(E), 'Z(E) = 'Z(G) /\ 'Z(R) = 'Z(G), extraspecial E /\ x \in E & if abelian R then R :=: 'Z(G) else extraspecial R]}}. Proof. case/setDP=> Gx notZx; rewrite inE Gx /= in notZx. have [[defPhiG defG'] prZ] := esG. have maxCx: maximal 'C_G[x] G. by rewrite subcent1_extraspecial_maximal // inE notZx. pose y := repr (G :\: 'C[x]). have [Gy not_cxy]: y \in G /\ y \notin 'C[x]. move/maxgroupp: maxCx => /properP[_ [t Gt not_cyt]]. by apply/setDP; apply: (mem_repr t); rewrite !inE Gt andbT in not_cyt *. pose E := <[x]> <*> <[y]>; pose R := 'C_G(E). exists [group of E]; exists [group of R] => /=. have sEG: E \subset G by rewrite join_subG !cycle_subG Gx. have [Ex Ey]: x \in E /\ y \in E by rewrite !mem_gen // inE cycle_id ?orbT. have sZE: 'Z(G) \subset E. rewrite (('Z(G) =P E^`(1)) _) ?der_sub // eqEsubset -{2}defG' dergS // andbT. apply: contraR not_cxy => /= not_sZE'. rewrite (sameP cent1P commgP) -in_set1 -[[set 1]](prime_TIg prZ not_sZE'). by rewrite /= -defG' inE !mem_commg. have ziER: E :&: R = 'Z(E) by rewrite setIA (setIidPl sEG). have cER: R \subset 'C(E) by rewrite subsetIr. have iCxG: #|G : 'C_G[x]| = p by exact: p_maximal_index. have maxR: maximal R 'C_G[x]. rewrite /R centY !cent_cycle setIA. rewrite subcent1_extraspecial_maximal ?subsetIl // inE Gy andbT -sub_cent1. by apply/subsetPn; exists x; rewrite 1?cent1C // inE Gx cent1id. have sRCx: R \subset 'C_G[x] by rewrite -cent_cycle setIS ?centS ?joing_subl. have sCxG: 'C_G[x] \subset G by rewrite subsetIl. have sRG: R \subset G by rewrite subsetIl. have iRCx: #|'C_G[x] : R| = p by rewrite (p_maximal_index (pgroupS sCxG pG)). have defG: E * R = G. rewrite -cent_joinEr //= -/R joingC joingA. have cGx_x: <[x]> \subset 'C_G[x] by rewrite cycle_subG inE Gx cent1id. have nsRcx := p_maximal_normal (pgroupS sCxG pG) maxR. rewrite (norm_joinEr (subset_trans cGx_x (normal_norm nsRcx))). rewrite (mulg_normal_maximal nsRcx) //=; last first. by rewrite centY !cent_cycle cycle_subG !in_setI Gx cent1id cent1C. have nsCxG := p_maximal_normal pG maxCx. have syG: <[y]> \subset G by rewrite cycle_subG. rewrite (norm_joinEr (subset_trans syG (normal_norm nsCxG))). by rewrite (mulg_normal_maximal nsCxG) //= cycle_subG inE Gy. have defZR: 'Z(R) = 'Z(G) by rewrite -['Z(R)]setIA -centM defG. have defZE: 'Z(E) = 'Z(G). by rewrite -defG -center_prod ?mulGSid //= -ziER subsetI center_sub defZR sZE. have [n oG] := p_natP pG. have n_gt1: n > 1. by rewrite ltnW // -(@leq_exp2l p) // -oG min_card_extraspecial. have oR: #|R| = (p ^ n.-2)%N. apply/eqP; rewrite -(divg_indexS sRCx) iRCx /= -(divg_indexS sCxG) iCxG /= oG. by rewrite -{1}(subnKC n_gt1) subn2 !expnS !mulKn. have oE: #|E| = (p ^ 3)%N. apply/eqP; rewrite -(@eqn_pmul2r #|R|) ?cardG_gt0 // mul_cardG defG ziER. by rewrite defZE oZ oG -{1}(subnKC n_gt1) oR -expnSr -expnD subn2. rewrite cprodE // oR oG -expnB ?subn2 //; split=> //. by split=> //; apply: card_p3group_extraspecial _ oE _; rewrite // defZE. case: ifP => [cRR | not_cRR]; first by rewrite -defZR (center_idP _). split; rewrite /special defZR //. have ntR': R^`(1) != 1 by rewrite (sameP eqP commG1P) -abelianE not_cRR. have pR: p.-group R := pgroupS sRG pG. have pR': p.-group R^`(1) := pgroupS (der_sub 1 _) pR. have defR': R^`(1) = 'Z(G). apply/eqP; rewrite eqEcard -{1}defG' dergS //= oZ. by have [_ _ [k ->]]:= pgroup_pdiv pR' ntR'; rewrite (leq_exp2l 1). split=> //; apply/eqP; rewrite eqEsubset -{1}defPhiG -defR' (PhiS pG) //=. by rewrite (Phi_joing pR) joing_subl. Qed. (* This is the tranposition of the proof that the dimension of any maximal *) (* totally singular subspace is equal to the Witt index (Aschbacher (20.8)), *) (* to subgroups of an extraspecial group (in a slightly more general form, *) (* since we allow for p != 2). *) (* Note that Aschbacher derives this from the Witt lemma, which we avoid. *) Lemma pmaxElem_extraspecial : 'E*_p(G) = 'E_p^('r_p(G))(G). Proof. have sZmax: {in 'E*_p(G), forall E, 'Z(G) \subset E}. move=> E maxE; have defE := pmaxElem_LdivP p_pr maxE. have abelZ: p.-abelem 'Z(G) by rewrite prime_abelem ?oZ. rewrite -(Ohm1_id abelZ) (OhmE 1 (abelem_pgroup abelZ)) gen_subG -defE. by rewrite setSI // setIS ?centS // -defE !subIset ?subxx. suffices card_max: {in 'E*_p(G) &, forall E F, #|E| <= #|F| }. have EprGmax: 'E_p^('r_p(G))(G) \subset 'E*_p(G) := p_rankElem_max p G. have [E EprE]:= p_rank_witness p G; have maxE := subsetP EprGmax E EprE. apply/eqP; rewrite eqEsubset EprGmax andbT; apply/subsetP=> F maxF. rewrite inE; have [-> _]:= pmaxElemP maxF; have [_ _ <-]:= pnElemP EprE. by apply/eqP; congr (logn p _); apply/eqP; rewrite eqn_leq !card_max. move=> E F maxE maxF; set U := E :&: F. have [sUE sUF]: U \subset E /\ U \subset F by apply/andP; rewrite -subsetI. have sZU: 'Z(G) \subset U by rewrite subsetI !sZmax. have [EpE _]:= pmaxElemP maxE; have{EpE} [sEG abelE] := pElemP EpE. have [EpF _]:= pmaxElemP maxF; have{EpF} [sFG abelF] := pElemP EpF. have [V] := abelem_split_dprod abelE sUE; case/dprodP=> _ defE cUV tiUV. have [W] := abelem_split_dprod abelF sUF; case/dprodP=> _ defF _ tiUW. have [sVE sWF]: V \subset E /\ W \subset F by rewrite -defE -defF !mulG_subr. have [sVG sWG] := (subset_trans sVE sEG, subset_trans sWF sFG). rewrite -defE -defF !TI_cardMg // leq_pmul2l ?cardG_gt0 //. rewrite -(leq_pmul2r (cardG_gt0 'C_G(W))) mul_cardG. rewrite card_subcent_extraspecial // mulnCA Lagrange // mulnC. rewrite leq_mul ?subset_leq_card //; last by rewrite mul_subG ?subsetIl. apply: subset_trans (sub1G _); rewrite -tiUV !subsetI subsetIl subIset ?sVE //=. rewrite -(pmaxElem_LdivP p_pr maxF) -defF centM -!setIA -(setICA 'C(W)). rewrite setIC setIA setIS // subsetI cUV sub_LdivT. by case/and3P: (abelemS sVE abelE). Qed. End ExtraspecialFormspace. (* This is B & G, Theorem 4.15, as done in Aschbacher (23.8) *) Lemma critical_extraspecial R S : p.-group R -> S \subset R -> extraspecial S -> [~: S, R] \subset S^`(1) -> S \* 'C_R(S) = R. Proof. move=> pR sSR esS sSR_S'; have [[defPhi defS'] _] := esS. have [pS [sPS nPS]] := (pgroupS sSR pR, andP (Phi_normal S : 'Phi(S) <| S)). have{esS} oZS: #|'Z(S)| = p := card_center_extraspecial pS esS. have nSR: R \subset 'N(S) by rewrite -commg_subl (subset_trans sSR_S') ?der_sub. have nsCR: 'C_R(S) <| R by rewrite (normalGI nSR) ?cent_normal. have nCS: S \subset 'N('C_R(S)) by rewrite cents_norm // centsC subsetIr. rewrite cprodE ?subsetIr //= -{2}(quotientGK nsCR) normC -?quotientK //. congr (_ @*^-1 _); apply/eqP; rewrite eqEcard quotientS //=. rewrite -(card_isog (second_isog nCS)) setIAC (setIidPr sSR) /= -/'Z(S) -defPhi. rewrite -ker_conj_aut (card_isog (first_isog_loc _ nSR)) //=; set A := _ @* R. have{pS} abelSb := Phi_quotient_abelem pS; have [pSb cSSb _] := and3P abelSb. have [/= Xb defSb oXb] := grank_witness (S / 'Phi(S)). pose X := (repr \o val : coset_of _ -> gT) @: Xb. have sXS: X \subset S; last have nPX := subset_trans sXS nPS. apply/subsetP=> x; case/imsetP=> xb Xxb ->; have nPx := repr_coset_norm xb. rewrite -sub1set -(quotientSGK _ sPS) ?sub1set ?quotient_set1 //= sub1set. by rewrite coset_reprK -defSb mem_gen. have defS: <> = S. apply: Phi_nongen; apply/eqP; rewrite eqEsubset join_subG sPS sXS -joing_idr. rewrite -genM_join sub_gen // -quotientSK ?quotient_gen // -defSb genS //. apply/subsetP=> xb Xxb; apply/imsetP; rewrite (setIidPr nPX). by exists (repr xb); rewrite /= ?coset_reprK //; exact: mem_imset. pose f (a : {perm gT}) := [ffun x => if x \in X then x^-1 * a x else 1]. have injf: {in A &, injective f}. move=> _ _ /morphimP[y nSy Ry ->] /morphimP[z nSz Rz ->]. move/ffunP=> eq_fyz; apply: (@eq_Aut _ S); rewrite ?Aut_aut //= => x Sx. rewrite !norm_conj_autE //; apply: canRL (conjgKV z) _; rewrite -conjgM. rewrite /conjg -(centP _ x Sx) ?mulKg {x Sx}// -defS cent_gen -sub_cent1. apply/subsetP=> x Xx; have Sx := subsetP sXS x Xx. move/(_ x): eq_fyz; rewrite !ffunE Xx !norm_conj_autE // => /mulgI xy_xz. by rewrite cent1C inE conjg_set1 conjgM xy_xz conjgK. have sfA_XS': f @: A \subset pffun_on 1 X S^`(1). apply/subsetP=> _ /imsetP[_ /morphimP[y nSy Ry ->] ->]. apply/pffun_onP; split=> [|_ /imageP[x /= Xx ->]]. by apply/subsetP=> x; apply: contraR; rewrite ffunE => /negPf->. have Sx := subsetP sXS x Xx. by rewrite ffunE Xx norm_conj_autE // (subsetP sSR_S') ?mem_commg. rewrite -(card_in_imset injf) (leq_trans (subset_leq_card sfA_XS')) // defS'. rewrite card_pffun_on (card_pgroup pSb) -rank_abelem -?grank_abelian // -oXb. by rewrite -oZS ?leq_pexp2l ?cardG_gt0 ?leq_imset_card. Qed. (* This is part of Aschbacher (23.13) and (23.14). *) Theorem extraspecial_structure S : p.-group S -> extraspecial S -> {Es | all (fun E => (#|E| == p ^ 3)%N && ('Z(E) == 'Z(S))) Es & \big[cprod/1%g]_(E <- Es) E \* 'Z(S) = S}. Proof. elim: {S}_.+1 {-2}S (ltnSn #|S|) => // m IHm S leSm pS esS. have [x Z'x]: {x | x \in S :\: 'Z(S)}. apply/sigW/set0Pn; rewrite -subset0 subDset setU0. apply: contra (extraspecial_nonabelian esS) => sSZ. exact: abelianS sSZ (center_abelian S). have [E [R [[oE oR]]]]:= split1_extraspecial pS esS Z'x. case=> defS _ [defZE defZR] _; case: ifP => [_ defR | _ esR]. by exists [:: E]; rewrite /= ?oE ?defZE ?eqxx // big_seq1 -defR. have sRS: R \subset S by case/cprodP: defS => _ <- _; rewrite mulG_subr. have [|Es esEs defR] := IHm _ _ (pgroupS sRS pS) esR. rewrite oR (leq_trans (ltn_Pdiv _ _)) ?cardG_gt0 // (ltn_exp2l 0) //. exact: prime_gt1 (extraspecial_prime pS esS). exists (E :: Es); first by rewrite /= oE defZE !eqxx -defZR. by rewrite -defZR big_cons -cprodA defR. Qed. Section StructureCorollaries. Variable S : {group gT}. Hypotheses (pS : p.-group S) (esS : extraspecial S). Let p_pr := extraspecial_prime pS esS. Let oZ := card_center_extraspecial pS esS. (* This is Aschbacher (23.10)(2). *) Lemma card_extraspecial : {n | n > 0 & #|S| = (p ^ n.*2.+1)%N}. Proof. exists (logn p #|S|)./2. rewrite half_gt0 ltnW // -(leq_exp2l _ _ (prime_gt1 p_pr)) -card_pgroup //. exact: min_card_extraspecial. have [Es] := extraspecial_structure pS esS. elim: Es {3 4 5}S => [_ _ <-| E s IHs T] /=. by rewrite big_nil cprod1g oZ (pfactorK 1). rewrite -andbA big_cons -cprodA; case/and3P; move/eqP=> oEp3; move/eqP=> defZE. move/IHs=> {IHs}IHs; case/cprodP=> [[_ U _ defU]]; rewrite defU => defT cEU. rewrite -(mulnK #|T| (cardG_gt0 (E :&: U))) -defT -mul_cardG /=. have ->: E :&: U = 'Z(S). apply/eqP; rewrite eqEsubset subsetI -{1 2}defZE subsetIl setIS //=. by case/cprodP: defU => [[V _ -> _]] <- _; exact: mulG_subr. rewrite (IHs U) // oEp3 oZ -expnD addSn expnS mulKn ?prime_gt0 //. by rewrite pfactorK //= uphalf_double. Qed. Lemma Aut_extraspecial_full : Aut_in (Aut S) 'Z(S) \isog Aut 'Z(S). Proof. have [p_gt1 p_gt0] := (prime_gt1 p_pr, prime_gt0 p_pr). have [Es] := extraspecial_structure pS esS. elim: Es S oZ => [T _ _ <-| E s IHs T oZT] /=. rewrite big_nil cprod1g (center_idP (center_abelian T)). by apply/Aut_sub_fullP=> // g injg gZ; exists g. rewrite -andbA big_cons -cprodA; case/and3P; move/eqP=> oE; move/eqP=> defZE. move=> es_s; case/cprodP=> [[_ U _ defU]]; rewrite defU => defT cEU. have sUT: U \subset T by rewrite -defT mulG_subr. have sZU: 'Z(T) \subset U. by case/cprodP: defU => [[V _ -> _] <- _]; exact: mulG_subr. have defZU: 'Z(E) = 'Z(U). apply/eqP; rewrite eqEsubset defZE subsetI sZU subIset ?centS ?orbT //=. by rewrite subsetI subIset ?sUT //= -defT centM setSI. apply: (Aut_cprod_full _ defZU); rewrite ?cprodE //; last first. by apply: IHs; rewrite -?defZU ?defZE. have oZE: #|'Z(E)| = p by rewrite defZE. have [p2 | odd_p] := even_prime p_pr. suffices <-: restr_perm 'Z(E) @* Aut E = Aut 'Z(E) by exact: Aut_in_isog. apply/eqP; rewrite eqEcard restr_perm_Aut ?center_sub //=. by rewrite card_Aut_cyclic ?prime_cyclic ?oZE // {1}p2 cardG_gt0. have pE: p.-group E by rewrite /pgroup oE pnat_exp pnat_id. have nZE: E \subset 'N('Z(E)) by rewrite normal_norm ?center_normal. have esE: extraspecial E := card_p3group_extraspecial p_pr oE oZE. have [[defPhiE defE'] prZ] := esE. have{defPhiE} sEpZ x: x \in E -> (x ^+ p)%g \in 'Z(E). move=> Ex; rewrite -defPhiE (Phi_joing pE) mem_gen // inE orbC. by rewrite (Mho_p_elt 1) // (mem_p_elt pE). have ltZE: 'Z(E) \proper E by rewrite properEcard subsetIl oZE oE (ltn_exp2l 1). have [x [Ex notZx oxp]]: exists x, [/\ x \in E, x \notin 'Z(E) & #[x] %| p]%N. have [_ [x Ex notZx]] := properP ltZE. case: (prime_subgroupVti <[x ^+ p]> prZ) => [sZxp | ]; last first. move/eqP; rewrite (setIidPl _) ?cycle_subG ?sEpZ //. by rewrite cycle_eq1 -order_dvdn; exists x. have [y Ey notxy]: exists2 y, y \in E & y \notin <[x]>. apply/subsetPn; apply: contra (extraspecial_nonabelian esE) => sEx. by rewrite (abelianS sEx) ?cycle_abelian. have: (y ^+ p)%g \in <[x ^+ p]> by rewrite (subsetP sZxp) ?sEpZ. case/cycleP=> i def_yp; set xi := (x ^- i)%g. have Exi: xi \in E by rewrite groupV groupX. exists (y * xi)%g; split; first by rewrite groupM. have sxpx: <[x ^+ p]> \subset <[x]> by rewrite cycle_subG mem_cycle. apply: contra notxy; move/(subsetP (subset_trans sZxp sxpx)). by rewrite groupMr // groupV mem_cycle. pose z := [~ xi, y]; have Zz: z \in 'Z(E) by rewrite -defE' mem_commg. case: (setIP Zz) => _; move/centP=> cEz. rewrite order_dvdn expMg_Rmul; try by apply: commute_sym; apply: cEz. rewrite def_yp expgVn -!expgM mulnC mulgV mul1g -order_dvdn. by rewrite (dvdn_trans (order_dvdG Zz)) //= oZE bin2odd // dvdn_mulr. have{oxp} ox: #[x] = p. apply/eqP; case/primeP: p_pr => _ dvd_p; case/orP: (dvd_p _ oxp) => //. by rewrite order_eq1; case: eqP notZx => // ->; rewrite group1. have [y Ey not_cxy]: exists2 y, y \in E & y \notin 'C[x]. by apply/subsetPn; rewrite sub_cent1; rewrite inE Ex in notZx. have notZy: y \notin 'Z(E). apply: contra not_cxy; rewrite inE Ey; apply: subsetP. by rewrite -cent_set1 centS ?sub1set. pose K := 'C_E[y]; have maxK: maximal K E by exact: cent1_extraspecial_maximal. have nsKE: K <| E := p_maximal_normal pE maxK; have [sKE nKE] := andP nsKE. have oK: #|K| = (p ^ 2)%N. by rewrite -(divg_indexS sKE) oE (p_maximal_index pE) ?mulKn. have cKK: abelian K := card_p2group_abelian p_pr oK. have sZK: 'Z(E) \subset K by rewrite setIS // -cent_set1 centS ?sub1set. have defE: K ><| <[x]> = E. have notKx: x \notin K by rewrite inE Ex cent1C. rewrite sdprodE ?(mulg_normal_maximal nsKE) ?cycle_subG ?(subsetP nKE) //. by rewrite setIC prime_TIg -?orderE ?ox ?cycle_subG. have /cyclicP[z defZ]: cyclic 'Z(E) by rewrite prime_cyclic ?oZE. apply/(Aut_sub_fullP (center_sub E)); rewrite /= defZ => g injg gZ. pose k := invm (injm_Zp_unitm z) (aut injg gZ). have fM: {in K &, {morph expgn^~ (val k): u v / u * v}}. by move=> u v Ku Kv; rewrite /= expgMn // /commute (centsP cKK). pose f := Morphism fM; have fK: f @* K = K. apply/setP=> u; rewrite morphimEdom. apply/imsetP/idP=> [[v Kv ->] | Ku]; first exact: groupX. exists (u ^+ expg_invn K (val k)); first exact: groupX. rewrite /f /= expgAC expgK // oK coprime_expl // -unitZpE //. by case: (k) => /=; rewrite orderE -defZ oZE => j; rewrite natr_Zp. have fMact: {in K & <[x]>, morph_act 'J 'J f (idm <[x]>)}. by move=> u v _ _; rewrite /= conjXg. exists (sdprodm_morphism defE fMact). rewrite im_sdprodm injm_sdprodm injm_idm -card_im_injm im_idm fK. have [_ -> _ ->] := sdprodP defE; rewrite !eqxx; split=> //= u Zu. rewrite sdprodmEl ?(subsetP sZK) ?defZ // -(autE injg gZ Zu). rewrite -[aut _ _](invmK (injm_Zp_unitm z)); first by rewrite permE Zu. by rewrite im_Zp_unitm Aut_aut. Qed. (* These are the parts of Aschbacher (23.12) and exercise 8.5 that are later *) (* used in Aschbacher (34.9), which itself replaces the informal discussion *) (* quoted from Gorenstein in the proof of B & G, Theorem 2.5. *) Lemma center_aut_extraspecial k : coprime k p -> exists2 f, f \in Aut S & forall z, z \in 'Z(S) -> f z = (z ^+ k)%g. Proof. have /cyclicP[z defZ]: cyclic 'Z(S) by rewrite prime_cyclic ?oZ. have oz: #[z] = p by rewrite orderE -defZ. rewrite coprime_sym -unitZpE ?prime_gt1 // -oz => u_k. pose g := Zp_unitm (FinRing.unit 'Z_#[z] u_k). have AutZg: g \in Aut 'Z(S) by rewrite defZ -im_Zp_unitm mem_morphim ?inE. have ZSfull := Aut_sub_fullP (center_sub S) Aut_extraspecial_full. have [f [injf fS fZ]] := ZSfull _ (injm_autm AutZg) (im_autm AutZg). exists (aut injf fS) => [|u Zu]; first exact: Aut_aut. have [Su _] := setIP Zu; have z_u: u \in <[z]> by rewrite -defZ. by rewrite autE // fZ //= autmE permE /= z_u /cyclem expg_znat. Qed. End StructureCorollaries. End Extraspecial. Section SCN. Variables (gT : finGroupType) (p : nat) (G : {group gT}). Implicit Types A Z H : {group gT}. Lemma SCN_P A : reflect (A <| G /\ 'C_G(A) = A) (A \in 'SCN(G)). Proof. by apply: (iffP setIdP) => [] [->]; move/eqP. Qed. Lemma SCN_abelian A : A \in 'SCN(G) -> abelian A. Proof. by case/SCN_P=> _ defA; rewrite /abelian -{1}defA subsetIr. Qed. Lemma exponent_Ohm1_class2 H : odd p -> p.-group H -> nil_class H <= 2 -> exponent 'Ohm_1(H) %| p. Proof. move=> odd_p pH; rewrite nil_class2 => sH'Z; apply/exponentP=> x /=. rewrite (OhmE 1 pH) expn1 gen_set_id => {x} [/LdivP[] //|]. apply/group_setP; split=> [|x y]; first by rewrite !inE group1 expg1n //=. case/LdivP=> Hx xp1 /LdivP[Hy yp1]; rewrite !inE groupM //=. have [_ czH]: [~ y, x] \in H /\ centralises [~ y, x] H. by apply/centerP; rewrite (subsetP sH'Z) ?mem_commg. rewrite expMg_Rmul ?xp1 ?yp1 /commute ?czH //= !mul1g. by rewrite bin2odd // -commXXg ?yp1 /commute ?czH // comm1g. Qed. (* SCN_max and max_SCN cover Aschbacher 23.15(1) *) Lemma SCN_max A : A \in 'SCN(G) -> [max A | A <| G & abelian A]. Proof. case/SCN_P => nAG scA; apply/maxgroupP; split=> [|H]. by rewrite nAG /abelian -{1}scA subsetIr. do 2![case/andP]=> sHG _ abelH sAH; apply/eqP. by rewrite eqEsubset sAH -scA subsetI sHG centsC (subset_trans sAH). Qed. Lemma max_SCN A : p.-group G -> [max A | A <| G & abelian A] -> A \in 'SCN(G). Proof. move/pgroup_nil=> nilG; rewrite /abelian. case/maxgroupP=> /andP[nsAG abelA] maxA; have [sAG nAG] := andP nsAG. rewrite inE nsAG eqEsubset /= andbC subsetI abelA normal_sub //=. rewrite -quotient_sub1; last by rewrite subIset 1?normal_norm. apply/trivgP; apply: (TI_center_nil (quotient_nil A nilG)). by rewrite quotient_normal // /normal subsetIl normsI ?normG ?norms_cent. apply/trivgP/subsetP=> _ /setIP[/morphimP[x Nx /setIP[_ Cx]] ->]. rewrite -cycle_subG in Cx => /setIP[GAx CAx]. have{CAx GAx}: <[coset A x]> <| G / A. by rewrite /normal cycle_subG GAx cents_norm // centsC cycle_subG. case/(inv_quotientN nsAG)=> B /= defB sAB nBG. rewrite -cycle_subG defB (maxA B) ?trivg_quotient // nBG. have{defB} defB : B :=: A * <[x]>. rewrite -quotientK ?cycle_subG ?quotient_cycle // defB quotientGK //. exact: normalS (normal_sub nBG) nsAG. apply/setIidPl; rewrite ?defB -[_ :&: _]center_prod //=. rewrite /center !(setIidPl _) //; exact: cycle_abelian. Qed. (* The two other assertions of Aschbacher 23.15 state properties of the *) (* normal series 1 <| Z = 'Ohm_1(A) <| A with A \in 'SCN(G). *) Section SCNseries. Variables A : {group gT}. Hypothesis SCN_A : A \in 'SCN(G). Let Z := 'Ohm_1(A). Let cAA := SCN_abelian SCN_A. Let sZA: Z \subset A := Ohm_sub 1 A. Let nZA : A \subset 'N(Z) := sub_abelian_norm cAA sZA. (* This is Aschbacher 23.15(2). *) Lemma der1_stab_Ohm1_SCN_series : ('C(Z) :&: 'C_G(A / Z | 'Q))^`(1) \subset A. Proof. case/SCN_P: SCN_A => /andP[sAG nAG] {4} <-. rewrite subsetI {1}setICA comm_subG ?subsetIl //= gen_subG. apply/subsetP=> w /imset2P[u v]. rewrite -groupV -(groupV _ v) /= astabQR //= -/Z !inE groupV. case/and4P=> cZu _ _ sRuZ /and4P[cZv' _ _ sRvZ] ->{w}. apply/centP=> a Aa; rewrite /commute -!mulgA (commgCV v) (mulgA u). rewrite (centP cZu); last by rewrite (subsetP sRvZ) ?mem_commg ?set11 ?groupV. rewrite 2!(mulgA v^-1) mulKVg 4!mulgA invgK (commgC u^-1) mulgA. rewrite -(mulgA _ _ v^-1) -(centP cZv') ?(subsetP sRuZ) ?mem_commg ?set11//. by rewrite -!mulgA invgK mulKVg !mulKg. Qed. (* This is Aschbacher 23.15(3); note that this proof does not depend on the *) (* maximality of A. *) Lemma Ohm1_stab_Ohm1_SCN_series : odd p -> p.-group G -> 'Ohm_1('C_G(Z)) \subset 'C_G(A / Z | 'Q). Proof. have [-> | ntG] := eqsVneq G 1; first by rewrite !(setIidPl (sub1G _)) Ohm1. move=> p_odd pG; have{ntG} [p_pr _ _] := pgroup_pdiv pG ntG. case/SCN_P: SCN_A => /andP[sAG nAG] _; have pA := pgroupS sAG pG. have pCGZ : p.-group 'C_G(Z) by rewrite (pgroupS _ pG) // subsetIl. rewrite {pCGZ}(OhmE 1 pCGZ) gen_subG; apply/subsetP=> x; rewrite 3!inE -andbA. rewrite -!cycle_subG => /and3P[sXG cZX xp1] /=; have cXX := cycle_abelian x. have nZX := cents_norm cZX; have{nAG} nAX := subset_trans sXG nAG. pose XA := <[x]> <*> A; pose C := 'C(<[x]> / Z | 'Q); pose CA := A :&: C. pose Y := <[x]> <*> CA; pose W := 'Ohm_1(Y). have sXC: <[x]> \subset C by rewrite sub_astabQ nZX (quotient_cents _ cXX). have defY : Y = <[x]> * CA by rewrite -norm_joinEl // normsI ?nAX ?normsG. have{nAX} defXA: XA = <[x]> * A := norm_joinEl nAX. suffices{sXC}: XA \subset Y. rewrite subsetI sXG /= sub_astabQ nZX centsC defY group_modl //= -/Z -/C. by rewrite subsetI sub_astabQ defXA quotientMl //= !mulG_subG; case/and4P. have sZCA: Z \subset CA by rewrite subsetI sZA [C]astabQ sub_cosetpre. have cZCA: CA \subset 'C(Z) by rewrite subIset 1?(sub_abelian_cent2 cAA). have sZY: Z \subset Y by rewrite (subset_trans sZCA) ?joing_subr. have{cZCA cZX} cZY: Y \subset 'C(Z) by rewrite join_subG cZX. have{cXX nZX} sY'Z : Y^`(1) \subset Z. rewrite der1_min ?cents_norm //= -/Y defY quotientMl // abelianM /= -/Z -/CA. rewrite !quotient_abelian // ?(abelianS _ cAA) ?subsetIl //=. by rewrite /= quotientGI ?Ohm_sub // quotient_astabQ subsetIr. have{sY'Z cZY} nil_classY: nil_class Y <= 2. by rewrite nil_class2 (subset_trans sY'Z ) // subsetI sZY centsC. have pY: p.-group Y by rewrite (pgroupS _ pG) // join_subG sXG subIset ?sAG. have sXW: <[x]> \subset W. by rewrite [W](OhmE 1 pY) ?genS // sub1set !inE -cycle_subG joing_subl. have{nil_classY pY sXW sZY sZCA} defW: W = <[x]> * Z. rewrite -[W](setIidPr (Ohm_sub _ _)) /= -/Y {1}defY -group_modl //= -/Y -/W. congr (_ * _); apply/eqP; rewrite eqEsubset {1}[Z](OhmE 1 pA). rewrite subsetI setIAC subIset //; first by rewrite sZCA -[Z]Ohm_id OhmS. rewrite sub_gen ?setIS //; apply/subsetP=> w Ww; rewrite inE. by apply/eqP; apply: exponentP w Ww; exact: exponent_Ohm1_class2. have{sXG sAG} sXAG: XA \subset G by rewrite join_subG sXG. have{sXAG} nilXA: nilpotent XA := nilpotentS sXAG (pgroup_nil pG). have sYXA: Y \subset XA by rewrite defY defXA mulgS ?subsetIl. rewrite -[Y](nilpotent_sub_norm nilXA) {nilXA sYXA}//= -/Y -/XA. apply: subset_trans (setIS _ (char_norm_trans (Ohm_char 1 _) (subxx _))) _. rewrite {XA}defXA -group_modl ?normsG /= -/W ?{W}defW ?mulG_subl //. rewrite {Y}defY mulgS // subsetI subsetIl {CA C}sub_astabQ subIset ?nZA //= -/Z. rewrite (subset_trans (quotient_subnorm _ _ _)) //= quotientMidr /= -/Z. rewrite -quotient_sub1 ?subIset ?cent_norm ?orbT //. rewrite (subset_trans (quotientI _ _ _)) ?coprime_TIg //. rewrite (@pnat_coprime p) // -/(pgroup p _) ?quotient_pgroup {pA}//=. rewrite -(setIidPr (cent_sub _)) [pnat _ _]p'group_quotient_cent_prime //. by rewrite (dvdn_trans (dvdn_quotient _ _)) ?order_dvdn. Qed. End SCNseries. (* This is Aschbacher 23.16. *) Lemma Ohm1_cent_max_normal_abelem Z : odd p -> p.-group G -> [max Z | Z <| G & p.-abelem Z] -> 'Ohm_1('C_G(Z)) = Z. Proof. move=> p_odd pG; set X := 'Ohm_1('C_G(Z)). case/maxgroupP=> /andP[nsZG abelZ] maxZ. have [sZG nZG] := andP nsZG; have [_ cZZ expZp] := and3P abelZ. have{nZG} nsXG: X <| G. apply: (char_normal_trans (Ohm_char 1 'C_G(Z))). by rewrite /normal subsetIl normsI ?normG ?norms_cent. have cZX : X \subset 'C(Z) := subset_trans (Ohm_sub _ _) (subsetIr _ _). have{sZG expZp} sZX: Z \subset X. rewrite [X](OhmE 1 (pgroupS _ pG)) ?subsetIl ?sub_gen //. apply/subsetP=> x Zx; rewrite !inE ?(subsetP sZG) ?(subsetP cZZ) //=. by rewrite (exponentP expZp). suffices{sZX} expXp: (exponent X %| p). apply/eqP; rewrite eqEsubset sZX andbT -quotient_sub1 ?cents_norm //= -/X. have pGq: p.-group (G / Z) by rewrite quotient_pgroup. rewrite (TI_center_nil (pgroup_nil pGq)) ?quotient_normal //= -/X setIC. apply/eqP/trivgPn=> [[Zd]]; rewrite inE -!cycle_subG -cycle_eq1 -subG1 /= -/X. case/andP=> /sub_center_normal nsZdG. have{nsZdG} [D defD sZD nsDG] := inv_quotientN nsZG nsZdG; rewrite defD. have sDG := normal_sub nsDG; have nsZD := normalS sZD sDG nsZG. rewrite quotientSGK ?quotient_sub1 ?normal_norm //= -/X => sDX; case/negP. rewrite (maxZ D) // nsDG andbA (pgroupS sDG) ?(dvdn_trans (exponentS sDX)) //. have sZZD: Z \subset 'Z(D) by rewrite subsetI sZD centsC (subset_trans sDX). by rewrite (cyclic_factor_abelian sZZD) //= -defD cycle_cyclic. pose normal_abelian := [pred A : {group gT} | A <| G & abelian A]. have{nsZG cZZ} normal_abelian_Z : normal_abelian Z by exact/andP. have{normal_abelian_Z} [A maxA sZA] := maxgroup_exists normal_abelian_Z. have SCN_A : A \in 'SCN(G) by apply: max_SCN pG maxA. move/maxgroupp: maxA => /andP[nsAG cAA] {normal_abelian}. have pA := pgroupS (normal_sub nsAG) pG. have{abelZ maxZ nsAG cAA sZA} defA1: 'Ohm_1(A) = Z. apply: maxZ; last by rewrite -(Ohm1_id abelZ) OhmS. by rewrite Ohm1_abelem ?(char_normal_trans (Ohm_char _ _) nsAG). have{SCN_A} sX'A: X^`(1) \subset A. have sX_CWA1 : X \subset 'C('Ohm_1(A)) :&: 'C_G(A / 'Ohm_1(A) | 'Q). rewrite subsetI /X -defA1 (Ohm1_stab_Ohm1_SCN_series _ p_odd) //= andbT. exact: subset_trans (Ohm_sub _ _) (subsetIr _ _). by apply: subset_trans (der1_stab_Ohm1_SCN_series SCN_A); rewrite commgSS. pose genXp := [pred U : {group gT} | 'Ohm_1(U) == U & ~~ (exponent U %| p)]. apply/idPn=> expXp'; have genXp_X: genXp [group of X] by rewrite /= Ohm_id eqxx. have{genXp_X expXp'} [U] := mingroup_exists genXp_X; case/mingroupP; case/andP. move/eqP=> defU1 expUp' minU sUX; case/negP: expUp'. have{nsXG} pU := pgroupS (subset_trans sUX (normal_sub nsXG)) pG. case gsetU1: (group_set 'Ldiv_p(U)). by rewrite -defU1 (OhmE 1 pU) gen_set_id // -sub_LdivT subsetIr. move: gsetU1; rewrite /group_set 2!inE group1 expg1n eqxx; case/subsetPn=> xy. case/imset2P=> x y; rewrite !inE => /andP[Ux xp1] /andP[Uy yp1] ->{xy}. rewrite groupM //= => nt_xyp; pose XY := <[x]> <*> <[y]>. have{yp1 nt_xyp} defXY: XY = U. have sXY_U: XY \subset U by rewrite join_subG !cycle_subG Ux Uy. rewrite [XY]minU //= eqEsubset Ohm_sub (OhmE 1 (pgroupS _ pU)) //. rewrite /= joing_idl joing_idr genS; last first. by rewrite subsetI subset_gen subUset !sub1set !inE xp1 yp1. apply: contra nt_xyp => /exponentP-> //. by rewrite groupMl mem_gen // (set21, set22). have: <[x]> <|<| U by rewrite nilpotent_subnormal ?(pgroup_nil pU) ?cycle_subG. case/subnormalEsupport=> [defU | /=]. by apply: dvdn_trans (exponent_dvdn U) _; rewrite -defU order_dvdn. set V := < U>>; case/andP=> sVU ltVU. have{genXp minU xp1 sVU ltVU} expVp: exponent V %| p. apply: contraR ltVU => expVp'; rewrite [V]minU //= expVp' eqEsubset Ohm_sub. rewrite (OhmE 1 (pgroupS sVU pU)) genS //= subsetI subset_gen class_supportEr. apply/bigcupsP=> z _; apply/subsetP=> v Vv. by rewrite inE -order_dvdn (dvdn_trans (order_dvdG Vv)) // cardJg order_dvdn. have{A pA defA1 sX'A V expVp} Zxy: [~ x, y] \in Z. rewrite -defA1 (OhmE 1 pA) mem_gen // !inE (exponentP expVp). by rewrite (subsetP sX'A) //= mem_commg ?(subsetP sUX). by rewrite groupMl -1?[x^-1]conjg1 mem_gen // mem_imset2 // ?groupV cycle_id. have{Zxy sUX cZX} cXYxy: [~ x, y] \in 'C(XY). by rewrite centsC in cZX; rewrite defXY (subsetP (centS sUX)) ?(subsetP cZX). rewrite -defU1 exponent_Ohm1_class2 // nil_class2 -defXY der1_joing_cycles //. by rewrite subsetI {1}defXY !cycle_subG groupR. Qed. Lemma critical_class2 H : critical H G -> nil_class H <= 2. Proof. case=> [chH _ sRZ _]. by rewrite nil_class2 (subset_trans _ sRZ) ?commSg // char_sub. Qed. (* This proof of the Thompson critical lemma is adapted from Aschbacher 23.6 *) Lemma Thompson_critical : p.-group G -> {K : {group gT} | critical K G}. Proof. move=> pG; pose qcr A := (A \char G) && ('Phi(A) :|: [~: G, A] \subset 'Z(A)). have [|K]:= @maxgroup_exists _ qcr 1 _. by rewrite /qcr char1 center1 commG1 subUset Phi_sub subxx. case/maxgroupP; rewrite {}/qcr subUset => /and3P[chK sPhiZ sRZ] maxK _. have sKG := char_sub chK; have nKG := char_normal chK. exists K; split=> //; apply/eqP; rewrite eqEsubset andbC setSI //=. have chZ: 'Z(K) \char G by [exact: subcent_char]; have nZG := char_norm chZ. have chC: 'C_G(K) \char G by exact: subcent_char (char_refl G) chK. rewrite -quotient_sub1; last by rewrite subIset // char_norm. apply/trivgP; apply: (TI_center_nil (quotient_nil _ (pgroup_nil pG))). rewrite quotient_normal // /normal subsetIl normsI ?normG ?norms_cent //. exact: char_norm. apply: TI_Ohm1; apply/trivgP; rewrite -trivg_quotient -sub_cosetpre_quo //. rewrite morphpreI quotientGK /=; last first. by apply: normalS (char_normal chZ); rewrite ?subsetIl ?setSI. set X := _ :&: _; pose gX := [group of X]. have sXG: X \subset G by rewrite subIset ?subsetIl. have cXK: K \subset 'C(gX) by rewrite centsC 2?subIset // subxx orbT. rewrite subsetI centsC cXK andbT -(mul1g K) -mulSG mul1g -(cent_joinEr cXK). rewrite [_ <*> K]maxK ?joing_subr //= andbC (cent_joinEr cXK). rewrite -center_prod // (subset_trans _ (mulG_subr _ _)). rewrite charM 1?charI ?(char_from_quotient (normal_cosetpre _)) //. by rewrite cosetpreK (char_trans _ (center_char _)) ?Ohm_char. rewrite (@Phi_mulg p) ?(pgroupS _ pG) // subUset commGC commMG; last first. by rewrite normsR ?(normsG sKG) // cents_norm // centsC. rewrite !mul_subG 1?commGC //. apply: subset_trans (commgS _ (subsetIr _ _)) _. rewrite -quotient_cents2 ?subsetIl // centsC // cosetpreK //. by rewrite (subset_trans (Ohm_sub _ _)) // subsetIr. have nZX := subset_trans sXG nZG; have pX : p.-group gX by exact: pgroupS pG. rewrite -quotient_sub1 ?(subset_trans (Phi_sub _)) //=. have pXZ: p.-group (gX / 'Z(K)) by exact: morphim_pgroup. rewrite (quotient_Phi pX nZX) subG1 (trivg_Phi pXZ). apply: (abelemS (quotientS _ (subsetIr _ _))); rewrite /= cosetpreK /=. have pZ: p.-group 'Z(G / 'Z(K)). by rewrite (pgroupS (center_sub _)) ?morphim_pgroup. by rewrite Ohm1_abelem ?center_abelian. Qed. Lemma critical_p_stab_Aut H : critical H G -> p.-group G -> p.-group 'C(H | [Aut G]). Proof. move=> [chH sPhiZ sRZ eqCZ] pG; have sHG := char_sub chH. pose G' := (sdpair1 [Aut G] @* G)%G; pose H' := (sdpair1 [Aut G] @* H)%G. apply/pgroupP=> q pr_q; case/Cauchy=>//= f cHF; move: (cHF);rewrite astab_ract. case/setIP=> Af cHFP ofq; rewrite -cycle_subG in cHF; apply: (pgroupP pG) => //. pose F' := (sdpair2 [Aut G] @* <[f]>)%G. have trHF: [~: H', F'] = 1. apply/trivgP; rewrite gen_subG; apply/subsetP=> u; case/imset2P=> x' a'. case/morphimP=> x Gx Hx ->; case/morphimP=> a Aa Fa -> -> {u x' a'}. by rewrite inE commgEl -sdpair_act ?(astab_act (subsetP cHF _ Fa) Hx) ?mulVg. have sGH_H: [~: G', H'] \subset H'. by rewrite -morphimR ?(char_sub chH) // morphimS // commg_subr char_norm. have{trHF sGH_H} trFGH: [~: F', G', H'] = 1. apply: three_subgroup; last by rewrite trHF comm1G. by apply/trivgP; rewrite -trHF commSg. apply/negP=> qG; case: (qG); rewrite -ofq. suffices ->: f = 1 by rewrite order1 dvd1n. apply/permP=> x; rewrite perm1; case Gx: (x \in G); last first. by apply: out_perm (negbT Gx); case/setIdP: Af. have Gfx: f x \in G by rewrite -(im_autm Af) -{1}(autmE Af) mem_morphim. pose y := x^-1 * f x; have Gy: y \in G by rewrite groupMl ?groupV. have [inj1 inj2] := (injm_sdpair1 [Aut G], injm_sdpair2 [Aut G]). have Hy: y \in H. rewrite (subsetP (center_sub H)) // -eqCZ -cycle_subG. rewrite -(injmSK inj1) ?cycle_subG // injm_subcent // subsetI. rewrite morphimS ?morphim_cycle ?cycle_subG //=. suffices: sdpair1 [Aut G] y \in [~: G', F']. by rewrite commGC; apply: subsetP; exact/commG1P. rewrite morphM ?groupV ?morphV //= sdpair_act // -commgEl. by rewrite mem_commg ?mem_morphim ?cycle_id. have fy: f y = y := astabP cHFP _ Hy. have: (f ^+ q) x = x * y ^+ q. elim: (q) => [|i IHi]; first by rewrite perm1 mulg1. rewrite expgSr permM {}IHi -(autmE Af) morphM ?morphX ?groupX //= autmE. by rewrite fy expgS mulgA mulKVg. move/eqP; rewrite -{1}ofq expg_order perm1 eq_mulVg1 mulKg -order_dvdn. case/primeP: pr_q => _ pr_q /pr_q; rewrite order_eq1 -eq_mulVg1. by case: eqP => //= _ /eqP oyq; case: qG; rewrite -oyq order_dvdG. Qed. End SCN. Implicit Arguments SCN_P [gT G A].mathcomp-1.5/theories/ssrnum.v0000644000175000017500000045713612307636117015541 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq div choice fintype. Require Import bigop ssralg finset fingroup zmodp poly. (******************************************************************************) (* *) (* This file defines some classes to manipulate number structures, i.e *) (* structures with an order and a norm *) (* *) (* * NumDomain (Integral domain with an order and a norm) *) (* NumMixin == the mixin that provides an order and a norm over *) (* a ring and their characteristic properties. *) (* numDomainType == interface for a num integral domain. *) (* NumDomainType T m *) (* == packs the num mixin into a numberDomainType. The *) (* carrier T must have a integral domain structure. *) (* [numDomainType of T for S ] *) (* == T-clone of the numDomainType structure S. *) (* [numDomainType of T] *) (* == clone of a canonical numDomainType structure on T. *) (* *) (* * NumField (Field with an order and a norm) *) (* numFieldType == interface for a num field. *) (* [numFieldType of T] *) (* == clone of a canonical numFieldType structure on T *) (* *) (* * NumClosedField (Closed Field with an order and a norm) *) (* numClosedFieldType *) (* == interface for a num closed field. *) (* [numClosedFieldType of T] *) (* == clone of a canonical numClosedFieldType structure on T *) (* *) (* * RealDomain (Num domain where all elements are positive or negative) *) (* realDomainType == interface for a real integral domain. *) (* RealDomainType T r *) (* == packs the real axiom r into a realDomainType. The *) (* carrier T must have a num domain structure. *) (* [realDomainType of T for S ] *) (* == T-clone of the realDomainType structure S. *) (* [realDomainType of T] *) (* == clone of a canonical realDomainType structure on T. *) (* *) (* * RealField (Num Field where all elements are positive or negative) *) (* realFieldType == interface for a real field. *) (* [realFieldType of T] *) (* == clone of a canonical realFieldType structure on T *) (* *) (* * ArchiField (A Real Field with the archimedean axiom) *) (* archiFieldType == interface for an archimedean field. *) (* ArchiFieldType T r *) (* == packs the archimeadean axiom r into an archiFieldType. *) (* The carrier T must have a real field type structure. *) (* [archiFieldType of T for S ] *) (* == T-clone of the archiFieldType structure S. *) (* [archiFieldType of T] *) (* == clone of a canonical archiFieldType structure on T *) (* *) (* * RealClosedField (Real Field with the real closed axiom) *) (* realClosedFieldType *) (* == interface for a real closed field. *) (* RealClosedFieldType T r *) (* == packs the real closed axiom r into a *) (* realClodedFieldType. The carrier T must have a real *) (* field type structure. *) (* [realClosedFieldType of T for S ] *) (* == T-clone of the realClosedFieldType structure S. *) (* [realClosedFieldype of T] *) (* == clone of a canonical realClosedFieldType structure on *) (* T. *) (* *) (* Over these structures, we have the following operations *) (* `|x| == norm of x. *) (* x <= y <=> x is less than or equal to y (:= '|y - x| == y - x). *) (* x < y <=> x is less than y (:= (x <= y) && (x != y)). *) (* x <= y ?= iff C <-> x is less than y, or equal iff C is true. *) (* Num.sg x == sign of x: equal to 0 iff x = 0, to 1 iff x > 0, and *) (* to -1 in all other cases (including x < 0). *) (* x \is a Num.pos <=> x is positive (:= x > 0). *) (* x \is a Num.neg <=> x is negative (:= x < 0). *) (* x \is a Num.nneg <=> x is positive or 0 (:= x >= 0). *) (* x \is a Num.real <=> x is real (:= x >= 0 or x < 0). *) (* Num.min x y == minimum of x y *) (* Num.max x y == maximum of x y *) (* Num.bound x == in archimedean fields, and upper bound for x, i.e., *) (* and n such that `|x| < n%:R. *) (* Num.sqrt x == in a real-closed field, a positive square root of x if *) (* x >= 0, or 0 otherwise. *) (* *) (* There are now three distinct uses of the symbols <, <=, > and >=: *) (* 0-ary, unary (prefix) and binary (infix). *) (* 0. <%R, <=%R, >%R, >=%R stand respectively for lt, le, gt and ge. *) (* 1. (< x), (<= x), (> x), (>= x) stand respectively for *) (* (gt x), (ge x), (lt x), (le x). *) (* So (< x) is a predicate characterizing elements smaller than x. *) (* 2. (x < y), (x <= y), ... mean what they are expected to. *) (* These convention are compatible with haskell's, *) (* where ((< y) x) = (x < y) = ((<) x y), *) (* except that we write <%R instead of (<). *) (* *) (* - list of prefixes : *) (* p : positive *) (* n : negative *) (* sp : strictly positive *) (* sn : strictly negative *) (* i : interior = in [0, 1] or ]0, 1[ *) (* e : exterior = in [1, +oo[ or ]1; +oo[ *) (* w : non strict (weak) monotony *) (* *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Local Open Scope ring_scope. Import GRing.Theory. Reserved Notation "<= y" (at level 35). Reserved Notation ">= y" (at level 35). Reserved Notation "< y" (at level 35). Reserved Notation "> y" (at level 35). Reserved Notation "<= y :> T" (at level 35, y at next level). Reserved Notation ">= y :> T" (at level 35, y at next level). Reserved Notation "< y :> T" (at level 35, y at next level). Reserved Notation "> y :> T" (at level 35, y at next level). Module Num. (* Principal mixin; further classes add axioms rather than operations. *) Record mixin_of (R : ringType) := Mixin { norm_op : R -> R; le_op : rel R; lt_op : rel R; _ : forall x y, le_op (norm_op (x + y)) (norm_op x + norm_op y); _ : forall x y, lt_op 0 x -> lt_op 0 y -> lt_op 0 (x + y); _ : forall x, norm_op x = 0 -> x = 0; _ : forall x y, le_op 0 x -> le_op 0 y -> le_op x y || le_op y x; _ : {morph norm_op : x y / x * y}; _ : forall x y, (le_op x y) = (norm_op (y - x) == y - x); _ : forall x y, (lt_op x y) = (y != x) && (le_op x y) }. Local Notation ring_for T b := (@GRing.Ring.Pack T b T). (* Base interface. *) Module NumDomain. Section ClassDef. Record class_of T := Class { base : GRing.IntegralDomain.class_of T; mixin : mixin_of (ring_for T base) }. Local Coercion base : class_of >-> GRing.IntegralDomain.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition clone c of phant_id class c := @Pack T c T. Definition pack b0 (m0 : mixin_of (ring_for T b0)) := fun bT b & phant_id (GRing.IntegralDomain.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.IntegralDomain.class_of. Coercion mixin : class_of >-> mixin_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Notation numDomainType := type. Notation NumMixin := Mixin. Notation NumDomainType T m := (@pack T _ m _ _ id _ id). Notation "[ 'numDomainType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'numDomainType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'numDomainType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'numDomainType' 'of' T ]") : form_scope. End Exports. End NumDomain. Import NumDomain.Exports. Module Import Def. Section Def. Import NumDomain. Context {R : type}. Implicit Types (x y : R) (C : bool). Definition normr : R -> R := norm_op (class R). Definition ler : rel R := le_op (class R). Definition ltr : rel R := lt_op (class R). Local Notation "x <= y" := (ler x y) : ring_scope. Local Notation "x < y" := (ltr x y) : ring_scope. Definition ger : simpl_rel R := [rel x y | y <= x]. Definition gtr : simpl_rel R := [rel x y | y < x]. Definition lerif x y C : Prop := ((x <= y) * ((x == y) = C))%type. Definition sgr x : R := if x == 0 then 0 else if x < 0 then -1 else 1. Definition minr x y : R := if x <= y then x else y. Definition maxr x y : R := if y <= x then x else y. Definition Rpos : qualifier 0 R := [qualify x : R | 0 < x]. Definition Rneg : qualifier 0 R := [qualify x : R | x < 0]. Definition Rnneg : qualifier 0 R := [qualify x : R | 0 <= x]. Definition Rreal : qualifier 0 R := [qualify x : R | (0 <= x) || (x <= 0)]. End Def. End Def. (* Shorter qualified names, when Num.Def is not imported. *) Notation norm := normr. Notation le := ler. Notation lt := ltr. Notation ge := ger. Notation gt := gtr. Notation sg := sgr. Notation max := maxr. Notation min := minr. Notation pos := Rpos. Notation neg := Rneg. Notation nneg := Rnneg. Notation real := Rreal. Module Keys. Section Keys. Variable R : numDomainType. Fact Rpos_key : pred_key (@pos R). Proof. by []. Qed. Definition Rpos_keyed := KeyedQualifier Rpos_key. Fact Rneg_key : pred_key (@real R). Proof. by []. Qed. Definition Rneg_keyed := KeyedQualifier Rneg_key. Fact Rnneg_key : pred_key (@nneg R). Proof. by []. Qed. Definition Rnneg_keyed := KeyedQualifier Rnneg_key. Fact Rreal_key : pred_key (@real R). Proof. by []. Qed. Definition Rreal_keyed := KeyedQualifier Rreal_key. Definition ler_of_leif x y C (le_xy : @lerif R x y C) := le_xy.1 : le x y. End Keys. End Keys. (* (Exported) symbolic syntax. *) Module Import Syntax. Import Def Keys. Notation "`| x |" := (norm x) : ring_scope. Notation "<%R" := lt : ring_scope. Notation ">%R" := gt : ring_scope. Notation "<=%R" := le : ring_scope. Notation ">=%R" := ge : ring_scope. Notation " T" := (< (y : T)) : ring_scope. Notation "> y" := (lt y) : ring_scope. Notation "> y :> T" := (> (y : T)) : ring_scope. Notation "<= y" := (ge y) : ring_scope. Notation "<= y :> T" := (<= (y : T)) : ring_scope. Notation ">= y" := (le y) : ring_scope. Notation ">= y :> T" := (>= (y : T)) : ring_scope. Notation "x < y" := (lt x y) : ring_scope. Notation "x < y :> T" := ((x : T) < (y : T)) : ring_scope. Notation "x > y" := (y < x) (only parsing) : ring_scope. Notation "x > y :> T" := ((x : T) > (y : T)) (only parsing) : ring_scope. Notation "x <= y" := (le x y) : ring_scope. Notation "x <= y :> T" := ((x : T) <= (y : T)) : ring_scope. Notation "x >= y" := (y <= x) (only parsing) : ring_scope. Notation "x >= y :> T" := ((x : T) >= (y : T)) (only parsing) : ring_scope. Notation "x <= y <= z" := ((x <= y) && (y <= z)) : ring_scope. Notation "x < y <= z" := ((x < y) && (y <= z)) : ring_scope. Notation "x <= y < z" := ((x <= y) && (y < z)) : ring_scope. Notation "x < y < z" := ((x < y) && (y < z)) : ring_scope. Notation "x <= y ?= 'iff' C" := (lerif x y C) : ring_scope. Notation "x <= y ?= 'iff' C :> R" := ((x : R) <= (y : R) ?= iff C) (only parsing) : ring_scope. Coercion ler_of_leif : lerif >-> is_true. Canonical Rpos_keyed. Canonical Rneg_keyed. Canonical Rnneg_keyed. Canonical Rreal_keyed. End Syntax. Section ExtensionAxioms. Variable R : numDomainType. Definition real_axiom : Prop := forall x : R, x \is real. Definition archimedean_axiom : Prop := forall x : R, exists ub, `|x| < ub%:R. Definition real_closed_axiom : Prop := forall (p : {poly R}) (a b : R), a <= b -> p.[a] <= 0 <= p.[b] -> exists2 x, a <= x <= b & root p x. End ExtensionAxioms. Local Notation num_for T b := (@NumDomain.Pack T b T). (* The rest of the numbers interface hierarchy. *) Module NumField. Section ClassDef. Record class_of R := Class { base : GRing.Field.class_of R; mixin : mixin_of (ring_for R base) }. Definition base2 R (c : class_of R) := NumDomain.Class (mixin c). Local Coercion base : class_of >-> GRing.Field.class_of. Local Coercion base2 : class_of >-> NumDomain.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack := fun bT b & phant_id (GRing.Field.class bT) (b : GRing.Field.class_of T) => fun mT m & phant_id (NumDomain.class mT) (@NumDomain.Class T b m) => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition numDomainType := @NumDomain.Pack cT xclass xT. Definition fieldType := @GRing.Field.Pack cT xclass xT. Definition join_numDomainType := @NumDomain.Pack fieldType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.Field.class_of. Coercion base2 : class_of >-> NumDomain.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Coercion numDomainType : type >-> NumDomain.type. Canonical numDomainType. Coercion fieldType : type >-> GRing.Field.type. Canonical fieldType. Notation numFieldType := type. Notation "[ 'numFieldType' 'of' T ]" := (@pack T _ _ id _ _ id) (at level 0, format "[ 'numFieldType' 'of' T ]") : form_scope. End Exports. End NumField. Import NumField.Exports. Module ClosedField. Section ClassDef. Record class_of R := Class { base : GRing.ClosedField.class_of R; mixin : mixin_of (ring_for R base) }. Definition base2 R (c : class_of R) := NumField.Class (mixin c). Local Coercion base : class_of >-> GRing.ClosedField.class_of. Local Coercion base2 : class_of >-> NumField.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack := fun bT b & phant_id (GRing.ClosedField.class bT) (b : GRing.ClosedField.class_of T) => fun mT m & phant_id (NumField.class mT) (@NumField.Class T b m) => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition numDomainType := @NumDomain.Pack cT xclass xT. Definition fieldType := @GRing.Field.Pack cT xclass xT. Definition decFieldType := @GRing.DecidableField.Pack cT xclass xT. Definition closedFieldType := @GRing.ClosedField.Pack cT xclass xT. Definition join_dec_numDomainType := @NumDomain.Pack decFieldType xclass xT. Definition join_dec_numFieldType := @NumField.Pack decFieldType xclass xT. Definition join_numDomainType := @NumDomain.Pack closedFieldType xclass xT. Definition join_numFieldType := @NumField.Pack closedFieldType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.ClosedField.class_of. Coercion base2 : class_of >-> NumField.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Coercion numDomainType : type >-> NumDomain.type. Canonical numDomainType. Coercion fieldType : type >-> GRing.Field.type. Canonical fieldType. Coercion decFieldType : type >-> GRing.DecidableField.type. Canonical decFieldType. Coercion closedFieldType : type >-> GRing.ClosedField.type. Canonical closedFieldType. Canonical join_dec_numDomainType. Canonical join_dec_numFieldType. Canonical join_numDomainType. Canonical join_numFieldType. Notation numClosedFieldType := type. Notation "[ 'numClosedFieldType' 'of' T ]" := (@pack T _ _ id _ _ id) (at level 0, format "[ 'numClosedFieldType' 'of' T ]") : form_scope. End Exports. End ClosedField. Import ClosedField.Exports. Module RealDomain. Section ClassDef. Record class_of R := Class {base : NumDomain.class_of R; _ : @real_axiom (num_for R base)}. Local Coercion base : class_of >-> NumDomain.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition clone c of phant_id class c := @Pack T c T. Definition pack b0 (m0 : real_axiom (num_for T b0)) := fun bT b & phant_id (NumDomain.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition numDomainType := @NumDomain.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> NumDomain.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Coercion numDomainType : type >-> NumDomain.type. Canonical numDomainType. Notation realDomainType := type. Notation RealDomainType T m := (@pack T _ m _ _ id _ id). Notation "[ 'realDomainType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'realDomainType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'realDomainType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'realDomainType' 'of' T ]") : form_scope. End Exports. End RealDomain. Import RealDomain.Exports. Module RealField. Section ClassDef. Record class_of R := Class { base : NumField.class_of R; mixin : real_axiom (num_for R base) }. Definition base2 R (c : class_of R) := RealDomain.Class (@mixin R c). Local Coercion base : class_of >-> NumField.class_of. Local Coercion base2 : class_of >-> RealDomain.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack := fun bT b & phant_id (NumField.class bT) (b : NumField.class_of T) => fun mT m & phant_id (RealDomain.class mT) (@RealDomain.Class T b m) => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition numDomainType := @NumDomain.Pack cT xclass xT. Definition realDomainType := @RealDomain.Pack cT xclass xT. Definition fieldType := @GRing.Field.Pack cT xclass xT. Definition numFieldType := @NumField.Pack cT xclass xT. Definition join_realDomainType := @RealDomain.Pack numFieldType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> NumField.class_of. Coercion base2 : class_of >-> RealDomain.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Coercion numDomainType : type >-> NumDomain.type. Canonical numDomainType. Coercion realDomainType : type >-> RealDomain.type. Canonical realDomainType. Coercion fieldType : type >-> GRing.Field.type. Canonical fieldType. Coercion numFieldType : type >-> NumField.type. Canonical numFieldType. Canonical join_realDomainType. Notation realFieldType := type. Notation "[ 'realFieldType' 'of' T ]" := (@pack T _ _ id _ _ id) (at level 0, format "[ 'realFieldType' 'of' T ]") : form_scope. End Exports. End RealField. Import RealField.Exports. Module ArchimedeanField. Section ClassDef. Record class_of R := Class { base : RealField.class_of R; _ : archimedean_axiom (num_for R base) }. Local Coercion base : class_of >-> RealField.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition clone c of phant_id class c := @Pack T c T. Definition pack b0 (m0 : archimedean_axiom (num_for T b0)) := fun bT b & phant_id (RealField.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition numDomainType := @NumDomain.Pack cT xclass xT. Definition realDomainType := @RealDomain.Pack cT xclass xT. Definition fieldType := @GRing.Field.Pack cT xclass xT. Definition numFieldType := @NumField.Pack cT xclass xT. Definition realFieldType := @RealField.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> RealField.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Coercion numDomainType : type >-> NumDomain.type. Canonical numDomainType. Coercion realDomainType : type >-> RealDomain.type. Canonical realDomainType. Coercion fieldType : type >-> GRing.Field.type. Canonical fieldType. Coercion numFieldType : type >-> NumField.type. Canonical numFieldType. Coercion realFieldType : type >-> RealField.type. Canonical realFieldType. Notation archiFieldType := type. Notation ArchiFieldType T m := (@pack T _ m _ _ id _ id). Notation "[ 'archiFieldType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'archiFieldType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'archiFieldType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'archiFieldType' 'of' T ]") : form_scope. End Exports. End ArchimedeanField. Import ArchimedeanField.Exports. Module RealClosedField. Section ClassDef. Record class_of R := Class { base : RealField.class_of R; _ : real_closed_axiom (num_for R base) }. Local Coercion base : class_of >-> RealField.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition clone c of phant_id class c := @Pack T c T. Definition pack b0 (m0 : real_closed_axiom (num_for T b0)) := fun bT b & phant_id (RealField.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition numDomainType := @NumDomain.Pack cT xclass xT. Definition realDomainType := @RealDomain.Pack cT xclass xT. Definition fieldType := @GRing.Field.Pack cT xclass xT. Definition numFieldType := @NumField.Pack cT xclass xT. Definition realFieldType := @RealField.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> RealField.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Coercion numDomainType : type >-> NumDomain.type. Canonical numDomainType. Coercion realDomainType : type >-> RealDomain.type. Canonical realDomainType. Coercion fieldType : type >-> GRing.Field.type. Canonical fieldType. Coercion numFieldType : type >-> NumField.type. Canonical numFieldType. Coercion realFieldType : type >-> RealField.type. Canonical realFieldType. Notation rcfType := Num.RealClosedField.type. Notation RcfType T m := (@pack T _ m _ _ id _ id). Notation "[ 'rcfType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'rcfType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'rcfType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'rcfType' 'of' T ]") : form_scope. End Exports. End RealClosedField. Import RealClosedField.Exports. (* The elementary theory needed to support the definition of the derived *) (* operations for the extensions described above. *) Module Import Internals. Section Domain. Variable R : numDomainType. Implicit Types x y : R. (* Lemmas from the signature *) Lemma normr0_eq0 x : `|x| = 0 -> x = 0. Proof. by case: R x => ? [? []]. Qed. Lemma ler_norm_add x y : `|x + y| <= `|x| + `|y|. Proof. by case: R x y => ? [? []]. Qed. Lemma addr_gt0 x y : 0 < x -> 0 < y -> 0 < x + y. Proof. by case: R x y => ? [? []]. Qed. Lemma ger_leVge x y : 0 <= x -> 0 <= y -> (x <= y) || (y <= x). Proof. by case: R x y => ? [? []]. Qed. Lemma normrM : {morph norm : x y / x * y : R}. Proof. by case: R => ? [? []]. Qed. Lemma ler_def x y : (x <= y) = (`|y - x| == y - x). Proof. by case: R x y => ? [? []]. Qed. Lemma ltr_def x y : (x < y) = (y != x) && (x <= y). Proof. by case: R x y => ? [? []]. Qed. (* Basic consequences (just enough to get predicate closure properties). *) Lemma ger0_def x : (0 <= x) = (`|x| == x). Proof. by rewrite ler_def subr0. Qed. Lemma subr_ge0 x y : (0 <= x - y) = (y <= x). Proof. by rewrite ger0_def -ler_def. Qed. Lemma oppr_ge0 x : (0 <= - x) = (x <= 0). Proof. by rewrite -sub0r subr_ge0. Qed. Lemma ler01 : 0 <= 1 :> R. Proof. have n1_nz: `|1| != 0 :> R by apply: contraNneq (@oner_neq0 R) => /normr0_eq0->. by rewrite ger0_def -(inj_eq (mulfI n1_nz)) -normrM !mulr1. Qed. Lemma ltr01 : 0 < 1 :> R. Proof. by rewrite ltr_def oner_neq0 ler01. Qed. Lemma ltrW x y : x < y -> x <= y. Proof. by rewrite ltr_def => /andP[]. Qed. Lemma lerr x : x <= x. Proof. have n2: `|2%:R| == 2%:R :> R by rewrite -ger0_def ltrW ?addr_gt0 ?ltr01. rewrite ler_def subrr -(inj_eq (addrI `|0|)) addr0 -mulr2n -mulr_natr. by rewrite -(eqP n2) -normrM mul0r. Qed. Lemma le0r x : (0 <= x) = (x == 0) || (0 < x). Proof. by rewrite ltr_def; case: eqP => // ->; rewrite lerr. Qed. Lemma addr_ge0 x y : 0 <= x -> 0 <= y -> 0 <= x + y. Proof. rewrite le0r; case/predU1P=> [-> | x_pos]; rewrite ?add0r // le0r. by case/predU1P=> [-> | y_pos]; rewrite ltrW ?addr0 ?addr_gt0. Qed. Lemma pmulr_rgt0 x y : 0 < x -> (0 < x * y) = (0 < y). Proof. rewrite !ltr_def !ger0_def normrM mulf_eq0 negb_or => /andP[x_neq0 /eqP->]. by rewrite x_neq0 (inj_eq (mulfI x_neq0)). Qed. (* Closure properties of the real predicates. *) Lemma posrE x : (x \is pos) = (0 < x). Proof. by []. Qed. Lemma nnegrE x : (x \is nneg) = (0 <= x). Proof. by []. Qed. Lemma realE x : (x \is real) = (0 <= x) || (x <= 0). Proof. by []. Qed. Fact pos_divr_closed : divr_closed (@pos R). Proof. split=> [|x y x_gt0 y_gt0]; rewrite posrE ?ltr01 //. have [Uy|/invr_out->] := boolP (y \is a GRing.unit); last by rewrite pmulr_rgt0. by rewrite -(pmulr_rgt0 _ y_gt0) mulrC divrK. Qed. Canonical pos_mulrPred := MulrPred pos_divr_closed. Canonical pos_divrPred := DivrPred pos_divr_closed. Fact nneg_divr_closed : divr_closed (@nneg R). Proof. split=> [|x y]; rewrite !nnegrE ?ler01 ?le0r // -!posrE. case/predU1P=> [-> _ | x_gt0]; first by rewrite mul0r eqxx. by case/predU1P=> [-> | y_gt0]; rewrite ?invr0 ?mulr0 ?eqxx // orbC rpred_div. Qed. Canonical nneg_mulrPred := MulrPred nneg_divr_closed. Canonical nneg_divrPred := DivrPred nneg_divr_closed. Fact nneg_addr_closed : addr_closed (@nneg R). Proof. by split; [exact: lerr | exact: addr_ge0]. Qed. Canonical nneg_addrPred := AddrPred nneg_addr_closed. Canonical nneg_semiringPred := SemiringPred nneg_divr_closed. Fact real_oppr_closed : oppr_closed (@real R). Proof. by move=> x; rewrite /= !realE oppr_ge0 orbC -!oppr_ge0 opprK. Qed. Canonical real_opprPred := OpprPred real_oppr_closed. Fact real_addr_closed : addr_closed (@real R). Proof. split=> [|x y Rx Ry]; first by rewrite realE lerr. without loss{Rx} x_ge0: x y Ry / 0 <= x. case/orP: Rx => [? | x_le0]; first exact. by rewrite -rpredN opprD; apply; rewrite ?rpredN ?oppr_ge0. case/orP: Ry => [y_ge0 | y_le0]; first by rewrite realE -nnegrE rpredD. by rewrite realE -[y]opprK orbC -oppr_ge0 opprB !subr_ge0 ger_leVge ?oppr_ge0. Qed. Canonical real_addrPred := AddrPred real_addr_closed. Canonical real_zmodPred := ZmodPred real_oppr_closed. Fact real_divr_closed : divr_closed (@real R). Proof. split=> [|x y Rx Ry]; first by rewrite realE ler01. without loss{Rx} x_ge0: x / 0 <= x. case/orP: Rx => [? | x_le0]; first exact. by rewrite -rpredN -mulNr; apply; rewrite ?oppr_ge0. without loss{Ry} y_ge0: y / 0 <= y; last by rewrite realE -nnegrE rpred_div. case/orP: Ry => [? | y_le0]; first exact. by rewrite -rpredN -mulrN -invrN; apply; rewrite ?oppr_ge0. Qed. Canonical real_mulrPred := MulrPred real_divr_closed. Canonical real_smulrPred := SmulrPred real_divr_closed. Canonical real_divrPred := DivrPred real_divr_closed. Canonical real_sdivrPred := SdivrPred real_divr_closed. Canonical real_semiringPred := SemiringPred real_divr_closed. Canonical real_subringPred := SubringPred real_divr_closed. Canonical real_divringPred := DivringPred real_divr_closed. End Domain. Lemma num_real (R : realDomainType) (x : R) : x \is real. Proof. by case: R x => T []. Qed. Fact archi_bound_subproof (R : archiFieldType) : archimedean_axiom R. Proof. by case: R => ? []. Qed. Section RealClosed. Variable R : rcfType. Lemma poly_ivt : real_closed_axiom R. Proof. by case: R => ? []. Qed. Fact sqrtr_subproof (x : R) : exists2 y, 0 <= y & if 0 <= x return bool then y ^+ 2 == x else y == 0. Proof. case x_ge0: (0 <= x); last by exists 0; rewrite ?lerr. have le0x1: 0 <= x + 1 by rewrite -nnegrE rpredD ?rpred1. have [|y /andP[y_ge0 _]] := @poly_ivt ('X^2 - x%:P) _ _ le0x1. rewrite !hornerE -subr_ge0 add0r opprK x_ge0 -expr2 sqrrD mulr1. by rewrite addrAC !addrA addrK -nnegrE !rpredD ?rpredX ?rpred1. by rewrite rootE !hornerE subr_eq0; exists y. Qed. End RealClosed. End Internals. Module PredInstances. Canonical pos_mulrPred. Canonical pos_divrPred. Canonical nneg_addrPred. Canonical nneg_mulrPred. Canonical nneg_divrPred. Canonical nneg_semiringPred. Canonical real_addrPred. Canonical real_opprPred. Canonical real_zmodPred. Canonical real_mulrPred. Canonical real_smulrPred. Canonical real_divrPred. Canonical real_sdivrPred. Canonical real_semiringPred. Canonical real_subringPred. Canonical real_divringPred. End PredInstances. Module Import ExtraDef. Definition archi_bound {R} x := sval (sigW (@archi_bound_subproof R x)). Definition sqrtr {R} x := s2val (sig2W (@sqrtr_subproof R x)). End ExtraDef. Notation bound := archi_bound. Notation sqrt := sqrtr. Module Theory. Section NumIntegralDomainTheory. Variable R : numDomainType. Implicit Types x y z t : R. (* Lemmas from the signature (reexported from internals). *) Definition ler_norm_add x y : `|x + y| <= `|x| + `|y| := ler_norm_add x y. Definition addr_gt0 x y : 0 < x -> 0 < y -> 0 < x + y := @addr_gt0 R x y. Definition normr0_eq0 x : `|x| = 0 -> x = 0 := @normr0_eq0 R x. Definition ger_leVge x y : 0 <= x -> 0 <= y -> (x <= y) || (y <= x) := @ger_leVge R x y. Definition normrM : {morph normr : x y / x * y : R} := @normrM R. Definition ler_def x y : (x <= y) = (`|y - x| == y - x) := @ler_def R x y. Definition ltr_def x y : (x < y) = (y != x) && (x <= y) := @ltr_def R x y. (* Predicate and relation definitions. *) Lemma gerE x y : ge x y = (y <= x). Proof. by []. Qed. Lemma gtrE x y : gt x y = (y < x). Proof. by []. Qed. Lemma posrE x : (x \is pos) = (0 < x). Proof. by []. Qed. Lemma negrE x : (x \is neg) = (x < 0). Proof. by []. Qed. Lemma nnegrE x : (x \is nneg) = (0 <= x). Proof. by []. Qed. Lemma realE x : (x \is real) = (0 <= x) || (x <= 0). Proof. by []. Qed. (* General properties of <= and < *) Lemma lerr x : x <= x. Proof. exact: lerr. Qed. Lemma ltrr x : x < x = false. Proof. by rewrite ltr_def eqxx. Qed. Lemma ltrW x y : x < y -> x <= y. Proof. exact: ltrW. Qed. Hint Resolve lerr ltrr ltrW. Lemma ltr_neqAle x y : (x < y) = (x != y) && (x <= y). Proof. by rewrite ltr_def eq_sym. Qed. Lemma ler_eqVlt x y : (x <= y) = (x == y) || (x < y). Proof. by rewrite ltr_neqAle; case: eqP => // ->; rewrite lerr. Qed. Lemma lt0r x : (0 < x) = (x != 0) && (0 <= x). Proof. by rewrite ltr_def. Qed. Lemma le0r x : (0 <= x) = (x == 0) || (0 < x). Proof. exact: le0r. Qed. Lemma lt0r_neq0 (x : R) : 0 < x -> x != 0. Proof. by rewrite lt0r; case/andP. Qed. Lemma ltr0_neq0 (x : R) : 0 < x -> x != 0. Proof. by rewrite lt0r; case/andP. Qed. Lemma gtr_eqF x y : y < x -> x == y = false. Proof. by rewrite ltr_def; case/andP; move/negPf=> ->. Qed. Lemma ltr_eqF x y : x < y -> x == y = false. Proof. by move=> hyx; rewrite eq_sym gtr_eqF. Qed. Lemma pmulr_rgt0 x y : 0 < x -> (0 < x * y) = (0 < y). Proof. exact: pmulr_rgt0. Qed. Lemma pmulr_rge0 x y : 0 < x -> (0 <= x * y) = (0 <= y). Proof. by rewrite !le0r mulf_eq0; case: eqP => // [-> /negPf[] | _ /pmulr_rgt0->]. Qed. (* Integer comparisons and characteristic 0. *) Lemma ler01 : 0 <= 1 :> R. Proof. exact: ler01. Qed. Lemma ltr01 : 0 < 1 :> R. Proof. exact: ltr01. Qed. Lemma ler0n n : 0 <= n%:R :> R. Proof. by rewrite -nnegrE rpred_nat. Qed. Hint Resolve ler01 ltr01 ler0n. Lemma ltr0Sn n : 0 < n.+1%:R :> R. Proof. by elim: n => // n; apply: addr_gt0. Qed. Lemma ltr0n n : (0 < n%:R :> R) = (0 < n)%N. Proof. by case: n => //= n; apply: ltr0Sn. Qed. Hint Resolve ltr0Sn. Lemma pnatr_eq0 n : (n%:R == 0 :> R) = (n == 0)%N. Proof. by case: n => [|n]; rewrite ?mulr0n ?eqxx // gtr_eqF. Qed. Lemma char_num : [char R] =i pred0. Proof. by case=> // p /=; rewrite !inE pnatr_eq0 andbF. Qed. (* Properties of the norm. *) Lemma ger0_def x : (0 <= x) = (`|x| == x). Proof. exact: ger0_def. Qed. Lemma normr_idP {x} : reflect (`|x| = x) (0 <= x). Proof. by rewrite ger0_def; apply: eqP. Qed. Lemma ger0_norm x : 0 <= x -> `|x| = x. Proof. exact: normr_idP. Qed. Lemma normr0 : `|0| = 0 :> R. Proof. exact: ger0_norm. Qed. Lemma normr1 : `|1| = 1 :> R. Proof. exact: ger0_norm. Qed. Lemma normr_nat n : `|n%:R| = n%:R :> R. Proof. exact: ger0_norm. Qed. Lemma normrMn x n : `|x *+ n| = `|x| *+ n. Proof. by rewrite -mulr_natl normrM normr_nat mulr_natl. Qed. Lemma normr_prod I r (P : pred I) (F : I -> R) : `|\prod_(i <- r | P i) F i| = \prod_(i <- r | P i) `|F i|. Proof. exact: (big_morph norm normrM normr1). Qed. Lemma normrX n x : `|x ^+ n| = `|x| ^+ n. Proof. by rewrite -(card_ord n) -!prodr_const normr_prod. Qed. Lemma normr_unit : {homo (@norm R) : x / x \is a GRing.unit}. Proof. move=> x /= /unitrP [y [yx xy]]; apply/unitrP; exists `|y|. by rewrite -!normrM xy yx normr1. Qed. Lemma normrV : {in GRing.unit, {morph (@normr R) : x / x ^-1}}. Proof. move=> x ux; apply: (mulrI (normr_unit ux)). by rewrite -normrM !divrr ?normr1 ?normr_unit. Qed. Lemma normr0P {x} : reflect (`|x| = 0) (x == 0). Proof. by apply: (iffP eqP)=> [->|/normr0_eq0 //]; apply: normr0. Qed. Definition normr_eq0 x := sameP (`|x| =P 0) normr0P. Lemma normrN1 : `|-1| = 1 :> R. Proof. have: `|-1| ^+ 2 == 1 :> R by rewrite -normrX -signr_odd normr1. rewrite sqrf_eq1 => /orP[/eqP //|]; rewrite -ger0_def le0r oppr_eq0 oner_eq0. by move/(addr_gt0 ltr01); rewrite subrr ltrr. Qed. Lemma normrN x : `|- x| = `|x|. Proof. by rewrite -mulN1r normrM normrN1 mul1r. Qed. Lemma distrC x y : `|x - y| = `|y - x|. Proof. by rewrite -opprB normrN. Qed. Lemma ler0_def x : (x <= 0) = (`|x| == - x). Proof. by rewrite ler_def sub0r normrN. Qed. Lemma normr_id x : `|`|x| | = `|x|. Proof. have nz2: 2%:R != 0 :> R by rewrite pnatr_eq0. apply: (mulfI nz2); rewrite -{1}normr_nat -normrM mulr_natl mulr2n ger0_norm //. by rewrite -{2}normrN -normr0 -(subrr x) ler_norm_add. Qed. Lemma normr_ge0 x : 0 <= `|x|. Proof. by rewrite ger0_def normr_id. Qed. Hint Resolve normr_ge0. Lemma ler0_norm x : x <= 0 -> `|x| = - x. Proof. by move=> x_le0; rewrite -[r in _ = r]ger0_norm ?normrN ?oppr_ge0. Qed. Definition gtr0_norm x (hx : 0 < x) := ger0_norm (ltrW hx). Definition ltr0_norm x (hx : x < 0) := ler0_norm (ltrW hx). (* Comparision to 0 of a difference *) Lemma subr_ge0 x y : (0 <= y - x) = (x <= y). Proof. exact: subr_ge0. Qed. Lemma subr_gt0 x y : (0 < y - x) = (x < y). Proof. by rewrite !ltr_def subr_eq0 subr_ge0. Qed. Lemma subr_le0 x y : (y - x <= 0) = (y <= x). Proof. by rewrite -subr_ge0 opprB add0r subr_ge0. Qed. Lemma subr_lt0 x y : (y - x < 0) = (y < x). Proof. by rewrite -subr_gt0 opprB add0r subr_gt0. Qed. Definition subr_lte0 := (subr_le0, subr_lt0). Definition subr_gte0 := (subr_ge0, subr_gt0). Definition subr_cp0 := (subr_lte0, subr_gte0). (* Ordered ring properties. *) Lemma ler_asym : antisymmetric (<=%R : rel R). Proof. move=> x y; rewrite !ler_def distrC -opprB -addr_eq0 => /andP[/eqP->]. by rewrite -mulr2n -mulr_natl mulf_eq0 subr_eq0 pnatr_eq0 => /eqP. Qed. Lemma eqr_le x y : (x == y) = (x <= y <= x). Proof. by apply/eqP/idP=> [->|/ler_asym]; rewrite ?lerr. Qed. Lemma ltr_trans : transitive (@ltr R). Proof. move=> y x z le_xy le_yz. by rewrite -subr_gt0 -(subrK y z) -addrA addr_gt0 ?subr_gt0. Qed. Lemma ler_lt_trans y x z : x <= y -> y < z -> x < z. Proof. by rewrite !ler_eqVlt => /orP[/eqP -> //|/ltr_trans]; apply. Qed. Lemma ltr_le_trans y x z : x < y -> y <= z -> x < z. Proof. by rewrite !ler_eqVlt => lxy /orP[/eqP <- //|/(ltr_trans lxy)]. Qed. Lemma ler_trans : transitive (@ler R). Proof. move=> y x z; rewrite !ler_eqVlt => /orP [/eqP -> //|lxy]. by move=> /orP [/eqP <-|/(ltr_trans lxy) ->]; rewrite ?lxy orbT. Qed. Definition lter01 := (ler01, ltr01). Definition lterr := (lerr, ltrr). Lemma addr_ge0 x y : 0 <= x -> 0 <= y -> 0 <= x + y. Proof. exact: addr_ge0. Qed. Lemma lerifP x y C : reflect (x <= y ?= iff C) (if C then x == y else x < y). Proof. rewrite /lerif ler_eqVlt; apply: (iffP idP)=> [|[]]. by case: C => [/eqP->|lxy]; rewrite ?eqxx // lxy ltr_eqF. by move=> /orP[/eqP->|lxy] <-; rewrite ?eqxx // ltr_eqF. Qed. Lemma ltr_asym x y : x < y < x = false. Proof. by apply/negP=> /andP [/ltr_trans hyx /hyx]; rewrite ltrr. Qed. Lemma ler_anti : antisymmetric (@ler R). Proof. by move=> x y; rewrite -eqr_le=> /eqP. Qed. Lemma ltr_le_asym x y : x < y <= x = false. Proof. by rewrite ltr_neqAle -andbA -eqr_le eq_sym; case: (_ == _). Qed. Lemma ler_lt_asym x y : x <= y < x = false. Proof. by rewrite andbC ltr_le_asym. Qed. Definition lter_anti := (=^~ eqr_le, ltr_asym, ltr_le_asym, ler_lt_asym). Lemma ltr_geF x y : x < y -> (y <= x = false). Proof. by move=> xy; apply: contraTF isT=> /(ltr_le_trans xy); rewrite ltrr. Qed. Lemma ler_gtF x y : x <= y -> (y < x = false). Proof. by apply: contraTF=> /ltr_geF->. Qed. Definition ltr_gtF x y hxy := ler_gtF (@ltrW x y hxy). (* Norm and order properties. *) Lemma normr_le0 x : (`|x| <= 0) = (x == 0). Proof. by rewrite -normr_eq0 eqr_le normr_ge0 andbT. Qed. Lemma normr_lt0 x : `|x| < 0 = false. Proof. by rewrite ltr_neqAle normr_le0 normr_eq0 andNb. Qed. Lemma normr_gt0 x : (`|x| > 0) = (x != 0). Proof. by rewrite ltr_def normr_eq0 normr_ge0 andbT. Qed. Definition normrE x := (normr_id, normr0, normr1, normrN1, normr_ge0, normr_eq0, normr_lt0, normr_le0, normr_gt0, normrN). End NumIntegralDomainTheory. Implicit Arguments ler01 [R]. Implicit Arguments ltr01 [R]. Implicit Arguments normr_idP [R x]. Implicit Arguments normr0P [R x]. Implicit Arguments lerifP [R x y C]. Hint Resolve @ler01 @ltr01 lerr ltrr ltrW ltr_eqF ltr0Sn ler0n normr_ge0. Section NumIntegralDomainMonotonyTheory. Variables R R' : numDomainType. Implicit Types m n p : nat. Implicit Types x y z : R. Implicit Types u v w : R'. Section AcrossTypes. Variable D D' : pred R. Variable (f : R -> R'). Lemma ltrW_homo : {homo f : x y / x < y} -> {homo f : x y / x <= y}. Proof. by move=> mf x y /=; rewrite ler_eqVlt => /orP[/eqP->|/mf/ltrW]. Qed. Lemma ltrW_nhomo : {homo f : x y /~ x < y} -> {homo f : x y /~ x <= y}. Proof. by move=> mf x y /=; rewrite ler_eqVlt => /orP[/eqP->|/mf/ltrW]. Qed. Lemma homo_inj_lt : injective f -> {homo f : x y / x <= y} -> {homo f : x y / x < y}. Proof. by move=> fI mf x y /= hxy; rewrite ltr_neqAle (inj_eq fI) mf (ltr_eqF, ltrW). Qed. Lemma nhomo_inj_lt : injective f -> {homo f : x y /~ x <= y} -> {homo f : x y /~ x < y}. Proof. by move=> fI mf x y /= hxy; rewrite ltr_neqAle (inj_eq fI) mf (gtr_eqF, ltrW). Qed. Lemma mono_inj : {mono f : x y / x <= y} -> injective f. Proof. by move=> mf x y /eqP; rewrite eqr_le !mf -eqr_le=> /eqP. Qed. Lemma nmono_inj : {mono f : x y /~ x <= y} -> injective f. Proof. by move=> mf x y /eqP; rewrite eqr_le !mf -eqr_le=> /eqP. Qed. Lemma lerW_mono : {mono f : x y / x <= y} -> {mono f : x y / x < y}. Proof. by move=> mf x y /=; rewrite !ltr_neqAle mf inj_eq //; apply: mono_inj. Qed. Lemma lerW_nmono : {mono f : x y /~ x <= y} -> {mono f : x y /~ x < y}. Proof. by move=> mf x y /=; rewrite !ltr_neqAle mf eq_sym inj_eq //; apply: nmono_inj. Qed. (* Monotony in D D' *) Lemma ltrW_homo_in : {in D & D', {homo f : x y / x < y}} -> {in D & D', {homo f : x y / x <= y}}. Proof. by move=> mf x y hx hy /=; rewrite ler_eqVlt => /orP[/eqP->|/mf/ltrW] //; apply. Qed. Lemma ltrW_nhomo_in : {in D & D', {homo f : x y /~ x < y}} -> {in D & D', {homo f : x y /~ x <= y}}. Proof. by move=> mf x y hx hy /=; rewrite ler_eqVlt => /orP[/eqP->|/mf/ltrW] //; apply. Qed. Lemma homo_inj_in_lt : {in D & D', injective f} -> {in D & D', {homo f : x y / x <= y}} -> {in D & D', {homo f : x y / x < y}}. Proof. move=> fI mf x y hx hy /= hxy; rewrite ltr_neqAle; apply/andP; split. by apply: contraTN hxy => /eqP /fI -> //; rewrite ltrr. by rewrite mf // (ltr_eqF, ltrW). Qed. Lemma nhomo_inj_in_lt : {in D & D', injective f} -> {in D & D', {homo f : x y /~ x <= y}} -> {in D & D', {homo f : x y /~ x < y}}. Proof. move=> fI mf x y hx hy /= hxy; rewrite ltr_neqAle; apply/andP; split. by apply: contraTN hxy => /eqP /fI -> //; rewrite ltrr. by rewrite mf // (gtr_eqF, ltrW). Qed. Lemma mono_inj_in : {in D &, {mono f : x y / x <= y}} -> {in D &, injective f}. Proof. by move=> mf x y hx hy /= /eqP; rewrite eqr_le !mf // -eqr_le => /eqP. Qed. Lemma nmono_inj_in : {in D &, {mono f : x y /~ x <= y}} -> {in D &, injective f}. Proof. by move=> mf x y hx hy /= /eqP; rewrite eqr_le !mf // -eqr_le => /eqP. Qed. Lemma lerW_mono_in : {in D &, {mono f : x y / x <= y}} -> {in D &, {mono f : x y / x < y}}. Proof. move=> mf x y hx hy /=; rewrite !ltr_neqAle mf // (@inj_in_eq _ _ D) //. exact: mono_inj_in. Qed. Lemma lerW_nmono_in : {in D &, {mono f : x y /~ x <= y}} -> {in D &, {mono f : x y /~ x < y}}. Proof. move=> mf x y hx hy /=; rewrite !ltr_neqAle mf // eq_sym (@inj_in_eq _ _ D) //. exact: nmono_inj_in. Qed. End AcrossTypes. Section NatToR. Variable (f : nat -> R). Lemma ltn_ltrW_homo : {homo f : m n / (m < n)%N >-> m < n} -> {homo f : m n / (m <= n)%N >-> m <= n}. Proof. by move=> mf m n /=; rewrite leq_eqVlt => /orP[/eqP->|/mf/ltrW //]. Qed. Lemma ltn_ltrW_nhomo : {homo f : m n / (n < m)%N >-> m < n} -> {homo f : m n / (n <= m)%N >-> m <= n}. Proof. by move=> mf m n /=; rewrite leq_eqVlt => /orP[/eqP->|/mf/ltrW//]. Qed. Lemma homo_inj_ltn_lt : injective f -> {homo f : m n / (m <= n)%N >-> m <= n} -> {homo f : m n / (m < n)%N >-> m < n}. Proof. move=> fI mf m n /= hmn. by rewrite ltr_neqAle (inj_eq fI) mf ?neq_ltn ?hmn ?orbT // ltnW. Qed. Lemma nhomo_inj_ltn_lt : injective f -> {homo f : m n / (n <= m)%N >-> m <= n} -> {homo f : m n / (n < m)%N >-> m < n}. Proof. move=> fI mf m n /= hmn; rewrite ltr_def (inj_eq fI). by rewrite mf ?neq_ltn ?hmn // ltnW. Qed. Lemma leq_mono_inj : {mono f : m n / (m <= n)%N >-> m <= n} -> injective f. Proof. by move=> mf m n /eqP; rewrite eqr_le !mf -eqn_leq => /eqP. Qed. Lemma leq_nmono_inj : {mono f : m n / (n <= m)%N >-> m <= n} -> injective f. Proof. by move=> mf m n /eqP; rewrite eqr_le !mf -eqn_leq => /eqP. Qed. Lemma leq_lerW_mono : {mono f : m n / (m <= n)%N >-> m <= n} -> {mono f : m n / (m < n)%N >-> m < n}. Proof. move=> mf m n /=; rewrite !ltr_neqAle mf inj_eq ?ltn_neqAle 1?eq_sym //. exact: leq_mono_inj. Qed. Lemma leq_lerW_nmono : {mono f : m n / (n <= m)%N >-> m <= n} -> {mono f : m n / (n < m)%N >-> m < n}. Proof. move=> mf x y /=; rewrite ltr_neqAle mf eq_sym inj_eq ?ltn_neqAle 1?eq_sym //. exact: leq_nmono_inj. Qed. Lemma homo_leq_mono : {homo f : m n / (m < n)%N >-> m < n} -> {mono f : m n / (m <= n)%N >-> m <= n}. Proof. move=> mf m n /=; case: leqP; last by move=> /mf /ltr_geF. by rewrite leq_eqVlt => /orP[/eqP->|/mf/ltrW //]; rewrite lerr. Qed. Lemma nhomo_leq_mono : {homo f : m n / (n < m)%N >-> m < n} -> {mono f : m n / (n <= m)%N >-> m <= n}. Proof. move=> mf m n /=; case: leqP; last by move=> /mf /ltr_geF. by rewrite leq_eqVlt => /orP[/eqP->|/mf/ltrW //]; rewrite lerr. Qed. End NatToR. End NumIntegralDomainMonotonyTheory. Section NumDomainOperationTheory. Variable R : numDomainType. Implicit Types x y z t : R. (* Comparision and opposite. *) Lemma ler_opp2 : {mono -%R : x y /~ x <= y :> R}. Proof. by move=> x y /=; rewrite -subr_ge0 opprK addrC subr_ge0. Qed. Hint Resolve ler_opp2. Lemma ltr_opp2 : {mono -%R : x y /~ x < y :> R}. Proof. by move=> x y /=; rewrite lerW_nmono. Qed. Hint Resolve ltr_opp2. Definition lter_opp2 := (ler_opp2, ltr_opp2). Lemma ler_oppr x y : (x <= - y) = (y <= - x). Proof. by rewrite (monoRL (@opprK _) ler_opp2). Qed. Lemma ltr_oppr x y : (x < - y) = (y < - x). Proof. by rewrite (monoRL (@opprK _) (lerW_nmono _)). Qed. Definition lter_oppr := (ler_oppr, ltr_oppr). Lemma ler_oppl x y : (- x <= y) = (- y <= x). Proof. by rewrite (monoLR (@opprK _) ler_opp2). Qed. Lemma ltr_oppl x y : (- x < y) = (- y < x). Proof. by rewrite (monoLR (@opprK _) (lerW_nmono _)). Qed. Definition lter_oppl := (ler_oppl, ltr_oppl). Lemma oppr_ge0 x : (0 <= - x) = (x <= 0). Proof. by rewrite lter_oppr oppr0. Qed. Lemma oppr_gt0 x : (0 < - x) = (x < 0). Proof. by rewrite lter_oppr oppr0. Qed. Definition oppr_gte0 := (oppr_ge0, oppr_gt0). Lemma oppr_le0 x : (- x <= 0) = (0 <= x). Proof. by rewrite lter_oppl oppr0. Qed. Lemma oppr_lt0 x : (- x < 0) = (0 < x). Proof. by rewrite lter_oppl oppr0. Qed. Definition oppr_lte0 := (oppr_le0, oppr_lt0). Definition oppr_cp0 := (oppr_gte0, oppr_lte0). Definition lter_oppE := (oppr_cp0, lter_opp2). Lemma ge0_cp x : 0 <= x -> (- x <= 0) * (- x <= x). Proof. by move=> hx; rewrite oppr_cp0 hx (@ler_trans _ 0) ?oppr_cp0. Qed. Lemma gt0_cp x : 0 < x -> (0 <= x) * (- x <= 0) * (- x <= x) * (- x < 0) * (- x < x). Proof. move=> hx; move: (ltrW hx) => hx'; rewrite !ge0_cp hx' //. by rewrite oppr_cp0 hx // (@ltr_trans _ 0) ?oppr_cp0. Qed. Lemma le0_cp x : x <= 0 -> (0 <= - x) * (x <= - x). Proof. by move=> hx; rewrite oppr_cp0 hx (@ler_trans _ 0) ?oppr_cp0. Qed. Lemma lt0_cp x : x < 0 -> (x <= 0) * (0 <= - x) * (x <= - x) * (0 < - x) * (x < - x). Proof. move=> hx; move: (ltrW hx) => hx'; rewrite !le0_cp // hx'. by rewrite oppr_cp0 hx // (@ltr_trans _ 0) ?oppr_cp0. Qed. (* Properties of the real subset. *) Lemma ger0_real x : 0 <= x -> x \is real. Proof. by rewrite realE => ->. Qed. Lemma ler0_real x : x <= 0 -> x \is real. Proof. by rewrite realE orbC => ->. Qed. Lemma gtr0_real x : 0 < x -> x \is real. Proof. by move=> /ltrW/ger0_real. Qed. Lemma ltr0_real x : x < 0 -> x \is real. Proof. by move=> /ltrW/ler0_real. Qed. Lemma real0 : 0 \is @real R. Proof. by rewrite ger0_real. Qed. Hint Resolve real0. Lemma real1 : 1 \is @real R. Proof. by rewrite ger0_real. Qed. Hint Resolve real1. Lemma realn n : n%:R \is @real R. Proof. by rewrite ger0_real. Qed. Lemma ler_leVge x y : x <= 0 -> y <= 0 -> (x <= y) || (y <= x). Proof. by rewrite -!oppr_ge0 => /(ger_leVge _) h /h; rewrite !ler_opp2. Qed. Lemma real_leVge x y : x \is real -> y \is real -> (x <= y) || (y <= x). Proof. rewrite !realE; have [x_ge0 _|x_nge0 /= x_le0] := boolP (_ <= _); last first. by have [/(ler_trans x_le0)->|_ /(ler_leVge x_le0) //] := boolP (0 <= _). by have [/(ger_leVge x_ge0)|_ /ler_trans->] := boolP (0 <= _); rewrite ?orbT. Qed. Lemma realB : {in real &, forall x y, x - y \is real}. Proof. exact: rpredB. Qed. Lemma realN : {mono (@GRing.opp R) : x / x \is real}. Proof. exact: rpredN. Qed. (* :TODO: add a rpredBC in ssralg *) Lemma realBC x y : (x - y \is real) = (y - x \is real). Proof. by rewrite -realN opprB. Qed. Lemma realD : {in real &, forall x y, x + y \is real}. Proof. exact: rpredD. Qed. (* dichotomy and trichotomy *) CoInductive ler_xor_gt (x y : R) : R -> R -> bool -> bool -> Set := | LerNotGt of x <= y : ler_xor_gt x y (y - x) (y - x) true false | GtrNotLe of y < x : ler_xor_gt x y (x - y) (x - y) false true. CoInductive ltr_xor_ge (x y : R) : R -> R -> bool -> bool -> Set := | LtrNotGe of x < y : ltr_xor_ge x y (y - x) (y - x) false true | GerNotLt of y <= x : ltr_xor_ge x y (x - y) (x - y) true false. CoInductive comparer x y : R -> R -> bool -> bool -> bool -> bool -> bool -> bool -> Set := | ComparerLt of x < y : comparer x y (y - x) (y - x) false false true false true false | ComparerGt of x > y : comparer x y (x - y) (x - y) false false false true false true | ComparerEq of x = y : comparer x y 0 0 true true true true false false. Lemma real_lerP x y : x \is real -> y \is real -> ler_xor_gt x y `|x - y| `|y - x| (x <= y) (y < x). Proof. move=> xR /(real_leVge xR); have [le_xy _|Nle_xy /= le_yx] := boolP (_ <= _). have [/(ler_lt_trans le_xy)|] := boolP (_ < _); first by rewrite ltrr. by rewrite ler0_norm ?ger0_norm ?subr_cp0 ?opprB //; constructor. have [lt_yx|] := boolP (_ < _). by rewrite ger0_norm ?ler0_norm ?subr_cp0 ?opprB //; constructor. by rewrite ltr_def le_yx andbT negbK=> /eqP exy; rewrite exy lerr in Nle_xy. Qed. Lemma real_ltrP x y : x \is real -> y \is real -> ltr_xor_ge x y `|x - y| `|y - x| (y <= x) (x < y). Proof. by move=> xR yR; case: real_lerP=> //; constructor. Qed. Lemma real_ltrNge : {in real &, forall x y, (x < y) = ~~ (y <= x)}. Proof. by move=> x y xR yR /=; case: real_lerP. Qed. Lemma real_lerNgt : {in real &, forall x y, (x <= y) = ~~ (y < x)}. Proof. by move=> x y xR yR /=; case: real_lerP. Qed. Lemma real_ltrgtP x y : x \is real -> y \is real -> comparer x y `|x - y| `|y - x| (y == x) (x == y) (x <= y) (y <= x) (x < y) (x > y). Proof. move=> xR yR; case: real_lerP => // [le_yx|lt_xy]; last first. by rewrite gtr_eqF // ltr_eqF // ler_gtF ?ltrW //; constructor. case: real_lerP => // [le_xy|lt_yx]; last first. by rewrite ltr_eqF // gtr_eqF //; constructor. have /eqP ->: x == y by rewrite eqr_le le_yx le_xy. by rewrite subrr eqxx; constructor. Qed. CoInductive ger0_xor_lt0 (x : R) : R -> bool -> bool -> Set := | Ger0NotLt0 of 0 <= x : ger0_xor_lt0 x x false true | Ltr0NotGe0 of x < 0 : ger0_xor_lt0 x (- x) true false. CoInductive ler0_xor_gt0 (x : R) : R -> bool -> bool -> Set := | Ler0NotLe0 of x <= 0 : ler0_xor_gt0 x (- x) false true | Gtr0NotGt0 of 0 < x : ler0_xor_gt0 x x true false. CoInductive comparer0 x : R -> bool -> bool -> bool -> bool -> bool -> bool -> Set := | ComparerGt0 of 0 < x : comparer0 x x false false false true false true | ComparerLt0 of x < 0 : comparer0 x (- x) false false true false true false | ComparerEq0 of x = 0 : comparer0 x 0 true true true true false false. Lemma real_ger0P x : x \is real -> ger0_xor_lt0 x `|x| (x < 0) (0 <= x). Proof. move=> hx; rewrite -{2}[x]subr0; case: real_ltrP; by rewrite ?subr0 ?sub0r //; constructor. Qed. Lemma real_ler0P x : x \is real -> ler0_xor_gt0 x `|x| (0 < x) (x <= 0). Proof. move=> hx; rewrite -{2}[x]subr0; case: real_ltrP; by rewrite ?subr0 ?sub0r //; constructor. Qed. Lemma real_ltrgt0P x : x \is real -> comparer0 x `|x| (0 == x) (x == 0) (x <= 0) (0 <= x) (x < 0) (x > 0). Proof. move=> hx; rewrite -{2}[x]subr0; case: real_ltrgtP; by rewrite ?subr0 ?sub0r //; constructor. Qed. Lemma real_neqr_lt : {in real &, forall x y, (x != y) = (x < y) || (y < x)}. Proof. by move=> * /=; case: real_ltrgtP. Qed. Lemma ler_sub_real x y : x <= y -> y - x \is real. Proof. by move=> le_xy; rewrite ger0_real // subr_ge0. Qed. Lemma ger_sub_real x y : x <= y -> x - y \is real. Proof. by move=> le_xy; rewrite ler0_real // subr_le0. Qed. Lemma ler_real y x : x <= y -> (x \is real) = (y \is real). Proof. by move=> le_xy; rewrite -(addrNK x y) rpredDl ?ler_sub_real. Qed. Lemma ger_real x y : y <= x -> (x \is real) = (y \is real). Proof. by move=> le_yx; rewrite -(ler_real le_yx). Qed. Lemma ger1_real x : 1 <= x -> x \is real. Proof. by move=> /ger_real->. Qed. Lemma ler1_real x : x <= 1 -> x \is real. Proof. by move=> /ler_real->. Qed. Lemma Nreal_leF x y : y \is real -> x \notin real -> (x <= y) = false. Proof. by move=> yR; apply: contraNF=> /ler_real->. Qed. Lemma Nreal_geF x y : y \is real -> x \notin real -> (y <= x) = false. Proof. by move=> yR; apply: contraNF=> /ger_real->. Qed. Lemma Nreal_ltF x y : y \is real -> x \notin real -> (x < y) = false. Proof. by move=> yR xNR; rewrite ltr_def Nreal_leF ?andbF. Qed. Lemma Nreal_gtF x y : y \is real -> x \notin real -> (y < x) = false. Proof. by move=> yR xNR; rewrite ltr_def Nreal_geF ?andbF. Qed. (* real wlog *) Lemma real_wlog_ler P : (forall a b, P b a -> P a b) -> (forall a b, a <= b -> P a b) -> forall a b : R, a \is real -> b \is real -> P a b. Proof. move=> sP hP a b ha hb; wlog: a b ha hb / a <= b => [hwlog|]; last exact: hP. by case: (real_lerP ha hb)=> [/hP //|/ltrW hba]; apply: sP; apply: hP. Qed. Lemma real_wlog_ltr P : (forall a, P a a) -> (forall a b, (P b a -> P a b)) -> (forall a b, a < b -> P a b) -> forall a b : R, a \is real -> b \is real -> P a b. Proof. move=> rP sP hP; apply: real_wlog_ler=> // a b. by rewrite ler_eqVlt; case: (altP (_ =P _))=> [->|] //= _ lab; apply: hP. Qed. (* Monotony of addition *) Lemma ler_add2l x : {mono +%R x : y z / y <= z}. Proof. by move=> y z /=; rewrite -subr_ge0 opprD addrAC addNKr addrC subr_ge0. Qed. Lemma ler_add2r x : {mono +%R^~ x : y z / y <= z}. Proof. by move=> y z /=; rewrite ![_ + x]addrC ler_add2l. Qed. Lemma ltr_add2r z x y : (x + z < y + z) = (x < y). Proof. by rewrite (lerW_mono (ler_add2r _)). Qed. Lemma ltr_add2l z x y : (z + x < z + y) = (x < y). Proof. by rewrite (lerW_mono (ler_add2l _)). Qed. Definition ler_add2 := (ler_add2l, ler_add2r). Definition ltr_add2 := (ltr_add2l, ltr_add2r). Definition lter_add2 := (ler_add2, ltr_add2). (* Addition, substraction and transitivity *) Lemma ler_add x y z t : x <= y -> z <= t -> x + z <= y + t. Proof. by move=> lxy lzt; rewrite (@ler_trans _ (y + z)) ?lter_add2. Qed. Lemma ler_lt_add x y z t : x <= y -> z < t -> x + z < y + t. Proof. by move=> lxy lzt; rewrite (@ler_lt_trans _ (y + z)) ?lter_add2. Qed. Lemma ltr_le_add x y z t : x < y -> z <= t -> x + z < y + t. Proof. by move=> lxy lzt; rewrite (@ltr_le_trans _ (y + z)) ?lter_add2. Qed. Lemma ltr_add x y z t : x < y -> z < t -> x + z < y + t. Proof. by move=> lxy lzt; rewrite ltr_le_add // ltrW. Qed. Lemma ler_sub x y z t : x <= y -> t <= z -> x - z <= y - t. Proof. by move=> lxy ltz; rewrite ler_add // lter_opp2. Qed. Lemma ler_lt_sub x y z t : x <= y -> t < z -> x - z < y - t. Proof. by move=> lxy lzt; rewrite ler_lt_add // lter_opp2. Qed. Lemma ltr_le_sub x y z t : x < y -> t <= z -> x - z < y - t. Proof. by move=> lxy lzt; rewrite ltr_le_add // lter_opp2. Qed. Lemma ltr_sub x y z t : x < y -> t < z -> x - z < y - t. Proof. by move=> lxy lzt; rewrite ltr_add // lter_opp2. Qed. Lemma ler_subl_addr x y z : (x - y <= z) = (x <= z + y). Proof. by rewrite (monoLR (addrK _) (ler_add2r _)). Qed. Lemma ltr_subl_addr x y z : (x - y < z) = (x < z + y). Proof. by rewrite (monoLR (addrK _) (ltr_add2r _)). Qed. Lemma ler_subr_addr x y z : (x <= y - z) = (x + z <= y). Proof. by rewrite (monoLR (addrNK _) (ler_add2r _)). Qed. Lemma ltr_subr_addr x y z : (x < y - z) = (x + z < y). Proof. by rewrite (monoLR (addrNK _) (ltr_add2r _)). Qed. Definition ler_sub_addr := (ler_subl_addr, ler_subr_addr). Definition ltr_sub_addr := (ltr_subl_addr, ltr_subr_addr). Definition lter_sub_addr := (ler_sub_addr, ltr_sub_addr). Lemma ler_subl_addl x y z : (x - y <= z) = (x <= y + z). Proof. by rewrite lter_sub_addr addrC. Qed. Lemma ltr_subl_addl x y z : (x - y < z) = (x < y + z). Proof. by rewrite lter_sub_addr addrC. Qed. Lemma ler_subr_addl x y z : (x <= y - z) = (z + x <= y). Proof. by rewrite lter_sub_addr addrC. Qed. Lemma ltr_subr_addl x y z : (x < y - z) = (z + x < y). Proof. by rewrite lter_sub_addr addrC. Qed. Definition ler_sub_addl := (ler_subl_addl, ler_subr_addl). Definition ltr_sub_addl := (ltr_subl_addl, ltr_subr_addl). Definition lter_sub_addl := (ler_sub_addl, ltr_sub_addl). Lemma ler_addl x y : (x <= x + y) = (0 <= y). Proof. by rewrite -{1}[x]addr0 lter_add2. Qed. Lemma ltr_addl x y : (x < x + y) = (0 < y). Proof. by rewrite -{1}[x]addr0 lter_add2. Qed. Lemma ler_addr x y : (x <= y + x) = (0 <= y). Proof. by rewrite -{1}[x]add0r lter_add2. Qed. Lemma ltr_addr x y : (x < y + x) = (0 < y). Proof. by rewrite -{1}[x]add0r lter_add2. Qed. Lemma ger_addl x y : (x + y <= x) = (y <= 0). Proof. by rewrite -{2}[x]addr0 lter_add2. Qed. Lemma gtr_addl x y : (x + y < x) = (y < 0). Proof. by rewrite -{2}[x]addr0 lter_add2. Qed. Lemma ger_addr x y : (y + x <= x) = (y <= 0). Proof. by rewrite -{2}[x]add0r lter_add2. Qed. Lemma gtr_addr x y : (y + x < x) = (y < 0). Proof. by rewrite -{2}[x]add0r lter_add2. Qed. Definition cpr_add := (ler_addl, ler_addr, ger_addl, ger_addl, ltr_addl, ltr_addr, gtr_addl, gtr_addl). (* Addition with left member knwon to be positive/negative *) Lemma ler_paddl y x z : 0 <= x -> y <= z -> y <= x + z. Proof. by move=> *; rewrite -[y]add0r ler_add. Qed. Lemma ltr_paddl y x z : 0 <= x -> y < z -> y < x + z. Proof. by move=> *; rewrite -[y]add0r ler_lt_add. Qed. Lemma ltr_spaddl y x z : 0 < x -> y <= z -> y < x + z. Proof. by move=> *; rewrite -[y]add0r ltr_le_add. Qed. Lemma ltr_spsaddl y x z : 0 < x -> y < z -> y < x + z. Proof. by move=> *; rewrite -[y]add0r ltr_add. Qed. Lemma ler_naddl y x z : x <= 0 -> y <= z -> x + y <= z. Proof. by move=> *; rewrite -[z]add0r ler_add. Qed. Lemma ltr_naddl y x z : x <= 0 -> y < z -> x + y < z. Proof. by move=> *; rewrite -[z]add0r ler_lt_add. Qed. Lemma ltr_snaddl y x z : x < 0 -> y <= z -> x + y < z. Proof. by move=> *; rewrite -[z]add0r ltr_le_add. Qed. Lemma ltr_snsaddl y x z : x < 0 -> y < z -> x + y < z. Proof. by move=> *; rewrite -[z]add0r ltr_add. Qed. (* Addition with right member we know positive/negative *) Lemma ler_paddr y x z : 0 <= x -> y <= z -> y <= z + x. Proof. by move=> *; rewrite [_ + x]addrC ler_paddl. Qed. Lemma ltr_paddr y x z : 0 <= x -> y < z -> y < z + x. Proof. by move=> *; rewrite [_ + x]addrC ltr_paddl. Qed. Lemma ltr_spaddr y x z : 0 < x -> y <= z -> y < z + x. Proof. by move=> *; rewrite [_ + x]addrC ltr_spaddl. Qed. Lemma ltr_spsaddr y x z : 0 < x -> y < z -> y < z + x. Proof. by move=> *; rewrite [_ + x]addrC ltr_spsaddl. Qed. Lemma ler_naddr y x z : x <= 0 -> y <= z -> y + x <= z. Proof. by move=> *; rewrite [_ + x]addrC ler_naddl. Qed. Lemma ltr_naddr y x z : x <= 0 -> y < z -> y + x < z. Proof. by move=> *; rewrite [_ + x]addrC ltr_naddl. Qed. Lemma ltr_snaddr y x z : x < 0 -> y <= z -> y + x < z. Proof. by move=> *; rewrite [_ + x]addrC ltr_snaddl. Qed. Lemma ltr_snsaddr y x z : x < 0 -> y < z -> y + x < z. Proof. by move=> *; rewrite [_ + x]addrC ltr_snsaddl. Qed. (* x and y have the same sign and their sum is null *) Lemma paddr_eq0 (x y : R) : 0 <= x -> 0 <= y -> (x + y == 0) = (x == 0) && (y == 0). Proof. rewrite le0r; case/orP=> [/eqP->|hx]; first by rewrite add0r eqxx. by rewrite (gtr_eqF hx) /= => hy; rewrite gtr_eqF // ltr_spaddl. Qed. Lemma naddr_eq0 (x y : R) : x <= 0 -> y <= 0 -> (x + y == 0) = (x == 0) && (y == 0). Proof. by move=> lex0 ley0; rewrite -oppr_eq0 opprD paddr_eq0 ?oppr_cp0 // !oppr_eq0. Qed. Lemma addr_ss_eq0 (x y : R) : (0 <= x) && (0 <= y) || (x <= 0) && (y <= 0) -> (x + y == 0) = (x == 0) && (y == 0). Proof. by case/orP=> /andP []; [apply: paddr_eq0 | apply: naddr_eq0]. Qed. (* big sum and ler *) Lemma sumr_ge0 I (r : seq I) (P : pred I) (F : I -> R) : (forall i, P i -> (0 <= F i)) -> 0 <= \sum_(i <- r | P i) (F i). Proof. exact: (big_ind _ _ (@ler_paddl 0)). Qed. Lemma ler_sum I (r : seq I) (P : pred I) (F G : I -> R) : (forall i, P i -> F i <= G i) -> \sum_(i <- r | P i) F i <= \sum_(i <- r | P i) G i. Proof. exact: (big_ind2 _ (lerr _) ler_add). Qed. Lemma psumr_eq0 (I : eqType) (r : seq I) (P : pred I) (F : I -> R) : (forall i, P i -> 0 <= F i) -> (\sum_(i <- r | P i) (F i) == 0) = (all (fun i => (P i) ==> (F i == 0)) r). Proof. elim: r=> [|a r ihr hr] /=; rewrite (big_nil, big_cons); first by rewrite eqxx. by case: ifP=> pa /=; rewrite ?paddr_eq0 ?ihr ?hr // sumr_ge0. Qed. (* :TODO: Cyril : See which form to keep *) Lemma psumr_eq0P (I : finType) (P : pred I) (F : I -> R) : (forall i, P i -> 0 <= F i) -> \sum_(i | P i) F i = 0 -> (forall i, P i -> F i = 0). Proof. move=> F_ge0 /eqP; rewrite psumr_eq0 // -big_all big_andE => /forallP hF i Pi. by move: (hF i); rewrite implyTb Pi /= => /eqP. Qed. (* mulr and ler/ltr *) Lemma ler_pmul2l x : 0 < x -> {mono *%R x : x y / x <= y}. Proof. by move=> x_gt0 y z /=; rewrite -subr_ge0 -mulrBr pmulr_rge0 // subr_ge0. Qed. Lemma ltr_pmul2l x : 0 < x -> {mono *%R x : x y / x < y}. Proof. by move=> x_gt0; apply: lerW_mono (ler_pmul2l _). Qed. Definition lter_pmul2l := (ler_pmul2l, ltr_pmul2l). Lemma ler_pmul2r x : 0 < x -> {mono *%R^~ x : x y / x <= y}. Proof. by move=> x_gt0 y z /=; rewrite ![_ * x]mulrC ler_pmul2l. Qed. Lemma ltr_pmul2r x : 0 < x -> {mono *%R^~ x : x y / x < y}. Proof. by move=> x_gt0; apply: lerW_mono (ler_pmul2r _). Qed. Definition lter_pmul2r := (ler_pmul2r, ltr_pmul2r). Lemma ler_nmul2l x : x < 0 -> {mono *%R x : x y /~ x <= y}. Proof. by move=> x_lt0 y z /=; rewrite -ler_opp2 -!mulNr ler_pmul2l ?oppr_gt0. Qed. Lemma ltr_nmul2l x : x < 0 -> {mono *%R x : x y /~ x < y}. Proof. by move=> x_lt0; apply: lerW_nmono (ler_nmul2l _). Qed. Definition lter_nmul2l := (ler_nmul2l, ltr_nmul2l). Lemma ler_nmul2r x : x < 0 -> {mono *%R^~ x : x y /~ x <= y}. Proof. by move=> x_lt0 y z /=; rewrite ![_ * x]mulrC ler_nmul2l. Qed. Lemma ltr_nmul2r x : x < 0 -> {mono *%R^~ x : x y /~ x < y}. Proof. by move=> x_lt0; apply: lerW_nmono (ler_nmul2r _). Qed. Definition lter_nmul2r := (ler_nmul2r, ltr_nmul2r). Lemma ler_wpmul2l x : 0 <= x -> {homo *%R x : y z / y <= z}. Proof. by rewrite le0r => /orP[/eqP-> y z | /ler_pmul2l/mono2W//]; rewrite !mul0r. Qed. Lemma ler_wpmul2r x : 0 <= x -> {homo *%R^~ x : y z / y <= z}. Proof. by move=> x_ge0 y z leyz; rewrite ![_ * x]mulrC ler_wpmul2l. Qed. Lemma ler_wnmul2l x : x <= 0 -> {homo *%R x : y z /~ y <= z}. Proof. by move=> x_le0 y z leyz; rewrite -![x * _]mulrNN ler_wpmul2l ?lter_oppE. Qed. Lemma ler_wnmul2r x : x <= 0 -> {homo *%R^~ x : y z /~ y <= z}. Proof. by move=> x_le0 y z leyz; rewrite -![_ * x]mulrNN ler_wpmul2r ?lter_oppE. Qed. (* Binary forms, for backchaining. *) Lemma ler_pmul x1 y1 x2 y2 : 0 <= x1 -> 0 <= x2 -> x1 <= y1 -> x2 <= y2 -> x1 * x2 <= y1 * y2. Proof. move=> x1ge0 x2ge0 le_xy1 le_xy2; have y1ge0 := ler_trans x1ge0 le_xy1. exact: ler_trans (ler_wpmul2r x2ge0 le_xy1) (ler_wpmul2l y1ge0 le_xy2). Qed. Lemma ltr_pmul x1 y1 x2 y2 : 0 <= x1 -> 0 <= x2 -> x1 < y1 -> x2 < y2 -> x1 * x2 < y1 * y2. Proof. move=> x1ge0 x2ge0 lt_xy1 lt_xy2; have y1gt0 := ler_lt_trans x1ge0 lt_xy1. by rewrite (ler_lt_trans (ler_wpmul2r x2ge0 (ltrW lt_xy1))) ?ltr_pmul2l. Qed. (* complement for x *+ n and <= or < *) Lemma ler_pmuln2r n : (0 < n)%N -> {mono (@GRing.natmul R)^~ n : x y / x <= y}. Proof. by case: n => // n _ x y /=; rewrite -mulr_natl -[y *+ _]mulr_natl ler_pmul2l. Qed. Lemma ltr_pmuln2r n : (0 < n)%N -> {mono (@GRing.natmul R)^~ n : x y / x < y}. Proof. by move/ler_pmuln2r/lerW_mono. Qed. Lemma pmulrnI n : (0 < n)%N -> injective ((@GRing.natmul R)^~ n). Proof. by move/ler_pmuln2r/mono_inj. Qed. Lemma eqr_pmuln2r n : (0 < n)%N -> {mono (@GRing.natmul R)^~ n : x y / x == y}. Proof. by move/pmulrnI/inj_eq. Qed. Lemma pmulrn_lgt0 x n : (0 < n)%N -> (0 < x *+ n) = (0 < x). Proof. by move=> n_gt0; rewrite -(mul0rn _ n) ltr_pmuln2r // mul0rn. Qed. Lemma pmulrn_llt0 x n : (0 < n)%N -> (x *+ n < 0) = (x < 0). Proof. by move=> n_gt0; rewrite -(mul0rn _ n) ltr_pmuln2r // mul0rn. Qed. Lemma pmulrn_lge0 x n : (0 < n)%N -> (0 <= x *+ n) = (0 <= x). Proof. by move=> n_gt0; rewrite -(mul0rn _ n) ler_pmuln2r // mul0rn. Qed. Lemma pmulrn_lle0 x n : (0 < n)%N -> (x *+ n <= 0) = (x <= 0). Proof. by move=> n_gt0; rewrite -(mul0rn _ n) ler_pmuln2r // mul0rn. Qed. Lemma ltr_wmuln2r x y n : x < y -> (x *+ n < y *+ n) = (0 < n)%N. Proof. by move=> ltxy; case: n=> // n; rewrite ltr_pmuln2r. Qed. Lemma ltr_wpmuln2r n : (0 < n)%N -> {homo (@GRing.natmul R)^~ n : x y / x < y}. Proof. by move=> n_gt0 x y /= / ltr_wmuln2r ->. Qed. Lemma ler_wmuln2r n : {homo (@GRing.natmul R)^~ n : x y / x <= y}. Proof. by move=> x y hxy /=; case: n=> // n; rewrite ler_pmuln2r. Qed. Lemma mulrn_wge0 x n : 0 <= x -> 0 <= x *+ n. Proof. by move=> /(ler_wmuln2r n); rewrite mul0rn. Qed. Lemma mulrn_wle0 x n : x <= 0 -> x *+ n <= 0. Proof. by move=> /(ler_wmuln2r n); rewrite mul0rn. Qed. Lemma ler_muln2r n x y : (x *+ n <= y *+ n) = ((n == 0%N) || (x <= y)). Proof. by case: n => [|n]; rewrite ?lerr ?eqxx // ler_pmuln2r. Qed. Lemma ltr_muln2r n x y : (x *+ n < y *+ n) = ((0 < n)%N && (x < y)). Proof. by case: n => [|n]; rewrite ?lerr ?eqxx // ltr_pmuln2r. Qed. Lemma eqr_muln2r n x y : (x *+ n == y *+ n) = (n == 0)%N || (x == y). Proof. by rewrite !eqr_le !ler_muln2r -orb_andr. Qed. (* More characteristic zero properties. *) Lemma mulrn_eq0 x n : (x *+ n == 0) = ((n == 0)%N || (x == 0)). Proof. by rewrite -mulr_natl mulf_eq0 pnatr_eq0. Qed. Lemma mulrIn x : x != 0 -> injective (GRing.natmul x). Proof. move=> x_neq0 m n; without loss /subnK <-: m n / (n <= m)%N. by move=> IH eq_xmn; case/orP: (leq_total m n) => /IH->. by move/eqP; rewrite mulrnDr -subr_eq0 addrK mulrn_eq0 => /predU1P[-> | /idPn]. Qed. Lemma ler_wpmuln2l x : 0 <= x -> {homo (@GRing.natmul R x) : m n / (m <= n)%N >-> m <= n}. Proof. by move=> xge0 m n /subnK <-; rewrite mulrnDr ler_paddl ?mulrn_wge0. Qed. Lemma ler_wnmuln2l x : x <= 0 -> {homo (@GRing.natmul R x) : m n / (n <= m)%N >-> m <= n}. Proof. by move=> xle0 m n hmn /=; rewrite -ler_opp2 -!mulNrn ler_wpmuln2l // oppr_cp0. Qed. Lemma mulrn_wgt0 x n : 0 < x -> 0 < x *+ n = (0 < n)%N. Proof. by case: n => // n hx; rewrite pmulrn_lgt0. Qed. Lemma mulrn_wlt0 x n : x < 0 -> x *+ n < 0 = (0 < n)%N. Proof. by case: n => // n hx; rewrite pmulrn_llt0. Qed. Lemma ler_pmuln2l x : 0 < x -> {mono (@GRing.natmul R x) : m n / (m <= n)%N >-> m <= n}. Proof. move=> x_gt0 m n /=; case: leqP => hmn; first by rewrite ler_wpmuln2l // ltrW. rewrite -(subnK (ltnW hmn)) mulrnDr ger_addr ltr_geF //. by rewrite mulrn_wgt0 // subn_gt0. Qed. Lemma ltr_pmuln2l x : 0 < x -> {mono (@GRing.natmul R x) : m n / (m < n)%N >-> m < n}. Proof. by move=> x_gt0; apply: leq_lerW_mono (ler_pmuln2l _). Qed. Lemma ler_nmuln2l x : x < 0 -> {mono (@GRing.natmul R x) : m n / (n <= m)%N >-> m <= n}. Proof. by move=> x_lt0 m n /=; rewrite -ler_opp2 -!mulNrn ler_pmuln2l // oppr_gt0. Qed. Lemma ltr_nmuln2l x : x < 0 -> {mono (@GRing.natmul R x) : m n / (n < m)%N >-> m < n}. Proof. by move=> x_lt0; apply: leq_lerW_nmono (ler_nmuln2l _). Qed. Lemma ler_nat m n : (m%:R <= n%:R :> R) = (m <= n)%N. Proof. by rewrite ler_pmuln2l. Qed. Lemma ltr_nat m n : (m%:R < n%:R :> R) = (m < n)%N. Proof. by rewrite ltr_pmuln2l. Qed. Lemma eqr_nat m n : (m%:R == n%:R :> R) = (m == n)%N. Proof. by rewrite (inj_eq (mulrIn _)) ?oner_eq0. Qed. Lemma pnatr_eq1 n : (n%:R == 1 :> R) = (n == 1)%N. Proof. exact: eqr_nat 1%N. Qed. Lemma lern0 n : (n%:R <= 0 :> R) = (n == 0%N). Proof. by rewrite -[0]/0%:R ler_nat leqn0. Qed. Lemma ltrn0 n : (n%:R < 0 :> R) = false. Proof. by rewrite -[0]/0%:R ltr_nat ltn0. Qed. Lemma ler1n n : 1 <= n%:R :> R = (1 <= n)%N. Proof. by rewrite -ler_nat. Qed. Lemma ltr1n n : 1 < n%:R :> R = (1 < n)%N. Proof. by rewrite -ltr_nat. Qed. Lemma lern1 n : n%:R <= 1 :> R = (n <= 1)%N. Proof. by rewrite -ler_nat. Qed. Lemma ltrn1 n : n%:R < 1 :> R = (n < 1)%N. Proof. by rewrite -ltr_nat. Qed. Lemma ltrN10 : -1 < 0 :> R. Proof. by rewrite oppr_lt0. Qed. Lemma lerN10 : -1 <= 0 :> R. Proof. by rewrite oppr_le0. Qed. Lemma ltr10 : 1 < 0 :> R = false. Proof. by rewrite ler_gtF. Qed. Lemma ler10 : 1 <= 0 :> R = false. Proof. by rewrite ltr_geF. Qed. Lemma ltr0N1 : 0 < -1 :> R = false. Proof. by rewrite ler_gtF // lerN10. Qed. Lemma ler0N1 : 0 <= -1 :> R = false. Proof. by rewrite ltr_geF // ltrN10. Qed. Lemma pmulrn_rgt0 x n : 0 < x -> 0 < x *+ n = (0 < n)%N. Proof. by move=> x_gt0; rewrite -(mulr0n x) ltr_pmuln2l. Qed. Lemma pmulrn_rlt0 x n : 0 < x -> x *+ n < 0 = false. Proof. by move=> x_gt0; rewrite -(mulr0n x) ltr_pmuln2l. Qed. Lemma pmulrn_rge0 x n : 0 < x -> 0 <= x *+ n. Proof. by move=> x_gt0; rewrite -(mulr0n x) ler_pmuln2l. Qed. Lemma pmulrn_rle0 x n : 0 < x -> x *+ n <= 0 = (n == 0)%N. Proof. by move=> x_gt0; rewrite -(mulr0n x) ler_pmuln2l ?leqn0. Qed. Lemma nmulrn_rgt0 x n : x < 0 -> 0 < x *+ n = false. Proof. by move=> x_lt0; rewrite -(mulr0n x) ltr_nmuln2l. Qed. Lemma nmulrn_rge0 x n : x < 0 -> 0 <= x *+ n = (n == 0)%N. Proof. by move=> x_lt0; rewrite -(mulr0n x) ler_nmuln2l ?leqn0. Qed. Lemma nmulrn_rle0 x n : x < 0 -> x *+ n <= 0. Proof. by move=> x_lt0; rewrite -(mulr0n x) ler_nmuln2l. Qed. (* (x * y) compared to 0 *) (* Remark : pmulr_rgt0 and pmulr_rge0 are defined above *) (* x positive and y right *) Lemma pmulr_rlt0 x y : 0 < x -> (x * y < 0) = (y < 0). Proof. by move=> x_gt0; rewrite -oppr_gt0 -mulrN pmulr_rgt0 // oppr_gt0. Qed. Lemma pmulr_rle0 x y : 0 < x -> (x * y <= 0) = (y <= 0). Proof. by move=> x_gt0; rewrite -oppr_ge0 -mulrN pmulr_rge0 // oppr_ge0. Qed. (* x positive and y left *) Lemma pmulr_lgt0 x y : 0 < x -> (0 < y * x) = (0 < y). Proof. by move=> x_gt0; rewrite mulrC pmulr_rgt0. Qed. Lemma pmulr_lge0 x y : 0 < x -> (0 <= y * x) = (0 <= y). Proof. by move=> x_gt0; rewrite mulrC pmulr_rge0. Qed. Lemma pmulr_llt0 x y : 0 < x -> (y * x < 0) = (y < 0). Proof. by move=> x_gt0; rewrite mulrC pmulr_rlt0. Qed. Lemma pmulr_lle0 x y : 0 < x -> (y * x <= 0) = (y <= 0). Proof. by move=> x_gt0; rewrite mulrC pmulr_rle0. Qed. (* x negative and y right *) Lemma nmulr_rgt0 x y : x < 0 -> (0 < x * y) = (y < 0). Proof. by move=> x_lt0; rewrite -mulrNN pmulr_rgt0 lter_oppE. Qed. Lemma nmulr_rge0 x y : x < 0 -> (0 <= x * y) = (y <= 0). Proof. by move=> x_lt0; rewrite -mulrNN pmulr_rge0 lter_oppE. Qed. Lemma nmulr_rlt0 x y : x < 0 -> (x * y < 0) = (0 < y). Proof. by move=> x_lt0; rewrite -mulrNN pmulr_rlt0 lter_oppE. Qed. Lemma nmulr_rle0 x y : x < 0 -> (x * y <= 0) = (0 <= y). Proof. by move=> x_lt0; rewrite -mulrNN pmulr_rle0 lter_oppE. Qed. (* x negative and y left *) Lemma nmulr_lgt0 x y : x < 0 -> (0 < y * x) = (y < 0). Proof. by move=> x_lt0; rewrite mulrC nmulr_rgt0. Qed. Lemma nmulr_lge0 x y : x < 0 -> (0 <= y * x) = (y <= 0). Proof. by move=> x_lt0; rewrite mulrC nmulr_rge0. Qed. Lemma nmulr_llt0 x y : x < 0 -> (y * x < 0) = (0 < y). Proof. by move=> x_lt0; rewrite mulrC nmulr_rlt0. Qed. Lemma nmulr_lle0 x y : x < 0 -> (y * x <= 0) = (0 <= y). Proof. by move=> x_lt0; rewrite mulrC nmulr_rle0. Qed. (* weak and symmetric lemmas *) Lemma mulr_ge0 x y : 0 <= x -> 0 <= y -> 0 <= x * y. Proof. by move=> x_ge0 y_ge0; rewrite -(mulr0 x) ler_wpmul2l. Qed. Lemma mulr_le0 x y : x <= 0 -> y <= 0 -> 0 <= x * y. Proof. by move=> x_le0 y_le0; rewrite -(mulr0 x) ler_wnmul2l. Qed. Lemma mulr_ge0_le0 x y : 0 <= x -> y <= 0 -> x * y <= 0. Proof. by move=> x_le0 y_le0; rewrite -(mulr0 x) ler_wpmul2l. Qed. Lemma mulr_le0_ge0 x y : x <= 0 -> 0 <= y -> x * y <= 0. Proof. by move=> x_le0 y_le0; rewrite -(mulr0 x) ler_wnmul2l. Qed. (* mulr_gt0 with only one case *) Lemma mulr_gt0 x y : 0 < x -> 0 < y -> 0 < x * y. Proof. by move=> x_gt0 y_gt0; rewrite pmulr_rgt0. Qed. (* Iterated products *) Lemma prodr_ge0 I r (P : pred I) (E : I -> R) : (forall i, P i -> 0 <= E i) -> 0 <= \prod_(i <- r | P i) E i. Proof. by move=> Ege0; rewrite -nnegrE rpred_prod. Qed. Lemma prodr_gt0 I r (P : pred I) (E : I -> R) : (forall i, P i -> 0 < E i) -> 0 < \prod_(i <- r | P i) E i. Proof. by move=> Ege0; rewrite -posrE rpred_prod. Qed. Lemma ler_prod I r (P : pred I) (E1 E2 : I -> R) : (forall i, P i -> 0 <= E1 i <= E2 i) -> \prod_(i <- r | P i) E1 i <= \prod_(i <- r | P i) E2 i. Proof. move=> leE12; elim/(big_load (fun x => 0 <= x)): _. elim/big_rec2: _ => // i x2 x1 /leE12/andP[le0Ei leEi12] [x1ge0 le_x12]. by rewrite mulr_ge0 // ler_pmul. Qed. Lemma ltr_prod (E1 E2 : nat -> R) (n m : nat) : (m < n)%N -> (forall i, (m <= i < n)%N -> 0 <= E1 i < E2 i) -> \prod_(m <= i < n) E1 i < \prod_(m <= i < n) E2 i. Proof. elim: n m => // n ihn m; rewrite ltnS leq_eqVlt; case/orP => [/eqP -> | ltnm hE]. by move/(_ n) => /andb_idr; rewrite !big_nat1 leqnn ltnSn /=; case/andP. rewrite big_nat_recr ?[X in _ < X]big_nat_recr ?(ltnW ltnm) //=. move/andb_idr: (hE n); rewrite leqnn ltnW //=; case/andP => h1n h12n. rewrite big_nat_cond [X in _ < X * _]big_nat_cond; apply: ltr_pmul => //=. - apply: prodr_ge0 => i; rewrite andbT; case/andP=> hm hn. by move/andb_idr: (hE i); rewrite hm /= ltnS ltnW //=; case/andP. rewrite -!big_nat_cond; apply: ihn => // i /andP [hm hn]; apply: hE. by rewrite hm ltnW. Qed. (* real of mul *) Lemma realMr x y : x != 0 -> x \is real -> (x * y \is real) = (y \is real). Proof. move=> x_neq0 xR; case: real_ltrgtP x_neq0 => // hx _; rewrite !realE. by rewrite nmulr_rge0 // nmulr_rle0 // orbC. by rewrite pmulr_rge0 // pmulr_rle0 // orbC. Qed. Lemma realrM x y : y != 0 -> y \is real -> (x * y \is real) = (x \is real). Proof. by move=> y_neq0 yR; rewrite mulrC realMr. Qed. Lemma realM : {in real &, forall x y, x * y \is real}. Proof. exact: rpredM. Qed. Lemma realrMn x n : (n != 0)%N -> (x *+ n \is real) = (x \is real). Proof. by move=> n_neq0; rewrite -mulr_natl realMr ?realn ?pnatr_eq0. Qed. (* ler/ltr and multiplication between a positive/negative *) Lemma ger_pmull x y : 0 < y -> (x * y <= y) = (x <= 1). Proof. by move=> hy; rewrite -{2}[y]mul1r ler_pmul2r. Qed. Lemma gtr_pmull x y : 0 < y -> (x * y < y) = (x < 1). Proof. by move=> hy; rewrite -{2}[y]mul1r ltr_pmul2r. Qed. Lemma ger_pmulr x y : 0 < y -> (y * x <= y) = (x <= 1). Proof. by move=> hy; rewrite -{2}[y]mulr1 ler_pmul2l. Qed. Lemma gtr_pmulr x y : 0 < y -> (y * x < y) = (x < 1). Proof. by move=> hy; rewrite -{2}[y]mulr1 ltr_pmul2l. Qed. Lemma ler_pmull x y : 0 < y -> (y <= x * y) = (1 <= x). Proof. by move=> hy; rewrite -{1}[y]mul1r ler_pmul2r. Qed. Lemma ltr_pmull x y : 0 < y -> (y < x * y) = (1 < x). Proof. by move=> hy; rewrite -{1}[y]mul1r ltr_pmul2r. Qed. Lemma ler_pmulr x y : 0 < y -> (y <= y * x) = (1 <= x). Proof. by move=> hy; rewrite -{1}[y]mulr1 ler_pmul2l. Qed. Lemma ltr_pmulr x y : 0 < y -> (y < y * x) = (1 < x). Proof. by move=> hy; rewrite -{1}[y]mulr1 ltr_pmul2l. Qed. Lemma ger_nmull x y : y < 0 -> (x * y <= y) = (1 <= x). Proof. by move=> hy; rewrite -{2}[y]mul1r ler_nmul2r. Qed. Lemma gtr_nmull x y : y < 0 -> (x * y < y) = (1 < x). Proof. by move=> hy; rewrite -{2}[y]mul1r ltr_nmul2r. Qed. Lemma ger_nmulr x y : y < 0 -> (y * x <= y) = (1 <= x). Proof. by move=> hy; rewrite -{2}[y]mulr1 ler_nmul2l. Qed. Lemma gtr_nmulr x y : y < 0 -> (y * x < y) = (1 < x). Proof. by move=> hy; rewrite -{2}[y]mulr1 ltr_nmul2l. Qed. Lemma ler_nmull x y : y < 0 -> (y <= x * y) = (x <= 1). Proof. by move=> hy; rewrite -{1}[y]mul1r ler_nmul2r. Qed. Lemma ltr_nmull x y : y < 0 -> (y < x * y) = (x < 1). Proof. by move=> hy; rewrite -{1}[y]mul1r ltr_nmul2r. Qed. Lemma ler_nmulr x y : y < 0 -> (y <= y * x) = (x <= 1). Proof. by move=> hy; rewrite -{1}[y]mulr1 ler_nmul2l. Qed. Lemma ltr_nmulr x y : y < 0 -> (y < y * x) = (x < 1). Proof. by move=> hy; rewrite -{1}[y]mulr1 ltr_nmul2l. Qed. (* ler/ltr and multiplication between a positive/negative and a exterior (1 <= _) or interior (0 <= _ <= 1) *) Lemma ler_pemull x y : 0 <= y -> 1 <= x -> y <= x * y. Proof. by move=> hy hx; rewrite -{1}[y]mul1r ler_wpmul2r. Qed. Lemma ler_nemull x y : y <= 0 -> 1 <= x -> x * y <= y. Proof. by move=> hy hx; rewrite -{2}[y]mul1r ler_wnmul2r. Qed. Lemma ler_pemulr x y : 0 <= y -> 1 <= x -> y <= y * x. Proof. by move=> hy hx; rewrite -{1}[y]mulr1 ler_wpmul2l. Qed. Lemma ler_nemulr x y : y <= 0 -> 1 <= x -> y * x <= y. Proof. by move=> hy hx; rewrite -{2}[y]mulr1 ler_wnmul2l. Qed. Lemma ler_pimull x y : 0 <= y -> x <= 1 -> x * y <= y. Proof. by move=> hy hx; rewrite -{2}[y]mul1r ler_wpmul2r. Qed. Lemma ler_nimull x y : y <= 0 -> x <= 1 -> y <= x * y. Proof. by move=> hy hx; rewrite -{1}[y]mul1r ler_wnmul2r. Qed. Lemma ler_pimulr x y : 0 <= y -> x <= 1 -> y * x <= y. Proof. by move=> hy hx; rewrite -{2}[y]mulr1 ler_wpmul2l. Qed. Lemma ler_nimulr x y : y <= 0 -> x <= 1 -> y <= y * x. Proof. by move=> hx hy; rewrite -{1}[y]mulr1 ler_wnmul2l. Qed. Lemma mulr_ile1 x y : 0 <= x -> 0 <= y -> x <= 1 -> y <= 1 -> x * y <= 1. Proof. by move=> *; rewrite (@ler_trans _ y) ?ler_pimull. Qed. Lemma mulr_ilt1 x y : 0 <= x -> 0 <= y -> x < 1 -> y < 1 -> x * y < 1. Proof. by move=> *; rewrite (@ler_lt_trans _ y) ?ler_pimull // ltrW. Qed. Definition mulr_ilte1 := (mulr_ile1, mulr_ilt1). Lemma mulr_ege1 x y : 1 <= x -> 1 <= y -> 1 <= x * y. Proof. by move=> le1x le1y; rewrite (@ler_trans _ y) ?ler_pemull // (ler_trans ler01). Qed. Lemma mulr_egt1 x y : 1 < x -> 1 < y -> 1 < x * y. Proof. by move=> le1x lt1y; rewrite (@ltr_trans _ y) // ltr_pmull // (ltr_trans ltr01). Qed. Definition mulr_egte1 := (mulr_ege1, mulr_egt1). Definition mulr_cp1 := (mulr_ilte1, mulr_egte1). (* ler and ^-1 *) Lemma invr_gt0 x : (0 < x^-1) = (0 < x). Proof. have [ux | nux] := boolP (x \is a GRing.unit); last by rewrite invr_out. by apply/idP/idP=> /ltr_pmul2r<-; rewrite mul0r (mulrV, mulVr) ?ltr01. Qed. Lemma invr_ge0 x : (0 <= x^-1) = (0 <= x). Proof. by rewrite !le0r invr_gt0 invr_eq0. Qed. Lemma invr_lt0 x : (x^-1 < 0) = (x < 0). Proof. by rewrite -oppr_cp0 -invrN invr_gt0 oppr_cp0. Qed. Lemma invr_le0 x : (x^-1 <= 0) = (x <= 0). Proof. by rewrite -oppr_cp0 -invrN invr_ge0 oppr_cp0. Qed. Definition invr_gte0 := (invr_ge0, invr_gt0). Definition invr_lte0 := (invr_le0, invr_lt0). Lemma divr_ge0 x y : 0 <= x -> 0 <= y -> 0 <= x / y. Proof. by move=> x_ge0 y_ge0; rewrite mulr_ge0 ?invr_ge0. Qed. Lemma divr_gt0 x y : 0 < x -> 0 < y -> 0 < x / y. Proof. by move=> x_gt0 y_gt0; rewrite pmulr_rgt0 ?invr_gt0. Qed. Lemma realV : {mono (@GRing.inv R) : x / x \is real}. Proof. exact: rpredV. Qed. (* ler and exprn *) Lemma exprn_ge0 n x : 0 <= x -> 0 <= x ^+ n. Proof. by move=> xge0; rewrite -nnegrE rpredX. Qed. Lemma realX n : {in real, forall x, x ^+ n \is real}. Proof. exact: rpredX. Qed. Lemma exprn_gt0 n x : 0 < x -> 0 < x ^+ n. Proof. by rewrite !lt0r expf_eq0 => /andP[/negPf-> /exprn_ge0->]; rewrite andbF. Qed. Definition exprn_gte0 := (exprn_ge0, exprn_gt0). Lemma exprn_ile1 n x : 0 <= x -> x <= 1 -> x ^+ n <= 1. Proof. move=> xge0 xle1; elim: n=> [|*]; rewrite ?expr0 // exprS. by rewrite mulr_ile1 ?exprn_ge0. Qed. Lemma exprn_ilt1 n x : 0 <= x -> x < 1 -> x ^+ n < 1 = (n != 0%N). Proof. move=> xge0 xlt1. case: n; [by rewrite eqxx ltrr | elim=> [|n ihn]; first by rewrite expr1]. by rewrite exprS mulr_ilt1 // exprn_ge0. Qed. Definition exprn_ilte1 := (exprn_ile1, exprn_ilt1). Lemma exprn_ege1 n x : 1 <= x -> 1 <= x ^+ n. Proof. by move=> x_ge1; elim: n=> [|n ihn]; rewrite ?expr0 // exprS mulr_ege1. Qed. Lemma exprn_egt1 n x : 1 < x -> 1 < x ^+ n = (n != 0%N). Proof. move=> xgt1; case: n; first by rewrite eqxx ltrr. elim=> [|n ihn]; first by rewrite expr1. by rewrite exprS mulr_egt1 // exprn_ge0. Qed. Definition exprn_egte1 := (exprn_ege1, exprn_egt1). Definition exprn_cp1 := (exprn_ilte1, exprn_egte1). Lemma ler_iexpr x n : (0 < n)%N -> 0 <= x -> x <= 1 -> x ^+ n <= x. Proof. by case: n => n // *; rewrite exprS ler_pimulr // exprn_ile1. Qed. Lemma ltr_iexpr x n : 0 < x -> x < 1 -> (x ^+ n < x) = (1 < n)%N. Proof. case: n=> [|[|n]] //; first by rewrite expr0 => _ /ltr_gtF ->. by move=> x0 x1; rewrite exprS gtr_pmulr // ?exprn_ilt1 // ltrW. Qed. Definition lter_iexpr := (ler_iexpr, ltr_iexpr). Lemma ler_eexpr x n : (0 < n)%N -> 1 <= x -> x <= x ^+ n. Proof. case: n => // n _ x_ge1. by rewrite exprS ler_pemulr ?(ler_trans _ x_ge1) // exprn_ege1. Qed. Lemma ltr_eexpr x n : 1 < x -> (x < x ^+ n) = (1 < n)%N. Proof. move=> x_ge1; case: n=> [|[|n]] //; first by rewrite expr0 ltr_gtF. by rewrite exprS ltr_pmulr ?(ltr_trans _ x_ge1) ?exprn_egt1. Qed. Definition lter_eexpr := (ler_eexpr, ltr_eexpr). Definition lter_expr := (lter_iexpr, lter_eexpr). Lemma ler_wiexpn2l x : 0 <= x -> x <= 1 -> {homo (GRing.exp x) : m n / (n <= m)%N >-> m <= n}. Proof. move=> xge0 xle1 m n /= hmn. by rewrite -(subnK hmn) exprD ler_pimull ?(exprn_ge0, exprn_ile1). Qed. Lemma ler_weexpn2l x : 1 <= x -> {homo (GRing.exp x) : m n / (m <= n)%N >-> m <= n}. Proof. move=> xge1 m n /= hmn; rewrite -(subnK hmn) exprD. by rewrite ler_pemull ?(exprn_ge0, exprn_ege1) // (ler_trans _ xge1) ?ler01. Qed. Lemma ieexprn_weq1 x n : 0 <= x -> (x ^+ n == 1) = ((n == 0%N) || (x == 1)). Proof. move=> xle0; case: n => [|n]; first by rewrite expr0 eqxx. case: (@real_ltrgtP x 1); do ?by rewrite ?ger0_real. + by move=> x_lt1; rewrite ?ltr_eqF // exprn_ilt1. + by move=> x_lt1; rewrite ?gtr_eqF // exprn_egt1. by move->; rewrite expr1n eqxx. Qed. Lemma ieexprIn x : 0 < x -> x != 1 -> injective (GRing.exp x). Proof. move=> x_gt0 x_neq1 m n; without loss /subnK <-: m n / (n <= m)%N. by move=> IH eq_xmn; case/orP: (leq_total m n) => /IH->. case: {m}(m - n)%N => // m /eqP/idPn[]; rewrite -[x ^+ n]mul1r exprD. by rewrite (inj_eq (mulIf _)) ?ieexprn_weq1 ?ltrW // expf_neq0 ?gtr_eqF. Qed. Lemma ler_iexpn2l x : 0 < x -> x < 1 -> {mono (GRing.exp x) : m n / (n <= m)%N >-> m <= n}. Proof. move=> xgt0 xlt1; apply: (nhomo_leq_mono (nhomo_inj_ltn_lt _ _)); last first. by apply: ler_wiexpn2l; rewrite ltrW. by apply: ieexprIn; rewrite ?ltr_eqF ?ltr_cpable. Qed. Lemma ltr_iexpn2l x : 0 < x -> x < 1 -> {mono (GRing.exp x) : m n / (n < m)%N >-> m < n}. Proof. by move=> xgt0 xlt1; apply: (leq_lerW_nmono (ler_iexpn2l _ _)). Qed. Definition lter_iexpn2l := (ler_iexpn2l, ltr_iexpn2l). Lemma ler_eexpn2l x : 1 < x -> {mono (GRing.exp x) : m n / (m <= n)%N >-> m <= n}. Proof. move=> xgt1; apply: (homo_leq_mono (homo_inj_ltn_lt _ _)); last first. by apply: ler_weexpn2l; rewrite ltrW. by apply: ieexprIn; rewrite ?gtr_eqF ?gtr_cpable //; apply: ltr_trans xgt1. Qed. Lemma ltr_eexpn2l x : 1 < x -> {mono (GRing.exp x) : m n / (m < n)%N >-> m < n}. Proof. by move=> xgt1; apply: (leq_lerW_mono (ler_eexpn2l _)). Qed. Definition lter_eexpn2l := (ler_eexpn2l, ltr_eexpn2l). Lemma ltr_expn2r n x y : 0 <= x -> x < y -> x ^+ n < y ^+ n = (n != 0%N). Proof. move=> xge0 xlty; case: n; first by rewrite ltrr. elim=> [|n IHn]; rewrite ?[_ ^+ _.+2]exprS //. rewrite (@ler_lt_trans _ (x * y ^+ n.+1)) ?ler_wpmul2l ?ltr_pmul2r ?IHn //. by rewrite ltrW // ihn. by rewrite exprn_gt0 // (ler_lt_trans xge0). Qed. Lemma ler_expn2r n : {in nneg & , {homo ((@GRing.exp R)^~ n) : x y / x <= y}}. Proof. move=> x y /= x0 y0 xy; elim: n => [|n IHn]; rewrite !(expr0, exprS) //. by rewrite (@ler_trans _ (x * y ^+ n)) ?ler_wpmul2l ?ler_wpmul2r ?exprn_ge0. Qed. Definition lter_expn2r := (ler_expn2r, ltr_expn2r). Lemma ltr_wpexpn2r n : (0 < n)%N -> {in nneg & , {homo ((@GRing.exp R)^~ n) : x y / x < y}}. Proof. by move=> ngt0 x y /= x0 y0 hxy; rewrite ltr_expn2r // -lt0n. Qed. Lemma ler_pexpn2r n : (0 < n)%N -> {in nneg & , {mono ((@GRing.exp R)^~ n) : x y / x <= y}}. Proof. case: n => // n _ x y; rewrite !qualifE /= => x_ge0 y_ge0. have [-> | nzx] := eqVneq x 0; first by rewrite exprS mul0r exprn_ge0. rewrite -subr_ge0 subrXX pmulr_lge0 ?subr_ge0 //= big_ord_recr /=. rewrite subnn expr0 mul1r /= ltr_spaddr // ?exprn_gt0 ?lt0r ?nzx //. by rewrite sumr_ge0 // => i _; rewrite mulr_ge0 ?exprn_ge0. Qed. Lemma ltr_pexpn2r n : (0 < n)%N -> {in nneg & , {mono ((@GRing.exp R)^~ n) : x y / x < y}}. Proof. by move=> n_gt0 x y x_ge0 y_ge0; rewrite !ltr_neqAle !eqr_le !ler_pexpn2r. Qed. Definition lter_pexpn2r := (ler_pexpn2r, ltr_pexpn2r). Lemma pexpIrn n : (0 < n)%N -> {in nneg &, injective ((@GRing.exp R)^~ n)}. Proof. by move=> n_gt0; apply: mono_inj_in (ler_pexpn2r _). Qed. (* expr and ler/ltr *) Lemma expr_le1 n x : (0 < n)%N -> 0 <= x -> (x ^+ n <= 1) = (x <= 1). Proof. by move=> ngt0 xge0; rewrite -{1}[1](expr1n _ n) ler_pexpn2r // [_ \in _]ler01. Qed. Lemma expr_lt1 n x : (0 < n)%N -> 0 <= x -> (x ^+ n < 1) = (x < 1). Proof. by move=> ngt0 xge0; rewrite -{1}[1](expr1n _ n) ltr_pexpn2r // [_ \in _]ler01. Qed. Definition expr_lte1 := (expr_le1, expr_lt1). Lemma expr_ge1 n x : (0 < n)%N -> 0 <= x -> (1 <= x ^+ n) = (1 <= x). Proof. by move=> ngt0 xge0; rewrite -{1}[1](expr1n _ n) ler_pexpn2r // [_ \in _]ler01. Qed. Lemma expr_gt1 n x : (0 < n)%N -> 0 <= x -> (1 < x ^+ n) = (1 < x). Proof. by move=> ngt0 xge0; rewrite -{1}[1](expr1n _ n) ltr_pexpn2r // [_ \in _]ler01. Qed. Definition expr_gte1 := (expr_ge1, expr_gt1). Lemma pexpr_eq1 x n : (0 < n)%N -> 0 <= x -> (x ^+ n == 1) = (x == 1). Proof. by move=> ngt0 xge0; rewrite !eqr_le expr_le1 // expr_ge1. Qed. Lemma pexprn_eq1 x n : 0 <= x -> (x ^+ n == 1) = (n == 0%N) || (x == 1). Proof. by case: n => [|n] xge0; rewrite ?eqxx // pexpr_eq1 ?gtn_eqF. Qed. Lemma eqr_expn2 n x y : (0 < n)%N -> 0 <= x -> 0 <= y -> (x ^+ n == y ^+ n) = (x == y). Proof. by move=> ngt0 xge0 yge0; rewrite (inj_in_eq (pexpIrn _)). Qed. Lemma sqrp_eq1 x : 0 <= x -> (x ^+ 2 == 1) = (x == 1). Proof. by move/pexpr_eq1->. Qed. Lemma sqrn_eq1 x : x <= 0 -> (x ^+ 2 == 1) = (x == -1). Proof. by rewrite -sqrrN -oppr_ge0 -eqr_oppLR => /sqrp_eq1. Qed. Lemma ler_sqr : {in nneg &, {mono (fun x => x ^+ 2) : x y / x <= y}}. Proof. exact: ler_pexpn2r. Qed. Lemma ltr_sqr : {in nneg &, {mono (fun x => x ^+ 2) : x y / x < y}}. Proof. exact: ltr_pexpn2r. Qed. Lemma ler_pinv : {in [pred x in GRing.unit | 0 < x] &, {mono (@GRing.inv R) : x y /~ x <= y}}. Proof. move=> x y /andP [ux hx] /andP [uy hy] /=. rewrite -(ler_pmul2l hx) -(ler_pmul2r hy). by rewrite !(divrr, mulrVK) ?unitf_gt0 // mul1r. Qed. Lemma ler_ninv : {in [pred x in GRing.unit | x < 0] &, {mono (@GRing.inv R) : x y /~ x <= y}}. Proof. move=> x y /andP [ux hx] /andP [uy hy] /=. rewrite -(ler_nmul2l hx) -(ler_nmul2r hy). by rewrite !(divrr, mulrVK) ?unitf_lt0 // mul1r. Qed. Lemma ltr_pinv : {in [pred x in GRing.unit | 0 < x] &, {mono (@GRing.inv R) : x y /~ x < y}}. Proof. exact: lerW_nmono_in ler_pinv. Qed. Lemma ltr_ninv : {in [pred x in GRing.unit | x < 0] &, {mono (@GRing.inv R) : x y /~ x < y}}. Proof. exact: lerW_nmono_in ler_ninv. Qed. Lemma invr_gt1 x : x \is a GRing.unit -> 0 < x -> (1 < x^-1) = (x < 1). Proof. by move=> Ux xgt0; rewrite -{1}[1]invr1 ltr_pinv ?inE ?unitr1 ?ltr01 ?Ux. Qed. Lemma invr_ge1 x : x \is a GRing.unit -> 0 < x -> (1 <= x^-1) = (x <= 1). Proof. by move=> Ux xgt0; rewrite -{1}[1]invr1 ler_pinv ?inE ?unitr1 ?ltr01 // Ux. Qed. Definition invr_gte1 := (invr_ge1, invr_gt1). Lemma invr_le1 x (ux : x \is a GRing.unit) (hx : 0 < x) : (x^-1 <= 1) = (1 <= x). Proof. by rewrite -invr_ge1 ?invr_gt0 ?unitrV // invrK. Qed. Lemma invr_lt1 x (ux : x \is a GRing.unit) (hx : 0 < x) : (x^-1 < 1) = (1 < x). Proof. by rewrite -invr_gt1 ?invr_gt0 ?unitrV // invrK. Qed. Definition invr_lte1 := (invr_le1, invr_lt1). Definition invr_cp1 := (invr_gte1, invr_lte1). (* norm *) Lemma real_ler_norm x : x \is real -> x <= `|x|. Proof. by case/real_ger0P=> hx //; rewrite (ler_trans (ltrW hx)) // oppr_ge0 ltrW. Qed. (* norm + add *) Lemma normr_real x : `|x| \is real. Proof. by rewrite ger0_real. Qed. Hint Resolve normr_real. Lemma ler_norm_sum I r (G : I -> R) (P : pred I): `|\sum_(i <- r | P i) G i| <= \sum_(i <- r | P i) `|G i|. Proof. elim/big_rec2: _ => [|i y x _]; first by rewrite normr0. by rewrite -(ler_add2l `|G i|); apply: ler_trans; apply: ler_norm_add. Qed. Lemma ler_norm_sub x y : `|x - y| <= `|x| + `|y|. Proof. by rewrite (ler_trans (ler_norm_add _ _)) ?normrN. Qed. Lemma ler_dist_add z x y : `|x - y| <= `|x - z| + `|z - y|. Proof. by rewrite (ler_trans _ (ler_norm_add _ _)) // addrA addrNK. Qed. Lemma ler_sub_norm_add x y : `|x| - `|y| <= `|x + y|. Proof. rewrite -{1}[x](addrK y) lter_sub_addl. by rewrite (ler_trans (ler_norm_add _ _)) // addrC normrN. Qed. Lemma ler_sub_dist x y : `|x| - `|y| <= `|x - y|. Proof. by rewrite -[`|y|]normrN ler_sub_norm_add. Qed. Lemma ler_dist_dist x y : `|`|x| - `|y| | <= `|x - y|. Proof. have [||_|_] // := @real_lerP `|x| `|y|; last by rewrite ler_sub_dist. by rewrite distrC ler_sub_dist. Qed. Lemma ler_dist_norm_add x y : `| `|x| - `|y| | <= `| x + y |. Proof. by rewrite -[y]opprK normrN ler_dist_dist. Qed. Lemma real_ler_norml x y : x \is real -> (`|x| <= y) = (- y <= x <= y). Proof. move=> xR; wlog x_ge0 : x xR / 0 <= x => [hwlog|]. move: (xR) => /(@real_leVge 0) /orP [|/hwlog->|hx] //. by rewrite -[x]opprK normrN ler_opp2 andbC ler_oppl hwlog ?realN ?oppr_ge0. rewrite ger0_norm //; have [le_xy|] := boolP (x <= y); last by rewrite andbF. by rewrite (ler_trans _ x_ge0) // oppr_le0 (ler_trans x_ge0). Qed. Lemma real_ler_normlP x y : x \is real -> reflect ((-x <= y) * (x <= y)) (`|x| <= y). Proof. by move=> Rx; rewrite real_ler_norml // ler_oppl; apply: (iffP andP) => [] []. Qed. Implicit Arguments real_ler_normlP [x y]. Lemma real_eqr_norml x y : x \is real -> (`|x| == y) = ((x == y) || (x == -y)) && (0 <= y). Proof. move=> Rx. apply/idP/idP=> [|/andP[/pred2P[]-> /ger0_norm/eqP]]; rewrite ?normrE //. case: real_ler0P => // hx; rewrite 1?eqr_oppLR => /eqP exy. by move: hx; rewrite exy ?oppr_le0 eqxx orbT //. by move: hx=> /ltrW; rewrite exy eqxx. Qed. Lemma real_eqr_norm2 x y : x \is real -> y \is real -> (`|x| == `|y|) = (x == y) || (x == -y). Proof. move=> Rx Ry; rewrite real_eqr_norml // normrE andbT. by case: real_ler0P; rewrite // opprK orbC. Qed. Lemma real_ltr_norml x y : x \is real -> (`|x| < y) = (- y < x < y). Proof. move=> Rx; wlog x_ge0 : x Rx / 0 <= x => [hwlog|]. move: (Rx) => /(@real_leVge 0) /orP [|/hwlog->|hx] //. by rewrite -[x]opprK normrN ltr_opp2 andbC ltr_oppl hwlog ?realN ?oppr_ge0. rewrite ger0_norm //; have [le_xy|] := boolP (x < y); last by rewrite andbF. by rewrite (ltr_le_trans _ x_ge0) // oppr_lt0 (ler_lt_trans x_ge0). Qed. Definition real_lter_norml := (real_ler_norml, real_ltr_norml). Lemma real_ltr_normlP x y : x \is real -> reflect ((-x < y) * (x < y)) (`|x| < y). Proof. move=> Rx; rewrite real_ltr_norml // ltr_oppl. by apply: (iffP (@andP _ _)); case. Qed. Implicit Arguments real_ltr_normlP [x y]. Lemma real_ler_normr x y : y \is real -> (x <= `|y|) = (x <= y) || (x <= - y). Proof. move=> Ry. have [xR|xNR] := boolP (x \is real); last by rewrite ?Nreal_leF ?realN. rewrite real_lerNgt ?real_ltr_norml // negb_and -?real_lerNgt ?realN //. by rewrite orbC ler_oppr. Qed. Lemma real_ltr_normr x y : y \is real -> (x < `|y|) = (x < y) || (x < - y). Proof. move=> Ry. have [xR|xNR] := boolP (x \is real); last by rewrite ?Nreal_ltF ?realN. rewrite real_ltrNge ?real_ler_norml // negb_and -?real_ltrNge ?realN //. by rewrite orbC ltr_oppr. Qed. Definition real_lter_normr := (real_ler_normr, real_ltr_normr). Lemma ler_nnorml x y : y < 0 -> `|x| <= y = false. Proof. by move=> y_lt0; rewrite ltr_geF // (ltr_le_trans y_lt0). Qed. Lemma ltr_nnorml x y : y <= 0 -> `|x| < y = false. Proof. by move=> y_le0; rewrite ler_gtF // (ler_trans y_le0). Qed. Definition lter_nnormr := (ler_nnorml, ltr_nnorml). Lemma real_ler_distl x y e : x - y \is real -> (`|x - y| <= e) = (y - e <= x <= y + e). Proof. by move=> Rxy; rewrite real_lter_norml // !lter_sub_addl. Qed. Lemma real_ltr_distl x y e : x - y \is real -> (`|x - y| < e) = (y - e < x < y + e). Proof. by move=> Rxy; rewrite real_lter_norml // !lter_sub_addl. Qed. Definition real_lter_distl := (real_ler_distl, real_ltr_distl). (* GG: pointless duplication }-( *) Lemma eqr_norm_id x : (`|x| == x) = (0 <= x). Proof. by rewrite ger0_def. Qed. Lemma eqr_normN x : (`|x| == - x) = (x <= 0). Proof. by rewrite ler0_def. Qed. Definition eqr_norm_idVN := =^~ (ger0_def, ler0_def). Lemma real_exprn_even_ge0 n x : x \is real -> ~~ odd n -> 0 <= x ^+ n. Proof. move=> xR even_n; have [/exprn_ge0 -> //|x_lt0] := real_ger0P xR. rewrite -[x]opprK -mulN1r exprMn -signr_odd (negPf even_n) expr0 mul1r. by rewrite exprn_ge0 ?oppr_ge0 ?ltrW. Qed. Lemma real_exprn_even_gt0 n x : x \is real -> ~~ odd n -> (0 < x ^+ n) = (n == 0)%N || (x != 0). Proof. move=> xR n_even; rewrite lt0r real_exprn_even_ge0 ?expf_eq0 //. by rewrite andbT negb_and lt0n negbK. Qed. Lemma real_exprn_even_le0 n x : x \is real -> ~~ odd n -> (x ^+ n <= 0) = (n != 0%N) && (x == 0). Proof. move=> xR n_even; rewrite !real_lerNgt ?rpred0 ?rpredX //. by rewrite real_exprn_even_gt0 // negb_or negbK. Qed. Lemma real_exprn_even_lt0 n x : x \is real -> ~~ odd n -> (x ^+ n < 0) = false. Proof. by move=> xR n_even; rewrite ler_gtF // real_exprn_even_ge0. Qed. Lemma real_exprn_odd_ge0 n x : x \is real -> odd n -> (0 <= x ^+ n) = (0 <= x). Proof. case/real_ger0P => [x_ge0|x_lt0] n_odd; first by rewrite exprn_ge0. apply: negbTE; rewrite ltr_geF //. case: n n_odd => // n /= n_even; rewrite exprS pmulr_llt0 //. by rewrite real_exprn_even_gt0 ?ler0_real ?ltrW // ltr_eqF ?orbT. Qed. Lemma real_exprn_odd_gt0 n x : x \is real -> odd n -> (0 < x ^+ n) = (0 < x). Proof. by move=> xR n_odd; rewrite !lt0r expf_eq0 real_exprn_odd_ge0; case: n n_odd. Qed. Lemma real_exprn_odd_le0 n x : x \is real -> odd n -> (x ^+ n <= 0) = (x <= 0). Proof. by move=> xR n_odd; rewrite !real_lerNgt ?rpred0 ?rpredX // real_exprn_odd_gt0. Qed. Lemma real_exprn_odd_lt0 n x : x \is real -> odd n -> (x ^+ n < 0) = (x < 0). Proof. by move=> xR n_odd; rewrite !real_ltrNge ?rpred0 ?rpredX // real_exprn_odd_ge0. Qed. (* GG: Could this be a better definition of "real" ? *) Lemma realEsqr x : (x \is real) = (0 <= x ^+ 2). Proof. by rewrite ger0_def normrX eqf_sqr -ger0_def -ler0_def. Qed. Lemma real_normK x : x \is real -> `|x| ^+ 2 = x ^+ 2. Proof. by move=> Rx; rewrite -normrX ger0_norm -?realEsqr. Qed. (* Binary sign ((-1) ^+ s). *) Lemma normr_sign s : `|(-1) ^+ s| = 1 :> R. Proof. by rewrite normrX normrN1 expr1n. Qed. Lemma normrMsign s x : `|(-1) ^+ s * x| = `|x|. Proof. by rewrite normrM normr_sign mul1r. Qed. Lemma signr_gt0 (b : bool) : (0 < (-1) ^+ b :> R) = ~~ b. Proof. by case: b; rewrite (ltr01, ltr0N1). Qed. Lemma signr_lt0 (b : bool) : ((-1) ^+ b < 0 :> R) = b. Proof. by case: b; rewrite // ?(ltrN10, ltr10). Qed. Lemma signr_ge0 (b : bool) : (0 <= (-1) ^+ b :> R) = ~~ b. Proof. by rewrite le0r signr_eq0 signr_gt0. Qed. Lemma signr_le0 (b : bool) : ((-1) ^+ b <= 0 :> R) = b. Proof. by rewrite ler_eqVlt signr_eq0 signr_lt0. Qed. (* This actually holds for char R != 2. *) Lemma signr_inj : injective (fun b : bool => (-1) ^+ b : R). Proof. exact: can_inj (fun x => 0 >= x) signr_le0. Qed. (* Ternary sign (sg). *) Lemma sgr_def x : sg x = (-1) ^+ (x < 0)%R *+ (x != 0). Proof. by rewrite /sg; do 2!case: ifP => //. Qed. Lemma neqr0_sign x : x != 0 -> (-1) ^+ (x < 0)%R = sgr x. Proof. by rewrite sgr_def => ->. Qed. Lemma gtr0_sg x : 0 < x -> sg x = 1. Proof. by move=> x_gt0; rewrite /sg gtr_eqF // ltr_gtF. Qed. Lemma ltr0_sg x : x < 0 -> sg x = -1. Proof. by move=> x_lt0; rewrite /sg x_lt0 ltr_eqF. Qed. Lemma sgr0 : sg 0 = 0 :> R. Proof. by rewrite /sgr eqxx. Qed. Lemma sgr1 : sg 1 = 1 :> R. Proof. by rewrite gtr0_sg // ltr01. Qed. Lemma sgrN1 : sg (-1) = -1 :> R. Proof. by rewrite ltr0_sg // ltrN10. Qed. Definition sgrE := (sgr0, sgr1, sgrN1). Lemma sqr_sg x : sg x ^+ 2 = (x != 0)%:R. Proof. by rewrite sgr_def exprMn_n sqrr_sign -mulnn mulnb andbb. Qed. Lemma mulr_sg_eq1 x y : (sg x * y == 1) = (x != 0) && (sg x == y). Proof. rewrite /sg eq_sym; case: ifP => _; first by rewrite mul0r oner_eq0. by case: ifP => _; rewrite ?mul1r // mulN1r eqr_oppLR. Qed. Lemma mulr_sg_eqN1 x y : (sg x * sg y == -1) = (x != 0) && (sg x == - sg y). Proof. move/sg: y => y; rewrite /sg eq_sym eqr_oppLR. case: ifP => _; first by rewrite mul0r oppr0 oner_eq0. by case: ifP => _; rewrite ?mul1r // mulN1r eqr_oppLR. Qed. Lemma sgr_eq0 x : (sg x == 0) = (x == 0). Proof. by rewrite -sqrf_eq0 sqr_sg pnatr_eq0; case: (x == 0). Qed. Lemma sgr_odd n x : x != 0 -> (sg x) ^+ n = (sg x) ^+ (odd n). Proof. by rewrite /sg; do 2!case: ifP => // _; rewrite ?expr1n ?signr_odd. Qed. Lemma sgrMn x n : sg (x *+ n) = (n != 0%N)%:R * sg x. Proof. case: n => [|n]; first by rewrite mulr0n sgr0 mul0r. by rewrite !sgr_def mulrn_eq0 mul1r pmulrn_llt0. Qed. Lemma sgr_nat n : sg n%:R = (n != 0%N)%:R :> R. Proof. by rewrite sgrMn sgr1 mulr1. Qed. Lemma sgr_id x : sg (sg x) = sg x. Proof. by rewrite !(fun_if sg) !sgrE. Qed. Lemma sgr_lt0 x : (sg x < 0) = (x < 0). Proof. rewrite /sg; case: eqP => [-> // | _]. by case: ifP => _; rewrite ?ltrN10 // ltr_gtF. Qed. Lemma sgr_le0 x : (sgr x <= 0) = (x <= 0). Proof. by rewrite !ler_eqVlt sgr_eq0 sgr_lt0. Qed. (* sign and norm *) Lemma realEsign x : x \is real -> x = (-1) ^+ (x < 0)%R * `|x|. Proof. by case/real_ger0P; rewrite (mul1r, mulN1r) ?opprK. Qed. Lemma realNEsign x : x \is real -> - x = (-1) ^+ (0 < x)%R * `|x|. Proof. by move=> Rx; rewrite -normrN -oppr_lt0 -realEsign ?rpredN. Qed. Lemma real_normrEsign (x : R) (xR : x \is real) : `|x| = (-1) ^+ (x < 0)%R * x. Proof. by rewrite {3}[x]realEsign // signrMK. Qed. (* GG: pointless duplication... *) Lemma real_mulr_sign_norm x : x \is real -> (-1) ^+ (x < 0)%R * `|x| = x. Proof. by move/realEsign. Qed. Lemma real_mulr_Nsign_norm x : x \is real -> (-1) ^+ (0 < x)%R * `|x| = - x. Proof. by move/realNEsign. Qed. Lemma realEsg x : x \is real -> x = sgr x * `|x|. Proof. move=> xR; have [-> | ] := eqVneq x 0; first by rewrite normr0 mulr0. by move=> /neqr0_sign <-; rewrite -realEsign. Qed. Lemma normr_sg x : `|sg x| = (x != 0)%:R. Proof. by rewrite sgr_def -mulr_natr normrMsign normr_nat. Qed. Lemma sgr_norm x : sg `|x| = (x != 0)%:R. Proof. by rewrite /sg ler_gtF ?normr_ge0 // normr_eq0 mulrb if_neg. Qed. (* lerif *) Lemma lerif_refl x C : reflect (x <= x ?= iff C) C. Proof. by apply: (iffP idP) => [-> | <-] //; split; rewrite ?eqxx. Qed. Lemma lerif_trans x1 x2 x3 C12 C23 : x1 <= x2 ?= iff C12 -> x2 <= x3 ?= iff C23 -> x1 <= x3 ?= iff C12 && C23. Proof. move=> ltx12 ltx23; apply/lerifP; rewrite -ltx12. case eqx12: (x1 == x2). by rewrite (eqP eqx12) ltr_neqAle !ltx23 andbT; case C23. by rewrite (@ltr_le_trans _ x2) ?ltx23 // ltr_neqAle eqx12 ltx12. Qed. Lemma lerif_le x y : x <= y -> x <= y ?= iff (x >= y). Proof. by move=> lexy; split=> //; rewrite eqr_le lexy. Qed. Lemma lerif_eq x y : x <= y -> x <= y ?= iff (x == y). Proof. by []. Qed. Lemma ger_lerif x y C : x <= y ?= iff C -> (y <= x) = C. Proof. by case=> le_xy; rewrite eqr_le le_xy. Qed. Lemma ltr_lerif x y C : x <= y ?= iff C -> (x < y) = ~~ C. Proof. by move=> le_xy; rewrite ltr_neqAle !le_xy andbT. Qed. Lemma lerif_nat m n C : (m%:R <= n%:R ?= iff C :> R) = (m <= n ?= iff C)%N. Proof. by rewrite /lerif !ler_nat eqr_nat. Qed. Lemma mono_in_lerif (A : pred R) (f : R -> R) C : {in A &, {mono f : x y / x <= y}} -> {in A &, forall x y, (f x <= f y ?= iff C) = (x <= y ?= iff C)}. Proof. by move=> mf x y Ax Ay; rewrite /lerif mf ?(inj_in_eq (mono_inj_in mf)). Qed. Lemma mono_lerif (f : R -> R) C : {mono f : x y / x <= y} -> forall x y, (f x <= f y ?= iff C) = (x <= y ?= iff C). Proof. by move=> mf x y; rewrite /lerif mf (inj_eq (mono_inj _)). Qed. Lemma nmono_in_lerif (A : pred R) (f : R -> R) C : {in A &, {mono f : x y /~ x <= y}} -> {in A &, forall x y, (f x <= f y ?= iff C) = (y <= x ?= iff C)}. Proof. by move=> mf x y Ax Ay; rewrite /lerif eq_sym mf ?(inj_in_eq (nmono_inj_in mf)). Qed. Lemma nmono_lerif (f : R -> R) C : {mono f : x y /~ x <= y} -> forall x y, (f x <= f y ?= iff C) = (y <= x ?= iff C). Proof. by move=> mf x y; rewrite /lerif eq_sym mf ?(inj_eq (nmono_inj mf)). Qed. Lemma lerif_subLR x y z C : (x - y <= z ?= iff C) = (x <= z + y ?= iff C). Proof. by rewrite /lerif !eqr_le ler_subr_addr ler_subl_addr. Qed. Lemma lerif_subRL x y z C : (x <= y - z ?= iff C) = (x + z <= y ?= iff C). Proof. by rewrite -lerif_subLR opprK. Qed. Lemma lerif_add x1 y1 C1 x2 y2 C2 : x1 <= y1 ?= iff C1 -> x2 <= y2 ?= iff C2 -> x1 + x2 <= y1 + y2 ?= iff C1 && C2. Proof. rewrite -(mono_lerif _ (ler_add2r x2)) -(mono_lerif C2 (ler_add2l y1)). exact: lerif_trans. Qed. Lemma lerif_sum (I : finType) (P C : pred I) (E1 E2 : I -> R) : (forall i, P i -> E1 i <= E2 i ?= iff C i) -> \sum_(i | P i) E1 i <= \sum_(i | P i) E2 i ?= iff [forall (i | P i), C i]. Proof. move=> leE12; rewrite -big_andE. elim/big_rec3: _ => [|i Ci m2 m1 /leE12]; first by rewrite /lerif lerr eqxx. exact: lerif_add. Qed. Lemma lerif_0_sum (I : finType) (P C : pred I) (E : I -> R) : (forall i, P i -> 0 <= E i ?= iff C i) -> 0 <= \sum_(i | P i) E i ?= iff [forall (i | P i), C i]. Proof. by move/lerif_sum; rewrite big1_eq. Qed. Lemma real_lerif_norm x : x \is real -> x <= `|x| ?= iff (0 <= x). Proof. by move=> xR; rewrite ger0_def eq_sym; apply: lerif_eq; rewrite real_ler_norm. Qed. Lemma lerif_pmul x1 x2 y1 y2 C1 C2 : 0 <= x1 -> 0 <= x2 -> x1 <= y1 ?= iff C1 -> x2 <= y2 ?= iff C2 -> x1 * x2 <= y1 * y2 ?= iff (y1 * y2 == 0) || C1 && C2. Proof. move=> x1_ge0 x2_ge0 le_xy1 le_xy2; have [y_0 | ] := altP (_ =P 0). apply/lerifP; rewrite y_0 /= mulf_eq0 !eqr_le x1_ge0 x2_ge0 !andbT. move/eqP: y_0; rewrite mulf_eq0. by case/pred2P=> <-; rewrite (le_xy1, le_xy2) ?orbT. rewrite /= mulf_eq0 => /norP[y1nz y2nz]. have y1_gt0: 0 < y1 by rewrite ltr_def y1nz (ler_trans _ le_xy1). have [x2_0 | x2nz] := eqVneq x2 0. apply/lerifP; rewrite -le_xy2 x2_0 eq_sym (negPf y2nz) andbF mulr0. by rewrite mulr_gt0 // ltr_def y2nz -x2_0 le_xy2. have:= le_xy2; rewrite -(mono_lerif _ (ler_pmul2l y1_gt0)). by apply: lerif_trans; rewrite (mono_lerif _ (ler_pmul2r _)) // ltr_def x2nz. Qed. Lemma lerif_nmul x1 x2 y1 y2 C1 C2 : y1 <= 0 -> y2 <= 0 -> x1 <= y1 ?= iff C1 -> x2 <= y2 ?= iff C2 -> y1 * y2 <= x1 * x2 ?= iff (x1 * x2 == 0) || C1 && C2. Proof. rewrite -!oppr_ge0 -mulrNN -[x1 * x2]mulrNN => y1le0 y2le0 le_xy1 le_xy2. by apply: lerif_pmul => //; rewrite (nmono_lerif _ ler_opp2). Qed. Lemma lerif_pprod (I : finType) (P C : pred I) (E1 E2 : I -> R) : (forall i, P i -> 0 <= E1 i) -> (forall i, P i -> E1 i <= E2 i ?= iff C i) -> let pi E := \prod_(i | P i) E i in pi E1 <= pi E2 ?= iff (pi E2 == 0) || [forall (i | P i), C i]. Proof. move=> E1_ge0 leE12 /=; rewrite -big_andE; elim/(big_load (fun x => 0 <= x)): _. elim/big_rec3: _ => [|i Ci m2 m1 Pi [m1ge0 le_m12]]. by split=> //; apply/lerifP; rewrite orbT. have Ei_ge0 := E1_ge0 i Pi; split; first by rewrite mulr_ge0. congr (lerif _ _ _): (lerif_pmul Ei_ge0 m1ge0 (leE12 i Pi) le_m12). by rewrite mulf_eq0 -!orbA; congr (_ || _); rewrite !orb_andr orbA orbb. Qed. (* Mean inequalities. *) Lemma real_lerif_mean_square_scaled x y : x \is real -> y \is real -> x * y *+ 2 <= x ^+ 2 + y ^+ 2 ?= iff (x == y). Proof. move=> Rx Ry; rewrite -[_ *+ 2]add0r -lerif_subRL addrAC -sqrrB -subr_eq0. by rewrite -sqrf_eq0 eq_sym; apply: lerif_eq; rewrite -realEsqr rpredB. Qed. Lemma real_lerif_AGM2_scaled x y : x \is real -> y \is real -> x * y *+ 4 <= (x + y) ^+ 2 ?= iff (x == y). Proof. move=> Rx Ry; rewrite sqrrD addrAC (mulrnDr _ 2) -lerif_subLR addrK. exact: real_lerif_mean_square_scaled. Qed. Lemma lerif_AGM_scaled (I : finType) (A : pred I) (E : I -> R) : let n := #|A| in {in A, forall i, 0 <= E i *+ n} -> \prod_(i in A) (E i *+ n) <= (\sum_(i in A) E i) ^+ n ?= iff [forall i in A, forall j in A, E i == E j]. Proof. elim: {A}_.+1 {-2}A (ltnSn #|A|) => // m IHm A leAm in E * => n Ege0. apply/lerifP; case: ifPn => [/forall_inP Econstant | Enonconstant]. have [i /= Ai | A0] := pickP (mem A); last first. by rewrite /n eq_card0 // big_pred0. have /eqfun_inP E_i := Econstant i Ai; rewrite -(eq_bigr _ E_i) sumr_const. by rewrite exprMn_n prodrMn -(eq_bigr _ E_i) prodr_const. set mu := \sum_(i in A) _. pose En i := E i *+ n; pose cmp_mu s := [pred i | s * mu < s * En i]. have{Enonconstant} has_cmp_mu e (s := (-1) ^+ e): {i | i \in A & cmp_mu s i}. apply/sig2W/exists_inP; apply: contraR Enonconstant. rewrite negb_exists_in => /forall_inP mu_s_A. have n_gt0 i: i \in A -> (0 < n)%N by rewrite /n (cardD1 i) => ->. have{mu_s_A} mu_s_A i: i \in A -> s * En i <= s * mu. move=> Ai; rewrite real_lerNgt ?mu_s_A ?rpredMsign ?ger0_real ?Ege0 //. by rewrite -(pmulrn_lge0 _ (n_gt0 i Ai)) -sumrMnl sumr_ge0. have [_ /esym/eqfun_inP] := lerif_sum (fun i Ai => lerif_eq (mu_s_A i Ai)). rewrite sumr_const -/n -mulr_sumr sumrMnl -/mu mulrnAr eqxx => A_mu. apply/forall_inP=> i Ai; apply/eqfun_inP=> j Aj. by apply: (pmulrnI (n_gt0 i Ai)); apply: (can_inj (signrMK e)); rewrite !A_mu. have [[i Ai Ei_lt_mu] [j Aj Ej_gt_mu]] := (has_cmp_mu true, has_cmp_mu false). rewrite {cmp_mu has_cmp_mu}/= !mul1r !mulN1r ltr_opp2 in Ei_lt_mu Ej_gt_mu. pose A' := [predD1 A & i]; pose n' := #|A'|. have [Dn n_gt0]: n = n'.+1 /\ (n > 0)%N by rewrite /n (cardD1 i) Ai. have i'j: j != i by apply: contraTneq Ej_gt_mu => ->; rewrite ltr_gtF. have{i'j} A'j: j \in A' by rewrite !inE Aj i'j. have mu_gt0: 0 < mu := ler_lt_trans (Ege0 i Ai) Ei_lt_mu. rewrite (bigD1 i) // big_andbC (bigD1 j) //= mulrA; set pi := \prod_(k | _) _. have [-> | nz_pi] := eqVneq pi 0; first by rewrite !mulr0 exprn_gt0. have{nz_pi} pi_gt0: 0 < pi. by rewrite ltr_def nz_pi prodr_ge0 // => k /andP[/andP[_ /Ege0]]. rewrite -/(En i) -/(En j); pose E' := [eta En with j |-> En i + En j - mu]. have E'ge0 k: k \in A' -> E' k *+ n' >= 0. case/andP=> /= _ Ak; apply: mulrn_wge0; case: ifP => _; last exact: Ege0. by rewrite subr_ge0 ler_paddl ?Ege0 // ltrW. rewrite -/n Dn in leAm; have{leAm IHm E'ge0}: _ <= _ := IHm _ leAm _ E'ge0. have ->: \sum_(k in A') E' k = mu *+ n'. apply: (addrI mu); rewrite -mulrS -Dn -sumrMnl (bigD1 i Ai) big_andbC /=. rewrite !(bigD1 j A'j) /= addrCA eqxx !addrA subrK; congr (_ + _). by apply: eq_bigr => k /andP[_ /negPf->]. rewrite prodrMn exprMn_n -/n' ler_pmuln2r ?expn_gt0; last by case: (n'). have ->: \prod_(k in A') E' k = E' j * pi. by rewrite (bigD1 j) //=; congr *%R; apply: eq_bigr => k /andP[_ /negPf->]. rewrite -(ler_pmul2l mu_gt0) -exprS -Dn mulrA; apply: ltr_le_trans. rewrite ltr_pmul2r //= eqxx -addrA mulrDr mulrC -subr_gt0 addrAC -mulrBl. by rewrite -opprB mulNr addrC mulrC -mulrBr mulr_gt0 ?subr_gt0. Qed. (* Polynomial bound. *) Implicit Type p : {poly R}. Lemma poly_disk_bound p b : {ub | forall x, `|x| <= b -> `|p.[x]| <= ub}. Proof. exists (\sum_(j < size p) `|p`_j| * b ^+ j) => x le_x_b. rewrite horner_coef (ler_trans (ler_norm_sum _ _ _)) ?ler_sum // => j _. rewrite normrM normrX ler_wpmul2l ?ler_expn2r ?unfold_in ?normr_ge0 //. exact: ler_trans (normr_ge0 x) le_x_b. Qed. End NumDomainOperationTheory. Hint Resolve ler_opp2 ltr_opp2 real0 real1 normr_real. Implicit Arguments ler_sqr [[R] x y]. Implicit Arguments ltr_sqr [[R] x y]. Implicit Arguments signr_inj [[R] x1 x2]. Implicit Arguments real_ler_normlP [R x y]. Implicit Arguments real_ltr_normlP [R x y]. Implicit Arguments lerif_refl [R x C]. Implicit Arguments mono_in_lerif [R A f C]. Implicit Arguments nmono_in_lerif [R A f C]. Implicit Arguments mono_lerif [R f C]. Implicit Arguments nmono_lerif [R f C]. Section NumDomainMonotonyTheoryForReals. Variables (R R' : numDomainType) (D : pred R) (f : R -> R'). Implicit Types (m n p : nat) (x y z : R) (u v w : R'). Lemma real_mono : {homo f : x y / x < y} -> {in real &, {mono f : x y / x <= y}}. Proof. move=> mf x y xR yR /=; have [lt_xy | le_yx] := real_lerP xR yR. by rewrite ltrW_homo. by rewrite ltr_geF ?mf. Qed. Lemma real_nmono : {homo f : x y /~ x < y} -> {in real &, {mono f : x y /~ x <= y}}. Proof. move=> mf x y xR yR /=; have [lt_xy|le_yx] := real_ltrP xR yR. by rewrite ltr_geF ?mf. by rewrite ltrW_nhomo. Qed. (* GG: Domain should precede condition. *) Lemma real_mono_in : {in D &, {homo f : x y / x < y}} -> {in [pred x in D | x \is real] &, {mono f : x y / x <= y}}. Proof. move=> Dmf x y /andP[hx xR] /andP[hy yR] /=. have [lt_xy|le_yx] := real_lerP xR yR; first by rewrite (ltrW_homo_in Dmf). by rewrite ltr_geF ?Dmf. Qed. Lemma real_nmono_in : {in D &, {homo f : x y /~ x < y}} -> {in [pred x in D | x \is real] &, {mono f : x y /~ x <= y}}. Proof. move=> Dmf x y /andP[hx xR] /andP[hy yR] /=. have [lt_xy|le_yx] := real_ltrP xR yR; last by rewrite (ltrW_nhomo_in Dmf). by rewrite ltr_geF ?Dmf. Qed. End NumDomainMonotonyTheoryForReals. Section FinGroup. Import GroupScope. Variables (R : numDomainType) (gT : finGroupType). Implicit Types G : {group gT}. Lemma natrG_gt0 G : #|G|%:R > 0 :> R. Proof. by rewrite ltr0n cardG_gt0. Qed. Lemma natrG_neq0 G : #|G|%:R != 0 :> R. Proof. by rewrite gtr_eqF // natrG_gt0. Qed. Lemma natr_indexg_gt0 G B : #|G : B|%:R > 0 :> R. Proof. by rewrite ltr0n indexg_gt0. Qed. Lemma natr_indexg_neq0 G B : #|G : B|%:R != 0 :> R. Proof. by rewrite gtr_eqF // natr_indexg_gt0. Qed. End FinGroup. Section NumFieldTheory. Variable F : numFieldType. Implicit Types x y z t : F. Lemma unitf_gt0 x : 0 < x -> x \is a GRing.unit. Proof. by move=> hx; rewrite unitfE eq_sym ltr_eqF. Qed. Lemma unitf_lt0 x : x < 0 -> x \is a GRing.unit. Proof. by move=> hx; rewrite unitfE ltr_eqF. Qed. Lemma lef_pinv : {in pos &, {mono (@GRing.inv F) : x y /~ x <= y}}. Proof. by move=> x y hx hy /=; rewrite ler_pinv ?inE ?unitf_gt0. Qed. Lemma lef_ninv : {in neg &, {mono (@GRing.inv F) : x y /~ x <= y}}. Proof. by move=> x y hx hy /=; rewrite ler_ninv ?inE ?unitf_lt0. Qed. Lemma ltf_pinv : {in pos &, {mono (@GRing.inv F) : x y /~ x < y}}. Proof. exact: lerW_nmono_in lef_pinv. Qed. Lemma ltf_ninv: {in neg &, {mono (@GRing.inv F) : x y /~ x < y}}. Proof. exact: lerW_nmono_in lef_ninv. Qed. Definition ltef_pinv := (lef_pinv, ltf_pinv). Definition ltef_ninv := (lef_ninv, ltf_ninv). Lemma invf_gt1 x : 0 < x -> (1 < x^-1) = (x < 1). Proof. by move=> x_gt0; rewrite -{1}[1]invr1 ltf_pinv ?posrE ?ltr01. Qed. Lemma invf_ge1 x : 0 < x -> (1 <= x^-1) = (x <= 1). Proof. by move=> x_lt0; rewrite -{1}[1]invr1 lef_pinv ?posrE ?ltr01. Qed. Definition invf_gte1 := (invf_ge1, invf_gt1). Lemma invf_le1 x : 0 < x -> (x^-1 <= 1) = (1 <= x). Proof. by move=> x_gt0; rewrite -invf_ge1 ?invr_gt0 // invrK. Qed. Lemma invf_lt1 x : 0 < x -> (x^-1 < 1) = (1 < x). Proof. by move=> x_lt0; rewrite -invf_gt1 ?invr_gt0 // invrK. Qed. Definition invf_lte1 := (invf_le1, invf_lt1). Definition invf_cp1 := (invf_gte1, invf_lte1). (* These lemma are all combinations of mono(LR|RL) with ler_[pn]mul2[rl]. *) Lemma ler_pdivl_mulr z x y : 0 < z -> (x <= y / z) = (x * z <= y). Proof. by move=> z_gt0; rewrite -(@ler_pmul2r _ z) ?mulfVK ?gtr_eqF. Qed. Lemma ltr_pdivl_mulr z x y : 0 < z -> (x < y / z) = (x * z < y). Proof. by move=> z_gt0; rewrite -(@ltr_pmul2r _ z) ?mulfVK ?gtr_eqF. Qed. Definition lter_pdivl_mulr := (ler_pdivl_mulr, ltr_pdivl_mulr). Lemma ler_pdivr_mulr z x y : 0 < z -> (y / z <= x) = (y <= x * z). Proof. by move=> z_gt0; rewrite -(@ler_pmul2r _ z) ?mulfVK ?gtr_eqF. Qed. Lemma ltr_pdivr_mulr z x y : 0 < z -> (y / z < x) = (y < x * z). Proof. by move=> z_gt0; rewrite -(@ltr_pmul2r _ z) ?mulfVK ?gtr_eqF. Qed. Definition lter_pdivr_mulr := (ler_pdivr_mulr, ltr_pdivr_mulr). Lemma ler_pdivl_mull z x y : 0 < z -> (x <= z^-1 * y) = (z * x <= y). Proof. by move=> z_gt0; rewrite mulrC ler_pdivl_mulr ?[z * _]mulrC. Qed. Lemma ltr_pdivl_mull z x y : 0 < z -> (x < z^-1 * y) = (z * x < y). Proof. by move=> z_gt0; rewrite mulrC ltr_pdivl_mulr ?[z * _]mulrC. Qed. Definition lter_pdivl_mull := (ler_pdivl_mull, ltr_pdivl_mull). Lemma ler_pdivr_mull z x y : 0 < z -> (z^-1 * y <= x) = (y <= z * x). Proof. by move=> z_gt0; rewrite mulrC ler_pdivr_mulr ?[z * _]mulrC. Qed. Lemma ltr_pdivr_mull z x y : 0 < z -> (z^-1 * y < x) = (y < z * x). Proof. by move=> z_gt0; rewrite mulrC ltr_pdivr_mulr ?[z * _]mulrC. Qed. Definition lter_pdivr_mull := (ler_pdivr_mull, ltr_pdivr_mull). Lemma ler_ndivl_mulr z x y : z < 0 -> (x <= y / z) = (y <= x * z). Proof. by move=> z_lt0; rewrite -(@ler_nmul2r _ z) ?mulfVK ?ltr_eqF. Qed. Lemma ltr_ndivl_mulr z x y : z < 0 -> (x < y / z) = (y < x * z). Proof. by move=> z_lt0; rewrite -(@ltr_nmul2r _ z) ?mulfVK ?ltr_eqF. Qed. Definition lter_ndivl_mulr := (ler_ndivl_mulr, ltr_ndivl_mulr). Lemma ler_ndivr_mulr z x y : z < 0 -> (y / z <= x) = (x * z <= y). Proof. by move=> z_lt0; rewrite -(@ler_nmul2r _ z) ?mulfVK ?ltr_eqF. Qed. Lemma ltr_ndivr_mulr z x y : z < 0 -> (y / z < x) = (x * z < y). Proof. by move=> z_lt0; rewrite -(@ltr_nmul2r _ z) ?mulfVK ?ltr_eqF. Qed. Definition lter_ndivr_mulr := (ler_ndivr_mulr, ltr_ndivr_mulr). Lemma ler_ndivl_mull z x y : z < 0 -> (x <= z^-1 * y) = (y <= z * x). Proof. by move=> z_lt0; rewrite mulrC ler_ndivl_mulr ?[z * _]mulrC. Qed. Lemma ltr_ndivl_mull z x y : z < 0 -> (x < z^-1 * y) = (y < z * x). Proof. by move=> z_lt0; rewrite mulrC ltr_ndivl_mulr ?[z * _]mulrC. Qed. Definition lter_ndivl_mull := (ler_ndivl_mull, ltr_ndivl_mull). Lemma ler_ndivr_mull z x y : z < 0 -> (z^-1 * y <= x) = (z * x <= y). Proof. by move=> z_lt0; rewrite mulrC ler_ndivr_mulr ?[z * _]mulrC. Qed. Lemma ltr_ndivr_mull z x y : z < 0 -> (z^-1 * y < x) = (z * x < y). Proof. by move=> z_lt0; rewrite mulrC ltr_ndivr_mulr ?[z * _]mulrC. Qed. Definition lter_ndivr_mull := (ler_ndivr_mull, ltr_ndivr_mull). Lemma natf_div m d : (d %| m)%N -> (m %/ d)%:R = m%:R / d%:R :> F. Proof. by apply: char0_natf_div; apply: (@char_num F). Qed. Lemma normfV : {morph (@norm F) : x / x ^-1}. Proof. move=> x /=; have [/normrV //|Nux] := boolP (x \is a GRing.unit). by rewrite !invr_out // unitfE normr_eq0 -unitfE. Qed. Lemma normf_div : {morph (@norm F) : x y / x / y}. Proof. by move=> x y /=; rewrite normrM normfV. Qed. Lemma invr_sg x : (sg x)^-1 = sgr x. Proof. by rewrite !(fun_if GRing.inv) !(invr0, invrN, invr1). Qed. Lemma sgrV x : sgr x^-1 = sgr x. Proof. by rewrite /sgr invr_eq0 invr_lt0. Qed. (* Interval midpoint. *) Local Notation mid x y := ((x + y) / 2%:R). Lemma midf_le x y : x <= y -> (x <= mid x y) * (mid x y <= y). Proof. move=> lexy; rewrite ler_pdivl_mulr ?ler_pdivr_mulr ?ltr0Sn //. by rewrite !mulrDr !mulr1 ler_add2r ler_add2l. Qed. Lemma midf_lt x y : x < y -> (x < mid x y) * (mid x y < y). Proof. move=> ltxy; rewrite ltr_pdivl_mulr ?ltr_pdivr_mulr ?ltr0Sn //. by rewrite !mulrDr !mulr1 ltr_add2r ltr_add2l. Qed. Definition midf_lte := (midf_le, midf_lt). (* The AGM, unscaled but without the nth root. *) Lemma real_lerif_mean_square x y : x \is real -> y \is real -> x * y <= mid (x ^+ 2) (y ^+ 2) ?= iff (x == y). Proof. move=> Rx Ry; rewrite -(mono_lerif (ler_pmul2r (ltr_nat F 0 2))). by rewrite divfK ?pnatr_eq0 // mulr_natr; apply: real_lerif_mean_square_scaled. Qed. Lemma real_lerif_AGM2 x y : x \is real -> y \is real -> x * y <= mid x y ^+ 2 ?= iff (x == y). Proof. move=> Rx Ry; rewrite -(mono_lerif (ler_pmul2r (ltr_nat F 0 4))). rewrite mulr_natr (natrX F 2 2) -exprMn divfK ?pnatr_eq0 //. exact: real_lerif_AGM2_scaled. Qed. Lemma lerif_AGM (I : finType) (A : pred I) (E : I -> F) : let n := #|A| in let mu := (\sum_(i in A) E i) / n%:R in {in A, forall i, 0 <= E i} -> \prod_(i in A) E i <= mu ^+ n ?= iff [forall i in A, forall j in A, E i == E j]. Proof. move=> n mu Ege0; have [n0 | n_gt0] := posnP n. by rewrite n0 -big_andE !(big_pred0 _ _ _ _ (card0_eq n0)); apply/lerifP. pose E' i := E i / n%:R. have defE' i: E' i *+ n = E i by rewrite -mulr_natr divfK ?pnatr_eq0 -?lt0n. have /lerif_AGM_scaled (i): i \in A -> 0 <= E' i *+ n by rewrite defE' => /Ege0. rewrite -/n -mulr_suml (eq_bigr _ (in1W defE')); congr (_ <= _ ?= iff _). by do 2![apply: eq_forallb_in => ? _]; rewrite -(eqr_pmuln2r n_gt0) !defE'. Qed. Implicit Type p : {poly F}. Lemma Cauchy_root_bound p : p != 0 -> {b | forall x, root p x -> `|x| <= b}. Proof. move=> nz_p; set a := lead_coef p; set n := (size p).-1. have [q Dp]: {q | forall x, x != 0 -> p.[x] = (a - q.[x^-1] / x) * x ^+ n}. exists (- \poly_(i < n) p`_(n - i.+1)) => x nz_x. rewrite hornerN mulNr opprK horner_poly mulrDl !mulr_suml addrC. rewrite horner_coef polySpred // big_ord_recr (reindex_inj rev_ord_inj) /=. rewrite -/n -lead_coefE; congr (_ + _); apply: eq_bigr=> i _. by rewrite exprB ?unitfE // -exprVn mulrA mulrAC exprSr mulrA. have [b ub_q] := poly_disk_bound q 1; exists (b / `|a| + 1) => x px0. have b_ge0: 0 <= b by rewrite (ler_trans (normr_ge0 q.[1])) ?ub_q ?normr1. have{b_ge0} ba_ge0: 0 <= b / `|a| by rewrite divr_ge0 ?normr_ge0. rewrite real_lerNgt ?rpredD ?rpred1 ?ger0_real ?normr_ge0 //. apply: contraL px0 => lb_x; rewrite rootE. have x_ge1: 1 <= `|x| by rewrite (ler_trans _ (ltrW lb_x)) // ler_paddl. have nz_x: x != 0 by rewrite -normr_gt0 (ltr_le_trans ltr01). rewrite {}Dp // mulf_neq0 ?expf_neq0 // subr_eq0 eq_sym. have: (b / `|a|) < `|x| by rewrite (ltr_trans _ lb_x) // ltr_spaddr ?ltr01. apply: contraTneq => /(canRL (divfK nz_x))Dax. rewrite ltr_pdivr_mulr ?normr_gt0 ?lead_coef_eq0 // mulrC -normrM -{}Dax. by rewrite ler_gtF // ub_q // normfV invf_le1 ?normr_gt0. Qed. Import GroupScope. Lemma natf_indexg (gT : finGroupType) (G H : {group gT}) : H \subset G -> #|G : H|%:R = (#|G|%:R / #|H|%:R)%R :> F. Proof. by move=> sHG; rewrite -divgS // natf_div ?cardSg. Qed. End NumFieldTheory. Section RealDomainTheory. Hint Resolve lerr. Variable R : realDomainType. Implicit Types x y z t : R. Lemma num_real x : x \is real. Proof. exact: num_real. Qed. Hint Resolve num_real. Lemma ler_total : total (@le R). Proof. by move=> x y; apply: real_leVge. Qed. Lemma ltr_total x y : x != y -> (x < y) || (y < x). Proof. by rewrite !ltr_def [_ == y]eq_sym => ->; apply: ler_total. Qed. Lemma wlog_ler P : (forall a b, P b a -> P a b) -> (forall a b, a <= b -> P a b) -> forall a b : R, P a b. Proof. by move=> sP hP a b; apply: real_wlog_ler. Qed. Lemma wlog_ltr P : (forall a, P a a) -> (forall a b, (P b a -> P a b)) -> (forall a b, a < b -> P a b) -> forall a b : R, P a b. Proof. by move=> rP sP hP a b; apply: real_wlog_ltr. Qed. Lemma ltrNge x y : (x < y) = ~~ (y <= x). Proof. exact: real_ltrNge. Qed. Lemma lerNgt x y : (x <= y) = ~~ (y < x). Proof. exact: real_lerNgt. Qed. Lemma lerP x y : ler_xor_gt x y `|x - y| `|y - x| (x <= y) (y < x). Proof. exact: real_lerP. Qed. Lemma ltrP x y : ltr_xor_ge x y `|x - y| `|y - x| (y <= x) (x < y). Proof. exact: real_ltrP. Qed. Lemma ltrgtP x y : comparer x y `|x - y| `|y - x| (y == x) (x == y) (x <= y) (y <= x) (x < y) (x > y) . Proof. exact: real_ltrgtP. Qed. Lemma ger0P x : ger0_xor_lt0 x `|x| (x < 0) (0 <= x). Proof. exact: real_ger0P. Qed. Lemma ler0P x : ler0_xor_gt0 x `|x| (0 < x) (x <= 0). Proof. exact: real_ler0P. Qed. Lemma ltrgt0P x : comparer0 x `|x| (0 == x) (x == 0) (x <= 0) (0 <= x) (x < 0) (x > 0). Proof. exact: real_ltrgt0P. Qed. Lemma neqr_lt x y : (x != y) = (x < y) || (y < x). Proof. exact: real_neqr_lt. Qed. Lemma eqr_leLR x y z t : (x <= y -> z <= t) -> (y < x -> t < z) -> (x <= y) = (z <= t). Proof. by move=> *; apply/idP/idP; rewrite // !lerNgt; apply: contra. Qed. Lemma eqr_leRL x y z t : (x <= y -> z <= t) -> (y < x -> t < z) -> (z <= t) = (x <= y). Proof. by move=> *; symmetry; apply: eqr_leLR. Qed. Lemma eqr_ltLR x y z t : (x < y -> z < t) -> (y <= x -> t <= z) -> (x < y) = (z < t). Proof. by move=> *; rewrite !ltrNge; congr negb; apply: eqr_leLR. Qed. Lemma eqr_ltRL x y z t : (x < y -> z < t) -> (y <= x -> t <= z) -> (z < t) = (x < y). Proof. by move=> *; symmetry; apply: eqr_ltLR. Qed. (* sign *) Lemma mulr_lt0 x y : (x * y < 0) = [&& x != 0, y != 0 & (x < 0) (+) (y < 0)]. Proof. have [x_gt0|x_lt0|->] /= := ltrgt0P x; last by rewrite mul0r. by rewrite pmulr_rlt0 //; case: ltrgt0P. by rewrite nmulr_rlt0 //; case: ltrgt0P. Qed. Lemma neq0_mulr_lt0 x y : x != 0 -> y != 0 -> (x * y < 0) = (x < 0) (+) (y < 0). Proof. by move=> x_neq0 y_neq0; rewrite mulr_lt0 x_neq0 y_neq0. Qed. Lemma mulr_sign_lt0 (b : bool) x : ((-1) ^+ b * x < 0) = (x != 0) && (b (+) (x < 0)%R). Proof. by rewrite mulr_lt0 signr_lt0 signr_eq0. Qed. (* sign & norm*) Lemma mulr_sign_norm x : (-1) ^+ (x < 0)%R * `|x| = x. Proof. by rewrite real_mulr_sign_norm. Qed. Lemma mulr_Nsign_norm x : (-1) ^+ (0 < x)%R * `|x| = - x. Proof. by rewrite real_mulr_Nsign_norm. Qed. Lemma numEsign x : x = (-1) ^+ (x < 0)%R * `|x|. Proof. by rewrite -realEsign. Qed. Lemma numNEsign x : -x = (-1) ^+ (0 < x)%R * `|x|. Proof. by rewrite -realNEsign. Qed. Lemma normrEsign x : `|x| = (-1) ^+ (x < 0)%R * x. Proof. by rewrite -real_normrEsign. Qed. End RealDomainTheory. Hint Resolve num_real. Section RealDomainMonotony. Variables (R : realDomainType) (R' : numDomainType) (D : pred R) (f : R -> R'). Implicit Types (m n p : nat) (x y z : R) (u v w : R'). Hint Resolve (@num_real R). Lemma homo_mono : {homo f : x y / x < y} -> {mono f : x y / x <= y}. Proof. by move=> mf x y; apply: real_mono. Qed. Lemma nhomo_mono : {homo f : x y /~ x < y} -> {mono f : x y /~ x <= y}. Proof. by move=> mf x y; apply: real_nmono. Qed. Lemma homo_mono_in : {in D &, {homo f : x y / x < y}} -> {in D &, {mono f : x y / x <= y}}. Proof. by move=> mf x y Dx Dy; apply: (real_mono_in mf); rewrite ?inE ?Dx ?Dy /=. Qed. Lemma nhomo_mono_in : {in D &, {homo f : x y /~ x < y}} -> {in D &, {mono f : x y /~ x <= y}}. Proof. by move=> mf x y Dx Dy; apply: (real_nmono_in mf); rewrite ?inE ?Dx ?Dy /=. Qed. End RealDomainMonotony. Section RealDomainOperations. (* sgr section *) Variable R : realDomainType. Implicit Types x y z t : R. Hint Resolve (@num_real R). Lemma sgr_cp0 x : ((sg x == 1) = (0 < x)) * ((sg x == -1) = (x < 0)) * ((sg x == 0) = (x == 0)). Proof. rewrite -[1]/((-1) ^+ false) -signrN lt0r lerNgt sgr_def. case: (x =P 0) => [-> | _]; first by rewrite !(eq_sym 0) !signr_eq0 ltrr eqxx. by rewrite !(inj_eq signr_inj) eqb_id eqbF_neg signr_eq0 //. Qed. CoInductive sgr_val x : R -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> R -> Set := | SgrNull of x = 0 : sgr_val x 0 true true true true false false true false false true false false 0 | SgrPos of x > 0 : sgr_val x x false false true false false true false false true false false true 1 | SgrNeg of x < 0 : sgr_val x (- x) false true false false true false false true false false true false (-1). Lemma sgrP x : sgr_val x `|x| (0 == x) (x <= 0) (0 <= x) (x == 0) (x < 0) (0 < x) (0 == sg x) (-1 == sg x) (1 == sg x) (sg x == 0) (sg x == -1) (sg x == 1) (sg x). Proof. by rewrite ![_ == sg _]eq_sym !sgr_cp0 /sg; case: ltrgt0P; constructor. Qed. Lemma normrEsg x : `|x| = sg x * x. Proof. by case: sgrP; rewrite ?(mul0r, mul1r, mulN1r). Qed. Lemma numEsg x : x = sg x * `|x|. Proof. by case: sgrP; rewrite !(mul1r, mul0r, mulrNN). Qed. (* GG: duplicate! *) Lemma mulr_sg_norm x : sg x * `|x| = x. Proof. by rewrite -numEsg. Qed. Lemma sgrM x y : sg (x * y) = sg x * sg y. Proof. rewrite !sgr_def mulr_lt0 andbA mulrnAr mulrnAl -mulrnA mulnb -negb_or mulf_eq0. by case: (~~ _) => //; rewrite signr_addb. Qed. Lemma sgrN x : sg (- x) = - sg x. Proof. by rewrite -mulrN1 sgrM sgrN1 mulrN1. Qed. Lemma sgrX n x : sg (x ^+ n) = (sg x) ^+ n. Proof. by elim: n => [|n IHn]; rewrite ?sgr1 // !exprS sgrM IHn. Qed. Lemma sgr_smul x y : sg (sg x * y) = sg x * sg y. Proof. by rewrite sgrM sgr_id. Qed. Lemma sgr_gt0 x : (sg x > 0) = (x > 0). Proof. by rewrite -sgr_cp0 sgr_id sgr_cp0. Qed. Lemma sgr_ge0 x : (sgr x >= 0) = (x >= 0). Proof. by rewrite !lerNgt sgr_lt0. Qed. (* norm section *) Lemma ler_norm x : (x <= `|x|). Proof. exact: real_ler_norm. Qed. Lemma ler_norml x y : (`|x| <= y) = (- y <= x <= y). Proof. exact: real_ler_norml. Qed. Lemma ler_normlP x y : reflect ((- x <= y) * (x <= y)) (`|x| <= y). Proof. exact: real_ler_normlP. Qed. Implicit Arguments ler_normlP [x y]. Lemma eqr_norml x y : (`|x| == y) = ((x == y) || (x == -y)) && (0 <= y). Proof. exact: real_eqr_norml. Qed. Lemma eqr_norm2 x y : (`|x| == `|y|) = (x == y) || (x == -y). Proof. exact: real_eqr_norm2. Qed. Lemma ltr_norml x y : (`|x| < y) = (- y < x < y). Proof. exact: real_ltr_norml. Qed. Definition lter_norml := (ler_norml, ltr_norml). Lemma ltr_normlP x y : reflect ((-x < y) * (x < y)) (`|x| < y). Proof. exact: real_ltr_normlP. Qed. Implicit Arguments ltr_normlP [x y]. Lemma ler_normr x y : (x <= `|y|) = (x <= y) || (x <= - y). Proof. by rewrite lerNgt ltr_norml negb_and -!lerNgt orbC ler_oppr. Qed. Lemma ltr_normr x y : (x < `|y|) = (x < y) || (x < - y). Proof. by rewrite ltrNge ler_norml negb_and -!ltrNge orbC ltr_oppr. Qed. Definition lter_normr := (ler_normr, ltr_normr). Lemma ler_distl x y e : (`|x - y| <= e) = (y - e <= x <= y + e). Proof. by rewrite lter_norml !lter_sub_addl. Qed. Lemma ltr_distl x y e : (`|x - y| < e) = (y - e < x < y + e). Proof. by rewrite lter_norml !lter_sub_addl. Qed. Definition lter_distl := (ler_distl, ltr_distl). Lemma exprn_even_ge0 n x : ~~ odd n -> 0 <= x ^+ n. Proof. by move=> even_n; rewrite real_exprn_even_ge0 ?num_real. Qed. Lemma exprn_even_gt0 n x : ~~ odd n -> (0 < x ^+ n) = (n == 0)%N || (x != 0). Proof. by move=> even_n; rewrite real_exprn_even_gt0 ?num_real. Qed. Lemma exprn_even_le0 n x : ~~ odd n -> (x ^+ n <= 0) = (n != 0%N) && (x == 0). Proof. by move=> even_n; rewrite real_exprn_even_le0 ?num_real. Qed. Lemma exprn_even_lt0 n x : ~~ odd n -> (x ^+ n < 0) = false. Proof. by move=> even_n; rewrite real_exprn_even_lt0 ?num_real. Qed. Lemma exprn_odd_ge0 n x : odd n -> (0 <= x ^+ n) = (0 <= x). Proof. by move=> even_n; rewrite real_exprn_odd_ge0 ?num_real. Qed. Lemma exprn_odd_gt0 n x : odd n -> (0 < x ^+ n) = (0 < x). Proof. by move=> even_n; rewrite real_exprn_odd_gt0 ?num_real. Qed. Lemma exprn_odd_le0 n x : odd n -> (x ^+ n <= 0) = (x <= 0). Proof. by move=> even_n; rewrite real_exprn_odd_le0 ?num_real. Qed. Lemma exprn_odd_lt0 n x : odd n -> (x ^+ n < 0) = (x < 0). Proof. by move=> even_n; rewrite real_exprn_odd_lt0 ?num_real. Qed. (* Special lemmas for squares. *) Lemma sqr_ge0 x : 0 <= x ^+ 2. Proof. by rewrite exprn_even_ge0. Qed. Lemma sqr_norm_eq1 x : (x ^+ 2 == 1) = (`|x| == 1). Proof. by rewrite sqrf_eq1 eqr_norml ler01 andbT. Qed. Lemma lerif_mean_square_scaled x y : x * y *+ 2 <= x ^+ 2 + y ^+ 2 ?= iff (x == y). Proof. exact: real_lerif_mean_square_scaled. Qed. Lemma lerif_AGM2_scaled x y : x * y *+ 4 <= (x + y) ^+ 2 ?= iff (x == y). Proof. exact: real_lerif_AGM2_scaled. Qed. Section MinMax. (* GG: Many of the first lemmas hold unconditionally, and others hold for *) (* the real subset of a general domain. *) Lemma minrC : @commutative R R min. Proof. by move=> x y; rewrite /min; case: ltrgtP. Qed. Lemma minrr : @idempotent R min. Proof. by move=> x; rewrite /min if_same. Qed. Lemma minr_l x y : x <= y -> min x y = x. Proof. by rewrite /minr => ->. Qed. Lemma minr_r x y : y <= x -> min x y = y. Proof. by move/minr_l; rewrite minrC. Qed. Lemma maxrC : @commutative R R max. Proof. by move=> x y; rewrite /maxr; case: ltrgtP. Qed. Lemma maxrr : @idempotent R max. Proof. by move=> x; rewrite /max if_same. Qed. Lemma maxr_l x y : y <= x -> max x y = x. Proof. by move=> hxy; rewrite /max hxy. Qed. Lemma maxr_r x y : x <= y -> max x y = y. Proof. by move=> hxy; rewrite maxrC maxr_l. Qed. Lemma addr_min_max x y : min x y + max x y = x + y. Proof. case: (lerP x y)=> hxy; first by rewrite maxr_r ?minr_l. by rewrite maxr_l ?minr_r ?ltrW // addrC. Qed. Lemma addr_max_min x y : max x y + min x y = x + y. Proof. by rewrite addrC addr_min_max. Qed. Lemma minr_to_max x y : min x y = x + y - max x y. Proof. by rewrite -[x + y]addr_min_max addrK. Qed. Lemma maxr_to_min x y : max x y = x + y - min x y. Proof. by rewrite -[x + y]addr_max_min addrK. Qed. Lemma minrA x y z : min x (min y z) = min (min x y) z. Proof. rewrite /min; case: (lerP y z) => [hyz | /ltrW hyz]. by case: lerP => hxy; rewrite ?hyz // (@ler_trans _ y). case: lerP=> hxz; first by rewrite !(ler_trans hxz). case: (lerP x y)=> hxy; first by rewrite lerNgt hxz. by case: ltrgtP hyz. Qed. Lemma minrCA : @left_commutative R R min. Proof. by move=> x y z; rewrite !minrA [minr x y]minrC. Qed. Lemma minrAC : @right_commutative R R min. Proof. by move=> x y z; rewrite -!minrA [minr y z]minrC. Qed. CoInductive minr_spec x y : bool -> bool -> R -> Type := | Minr_r of x <= y : minr_spec x y true false x | Minr_l of y < x : minr_spec x y false true y. Lemma minrP x y : minr_spec x y (x <= y) (y < x) (min x y). Proof. case: lerP=> hxy; first by rewrite minr_l //; constructor. by rewrite minr_r 1?ltrW //; constructor. Qed. Lemma oppr_max x y : - max x y = min (- x) (- y). Proof. case: minrP; rewrite lter_opp2 => hxy; first by rewrite maxr_l. by rewrite maxr_r // ltrW. Qed. Lemma oppr_min x y : - min x y = max (- x) (- y). Proof. by rewrite -[maxr _ _]opprK oppr_max !opprK. Qed. Lemma maxrA x y z : max x (max y z) = max (max x y) z. Proof. by apply/eqP; rewrite -eqr_opp !oppr_max minrA. Qed. Lemma maxrCA : @left_commutative R R max. Proof. by move=> x y z; rewrite !maxrA [maxr x y]maxrC. Qed. Lemma maxrAC : @right_commutative R R max. Proof. by move=> x y z; rewrite -!maxrA [maxr y z]maxrC. Qed. CoInductive maxr_spec x y : bool -> bool -> R -> Type := | Maxr_r of y <= x : maxr_spec x y true false x | Maxr_l of x < y : maxr_spec x y false true y. Lemma maxrP x y : maxr_spec x y (y <= x) (x < y) (maxr x y). Proof. case: lerP => hxy; first by rewrite maxr_l //; constructor. by rewrite maxr_r 1?ltrW //; constructor. Qed. Lemma eqr_minl x y : (min x y == x) = (x <= y). Proof. by case: minrP=> hxy; rewrite ?eqxx // ltr_eqF. Qed. Lemma eqr_minr x y : (min x y == y) = (y <= x). Proof. by rewrite minrC eqr_minl. Qed. Lemma eqr_maxl x y : (max x y == x) = (y <= x). Proof. by case: maxrP=> hxy; rewrite ?eqxx // eq_sym ltr_eqF. Qed. Lemma eqr_maxr x y : (max x y == y) = (x <= y). Proof. by rewrite maxrC eqr_maxl. Qed. Lemma ler_minr x y z : (x <= min y z) = (x <= y) && (x <= z). Proof. case: minrP=> hyz. by case: lerP=> hxy //; rewrite (ler_trans _ hyz). by case: lerP=> hxz; rewrite andbC // (ler_trans hxz) // ltrW. Qed. Lemma ler_minl x y z : (min y z <= x) = (y <= x) || (z <= x). Proof. case: minrP => hyz. case: lerP => hyx //=; symmetry; apply: negbTE. by rewrite -ltrNge (@ltr_le_trans _ y). case: lerP => hzx; rewrite orbC //=; symmetry; apply: negbTE. by rewrite -ltrNge (@ltr_trans _ z). Qed. Lemma ler_maxr x y z : (x <= max y z) = (x <= y) || (x <= z). Proof. by rewrite -lter_opp2 oppr_max ler_minl !ler_opp2. Qed. Lemma ler_maxl x y z : (max y z <= x) = (y <= x) && (z <= x). Proof. by rewrite -lter_opp2 oppr_max ler_minr !ler_opp2. Qed. Lemma ltr_minr x y z : (x < min y z) = (x < y) && (x < z). Proof. by rewrite !ltrNge ler_minl negb_or. Qed. Lemma ltr_minl x y z : (min y z < x) = (y < x) || (z < x). Proof. by rewrite !ltrNge ler_minr negb_and. Qed. Lemma ltr_maxr x y z : (x < max y z) = (x < y) || (x < z). Proof. by rewrite !ltrNge ler_maxl negb_and. Qed. Lemma ltr_maxl x y z : (max y z < x) = (y < x) && (z < x). Proof. by rewrite !ltrNge ler_maxr negb_or. Qed. Definition lter_minr := (ler_minr, ltr_minr). Definition lter_minl := (ler_minl, ltr_minl). Definition lter_maxr := (ler_maxr, ltr_maxr). Definition lter_maxl := (ler_maxl, ltr_maxl). Lemma addr_minl : @left_distributive R R +%R min. Proof. move=> x y z; case: minrP=> hxy; first by rewrite minr_l // ler_add2r. by rewrite minr_r // ltrW // ltr_add2r. Qed. Lemma addr_minr : @right_distributive R R +%R min. Proof. move=> x y z; case: minrP=> hxy; first by rewrite minr_l // ler_add2l. by rewrite minr_r // ltrW // ltr_add2l. Qed. Lemma addr_maxl : @left_distributive R R +%R max. Proof. move=> x y z; rewrite -[_ + _]opprK opprD oppr_max. by rewrite addr_minl -!opprD oppr_min !opprK. Qed. Lemma addr_maxr : @right_distributive R R +%R max. Proof. move=> x y z; rewrite -[_ + _]opprK opprD oppr_max. by rewrite addr_minr -!opprD oppr_min !opprK. Qed. Lemma minrK x y : max (min x y) x = x. Proof. by case: minrP => hxy; rewrite ?maxrr ?maxr_r // ltrW. Qed. Lemma minKr x y : min y (max x y) = y. Proof. by case: maxrP => hxy; rewrite ?minrr ?minr_l. Qed. Lemma maxr_minl : @left_distributive R R max min. Proof. move=> x y z; case: minrP => hxy. by case: maxrP => hm; rewrite minr_l // ler_maxr (hxy, lerr) ?orbT. by case: maxrP => hyz; rewrite minr_r // ler_maxr (ltrW hxy, lerr) ?orbT. Qed. Lemma maxr_minr : @right_distributive R R max min. Proof. by move=> x y z; rewrite maxrC maxr_minl ![_ _ x]maxrC. Qed. Lemma minr_maxl : @left_distributive R R min max. Proof. move=> x y z; rewrite -[min _ _]opprK !oppr_min [- max x y]oppr_max. by rewrite maxr_minl !(oppr_max, oppr_min, opprK). Qed. Lemma minr_maxr : @right_distributive R R min max. Proof. by move=> x y z; rewrite minrC minr_maxl ![_ _ x]minrC. Qed. Lemma minr_pmulr x y z : 0 <= x -> x * min y z = min (x * y) (x * z). Proof. case: sgrP=> // hx _; first by rewrite hx !mul0r minrr. case: minrP=> hyz; first by rewrite minr_l // ler_pmul2l. by rewrite minr_r // ltrW // ltr_pmul2l. Qed. Lemma minr_nmulr x y z : x <= 0 -> x * min y z = max (x * y) (x * z). Proof. move=> hx; rewrite -[_ * _]opprK -mulNr minr_pmulr ?oppr_cp0 //. by rewrite oppr_min !mulNr !opprK. Qed. Lemma maxr_pmulr x y z : 0 <= x -> x * max y z = max (x * y) (x * z). Proof. move=> hx; rewrite -[_ * _]opprK -mulrN oppr_max minr_pmulr //. by rewrite oppr_min !mulrN !opprK. Qed. Lemma maxr_nmulr x y z : x <= 0 -> x * max y z = min (x * y) (x * z). Proof. move=> hx; rewrite -[_ * _]opprK -mulrN oppr_max minr_nmulr //. by rewrite oppr_max !mulrN !opprK. Qed. Lemma minr_pmull x y z : 0 <= x -> min y z * x = min (y * x) (z * x). Proof. by move=> *; rewrite mulrC minr_pmulr // ![_ * x]mulrC. Qed. Lemma minr_nmull x y z : x <= 0 -> min y z * x = max (y * x) (z * x). Proof. by move=> *; rewrite mulrC minr_nmulr // ![_ * x]mulrC. Qed. Lemma maxr_pmull x y z : 0 <= x -> max y z * x = max (y * x) (z * x). Proof. by move=> *; rewrite mulrC maxr_pmulr // ![_ * x]mulrC. Qed. Lemma maxr_nmull x y z : x <= 0 -> max y z * x = min (y * x) (z * x). Proof. by move=> *; rewrite mulrC maxr_nmulr // ![_ * x]mulrC. Qed. Lemma maxrN x : max x (- x) = `|x|. Proof. case: ger0P=> hx; first by rewrite maxr_l // ge0_cp //. by rewrite maxr_r // le0_cp // ltrW. Qed. Lemma maxNr x : max (- x) x = `|x|. Proof. by rewrite maxrC maxrN. Qed. Lemma minrN x : min x (- x) = - `|x|. Proof. by rewrite -[minr _ _]opprK oppr_min opprK maxNr. Qed. Lemma minNr x : min (- x) x = - `|x|. Proof. by rewrite -[minr _ _]opprK oppr_min opprK maxrN. Qed. End MinMax. Section PolyBounds. Variable p : {poly R}. Lemma poly_itv_bound a b : {ub | forall x, a <= x <= b -> `|p.[x]| <= ub}. Proof. have [ub le_p_ub] := poly_disk_bound p (Num.max `|a| `|b|). exists ub => x /andP[le_a_x le_x_b]; rewrite le_p_ub // ler_maxr !ler_normr. by have [_|_] := ler0P x; rewrite ?ler_opp2 ?le_a_x ?le_x_b orbT. Qed. Lemma monic_Cauchy_bound : p \is monic -> {b | forall x, x >= b -> p.[x] > 0}. Proof. move/monicP=> mon_p; pose n := (size p - 2)%N. have [p_le1 | p_gt1] := leqP (size p) 1. exists 0 => x _; rewrite (size1_polyC p_le1) hornerC. by rewrite -[p`_0]lead_coefC -size1_polyC // mon_p ltr01. pose lb := \sum_(j < n.+1) `|p`_j|; exists (lb + 1) => x le_ub_x. have x_ge1: 1 <= x; last have x_gt0 := ltr_le_trans ltr01 x_ge1. by rewrite -(ler_add2l lb) ler_paddl ?sumr_ge0 // => j _; apply: normr_ge0. rewrite horner_coef -(subnK p_gt1) -/n addnS big_ord_recr /= addn1. rewrite [in p`__]subnSK // subn1 -lead_coefE mon_p mul1r -ltr_subl_addl sub0r. apply: ler_lt_trans (_ : lb * x ^+ n < _); last first. rewrite exprS ltr_pmul2r ?exprn_gt0 ?(ltr_le_trans ltr01) //. by rewrite -(ltr_add2r 1) ltr_spaddr ?ltr01. rewrite -sumrN mulr_suml ler_sum // => j _; apply: ler_trans (ler_norm _) _. rewrite normrN normrM ler_wpmul2l ?normr_ge0 // normrX. by rewrite ger0_norm ?(ltrW x_gt0) // ler_weexpn2l ?leq_ord. Qed. End PolyBounds. End RealDomainOperations. Section RealField. Variables (F : realFieldType) (x y : F). Lemma lerif_mean_square : x * y <= (x ^+ 2 + y ^+ 2) / 2%:R ?= iff (x == y). Proof. by apply: real_lerif_mean_square; apply: num_real. Qed. Lemma lerif_AGM2 : x * y <= ((x + y) / 2%:R)^+ 2 ?= iff (x == y). Proof. by apply: real_lerif_AGM2; apply: num_real. Qed. End RealField. Section ArchimedeanFieldTheory. Variables (F : archiFieldType) (x : F). Lemma archi_boundP : 0 <= x -> x < (bound x)%:R. Proof. by move/ger0_norm=> {1}<-; rewrite /bound; case: (sigW _). Qed. Lemma upper_nthrootP i : (bound x <= i)%N -> x < 2%:R ^+ i. Proof. rewrite /bound; case: (sigW _) => /= b le_x_b le_b_i. apply: ler_lt_trans (ler_norm x) (ltr_trans le_x_b _ ). by rewrite -natrX ltr_nat (leq_ltn_trans le_b_i) // ltn_expl. Qed. End ArchimedeanFieldTheory. Section RealClosedFieldTheory. Variable R : rcfType. Implicit Types a x y : R. Lemma poly_ivt : real_closed_axiom R. Proof. exact: poly_ivt. Qed. (* Square Root theory *) Lemma sqrtr_ge0 a : 0 <= sqrt a. Proof. by rewrite /sqrt; case: (sig2W _). Qed. Hint Resolve sqrtr_ge0. Lemma sqr_sqrtr a : 0 <= a -> sqrt a ^+ 2 = a. Proof. by rewrite /sqrt => a_ge0; case: (sig2W _) => /= x _; rewrite a_ge0 => /eqP. Qed. Lemma ler0_sqrtr a : a <= 0 -> sqrt a = 0. Proof. rewrite /sqrtr; case: (sig2W _) => x /= _. by have [//|_ /eqP//|->] := ltrgt0P a; rewrite mulf_eq0 orbb => /eqP. Qed. Lemma ltr0_sqrtr a : a < 0 -> sqrt a = 0. Proof. by move=> /ltrW; apply: ler0_sqrtr. Qed. CoInductive sqrtr_spec a : R -> bool -> bool -> R -> Type := | IsNoSqrtr of a < 0 : sqrtr_spec a a false true 0 | IsSqrtr b of 0 <= b : sqrtr_spec a (b ^+ 2) true false b. Lemma sqrtrP a : sqrtr_spec a a (0 <= a) (a < 0) (sqrt a). Proof. have [a_ge0|a_lt0] := ger0P a. by rewrite -{1 2}[a]sqr_sqrtr //; constructor. by rewrite ltr0_sqrtr //; constructor. Qed. Lemma sqrtr_sqr a : sqrt (a ^+ 2) = `|a|. Proof. have /eqP : sqrt (a ^+ 2) ^+ 2 = `|a| ^+ 2. by rewrite -normrX ger0_norm ?sqr_sqrtr ?sqr_ge0. rewrite eqf_sqr => /predU1P[-> //|ha]. have := sqrtr_ge0 (a ^+ 2); rewrite (eqP ha) oppr_ge0 normr_le0 => /eqP ->. by rewrite normr0 oppr0. Qed. Lemma sqrtrM a b : 0 <= a -> sqrt (a * b) = sqrt a * sqrt b. Proof. case: (sqrtrP a) => // {a} a a_ge0 _; case: (sqrtrP b) => [b_lt0 | {b} b b_ge0]. by rewrite mulr0 ler0_sqrtr // nmulr_lle0 ?mulr_ge0. by rewrite mulrACA sqrtr_sqr ger0_norm ?mulr_ge0. Qed. Lemma sqrtr0 : sqrt 0 = 0 :> R. Proof. by move: (sqrtr_sqr 0); rewrite exprS mul0r => ->; rewrite normr0. Qed. Lemma sqrtr1 : sqrt 1 = 1 :> R. Proof. by move: (sqrtr_sqr 1); rewrite expr1n => ->; rewrite normr1. Qed. Lemma sqrtr_eq0 a : (sqrt a == 0) = (a <= 0). Proof. case: sqrtrP => [/ltrW ->|b]; first by rewrite eqxx. case: ltrgt0P => [b_gt0|//|->]; last by rewrite exprS mul0r lerr. by rewrite ltr_geF ?pmulr_rgt0. Qed. Lemma sqrtr_gt0 a : (0 < sqrt a) = (0 < a). Proof. by rewrite lt0r sqrtr_ge0 sqrtr_eq0 -ltrNge andbT. Qed. Lemma eqr_sqrt a b : 0 <= a -> 0 <= b -> (sqrt a == sqrt b) = (a == b). Proof. move=> a_ge0 b_ge0; apply/eqP/eqP=> [HS|->] //. by move: (sqr_sqrtr a_ge0); rewrite HS (sqr_sqrtr b_ge0). Qed. Lemma ler_wsqrtr : {homo @sqrt R : a b / a <= b}. Proof. move=> a b /= le_ab; case: (boolP (0 <= a))=> [pa|]; last first. by rewrite -ltrNge; move/ltrW; rewrite -sqrtr_eq0; move/eqP->. rewrite -(@ler_pexpn2r R 2) ?nnegrE ?sqrtr_ge0 //. by rewrite !sqr_sqrtr // (ler_trans pa). Qed. Lemma ler_psqrt : {in @pos R &, {mono sqrt : a b / a <= b}}. Proof. apply: homo_mono_in => x y x_gt0 y_gt0. rewrite !ltr_neqAle => /andP[neq_xy le_xy]. by rewrite ler_wsqrtr // eqr_sqrt ?ltrW // neq_xy. Qed. Lemma ler_sqrt a b : 0 < b -> (sqrt a <= sqrt b) = (a <= b). Proof. move=> b_gt0; have [a_le0|a_gt0] := ler0P a; last by rewrite ler_psqrt. by rewrite ler0_sqrtr // sqrtr_ge0 (ler_trans a_le0) ?ltrW. Qed. Lemma ltr_sqrt a b : 0 < b -> (sqrt a < sqrt b) = (a < b). Proof. move=> b_gt0; have [a_le0|a_gt0] := ler0P a; last first. by rewrite (lerW_mono_in ler_psqrt). by rewrite ler0_sqrtr // sqrtr_gt0 b_gt0 (ler_lt_trans a_le0). Qed. End RealClosedFieldTheory. End Theory. Module RealMixin. Section RealMixins. Variables (R : idomainType) (le : rel R) (lt : rel R) (norm : R -> R). Local Infix "<=" := le. Local Infix "<" := lt. Local Notation "`| x |" := (norm x) : ring_scope. Section LeMixin. Hypothesis le0_add : forall x y, 0 <= x -> 0 <= y -> 0 <= x + y. Hypothesis le0_mul : forall x y, 0 <= x -> 0 <= y -> 0 <= x * y. Hypothesis le0_anti : forall x, 0 <= x -> x <= 0 -> x = 0. Hypothesis sub_ge0 : forall x y, (0 <= y - x) = (x <= y). Hypothesis le0_total : forall x, (0 <= x) || (x <= 0). Hypothesis normN: forall x, `|- x| = `|x|. Hypothesis ge0_norm : forall x, 0 <= x -> `|x| = x. Hypothesis lt_def : forall x y, (x < y) = (y != x) && (x <= y). Let le0N x : (0 <= - x) = (x <= 0). Proof. by rewrite -sub0r sub_ge0. Qed. Let leN_total x : 0 <= x \/ 0 <= - x. Proof. by apply/orP; rewrite le0N le0_total. Qed. Let le00 : (0 <= 0). Proof. by have:= le0_total 0; rewrite orbb. Qed. Let le01 : (0 <= 1). Proof. by case/orP: (le0_total 1)=> // ?; rewrite -[1]mul1r -mulrNN le0_mul ?le0N. Qed. Fact lt0_add x y : 0 < x -> 0 < y -> 0 < x + y. Proof. rewrite !lt_def => /andP[x_neq0 l0x] /andP[y_neq0 l0y]; rewrite le0_add //. rewrite andbT addr_eq0; apply: contraNneq x_neq0 => hxy. by rewrite [x]le0_anti // hxy -le0N opprK. Qed. Fact eq0_norm x : `|x| = 0 -> x = 0. Proof. case: (leN_total x) => /ge0_norm => [-> // | Dnx nx0]. by rewrite -[x]opprK -Dnx normN nx0 oppr0. Qed. Fact le_def x y : (x <= y) = (`|y - x| == y - x). Proof. wlog ->: x y / x = 0 by move/(_ 0 (y - x)); rewrite subr0 sub_ge0 => ->. rewrite {x}subr0; apply/idP/eqP=> [/ge0_norm// | Dy]. by have [//| ny_ge0] := leN_total y; rewrite -Dy -normN ge0_norm. Qed. Fact normM : {morph norm : x y / x * y}. Proof. move=> x y /=; wlog x_ge0 : x / 0 <= x. by move=> IHx; case: (leN_total x) => /IHx//; rewrite mulNr !normN. wlog y_ge0 : y / 0 <= y; last by rewrite ?ge0_norm ?le0_mul. by move=> IHy; case: (leN_total y) => /IHy//; rewrite mulrN !normN. Qed. Fact le_normD x y : `|x + y| <= `|x| + `|y|. Proof. wlog x_ge0 : x y / 0 <= x. by move=> IH; case: (leN_total x) => /IH// /(_ (- y)); rewrite -opprD !normN. rewrite -sub_ge0 ge0_norm //; have [y_ge0 | ny_ge0] := leN_total y. by rewrite !ge0_norm ?subrr ?le0_add. rewrite -normN ge0_norm //; have [hxy|hxy] := leN_total (x + y). by rewrite ge0_norm // opprD addrCA -addrA addKr le0_add. by rewrite -normN ge0_norm // opprK addrCA addrNK le0_add. Qed. Lemma le_total x y : (x <= y) || (y <= x). Proof. by rewrite -sub_ge0 -opprB le0N orbC -sub_ge0 le0_total. Qed. Definition Le := Mixin le_normD lt0_add eq0_norm (in2W le_total) normM le_def lt_def. Lemma Real (R' : numDomainType) & phant R' : R' = NumDomainType R Le -> real_axiom R'. Proof. by move->. Qed. End LeMixin. Section LtMixin. Hypothesis lt0_add : forall x y, 0 < x -> 0 < y -> 0 < x + y. Hypothesis lt0_mul : forall x y, 0 < x -> 0 < y -> 0 < x * y. Hypothesis lt0_ngt0 : forall x, 0 < x -> ~~ (x < 0). Hypothesis sub_gt0 : forall x y, (0 < y - x) = (x < y). Hypothesis lt0_total : forall x, x != 0 -> (0 < x) || (x < 0). Hypothesis normN : forall x, `|- x| = `|x|. Hypothesis ge0_norm : forall x, 0 <= x -> `|x| = x. Hypothesis le_def : forall x y, (x <= y) = (y == x) || (x < y). Fact le0_add x y : 0 <= x -> 0 <= y -> 0 <= x + y. Proof. rewrite !le_def => /predU1P[->|x_gt0]; first by rewrite add0r. by case/predU1P=> [->|y_gt0]; rewrite ?addr0 ?x_gt0 ?lt0_add // orbT. Qed. Fact le0_mul x y : 0 <= x -> 0 <= y -> 0 <= x * y. Proof. rewrite !le_def => /predU1P[->|x_gt0]; first by rewrite mul0r eqxx. by case/predU1P=> [->|y_gt0]; rewrite ?mulr0 ?eqxx // orbC lt0_mul. Qed. Fact le0_anti x : 0 <= x -> x <= 0 -> x = 0. Proof. by rewrite !le_def => /predU1P[] // /lt0_ngt0/negPf-> /predU1P[]. Qed. Fact sub_ge0 x y : (0 <= y - x) = (x <= y). Proof. by rewrite !le_def subr_eq0 sub_gt0. Qed. Fact lt_def x y : (x < y) = (y != x) && (x <= y). Proof. rewrite le_def; case: eqP => //= ->; rewrite -sub_gt0 subrr. by apply/idP=> lt00; case/negP: (lt0_ngt0 lt00). Qed. Fact le0_total x : (0 <= x) || (x <= 0). Proof. by rewrite !le_def [0 == _]eq_sym; have [|/lt0_total] := altP eqP. Qed. Definition Lt := Le le0_add le0_mul le0_anti sub_ge0 le0_total normN ge0_norm lt_def. End LtMixin. End RealMixins. End RealMixin. End Num. Export Num.NumDomain.Exports Num.NumField.Exports Num.ClosedField.Exports. Export Num.RealDomain.Exports Num.RealField.Exports. Export Num.ArchimedeanField.Exports Num.RealClosedField.Exports. Export Num.Syntax Num.PredInstances. Notation RealLeMixin := Num.RealMixin.Le. Notation RealLtMixin := Num.RealMixin.Lt. Notation RealLeAxiom R := (Num.RealMixin.Real (Phant R) (erefl _)). mathcomp-1.5/theories/cyclic.v0000644000175000017500000010133512307636117015443 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div fintype bigop. Require Import prime finset fingroup morphism perm automorphism quotient. Require Import gproduct ssralg finalg zmodp poly. (******************************************************************************) (* Properties of cyclic groups. *) (* Definitions: *) (* Defined in fingroup.v: *) (* <[x]> == the cycle (cyclic group) generated by x. *) (* #[x] == the order of x, i.e., the cardinal of <[x]>. *) (* Defined in prime.v: *) (* totient n == Euler's totient function *) (* Definitions in this file: *) (* cyclic G <=> G is a cyclic group. *) (* metacyclic G <=> G is a metacyclic group (i.e., a cyclic extension of a *) (* cyclic group). *) (* generator G x <=> x is a generator of the (cyclic) group G. *) (* Zpm x == the isomorphism mapping the additive group of integers *) (* mod #[x] to the cyclic group <[x]>. *) (* cyclem x n == the endomorphism y |-> y ^+ n of <[x]>. *) (* Zp_unitm x == the isomorphism mapping the multiplicative group of the *) (* units of the ring of integers mod #[x] to the group of *) (* automorphisms of <[x]> (i.e., Aut <[x]>). *) (* Zp_unitm x maps u to cyclem x u. *) (* eltm dvd_y_x == the smallest morphism (with domain <[x]>) mapping x to *) (* y, given a proof dvd_y_x : #[y] %| #[x]. *) (* expg_invn G k == if coprime #|G| k, the inverse of exponent k in G. *) (* Basic results for these notions, plus the classical result that any finite *) (* group isomorphic to a subgroup of a field is cyclic, hence that Aut G is *) (* cyclic when G is of prime order. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope GRing.Theory. (***********************************************************************) (* Cyclic groups. *) (***********************************************************************) Section Cyclic. Variable gT : finGroupType. Implicit Types (a x y : gT) (A B : {set gT}) (G K H : {group gT}). Definition cyclic A := [exists x, A == <[x]>]. Lemma cyclicP A : reflect (exists x, A = <[x]>) (cyclic A). Proof. exact: exists_eqP. Qed. Lemma cycle_cyclic x : cyclic <[x]>. Proof. by apply/cyclicP; exists x. Qed. Lemma cyclic1 : cyclic [1 gT]. Proof. by rewrite -cycle1 cycle_cyclic. Qed. (***********************************************************************) (* Isomorphism with the additive group *) (***********************************************************************) Section Zpm. Variable a : gT. Definition Zpm (i : 'Z_#[a]) := a ^+ i. Lemma ZpmM : {in Zp #[a] &, {morph Zpm : x y / x * y}}. Proof. rewrite /Zpm; case: (eqVneq a 1) => [-> | nta] i j _ _. by rewrite !expg1n ?mulg1. by rewrite /= {3}Zp_cast ?order_gt1 // expg_mod_order expgD. Qed. Canonical Zpm_morphism := Morphism ZpmM. Lemma im_Zpm : Zpm @* Zp #[a] = <[a]>. Proof. apply/eqP; rewrite eq_sym eqEcard cycle_subG /= andbC morphimEdom. rewrite (leq_trans (leq_imset_card _ _)) ?card_Zp //= /Zp order_gt1. case: eqP => /= [a1 | _]; first by rewrite imset_set1 morph1 a1 set11. by apply/imsetP; exists 1%R; rewrite ?expg1 ?inE. Qed. Lemma injm_Zpm : 'injm Zpm. Proof. apply/injmP/dinjectiveP/card_uniqP. rewrite size_map -cardE card_Zp //= {7}/order -im_Zpm morphimEdom /=. by apply: eq_card => x; apply/imageP/imsetP=> [] [i Zp_i ->]; exists i. Qed. Lemma eq_expg_mod_order m n : (a ^+ m == a ^+ n) = (m == n %[mod #[a]]). Proof. have [->|] := eqVneq a 1; first by rewrite order1 !modn1 !expg1n eqxx. rewrite -order_gt1 => lt1a; have ZpT: Zp #[a] = setT by rewrite /Zp lt1a. have: injective Zpm by move=> i j; apply (injmP injm_Zpm); rewrite /= ZpT inE. move/inj_eq=> eqZ; symmetry; rewrite -(Zp_cast lt1a). by rewrite -[_ == _](eqZ (inZp m) (inZp n)) /Zpm /= Zp_cast ?expg_mod_order. Qed. Lemma Zp_isom : isom (Zp #[a]) <[a]> Zpm. Proof. by apply/isomP; rewrite injm_Zpm im_Zpm. Qed. Lemma Zp_isog : isog (Zp #[a]) <[a]>. Proof. exact: isom_isog Zp_isom. Qed. End Zpm. (***********************************************************************) (* Central and direct product of cycles *) (***********************************************************************) Lemma cyclic_abelian A : cyclic A -> abelian A. Proof. by case/cyclicP=> a ->; exact: cycle_abelian. Qed. Lemma cycleMsub a b : commute a b -> coprime #[a] #[b] -> <[a]> \subset <[a * b]>. Proof. move=> cab co_ab; apply/subsetP=> _ /cycleP[k ->]. apply/cycleP; exists (chinese #[a] #[b] k 0); symmetry. rewrite expgMn // -expg_mod_order chinese_modl // expg_mod_order. by rewrite /chinese addn0 -mulnA mulnCA expgM expg_order expg1n mulg1. Qed. Lemma cycleM a b : commute a b -> coprime #[a] #[b] -> <[a * b]> = <[a]> * <[b]>. Proof. move=> cab co_ab; apply/eqP; rewrite eqEsubset -(cent_joinEl (cents_cycle cab)). rewrite join_subG {3}cab !cycleMsub // 1?coprime_sym //. by rewrite -genM_join cycle_subG mem_gen // mem_imset2 ?cycle_id. Qed. Lemma cyclicM A B : cyclic A -> cyclic B -> B \subset 'C(A) -> coprime #|A| #|B| -> cyclic (A * B). Proof. move=> /cyclicP[a ->] /cyclicP[b ->]; rewrite cent_cycle cycle_subG => cab coab. by rewrite -cycleM ?cycle_cyclic //; exact/esym/cent1P. Qed. Lemma cyclicY K H : cyclic K -> cyclic H -> H \subset 'C(K) -> coprime #|K| #|H| -> cyclic (K <*> H). Proof. by move=> cycK cycH cKH coKH; rewrite cent_joinEr // cyclicM. Qed. (***********************************************************************) (* Order properties *) (***********************************************************************) Lemma order_dvdn a n : #[a] %| n = (a ^+ n == 1). Proof. by rewrite (eq_expg_mod_order a n 0) mod0n. Qed. Lemma order_inf a n : a ^+ n.+1 == 1 -> #[a] <= n.+1. Proof. by rewrite -order_dvdn; exact: dvdn_leq. Qed. Lemma order_dvdG G a : a \in G -> #[a] %| #|G|. Proof. by move=> Ga; apply: cardSg; rewrite cycle_subG. Qed. Lemma expg_cardG G a : a \in G -> a ^+ #|G| = 1. Proof. by move=> Ga; apply/eqP; rewrite -order_dvdn order_dvdG. Qed. Lemma expg_znat G x k : x \in G -> x ^+ (k%:R : 'Z_(#|G|))%R = x ^+ k. Proof. case: (eqsVneq G 1) => [-> /set1P-> | ntG Gx]; first by rewrite !expg1n. apply/eqP; rewrite val_Zp_nat ?cardG_gt1 // eq_expg_mod_order. by rewrite modn_dvdm ?order_dvdG. Qed. Lemma expg_zneg G x (k : 'Z_(#|G|)) : x \in G -> x ^+ (- k)%R = x ^- k. Proof. move=> Gx; apply/eqP; rewrite eq_sym eq_invg_mul -expgD. by rewrite -(expg_znat _ Gx) natrD natr_Zp natr_negZp subrr. Qed. Lemma nt_gen_prime G x : prime #|G| -> x \in G^# -> G :=: <[x]>. Proof. move=> Gpr /setD1P[]; rewrite -cycle_subG -cycle_eq1 => ntX sXG. apply/eqP; rewrite eqEsubset sXG andbT. by apply: contraR ntX => /(prime_TIg Gpr); rewrite (setIidPr sXG) => ->. Qed. Lemma nt_prime_order p x : prime p -> x ^+ p = 1 -> x != 1 -> #[x] = p. Proof. move=> p_pr xp ntx; apply/prime_nt_dvdP; rewrite ?order_eq1 //. by rewrite order_dvdn xp. Qed. Lemma orderXdvd a n : #[a ^+ n] %| #[a]. Proof. by apply: order_dvdG; exact: mem_cycle. Qed. Lemma orderXgcd a n : #[a ^+ n] = #[a] %/ gcdn #[a] n. Proof. apply/eqP; rewrite eqn_dvd; apply/andP; split. rewrite order_dvdn -expgM -muln_divCA_gcd //. by rewrite expgM expg_order expg1n. have [-> | n_gt0] := posnP n; first by rewrite gcdn0 divnn order_gt0 dvd1n. rewrite -(dvdn_pmul2r n_gt0) divn_mulAC ?dvdn_gcdl // dvdn_lcm. by rewrite order_dvdn mulnC expgM expg_order eqxx dvdn_mulr. Qed. Lemma orderXdiv a n : n %| #[a] -> #[a ^+ n] = #[a] %/ n. Proof. by case/dvdnP=> q defq; rewrite orderXgcd {2}defq gcdnC gcdnMl. Qed. Lemma orderXexp p m n x : #[x] = (p ^ n)%N -> #[x ^+ (p ^ m)] = (p ^ (n - m))%N. Proof. move=> ox; have [n_le_m | m_lt_n] := leqP n m. rewrite -(subnKC n_le_m) subnDA subnn expnD expgM -ox. by rewrite expg_order expg1n order1. rewrite orderXdiv ox ?dvdn_exp2l ?expnB ?(ltnW m_lt_n) //. by have:= order_gt0 x; rewrite ox expn_gt0 orbC -(ltn_predK m_lt_n). Qed. Lemma orderXpfactor p k n x : #[x ^+ (p ^ k)] = n -> prime p -> p %| n -> #[x] = (p ^ k * n)%N. Proof. move=> oxp p_pr dv_p_n. suffices pk_x: p ^ k %| #[x] by rewrite -oxp orderXdiv // mulnC divnK. rewrite pfactor_dvdn // leqNgt; apply: contraL dv_p_n => lt_x_k. rewrite -oxp -p'natE // -(subnKC (ltnW lt_x_k)) expnD expgM. rewrite (pnat_dvd (orderXdvd _ _)) // -p_part // orderXdiv ?dvdn_part //. by rewrite -{1}[#[x]](partnC p) // mulKn // part_pnat. Qed. Lemma orderXprime p n x : #[x ^+ p] = n -> prime p -> p %| n -> #[x] = (p * n)%N. Proof. exact: (@orderXpfactor p 1). Qed. Lemma orderXpnat m n x : #[x ^+ m] = n -> \pi(n).-nat m -> #[x] = (m * n)%N. Proof. move=> oxm n_m; have [m_gt0 _] := andP n_m. suffices m_x: m %| #[x] by rewrite -oxm orderXdiv // mulnC divnK. apply/dvdn_partP=> // p; rewrite mem_primes => /and3P[p_pr _ p_m]. have n_p: p \in \pi(n) by apply: (pnatP _ _ n_m). have p_oxm: p %| #[x ^+ (p ^ logn p m)]. apply: dvdn_trans (orderXdvd _ m`_p^'); rewrite -expgM -p_part ?partnC //. by rewrite oxm; rewrite mem_primes in n_p; case/and3P: n_p. by rewrite (orderXpfactor (erefl _) p_pr p_oxm) p_part // dvdn_mulr. Qed. Lemma orderM a b : commute a b -> coprime #[a] #[b] -> #[a * b] = (#[a] * #[b])%N. Proof. by move=> cab co_ab; rewrite -coprime_cardMg -?cycleM. Qed. Definition expg_invn A k := (egcdn k #|A|).1. Lemma expgK G k : coprime #|G| k -> {in G, cancel (expgn^~ k) (expgn^~ (expg_invn G k))}. Proof. move=> coGk x /order_dvdG Gx; apply/eqP. rewrite -expgM (eq_expg_mod_order _ _ 1) -(modn_dvdm 1 Gx). by rewrite -(chinese_modl coGk 1 0) /chinese mul1n addn0 modn_dvdm. Qed. Lemma cyclic_dprod K H G : K \x H = G -> cyclic K -> cyclic H -> cyclic G = coprime #|K| #|H| . Proof. case/dprodP=> _ defKH cKH tiKH cycK cycH; pose m := lcmn #|K| #|H|. apply/idP/idP=> [/cyclicP[x defG] | coKH]; last by rewrite -defKH cyclicM. rewrite /coprime -dvdn1 -(@dvdn_pmul2l m) ?lcmn_gt0 ?cardG_gt0 //. rewrite muln_lcm_gcd muln1 -TI_cardMg // defKH defG order_dvdn. have /mulsgP[y z Ky Hz ->]: x \in K * H by rewrite defKH defG cycle_id. rewrite -[1]mulg1 expgMn; last exact/commute_sym/(centsP cKH). apply/eqP; congr (_ * _); apply/eqP; rewrite -order_dvdn. exact: dvdn_trans (order_dvdG Ky) (dvdn_lcml _ _). exact: dvdn_trans (order_dvdG Hz) (dvdn_lcmr _ _). Qed. (***********************************************************************) (* Generator *) (***********************************************************************) Definition generator (A : {set gT}) a := A == <[a]>. Lemma generator_cycle a : generator <[a]> a. Proof. exact: eqxx. Qed. Lemma cycle_generator a x : generator <[a]> x -> x \in <[a]>. Proof. by move/(<[a]> =P _)->; exact: cycle_id. Qed. Lemma generator_order a b : generator <[a]> b -> #[a] = #[b]. Proof. by rewrite /order => /(<[a]> =P _)->. Qed. End Cyclic. Arguments Scope cyclic [_ group_scope]. Arguments Scope generator [_ group_scope group_scope]. Arguments Scope expg_invn [_ group_scope nat_scope]. Implicit Arguments cyclicP [gT A]. Prenex Implicits cyclic Zpm generator expg_invn. (* Euler's theorem *) Theorem Euler_exp_totient a n : coprime a n -> a ^ totient n = 1 %[mod n]. Proof. case: n => [|[|n']] //; [by rewrite !modn1 | set n := n'.+2] => co_a_n. have{co_a_n} Ua: coprime n (inZp a : 'I_n) by rewrite coprime_sym coprime_modl. have: FinRing.unit 'Z_n Ua ^+ totient n == 1. by rewrite -card_units_Zp // -order_dvdn order_dvdG ?inE. by rewrite -2!val_eqE unit_Zp_expg /= -/n modnXm => /eqP. Qed. Section Eltm. Variables (aT rT : finGroupType) (x : aT) (y : rT). Definition eltm of #[y] %| #[x] := fun x_i => y ^+ invm (injm_Zpm x) x_i. Hypothesis dvd_y_x : #[y] %| #[x]. Lemma eltmE i : eltm dvd_y_x (x ^+ i) = y ^+ i. Proof. apply/eqP; rewrite eq_expg_mod_order. have [x_le1 | x_gt1] := leqP #[x] 1. suffices: #[y] %| 1 by rewrite dvdn1 => /eqP->; rewrite !modn1. by rewrite (dvdn_trans dvd_y_x) // dvdn1 order_eq1 -cycle_eq1 trivg_card_le1. rewrite -(expg_znat i (cycle_id x)) invmE /=; last by rewrite /Zp x_gt1 inE. by rewrite val_Zp_nat // modn_dvdm. Qed. Lemma eltm_id : eltm dvd_y_x x = y. Proof. exact: (eltmE 1). Qed. Lemma eltmM : {in <[x]> &, {morph eltm dvd_y_x : x_i x_j / x_i * x_j}}. Proof. move=> _ _ /cycleP[i ->] /cycleP[j ->]. by apply/eqP; rewrite -expgD !eltmE expgD. Qed. Canonical eltm_morphism := Morphism eltmM. Lemma im_eltm : eltm dvd_y_x @* <[x]> = <[y]>. Proof. by rewrite morphim_cycle ?cycle_id //= eltm_id. Qed. Lemma ker_eltm : 'ker (eltm dvd_y_x) = <[x ^+ #[y]]>. Proof. apply/eqP; rewrite eq_sym eqEcard cycle_subG 3!inE mem_cycle /= eltmE. rewrite expg_order eqxx (orderE y) -im_eltm card_morphim setIid -orderE. by rewrite orderXdiv ?dvdn_indexg //= leq_divRL ?indexg_gt0 ?Lagrange ?subsetIl. Qed. Lemma injm_eltm : 'injm (eltm dvd_y_x) = (#[x] %| #[y]). Proof. by rewrite ker_eltm subG1 cycle_eq1 -order_dvdn. Qed. End Eltm. Section CycleSubGroup. Variable gT : finGroupType. (* Gorenstein, 1.3.1 (i) *) Lemma cycle_sub_group (a : gT) m : m %| #[a] -> [set H : {group gT} | H \subset <[a]> & #|H| == m] = [set <[a ^+ (#[a] %/ m)]>%G]. Proof. move=> m_dv_a; have m_gt0: 0 < m by apply: dvdn_gt0 m_dv_a. have oam: #|<[a ^+ (#[a] %/ m)]>| = m. apply/eqP; rewrite [#|_|]orderXgcd -(divnMr m_gt0) muln_gcdl divnK //. by rewrite gcdnC gcdnMr mulKn. apply/eqP; rewrite eqEsubset sub1set inE /= cycleX oam eqxx !andbT. apply/subsetP=> X; rewrite in_set1 inE -val_eqE /= eqEcard oam. case/andP=> sXa /eqP oX; rewrite oX leqnn andbT. apply/subsetP=> x Xx; case/cycleP: (subsetP sXa _ Xx) => k def_x. have: (x ^+ m == 1)%g by rewrite -oX -order_dvdn cardSg // gen_subG sub1set. rewrite {x Xx}def_x -expgM -order_dvdn -[#[a]](Lagrange sXa) -oX mulnC. rewrite dvdn_pmul2r // mulnK // => /dvdnP[i ->]. by rewrite mulnC expgM groupX // cycle_id. Qed. Lemma cycle_subgroup_char a (H : {group gT}) : H \subset <[a]> -> H \char <[a]>. Proof. move=> sHa; apply: lone_subgroup_char => // J sJa isoJH. have dvHa: #|H| %| #[a] by exact: cardSg. have{dvHa} /setP Huniq := esym (cycle_sub_group dvHa). move: (Huniq H) (Huniq J); rewrite !inE /=. by rewrite sHa sJa (card_isog isoJH) eqxx => /eqP<- /eqP<-. Qed. End CycleSubGroup. (***********************************************************************) (* Reflected boolean property and morphic image, injection, bijection *) (***********************************************************************) Section MorphicImage. Variables aT rT : finGroupType. Variables (D : {group aT}) (f : {morphism D >-> rT}) (x : aT). Hypothesis Dx : x \in D. Lemma morph_order : #[f x] %| #[x]. Proof. by rewrite order_dvdn -morphX // expg_order morph1. Qed. Lemma morph_generator A : generator A x -> generator (f @* A) (f x). Proof. by move/(A =P _)->; rewrite /generator morphim_cycle. Qed. End MorphicImage. Section CyclicProps. Variables gT : finGroupType. Implicit Types (aT rT : finGroupType) (G H K : {group gT}). Lemma cyclicS G H : H \subset G -> cyclic G -> cyclic H. Proof. move=> sHG /cyclicP[x defG]; apply/cyclicP. exists (x ^+ (#[x] %/ #|H|)); apply/congr_group/set1P. by rewrite -cycle_sub_group /order -defG ?cardSg // inE sHG eqxx. Qed. Lemma cyclicJ G x : cyclic (G :^ x) = cyclic G. Proof. apply/cyclicP/cyclicP=> [[y /(canRL (conjsgK x))] | [y ->]]. by rewrite -cycleJ; exists (y ^ x^-1). by exists (y ^ x); rewrite cycleJ. Qed. Lemma eq_subG_cyclic G H K : cyclic G -> H \subset G -> K \subset G -> (H :==: K) = (#|H| == #|K|). Proof. case/cyclicP=> x -> sHx sKx; apply/eqP/eqP=> [-> //| eqHK]. have def_GHx := cycle_sub_group (cardSg sHx); set GHx := [set _] in def_GHx. have []: H \in GHx /\ K \in GHx by rewrite -def_GHx !inE sHx sKx eqHK /=. by do 2!move/set1P->. Qed. Lemma cardSg_cyclic G H K : cyclic G -> H \subset G -> K \subset G -> (#|H| %| #|K|) = (H \subset K). Proof. move=> cycG sHG sKG; apply/idP/idP; last exact: cardSg. case/cyclicP: (cyclicS sKG cycG) => x defK; rewrite {K}defK in sKG *. case/dvdnP=> k ox; suffices ->: H :=: <[x ^+ k]> by exact: cycleX. apply/eqP; rewrite (eq_subG_cyclic cycG) ?(subset_trans (cycleX _ _)) //. rewrite -orderE orderXdiv orderE ox ?dvdn_mulr ?mulKn //. by have:= order_gt0 x; rewrite orderE ox; case k. Qed. Lemma sub_cyclic_char G H : cyclic G -> (H \char G) = (H \subset G). Proof. case/cyclicP=> x ->; apply/idP/idP => [/andP[] //|]. exact: cycle_subgroup_char. Qed. Lemma morphim_cyclic rT G H (f : {morphism G >-> rT}) : cyclic H -> cyclic (f @* H). Proof. move=> cycH; wlog sHG: H cycH / H \subset G. by rewrite -morphimIdom; apply; rewrite (cyclicS _ cycH, subsetIl) ?subsetIr. case/cyclicP: cycH sHG => x ->; rewrite gen_subG sub1set => Gx. by apply/cyclicP; exists (f x); rewrite morphim_cycle. Qed. Lemma quotient_cycle x H : x \in 'N(H) -> <[x]> / H = <[coset H x]>. Proof. exact: morphim_cycle. Qed. Lemma quotient_cyclic G H : cyclic G -> cyclic (G / H). Proof. exact: morphim_cyclic. Qed. Lemma quotient_generator x G H : x \in 'N(H) -> generator G x -> generator (G / H) (coset H x). Proof. by move=> Nx; apply: morph_generator. Qed. Lemma prime_cyclic G : prime #|G| -> cyclic G. Proof. case/primeP; rewrite ltnNge -trivg_card_le1. case/trivgPn=> x Gx ntx /(_ _ (order_dvdG Gx)). rewrite order_eq1 (negbTE ntx) => /eqnP oxG; apply/cyclicP. by exists x; apply/eqP; rewrite eq_sym eqEcard -oxG cycle_subG Gx leqnn. Qed. Lemma dvdn_prime_cyclic G p : prime p -> #|G| %| p -> cyclic G. Proof. move=> p_pr pG; case: (eqsVneq G 1) => [-> | ntG]; first exact: cyclic1. by rewrite prime_cyclic // (prime_nt_dvdP p_pr _ pG) -?trivg_card1. Qed. Lemma cyclic_small G : #|G| <= 3 -> cyclic G. Proof. rewrite 4!(ltnS, leq_eqVlt) -trivg_card_le1 orbA orbC. case/predU1P=> [-> | oG]; first exact: cyclic1. by apply: prime_cyclic; case/pred2P: oG => ->. Qed. End CyclicProps. Section IsoCyclic. Variables gT rT : finGroupType. Implicit Types (G H : {group gT}) (M : {group rT}). Lemma injm_cyclic G H (f : {morphism G >-> rT}) : 'injm f -> H \subset G -> cyclic (f @* H) = cyclic H. Proof. move=> injf sHG; apply/idP/idP; last exact: morphim_cyclic. rewrite -{2}(morphim_invm injf sHG); exact: morphim_cyclic. Qed. Lemma isog_cyclic G M : G \isog M -> cyclic G = cyclic M. Proof. by case/isogP=> f injf <-; rewrite injm_cyclic. Qed. Lemma isog_cyclic_card G M : cyclic G -> isog G M = cyclic M && (#|M| == #|G|). Proof. move=> cycG; apply/idP/idP=> [isoGM | ]. by rewrite (card_isog isoGM) -(isog_cyclic isoGM) cycG /=. case/cyclicP: cycG => x ->{G} /andP[/cyclicP[y ->] /eqP oy]. by apply: isog_trans (isog_symr _) (Zp_isog y); rewrite /order oy Zp_isog. Qed. Lemma injm_generator G H (f : {morphism G >-> rT}) x : 'injm f -> x \in G -> H \subset G -> generator (f @* H) (f x) = generator H x. Proof. move=> injf Gx sHG; apply/idP/idP; last exact: morph_generator. rewrite -{2}(morphim_invm injf sHG) -{2}(invmE injf Gx). by apply: morph_generator; exact: mem_morphim. Qed. End IsoCyclic. (* Metacyclic groups. *) Section Metacyclic. Variable gT : finGroupType. Implicit Types (A : {set gT}) (G H : {group gT}). Definition metacyclic A := [exists H : {group gT}, [&& cyclic H, H <| A & cyclic (A / H)]]. Lemma metacyclicP A : reflect (exists H : {group gT}, [/\ cyclic H, H <| A & cyclic (A / H)]) (metacyclic A). Proof. exact: 'exists_and3P. Qed. Lemma metacyclic1 : metacyclic 1. Proof. by apply/existsP; exists 1%G; rewrite normal1 trivg_quotient !cyclic1. Qed. Lemma cyclic_metacyclic A : cyclic A -> metacyclic A. Proof. case/cyclicP=> x ->; apply/existsP; exists (<[x]>)%G. by rewrite normal_refl cycle_cyclic trivg_quotient cyclic1. Qed. Lemma metacyclicS G H : H \subset G -> metacyclic G -> metacyclic H. Proof. move=> sHG /metacyclicP[K [cycK nsKG cycGq]]; apply/metacyclicP. exists (H :&: K)%G; rewrite (cyclicS (subsetIr H K)) ?(normalGI sHG) //=. rewrite setIC (isog_cyclic (second_isog _)) ?(cyclicS _ cycGq) ?quotientS //. by rewrite (subset_trans sHG) ?normal_norm. Qed. End Metacyclic. Arguments Scope metacyclic [_ group_scope]. Prenex Implicits metacyclic. Implicit Arguments metacyclicP [gT A]. (* Automorphisms of cyclic groups. *) Section CyclicAutomorphism. Variable gT : finGroupType. Section CycleAutomorphism. Variable a : gT. Section CycleMorphism. Variable n : nat. Definition cyclem of gT := fun x : gT => x ^+ n. Lemma cyclemM : {in <[a]> & , {morph cyclem a : x y / x * y}}. Proof. by move=> x y ax ay; apply: expgMn; exact: (centsP (cycle_abelian a)). Qed. Canonical cyclem_morphism := Morphism cyclemM. End CycleMorphism. Section ZpUnitMorphism. Variable u : {unit 'Z_#[a]}. Lemma injm_cyclem : 'injm (cyclem (val u) a). Proof. apply/subsetP=> x /setIdP[ax]; rewrite !inE -order_dvdn. case: (eqVneq a 1) => [a1 | nta]; first by rewrite a1 cycle1 inE in ax. rewrite -order_eq1 -dvdn1; move/eqnP: (valP u) => /= <-. by rewrite dvdn_gcd {2}Zp_cast ?order_gt1 // order_dvdG. Qed. Lemma im_cyclem : cyclem (val u) a @* <[a]> = <[a]>. Proof. apply/morphim_fixP=> //; first exact: injm_cyclem. by rewrite morphim_cycle ?cycle_id ?cycleX. Qed. Definition Zp_unitm := aut injm_cyclem im_cyclem. End ZpUnitMorphism. Lemma Zp_unitmM : {in units_Zp #[a] &, {morph Zp_unitm : u v / u * v}}. Proof. move=> u v _ _; apply: (eq_Aut (Aut_aut _ _)) => [|x a_x]. by rewrite groupM ?Aut_aut. rewrite permM !autE ?groupX //= /cyclem -expgM. rewrite -expg_mod_order modn_dvdm ?expg_mod_order //. case: (leqP #[a] 1) => [lea1 | lt1a]; last by rewrite Zp_cast ?order_dvdG. by rewrite card_le1_trivg // in a_x; rewrite (set1P a_x) order1 dvd1n. Qed. Canonical Zp_unit_morphism := Morphism Zp_unitmM. Lemma injm_Zp_unitm : 'injm Zp_unitm. Proof. case: (eqVneq a 1) => [a1 | nta]. by rewrite subIset //= card_le1_trivg ?subxx // card_units_Zp a1 order1. apply/subsetP=> /= u /morphpreP[_ /set1P/= um1]. have{um1}: Zp_unitm u a == Zp_unitm 1 a by rewrite um1 morph1. rewrite !autE ?cycle_id // eq_expg_mod_order. by rewrite -[n in _ == _ %[mod n]]Zp_cast ?order_gt1 // !modZp inE. Qed. Lemma generator_coprime m : generator <[a]> (a ^+ m) = coprime #[a] m. Proof. rewrite /generator eq_sym eqEcard cycleX -/#[a] [#|_|]orderXgcd /=. apply/idP/idP=> [le_a_am|co_am]; last by rewrite (eqnP co_am) divn1. have am_gt0: 0 < gcdn #[a] m by rewrite gcdn_gt0 order_gt0. by rewrite /coprime eqn_leq am_gt0 andbT -(@leq_pmul2l #[a]) ?muln1 -?leq_divRL. Qed. Lemma im_Zp_unitm : Zp_unitm @* units_Zp #[a] = Aut <[a]>. Proof. rewrite morphimEdom; apply/setP=> f; pose n := invm (injm_Zpm a) (f a). apply/imsetP/idP=> [[u _ ->] | Af]; first exact: Aut_aut. have [a1 | nta] := eqVneq a 1. by rewrite a1 cycle1 Aut1 in Af; exists 1; rewrite // morph1 (set1P Af). have a_fa: <[a]> = <[f a]>. by rewrite -(autmE Af) -morphim_cycle ?im_autm ?cycle_id. have def_n: a ^+ n = f a. by rewrite -/(Zpm n) invmK // im_Zpm a_fa cycle_id. have co_a_n: coprime #[a].-2.+2 n. by rewrite {1}Zp_cast ?order_gt1 // -generator_coprime def_n; exact/eqP. exists (FinRing.unit 'Z_#[a] co_a_n); rewrite ?inE //. apply: eq_Aut (Af) (Aut_aut _ _) _ => x ax. rewrite autE //= /cyclem; case/cycleP: ax => k ->{x}. by rewrite -(autmE Af) morphX ?cycle_id //= autmE -def_n -!expgM mulnC. Qed. Lemma Zp_unit_isom : isom (units_Zp #[a]) (Aut <[a]>) Zp_unitm. Proof. by apply/isomP; rewrite ?injm_Zp_unitm ?im_Zp_unitm. Qed. Lemma Zp_unit_isog : isog (units_Zp #[a]) (Aut <[a]>). Proof. exact: isom_isog Zp_unit_isom. Qed. Lemma card_Aut_cycle : #|Aut <[a]>| = totient #[a]. Proof. by rewrite -(card_isog Zp_unit_isog) card_units_Zp. Qed. Lemma totient_gen : totient #[a] = #|[set x | generator <[a]> x]|. Proof. have [lea1 | lt1a] := leqP #[a] 1. rewrite /order card_le1_trivg // cards1 (@eq_card1 _ 1) // => x. by rewrite !inE -cycle_eq1 eq_sym. rewrite -(card_injm (injm_invm (injm_Zpm a))) /= ?im_Zpm; last first. by apply/subsetP=> x; rewrite inE; exact: cycle_generator. rewrite -card_units_Zp // cardsE card_sub morphim_invmE; apply: eq_card => /= d. by rewrite !inE /= qualifE /= /Zp lt1a inE /= generator_coprime {1}Zp_cast. Qed. Lemma Aut_cycle_abelian : abelian (Aut <[a]>). Proof. by rewrite -im_Zp_unitm morphim_abelian ?units_Zp_abelian. Qed. End CycleAutomorphism. Variable G : {group gT}. Lemma Aut_cyclic_abelian : cyclic G -> abelian (Aut G). Proof. by case/cyclicP=> x ->; exact: Aut_cycle_abelian. Qed. Lemma card_Aut_cyclic : cyclic G -> #|Aut G| = totient #|G|. Proof. by case/cyclicP=> x ->; exact: card_Aut_cycle. Qed. Lemma sum_ncycle_totient : \sum_(d < #|G|.+1) #|[set <[x]> | x in G & #[x] == d]| * totient d = #|G|. Proof. pose h (x : gT) : 'I_#|G|.+1 := inord #[x]. symmetry; rewrite -{1}sum1_card (partition_big h xpredT) //=. apply: eq_bigr => d _; set Gd := finset _. rewrite -sum_nat_const sum1dep_card -sum1_card (_ : finset _ = Gd); last first. apply/setP=> x; rewrite !inE; apply: andb_id2l => Gx. by rewrite /eq_op /= inordK // ltnS subset_leq_card ?cycle_subG. rewrite (partition_big_imset cycle) {}/Gd; apply: eq_bigr => C /=. case/imsetP=> x /setIdP[Gx /eqP <-] -> {C d}. rewrite sum1dep_card totient_gen; apply: eq_card => y; rewrite !inE /generator. move: Gx; rewrite andbC eq_sym -!cycle_subG /order. by case: eqP => // -> ->; rewrite eqxx. Qed. End CyclicAutomorphism. Lemma sum_totient_dvd n : \sum_(d < n.+1 | d %| n) totient d = n. Proof. case: n => [|[|n']]; try by rewrite big_mkcond !big_ord_recl big_ord0. set n := n'.+2; pose x1 : 'Z_n := 1%R. have ox1: #[x1] = n by rewrite /order -Zp_cycle card_Zp. rewrite -[rhs in _ = rhs]ox1 -[#[_]]sum_ncycle_totient [#|_|]ox1 big_mkcond /=. apply: eq_bigr => d _; rewrite -{2}ox1; case: ifP => [|ndv_dG]; last first. rewrite eq_card0 // => C; apply/imsetP=> [[x /setIdP[Gx oxd] _{C}]]. by rewrite -(eqP oxd) order_dvdG in ndv_dG. move/cycle_sub_group; set Gd := [set _] => def_Gd. rewrite (_ : _ @: _ = @gval _ @: Gd); first by rewrite imset_set1 cards1 mul1n. apply/setP=> C; apply/idP/imsetP=> [| [gC GdC ->{C}]]. case/imsetP=> x /setIdP[_ oxd] ->; exists <[x]>%G => //. by rewrite -def_Gd inE -Zp_cycle subsetT. have:= GdC; rewrite -def_Gd => /setIdP[_ /eqP <-]. by rewrite (set1P GdC) /= mem_imset // inE eqxx (mem_cycle x1). Qed. Section FieldMulCyclic. (***********************************************************************) (* A classic application to finite multiplicative subgroups of fields. *) (***********************************************************************) Import GRing.Theory. Variables (gT : finGroupType) (G : {group gT}). Lemma order_inj_cyclic : {in G &, forall x y, #[x] = #[y] -> <[x]> = <[y]>} -> cyclic G. Proof. move=> ucG; apply: negbNE (contra _ (negbT (ltnn #|G|))) => ncG. rewrite -{2}[#|G|]sum_totient_dvd big_mkcond (bigD1 ord_max) ?dvdnn //=. rewrite -{1}[#|G|]sum_ncycle_totient (bigD1 ord_max) //= -addSn leq_add //. rewrite eq_card0 ?totient_gt0 ?cardG_gt0 // => C. apply/imsetP=> [[x /setIdP[Gx /eqP oxG]]]; case/cyclicP: ncG. by exists x; apply/eqP; rewrite eq_sym eqEcard cycle_subG Gx -oxG /=. elim/big_ind2: _ => // [m1 n1 m2 n2 | d _]; first exact: leq_add. set Gd := _ @: _; case: (set_0Vmem Gd) => [-> | [C]]; first by rewrite cards0. rewrite {}/Gd => /imsetP[x /setIdP[Gx /eqP <-] _ {C d}]. rewrite order_dvdG // (@eq_card1 _ <[x]>) ?mul1n // => C. apply/idP/eqP=> [|-> {C}]; last by rewrite mem_imset // inE Gx eqxx. by case/imsetP=> y /setIdP[Gy /eqP/ucG->]. Qed. Lemma div_ring_mul_group_cyclic (R : unitRingType) (f : gT -> R) : f 1 = 1%R -> {in G &, {morph f : u v / u * v >-> (u * v)%R}} -> {in G^#, forall x, f x - 1 \in GRing.unit}%R -> abelian G -> cyclic G. Proof. move=> f1 fM f1P abelG. have fX n: {in G, {morph f : u / u ^+ n >-> (u ^+ n)%R}}. by case: n => // n x Gx; elim: n => //= n IHn; rewrite expgS fM ?groupX ?IHn. have fU x: x \in G -> f x \in GRing.unit. by move=> Gx; apply/unitrP; exists (f x^-1); rewrite -!fM ?groupV ?gsimp. apply: order_inj_cyclic => x y Gx Gy; set n := #[x] => yn. apply/eqP; rewrite eq_sym eqEcard -[#|_|]/n yn leqnn andbT cycle_subG /=. suff{y Gy yn} ->: <[x]> = G :&: [set z | #[z] %| n] by rewrite !inE Gy yn /=. apply/eqP; rewrite eqEcard subsetI cycle_subG {}Gx /= cardE; set rs := enum _. apply/andP; split; first by apply/subsetP=> y xy; rewrite inE order_dvdG. pose P : {poly R} := ('X^n - 1)%R; have n_gt0: n > 0 by exact: order_gt0. have szP: size P = n.+1 by rewrite size_addl size_polyXn ?size_opp ?size_poly1. rewrite -ltnS -szP -(size_map f) max_ring_poly_roots -?size_poly_eq0 ?{}szP //. apply/allP=> fy /mapP[y]; rewrite mem_enum !inE order_dvdn => /andP[Gy]. move/eqP=> yn1 ->{fy}; apply/eqP. by rewrite !(hornerE, hornerXn) -fX // yn1 f1 subrr. have: uniq rs by exact: enum_uniq. have: all (mem G) rs by apply/allP=> y; rewrite mem_enum; case/setIP. elim: rs => //= y rs IHrs /andP[Gy Grs] /andP[y_rs]; rewrite andbC. move/IHrs=> -> {IHrs}//; apply/allP=> _ /mapP[z rs_z ->]. have{Grs} Gz := allP Grs z rs_z; rewrite /diff_roots -!fM // (centsP abelG) //. rewrite eqxx -[f y]mul1r -(mulgKV y z) fM ?groupM ?groupV //=. rewrite -mulNr -mulrDl unitrMl ?fU ?f1P // !inE. by rewrite groupM ?groupV // andbT -eq_mulgV1; apply: contra y_rs; move/eqP <-. Qed. Lemma field_mul_group_cyclic (F : fieldType) (f : gT -> F) : {in G &, {morph f : u v / u * v >-> (u * v)%R}} -> {in G, forall x, f x = 1%R <-> x = 1} -> cyclic G. Proof. move=> fM f1P; have f1 : f 1 = 1%R by exact/f1P. apply: (div_ring_mul_group_cyclic f1 fM) => [x|]. case/setD1P=> x1 Gx; rewrite unitfE; apply: contra x1. by rewrite subr_eq0 => /eqP/f1P->. apply/centsP=> x Gx y Gy; apply/commgP/eqP. apply/f1P; rewrite ?fM ?groupM ?groupV //. by rewrite mulrCA -!fM ?groupM ?groupV // mulKg mulVg. Qed. End FieldMulCyclic. Lemma field_unit_group_cyclic (F : finFieldType) (G : {group {unit F}}) : cyclic G. Proof. apply: field_mul_group_cyclic FinRing.uval _ _ => // u _. by split=> /eqP ?; exact/eqP. Qed. Section PrimitiveRoots. Open Scope ring_scope. Import GRing.Theory. Lemma has_prim_root (F : fieldType) (n : nat) (rs : seq F) : n > 0 -> all n.-unity_root rs -> uniq rs -> size rs >= n -> has n.-primitive_root rs. Proof. move=> n_gt0 rsn1 Urs; rewrite leq_eqVlt ltnNge max_unity_roots // orbF eq_sym. move/eqP=> sz_rs; pose r := val (_ : seq_sub rs). have rn1 x: r x ^+ n = 1. by apply/eqP; rewrite -unity_rootE (allP rsn1) ?(valP x). have prim_r z: z ^+ n = 1 -> z \in rs. by move/eqP; rewrite -unity_rootE -(mem_unity_roots n_gt0). pose r' := SeqSub (prim_r _ _); pose sG_1 := r' _ (expr1n _ _). have sG_VP: r _ ^+ n.-1 ^+ n = 1. by move=> x; rewrite -exprM mulnC exprM rn1 expr1n. have sG_MP: (r _ * r _) ^+ n = 1 by move=> x y; rewrite exprMn !rn1 mul1r. pose sG_V := r' _ (sG_VP _); pose sG_M := r' _ (sG_MP _ _). have sG_Ag: associative sG_M by move=> x y z; apply: val_inj; rewrite /= mulrA. have sG_1g: left_id sG_1 sG_M by move=> x; apply: val_inj; rewrite /= mul1r. have sG_Vg: left_inverse sG_1 sG_V sG_M. by move=> x; apply: val_inj; rewrite /= -exprSr prednK ?rn1. pose sgT := BaseFinGroupType _ (FinGroup.Mixin sG_Ag sG_1g sG_Vg). pose gT := @FinGroupType sgT sG_Vg. have /cyclicP[x gen_x]: @cyclic gT setT. apply: (@field_mul_group_cyclic gT [set: _] F r) => // x _. by split=> [ri1 | ->]; first exact: val_inj. apply/hasP; exists (r x); first exact: (valP x). have [m prim_x dvdmn] := prim_order_exists n_gt0 (rn1 x). rewrite -((m =P n) _) // eqn_dvd {}dvdmn -sz_rs -(card_seq_sub Urs) -cardsT. rewrite gen_x (@order_dvdn gT) /(_ == _) /= -{prim_x}(prim_expr_order prim_x). by apply/eqP; elim: m => //= m IHm; rewrite exprS expgS /= -IHm. Qed. End PrimitiveRoots. (***********************************************************************) (* Cycles of prime order *) (***********************************************************************) Section AutPrime. Variable gT : finGroupType. Lemma Aut_prime_cycle_cyclic (a : gT) : prime #[a] -> cyclic (Aut <[a]>). Proof. move=> pr_a; have inj_um := injm_Zp_unitm a; have eq_a := Fp_Zcast pr_a. pose fm := cast_ord (esym eq_a) \o val \o invm inj_um. apply: (@field_mul_group_cyclic _ _ _ fm) => [f g Af Ag | f Af] /=. by apply: val_inj; rewrite /= morphM ?im_Zp_unitm //= eq_a. split=> [/= fm1 |->]; last by apply: val_inj; rewrite /= morph1. apply: (injm1 (injm_invm inj_um)); first by rewrite /= im_Zp_unitm. by do 2!apply: val_inj; move/(congr1 val): fm1. Qed. Lemma Aut_prime_cyclic (G : {group gT}) : prime #|G| -> cyclic (Aut G). Proof. move=> pr_G; case/cyclicP: (prime_cyclic pr_G) (pr_G) => x ->. exact: Aut_prime_cycle_cyclic. Qed. End AutPrime. mathcomp-1.5/theories/finmodule.v0000644000175000017500000006500012307636117016155 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. Require Import fintype bigop ssralg finset fingroup morphism perm. Require Import finalg action gproduct commutator cyclic. (******************************************************************************) (* This file regroups constructions and results that are based on the most *) (* primitive version of representation theory -- viewing an abelian group as *) (* the additive group of a (finite) Z-module. This includes the Gaschutz *) (* splitting and transitivity theorem, from which we will later derive the *) (* Schur-Zassenhaus theorem and the elementary abelian special case of *) (* Maschke's theorem, the coprime abelian centraliser/commutator trivial *) (* intersection theorem, from which we will derive that p-groups under coprime*) (* action factor into special groups, and the construction of the transfer *) (* homomorphism and its expansion relative to a cycle, from which we derive *) (* the Higman Focal Subgroup and the Burnside Normal Complement theorems. *) (* The definitions and lemmas for the finite Z-module induced by an abelian *) (* are packaged in an auxiliary FiniteModule submodule: they should not be *) (* needed much outside this file, which contains all the results that exploit *) (* this construction. *) (* FiniteModule defines the Z[N(A)]-module associated with a finite abelian *) (* abelian group A, given a proof abelA : abelian A) : *) (* fmod_of abelA == the type of elements of the module (similar to but *) (* distinct from [subg A]). *) (* fmod abelA x == the injection of x into fmod_of abelA if x \in A, else 0 *) (* fmval u == the projection of u : fmod_of abelA onto A *) (* u ^@ x == the action of x \in 'N(A) on u : fmod_of abelA *) (* The transfer morphism is be constructed from a morphism f : H >-> rT, and *) (* a group G, along with the two assumptions sHG : H \subset G and *) (* abfH : abelian (f @* H): *) (* transfer sGH abfH == the function gT -> FiniteModule.fmod_of abfH that *) (* implements the transfer morphism induced by f on G. *) (* The Lemma transfer_indep states that the transfer morphism can be expanded *) (* using any transversal of the partition HG := rcosets H G of G. *) (* Further, for any g \in G, HG :* <[g]> is also a partition of G (Lemma *) (* rcosets_cycle_partition), and for any transversal X of HG :* <[g]> the *) (* function r mapping x : gT to rcosets (H :* x) <[g]> is (constructively) a *) (* bijection from X to the <[g]>-orbit partition of HG, and Lemma *) (* transfer_pcycle_def gives a simplified expansion of the transfer morphism. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope GRing.Theory FinRing.Theory. Local Open Scope ring_scope. Module FiniteModule. Reserved Notation "u ^@ x" (at level 31, left associativity). Inductive fmod_of (gT : finGroupType) (A : {group gT}) (abelA : abelian A) := Fmod x & x \in A. Bind Scope ring_scope with fmod_of. Section OneFinMod. Let f2sub (gT : finGroupType) (A : {group gT}) (abA : abelian A) := fun u : fmod_of abA => let : Fmod x Ax := u in Subg Ax : FinGroup.arg_sort _. Local Coercion f2sub : fmod_of >-> FinGroup.arg_sort. Variables (gT : finGroupType) (A : {group gT}) (abelA : abelian A). Local Notation fmodA := (fmod_of abelA). Implicit Types (x y z : gT) (u v w : fmodA). Let sub2f (s : [subg A]) := Fmod abelA (valP s). Definition fmval u := val (f2sub u). Canonical fmod_subType := [subType for fmval]. Local Notation valA := (@val _ _ fmod_subType) (only parsing). Definition fmod_eqMixin := Eval hnf in [eqMixin of fmodA by <:]. Canonical fmod_eqType := Eval hnf in EqType fmodA fmod_eqMixin. Definition fmod_choiceMixin := [choiceMixin of fmodA by <:]. Canonical fmod_choiceType := Eval hnf in ChoiceType fmodA fmod_choiceMixin. Definition fmod_countMixin := [countMixin of fmodA by <:]. Canonical fmod_countType := Eval hnf in CountType fmodA fmod_countMixin. Canonical fmod_subCountType := Eval hnf in [subCountType of fmodA]. Definition fmod_finMixin := [finMixin of fmodA by <:]. Canonical fmod_finType := Eval hnf in FinType fmodA fmod_finMixin. Canonical fmod_subFinType := Eval hnf in [subFinType of fmodA]. Definition fmod x := sub2f (subg A x). Definition actr u x := if x \in 'N(A) then fmod (fmval u ^ x) else u. Definition fmod_opp u := sub2f u^-1. Definition fmod_add u v := sub2f (u * v). Fact fmod_add0r : left_id (sub2f 1) fmod_add. Proof. move=> u; apply: val_inj; exact: mul1g. Qed. Fact fmod_addrA : associative fmod_add. Proof. move=> u v w; apply: val_inj; exact: mulgA. Qed. Fact fmod_addNr : left_inverse (sub2f 1) fmod_opp fmod_add. Proof. move=> u; apply: val_inj; exact: mulVg. Qed. Fact fmod_addrC : commutative fmod_add. Proof. case=> x Ax [y Ay]; apply: val_inj; exact: (centsP abelA). Qed. Definition fmod_zmodMixin := ZmodMixin fmod_addrA fmod_addrC fmod_add0r fmod_addNr. Canonical fmod_zmodType := Eval hnf in ZmodType fmodA fmod_zmodMixin. Canonical fmod_finZmodType := Eval hnf in [finZmodType of fmodA]. Canonical fmod_baseFinGroupType := Eval hnf in [baseFinGroupType of fmodA for +%R]. Canonical fmod_finGroupType := Eval hnf in [finGroupType of fmodA for +%R]. Lemma fmodP u : val u \in A. Proof. exact: valP. Qed. Lemma fmod_inj : injective fmval. Proof. exact: val_inj. Qed. Lemma congr_fmod u v : u = v -> fmval u = fmval v. Proof. exact: congr1. Qed. Lemma fmvalA : {morph valA : x y / x + y >-> (x * y)%g}. Proof. by []. Qed. Lemma fmvalN : {morph valA : x / - x >-> x^-1%g}. Proof. by []. Qed. Lemma fmval0 : valA 0 = 1%g. Proof. by []. Qed. Canonical fmval_morphism := @Morphism _ _ setT fmval (in2W fmvalA). Definition fmval_sum := big_morph fmval fmvalA fmval0. Lemma fmvalZ n : {morph valA : x / x *+ n >-> (x ^+ n)%g}. Proof. by move=> u; rewrite /= morphX ?inE. Qed. Lemma fmodKcond x : val (fmod x) = if x \in A then x else 1%g. Proof. by rewrite /= /fmval /= val_insubd. Qed. Lemma fmodK : {in A, cancel fmod val}. Proof. exact: subgK. Qed. Lemma fmvalK : cancel val fmod. Proof. by case=> x Ax; apply: val_inj; rewrite /fmod /= sgvalK. Qed. Lemma fmod1 : fmod 1 = 0. Proof. by rewrite -fmval0 fmvalK. Qed. Lemma fmodM : {in A &, {morph fmod : x y / (x * y)%g >-> x + y}}. Proof. by move=> x y Ax Ay /=; apply: val_inj; rewrite /fmod morphM. Qed. Canonical fmod_morphism := Morphism fmodM. Lemma fmodX n : {in A, {morph fmod : x / (x ^+ n)%g >-> x *+ n}}. Proof. exact: morphX. Qed. Lemma fmodV : {morph fmod : x / x^-1%g >-> - x}. Proof. move=> x; apply: val_inj; rewrite fmvalN !fmodKcond groupV. by case: (x \in A); rewrite ?invg1. Qed. Lemma injm_fmod : 'injm fmod. Proof. apply/injmP=> x y Ax Ay []; move/val_inj; exact: (injmP (injm_subg A)). Qed. Notation "u ^@ x" := (actr u x) : ring_scope. Lemma fmvalJcond u x : val (u ^@ x) = if x \in 'N(A) then val u ^ x else val u. Proof. by case: ifP => Nx; rewrite /actr Nx ?fmodK // memJ_norm ?fmodP. Qed. Lemma fmvalJ u x : x \in 'N(A) -> val (u ^@ x) = val u ^ x. Proof. by move=> Nx; rewrite fmvalJcond Nx. Qed. Lemma fmodJ x y : y \in 'N(A) -> fmod (x ^ y) = fmod x ^@ y. Proof. move=> Ny; apply: val_inj; rewrite fmvalJ ?fmodKcond ?memJ_norm //. by case: ifP => // _; rewrite conj1g. Qed. Fact actr_is_action : is_action 'N(A) actr. Proof. split=> [a u v eq_uv_a | u a b Na Nb]. case Na: (a \in 'N(A)); last by rewrite /actr Na in eq_uv_a. by apply: val_inj; apply: (conjg_inj a); rewrite -!fmvalJ ?eq_uv_a. by apply: val_inj; rewrite !fmvalJ ?groupM ?conjgM. Qed. Canonical actr_action := Action actr_is_action. Notation "''M'" := actr_action (at level 8) : action_scope. Lemma act0r x : 0 ^@ x = 0. Proof. by rewrite /actr conj1g morph1 if_same. Qed. Lemma actAr x : {morph actr^~ x : u v / u + v}. Proof. by move=> u v; apply: val_inj; rewrite !(fmvalA, fmvalJcond) conjMg; case: ifP. Qed. Definition actr_sum x := big_morph _ (actAr x) (act0r x). Lemma actNr x : {morph actr^~ x : u / - u}. Proof. by move=> u; apply: (addrI (u ^@ x)); rewrite -actAr !subrr act0r. Qed. Lemma actZr x n : {morph actr^~ x : u / u *+ n}. Proof. by move=> u; elim: n => [|n IHn]; rewrite ?act0r // !mulrS actAr IHn. Qed. Fact actr_is_groupAction : is_groupAction setT 'M. Proof. move=> a Na /=; rewrite inE; apply/andP; split. by apply/subsetP=> u _; rewrite inE. by apply/morphicP=> u v _ _; rewrite !permE /= actAr. Qed. Canonical actr_groupAction := GroupAction actr_is_groupAction. Notation "''M'" := actr_groupAction (at level 8) : groupAction_scope. Lemma actr1 u : u ^@ 1 = u. Proof. exact: act1. Qed. Lemma actrM : {in 'N(A) &, forall x y u, u ^@ (x * y) = u ^@ x ^@ y}. Proof. by move=> x y Nx Ny /= u; apply: val_inj; rewrite !fmvalJ ?conjgM ?groupM. Qed. Lemma actrK x : cancel (actr^~ x) (actr^~ x^-1%g). Proof. move=> u; apply: val_inj; rewrite !fmvalJcond groupV. by case: ifP => -> //; rewrite conjgK. Qed. Lemma actrKV x : cancel (actr^~ x^-1%g) (actr^~ x). Proof. by move=> u; rewrite /= -{2}(invgK x) actrK. Qed. End OneFinMod. Bind Scope ring_scope with fmod_of. Prenex Implicits fmval fmod actr. Notation "u ^@ x" := (actr u x) : ring_scope. Notation "''M'" := actr_action (at level 8) : action_scope. Notation "''M'" := actr_groupAction : groupAction_scope. End FiniteModule. Canonical FiniteModule.fmod_subType. Canonical FiniteModule.fmod_eqType. Canonical FiniteModule.fmod_choiceType. Canonical FiniteModule.fmod_countType. Canonical FiniteModule.fmod_finType. Canonical FiniteModule.fmod_subCountType. Canonical FiniteModule.fmod_subFinType. Canonical FiniteModule.fmod_zmodType. Canonical FiniteModule.fmod_finZmodType. Canonical FiniteModule.fmod_baseFinGroupType. Canonical FiniteModule.fmod_finGroupType. (* Still allow ring notations, but give priority to groups now. *) Import FiniteModule GroupScope. Section Gaschutz. Variables (gT : finGroupType) (G H P : {group gT}). Implicit Types K L : {group gT}. Hypotheses (nsHG : H <| G) (sHP : H \subset P) (sPG : P \subset G). Hypotheses (abelH : abelian H) (coHiPG : coprime #|H| #|G : P|). Let sHG := normal_sub nsHG. Let nHG := subsetP (normal_norm nsHG). Let m := (expg_invn H #|G : P|). Implicit Types a b : fmod_of abelH. Local Notation fmod := (fmod abelH). Theorem Gaschutz_split : [splits G, over H] = [splits P, over H]. Proof. apply/splitsP/splitsP=> [[K /complP[tiHK eqHK]] | [Q /complP[tiHQ eqHQ]]]. exists (K :&: P)%G; rewrite inE setICA (setIidPl sHP) setIC tiHK eqxx. by rewrite group_modl // eqHK (sameP eqP setIidPr). have sQP: Q \subset P by rewrite -eqHQ mulG_subr. pose rP x := repr (P :* x); pose pP x := x * (rP x)^-1. have PpP x: pP x \in P by rewrite -mem_rcoset rcoset_repr rcoset_refl. have rPmul x y: x \in P -> rP (x * y) = rP y. by move=> Px; rewrite /rP rcosetM rcoset_id. pose pQ x := remgr H Q x; pose rH x := pQ (pP x) * rP x. have pQhq: {in H & Q, forall h q, pQ (h * q) = q} by exact: remgrMid. have pQmul: {in P &, {morph pQ : x y / x * y}}. apply: remgrM; [exact/complP | exact: normalS (nsHG)]. have HrH x: rH x \in H :* x. by rewrite rcoset_sym mem_rcoset invMg mulgA mem_divgr // eqHQ PpP. have GrH x: x \in G -> rH x \in G. move=> Gx; case/rcosetP: (HrH x) => y Hy ->. by rewrite groupM // (subsetP sHG). have rH_Pmul x y: x \in P -> rH (x * y) = pQ x * rH y. by move=> Px; rewrite /rH mulgA -pQmul; first by rewrite /pP rPmul ?mulgA. have rH_Hmul h y: h \in H -> rH (h * y) = rH y. by move=> Hh; rewrite rH_Pmul ?(subsetP sHP) // -(mulg1 h) pQhq ?mul1g. pose mu x y := fmod ((rH x * rH y)^-1 * rH (x * y)). pose nu y := (\sum_(Px in rcosets P G) mu (repr Px) y)%R. have rHmul: {in G &, forall x y, rH (x * y) = rH x * rH y * val (mu x y)}. move=> x y Gx Gy; rewrite /= fmodK ?mulKVg // -mem_lcoset lcoset_sym. rewrite -norm_rlcoset; last by rewrite nHG ?GrH ?groupM. by rewrite (rcoset_transl (HrH _)) -rcoset_mul ?nHG ?GrH // mem_mulg. have actrH a x: x \in G -> (a ^@ rH x = a ^@ x)%R. move=> Gx; apply: val_inj; rewrite /= !fmvalJ ?nHG ?GrH //. case/rcosetP: (HrH x) => b /(fmodK abelH) <- ->; rewrite conjgM. by congr (_ ^ _); rewrite conjgE -fmvalN -!fmvalA (addrC a) addKr. have mu_Pmul x y z: x \in P -> mu (x * y) z = mu y z. move=> Px; congr fmod; rewrite -mulgA !(rH_Pmul x) ?rPmul //. by rewrite -mulgA invMg -mulgA mulKg. have mu_Hmul x y z: x \in G -> y \in H -> mu x (y * z) = mu x z. move=> Gx Hy; congr fmod; rewrite (mulgA x) (conjgCV x) -mulgA 2?rH_Hmul //. by rewrite -mem_conjg (normP _) ?nHG. have{mu_Hmul} nu_Hmul y z: y \in H -> nu (y * z) = nu z. move=> Hy; apply: eq_bigr => _ /rcosetsP[x Gx ->]; apply: mu_Hmul y z _ Hy. by rewrite -(groupMl _ (subsetP sPG _ (PpP x))) mulgKV. have cocycle_mu: {in G & &, forall x y z, mu (x * y)%g z + mu x y ^@ z = mu y z + mu x (y * z)%g}%R. - move=> x y z Gx Gy Gz; apply: val_inj. apply: (mulgI (rH x * rH y * rH z)). rewrite -(actrH _ _ Gz) addrC fmvalA fmvalJ ?nHG ?GrH //. rewrite mulgA -(mulgA _ (rH z)) -conjgC mulgA -!rHmul ?groupM //. by rewrite mulgA -mulgA -2!(mulgA (rH x)) -!rHmul ?groupM. move: mu => mu in rHmul mu_Pmul cocycle_mu nu nu_Hmul. have{cocycle_mu} cocycle_nu: {in G &, forall y z, nu z + nu y ^@ z = mu y z *+ #|G : P| + nu (y * z)%g}%R. - move=> y z Gy Gz; rewrite /= (actr_sum z) /=. have ->: (nu z = \sum_(Px in rcosets P G) mu (repr Px * y)%g z)%R. rewrite /nu (reindex_acts _ (actsRs_rcosets P G) Gy) /=. apply: eq_bigr => _ /rcosetsP[x Gx /= ->]. rewrite rcosetE -rcosetM. case: repr_rcosetP=> p1 Pp1; case: repr_rcosetP=> p2 Pp2. by rewrite -mulgA [x * y]lock !mu_Pmul. rewrite -sumr_const -!big_split /=; apply: eq_bigr => _ /rcosetsP[x Gx ->]. rewrite -cocycle_mu //; case: repr_rcosetP => p1 Pp1. by rewrite groupMr // (subsetP sPG). move: nu => nu in nu_Hmul cocycle_nu. pose f x := rH x * val (nu x *+ m)%R. have{cocycle_nu} fM: {in G &, {morph f : x y / x * y}}. move=> x y Gx Gy; rewrite /f ?rHmul // -3!mulgA; congr (_ * _). rewrite (mulgA _ (rH y)) (conjgC _ (rH y)) -mulgA; congr (_ * _). rewrite -fmvalJ ?actrH ?nHG ?GrH // -!fmvalA actZr -mulrnDl. rewrite -(addrC (nu y)) cocycle_nu // mulrnDl !fmvalA; congr (_ * _). by rewrite !fmvalZ expgK ?fmodP. exists (Morphism fM @* G)%G; apply/complP; split. apply/trivgP/subsetP=> x /setIP[Hx /morphimP[y _ Gy eq_x]]. apply/set1P; move: Hx; rewrite {x}eq_x /= groupMr ?subgP //. rewrite -{1}(mulgKV y (rH y)) groupMl -?mem_rcoset // => Hy. by rewrite -(mulg1 y) /f nu_Hmul // rH_Hmul //; exact: (morph1 (Morphism fM)). apply/setP=> x; apply/mulsgP/idP=> [[h y Hh fy ->{x}] | Gx]. rewrite groupMl; last exact: (subsetP sHG). case/morphimP: fy => z _ Gz ->{h Hh y}. by rewrite /= /f groupMl ?GrH // (subsetP sHG) ?fmodP. exists (x * (f x)^-1) (f x); last first; first by rewrite mulgKV. by apply/morphimP; exists x. rewrite -groupV invMg invgK -mulgA (conjgC (val _)) mulgA. by rewrite groupMl -(mem_rcoset, mem_conjg) // (normP _) ?nHG ?fmodP. Qed. Theorem Gaschutz_transitive : {in [complements to H in G] &, forall K L, K :&: P = L :&: P -> exists2 x, x \in H & L :=: K :^ x}. Proof. move=> K L /=; set Q := K :&: P => /complP[tiHK eqHK] cpHL QeqLP. have [trHL eqHL] := complP cpHL. pose nu x := fmod (divgr H L x^-1). have sKG: {subset K <= G} by apply/subsetP; rewrite -eqHK mulG_subr. have sLG: {subset L <= G} by apply/subsetP; rewrite -eqHL mulG_subr. have val_nu x: x \in G -> val (nu x) = divgr H L x^-1. by move=> Gx; rewrite fmodK // mem_divgr // eqHL groupV. have nu_cocycle: {in G &, forall x y, nu (x * y)%g = nu x ^@ y + nu y}%R. move=> x y Gx Gy; apply: val_inj; rewrite fmvalA fmvalJ ?nHG //. rewrite !val_nu ?groupM // /divgr conjgE !mulgA mulgK. by rewrite !(invMg, remgrM cpHL) ?groupV ?mulgA. have nuL x: x \in L -> nu x = 0%R. move=> Lx; apply: val_inj; rewrite val_nu ?sLG //. by rewrite /divgr remgr_id ?groupV ?mulgV. exists (fmval ((\sum_(X in rcosets Q K) nu (repr X)) *+ m)). exact: fmodP. apply/eqP; rewrite eq_sym eqEcard; apply/andP; split; last first. by rewrite cardJg -(leq_pmul2l (cardG_gt0 H)) -!TI_cardMg // eqHL eqHK. apply/subsetP=> _ /imsetP[x Kx ->]; rewrite conjgE mulgA (conjgC _ x). have Gx: x \in G by rewrite sKG. rewrite conjVg -mulgA -fmvalJ ?nHG // -fmvalN -fmvalA (_ : _ + _ = nu x)%R. by rewrite val_nu // mulKVg groupV mem_remgr // eqHL groupV. rewrite actZr -!mulNrn -mulrnDl actr_sum. rewrite addrC (reindex_acts _ (actsRs_rcosets _ K) Kx) -sumrB /= -/Q. rewrite (eq_bigr (fun _ => nu x)) => [|_ /imsetP[y Ky ->]]; last first. rewrite !rcosetE -rcosetM QeqLP. case: repr_rcosetP => z /setIP[Lz _]; case: repr_rcosetP => t /setIP[Lt _]. rewrite !nu_cocycle ?groupM ?(sKG y) // ?sLG //. by rewrite (nuL z) ?(nuL t) // !act0r !add0r addrC addKr. apply: val_inj; rewrite sumr_const !fmvalZ. rewrite -{2}(expgK coHiPG (fmodP (nu x))); congr (_ ^+ _ ^+ _). rewrite -[#|_|]divgS ?subsetIl // -(divnMl (cardG_gt0 H)). rewrite -!TI_cardMg //; last by rewrite setIA setIAC (setIidPl sHP). by rewrite group_modl // eqHK (setIidPr sPG) divgS. Qed. End Gaschutz. (* This is the TI part of B & G, Proposition 1.6(d). *) (* We go with B & G rather than Aschbacher and will derive 1.6(e) from (d), *) (* rather than the converse, because the derivation of 24.6 from 24.3 in *) (* Aschbacher requires a separate reduction to p-groups to yield 1.6(d), *) (* making it altogether longer than the direct Gaschutz-style proof. *) (* This Lemma is used in maximal.v for the proof of Aschbacher 24.7. *) Lemma coprime_abel_cent_TI (gT : finGroupType) (A G : {group gT}) : A \subset 'N(G) -> coprime #|G| #|A| -> abelian G -> 'C_[~: G, A](A) = 1. Proof. move=> nGA coGA abG; pose f x := val (\sum_(a in A) fmod abG x ^@ a)%R. have fM: {in G &, {morph f : x y / x * y}}. move=> x y Gx Gy /=; rewrite -fmvalA -big_split /=; congr (fmval _). by apply: eq_bigr => a Aa; rewrite fmodM // actAr. have nfA x a: a \in A -> f (x ^ a) = f x. move=> Aa; rewrite {2}/f (reindex_inj (mulgI a)) /=; congr (fmval _). apply: eq_big => [b | b Ab]; first by rewrite groupMl. by rewrite -!fmodJ ?groupM ?(subsetP nGA) // conjgM. have kerR: [~: G, A] \subset 'ker (Morphism fM). rewrite gen_subG; apply/subsetP=> xa; case/imset2P=> x a Gx Aa -> {xa}. have Gxa: x ^ a \in G by rewrite memJ_norm ?(subsetP nGA). rewrite commgEl; apply/kerP; rewrite (groupM, morphM) ?(groupV, morphV) //=. by rewrite nfA ?mulVg. apply/trivgP; apply/subsetP=> x /setIP[Rx cAx]; apply/set1P. have Gx: x \in G by apply: subsetP Rx; rewrite commg_subl. rewrite -(expgK coGA Gx) (_ : x ^+ _ = 1) ?expg1n //. rewrite -(fmodK abG Gx) -fmvalZ -(mker (subsetP kerR x Rx)); congr fmval. rewrite -GRing.sumr_const; apply: eq_bigr => a Aa. by rewrite -fmodJ ?(subsetP nGA) // /conjg (centP cAx) // mulKg. Qed. Section Transfer. Variables (gT aT : finGroupType) (G H : {group gT}). Variable alpha : {morphism H >-> aT}. Hypotheses (sHG : H \subset G) (abelA : abelian (alpha @* H)). Local Notation HG := (rcosets (gval H) (gval G)). Fact transfer_morph_subproof : H \subset alpha @*^-1 (alpha @* H). Proof. by rewrite -sub_morphim_pre. Qed. Let fmalpha := restrm transfer_morph_subproof (fmod abelA \o alpha). Let V (rX : {set gT} -> gT) g := \sum_(Hx in rcosets H G) fmalpha (rX Hx * g * (rX (Hx :* g))^-1). Definition transfer g := V repr g. (* This is Aschbacher (37.2). *) Lemma transferM : {in G &, {morph transfer : x y / (x * y)%g >-> x + y}}. Proof. move=> s t Gs Gt /=. rewrite [transfer t](reindex_acts 'Rs _ Gs) ?actsRs_rcosets //= -big_split /=. apply: eq_bigr => _ /rcosetsP[x Gx ->]; rewrite !rcosetE -!rcosetM. rewrite -zmodMgE -morphM -?mem_rcoset; first by rewrite !mulgA mulgKV rcosetM. by rewrite rcoset_repr rcosetM mem_rcoset mulgK mem_repr_rcoset. by rewrite rcoset_repr (rcosetM _ _ t) mem_rcoset mulgK mem_repr_rcoset. Qed. Canonical transfer_morphism := Morphism transferM. (* This is Aschbacher (37.1). *) Lemma transfer_indep X (rX := transversal_repr 1 X) : is_transversal X HG G -> {in G, transfer =1 V rX}. Proof. move=> trX g Gg; have mem_rX := repr_mem_pblock trX 1; rewrite -/rX in mem_rX. apply: (addrI (\sum_(Hx in HG) fmalpha (repr Hx * (rX Hx)^-1))). rewrite {1}(reindex_acts 'Rs _ Gg) ?actsRs_rcosets // -!big_split /=. apply: eq_bigr => _ /rcosetsP[x Gx ->]; rewrite !rcosetE -!rcosetM. case: repr_rcosetP => h1 Hh1; case: repr_rcosetP => h2 Hh2. have: H :* (x * g) \in rcosets H G by rewrite -rcosetE mem_imset ?groupM. have: H :* x \in rcosets H G by rewrite -rcosetE mem_imset. case/mem_rX/rcosetP=> h3 Hh3 -> /mem_rX/rcosetP[h4 Hh4 ->]. rewrite -!(mulgA h1) -!(mulgA h2) -!(mulgA h3) !(mulKVg, invMg). by rewrite addrC -!zmodMgE -!morphM ?groupM ?groupV // -!mulgA !mulKg. Qed. Section FactorTransfer. Variable g : gT. Hypothesis Gg : g \in G. Let sgG : <[g]> \subset G. Proof. by rewrite cycle_subG. Qed. Let H_g_rcosets x : {set {set gT}} := rcosets (H :* x) <[g]>. Let n_ x := #|<[g]> : H :* x|. Lemma mulg_exp_card_rcosets x : x * (g ^+ n_ x) \in H :* x. Proof. rewrite /n_ /indexg -orbitRs -pcycle_actperm ?inE //. rewrite -{2}(iter_pcycle (actperm 'Rs g) (H :* x)) -permX -morphX ?inE //. by rewrite actpermE //= rcosetE -rcosetM rcoset_refl. Qed. Let HGg : {set {set {set gT}}} := orbit 'Rs <[g]> @: HG. Let partHG : partition HG G := rcosets_partition sHG. Let actsgHG : [acts <[g]>, on HG | 'Rs]. Proof. exact: subset_trans sgG (actsRs_rcosets H G). Qed. Let partHGg : partition HGg HG := orbit_partition actsgHG. Let injHGg : {in HGg &, injective cover}. Proof. by have [] := partition_partition partHG partHGg. Qed. Let defHGg : HG :* <[g]> = cover @: HGg. Proof. rewrite -imset_comp [_ :* _]imset2_set1r; apply: eq_imset => Hx /=. by rewrite cover_imset -curry_imset2r. Qed. Lemma rcosets_cycle_partition : partition (HG :* <[g]>) G. Proof. by rewrite defHGg; have [] := partition_partition partHG partHGg. Qed. Variable X : {set gT}. Hypothesis trX : is_transversal X (HG :* <[g]>) G. Let sXG : {subset X <= G}. Proof. exact/subsetP/(transversal_sub trX). Qed. Lemma rcosets_cycle_transversal : H_g_rcosets @: X = HGg. Proof. have sHXgHGg x: x \in X -> H_g_rcosets x \in HGg. by move/sXG=> Gx; apply: mem_imset; rewrite -rcosetE mem_imset. apply/setP=> Hxg; apply/imsetP/idP=> [[x /sHXgHGg HGgHxg -> //] | HGgHxg]. have [_ /rcosetsP[z Gz ->] ->] := imsetP HGgHxg. pose Hzg := H :* z * <[g]>; pose x := transversal_repr 1 X Hzg. have HGgHzg: Hzg \in HG :* <[g]>. by rewrite mem_mulg ?set11 // -rcosetE mem_imset. have Hzg_x: x \in Hzg by rewrite (repr_mem_pblock trX). exists x; first by rewrite (repr_mem_transversal trX). case/mulsgP: Hzg_x => y u /rcoset_transl <- /(orbit_act 'Rs) <- -> /=. by rewrite rcosetE -rcosetM. Qed. Local Notation defHgX := rcosets_cycle_transversal. Let injHg: {in X &, injective H_g_rcosets}. Proof. apply/imset_injP; rewrite defHgX (card_transversal trX) defHGg. by rewrite (card_in_imset injHGg). Qed. Lemma sum_index_rcosets_cycle : (\sum_(x in X) n_ x)%N = #|G : H|. Proof. by rewrite [#|G : H|](card_partition partHGg) -defHgX big_imset. Qed. Lemma transfer_cycle_expansion : transfer g = \sum_(x in X) fmalpha ((g ^+ n_ x) ^ x^-1). Proof. pose Y := \bigcup_(x in X) [set x * g ^+ i | i : 'I_(n_ x)]. pose rY := transversal_repr 1 Y. pose pcyc x := pcycle (actperm 'Rs g) (H :* x). pose traj x := traject (actperm 'Rs g) (H :* x) #|pcyc x|. have Hgr_eq x: H_g_rcosets x = pcyc x. by rewrite /H_g_rcosets -orbitRs -pcycle_actperm ?inE. have pcyc_eq x: pcyc x =i traj x by exact: pcycle_traject. have uniq_traj x: uniq (traj x) by apply: uniq_traject_pcycle. have n_eq x: n_ x = #|pcyc x| by rewrite -Hgr_eq. have size_traj x: size (traj x) = n_ x by rewrite n_eq size_traject. have nth_traj x j: j < n_ x -> nth (H :* x) (traj x) j = H :* (x * g ^+ j). move=> lt_j_x; rewrite nth_traject -?n_eq //. by rewrite -permX -morphX ?inE // actpermE //= rcosetE rcosetM. have sYG: Y \subset G. apply/bigcupsP=> x Xx; apply/subsetP=> _ /imsetP[i _ ->]. by rewrite groupM ?groupX // sXG. have trY: is_transversal Y HG G. apply/and3P; split=> //; apply/forall_inP=> Hy. have /and3P[/eqP <- _ _] := partHGg; rewrite -defHgX cover_imset. case/bigcupP=> x Xx; rewrite Hgr_eq pcyc_eq => /trajectP[i]. rewrite -n_eq -permX -morphX ?in_setT // actpermE /= rcosetE -rcosetM => lti. set y := x * _ => ->{Hy}; pose oi := Ordinal lti. have Yy: y \in Y by apply/bigcupP; exists x => //; apply/imsetP; exists oi. apply/cards1P; exists y; apply/esym/eqP. rewrite eqEsubset sub1set inE Yy rcoset_refl. apply/subsetP=> _ /setIP[/bigcupP[x' Xx' /imsetP[j _ ->]] Hy_x'gj]. have eq_xx': x = x'. apply: (pblock_inj trX) => //; have /andP[/and3P[_ tiX _] _] := trX. have HGgHyg: H :* y * <[g]> \in HG :* <[g]>. by rewrite mem_mulg ?set11 // -rcosetE mem_imset ?(subsetP sYG). rewrite !(def_pblock tiX HGgHyg) //. by rewrite -[x'](mulgK (g ^+ j)) mem_mulg // groupV mem_cycle. by rewrite -[x](mulgK (g ^+ i)) mem_mulg ?rcoset_refl // groupV mem_cycle. apply/set1P; rewrite /y eq_xx'; congr (_ * _ ^+ _) => //; apply/eqP. rewrite -(@nth_uniq _ (H :* x) (traj x)) ?size_traj // ?eq_xx' //. by rewrite !nth_traj ?(rcoset_transl Hy_x'gj) // -eq_xx'. have rYE x i : x \in X -> i < n_ x -> rY (H :* x :* g ^+ i) = x * g ^+ i. move=> Xx lt_i_x; rewrite -rcosetM; apply: (canLR_in (pblockK trY 1)). by apply/bigcupP; exists x => //; apply/imsetP; exists (Ordinal lt_i_x). apply/esym/def_pblock; last exact: rcoset_refl; first by case/and3P: partHG. by rewrite -rcosetE mem_imset ?groupM ?groupX // sXG. rewrite (transfer_indep trY Gg) /V -/rY (set_partition_big _ partHGg) /=. rewrite -defHgX big_imset /=; last first. apply/imset_injP; rewrite defHgX (card_transversal trX) defHGg. by rewrite (card_in_imset injHGg). apply eq_bigr=> x Xx; rewrite Hgr_eq (eq_bigl _ _ (pcyc_eq x)) -big_uniq //=. have n_gt0: 0 < n_ x by rewrite indexg_gt0. rewrite /traj -n_eq; case def_n: (n_ x) (n_gt0) => // [n] _. rewrite conjgE invgK -{1}[H :* x]rcoset1 -{1}(expg0 g). elim: {1 3}n 0%N (addn0 n) => [|m IHm] i def_i /=. rewrite big_seq1 {i}[i]def_i rYE // ?def_n //. rewrite -(mulgA _ _ g) -rcosetM -expgSr -[(H :* x) :* _]rcosetE. rewrite -actpermE morphX ?inE // permX // -{2}def_n n_eq iter_pcycle mulgA. by rewrite -[H :* x]rcoset1 (rYE _ 0%N) ?mulg1. rewrite big_cons rYE //; last by rewrite def_n -def_i ltnS leq_addl. rewrite permE /= rcosetE -rcosetM -(mulgA _ _ g) -expgSr. rewrite addSnnS in def_i; rewrite IHm //. rewrite rYE //; last by rewrite def_n -def_i ltnS leq_addl. by rewrite mulgV [fmalpha 1]morph1 add0r. Qed. End FactorTransfer. End Transfer. mathcomp-1.5/theories/gfunctor.v0000644000175000017500000004652012307636117016030 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat fintype bigop finset. Require Import fingroup morphism automorphism quotient gproduct. (******************************************************************************) (* This file provides basic interfaces for the notion of "generic" *) (* characteristic subgroups; these amount to subfunctors of the identity *) (* functor in some category of groups. *) (* See "Generic Proof Tools And Finite Group Theory", *) (* Francois Garillot, PhD, 2011, Chapter 3. *) (* The implementation proposed here is fairly basic, relying on first order *) (* function matching and on structure telescopes, both of which are somewhat *) (* limited and fragile. It should switch in the future to more general and *) (* more robust quotation matching. *) (* The definitions in this file (types, properties and structures) are all *) (* packaged under the GFunctor submodule, i.e., client code should refer to *) (* GFunctor.continuous, GFunctor.map, etc. Notations, Coercions and Lemmas *) (* are exported and thus directly available, however. *) (* We provide the following: *) (* object_map == the type of the (polymorphic) object map of a group *) (* functor; the %gF scope is bound to object_map. *) (* := forall gT : finGroupType, {set gT} -> {set gT}. *) (* We define two operations on object_map (with notations in the %gF scope): *) (* F1 \o F2 == the composite map; (F1 \o F2) G expands to F1 (F2 G). *) (* F1 %% F2 == F1 computed modulo F2; we have *) (* (F1 %% F2) G / F2 G = F1 (G / F2 G) *) (* We define the following (type-polymorphic) properties of an object_map F: *) (* group_valued F <-> F G is a group when G is a group *) (* closed F <-> F G is a subgroup o fG when G is a group *) (* continuous F <-> F is continuous with respect to morphism image: *) (* for any f : {morphism G >-> ..}, f @* (F G) is a *) (* a subgroup of F (f @* G); equivalently, F is *) (* functorial in the category Grp of groups. *) (* Most common "characteristic subgroup" are produced *) (* continuous object maps. *) (* iso_continuous F <-> F is continuous with respect to isomorphism image; *) (* equivalently, F is functorial in the Grp groupoid. *) (* The Puig and the Thompson J subgroups are examples *) (* of iso_continuous maps that are not continuous. *) (* pcontinuous F <-> F is continuous with respect to partial morphism *) (* image, i.e., functorial in the category of groups *) (* and partial morphisms. The center and p-core are *) (* examples of pcontinuous maps. *) (* hereditary F <-> inclusion in the image of F is hereditary, i.e., *) (* for any subgroup H of G, the intersection of H with *) (* F G is included in H. Note that F is pcontinuous *) (* iff it is continuous and hereditary; indeed proofs *) (* of pcontinuous F coerce to proofs of hereditary F *) (* and continuous F. *) (* monotonic F <-> F is monotonic with respect to inclusion: for any *) (* subgroup H of G, F H is a subgroup of F G. The *) (* derived and lower central series are examples of *) (* monotonic maps. *) (* Four structures provide interfaces to these properties: *) (* GFunctor.iso_map == structure for object maps that are group_valued, *) (* closed, and iso_continuous. *) (* [igFun by Fsub & !Fcont] == the iso_map structure for an object map F *) (* such that F G is canonically a group when G is, and *) (* given Fsub : closed F and Fcont : iso_continuous F. *) (* [igFun by Fsub & Fcont] == as above, but expecting Fcont : continuous F. *) (* [igFun of F] == clone an existing GFunctor.iso_map structure for F. *) (* GFunctor.map == structure for continuous object maps, inheriting *) (* from the GFunctor.iso_map structure. *) (* [gFun by Fcont] == the map structure for an F with a canonical iso_map *) (* structure, given Fcont : continuous F. *) (* [gFun of F] == clone an existing GFunctor.map structure for F. *) (* GFunctor.pmap == structure for pcontinuous object maps, inheriting *) (* from the GFunctor.map structure. *) (* [pgFun by Fher] == the pmap structure for an F with a canonical map *) (* structure, given Fher : hereditary F. *) (* [pgFun of F] == clone an existing GFunctor.pmap structure for F. *) (* GFunctor.mono_map == structure for monotonic, continuous object maps *) (* inheriting from the GFunctor.map structure. *) (* [mgFun by Fmon] == the mono_map structure for an F with a canonical *) (* map structure, given Fmon : monotonic F. *) (* [mgFun of F] == clone an existing GFunctor.mono_map structure for F *) (* Lemmas for these group functors use either a 'gF' prefix or an 'F' suffix. *) (* The (F1 \o F2) and (F1 %% F2) operations have canonical GFunctor.map *) (* structures when F1 is monotonic or hereditary, respectively. *) (******************************************************************************) Import GroupScope. Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Delimit Scope gFun_scope with gF. Module GFunctor. Definition object_map := forall gT : finGroupType, {set gT} -> {set gT}. Bind Scope gFun_scope with object_map. Section Definitions. Implicit Types gT hT : finGroupType. Variable F : object_map. (* Group closure. *) Definition group_valued := forall gT (G : {group gT}), group_set (F G). (* Subgroup closure. *) Definition closed := forall gT (G : {group gT}), F G \subset G. (* General functoriality, i.e., continuity of the object map *) Definition continuous := forall gT hT (G : {group gT}) (phi : {morphism G >-> hT}), phi @* F G \subset F (phi @* G). (* Functoriality on the Grp groupoid (arrows are restricted to isos). *) Definition iso_continuous := forall gT hT (G : {group gT}) (phi : {morphism G >-> hT}), 'injm phi -> phi @* F G \subset F (phi @* G). Lemma continuous_is_iso_continuous : continuous -> iso_continuous. Proof. by move=> Fcont gT hT G phi inj_phi; exact: Fcont. Qed. (* Functoriality on Grp with partial morphisms. *) Definition pcontinuous := forall gT hT (G D : {group gT}) (phi : {morphism D >-> hT}), phi @* F G \subset F (phi @* G). Lemma pcontinuous_is_continuous : pcontinuous -> continuous. Proof. by move=> Fcont gT hT G; exact: Fcont. Qed. (* Heredity with respect to inclusion *) Definition hereditary := forall gT (H G : {group gT}), H \subset G -> F G :&: H \subset F H. Lemma pcontinuous_is_hereditary : pcontinuous -> hereditary. Proof. move=> Fcont gT H G sHG; rewrite -{2}(setIidPl sHG) setIC. by do 2!rewrite -(morphim_idm (subsetIl H _)) morphimIdom ?Fcont. Qed. (* Monotonicity with respect to inclusion *) Definition monotonic := forall gT (H G : {group gT}), H \subset G -> F H \subset F G. (* Self-expanding composition, and modulo *) Variables (k : unit) (F1 F2 : object_map). Definition comp_head : object_map := fun gT A => let: tt := k in F1 (F2 A). Definition modulo : object_map := fun gT A => coset (F2 A) @*^-1 (F1 (A / (F2 A))). End Definitions. Section ClassDefinitions. Structure iso_map := IsoMap { apply : object_map; _ : group_valued apply; _ : closed apply; _ : iso_continuous apply }. Local Coercion apply : iso_map >-> object_map. Structure map := Map { iso_of_map : iso_map; _ : continuous iso_of_map }. Local Coercion iso_of_map : map >-> iso_map. Structure pmap := Pmap { map_of_pmap : map; _ : hereditary map_of_pmap }. Local Coercion map_of_pmap : pmap >-> map. Structure mono_map := MonoMap { map_of_mono : map; _ : monotonic map_of_mono }. Local Coercion map_of_mono : mono_map >-> map. Definition pack_iso F Fcont Fgrp Fsub := @IsoMap F Fgrp Fsub Fcont. Definition clone_iso (F : object_map) := fun Fgrp Fsub Fcont (isoF := @IsoMap F Fgrp Fsub Fcont) => fun isoF0 & phant_id (apply isoF0) F & phant_id isoF isoF0 => isoF. Definition clone (F : object_map) := fun isoF & phant_id (apply isoF) F => fun (funF0 : map) & phant_id (apply funF0) F => fun Fcont (funF := @Map isoF Fcont) & phant_id funF0 funF => funF. Definition clone_pmap (F : object_map) := fun (funF : map) & phant_id (apply funF) F => fun (pfunF0 : pmap) & phant_id (apply pfunF0) F => fun Fher (pfunF := @Pmap funF Fher) & phant_id pfunF0 pfunF => pfunF. Definition clone_mono (F : object_map) := fun (funF : map) & phant_id (apply funF) F => fun (mfunF0 : mono_map) & phant_id (apply mfunF0) F => fun Fmon (mfunF := @MonoMap funF Fmon) & phant_id mfunF0 mfunF => mfunF. End ClassDefinitions. Module Exports. Identity Coercion fun_of_object_map : object_map >-> Funclass. Coercion apply : iso_map >-> object_map. Coercion iso_of_map : map >-> iso_map. Coercion map_of_pmap : pmap >-> map. Coercion map_of_mono : mono_map >-> map. Coercion continuous_is_iso_continuous : continuous >-> iso_continuous. Coercion pcontinuous_is_continuous : pcontinuous >-> continuous. Coercion pcontinuous_is_hereditary : pcontinuous >-> hereditary. Notation "[ 'igFun' 'by' Fsub & Fcont ]" := (pack_iso (continuous_is_iso_continuous Fcont) (fun gT G => groupP _) Fsub) (at level 0, format "[ 'igFun' 'by' Fsub & Fcont ]") : form_scope. Notation "[ 'igFun' 'by' Fsub & ! Fcont ]" := (pack_iso Fcont (fun gT G => groupP _) Fsub) (at level 0, format "[ 'igFun' 'by' Fsub & ! Fcont ]") : form_scope. Notation "[ 'igFun' 'of' F ]" := (@clone_iso F _ _ _ _ id id) (at level 0, format "[ 'igFun' 'of' F ]") : form_scope. Notation "[ 'gFun' 'by' Fcont ]" := (Map Fcont) (at level 0, format "[ 'gFun' 'by' Fcont ]") : form_scope. Notation "[ 'gFun' 'of' F ]" := (@clone F _ id _ id _ id) (at level 0, format "[ 'gFun' 'of' F ]") : form_scope. Notation "[ 'pgFun' 'by' Fher ]" := (Pmap Fher) (at level 0, format "[ 'pgFun' 'by' Fher ]") : form_scope. Notation "[ 'pgFun' 'of' F ]" := (@clone_pmap F _ id _ id _ id) (at level 0, format "[ 'pgFun' 'of' F ]") : form_scope. Notation "[ 'mgFun' 'by' Fmon ]" := (MonoMap Fmon) (at level 0, format "[ 'mgFun' 'by' Fmon ]") : form_scope. Notation "[ 'mgFun' 'of' F ]" := (@clone_mono F _ id _ id _ id) (at level 0, format "[ 'mgFun' 'of' F ]") : form_scope. End Exports. End GFunctor. Export GFunctor.Exports. Bind Scope gFun_scope with GFunctor.object_map. Notation "F1 \o F2" := (GFunctor.comp_head tt F1 F2) : gFun_scope. Notation "F1 %% F2" := (GFunctor.modulo F1 F2) : gFun_scope. Section FunctorGroup. Variables (F : GFunctor.iso_map) (gT : finGroupType) (G : {group gT}). Lemma gFgroupset : group_set (F gT G). Proof. by case: F. Qed. Canonical gFgroup := Group gFgroupset. End FunctorGroup. Canonical gFmod_group (F1 : GFunctor.iso_map) (F2 : GFunctor.object_map) (gT : finGroupType) (G : {group gT}) := [group of (F1 %% F2)%gF gT G]. Section IsoFunctorTheory. Implicit Types gT rT : finGroupType. Variable F : GFunctor.iso_map. Lemma gFsub gT (G : {group gT}) : F gT G \subset G. Proof. by case: F gT G. Qed. Lemma gF1 gT : F gT 1 = 1. Proof. exact/trivgP/gFsub. Qed. Lemma gFiso_cont : GFunctor.iso_continuous F. Proof. by case F. Qed. Lemma gFchar gT (G : {group gT}) : F gT G \char G. Proof. apply/andP; split => //; first by apply: gFsub. apply/forall_inP=> f Af; rewrite -{2}(im_autm Af) -(autmE Af). by rewrite -morphimEsub ?gFsub ?gFiso_cont ?injm_autm. Qed. Lemma gFnorm gT (G : {group gT}) : G \subset 'N(F gT G). Proof. by rewrite char_norm ?gFchar. Qed. Lemma gFnormal gT (G : {group gT}) : F gT G <| G. Proof. by rewrite char_normal ?gFchar. Qed. Lemma injmF_sub gT rT (G D : {group gT}) (f : {morphism D >-> rT}) : 'injm f -> G \subset D -> f @* (F gT G) \subset F rT (f @* G). Proof. move=> injf sGD; apply/eqP; rewrite -(setIidPr (gFsub G)). by rewrite-{3}(setIid G) -!(morphim_restrm sGD) gFiso_cont // injm_restrm. Qed. Lemma injmF gT rT (G D : {group gT}) (f : {morphism D >-> rT}) : 'injm f -> G \subset D -> f @* (F gT G) = F rT (f @* G). Proof. move=> injf sGD; apply/eqP; rewrite eqEsubset injmF_sub //=. rewrite -{2}(morphim_invm injf sGD) -[f @* F _ _](morphpre_invm injf). have Fsubs := subset_trans (gFsub _). by rewrite -sub_morphim_pre (injmF_sub, Fsubs) ?morphimS ?injm_invm. Qed. Lemma gFisom gT rT (G D : {group gT}) R (f : {morphism D >-> rT}) : G \subset D -> isom G (gval R) f -> isom (F gT G) (F rT R) f. Proof. case/(restrmP f)=> g [gf _ _ _]; rewrite -{f}gf. by case/isomP=> injg <-; rewrite sub_isom ?gFsub ?injmF. Qed. Lemma gFisog gT rT (G : {group gT}) (R : {group rT}) : G \isog R -> F gT G \isog F rT R. Proof. by case/isogP=> f injf <-; rewrite -injmF // sub_isog ?gFsub. Qed. End IsoFunctorTheory. Section FunctorTheory. Implicit Types gT rT : finGroupType. Variable F : GFunctor.map. Lemma gFcont : GFunctor.continuous F. Proof. by case F. Qed. Lemma morphimF gT rT (G D : {group gT}) (f : {morphism D >-> rT}) : G \subset D -> f @* (F gT G) \subset F rT (f @* G). Proof. move=> sGD; rewrite -(setIidPr (gFsub F G)). by rewrite -{3}(setIid G) -!(morphim_restrm sGD) gFcont. Qed. End FunctorTheory. Section PartialFunctorTheory. Implicit Types gT rT : finGroupType. Section BasicTheory. Variable F : GFunctor.pmap. Lemma gFhereditary : GFunctor.hereditary F. Proof. by case F. Qed. Lemma gFunctorI gT (G H : {group gT}) : F gT G :&: H = F gT G :&: F gT (G :&: H). Proof. rewrite -{1}(setIidPr (gFsub F G)) [G :&: _]setIC -setIA. rewrite -(setIidPr (gFhereditary (subsetIl G H))). by rewrite setIC -setIA (setIidPr (gFsub F (G :&: H))). Qed. Lemma pmorphimF : GFunctor.pcontinuous F. Proof. move=> gT rT G D f; rewrite -morphimIdom -(setIidPl (gFsub F G)) setICA. apply: (subset_trans (morphimS f (gFhereditary (subsetIr D G)))). by rewrite (subset_trans (morphimF F _ _ )) ?morphimIdom ?subsetIl. Qed. Lemma gFid gT (G : {group gT}) : F gT (F gT G) = F gT G. Proof. apply/eqP; rewrite eqEsubset gFsub. by move/gFhereditary: (gFsub F G); rewrite setIid /=. Qed. End BasicTheory. Section Modulo. Variables (F1 : GFunctor.pmap) (F2 : GFunctor.map). Lemma gFmod_closed : GFunctor.closed (F1 %% F2). Proof. by move=> gT G; rewrite sub_cosetpre_quo ?gFsub ?gFnormal. Qed. Lemma gFmod_cont : GFunctor.continuous (F1 %% F2). Proof. move=> gT rT G f; have nF2 := gFnorm F2. have sDF: G \subset 'dom (coset (F2 _ G)) by rewrite nF2. have sDFf: G \subset 'dom (coset (F2 _ (f @* G)) \o f). by rewrite -sub_morphim_pre ?subsetIl // nF2. pose K := 'ker (restrm sDFf (coset (F2 _ (f @* G)) \o f)). have sFK: 'ker (restrm sDF (coset (F2 _ G))) \subset K. rewrite {}/K !ker_restrm ker_comp /= subsetI subsetIl !ker_coset /=. by rewrite -sub_morphim_pre ?subsetIl // morphimIdom ?morphimF. have sOF := gFsub F1 (G / F2 _ G); have sGG: G \subset G by []. rewrite -sub_quotient_pre; last first. by apply: subset_trans (nF2 _ _); rewrite morphimS ?gFmod_closed. suffices im_fact H : F2 _ G \subset gval H -> H \subset G -> factm sFK sGG @* (H / F2 _ G) = f @* H / F2 _ (f @* G). - rewrite -2?im_fact ?gFmod_closed ?gFsub //. by rewrite cosetpreK morphimF /= ?morphim_restrm ?setIid. by rewrite -sub_quotient_pre ?normG //= trivg_quotient sub1G. move=> sFH sHG; rewrite -(morphimIdom _ (H / _)) /= {2}morphim_restrm setIid. rewrite -morphimIG ?ker_coset // -(morphim_restrm sDF) morphim_factm. by rewrite morphim_restrm morphim_comp -quotientE morphimIdom. Qed. Canonical gFmod_igFun := [igFun by gFmod_closed & gFmod_cont]. Canonical gFmod_gFun := [gFun by gFmod_cont]. End Modulo. Variables F1 F2 : GFunctor.pmap. Lemma gFmod_hereditary : GFunctor.hereditary (F1 %% F2). Proof. move=> gT H G sHG; set FGH := _ :&: H; have nF2H := gFnorm F2 H. rewrite -sub_quotient_pre; last exact: subset_trans (subsetIr _ _) _. pose rH := restrm nF2H (coset (F2 _ H)); pose rHM := [morphism of rH]. have rnorm_simpl: rHM @* H = H / F2 _ H by rewrite morphim_restrm setIid. have nF2G := subset_trans sHG (gFnorm F2 G). pose rG := restrm nF2G (coset (F2 _ G)); pose rGM := [morphism of rG]. have sqKfK: 'ker rGM \subset 'ker rHM. rewrite !ker_restrm !ker_coset (setIidPr (gFsub F2 _)) setIC /=. exact: gFhereditary. have sHH := subxx H; rewrite -rnorm_simpl /= -(morphim_factm sqKfK sHH) /=. apply: subset_trans (gFcont F1 _); rewrite /= {2}morphim_restrm setIid /=. apply: subset_trans (morphimS _ (gFhereditary _ (quotientS _ sHG))) => /=. have ->: FGH / _ = restrm nF2H (coset _) @* FGH. by rewrite morphim_restrm setICA setIid. rewrite -(morphim_factm sqKfK sHH) morphimS //= morphim_restrm -quotientE. by rewrite setICA setIid (subset_trans (quotientI _ _ _)) // cosetpreK. Qed. Canonical gFmod_pgFun := [pgFun by gFmod_hereditary]. End PartialFunctorTheory. Section MonotonicFunctorTheory. Implicit Types gT rT : finGroupType. Lemma gFunctorS (F : GFunctor.mono_map) : GFunctor.monotonic F. Proof. by case: F. Qed. Section Composition. Variables (F1 : GFunctor.mono_map) (F2 : GFunctor.map). Lemma gFcomp_closed : GFunctor.closed (F1 \o F2). Proof. by move=> gT G; rewrite (subset_trans (gFsub _ _)) ?gFsub. Qed. Lemma gFcomp_cont : GFunctor.continuous (F1 \o F2). Proof. move=> gT rT G phi; rewrite (subset_trans (morphimF _ _ (gFsub _ _))) //. by rewrite (subset_trans (gFunctorS F1 (gFcont F2 phi))). Qed. Canonical gFcomp_igFun := [igFun by gFcomp_closed & gFcomp_cont]. Canonical gFcomp_gFun :=[gFun by gFcomp_cont]. End Composition. Variables F1 F2 : GFunctor.mono_map. Lemma gFcompS : GFunctor.monotonic (F1 \o F2). Proof. by move=> gT H G sHG; rewrite !gFunctorS. Qed. Canonical gFcomp_mgFun := [mgFun by gFcompS]. End MonotonicFunctorTheory. Section GFunctorExamples. Implicit Types gT : finGroupType. Definition idGfun gT := @id {set gT}. Lemma idGfun_closed : GFunctor.closed idGfun. Proof. by []. Qed. Lemma idGfun_cont : GFunctor.continuous idGfun. Proof. by []. Qed. Lemma idGfun_monotonic : GFunctor.monotonic idGfun. Proof. by []. Qed. Canonical bgFunc_id := [igFun by idGfun_closed & idGfun_cont]. Canonical gFunc_id := [gFun by idGfun_cont]. Canonical mgFunc_id := [mgFun by idGfun_monotonic]. Definition trivGfun gT of {set gT} := [1 gT]. Lemma trivGfun_cont : GFunctor.pcontinuous trivGfun. Proof. by move=> gT rT D G f; rewrite morphim1. Qed. Canonical trivGfun_igFun := [igFun by sub1G & trivGfun_cont]. Canonical trivGfun_gFun := [gFun by trivGfun_cont]. Canonical trivGfun_pgFun := [pgFun by trivGfun_cont]. End GFunctorExamples. mathcomp-1.5/theories/presentation.v0000644000175000017500000002606512307636117016716 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq fintype finset. Require Import fingroup morphism. (******************************************************************************) (* Support for generator-and-relation presentations of groups. We provide the *) (* syntax: *) (* G \homg Grp (x_1 : ... x_n : (s_1 = t_1, ..., s_m = t_m)) *) (* <=> G is generated by elements x_1, ..., x_m satisfying the relations *) (* s_1 = t_1, ..., s_m = t_m, i.e., G is a homomorphic image of the *) (* group generated by the x_i, subject to the relations s_j = t_j. *) (* G \isog Grp (x_1 : ... x_n : (s_1 = t_1, ..., s_m = t_m)) *) (* <=> G is isomorphic to the group generated by the x_i, subject to the *) (* relations s_j = t_j. This is an intensional predicate (in Prop), as *) (* even the non-triviality of a generated group is undecidable. *) (* Syntax details: *) (* - Grp is a litteral constant. *) (* - There must be at least one generator and one relation. *) (* - A relation s_j = 1 can be abbreviated as simply s_j (a.k.a. a relator). *) (* - Two consecutive relations s_j = t, s_j+1 = t can be abbreviated *) (* s_j = s_j+1 = t. *) (* - The s_j and t_j are terms built from the x_i and the standard group *) (* operators *, 1, ^-1, ^+, ^-, ^, [~ u_1, ..., u_k]; no other operator or *) (* abbreviation may be used, as the notation is implemented using static *) (* overloading. *) (* - This is the closest we could get to the notation used in Aschbacher, *) (* Grp (x_1, ... x_n : t_1,1 = ... = t_1,k1, ..., t_m,1 = ... = t_m,km) *) (* under the current limitations of the Coq Notation facility. *) (* Semantics details: *) (* - G \isog Grp (...) : Prop expands to the statement *) (* forall rT (H : {group rT}), (H \homg G) = (H \homg Grp (...)) *) (* (with rT : finGroupType). *) (* - G \homg Grp (x_1 : ... x_n : (s_1 = t_1, ..., s_m = t_m)) : bool, with *) (* G : {set gT}, is convertible to the boolean expression *) (* [exists t : gT * ... gT, let: (x_1, ..., x_n) := t in *) (* (<[x_1]> <*> ... <*> <[x_n]>, (s_1, ... (s_m-1, s_m) ...)) *) (* == (G, (t_1, ... (t_m-1, t_m) ...))] *) (* where the tuple comparison above is convertible to the conjunction *) (* [&& <[x_1]> <*> ... <*> <[x_n]> == G, s_1 == t_1, ... & s_m == t_m] *) (* Thus G \homg Grp (...) can be easily exploited by destructing the tuple *) (* created case/existsP, then destructing the tuple equality with case/eqP. *) (* Conversely it can be proved by using apply/existsP, providing the tuple *) (* with a single exists (u_1, ..., u_n), then using rewrite !xpair_eqE /= *) (* to expose the conjunction, and optionally using an apply/and{m+1}P view *) (* to split it into subgoals (in that case, the rewrite is in principle *) (* redundant, but necessary in practice because of the poor performance of *) (* conversion in the Coq unifier). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Module Presentation. Section Presentation. Implicit Types gT rT : finGroupType. Implicit Type vT : finType. (* tuple value type *) Inductive term := | Cst of nat | Idx | Inv of term | Exp of term & nat | Mul of term & term | Conj of term & term | Comm of term & term. Fixpoint eval {gT} e t : gT := match t with | Cst i => nth 1 e i | Idx => 1 | Inv t1 => (eval e t1)^-1 | Exp t1 n => eval e t1 ^+ n | Mul t1 t2 => eval e t1 * eval e t2 | Conj t1 t2 => eval e t1 ^ eval e t2 | Comm t1 t2 => [~ eval e t1, eval e t2] end. Inductive formula := Eq2 of term & term | And of formula & formula. Definition Eq1 s := Eq2 s Idx. Definition Eq3 s1 s2 t := And (Eq2 s1 t) (Eq2 s2 t). Inductive rel_type := NoRel | Rel vT of vT & vT. Definition bool_of_rel r := if r is Rel vT v1 v2 then v1 == v2 else true. Local Coercion bool_of_rel : rel_type >-> bool. Definition and_rel vT (v1 v2 : vT) r := if r is Rel wT w1 w2 then Rel (v1, w1) (v2, w2) else Rel v1 v2. Fixpoint rel {gT} (e : seq gT) f r := match f with | Eq2 s t => and_rel (eval e s) (eval e t) r | And f1 f2 => rel e f1 (rel e f2 r) end. Inductive type := Generator of term -> type | Formula of formula. Definition Cast p : type := p. (* syntactic scope cast *) Local Coercion Formula : formula >-> type. Inductive env gT := Env of {set gT} & seq gT. Definition env1 {gT} (x : gT : finType) := Env <[x]> [:: x]. Fixpoint sat gT vT B n (s : vT -> env gT) p := match p with | Formula f => [exists v, let: Env A e := s v in and_rel A B (rel (rev e) f NoRel)] | Generator p' => let s' v := let: Env A e := s v.1 in Env (A <*> <[v.2]>) (v.2 :: e) in sat B n.+1 s' (p' (Cst n)) end. Definition hom gT (B : {set gT}) p := sat B 1 env1 (p (Cst 0)). Definition iso gT (B : {set gT}) p := forall rT (H : {group rT}), (H \homg B) = hom H p. End Presentation. End Presentation. Import Presentation. Coercion bool_of_rel : rel_type >-> bool. Coercion Eq1 : term >-> formula. Coercion Formula : formula >-> type. (* Declare (implicitly) the argument scope tags. *) Notation "1" := Idx : group_presentation. Arguments Scope Inv [group_presentation]. Arguments Scope Exp [group_presentation nat_scope]. Arguments Scope Mul [group_presentation group_presentation]. Arguments Scope Conj [group_presentation group_presentation]. Arguments Scope Comm [group_presentation group_presentation]. Arguments Scope Eq1 [group_presentation]. Arguments Scope Eq2 [group_presentation group_presentation]. Arguments Scope Eq3 [group_presentation group_presentation group_presentation]. Arguments Scope And [group_presentation group_presentation]. Arguments Scope Formula [group_presentation]. Arguments Scope Cast [group_presentation]. Infix "*" := Mul : group_presentation. Infix "^+" := Exp : group_presentation. Infix "^" := Conj : group_presentation. Notation "x ^-1" := (Inv x) : group_presentation. Notation "x ^- n" := (Inv (x ^+ n)) : group_presentation. Notation "[ ~ x1 , x2 , .. , xn ]" := (Comm .. (Comm x1 x2) .. xn) : group_presentation. Notation "x = y" := (Eq2 x y) : group_presentation. Notation "x = y = z" := (Eq3 x y z) : group_presentation. Notation "( r1 , r2 , .. , rn )" := (And .. (And r1 r2) .. rn) : group_presentation. (* Declare (implicitly) the argument scope tags. *) Notation "x : p" := (fun x => Cast p) : nt_group_presentation. Arguments Scope Generator [nt_group_presentation]. Arguments Scope hom [_ group_scope nt_group_presentation]. Arguments Scope iso [_ group_scope nt_group_presentation]. Notation "x : p" := (Generator (x : p)) : group_presentation. Notation "H \homg 'Grp' p" := (hom H p) (at level 70, p at level 0, format "H \homg 'Grp' p") : group_scope. Notation "H \isog 'Grp' p" := (iso H p) (at level 70, p at level 0, format "H \isog 'Grp' p") : group_scope. Notation "H \homg 'Grp' ( x : p )" := (hom H (x : p)) (at level 70, x at level 0, format "'[hv' H '/ ' \homg 'Grp' ( x : p ) ']'") : group_scope. Notation "H \isog 'Grp' ( x : p )" := (iso H (x : p)) (at level 70, x at level 0, format "'[hv' H '/ ' \isog 'Grp' ( x : p ) ']'") : group_scope. Section PresentationTheory. Implicit Types gT rT : finGroupType. Import Presentation. Lemma isoGrp_hom gT (G : {group gT}) p : G \isog Grp p -> G \homg Grp p. Proof. by move <-; exact: homg_refl. Qed. Lemma isoGrpP gT (G : {group gT}) p rT (H : {group rT}) : G \isog Grp p -> reflect (#|H| = #|G| /\ H \homg Grp p) (H \isog G). Proof. move=> isoGp; apply: (iffP idP) => [isoGH | [oH homHp]]. by rewrite (card_isog isoGH) -isoGp isog_hom. by rewrite isogEcard isoGp homHp /= oH. Qed. Lemma homGrp_trans rT gT (H : {set rT}) (G : {group gT}) p : H \homg G -> G \homg Grp p -> H \homg Grp p. Proof. case/homgP=> h <-{H}; rewrite /hom; move: {p}(p _) => p. have evalG e t: all (mem G) e -> eval (map h e) t = h (eval e t). move=> Ge; apply: (@proj2 (eval e t \in G)); elim: t => /=. - move=> i; case: (leqP (size e) i) => [le_e_i | lt_i_e]. by rewrite !nth_default ?size_map ?morph1. by rewrite (nth_map 1) // [_ \in G](allP Ge) ?mem_nth. - by rewrite morph1. - by move=> t [Gt ->]; rewrite groupV morphV. - by move=> t [Gt ->] n; rewrite groupX ?morphX. - by move=> t1 [Gt1 ->] t2 [Gt2 ->]; rewrite groupM ?morphM. - by move=> t1 [Gt1 ->] t2 [Gt2 ->]; rewrite groupJ ?morphJ. by move=> t1 [Gt1 ->] t2 [Gt2 ->]; rewrite groupR ?morphR. have and_relE xT x1 x2 r: @and_rel xT x1 x2 r = (x1 == x2) && r :> bool. by case: r => //=; rewrite andbT. have rsatG e f: all (mem G) e -> rel e f NoRel -> rel (map h e) f NoRel. move=> Ge; have: NoRel -> NoRel by []; move: NoRel {2 4}NoRel. elim: f => [x1 x2 | f1 IH1 f2 IH2] r hr IHr; last by apply: IH1; exact: IH2. by rewrite !and_relE !evalG //; case/andP; move/eqP->; rewrite eqxx. set s := env1; set vT := gT : finType in s *. set s' := env1; set vT' := rT : finType in s' *. have (v): let: Env A e := s v in A \subset G -> all (mem G) e /\ exists v', s' v' = Env (h @* A) (map h e). - rewrite /= cycle_subG andbT => Gv; rewrite morphim_cycle //. by split; last exists (h v). elim: p 1%N vT vT' s s' => /= [p IHp | f] n vT vT' s s' Gs. apply: IHp => [[v x]] /=; case: (s v) {Gs}(Gs v) => A e /= Gs. rewrite join_subG cycle_subG; case/andP=> sAG Gx; rewrite Gx. have [//|-> [v' def_v']] := Gs; split=> //; exists (v', h x); rewrite def_v'. by congr (Env _ _); rewrite morphimY ?cycle_subG // morphim_cycle. case/existsP=> v; case: (s v) {Gs}(Gs v) => /= A e Gs. rewrite and_relE => /andP[/eqP defA rel_f]. have{Gs} [|Ge [v' def_v']] := Gs; first by rewrite defA. apply/existsP; exists v'; rewrite def_v' and_relE defA eqxx /=. by rewrite -map_rev rsatG ?(eq_all_r (mem_rev e)). Qed. Lemma eq_homGrp gT rT (G : {group gT}) (H : {group rT}) p : G \isog H -> (G \homg Grp p) = (H \homg Grp p). Proof. by rewrite isogEhom => /andP[homGH homHG]; apply/idP/idP; exact: homGrp_trans. Qed. Lemma isoGrp_trans gT rT (G : {group gT}) (H : {group rT}) p : G \isog H -> H \isog Grp p -> G \isog Grp p. Proof. by move=> isoGH isoHp kT K; rewrite -isoHp; exact: eq_homgr. Qed. Lemma intro_isoGrp gT (G : {group gT}) p : G \homg Grp p -> (forall rT (H : {group rT}), H \homg Grp p -> H \homg G) -> G \isog Grp p. Proof. move=> homGp freeG rT H. by apply/idP/idP=> [homHp|]; [exact: homGrp_trans homGp | exact: freeG]. Qed. End PresentationTheory. mathcomp-1.5/theories/gproduct.v0000644000175000017500000017402412307636117016031 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div choice fintype. Require Import bigop finset fingroup morphism quotient action. (******************************************************************************) (* Partial, semidirect, central, and direct products. *) (* ++ Internal products, with A, B : {set gT}, are partial operations : *) (* partial_product A B == A * B if A is a group normalised by the group B, *) (* and the empty set otherwise. *) (* A ><| B == A * B if this is a semi-direct product (i.e., if A *) (* is normalised by B and intersects it trivially). *) (* A \* B == A * B if this is a central product ([A, B] = 1). *) (* A \x B == A * B if this is a direct product. *) (* [complements to K in G] == set of groups H s.t. K * H = G and K :&: H = 1. *) (* [splits G, over K] == [complements to K in G] is not empty. *) (* remgr A B x == the right remainder in B of x mod A, i.e., *) (* some element of (A :* x) :&: B. *) (* divgr A B x == the "quotient" in B of x by A: for all x, *) (* x = divgr A B x * remgr A B x. *) (* ++ External products : *) (* pairg1, pair1g == the isomorphisms aT1 -> aT1 * aT2, aT2 -> aT1 * aT2. *) (* (aT1 * aT2 has a direct product group structure.) *) (* sdprod_by to == the semidirect product defined by to : groupAction H K. *) (* This is a finGroupType; the actual semidirect product is *) (* the total set [set: sdprod_by to] on that type. *) (* sdpair[12] to == the isomorphisms injecting K and H into *) (* sdprod_by to = sdpair1 to @* K ><| sdpair2 to @* H. *) (* External central products (with identified centers) will be defined later *) (* in file center.v. *) (* ++ Morphisms on product groups: *) (* pprodm nAB fJ fAB == the morphism extending fA and fB on A <*> B when *) (* nAB : B \subset 'N(A), *) (* fJ : {in A & B, morph_actj fA fB}, and *) (* fAB : {in A :&: B, fA =1 fB}. *) (* sdprodm defG fJ == the morphism extending fA and fB on G, given *) (* defG : A ><| B = G and *) (* fJ : {in A & B, morph_act 'J 'J fA fB}. *) (* xsdprodm fHKact == the total morphism on sdprod_by to induced by *) (* fH : {morphism H >-> rT}, fK : {morphism K >-> rT}, *) (* with to : groupAction K H, *) (* given fHKact : morph_act to 'J fH fK. *) (* cprodm defG cAB fAB == the morphism extending fA and fB on G, when *) (* defG : A \* B = G, *) (* cAB : fB @* B \subset 'C(fB @* A), *) (* and fAB : {in A :&: B, fA =1 fB}. *) (* dprodm defG cAB == the morphism extending fA and fB on G, when *) (* defG : A \x B = G and *) (* cAB : fA @* B \subset 'C(fA @* A) *) (* mulgm (x, y) == x * y; mulgm is an isomorphism from setX A B to G *) (* iff A \x B = G . *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section Defs. Variables gT : finGroupType. Implicit Types A B C : {set gT}. Definition partial_product A B := if A == 1 then B else if B == 1 then A else if [&& group_set A, group_set B & B \subset 'N(A)] then A * B else set0. Definition semidirect_product A B := if A :&: B \subset 1%G then partial_product A B else set0. Definition central_product A B := if B \subset 'C(A) then partial_product A B else set0. Definition direct_product A B := if A :&: B \subset 1%G then central_product A B else set0. Definition complements_to_in A B := [set K : {group gT} | A :&: K == 1 & A * K == B]. Definition splits_over B A := complements_to_in A B != set0. (* Product remainder functions -- right variant only. *) Definition remgr A B x := repr (A :* x :&: B). Definition divgr A B x := x * (remgr A B x)^-1. End Defs. Arguments Scope partial_product [_ group_scope group_scope]. Arguments Scope semidirect_product [_ group_scope group_scope]. Arguments Scope central_product [_ group_scope group_scope]. Arguments Scope complements_to_in [_ group_scope group_scope]. Arguments Scope splits_over [_ group_scope group_scope]. Arguments Scope remgr [_ group_scope group_scope group_scope]. Arguments Scope divgr [_ group_scope group_scope group_scope]. Implicit Arguments partial_product []. Implicit Arguments semidirect_product []. Implicit Arguments central_product []. Implicit Arguments direct_product []. Notation pprod := (partial_product _). Notation sdprod := (semidirect_product _). Notation cprod := (central_product _). Notation dprod := (direct_product _). Notation "G ><| H" := (sdprod G H)%g (at level 40, left associativity). Notation "G \* H" := (cprod G H)%g (at level 40, left associativity). Notation "G \x H" := (dprod G H)%g (at level 40, left associativity). Notation "[ 'complements' 'to' A 'in' B ]" := (complements_to_in A B) (at level 0, format "[ 'complements' 'to' A 'in' B ]") : group_scope. Notation "[ 'splits' B , 'over' A ]" := (splits_over B A) (at level 0, format "[ 'splits' B , 'over' A ]") : group_scope. (* Prenex Implicits remgl divgl. *) Prenex Implicits remgr divgr. Section InternalProd. Variable gT : finGroupType. Implicit Types A B C : {set gT}. Implicit Types G H K L M : {group gT}. Local Notation pprod := (partial_product gT). Local Notation sdprod := (semidirect_product gT) (only parsing). Local Notation cprod := (central_product gT) (only parsing). Local Notation dprod := (direct_product gT) (only parsing). Lemma pprod1g : left_id 1 pprod. Proof. by move=> A; rewrite /pprod eqxx. Qed. Lemma pprodg1 : right_id 1 pprod. Proof. by move=> A; rewrite /pprod eqxx; case: eqP. Qed. CoInductive are_groups A B : Prop := AreGroups K H of A = K & B = H. Lemma group_not0 G : set0 <> G. Proof. by move/setP/(_ 1); rewrite inE group1. Qed. Lemma mulg0 : right_zero (@set0 gT) mulg. Proof. by move=> A; apply/setP=> x; rewrite inE; apply/imset2P=> [[y z]]; rewrite inE. Qed. Lemma mul0g : left_zero (@set0 gT) mulg. Proof. by move=> A; apply/setP=> x; rewrite inE; apply/imset2P=> [[y z]]; rewrite inE. Qed. Lemma pprodP A B G : pprod A B = G -> [/\ are_groups A B, A * B = G & B \subset 'N(A)]. Proof. have Gnot0 := @group_not0 G; rewrite /pprod; do 2?case: eqP => [-> ->| _]. - by rewrite mul1g norms1; split; first exists 1%G G. - by rewrite mulg1 sub1G; split; first exists G 1%G. by case: and3P => // [[gA gB ->]]; split; first exists (Group gA) (Group gB). Qed. Lemma pprodE K H : H \subset 'N(K) -> pprod K H = K * H. Proof. move=> nKH; rewrite /pprod nKH !groupP /=. by do 2?case: eqP => [-> | _]; rewrite ?mulg1 ?mul1g. Qed. Lemma pprodEY K H : H \subset 'N(K) -> pprod K H = K <*> H. Proof. by move=> nKH; rewrite pprodE ?norm_joinEr. Qed. Lemma pprodW A B G : pprod A B = G -> A * B = G. Proof. by case/pprodP. Qed. Lemma pprodWC A B G : pprod A B = G -> B * A = G. Proof. by case/pprodP=> _ <- /normC. Qed. Lemma pprodWY A B G : pprod A B = G -> A <*> B = G. Proof. by case/pprodP=> [[K H -> ->] <- /norm_joinEr]. Qed. Lemma pprodJ A B x : pprod A B :^ x = pprod (A :^ x) (B :^ x). Proof. rewrite /pprod !conjsg_eq1 !group_setJ normJ conjSg -conjsMg. by do 3?case: ifP => // _; exact: conj0g. Qed. (* Properties of the remainders *) Lemma remgrMl K B x y : y \in K -> remgr K B (y * x) = remgr K B x. Proof. by move=> Ky; rewrite {1}/remgr rcosetM rcoset_id. Qed. Lemma remgrP K B x : (remgr K B x \in K :* x :&: B) = (x \in K * B). Proof. set y := _ x; apply/idP/mulsgP=> [|[g b Kg Bb x_gb]]. rewrite inE rcoset_sym mem_rcoset => /andP[Kxy' By]. by exists (x * y^-1) y; rewrite ?mulgKV. by apply: (mem_repr b); rewrite inE rcoset_sym mem_rcoset x_gb mulgK Kg. Qed. Lemma remgr1 K H x : x \in K -> remgr K H x = 1. Proof. by move=> Kx; rewrite /remgr rcoset_id ?repr_group. Qed. Lemma divgr_eq A B x : x = divgr A B x * remgr A B x. Proof. by rewrite mulgKV. Qed. Lemma divgrMl K B x y : x \in K -> divgr K B (x * y) = x * divgr K B y. Proof. by move=> Hx; rewrite /divgr remgrMl ?mulgA. Qed. Lemma divgr_id K H x : x \in K -> divgr K H x = x. Proof. by move=> Kx; rewrite /divgr remgr1 // invg1 mulg1. Qed. Lemma mem_remgr K B x : x \in K * B -> remgr K B x \in B. Proof. by rewrite -remgrP => /setIP[]. Qed. Lemma mem_divgr K B x : x \in K * B -> divgr K B x \in K. Proof. by rewrite -remgrP inE rcoset_sym mem_rcoset => /andP[]. Qed. Section DisjointRem. Variables K H : {group gT}. Hypothesis tiKH : K :&: H = 1. Lemma remgr_id x : x \in H -> remgr K H x = x. Proof. move=> Hx; apply/eqP; rewrite eq_mulgV1 (sameP eqP set1gP) -tiKH inE. rewrite -mem_rcoset groupMr ?groupV // -in_setI remgrP. by apply: subsetP Hx; exact: mulG_subr. Qed. Lemma remgrMid x y : x \in K -> y \in H -> remgr K H (x * y) = y. Proof. by move=> Kx Hy; rewrite remgrMl ?remgr_id. Qed. Lemma divgrMid x y : x \in K -> y \in H -> divgr K H (x * y) = x. Proof. by move=> Kx Hy; rewrite /divgr remgrMid ?mulgK. Qed. End DisjointRem. (* Intersection of a centraliser with a disjoint product. *) Lemma subcent_TImulg K H A : K :&: H = 1 -> A \subset 'N(K) :&: 'N(H) -> 'C_K(A) * 'C_H(A) = 'C_(K * H)(A). Proof. move=> tiKH /subsetIP[nKA nHA]; apply/eqP. rewrite group_modl ?subsetIr // eqEsubset setSI ?mulSg ?subsetIl //=. apply/subsetP=> _ /setIP[/mulsgP[x y Kx Hy ->] cAxy]. rewrite inE cAxy mem_mulg // inE Kx /=. apply/centP=> z Az; apply/commgP/conjg_fixP. move/commgP/conjg_fixP/(congr1 (divgr K H)): (centP cAxy z Az). by rewrite conjMg !divgrMid ?memJ_norm // (subsetP nKA, subsetP nHA). Qed. (* Complements, and splitting. *) Lemma complP H A B : reflect (A :&: H = 1 /\ A * H = B) (H \in [complements to A in B]). Proof. by apply: (iffP setIdP); case; split; apply/eqP. Qed. Lemma splitsP B A : reflect (exists H, H \in [complements to A in B]) [splits B, over A]. Proof. exact: set0Pn. Qed. Lemma complgC H K G : (H \in [complements to K in G]) = (K \in [complements to H in G]). Proof. rewrite !inE setIC; congr (_ && _). by apply/eqP/eqP=> defG; rewrite -(comm_group_setP _) // defG groupP. Qed. Section NormalComplement. Variables K H G : {group gT}. Hypothesis complH_K : H \in [complements to K in G]. Lemma remgrM : K <| G -> {in G &, {morph remgr K H : x y / x * y}}. Proof. case/normalP=> _; case/complP: complH_K => tiKH <- nK_KH x y KHx KHy. rewrite {1}(divgr_eq K H y) mulgA (conjgCV x) {2}(divgr_eq K H x) -2!mulgA. rewrite mulgA remgrMid //; last by rewrite groupMl mem_remgr. by rewrite groupMl !(=^~ mem_conjg, nK_KH, mem_divgr). Qed. Lemma divgrM : H \subset 'C(K) -> {in G &, {morph divgr K H : x y / x * y}}. Proof. move=> cKH; have /complP[_ defG] := complH_K. have nsKG: K <| G by rewrite -defG -cent_joinEr // normalYl cents_norm. move=> x y Gx Gy; rewrite {1}/divgr remgrM // invMg -!mulgA (mulgA y). by congr (_ * _); rewrite -(centsP cKH) ?groupV ?(mem_remgr, mem_divgr, defG). Qed. End NormalComplement. (* Semi-direct product *) Lemma sdprod1g : left_id 1 sdprod. Proof. by move=> A; rewrite /sdprod subsetIl pprod1g. Qed. Lemma sdprodg1 : right_id 1 sdprod. Proof. by move=> A; rewrite /sdprod subsetIr pprodg1. Qed. Lemma sdprodP A B G : A ><| B = G -> [/\ are_groups A B, A * B = G, B \subset 'N(A) & A :&: B = 1]. Proof. rewrite /sdprod; case: ifP => [trAB | _ /group_not0[] //]. case/pprodP=> gAB defG nBA; split=> {defG nBA}//. by case: gAB trAB => H K -> -> /trivgP. Qed. Lemma sdprodE K H : H \subset 'N(K) -> K :&: H = 1 -> K ><| H = K * H. Proof. by move=> nKH tiKH; rewrite /sdprod tiKH subxx pprodE. Qed. Lemma sdprodEY K H : H \subset 'N(K) -> K :&: H = 1 -> K ><| H = K <*> H. Proof. by move=> nKH tiKH; rewrite sdprodE ?norm_joinEr. Qed. Lemma sdprodWpp A B G : A ><| B = G -> pprod A B = G. Proof. by case/sdprodP=> [[K H -> ->] <- /pprodE]. Qed. Lemma sdprodW A B G : A ><| B = G -> A * B = G. Proof. by move/sdprodWpp/pprodW. Qed. Lemma sdprodWC A B G : A ><| B = G -> B * A = G. Proof. by move/sdprodWpp/pprodWC. Qed. Lemma sdprodWY A B G : A ><| B = G -> A <*> B = G. Proof. by move/sdprodWpp/pprodWY. Qed. Lemma sdprodJ A B x : (A ><| B) :^ x = A :^ x ><| B :^ x. Proof. rewrite /sdprod -conjIg sub_conjg conjs1g -pprodJ. by case: ifP => _ //; exact: imset0. Qed. Lemma sdprod_context G K H : K ><| H = G -> [/\ K <| G, H \subset G, K * H = G, H \subset 'N(K) & K :&: H = 1]. Proof. case/sdprodP=> _ <- nKH tiKH. by rewrite /normal mulG_subl mulG_subr mulG_subG normG. Qed. Lemma sdprod_compl G K H : K ><| H = G -> H \in [complements to K in G]. Proof. by case/sdprodP=> _ mulKH _ tiKH; exact/complP. Qed. Lemma sdprod_normal_complP G K H : K <| G -> reflect (K ><| H = G) (K \in [complements to H in G]). Proof. case/andP=> _ nKG; rewrite complgC. apply: (iffP idP); [case/complP=> tiKH mulKH | exact: sdprod_compl]. by rewrite sdprodE ?(subset_trans _ nKG) // -mulKH mulG_subr. Qed. Lemma sdprod_card G A B : A ><| B = G -> (#|A| * #|B|)%N = #|G|. Proof. by case/sdprodP=> [[H K -> ->] <- _ /TI_cardMg]. Qed. Lemma sdprod_isom G A B : A ><| B = G -> {nAB : B \subset 'N(A) | isom B (G / A) (restrm nAB (coset A))}. Proof. case/sdprodP=> [[K H -> ->] <- nKH tiKH]. by exists nKH; rewrite quotientMidl quotient_isom. Qed. Lemma sdprod_isog G A B : A ><| B = G -> B \isog G / A. Proof. by case/sdprod_isom=> nAB; apply: isom_isog. Qed. Lemma sdprod_subr G A B M : A ><| B = G -> M \subset B -> A ><| M = A <*> M. Proof. case/sdprodP=> [[K H -> ->] _ nKH tiKH] sMH. by rewrite sdprodEY ?(subset_trans sMH) //; apply/trivgP; rewrite -tiKH setIS. Qed. Lemma index_sdprod G A B : A ><| B = G -> #|B| = #|G : A|. Proof. case/sdprodP=> [[K H -> ->] <- _ tiHK]. by rewrite indexMg -indexgI setIC tiHK indexg1. Qed. Lemma index_sdprodr G A B M : A ><| B = G -> M \subset B -> #|B : M| = #|G : A <*> M|. Proof. move=> defG; case/sdprodP: defG (defG) => [[K H -> ->] mulKH nKH _] defG sMH. rewrite -!divgS //=; last by rewrite -genM_join gen_subG -mulKH mulgS. by rewrite -(sdprod_card defG) -(sdprod_card (sdprod_subr defG sMH)) divnMl. Qed. Lemma quotient_sdprodr_isom G A B M : A ><| B = G -> M <| B -> {f : {morphism B / M >-> coset_of (A <*> M)} | isom (B / M) (G / (A <*> M)) f & forall L, L \subset B -> f @* (L / M) = A <*> L / (A <*> M)}. Proof. move=> defG nsMH; have [defA defB]: A = <>%G /\ B = <>%G. by have [[K1 H1 -> ->] _ _ _] := sdprodP defG; rewrite /= !genGid. do [rewrite {}defA {}defB; move: {A}<>%G {B}<>%G => K H] in defG nsMH *. have [[nKH /isomP[injKH imKH]] sMH] := (sdprod_isom defG, normal_sub nsMH). have [[nsKG sHG mulKH _ _] nKM] := (sdprod_context defG, subset_trans sMH nKH). have nsKMG: K <*> M <| G. by rewrite -quotientYK // -mulKH -quotientK ?cosetpre_normal ?quotient_normal. have [/= f inj_f im_f] := third_isom (joing_subl K M) nsKG nsKMG. rewrite quotientYidl //= -imKH -(restrm_quotientE nKH sMH) in f inj_f im_f. have /domP[h [_ ker_h _ im_h]]: 'dom (f \o quotm _ nsMH) = H / M. by rewrite ['dom _]morphpre_quotm injmK. have{im_h} im_h L: L \subset H -> h @* (L / M) = K <*> L / (K <*> M). move=> sLH; have [sLG sKKM] := (subset_trans sLH sHG, joing_subl K M). rewrite im_h morphim_comp morphim_quotm [_ @* L]restrm_quotientE ?im_f //. rewrite quotientY ?(normsG sKKM) ?(subset_trans sLG) ?normal_norm //. by rewrite (quotientS1 sKKM) joing1G. exists h => //; apply/isomP; split; last by rewrite im_h //= (sdprodWY defG). by rewrite ker_h injm_comp ?injm_quotm. Qed. Lemma quotient_sdprodr_isog G A B M : A ><| B = G -> M <| B -> B / M \isog G / (A <*> M). Proof. move=> defG; case/sdprodP: defG (defG) => [[K H -> ->] _ _ _] => defG nsMH. by have [h /isom_isog->] := quotient_sdprodr_isom defG nsMH. Qed. Lemma sdprod_modl A B G H : A ><| B = G -> A \subset H -> A ><| (B :&: H) = G :&: H. Proof. case/sdprodP=> {A B} [[A B -> ->]] <- nAB tiAB sAH. rewrite -group_modl ?sdprodE ?subIset ?nAB //. by rewrite setIA tiAB (setIidPl _) ?sub1G. Qed. Lemma sdprod_modr A B G H : A ><| B = G -> B \subset H -> (H :&: A) ><| B = H :&: G. Proof. case/sdprodP=> {A B}[[A B -> ->]] <- nAB tiAB sAH. rewrite -group_modr ?sdprodE ?normsI // ?normsG //. by rewrite -setIA tiAB (setIidPr _) ?sub1G. Qed. Lemma subcent_sdprod B C G A : B ><| C = G -> A \subset 'N(B) :&: 'N(C) -> 'C_B(A) ><| 'C_C(A) = 'C_G(A). Proof. case/sdprodP=> [[H K -> ->] <- nHK tiHK] nHKA {B C G}. rewrite sdprodE ?subcent_TImulg ?normsIG //. by rewrite -setIIl tiHK (setIidPl (sub1G _)). Qed. Lemma sdprod_recl n G K H K1 : #|G| <= n -> K ><| H = G -> K1 \proper K -> H \subset 'N(K1) -> exists G1 : {group gT}, [/\ #|G1| < n, G1 \subset G & K1 ><| H = G1]. Proof. move=> leGn; case/sdprodP=> _ defG nKH tiKH ltK1K nK1H. have tiK1H: K1 :&: H = 1 by apply/trivgP; rewrite -tiKH setSI ?proper_sub. exists (K1 <*> H)%G; rewrite /= -defG sdprodE // norm_joinEr //. rewrite ?mulSg ?proper_sub ?(leq_trans _ leGn) //=. by rewrite -defG ?TI_cardMg // ltn_pmul2r ?proper_card. Qed. Lemma sdprod_recr n G K H H1 : #|G| <= n -> K ><| H = G -> H1 \proper H -> exists G1 : {group gT}, [/\ #|G1| < n, G1 \subset G & K ><| H1 = G1]. Proof. move=> leGn; case/sdprodP=> _ defG nKH tiKH ltH1H. have [sH1H _] := andP ltH1H; have nKH1 := subset_trans sH1H nKH. have tiKH1: K :&: H1 = 1 by apply/trivgP; rewrite -tiKH setIS. exists (K <*> H1)%G; rewrite /= -defG sdprodE // norm_joinEr //. rewrite ?mulgS // ?(leq_trans _ leGn) //=. by rewrite -defG ?TI_cardMg // ltn_pmul2l ?proper_card. Qed. Lemma mem_sdprod G A B x : A ><| B = G -> x \in G -> exists y, exists z, [/\ y \in A, z \in B, x = y * z & {in A & B, forall u t, x = u * t -> u = y /\ t = z}]. Proof. case/sdprodP=> [[K H -> ->{A B}] <- _ tiKH] /mulsgP[y z Ky Hz ->{x}]. exists y; exists z; split=> // u t Ku Ht eqyzut. move: (congr1 (divgr K H) eqyzut) (congr1 (remgr K H) eqyzut). by rewrite !remgrMid // !divgrMid. Qed. (* Central product *) Lemma cprod1g : left_id 1 cprod. Proof. by move=> A; rewrite /cprod cents1 pprod1g. Qed. Lemma cprodg1 : right_id 1 cprod. Proof. by move=> A; rewrite /cprod sub1G pprodg1. Qed. Lemma cprodP A B G : A \* B = G -> [/\ are_groups A B, A * B = G & B \subset 'C(A)]. Proof. by rewrite /cprod; case: ifP => [cAB /pprodP[] | _ /group_not0[]]. Qed. Lemma cprodE G H : H \subset 'C(G) -> G \* H = G * H. Proof. by move=> cGH; rewrite /cprod cGH pprodE ?cents_norm. Qed. Lemma cprodEY G H : H \subset 'C(G) -> G \* H = G <*> H. Proof. by move=> cGH; rewrite cprodE ?cent_joinEr. Qed. Lemma cprodWpp A B G : A \* B = G -> pprod A B = G. Proof. by case/cprodP=> [[K H -> ->] <- /cents_norm/pprodE]. Qed. Lemma cprodW A B G : A \* B = G -> A * B = G. Proof. by move/cprodWpp/pprodW. Qed. Lemma cprodWC A B G : A \* B = G -> B * A = G. Proof. by move/cprodWpp/pprodWC. Qed. Lemma cprodWY A B G : A \* B = G -> A <*> B = G. Proof. by move/cprodWpp/pprodWY. Qed. Lemma cprodJ A B x : (A \* B) :^ x = A :^ x \* B :^ x. Proof. by rewrite /cprod centJ conjSg -pprodJ; case: ifP => _ //; exact: imset0. Qed. Lemma cprod_normal2 A B G : A \* B = G -> A <| G /\ B <| G. Proof. case/cprodP=> [[K H -> ->] <- cKH]; rewrite -cent_joinEr //. by rewrite normalYl normalYr !cents_norm // centsC. Qed. Lemma bigcprodW I (r : seq I) P F G : \big[cprod/1]_(i <- r | P i) F i = G -> \prod_(i <- r | P i) F i = G. Proof. elim/big_rec2: _ G => // i A B _ IH G /cprodP[[_ H _ defB] <- _]. by rewrite (IH H) defB. Qed. Lemma bigcprodWY I (r : seq I) P F G : \big[cprod/1]_(i <- r | P i) F i = G -> << \bigcup_(i <- r | P i) F i >> = G. Proof. elim/big_rec2: _ G => [|i A B _ IH G]; first by rewrite gen0. case /cprodP => [[K H -> defB] <- cKH]. by rewrite -[<<_>>]joing_idr (IH H) ?cent_joinEr -?defB. Qed. Lemma triv_cprod A B : (A \* B == 1) = (A == 1) && (B == 1). Proof. case A1: (A == 1); first by rewrite (eqP A1) cprod1g. apply/eqP=> /cprodP[[G H defA ->]] /eqP. by rewrite defA trivMg -defA A1. Qed. Lemma cprod_ntriv A B : A != 1 -> B != 1 -> A \* B = if [&& group_set A, group_set B & B \subset 'C(A)] then A * B else set0. Proof. move=> A1 B1; rewrite /cprod; case: ifP => cAB; rewrite ?cAB ?andbF //=. by rewrite /pprod -if_neg A1 -if_neg B1 cents_norm. Qed. Lemma trivg0 : (@set0 gT == 1) = false. Proof. by rewrite eqEcard cards0 cards1 andbF. Qed. Lemma group0 : group_set (@set0 gT) = false. Proof. by rewrite /group_set inE. Qed. Lemma cprod0g A : set0 \* A = set0. Proof. by rewrite /cprod centsC sub0set /pprod group0 trivg0 !if_same. Qed. Lemma cprodC : commutative cprod. Proof. rewrite /cprod => A B; case: ifP => cAB; rewrite centsC cAB // /pprod. by rewrite andbCA normC !cents_norm // 1?centsC //; do 2!case: eqP => // ->. Qed. Lemma cprodA : associative cprod. Proof. move=> A B C; case A1: (A == 1); first by rewrite (eqP A1) !cprod1g. case B1: (B == 1); first by rewrite (eqP B1) cprod1g cprodg1. case C1: (C == 1); first by rewrite (eqP C1) !cprodg1. rewrite !(triv_cprod, cprod_ntriv) ?{}A1 ?{}B1 ?{}C1 //. case: isgroupP => [[G ->{A}] | _]; last by rewrite group0. case: (isgroupP B) => [[H ->{B}] | _]; last by rewrite group0. case: (isgroupP C) => [[K ->{C}] | _]; last by rewrite group0 !andbF. case cGH: (H \subset 'C(G)); case cHK: (K \subset 'C(H)); last first. - by rewrite group0. - by rewrite group0 /= mulG_subG cGH andbF. - by rewrite group0 /= centM subsetI cHK !andbF. rewrite /= mulgA mulG_subG centM subsetI cGH cHK andbT -(cent_joinEr cHK). by rewrite -(cent_joinEr cGH) !groupP. Qed. Canonical cprod_law := Monoid.Law cprodA cprod1g cprodg1. Canonical cprod_abelaw := Monoid.ComLaw cprodC. Lemma cprod_modl A B G H : A \* B = G -> A \subset H -> A \* (B :&: H) = G :&: H. Proof. case/cprodP=> [[U V -> -> {A B}]] defG cUV sUH. by rewrite cprodE; [rewrite group_modl ?defG | rewrite subIset ?cUV]. Qed. Lemma cprod_modr A B G H : A \* B = G -> B \subset H -> (H :&: A) \* B = H :&: G. Proof. by rewrite -!(cprodC B) !(setIC H); exact: cprod_modl. Qed. Lemma bigcprodYP (I : finType) (P : pred I) (H : I -> {group gT}) : reflect (forall i j, P i -> P j -> i != j -> H i \subset 'C(H j)) (\big[cprod/1]_(i | P i) H i == (\prod_(i | P i) H i)%G). Proof. apply: (iffP eqP) => [defG i j Pi Pj neq_ij | cHH]. rewrite (bigD1 j) // (bigD1 i) /= ?cprodA in defG; last exact/andP. by case/cprodP: defG => [[K _ /cprodP[//]]]. set Q := P; have: subpred Q P by []. elim: {Q}_.+1 {-2}Q (ltnSn #|Q|) => // n IHn Q leQn sQP. have [i Qi | Q0] := pickP Q; last by rewrite !big_pred0. rewrite (cardD1x Qi) add1n ltnS !(bigD1 i Qi) /= in leQn *. rewrite {}IHn {n leQn}// => [|j /andP[/sQP //]]. rewrite bigprodGE cprodEY // gen_subG; apply/bigcupsP=> j /andP[neq_ji Qj]. by rewrite cHH ?sQP. Qed. Lemma bigcprodEY I r (P : pred I) (H : I -> {group gT}) G : abelian G -> (forall i, P i -> H i \subset G) -> \big[cprod/1]_(i <- r | P i) H i = (\prod_(i <- r | P i) H i)%G. Proof. move=> cGG sHG; apply/eqP; rewrite !(big_tnth _ _ r). by apply/bigcprodYP=> i j Pi Pj _; rewrite (sub_abelian_cent2 cGG) ?sHG. Qed. Lemma perm_bigcprod (I : eqType) r1 r2 (A : I -> {set gT}) G x : \big[cprod/1]_(i <- r1) A i = G -> {in r1, forall i, x i \in A i} -> perm_eq r1 r2 -> \prod_(i <- r1) x i = \prod_(i <- r2) x i. Proof. elim: r1 r2 G => [|i r1 IHr] r2 G defG Ax eq_r12. by rewrite perm_eq_sym in eq_r12; rewrite (perm_eq_small _ eq_r12) ?big_nil. have /rot_to[n r3 Dr2]: i \in r2 by rewrite -(perm_eq_mem eq_r12) mem_head. transitivity (\prod_(j <- rot n r2) x j). rewrite Dr2 !big_cons in defG Ax *; have [[_ G1 _ defG1] _ _] := cprodP defG. rewrite (IHr r3 G1) //; first by case/allP/andP: Ax => _ /allP. by rewrite -(perm_cons i) -Dr2 perm_eq_sym perm_rot perm_eq_sym. rewrite -{-2}(cat_take_drop n r2) in eq_r12 *. rewrite (eq_big_perm _ eq_r12) !big_cat /= !(big_nth i) !big_mkord in defG *. have /cprodP[[G1 G2 defG1 defG2] _ /centsP-> //] := defG. rewrite defG2 -(bigcprodW defG2) mem_prodg // => k _; apply: Ax. by rewrite (perm_eq_mem eq_r12) mem_cat orbC mem_nth. rewrite defG1 -(bigcprodW defG1) mem_prodg // => k _; apply: Ax. by rewrite (perm_eq_mem eq_r12) mem_cat mem_nth. Qed. Lemma reindex_bigcprod (I J : finType) (h : J -> I) P (A : I -> {set gT}) G x : {on SimplPred P, bijective h} -> \big[cprod/1]_(i | P i) A i = G -> {in SimplPred P, forall i, x i \in A i} -> \prod_(i | P i) x i = \prod_(j | P (h j)) x (h j). Proof. case=> h1 hK h1K; rewrite -!(big_filter _ P) filter_index_enum => defG Ax. rewrite -(big_map h P x) -(big_filter _ P) filter_map filter_index_enum. apply: perm_bigcprod defG _ _ => [i|]; first by rewrite mem_enum => /Ax. apply: uniq_perm_eq (enum_uniq P) _ _ => [|i]. by apply/dinjectiveP; apply: (can_in_inj hK). rewrite mem_enum; apply/idP/imageP=> [Pi | [j Phj ->//]]. by exists (h1 i); rewrite ?inE h1K. Qed. (* Direct product *) Lemma dprod1g : left_id 1 dprod. Proof. by move=> A; rewrite /dprod subsetIl cprod1g. Qed. Lemma dprodg1 : right_id 1 dprod. Proof. by move=> A; rewrite /dprod subsetIr cprodg1. Qed. Lemma dprodP A B G : A \x B = G -> [/\ are_groups A B, A * B = G, B \subset 'C(A) & A :&: B = 1]. Proof. rewrite /dprod; case: ifP => trAB; last by case/group_not0. by case/cprodP=> gAB; split=> //; case: gAB trAB => ? ? -> -> /trivgP. Qed. Lemma dprodE G H : H \subset 'C(G) -> G :&: H = 1 -> G \x H = G * H. Proof. by move=> cGH trGH; rewrite /dprod trGH sub1G cprodE. Qed. Lemma dprodEY G H : H \subset 'C(G) -> G :&: H = 1 -> G \x H = G <*> H. Proof. by move=> cGH trGH; rewrite /dprod trGH subxx cprodEY. Qed. Lemma dprodEcp A B : A :&: B = 1 -> A \x B = A \* B. Proof. by move=> trAB; rewrite /dprod trAB subxx. Qed. Lemma dprodEsd A B : B \subset 'C(A) -> A \x B = A ><| B. Proof. by rewrite /dprod /cprod => ->. Qed. Lemma dprodWcp A B G : A \x B = G -> A \* B = G. Proof. by move=> defG; have [_ _ _ /dprodEcp <-] := dprodP defG. Qed. Lemma dprodWsd A B G : A \x B = G -> A ><| B = G. Proof. by move=> defG; have [_ _ /dprodEsd <-] := dprodP defG. Qed. Lemma dprodW A B G : A \x B = G -> A * B = G. Proof. by move/dprodWsd/sdprodW. Qed. Lemma dprodWC A B G : A \x B = G -> B * A = G. Proof. by move/dprodWsd/sdprodWC. Qed. Lemma dprodWY A B G : A \x B = G -> A <*> B = G. Proof. by move/dprodWsd/sdprodWY. Qed. Lemma cprod_card_dprod G A B : A \* B = G -> #|A| * #|B| <= #|G| -> A \x B = G. Proof. by case/cprodP=> [[K H -> ->] <- cKH] /cardMg_TI; exact: dprodE. Qed. Lemma dprodJ A B x : (A \x B) :^ x = A :^ x \x B :^ x. Proof. rewrite /dprod -conjIg sub_conjg conjs1g -cprodJ. by case: ifP => _ //; exact: imset0. Qed. Lemma dprod_normal2 A B G : A \x B = G -> A <| G /\ B <| G. Proof. by move/dprodWcp/cprod_normal2. Qed. Lemma dprodYP K H : reflect (K \x H = K <*> H) (H \subset 'C(K) :\: K^#). Proof. rewrite subsetD -setI_eq0 setIDA setD_eq0 setIC subG1 /=. by apply: (iffP andP) => [[cKH /eqP/dprodEY->] | /dprodP[_ _ -> ->]]. Qed. Lemma dprodC : commutative dprod. Proof. by move=> A B; rewrite /dprod setIC cprodC. Qed. Lemma dprodWsdC A B G : A \x B = G -> B ><| A = G. Proof. by rewrite dprodC => /dprodWsd. Qed. Lemma dprodA : associative dprod. Proof. move=> A B C; case A1: (A == 1); first by rewrite (eqP A1) !dprod1g. case B1: (B == 1); first by rewrite (eqP B1) dprod1g dprodg1. case C1: (C == 1); first by rewrite (eqP C1) !dprodg1. rewrite /dprod (fun_if (cprod A)) (fun_if (cprod^~ C)) -cprodA. rewrite -(cprodC set0) !cprod0g cprod_ntriv ?B1 ?{}C1 //. case: and3P B1 => [[] | _ _]; last by rewrite cprodC cprod0g !if_same. case/isgroupP=> H ->; case/isgroupP=> K -> {B C}; move/cent_joinEr=> eHK H1. rewrite cprod_ntriv ?trivMg ?{}A1 ?{}H1 // mulG_subG. case: and4P => [[] | _]; last by rewrite !if_same. case/isgroupP=> G ->{A} _ cGH _; rewrite cprodEY // -eHK. case trGH: (G :&: H \subset _); case trHK: (H :&: K \subset _); last first. - by rewrite !if_same. - rewrite if_same; case: ifP => // trG_HK; case/negP: trGH. by apply: subset_trans trG_HK; rewrite setIS ?joing_subl. - rewrite if_same; case: ifP => // trGH_K; case/negP: trHK. by apply: subset_trans trGH_K; rewrite setSI ?joing_subr. do 2![case: ifP] => // trGH_K trG_HK; [case/negP: trGH_K | case/negP: trG_HK]. apply: subset_trans trHK; rewrite subsetI subsetIr -{2}(mulg1 H) -mulGS. rewrite setIC group_modl ?joing_subr //= cent_joinEr // -eHK. by rewrite -group_modr ?joing_subl //= setIC -(normC (sub1G _)) mulSg. apply: subset_trans trGH; rewrite subsetI subsetIl -{2}(mul1g H) -mulSG. rewrite setIC group_modr ?joing_subl //= eHK -(cent_joinEr cGH). by rewrite -group_modl ?joing_subr //= setIC (normC (sub1G _)) mulgS. Qed. Canonical dprod_law := Monoid.Law dprodA dprod1g dprodg1. Canonical dprod_abelaw := Monoid.ComLaw dprodC. Lemma bigdprodWcp I (r : seq I) P F G : \big[dprod/1]_(i <- r | P i) F i = G -> \big[cprod/1]_(i <- r | P i) F i = G. Proof. elim/big_rec2: _ G => // i A B _ IH G /dprodP[[K H -> defB] <- cKH _]. by rewrite (IH H) // cprodE -defB. Qed. Lemma bigdprodW I (r : seq I) P F G : \big[dprod/1]_(i <- r | P i) F i = G -> \prod_(i <- r | P i) F i = G. Proof. by move/bigdprodWcp; exact: bigcprodW. Qed. Lemma bigdprodWY I (r : seq I) P F G : \big[dprod/1]_(i <- r | P i) F i = G -> << \bigcup_(i <- r | P i) F i >> = G. Proof. by move/bigdprodWcp; exact: bigcprodWY. Qed. Lemma bigdprodYP (I : finType) (P : pred I) (F : I -> {group gT}) : reflect (forall i, P i -> (\prod_(j | P j && (j != i)) F j)%G \subset 'C(F i) :\: (F i)^#) (\big[dprod/1]_(i | P i) F i == (\prod_(i | P i) F i)%G). Proof. apply: (iffP eqP) => [defG i Pi | dxG]. rewrite !(bigD1 i Pi) /= in defG; have [[_ G' _ defG'] _ _ _] := dprodP defG. by apply/dprodYP; rewrite -defG defG' bigprodGE (bigdprodWY defG'). set Q := P; have: subpred Q P by []. elim: {Q}_.+1 {-2}Q (ltnSn #|Q|) => // n IHn Q leQn sQP. have [i Qi | Q0] := pickP Q; last by rewrite !big_pred0. rewrite (cardD1x Qi) add1n ltnS !(bigD1 i Qi) /= in leQn *. rewrite {}IHn {n leQn}// => [|j /andP[/sQP //]]. apply/dprodYP; apply: subset_trans (dxG i (sQP i Qi)); rewrite !bigprodGE. by apply: genS; apply/bigcupsP=> j /andP[Qj ne_ji]; rewrite (bigcup_max j) ?sQP. Qed. Lemma dprod_modl A B G H : A \x B = G -> A \subset H -> A \x (B :&: H) = G :&: H. Proof. case/dprodP=> [[U V -> -> {A B}]] defG cUV trUV sUH. rewrite dprodEcp; first by apply: cprod_modl; rewrite ?cprodE. by rewrite setIA trUV (setIidPl _) ?sub1G. Qed. Lemma dprod_modr A B G H : A \x B = G -> B \subset H -> (H :&: A) \x B = H :&: G. Proof. by rewrite -!(dprodC B) !(setIC H); exact: dprod_modl. Qed. Lemma subcent_dprod B C G A : B \x C = G -> A \subset 'N(B) :&: 'N(C) -> 'C_B(A) \x 'C_C(A) = 'C_G(A). Proof. move=> defG; have [_ _ cBC _] := dprodP defG; move: defG. by rewrite !dprodEsd 1?(centSS _ _ cBC) ?subsetIl //; exact: subcent_sdprod. Qed. Lemma dprod_card A B G : A \x B = G -> (#|A| * #|B|)%N = #|G|. Proof. by case/dprodP=> [[H K -> ->] <- _]; move/TI_cardMg. Qed. Lemma bigdprod_card I r (P : pred I) E G : \big[dprod/1]_(i <- r | P i) E i = G -> (\prod_(i <- r | P i) #|E i|)%N = #|G|. Proof. elim/big_rec2: _ G => [G <- | i A B _ IH G defG]; first by rewrite cards1. have [[_ H _ defH] _ _ _] := dprodP defG. by rewrite -(dprod_card defG) (IH H) defH. Qed. Lemma bigcprod_card_dprod I r (P : pred I) (A : I -> {set gT}) G : \big[cprod/1]_(i <- r | P i) A i = G -> \prod_(i <- r | P i) #|A i| <= #|G| -> \big[dprod/1]_(i <- r | P i) A i = G. Proof. elim: r G => [|i r IHr]; rewrite !(big_nil, big_cons) //; case: ifP => _ // G. case/cprodP=> [[K H -> defH]]; rewrite defH => <- cKH leKH_G. have /implyP := leq_trans leKH_G (dvdn_leq _ (dvdn_cardMg K H)). rewrite muln_gt0 leq_pmul2l !cardG_gt0 //= => /(IHr H defH){defH}defH. by rewrite defH dprodE // cardMg_TI // -(bigdprod_card defH). Qed. Lemma bigcprod_coprime_dprod (I : finType) (P : pred I) (A : I -> {set gT}) G : \big[cprod/1]_(i | P i) A i = G -> (forall i j, P i -> P j -> i != j -> coprime #|A i| #|A j|) -> \big[dprod/1]_(i | P i) A i = G. Proof. move=> defG coA; set Q := P in defG *; have: subpred Q P by []. elim: {Q}_.+1 {-2}Q (ltnSn #|Q|) => // m IHm Q leQm in G defG * => sQP. have [i Qi | Q0] := pickP Q; last by rewrite !big_pred0 in defG *. move: defG; rewrite !(bigD1 i Qi) /= => /cprodP[[Hi Gi defAi defGi] <-]. rewrite defAi defGi => cHGi. have{defGi} defGi: \big[dprod/1]_(j | Q j && (j != i)) A j = Gi. by apply: IHm => [||j /andP[/sQP]] //; rewrite (cardD1x Qi) in leQm. rewrite defGi dprodE // coprime_TIg // -defAi -(bigdprod_card defGi). elim/big_rec: _ => [|j n /andP[neq_ji Qj] IHn]; first exact: coprimen1. by rewrite coprime_mulr coprime_sym coA ?sQP. Qed. Lemma mem_dprod G A B x : A \x B = G -> x \in G -> exists y, exists z, [/\ y \in A, z \in B, x = y * z & {in A & B, forall u t, x = u * t -> u = y /\ t = z}]. Proof. move=> defG; have [_ _ cBA _] := dprodP defG. by apply: mem_sdprod; rewrite -dprodEsd. Qed. Lemma mem_bigdprod (I : finType) (P : pred I) F G x : \big[dprod/1]_(i | P i) F i = G -> x \in G -> exists c, [/\ forall i, P i -> c i \in F i, x = \prod_(i | P i) c i & forall e, (forall i, P i -> e i \in F i) -> x = \prod_(i | P i) e i -> forall i, P i -> e i = c i]. Proof. move=> defG; rewrite -(bigdprodW defG) => /prodsgP[c Fc ->]. exists c; split=> // e Fe eq_ce i Pi. set r := index_enum _ in defG eq_ce. have: i \in r by rewrite -[r]enumT mem_enum. elim: r G defG eq_ce => // j r IHr G; rewrite !big_cons inE. case Pj: (P j); last by case: eqP (IHr G) => // eq_ij; rewrite eq_ij Pj in Pi. case/dprodP=> [[K H defK defH] _ _]; rewrite defK defH => tiFjH eq_ce. suffices{i Pi IHr} eq_cej: c j = e j. case/predU1P=> [-> //|]; apply: IHr defH _. by apply: (mulgI (c j)); rewrite eq_ce eq_cej. rewrite !(big_nth j) !big_mkord in defH eq_ce. move/(congr1 (divgr K H)) : eq_ce; move/bigdprodW: defH => defH. by rewrite !divgrMid // -?defK -?defH ?mem_prodg // => *; rewrite ?Fc ?Fe. Qed. End InternalProd. Implicit Arguments complP [gT H A B]. Implicit Arguments splitsP [gT A B]. Implicit Arguments sdprod_normal_complP [gT K H G]. Implicit Arguments dprodYP [gT K H]. Implicit Arguments bigdprodYP [gT I P F]. Section MorphimInternalProd. Variables (gT rT : finGroupType) (D : {group gT}) (f : {morphism D >-> rT}). Section OneProd. Variables G H K : {group gT}. Hypothesis sGD : G \subset D. Lemma morphim_pprod : pprod K H = G -> pprod (f @* K) (f @* H) = f @* G. Proof. case/pprodP=> _ defG mKH; rewrite pprodE ?morphim_norms //. by rewrite -morphimMl ?(subset_trans _ sGD) -?defG // mulG_subl. Qed. Lemma morphim_coprime_sdprod : K ><| H = G -> coprime #|K| #|H| -> f @* K ><| f @* H = f @* G. Proof. rewrite /sdprod => defG coHK; move: defG. by rewrite !coprime_TIg ?coprime_morph // !subxx; exact: morphim_pprod. Qed. Lemma injm_sdprod : 'injm f -> K ><| H = G -> f @* K ><| f @* H = f @* G. Proof. move=> inj_f; case/sdprodP=> _ defG nKH tiKH. by rewrite /sdprod -injmI // tiKH morphim1 subxx morphim_pprod // pprodE. Qed. Lemma morphim_cprod : K \* H = G -> f @* K \* f @* H = f @* G. Proof. case/cprodP=> _ defG cKH; rewrite /cprod morphim_cents // morphim_pprod //. by rewrite pprodE // cents_norm // centsC. Qed. Lemma injm_dprod : 'injm f -> K \x H = G -> f @* K \x f @* H = f @* G. Proof. move=> inj_f; case/dprodP=> _ defG cHK tiKH. by rewrite /dprod -injmI // tiKH morphim1 subxx morphim_cprod // cprodE. Qed. Lemma morphim_coprime_dprod : K \x H = G -> coprime #|K| #|H| -> f @* K \x f @* H = f @* G. Proof. rewrite /dprod => defG coHK; move: defG. by rewrite !coprime_TIg ?coprime_morph // !subxx; exact: morphim_cprod. Qed. End OneProd. Implicit Type G : {group gT}. Lemma morphim_bigcprod I r (P : pred I) (H : I -> {group gT}) G : G \subset D -> \big[cprod/1]_(i <- r | P i) H i = G -> \big[cprod/1]_(i <- r | P i) f @* H i = f @* G. Proof. elim/big_rec2: _ G => [|i fB B Pi def_fB] G sGD defG. by rewrite -defG morphim1. case/cprodP: defG (defG) => [[Hi Gi -> defB] _ _]; rewrite defB => defG. rewrite (def_fB Gi) //; first exact: morphim_cprod. by apply: subset_trans sGD; case/cprod_normal2: defG => _ /andP[]. Qed. Lemma injm_bigdprod I r (P : pred I) (H : I -> {group gT}) G : G \subset D -> 'injm f -> \big[dprod/1]_(i <- r | P i) H i = G -> \big[dprod/1]_(i <- r | P i) f @* H i = f @* G. Proof. move=> sGD injf; elim/big_rec2: _ G sGD => [|i fB B Pi def_fB] G sGD defG. by rewrite -defG morphim1. case/dprodP: defG (defG) => [[Hi Gi -> defB] _ _ _]; rewrite defB => defG. rewrite (def_fB Gi) //; first exact: injm_dprod. by apply: subset_trans sGD; case/dprod_normal2: defG => _ /andP[]. Qed. Lemma morphim_coprime_bigdprod (I : finType) P (H : I -> {group gT}) G : G \subset D -> \big[dprod/1]_(i | P i) H i = G -> (forall i j, P i -> P j -> i != j -> coprime #|H i| #|H j|) -> \big[dprod/1]_(i | P i) f @* H i = f @* G. Proof. move=> sGD /bigdprodWcp defG coH; have def_fG := morphim_bigcprod sGD defG. by apply: bigcprod_coprime_dprod => // i j *; rewrite coprime_morph ?coH. Qed. End MorphimInternalProd. Section QuotientInternalProd. Variables (gT : finGroupType) (G K H M : {group gT}). Hypothesis nMG: G \subset 'N(M). Lemma quotient_pprod : pprod K H = G -> pprod (K / M) (H / M) = G / M. Proof. exact: morphim_pprod. Qed. Lemma quotient_coprime_sdprod : K ><| H = G -> coprime #|K| #|H| -> (K / M) ><| (H / M) = G / M. Proof. exact: morphim_coprime_sdprod. Qed. Lemma quotient_cprod : K \* H = G -> (K / M) \* (H / M) = G / M. Proof. exact: morphim_cprod. Qed. Lemma quotient_coprime_dprod : K \x H = G -> coprime #|K| #|H| -> (K / M) \x (H / M) = G / M. Proof. exact: morphim_coprime_dprod. Qed. End QuotientInternalProd. Section ExternalDirProd. Variables gT1 gT2 : finGroupType. Definition extprod_mulg (x y : gT1 * gT2) := (x.1 * y.1, x.2 * y.2). Definition extprod_invg (x : gT1 * gT2) := (x.1^-1, x.2^-1). Lemma extprod_mul1g : left_id (1, 1) extprod_mulg. Proof. case=> x1 x2; congr (_, _); exact: mul1g. Qed. Lemma extprod_mulVg : left_inverse (1, 1) extprod_invg extprod_mulg. Proof. by move=> x; congr (_, _); exact: mulVg. Qed. Lemma extprod_mulgA : associative extprod_mulg. Proof. by move=> x y z; congr (_, _); exact: mulgA. Qed. Definition extprod_groupMixin := Eval hnf in FinGroup.Mixin extprod_mulgA extprod_mul1g extprod_mulVg. Canonical extprod_baseFinGroupType := Eval hnf in BaseFinGroupType (gT1 * gT2) extprod_groupMixin. Canonical prod_group := FinGroupType extprod_mulVg. Lemma group_setX (H1 : {group gT1}) (H2 : {group gT2}) : group_set (setX H1 H2). Proof. apply/group_setP; split; first by rewrite inE !group1. case=> [x1 x2] [y1 y2]; rewrite !inE; case/andP=> Hx1 Hx2; case/andP=> Hy1 Hy2. by rewrite /= !groupM. Qed. Canonical setX_group H1 H2 := Group (group_setX H1 H2). Definition pairg1 x : gT1 * gT2 := (x, 1). Definition pair1g x : gT1 * gT2 := (1, x). Lemma pairg1_morphM : {morph pairg1 : x y / x * y}. Proof. by move=> x y /=; rewrite {2}/mulg /= /extprod_mulg /= mul1g. Qed. Canonical pairg1_morphism := @Morphism _ _ setT _ (in2W pairg1_morphM). Lemma pair1g_morphM : {morph pair1g : x y / x * y}. Proof. by move=> x y /=; rewrite {2}/mulg /= /extprod_mulg /= mul1g. Qed. Canonical pair1g_morphism := @Morphism _ _ setT _ (in2W pair1g_morphM). Lemma fst_morphM : {morph (@fst gT1 gT2) : x y / x * y}. Proof. by move=> x y. Qed. Lemma snd_morphM : {morph (@snd gT1 gT2) : x y / x * y}. Proof. by move=> x y. Qed. Canonical fst_morphism := @Morphism _ _ setT _ (in2W fst_morphM). Canonical snd_morphism := @Morphism _ _ setT _ (in2W snd_morphM). Lemma injm_pair1g : 'injm pair1g. Proof. by apply/subsetP=> x /morphpreP[_ /set1P[->]]; exact: set11. Qed. Lemma injm_pairg1 : 'injm pairg1. Proof. by apply/subsetP=> x /morphpreP[_ /set1P[->]]; exact: set11. Qed. Lemma morphim_pairg1 (H1 : {set gT1}) : pairg1 @* H1 = setX H1 1. Proof. by rewrite -imset2_pair imset2_set1r morphimEsub ?subsetT. Qed. Lemma morphim_pair1g (H2 : {set gT2}) : pair1g @* H2 = setX 1 H2. Proof. by rewrite -imset2_pair imset2_set1l morphimEsub ?subsetT. Qed. Lemma morphim_fstX (H1: {set gT1}) (H2 : {group gT2}) : [morphism of fun x => x.1] @* setX H1 H2 = H1. Proof. apply/eqP; rewrite eqEsubset morphimE setTI /=. apply/andP; split; apply/subsetP=> x. by case/imsetP=> x0; rewrite inE; move/andP=> [Hx1 _] ->. move=> Hx1; apply/imsetP; exists (x, 1); last by trivial. by rewrite in_setX Hx1 /=. Qed. Lemma morphim_sndX (H1: {group gT1}) (H2 : {set gT2}) : [morphism of fun x => x.2] @* setX H1 H2 = H2. Proof. apply/eqP; rewrite eqEsubset morphimE setTI /=. apply/andP; split; apply/subsetP=> x. by case/imsetP=> x0; rewrite inE; move/andP=> [_ Hx2] ->. move=>Hx2; apply/imsetP; exists (1, x); last by []. by rewrite in_setX Hx2 andbT. Qed. Lemma setX_prod (H1 : {set gT1}) (H2 : {set gT2}) : setX H1 1 * setX 1 H2 = setX H1 H2. Proof. apply/setP=> [[x y]]; rewrite !inE /=. apply/imset2P/andP=> [[[x1 u1] [v1 y1]] | [Hx Hy]]. rewrite !inE /= => /andP[Hx1 /eqP->] /andP[/eqP-> Hx] [-> ->]. by rewrite mulg1 mul1g. exists (x, 1 : gT2) (1 : gT1, y); rewrite ?inE ?Hx ?eqxx //. by rewrite /mulg /= /extprod_mulg /= mulg1 mul1g. Qed. Lemma setX_dprod (H1 : {group gT1}) (H2 : {group gT2}) : setX H1 1 \x setX 1 H2 = setX H1 H2. Proof. rewrite dprodE ?setX_prod //. apply/centsP=> [[x u]]; rewrite !inE /= => /andP[/eqP-> _] [v y]. by rewrite !inE /= => /andP[_ /eqP->]; congr (_, _); rewrite ?mul1g ?mulg1. apply/trivgP; apply/subsetP=> [[x y]]; rewrite !inE /= -!andbA. by case/and4P=> _ /eqP-> /eqP->; rewrite eqxx. Qed. Lemma isog_setX1 (H1 : {group gT1}) : isog H1 (setX H1 1). Proof. apply/isogP; exists [morphism of restrm (subsetT H1) pairg1]. by rewrite injm_restrm ?injm_pairg1. by rewrite morphim_restrm morphim_pairg1 setIid. Qed. Lemma isog_set1X (H2 : {group gT2}) : isog H2 (setX 1 H2). Proof. apply/isogP; exists [morphism of restrm (subsetT H2) pair1g]. by rewrite injm_restrm ?injm_pair1g. by rewrite morphim_restrm morphim_pair1g setIid. Qed. Lemma setX_gen (H1 : {set gT1}) (H2 : {set gT2}) : 1 \in H1 -> 1 \in H2 -> <> = setX <

> <

>. Proof. move=> H1_1 H2_1; apply/eqP. rewrite eqEsubset gen_subG setXS ?subset_gen //. rewrite -setX_prod -morphim_pair1g -morphim_pairg1 !morphim_gen ?subsetT //. by rewrite morphim_pair1g morphim_pairg1 mul_subG // genS // setXS ?sub1set. Qed. End ExternalDirProd. Section ExternalSDirProd. Variables (aT rT : finGroupType) (D : {group aT}) (R : {group rT}). (* The pair (a, x) denotes the product sdpair2 a * sdpair1 x *) Inductive sdprod_by (to : groupAction D R) : predArgType := SdPair (ax : aT * rT) of ax \in setX D R. Coercion pair_of_sd to (u : sdprod_by to) := let: SdPair ax _ := u in ax. Variable to : groupAction D R. Notation sdT := (sdprod_by to). Notation sdval := (@pair_of_sd to). Canonical sdprod_subType := Eval hnf in [subType for sdval]. Definition sdprod_eqMixin := Eval hnf in [eqMixin of sdT by <:]. Canonical sdprod_eqType := Eval hnf in EqType sdT sdprod_eqMixin. Definition sdprod_choiceMixin := [choiceMixin of sdT by <:]. Canonical sdprod_choiceType := ChoiceType sdT sdprod_choiceMixin. Definition sdprod_countMixin := [countMixin of sdT by <:]. Canonical sdprod_countType := CountType sdT sdprod_countMixin. Canonical sdprod_subCountType := Eval hnf in [subCountType of sdT]. Definition sdprod_finMixin := [finMixin of sdT by <:]. Canonical sdprod_finType := FinType sdT sdprod_finMixin. Canonical sdprod_subFinType := Eval hnf in [subFinType of sdT]. Definition sdprod_one := SdPair to (group1 _). Lemma sdprod_inv_proof (u : sdT) : (u.1^-1, to u.2^-1 u.1^-1) \in setX D R. Proof. by case: u => [[a x]] /= /setXP[Da Rx]; rewrite inE gact_stable !groupV ?Da. Qed. Definition sdprod_inv u := SdPair to (sdprod_inv_proof u). Lemma sdprod_mul_proof (u v : sdT) : (u.1 * v.1, to u.2 v.1 * v.2) \in setX D R. Proof. case: u v => [[a x] /= /setXP[Da Rx]] [[b y] /= /setXP[Db Ry]]. by rewrite inE !groupM //= gact_stable. Qed. Definition sdprod_mul u v := SdPair to (sdprod_mul_proof u v). Lemma sdprod_mul1g : left_id sdprod_one sdprod_mul. Proof. move=> u; apply: val_inj; case: u => [[a x] /=]; case/setXP=> Da _. by rewrite gact1 // !mul1g. Qed. Lemma sdprod_mulVg : left_inverse sdprod_one sdprod_inv sdprod_mul. Proof. move=> u; apply: val_inj; case: u => [[a x] /=]; case/setXP=> Da _. by rewrite actKVin ?mulVg. Qed. Lemma sdprod_mulgA : associative sdprod_mul. Proof. move=> u v w; apply: val_inj; case: u => [[a x]] /=; case/setXP=> Da Rx. case: v w => [[b y]] /=; case/setXP=> Db Ry [[c z]] /=; case/setXP=> Dc Rz. by rewrite !(actMin to) // gactM ?gact_stable // !mulgA. Qed. Canonical sdprod_groupMixin := FinGroup.Mixin sdprod_mulgA sdprod_mul1g sdprod_mulVg. Canonical sdprod_baseFinGroupType := Eval hnf in BaseFinGroupType sdT sdprod_groupMixin. Canonical sdprod_groupType := FinGroupType sdprod_mulVg. Definition sdpair1 x := insubd sdprod_one (1, x) : sdT. Definition sdpair2 a := insubd sdprod_one (a, 1) : sdT. Lemma sdpair1_morphM : {in R &, {morph sdpair1 : x y / x * y}}. Proof. move=> x y Rx Ry; apply: val_inj. by rewrite /= !val_insubd !inE !group1 !groupM ?Rx ?Ry //= mulg1 act1. Qed. Lemma sdpair2_morphM : {in D &, {morph sdpair2 : a b / a * b}}. Proof. move=> a b Da Db; apply: val_inj. by rewrite /= !val_insubd !inE !group1 !groupM ?Da ?Db //= mulg1 gact1. Qed. Canonical sdpair1_morphism := Morphism sdpair1_morphM. Canonical sdpair2_morphism := Morphism sdpair2_morphM. Lemma injm_sdpair1 : 'injm sdpair1. Proof. apply/subsetP=> x /setIP[Rx]. by rewrite !inE -val_eqE val_insubd inE Rx group1 /=; case/andP. Qed. Lemma injm_sdpair2 : 'injm sdpair2. Proof. apply/subsetP=> a /setIP[Da]. by rewrite !inE -val_eqE val_insubd inE Da group1 /=; case/andP. Qed. Lemma sdpairE (u : sdT) : u = sdpair2 u.1 * sdpair1 u.2. Proof. apply: val_inj; case: u => [[a x] /= /setXP[Da Rx]]. by rewrite !val_insubd !inE Da Rx !(group1, gact1) // mulg1 mul1g. Qed. Lemma sdpair_act : {in R & D, forall x a, sdpair1 (to x a) = sdpair1 x ^ sdpair2 a}. Proof. move=> x a Rx Da; apply: val_inj. rewrite /= !val_insubd !inE !group1 gact_stable ?Da ?Rx //=. by rewrite !mul1g mulVg invg1 mulg1 actKVin ?mul1g. Qed. Lemma sdpair_setact (G : {set rT}) a : G \subset R -> a \in D -> sdpair1 @* (to^~ a @: G) = (sdpair1 @* G) :^ sdpair2 a. Proof. move=> sGR Da; have GtoR := subsetP sGR; apply/eqP. rewrite eqEcard cardJg !(card_injm injm_sdpair1) //; last first. by apply/subsetP=> _ /imsetP[x Gx ->]; rewrite gact_stable ?GtoR. rewrite (card_imset _ (act_inj _ _)) leqnn andbT. apply/subsetP=> _ /morphimP[xa Rxa /imsetP[x Gx def_xa ->]]. rewrite mem_conjg -morphV // -sdpair_act ?groupV // def_xa actKin //. by rewrite mem_morphim ?GtoR. Qed. Lemma im_sdpair_norm : sdpair2 @* D \subset 'N(sdpair1 @* R). Proof. apply/subsetP=> _ /morphimP[a _ Da ->]. rewrite inE -sdpair_setact // morphimS //. by apply/subsetP=> _ /imsetP[x Rx ->]; rewrite gact_stable. Qed. Lemma im_sdpair_TI : (sdpair1 @* R) :&: (sdpair2 @* D) = 1. Proof. apply/trivgP; apply/subsetP=> _ /setIP[/morphimP[x _ Rx ->]]. case/morphimP=> a _ Da /eqP; rewrite inE -!val_eqE. by rewrite !val_insubd !inE Da Rx !group1 /eq_op /= eqxx; case/andP. Qed. Lemma im_sdpair : (sdpair1 @* R) * (sdpair2 @* D) = setT. Proof. apply/eqP; rewrite -subTset -(normC im_sdpair_norm). apply/subsetP=> /= u _; rewrite [u]sdpairE. by case: u => [[a x] /= /setXP[Da Rx]]; rewrite mem_mulg ?mem_morphim. Qed. Lemma sdprod_sdpair : sdpair1 @* R ><| sdpair2 @* D = setT. Proof. by rewrite sdprodE ?(im_sdpair_norm, im_sdpair, im_sdpair_TI). Qed. Variables (A : {set aT}) (G : {set rT}). Lemma gacentEsd : 'C_(|to)(A) = sdpair1 @*^-1 'C(sdpair2 @* A). Proof. apply/setP=> x; apply/idP/idP. case/setIP=> Rx /afixP cDAx; rewrite mem_morphpre //. apply/centP=> _ /morphimP[a Da Aa ->]; red. by rewrite conjgC -sdpair_act // cDAx // inE Da. case/morphpreP=> Rx cAx; rewrite inE Rx; apply/afixP=> a /setIP[Da Aa]. apply: (injmP injm_sdpair1); rewrite ?gact_stable /= ?sdpair_act //=. by rewrite /conjg (centP cAx) ?mulKg ?mem_morphim. Qed. Hypotheses (sAD : A \subset D) (sGR : G \subset R). Lemma astabEsd : 'C(G | to) = sdpair2 @*^-1 'C(sdpair1 @* G). Proof. have ssGR := subsetP sGR; apply/setP=> a; apply/idP/idP=> [cGa|]. rewrite mem_morphpre ?(astab_dom cGa) //. apply/centP=> _ /morphimP[x Rx Gx ->]; symmetry. by rewrite conjgC -sdpair_act ?(astab_act cGa) ?(astab_dom cGa). case/morphpreP=> Da cGa; rewrite !inE Da; apply/subsetP=> x Gx; rewrite inE. apply/eqP; apply: (injmP injm_sdpair1); rewrite ?gact_stable ?ssGR //=. by rewrite sdpair_act ?ssGR // /conjg -(centP cGa) ?mulKg ?mem_morphim ?ssGR. Qed. Lemma astabsEsd : 'N(G | to) = sdpair2 @*^-1 'N(sdpair1 @* G). Proof. apply/setP=> a; apply/idP/idP=> [nGa|]. have Da := astabs_dom nGa; rewrite mem_morphpre // inE sub_conjg. apply/subsetP=> _ /morphimP[x Rx Gx ->]. by rewrite mem_conjgV -sdpair_act // mem_morphim ?gact_stable ?astabs_act. case/morphpreP=> Da nGa; rewrite !inE Da; apply/subsetP=> x Gx. have Rx := subsetP sGR _ Gx; have Rxa: to x a \in R by rewrite gact_stable. rewrite inE -sub1set -(injmSK injm_sdpair1) ?morphim_set1 ?sub1set //=. by rewrite sdpair_act ?memJ_norm ?mem_morphim. Qed. Lemma actsEsd : [acts A, on G | to] = (sdpair2 @* A \subset 'N(sdpair1 @* G)). Proof. by rewrite sub_morphim_pre -?astabsEsd. Qed. End ExternalSDirProd. Section ProdMorph. Variables gT rT : finGroupType. Implicit Types A B : {set gT}. Implicit Types G H K : {group gT}. Implicit Types C D : {set rT}. Implicit Type L : {group rT}. Section defs. Variables (A B : {set gT}) (fA fB : gT -> FinGroup.sort rT). Definition pprodm of B \subset 'N(A) & {in A & B, morph_act 'J 'J fA fB} & {in A :&: B, fA =1 fB} := fun x => fA (divgr A B x) * fB (remgr A B x). End defs. Section Props. Variables H K : {group gT}. Variables (fH : {morphism H >-> rT}) (fK : {morphism K >-> rT}). Hypothesis nHK : K \subset 'N(H). Hypothesis actf : {in H & K, morph_act 'J 'J fH fK}. Hypothesis eqfHK : {in H :&: K, fH =1 fK}. Notation Local f := (pprodm nHK actf eqfHK). Lemma pprodmE x a : x \in H -> a \in K -> f (x * a) = fH x * fK a. Proof. move=> Hx Ka; have: x * a \in H * K by rewrite mem_mulg. rewrite -remgrP inE /f rcoset_sym mem_rcoset /divgr -mulgA groupMl //. case/andP; move: (remgr H K _) => b Hab Kb; rewrite morphM // -mulgA. have Kab: a * b^-1 \in K by rewrite groupM ?groupV. by congr (_ * _); rewrite eqfHK 1?inE ?Hab // -morphM // mulgKV. Qed. Lemma pprodmEl : {in H, f =1 fH}. Proof. by move=> x Hx; rewrite -(mulg1 x) pprodmE // morph1 !mulg1. Qed. Lemma pprodmEr : {in K, f =1 fK}. Proof. by move=> a Ka; rewrite -(mul1g a) pprodmE // morph1 !mul1g. Qed. Lemma pprodmM : {in H <*> K &, {morph f: x y / x * y}}. Proof. move=> xa yb; rewrite norm_joinEr //. move=> /imset2P[x a Ha Ka ->{xa}] /imset2P[y b Hy Kb ->{yb}]. have Hya: y ^ a^-1 \in H by rewrite -mem_conjg (normsP nHK). rewrite mulgA -(mulgA x) (conjgCV a y) (mulgA x) -mulgA !pprodmE 1?groupMl //. by rewrite morphM // actf ?groupV ?morphV // morphM // !mulgA mulgKV invgK. Qed. Canonical pprodm_morphism := Morphism pprodmM. Lemma morphim_pprodm A B : A \subset H -> B \subset K -> f @* (A * B) = fH @* A * fK @* B. Proof. move=> sAH sBK; rewrite [f @* _]morphimEsub /=; last first. by rewrite norm_joinEr // mulgSS. apply/setP=> y; apply/imsetP/idP=> [[_ /mulsgP[x a Ax Ba ->] ->{y}] |]. have Hx := subsetP sAH x Ax; have Ka := subsetP sBK a Ba. by rewrite pprodmE // mem_imset2 ?mem_morphim. case/mulsgP=> _ _ /morphimP[x Hx Ax ->] /morphimP[a Ka Ba ->] ->{y}. by exists (x * a); rewrite ?mem_mulg ?pprodmE. Qed. Lemma morphim_pprodml A : A \subset H -> f @* A = fH @* A. Proof. by move=> sAH; rewrite -{1}(mulg1 A) morphim_pprodm ?sub1G // morphim1 mulg1. Qed. Lemma morphim_pprodmr B : B \subset K -> f @* B = fK @* B. Proof. by move=> sBK; rewrite -{1}(mul1g B) morphim_pprodm ?sub1G // morphim1 mul1g. Qed. Lemma ker_pprodm : 'ker f = [set x * a^-1 | x in H, a in K & fH x == fK a]. Proof. apply/setP=> y; rewrite 3!inE {1}norm_joinEr //=. apply/andP/imset2P=> [[/mulsgP[x a Hx Ka ->{y}]]|[x a Hx]]. rewrite pprodmE // => fxa1. by exists x a^-1; rewrite ?invgK // inE groupVr ?morphV // eq_mulgV1 invgK. case/setIdP=> Kx /eqP fx ->{y}. by rewrite mem_imset2 ?pprodmE ?groupV ?morphV // fx mulgV. Qed. Lemma injm_pprodm : 'injm f = [&& 'injm fH, 'injm fK & fH @* H :&: fK @* K == fH @* K]. Proof. apply/idP/and3P=> [injf | [injfH injfK]]. rewrite eq_sym -{1}morphimIdom -(morphim_pprodml (subsetIl _ _)) injmI //. rewrite morphim_pprodml // morphim_pprodmr //=; split=> //. apply/injmP=> x y Hx Hy /=; rewrite -!pprodmEl //. by apply: (injmP injf); rewrite ?mem_gen ?inE ?Hx ?Hy. apply/injmP=> a b Ka Kb /=; rewrite -!pprodmEr //. by apply: (injmP injf); rewrite ?mem_gen //; apply/setUP; right. move/eqP=> fHK; rewrite ker_pprodm; apply/subsetP=> y. case/imset2P=> x a Hx /setIdP[Ka /eqP fxa] ->. have: fH x \in fH @* K by rewrite -fHK inE {2}fxa !mem_morphim. case/morphimP=> z Hz Kz /(injmP injfH) def_x. rewrite def_x // eqfHK ?inE ?Hz // in fxa. by rewrite def_x // (injmP injfK _ _ Kz Ka fxa) mulgV set11. Qed. End Props. Section Sdprodm. Variables H K G : {group gT}. Variables (fH : {morphism H >-> rT}) (fK : {morphism K >-> rT}). Hypothesis eqHK_G : H ><| K = G. Hypothesis actf : {in H & K, morph_act 'J 'J fH fK}. Lemma sdprodm_norm : K \subset 'N(H). Proof. by case/sdprodP: eqHK_G. Qed. Lemma sdprodm_sub : G \subset H <*> K. Proof. by case/sdprodP: eqHK_G => _ <- nHK _; rewrite norm_joinEr. Qed. Lemma sdprodm_eqf : {in H :&: K, fH =1 fK}. Proof. by case/sdprodP: eqHK_G => _ _ _ -> _ /set1P->; rewrite !morph1. Qed. Definition sdprodm := restrm sdprodm_sub (pprodm sdprodm_norm actf sdprodm_eqf). Canonical sdprodm_morphism := Eval hnf in [morphism of sdprodm]. Lemma sdprodmE a b : a \in H -> b \in K -> sdprodm (a * b) = fH a * fK b. Proof. exact: pprodmE. Qed. Lemma sdprodmEl a : a \in H -> sdprodm a = fH a. Proof. exact: pprodmEl. Qed. Lemma sdprodmEr b : b \in K -> sdprodm b = fK b. Proof. exact: pprodmEr. Qed. Lemma morphim_sdprodm A B : A \subset H -> B \subset K -> sdprodm @* (A * B) = fH @* A * fK @* B. Proof. move=> sAH sBK; rewrite morphim_restrm /= (setIidPr _) ?morphim_pprodm //. case/sdprodP: eqHK_G => _ <- _ _; exact: mulgSS. Qed. Lemma im_sdprodm : sdprodm @* G = fH @* H * fK @* K. Proof. by rewrite -morphim_sdprodm //; case/sdprodP: eqHK_G => _ ->. Qed. Lemma morphim_sdprodml A : A \subset H -> sdprodm @* A = fH @* A. Proof. by move=> sHA; rewrite -{1}(mulg1 A) morphim_sdprodm ?sub1G // morphim1 mulg1. Qed. Lemma morphim_sdprodmr B : B \subset K -> sdprodm @* B = fK @* B. Proof. by move=> sBK; rewrite -{1}(mul1g B) morphim_sdprodm ?sub1G // morphim1 mul1g. Qed. Lemma ker_sdprodm : 'ker sdprodm = [set a * b^-1 | a in H, b in K & fH a == fK b]. Proof. rewrite ker_restrm (setIidPr _) ?subIset ?ker_pprodm //; apply/orP; left. by case/sdprodP: eqHK_G => _ <- nHK _; rewrite norm_joinEr. Qed. Lemma injm_sdprodm : 'injm sdprodm = [&& 'injm fH, 'injm fK & fH @* H :&: fK @* K == 1]. Proof. rewrite ker_sdprodm -(ker_pprodm sdprodm_norm actf sdprodm_eqf) injm_pprodm. congr [&& _, _ & _ == _]; have [_ _ _ tiHK] := sdprodP eqHK_G. by rewrite -morphimIdom tiHK morphim1. Qed. End Sdprodm. Section Cprodm. Variables H K G : {group gT}. Variables (fH : {morphism H >-> rT}) (fK : {morphism K >-> rT}). Hypothesis eqHK_G : H \* K = G. Hypothesis cfHK : fK @* K \subset 'C(fH @* H). Hypothesis eqfHK : {in H :&: K, fH =1 fK}. Lemma cprodm_norm : K \subset 'N(H). Proof. by rewrite cents_norm //; case/cprodP: eqHK_G. Qed. Lemma cprodm_sub : G \subset H <*> K. Proof. by case/cprodP: eqHK_G => _ <- cHK; rewrite cent_joinEr. Qed. Lemma cprodm_actf : {in H & K, morph_act 'J 'J fH fK}. Proof. case/cprodP: eqHK_G => _ _ cHK a b Ha Kb /=. by rewrite /conjg -(centsP cHK b) // -(centsP cfHK (fK b)) ?mulKg ?mem_morphim. Qed. Definition cprodm := restrm cprodm_sub (pprodm cprodm_norm cprodm_actf eqfHK). Canonical cprodm_morphism := Eval hnf in [morphism of cprodm]. Lemma cprodmE a b : a \in H -> b \in K -> cprodm (a * b) = fH a * fK b. Proof. exact: pprodmE. Qed. Lemma cprodmEl a : a \in H -> cprodm a = fH a. Proof. exact: pprodmEl. Qed. Lemma cprodmEr b : b \in K -> cprodm b = fK b. Proof. exact: pprodmEr. Qed. Lemma morphim_cprodm A B : A \subset H -> B \subset K -> cprodm @* (A * B) = fH @* A * fK @* B. Proof. move=> sAH sBK; rewrite morphim_restrm /= (setIidPr _) ?morphim_pprodm //. case/cprodP: eqHK_G => _ <- _; exact: mulgSS. Qed. Lemma im_cprodm : cprodm @* G = fH @* H * fK @* K. Proof. by have [_ defHK _] := cprodP eqHK_G; rewrite -{2}defHK morphim_cprodm. Qed. Lemma morphim_cprodml A : A \subset H -> cprodm @* A = fH @* A. Proof. by move=> sHA; rewrite -{1}(mulg1 A) morphim_cprodm ?sub1G // morphim1 mulg1. Qed. Lemma morphim_cprodmr B : B \subset K -> cprodm @* B = fK @* B. Proof. by move=> sBK; rewrite -{1}(mul1g B) morphim_cprodm ?sub1G // morphim1 mul1g. Qed. Lemma ker_cprodm : 'ker cprodm = [set a * b^-1 | a in H, b in K & fH a == fK b]. Proof. rewrite ker_restrm (setIidPr _) ?subIset ?ker_pprodm //; apply/orP; left. by case/cprodP: eqHK_G => _ <- cHK; rewrite cent_joinEr. Qed. Lemma injm_cprodm : 'injm cprodm = [&& 'injm fH, 'injm fK & fH @* H :&: fK @* K == fH @* K]. Proof. by rewrite ker_cprodm -(ker_pprodm cprodm_norm cprodm_actf eqfHK) injm_pprodm. Qed. End Cprodm. Section Dprodm. Variables G H K : {group gT}. Variables (fH : {morphism H >-> rT}) (fK : {morphism K >-> rT}). Hypothesis eqHK_G : H \x K = G. Hypothesis cfHK : fK @* K \subset 'C(fH @* H). Lemma dprodm_cprod : H \* K = G. Proof. by rewrite -eqHK_G /dprod; case/dprodP: eqHK_G => _ _ _ ->; rewrite subxx. Qed. Lemma dprodm_eqf : {in H :&: K, fH =1 fK}. Proof. by case/dprodP: eqHK_G => _ _ _ -> _ /set1P->; rewrite !morph1. Qed. Definition dprodm := cprodm dprodm_cprod cfHK dprodm_eqf. Canonical dprodm_morphism := Eval hnf in [morphism of dprodm]. Lemma dprodmE a b : a \in H -> b \in K -> dprodm (a * b) = fH a * fK b. Proof. exact: pprodmE. Qed. Lemma dprodmEl a : a \in H -> dprodm a = fH a. Proof. exact: pprodmEl. Qed. Lemma dprodmEr b : b \in K -> dprodm b = fK b. Proof. exact: pprodmEr. Qed. Lemma morphim_dprodm A B : A \subset H -> B \subset K -> dprodm @* (A * B) = fH @* A * fK @* B. Proof. exact: morphim_cprodm. Qed. Lemma im_dprodm : dprodm @* G = fH @* H * fK @* K. Proof. exact: im_cprodm. Qed. Lemma morphim_dprodml A : A \subset H -> dprodm @* A = fH @* A. Proof. exact: morphim_cprodml. Qed. Lemma morphim_dprodmr B : B \subset K -> dprodm @* B = fK @* B. Proof. exact: morphim_cprodmr. Qed. Lemma ker_dprodm : 'ker dprodm = [set a * b^-1 | a in H, b in K & fH a == fK b]. Proof. exact: ker_cprodm. Qed. Lemma injm_dprodm : 'injm dprodm = [&& 'injm fH, 'injm fK & fH @* H :&: fK @* K == 1]. Proof. rewrite injm_cprodm -(morphimIdom fH K). by case/dprodP: eqHK_G => _ _ _ ->; rewrite morphim1. Qed. End Dprodm. Lemma isog_dprod A B G C D L : A \x B = G -> C \x D = L -> isog A C -> isog B D -> isog G L. Proof. move=> defG {C D} /dprodP[[C D -> ->] defL cCD trCD]. case/dprodP: defG (defG) => {A B} [[A B -> ->] defG _ _] dG defC defD. case/isogP: defC defL cCD trCD => fA injfA <-{C}. case/isogP: defD => fB injfB <-{D} defL cCD trCD. apply/isogP; exists (dprodm_morphism dG cCD). by rewrite injm_dprodm injfA injfB trCD eqxx. by rewrite /= -{2}defG morphim_dprodm. Qed. End ProdMorph. Section ExtSdprodm. Variables gT aT rT : finGroupType. Variables (H : {group gT}) (K : {group aT}) (to : groupAction K H). Variables (fH : {morphism H >-> rT}) (fK : {morphism K >-> rT}). Hypothesis actf : {in H & K, morph_act to 'J fH fK}. Local Notation fsH := (fH \o invm (injm_sdpair1 to)). Local Notation fsK := (fK \o invm (injm_sdpair2 to)). Let DgH := sdpair1 to @* H. Let DgK := sdpair2 to @* K. Lemma xsdprodm_dom1 : DgH \subset 'dom fsH. Proof. by rewrite ['dom _]morphpre_invm. Qed. Local Notation gH := (restrm xsdprodm_dom1 fsH). Lemma xsdprodm_dom2 : DgK \subset 'dom fsK. Proof. by rewrite ['dom _]morphpre_invm. Qed. Local Notation gK := (restrm xsdprodm_dom2 fsK). Lemma im_sdprodm1 : gH @* DgH = fH @* H. Proof. by rewrite morphim_restrm setIid morphim_comp im_invm. Qed. Lemma im_sdprodm2 : gK @* DgK = fK @* K. Proof. by rewrite morphim_restrm setIid morphim_comp im_invm. Qed. Lemma xsdprodm_act : {in DgH & DgK, morph_act 'J 'J gH gK}. Proof. move=> fh fk; case/morphimP=> h _ Hh ->{fh}; case/morphimP=> k _ Kk ->{fk}. by rewrite /= -sdpair_act // /restrm /= !invmE ?actf ?gact_stable. Qed. Definition xsdprodm := sdprodm (sdprod_sdpair to) xsdprodm_act. Canonical xsdprod_morphism := [morphism of xsdprodm]. Lemma im_xsdprodm : xsdprodm @* setT = fH @* H * fK @* K. Proof. by rewrite -im_sdpair morphim_sdprodm // im_sdprodm1 im_sdprodm2. Qed. Lemma injm_xsdprodm : 'injm xsdprodm = [&& 'injm fH, 'injm fK & fH @* H :&: fK @* K == 1]. Proof. rewrite injm_sdprodm im_sdprodm1 im_sdprodm2 !subG1 /= !ker_restrm !ker_comp. rewrite !morphpre_invm !morphimIim. by rewrite !morphim_injm_eq1 ?subsetIl ?injm_sdpair1 ?injm_sdpair2. Qed. End ExtSdprodm. Section DirprodIsom. Variable gT : finGroupType. Implicit Types G H : {group gT}. Definition mulgm : gT * gT -> _ := prod_curry mulg. Lemma imset_mulgm (A B : {set gT}) : mulgm @: setX A B = A * B. Proof. by rewrite -curry_imset2X. Qed. Lemma mulgmP H1 H2 G : reflect (H1 \x H2 = G) (misom (setX H1 H2) G mulgm). Proof. apply: (iffP misomP) => [[pM /isomP[injf /= <-]] | ]. have /dprodP[_ /= defX cH12] := setX_dprod H1 H2. rewrite -{4}defX {}defX => /(congr1 (fun A => morphm pM @* A)). move/(morphimS (morphm_morphism pM)): cH12 => /=. have sH1H: setX H1 1 \subset setX H1 H2 by rewrite setXS ?sub1G. have sH2H: setX 1 H2 \subset setX H1 H2 by rewrite setXS ?sub1G. rewrite morphim1 injm_cent ?injmI //= subsetI => /andP[_]. by rewrite !morphimEsub //= !imset_mulgm mulg1 mul1g; exact: dprodE. case/dprodP=> _ defG cH12 trH12. have fM: morphic (setX H1 H2) mulgm. apply/morphicP=> [[x1 x2] [y1 y2] /setXP[_ Hx2] /setXP[Hy1 _]]. by rewrite /= mulgA -(mulgA x1) -(centsP cH12 x2) ?mulgA. exists fM; apply/isomP; split; last by rewrite morphimEsub //= imset_mulgm. apply/subsetP=> [[x1 x2]]; rewrite !inE /= andbC -eq_invg_mul. case: eqP => //= <-; rewrite groupV -in_setI trH12 => /set1P->. by rewrite invg1 eqxx. Qed. End DirprodIsom. Implicit Arguments mulgmP [gT H1 H2 G]. Prenex Implicits mulgm mulgmP. mathcomp-1.5/theories/separable.v0000644000175000017500000012735112307636117016141 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div choice fintype. Require Import tuple finfun bigop finset prime binomial ssralg poly polydiv. Require Import fingroup perm morphism quotient gproduct finalg zmodp cyclic. Require Import matrix mxalgebra mxpoly polyXY vector falgebra fieldext. (******************************************************************************) (* This file provides a theory of separable and inseparable field extensions. *) (* *) (* separable_poly p <=> p has no multiple roots in any field extension. *) (* separable_element K x <=> the minimal polynomial of x over K is separable. *) (* separable K E <=> every member of E is separable over K. *) (* separable_generator K E == some x \in E that generates the largest *) (* subfield K[x] that is separable over K. *) (* purely_inseparable_element K x <=> there is a [char L].-nat n such that *) (* x ^+ n \in K. *) (* purely_inseparable K E <=> every member of E is purely inseparable over K. *) (* *) (* Derivations are introduced to prove the adjoin_separableP Lemma: *) (* Derivation K D <=> the linear operator D satifies the Leibniz *) (* product rule inside K. *) (* extendDerivation x D K == given a derivation D on K and a separable *) (* element x over K, this function returns the *) (* unique extension of D to K(x). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Open Local Scope ring_scope. Import GRing.Theory. Section SeparablePoly. Variable R : idomainType. Implicit Types p q d u v : {poly R}. Definition separable_poly p := coprimep p p^`(). Local Notation separable := separable_poly. Local Notation lcn_neq0 := (Pdiv.Idomain.lc_expn_scalp_neq0 _). Lemma separable_poly_neq0 p : separable p -> p != 0. Proof. by apply: contraTneq => ->; rewrite /separable deriv0 coprime0p eqp01. Qed. Lemma poly_square_freeP p : (forall u v, u * v %| p -> coprimep u v) <-> (forall u, size u != 1%N -> ~~ (u ^+ 2 %| p)). Proof. split=> [sq'p u | sq'p u v dvd_uv_p]. by apply: contra => /sq'p; rewrite coprimepp. rewrite coprimep_def (contraLR (sq'p _)) // (dvdp_trans _ dvd_uv_p) //. by rewrite dvdp_mul ?dvdp_gcdl ?dvdp_gcdr. Qed. Lemma separable_polyP {p} : reflect [/\ forall u v, u * v %| p -> coprimep u v & forall u, u %| p -> 1 < size u -> u^`() != 0] (separable p). Proof. apply: (iffP idP) => [sep_p | [sq'p nz_der1p]]. split=> [u v | u u_dv_p]; last first. apply: contraTneq => u'0; rewrite -leqNgt -(eqnP sep_p). rewrite dvdp_leq -?size_poly_eq0 ?(eqnP sep_p) // dvdp_gcd u_dv_p. have /dvdp_scaler <-: lead_coef u ^+ scalp p u != 0 by rewrite lcn_neq0. by rewrite -derivZ -Pdiv.Idomain.divpK //= derivM u'0 mulr0 addr0 dvdp_mull. rewrite Pdiv.Idomain.dvdp_eq mulrCA mulrA; set c := _ ^+ _ => /eqP Dcp. have nz_c: c != 0 by rewrite lcn_neq0. move: sep_p; rewrite coprimep_sym -[separable _](coprimep_scalel _ _ nz_c). rewrite -(coprimep_scaler _ _ nz_c) -derivZ Dcp derivM coprimep_mull. by rewrite coprimep_addl_mul !coprimep_mulr -andbA => /and4P[]. rewrite /separable coprimep_def eqn_leq size_poly_gt0; set g := gcdp _ _. have nz_g: g != 0. rewrite -dvd0p dvdp_gcd -(mulr0 0); apply/nandP; left. by have /poly_square_freeP-> := sq'p; rewrite ?size_poly0. have [g_p]: g %| p /\ g %| p^`() by rewrite dvdp_gcdr ?dvdp_gcdl. pose c := lead_coef g ^+ scalp p g; have nz_c: c != 0 by rewrite lcn_neq0. have Dcp: c *: p = p %/ g * g by rewrite Pdiv.Idomain.divpK. rewrite nz_g andbT leqNgt -(dvdp_scaler _ _ nz_c) -derivZ Dcp derivM. rewrite dvdp_addr; last by rewrite dvdp_mull. rewrite Gauss_dvdpr; last by rewrite sq'p // mulrC -Dcp dvdp_scalel. by apply: contraL => /nz_der1p nz_g'; rewrite gtNdvdp ?nz_g' ?lt_size_deriv. Qed. Lemma separable_coprime p u v : separable p -> u * v %| p -> coprimep u v. Proof. by move=> /separable_polyP[sq'p _] /sq'p. Qed. Lemma separable_nosquare p u k : separable p -> 1 < k -> size u != 1%N -> (u ^+ k %| p) = false. Proof. move=> /separable_polyP[/poly_square_freeP sq'p _] /subnKC <- /sq'p. by apply: contraNF; apply: dvdp_trans; rewrite exprD dvdp_mulr. Qed. Lemma separable_deriv_eq0 p u : separable p -> u %| p -> 1 < size u -> (u^`() == 0) = false. Proof. by move=> /separable_polyP[_ nz_der1p] u_p /nz_der1p/negPf->. Qed. Lemma dvdp_separable p q : q %| p -> separable p -> separable q. Proof. move=> /(dvdp_trans _)q_dv_p /separable_polyP[sq'p nz_der1p]. by apply/separable_polyP; split=> [u v /q_dv_p/sq'p | u /q_dv_p/nz_der1p]. Qed. Lemma separable_mul p q : separable (p * q) = [&& separable p, separable q & coprimep p q]. Proof. apply/idP/and3P => [sep_pq | [sep_p seq_q co_pq]]. rewrite !(dvdp_separable _ sep_pq) ?dvdp_mulIr ?dvdp_mulIl //. by rewrite (separable_coprime sep_pq). rewrite /separable derivM coprimep_mull {1}addrC mulrC !coprimep_addl_mul. by rewrite !coprimep_mulr (coprimep_sym q p) co_pq !andbT; apply/andP. Qed. Lemma eqp_separable p q : p %= q -> separable p = separable q. Proof. by case/andP=> p_q q_p; apply/idP/idP=> /dvdp_separable->. Qed. Lemma separable_root p x : separable (p * ('X - x%:P)) = separable p && ~~ root p x. Proof. rewrite separable_mul; apply: andb_id2l => seq_p. by rewrite /separable derivXsubC coprimep1 coprimep_XsubC. Qed. Lemma separable_prod_XsubC (r : seq R) : separable (\prod_(x <- r) ('X - x%:P)) = uniq r. Proof. elim: r => [|x r IH]; first by rewrite big_nil /separable_poly coprime1p. by rewrite big_cons mulrC separable_root IH root_prod_XsubC andbC. Qed. Lemma make_separable p : p != 0 -> separable (p %/ gcdp p p^`()). Proof. set g := gcdp p p^`() => nz_p; apply/separable_polyP. have max_dvd_u (u : {poly R}): 1 < size u -> exists k, ~~ (u ^+ k %| p). move=> u_gt1; exists (size p); rewrite gtNdvdp // polySpred //. by rewrite -(ltn_subRL 1) subn1 size_exp leq_pmull // -(subnKC u_gt1). split=> [|u u_pg u_gt1]; last first. apply/eqP=> u'0 /=; have [k /negP[]] := max_dvd_u u u_gt1. elim: k => [|k IHk]; first by rewrite dvd1p. suffices: u ^+ k.+1 %| (p %/ g) * g. by rewrite Pdiv.Idomain.divpK ?dvdp_gcdl // dvdp_scaler ?lcn_neq0. rewrite exprS dvdp_mul // dvdp_gcd IHk //=. suffices: u ^+ k %| (p %/ u ^+ k * u ^+ k)^`(). by rewrite Pdiv.Idomain.divpK // derivZ dvdp_scaler ?lcn_neq0. by rewrite !derivCE u'0 mul0r mul0rn mulr0 addr0 dvdp_mull. have pg_dv_p: p %/ g %| p by rewrite divp_dvd ?dvdp_gcdl. apply/poly_square_freeP=> u; rewrite neq_ltn ltnS leqn0 size_poly_eq0. case/predU1P=> [-> | /max_dvd_u[k]]. by apply: contra nz_p; rewrite expr0n -dvd0p => /dvdp_trans->. apply: contra => u2_dv_pg; case: k; [by rewrite dvd1p | elim=> [|n IHn]]. exact: dvdp_trans (dvdp_mulr _ _) (dvdp_trans u2_dv_pg pg_dv_p). suff: u ^+ n.+2 %| (p %/ g) * g. by rewrite Pdiv.Idomain.divpK ?dvdp_gcdl // dvdp_scaler ?lcn_neq0. rewrite -add2n exprD dvdp_mul // dvdp_gcd. rewrite (dvdp_trans _ IHn) ?exprS ?dvdp_mull //=. suff: u ^+ n %| ((p %/ u ^+ n.+1) * u ^+ n.+1)^`(). by rewrite Pdiv.Idomain.divpK // derivZ dvdp_scaler ?lcn_neq0. by rewrite !derivCE dvdp_add // -1?mulr_natl ?exprS !dvdp_mull. Qed. End SeparablePoly. Implicit Arguments separable_polyP [R p]. Lemma separable_map (F : fieldType) (R : idomainType) (f : {rmorphism F -> R}) (p : {poly F}) : separable_poly (map_poly f p) = separable_poly p. Proof. by rewrite /separable_poly deriv_map /coprimep -gcdp_map size_map_poly. Qed. Section InfinitePrimitiveElementTheorem. Local Notation "p ^ f" := (map_poly f p) : ring_scope. Variables (F L : fieldType) (iota : {rmorphism F -> L}). Variables (x y : L) (p : {poly F}). Hypotheses (nz_p : p != 0) (px_0 : root (p ^ iota) x). Let inFz z w := exists q, (q ^ iota).[z] = w. Lemma large_field_PET q : root (q ^ iota) y -> separable_poly q -> exists2 r, r != 0 & forall t (z := iota t * y - x), ~~ root r (iota t) -> inFz z x /\ inFz z y. Proof. move=> qy_0 sep_q; have nz_q := separable_poly_neq0 sep_q. have /factor_theorem[q0 Dq] := qy_0. set p1 := p ^ iota \Po ('X + x%:P); set q1 := q0 \Po ('X + y%:P). have nz_p1: p1 != 0. apply: contraNneq nz_p => /(canRL (fun r => comp_polyXaddC_K r _))/eqP. by rewrite comp_poly0 map_poly_eq0. have{sep_q} nz_q10: q1.[0] != 0. move: sep_q; rewrite -(separable_map iota) Dq separable_root => /andP[_]. by rewrite horner_comp !hornerE. have nz_q1: q1 != 0 by apply: contraNneq nz_q10 => ->; rewrite horner0. pose p2 := p1 ^ polyC \Po ('X * 'Y); pose q2 := q1 ^ polyC. have /Bezout_coprimepP[[u v]]: coprimep p2 q2. rewrite coprimep_def eqn_leq leqNgt andbC size_poly_gt0 gcdp_eq0 poly_XmY_eq0. by rewrite map_polyC_eq0 (negPf nz_p1) -resultant_eq0 div_annihilant_neq0. rewrite -size_poly_eq1 => /size_poly1P[r nzr Dr]; exists r => {nzr}// t z nz_rt. have [r1 nz_r1 r1z_0]: algebraicOver iota z. apply/algebraic_sub; last by exists p. by apply: algebraic_mul; [apply: algebraic_id | exists q]. pose Fz := subFExtend iota z r1; pose kappa : Fz -> L := subfx_inj. pose kappa' := inj_subfx iota z r1. have /eq_map_poly Diota: kappa \o kappa' =1 iota. by move=> w; rewrite /kappa /= subfx_inj_eval // map_polyC hornerC. suffices [y3]: exists y3, y = kappa y3. have [q3 ->] := subfxE y3; rewrite /kappa subfx_inj_eval // => Dy. split; [exists (t *: q3 - 'X) | by exists q3]. by rewrite rmorphB linearZ /= map_polyX !hornerE -Dy opprB addrC addrNK. pose p0 := p ^ iota \Po (iota t *: 'X - z%:P). have co_p0_q0: coprimep p0 q0. pose at_t := horner_eval (iota t); have at_t0: at_t 0 = 0 by apply: rmorph0. have /map_polyK polyCK: cancel polyC at_t by move=> w; apply: hornerC. have ->: p0 = p2 ^ at_t \Po ('X - y%:P). rewrite map_comp_poly polyCK // rmorphM /= map_polyC map_polyX /=. rewrite horner_evalE hornerX. rewrite -!comp_polyA comp_polyM comp_polyD !comp_polyC !comp_polyX. by rewrite mulrC mulrBr mul_polyC addrAC -addrA -opprB -rmorphM -rmorphB. have ->: q0 = q2 ^ at_t \Po ('X - y%:P) by rewrite polyCK ?comp_polyXaddC_K. apply/coprimep_comp_poly/Bezout_coprimepP; exists (u ^ at_t, v ^ at_t). by rewrite -!rmorphM -rmorphD Dr /= map_polyC polyC_eqp1. have{co_p0_q0}: gcdp p0 (q ^ iota) %= 'X - y%:P. rewrite /eqp Dq (eqp_dvdl _ (Gauss_gcdpr _ _)) // dvdp_gcdr dvdp_gcd. rewrite dvdp_mull // -root_factor_theorem rootE horner_comp !hornerE. by rewrite opprB addrC subrK. have{p0} [p3 ->]: exists p3, p0 = p3 ^ kappa. exists (p ^ kappa' \Po (kappa' t *: 'X - (subfx_eval iota z r1 'X)%:P)). rewrite map_comp_poly rmorphB linearZ /= map_polyC map_polyX /=. rewrite !subfx_inj_eval // map_polyC hornerC map_polyX hornerX. by rewrite -map_poly_comp Diota. rewrite -Diota map_poly_comp -gcdp_map /= -/kappa. move: (gcdp _ _) => r3 /eqpf_eq[c nz_c Dr3]. exists (- (r3`_0 / r3`_1)); rewrite [kappa _]rmorphN fmorph_div -!coef_map Dr3. by rewrite !coefZ polyseqXsubC mulr1 mulrC mulKf ?opprK. Qed. Lemma char0_PET (q : {poly F}) : q != 0 -> root (q ^ iota) y -> [char F] =i pred0 -> exists n, let z := y *+ n - x in inFz z x /\ inFz z y. Proof. move=> nz_q qy_0 /charf0P charF0. without loss{nz_q} sep_q: q qy_0 / separable_poly q. move=> IHq; apply: IHq (make_separable nz_q). have /dvdpP[q1 Dq] := dvdp_gcdl q q^`(). rewrite {1}Dq mulpK ?gcdp_eq0; last by apply/nandP; left. have [n [r nz_ry Dr]] := multiplicity_XsubC (q ^ iota) y. rewrite map_poly_eq0 nz_q /= in nz_ry. case: n => [|n] in Dr; first by rewrite Dr mulr1 (negPf nz_ry) in qy_0. have: ('X - y%:P) ^+ n.+1 %| q ^ iota by rewrite Dr dvdp_mulIr. rewrite Dq rmorphM /= gcdp_map -(eqp_dvdr _ (gcdp_mul2l _ _ _)) -deriv_map Dr. rewrite dvdp_gcd derivM deriv_exp derivXsubC mul1r !mulrA dvdp_mulIr /=. rewrite mulrDr mulrA dvdp_addr ?dvdp_mulIr // exprS -scaler_nat -!scalerAr. rewrite dvdp_scaler -?(rmorph_nat iota) ?fmorph_eq0 ?charF0 //. rewrite mulrA dvdp_mul2r ?expf_neq0 ?polyXsubC_eq0 //. by rewrite Gauss_dvdpl ?dvdp_XsubCl // coprimep_sym coprimep_XsubC. have [r nz_r PETxy] := large_field_PET qy_0 sep_q. pose ts := mkseq (fun n => iota n%:R) (size r). have /(max_ring_poly_roots nz_r)/=/implyP: uniq_roots ts. rewrite uniq_rootsE mkseq_uniq // => m n eq_mn; apply/eqP; rewrite eqn_leq. wlog suffices: m n eq_mn / m <= n by move=> IHmn; rewrite !IHmn. move/fmorph_inj/eqP: eq_mn; rewrite -subr_eq0 leqNgt; apply: contraL => lt_mn. by rewrite -natrB ?(ltnW lt_mn) // charF0 -lt0n subn_gt0. rewrite size_mkseq ltnn implybF all_map => /allPn[n _ /= /PETxy]. by rewrite rmorph_nat mulr_natl; exists n. Qed. End InfinitePrimitiveElementTheorem. Section Separable. Variables (F : fieldType) (L : fieldExtType F). Implicit Types (U V W : {vspace L}) (E K M : {subfield L}) (D : 'End(L)). Section Derivation. Variables (K : {vspace L}) (D : 'End(L)). (* A deriviation only needs to be additive and satify Lebniz's law, but all *) (* the deriviations used here are going to be linear, so we only define *) (* the Derivation predicate for linear endomorphisms. *) Definition Derivation (s := vbasis K) : bool := all (fun u => all (fun v => D (u * v) == D u * v + u * D v) s) s. Hypothesis derD : Derivation. Lemma Derivation_mul : {in K &, forall u v, D (u * v) = D u * v + u * D v}. Proof. move=> u v /coord_vbasis-> /coord_vbasis->. rewrite !(mulr_sumr, linear_sum) -big_split; apply: eq_bigr => /= j _. rewrite !mulr_suml linear_sum -big_split; apply: eq_bigr => /= i _. rewrite !(=^~ scalerAl, linearZZ) -!scalerAr linearZZ -!scalerDr !scalerA /=. by congr (_ *: _); apply/eqP; rewrite (allP (allP derD _ _)) ?memt_nth. Qed. Lemma Derivation_mul_poly (Dp := map_poly D) : {in polyOver K &, forall p q, Dp (p * q) = Dp p * q + p * Dp q}. Proof. move=> p q Kp Kq; apply/polyP=> i; rewrite {}/Dp coefD coef_map /= !coefM. rewrite linear_sum -big_split; apply: eq_bigr => /= j _. by rewrite !{1}coef_map Derivation_mul ?(polyOverP _). Qed. End Derivation. Lemma DerivationS E K D : (K <= E)%VS -> Derivation E D -> Derivation K D. Proof. move/subvP=> sKE derD; apply/allP=> x Kx; apply/allP=> y Ky; apply/eqP. by rewrite (Derivation_mul derD) ?sKE // vbasis_mem. Qed. Section DerivationAlgebra. Variables (E : {subfield L}) (D : 'End(L)). Hypothesis derD : Derivation E D. Lemma Derivation1 : D 1 = 0. Proof. apply: (addIr (D (1 * 1))); rewrite add0r {1}mul1r. by rewrite (Derivation_mul derD) ?mem1v // mulr1 mul1r. Qed. Lemma Derivation_scalar x : x \in 1%VS -> D x = 0. Proof. by case/vlineP=> y ->; rewrite linearZ /= Derivation1 scaler0. Qed. Lemma Derivation_exp x m : x \in E -> D (x ^+ m) = x ^+ m.-1 *+ m * D x. Proof. move=> Ex; case: m; first by rewrite expr0 mulr0n mul0r Derivation1. elim=> [|m IHm]; first by rewrite mul1r. rewrite exprS (Derivation_mul derD) //; last by apply: rpredX. by rewrite mulrC IHm mulrA mulrnAr -exprS -mulrDl. Qed. Lemma Derivation_horner p x : p \is a polyOver E -> x \in E -> D p.[x] = (map_poly D p).[x] + p^`().[x] * D x. Proof. move=> Ep Ex; elim/poly_ind: p Ep => [|p c IHp] /polyOverP EpXc. by rewrite !(raddf0, horner0) mul0r add0r. have Ep: p \is a polyOver E. by apply/polyOverP=> i; have:= EpXc i.+1; rewrite coefD coefMX coefC addr0. have->: map_poly D (p * 'X + c%:P) = map_poly D p * 'X + (D c)%:P. apply/polyP=> i; rewrite !(coefD, coefMX, coef_map) /= linearD /= !coefC. by rewrite !(fun_if D) linear0. rewrite derivMXaddC !hornerE mulrDl mulrAC addrAC linearD /=; congr (_ + _). by rewrite addrCA -mulrDl -IHp // addrC (Derivation_mul derD) ?rpred_horner. Qed. End DerivationAlgebra. Definition separable_element U x := separable_poly (minPoly U x). Section SeparableElement. Variables (K : {subfield L}) (x : L). (* begin hide *) Let sKxK : (K <= <>)%VS := subv_adjoin K x. Let Kx_x : x \in <>%VS := memv_adjoin K x. (* end hide *) Lemma separable_elementP : reflect (exists f, [/\ f \is a polyOver K, root f x & separable_poly f]) (separable_element K x). Proof. apply: (iffP idP) => [sep_x | [f [Kf /(minPoly_dvdp Kf)/dvdpP[g ->]]]]. by exists (minPoly K x); rewrite minPolyOver root_minPoly. by rewrite separable_mul => /and3P[]. Qed. Lemma base_separable : x \in K -> separable_element K x. Proof. move=> Kx; apply/separable_elementP; exists ('X - x%:P). by rewrite polyOverXsubC root_XsubC /separable_poly !derivCE coprimep1. Qed. Lemma separable_nz_der : separable_element K x = ((minPoly K x)^`() != 0). Proof. rewrite /separable_element /separable_poly. apply/idP/idP=> [|nzPx']. by apply: contraTneq => ->; rewrite coprimep0 -size_poly_eq1 size_minPoly. have gcdK : gcdp (minPoly K x) (minPoly K x)^`() \in polyOver K. by rewrite gcdp_polyOver ?polyOver_deriv // minPolyOver. rewrite -gcdp_eqp1 -size_poly_eq1 -dvdp1. have /orP[/andP[_]|/andP[]//] := minPoly_irr gcdK (dvdp_gcdl _ _). rewrite dvdp_gcd dvdpp /= => /(dvdp_leq nzPx')/leq_trans/(_ (size_poly _ _)). by rewrite size_minPoly ltnn. Qed. Lemma separablePn : reflect (exists2 p, p \in [char L] & exists2 g, g \is a polyOver K & minPoly K x = g \Po 'X^p) (~~ separable_element K x). Proof. rewrite separable_nz_der negbK; set f := minPoly K x. apply: (iffP eqP) => [f'0 | [p Hp [g _ ->]]]; last first. by rewrite deriv_comp derivXn -scaler_nat (charf0 Hp) scale0r mulr0. pose n := adjoin_degree K x; have sz_f: size f = n.+1 := size_minPoly K x. have fn1: f`_n = 1 by rewrite -(monicP (monic_minPoly K x)) lead_coefE sz_f. have dimKx: (adjoin_degree K x)%:R == 0 :> L. by rewrite -(coef0 _ n.-1) -f'0 coef_deriv fn1. have /natf0_char[// | p charLp] := dimKx. have /dvdnP[r Dn]: (p %| n)%N by rewrite (dvdn_charf charLp). exists p => //; exists (\poly_(i < r.+1) f`_(i * p)). by apply: polyOver_poly => i _; rewrite (polyOverP _) ?minPolyOver. rewrite comp_polyE size_poly_eq -?Dn ?fn1 ?oner_eq0 //. have pr_p := charf_prime charLp; have p_gt0 := prime_gt0 pr_p. apply/polyP=> i; rewrite coef_sum. have [[{i} i ->] | p'i] := altP (@dvdnP p i); last first. rewrite big1 => [|j _]; last first. rewrite coefZ -exprM coefXn [_ == _](contraNF _ p'i) ?mulr0 // => /eqP->. by rewrite dvdn_mulr. rewrite (dvdn_charf charLp) in p'i; apply: mulfI p'i _ _ _. by rewrite mulr0 mulr_natl; case: i => // i; rewrite -coef_deriv f'0 coef0. have [ltri | leir] := leqP r.+1 i. rewrite nth_default ?sz_f ?Dn ?ltn_pmul2r ?big1 // => j _. rewrite coefZ -exprM coefXn mulnC gtn_eqF ?mulr0 //. by rewrite ltn_pmul2l ?(leq_trans _ ltri). rewrite (bigD1 (Sub i _)) //= big1 ?addr0 => [|j i'j]; last first. by rewrite coefZ -exprM coefXn mulnC eqn_pmul2l // mulr_natr mulrb ifN_eqC. by rewrite coef_poly leir coefZ -exprM coefXn mulnC eqxx mulr1. Qed. Lemma separable_root_der : separable_element K x (+) root (minPoly K x)^`() x. Proof. have KpKx': _^`() \is a polyOver K := polyOver_deriv (minPolyOver K x). rewrite separable_nz_der addNb (root_small_adjoin_poly KpKx') ?addbb //. by rewrite (leq_trans (size_poly _ _)) ?size_minPoly. Qed. Lemma Derivation_separable D : Derivation <> D -> separable_element K x -> D x = - (map_poly D (minPoly K x)).[x] / (minPoly K x)^`().[x]. Proof. move=> derD sepKx; have:= separable_root_der; rewrite {}sepKx -sub0r => nzKx'x. apply: canRL (mulfK nzKx'x) (canRL (addrK _) _); rewrite mulrC addrC. rewrite -(Derivation_horner derD) ?minPolyxx ?linear0 //. exact: polyOverSv sKxK _ (minPolyOver _ _). Qed. Section ExtendDerivation. Variable D : 'End(L). Let Dx E := - (map_poly D (minPoly E x)).[x] / ((minPoly E x)^`()).[x]. Fact extendDerivation_subproof E (adjEx := Fadjoin_poly E x) : let body y (p := adjEx y) := (map_poly D p).[x] + p^`().[x] * Dx E in linear body. Proof. move: Dx => C /= a u v. rewrite /adjEx linearP /= -mul_polyC derivD derivM derivC mul0r add0r -/adjEx. rewrite !hornerE /= -scalerAl mul1r raddfD /=. have ->: map_poly D (a%:A%:P * adjEx u) = a%:A%:P * map_poly D (adjEx u). apply/polyP=> i; rewrite !mul_polyC !coef_map !coefZ !mulr_algl /= linearZ. by rewrite coef_map. rewrite !hornerE !mulr_algl mulrDl scalerDr -scalerAl -!addrA; congr (_ + _). by rewrite addrCA. Qed. Definition extendDerivation E : 'End(L) := linfun (Linear (extendDerivation_subproof E)). Hypothesis derD : Derivation K D. Lemma extendDerivation_id y : y \in K -> extendDerivation K y = D y. Proof. move=> yK; rewrite lfunE /= Fadjoin_polyC // derivC map_polyC hornerC. by rewrite horner0 mul0r addr0. Qed. Lemma extendDerivation_horner p : p \is a polyOver K -> separable_element K x -> extendDerivation K p.[x] = (map_poly D p).[x] + p^`().[x] * Dx K. Proof. move=> Kp sepKx; have:= separable_root_der; rewrite {}sepKx /= => nz_pKx'x. rewrite {-1}(divp_eq p (minPoly K x)) lfunE /= Fadjoin_poly_mod // raddfD /=. rewrite {1}(Derivation_mul_poly derD) ?divp_polyOver ?minPolyOver //. rewrite derivD derivM !{1}hornerD !{1}hornerM minPolyxx !{1}mulr0 !{1}add0r. rewrite mulrDl addrA [_ + (_ * _ * _)]addrC {2}/Dx -mulrA -/Dx. by rewrite [_ / _]mulrC (mulVKf nz_pKx'x) mulrN addKr. Qed. Lemma extendDerivationP : separable_element K x -> Derivation <> (extendDerivation K). Proof. move=> sep; apply/allP=> u /vbasis_mem Hu; apply/allP=> v /vbasis_mem Hv. apply/eqP. rewrite -(Fadjoin_poly_eq Hu) -(Fadjoin_poly_eq Hv) -hornerM. rewrite !{1}extendDerivation_horner ?{1}rpredM ?Fadjoin_polyOver //. rewrite (Derivation_mul_poly derD) ?Fadjoin_polyOver //. rewrite derivM !{1}hornerD !{1}hornerM !{1}mulrDl !{1}mulrDr -!addrA. congr (_ + _); rewrite [Dx K]lock -!{1}mulrA !{1}addrA; congr (_ + _). by rewrite addrC; congr (_ * _ + _); rewrite mulrC. Qed. End ExtendDerivation. (* Reference: http://www.math.uconn.edu/~kconrad/blurbs/galoistheory/separable2.pdf *) Lemma Derivation_separableP : reflect (forall D, Derivation <> D -> K <= lker D -> <> <= lker D)%VS (separable_element K x). Proof. apply: (iffP idP) => [sepKx D derD /subvP DK_0 | derKx_0]. have{DK_0} DK_0 q: q \is a polyOver K -> map_poly D q = 0. move=> /polyOverP Kq; apply/polyP=> i; apply/eqP. by rewrite coef0 coef_map -memv_ker DK_0. apply/subvP=> _ /Fadjoin_polyP[p Kp ->]; rewrite memv_ker. rewrite (Derivation_horner derD) ?(polyOverSv sKxK) //. rewrite (Derivation_separable derD sepKx) !DK_0 ?minPolyOver //. by rewrite horner0 oppr0 mul0r mulr0 addr0. apply: wlog_neg; rewrite {1}separable_nz_der negbK => /eqP pKx'_0. have Dlin: linear (fun y => (Fadjoin_poly K x y)^`().[x]). move=> a u v; rewrite linearP /= -mul_polyC derivD derivM derivC mul0r add0r. by rewrite hornerD hornerM hornerC -scalerAl mul1r. pose D := linfun (Linear Dlin); apply: base_separable. have DK_0: (K <= lker D)%VS. apply/subvP=> v Kv; rewrite memv_ker lfunE /= Fadjoin_polyC //. by rewrite derivC horner0. have Dder: Derivation <> D. apply/allP=> u /vbasis_mem Kx_u; apply/allP=> v /vbasis_mem Kx_v. rewrite !lfunE /= -{-2}(Fadjoin_poly_eq Kx_u) -{-3}(Fadjoin_poly_eq Kx_v). rewrite -!hornerM -hornerD -derivM. rewrite Fadjoin_poly_mod ?rpredM ?Fadjoin_polyOver //. rewrite {2}(divp_eq (_ * _) (minPoly K x)) derivD derivM pKx'_0 mulr0 addr0. by rewrite hornerD hornerM minPolyxx mulr0 add0r. have{Dder DK_0}: x \in lker D by apply: subvP Kx_x; apply: derKx_0. apply: contraLR => K'x; rewrite memv_ker lfunE /= Fadjoin_polyX //. by rewrite derivX hornerC oner_eq0. Qed. End SeparableElement. Implicit Arguments separable_elementP [K x]. Lemma separable_elementS K E x : (K <= E)%VS -> separable_element K x -> separable_element E x. Proof. move=> sKE /separable_elementP[f [fK rootf sepf]]; apply/separable_elementP. by exists f; rewrite (polyOverSv sKE). Qed. Lemma adjoin_separableP {K x} : reflect (forall y, y \in <>%VS -> separable_element K y) (separable_element K x). Proof. apply: (iffP idP) => [sepKx | -> //]; last exact: memv_adjoin. move=> _ /Fadjoin_polyP[q Kq ->]; apply/Derivation_separableP=> D derD DK_0. apply/subvP=> _ /Fadjoin_polyP[p Kp ->]. rewrite memv_ker -(extendDerivation_id x D (mempx_Fadjoin _ Kp)). have sepFyx: (separable_element <> x). by apply: (separable_elementS (subv_adjoin _ _)). have KyxEqKx: (<< <>; x>> = <>)%VS. apply/eqP; rewrite eqEsubv andbC adjoinSl ?subv_adjoin //=. apply/FadjoinP/andP; rewrite memv_adjoin andbT. by apply/FadjoinP/andP; rewrite subv_adjoin mempx_Fadjoin. have:= extendDerivationP derD sepFyx; rewrite KyxEqKx => derDx. rewrite -horner_comp (Derivation_horner derDx) ?memv_adjoin //; last first. by apply: (polyOverSv (subv_adjoin _ _)); apply: polyOver_comp. set Dx_p := map_poly _; have Dx_p_0 t: t \is a polyOver K -> (Dx_p t).[x] = 0. move/polyOverP=> Kt; congr (_.[x] = 0): (horner0 x); apply/esym/polyP => i. have /eqP Dti_0: D t`_i == 0 by rewrite -memv_ker (subvP DK_0) ?Kt. by rewrite coef0 coef_map /= {1}extendDerivation_id ?subvP_adjoin. rewrite (Derivation_separable derDx sepKx) -/Dx_p Dx_p_0 ?polyOver_comp //. by rewrite add0r mulrCA Dx_p_0 ?minPolyOver ?oppr0 ?mul0r. Qed. Lemma separable_exponent K x : exists n, [char L].-nat n && separable_element K (x ^+ n). Proof. pose d := adjoin_degree K x; move: {2}d.+1 (ltnSn d) => n. elim: n => // n IHn in x @d *; rewrite ltnS => le_d_n. have [[p charLp]|] := altP (separablePn K x); last by rewrite negbK; exists 1%N. case=> g Kg defKx; have p_pr := charf_prime charLp. suffices /IHn[m /andP[charLm sepKxpm]]: adjoin_degree K (x ^+ p) < n. by exists (p * m)%N; rewrite pnat_mul pnatE // charLp charLm exprM. apply: leq_trans le_d_n; rewrite -ltnS -!size_minPoly. have nzKx: minPoly K x != 0 by rewrite monic_neq0 ?monic_minPoly. have nzg: g != 0 by apply: contra_eqN defKx => /eqP->; rewrite comp_poly0. apply: leq_ltn_trans (dvdp_leq nzg _) _. by rewrite minPoly_dvdp // rootE -hornerXn -horner_comp -defKx minPolyxx. rewrite (polySpred nzKx) ltnS defKx size_comp_poly size_polyXn /=. suffices g_gt1: 1 < size g by rewrite -(subnKC g_gt1) ltn_Pmulr ?prime_gt1. apply: contra_eqT (size_minPoly K x); rewrite defKx -leqNgt => /size1_polyC->. by rewrite comp_polyC size_polyC; case: (_ != 0). Qed. Lemma charf0_separable K : [char L] =i pred0 -> forall x, separable_element K x. Proof. move=> charL0 x; have [n /andP[charLn]] := separable_exponent K x. by rewrite (pnat_1 charLn (sub_in_pnat _ charLn)) // => p _; rewrite charL0. Qed. Lemma charf_p_separable K x e p : p \in [char L] -> separable_element K x = (x \in <>%VS). Proof. move=> charLp; apply/idP/idP=> [sepKx | /Fadjoin_poly_eq]; last first. set m := p ^ _;set f := Fadjoin_poly K _ x => Dx; apply/separable_elementP. have mL0: m%:R = 0 :> L by apply/eqP; rewrite -(dvdn_charf charLp) dvdn_exp. exists ('X - (f \Po 'X^m)); split. - by rewrite rpredB ?polyOver_comp ?rpredX ?polyOverX ?Fadjoin_polyOver. - by rewrite rootE !hornerE horner_comp hornerXn Dx subrr. rewrite /separable_poly !(derivE, deriv_comp) -mulr_natr -rmorphMn /= mL0. by rewrite !mulr0 subr0 coprimep1. without loss{e} ->: e x sepKx / e = 0%N. move=> IH; elim: {e}e.+1 => [|e]; [exact: memv_adjoin | apply: subvP]. apply/FadjoinP/andP; rewrite subv_adjoin expnSr exprM (IH 0%N) //. by have /adjoin_separableP-> := sepKx; rewrite ?rpredX ?memv_adjoin. set K' := <>%VS; have sKK': (K <= K')%VS := subv_adjoin _ _. pose q := minPoly K' x; pose g := 'X^p - (x ^+ p)%:P. have [K'g]: g \is a polyOver K' /\ q \is a polyOver K'. by rewrite minPolyOver rpredB ?rpredX ?polyOverX // polyOverC memv_adjoin. have /dvdpP[c Dq]: 'X - x%:P %| q by rewrite dvdp_XsubCl root_minPoly. have co_c_g: coprimep c g. have charPp: p \in [char {poly L}] := rmorph_char (polyC_rmorphism _) charLp. rewrite /g polyC_exp -!(Frobenius_autE charPp) -rmorphB coprimep_expr //. have: separable_poly q := separable_elementS sKK' sepKx. by rewrite Dq separable_mul => /and3P[]. have{g K'g co_c_g} /size_poly1P[a nz_a Dc]: size c == 1%N. suffices c_dv_g: c %| g by rewrite -(eqp_size (dvdp_gcd_idl c_dv_g)). have: q %| g by rewrite minPoly_dvdp // rootE !hornerE hornerXn subrr. by apply: dvdp_trans; rewrite Dq dvdp_mulIl. rewrite {q}Dq {c}Dc mulrBr -rmorphM -rmorphN -cons_poly_def qualifE. by rewrite polyseq_cons !polyseqC nz_a /= rpredN andbCA => /and3P[/fpredMl->]. Qed. Lemma charf_n_separable K x n : [char L].-nat n -> 1 < n -> separable_element K x = (x \in <>%VS). Proof. rewrite -pi_pdiv; set p := pdiv n => charLn pi_n_p. have charLp: p \in [char L] := pnatPpi charLn pi_n_p. have <-: (n`_p)%N = n by rewrite -(eq_partn n (charf_eq charLp)) part_pnat_id. by rewrite p_part lognE -mem_primes pi_n_p -charf_p_separable. Qed. Definition purely_inseparable_element U x := x ^+ ex_minn (separable_exponent <> x) \in U. Lemma purely_inseparable_elementP {K x} : reflect (exists2 n, [char L].-nat n & x ^+ n \in K) (purely_inseparable_element K x). Proof. rewrite /purely_inseparable_element. case: ex_minnP => n /andP[charLn /=]; rewrite subfield_closed => sepKxn min_xn. apply: (iffP idP) => [Kxn | [m charLm Kxm]]; first by exists n. have{min_xn}: n <= m by rewrite min_xn ?charLm ?base_separable. rewrite leq_eqVlt => /predU1P[-> // | ltnm]; pose p := pdiv m. have m_gt1: 1 < m by have [/leq_ltn_trans->] := andP charLn. have charLp: p \in [char L] by rewrite (pnatPpi charLm) ?pi_pdiv. have [/p_natP[em Dm] /p_natP[en Dn]]: p.-nat m /\ p.-nat n. by rewrite -!(eq_pnat _ (charf_eq charLp)). rewrite Dn Dm ltn_exp2l ?prime_gt1 ?pdiv_prime // in ltnm. rewrite -(Fadjoin_idP Kxm) Dm -(subnKC ltnm) addSnnS expnD exprM -Dn. by rewrite -charf_p_separable. Qed. Lemma separable_inseparable_element K x : separable_element K x && purely_inseparable_element K x = (x \in K). Proof. rewrite /purely_inseparable_element; case: ex_minnP => [[|m]] //=. rewrite subfield_closed; case: m => /= [-> //| m _ /(_ 1%N)/implyP/= insepKx]. by rewrite (negPf insepKx) (contraNF (@base_separable K x) insepKx). Qed. Lemma base_inseparable K x : x \in K -> purely_inseparable_element K x. Proof. by rewrite -separable_inseparable_element => /andP[]. Qed. Lemma sub_inseparable K E x : (K <= E)%VS -> purely_inseparable_element K x -> purely_inseparable_element E x. Proof. move/subvP=> sKE /purely_inseparable_elementP[n charLn /sKE Exn]. by apply/purely_inseparable_elementP; exists n. Qed. Section PrimitiveElementTheorem. Variables (K : {subfield L}) (x y : L). Section FiniteCase. Variable N : nat. Let K_is_large := exists s, [/\ uniq s, {subset s <= K} & N < size s]. Let cyclic_or_large (z : L) : z != 0 -> K_is_large \/ exists a, z ^+ a.+1 = 1. Proof. move=> nz_z; pose d := adjoin_degree K z. pose h0 (i : 'I_(N ^ d).+1) (j : 'I_d) := (Fadjoin_poly K z (z ^+ i))`_j. pose s := undup [seq h0 i j | i <- enum 'I_(N ^ d).+1, j <- enum 'I_d]. have s_h0 i j: h0 i j \in s. by rewrite mem_undup; apply/allpairsP; exists (i, j); rewrite !mem_enum. pose h i := [ffun j => Ordinal (etrans (index_mem _ _) (s_h0 i j))]. pose h' (f : {ffun 'I_d -> 'I_(size s)}) := \sum_(j < d) s`_(f j) * z ^+ j. have hK i: h' (h i) = z ^+ i. have Kz_zi: z ^+ i \in <>%VS by rewrite rpredX ?memv_adjoin. rewrite -(Fadjoin_poly_eq Kz_zi) (horner_coef_wide z (size_poly _ _)) -/d. by apply: eq_bigr => j _; rewrite ffunE /= nth_index. have [inj_h | ] := altP (@injectiveP _ _ h). left; exists s; split=> [|zi_j|]; rewrite ?undup_uniq ?mem_undup //=. by case/allpairsP=> ij [_ _ ->]; apply/polyOverP/Fadjoin_polyOver. rewrite -[size s]card_ord -(@ltn_exp2r _ _ d) // -{2}[d]card_ord -card_ffun. by rewrite -[_.+1]card_ord -(card_image inj_h) max_card. case/injectivePn=> i1 [i2 i1'2 /(congr1 h')]; rewrite !hK => eq_zi12; right. without loss{i1'2} lti12: i1 i2 eq_zi12 / i1 < i2. by move=> IH; move: i1'2; rewrite neq_ltn => /orP[]; apply: IH. by exists (i2 - i1.+1)%N; rewrite subnSK ?expfB // eq_zi12 divff ?expf_neq0. Qed. Lemma finite_PET : K_is_large \/ exists z, (<< <>; x>> = <>)%VS. Proof. have [-> | /cyclic_or_large[|[a Dxa]]] := eqVneq x 0; first 2 [by left]. by rewrite addv0 subfield_closed; right; exists y. have [-> | /cyclic_or_large[|[b Dyb]]] := eqVneq y 0; first 2 [by left]. by rewrite addv0 subfield_closed; right; exists x. pose h0 (ij : 'I_a.+1 * 'I_b.+1) := x ^+ ij.1 * y ^+ ij.2. pose H := <<[set ij | h0 ij == 1%R]>>%G; pose h (u : coset_of H) := h0 (repr u). have h0M: {morph h0: ij1 ij2 / (ij1 * ij2)%g >-> ij1 * ij2}. by rewrite /h0 => [] [i1 j1] [i2 j2] /=; rewrite mulrACA -!exprD !expr_mod. have memH ij: (ij \in H) = (h0 ij == 1). rewrite /= gen_set_id ?inE //; apply/group_setP; rewrite inE [h0 _]mulr1. by split=> // ? ?; rewrite !inE h0M => /eqP-> /eqP->; rewrite mulr1. have nH ij: ij \in 'N(H)%g. by apply/(subsetP (cent_sub _))/centP=> ij1 _; congr (_, _); rewrite Zp_mulgC. have hE ij: h (coset H ij) = h0 ij. rewrite /h val_coset //; case: repr_rcosetP => ij1. by rewrite memH h0M => /eqP->; rewrite mul1r. have h1: h 1%g = 1 by rewrite /h repr_coset1 [h0 _]mulr1. have hM: {morph h: u v / (u * v)%g >-> u * v}. by do 2![move=> u; have{u} [? _ ->] := cosetP u]; rewrite -morphM // !hE h0M. have /cyclicP[w defW]: cyclic [set: coset_of H]. apply: field_mul_group_cyclic (in2W hM) _ => u _; have [ij _ ->] := cosetP u. by split=> [/eqP | -> //]; rewrite hE -memH => /coset_id. have Kw_h ij t: h0 ij = t -> t \in <>%VS. have /cycleP[k Dk]: coset H ij \in <[w]>%g by rewrite -defW inE. rewrite -hE {}Dk => <-; elim: k => [|k IHk]; first by rewrite h1 rpred1. by rewrite expgS hM rpredM // memv_adjoin. right; exists (h w); apply/eqP; rewrite eqEsubv !(sameP FadjoinP andP). rewrite subv_adjoin (subv_trans (subv_adjoin K y)) ?subv_adjoin //=. rewrite (Kw_h (0, inZp 1)) 1?(Kw_h (inZp 1, 0)) /h0 ?mulr1 ?mul1r ?expr_mod //=. by rewrite rpredM ?rpredX ?memv_adjoin // subvP_adjoin ?memv_adjoin. Qed. End FiniteCase. Hypothesis sepKy : separable_element K y. Lemma Primitive_Element_Theorem : exists z, (<< <>; x>> = <>)%VS. Proof. have /polyOver_subvs[p Dp]: minPoly K x \is a polyOver K := minPolyOver K x. have nz_pKx: minPoly K x != 0 by rewrite monic_neq0 ?monic_minPoly. have{nz_pKx} nz_p: p != 0 by rewrite Dp map_poly_eq0 in nz_pKx. have{Dp} px0: root (map_poly vsval p) x by rewrite -Dp root_minPoly. have [q0 [Kq0 [q0y0 sepKq0]]] := separable_elementP sepKy. have /polyOver_subvs[q Dq]: minPoly K y \is a polyOver K := minPolyOver K y. have qy0: root (map_poly vsval q) y by rewrite -Dq root_minPoly. have sep_pKy: separable_poly (minPoly K y). by rewrite (dvdp_separable _ sepKq0) ?minPoly_dvdp. have{sep_pKy} sep_q: separable_poly q by rewrite Dq separable_map in sep_pKy. have [r [nz_r PETr]] := large_field_PET nz_p px0 qy0 sep_q. have [[s [Us Ks /ltnW leNs]] | //] := finite_PET (size r). have{s Us Ks leNs} /allPn[t /Ks Kt nz_rt]: ~~ all (root r) s. by apply: contraTN leNs; rewrite -ltnNge => /max_poly_roots->. have{PETr} [/= [p1 Dx] [q1 Dy]] := PETr (Subvs Kt) nz_rt. set z := t * y - x in Dx Dy; exists z; apply/eqP. rewrite eqEsubv !(sameP FadjoinP andP) subv_adjoin. have Kz_p1z (r1 : {poly subvs_of K}): (map_poly vsval r1).[z] \in <>%VS. rewrite rpred_horner ?memv_adjoin ?(polyOverSv (subv_adjoin K z)) //. by apply/polyOver_subvs; exists r1. rewrite -{1}Dx -{1}Dy !{Dx Dy}Kz_p1z /=. rewrite (subv_trans (subv_adjoin K y)) ?subv_adjoin // rpredB ?memv_adjoin //. by rewrite subvP_adjoin // rpredM ?memv_adjoin ?subvP_adjoin. Qed. Lemma adjoin_separable : separable_element <> x -> separable_element K x. Proof. have /Derivation_separableP derKy := sepKy => /Derivation_separableP derKy_x. have [z defKz] := Primitive_Element_Theorem. suffices /adjoin_separableP: separable_element K z. by apply; rewrite -defKz memv_adjoin. apply/Derivation_separableP=> D; rewrite -defKz => derKxyD DK_0. suffices derKyD: Derivation <>%VS D by rewrite derKy_x // derKy. by apply: DerivationS derKxyD; apply: subv_adjoin. Qed. End PrimitiveElementTheorem. Lemma strong_Primitive_Element_Theorem K x y : separable_element <> y -> exists2 z : L, (<< <>; x>> = <>)%VS & separable_element K x -> separable_element K y. Proof. move=> sepKx_y; have [n /andP[charLn sepKyn]] := separable_exponent K y. have adjK_C z t: (<<<>; t>> = <<<>; z>>)%VS. by rewrite !agenv_add_id -!addvA (addvC <[_]>%VS). have [z defKz] := Primitive_Element_Theorem x sepKyn. exists z => [|/adjoin_separable->]; rewrite ?sepKx_y // -defKz. have [|n_gt1|-> //] := ltngtP n 1%N; first by case: (n) charLn. apply/eqP; rewrite !(adjK_C _ x) eqEsubv; apply/andP. split; apply/FadjoinP/andP; rewrite subv_adjoin ?rpredX ?memv_adjoin //=. by rewrite -charf_n_separable ?sepKx_y. Qed. Definition separable U W : bool := all (separable_element U) (vbasis W). Definition purely_inseparable U W : bool := all (purely_inseparable_element U) (vbasis W). Lemma separable_add K x y : separable_element K x -> separable_element K y -> separable_element K (x + y). Proof. move/(separable_elementS (subv_adjoin K y))=> sepKy_x sepKy. have [z defKz] := Primitive_Element_Theorem x sepKy. have /(adjoin_separableP _): x + y \in <>%VS. by rewrite -defKz rpredD ?memv_adjoin // subvP_adjoin ?memv_adjoin. apply; apply: adjoin_separable sepKy (adjoin_separable sepKy_x _). by rewrite defKz base_separable ?memv_adjoin. Qed. Lemma separable_sum I r (P : pred I) (v_ : I -> L) K : (forall i, P i -> separable_element K (v_ i)) -> separable_element K (\sum_(i <- r | P i) v_ i). Proof. move=> sepKi. by elim/big_ind: _; [apply/base_separable/mem0v | apply: separable_add |]. Qed. Lemma inseparable_add K x y : purely_inseparable_element K x -> purely_inseparable_element K y -> purely_inseparable_element K (x + y). Proof. have insepP := purely_inseparable_elementP. move=> /insepP[n charLn Kxn] /insepP[m charLm Kym]; apply/insepP. have charLnm: [char L].-nat (n * m)%N by rewrite pnat_mul charLn. by exists (n * m)%N; rewrite ?exprDn_char // {2}mulnC !exprM memvD // rpredX. Qed. Lemma inseparable_sum I r (P : pred I) (v_ : I -> L) K : (forall i, P i -> purely_inseparable_element K (v_ i)) -> purely_inseparable_element K (\sum_(i <- r | P i) v_ i). Proof. move=> insepKi. by elim/big_ind: _; [apply/base_inseparable/mem0v | apply: inseparable_add |]. Qed. Lemma separableP {K E} : reflect (forall y, y \in E -> separable_element K y) (separable K E). Proof. apply/(iffP idP)=> [/allP|] sepK_E; last by apply/allP=> x /vbasis_mem/sepK_E. move=> y /coord_vbasis->; apply/separable_sum=> i _. have: separable_element K (vbasis E)`_i by apply/sepK_E/memt_nth. by move/adjoin_separableP; apply; rewrite rpredZ ?memv_adjoin. Qed. Lemma purely_inseparableP {K E} : reflect (forall y, y \in E -> purely_inseparable_element K y) (purely_inseparable K E). Proof. apply/(iffP idP)=> [/allP|] sep'K_E; last by apply/allP=> x /vbasis_mem/sep'K_E. move=> y /coord_vbasis->; apply/inseparable_sum=> i _. have: purely_inseparable_element K (vbasis E)`_i by apply/sep'K_E/memt_nth. case/purely_inseparable_elementP=> n charLn K_Ein. by apply/purely_inseparable_elementP; exists n; rewrite // exprZn rpredZ. Qed. Lemma adjoin_separable_eq K x : separable_element K x = separable K <>%VS. Proof. exact: sameP adjoin_separableP separableP. Qed. Lemma separable_inseparable_decomposition E K : {x | x \in E /\ separable_element K x & purely_inseparable <> E}. Proof. without loss sKE: K / (K <= E)%VS. case/(_ _ (capvSr K E)) => x [Ex sepKEx] /purely_inseparableP sep'KExE. exists x; first by split; last exact/(separable_elementS _ sepKEx)/capvSl. apply/purely_inseparableP=> y /sep'KExE; apply: sub_inseparable. exact/adjoinSl/capvSl. pose E_ i := (vbasis E)`_i; pose fP i := separable_exponent K (E_ i). pose f i := E_ i ^+ ex_minn (fP i); pose s := mkseq f (\dim E). pose K' := <>%VS. have sepKs: all (separable_element K) s. by rewrite all_map /f; apply/allP=> i _ /=; case: ex_minnP => m /andP[]. have [x sepKx defKx]: {x | x \in E /\ separable_element K x & K' = <>%VS}. have: all (mem E) s. rewrite all_map; apply/allP=> i; rewrite mem_iota => ltis /=. by rewrite rpredX // vbasis_mem // memt_nth. rewrite {}/K'; elim/last_ind: s sepKs => [|s t IHs]. by exists 0; [rewrite base_separable mem0v | rewrite adjoin_nil addv0]. rewrite adjoin_rcons !all_rcons => /andP[sepKt sepKs] /andP[/= Et Es]. have{IHs sepKs Es} [y [Ey sepKy] ->{s}] := IHs sepKs Es. have /sig_eqW[x defKx] := Primitive_Element_Theorem t sepKy. exists x; [split | exact: defKx]. suffices: (<> <= E)%VS by case/FadjoinP. by rewrite -defKx !(sameP FadjoinP andP) sKE Ey Et. apply/adjoin_separableP=> z; rewrite -defKx => Kyt_z. apply: adjoin_separable sepKy _; apply: adjoin_separableP Kyt_z. exact: separable_elementS (subv_adjoin K y) sepKt. exists x; rewrite // -defKx; apply/(all_nthP 0)=> i; rewrite size_tuple => ltiE. apply/purely_inseparable_elementP. exists (ex_minn (fP i)); first by case: ex_minnP => n /andP[]. by apply/seqv_sub_adjoin/map_f; rewrite mem_iota. Qed. Definition separable_generator K E : L := s2val (locked (separable_inseparable_decomposition E K)). Lemma separable_generator_mem E K : separable_generator K E \in E. Proof. by rewrite /separable_generator; case: (locked _) => ? []. Qed. Lemma separable_generatorP E K : separable_element K (separable_generator K E). Proof. by rewrite /separable_generator; case: (locked _) => ? []. Qed. Lemma separable_generator_maximal E K : purely_inseparable <> E. Proof. by rewrite /separable_generator; case: (locked _). Qed. Lemma sub_adjoin_separable_generator E K : separable K E -> (E <= <>)%VS. Proof. move/separableP=> sepK_E; apply/subvP=> v Ev. rewrite -separable_inseparable_element. have /purely_inseparableP-> // := separable_generator_maximal E K. by rewrite (separable_elementS _ (sepK_E _ Ev)) // subv_adjoin. Qed. Lemma eq_adjoin_separable_generator E K : separable K E -> (K <= E)%VS -> E = <>%VS :> {vspace _}. Proof. move=> sepK_E sKE; apply/eqP; rewrite eqEsubv sub_adjoin_separable_generator //. by apply/FadjoinP/andP; rewrite sKE separable_generator_mem. Qed. Lemma separable_refl K : separable K K. Proof. by apply/separableP; apply: base_separable. Qed. Lemma separable_trans M K E : separable K M -> separable M E -> separable K E. Proof. move/sub_adjoin_separable_generator. set x := separable_generator K M => sMKx /separableP sepM_E. apply/separableP => w /sepM_E/(separable_elementS sMKx). case/strong_Primitive_Element_Theorem => _ _ -> //. exact: separable_generatorP. Qed. Lemma separableS K1 K2 E2 E1 : (K1 <= K2)%VS -> (E2 <= E1)%VS -> separable K1 E1 -> separable K2 E2. Proof. move=> sK12 /subvP sE21 /separableP sepK1_E1. by apply/separableP=> y /sE21/sepK1_E1/(separable_elementS sK12). Qed. Lemma separableSl K M E : (K <= M)%VS -> separable K E -> separable M E. Proof. by move/separableS; apply. Qed. Lemma separableSr K M E : (M <= E)%VS -> separable K E -> separable K M. Proof. exact: separableS. Qed. Lemma separable_Fadjoin_seq K rs : all (separable_element K) rs -> separable K <>. Proof. elim/last_ind: rs => [|s x IHs] in K *. by rewrite adjoin_nil subfield_closed separable_refl. rewrite all_rcons adjoin_rcons => /andP[sepKx /IHs/separable_trans-> //]. by rewrite -adjoin_separable_eq (separable_elementS _ sepKx) ?subv_adjoin_seq. Qed. Lemma purely_inseparable_refl K : purely_inseparable K K. Proof. by apply/purely_inseparableP; apply: base_inseparable. Qed. Lemma purely_inseparable_trans M K E : purely_inseparable K M -> purely_inseparable M E -> purely_inseparable K E. Proof. have insepP := purely_inseparableP => /insepP insepK_M /insepP insepM_E. have insepPe := purely_inseparable_elementP. apply/insepP=> x /insepM_E/insepPe[n charLn /insepK_M/insepPe[m charLm Kxnm]]. by apply/insepPe; exists (n * m)%N; rewrite ?exprM // pnat_mul charLn charLm. Qed. End Separable. Implicit Arguments separable_elementP [F L K x]. Implicit Arguments separablePn [F L K x]. Implicit Arguments Derivation_separableP [F L K x]. Implicit Arguments adjoin_separableP [F L K x]. Implicit Arguments purely_inseparable_elementP [F L K x]. Implicit Arguments separableP [F L K E]. Implicit Arguments purely_inseparableP [F L K E]. mathcomp-1.5/theories/automorphism.v0000644000175000017500000004100112307636117016715 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat fintype finset. Require Import fingroup perm morphism. (******************************************************************************) (* Group automorphisms and characteristic subgroups. *) (* Unlike morphisms on a group G, which are functions of type gT -> rT, with *) (* a canonical structure of dependent type {morphim G >-> rT}, automorphisms *) (* are permutations of type {perm gT} contained in Aut G : {set {perm gT}}. *) (* This lets us use the finGroupType of {perm gT}. Note also that while *) (* morphisms on G are undefined outside G, automorphisms have their support *) (* in G, i.e., they are the identity ouside G. *) (* Definitions: *) (* Aut G (or [Aut G]) == the automorphism group of G. *) (* [Aut G]%G == the group structure for Aut G. *) (* autm AutGa == the morphism on G induced by a, given *) (* AutGa : a \in Aut G. *) (* perm_in injf fA == the permutation with support B in induced by f, *) (* given injf : {in A &, injective f} and *) (* fA : f @: A \subset A. *) (* aut injf fG == the automorphism of G induced by the morphism f, *) (* given injf : 'injm f and fG : f @* G \subset G. *) (* Aut_isom injf sDom == the injective homomorphism that maps Aut G to *) (* Aut (f @* G), with f : {morphism D >-> rT} and *) (* given injf: 'injm f and sDom : G \subset D. *) (* conjgm G == the conjugation automorphism on G. *) (* H \char G == H is a characteristic subgroup of G. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. (***********************************************************************) (* A group automorphism, defined as a permutation on a subset of a *) (* finGroupType that respects the morphism law. *) (* Here perm_on is used as a closure rule for the set A. *) (***********************************************************************) Section Automorphism. Variable gT : finGroupType. Implicit Type A : {set gT}. Implicit Types a b : {perm gT}. Definition Aut A := [set a | perm_on A a & morphic A a]. Lemma Aut_morphic A a : a \in Aut A -> morphic A a. Proof. by case/setIdP. Qed. Lemma out_Aut A a x : a \in Aut A -> x \notin A -> a x = x. Proof. by case/setIdP=> Aa _; exact: out_perm. Qed. Lemma eq_Aut A : {in Aut A &, forall a b, {in A, a =1 b} -> a = b}. Proof. move=> a g Aa Ag /= eqag; apply/permP=> x. by have [/eqag // | /out_Aut out] := boolP (x \in A); rewrite !out. Qed. (* The morphism that is represented by a given element of Aut A. *) Definition autm A a (AutAa : a \in Aut A) := morphm (Aut_morphic AutAa). Lemma autmE A a (AutAa : a \in Aut A) : autm AutAa = a. Proof. by []. Qed. Canonical autm_morphism A a aM := Eval hnf in [morphism of @autm A a aM]. Section AutGroup. Variable G : {group gT}. Lemma Aut_group_set : group_set (Aut G). Proof. apply/group_setP; split=> [|a b]. by rewrite inE perm_on1; apply/morphicP=> ? *; rewrite !permE. rewrite !inE => /andP[Ga aM] /andP[Gb bM]; rewrite perm_onM //=. apply/morphicP=> x y Gx Gy; rewrite !permM (morphicP aM) //. by rewrite (morphicP bM) ?perm_closed. Qed. Canonical Aut_group := group Aut_group_set. Variable (a : {perm gT}) (AutGa : a \in Aut G). Notation f := (autm AutGa). Notation fE := (autmE AutGa). Lemma injm_autm : 'injm f. Proof. apply/injmP; apply: in2W; exact: perm_inj. Qed. Lemma ker_autm : 'ker f = 1. Proof. by move/trivgP: injm_autm. Qed. Lemma im_autm : f @* G = G. Proof. apply/setP=> x; rewrite morphimEdom (can_imset_pre _ (permK a)) inE. by have:= AutGa; rewrite inE => /andP[/perm_closed <-]; rewrite permKV. Qed. Lemma Aut_closed x : x \in G -> a x \in G. Proof. by move=> Gx; rewrite -im_autm; exact: mem_morphim. Qed. End AutGroup. Lemma Aut1 : Aut 1 = 1. Proof. apply/trivgP/subsetP=> a /= AutGa; apply/set1P. apply: eq_Aut (AutGa) (group1 _) _ => _ /set1P->. by rewrite -(autmE AutGa) morph1 perm1. Qed. End Automorphism. Arguments Scope Aut [_ group_scope]. Notation "[ 'Aut' G ]" := (Aut_group G) (at level 0, format "[ 'Aut' G ]") : Group_scope. Notation "[ 'Aut' G ]" := (Aut G) (at level 0, only parsing) : group_scope. Prenex Implicits Aut autm. (* The permutation function (total on the underlying groupType) that is the *) (* representant of a given morphism f with domain A in (Aut A). *) Section PermIn. Variables (T : finType) (A : {set T}) (f : T -> T). Hypotheses (injf : {in A &, injective f}) (sBf : f @: A \subset A). Lemma perm_in_inj : injective (fun x => if x \in A then f x else x). Proof. move=> x y /=; wlog Ay: x y / y \in A. by move=> IH eqfxy; case: ifP (eqfxy); [symmetry | case: ifP => //]; auto. rewrite Ay; case: ifP => [Ax | nAx def_x]; first exact: injf. by case/negP: nAx; rewrite def_x (subsetP sBf) ?mem_imset. Qed. Definition perm_in := perm perm_in_inj. Lemma perm_in_on : perm_on A perm_in. Proof. by apply/subsetP=> x; rewrite inE /= permE; case: ifP => // _; case/eqP. Qed. Lemma perm_inE : {in A, perm_in =1 f}. Proof. by move=> x Ax; rewrite /= permE Ax. Qed. End PermIn. (* properties of injective endomorphisms *) Section MakeAut. Variables (gT : finGroupType) (G : {group gT}) (f : {morphism G >-> gT}). Implicit Type A : {set gT}. Hypothesis injf : 'injm f. Lemma morphim_fixP A : A \subset G -> reflect (f @* A = A) (f @* A \subset A). Proof. rewrite /morphim => sAG; have:= eqEcard (f @: A) A. rewrite (setIidPr sAG) card_in_imset ?leqnn ?andbT => [<-|]; first exact: eqP. move/injmP: injf; apply: sub_in2; exact/subsetP. Qed. Hypothesis Gf : f @* G = G. Lemma aut_closed : f @: G \subset G. Proof. by rewrite -morphimEdom; exact/morphim_fixP. Qed. Definition aut := perm_in (injmP injf) aut_closed. Lemma autE : {in G, aut =1 f}. Proof. exact: perm_inE. Qed. Lemma morphic_aut : morphic G aut. Proof. by apply/morphicP=> x y Gx Gy /=; rewrite !autE ?groupM // morphM. Qed. Lemma Aut_aut : aut \in Aut G. Proof. by rewrite inE morphic_aut perm_in_on. Qed. Lemma imset_autE A : A \subset G -> aut @: A = f @* A. Proof. move=> sAG; rewrite /morphim (setIidPr sAG). apply: eq_in_imset; apply: sub_in1 autE; exact/subsetP. Qed. Lemma preim_autE A : A \subset G -> aut @^-1: A = f @*^-1 A. Proof. move=> sAG; apply/setP=> x; rewrite !inE permE /=. by case Gx: (x \in G) => //; apply/negP=> Ax; rewrite (subsetP sAG) in Gx. Qed. End MakeAut. Implicit Arguments morphim_fixP [gT G f]. Prenex Implicits aut morphim_fixP. Section AutIsom. Variables (gT rT : finGroupType) (G D : {group gT}) (f : {morphism D >-> rT}). Hypotheses (injf : 'injm f) (sGD : G \subset D). Let domG := subsetP sGD. Lemma Aut_isom_subproof a : {a' | a' \in Aut (f @* G) & a \in Aut G -> {in G, a' \o f =1 f \o a}}. Proof. set Aut_a := autm (subgP (subg [Aut G] a)). have aDom: 'dom (f \o Aut_a \o invm injf) = f @* G. rewrite /dom /= morphpre_invm -morphpreIim; congr (f @* _). by rewrite [_ :&: D](setIidPl _) ?injmK ?injm_autm ?im_autm. have [af [def_af ker_af _ im_af]] := domP _ aDom. have inj_a': 'injm af by rewrite ker_af !injm_comp ?injm_autm ?injm_invm. have im_a': af @* (f @* G) = f @* G. by rewrite im_af !morphim_comp morphim_invm // im_autm. pose a' := aut inj_a' im_a'; exists a' => [|AutGa x Gx]; first exact: Aut_aut. have Dx := domG Gx; rewrite /= [a' _]autE ?mem_morphim //. by rewrite def_af /= invmE // autmE subgK. Qed. Definition Aut_isom a := s2val (Aut_isom_subproof a). Lemma Aut_Aut_isom a : Aut_isom a \in Aut (f @* G). Proof. by rewrite /Aut_isom; case: (Aut_isom_subproof a). Qed. Lemma Aut_isomE a : a \in Aut G -> {in G, forall x, Aut_isom a (f x) = f (a x)}. Proof. by rewrite /Aut_isom; case: (Aut_isom_subproof a). Qed. Lemma Aut_isomM : {in Aut G &, {morph Aut_isom: x y / x * y}}. Proof. move=> a b AutGa AutGb. apply: (eq_Aut (Aut_Aut_isom _)); rewrite ?groupM ?Aut_Aut_isom // => fx. case/morphimP=> x Dx Gx ->{fx}. by rewrite permM !Aut_isomE ?groupM /= ?permM ?Aut_closed. Qed. Canonical Aut_isom_morphism := Morphism Aut_isomM. Lemma injm_Aut_isom : 'injm Aut_isom. Proof. apply/injmP=> a b AutGa AutGb eq_ab'; apply: (eq_Aut AutGa AutGb) => x Gx. by apply: (injmP injf); rewrite ?domG ?Aut_closed // -!Aut_isomE //= eq_ab'. Qed. End AutIsom. Section InjmAut. Variables (gT rT : finGroupType) (G D : {group gT}) (f : {morphism D >-> rT}). Hypotheses (injf : 'injm f) (sGD : G \subset D). Let domG := subsetP sGD. Lemma im_Aut_isom : Aut_isom injf sGD @* Aut G = Aut (f @* G). Proof. apply/eqP; rewrite eqEcard; apply/andP; split. by apply/subsetP=> _ /morphimP[a _ AutGa ->]; exact: Aut_Aut_isom. have inj_isom' := injm_Aut_isom (injm_invm injf) (morphimS _ sGD). rewrite card_injm ?injm_Aut_isom // -(card_injm inj_isom') ?subset_leq_card //. apply/subsetP=> a /morphimP[a' _ AutfGa' def_a]. by rewrite -(morphim_invm injf sGD) def_a Aut_Aut_isom. Qed. Lemma Aut_isomP : isom (Aut G) (Aut (f @* G)) (Aut_isom injf sGD). Proof. by apply/isomP; split; [exact: injm_Aut_isom | exact: im_Aut_isom]. Qed. Lemma injm_Aut : Aut (f @* G) \isog Aut G. Proof. by rewrite isog_sym (isom_isog _ _ Aut_isomP). Qed. End InjmAut. (* conjugation automorphism *) Section ConjugationMorphism. Variable gT : finGroupType. Implicit Type A : {set gT}. Definition conjgm of {set gT} := fun x y : gT => y ^ x. Lemma conjgmE A x y : conjgm A x y = y ^ x. Proof. by []. Qed. Canonical conjgm_morphism A x := @Morphism _ _ A (conjgm A x) (in2W (fun y z => conjMg y z x)). Lemma morphim_conj A x B : conjgm A x @* B = (A :&: B) :^ x. Proof. by []. Qed. Variable G : {group gT}. Lemma injm_conj x : 'injm (conjgm G x). Proof. by apply/injmP; apply: in2W; exact: conjg_inj. Qed. Lemma conj_isom x : isom G (G :^ x) (conjgm G x). Proof. by apply/isomP; rewrite morphim_conj setIid injm_conj. Qed. Lemma conj_isog x : G \isog G :^ x. Proof. exact: isom_isog (conj_isom x). Qed. Lemma norm_conjg_im x : x \in 'N(G) -> conjgm G x @* G = G. Proof. by rewrite morphimEdom; exact: normP. Qed. Lemma norm_conj_isom x : x \in 'N(G) -> isom G G (conjgm G x). Proof. by move/norm_conjg_im/restr_isom_to/(_ (conj_isom x))->. Qed. Definition conj_aut x := aut (injm_conj _) (norm_conjg_im (subgP (subg _ x))). Lemma norm_conj_autE : {in 'N(G) & G, forall x y, conj_aut x y = y ^ x}. Proof. by move=> x y nGx Gy; rewrite /= autE //= subgK. Qed. Lemma conj_autE : {in G &, forall x y, conj_aut x y = y ^ x}. Proof. by apply: sub_in11 norm_conj_autE => //; exact: subsetP (normG G). Qed. Lemma conj_aut_morphM : {in 'N(G) &, {morph conj_aut : x y / x * y}}. Proof. move=> x y nGx nGy; apply/permP=> z /=; rewrite permM. case Gz: (z \in G); last by rewrite !permE /= !Gz. by rewrite !norm_conj_autE // (conjgM, memJ_norm, groupM). Qed. Canonical conj_aut_morphism := Morphism conj_aut_morphM. Lemma ker_conj_aut : 'ker conj_aut = 'C(G). Proof. apply/setP=> x; rewrite inE; case nGx: (x \in 'N(G)); last first. by symmetry; apply/idP=> cGx; rewrite (subsetP (cent_sub G)) in nGx. rewrite 2!inE /=; apply/eqP/centP=> [cx1 y Gy | cGx]. by rewrite /commute (conjgC y) -norm_conj_autE // cx1 perm1. apply/permP=> y; case Gy: (y \in G); last by rewrite !permE Gy. by rewrite perm1 norm_conj_autE // conjgE -cGx ?mulKg. Qed. Lemma Aut_conj_aut A : conj_aut @* A \subset Aut G. Proof. by apply/subsetP=> _ /imsetP[x _ ->]; exact: Aut_aut. Qed. End ConjugationMorphism. Arguments Scope conjgm [_ group_scope]. Prenex Implicits conjgm conj_aut. Reserved Notation "G \char H" (at level 70). (* Characteristic subgroup *) Section Characteristicity. Variable gT : finGroupType. Implicit Types A B : {set gT}. Implicit Types G H K L : {group gT}. Definition characteristic A B := (A \subset B) && [forall f in Aut B, f @: A \subset A]. Infix "\char" := characteristic. Lemma charP H G : reflect [/\ H \subset G & forall f : {morphism G >-> gT}, 'injm f -> f @* G = G -> f @* H = H] (H \char G). Proof. apply: (iffP andP) => [] [sHG chHG]; split=> //. move=> f injf Gf; apply/morphim_fixP=> //. by have:= forallP chHG (aut injf Gf); rewrite Aut_aut imset_autE. apply/forall_inP=> f Af; have injf := injm_autm Af. move/(morphim_fixP injf _ sHG): (chHG _ injf (im_autm Af)). by rewrite /morphim (setIidPr _). Qed. (* Characteristic subgroup properties : composition, relational properties *) Lemma char1 G : 1 \char G. Proof. by apply/charP; split=> [|f _ _]; rewrite (sub1G, morphim1). Qed. Lemma char_refl G : G \char G. Proof. exact/charP. Qed. Lemma char_trans H G K : K \char H -> H \char G -> K \char G. Proof. case/charP=> sKH chKH; case/charP=> sHG chHG. apply/charP; split=> [|f injf Gf]; first exact: subset_trans sHG. rewrite -{1}(setIidPr sKH) -(morphim_restrm sHG) chKH //. rewrite ker_restrm; move/trivgP: injf => ->; exact: subsetIr. by rewrite morphim_restrm setIid chHG. Qed. Lemma char_norms H G : H \char G -> 'N(G) \subset 'N(H). Proof. case/charP=> sHG chHG; apply/normsP=> x /normP Nx. have:= chHG [morphism of conjgm G x] => /=. by rewrite !morphimEsub //=; apply; rewrite // injm_conj. Qed. Lemma char_sub A B : A \char B -> A \subset B. Proof. by case/andP. Qed. Lemma char_norm_trans H G A : H \char G -> A \subset 'N(G) -> A \subset 'N(H). Proof. by move/char_norms=> nHnG nGA; exact: subset_trans nHnG. Qed. Lemma char_normal_trans H G K : K \char H -> H <| G -> K <| G. Proof. move=> chKH /andP[sHG nHG]. by rewrite /normal (subset_trans (char_sub chKH)) // (char_norm_trans chKH). Qed. Lemma char_normal H G : H \char G -> H <| G. Proof. by move/char_normal_trans; apply; apply/andP; rewrite normG. Qed. Lemma char_norm H G : H \char G -> G \subset 'N(H). Proof. by case/char_normal/andP. Qed. Lemma charI G H K : H \char G -> K \char G -> H :&: K \char G. Proof. case/charP=> sHG chHG; case/charP=> _ chKG. apply/charP; split=> [|f injf Gf]; first by rewrite subIset // sHG. rewrite morphimGI ?(chHG, chKG) //; exact: subset_trans (sub1G H). Qed. Lemma charMgen G H K : H \char G -> K \char G -> H <*> K \char G. Proof. case/charP=> sHG chHG; case/charP=> sKG chKG. apply/charP; split=> [|f injf Gf]; first by rewrite gen_subG subUset sHG. by rewrite morphim_gen ?(morphimU, subUset, sHG, chHG, chKG). Qed. Lemma charM G H K : H \char G -> K \char G -> H * K \char G. Proof. move=> chHG chKG; rewrite -norm_joinEl ?charMgen //. exact: subset_trans (char_sub chHG) (char_norm chKG). Qed. Lemma lone_subgroup_char G H : H \subset G -> (forall K, K \subset G -> K \isog H -> K \subset H) -> H \char G. Proof. move=> sHG Huniq; apply/charP; split=> // f injf Gf; apply/eqP. have{injf} injf: {in H &, injective f}. by move/injmP: injf; apply: sub_in2; exact/subsetP. have fH: f @* H = f @: H by rewrite /morphim (setIidPr sHG). rewrite eqEcard {2}fH card_in_imset ?{}Huniq //=. by rewrite -{3}Gf morphimS. rewrite isog_sym; apply/isogP. exists [morphism of restrm sHG f] => //=; first exact/injmP. by rewrite morphimEdom fH. Qed. End Characteristicity. Arguments Scope characteristic [_ group_scope group_scope]. Notation "H \char G" := (characteristic H G) : group_scope. Section InjmChar. Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}). Hypothesis injf : 'injm f. Lemma injm_char (G H : {group aT}) : G \subset D -> H \char G -> f @* H \char f @* G. Proof. move=> sGD /charP[sHG charH]. apply/charP; split=> [|g injg gfG]; first exact: morphimS. have /domP[h [_ ker_h _ im_h]]: 'dom (invm injf \o g \o f) = G. by rewrite /dom /= -(morphpreIim g) (setIidPl _) ?injmK // gfG morphimS. have hH: h @* H = H. apply: charH; first by rewrite ker_h !injm_comp ?injm_invm. by rewrite im_h !morphim_comp gfG morphim_invm. rewrite /= -{2}hH im_h !morphim_comp morphim_invmE morphpreK //. by rewrite (subset_trans _ (morphimS f sGD)) //= -{3}gfG !morphimS. Qed. End InjmChar. Section CharInjm. Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}). Hypothesis injf : 'injm f. Lemma char_injm (G H : {group aT}) : G \subset D -> H \subset D -> (f @* H \char f @* G) = (H \char G). Proof. move=> sGD sHD; apply/idP/idP; last exact: injm_char. by move/(injm_char (injm_invm injf)); rewrite !morphim_invm ?morphimS // => ->. Qed. End CharInjm. Unset Implicit Arguments. mathcomp-1.5/theories/inertia.v0000644000175000017500000021113712307636117015632 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq path choice div. Require Import fintype tuple finfun bigop prime ssralg ssrnum finset fingroup. Require Import morphism perm automorphism quotient action zmodp cyclic center. Require Import gproduct commutator gseries nilpotent pgroup sylow maximal. Require Import frobenius. Require Import matrix mxalgebra mxrepresentation vector algC classfun character. Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope GRing.Theory Num.Theory. Local Open Scope ring_scope. (******************************************************************************) (* This file contains the definitions and properties of inertia groups: *) (* (phi ^ y)%CF == the y-conjugate of phi : 'CF(G), i.e., the class *) (* function mapping x ^ y to phi x provided y normalises G. *) (* We take (phi ^ y)%CF = phi when y \notin 'N(G). *) (* (phi ^: G)%CF == the sequence of all distinct conjugates of phi : 'CF(H) *) (* by all y in G. *) (* 'I[phi] == the inertia group of phi : CF(H), i.e., the set of y *) (* such that (phi ^ y)%CF = phi AND H :^ y = y. *) (* 'I_G[phi] == the inertia group of phi in G, i.e., G :&: 'I[phi]. *) (* conjg_Iirr i y == the index j : Iirr G such that ('chi_i ^ y)%CF = 'chi_j. *) (* cfclass_Iirr G i == the image of G under conjg_Iirr i, i.e., the set of j *) (* such that 'chi_j \in ('chi_i ^: G)%CF. *) (* mul_Iirr i j == the index k such that 'chi_j * 'chi_i = 'chi[G]_k, *) (* or 0 if 'chi_j * 'chi_i is reducible. *) (* mul_mod_Iirr i j := mul_Iirr i (mod_Iirr j), for j : Iirr (G / H). *) (******************************************************************************) Reserved Notation "''I[' phi ]" (at level 8, format "''I[' phi ]"). Reserved Notation "''I_' G [ phi ]" (at level 8, G at level 2, format "''I_' G [ phi ]"). Section ConjDef. Variables (gT : finGroupType) (B : {set gT}) (y : gT) (phi : 'CF(B)). Local Notation G := <>. Fact cfConjg_subproof : is_class_fun G [ffun x => phi (if y \in 'N(G) then x ^ y^-1 else x)]. Proof. apply: intro_class_fun => [x z _ Gz | x notGx]. have [nGy | _] := ifP; last by rewrite cfunJgen. by rewrite -conjgM conjgC conjgM cfunJgen // memJ_norm ?groupV. by rewrite cfun0gen //; case: ifP => // nGy; rewrite memJ_norm ?groupV. Qed. Definition cfConjg := Cfun 1 cfConjg_subproof. End ConjDef. Prenex Implicits cfConjg. Notation "f ^ y" := (cfConjg y f) : cfun_scope. Section Conj. Variables (gT : finGroupType) (G : {group gT}). Implicit Type phi : 'CF(G). Lemma cfConjgE phi y x : y \in 'N(G) -> (phi ^ y)%CF x = phi (x ^ y^-1)%g. Proof. by rewrite cfunElock genGid => ->. Qed. Lemma cfConjgEJ phi y x : y \in 'N(G) -> (phi ^ y)%CF (x ^ y) = phi x. Proof. by move/cfConjgE->; rewrite conjgK. Qed. Lemma cfConjgEout phi y : y \notin 'N(G) -> (phi ^ y = phi)%CF. Proof. by move/negbTE=> notNy; apply/cfunP=> x; rewrite !cfunElock genGid notNy. Qed. Lemma cfConjgEin phi y (nGy : y \in 'N(G)) : (phi ^ y)%CF = cfIsom (norm_conj_isom nGy) phi. Proof. apply/cfun_inP=> x Gx. by rewrite cfConjgE // -{2}[x](conjgKV y) cfIsomE ?memJ_norm ?groupV. Qed. Lemma cfConjgMnorm phi : {in 'N(G) &, forall y z, phi ^ (y * z) = (phi ^ y) ^ z}%CF. Proof. move=> y z nGy nGz. by apply/cfunP=> x; rewrite !cfConjgE ?groupM // invMg conjgM. Qed. Lemma cfConjg_id phi y : y \in G -> (phi ^ y)%CF = phi. Proof. move=> Gy; apply/cfunP=> x; have nGy := subsetP (normG G) y Gy. by rewrite -(cfunJ _ _ Gy) cfConjgEJ. Qed. (* Isaacs' 6.1.b *) Lemma cfConjgM L phi : G <| L -> {in L &, forall y z, phi ^ (y * z) = (phi ^ y) ^ z}%CF. Proof. by case/andP=> _ /subsetP nGL; exact: sub_in2 (cfConjgMnorm phi). Qed. Lemma cfConjgJ1 phi : (phi ^ 1)%CF = phi. Proof. by apply/cfunP=> x; rewrite cfConjgE ?group1 // invg1 conjg1. Qed. Lemma cfConjgK y : cancel (cfConjg y) (cfConjg y^-1 : 'CF(G) -> 'CF(G)). Proof. move=> phi; apply/cfunP=> x; rewrite !cfunElock groupV /=. by case: ifP => -> //; rewrite conjgKV. Qed. Lemma cfConjgKV y : cancel (cfConjg y^-1) (cfConjg y : 'CF(G) -> 'CF(G)). Proof. by move=> phi /=; rewrite -{1}[y]invgK cfConjgK. Qed. Lemma cfConjg1 phi y : (phi ^ y)%CF 1%g = phi 1%g. Proof. by rewrite cfunElock conj1g if_same. Qed. Fact cfConjg_is_linear y : linear (cfConjg y : 'CF(G) -> 'CF(G)). Proof. by move=> a phi psi; apply/cfunP=> x; rewrite !cfunElock. Qed. Canonical cfConjg_additive y := Additive (cfConjg_is_linear y). Canonical cfConjg_linear y := AddLinear (cfConjg_is_linear y). Lemma cfConjg_cfuniJ A y : y \in 'N(G) -> ('1_A ^ y)%CF = '1_(A :^ y) :> 'CF(G). Proof. move=> nGy; apply/cfunP=> x; rewrite !cfunElock genGid nGy -sub_conjgV. by rewrite -class_lcoset -class_rcoset norm_rlcoset ?memJ_norm ?groupV. Qed. Lemma cfConjg_cfuni A y : y \in 'N(A) -> ('1_A ^ y)%CF = '1_A :> 'CF(G). Proof. by have [/cfConjg_cfuniJ-> /normP-> | /cfConjgEout] := boolP (y \in 'N(G)). Qed. Lemma cfConjg_cfun1 y : (1 ^ y)%CF = 1 :> 'CF(G). Proof. by rewrite -cfuniG; have [/cfConjg_cfuni|/cfConjgEout] := boolP (y \in 'N(G)). Qed. Fact cfConjg_is_multiplicative y : multiplicative (cfConjg y : _ -> 'CF(G)). Proof. split=> [phi psi|]; last exact: cfConjg_cfun1. by apply/cfunP=> x; rewrite !cfunElock. Qed. Canonical cfConjg_rmorphism y := AddRMorphism (cfConjg_is_multiplicative y). Canonical cfConjg_lrmorphism y := [lrmorphism of cfConjg y]. Lemma cfConjg_eq1 phi y : ((phi ^ y)%CF == 1) = (phi == 1). Proof. by apply: rmorph_eq1; apply: can_inj (cfConjgK y). Qed. Lemma cfAutConjg phi u y : cfAut u (phi ^ y) = (cfAut u phi ^ y)%CF. Proof. by apply/cfunP=> x; rewrite !cfunElock. Qed. Lemma conj_cfConjg phi y : (phi ^ y)^*%CF = (phi^* ^ y)%CF. Proof. exact: cfAutConjg. Qed. Lemma cfker_conjg phi y : y \in 'N(G) -> cfker (phi ^ y) = cfker phi :^ y. Proof. move=> nGy; rewrite cfConjgEin // cfker_isom. by rewrite morphim_conj (setIidPr (cfker_sub _)). Qed. Lemma cfDetConjg phi y : cfDet (phi ^ y) = (cfDet phi ^ y)%CF. Proof. have [nGy | not_nGy] := boolP (y \in 'N(G)); last by rewrite !cfConjgEout. by rewrite !cfConjgEin cfDetIsom. Qed. End Conj. Section Inertia. Variable gT : finGroupType. Definition inertia (B : {set gT}) (phi : 'CF(B)) := [set y in 'N(B) | (phi ^ y)%CF == phi]. Local Notation "''I[' phi ]" := (inertia phi) : group_scope. Local Notation "''I_' G [ phi ]" := (G%g :&: 'I[phi]) : group_scope. Fact group_set_inertia (H : {group gT}) phi : group_set 'I[phi : 'CF(H)]. Proof. apply/group_setP; split; first by rewrite inE group1 /= cfConjgJ1. move=> y z /setIdP[nHy /eqP n_phi_y] /setIdP[nHz n_phi_z]. by rewrite inE groupM //= cfConjgMnorm ?n_phi_y. Qed. Canonical inertia_group H phi := Group (@group_set_inertia H phi). Local Notation "''I[' phi ]" := (inertia_group phi) : Group_scope. Local Notation "''I_' G [ phi ]" := (G :&: 'I[phi])%G : Group_scope. Variables G H : {group gT}. Implicit Type phi : 'CF(H). Lemma inertiaJ phi y : y \in 'I[phi] -> (phi ^ y)%CF = phi. Proof. by case/setIdP=> _ /eqP->. Qed. Lemma inertia_valJ phi x y : y \in 'I[phi] -> phi (x ^ y)%g = phi x. Proof. by case/setIdP=> nHy /eqP {1}<-; rewrite cfConjgEJ. Qed. (* To disambiguate basic inclucion lemma names we capitalize Inertia for *) (* lemmas concerning the localized inertia group 'I_G[phi]. *) Lemma Inertia_sub phi : 'I_G[phi] \subset G. Proof. exact: subsetIl. Qed. Lemma norm_inertia phi : 'I[phi] \subset 'N(H). Proof. by rewrite ['I[_]]setIdE subsetIl. Qed. Lemma sub_inertia phi : H \subset 'I[phi]. Proof. by apply/subsetP=> y Hy; rewrite inE cfConjg_id ?(subsetP (normG H)) /=. Qed. Lemma normal_inertia phi : H <| 'I[phi]. Proof. by rewrite /normal sub_inertia norm_inertia. Qed. Lemma sub_Inertia phi : H \subset G -> H \subset 'I_G[phi]. Proof. by rewrite subsetI sub_inertia andbT. Qed. Lemma norm_Inertia phi : 'I_G[phi] \subset 'N(H). Proof. by rewrite setIC subIset ?norm_inertia. Qed. Lemma normal_Inertia phi : H \subset G -> H <| 'I_G[phi]. Proof. by rewrite /normal norm_Inertia andbT; apply: sub_Inertia. Qed. Lemma cfConjg_eqE phi : H <| G -> {in G &, forall y z, (phi ^ y == phi ^ z)%CF = (z \in 'I_G[phi] :* y)}. Proof. case/andP=> _ nHG y z Gy; rewrite -{1 2}[z](mulgKV y) groupMr // mem_rcoset. move: {z}(z * _)%g => z Gz; rewrite 2!inE Gz cfConjgMnorm ?(subsetP nHG) //=. by rewrite eq_sym (can_eq (cfConjgK y)). Qed. Lemma cent_sub_inertia phi : 'C(H) \subset 'I[phi]. Proof. apply/subsetP=> y cHy; have nHy := subsetP (cent_sub H) y cHy. rewrite inE nHy; apply/eqP/cfun_inP=> x Hx; rewrite cfConjgE //. by rewrite /conjg invgK mulgA (centP cHy) ?mulgK. Qed. Lemma cent_sub_Inertia phi : 'C_G(H) \subset 'I_G[phi]. Proof. exact: setIS (cent_sub_inertia phi). Qed. Lemma center_sub_Inertia phi : H \subset G -> 'Z(G) \subset 'I_G[phi]. Proof. by move/centS=> sHG; rewrite setIS // (subset_trans sHG) // cent_sub_inertia. Qed. Lemma conjg_inertia phi y : y \in 'N(H) -> 'I[phi] :^ y = 'I[phi ^ y]. Proof. move=> nHy; apply/setP=> z; rewrite !['I[_]]setIdE conjIg conjGid // !in_setI. apply/andb_id2l=> nHz; rewrite mem_conjg !inE. by rewrite !cfConjgMnorm ?in_group ?(can2_eq (cfConjgKV y) (cfConjgK y)) ?invgK. Qed. Lemma inertia0 : 'I[0 : 'CF(H)] = 'N(H). Proof. by apply/setP=> x; rewrite !inE linear0 eqxx andbT. Qed. Lemma inertia_add phi psi : 'I[phi] :&: 'I[psi] \subset 'I[phi + psi]. Proof. rewrite !['I[_]]setIdE -setIIr setIS //. by apply/subsetP=> x; rewrite !inE linearD /= => /andP[/eqP-> /eqP->]. Qed. Lemma inertia_sum I r (P : pred I) (Phi : I -> 'CF(H)) : 'N(H) :&: \bigcap_(i <- r | P i) 'I[Phi i] \subset 'I[\sum_(i <- r | P i) Phi i]. Proof. elim/big_rec2: _ => [|i K psi Pi sK_Ipsi]; first by rewrite setIT inertia0. by rewrite setICA; apply: subset_trans (setIS _ sK_Ipsi) (inertia_add _ _). Qed. Lemma inertia_scale a phi : 'I[phi] \subset 'I[a *: phi]. Proof. apply/subsetP=> x /setIdP[nHx /eqP Iphi_x]. by rewrite inE nHx linearZ /= Iphi_x. Qed. Lemma inertia_scale_nz a phi : a != 0 -> 'I[a *: phi] = 'I[phi]. Proof. move=> nz_a; apply/eqP. by rewrite eqEsubset -{2}(scalerK nz_a phi) !inertia_scale. Qed. Lemma inertia_opp phi : 'I[- phi] = 'I[phi]. Proof. by rewrite -scaleN1r inertia_scale_nz // oppr_eq0 oner_eq0. Qed. Lemma inertia1 : 'I[1 : 'CF(H)] = 'N(H). Proof. by apply/setP=> x; rewrite inE rmorph1 eqxx andbT. Qed. Lemma Inertia1 : H <| G -> 'I_G[1 : 'CF(H)] = G. Proof. by rewrite inertia1 => /normal_norm/setIidPl. Qed. Lemma inertia_mul phi psi : 'I[phi] :&: 'I[psi] \subset 'I[phi * psi]. Proof. rewrite !['I[_]]setIdE -setIIr setIS //. by apply/subsetP=> x; rewrite !inE rmorphM /= => /andP[/eqP-> /eqP->]. Qed. Lemma inertia_prod I r (P : pred I) (Phi : I -> 'CF(H)) : 'N(H) :&: \bigcap_(i <- r | P i) 'I[Phi i] \subset 'I[\prod_(i <- r | P i) Phi i]. Proof. elim/big_rec2: _ => [|i K psi Pi sK_psi]; first by rewrite inertia1 setIT. by rewrite setICA; apply: subset_trans (setIS _ sK_psi) (inertia_mul _ _). Qed. Lemma inertia_injective (chi : 'CF(H)) : {in H &, injective chi} -> 'I[chi] = 'C(H). Proof. move=> inj_chi; apply/eqP; rewrite eqEsubset cent_sub_inertia andbT. apply/subsetP=> y Ichi_y; have /setIdP[nHy _] := Ichi_y. apply/centP=> x Hx; apply/esym/commgP/conjg_fixP. by apply/inj_chi; rewrite ?memJ_norm ?(inertia_valJ _ Ichi_y). Qed. Lemma inertia_irr_prime p i : #|H| = p -> prime p -> i != 0 -> 'I['chi[H]_i] = 'C(H). Proof. by move=> <- pr_H /(irr_prime_injP pr_H); apply: inertia_injective. Qed. Lemma inertia_irr0 : 'I['chi[H]_0] = 'N(H). Proof. by rewrite irr0 inertia1. Qed. (* Isaacs' 6.1.c *) Lemma cfConjg_iso y : isometry (cfConjg y : 'CF(H) -> 'CF(H)). Proof. move=> phi psi; congr (_ * _). have [nHy | not_nHy] := boolP (y \in 'N(H)); last by rewrite !cfConjgEout. rewrite (reindex_astabs 'J y) ?astabsJ //=. by apply: eq_bigr=> x _; rewrite !cfConjgEJ. Qed. (* Isaacs' 6.1.d *) Lemma cfdot_Res_conjg psi phi y : y \in G -> '['Res[H, G] psi, phi ^ y] = '['Res[H] psi, phi]. Proof. move=> Gy; rewrite -(cfConjg_iso y _ phi); congr '[_, _]; apply/cfunP=> x. rewrite !cfunElock !genGid; case nHy: (y \in 'N(H)) => //. by rewrite !(fun_if psi) cfunJ ?memJ_norm ?groupV. Qed. (* Isaac's 6.1.e *) Lemma cfConjg_char (chi : 'CF(H)) y : chi \is a character -> (chi ^ y)%CF \is a character. Proof. have [nHy Nchi | /cfConjgEout-> //] := boolP (y \in 'N(H)). by rewrite cfConjgEin cfIsom_char. Qed. Lemma cfConjg_lin_char (chi : 'CF(H)) y : chi \is a linear_char -> (chi ^ y)%CF \is a linear_char. Proof. by case/andP=> Nchi chi1; rewrite qualifE cfConjg1 cfConjg_char. Qed. Lemma cfConjg_irr y chi : chi \in irr H -> (chi ^ y)%CF \in irr H. Proof. by rewrite !irrEchar cfConjg_iso => /andP[/cfConjg_char->]. Qed. Definition conjg_Iirr i y := cfIirr ('chi[H]_i ^ y)%CF. Lemma conjg_IirrE i y : 'chi_(conjg_Iirr i y) = ('chi_i ^ y)%CF. Proof. by rewrite cfIirrE ?cfConjg_irr ?mem_irr. Qed. Lemma conjg_IirrK y : cancel (conjg_Iirr^~ y) (conjg_Iirr^~ y^-1%g). Proof. by move=> i; apply/irr_inj; rewrite !conjg_IirrE cfConjgK. Qed. Lemma conjg_IirrKV y : cancel (conjg_Iirr^~ y^-1%g) (conjg_Iirr^~ y). Proof. by rewrite -{2}[y]invgK; apply: conjg_IirrK. Qed. Lemma conjg_Iirr_inj y : injective (conjg_Iirr^~ y). Proof. exact: can_inj (conjg_IirrK y). Qed. Lemma conjg_Iirr_eq0 i y : (conjg_Iirr i y == 0) = (i == 0). Proof. by rewrite -!irr_eq1 conjg_IirrE cfConjg_eq1. Qed. Lemma conjg_Iirr0 x : conjg_Iirr 0 x = 0. Proof. by apply/eqP; rewrite conjg_Iirr_eq0. Qed. Lemma cfdot_irr_conjg i y : H <| G -> y \in G -> '['chi_i, 'chi_i ^ y]_H = (y \in 'I_G['chi_i])%:R. Proof. move=> nsHG Gy; rewrite -conjg_IirrE cfdot_irr -(inj_eq irr_inj) conjg_IirrE. by rewrite -{1}['chi_i]cfConjgJ1 cfConjg_eqE ?mulg1. Qed. Definition cfclass (A : {set gT}) (phi : 'CF(A)) (B : {set gT}) := [seq (phi ^ repr Tx)%CF | Tx in rcosets 'I_B[phi] B]. Local Notation "phi ^: G" := (cfclass phi G) : cfun_scope. Lemma size_cfclass i : size ('chi[H]_i ^: G)%CF = #|G : 'I_G['chi_i]|. Proof. by rewrite size_map -cardE. Qed. Lemma cfclassP (A : {group gT}) phi psi : reflect (exists2 y, y \in A & psi = phi ^ y)%CF (psi \in phi ^: A)%CF. Proof. apply: (iffP imageP) => [[_ /rcosetsP[y Ay ->] ->] | [y Ay ->]]. by case: repr_rcosetP => z /setIdP[Az _]; exists (z * y)%g; rewrite ?groupM. without loss nHy: y Ay / y \in 'N(H). have [nHy | /cfConjgEout->] := boolP (y \in 'N(H)); first exact. by move/(_ 1%g); rewrite !group1 !cfConjgJ1; exact. exists ('I_A[phi] :* y); first by rewrite -rcosetE mem_imset. case: repr_rcosetP => z /setIP[_ /setIdP[nHz /eqP Tz]]. by rewrite cfConjgMnorm ?Tz. Qed. Lemma cfclassInorm phi : (phi ^: 'N_G(H) =i phi ^: G)%CF. Proof. move=> xi; apply/cfclassP/cfclassP=> [[x /setIP[Gx _] ->] | [x Gx ->]]. by exists x. have [Nx | /cfConjgEout-> //] := boolP (x \in 'N(H)). by exists x; first exact/setIP. by exists 1%g; rewrite ?group1 ?cfConjgJ1. Qed. Lemma cfclass_refl phi : phi \in (phi ^: G)%CF. Proof. by apply/cfclassP; exists 1%g => //; rewrite cfConjgJ1. Qed. Lemma cfclass_transl phi psi : (psi \in phi ^: G)%CF -> (phi ^: G =i psi ^: G)%CF. Proof. rewrite -cfclassInorm; case/cfclassP=> x Gx -> xi; rewrite -!cfclassInorm. have nHN: {subset 'N_G(H) <= 'N(H)} by apply/subsetP; exact: subsetIr. apply/cfclassP/cfclassP=> [[y Gy ->] | [y Gy ->]]. by exists (x^-1 * y)%g; rewrite -?cfConjgMnorm ?groupM ?groupV ?nHN // mulKVg. by exists (x * y)%g; rewrite -?cfConjgMnorm ?groupM ?nHN. Qed. Lemma cfclass_sym phi psi : (psi \in phi ^: G)%CF = (phi \in psi ^: G)%CF. Proof. by apply/idP/idP=> /cfclass_transl <-; exact: cfclass_refl. Qed. Lemma cfclass_uniq phi : H <| G -> uniq (phi ^: G)%CF. Proof. move=> nsHG; rewrite map_inj_in_uniq ?enum_uniq // => Ty Tz; rewrite !mem_enum. move=> {Ty}/rcosetsP[y Gy ->] {Tz}/rcosetsP[z Gz ->] /eqP. case: repr_rcosetP => u Iphi_u; case: repr_rcosetP => v Iphi_v. have [[Gu _] [Gv _]] := (setIdP Iphi_u, setIdP Iphi_v). rewrite cfConjg_eqE ?groupM // => /rcoset_transl. by rewrite !rcosetM (rcoset_id Iphi_v) (rcoset_id Iphi_u). Qed. Lemma cfclass_invariant phi : G \subset 'I[phi] -> (phi ^: G)%CF = phi. Proof. move/setIidPl=> IGphi; rewrite /cfclass IGphi // rcosets_id. by rewrite /(image _ _) enum_set1 /= repr_group cfConjgJ1. Qed. Lemma cfclass1 : H <| G -> (1 ^: G)%CF = [:: 1 : 'CF(H)]. Proof. by move/normal_norm=> nHG; rewrite cfclass_invariant ?inertia1. Qed. Definition cfclass_Iirr (A : {set gT}) i := conjg_Iirr i @: A. Lemma cfclass_IirrE i j : (j \in cfclass_Iirr G i) = ('chi_j \in 'chi_i ^: G)%CF. Proof. apply/imsetP/cfclassP=> [[y Gy ->] | [y]]; exists y; rewrite ?conjg_IirrE //. by apply: irr_inj; rewrite conjg_IirrE. Qed. Lemma eq_cfclass_IirrE i j : (cfclass_Iirr G j == cfclass_Iirr G i) = (j \in cfclass_Iirr G i). Proof. apply/eqP/idP=> [<- | iGj]; first by rewrite cfclass_IirrE cfclass_refl. by apply/setP=> k; rewrite !cfclass_IirrE in iGj *; apply/esym/cfclass_transl. Qed. Lemma im_cfclass_Iirr i : H <| G -> perm_eq [seq 'chi_j | j in cfclass_Iirr G i] ('chi_i ^: G)%CF. Proof. move=> nsHG; have UchiG := cfclass_uniq 'chi_i nsHG. apply: uniq_perm_eq; rewrite ?(map_inj_uniq irr_inj) ?enum_uniq // => phi. apply/imageP/idP=> [[j iGj ->] | /cfclassP[y]]; first by rewrite -cfclass_IirrE. by exists (conjg_Iirr i y); rewrite ?mem_imset ?conjg_IirrE. Qed. Lemma card_cfclass_Iirr i : H <| G -> #|cfclass_Iirr G i| = #|G : 'I_G['chi_i]|. Proof. move=> nsHG; rewrite -size_cfclass -(perm_eq_size (im_cfclass_Iirr i nsHG)). by rewrite size_map -cardE. Qed. Lemma reindex_cfclass R idx (op : Monoid.com_law idx) (F : 'CF(H) -> R) i : H <| G -> \big[op/idx]_(chi <- ('chi_i ^: G)%CF) F chi = \big[op/idx]_(j | 'chi_j \in ('chi_i ^: G)%CF) F 'chi_j. Proof. move/im_cfclass_Iirr/(eq_big_perm _) <-; rewrite big_map big_filter /=. by apply: eq_bigl => j; rewrite cfclass_IirrE. Qed. Lemma cfResInd j: H <| G -> 'Res[H] ('Ind[G] 'chi_j) = #|H|%:R^-1 *: (\sum_(y in G) 'chi_j ^ y)%CF. Proof. case/andP=> [sHG /subsetP nHG]. rewrite (reindex_inj invg_inj); apply/cfun_inP=> x Hx. rewrite cfResE // cfIndE // ?cfunE ?sum_cfunE; congr (_ * _). by apply: eq_big => [y | y Gy]; rewrite ?cfConjgE ?groupV ?invgK ?nHG. Qed. (* This is Isaacs, Theorem (6.2) *) Lemma Clifford_Res_sum_cfclass i j : H <| G -> j \in irr_constt ('Res[H, G] 'chi_i) -> 'Res[H] 'chi_i = '['Res[H] 'chi_i, 'chi_j] *: (\sum_(chi <- ('chi_j ^: G)%CF) chi). Proof. move=> nsHG chiHj; have [sHG /subsetP nHG] := andP nsHG. rewrite reindex_cfclass //= big_mkcond. rewrite {1}['Res _]cfun_sum_cfdot linear_sum /=; apply: eq_bigr => k _. have [[y Gy ->] | ] := altP (cfclassP _ _ _); first by rewrite cfdot_Res_conjg. apply: contraNeq; rewrite scaler0 scaler_eq0 orbC => /norP[_ chiHk]. have{chiHk chiHj}: '['Res[H] ('Ind[G] 'chi_j), 'chi_k] != 0. rewrite !inE !cfdot_Res_l in chiHj chiHk *. apply: contraNneq chiHk; rewrite cfdot_sum_irr => /psumr_eq0P/(_ i isT)/eqP. rewrite -cfdotC cfdotC mulf_eq0 conjC_eq0 (negbTE chiHj) /= => -> // i1. by rewrite -cfdotC Cnat_ge0 // rpredM ?Cnat_cfdot_char ?cfInd_char ?irr_char. rewrite cfResInd // cfdotZl mulf_eq0 cfdot_suml => /norP[_]. apply: contraR => chiGk'j; rewrite big1 // => x Gx; apply: contraNeq chiGk'j. rewrite -conjg_IirrE cfdot_irr pnatr_eq0; case: (_ =P k) => // <- _. by rewrite conjg_IirrE; apply/cfclassP; exists x. Qed. Lemma cfRes_Ind_invariant psi : H <| G -> G \subset 'I[psi] -> 'Res ('Ind[G, H] psi) = #|G : H|%:R *: psi. Proof. case/andP=> sHG _ /subsetP IGpsi; apply/cfun_inP=> x Hx. rewrite cfResE ?cfIndE ?natf_indexg // cfunE -mulrA mulrCA; congr (_ * _). by rewrite mulr_natl -sumr_const; apply: eq_bigr => y /IGpsi/inertia_valJ->. Qed. (* This is Isaacs, Corollary (6.7). *) Corollary constt0_Res_cfker i : H <| G -> 0 \in irr_constt ('Res[H] 'chi[G]_i) -> H \subset cfker 'chi[G]_i. Proof. move=> nsHG /(Clifford_Res_sum_cfclass nsHG); have [sHG nHG] := andP nsHG. rewrite irr0 cfdot_Res_l cfclass1 // big_seq1 cfInd_cfun1 //. rewrite cfdotZr conjC_nat => def_chiH. apply/subsetP=> x Hx; rewrite cfkerEirr inE -!(cfResE _ sHG) //. by rewrite def_chiH !cfunE cfun11 cfun1E Hx. Qed. (* This is Isaacs, Lemma (6.8). *) Lemma dvdn_constt_Res1_irr1 i j : H <| G -> j \in irr_constt ('Res[H, G] 'chi_i) -> exists n, 'chi_i 1%g = n%:R * 'chi_j 1%g. Proof. move=> nsHG chiHj; have [sHG nHG] := andP nsHG; rewrite -(cfResE _ sHG) //. rewrite {1}(Clifford_Res_sum_cfclass nsHG chiHj) cfunE sum_cfunE. have /CnatP[n ->]: '['Res[H] 'chi_i, 'chi_j] \in Cnat. by rewrite Cnat_cfdot_char ?cfRes_char ?irr_char. exists (n * size ('chi_j ^: G)%CF)%N; rewrite natrM -mulrA; congr (_ * _). rewrite mulr_natl -[size _]card_ord big_tnth -sumr_const; apply: eq_bigr => k _. by have /cfclassP[y Gy ->]:= mem_tnth k (in_tuple _); rewrite cfConjg1. Qed. Lemma cfclass_Ind phi psi : H <| G -> psi \in (phi ^: G)%CF -> 'Ind[G] phi = 'Ind[G] psi. Proof. move=> nsHG /cfclassP[y Gy ->]; have [sHG /subsetP nHG] := andP nsHG. apply/cfun_inP=> x Hx; rewrite !cfIndE //; congr (_ * _). rewrite (reindex_acts 'R _ (groupVr Gy)) ?astabsR //=. by apply: eq_bigr => z Gz; rewrite conjgM cfConjgE ?nHG. Qed. End Inertia. Arguments Scope inertia [_ group_scope cfun_scope]. Arguments Scope cfclass [_ group_scope cfun_scope group_scope]. Implicit Arguments conjg_Iirr_inj [gT H x1 x2]. Notation "''I[' phi ] " := (inertia phi) : group_scope. Notation "''I[' phi ] " := (inertia_group phi) : Group_scope. Notation "''I_' G [ phi ] " := (G%g :&: 'I[phi]) : group_scope. Notation "''I_' G [ phi ] " := (G :&: 'I[phi])%G : Group_scope. Notation "phi ^: G" := (cfclass phi G) : cfun_scope. Section ConjRestrict. Variables (gT : finGroupType) (G H K : {group gT}). Lemma cfConjgRes_norm phi y : y \in 'N(K) -> y \in 'N(H) -> ('Res[K, H] phi ^ y)%CF = 'Res (phi ^ y)%CF. Proof. move=> nKy nHy; have [sKH | not_sKH] := boolP (K \subset H); last first. by rewrite !cfResEout // linearZ rmorph1 cfConjg1. by apply/cfun_inP=> x Kx; rewrite !(cfConjgE, cfResE) ?memJ_norm ?groupV. Qed. Lemma cfConjgRes phi y : H <| G -> K <| G -> y \in G -> ('Res[K, H] phi ^ y)%CF = 'Res (phi ^ y)%CF. Proof. move=> /andP[_ nHG] /andP[_ nKG] Gy. by rewrite cfConjgRes_norm ?(subsetP nHG) ?(subsetP nKG). Qed. Lemma sub_inertia_Res phi : G \subset 'N(K) -> 'I_G[phi] \subset 'I_G['Res[K, H] phi]. Proof. move=> nKG; apply/subsetP=> y /setIP[Gy /setIdP[nHy /eqP Iphi_y]]. by rewrite 2!inE Gy cfConjgRes_norm ?(subsetP nKG) ?Iphi_y /=. Qed. Lemma cfConjgInd_norm phi y : y \in 'N(K) -> y \in 'N(H) -> ('Ind[H, K] phi ^ y)%CF = 'Ind (phi ^ y)%CF. Proof. move=> nKy nHy; have [sKH | not_sKH] := boolP (K \subset H). by rewrite !cfConjgEin (cfIndIsom (norm_conj_isom nHy)). rewrite !cfIndEout // linearZ -(cfConjg_iso y) rmorph1 /=; congr (_ *: _). by rewrite cfConjg_cfuni ?norm1 ?inE. Qed. Lemma cfConjgInd phi y : H <| G -> K <| G -> y \in G -> ('Ind[H, K] phi ^ y)%CF = 'Ind (phi ^ y)%CF. Proof. move=> /andP[_ nHG] /andP[_ nKG] Gy. by rewrite cfConjgInd_norm ?(subsetP nHG) ?(subsetP nKG). Qed. Lemma sub_inertia_Ind phi : G \subset 'N(H) -> 'I_G[phi] \subset 'I_G['Ind[H, K] phi]. Proof. move=> nHG; apply/subsetP=> y /setIP[Gy /setIdP[nKy /eqP Iphi_y]]. by rewrite 2!inE Gy cfConjgInd_norm ?(subsetP nHG) ?Iphi_y /=. Qed. End ConjRestrict. Section MoreInertia. Variables (gT : finGroupType) (G H : {group gT}) (i : Iirr H). Let T := 'I_G['chi_i]. Lemma inertia_id : 'I_T['chi_i] = T. Proof. by rewrite -setIA setIid. Qed. Lemma cfclass_inertia : ('chi[H]_i ^: T)%CF = [:: 'chi_i]. Proof. rewrite /cfclass inertia_id rcosets_id /(image _ _) enum_set1 /=. by rewrite repr_group cfConjgJ1. Qed. End MoreInertia. Section ConjMorph. Variables (aT rT : finGroupType) (D G H : {group aT}) (f : {morphism D >-> rT}). Lemma cfConjgMorph (phi : 'CF(f @* H)) y : y \in D -> y \in 'N(H) -> (cfMorph phi ^ y)%CF = cfMorph (phi ^ f y). Proof. move=> Dy nHy; have [sHD | not_sHD] := boolP (H \subset D); last first. by rewrite !cfMorphEout // linearZ rmorph1 cfConjg1. apply/cfun_inP=> x Gx; rewrite !(cfConjgE, cfMorphE) ?memJ_norm ?groupV //. by rewrite morphJ ?morphV ?groupV // (subsetP sHD). by rewrite (subsetP (morphim_norm _ _)) ?mem_morphim. Qed. Lemma inertia_morph_pre (phi : 'CF(f @* H)) : H <| G -> G \subset D -> 'I_G[cfMorph phi] = G :&: f @*^-1 'I_(f @* G)[phi]. Proof. case/andP=> sHG nHG sGD; have sHD := subset_trans sHG sGD. apply/setP=> y; rewrite !in_setI; apply: andb_id2l => Gy. have [Dy nHy] := (subsetP sGD y Gy, subsetP nHG y Gy). rewrite Dy inE nHy 4!inE mem_morphim // -morphimJ ?(normP nHy) // subxx /=. rewrite cfConjgMorph //; apply/eqP/eqP=> [Iphi_y | -> //]. by apply/cfun_inP=> _ /morphimP[x Dx Hx ->]; rewrite -!cfMorphE ?Iphi_y. Qed. Lemma inertia_morph_im (phi : 'CF(f @* H)) : H <| G -> G \subset D -> f @* 'I_G[cfMorph phi] = 'I_(f @* G)[phi]. Proof. move=> nsHG sGD; rewrite inertia_morph_pre // morphim_setIpre. by rewrite (setIidPr _) ?Inertia_sub. Qed. Variables (R S : {group rT}). Variables (g : {morphism G >-> rT}) (h : {morphism H >-> rT}). Hypotheses (isoG : isom G R g) (isoH : isom H S h). Hypotheses (eq_hg : {in H, h =1 g}) (sHG : H \subset G). (* This does not depend on the (isoG : isom G R g) assumption. *) Lemma cfConjgIsom phi y : y \in G -> y \in 'N(H) -> (cfIsom isoH phi ^ g y)%CF = cfIsom isoH (phi ^ y). Proof. move=> Gy nHy; have [_ defS] := isomP isoH. rewrite morphimEdom (eq_in_imset eq_hg) -morphimEsub // in defS. apply/cfun_inP=> gx; rewrite -{1}defS => /morphimP[x Gx Hx ->] {gx}. rewrite cfConjgE; last by rewrite -defS inE -morphimJ ?(normP nHy). by rewrite -morphV -?morphJ -?eq_hg ?cfIsomE ?cfConjgE ?memJ_norm ?groupV. Qed. Lemma inertia_isom phi : 'I_R[cfIsom isoH phi] = g @* 'I_G[phi]. Proof. have [[_ defS] [injg <-]] := (isomP isoH, isomP isoG). rewrite morphimEdom (eq_in_imset eq_hg) -morphimEsub // in defS. rewrite /inertia !setIdE morphimIdom setIA -{1}defS -injm_norm ?injmI //. apply/setP=> gy; rewrite !inE; apply: andb_id2l => /morphimP[y Gy nHy ->] {gy}. rewrite cfConjgIsom // -sub1set -morphim_set1 // injmSK ?sub1set //= inE. apply/eqP/eqP=> [Iphi_y | -> //]. by apply/cfun_inP=> x Hx; rewrite -!(cfIsomE isoH) ?Iphi_y. Qed. End ConjMorph. Section ConjQuotient. Variables gT : finGroupType. Implicit Types G H K : {group gT}. Lemma cfConjgMod_norm H K (phi : 'CF(H / K)) y : y \in 'N(K) -> y \in 'N(H) -> ((phi %% K) ^ y)%CF = (phi ^ coset K y %% K)%CF. Proof. exact: cfConjgMorph. Qed. Lemma cfConjgMod G H K (phi : 'CF(H / K)) y : H <| G -> K <| G -> y \in G -> ((phi %% K) ^ y)%CF = (phi ^ coset K y %% K)%CF. Proof. move=> /andP[_ nHG] /andP[_ nKG] Gy. by rewrite cfConjgMod_norm ?(subsetP nHG) ?(subsetP nKG). Qed. Lemma cfConjgQuo_norm H K (phi : 'CF(H)) y : y \in 'N(K) -> y \in 'N(H) -> ((phi / K) ^ coset K y)%CF = (phi ^ y / K)%CF. Proof. move=> nKy nHy; have keryK: (K \subset cfker (phi ^ y)) = (K \subset cfker phi). by rewrite cfker_conjg // -{1}(normP nKy) conjSg. have [kerK | not_kerK] := boolP (K \subset cfker phi); last first. by rewrite !cfQuoEout ?linearZ ?rmorph1 ?cfConjg1 ?keryK. apply/cfun_inP=> _ /morphimP[x nKx Hx ->]. have nHyb: coset K y \in 'N(H / K) by rewrite inE -morphimJ ?(normP nHy). rewrite !(cfConjgE, cfQuoEnorm) ?keryK // ?in_setI ?Hx //. rewrite -morphV -?morphJ ?groupV // cfQuoEnorm //. by rewrite inE memJ_norm ?Hx ?groupJ ?groupV. Qed. Lemma cfConjgQuo G H K (phi : 'CF(H)) y : H <| G -> K <| G -> y \in G -> ((phi / K) ^ coset K y)%CF = (phi ^ y / K)%CF. Proof. move=> /andP[_ nHG] /andP[_ nKG] Gy. by rewrite cfConjgQuo_norm ?(subsetP nHG) ?(subsetP nKG). Qed. Lemma inertia_mod_pre G H K (phi : 'CF(H / K)) : H <| G -> K <| G -> 'I_G[phi %% K] = G :&: coset K @*^-1 'I_(G / K)[phi]. Proof. by move=> nsHG /andP[_]; apply: inertia_morph_pre. Qed. Lemma inertia_mod_quo G H K (phi : 'CF(H / K)) : H <| G -> K <| G -> ('I_G[phi %% K] / K)%g = 'I_(G / K)[phi]. Proof. by move=> nsHG /andP[_]; apply: inertia_morph_im. Qed. Lemma inertia_quo G H K (phi : 'CF(H)) : H <| G -> K <| G -> K \subset cfker phi -> 'I_(G / K)[phi / K] = ('I_G[phi] / K)%g. Proof. move=> nsHG nsKG kerK; rewrite -inertia_mod_quo ?cfQuoK //. by rewrite (normalS _ (normal_sub nsHG)) // (subset_trans _ (cfker_sub phi)). Qed. End ConjQuotient. Section InertiaSdprod. Variables (gT : finGroupType) (K H G : {group gT}). Hypothesis defG : K ><| H = G. Lemma cfConjgSdprod phi y : y \in 'N(K) -> y \in 'N(H) -> (cfSdprod defG phi ^ y = cfSdprod defG (phi ^ y))%CF. Proof. move=> nKy nHy. have nGy: y \in 'N(G) by rewrite -sub1set -(sdprodW defG) normsM ?sub1set. rewrite -{2}[phi](cfSdprodK defG) cfConjgRes_norm // cfRes_sdprodK //. by rewrite cfker_conjg // -{1}(normP nKy) conjSg cfker_sdprod. Qed. Lemma inertia_sdprod (L : {group gT}) phi : L \subset 'N(K) -> L \subset 'N(H) -> 'I_L[cfSdprod defG phi] = 'I_L[phi]. Proof. move=> nKL nHL; have nGL: L \subset 'N(G) by rewrite -(sdprodW defG) normsM. apply/setP=> z; rewrite !in_setI ![z \in 'I[_]]inE; apply: andb_id2l => Lz. rewrite cfConjgSdprod ?(subsetP nKL) ?(subsetP nHL) ?(subsetP nGL) //=. by rewrite (can_eq (cfSdprodK defG)). Qed. End InertiaSdprod. Section InertiaDprod. Variables (gT : finGroupType) (G K H : {group gT}). Implicit Type L : {group gT}. Hypothesis KxH : K \x H = G. Lemma cfConjgDprodl phi y : y \in 'N(K) -> y \in 'N(H) -> (cfDprodl KxH phi ^ y = cfDprodl KxH (phi ^ y))%CF. Proof. by move=> nKy nHy; apply: cfConjgSdprod. Qed. Lemma cfConjgDprodr psi y : y \in 'N(K) -> y \in 'N(H) -> (cfDprodr KxH psi ^ y = cfDprodr KxH (psi ^ y))%CF. Proof. by move=> nKy nHy; apply: cfConjgSdprod. Qed. Lemma cfConjgDprod phi psi y : y \in 'N(K) -> y \in 'N(H) -> (cfDprod KxH phi psi ^ y = cfDprod KxH (phi ^ y) (psi ^ y))%CF. Proof. by move=> nKy nHy; rewrite rmorphM /= cfConjgDprodl ?cfConjgDprodr. Qed. Lemma inertia_dprodl L phi : L \subset 'N(K) -> L \subset 'N(H) -> 'I_L[cfDprodl KxH phi] = 'I_L[phi]. Proof. by move=> nKL nHL; apply: inertia_sdprod. Qed. Lemma inertia_dprodr L psi : L \subset 'N(K) -> L \subset 'N(H) -> 'I_L[cfDprodr KxH psi] = 'I_L[psi]. Proof. by move=> nKL nHL; apply: inertia_sdprod. Qed. Lemma inertia_dprod L (phi : 'CF(K)) (psi : 'CF(H)) : L \subset 'N(K) -> L \subset 'N(H) -> phi 1%g != 0 -> psi 1%g != 0 -> 'I_L[cfDprod KxH phi psi] = 'I_L[phi] :&: 'I_L[psi]. Proof. move=> nKL nHL nz_phi nz_psi; apply/eqP; rewrite eqEsubset subsetI. rewrite -{1}(inertia_scale_nz psi nz_phi) -{1}(inertia_scale_nz phi nz_psi). rewrite -(cfDprod_Resl KxH) -(cfDprod_Resr KxH) !sub_inertia_Res //=. by rewrite -inertia_dprodl -?inertia_dprodr // -setIIr setIS ?inertia_mul. Qed. Lemma inertia_dprod_irr L i j : L \subset 'N(K) -> L \subset 'N(H) -> 'I_L[cfDprod KxH 'chi_i 'chi_j] = 'I_L['chi_i] :&: 'I_L['chi_j]. Proof. by move=> nKL nHL; rewrite inertia_dprod ?irr1_neq0. Qed. End InertiaDprod. Section InertiaBigdprod. Variables (gT : finGroupType) (I : finType) (P : pred I). Variables (A : I -> {group gT}) (G : {group gT}). Implicit Type L : {group gT}. Hypothesis defG : \big[dprod/1%g]_(i | P i) A i = G. Section ConjBig. Variable y : gT. Hypothesis nAy: forall i, P i -> y \in 'N(A i). Lemma cfConjgBigdprodi i (phi : 'CF(A i)) : (cfBigdprodi defG phi ^ y = cfBigdprodi defG (phi ^ y))%CF. Proof. rewrite cfConjgDprodl; try by case: ifP => [/nAy// | _]; rewrite norm1 inE. congr (cfDprodl _ _); case: ifP => [Pi | _]. by rewrite cfConjgRes_norm ?nAy. by apply/cfun_inP=> _ /set1P->; rewrite !(cfRes1, cfConjg1). rewrite -sub1set norms_gen ?norms_bigcup // sub1set. by apply/bigcapP=> j /andP[/nAy]. Qed. Lemma cfConjgBigdprod phi : (cfBigdprod defG phi ^ y = cfBigdprod defG (fun i => phi i ^ y))%CF. Proof. by rewrite rmorph_prod /=; apply: eq_bigr => i _; apply: cfConjgBigdprodi. Qed. End ConjBig. Section InertiaBig. Variable L : {group gT}. Hypothesis nAL : forall i, P i -> L \subset 'N(A i). Lemma inertia_bigdprodi i (phi : 'CF(A i)) : P i -> 'I_L[cfBigdprodi defG phi] = 'I_L[phi]. Proof. move=> Pi; rewrite inertia_dprodl ?Pi ?cfRes_id ?nAL //. by apply/norms_gen/norms_bigcup/bigcapsP=> j /andP[/nAL]. Qed. Lemma inertia_bigdprod phi (Phi := cfBigdprod defG phi) : Phi 1%g != 0 -> 'I_L[Phi] = L :&: \bigcap_(i | P i) 'I_L[phi i]. Proof. move=> nz_Phi; apply/eqP; rewrite eqEsubset; apply/andP; split. rewrite subsetI Inertia_sub; apply/bigcapsP=> i Pi. have [] := cfBigdprodK nz_Phi Pi; move: (_ / _) => a nz_a <-. by rewrite inertia_scale_nz ?sub_inertia_Res //= ?nAL. rewrite subsetI subsetIl; apply: subset_trans (inertia_prod _ _ _). apply: setISS. by rewrite -(bigdprodWY defG) norms_gen ?norms_bigcup //; apply/bigcapsP. apply/bigcapsP=> i Pi; rewrite (bigcap_min i) //. by rewrite -inertia_bigdprodi ?subsetIr. Qed. Lemma inertia_bigdprod_irr Iphi (phi := fun i => 'chi_(Iphi i)) : 'I_L[cfBigdprod defG phi] = L :&: \bigcap_(i | P i) 'I_L[phi i]. Proof. rewrite inertia_bigdprod // -[cfBigdprod _ _]cfIirrE ?irr1_neq0 //. by apply: cfBigdprod_irr => i _; apply: mem_irr. Qed. End InertiaBig. End InertiaBigdprod. Section ConsttInertiaBijection. Variables (gT : finGroupType) (H G : {group gT}) (t : Iirr H). Hypothesis nsHG : H <| G. Local Notation theta := 'chi_t. Local Notation T := 'I_G[theta]%G. Local Notation "` 'T'" := 'I_(gval G)[theta] (at level 0, format "` 'T'") : group_scope. Let calA := irr_constt ('Ind[T] theta). Let calB := irr_constt ('Ind[G] theta). Local Notation AtoB := (Ind_Iirr G). (* This is Isaacs, Theorem (6.11). *) Theorem constt_Inertia_bijection : [/\ (*a*) {in calA, forall s, 'Ind[G] 'chi_s \in irr G}, (*b*) {in calA &, injective (Ind_Iirr G)}, Ind_Iirr G @: calA =i calB, (*c*) {in calA, forall s (psi := 'chi_s) (chi := 'Ind[G] psi), [predI irr_constt ('Res chi) & calA] =i pred1 s} & (*d*) {in calA, forall s (psi := 'chi_s) (chi := 'Ind[G] psi), '['Res psi, theta] = '['Res chi, theta]}]. Proof. have [sHG sTG]: H \subset G /\ T \subset G by rewrite subsetIl normal_sub. have nsHT : H <| T := normal_Inertia theta sHG; have sHT := normal_sub nsHT. have AtoB_P s (psi := 'chi_s) (chi := 'Ind[G] psi): s \in calA -> [/\ chi \in irr G, AtoB s \in calB & '['Res psi, theta] = '['Res chi, theta]]. - rewrite !constt_Ind_Res => sHt; have [r sGr] := constt_cfInd_irr s sTG. have rTs: s \in irr_constt ('Res[T] 'chi_r) by rewrite -constt_Ind_Res. have NrT: 'Res[T] 'chi_r \is a character by rewrite cfRes_char ?irr_char. have rHt: t \in irr_constt ('Res[H] 'chi_r). by have:= constt_Res_trans NrT rTs sHt; rewrite cfResRes. pose e := '['Res[H] 'chi_r, theta]; set f := '['Res[H] psi, theta]. have DrH: 'Res[H] 'chi_r = e *: \sum_(xi <- (theta ^: G)%CF) xi. exact: Clifford_Res_sum_cfclass. have DpsiH: 'Res[H] psi = f *: theta. rewrite (Clifford_Res_sum_cfclass nsHT sHt). by rewrite cfclass_invariant ?subsetIr ?big_seq1. have ub_chi_r: 'chi_r 1%g <= chi 1%g ?= iff ('chi_r == chi). have Nchi: chi \is a character by rewrite cfInd_char ?irr_char. have [chi1 Nchi1->] := constt_charP _ Nchi sGr. rewrite addrC cfunE -lerif_subLR subrr eq_sym -subr_eq0 addrK. by split; rewrite ?char1_ge0 // eq_sym char1_eq0. have lb_chi_r: chi 1%g <= 'chi_r 1%g ?= iff (f == e). rewrite cfInd1 // -(cfRes1 H) DpsiH -(cfRes1 H 'chi_r) DrH !cfunE sum_cfunE. rewrite (eq_big_seq (fun _ => theta 1%g)) => [|i]; last first. by case/cfclassP=> y _ ->; rewrite cfConjg1. rewrite reindex_cfclass //= sumr_const -(eq_card (cfclass_IirrE _ _)). rewrite mulr_natl mulrnAr card_cfclass_Iirr //. rewrite (mono_lerif (ler_pmuln2r (indexg_gt0 G T))). rewrite (mono_lerif (ler_pmul2r (irr1_gt0 t))); apply: lerif_eq. by rewrite /e -(cfResRes _ sHT) ?cfdot_Res_ge_constt. have [_ /esym] := lerif_trans ub_chi_r lb_chi_r; rewrite eqxx. by case/andP=> /eqP Dchi /eqP->;rewrite cfIirrE -/chi -?Dchi ?mem_irr. have part_c: {in calA, forall s (chi := 'Ind[G] 'chi_s), [predI irr_constt ('Res[T] chi) & calA] =i pred1 s}. - move=> s As chi s1; have [irr_chi _ /eqP Dchi_theta] := AtoB_P s As. have chiTs: s \in irr_constt ('Res[T] chi). by rewrite irr_consttE cfdot_Res_l irrWnorm ?oner_eq0. apply/andP/eqP=> [[/= chiTs1 As1] | -> //]. apply: contraTeq Dchi_theta => s's1; rewrite ltr_eqF // -/chi. have [|phi Nphi DchiT] := constt_charP _ _ chiTs. by rewrite cfRes_char ?cfInd_char ?irr_char. have [|phi1 Nphi1 Dphi] := constt_charP s1 Nphi _. rewrite irr_consttE -(canLR (addKr _) DchiT) addrC cfdotBl cfdot_irr. by rewrite mulrb ifN_eqC ?subr0. rewrite -(cfResRes chi sHT sTG) DchiT Dphi !rmorphD !cfdotDl /=. rewrite -ltr_subl_addl subrr ltr_paddr ?ltr_def //; rewrite Cnat_ge0 ?Cnat_cfdot_char ?cfRes_char ?irr_char //. by rewrite andbT -irr_consttE -constt_Ind_Res. do [split=> //; try by move=> s /AtoB_P[]] => [s1 s2 As1 As2 | r]. have [[irr_s1G _ _] [irr_s2G _ _]] := (AtoB_P _ As1, AtoB_P _ As2). move/(congr1 (tnth (irr G))); rewrite !cfIirrE // => eq_s12_G. apply/eqP; rewrite -[_ == _]part_c // inE /= As1 -eq_s12_G. by rewrite -As1 [_ && _]part_c // inE /=. apply/imsetP/idP=> [[s /AtoB_P[_ BsG _] -> //] | Br]. have /exists_inP[s rTs As]: [exists s in irr_constt ('Res 'chi_r), s \in calA]. rewrite -negb_forall_in; apply: contra Br => /eqfun_inP => o_tT_rT. rewrite -(cfIndInd _ sTG sHT) -cfdot_Res_r ['Res _]cfun_sum_constt. by rewrite cfdot_sumr big1 // => i rTi; rewrite cfdotZr o_tT_rT ?mulr0. exists s => //; have [/irrP[r1 DsG] _ _] := AtoB_P s As. by apply/eqP; rewrite /AtoB -constt_Ind_Res DsG irrK constt_irr in rTs *. Qed. End ConsttInertiaBijection. Section ExtendInvariantIrr. Variable gT : finGroupType. Implicit Types G H K L M N : {group gT}. Section ConsttIndExtendible. Variables (G N : {group gT}) (t : Iirr N) (c : Iirr G). Let theta := 'chi_t. Let chi := 'chi_c. Definition mul_Iirr b := cfIirr ('chi_b * chi). Definition mul_mod_Iirr (b : Iirr (G / N)) := mul_Iirr (mod_Iirr b). Hypotheses (nsNG : N <| G) (cNt : 'Res[N] chi = theta). Let sNG : N \subset G. Proof. exact: normal_sub. Qed. Let nNG : G \subset 'N(N). Proof. exact: normal_norm. Qed. Lemma extendible_irr_invariant : G \subset 'I[theta]. Proof. apply/subsetP=> y Gy; have nNy := subsetP nNG y Gy. rewrite inE nNy; apply/eqP/cfun_inP=> x Nx; rewrite cfConjgE // -cNt. by rewrite !cfResE ?memJ_norm ?cfunJ ?groupV. Qed. Let IGtheta := extendible_irr_invariant. (* This is Isaacs, Theorem (6.16) *) Theorem constt_Ind_mul_ext f (phi := 'chi_f) (psi := phi * theta) : G \subset 'I[phi] -> psi \in irr N -> let calS := irr_constt ('Ind phi) in [/\ {in calS, forall b, 'chi_b * chi \in irr G}, {in calS &, injective mul_Iirr}, irr_constt ('Ind psi) =i [seq mul_Iirr b | b in calS] & 'Ind psi = \sum_(b in calS) '['Ind phi, 'chi_b] *: 'chi_(mul_Iirr b)]. Proof. move=> IGphi irr_psi calS. have IGpsi: G \subset 'I[psi]. by rewrite (subset_trans _ (inertia_mul _ _)) // subsetI IGphi. pose e b := '['Ind[G] phi, 'chi_b]; pose d b g := '['chi_b * chi, 'chi_g * chi]. have Ne b: e b \in Cnat by rewrite Cnat_cfdot_char ?cfInd_char ?irr_char. have egt0 b: b \in calS -> e b > 0 by rewrite Cnat_gt0. have DphiG: 'Ind phi = \sum_(b in calS) e b *: 'chi_b := cfun_sum_constt _. have DpsiG: 'Ind psi = \sum_(b in calS) e b *: 'chi_b * chi. by rewrite /psi -cNt cfIndM // DphiG mulr_suml. pose d_delta := [forall b in calS, forall g in calS, d b g == (b == g)%:R]. have charMchi b: 'chi_b * chi \is a character by rewrite rpredM ?irr_char. have [_]: '['Ind[G] phi] <= '['Ind[G] psi] ?= iff d_delta. pose sum_delta := \sum_(b in calS) e b * \sum_(g in calS) e g * (b == g)%:R. pose sum_d := \sum_(b in calS) e b * \sum_(g in calS) e g * d b g. have ->: '['Ind[G] phi] = sum_delta. rewrite DphiG cfdot_suml; apply: eq_bigr => b _; rewrite cfdotZl cfdot_sumr. by congr (_ * _); apply: eq_bigr => g; rewrite cfdotZr cfdot_irr conj_Cnat. have ->: '['Ind[G] psi] = sum_d. rewrite DpsiG cfdot_suml; apply: eq_bigr => b _. rewrite -scalerAl cfdotZl cfdot_sumr; congr (_ * _). by apply: eq_bigr => g _; rewrite -scalerAl cfdotZr conj_Cnat. have eMmono := mono_lerif (ler_pmul2l (egt0 _ _)). apply: lerif_sum => b /eMmono->; apply: lerif_sum => g /eMmono->. split; last exact: eq_sym. have /CnatP[n Dd]: d b g \in Cnat by rewrite Cnat_cfdot_char. have [Db | _] := eqP; rewrite Dd leC_nat // -ltC_nat -Dd Db cfnorm_gt0. by rewrite -char1_eq0 // cfunE mulf_neq0 ?irr1_neq0. rewrite -!cfdot_Res_l ?cfRes_Ind_invariant // !cfdotZl cfnorm_irr irrWnorm //. rewrite eqxx => /esym/forall_inP/(_ _ _)/eqfun_inP; rewrite /d /= => Dd. have irrMchi: {in calS, forall b, 'chi_b * chi \in irr G}. by move=> b Sb; rewrite /= irrEchar charMchi Dd ?eqxx. have injMchi: {in calS &, injective mul_Iirr}. move=> b g Sb Sg /(congr1 (fun s => '['chi_s, 'chi_(mul_Iirr g)]))/eqP. by rewrite cfnorm_irr !cfIirrE ?irrMchi ?Dd // pnatr_eq1; case: (b =P g). have{DpsiG} ->: 'Ind psi = \sum_(b in calS) e b *: 'chi_(mul_Iirr b). by rewrite DpsiG; apply: eq_bigr => b Sb; rewrite -scalerAl cfIirrE ?irrMchi. split=> // i; rewrite irr_consttE cfdot_suml; apply/idP/idP=> [|/imageP[b Sb ->]]. apply: contraR => N'i; rewrite big1 // => b Sb. rewrite cfdotZl cfdot_irr mulrb ifN_eqC ?mulr0 //. by apply: contraNneq N'i => ->; apply: image_f. rewrite gtr_eqF // (bigD1 b) //= cfdotZl cfnorm_irr mulr1 ltr_paddr ?egt0 //. apply: sumr_ge0 => g /andP[Sg _]; rewrite cfdotZl cfdot_irr. by rewrite mulr_ge0 ?ler0n ?Cnat_ge0. Qed. (* This is Isaacs, Corollary (6.17) (due to Gallagher). *) Corollary constt_Ind_ext : [/\ forall b : Iirr (G / N), 'chi_(mod_Iirr b) * chi \in irr G, injective mul_mod_Iirr, irr_constt ('Ind theta) =i codom mul_mod_Iirr & 'Ind theta = \sum_b 'chi_b 1%g *: 'chi_(mul_mod_Iirr b)]. Proof. have IHchi0: G \subset 'I['chi[N]_0] by rewrite inertia_irr0. have [] := constt_Ind_mul_ext IHchi0; rewrite irr0 ?mul1r ?mem_irr //. set psiG := 'Ind 1 => irrMchi injMchi constt_theta {2}->. have dot_psiG b: '[psiG, 'chi_(mod_Iirr b)] = 'chi[G / N]_b 1%g. rewrite mod_IirrE // -cfdot_Res_r cfRes_sub_ker ?cfker_mod //. by rewrite cfdotZr cfnorm1 mulr1 conj_Cnat ?cfMod1 ?Cnat_irr1. have mem_psiG (b : Iirr (G / N)): mod_Iirr b \in irr_constt psiG. by rewrite irr_consttE dot_psiG irr1_neq0. have constt_psiG b: (b \in irr_constt psiG) = (N \subset cfker 'chi_b). apply/idP/idP=> [psiGb | /quo_IirrK <- //]. by rewrite constt0_Res_cfker // -constt_Ind_Res irr0. split=> [b | b g /injMchi/(can_inj (mod_IirrK nsNG))-> // | b0 | ]. - exact: irrMchi. - rewrite constt_theta. apply/imageP/imageP=> [][b psiGb ->]; last by exists (mod_Iirr b). by exists (quo_Iirr N b) => //; rewrite /mul_mod_Iirr quo_IirrK -?constt_psiG. rewrite (reindex_onto _ _ (in1W (mod_IirrK nsNG))) /=. apply/esym/eq_big => b; first by rewrite constt_psiG quo_IirrKeq. by rewrite -dot_psiG /mul_mod_Iirr => /eqP->. Qed. End ConsttIndExtendible. (* This is Isaacs, Theorem (6.19). *) Theorem invariant_chief_irr_cases G K L s (theta := 'chi[K]_s) : chief_factor G L K -> abelian (K / L) -> G \subset 'I[theta] -> let t := #|K : L| in [\/ 'Res[L] theta \in irr L, exists2 e, exists p, 'Res[L] theta = e%:R *: 'chi_p & (e ^ 2)%N = t | exists2 p, injective p & 'Res[L] theta = \sum_(i < t) 'chi_(p i)]. Proof. case/andP=> /maxgroupP[/andP[ltLK nLG] maxL] nsKG abKbar IGtheta t. have [sKG nKG] := andP nsKG; have sLG := subset_trans (proper_sub ltLK) sKG. have nsLG: L <| G by apply/andP. have nsLK := normalS (proper_sub ltLK) sKG nsLG; have [sLK nLK] := andP nsLK. have [p0 sLp0] := constt_cfRes_irr L s; rewrite -/theta in sLp0. pose phi := 'chi_p0; pose T := 'I_G[phi]. have sTG: T \subset G := subsetIl G _. have /eqP mulKT: (K * T)%g == G. rewrite eqEcard mulG_subG sKG sTG -LagrangeMr -indexgI -(Lagrange sTG) /= -/T. rewrite mulnC leq_mul // setIA (setIidPl sKG) -!size_cfclass // -/phi. rewrite uniq_leq_size ?cfclass_uniq // => _ /cfclassP[x Gx ->]. have: conjg_Iirr p0 x \in irr_constt ('Res theta). have /inertiaJ <-: x \in 'I[theta] := subsetP IGtheta x Gx. by rewrite -(cfConjgRes _ nsKG) // irr_consttE conjg_IirrE // cfConjg_iso. apply: contraR; rewrite -conjg_IirrE // => not_sLp0x. rewrite (Clifford_Res_sum_cfclass nsLK sLp0) cfdotZl cfdot_suml. rewrite big1_seq ?mulr0 // => _ /cfclassP[y Ky ->]; rewrite -conjg_IirrE //. rewrite cfdot_irr mulrb ifN_eq ?(contraNneq _ not_sLp0x) // => <-. by rewrite conjg_IirrE //; apply/cfclassP; exists y. have nsKT_G: K :&: T <| G. rewrite /normal subIset ?sKG // -mulKT setIA (setIidPl sKG) mulG_subG. rewrite normsIG // sub_der1_norm ?subsetIl //. exact: subset_trans (der1_min nLK abKbar) (sub_Inertia _ sLK). have [e DthL]: exists e, 'Res theta = e%:R *: \sum_(xi <- (phi ^: K)%CF) xi. rewrite (Clifford_Res_sum_cfclass nsLK sLp0) -/phi; set e := '[_, _]. by exists (truncC e); rewrite truncCK ?Cnat_cfdot_char ?cfRes_char ?irr_char. have [defKT | ltKT_K] := eqVneq (K :&: T) K; last first. have defKT: K :&: T = L. apply: maxL; last by rewrite subsetI sLK sub_Inertia. by rewrite normal_norm // properEneq ltKT_K subsetIl. have t_cast: size (phi ^: K)%CF = t. by rewrite size_cfclass //= -{2}(setIidPl sKG) -setIA defKT. pose phiKt := Tuple (introT eqP t_cast); pose p i := cfIirr (tnth phiKt i). have pK i: 'chi_(p i) = (phi ^: K)%CF`_i. rewrite cfIirrE; first by rewrite (tnth_nth 0). by have /cfclassP[y _ ->] := mem_tnth i phiKt; rewrite cfConjg_irr ?mem_irr. constructor 3; exists p => [i j /(congr1 (tnth (irr L)))/eqP| ]. by apply: contraTeq; rewrite !pK !nth_uniq ?t_cast ?cfclass_uniq. have{DthL} DthL: 'Res theta = e%:R *: \sum_(i < t) (phi ^: K)%CF`_i. by rewrite DthL (big_nth 0) big_mkord t_cast. suffices /eqP e1: e == 1%N by rewrite DthL e1 scale1r; apply: eq_bigr. have Dth1: theta 1%g = e%:R * t%:R * phi 1%g. rewrite -[t]card_ord -mulrA -(cfRes1 L) DthL cfunE; congr (_ * _). rewrite mulr_natl -sumr_const sum_cfunE -t_cast; apply: eq_bigr => i _. by have /cfclassP[y _ ->] := mem_nth 0 (valP i); rewrite cfConjg1. rewrite eqn_leq lt0n (contraNneq _ (irr1_neq0 s)); last first. by rewrite Dth1 => ->; rewrite !mul0r. rewrite -leC_nat -(ler_pmul2r (gt0CiG K L)) -/t -(ler_pmul2r (irr1_gt0 p0)). rewrite mul1r -Dth1 -cfInd1 //. by rewrite char1_ge_constt ?cfInd_char ?irr_char ?constt_Ind_Res. have IKphi: 'I_K[phi] = K by rewrite -{1}(setIidPl sKG) -setIA. have{DthL} DthL: 'Res[L] theta = e%:R *: phi. by rewrite DthL -[rhs in (_ ^: rhs)%CF]IKphi cfclass_inertia big_seq1. pose mmLth := @mul_mod_Iirr K L s. have linKbar := char_abelianP _ abKbar. have LmodL i: ('chi_i %% L)%CF \is a linear_char := cfMod_lin_char (linKbar i). have mmLthE i: 'chi_(mmLth i) = ('chi_i %% L)%CF * theta. by rewrite cfIirrE ?mod_IirrE // mul_lin_irr ?mem_irr. have mmLthL i: 'Res[L] 'chi_(mmLth i) = 'Res[L] theta. rewrite mmLthE rmorphM /= cfRes_sub_ker ?cfker_mod ?lin_char1 //. by rewrite scale1r mul1r. have [inj_Mphi | /injectivePn[i [j i'j eq_mm_ij]]] := boolP (injectiveb mmLth). suffices /eqP e1: e == 1%N by constructor 1; rewrite DthL e1 scale1r mem_irr. rewrite eqn_leq lt0n (contraNneq _ (irr1_neq0 s)); last first. by rewrite -(cfRes1 L) DthL cfunE => ->; rewrite !mul0r. rewrite -leq_sqr -leC_nat natrX -(ler_pmul2r (irr1_gt0 p0)) -mulrA mul1r. have ->: e%:R * 'chi_p0 1%g = 'Res[L] theta 1%g by rewrite DthL cfunE. rewrite cfRes1 -(ler_pmul2l (gt0CiG K L)) -cfInd1 // -/phi. rewrite -card_quotient // -card_Iirr_abelian // mulr_natl. rewrite ['Ind phi]cfun_sum_cfdot sum_cfunE (bigID (mem (codom mmLth))) /=. rewrite ler_paddr ?sumr_ge0 // => [i _|]. by rewrite char1_ge0 ?rpredZ_Cnat ?Cnat_cfdot_char ?cfInd_char ?irr_char. rewrite -big_uniq //= big_map big_filter -sumr_const ler_sum // => i _. rewrite cfunE -[in rhs in _ <= rhs](cfRes1 L) -cfdot_Res_r mmLthL cfRes1. by rewrite DthL cfdotZr rmorph_nat cfnorm_irr mulr1. constructor 2; exists e; first by exists p0. pose mu := (('chi_i / 'chi_j)%R %% L)%CF; pose U := cfker mu. have lin_mu: mu \is a linear_char by rewrite cfMod_lin_char ?rpred_div. have Uj := lin_char_unitr (linKbar j). have ltUK: U \proper K. rewrite /proper cfker_sub /U; have /irrP[k Dmu] := lin_char_irr lin_mu. rewrite Dmu subGcfker -irr_eq1 -Dmu cfMod_eq1 //. by rewrite (can2_eq (divrK Uj) (mulrK Uj)) mul1r (inj_eq irr_inj). suffices: theta \in 'CF(K, L). rewrite -cfnorm_Res_lerif // DthL cfnormZ !cfnorm_irr !mulr1 normr_nat. by rewrite -natrX eqC_nat => /eqP. have <-: gcore U G = L. apply: maxL; last by rewrite sub_gcore ?cfker_mod. by rewrite gcore_norm (sub_proper_trans (gcore_sub _ _)). apply/cfun_onP=> x; apply: contraNeq => nz_th_x. apply/bigcapP=> y /(subsetP IGtheta)/setIdP[nKy /eqP th_y]. apply: contraR nz_th_x; rewrite mem_conjg -{}th_y cfConjgE {nKy}//. move: {x y}(x ^ _) => x U'x; have [Kx | /cfun0-> //] := boolP (x \in K). have /eqP := congr1 (fun k => (('chi_j %% L)%CF^-1 * 'chi_k) x) eq_mm_ij. rewrite -rmorphV // !mmLthE !mulrA -!rmorphM mulVr //= rmorph1 !cfunE. rewrite (mulrC _^-1) -/mu -subr_eq0 -mulrBl cfun1E Kx mulf_eq0 => /orP[]//. rewrite mulrb subr_eq0 -(lin_char1 lin_mu) [_ == _](contraNF _ U'x) //. by rewrite /U cfkerEchar ?lin_charW // inE Kx. Qed. (* This is Isaacs, Corollary (6.19). *) Corollary cfRes_prime_irr_cases G N s p (chi := 'chi[G]_s) : N <| G -> #|G : N| = p -> prime p -> [\/ 'Res[N] chi \in irr N | exists2 c, injective c & 'Res[N] chi = \sum_(i < p) 'chi_(c i)]. Proof. move=> /andP[sNG nNG] iGN pr_p. have chiefGN: chief_factor G N G. apply/andP; split=> //; apply/maxgroupP. split=> [|M /andP[/andP[sMG ltMG] _] sNM]. by rewrite /proper sNG -indexg_gt1 iGN prime_gt1. apply/esym/eqP; rewrite eqEsubset sNM -indexg_eq1 /= eq_sym. rewrite -(eqn_pmul2l (indexg_gt0 G M)) muln1 Lagrange_index // iGN. by apply/eqP/prime_nt_dvdP; rewrite ?indexg_eq1 // -iGN indexgS. have abGbar: abelian (G / N). by rewrite cyclic_abelian ?prime_cyclic ?card_quotient ?iGN. have IGchi: G \subset 'I[chi] by apply: sub_inertia. have [] := invariant_chief_irr_cases chiefGN abGbar IGchi; first by left. case=> e _ /(congr1 (fun m => odd (logn p m)))/eqP/idPn[]. by rewrite lognX mul2n odd_double iGN logn_prime // eqxx. by rewrite iGN; right. Qed. (* This is Isaacs, Corollary (6.20). *) Corollary prime_invariant_irr_extendible G N s p : N <| G -> #|G : N| = p -> prime p -> G \subset 'I['chi_s] -> {t | 'Res[N, G] 'chi_t = 'chi_s}. Proof. move=> nsNG iGN pr_p IGchi. have [t sGt] := constt_cfInd_irr s (normal_sub nsNG); exists t. have [e DtN]: exists e, 'Res 'chi_t = e%:R *: 'chi_s. rewrite constt_Ind_Res in sGt. rewrite (Clifford_Res_sum_cfclass nsNG sGt); set e := '[_, _]. rewrite cfclass_invariant // big_seq1. by exists (truncC e); rewrite truncCK ?Cnat_cfdot_char ?cfRes_char ?irr_char. have [/irrWnorm/eqP | [c injc DtNc]] := cfRes_prime_irr_cases t nsNG iGN pr_p. rewrite DtN cfnormZ cfnorm_irr normr_nat mulr1 -natrX pnatr_eq1. by rewrite muln_eq1 andbb => /eqP->; rewrite scale1r. have nz_e: e != 0%N. have: 'Res[N] 'chi_t != 0 by rewrite cfRes_eq0 // ?irr_char ?irr_neq0. by rewrite DtN; apply: contraNneq => ->; rewrite scale0r. have [i s'ci]: exists i, c i != s. pose i0 := Ordinal (prime_gt0 pr_p); pose i1 := Ordinal (prime_gt1 pr_p). have [<- | ] := eqVneq (c i0) s; last by exists i0. by exists i1; rewrite (inj_eq injc). have /esym/eqP/idPn[] := congr1 (cfdotr 'chi_(c i)) DtNc; rewrite {1}DtN /=. rewrite cfdot_suml cfdotZl cfdot_irr mulrb ifN_eqC // mulr0. rewrite (bigD1 i) //= cfnorm_irr big1 ?addr0 ?oner_eq0 // => j i'j. by rewrite cfdot_irr mulrb ifN_eq ?(inj_eq injc). Qed. (* This is Isaacs, Lemma (6.24). *) Lemma extend_to_cfdet G N s c0 u : let theta := 'chi_s in let lambda := cfDet theta in let mu := 'chi_u in N <| G -> coprime #|G : N| (truncC (theta 1%g)) -> 'Res[N, G] 'chi_c0 = theta -> 'Res[N, G] mu = lambda -> exists2 c, 'Res 'chi_c = theta /\ cfDet 'chi_c = mu & forall c1, 'Res 'chi_c1 = theta -> cfDet 'chi_c1 = mu -> c1 = c. Proof. move=> theta lambda mu nsNG; set e := #|G : N|; set f := truncC _. set eta := 'chi_c0 => co_e_f etaNth muNlam; have [sNG nNG] := andP nsNG. have fE: f%:R = theta 1%g by rewrite truncCK ?Cnat_irr1. pose nu := cfDet eta; have lin_nu: nu \is a linear_char := cfDet_lin_char _. have nuNlam: 'Res nu = lambda by rewrite -cfDetRes ?irr_char ?etaNth. have lin_lam: lambda \is a linear_char := cfDet_lin_char _. have lin_mu: mu \is a linear_char. by have:= lin_lam; rewrite -muNlam; apply: cfRes_lin_lin; apply: irr_char. have [Unu Ulam] := (lin_char_unitr lin_nu, lin_char_unitr lin_lam). pose alpha := mu / nu. have alphaN_1: 'Res[N] alpha = 1 by rewrite rmorph_div //= muNlam nuNlam divrr. have lin_alpha: alpha \is a linear_char by apply: rpred_div. have alpha_e: alpha ^+ e = 1. have kerNalpha: N \subset cfker alpha. by rewrite -subsetIidl -cfker_Res ?lin_charW // alphaN_1 cfker_cfun1. apply/eqP; rewrite -(cfQuoK nsNG kerNalpha) -rmorphX cfMod_eq1 //. rewrite -dvdn_cforder /e -card_quotient //. by rewrite cforder_lin_char_dvdG ?cfQuo_lin_char. have det_alphaXeta b: cfDet (alpha ^+ b * eta) = alpha ^+ (b * f) * nu. by rewrite cfDet_mul_lin ?rpredX ?irr_char // -exprM -(cfRes1 N) etaNth. have [b bf_mod_e]: exists b, b * f = 1 %[mod e]. rewrite -(chinese_modl co_e_f 1 0) /chinese !mul0n addn0 !mul1n mulnC. by exists (egcdn f e).1. have alpha_bf: alpha ^+ (b * f) = alpha. by rewrite -(expr_mod _ alpha_e) bf_mod_e expr_mod. have /irrP[c Dc]: alpha ^+ b * eta \in irr G. by rewrite mul_lin_irr ?rpredX ?mem_irr. have chiN: 'Res 'chi_c = theta. by rewrite -Dc rmorphM rmorphX /= alphaN_1 expr1n mul1r. have det_chi: cfDet 'chi_c = mu by rewrite -Dc det_alphaXeta alpha_bf divrK. exists c => // c2 c2Nth det_c2_mu; apply: irr_inj. have [irrMc _ imMc _] := constt_Ind_ext nsNG chiN. have /codomP[s2 Dc2]: c2 \in codom (@mul_mod_Iirr G N c). by rewrite -imMc constt_Ind_Res c2Nth constt_irr ?inE. have{Dc2} Dc2: 'chi_c2 = ('chi_s2 %% N)%CF * 'chi_c. by rewrite Dc2 cfIirrE // mod_IirrE. have s2_lin: 'chi_s2 \is a linear_char. rewrite qualifE irr_char; apply/eqP/(mulIf (irr1_neq0 c)). rewrite mul1r -[in rhs in _ = rhs](cfRes1 N) chiN -c2Nth cfRes1. by rewrite Dc2 cfunE cfMod1. have s2Xf_1: 'chi_s2 ^+ f = 1. apply/(can_inj (cfModK nsNG))/(mulIr (lin_char_unitr lin_mu))/esym. rewrite rmorph1 rmorphX /= mul1r -{1}det_c2_mu Dc2 -det_chi. by rewrite cfDet_mul_lin ?cfMod_lin_char ?irr_char // -(cfRes1 N) chiN. suffices /eqP s2_1: 'chi_s2 == 1 by rewrite Dc2 s2_1 rmorph1 mul1r. rewrite -['chi_s2]expr1 -dvdn_cforder -(eqnP co_e_f) dvdn_gcd. by rewrite /e -card_quotient ?cforder_lin_char_dvdG //= dvdn_cforder s2Xf_1. Qed. (* This is Isaacs, Theorem (6.25). *) Theorem solvable_irr_extendible_from_det G N s (theta := 'chi[N]_s) : N <| G -> solvable (G / N) -> G \subset 'I[theta] -> coprime #|G : N| (truncC (theta 1%g)) -> [exists c, 'Res 'chi[G]_c == theta] = [exists u, 'Res 'chi[G]_u == cfDet theta]. Proof. set e := #|G : N|; set f := truncC _ => nsNG solG IGtheta co_e_f. apply/exists_eqP/exists_eqP=> [[c cNth] | [u uNdth]]. have /lin_char_irr/irrP[u Du] := cfDet_lin_char 'chi_c. by exists u; rewrite -Du -cfDetRes ?irr_char ?cNth. move: {2}e.+1 (ltnSn e) => m. elim: m => // m IHm in G u e nsNG solG IGtheta co_e_f uNdth *. rewrite ltnS => le_e; have [sNG nNG] := andP nsNG. have [<- | ltNG] := eqsVneq N G; first by exists s; rewrite cfRes_id. have [G0 maxG0 sNG0]: {G0 | maxnormal (gval G0) G G & N \subset G0}. by apply: maxgroup_exists; rewrite properEneq ltNG sNG. have [/andP[ltG0G nG0G] maxG0_P] := maxgroupP maxG0. set mu := 'chi_u in uNdth; have lin_mu: mu \is a linear_char. by rewrite qualifE irr_char -(cfRes1 N) uNdth /= lin_char1 ?cfDet_lin_char. have sG0G := proper_sub ltG0G; have nsNG0 := normalS sNG0 sG0G nsNG. have nsG0G: G0 <| G by apply/andP. have /lin_char_irr/irrP[u0 Du0] := cfRes_lin_char G0 lin_mu. have u0Ndth: 'Res 'chi_u0 = cfDet theta by rewrite -Du0 cfResRes. have IG0theta: G0 \subset 'I[theta]. by rewrite (subset_trans sG0G) // -IGtheta subsetIr. have coG0f: coprime #|G0 : N| f by rewrite (coprime_dvdl _ co_e_f) ?indexSg. have{m IHm le_e} [c0 c0Ns]: exists c0, 'Res 'chi[G0]_c0 = theta. have solG0: solvable (G0 / N) := solvableS (quotientS N sG0G) solG. apply: IHm nsNG0 solG0 IG0theta coG0f u0Ndth (leq_trans _ le_e). by rewrite -(ltn_pmul2l (cardG_gt0 N)) !Lagrange ?proper_card. have{c0 c0Ns} [c0 [c0Ns dc0_u0] Uc0] := extend_to_cfdet nsNG0 coG0f c0Ns u0Ndth. have IGc0: G \subset 'I['chi_c0]. apply/subsetP=> x Gx; rewrite inE (subsetP nG0G) //= -conjg_IirrE. apply/eqP; congr 'chi__; apply: Uc0; rewrite conjg_IirrE. by rewrite -(cfConjgRes _ nsG0G nsNG) // c0Ns inertiaJ ?(subsetP IGtheta). by rewrite cfDetConjg dc0_u0 -Du0 (cfConjgRes _ _ nsG0G) // cfConjg_id. have prG0G: prime #|G : G0|. have [h injh im_h] := third_isom sNG0 nsNG nsG0G. rewrite -card_quotient // -im_h // card_injm //. rewrite simple_sol_prime 1?quotient_sol //. by rewrite /simple -(injm_minnormal injh) // im_h // maxnormal_minnormal. have [t tG0c0] := prime_invariant_irr_extendible nsG0G (erefl _) prG0G IGc0. by exists t; rewrite /theta -c0Ns -tG0c0 cfResRes. Qed. (* This is Isaacs, Theorem (6.26). *) Theorem extend_linear_char_from_Sylow G N (lambda : 'CF(N)) : N <| G -> lambda \is a linear_char -> G \subset 'I[lambda] -> (forall p, p \in \pi('o(lambda)%CF) -> exists2 Hp : {group gT}, [/\ N \subset Hp, Hp \subset G & p.-Sylow(G / N) (Hp / N)%g] & exists u, 'Res 'chi[Hp]_u = lambda) -> exists u, 'Res[N, G] 'chi_u = lambda. Proof. set m := 'o(lambda)%CF => nsNG lam_lin IGlam p_ext_lam. have [sNG nNG] := andP nsNG; have linN := @cfRes_lin_lin _ _ N. wlog [p p_lam]: lambda @m lam_lin IGlam p_ext_lam / exists p : nat, \pi(m) =i (p : nat_pred). - move=> IHp; have [linG [cf [inj_cf _ lin_cf onto_cf]]] := lin_char_group N. case=> cf1 cfM cfX _ cf_order; have [lam cf_lam] := onto_cf _ lam_lin. pose mu p := cf lam.`_p; pose pi_m p := p \in \pi(m). have Dm: m = #[lam] by rewrite /m cfDet_order_lin // cf_lam cf_order. have Dlambda: lambda = \prod_(p < m.+1 | pi_m p) mu p. rewrite -(big_morph cf cfM cf1) big_mkcond cf_lam /pi_m Dm; congr (cf _). rewrite -{1}[lam]prod_constt big_mkord; apply: eq_bigr => p _. by case: ifPn => // p'lam; apply/constt1P; rewrite /p_elt p'natEpi. have lin_mu p: mu p \is a linear_char by rewrite /mu cfX -cf_lam rpredX. suffices /fin_all_exists [u uNlam] (p : 'I_m.+1): exists u, pi_m p -> 'Res[N, G] 'chi_u = mu p. - pose nu := \prod_(p < m.+1 | pi_m p) 'chi_(u p). have lin_nu: nu \is a linear_char. by apply: rpred_prod => p m_p; rewrite linN ?irr_char ?uNlam. have /irrP[u1 Dnu] := lin_char_irr lin_nu. by exists u1; rewrite Dlambda -Dnu rmorph_prod; apply: eq_bigr. have [m_p | _] := boolP (pi_m p); last by exists 0. have o_mu: \pi('o(mu p)%CF) =i (p : nat_pred). rewrite cfDet_order_lin // cf_order orderE /=. have [|pr_p _ [k ->]] := pgroup_pdiv (p_elt_constt p lam). by rewrite cycle_eq1 (sameP eqP constt1P) /p_elt p'natEpi // negbK -Dm. by move=> q; rewrite pi_of_exp // pi_of_prime. have IGmu: G \subset 'I[mu p]. rewrite (subset_trans IGlam) // /mu cfX -cf_lam. elim: (chinese _ _ _ _) => [|k IHk]; first by rewrite inertia1 norm_inertia. by rewrite exprS (subset_trans _ (inertia_mul _ _)) // subsetIidl. have [q||u] := IHp _ (lin_mu p) IGmu; [ | by exists p | by exists u]. rewrite o_mu => /eqnP-> {q}. have [Hp sylHp [u uNlam]] := p_ext_lam p m_p; exists Hp => //. rewrite /mu cfX -cf_lam -uNlam -rmorphX /=; set nu := _ ^+ _. have /lin_char_irr/irrP[v ->]: nu \is a linear_char; last by exists v. by rewrite rpredX // linN ?irr_char ?uNlam. have pi_m_p: p \in \pi(m) by rewrite p_lam !inE. have [pr_p mgt0]: prime p /\ (m > 0)%N. by have:= pi_m_p; rewrite mem_primes => /and3P[]. have p_m: p.-nat m by rewrite -(eq_pnat _ p_lam) pnat_pi. have{p_ext_lam} [H [sNH sHG sylHbar] [v vNlam]] := p_ext_lam p pi_m_p. have co_p_GH: coprime p #|G : H|. rewrite -(index_quotient_eq _ sHG nNG) ?subIset ?sNH ?orbT //. by rewrite (pnat_coprime (pnat_id pr_p)) //; have [] := and3P sylHbar. have lin_v: 'chi_v \is a linear_char by rewrite linN ?irr_char ?vNlam. pose nuG := 'Ind[G] 'chi_v. have [c vGc co_p_f]: exists2 c, c \in irr_constt nuG & ~~ (p %| 'chi_c 1%g)%C. apply/exists_inP; rewrite -negb_forall_in. apply: contraL co_p_GH => /forall_inP p_dv_v1. rewrite prime_coprime // negbK -dvdC_nat -[rhs in (_ %| rhs)%C]mulr1. rewrite -(lin_char1 lin_v) -cfInd1 // ['Ind _]cfun_sum_constt /=. rewrite sum_cfunE rpred_sum // => i /p_dv_v1 p_dv_chi1i. rewrite cfunE dvdC_mull // rpred_Cnat //. by rewrite Cnat_cfdot_char ?cfInd_char ?irr_char. pose f := truncC ('chi_c 1%g); pose b := (egcdn f m).1. have fK: f%:R = 'chi_c 1%g by rewrite truncCK ?Cnat_irr1. have fb_mod_m: f * b = 1 %[mod m]. have co_m_f: coprime m f. by rewrite (pnat_coprime p_m) ?p'natE // -dvdC_nat CdivE fK. by rewrite -(chinese_modl co_m_f 1 0) /chinese !mul0n addn0 mul1n. have /irrP[s Dlam] := lin_char_irr lam_lin. have cHv: v \in irr_constt ('Res[H] 'chi_c) by rewrite -constt_Ind_Res. have{cHv} cNs: s \in irr_constt ('Res[N] 'chi_c). rewrite -(cfResRes _ sNH) ?(constt_Res_trans _ cHv) ?cfRes_char ?irr_char //. by rewrite vNlam Dlam constt_irr !inE. have DcN: 'Res[N] 'chi_c = lambda *+ f. have:= Clifford_Res_sum_cfclass nsNG cNs. rewrite cfclass_invariant -Dlam // big_seq1 Dlam => DcN. have:= cfRes1 N 'chi_c; rewrite DcN cfunE -Dlam lin_char1 // mulr1 => ->. by rewrite -scaler_nat fK. have /lin_char_irr/irrP[d Dd]: cfDet 'chi_c ^+ b \is a linear_char. by rewrite rpredX // cfDet_lin_char. exists d; rewrite -{}Dd rmorphX /= -cfDetRes ?irr_char // DcN. rewrite cfDetMn ?lin_charW // -exprM cfDet_id //. rewrite -(expr_mod _ (exp_cforder _)) -cfDet_order_lin // -/m. by rewrite fb_mod_m /m cfDet_order_lin // expr_mod ?exp_cforder. Qed. (* This is Isaacs, Corollary (6.27). *) Corollary extend_coprime_linear_char G N (lambda : 'CF(N)) : N <| G -> lambda \is a linear_char -> G \subset 'I[lambda] -> coprime #|G : N| 'o(lambda)%CF -> exists u, [/\ 'Res 'chi[G]_u = lambda, 'o('chi_u)%CF = 'o(lambda)%CF & forall v, 'Res 'chi_v = lambda -> coprime #|G : N| 'o('chi_v)%CF -> v = u]. Proof. set e := #|G : N| => nsNG lam_lin IGlam co_e_lam; have [sNG nNG] := andP nsNG. have [p lam_p | v vNlam] := extend_linear_char_from_Sylow nsNG lam_lin IGlam. exists N; last first. by have /irrP[u ->] := lin_char_irr lam_lin; exists u; rewrite cfRes_id. split=> //; rewrite trivg_quotient /pHall sub1G pgroup1 indexg1. rewrite card_quotient //= -/e (pi'_p'nat _ lam_p) //. rewrite -coprime_pi' ?indexg_gt0 1?coprime_sym //. by have:= lam_p; rewrite mem_primes => /and3P[]. set nu := 'chi_v in vNlam. have lin_nu: nu \is a linear_char. by rewrite (@cfRes_lin_lin _ _ N) ?vNlam ?irr_char. have [b be_mod_lam]: exists b, b * e = 1 %[mod 'o(lambda)%CF]. rewrite -(chinese_modr co_e_lam 0 1) /chinese !mul0n !mul1n mulnC. by set b := _.1; exists b. have /irrP[u Du]: nu ^+ (b * e) \in irr G by rewrite lin_char_irr ?rpredX. exists u; set mu := 'chi_u in Du *. have uNlam: 'Res mu = lambda. rewrite cfDet_order_lin // in be_mod_lam. rewrite -Du rmorphX /= vNlam -(expr_mod _ (exp_cforder _)) //. by rewrite be_mod_lam expr_mod ?exp_cforder. have lin_mu: mu \is a linear_char by rewrite -Du rpredX. have o_mu: ('o(mu) = 'o(lambda))%CF. have dv_o_lam_mu: 'o(lambda)%CF %| 'o(mu)%CF. by rewrite !cfDet_order_lin // -uNlam cforder_Res. have kerNnu_olam: N \subset cfker (nu ^+ 'o(lambda)%CF). rewrite -subsetIidl -cfker_Res ?rpredX ?irr_char //. by rewrite rmorphX /= vNlam cfDet_order_lin // exp_cforder cfker_cfun1. apply/eqP; rewrite eqn_dvd dv_o_lam_mu andbT cfDet_order_lin //. rewrite dvdn_cforder -Du exprAC -dvdn_cforder dvdn_mull //. rewrite -(cfQuoK nsNG kerNnu_olam) cforder_mod // /e -card_quotient //. by rewrite cforder_lin_char_dvdG ?cfQuo_lin_char ?rpredX. split=> // t tNlam co_e_t. have lin_t: 'chi_t \is a linear_char. by rewrite (@cfRes_lin_lin _ _ N) ?tNlam ?irr_char. have Ut := lin_char_unitr lin_t. have kerN_mu_t: N \subset cfker (mu / 'chi_t)%R. rewrite -subsetIidl -cfker_Res ?lin_charW ?rpred_div ?rmorph_div //. by rewrite /= uNlam tNlam divrr ?lin_char_unitr ?cfker_cfun1. have co_e_mu_t: coprime e #[(mu / 'chi_t)%R]%CF. suffices dv_o_mu_t: #[(mu / 'chi_t)%R]%CF %| 'o(mu)%CF * 'o('chi_t)%CF. by rewrite (coprime_dvdr dv_o_mu_t) // coprime_mulr o_mu co_e_lam. rewrite !cfDet_order_lin //; apply/dvdn_cforderP=> x Gx. rewrite invr_lin_char // !cfunE exprMn -rmorphX {2}mulnC. by rewrite !(dvdn_cforderP _) ?conjC1 ?mulr1 // dvdn_mulr. have /eqP mu_t_1: mu / 'chi_t == 1. rewrite -(dvdn_cforder (_ / _)%R 1) -(eqnP co_e_mu_t) dvdn_gcd dvdnn andbT. rewrite -(cfQuoK nsNG kerN_mu_t) cforder_mod // /e -card_quotient //. by rewrite cforder_lin_char_dvdG ?cfQuo_lin_char ?rpred_div. by apply: irr_inj; rewrite -['chi_t]mul1r -mu_t_1 divrK. Qed. (* This is Isaacs, Corollary (6.28). *) Corollary extend_solvable_coprime_irr G N t (theta := 'chi[N]_t) : N <| G -> solvable (G / N) -> G \subset 'I[theta] -> coprime #|G : N| ('o(theta)%CF * truncC (theta 1%g)) -> exists c, [/\ 'Res 'chi[G]_c = theta, 'o('chi_c)%CF = 'o(theta)%CF & forall d, 'Res 'chi_d = theta -> coprime #|G : N| 'o('chi_d)%CF -> d = c]. Proof. set e := #|G : N|; set f := truncC _ => nsNG solG IGtheta. rewrite coprime_mulr => /andP[co_e_th co_e_f]. have [sNG nNG] := andP nsNG; pose lambda := cfDet theta. have lin_lam: lambda \is a linear_char := cfDet_lin_char theta. have IGlam: G \subset 'I[lambda]. apply/subsetP=> y /(subsetP IGtheta)/setIdP[nNy /eqP th_y]. by rewrite inE nNy /= -cfDetConjg th_y. have co_e_lam: coprime e 'o(lambda)%CF by rewrite cfDet_order_lin. have [//|u [uNlam o_u Uu]] := extend_coprime_linear_char nsNG lin_lam IGlam. have /exists_eqP[c cNth]: [exists c, 'Res 'chi[G]_c == theta]. rewrite solvable_irr_extendible_from_det //. by apply/exists_eqP; exists u. have{c cNth} [c [cNth det_c] Uc] := extend_to_cfdet nsNG co_e_f cNth uNlam. have lin_u: 'chi_u \is a linear_char by rewrite -det_c cfDet_lin_char. exists c; split=> // [|c0 c0Nth co_e_c0]. by rewrite !cfDet_order_lin // -det_c in o_u. have lin_u0: cfDet 'chi_c0 \is a linear_char := cfDet_lin_char 'chi_c0. have /irrP[u0 Du0] := lin_char_irr lin_u0. have co_e_u0: coprime e 'o('chi_u0)%CF by rewrite -Du0 cfDet_order_lin. have eq_u0u: u0 = u by apply: Uu; rewrite // -Du0 -cfDetRes ?irr_char ?c0Nth. by apply: Uc; rewrite // Du0 eq_u0u. Qed. End ExtendInvariantIrr. Section Frobenius. Variables (gT : finGroupType) (G K : {group gT}). (* Because he only defines Frobenius groups in chapter 7, Isaacs does not *) (* state these theorems using the Frobenius property. *) Hypothesis frobGK : [Frobenius G with kernel K]. (* This is Isaacs, Theorem 6.34(a1). *) Theorem inertia_Frobenius_ker i : i != 0 -> 'I_G['chi[K]_i] = K. Proof. have [_ _ nsKG regK] := Frobenius_kerP frobGK; have [sKG nKG] := andP nsKG. move=> nzi; apply/eqP; rewrite eqEsubset sub_Inertia // andbT. apply/subsetP=> x /setIP[Gx /setIdP[nKx /eqP x_stab_i]]. have actIirrK: is_action G (@conjg_Iirr _ K). split=> [y j k eq_jk | j y z Gy Gz]. by apply/irr_inj/(can_inj (cfConjgK y)); rewrite -!conjg_IirrE eq_jk. by apply: irr_inj; rewrite !conjg_IirrE (cfConjgM _ nsKG). pose ito := Action actIirrK; pose cto := ('Js \ (subsetT G))%act. have acts_Js : [acts G, on classes K | 'Js]. apply/subsetP=> y Gy; have nKy := subsetP nKG y Gy. rewrite !inE; apply/subsetP=> _ /imsetP[z Gz ->]; rewrite !inE /=. rewrite -class_rcoset norm_rlcoset // class_lcoset. by apply: mem_imset; rewrite memJ_norm. have acts_cto : [acts G, on classes K | cto] by rewrite astabs_ract subsetIidl. pose m := #|'Fix_(classes K | cto)[x]|. have def_m: #|'Fix_ito[x]| = m. apply: card_afix_irr_classes => // j y _ Ky /imsetP[_ /imsetP[z Kz ->] ->]. by rewrite conjg_IirrE cfConjgEJ // cfunJ. have: (m != 1)%N. rewrite -def_m (cardD1 (0 : Iirr K)) (cardD1 i) !(inE, sub1set) /=. by rewrite conjg_Iirr0 nzi eqxx -(inj_eq irr_inj) conjg_IirrE x_stab_i eqxx. apply: contraR => notKx; apply/cards1P; exists 1%g; apply/esym/eqP. rewrite eqEsubset !(sub1set, inE) classes1 /= conjs1g eqxx /=. apply/subsetP=> _ /setIP[/imsetP[y Ky ->] /afix1P /= cyKx]. have /imsetP[z Kz def_yx]: y ^ x \in y ^: K. by rewrite -cyKx; apply: mem_imset; exact: class_refl. rewrite inE classG_eq1; apply: contraR notKx => nty. rewrite -(groupMr x (groupVr Kz)). apply: (subsetP (regK y _)); first exact/setD1P. rewrite !inE groupMl // groupV (subsetP sKG) //=. by rewrite conjg_set1 conjgM def_yx conjgK. Qed. (* This is Isaacs, Theorem 6.34(a2) *) Theorem irr_induced_Frobenius_ker i : i != 0 -> 'Ind[G, K] 'chi_i \in irr G. Proof. move/inertia_Frobenius_ker/group_inj=> defK. have [_ _ nsKG _] := Frobenius_kerP frobGK. have [] := constt_Inertia_bijection i nsKG; rewrite defK cfInd_id => -> //. by rewrite constt_irr !inE. Qed. (* This is Isaacs, Theorem 6.34(b) *) Theorem Frobenius_Ind_irrP j : reflect (exists2 i, i != 0 & 'chi_j = 'Ind[G, K] 'chi_i) (~~ (K \subset cfker 'chi_j)). Proof. have [_ _ nsKG _] := Frobenius_kerP frobGK; have [sKG nKG] := andP nsKG. apply: (iffP idP) => [not_chijK1 | [i nzi ->]]; last first. by rewrite cfker_Ind_irr ?sub_gcore // subGcfker. have /neq0_has_constt[i chijKi]: 'Res[K] 'chi_j != 0 by exact: Res_irr_neq0. have nz_i: i != 0. by apply: contraNneq not_chijK1 => i0; rewrite constt0_Res_cfker // -i0. have /irrP[k def_chik] := irr_induced_Frobenius_ker nz_i. have: '['chi_j, 'chi_k] != 0 by rewrite -def_chik -cfdot_Res_l. by rewrite cfdot_irr pnatr_eq0; case: (j =P k) => // ->; exists i. Qed. End Frobenius. mathcomp-1.5/theories/galois.v0000644000175000017500000021136712307636117015462 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div choice fintype. Require Import tuple finfun bigop ssralg poly polydiv. Require Import finset fingroup morphism quotient perm action zmodp cyclic. Require Import matrix mxalgebra vector falgebra fieldext separable. (******************************************************************************) (* This file develops some basic Galois field theory, defining: *) (* splittingFieldFor K p E <-> E is the smallest field over K that splits p *) (* into linear factors. *) (* kHom K E f <=> f : 'End(L) is a ring morphism on E and fixes K. *) (* kAut K E f <=> f : 'End(L) is a kHom K E and f @: E == E. *) (* kHomExtend E f x y == a kHom K <> that extends f and maps x to y, *) (* when f \is a kHom K E and root (minPoly E x) y. *) (* *) (* splittingFieldFor K p E <-> E is splitting field for p over K: p splits in *) (* E and its roots generate E from K. *) (* splittingFieldType F == the interface type of splitting field extensions *) (* of F, that is, extensions generated by all the *) (* algebraic roots of some polynomial, or, *) (* equivalently, normal field extensions of F. *) (* SplittingField.axiom F L == the axiom stating that L is a splitting field. *) (* SplittingFieldType F L FsplitL == packs a proof FsplitL of the splitting *) (* field axiom for L into a splitingFieldType F, *) (* provided L has a fieldExtType F structure. *) (* [splittingFieldType F of L] == a clone of the canonical splittingFieldType *) (* structure for L. *) (*[splittingFieldType F of L for M] == an L-clone of the canonical *) (* splittingFieldType structure on M. *) (* *) (* gal_of E == the group_type of automorphisms of E over the *) (* base field F. *) (* 'Gal(E / K) == the group of automorphisms of E that fix K. *) (* fixedField s == the field fixed by the set of automorphisms s. *) (* fixedField set0 = E when set0 : {set: gal_of E} *) (* normalField K E <=> E is invariant for every 'Gal(L / K) for every L. *) (* galois K E <=> E is a normal and separable field extension of K. *) (* galTrace K E a == \sum_(f in 'Gal(E / K)) (f a). *) (* galNorm K E a == \prod_(f in 'Gal(E / K)) (f a). *) (* *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Reserved Notation "''Gal' ( A / B )" (at level 8, A at level 35, format "''Gal' ( A / B )"). Import GroupScope GRing.Theory. Local Open Scope ring_scope. Section SplittingFieldFor. Variables (F : fieldType) (L : fieldExtType F). Definition splittingFieldFor (U : {vspace L}) (p : {poly L}) (V : {vspace L}) := exists2 rs, p %= \prod_(z <- rs) ('X - z%:P) & <>%VS = V. Lemma splittingFieldForS (K M E : {subfield L}) p : (K <= M)%VS -> (M <= E)%VS -> splittingFieldFor K p E -> splittingFieldFor M p E. Proof. move=> sKM sKE [rs Dp genL]; exists rs => //; apply/eqP. rewrite eqEsubv -[in X in _ && (X <= _)%VS]genL adjoin_seqSl // andbT. by apply/Fadjoin_seqP; split; rewrite // -genL; apply: seqv_sub_adjoin. Qed. End SplittingFieldFor. Section kHom. Variables (F : fieldType) (L : fieldExtType F). Implicit Types (U V : {vspace L}) (K E : {subfield L}) (f g : 'End(L)). Definition kHom U V f := ahom_in V f && (U <= fixedSpace f)%VS. Lemma kHomP {K V f} : reflect [/\ {in V &, forall x y, f (x * y) = f x * f y} & {in K, forall x, f x = x}] (kHom K V f). Proof. apply: (iffP andP) => [[/ahom_inP[fM _] /subvP idKf] | [fM idKf]]. by split=> // x /idKf/fixedSpaceP. split; last by apply/subvP=> x /idKf/fixedSpaceP. by apply/ahom_inP; split=> //; rewrite idKf ?mem1v. Qed. Lemma kAHomP {U V} {f : 'AEnd(L)} : reflect {in U, forall x, f x = x} (kHom U V f). Proof. by rewrite /kHom ahomWin; apply: fixedSpacesP. Qed. Lemma kHom1 U V : kHom U V \1. Proof. by apply/kAHomP => u _; rewrite lfunE. Qed. Lemma k1HomE V f : kHom 1 V f = ahom_in V f. Proof. by apply: andb_idr => /ahom_inP[_ f1]; apply/fixedSpaceP. Qed. Lemma kHom_lrmorphism (f : 'End(L)) : reflect (lrmorphism f) (kHom 1 {:L} f). Proof. by rewrite k1HomE; apply: ahomP. Qed. Lemma k1AHom V (f : 'AEnd(L)) : kHom 1 V f. Proof. by rewrite k1HomE ahomWin. Qed. Lemma kHom_poly_id K E f p : kHom K E f -> p \is a polyOver K -> map_poly f p = p. Proof. by case/kHomP=> _ idKf /polyOverP Kp; apply/polyP=> i; rewrite coef_map /= idKf. Qed. Lemma kHomSl U1 U2 V f : (U1 <= U2)%VS -> kHom U2 V f -> kHom U1 V f. Proof. by rewrite /kHom => sU12 /andP[-> /(subv_trans sU12)]. Qed. Lemma kHomSr K V1 V2 f : (V1 <= V2)%VS -> kHom K V2 f -> kHom K V1 f. Proof. by move/subvP=> sV12 /kHomP[/(sub_in2 sV12)fM idKf]; apply/kHomP. Qed. Lemma kHomS K1 K2 V1 V2 f : (K1 <= K2)%VS -> (V1 <= V2)%VS -> kHom K2 V2 f -> kHom K1 V1 f. Proof. by move=> sK12 sV12 /(kHomSl sK12)/(kHomSr sV12). Qed. Lemma kHom_eq K E f g : (K <= E)%VS -> {in E, f =1 g} -> kHom K E f = kHom K E g. Proof. move/subvP=> sKE eq_fg; wlog suffices: f g eq_fg / kHom K E f -> kHom K E g. by move=> IH; apply/idP/idP; apply: IH => x /eq_fg. case/kHomP=> fM idKf; apply/kHomP. by split=> [x y Ex Ey | x Kx]; rewrite -!eq_fg ?fM ?rpredM // ?idKf ?sKE. Qed. Lemma kHom_inv K E f : kHom K E f -> {in E, {morph f : x / x^-1}}. Proof. case/kHomP=> fM idKf x Ex. case (eqVneq x 0) => [-> | nz_x]; first by rewrite linear0 invr0 linear0. have fxV: f x * f x^-1 = 1 by rewrite -fM ?rpredV ?divff // idKf ?mem1v. have Ufx: f x \is a GRing.unit by apply/unitrPr; exists (f x^-1). by apply: (mulrI Ufx); rewrite divrr. Qed. Lemma kHom_dim K E f : kHom K E f -> \dim (f @: E) = \dim E. Proof. move=> homKf; have [fM idKf] := kHomP homKf. apply/limg_dim_eq/eqP; rewrite -subv0; apply/subvP=> v. rewrite memv_cap memv0 memv_ker => /andP[Ev]; apply: contraLR => nz_v. by rewrite -unitfE unitrE -(kHom_inv homKf) // -fM ?rpredV ?divff ?idKf ?mem1v. Qed. Lemma kHom_is_rmorphism K E f : kHom K E f -> rmorphism (f \o vsval : subvs_of E -> L). Proof. case/kHomP=> fM idKf; split=> [a b|]; first exact: raddfB. by split=> [a b|] /=; [rewrite /= fM ?subvsP | rewrite algid1 idKf // mem1v]. Qed. Definition kHom_rmorphism K E f homKEf := RMorphism (@kHom_is_rmorphism K E f homKEf). Lemma kHom_horner K E f p x : kHom K E f -> p \is a polyOver E -> x \in E -> f p.[x] = (map_poly f p).[f x]. Proof. move=> homKf /polyOver_subvs[{p}p -> Ex]; pose fRM := kHom_rmorphism homKf. by rewrite (horner_map _ _ (Subvs Ex)) -[f _](horner_map fRM) map_poly_comp. Qed. Lemma kHom_root K E f p x : kHom K E f -> p \is a polyOver E -> x \in E -> root p x -> root (map_poly f p) (f x). Proof. by move/kHom_horner=> homKf Ep Ex /rootP px0; rewrite /root -homKf ?px0 ?raddf0. Qed. Lemma kHom_root_id K E f p x : (K <= E)%VS -> kHom K E f -> p \is a polyOver K -> x \in E -> root p x -> root p (f x). Proof. move=> sKE homKf Kp Ex /(kHom_root homKf (polyOverSv sKE Kp) Ex). by rewrite (kHom_poly_id homKf). Qed. Section kHomExtend. Variables (K E : {subfield L}) (f : 'End(L)) (x y : L). Fact kHomExtend_subproof : linear (fun z => (map_poly f (Fadjoin_poly E x z)).[y]). Proof. move=> k a b; rewrite linearP /= raddfD hornerE; congr (_ + _). rewrite -[rhs in _ = rhs]mulr_algl -hornerZ /=; congr _.[_]. by apply/polyP => i; rewrite !(coefZ, coef_map) /= !mulr_algl linearZ. Qed. Definition kHomExtend := linfun (Linear kHomExtend_subproof). Lemma kHomExtendE z : kHomExtend z = (map_poly f (Fadjoin_poly E x z)).[y]. Proof. by rewrite lfunE. Qed. Hypotheses (sKE : (K <= E)%VS) (homKf : kHom K E f). Local Notation Px := (minPoly E x). Hypothesis fPx_y_0 : root (map_poly f Px) y. Lemma kHomExtend_id z : z \in E -> kHomExtend z = f z. Proof. by move=> Ez; rewrite kHomExtendE Fadjoin_polyC ?map_polyC ?hornerC. Qed. Lemma kHomExtend_val : kHomExtend x = y. Proof. have fX: map_poly f 'X = 'X by rewrite (kHom_poly_id homKf) ?polyOverX. have [Ex | E'x] := boolP (x \in E); last first. by rewrite kHomExtendE Fadjoin_polyX // fX hornerX. have:= fPx_y_0; rewrite (minPoly_XsubC Ex) raddfB /= map_polyC fX root_XsubC /=. by rewrite (kHomExtend_id Ex) => /eqP->. Qed. Lemma kHomExtend_poly p : p \in polyOver E -> kHomExtend p.[x] = (map_poly f p).[y]. Proof. move=> Ep; rewrite kHomExtendE (Fadjoin_poly_mod x) //. rewrite (divp_eq (map_poly f p) (map_poly f Px)). rewrite !hornerE (rootP fPx_y_0) mulr0 add0r. have [p1 ->] := polyOver_subvs Ep. have [Px1 ->] := polyOver_subvs (minPolyOver E x). by rewrite -map_modp -!map_poly_comp (map_modp (kHom_rmorphism homKf)). Qed. Lemma kHomExtendP : kHom K <> kHomExtend. Proof. have [fM idKf] := kHomP homKf. apply/kHomP; split=> [|z Kz]; last by rewrite kHomExtend_id ?(subvP sKE) ?idKf. move=> _ _ /Fadjoin_polyP[p Ep ->] /Fadjoin_polyP[q Eq ->]. rewrite -hornerM !kHomExtend_poly ?rpredM // -hornerM; congr _.[_]. apply/polyP=> i; rewrite coef_map !coefM /= linear_sum /=. by apply: eq_bigr => j _; rewrite !coef_map /= fM ?(polyOverP _). Qed. End kHomExtend. Definition kAut U V f := kHom U V f && (f @: V == V)%VS. Lemma kAutE K E f : kAut K E f = kHom K E f && (f @: E <= E)%VS. Proof. apply/andP/andP=> [[-> /eqP->] // | [homKf EfE]]. by rewrite eqEdim EfE /= (kHom_dim homKf). Qed. Lemma kAutS U1 U2 V f : (U1 <= U2)%VS -> kAut U2 V f -> kAut U1 V f. Proof. by move=> sU12 /andP[/(kHomSl sU12)homU1f EfE]; apply/andP. Qed. Lemma kHom_kAut_sub K E f : kAut K E f -> kHom K E f. Proof. by case/andP. Qed. Lemma kAut_eq K E (f g : 'End(L)) : (K <= E)%VS -> {in E, f =1 g} -> kAut K E f = kAut K E g. Proof. by move=> sKE eq_fg; rewrite !kAutE (kHom_eq sKE eq_fg) (eq_in_limg eq_fg). Qed. Lemma kAutfE K f : kAut K {:L} f = kHom K {:L} f. Proof. by rewrite kAutE subvf andbT. Qed. Lemma kAut1E E (f : 'AEnd(L)) : kAut 1 E f = (f @: E <= E)%VS. Proof. by rewrite kAutE k1AHom. Qed. Lemma kAutf_lker0 K f : kHom K {:L} f -> lker f == 0%VS. Proof. move/(kHomSl (sub1v _))/kHom_lrmorphism=> fM. by apply/lker0P; apply: (fmorph_inj (RMorphism fM)). Qed. Lemma inv_kHomf K f : kHom K {:L} f -> kHom K {:L} f^-1. Proof. move=> homKf; have [[fM idKf] kerf0] := (kHomP homKf, kAutf_lker0 homKf). have f1K: cancel f^-1%VF f by apply: lker0_lfunVK. apply/kHomP; split=> [x y _ _ | x Kx]; apply: (lker0P kerf0). by rewrite fM ?memvf ?{1}f1K. by rewrite f1K idKf. Qed. Lemma inv_is_ahom (f : 'AEnd(L)) : ahom_in {:L} f^-1. Proof. have /ahomP/kHom_lrmorphism hom1f := valP f. exact/ahomP/kHom_lrmorphism/inv_kHomf. Qed. Canonical inv_ahom (f : 'AEnd(L)) : 'AEnd(L) := AHom (inv_is_ahom f). Notation "f ^-1" := (inv_ahom f) : lrfun_scope. Lemma comp_kHom_img K E f g : kHom K (g @: E) f -> kHom K E g -> kHom K E (f \o g). Proof. move=> /kHomP[fM idKf] /kHomP[gM idKg]; apply/kHomP; split=> [x y Ex Ey | x Kx]. by rewrite !lfunE /= gM // fM ?memv_img. by rewrite lfunE /= idKg ?idKf. Qed. Lemma comp_kHom K E f g : kHom K {:L} f -> kHom K E g -> kHom K E (f \o g). Proof. by move/(kHomSr (subvf (g @: E))); apply: comp_kHom_img. Qed. Lemma kHom_extends K E f p U : (K <= E)%VS -> kHom K E f -> p \is a polyOver K -> splittingFieldFor E p U -> {g | kHom K U g & {in E, f =1 g}}. Proof. move=> sKE homEf Kp /sig2_eqW[rs Dp <-{U}]. set r := rs; have rs_r: all (mem rs) r by apply/allP. elim: r rs_r => [_|z r IHr /=/andP[rs_z rs_r]] /= in E f sKE homEf *. by exists f; rewrite ?Fadjoin_nil. set Ez := <>%AS; pose fpEz := map_poly f (minPoly E z). suffices{IHr} /sigW[y fpEz_y]: exists y, root fpEz y. have homEz_fz: kHom K Ez (kHomExtend E f z y) by apply: kHomExtendP. have sKEz: (K <= Ez)%VS := subv_trans sKE (subv_adjoin E z). have [g homGg Dg] := IHr rs_r _ _ sKEz homEz_fz. exists g => [|x Ex]; first by rewrite adjoin_cons. by rewrite -Dg ?subvP_adjoin // kHomExtend_id. have [m DfpEz]: {m | fpEz %= \prod_(w <- mask m rs) ('X - w%:P)}. apply: dvdp_prod_XsubC; rewrite -(eqp_dvdr _ Dp) -(kHom_poly_id homEf Kp). have /polyOver_subvs[q Dq] := polyOverSv sKE Kp. have /polyOver_subvs[qz Dqz] := minPolyOver E z. rewrite /fpEz Dq Dqz -2?{1}map_poly_comp (dvdp_map (kHom_rmorphism homEf)). rewrite -(dvdp_map [rmorphism of @vsval _ _ E]) -Dqz -Dq. by rewrite minPoly_dvdp ?(polyOverSv sKE) // (eqp_root Dp) root_prod_XsubC. exists (mask m rs)`_0; rewrite (eqp_root DfpEz) root_prod_XsubC mem_nth //. rewrite -ltnS -(size_prod_XsubC _ id) -(eqp_size DfpEz). rewrite size_poly_eq -?lead_coefE ?size_minPoly // (monicP (monic_minPoly E z)). by have [_ idKf] := kHomP homEf; rewrite idKf ?mem1v ?oner_eq0. Qed. End kHom. Notation "f ^-1" := (inv_ahom f) : lrfun_scope. Implicit Arguments kHomP [F L K V f]. Implicit Arguments kAHomP [F L U V f]. Implicit Arguments kHom_lrmorphism [F L f]. Module SplittingField. Import GRing. Section ClassDef. Variable F : fieldType. Definition axiom (L : fieldExtType F) := exists2 p : {poly L}, p \is a polyOver 1%VS & splittingFieldFor 1 p {:L}. Record class_of (L : Type) : Type := Class {base : FieldExt.class_of F L; _ : axiom (FieldExt.Pack _ base L)}. Local Coercion base : class_of >-> FieldExt.class_of. Structure type (phF : phant F) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variable (phF : phant F) (T : Type) (cT : type phF). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition clone c of phant_id class c := @Pack phF T c T. Definition pack b0 (ax0 : axiom (@FieldExt.Pack F (Phant F) T b0 T)) := fun bT b & phant_id (@FieldExt.class F phF bT) b => fun ax & phant_id ax0 ax => Pack (Phant F) (@Class T b ax) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. Definition unitRingType := @UnitRing.Pack cT xclass xT. Definition comRingType := @ComRing.Pack cT xclass xT. Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @IntegralDomain.Pack cT xclass xT. Definition fieldType := @Field.Pack cT xclass xT. Definition lmodType := @Lmodule.Pack F phF cT xclass xT. Definition lalgType := @Lalgebra.Pack F phF cT xclass xT. Definition algType := @Algebra.Pack F phF cT xclass xT. Definition unitAlgType := @UnitAlgebra.Pack F phF cT xclass xT. Definition vectType := @Vector.Pack F phF cT xclass xT. Definition FalgType := @Falgebra.Pack F phF cT xclass xT. Definition fieldExtType := @FieldExt.Pack F phF cT xclass xT. End ClassDef. Module Exports. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion base : class_of >-> FieldExt.class_of. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Coercion unitRingType : type >-> UnitRing.type. Canonical unitRingType. Coercion comRingType : type >-> ComRing.type. Canonical comRingType. Coercion comUnitRingType : type >-> ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> IntegralDomain.type. Canonical idomainType. Coercion fieldType : type >-> Field.type. Canonical fieldType. Coercion lmodType : type >-> Lmodule.type. Canonical lmodType. Coercion lalgType : type >-> Lalgebra.type. Canonical lalgType. Coercion algType : type >-> Algebra.type. Canonical algType. Coercion unitAlgType : type >-> UnitAlgebra.type. Canonical unitAlgType. Coercion vectType : type >-> Vector.type. Canonical vectType. Coercion FalgType : type >-> Falgebra.type. Canonical FalgType. Coercion fieldExtType : type >-> FieldExt.type. Canonical fieldExtType. Notation splittingFieldType F := (type (Phant F)). Notation SplittingFieldType F L ax := (@pack _ (Phant F) L _ ax _ _ id _ id). Notation "[ 'splittingFieldType' F 'of' L 'for' K ]" := (@clone _ (Phant F) L K _ idfun) (at level 0, format "[ 'splittingFieldType' F 'of' L 'for' K ]") : form_scope. Notation "[ 'splittingFieldType' F 'of' L ]" := (@clone _ (Phant F) L _ _ id) (at level 0, format "[ 'splittingFieldType' F 'of' L ]") : form_scope. End Exports. End SplittingField. Export SplittingField.Exports. Lemma normal_field_splitting (F : fieldType) (L : fieldExtType F) : (forall (K : {subfield L}) x, exists r, minPoly K x == \prod_(y <- r) ('X - y%:P)) -> SplittingField.axiom L. Proof. move=> normalL; pose r i := sval (sigW (normalL 1%AS (tnth (vbasis {:L}) i))). have sz_r i: size (r i) <= \dim {:L}. rewrite -ltnS -(size_prod_XsubC _ id) /r; case: sigW => _ /= /eqP <-. rewrite size_minPoly ltnS; move: (tnth _ _) => x. by rewrite adjoin_degreeE dimv1 divn1 dimvS // subvf. pose mkf (z : L) := 'X - z%:P. exists (\prod_i \prod_(j < \dim {:L} | j < size (r i)) mkf (r i)`_j). apply: rpred_prod => i _; rewrite big_ord_narrow /= /r; case: sigW => rs /=. by rewrite (big_nth 0) big_mkord => /eqP <- {rs}; apply: minPolyOver. rewrite pair_big_dep /= -big_filter filter_index_enum -(big_map _ xpredT mkf). set rF := map _ _; exists rF; first exact: eqpxx. apply/eqP; rewrite eqEsubv subvf -(span_basis (vbasisP {:L})). apply/span_subvP=> _ /tnthP[i ->]; set x := tnth _ i. have /tnthP[j ->]: x \in in_tuple (r i). by rewrite -root_prod_XsubC /r; case: sigW => _ /=/eqP<-; apply: root_minPoly. apply/seqv_sub_adjoin/imageP; rewrite (tnth_nth 0) /in_mem/=. by exists (i, widen_ord (sz_r i) j) => /=. Qed. Section SplittingFieldTheory. Variables (F : fieldType) (L : splittingFieldType F). Implicit Types (U V W : {vspace L}). Implicit Types (K M E : {subfield L}). Lemma splittingFieldP : SplittingField.axiom L. Proof. by case: L => ? []. Qed. Lemma splittingPoly : {p : {poly L} | p \is a polyOver 1%VS & splittingFieldFor 1 p {:L}}. Proof. pose factF p s := (p \is a polyOver 1%VS) && (p %= \prod_(z <- s) ('X - z%:P)). suffices [[p rs] /andP[]]: {ps | factF F L ps.1 ps.2 & <<1 & ps.2>> = {:L}}%VS. by exists p; last exists rs. apply: sig2_eqW; have [p F0p [rs splitLp genLrs]] := splittingFieldP. by exists (p, rs); rewrite // /factF F0p splitLp. Qed. Fact fieldOver_splitting E : SplittingField.axiom (fieldOver_fieldExtType E). Proof. have [p Fp [r Dp defL]] := splittingFieldP; exists p. apply/polyOverP=> j; rewrite trivial_fieldOver. by rewrite (subvP (sub1v E)) ?(polyOverP Fp). exists r => //; apply/vspaceP=> x; rewrite memvf. have [L0 [_ _ defL0]] := @aspaceOverP _ _ E <<1 & r : seq (fieldOver E)>>. rewrite defL0; have: x \in <<1 & r>>%VS by rewrite defL (@memvf _ L). apply: subvP; apply/Fadjoin_seqP; rewrite -memvE -defL0 mem1v. by split=> // y r_y; rewrite -defL0 seqv_sub_adjoin. Qed. Canonical fieldOver_splittingFieldType E := SplittingFieldType (subvs_of E) (fieldOver E) (fieldOver_splitting E). Lemma enum_AEnd : {kAutL : seq 'AEnd(L) | forall f, f \in kAutL}. Proof. pose isAutL (s : seq 'AEnd(L)) (f : 'AEnd(L)) := kHom 1 {:L} f = (f \in s). suffices [kAutL in_kAutL] : {kAutL : seq 'AEnd(L) | forall f, isAutL kAutL f}. by exists kAutL => f; rewrite -in_kAutL k1AHom. have [p Kp /sig2_eqW[rs Dp defL]] := splittingPoly. do [rewrite {}/isAutL -(erefl (asval 1)); set r := rs; set E := 1%AS] in defL *. have [sKE rs_r]: (1 <= E)%VS /\ all (mem rs) r by split; last apply/allP. elim: r rs_r => [_|z r IHr /=/andP[rs_z rs_r]] /= in (E) sKE defL *. rewrite Fadjoin_nil in defL; exists [tuple \1%AF] => f; rewrite defL inE. apply/idP/eqP=> [/kAHomP f1 | ->]; last exact: kHom1. by apply/val_inj/lfunP=> x; rewrite id_lfunE f1 ?memvf. do [set Ez := <>%VS; rewrite adjoin_cons] in defL. have sEEz: (E <= Ez)%VS := subv_adjoin E z; have sKEz := subv_trans sKE sEEz. have{IHr} [homEz DhomEz] := IHr rs_r _ sKEz defL. have Ep: p \in polyOver E := polyOverSv sKE Kp. have{rs_z} pz0: root p z by rewrite (eqp_root Dp) root_prod_XsubC. pose pEz := minPoly E z; pose n := \dim_E Ez. have{pz0} [rz DpEz]: {rz : n.-tuple L | pEz %= \prod_(w <- rz) ('X - w%:P)}. have /dvdp_prod_XsubC[m DpEz]: pEz %| \prod_(w <- rs) ('X - w%:P). by rewrite -(eqp_dvdr _ Dp) minPoly_dvdp ?(polyOverSv sKE). suffices sz_rz: size (mask m rs) == n by exists (Tuple sz_rz). rewrite -[n]adjoin_degreeE -eqSS -size_minPoly. by rewrite (eqp_size DpEz) size_prod_XsubC. have fEz i (y := tnth rz i): {f : 'AEnd(L) | kHom E {:L} f & f z = y}. have homEfz: kHom E Ez (kHomExtend E \1 z y). rewrite kHomExtendP ?kHom1 // lfun1_poly. by rewrite (eqp_root DpEz) -/rz root_prod_XsubC mem_tnth. have splitFp: splittingFieldFor Ez p {:L}. exists rs => //; apply/eqP; rewrite eqEsubv subvf -defL adjoin_seqSr //. exact/allP. have [f homLf Df] := kHom_extends sEEz homEfz Ep splitFp. have [ahomf _] := andP homLf; exists (AHom ahomf) => //. rewrite -Df ?memv_adjoin ?(kHomExtend_val (kHom1 E E)) // lfun1_poly. by rewrite (eqp_root DpEz) root_prod_XsubC mem_tnth. exists [seq (s2val (fEz i) \o f)%AF| i <- enum 'I_n, f <- homEz] => f. apply/idP/allpairsP => [homLf | [[i g] [_ Hg ->]] /=]; last first. by case: (fEz i) => fi /= /comp_kHom->; rewrite ?(kHomSl sEEz) ?DhomEz. have /tnthP[i Dfz]: f z \in rz. rewrite memtE /= -root_prod_XsubC -(eqp_root DpEz). by rewrite (kHom_root_id _ homLf) ?memvf ?subvf ?minPolyOver ?root_minPoly. case Dfi: (fEz i) => [fi homLfi fi_z]; have kerfi0 := kAutf_lker0 homLfi. set fj := (fi ^-1 \o f)%AF; suffices Hfj : fj \in homEz. exists (i, fj) => //=; rewrite mem_enum inE Hfj; split => //. by apply/val_inj; rewrite {}Dfi /= (lker0_compVKf kerfi0). rewrite -DhomEz; apply/kAHomP => _ /Fadjoin_polyP[q Eq ->]. have homLfj: kHom E {:L} fj := comp_kHom (inv_kHomf homLfi) homLf. have /kHom_lrmorphism fjM := kHomSl (sub1v _) homLfj. rewrite -[fj _](horner_map (RMorphism fjM)) (kHom_poly_id homLfj) //=. by rewrite lfunE /= Dfz -fi_z lker0_lfunK. Qed. Lemma splitting_field_normal K x : exists r, minPoly K x == \prod_(y <- r) ('X - y%:P). Proof. pose q1 := minPoly 1 x; pose fx_root q (f : 'AEnd(L)) := root q (f x). have [[p F0p splitLp] [autL DautL]] := (splittingFieldP, enum_AEnd). suffices{K} autL_px q: q != 0 -> q %| q1 -> size q > 1 -> has (fx_root q) autL. set q := minPoly K x; have: q \is monic := monic_minPoly K x. have: q %| q1 by rewrite minPolyS // sub1v. elim: {q}_.+1 {-2}q (ltnSn (size q)) => // d IHd q leqd q_dv_q1 mon_q. have nz_q: q != 0 := monic_neq0 mon_q. have [|q_gt1|q_1] := ltngtP (size q) 1; last first; last by rewrite polySpred. by exists nil; rewrite big_nil -eqp_monic ?monic1 // -size_poly_eq1 q_1. have /hasP[f autLf /factor_theorem[q2 Dq]] := autL_px q nz_q q_dv_q1 q_gt1. have mon_q2: q2 \is monic by rewrite -(monicMr _ (monicXsubC (f x))) -Dq. rewrite Dq size_monicM -?size_poly_eq0 ?size_XsubC ?addn2 //= ltnS in leqd. have q2_dv_q1: q2 %| q1 by rewrite (dvdp_trans _ q_dv_q1) // Dq dvdp_mulr. rewrite Dq; have [r /eqP->] := IHd q2 leqd q2_dv_q1 mon_q2. by exists (f x :: r); rewrite big_cons mulrC. elim: {q}_.+1 {-2}q (ltnSn (size q)) => // d IHd q leqd nz_q q_dv_q1 q_gt1. without loss{d leqd IHd nz_q q_gt1} irr_q: q q_dv_q1 / irreducible_poly q. move=> IHq; apply: wlog_neg => not_autLx_q; apply: IHq => //. split=> // q2 q2_neq1 q2_dv_q; rewrite -dvdp_size_eqp // eqn_leq dvdp_leq //=. rewrite leqNgt; apply: contra not_autLx_q => ltq2q. have nz_q2: q2 != 0 by apply: contraTneq q2_dv_q => ->; rewrite dvd0p. have{q2_neq1} q2_gt1: size q2 > 1 by rewrite neq_ltn polySpred in q2_neq1 *. have{leqd ltq2q} ltq2d: size q2 < d by apply: leq_trans ltq2q _. apply: sub_has (IHd _ ltq2d nz_q2 (dvdp_trans q2_dv_q q_dv_q1) q2_gt1) => f. by rewrite /fx_root !root_factor_theorem => /dvdp_trans->. have{irr_q} [Lz [inLz [z qz0]]]: {Lz : fieldExtType F & {inLz : 'AHom(L, Lz) & {z : Lz | root (map_poly inLz q) z}}}. - have [Lz0 _ [z qz0 defLz]] := irredp_FAdjoin irr_q. pose Lz := baseField_extFieldType Lz0. pose inLz : {rmorphism L -> Lz} := [rmorphism of in_alg Lz0]. have inLzL_linear: linear (locked inLz). move=> a u v; rewrite -(@mulr_algl F Lz) baseField_scaleE. by rewrite -{1}mulr_algl rmorphD rmorphM -lock. have ihLzZ: ahom_in {:L} (linfun (Linear inLzL_linear)). by apply/ahom_inP; split=> [u v|]; rewrite !lfunE (rmorphM, rmorph1). exists Lz, (AHom ihLzZ), z; congr (root _ z): qz0. by apply: eq_map_poly => y; rewrite lfunE /= -lock. pose imL := [aspace of limg inLz]; pose pz := map_poly inLz p. have in_imL u: inLz u \in imL by rewrite memv_img ?memvf. have F0pz: pz \is a polyOver 1%VS. apply/polyOverP=> i; rewrite -(aimg1 inLz) coef_map /= memv_img //. exact: (polyOverP F0p). have{splitLp} splitLpz: splittingFieldFor 1 pz imL. have [r def_p defL] := splitLp; exists (map inLz r) => [|{def_p}]. move: def_p; rewrite -(eqp_map [rmorphism of inLz]) rmorph_prod. rewrite big_map; congr (_ %= _); apply: eq_big => // y _. by rewrite rmorphB /= map_polyX map_polyC. apply/eqP; rewrite eqEsubv /= -{2}defL {defL}; apply/andP; split. by apply/Fadjoin_seqP; rewrite sub1v; split=> // _ /mapP[y r_y ->]. elim/last_ind: r => [|r y IHr] /=; first by rewrite !Fadjoin_nil aimg1. rewrite map_rcons !adjoin_rcons /=. apply/subvP=> _ /memv_imgP[_ /Fadjoin_polyP[p1 r_p1 ->] ->]. rewrite -horner_map /= mempx_Fadjoin //=; apply/polyOverP=> i. by rewrite coef_map (subvP IHr) //= memv_img ?(polyOverP r_p1). have [f homLf fxz]: exists2 f : 'End(Lz), kHom 1 imL f & f (inLz x) = z. pose q1z := minPoly 1 (inLz x). have Dq1z: map_poly inLz q1 %| q1z. have F0q1z i: exists a, q1z`_i = a%:A by apply/vlineP/polyOverP/minPolyOver. have [q2 Dq2]: exists q2, q1z = map_poly inLz q2. exists (\poly_(i < size q1z) (sval (sig_eqW (F0q1z i)))%:A). rewrite -{1}[q1z]coefK; apply/polyP=> i; rewrite coef_map !{1}coef_poly. by case: sig_eqW => a; case: ifP; rewrite /= ?rmorph0 ?linearZ ?rmorph1. rewrite Dq2 dvdp_map minPoly_dvdp //. apply/polyOverP=> i; have[a] := F0q1z i. rewrite -(rmorph1 [rmorphism of inLz]) -linearZ. by rewrite Dq2 coef_map => /fmorph_inj->; rewrite rpredZ ?mem1v. by rewrite -(fmorph_root [rmorphism of inLz]) -Dq2 root_minPoly. have q1z_z: root q1z z. rewrite !root_factor_theorem in qz0 *. by apply: dvdp_trans qz0 (dvdp_trans _ Dq1z); rewrite dvdp_map. have map1q1z_z: root (map_poly \1%VF q1z) z. by rewrite map_poly_id => // ? _; rewrite lfunE. pose f0 := kHomExtend 1 \1 (inLz x) z. have{map1q1z_z} hom_f0 : kHom 1 <<1; inLz x>> f0. by apply: kHomExtendP map1q1z_z => //; apply: kHom1. have{splitLpz} splitLpz: splittingFieldFor <<1; inLz x>> pz imL. have [r def_pz defLz] := splitLpz; exists r => //. apply/eqP; rewrite eqEsubv -{2}defLz adjoin_seqSl ?sub1v // andbT. apply/Fadjoin_seqP; split; last first. by rewrite /= -[limg _]defLz; apply: seqv_sub_adjoin. by apply/FadjoinP/andP; rewrite sub1v memv_img ?memvf. have [f homLzf Df] := kHom_extends (sub1v _) hom_f0 F0pz splitLpz. have [-> | x'z] := eqVneq (inLz x) z. by exists \1%VF; rewrite ?lfunE ?kHom1. exists f => //; rewrite -Df ?memv_adjoin ?(kHomExtend_val (kHom1 1 1)) //. by rewrite lfun1_poly. pose f1 := (inLz^-1 \o f \o inLz)%VF; have /kHomP[fM fFid] := homLf. have Df1 u: inLz (f1 u) = f (inLz u). rewrite !comp_lfunE limg_lfunVK //= -[limg _]/(asval imL). have [r def_pz defLz] := splitLpz. have []: all (mem r) r /\ inLz u \in imL by split; first apply/allP. rewrite -{1}defLz; elim/last_ind: {-1}r {u}(inLz u) => [|r1 y IHr1] u. by rewrite Fadjoin_nil => _ Fu; rewrite fFid // (subvP (sub1v _)). rewrite all_rcons adjoin_rcons => /andP[rr1 ry] /Fadjoin_polyP[pu r1pu ->]. rewrite (kHom_horner homLf) -defLz; last exact: seqv_sub_adjoin; last first. by apply: polyOverS r1pu; apply/subvP/adjoin_seqSr/allP. apply: rpred_horner. by apply/polyOverP=> i; rewrite coef_map /= defLz IHr1 ?(polyOverP r1pu). rewrite seqv_sub_adjoin // -root_prod_XsubC -(eqp_root def_pz). rewrite (kHom_root_id _ homLf) ?sub1v //. by rewrite -defLz seqv_sub_adjoin. by rewrite (eqp_root def_pz) root_prod_XsubC. suffices f1_is_ahom : ahom_in {:L} f1. apply/hasP; exists (AHom f1_is_ahom); first exact: DautL. by rewrite /fx_root -(fmorph_root [rmorphism of inLz]) /= Df1 fxz. apply/ahom_inP; split=> [a b _ _|]; apply: (fmorph_inj [rmorphism of inLz]). by rewrite rmorphM /= !Df1 rmorphM fM ?in_imL. by rewrite /= Df1 /= fFid ?rmorph1 ?mem1v. Qed. Lemma kHom_to_AEnd K E f : kHom K E f -> {g : 'AEnd(L) | {in E, f =1 val g}}. Proof. move=> homKf; have{homKf} [homFf sFE] := (kHomSl (sub1v K) homKf, sub1v E). have [p Fp /(splittingFieldForS sFE (subvf E))splitLp] := splittingPoly. have [g0 homLg0 eq_fg] := kHom_extends sFE homFf Fp splitLp. by apply: exist (Sub g0 _) _ => //; apply/ahomP/kHom_lrmorphism. Qed. End SplittingFieldTheory. (* Hide the finGroup structure on 'AEnd(L) in a module so that we can control *) (* when it is exported. Most people will want to use the finGroup structure *) (* on 'Gal(E / K) and will not need this module. *) Module Import AEnd_FinGroup. Section AEnd_FinGroup. Variables (F : fieldType) (L : splittingFieldType F). Implicit Types (U V W : {vspace L}) (K M E : {subfield L}). Definition inAEnd f := SeqSub (svalP (enum_AEnd L) f). Fact inAEndK : cancel inAEnd val. Proof. by []. Qed. Definition AEnd_countMixin := Eval hnf in CanCountMixin inAEndK. Canonical AEnd_countType := Eval hnf in CountType 'AEnd(L) AEnd_countMixin. Canonical AEnd_subCountType := Eval hnf in [subCountType of 'AEnd(L)]. Definition AEnd_finMixin := Eval hnf in CanFinMixin inAEndK. Canonical AEnd_finType := Eval hnf in FinType 'AEnd(L) AEnd_finMixin. Canonical AEnd_subFinType := Eval hnf in [subFinType of 'AEnd(L)]. (* the group operation is the categorical composition operation *) Definition comp_AEnd (f g : 'AEnd(L)) : 'AEnd(L) := (g \o f)%AF. Fact comp_AEndA : associative comp_AEnd. Proof. by move=> f g h; apply: val_inj; symmetry; apply: comp_lfunA. Qed. Fact comp_AEnd1l : left_id \1%AF comp_AEnd. Proof. by move=> f; apply/val_inj/comp_lfun1r. Qed. Fact comp_AEndK : left_inverse \1%AF (@inv_ahom _ L) comp_AEnd. Proof. by move=> f; apply/val_inj; rewrite /= lker0_compfV ?AEnd_lker0. Qed. Definition AEnd_baseFinGroupMixin := FinGroup.Mixin comp_AEndA comp_AEnd1l comp_AEndK. Canonical AEnd_baseFinGroupType := BaseFinGroupType 'AEnd(L) AEnd_baseFinGroupMixin. Canonical AEnd_finGroupType := FinGroupType comp_AEndK. Definition kAEnd U V := [set f : 'AEnd(L) | kAut U V f]. Definition kAEndf U := kAEnd U {:L}. Lemma kAEnd_group_set K E : group_set (kAEnd K E). Proof. apply/group_setP; split=> [|f g]; first by rewrite inE /kAut kHom1 lim1g eqxx. rewrite !inE !kAutE => /andP[homKf EfE] /andP[/(kHomSr EfE)homKg EgE]. by rewrite (comp_kHom_img homKg homKf) limg_comp (subv_trans _ EgE) ?limgS. Qed. Canonical kAEnd_group K E := group (kAEnd_group_set K E). Canonical kAEndf_group K := [group of kAEndf K]. Lemma kAEnd_norm K E : kAEnd K E \subset 'N(kAEndf E)%g. Proof. apply/subsetP=> x; rewrite -groupV 2!in_set => /andP[_ /eqP ExE]. apply/subsetP=> _ /imsetP[y homEy ->]; rewrite !in_set !kAutfE in homEy *. apply/kAHomP=> u Eu; have idEy := kAHomP homEy; rewrite -ExE in idEy. by rewrite !lfunE /= lfunE /= idEy ?memv_img // lker0_lfunVK ?AEnd_lker0. Qed. Lemma mem_kAut_coset K E (g : 'AEnd(L)) : kAut K E g -> g \in coset (kAEndf E) g. Proof. move=> autEg; rewrite val_coset ?rcoset_refl //. by rewrite (subsetP (kAEnd_norm K E)) // inE. Qed. Lemma aut_mem_eqP E (x y : coset_of (kAEndf E)) f g : f \in x -> g \in y -> reflect {in E, f =1 g} (x == y). Proof. move=> x_f y_g; rewrite -(coset_mem x_f) -(coset_mem y_g). have [Nf Ng] := (subsetP (coset_norm x) f x_f, subsetP (coset_norm y) g y_g). rewrite (sameP eqP (rcoset_kercosetP Nf Ng)) mem_rcoset inE kAutfE. apply: (iffP kAHomP) => idEfg u Eu. by rewrite -(mulgKV g f) lfunE /= idEfg. by rewrite lfunE /= idEfg // lker0_lfunK ?AEnd_lker0. Qed. End AEnd_FinGroup. End AEnd_FinGroup. Section GaloisTheory. Variables (F : fieldType) (L : splittingFieldType F). Implicit Types (U V W : {vspace L}). Implicit Types (K M E : {subfield L}). (* We take Galois automorphisms for a subfield E to be automorphisms of the *) (* full field {:L} that operate in E taken modulo those that fix E pointwise. *) (* The type of Galois automorphisms of E is then the subtype of elements of *) (* the quotient kAEnd 1 E / kAEndf E, which we encapsulate in a specific *) (* wrapper to ensure stability of the gal_repr coercion insertion. *) Section gal_of_Definition. Variable V : {vspace L}. (* The <<_>>, which becomes redundant when V is a {subfield L}, ensures that *) (* the argument of [subg _] is syntactically a group. *) Inductive gal_of := Gal of [subg kAEnd_group 1 <> / kAEndf (agenv V)]. Definition gal (f : 'AEnd(L)) := Gal (subg _ (coset _ f)). Definition gal_sgval x := let: Gal u := x in u. Fact gal_sgvalK : cancel gal_sgval Gal. Proof. by case. Qed. Let gal_sgval_inj := can_inj gal_sgvalK. Definition gal_eqMixin := CanEqMixin gal_sgvalK. Canonical gal_eqType := Eval hnf in EqType gal_of gal_eqMixin. Definition gal_choiceMixin := CanChoiceMixin gal_sgvalK. Canonical gal_choiceType := Eval hnf in ChoiceType gal_of gal_choiceMixin. Definition gal_countMixin := CanCountMixin gal_sgvalK. Canonical gal_countType := Eval hnf in CountType gal_of gal_countMixin. Definition gal_finMixin := CanFinMixin gal_sgvalK. Canonical gal_finType := Eval hnf in FinType gal_of gal_finMixin. Definition gal_one := Gal 1%g. Definition gal_inv x := Gal (gal_sgval x)^-1. Definition gal_mul x y := Gal (gal_sgval x * gal_sgval y). Fact gal_oneP : left_id gal_one gal_mul. Proof. by move=> x; apply/gal_sgval_inj/mul1g. Qed. Fact gal_invP : left_inverse gal_one gal_inv gal_mul. Proof. by move=> x; apply/gal_sgval_inj/mulVg. Qed. Fact gal_mulP : associative gal_mul. Proof. by move=> x y z; apply/gal_sgval_inj/mulgA. Qed. Definition gal_finGroupMixin := FinGroup.Mixin gal_mulP gal_oneP gal_invP. Canonical gal_finBaseGroupType := Eval hnf in BaseFinGroupType gal_of gal_finGroupMixin. Canonical gal_finGroupType := Eval hnf in FinGroupType gal_invP. Coercion gal_repr u : 'AEnd(L) := repr (sgval (gal_sgval u)). Fact gal_is_morphism : {in kAEnd 1 (agenv V) &, {morph gal : x y / x * y}%g}. Proof. move=> f g /= autEa autEb; congr (Gal _). by rewrite !morphM ?mem_morphim // (subsetP (kAEnd_norm 1 _)). Qed. Canonical gal_morphism := Morphism gal_is_morphism. Lemma gal_reprK : cancel gal_repr gal. Proof. by case=> x; rewrite /gal coset_reprK sgvalK. Qed. Lemma gal_repr_inj : injective gal_repr. Proof. exact: can_inj gal_reprK. Qed. Lemma gal_AEnd x : gal_repr x \in kAEnd 1 (agenv V). Proof. rewrite /gal_repr; case/gal_sgval: x => _ /=/morphimP[g Ng autEg ->]. rewrite val_coset //=; case: repr_rcosetP => f; rewrite groupMr // !inE kAut1E. by rewrite kAutE -andbA => /and3P[_ /fixedSpace_limg-> _]. Qed. End gal_of_Definition. Prenex Implicits gal_repr. Lemma gal_eqP E {x y : gal_of E} : reflect {in E, x =1 y} (x == y). Proof. by rewrite -{1}(subfield_closed E); apply: aut_mem_eqP; apply: mem_repr_coset. Qed. Lemma galK E (f : 'AEnd(L)) : (f @: E <= E)%VS -> {in E, gal E f =1 f}. Proof. rewrite -kAut1E -{1 2}(subfield_closed E) => autEf. apply: (aut_mem_eqP (mem_repr_coset _) _ (eqxx _)). by rewrite subgK /= ?(mem_kAut_coset autEf) // ?mem_quotient ?inE. Qed. Lemma eq_galP E (f g : 'AEnd(L)) : (f @: E <= E)%VS -> (g @: E <= E)%VS -> reflect {in E, f =1 g} (gal E f == gal E g). Proof. move=> EfE EgE. by apply: (iffP gal_eqP) => Dfg a Ea; have:= Dfg a Ea; rewrite !{1}galK. Qed. Lemma limg_gal E (x : gal_of E) : (x @: E)%VS = E. Proof. by have:= gal_AEnd x; rewrite inE subfield_closed => /andP[_ /eqP]. Qed. Lemma memv_gal E (x : gal_of E) a : a \in E -> x a \in E. Proof. by move/(memv_img x); rewrite limg_gal. Qed. Lemma gal_id E a : (1 : gal_of E)%g a = a. Proof. by rewrite /gal_repr repr_coset1 id_lfunE. Qed. Lemma galM E (x y : gal_of E) a : a \in E -> (x * y)%g a = y (x a). Proof. rewrite /= -comp_lfunE; apply/eq_galP; rewrite ?limg_comp ?limg_gal //. by rewrite morphM /= ?gal_reprK ?gal_AEnd. Qed. Lemma galV E (x : gal_of E) : {in E, (x^-1)%g =1 x^-1%VF}. Proof. move=> a Ea; apply: canRL (lker0_lfunK (AEnd_lker0 _)) _. by rewrite -galM // mulVg gal_id. Qed. (* Standard mathematical notation for 'Gal(E / K) puts the larger field first.*) Definition galoisG V U := gal V @* <>. Local Notation "''Gal' ( V / U )" := (galoisG V U) : group_scope. Canonical galoisG_group E U := Eval hnf in [group of (galoisG E U)]. Local Notation "''Gal' ( V / U )" := (galoisG_group V U) : Group_scope. Section Automorphism. Lemma gal_cap U V : 'Gal(V / U) = 'Gal(V / U :&: V). Proof. by rewrite /galoisG -capvA capvv. Qed. Lemma gal_kAut K E x : (K <= E)%VS -> (x \in 'Gal(E / K)) = kAut K E x. Proof. move=> sKE; apply/morphimP/idP=> /= [[g EgE KautEg ->{x}] | KautEx]. rewrite genGid !inE kAut1E /= subfield_closed (capv_idPl sKE) in KautEg EgE. by apply: etrans KautEg; apply/(kAut_eq sKE); apply: galK. exists (x : 'AEnd(L)); rewrite ?gal_reprK ?gal_AEnd //. by rewrite (capv_idPl sKE) mem_gen ?inE. Qed. Lemma gal_kHom K E x : (K <= E)%VS -> (x \in 'Gal(E / K)) = kHom K E x. Proof. by move/gal_kAut->; rewrite /kAut limg_gal eqxx andbT. Qed. Lemma kAut_to_gal K E f : kAut K E f -> {x : gal_of E | x \in 'Gal(E / K) & {in E, f =1 x}}. Proof. case/andP=> homKf EfE; have [g Df] := kHom_to_AEnd homKf. have{homKf EfE} autEg: kAut (K :&: E) E g. rewrite /kAut -(kHom_eq (capvSr _ _) Df) (kHomSl (capvSl _ _) homKf) /=. by rewrite -(eq_in_limg Df). have FautEg := kAutS (sub1v _) autEg. exists (gal E g) => [|a Ea]; last by rewrite {f}Df // galK // -kAut1E. by rewrite mem_morphim /= ?subfield_closed ?genGid ?inE. Qed. Lemma fixed_gal K E x a : (K <= E)%VS -> x \in 'Gal(E / K) -> a \in K -> x a = a. Proof. by move/gal_kHom=> -> /kAHomP idKx /idKx. Qed. Lemma fixedPoly_gal K E x p : (K <= E)%VS -> x \in 'Gal(E / K) -> p \is a polyOver K -> map_poly x p = p. Proof. move=> sKE galEKx /polyOverP Kp; apply/polyP => i. by rewrite coef_map /= (fixed_gal sKE). Qed. Lemma root_minPoly_gal K E x a : (K <= E)%VS -> x \in 'Gal(E / K) -> a \in E -> root (minPoly K a) (x a). Proof. move=> sKE galEKx Ea; have homKx: kHom K E x by rewrite -gal_kHom. have K_Pa := minPolyOver K a; rewrite -[minPoly K a](fixedPoly_gal _ galEKx) //. by rewrite (kHom_root homKx) ?root_minPoly // (polyOverS (subvP sKE)). Qed. End Automorphism. Lemma gal_adjoin_eq K a x y : x \in 'Gal(<> / K) -> y \in 'Gal(<> / K) -> (x == y) = (x a == y a). Proof. move=> galKa_x galKa_y; apply/idP/eqP=> [/eqP-> // | eq_xy_a]. apply/gal_eqP => _ /Fadjoin_polyP[p Kp ->]. by rewrite -!horner_map !(fixedPoly_gal (subv_adjoin K a)) //= eq_xy_a. Qed. Lemma galS K M E : (K <= M)%VS -> 'Gal(E / M) \subset 'Gal(E / K). Proof. rewrite gal_cap (gal_cap K E) => sKM; apply/subsetP=> x. by rewrite !gal_kAut ?capvSr //; apply: kAutS; apply: capvS. Qed. Lemma gal_conjg K E x : 'Gal(E / K) :^ x = 'Gal(E / x @: K). Proof. without loss sKE: K / (K <= E)%VS. move=> IH_K; rewrite gal_cap {}IH_K ?capvSr //. transitivity 'Gal(E / x @: K :&: x @: E); last by rewrite limg_gal -gal_cap. congr 'Gal(E / _); apply/eqP; rewrite eqEsubv limg_cap; apply/subvP=> a. rewrite memv_cap => /andP[/memv_imgP[b Kb ->] /memv_imgP[c Ec] eq_bc]. by rewrite memv_img // memv_cap Kb (lker0P (AEnd_lker0 _) _ _ eq_bc). wlog suffices IHx: x K sKE / 'Gal(E / K) :^ x \subset 'Gal(E / x @: K). apply/eqP; rewrite eqEsubset IHx // -sub_conjgV (subset_trans (IHx _ _ _)) //. by apply/subvP=> _ /memv_imgP[a Ka ->]; rewrite memv_gal ?(subvP sKE). rewrite -limg_comp (etrans (eq_in_limg _) (lim1g _)) // => a /(subvP sKE)Ka. by rewrite !lfunE /= -galM // mulgV gal_id. apply/subsetP=> _ /imsetP[y galEy ->]; rewrite gal_cap gal_kHom ?capvSr //=. apply/kAHomP=> _ /memv_capP[/memv_imgP[a Ka ->] _]; have Ea := subvP sKE a Ka. by rewrite -galM // -conjgC galM // (fixed_gal sKE galEy). Qed. Definition fixedField V (A : {set gal_of V}) := (V :&: \bigcap_(x in A) fixedSpace x)%VS. Lemma fixedFieldP E {A : {set gal_of E}} a : a \in E -> reflect (forall x, x \in A -> x a = a) (a \in fixedField A). Proof. by rewrite memv_cap => ->; apply: (iffP subv_bigcapP) => cAa x /cAa/fixedSpaceP. Qed. Lemma mem_fixedFieldP E (A : {set gal_of E}) a : a \in fixedField A -> a \in E /\ (forall x, x \in A -> x a = a). Proof. by move=> fixAa; have [Ea _] := memv_capP fixAa; have:= fixedFieldP Ea fixAa. Qed. Fact fixedField_is_aspace E (A : {set gal_of E}) : is_aspace (fixedField A). Proof. rewrite /fixedField; elim/big_rec: _ {1}E => [|x K _ IH_K] M. exact: (valP (M :&: _)%AS). by rewrite capvA IH_K. Qed. Canonical fixedField_aspace E A : {subfield L} := ASpace (@fixedField_is_aspace E A). Lemma fixedField_bound E (A : {set gal_of E}) : (fixedField A <= E)%VS. Proof. exact: capvSl. Qed. Lemma fixedFieldS E (A B : {set gal_of E}) : A \subset B -> (fixedField B <= fixedField A)%VS. Proof. move/subsetP=> sAB; apply/subvP => a /mem_fixedFieldP[Ea cBa]. by apply/fixedFieldP; last apply: sub_in1 cBa. Qed. Lemma galois_connection_subv K E : (K <= E)%VS -> (K <= fixedField ('Gal(E / K)))%VS. Proof. move=> sKE; apply/subvP => a Ka; have Ea := subvP sKE a Ka. by apply/fixedFieldP=> // x galEx; apply: (fixed_gal sKE). Qed. Lemma galois_connection_subset E (A : {set gal_of E}): A \subset 'Gal(E / fixedField A). Proof. apply/subsetP => x Ax; rewrite gal_kAut ?capvSl // kAutE limg_gal subvv andbT. by apply/kAHomP=> a /mem_fixedFieldP[_ ->]. Qed. Lemma galois_connection K E (A : {set gal_of E}): (K <= E)%VS -> (A \subset 'Gal(E / K)) = (K <= fixedField A)%VS. Proof. move=> sKE; apply/idP/idP => [/fixedFieldS | /(galS E)]. by apply: subv_trans; apply galois_connection_subv. by apply: subset_trans; apply: galois_connection_subset. Qed. Definition galTrace U V a := \sum_(x in 'Gal(V / U)) (x a). Definition galNorm U V a := \prod_(x in 'Gal(V / U)) (x a). Section TraceAndNormMorphism. Variables U V : {vspace L}. Fact galTrace_is_additive : additive (galTrace U V). Proof. by move=> a b /=; rewrite -sumrB; apply: eq_bigr => x _; rewrite rmorphB. Qed. Canonical galTrace_additive := Additive galTrace_is_additive. Lemma galNorm1 : galNorm U V 1 = 1. Proof. by apply: big1 => x _; rewrite rmorph1. Qed. Lemma galNormM : {morph galNorm U V : a b / a * b}. Proof. by move=> a b /=; rewrite -big_split; apply: eq_bigr => x _; rewrite rmorphM. Qed. Lemma galNormV : {morph galNorm U V : a / a^-1}. Proof. by move=> a /=; rewrite -prodfV; apply: eq_bigr => x _; rewrite fmorphV. Qed. Lemma galNormX n : {morph galNorm U V : a / a ^+ n}. Proof. move=> a; elim: n => [|n IHn]; first by apply: galNorm1. by rewrite !exprS galNormM IHn. Qed. Lemma galNorm_prod (I : Type) (r : seq I) (P : pred I) (B : I -> L) : galNorm U V (\prod_(i <- r | P i) B i) = \prod_(i <- r | P i) galNorm U V (B i). Proof. exact: (big_morph _ galNormM galNorm1). Qed. Lemma galNorm0 : galNorm U V 0 = 0. Proof. by rewrite /galNorm (bigD1 1%g) ?group1 // rmorph0 /= mul0r. Qed. Lemma galNorm_eq0 a : (galNorm U V a == 0) = (a == 0). Proof. apply/idP/eqP=> [/prodf_eq0[x _] | ->]; last by rewrite galNorm0. by rewrite fmorph_eq0 => /eqP. Qed. End TraceAndNormMorphism. Section TraceAndNormField. Variables K E : {subfield L}. Lemma galTrace_fixedField a : a \in E -> galTrace K E a \in fixedField 'Gal(E / K). Proof. move=> Ea; apply/fixedFieldP=> [|x galEx]. by apply: rpred_sum => x _; apply: memv_gal. rewrite {2}/galTrace (reindex_acts 'R _ galEx) ?astabsR //=. by rewrite rmorph_sum; apply: eq_bigr => y _; rewrite galM ?lfunE. Qed. Lemma galTrace_gal a x : a \in E -> x \in 'Gal(E / K) -> galTrace K E (x a) = galTrace K E a. Proof. move=> Ea galEx; rewrite {2}/galTrace (reindex_inj (mulgI x)). by apply: eq_big => [b | b _]; rewrite ?groupMl // galM ?lfunE. Qed. Lemma galNorm_fixedField a : a \in E -> galNorm K E a \in fixedField 'Gal(E / K). Proof. move=> Ea; apply/fixedFieldP=> [|x galEx]. by apply: rpred_prod => x _; apply: memv_gal. rewrite {2}/galNorm (reindex_acts 'R _ galEx) ?astabsR //=. by rewrite rmorph_prod; apply: eq_bigr => y _; rewrite galM ?lfunE. Qed. Lemma galNorm_gal a x : a \in E -> x \in 'Gal(E / K) -> galNorm K E (x a) = galNorm K E a. Proof. move=> Ea galEx; rewrite {2}/galNorm (reindex_inj (mulgI x)). by apply: eq_big => [b | b _]; rewrite ?groupMl // galM ?lfunE. Qed. End TraceAndNormField. Definition normalField U V := [forall x in kAEndf U, x @: V == V]%VS. Lemma normalField_kAut K M E f : (K <= M <= E)%VS -> normalField K M -> kAut K E f -> kAut K M f. Proof. case/andP=> sKM sME nKM /kAut_to_gal[x galEx /(sub_in1 (subvP sME))Df]. have sKE := subv_trans sKM sME; rewrite gal_kHom // in galEx. rewrite (kAut_eq sKM Df) /kAut (kHomSr sME) //= (forall_inP nKM) // inE. by rewrite kAutfE; apply/kAHomP; apply: (kAHomP galEx). Qed. Lemma normalFieldP K E : reflect {in E, forall a, exists2 r, all (mem E) r & minPoly K a = \prod_(b <- r) ('X - b%:P)} (normalField K E). Proof. apply: (iffP eqfun_inP) => [nKE a Ea | nKE x]; last first. rewrite inE kAutfE => homKx; suffices: kAut K E x by case/andP=> _ /eqP. rewrite kAutE (kHomSr (subvf E)) //=; apply/subvP=> _ /memv_imgP[a Ea ->]. have [r /allP/=srE splitEa] := nKE a Ea. rewrite srE // -root_prod_XsubC -splitEa. by rewrite -(kHom_poly_id homKx (minPolyOver K a)) fmorph_root root_minPoly. have [r /eqP splitKa] := splitting_field_normal K a. exists r => //; apply/allP => b; rewrite -root_prod_XsubC -splitKa => pKa_b_0. pose y := kHomExtend K \1 a b; have [hom1K lf1p] := (kHom1 K K, lfun1_poly). have homKy: kHom K <> y by apply/kHomExtendP; rewrite ?lf1p. have [[g Dy] [_ idKy]] := (kHom_to_AEnd homKy, kHomP homKy). have <-: g a = b by rewrite -Dy ?memv_adjoin // (kHomExtend_val hom1K) ?lf1p. suffices /nKE <-: g \in kAEndf K by apply: memv_img. by rewrite inE kAutfE; apply/kAHomP=> c Kc; rewrite -Dy ?subvP_adjoin ?idKy. Qed. Lemma normalFieldf K : normalField K {:L}. Proof. apply/normalFieldP=> a _; have [r /eqP->] := splitting_field_normal K a. by exists r => //; apply/allP=> b; rewrite /= memvf. Qed. Lemma normalFieldS K M E : (K <= M)%VS -> normalField K E -> normalField M E. Proof. move=> sKM /normalFieldP nKE; apply/normalFieldP=> a Ea. have [r /allP Er splitKa] := nKE a Ea. have /dvdp_prod_XsubC[m splitMa]: minPoly M a %| \prod_(b <- r) ('X - b%:P). by rewrite -splitKa minPolyS. exists (mask m r); first by apply/allP=> b /mem_mask/Er. by apply/eqP; rewrite -eqp_monic ?monic_prod_XsubC ?monic_minPoly. Qed. Lemma splitting_normalField E K : (K <= E)%VS -> reflect (exists2 p, p \is a polyOver K & splittingFieldFor K p E) (normalField K E). Proof. move=> sKE; apply: (iffP idP) => [nKE| [p Kp [rs Dp defE]]]; last first. apply/forall_inP=> g; rewrite inE kAutE => /andP[homKg _]. rewrite -dimv_leqif_eq ?limg_dim_eq ?(eqP (AEnd_lker0 g)) ?capv0 //. rewrite -defE aimg_adjoin_seq; have [_ /fixedSpace_limg->] := andP homKg. apply/adjoin_seqSr=> _ /mapP[a rs_a ->]. rewrite -!root_prod_XsubC -!(eqp_root Dp) in rs_a *. by apply: kHom_root_id homKg Kp _ rs_a; rewrite ?subvf ?memvf. pose splitK a r := minPoly K a = \prod_(b <- r) ('X - b%:P). have{nKE} rK_ a: {r | a \in E -> all (mem E) r /\ splitK a r}. case Ea: (a \in E); last by exists [::]. by have /sig2_eqW[r] := normalFieldP _ _ nKE a Ea; exists r. have sXE := basis_mem (vbasisP E); set X : seq L := vbasis E in sXE. exists (\prod_(a <- X) minPoly K a). by apply: rpred_prod => a _; apply: minPolyOver. exists (flatten [seq (sval (rK_ a)) | a <- X]). move/allP: sXE; elim: X => [|a X IHX] ; first by rewrite !big_nil eqpxx. rewrite big_cons /= big_cat /= => /andP[Ea sXE]. by case: (rK_ a) => /= r [] // _ <-; apply/eqp_mull/IHX. apply/eqP; rewrite eqEsubv; apply/andP; split. apply/Fadjoin_seqP; split=> // b /flatten_mapP[a /sXE Ea]. by apply/allP; case: rK_ => r /= []. rewrite -{1}(span_basis (vbasisP E)); apply/span_subvP=> a Xa. apply/seqv_sub_adjoin/flatten_mapP; exists a => //; rewrite -root_prod_XsubC. by case: rK_ => /= r [| _ <-]; rewrite ?sXE ?root_minPoly. Qed. Lemma kHom_to_gal K M E f : (K <= M <= E)%VS -> normalField K E -> kHom K M f -> {x | x \in 'Gal(E / K) & {in M, f =1 x}}. Proof. case/andP=> /subvP sKM /subvP sME nKE KhomMf. have [[g Df] [_ idKf]] := (kHom_to_AEnd KhomMf, kHomP KhomMf). suffices /kAut_to_gal[x galEx Dg]: kAut K E g. by exists x => //= a Ma; rewrite Df // Dg ?sME. have homKg: kHom K {:L} g by apply/kAHomP=> a Ka; rewrite -Df ?sKM ?idKf. by rewrite /kAut (kHomSr (subvf _)) // (forall_inP nKE) // inE kAutfE. Qed. Lemma normalField_root_minPoly K E a b : (K <= E)%VS -> normalField K E -> a \in E -> root (minPoly K a) b -> exists2 x, x \in 'Gal(E / K) & x a = b. Proof. move=> sKE nKE Ea pKa_b_0; pose f := kHomExtend K \1 a b. have homKa_f: kHom K <> f. by apply: kHomExtendP; rewrite ?kHom1 ?lfun1_poly. have sK_Ka_E: (K <= <> <= E)%VS. by rewrite subv_adjoin; apply/FadjoinP; rewrite sKE Ea. have [x galEx Df] := kHom_to_gal sK_Ka_E nKE homKa_f; exists x => //. by rewrite -Df ?memv_adjoin // (kHomExtend_val (kHom1 K K)) ?lfun1_poly. Qed. Implicit Arguments normalFieldP [K E]. Lemma normalField_factors K E : (K <= E)%VS -> reflect {in E, forall a, exists2 r : seq (gal_of E), r \subset 'Gal(E / K) & minPoly K a = \prod_(x <- r) ('X - (x a)%:P)} (normalField K E). Proof. move=> sKE; apply: (iffP idP) => [nKE a Ea | nKE]; last first. apply/normalFieldP=> a Ea; have [r _ ->] := nKE a Ea. exists [seq x a | x : gal_of E <- r]; last by rewrite big_map. by rewrite all_map; apply/allP=> b _; apply: memv_gal. have [r Er splitKa] := normalFieldP nKE a Ea. pose f b := [pick x in 'Gal(E / K) | x a == b]. exists (pmap f r). apply/subsetP=> x; rewrite mem_pmap /f => /mapP[b _]. by case: (pickP _) => // c /andP[galEc _] [->]. rewrite splitKa; have{splitKa}: all (root (minPoly K a)) r. by apply/allP => b; rewrite splitKa root_prod_XsubC. elim: r Er => /= [|b r IHr]; first by rewrite !big_nil. case/andP=> Eb Er /andP[pKa_b_0 /(IHr Er){IHr Er}IHr]. have [x galE /eqP xa_b] := normalField_root_minPoly sKE nKE Ea pKa_b_0. rewrite /(f b); case: (pickP _) => [y /andP[_ /eqP<-]|/(_ x)/andP[]//]. by rewrite !big_cons IHr. Qed. Definition galois U V := [&& (U <= V)%VS, separable U V & normalField U V]. Lemma galoisS K M E : (K <= M <= E)%VS -> galois K E -> galois M E. Proof. case/andP=> sKM sME /and3P[_ sepUV nUV]. by rewrite /galois sME (separableSl sKM) ?(normalFieldS sKM). Qed. Lemma galois_dim K E : galois K E -> \dim_K E = #|'Gal(E / K)|. Proof. case/and3P=> sKE /eq_adjoin_separable_generator-> // nKE. set a := separable_generator K E in nKE *. have [r /allP/=Er splitKa] := normalFieldP nKE a (memv_adjoin K a). rewrite (dim_sup_field (subv_adjoin K a)) mulnK ?adim_gt0 //. apply/eqP; rewrite -eqSS -adjoin_degreeE -size_minPoly splitKa size_prod_XsubC. set n := size r; rewrite eqSS -[n]card_ord. have x_ (i : 'I_n): {x | x \in 'Gal(<> / K) & x a = r`_i}. apply/sig2_eqW/normalField_root_minPoly; rewrite ?subv_adjoin ?memv_adjoin //. by rewrite splitKa root_prod_XsubC mem_nth. have /card_image <-: injective (fun i => s2val (x_ i)). move=> i j /eqP; case: (x_ i) (x_ j) => y /= galEy Dya [z /= galEx Dza]. rewrite gal_adjoin_eq // Dya Dza nth_uniq // => [/(i =P j)//|]. by rewrite -separable_prod_XsubC -splitKa; apply: separable_generatorP. apply/eqP/eq_card=> x; apply/codomP/idP=> [[i ->] | galEx]; first by case: x_. have /(nthP 0) [i ltin Dxa]: x a \in r. rewrite -root_prod_XsubC -splitKa. by rewrite root_minPoly_gal ?memv_adjoin ?subv_adjoin. exists (Ordinal ltin); apply/esym/eqP. by case: x_ => y /= galEy /eqP; rewrite Dxa gal_adjoin_eq. Qed. Lemma galois_factors K E : (K <= E)%VS -> reflect {in E, forall a, exists r, let r_a := [seq x a | x : gal_of E <- r] in [/\ r \subset 'Gal(E / K), uniq r_a & minPoly K a = \prod_(b <- r_a) ('X - b%:P)]} (galois K E). Proof. move=> sKE; apply: (iffP and3P) => [[_ sepKE nKE] a Ea | galKE]. have [r galEr splitEa] := normalField_factors sKE nKE a Ea. exists r; rewrite /= -separable_prod_XsubC !big_map -splitEa. by split=> //; apply: separableP Ea. split=> //. apply/separableP => a /galKE[r [_ Ur_a splitKa]]. by rewrite /separable_element splitKa separable_prod_XsubC. apply/(normalField_factors sKE)=> a /galKE[r [galEr _ ->]]. by rewrite big_map; exists r. Qed. Lemma splitting_galoisField K E : reflect (exists p, [/\ p \is a polyOver K, separable_poly p & splittingFieldFor K p E]) (galois K E). Proof. apply: (iffP and3P) => [[sKE sepKE nKE]|[p [Kp sep_p [r Dp defE]]]]. rewrite (eq_adjoin_separable_generator sepKE) // in nKE *. set a := separable_generator K E in nKE *; exists (minPoly K a). split; first 1 [exact: minPolyOver | exact/separable_generatorP]. have [r /= /allP Er splitKa] := normalFieldP nKE a (memv_adjoin _ _). exists r; first by rewrite splitKa eqpxx. apply/eqP; rewrite eqEsubv; apply/andP; split. by apply/Fadjoin_seqP; split => //; apply: subv_adjoin. apply/FadjoinP; split; first exact: subv_adjoin_seq. by rewrite seqv_sub_adjoin // -root_prod_XsubC -splitKa root_minPoly. have sKE: (K <= E)%VS by rewrite -defE subv_adjoin_seq. split=> //; last by apply/splitting_normalField=> //; exists p; last exists r. rewrite -defE; apply/separable_Fadjoin_seq/allP=> a r_a. by apply/separable_elementP; exists p; rewrite (eqp_root Dp) root_prod_XsubC. Qed. Lemma galois_fixedField K E : reflect (fixedField 'Gal(E / K) = K) (galois K E). Proof. apply (iffP idP) => [/and3P[sKE /separableP sepKE nKE] | fixedKE]. apply/eqP; rewrite eqEsubv galois_connection_subv ?andbT //. apply/subvP=> a /mem_fixedFieldP[Ea fixEa]; rewrite -adjoin_deg_eq1. have [r /allP Er splitKa] := normalFieldP nKE a Ea. rewrite -eqSS -size_minPoly splitKa size_prod_XsubC eqSS -/(size [:: a]). have Ur: uniq r by rewrite -separable_prod_XsubC -splitKa; apply: sepKE. rewrite -uniq_size_uniq {Ur}// => b; rewrite inE -root_prod_XsubC -splitKa. apply/eqP/idP=> [-> | pKa_b_0]; first exact: root_minPoly. by have [x /fixEa-> ->] := normalField_root_minPoly sKE nKE Ea pKa_b_0. have sKE: (K <= E)%VS by rewrite -fixedKE capvSl. apply/galois_factors=> // a Ea. pose r_pKa := [seq x a | x : gal_of E in 'Gal(E / K)]. have /fin_all_exists2[x_ galEx_ Dx_a] (b : seq_sub r_pKa) := imageP (valP b). exists (codom x_); rewrite -map_comp; set r := map _ _. have r_xa x: x \in 'Gal(E / K) -> x a \in r. move=> galEx; have r_pKa_xa: x a \in r_pKa by apply/imageP; exists x. by rewrite [x a](Dx_a (SeqSub r_pKa_xa)); apply: codom_f. have Ur: uniq r by apply/injectiveP=> b c /=; rewrite -!Dx_a => /val_inj. split=> //; first by apply/subsetP=> _ /codomP[b ->]. apply/eqP; rewrite -eqp_monic ?monic_minPoly ?monic_prod_XsubC //. apply/andP; split; last first. rewrite uniq_roots_dvdp ?uniq_rootsE // all_map. by apply/allP=> b _ /=; rewrite root_minPoly_gal. apply: minPoly_dvdp; last by rewrite root_prod_XsubC -(gal_id E a) r_xa ?group1. rewrite -fixedKE; apply/polyOverP => i; apply/fixedFieldP=> [|x galEx]. rewrite (polyOverP _) // big_map rpred_prod // => b _. by rewrite polyOverXsubC memv_gal. rewrite -coef_map rmorph_prod; congr (_ : {poly _})`_i. symmetry; rewrite (eq_big_perm (map x r)) /= ?(big_map x). by apply: eq_bigr => b _; rewrite rmorphB /= map_polyX map_polyC. have Uxr: uniq (map x r) by rewrite map_inj_uniq //; apply: fmorph_inj. have /leq_size_perm: {subset map x r <= r}. by rewrite -map_comp => _ /codomP[b ->] /=; rewrite -galM // r_xa ?groupM. by rewrite (size_map x) perm_eq_sym; case=> // /uniq_perm_eq->. Qed. Lemma mem_galTrace K E a : galois K E -> a \in E -> galTrace K E a \in K. Proof. by move/galois_fixedField => {2}<- /galTrace_fixedField. Qed. Lemma mem_galNorm K E a : galois K E -> a \in E -> galNorm K E a \in K. Proof. by move/galois_fixedField=> {2}<- /galNorm_fixedField. Qed. Lemma gal_independent_contra E (P : pred (gal_of E)) (c_ : gal_of E -> L) x : P x -> c_ x != 0 -> exists2 a, a \in E & \sum_(y | P y) c_ y * y a != 0. Proof. elim: {P}_.+1 c_ x {-2}P (ltnSn #|P|) => // n IHn c_ x P lePn Px nz_cx. rewrite ltnS (cardD1x Px) in lePn; move/IHn: lePn => {n IHn}/=IH_P. have [/eqfun_inP c_Px'_0 | ] := boolP [forall (y | P y && (y != x)), c_ y == 0]. exists 1; rewrite ?mem1v // (bigD1 x Px) /= rmorph1 mulr1. by rewrite big1 ?addr0 // => y /c_Px'_0->; rewrite mul0r. rewrite negb_forall_in => /exists_inP[y Px'y nz_cy]. have [Py /gal_eqP/eqlfun_inP/subvPn[a Ea]] := andP Px'y. rewrite memv_ker !lfun_simp => nz_yxa; pose d_ y := c_ y * (y a - x a). have /IH_P[//|b Eb nz_sumb]: d_ y != 0 by rewrite mulf_neq0. have [sumb_0|] := eqVneq (\sum_(z | P z) c_ z * z b) 0; last by exists b. exists (a * b); first exact: rpredM. rewrite -subr_eq0 -[z in _ - z](mulr0 (x a)) -[in z in _ - z]sumb_0. rewrite mulr_sumr -sumrB (bigD1 x Px) rmorphM /= mulrCA subrr add0r. congr (_ != 0): nz_sumb; apply: eq_bigr => z _. by rewrite mulrCA rmorphM -mulrBr -mulrBl mulrA. Qed. Lemma gal_independent E (P : pred (gal_of E)) (c_ : gal_of E -> L) : (forall a, a \in E -> \sum_(x | P x) c_ x * x a = 0) -> (forall x, P x -> c_ x = 0). Proof. move=> sum_cP_0 x Px; apply/eqP/idPn=> /(gal_independent_contra Px)[a Ea]. by rewrite sum_cP_0 ?eqxx. Qed. Lemma Hilbert's_theorem_90 K E x a : generator 'Gal(E / K) x -> a \in E -> reflect (exists2 b, b \in E /\ b != 0 & a = b / x b) (galNorm K E a == 1). Proof. move/(_ =P <[x]>)=> DgalE Ea. have galEx: x \in 'Gal(E / K) by rewrite DgalE cycle_id. apply: (iffP eqP) => [normEa1 | [b [Eb nzb] ->]]; last first. by rewrite galNormM galNormV galNorm_gal // mulfV // galNorm_eq0. have [x1 | ntx] := eqVneq x 1%g. exists 1; first by rewrite mem1v oner_neq0. by rewrite -{1}normEa1 /galNorm DgalE x1 cycle1 big_set1 !gal_id divr1. pose c_ y := \prod_(i < invm (injm_Zpm x) y) (x ^+ i)%g a. have nz_c1: c_ 1%g != 0 by rewrite /c_ morph1 big_ord0 oner_neq0. have [d] := @gal_independent_contra _ (mem 'Gal(E / K)) _ _ (group1 _) nz_c1. set b := \sum_(y in _) _ => Ed nz_b; exists b. split=> //; apply: rpred_sum => y galEy. by apply: rpredM; first apply: rpred_prod => i _; apply: memv_gal. apply: canRL (mulfK _) _; first by rewrite fmorph_eq0. rewrite rmorph_sum mulr_sumr [b](reindex_acts 'R _ galEx) ?astabsR //=. apply: eq_bigr => y galEy; rewrite galM // rmorphM mulrA; congr (_ * _). have /morphimP[/= i _ _ ->] /=: y \in Zpm @* Zp #[x] by rewrite im_Zpm -DgalE. have <-: Zpm (i + 1) = (Zpm i * x)%g by rewrite morphM ?mem_Zp ?order_gt1. rewrite /c_ !invmE ?mem_Zp ?order_gt1 //= addn1; set n := _.+2. transitivity (\prod_(j < i.+1) (x ^+ j)%g a). rewrite big_ord_recl gal_id rmorph_prod; congr (_ * _). by apply: eq_bigr => j _; rewrite expgSr galM ?lfunE. have [/modn_small->//||->] := ltngtP i.+1 n; first by rewrite ltnNge ltn_ord. rewrite modnn big_ord0; apply: etrans normEa1; rewrite /galNorm DgalE -im_Zpm. rewrite morphimEdom big_imset /=; last exact/injmP/injm_Zpm. by apply: eq_bigl => j /=; rewrite mem_Zp ?order_gt1. Qed. Section Matrix. Variable (E : {subfield L}) (A : {set gal_of E}). Let K := fixedField A. Lemma gal_matrix : {w : #|A|.-tuple L | {subset w <= E} /\ 0 \notin w & [/\ \matrix_(i, j < #|A|) enum_val i (tnth w j) \in unitmx, directv (\sum_i K * <[tnth w i]>) & group_set A -> (\sum_i K * <[tnth w i]>)%VS = E] }. Proof. pose nzE (w : #|A|.-tuple L) := {subset w <= E} /\ 0 \notin w. pose M w := \matrix_(i, j < #|A|) nth 1%g (enum A) i (tnth w j). have [w [Ew nzw] uM]: {w : #|A|.-tuple L | nzE w & M w \in unitmx}. rewrite {}/nzE {}/M cardE; have: uniq (enum A) := enum_uniq _. elim: (enum A) => [|x s IHs] Uxs. by exists [tuple]; rewrite // flatmx0 -(flatmx0 1%:M) unitmx1. have [s'x Us]: x \notin s /\ uniq s by apply/andP. have{IHs} [w [Ew nzw] uM] := IHs Us; set M := \matrix_(i, j) _ in uM. pose a := \row_i x (tnth w i) *m invmx M. pose c_ y := oapp (a 0) (-1) (insub (index y s)). have cx_n1 : c_ x = -1 by rewrite /c_ insubN ?index_mem. have nz_cx : c_ x != 0 by rewrite cx_n1 oppr_eq0 oner_neq0. have Px: [pred y in x :: s] x := mem_head x s. have{Px nz_cx} /sig2W[w0 Ew0 nzS] := gal_independent_contra Px nz_cx. exists [tuple of cons w0 w]. split; first by apply/allP; rewrite /= Ew0; apply/allP. rewrite inE negb_or (contraNneq _ nzS) // => <-. by rewrite big1 // => y _; rewrite rmorph0 mulr0. rewrite unitmxE -[\det _]mul1r; set M1 := \matrix_(i, j < 1 + size s) _. have <-: \det (block_mx 1 (- a) 0 1%:M) = 1 by rewrite det_ublock !det1 mulr1. rewrite -det_mulmx -[M1]submxK mulmx_block !mul0mx !mul1mx !add0r !mulNmx. have ->: drsubmx M1 = M by apply/matrixP => i j; rewrite !mxE !(tnth_nth 0). have ->: ursubmx M1 - a *m M = 0. by apply/rowP=> i; rewrite mulmxKV // !mxE !(tnth_nth 0) subrr. rewrite det_lblock unitrM andbC -unitmxE uM unitfE -oppr_eq0. congr (_ != 0): nzS; rewrite [_ - _]mx11_scalar det_scalar !mxE opprB /=. rewrite -big_uniq // big_cons /= cx_n1 mulN1r addrC; congr (_ + _). rewrite (big_nth 1%g) big_mkord; apply: eq_bigr => j _. by rewrite /c_ index_uniq // valK; congr (_ * _); rewrite !mxE. exists w => [//|]; split=> [||gA]. - by congr (_ \in unitmx): uM; apply/matrixP=> i j; rewrite !mxE -enum_val_nth. - apply/directv_sum_independent=> kw_ Kw_kw sum_kw_0 j _. have /fin_all_exists2[k_ Kk_ Dk_] i := memv_cosetP (Kw_kw i isT). pose kv := \col_i k_ i. transitivity (kv j 0 * tnth w j); first by rewrite !mxE. suffices{j}/(canRL (mulKmx uM))->: M w *m kv = 0 by rewrite mulmx0 mxE mul0r. apply/colP=> i; rewrite !mxE; pose Ai := nth 1%g (enum A) i. transitivity (Ai (\sum_j kw_ j)); last by rewrite sum_kw_0 rmorph0. rewrite rmorph_sum; apply: eq_bigr => j _; rewrite !mxE /= -/Ai. rewrite Dk_ mulrC rmorphM /=; congr (_ * _). by have /mem_fixedFieldP[_ -> //] := Kk_ j; rewrite -mem_enum mem_nth -?cardE. pose G := group gA; have G_1 := group1 G; pose iG := enum_rank_in G_1. apply/eqP; rewrite eqEsubv; apply/andP; split. apply/subv_sumP=> i _; apply: subv_trans (asubv _). by rewrite prodvS ?capvSl // -memvE Ew ?mem_tnth. apply/subvP=> w0 Ew0; apply/memv_sumP. pose wv := \col_(i < #|A|) enum_val i w0; pose v := invmx (M w) *m wv. exists (fun i => tnth w i * v i 0) => [i _|]; last first. transitivity (wv (iG 1%g) 0); first by rewrite mxE enum_rankK_in ?gal_id. rewrite -[wv](mulKVmx uM) -/v; rewrite mxE; apply: eq_bigr => i _. by congr (_ * _); rewrite !mxE -enum_val_nth enum_rankK_in ?gal_id. rewrite mulrC memv_mul ?memv_line //; apply/fixedFieldP=> [|x Gx]. rewrite mxE rpred_sum // => j _; rewrite !mxE rpredM //; last exact: memv_gal. have E_M k l: M w k l \in E by rewrite mxE memv_gal // Ew ?mem_tnth. have Edet n (N : 'M_n) (E_N : forall i j, N i j \in E): \det N \in E. by apply: rpred_sum => sigma _; rewrite rpredMsign rpred_prod. rewrite /invmx uM 2!mxE mulrC rpred_div ?Edet //. by rewrite rpredMsign Edet // => k l; rewrite 2!mxE. suffices{i} {2}<-: map_mx x v = v by rewrite [map_mx x v i 0]mxE. have uMx: map_mx x (M w) \in unitmx by rewrite map_unitmx. rewrite map_mxM map_invmx /=; apply: canLR {uMx}(mulKmx uMx) _. apply/colP=> i; rewrite !mxE; pose ix := iG (enum_val i * x)%g. have Dix b: b \in E -> enum_val ix b = x (enum_val i b). by move=> Eb; rewrite enum_rankK_in ?groupM ?enum_valP // galM ?lfunE. transitivity ((M w *m v) ix 0); first by rewrite mulKVmx // mxE Dix. rewrite mxE; apply: eq_bigr => j _; congr (_ * _). by rewrite !mxE -!enum_val_nth Dix // ?Ew ?mem_tnth. Qed. End Matrix. Lemma dim_fixedField E (G : {group gal_of E}) : #|G| = \dim_(fixedField G) E. Proof. have [w [_ nzw] [_ Edirect /(_ (groupP G))defE]] := gal_matrix G. set n := #|G|; set m := \dim (fixedField G); rewrite -defE (directvP Edirect). rewrite -[n]card_ord -(@mulnK #|'I_n| m) ?adim_gt0 //= -sum_nat_const. congr (_ %/ _)%N; apply: eq_bigr => i _. by rewrite dim_cosetv ?(memPn nzw) ?mem_tnth. Qed. Lemma dim_fixed_galois K E (G : {group gal_of E}) : galois K E -> G \subset 'Gal(E / K) -> \dim_K (fixedField G) = #|'Gal(E / K) : G|. Proof. move=> galE sGgal; have [sFE _ _] := and3P galE; apply/eqP. rewrite -divgS // eqn_div ?cardSg // dim_fixedField -galois_dim //. by rewrite mulnC muln_divA ?divnK ?field_dimS ?capvSl -?galois_connection. Qed. Lemma gal_fixedField E (G : {group gal_of E}): 'Gal(E / fixedField G) = G. Proof. apply/esym/eqP; rewrite eqEcard galois_connection_subset /= (dim_fixedField G). rewrite galois_dim //; apply/galois_fixedField/eqP. rewrite eqEsubv galois_connection_subv ?capvSl //. by rewrite fixedFieldS ?galois_connection_subset. Qed. Lemma gal_generated E (A : {set gal_of E}) : 'Gal(E / fixedField A) = <>. Proof. apply/eqP; rewrite eqEsubset gen_subG galois_connection_subset. by rewrite -[<>]gal_fixedField galS // fixedFieldS // subset_gen. Qed. Lemma fixedField_galois E (A : {set gal_of E}): galois (fixedField A) E. Proof. have: galois (fixedField <>) E. by apply/galois_fixedField; rewrite gal_fixedField. by apply: galoisS; rewrite capvSl fixedFieldS // subset_gen. Qed. Section FundamentalTheoremOfGaloisTheory. Variables E K : {subfield L}. Hypothesis galKE : galois K E. Section IntermediateField. Variable M : {subfield L}. Hypothesis (sKME : (K <= M <= E)%VS) (nKM : normalField K M). Lemma normalField_galois : galois K M. Proof. have [[sKM sME] [_ sepKE nKE]] := (andP sKME, and3P galKE). by rewrite /galois sKM (separableSr sME). Qed. Definition normalField_cast (x : gal_of E) : gal_of M := gal M x. Lemma normalField_cast_eq x : x \in 'Gal(E / K) -> {in M, normalField_cast x =1 x}. Proof. have [sKM sME] := andP sKME; have sKE := subv_trans sKM sME. rewrite gal_kAut // => /(normalField_kAut sKME nKM). by rewrite kAutE => /andP[_ /galK]. Qed. Lemma normalField_castM : {in 'Gal(E / K) &, {morph normalField_cast : x y / (x * y)%g}}. Proof. move=> x y galEx galEy /=; apply/eqP/gal_eqP => a Ma. have Ea: a \in E by have [_ /subvP->] := andP sKME. rewrite normalField_cast_eq ?groupM ?galM //=. by rewrite normalField_cast_eq ?memv_gal // normalField_cast_eq. Qed. Canonical normalField_cast_morphism := Morphism normalField_castM. Lemma normalField_ker : 'ker normalField_cast = 'Gal(E / M). Proof. have [sKM sME] := andP sKME. apply/setP=> x; apply/idP/idP=> [kerMx | galEMx]. rewrite gal_kHom //; apply/kAHomP=> a Ma. by rewrite -normalField_cast_eq ?(dom_ker kerMx) // (mker kerMx) gal_id. have galEM: x \in 'Gal(E / K) := subsetP (galS E sKM) x galEMx. apply/kerP=> //; apply/eqP/gal_eqP=> a Ma. by rewrite normalField_cast_eq // gal_id (fixed_gal sME). Qed. Lemma normalField_normal : 'Gal(E / M) <| 'Gal(E / K). Proof. by rewrite -normalField_ker ker_normal. Qed. Lemma normalField_img : normalField_cast @* 'Gal(E / K) = 'Gal(M / K). Proof. have [[sKM sME] [sKE _ nKE]] := (andP sKME, and3P galKE). apply/setP=> x; apply/idP/idP=> [/morphimP[{x}x galEx _ ->] | galMx]. rewrite gal_kHom //; apply/kAHomP=> a Ka; have Ma := subvP sKM a Ka. by rewrite normalField_cast_eq // (fixed_gal sKE). have /(kHom_to_gal sKME nKE)[y galEy eq_xy]: kHom K M x by rewrite -gal_kHom. apply/morphimP; exists y => //; apply/eqP/gal_eqP => a Ha. by rewrite normalField_cast_eq // eq_xy. Qed. Lemma normalField_isom : {f : {morphism ('Gal(E / K) / 'Gal(E / M)) >-> gal_of M} | isom ('Gal(E / K) / 'Gal (E / M)) 'Gal(M / K) f & (forall A, f @* (A / 'Gal(E / M)) = normalField_cast @* A) /\ {in 'Gal(E / K) & M, forall x, f (coset 'Gal (E / M) x) =1 x} }%g. Proof. have:= first_isom normalField_cast_morphism; rewrite normalField_ker. case=> f injf Df; exists f; first by apply/isomP; rewrite Df normalField_img. split=> [//|x a galEx /normalField_cast_eq<- //]; congr ((_ : gal_of M) a). apply: set1_inj; rewrite -!morphim_set1 ?mem_quotient ?Df //. by rewrite (subsetP (normal_norm normalField_normal)). Qed. Lemma normalField_isog : 'Gal(E / K) / 'Gal(E / M) \isog 'Gal(M / K). Proof. by rewrite -normalField_ker -normalField_img first_isog. Qed. End IntermediateField. Section IntermediateGroup. Variable G : {group gal_of E}. Hypothesis nsGgalE : G <| 'Gal(E / K). Lemma normal_fixedField_galois : galois K (fixedField G). Proof. have [[sKE sepKE nKE] [sGgal nGgal]] := (and3P galKE, andP nsGgalE). rewrite /galois -(galois_connection _ sKE) sGgal. rewrite (separableSr _ sepKE) ?capvSl //; apply/forall_inP=> f autKf. rewrite eqEdim limg_dim_eq ?(eqP (AEnd_lker0 _)) ?capv0 // leqnn andbT. apply/subvP => _ /memv_imgP[a /mem_fixedFieldP[Ea cGa] ->]. have /kAut_to_gal[x galEx -> //]: kAut K E f. rewrite /kAut (forall_inP nKE) // andbT; apply/kAHomP. by move: autKf; rewrite inE kAutfE => /kHomP[]. apply/fixedFieldP=> [|y Gy]; first exact: memv_gal. by rewrite -galM // conjgCV galM //= cGa // memJ_norm ?groupV ?(subsetP nGgal). Qed. End IntermediateGroup. End FundamentalTheoremOfGaloisTheory. End GaloisTheory. Notation "''Gal' ( V / U )" := (galoisG V U) : group_scope. Notation "''Gal' ( V / U )" := (galoisG_group V U) : Group_scope. Implicit Arguments fixedFieldP [F L E A a]. Implicit Arguments normalFieldP [F L K E]. Implicit Arguments splitting_galoisField [F L K E]. Implicit Arguments galois_fixedField [F L K E]. mathcomp-1.5/theories/zmodp.v0000644000175000017500000003221612307636117015327 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq div. Require Import fintype bigop finset prime fingroup ssralg finalg. (******************************************************************************) (* Definition of the additive group and ring Zp, represented as 'I_p *) (******************************************************************************) (* Definitions: *) (* From fintype.v: *) (* 'I_p == the subtype of integers less than p, taken here as the type of *) (* the integers mod p. *) (* This file: *) (* inZp == the natural projection from nat into the integers mod p, *) (* represented as 'I_p. Here p is implicit, but MUST be of the *) (* form n.+1. *) (* The operations: *) (* Zp0 == the identity element for addition *) (* Zp1 == the identity element for multiplication, and a generator of *) (* additive group *) (* Zp_opp == inverse function for addition *) (* Zp_add == addition *) (* Zp_mul == multiplication *) (* Zp_inv == inverse function for multiplication *) (* Note that while 'I_n.+1 has canonical finZmodType and finGroupType *) (* structures, only 'I_n.+2 has a canonical ring structure (it has, in fact, *) (* a canonical finComUnitRing structure), and hence an associated *) (* multiplicative unit finGroupType. To mitigate the issues caused by the *) (* trivial "ring" (which is, indeed is NOT a ring in the ssralg/finalg *) (* formalization), we define additional notation: *) (* 'Z_p == the type of integers mod (max p 2); this is always a proper *) (* ring, by constructions. Note that 'Z_p is provably equal to *) (* 'I_p if p > 1, and convertible to 'I_p if p is of the form *) (* n.+2. *) (* Zp p == the subgroup of integers mod (max p 1) in 'Z_p; this is thus *) (* is thus all of 'Z_p if p > 1, and else the trivial group. *) (* units_Zp p == the group of all units of 'Z_p -- i.e., the group of *) (* (multiplicative) automorphisms of Zp p. *) (* We show that Zp and units_Zp are abelian, and compute their orders. *) (* We use a similar technique to represent the prime fields: *) (* 'F_p == the finite field of integers mod the first prime divisor of *) (* maxn p 2. This is provably equal to 'Z_p and 'I_p if p is *) (* provably prime, and indeed convertible to the above if p is *) (* a concrete prime such as 2, 5 or 23. *) (* Note finally that due to the canonical structures it is possible to use *) (* 0%R instead of Zp0, and 1%R instead of Zp1 (for the latter, p must be of *) (* the form n.+2, and 1%R : nat will simplify to 1%N). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Local Open Scope ring_scope. Section ZpDef. (***********************************************************************) (* *) (* Mod p arithmetic on the finite set {0, 1, 2, ..., p - 1} *) (* *) (***********************************************************************) Variable p' : nat. Local Notation p := p'.+1. Implicit Types x y z : 'I_p. (* Standard injection; val (inZp i) = i %% p *) Definition inZp i := Ordinal (ltn_pmod i (ltn0Sn p')). Lemma modZp x : x %% p = x. Proof. by rewrite modn_small ?ltn_ord. Qed. Lemma valZpK x : inZp x = x. Proof. by apply: val_inj; rewrite /= modZp. Qed. (* Operations *) Definition Zp0 : 'I_p := ord0. Definition Zp1 := inZp 1. Definition Zp_opp x := inZp (p - x). Definition Zp_add x y := inZp (x + y). Definition Zp_mul x y := inZp (x * y). Definition Zp_inv x := if coprime p x then inZp (egcdn x p).1 else x. (* Additive group structure. *) Lemma Zp_add0z : left_id Zp0 Zp_add. Proof. exact: valZpK. Qed. Lemma Zp_addNz : left_inverse Zp0 Zp_opp Zp_add. Proof. by move=> x; apply: val_inj; rewrite /= modnDml subnK ?modnn // ltnW. Qed. Lemma Zp_addA : associative Zp_add. Proof. by move=> x y z; apply: val_inj; rewrite /= modnDml modnDmr addnA. Qed. Lemma Zp_addC : commutative Zp_add. Proof. by move=> x y; apply: val_inj; rewrite /= addnC. Qed. Definition Zp_zmodMixin := ZmodMixin Zp_addA Zp_addC Zp_add0z Zp_addNz. Canonical Zp_zmodType := Eval hnf in ZmodType 'I_p Zp_zmodMixin. Canonical Zp_finZmodType := Eval hnf in [finZmodType of 'I_p]. Canonical Zp_baseFinGroupType := Eval hnf in [baseFinGroupType of 'I_p for +%R]. Canonical Zp_finGroupType := Eval hnf in [finGroupType of 'I_p for +%R]. (* Ring operations *) Lemma Zp_mul1z : left_id Zp1 Zp_mul. Proof. by move=> x; apply: val_inj; rewrite /= modnMml mul1n modZp. Qed. Lemma Zp_mulC : commutative Zp_mul. Proof. by move=> x y; apply: val_inj; rewrite /= mulnC. Qed. Lemma Zp_mulz1 : right_id Zp1 Zp_mul. Proof. by move=> x; rewrite Zp_mulC Zp_mul1z. Qed. Lemma Zp_mulA : associative Zp_mul. Proof. by move=> x y z; apply: val_inj; rewrite /= modnMml modnMmr mulnA. Qed. Lemma Zp_mul_addr : right_distributive Zp_mul Zp_add. Proof. by move=> x y z; apply: val_inj; rewrite /= modnMmr modnDm mulnDr. Qed. Lemma Zp_mul_addl : left_distributive Zp_mul Zp_add. Proof. by move=> x y z; rewrite -!(Zp_mulC z) Zp_mul_addr. Qed. Lemma Zp_mulVz x : coprime p x -> Zp_mul (Zp_inv x) x = Zp1. Proof. move=> co_p_x; apply: val_inj; rewrite /Zp_inv co_p_x /= modnMml. by rewrite -(chinese_modl co_p_x 1 0) /chinese addn0 mul1n mulnC. Qed. Lemma Zp_mulzV x : coprime p x -> Zp_mul x (Zp_inv x) = Zp1. Proof. by move=> Ux; rewrite /= Zp_mulC Zp_mulVz. Qed. Lemma Zp_intro_unit x y : Zp_mul y x = Zp1 -> coprime p x. Proof. case=> yx1; have:= coprimen1 p. by rewrite -coprime_modr -yx1 coprime_modr coprime_mulr; case/andP. Qed. Lemma Zp_inv_out x : ~~ coprime p x -> Zp_inv x = x. Proof. by rewrite /Zp_inv => /negPf->. Qed. Lemma Zp_mulrn x n : x *+ n = inZp (x * n). Proof. apply: val_inj => /=; elim: n => [|n IHn]; first by rewrite muln0 modn_small. by rewrite !GRing.mulrS /= IHn modnDmr mulnS. Qed. Import GroupScope. Lemma Zp_mulgC : @commutative 'I_p _ mulg. Proof. exact: Zp_addC. Qed. Lemma Zp_abelian : abelian [set: 'I_p]. Proof. exact: FinRing.zmod_abelian. Qed. Lemma Zp_expg x n : x ^+ n = inZp (x * n). Proof. exact: Zp_mulrn. Qed. Lemma Zp1_expgz x : Zp1 ^+ x = x. Proof. by rewrite Zp_expg; exact: Zp_mul1z. Qed. Lemma Zp_cycle : setT = <[Zp1]>. Proof. by apply/setP=> x; rewrite -[x]Zp1_expgz inE groupX ?mem_gen ?set11. Qed. Lemma order_Zp1 : #[Zp1] = p. Proof. by rewrite orderE -Zp_cycle cardsT card_ord. Qed. End ZpDef. Implicit Arguments Zp0 [[p']]. Implicit Arguments Zp1 [[p']]. Implicit Arguments inZp [[p']]. Lemma ord1 : all_equal_to (0 : 'I_1). Proof. by case=> [[] // ?]; exact: val_inj. Qed. Lemma lshift0 m n : lshift m (0 : 'I_n.+1) = (0 : 'I_(n + m).+1). Proof. exact: val_inj. Qed. Lemma rshift1 n : @rshift 1 n =1 lift (0 : 'I_n.+1). Proof. by move=> i; exact: val_inj. Qed. Lemma split1 n i : split (i : 'I_(1 + n)) = oapp (@inr _ _) (inl _ 0) (unlift 0 i). Proof. case: unliftP => [i'|] -> /=. by rewrite -rshift1 (unsplitK (inr _ _)). by rewrite -(lshift0 n 0) (unsplitK (inl _ _)). Qed. Lemma big_ord1 R idx (op : @Monoid.law R idx) F : \big[op/idx]_(i < 1) F i = F 0. Proof. by rewrite big_ord_recl big_ord0 Monoid.mulm1. Qed. Lemma big_ord1_cond R idx (op : @Monoid.law R idx) P F : \big[op/idx]_(i < 1 | P i) F i = if P 0 then F 0 else idx. Proof. by rewrite big_mkcond big_ord1. Qed. Section ZpRing. Variable p' : nat. Local Notation p := p'.+2. Lemma Zp_nontrivial : Zp1 != 0 :> 'I_p. Proof. by []. Qed. Definition Zp_ringMixin := ComRingMixin (@Zp_mulA _) (@Zp_mulC _) (@Zp_mul1z _) (@Zp_mul_addl _) Zp_nontrivial. Canonical Zp_ringType := Eval hnf in RingType 'I_p Zp_ringMixin. Canonical Zp_finRingType := Eval hnf in [finRingType of 'I_p]. Canonical Zp_comRingType := Eval hnf in ComRingType 'I_p (@Zp_mulC _). Canonical Zp_finComRingType := Eval hnf in [finComRingType of 'I_p]. Definition Zp_unitRingMixin := ComUnitRingMixin (@Zp_mulVz _) (@Zp_intro_unit _) (@Zp_inv_out _). Canonical Zp_unitRingType := Eval hnf in UnitRingType 'I_p Zp_unitRingMixin. Canonical Zp_finUnitRingType := Eval hnf in [finUnitRingType of 'I_p]. Canonical Zp_comUnitRingType := Eval hnf in [comUnitRingType of 'I_p]. Canonical Zp_finComUnitRingType := Eval hnf in [finComUnitRingType of 'I_p]. Lemma Zp_nat n : n%:R = inZp n :> 'I_p. Proof. by apply: val_inj; rewrite [n%:R]Zp_mulrn /= modnMml mul1n. Qed. Lemma natr_Zp (x : 'I_p) : x%:R = x. Proof. by rewrite Zp_nat valZpK. Qed. Lemma natr_negZp (x : 'I_p) : (- x)%:R = - x. Proof. by apply: val_inj; rewrite /= Zp_nat /= modn_mod. Qed. Import GroupScope. Lemma unit_Zp_mulgC : @commutative {unit 'I_p} _ mulg. Proof. by move=> u v; apply: val_inj; rewrite /= GRing.mulrC. Qed. Lemma unit_Zp_expg (u : {unit 'I_p}) n : val (u ^+ n) = inZp (val u ^ n) :> 'I_p. Proof. apply: val_inj => /=; elim: n => [|n IHn] //. by rewrite expgS /= IHn expnS modnMmr. Qed. End ZpRing. Definition Zp_trunc p := p.-2. Notation "''Z_' p" := 'I_(Zp_trunc p).+2 (at level 8, p at level 2, format "''Z_' p") : type_scope. Notation "''F_' p" := 'Z_(pdiv p) (at level 8, p at level 2, format "''F_' p") : type_scope. Section Groups. Variable p : nat. Definition Zp := if p > 1 then [set: 'Z_p] else 1%g. Definition units_Zp := [set: {unit 'Z_p}]. Lemma Zp_cast : p > 1 -> (Zp_trunc p).+2 = p. Proof. by case: p => [|[]]. Qed. Lemma val_Zp_nat (p_gt1 : p > 1) n : (n%:R : 'Z_p) = (n %% p)%N :> nat. Proof. by rewrite Zp_nat /= Zp_cast. Qed. Lemma Zp_nat_mod (p_gt1 : p > 1)m : (m %% p)%:R = m%:R :> 'Z_p. Proof. by apply: ord_inj; rewrite !val_Zp_nat // modn_mod. Qed. Lemma char_Zp : p > 1 -> p%:R = 0 :> 'Z_p. Proof. by move=> p_gt1; rewrite -Zp_nat_mod ?modnn. Qed. Lemma unitZpE x : p > 1 -> ((x%:R : 'Z_p) \is a GRing.unit) = coprime p x. Proof. by move=> p_gt1; rewrite qualifE /= val_Zp_nat ?Zp_cast ?coprime_modr. Qed. Lemma Zp_group_set : group_set Zp. Proof. rewrite /Zp; case: (p > 1); exact: groupP. Qed. Canonical Zp_group := Group Zp_group_set. Lemma card_Zp : p > 0 -> #|Zp| = p. Proof. rewrite /Zp; case: p => [|[|p']] //= _; first by rewrite cards1. by rewrite cardsT card_ord. Qed. Lemma mem_Zp x : p > 1 -> x \in Zp. Proof. by rewrite /Zp => ->. Qed. Canonical units_Zp_group := [group of units_Zp]. Lemma card_units_Zp : p > 0 -> #|units_Zp| = totient p. Proof. move=> p_gt0; transitivity (totient p.-2.+2); last by case: p p_gt0 => [|[|p']]. rewrite cardsT card_sub -sum1_card big_mkcond /=. by rewrite totient_count_coprime big_mkord. Qed. Lemma units_Zp_abelian : abelian units_Zp. Proof. apply/centsP=> u _ v _; exact: unit_Zp_mulgC. Qed. End Groups. (* Field structure for primes. *) Section PrimeField. Open Scope ring_scope. Variable p : nat. Section F_prime. Hypothesis p_pr : prime p. Lemma Fp_Zcast : (Zp_trunc (pdiv p)).+2 = (Zp_trunc p).+2. Proof. by rewrite /pdiv primes_prime. Qed. Lemma Fp_cast : (Zp_trunc (pdiv p)).+2 = p. Proof. by rewrite Fp_Zcast ?Zp_cast ?prime_gt1. Qed. Lemma card_Fp : #|'F_p| = p. Proof. by rewrite card_ord Fp_cast. Qed. Lemma val_Fp_nat n : (n%:R : 'F_p) = (n %% p)%N :> nat. Proof. by rewrite Zp_nat /= Fp_cast. Qed. Lemma Fp_nat_mod m : (m %% p)%:R = m%:R :> 'F_p. Proof. by apply: ord_inj; rewrite !val_Fp_nat // modn_mod. Qed. Lemma char_Fp : p \in [char 'F_p]. Proof. by rewrite !inE -Fp_nat_mod p_pr ?modnn. Qed. Lemma char_Fp_0 : p%:R = 0 :> 'F_p. Proof. exact: GRing.charf0 char_Fp. Qed. Lemma unitFpE x : ((x%:R : 'F_p) \is a GRing.unit) = coprime p x. Proof. by rewrite pdiv_id // unitZpE // prime_gt1. Qed. End F_prime. Lemma Fp_fieldMixin : GRing.Field.mixin_of [the unitRingType of 'F_p]. Proof. move=> x nzx; rewrite qualifE /= prime_coprime ?gtnNdvd ?lt0n //. case: (ltnP 1 p) => [lt1p | ]; last by case: p => [|[|p']]. by rewrite Zp_cast ?prime_gt1 ?pdiv_prime. Qed. Definition Fp_idomainMixin := FieldIdomainMixin Fp_fieldMixin. Canonical Fp_idomainType := Eval hnf in IdomainType 'F_p Fp_idomainMixin. Canonical Fp_finIdomainType := Eval hnf in [finIdomainType of 'F_p]. Canonical Fp_fieldType := Eval hnf in FieldType 'F_p Fp_fieldMixin. Canonical Fp_finFieldType := Eval hnf in [finFieldType of 'F_p]. Canonical Fp_decFieldType := Eval hnf in [decFieldType of 'F_p for Fp_finFieldType]. End PrimeField. mathcomp-1.5/theories/path.v0000644000175000017500000010235612307636117015135 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq. (******************************************************************************) (* The basic theory of paths over an eqType; this file is essentially a *) (* complement to seq.v. Paths are non-empty sequences that obey a progression *) (* relation. They are passed around in three parts: the head and tail of the *) (* sequence, and a proof of (boolean) predicate asserting the progression. *) (* This "exploded" view is rarely embarrassing, as the first two parameters *) (* are usually inferred from the type of the third; on the contrary, it saves *) (* the hassle of constantly constructing and destructing a dependent record. *) (* We define similarly cycles, for which we allow the empty sequence, *) (* which represents a non-rooted empty cycle; by contrast, the "empty" path *) (* from a point x is the one-item sequence containing only x. *) (* We allow duplicates; uniqueness, if desired (as is the case for several *) (* geometric constructions), must be asserted separately. We do provide *) (* shorthand, but only for cycles, because the equational properties of *) (* "path" and "uniq" are unfortunately incompatible (esp. wrt "cat"). *) (* We define notations for the common cases of function paths, where the *) (* progress relation is actually a function. In detail: *) (* path e x p == x :: p is an e-path [:: x_0; x_1; ... ; x_n], i.e., we *) (* e x_i x_{i+1} for all i < n. The path x :: p starts at x *) (* and ends at last x p. *) (* fpath f x p == x :: p is an f-path, where f is a function, i.e., p is of *) (* the form [:: f x; f (f x); ...]. This is just a notation *) (* for path (frel f) x p. *) (* sorted e s == s is an e-sorted sequence: either s = [::], or s = x :: p *) (* is an e-path (this is oten used with e = leq or ltn). *) (* cycle e c == c is an e-cycle: either c = [::], or c = x :: p with *) (* x :: (rcons p x) an e-path. *) (* fcycle f c == c is an f-cycle, for a function f. *) (* traject f x n == the f-path of size n starting at x *) (* := [:: x; f x; ...; iter n.-1 f x] *) (* looping f x n == the f-paths of size greater than n starting at x loop *) (* back, or, equivalently, traject f x n contains all *) (* iterates of f at x. *) (* merge e s1 s2 == the e-sorted merge of sequences s1 and s2: this is always *) (* a permutation of s1 ++ s2, and is e-sorted when s1 and s2 *) (* are and e is total. *) (* sort e s == a permutation of the sequence s, that is e-sorted when e *) (* is total (computed by a merge sort with the merge function *) (* above). *) (* mem2 s x y == x, then y occur in the sequence (path) s; this is *) (* non-strict: mem2 s x x = (x \in s). *) (* next c x == the successor of the first occurrence of x in the sequence *) (* c (viewed as a cycle), or x if x \notin c. *) (* prev c x == the predecessor of the first occurrence of x in the *) (* sequence c (viewed as a cycle), or x if x \notin c. *) (* arc c x y == the sub-arc of the sequece c (viewed as a cycle) starting *) (* at the first occurrence of x in c, and ending just before *) (* the next ocurrence of y (in cycle order); arc c x y *) (* returns an unspecified sub-arc of c if x and y do not both *) (* occur in c. *) (* ucycle e c <-> ucycleb e c (ucycle e c is a Coercion target of type Prop) *) (* ufcycle f c <-> c is a simple f-cycle, for a function f. *) (* shorten x p == the tail a duplicate-free subpath of x :: p with the same *) (* endpoints (x and last x p), obtained by removing all loops *) (* from x :: p. *) (* rel_base e e' h b <-> the function h is a functor from relation e to *) (* relation e', EXCEPT at points whose image under h satisfy *) (* the "base" predicate b: *) (* e' (h x) (h y) = e x y UNLESS b (h x) holds *) (* This is the statement of the side condition of the path *) (* functorial mapping lemma map_path. *) (* fun_base f f' h b <-> the function h is a functor from function f to f', *) (* except at the preimage of predicate b under h. *) (* We also provide three segmenting dependently-typed lemmas (splitP, splitPl *) (* and splitPr) whose elimination split a path x0 :: p at an internal point x *) (* as follows: *) (* - splitP applies when x \in p; it replaces p with (rcons p1 x ++ p2), so *) (* that x appears explicitly at the end of the left part. The elimination *) (* of splitP will also simultaneously replace take (index x p) with p1 and *) (* drop (index x p).+1 p with p2. *) (* - splitPl applies when x \in x0 :: p; it replaces p with p1 ++ p2 and *) (* simulaneously generates an equation x = last x0 p. *) (* - splitPr applies when x \in p; it replaces p with (p1 ++ x :: p2), so x *) (* appears explicitly at the start of the right part. *) (* The parts p1 and p2 are computed using index/take/drop in all cases, but *) (* only splitP attemps to subsitute the explicit values. The substitution of *) (* p can be deferred using the dependent equation generation feature of *) (* ssreflect, e.g.: case/splitPr def_p: {1}p / x_in_p => [p1 p2] generates *) (* the equation p = p1 ++ p2 instead of performing the substitution outright. *) (* Similarly, eliminating the loop removal lemma shortenP simultaneously *) (* replaces shorten e x p with a fresh constant p', and last x p with *) (* last x p'. *) (* Note that although all "path" functions actually operate on the *) (* underlying sequence, we provide a series of lemmas that define their *) (* interaction with thepath and cycle predicates, e.g., the cat_path equation *) (* can be used to split the path predicate after splitting the underlying *) (* sequence. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Section Paths. Variables (n0 : nat) (T : Type). Section Path. Variables (x0_cycle : T) (e : rel T). Fixpoint path x (p : seq T) := if p is y :: p' then e x y && path y p' else true. Lemma cat_path x p1 p2 : path x (p1 ++ p2) = path x p1 && path (last x p1) p2. Proof. by elim: p1 x => [|y p1 Hrec] x //=; rewrite Hrec -!andbA. Qed. Lemma rcons_path x p y : path x (rcons p y) = path x p && e (last x p) y. Proof. by rewrite -cats1 cat_path /= andbT. Qed. Lemma pathP x p x0 : reflect (forall i, i < size p -> e (nth x0 (x :: p) i) (nth x0 p i)) (path x p). Proof. elim: p x => [|y p IHp] x /=; first by left. apply: (iffP andP) => [[e_xy /IHp e_p [] //] | e_p]. by split; [exact: (e_p 0) | apply/(IHp y) => i; exact: e_p i.+1]. Qed. Definition cycle p := if p is x :: p' then path x (rcons p' x) else true. Lemma cycle_path p : cycle p = path (last x0_cycle p) p. Proof. by case: p => //= x p; rewrite rcons_path andbC. Qed. Lemma rot_cycle p : cycle (rot n0 p) = cycle p. Proof. case: n0 p => [|n] [|y0 p] //=; first by rewrite /rot /= cats0. rewrite /rot /= -{3}(cat_take_drop n p) -cats1 -catA cat_path. case: (drop n p) => [|z0 q]; rewrite /= -cats1 !cat_path /= !andbT andbC //. by rewrite last_cat; repeat bool_congr. Qed. Lemma rotr_cycle p : cycle (rotr n0 p) = cycle p. Proof. by rewrite -rot_cycle rotrK. Qed. End Path. Lemma eq_path e e' : e =2 e' -> path e =2 path e'. Proof. by move=> ee' x p; elim: p x => //= y p IHp x; rewrite ee' IHp. Qed. Lemma eq_cycle e e' : e =2 e' -> cycle e =1 cycle e'. Proof. by move=> ee' [|x p] //=; exact: eq_path. Qed. Lemma sub_path e e' : subrel e e' -> forall x p, path e x p -> path e' x p. Proof. by move=> ee' x p; elim: p x => //= y p IHp x /andP[/ee'-> /IHp]. Qed. Lemma rev_path e x p : path e (last x p) (rev (belast x p)) = path (fun z => e^~ z) x p. Proof. elim: p x => //= y p IHp x; rewrite rev_cons rcons_path -{}IHp andbC. by rewrite -(last_cons x) -rev_rcons -lastI rev_cons last_rcons. Qed. End Paths. Implicit Arguments pathP [T e x p]. Prenex Implicits pathP. Section EqPath. Variables (n0 : nat) (T : eqType) (x0_cycle : T) (e : rel T). Implicit Type p : seq T. CoInductive split x : seq T -> seq T -> seq T -> Type := Split p1 p2 : split x (rcons p1 x ++ p2) p1 p2. Lemma splitP p x (i := index x p) : x \in p -> split x p (take i p) (drop i.+1 p). Proof. move=> p_x; have lt_ip: i < size p by rewrite index_mem. by rewrite -{1}(cat_take_drop i p) (drop_nth x lt_ip) -cat_rcons nth_index. Qed. CoInductive splitl x1 x : seq T -> Type := Splitl p1 p2 of last x1 p1 = x : splitl x1 x (p1 ++ p2). Lemma splitPl x1 p x : x \in x1 :: p -> splitl x1 x p. Proof. rewrite inE; case: eqP => [->| _ /splitP[]]; first by rewrite -(cat0s p). by split; exact: last_rcons. Qed. CoInductive splitr x : seq T -> Type := Splitr p1 p2 : splitr x (p1 ++ x :: p2). Lemma splitPr p x : x \in p -> splitr x p. Proof. by case/splitP=> p1 p2; rewrite cat_rcons. Qed. Fixpoint next_at x y0 y p := match p with | [::] => if x == y then y0 else x | y' :: p' => if x == y then y' else next_at x y0 y' p' end. Definition next p x := if p is y :: p' then next_at x y y p' else x. Fixpoint prev_at x y0 y p := match p with | [::] => if x == y0 then y else x | y' :: p' => if x == y' then y else prev_at x y0 y' p' end. Definition prev p x := if p is y :: p' then prev_at x y y p' else x. Lemma next_nth p x : next p x = if x \in p then if p is y :: p' then nth y p' (index x p) else x else x. Proof. case: p => //= y0 p. elim: p {2 3 5}y0 => [|y' p IHp] y /=; rewrite (eq_sym y) inE; by case: ifP => // _; exact: IHp. Qed. Lemma prev_nth p x : prev p x = if x \in p then if p is y :: p' then nth y p (index x p') else x else x. Proof. case: p => //= y0 p; rewrite inE orbC. elim: p {2 5}y0 => [|y' p IHp] y; rewrite /= ?inE // (eq_sym y'). by case: ifP => // _; exact: IHp. Qed. Lemma mem_next p x : (next p x \in p) = (x \in p). Proof. rewrite next_nth; case p_x: (x \in p) => //. case: p (index x p) p_x => [|y0 p'] //= i _; rewrite inE. have [lt_ip | ge_ip] := ltnP i (size p'); first by rewrite orbC mem_nth. by rewrite nth_default ?eqxx. Qed. Lemma mem_prev p x : (prev p x \in p) = (x \in p). Proof. rewrite prev_nth; case p_x: (x \in p) => //; case: p => [|y0 p] // in p_x *. by apply mem_nth; rewrite /= ltnS index_size. Qed. (* ucycleb is the boolean predicate, but ucycle is defined as a Prop *) (* so that it can be used as a coercion target. *) Definition ucycleb p := cycle e p && uniq p. Definition ucycle p : Prop := cycle e p && uniq p. (* Projections, used for creating local lemmas. *) Lemma ucycle_cycle p : ucycle p -> cycle e p. Proof. by case/andP. Qed. Lemma ucycle_uniq p : ucycle p -> uniq p. Proof. by case/andP. Qed. Lemma next_cycle p x : cycle e p -> x \in p -> e x (next p x). Proof. case: p => //= y0 p; elim: p {1 3 5}y0 => [|z p IHp] y /=; rewrite inE. by rewrite andbT; case: (x =P y) => // ->. by case/andP=> eyz /IHp; case: (x =P y) => // ->. Qed. Lemma prev_cycle p x : cycle e p -> x \in p -> e (prev p x) x. Proof. case: p => //= y0 p; rewrite inE orbC. elim: p {1 5}y0 => [|z p IHp] y /=; rewrite ?inE. by rewrite andbT; case: (x =P y0) => // ->. by case/andP=> eyz /IHp; case: (x =P z) => // ->. Qed. Lemma rot_ucycle p : ucycle (rot n0 p) = ucycle p. Proof. by rewrite /ucycle rot_uniq rot_cycle. Qed. Lemma rotr_ucycle p : ucycle (rotr n0 p) = ucycle p. Proof. by rewrite /ucycle rotr_uniq rotr_cycle. Qed. (* The "appears no later" partial preorder defined by a path. *) Definition mem2 p x y := y \in drop (index x p) p. Lemma mem2l p x y : mem2 p x y -> x \in p. Proof. by rewrite /mem2 -!index_mem size_drop => /ltn_predK; rewrite -subn_gt0 => <-. Qed. Lemma mem2lf {p x y} : x \notin p -> mem2 p x y = false. Proof. by apply: contraNF; exact: mem2l. Qed. Lemma mem2r p x y : mem2 p x y -> y \in p. Proof. rewrite /mem2 => pxy. by rewrite -(cat_take_drop (index x p) p) mem_cat pxy orbT. Qed. Lemma mem2rf {p x y} : y \notin p -> mem2 p x y = false. Proof. by apply: contraNF; exact: mem2r. Qed. Lemma mem2_cat p1 p2 x y : mem2 (p1 ++ p2) x y = mem2 p1 x y || mem2 p2 x y || (x \in p1) && (y \in p2). Proof. rewrite {1}/mem2 index_cat drop_cat; have [p1x | p1'x] := boolP (x \in p1). rewrite index_mem p1x mem_cat /= -orbA. by have [|p2'y] := boolP (y \in p2); [rewrite !orbT | rewrite (mem2rf p2'y)]. by rewrite ltnNge leq_addr /= orbF addKn (mem2lf p1'x). Qed. Lemma mem2_splice p1 p3 x y p2 : mem2 (p1 ++ p3) x y -> mem2 (p1 ++ p2 ++ p3) x y. Proof. move=> p13xy; move: p13xy; rewrite !mem2_cat mem_cat -orbA. by case/or3P=> [-> | -> | /andP[-> ->]]; rewrite ?orbT. Qed. Lemma mem2_splice1 p1 p3 x y z : mem2 (p1 ++ p3) x y -> mem2 (p1 ++ z :: p3) x y. Proof. exact: (mem2_splice [::z]). Qed. Lemma mem2_cons x p y : mem2 (x :: p) y =1 (if x == y then mem (x :: p) : pred T else mem2 p y). Proof. by move=> z; rewrite {1}/mem2 /=; case (x == y). Qed. Lemma mem2_last y0 p x : mem2 (y0 :: p) x (last y0 p) = (x \in y0 :: p). Proof. apply/idP/idP; first exact: mem2l. rewrite -index_mem /mem2; move: (index x _) => i le_ip. by rewrite lastI drop_rcons ?size_belast // mem_rcons mem_head. Qed. Lemma mem2l_cat {p1 p2 x} : x \notin p1 -> mem2 (p1 ++ p2) x =1 mem2 p2 x. Proof. by move=> p1'x y; rewrite mem2_cat (negPf p1'x) mem2lf ?orbF. Qed. Lemma mem2r_cat {p1 p2 x y} : y \notin p2 -> mem2 (p1 ++ p2) x y = mem2 p1 x y. Proof. by move=> p2'y; rewrite mem2_cat (negPf p2'y) -orbA orbC andbF mem2rf. Qed. Lemma mem2lr_splice {p1 p2 p3 x y} : x \notin p2 -> y \notin p2 -> mem2 (p1 ++ p2 ++ p3) x y = mem2 (p1 ++ p3) x y. Proof. move=> p2'x p2'y; rewrite catA !mem2_cat !mem_cat. by rewrite (negPf p2'x) (negPf p2'y) (mem2lf p2'x) andbF !orbF. Qed. CoInductive split2r x y : seq T -> Type := Split2r p1 p2 of y \in x :: p2 : split2r x y (p1 ++ x :: p2). Lemma splitP2r p x y : mem2 p x y -> split2r x y p. Proof. move=> pxy; have px := mem2l pxy. have:= pxy; rewrite /mem2 (drop_nth x) ?index_mem ?nth_index //. by case/splitP: px => p1 p2; rewrite cat_rcons. Qed. Fixpoint shorten x p := if p is y :: p' then if x \in p then shorten x p' else y :: shorten y p' else [::]. CoInductive shorten_spec x p : T -> seq T -> Type := ShortenSpec p' of path e x p' & uniq (x :: p') & subpred (mem p') (mem p) : shorten_spec x p (last x p') p'. Lemma shortenP x p : path e x p -> shorten_spec x p (last x p) (shorten x p). Proof. move=> e_p; have: x \in x :: p by exact: mem_head. elim: p x {1 3 5}x e_p => [|y2 p IHp] x y1. by rewrite mem_seq1 => _ /eqP->. rewrite inE orbC /= => /andP[ey12 /IHp {IHp}IHp]. case: ifPn => [y2p_x _ | not_y2p_x /eqP def_x]. have [p' e_p' Up' p'p] := IHp _ y2p_x. by split=> // y /p'p; exact: predU1r. have [p' e_p' Up' p'p] := IHp y2 (mem_head y2 p). have{p'p} p'p z: z \in y2 :: p' -> z \in y2 :: p. by rewrite !inE; case: (z == y2) => // /p'p. rewrite -(last_cons y1) def_x; split=> //=; first by rewrite ey12. by rewrite (contra (p'p y1)) -?def_x. Qed. End EqPath. (* Ordered paths and sorting. *) Section SortSeq. Variable T : eqType. Variable leT : rel T. Definition sorted s := if s is x :: s' then path leT x s' else true. Lemma path_sorted x s : path leT x s -> sorted s. Proof. by case: s => //= y s /andP[]. Qed. Lemma path_min_sorted x s : {in s, forall y, leT x y} -> path leT x s = sorted s. Proof. by case: s => //= y s -> //; exact: mem_head. Qed. Section Transitive. Hypothesis leT_tr : transitive leT. Lemma subseq_order_path x s1 s2 : subseq s1 s2 -> path leT x s2 -> path leT x s1. Proof. elim: s2 x s1 => [|y s2 IHs] x [|z s1] //= {IHs}/(IHs y). case: eqP => [-> | _] IHs /andP[] => [-> // | leTxy /IHs /=]. by case/andP=> /(leT_tr leTxy)->. Qed. Lemma order_path_min x s : path leT x s -> all (leT x) s. Proof. move/subseq_order_path=> le_x_s; apply/allP=> y. by rewrite -sub1seq => /le_x_s/andP[]. Qed. Lemma subseq_sorted s1 s2 : subseq s1 s2 -> sorted s2 -> sorted s1. Proof. case: s1 s2 => [|x1 s1] [|x2 s2] //= sub_s12 /(subseq_order_path sub_s12). by case: eqP => [-> | _ /andP[]]. Qed. Lemma sorted_filter a s : sorted s -> sorted (filter a s). Proof. exact: subseq_sorted (filter_subseq a s). Qed. Lemma sorted_uniq : irreflexive leT -> forall s, sorted s -> uniq s. Proof. move=> leT_irr; elim=> //= x s IHs s_ord. rewrite (IHs (path_sorted s_ord)) andbT; apply/negP=> s_x. by case/allPn: (order_path_min s_ord); exists x; rewrite // leT_irr. Qed. Lemma eq_sorted : antisymmetric leT -> forall s1 s2, sorted s1 -> sorted s2 -> perm_eq s1 s2 -> s1 = s2. Proof. move=> leT_asym; elim=> [|x1 s1 IHs1] s2 //= ord_s1 ord_s2 eq_s12. by case: {+}s2 (perm_eq_size eq_s12). have s2_x1: x1 \in s2 by rewrite -(perm_eq_mem eq_s12) mem_head. case: s2 s2_x1 eq_s12 ord_s2 => //= x2 s2; rewrite in_cons. case: eqP => [<- _| ne_x12 /= s2_x1] eq_s12 ord_s2. by rewrite {IHs1}(IHs1 s2) ?(@path_sorted x1) // -(perm_cons x1). case: (ne_x12); apply: leT_asym; rewrite (allP (order_path_min ord_s2)) //. have: x2 \in x1 :: s1 by rewrite (perm_eq_mem eq_s12) mem_head. case/predU1P=> [eq_x12 | s1_x2]; first by case ne_x12. by rewrite (allP (order_path_min ord_s1)). Qed. Lemma eq_sorted_irr : irreflexive leT -> forall s1 s2, sorted s1 -> sorted s2 -> s1 =i s2 -> s1 = s2. Proof. move=> leT_irr s1 s2 s1_sort s2_sort eq_s12. have: antisymmetric leT. by move=> m n /andP[? ltnm]; case/idP: (leT_irr m); exact: leT_tr ltnm. by move/eq_sorted; apply=> //; apply: uniq_perm_eq => //; exact: sorted_uniq. Qed. End Transitive. Hypothesis leT_total : total leT. Fixpoint merge s1 := if s1 is x1 :: s1' then let fix merge_s1 s2 := if s2 is x2 :: s2' then if leT x2 x1 then x2 :: merge_s1 s2' else x1 :: merge s1' s2 else s1 in merge_s1 else id. Lemma merge_path x s1 s2 : path leT x s1 -> path leT x s2 -> path leT x (merge s1 s2). Proof. elim: s1 s2 x => //= x1 s1 IHs1. elim=> //= x2 s2 IHs2 x /andP[le_x_x1 ord_s1] /andP[le_x_x2 ord_s2]. case: ifP => le_x21 /=; first by rewrite le_x_x2 {}IHs2 // le_x21. by rewrite le_x_x1 IHs1 //=; have:= leT_total x2 x1; rewrite le_x21 /= => ->. Qed. Lemma merge_sorted s1 s2 : sorted s1 -> sorted s2 -> sorted (merge s1 s2). Proof. case: s1 s2 => [|x1 s1] [|x2 s2] //= ord_s1 ord_s2. case: ifP => le_x21 /=. by apply: (@merge_path x2 (x1 :: s1)) => //=; rewrite le_x21. by apply: merge_path => //=; have:= leT_total x2 x1; rewrite le_x21 /= => ->. Qed. Lemma perm_merge s1 s2 : perm_eql (merge s1 s2) (s1 ++ s2). Proof. apply/perm_eqlP; rewrite perm_eq_sym; elim: s1 s2 => //= x1 s1 IHs1. elim=> [|x2 s2 IHs2]; rewrite /= ?cats0 //. case: ifP => _ /=; last by rewrite perm_cons. by rewrite (perm_catCA (_ :: _) [::x2]) perm_cons. Qed. Lemma mem_merge s1 s2 : merge s1 s2 =i s1 ++ s2. Proof. by apply: perm_eq_mem; rewrite perm_merge. Qed. Lemma size_merge s1 s2 : size (merge s1 s2) = size (s1 ++ s2). Proof. by apply: perm_eq_size; rewrite perm_merge. Qed. Lemma merge_uniq s1 s2 : uniq (merge s1 s2) = uniq (s1 ++ s2). Proof. by apply: perm_eq_uniq; rewrite perm_merge. Qed. Fixpoint merge_sort_push s1 ss := match ss with | [::] :: ss' | [::] as ss' => s1 :: ss' | s2 :: ss' => [::] :: merge_sort_push (merge s1 s2) ss' end. Fixpoint merge_sort_pop s1 ss := if ss is s2 :: ss' then merge_sort_pop (merge s1 s2) ss' else s1. Fixpoint merge_sort_rec ss s := if s is [:: x1, x2 & s'] then let s1 := if leT x1 x2 then [:: x1; x2] else [:: x2; x1] in merge_sort_rec (merge_sort_push s1 ss) s' else merge_sort_pop s ss. Definition sort := merge_sort_rec [::]. Lemma sort_sorted s : sorted (sort s). Proof. rewrite /sort; have allss: all sorted [::] by []. elim: {s}_.+1 {-2}s [::] allss (ltnSn (size s)) => // n IHn s ss allss. have: sorted s -> sorted (merge_sort_pop s ss). elim: ss allss s => //= s2 ss IHss /andP[ord_s2 ord_ss] s ord_s. exact: IHss ord_ss _ (merge_sorted ord_s ord_s2). case: s => [|x1 [|x2 s _]]; try by auto. move/ltnW/IHn; apply=> {n IHn s}; set s1 := if _ then _ else _. have: sorted s1 by exact: (@merge_sorted [::x2] [::x1]). elim: ss {x1 x2}s1 allss => /= [|s2 ss IHss] s1; first by rewrite andbT. case/andP=> ord_s2 ord_ss ord_s1. by case: {1}s2=> /= [|_ _]; [rewrite ord_s1 | exact: IHss (merge_sorted _ _)]. Qed. Lemma perm_sort s : perm_eql (sort s) s. Proof. rewrite /sort; apply/perm_eqlP; pose catss := foldr (@cat T) [::]. rewrite perm_eq_sym -{1}[s]/(catss [::] ++ s). elim: {s}_.+1 {-2}s [::] (ltnSn (size s)) => // n IHn s ss. have: perm_eq (catss ss ++ s) (merge_sort_pop s ss). elim: ss s => //= s2 ss IHss s1; rewrite -{IHss}(perm_eqrP (IHss _)). by rewrite perm_catC catA perm_catC perm_cat2l -perm_merge. case: s => // x1 [//|x2 s _]; move/ltnW; move/IHn=> {n IHn}IHs. rewrite -{IHs}(perm_eqrP (IHs _)) ifE; set s1 := if_expr _ _ _. rewrite (catA _ [::_;_] s) {s}perm_cat2r. apply: (@perm_eq_trans _ (catss ss ++ s1)). by rewrite perm_cat2l /s1 -ifE; case: ifP; rewrite // (perm_catC [::_]). elim: ss {x1 x2}s1 => /= [|s2 ss IHss] s1; first by rewrite cats0. rewrite perm_catC; case def_s2: {2}s2=> /= [|y s2']; first by rewrite def_s2. by rewrite catA -{IHss}(perm_eqrP (IHss _)) perm_catC perm_cat2l -perm_merge. Qed. Lemma mem_sort s : sort s =i s. Proof. by apply: perm_eq_mem; rewrite perm_sort. Qed. Lemma size_sort s : size (sort s) = size s. Proof. by apply: perm_eq_size; rewrite perm_sort. Qed. Lemma sort_uniq s : uniq (sort s) = uniq s. Proof. by apply: perm_eq_uniq; rewrite perm_sort. Qed. Lemma perm_sortP : transitive leT -> antisymmetric leT -> forall s1 s2, reflect (sort s1 = sort s2) (perm_eq s1 s2). Proof. move=> leT_tr leT_asym s1 s2. apply: (iffP idP) => eq12; last by rewrite -perm_sort eq12 perm_sort. apply: eq_sorted; rewrite ?sort_sorted //. by rewrite perm_sort (perm_eqlP eq12) -perm_sort. Qed. End SortSeq. Lemma rev_sorted (T : eqType) (leT : rel T) s : sorted leT (rev s) = sorted (fun y x => leT x y) s. Proof. by case: s => //= x p; rewrite -rev_path lastI rev_rcons. Qed. Lemma ltn_sorted_uniq_leq s : sorted ltn s = uniq s && sorted leq s. Proof. case: s => //= n s; elim: s n => //= m s IHs n. rewrite inE ltn_neqAle negb_or IHs -!andbA. case sn: (n \in s); last do !bool_congr. rewrite andbF; apply/and5P=> [[ne_nm lenm _ _ le_ms]]; case/negP: ne_nm. rewrite eqn_leq lenm; exact: (allP (order_path_min leq_trans le_ms)). Qed. Lemma iota_sorted i n : sorted leq (iota i n). Proof. by elim: n i => // [[|n] //= IHn] i; rewrite IHn leqW. Qed. Lemma iota_ltn_sorted i n : sorted ltn (iota i n). Proof. by rewrite ltn_sorted_uniq_leq iota_sorted iota_uniq. Qed. (* Function trajectories. *) Notation fpath f := (path (coerced_frel f)). Notation fcycle f := (cycle (coerced_frel f)). Notation ufcycle f := (ucycle (coerced_frel f)). Prenex Implicits path next prev cycle ucycle mem2. Section Trajectory. Variables (T : Type) (f : T -> T). Fixpoint traject x n := if n is n'.+1 then x :: traject (f x) n' else [::]. Lemma trajectS x n : traject x n.+1 = x :: traject (f x) n. Proof. by []. Qed. Lemma trajectSr x n : traject x n.+1 = rcons (traject x n) (iter n f x). Proof. by elim: n x => //= n IHn x; rewrite IHn -iterSr. Qed. Lemma last_traject x n : last x (traject (f x) n) = iter n f x. Proof. by case: n => // n; rewrite iterSr trajectSr last_rcons. Qed. Lemma traject_iteri x n : traject x n = iteri n (fun i => rcons^~ (iter i f x)) [::]. Proof. by elim: n => //= n <-; rewrite -trajectSr. Qed. Lemma size_traject x n : size (traject x n) = n. Proof. by elim: n x => //= n IHn x //=; rewrite IHn. Qed. Lemma nth_traject i n : i < n -> forall x, nth x (traject x n) i = iter i f x. Proof. elim: n => // n IHn; rewrite ltnS leq_eqVlt => le_i_n x. rewrite trajectSr nth_rcons size_traject. case: ltngtP le_i_n => [? _||->] //; exact: IHn. Qed. End Trajectory. Section EqTrajectory. Variables (T : eqType) (f : T -> T). Lemma eq_fpath f' : f =1 f' -> fpath f =2 fpath f'. Proof. by move/eq_frel/eq_path. Qed. Lemma eq_fcycle f' : f =1 f' -> fcycle f =1 fcycle f'. Proof. by move/eq_frel/eq_cycle. Qed. Lemma fpathP x p : reflect (exists n, p = traject f (f x) n) (fpath f x p). Proof. elim: p x => [|y p IHp] x; first by left; exists 0. rewrite /= andbC; case: IHp => [fn_p | not_fn_p]; last first. by right=> [] [[//|n]] [<- fn_p]; case: not_fn_p; exists n. apply: (iffP eqP) => [-> | [[] // _ []//]]. by have [n ->] := fn_p; exists n.+1. Qed. Lemma fpath_traject x n : fpath f x (traject f (f x) n). Proof. by apply/(fpathP x); exists n. Qed. Definition looping x n := iter n f x \in traject f x n. Lemma loopingP x n : reflect (forall m, iter m f x \in traject f x n) (looping x n). Proof. apply: (iffP idP) => loop_n; last exact: loop_n. case: n => // n in loop_n *; elim=> [|m /= IHm]; first exact: mem_head. move: (fpath_traject x n) loop_n; rewrite /looping !iterS -last_traject /=. move: (iter m f x) IHm => y /splitPl[p1 p2 def_y]. rewrite cat_path last_cat def_y; case: p2 => // z p2 /and3P[_ /eqP-> _] _. by rewrite inE mem_cat mem_head !orbT. Qed. Lemma trajectP x n y : reflect (exists2 i, i < n & y = iter i f x) (y \in traject f x n). Proof. elim: n x => [|n IHn] x /=; first by right; case. rewrite inE; have [-> | /= neq_xy] := eqP; first by left; exists 0. apply: {IHn}(iffP (IHn _)) => [[i] | [[|i]]] // lt_i_n ->. by exists i.+1; rewrite ?iterSr. by exists i; rewrite ?iterSr. Qed. Lemma looping_uniq x n : uniq (traject f x n.+1) = ~~ looping x n. Proof. rewrite /looping; elim: n x => [|n IHn] x //. rewrite {-3}[n.+1]lock /= -lock {}IHn -iterSr -negb_or inE; congr (~~ _). apply: orb_id2r => /trajectP no_loop. apply/idP/eqP => [/trajectP[m le_m_n def_x] | {1}<-]; last first. by rewrite iterSr -last_traject mem_last. have loop_m: looping x m.+1 by rewrite /looping iterSr -def_x mem_head. have/trajectP[[|i] // le_i_m def_fn1x] := loopingP _ _ loop_m n.+1. by case: no_loop; exists i; rewrite -?iterSr // -ltnS (leq_trans le_i_m). Qed. End EqTrajectory. Implicit Arguments fpathP [T f x p]. Implicit Arguments loopingP [T f x n]. Implicit Arguments trajectP [T f x n y]. Prenex Implicits traject fpathP loopingP trajectP. Section UniqCycle. Variables (n0 : nat) (T : eqType) (e : rel T) (p : seq T). Hypothesis Up : uniq p. Lemma prev_next : cancel (next p) (prev p). Proof. move=> x; rewrite prev_nth mem_next next_nth; case p_x: (x \in p) => //. case def_p: p Up p_x => // [y q]; rewrite -{-1}def_p => /= /andP[not_qy Uq] p_x. rewrite -{2}(nth_index y p_x); congr (nth y _ _); set i := index x p. have: ~~ (size q < i) by rewrite -index_mem -/i def_p leqNgt in p_x. case: ltngtP => // [lt_i_q | ->] _; first by rewrite index_uniq. by apply/eqP; rewrite nth_default // eqn_leq index_size leqNgt index_mem. Qed. Lemma next_prev : cancel (prev p) (next p). Proof. move=> x; rewrite next_nth mem_prev prev_nth; case p_x: (x \in p) => //. case def_p: p p_x => // [y q]; rewrite -def_p => p_x. rewrite index_uniq //; last by rewrite def_p ltnS index_size. case q_x: (x \in q); first exact: nth_index. rewrite nth_default; last by rewrite leqNgt index_mem q_x. by apply/eqP; rewrite def_p inE q_x orbF eq_sym in p_x. Qed. Lemma cycle_next : fcycle (next p) p. Proof. case def_p: {-2}p Up => [|x q] Uq //. apply/(pathP x)=> i; rewrite size_rcons => le_i_q. rewrite -cats1 -cat_cons nth_cat le_i_q /= next_nth {}def_p mem_nth //. rewrite index_uniq // nth_cat /= ltn_neqAle andbC -ltnS le_i_q. by case: (i =P _) => //= ->; rewrite subnn nth_default. Qed. Lemma cycle_prev : cycle (fun x y => x == prev p y) p. Proof. apply: etrans cycle_next; symmetry; case def_p: p => [|x q] //. apply: eq_path; rewrite -def_p; exact (can2_eq prev_next next_prev). Qed. Lemma cycle_from_next : (forall x, x \in p -> e x (next p x)) -> cycle e p. Proof. case: p (next p) cycle_next => //= [x q] n; rewrite -(belast_rcons x q x). move: {q}(rcons q x) => q n_q; move/allP. by elim: q x n_q => //= _ q IHq x /andP[/eqP <- n_q] /andP[-> /IHq->]. Qed. Lemma cycle_from_prev : (forall x, x \in p -> e (prev p x) x) -> cycle e p. Proof. move=> e_p; apply: cycle_from_next => x p_x. by rewrite -{1}[x]prev_next e_p ?mem_next. Qed. Lemma next_rot : next (rot n0 p) =1 next p. Proof. move=> x; have n_p := cycle_next; rewrite -(rot_cycle n0) in n_p. case p_x: (x \in p); last by rewrite !next_nth mem_rot p_x. by rewrite (eqP (next_cycle n_p _)) ?mem_rot. Qed. Lemma prev_rot : prev (rot n0 p) =1 prev p. Proof. move=> x; have p_p := cycle_prev; rewrite -(rot_cycle n0) in p_p. case p_x: (x \in p); last by rewrite !prev_nth mem_rot p_x. by rewrite (eqP (prev_cycle p_p _)) ?mem_rot. Qed. End UniqCycle. Section UniqRotrCycle. Variables (n0 : nat) (T : eqType) (p : seq T). Hypothesis Up : uniq p. Lemma next_rotr : next (rotr n0 p) =1 next p. Proof. exact: next_rot. Qed. Lemma prev_rotr : prev (rotr n0 p) =1 prev p. Proof. exact: prev_rot. Qed. End UniqRotrCycle. Section UniqCycleRev. Variable T : eqType. Implicit Type p : seq T. Lemma prev_rev p : uniq p -> prev (rev p) =1 next p. Proof. move=> Up x; case p_x: (x \in p); last first. by rewrite next_nth prev_nth mem_rev p_x. case/rot_to: p_x (Up) => [i q def_p] Urp; rewrite -rev_uniq in Urp. rewrite -(prev_rotr i Urp); do 2 rewrite -(prev_rotr 1) ?rotr_uniq //. rewrite -rev_rot -(next_rot i Up) {i p Up Urp}def_p. by case: q => // y q; rewrite !rev_cons !(=^~ rcons_cons, rotr1_rcons) /= eqxx. Qed. Lemma next_rev p : uniq p -> next (rev p) =1 prev p. Proof. by move=> Up x; rewrite -{2}[p]revK prev_rev // rev_uniq. Qed. End UniqCycleRev. Section MapPath. Variables (T T' : Type) (h : T' -> T) (e : rel T) (e' : rel T'). Definition rel_base (b : pred T) := forall x' y', ~~ b (h x') -> e (h x') (h y') = e' x' y'. Lemma map_path b x' p' (Bb : rel_base b) : ~~ has (preim h b) (belast x' p') -> path e (h x') (map h p') = path e' x' p'. Proof. by elim: p' x' => [|y' p' IHp'] x' //= /norP[/Bb-> /IHp'->]. Qed. End MapPath. Section MapEqPath. Variables (T T' : eqType) (h : T' -> T) (e : rel T) (e' : rel T'). Hypothesis Ih : injective h. Lemma mem2_map x' y' p' : mem2 (map h p') (h x') (h y') = mem2 p' x' y'. Proof. by rewrite {1}/mem2 (index_map Ih) -map_drop mem_map. Qed. Lemma next_map p : uniq p -> forall x, next (map h p) (h x) = h (next p x). Proof. move=> Up x; case p_x: (x \in p); last by rewrite !next_nth (mem_map Ih) p_x. case/rot_to: p_x => i p' def_p. rewrite -(next_rot i Up); rewrite -(map_inj_uniq Ih) in Up. rewrite -(next_rot i Up) -map_rot {i p Up}def_p /=. by case: p' => [|y p''] //=; rewrite !eqxx. Qed. Lemma prev_map p : uniq p -> forall x, prev (map h p) (h x) = h (prev p x). Proof. move=> Up x; rewrite -{1}[x](next_prev Up) -(next_map Up). by rewrite prev_next ?map_inj_uniq. Qed. End MapEqPath. Definition fun_base (T T' : eqType) (h : T' -> T) f f' := rel_base h (frel f) (frel f'). Section CycleArc. Variable T : eqType. Implicit Type p : seq T. Definition arc p x y := let px := rot (index x p) p in take (index y px) px. Lemma arc_rot i p : uniq p -> {in p, arc (rot i p) =2 arc p}. Proof. move=> Up x p_x y; congr (fun q => take (index y q) q); move: Up p_x {y}. rewrite -{1 2 5 6}(cat_take_drop i p) /rot cat_uniq => /and3P[_ Up12 _]. rewrite !drop_cat !take_cat !index_cat mem_cat orbC. case p2x: (x \in drop i p) => /= => [_ | p1x]. rewrite index_mem p2x [x \in _](negbTE (hasPn Up12 _ p2x)) /= addKn. by rewrite ltnNge leq_addr catA. by rewrite p1x index_mem p1x addKn ltnNge leq_addr /= catA. Qed. Lemma left_arc x y p1 p2 (p := x :: p1 ++ y :: p2) : uniq p -> arc p x y = x :: p1. Proof. rewrite /arc /p [index x _]/= eqxx rot0 -cat_cons cat_uniq index_cat. move: (x :: p1) => xp1 /and3P[_ /norP[/= /negbTE-> _] _]. by rewrite eqxx addn0 take_size_cat. Qed. Lemma right_arc x y p1 p2 (p := x :: p1 ++ y :: p2) : uniq p -> arc p y x = y :: p2. Proof. rewrite -[p]cat_cons -rot_size_cat rot_uniq => Up. by rewrite arc_rot ?left_arc ?mem_head. Qed. CoInductive rot_to_arc_spec p x y := RotToArcSpec i p1 p2 of x :: p1 = arc p x y & y :: p2 = arc p y x & rot i p = x :: p1 ++ y :: p2 : rot_to_arc_spec p x y. Lemma rot_to_arc p x y : uniq p -> x \in p -> y \in p -> x != y -> rot_to_arc_spec p x y. Proof. move=> Up p_x p_y ne_xy; case: (rot_to p_x) (p_y) (Up) => [i q def_p] q_y. rewrite -(mem_rot i) def_p inE eq_sym (negbTE ne_xy) in q_y. rewrite -(rot_uniq i) def_p. case/splitPr: q / q_y def_p => q1 q2 def_p Uq12; exists i q1 q2 => //. by rewrite -(arc_rot i Up p_x) def_p left_arc. by rewrite -(arc_rot i Up p_y) def_p right_arc. Qed. End CycleArc. Prenex Implicits arc. mathcomp-1.5/theories/falgebra.v0000644000175000017500000013533412307636117015746 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq path choice fintype. Require Import div tuple finfun bigop ssralg finalg zmodp matrix vector poly. (******************************************************************************) (* Finite dimensional free algebras, usually known as F-algebras. *) (* FalgType K == the interface type for F-algebras over K; it simply *) (* joins the unitAlgType K and vectType K interfaces. *) (* [FalgType K of aT] == an FalgType K structure for a type aT that has both *) (* unitAlgType K and vectType K canonical structures. *) (* [FalgType K of aT for vT] == an FalgType K structure for a type aT with a *) (* unitAlgType K canonical structure, given a structure *) (* vT : vectType K whose lmodType K projection matches *) (* the canonical lmodType for aT. *) (* FalgUnitRingType T == a default unitRingType structure for a type T with *) (* both algType and vectType structures. *) (* Any aT with an FalgType structure inherits all the Vector, Ring and *) (* Algebra operations, and supports the following additional operations: *) (* \dim_A M == (\dim M %/ dim A)%N -- free module dimension. *) (* amull u == the linear function v |-> u * v, for u, v : aT. *) (* amulr u == the linear function v |-> v * u, for u, v : aT. *) (* 1, f * g, f ^+ n == the identity function, the composite g \o f, the nth *) (* iterate of f, for 1, f, g in 'End(aT). This is just *) (* the usual F-algebra structure on 'End(aT). It is NOT *) (* canonical by default, but can be activated by the *) (* line Import FalgLfun. Beware also that (f^-1)%VF is *) (* the linear function inverse, not the ring inverse of *) (* f (though they do coincide when f is injective). *) (* 1%VS == the line generated by 1 : aT. *) (* (U * V)%VS == the smallest subspace of aT that contains all *) (* products u * v for u in U, v in V. *) (* (U ^+ n)%VS == (U * U * ... * U), n-times. U ^+ 0 = 1%VS *) (* 'C[u]%VS == the centraliser subspace of the vector u. *) (* 'C_U[v]%VS := (U :&: 'C[v])%VS. *) (* 'C(V)%VS == the centraliser subspace of the subspace V. *) (* 'C_U(V)%VS := (U :&: 'C(V))%VS. *) (* 'Z(V)%VS == the center subspace of the subspace V. *) (* agenv U == the smallest subalgebra containing U ^+ n for all n. *) (* <>%VS == agenv (U + <[v]>) (adjoin v to U). *) (* <>%VS == agenv (U + <>) (adjoin vs to U). *) (* {aspace aT} == a subType of {vspace aT} consisting of sub-algebras *) (* of aT (see below); for A : {aspace aT}, subvs_of A *) (* has a canonical FalgType K structure. *) (* is_aspace U <=> the characteristic predicate of {aspace aT} stating *) (* that U is closed under product and contains an *) (* identity element, := has_algid U && (U * U <= U)%VS. *) (* algid A == the identity element of A : {aspace aT}, which need *) (* not be equal to 1 (indeed, in a Wedderburn *) (* decomposition it is not even a unit in aT). *) (* is_algid U e <-> e : aT is an identity element for the subspace U: *) (* e in U, e != 0 & e * u = u * e = u for all u in U. *) (* has_algid U <=> there is an e such that is_algid U e. *) (* [aspace of U] == a clone of an existing {aspace aT} structure on *) (* U : {vspace aT} (more instances of {aspace aT} will *) (* be defined in extFieldType). *) (* [aspace of U for A] == a clone of A : {aspace aT} for U : {vspace aT}. *) (* 1%AS == the canonical sub-algebra 1%VS. *) (* {:aT}%AS == the canonical full algebra. *) (* <>%AS == the canonical algebra for agenv U; note that this is *) (* unrelated to <>%VS, the subspace spanned by vs. *) (* <>%AS == the canonical algebra for <>%VS. *) (* <>%AS == the canonical algebra for <>%VS. *) (* ahom_in U f <=> f : 'Hom(aT, rT) is a multiplicative homomorphism *) (* inside U, and in addition f 1 = 1 (even if U doesn't *) (* contain 1). Note that f @: U need not be a *) (* subalgebra when U is, as f could annilate U. *) (* 'AHom(aT, rT) == the type of algebra homomorphisms from aT to rT, *) (* where aT and rT ARE FalgType structures. Elements of *) (* 'AHom(aT, rT) coerce to 'End(aT, rT) and aT -> rT. *) (* --> Caveat: aT and rT must denote actual FalgType structures, not their *) (* projections on Type. *) (* 'AEnd(aT) == algebra endomorphisms of aT (:= 'AHom(aT, aT)). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Open Local Scope ring_scope. Reserved Notation "{ 'aspace' T }" (at level 0, format "{ 'aspace' T }"). Reserved Notation "<< U & vs >>" (at level 0, format "<< U & vs >>"). Reserved Notation "<< U ; x >>" (at level 0, format "<< U ; x >>"). Reserved Notation "''AHom' ( T , rT )" (at level 8, format "''AHom' ( T , rT )"). Reserved Notation "''AEnd' ( T )" (at level 8, format "''AEnd' ( T )"). Notation "\dim_ E V" := (divn (\dim V) (\dim E)) (at level 10, E at level 2, V at level 8, format "\dim_ E V") : nat_scope. Import GRing.Theory. (* Finite dimensional algebra *) Module Falgebra. (* Supply a default unitRing mixin for the default unitAlgType base type. *) Section DefaultBase. Variables (K : fieldType) (A : algType K). Lemma BaseMixin : Vector.mixin_of A -> GRing.UnitRing.mixin_of A. Proof. move=> vAm; pose vA := VectType K A vAm. pose am u := linfun (u \o* idfun : vA -> vA). have amE u v : am u v = v * u by rewrite lfunE. pose uam := [pred u | lker (am u) == 0%VS]. pose vam := [fun u => if u \in uam then (am u)^-1%VF 1 else u]. have vamKl: {in uam, left_inverse 1 vam *%R}. by move=> u Uu; rewrite /= Uu -amE lker0_lfunVK. exists uam vam => // [u Uu | u v [_ uv1] | u /negbTE/= -> //]. by apply/(lker0P Uu); rewrite !amE -mulrA vamKl // mul1r mulr1. by apply/lker0P=> w1 w2 /(congr1 (am v)); rewrite !amE -!mulrA uv1 !mulr1. Qed. Definition BaseType T := fun c vAm & phant_id c (GRing.UnitRing.Class (BaseMixin vAm)) => fun (vT : vectType K) & phant vT & phant_id (Vector.mixin (Vector.class vT)) vAm => @GRing.UnitRing.Pack T c T. End DefaultBase. Section ClassDef. Variable R : ringType. Implicit Type phR : phant R. Record class_of A := Class { base1 : GRing.UnitAlgebra.class_of R A; mixin : Vector.mixin_of (GRing.Lmodule.Pack _ base1 A) }. Local Coercion base1 : class_of >-> GRing.UnitAlgebra.class_of. Definition base2 A c := @Vector.Class _ _ (@base1 A c) (mixin c). Local Coercion base2 : class_of >-> Vector.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (phR : phant R) (T : Type) (cT : type phR). Definition class := let: Pack _ c _ := cT return class_of cT in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack := fun bT b & phant_id (@GRing.UnitAlgebra.class R phR bT) (b : GRing.UnitAlgebra.class_of R T) => fun mT m & phant_id (@Vector.class R phR mT) (@Vector.Class R T b m) => Pack (Phant R) (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition lmodType := @GRing.Lmodule.Pack R phR cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition lalgType := @GRing.Lalgebra.Pack R phR cT xclass xT. Definition algType := @GRing.Algebra.Pack R phR cT xclass xT. Definition unitAlgType := @GRing.UnitAlgebra.Pack R phR cT xclass xT. Definition vectType := @Vector.Pack R phR cT xclass cT. Definition vect_ringType := @GRing.Ring.Pack vectType xclass xT. Definition vect_unitRingType := @GRing.UnitRing.Pack vectType xclass xT. Definition vect_lalgType := @GRing.Lalgebra.Pack R phR vectType xclass xT. Definition vect_algType := @GRing.Algebra.Pack R phR vectType xclass xT. Definition vect_unitAlgType := @GRing.UnitAlgebra.Pack R phR vectType xclass xT. End ClassDef. Module Exports. Coercion base1 : class_of >-> GRing.UnitAlgebra.class_of. Coercion base2 : class_of >-> Vector.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion lmodType : type>-> GRing.Lmodule.type. Canonical lmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion lalgType : type >-> GRing.Lalgebra.type. Canonical lalgType. Coercion algType : type >-> GRing.Algebra.type. Canonical algType. Coercion unitAlgType : type >-> GRing.UnitAlgebra.type. Canonical unitAlgType. Coercion vectType : type >-> Vector.type. Canonical vectType. Canonical vect_ringType. Canonical vect_unitRingType. Canonical vect_lalgType. Canonical vect_algType. Canonical vect_unitAlgType. Notation FalgType R := (type (Phant R)). Notation "[ 'FalgType' R 'of' A ]" := (@pack _ (Phant R) A _ _ id _ _ id) (at level 0, format "[ 'FalgType' R 'of' A ]") : form_scope. Notation "[ 'FalgType' R 'of' A 'for' vT ]" := (@pack _ (Phant R) A _ _ id vT _ idfun) (at level 0, format "[ 'FalgType' R 'of' A 'for' vT ]") : form_scope. Notation FalgUnitRingType T := (@BaseType _ _ T _ _ id _ (Phant T) id). End Exports. End Falgebra. Export Falgebra.Exports. Notation "1" := (vline 1) : vspace_scope. Canonical matrix_FalgType (K : fieldType) n := [FalgType K of 'M[K]_n.+1]. Section Proper. Variables (R : ringType) (aT : FalgType R). Import Vector.InternalTheory. Lemma FalgType_proper : Vector.dim aT > 0. Proof. rewrite lt0n; apply: contraNneq (oner_neq0 aT) => aT0. by apply/eqP/v2r_inj; do 2!move: (v2r _); rewrite aT0 => u v; rewrite !thinmx0. Qed. End Proper. Module FalgLfun. Section FalgLfun. Variable (R : comRingType) (aT : FalgType R). Implicit Types f g : 'End(aT). Canonical Falg_fun_ringType := lfun_ringType (FalgType_proper aT). Canonical Falg_fun_lalgType := lfun_lalgType (FalgType_proper aT). Canonical Falg_fun_algType := lfun_algType (FalgType_proper aT). Lemma lfun_mulE f g u : (f * g) u = g (f u). Proof. exact: lfunE. Qed. Lemma lfun_compE f g : (g \o f)%VF = f * g. Proof. by []. Qed. End FalgLfun. Section InvLfun. Variable (K : fieldType) (aT : FalgType K). Implicit Types f g : 'End(aT). Definition lfun_invr f := if lker f == 0%VS then f^-1%VF else f. Lemma lfun_mulVr f : lker f == 0%VS -> f^-1%VF * f = 1. Proof. exact: lker0_compfV. Qed. Lemma lfun_mulrV f : lker f == 0%VS -> f * f^-1%VF = 1. Proof. exact: lker0_compVf. Qed. Fact lfun_mulRVr f : lker f == 0%VS -> lfun_invr f * f = 1. Proof. by move=> Uf; rewrite /lfun_invr Uf lfun_mulVr. Qed. Fact lfun_mulrRV f : lker f == 0%VS -> f * lfun_invr f = 1. Proof. by move=> Uf; rewrite /lfun_invr Uf lfun_mulrV. Qed. Fact lfun_unitrP f g : g * f = 1 /\ f * g = 1 -> lker f == 0%VS. Proof. case=> _ fK; apply/lker0P; apply: can_inj (g) _ => u. by rewrite -lfun_mulE fK lfunE. Qed. Lemma lfun_invr_out f : lker f != 0%VS -> lfun_invr f = f. Proof. by rewrite /lfun_invr => /negPf->. Qed. Definition lfun_unitRingMixin := UnitRingMixin lfun_mulRVr lfun_mulrRV lfun_unitrP lfun_invr_out. Canonical lfun_unitRingType := UnitRingType 'End(aT) lfun_unitRingMixin. Canonical lfun_unitAlgType := [unitAlgType K of 'End(aT)]. Canonical Falg_fun_FalgType := [FalgType K of 'End(aT)]. Lemma lfun_invE f : lker f == 0%VS -> f^-1%VF = f^-1. Proof. by rewrite /f^-1 /= /lfun_invr => ->. Qed. End InvLfun. End FalgLfun. Section FalgebraTheory. Variables (K : fieldType) (aT : FalgType K). Implicit Types (u v : aT) (U V W : {vspace aT}). Import FalgLfun. Definition amull u : 'End(aT) := linfun (u \*o @idfun aT). Definition amulr u : 'End(aT) := linfun (u \o* @idfun aT). Lemma amull_inj : injective amull. Proof. by move=> u v /lfunP/(_ 1); rewrite !lfunE /= !mulr1. Qed. Lemma amulr_inj : injective amulr. Proof. by move=> u v /lfunP/(_ 1); rewrite !lfunE /= !mul1r. Qed. Fact amull_is_linear : linear amull. Proof. move=> a u v; apply/lfunP => w. by rewrite !lfunE /= scale_lfunE !lfunE /= mulrDl scalerAl. Qed. Canonical amull_additive := Eval hnf in Additive amull_is_linear. Canonical amull_linear := Eval hnf in AddLinear amull_is_linear. (* amull is a converse ring morphism *) Lemma amull1 : amull 1 = \1%VF. Proof. by apply/lfunP => z; rewrite id_lfunE lfunE /= mul1r. Qed. Lemma amullM u v : (amull (u * v) = amull v * amull u)%VF. Proof. by apply/lfunP => w; rewrite comp_lfunE !lfunE /= mulrA. Qed. Lemma amulr_is_lrmorphism : lrmorphism amulr. Proof. split=> [|a u]; last by apply/lfunP=> w; rewrite scale_lfunE !lfunE /= scalerAr. split=> [u v|]; first by apply/lfunP => w; do 3!rewrite !lfunE /= ?mulrBr. split=> [u v|]; last by apply/lfunP=> w; rewrite id_lfunE !lfunE /= mulr1. by apply/lfunP=> w; rewrite comp_lfunE !lfunE /= mulrA. Qed. Canonical amulr_additive := Eval hnf in Additive amulr_is_lrmorphism. Canonical amulr_linear := Eval hnf in AddLinear amulr_is_lrmorphism. Canonical amulr_rmorphism := Eval hnf in AddRMorphism amulr_is_lrmorphism. Canonical amulr_lrmorphism := Eval hnf in LRMorphism amulr_is_lrmorphism. Lemma lker0_amull u : u \is a GRing.unit -> lker (amull u) == 0%VS. Proof. by move=> Uu; apply/lker0P=> v w; rewrite !lfunE; apply: mulrI. Qed. Lemma lker0_amulr u : u \is a GRing.unit -> lker (amulr u) == 0%VS. Proof. by move=> Uu; apply/lker0P=> v w; rewrite !lfunE; apply: mulIr. Qed. Lemma lfun1_poly (p : {poly aT}) : map_poly \1%VF p = p. Proof. by apply: map_poly_id => u _; apply: id_lfunE. Qed. Fact prodv_key : unit. Proof. by []. Qed. Definition prodv := locked_with prodv_key (fun U V => <>%VS). Canonical prodv_unlockable := [unlockable fun prodv]. Local Notation "A * B" := (prodv A B) : vspace_scope. Lemma memv_mul U V : {in U & V, forall u v, u * v \in (U * V)%VS}. Proof. move=> u v /coord_vbasis-> /coord_vbasis->. rewrite mulr_suml; apply: memv_suml => i _. rewrite mulr_sumr; apply: memv_suml => j _. rewrite -scalerAl -scalerAr !memvZ // [prodv]unlock memv_span //. by apply/allpairsP; exists ((vbasis U)`_i, (vbasis V)`_j); rewrite !memt_nth. Qed. Lemma prodvP {U V W} : reflect {in U & V, forall u v, u * v \in W} (U * V <= W)%VS. Proof. apply: (iffP idP) => [sUVW u v Uu Vv | sUVW]. by rewrite (subvP sUVW) ?memv_mul. rewrite [prodv]unlock; apply/span_subvP=> _ /allpairsP[[u v] /= [Uu Vv ->]]. by rewrite sUVW ?vbasis_mem. Qed. Lemma prodv_line u v : (<[u]> * <[v]> = <[u * v]>)%VS. Proof. apply: subv_anti; rewrite -memvE memv_mul ?memv_line // andbT. apply/prodvP=> _ _ /vlineP[a ->] /vlineP[b ->]. by rewrite -scalerAr -scalerAl !memvZ ?memv_line. Qed. Lemma dimv1: \dim (1%VS : {vspace aT}) = 1%N. Proof. by rewrite dim_vline oner_neq0. Qed. Lemma dim_prodv U V : \dim (U * V) <= \dim U * \dim V. Proof. by rewrite unlock (leq_trans (dim_span _)) ?size_tuple. Qed. Lemma vspace1_neq0 : (1 != 0 :> {vspace aT})%VS. Proof. by rewrite -dimv_eq0 dimv1. Qed. Lemma vbasis1 : exists2 k, k != 0 & vbasis 1 = [:: k%:A] :> seq aT. Proof. move: (vbasis 1) (@vbasisP K aT 1); rewrite dim_vline oner_neq0. case/tupleP=> x X0; rewrite {X0}tuple0 => defX; have Xx := mem_head x nil. have /vlineP[k def_x] := basis_mem defX Xx; exists k; last by rewrite def_x. by have:= basis_not0 defX Xx; rewrite def_x scaler_eq0 oner_eq0 orbF. Qed. Lemma prod0v : left_zero 0%VS prodv. Proof. move=> U; apply/eqP; rewrite -dimv_eq0 -leqn0 (leq_trans (dim_prodv 0 U)) //. by rewrite dimv0. Qed. Lemma prodv0 : right_zero 0%VS prodv. Proof. move=> U; apply/eqP; rewrite -dimv_eq0 -leqn0 (leq_trans (dim_prodv U 0)) //. by rewrite dimv0 muln0. Qed. Canonical prodv_muloid := Monoid.MulLaw prod0v prodv0. Lemma prod1v : left_id 1%VS prodv. Proof. move=> U; apply/subv_anti/andP; split. by apply/prodvP=> _ u /vlineP[a ->] Uu; rewrite mulr_algl memvZ. by apply/subvP=> u Uu; rewrite -[u]mul1r memv_mul ?memv_line. Qed. Lemma prodv1 : right_id 1%VS prodv. Proof. move=> U; apply/subv_anti/andP; split. by apply/prodvP=> u _ Uu /vlineP[a ->]; rewrite mulr_algr memvZ. by apply/subvP=> u Uu; rewrite -[u]mulr1 memv_mul ?memv_line. Qed. Lemma prodvS U1 U2 V1 V2 : (U1 <= U2 -> V1 <= V2 -> U1 * V1 <= U2 * V2)%VS. Proof. move/subvP=> sU12 /subvP sV12; apply/prodvP=> u v Uu Vv. by rewrite memv_mul ?sU12 ?sV12. Qed. Lemma prodvSl U1 U2 V : (U1 <= U2 -> U1 * V <= U2 * V)%VS. Proof. by move/prodvS->. Qed. Lemma prodvSr U V1 V2 : (V1 <= V2 -> U * V1 <= U * V2)%VS. Proof. exact: prodvS. Qed. Lemma prodvDl : left_distributive prodv addv. Proof. move=> U1 U2 V; apply/esym/subv_anti/andP; split. by rewrite subv_add 2?prodvS ?addvSl ?addvSr. apply/prodvP=> _ v /memv_addP[u1 Uu1 [u2 Uu2 ->]] Vv. by rewrite mulrDl memv_add ?memv_mul. Qed. Lemma prodvDr : right_distributive prodv addv. Proof. move=> U V1 V2; apply/esym/subv_anti/andP; split. by rewrite subv_add 2?prodvS ?addvSl ?addvSr. apply/prodvP=> u _ Uu /memv_addP[v1 Vv1 [v2 Vv2 ->]]. by rewrite mulrDr memv_add ?memv_mul. Qed. Canonical addv_addoid := Monoid.AddLaw prodvDl prodvDr. Lemma prodvA : associative prodv. Proof. move=> U V W; rewrite -(span_basis (vbasisP U)) span_def !big_distrl /=. apply: eq_bigr => u _; rewrite -(span_basis (vbasisP W)) span_def !big_distrr. apply: eq_bigr => w _; rewrite -(span_basis (vbasisP V)) span_def /=. rewrite !(big_distrl, big_distrr) /=; apply: eq_bigr => v _. by rewrite !prodv_line mulrA. Qed. Canonical prodv_monoid := Monoid.Law prodvA prod1v prodv1. Definition expv U n := iterop n.+1.-1 prodv U 1%VS. Local Notation "A ^+ n" := (expv A n) : vspace_scope. Lemma expv0 U : (U ^+ 0 = 1)%VS. Proof. by []. Qed. Lemma expv1 U : (U ^+ 1 = U)%VS. Proof. by []. Qed. Lemma expv2 U : (U ^+ 2 = U * U)%VS. Proof. by []. Qed. Lemma expvSl U n : (U ^+ n.+1 = U * U ^+ n)%VS. Proof. by case: n => //; rewrite prodv1. Qed. Lemma expv0n n : (0 ^+ n = if n is _.+1 then 0 else 1)%VS. Proof. by case: n => // n; rewrite expvSl prod0v. Qed. Lemma expv1n n : (1 ^+ n = 1)%VS. Proof. by elim: n => // n IHn; rewrite expvSl IHn prodv1. Qed. Lemma expvD U m n : (U ^+ (m + n) = U ^+ m * U ^+ n)%VS. Proof. by elim: m => [|m IHm]; rewrite ?prod1v // !expvSl IHm prodvA. Qed. Lemma expvSr U n : (U ^+ n.+1 = U ^+ n * U)%VS. Proof. by rewrite -addn1 expvD. Qed. Lemma expvM U m n : (U ^+ (m * n) = U ^+ m ^+ n)%VS. Proof. by elim: n => [|n IHn]; rewrite ?muln0 // mulnS expvD IHn expvSl. Qed. Lemma expvS U V n : (U <= V -> U ^+ n <= V ^+ n)%VS. Proof. move=> sUV; elim: n => [|n IHn]; first by rewrite !expv0 subvv. by rewrite !expvSl prodvS. Qed. Lemma expv_line u n : (<[u]> ^+ n = <[u ^+ n]>)%VS. Proof. elim: n => [|n IH]; first by rewrite expr0 expv0. by rewrite exprS expvSl IH prodv_line. Qed. (* Centralisers and centers. *) Definition centraliser1_vspace u := lker (amulr u - amull u). Local Notation "'C [ u ]" := (centraliser1_vspace u) : vspace_scope. Definition centraliser_vspace V := (\bigcap_i 'C[tnth (vbasis V) i])%VS. Local Notation "'C ( V )" := (centraliser_vspace V) : vspace_scope. Definition center_vspace V := (V :&: 'C(V))%VS. Local Notation "'Z ( V )" := (center_vspace V) : vspace_scope. Lemma cent1vP u v : reflect (u * v = v * u) (u \in 'C[v]%VS). Proof. by rewrite (sameP eqlfunP eqP) !lfunE /=; apply: eqP. Qed. Lemma cent1v1 u : 1 \in 'C[u]%VS. Proof. by apply/cent1vP; rewrite commr1. Qed. Lemma cent1v_id u : u \in 'C[u]%VS. Proof. exact/cent1vP. Qed. Lemma cent1vX u n : u ^+ n \in 'C[u]%VS. Proof. exact/cent1vP/esym/commrX. Qed. Lemma cent1vC u v : (u \in 'C[v])%VS = (v \in 'C[u])%VS. Proof. exact/cent1vP/cent1vP. Qed. Lemma centvP u V : reflect {in V, forall v, u * v = v * u} (u \in 'C(V))%VS. Proof. apply: (iffP subv_bigcapP) => [cVu y /coord_vbasis-> | cVu i _]. apply/esym/cent1vP/rpred_sum=> i _; apply: rpredZ. by rewrite -tnth_nth cent1vC memvE cVu. exact/cent1vP/cVu/vbasis_mem/mem_tnth. Qed. Lemma centvsP U V : reflect {in U & V, commutative *%R} (U <= 'C(V))%VS. Proof. by apply: (iffP subvP) => [cUV u v | cUV u] /cUV-/centvP; apply. Qed. Lemma subv_cent1 U v : (U <= 'C[v])%VS = (v \in 'C(U)%VS). Proof. by apply/subvP/centvP=> cUv u Uu; apply/cent1vP; rewrite 1?cent1vC cUv. Qed. Lemma centv1 V : 1 \in 'C(V)%VS. Proof. by apply/centvP=> v _; rewrite commr1. Qed. Lemma centvX V u n : u \in 'C(V)%VS -> u ^+ n \in 'C(V)%VS. Proof. by move/centvP=> cVu; apply/centvP=> v /cVu/esym/commrX->. Qed. Lemma centvC U V : (U <= 'C(V))%VS = (V <= 'C(U))%VS. Proof. by apply/centvsP/centvsP=> cUV u v UVu /cUV->. Qed. Lemma centerv_sub V : ('Z(V) <= V)%VS. Proof. exact: capvSl. Qed. Lemma cent_centerv V : (V <= 'C('Z(V)))%VS. Proof. by rewrite centvC capvSr. Qed. (* Building the predicate that checks is a vspace has a unit *) Definition is_algid e U := [/\ e \in U, e != 0 & {in U, forall u, e * u = u /\ u * e = u}]. Fact algid_decidable U : decidable (exists e, is_algid e U). Proof. have [-> | nzU] := eqVneq U 0%VS. by right=> [[e []]]; rewrite memv0 => ->. pose X := vbasis U; pose feq f1 f2 := [tuple of map f1 X ++ map f2 X]. have feqL f i: tnth (feq _ f _) (lshift _ i) = f X`_i. set v := f _; rewrite (tnth_nth v) /= nth_cat size_map size_tuple. by rewrite ltn_ord (nth_map 0) ?size_tuple. have feqR f i: tnth (feq _ _ f) (rshift _ i) = f X`_i. set v := f _; rewrite (tnth_nth v) /= nth_cat size_map size_tuple. by rewrite ltnNge leq_addr addKn /= (nth_map 0) ?size_tuple. apply: decP (vsolve_eq (feq _ amulr amull) (feq _ id id) U) _. apply: (iffP (vsolve_eqP _ _ _)) => [[e Ue id_e] | [e [Ue _ id_e]]]. suffices idUe: {in U, forall u, e * u = u /\ u * e = u}. exists e; split=> //; apply: contraNneq nzU => e0; rewrite -subv0. by apply/subvP=> u /idUe[<- _]; rewrite e0 mul0r mem0v. move=> u /coord_vbasis->; rewrite mulr_sumr mulr_suml. split; apply/eq_bigr=> i _; rewrite -(scalerAr, scalerAl); congr (_ *: _). by have:= id_e (lshift _ i); rewrite !feqL lfunE. by have:= id_e (rshift _ i); rewrite !feqR lfunE. have{id_e} /all_and2[ideX idXe]:= id_e _ (vbasis_mem (mem_tnth _ X)). exists e => // k; rewrite -[k]splitK. by case: (split k) => i; rewrite !(feqL, feqR) lfunE /= -tnth_nth. Qed. Definition has_algid : pred {vspace aT} := algid_decidable. Lemma has_algidP {U} : reflect (exists e, is_algid e U) (has_algid U). Proof. exact: sumboolP. Qed. Lemma has_algid1 U : 1 \in U -> has_algid U. Proof. move=> U1; apply/has_algidP; exists 1; split; rewrite ?oner_eq0 // => u _. by rewrite mulr1 mul1r. Qed. Definition is_aspace U := has_algid U && (U * U <= U)%VS. Structure aspace := ASpace {asval :> {vspace aT}; _ : is_aspace asval}. Definition aspace_of of phant aT := aspace. Local Notation "{ 'aspace' T }" := (aspace_of (Phant T)) : type_scope. Canonical aspace_subType := Eval hnf in [subType for asval]. Definition aspace_eqMixin := [eqMixin of aspace by <:]. Canonical aspace_eqType := Eval hnf in EqType aspace aspace_eqMixin. Definition aspace_choiceMixin := [choiceMixin of aspace by <:]. Canonical aspace_choiceType := Eval hnf in ChoiceType aspace aspace_choiceMixin. Canonical aspace_of_subType := Eval hnf in [subType of {aspace aT}]. Canonical aspace_of_eqType := Eval hnf in [eqType of {aspace aT}]. Canonical aspace_of_choiceType := Eval hnf in [choiceType of {aspace aT}]. Definition clone_aspace U (A : {aspace aT}) := fun algU & phant_id algU (valP A) => @ASpace U algU : {aspace aT}. Fact aspace1_subproof : is_aspace 1. Proof. by rewrite /is_aspace prod1v -memvE has_algid1 memv_line. Qed. Canonical aspace1 : {aspace aT} := ASpace aspace1_subproof. Lemma aspacef_subproof : is_aspace fullv. Proof. by rewrite /is_aspace subvf has_algid1 ?memvf. Qed. Canonical aspacef : {aspace aT} := ASpace aspacef_subproof. Lemma polyOver1P p : reflect (exists q, p = map_poly (in_alg aT) q) (p \is a polyOver 1%VS). Proof. apply: (iffP idP) => [/allP/=Qp | [q ->]]; last first. by apply/polyOverP=> j; rewrite coef_map rpredZ ?memv_line. exists (map_poly (coord [tuple 1] 0) p). rewrite -map_poly_comp map_poly_id // => _ /Qp/vlineP[a ->] /=. by rewrite linearZ /= (coord_free 0) ?mulr1 // seq1_free ?oner_eq0. Qed. End FalgebraTheory. Delimit Scope aspace_scope with AS. Bind Scope aspace_scope with aspace. Bind Scope aspace_scope with aspace_of. Arguments Scope asval [_ _ aspace_scope]. Arguments Scope clone_aspace [_ _ vspace_scope aspace_scope _ _]. Notation "{ 'aspace' T }" := (aspace_of (Phant T)) : type_scope. Notation "A * B" := (prodv A B) : vspace_scope. Notation "A ^+ n" := (expv A n) : vspace_scope. Notation "'C [ u ]" := (centraliser1_vspace u) : vspace_scope. Notation "'C_ U [ v ]" := (capv U 'C[v]) : vspace_scope. Notation "'C_ ( U ) [ v ]" := (capv U 'C[v]) (only parsing) : vspace_scope. Notation "'C ( V )" := (centraliser_vspace V) : vspace_scope. Notation "'C_ U ( V )" := (capv U 'C(V)) : vspace_scope. Notation "'C_ ( U ) ( V )" := (capv U 'C(V)) (only parsing) : vspace_scope. Notation "'Z ( V )" := (center_vspace V) : vspace_scope. Notation "1" := (aspace1 _) : aspace_scope. Notation "{ : aT }" := (aspacef aT) : aspace_scope. Notation "[ 'aspace' 'of' U ]" := (@clone_aspace _ _ U _ _ id) (at level 0, format "[ 'aspace' 'of' U ]") : form_scope. Notation "[ 'aspace' 'of' U 'for' A ]" := (@clone_aspace _ _ U A _ idfun) (at level 0, format "[ 'aspace' 'of' U 'for' A ]") : form_scope. Implicit Arguments prodvP [K aT U V W]. Implicit Arguments cent1vP [K aT u v]. Implicit Arguments centvP [K aT u V]. Implicit Arguments centvsP [K aT U V]. Implicit Arguments has_algidP [K aT U]. Implicit Arguments polyOver1P [K aT p]. Section AspaceTheory. Variables (K : fieldType) (aT : FalgType K). Implicit Types (u v e : aT) (U V : {vspace aT}) (A B : {aspace aT}). Import FalgLfun. Lemma algid_subproof U : {e | e \in U & has_algid U ==> (U <= lker (amull e - 1) :&: lker (amulr e - 1))%VS}. Proof. apply: sig2W; case: has_algidP => [[e]|]; last by exists 0; rewrite ?mem0v. case=> Ae _ idAe; exists e => //; apply/subvP=> u /idAe[eu_u ue_u]. by rewrite memv_cap !memv_ker !lfun_simp /= eu_u ue_u subrr eqxx. Qed. Definition algid U := s2val (algid_subproof U). Lemma memv_algid U : algid U \in U. Proof. by rewrite /algid; case: algid_subproof. Qed. Lemma algidl A : {in A, left_id (algid A) *%R}. Proof. rewrite /algid; case: algid_subproof => e _ /=; have /andP[-> _] := valP A. move/subvP=> idAe u /idAe/memv_capP[]. by rewrite memv_ker !lfun_simp /= subr_eq0 => /eqP. Qed. Lemma algidr A : {in A, right_id (algid A) *%R}. Proof. rewrite /algid; case: algid_subproof => e _ /=; have /andP[-> _] := valP A. move/subvP=> idAe u /idAe/memv_capP[_]. by rewrite memv_ker !lfun_simp /= subr_eq0 => /eqP. Qed. Lemma unitr_algid1 A u : u \in A -> u \is a GRing.unit -> algid A = 1. Proof. by move=> Eu /mulrI; apply; rewrite mulr1 algidr. Qed. Lemma algid_eq1 A : (algid A == 1) = (1 \in A). Proof. by apply/eqP/idP=> [<- | /algidr <-]; rewrite ?memv_algid ?mul1r. Qed. Lemma algid_neq0 A : algid A != 0. Proof. have /andP[/has_algidP[u [Au nz_u _]] _] := valP A. by apply: contraNneq nz_u => e0; rewrite -(algidr Au) e0 mulr0. Qed. Lemma dim_algid A : \dim <[algid A]> = 1%N. Proof. by rewrite dim_vline algid_neq0. Qed. Lemma adim_gt0 A : (0 < \dim A)%N. Proof. by rewrite -(dim_algid A) dimvS // -memvE ?memv_algid. Qed. Lemma not_asubv0 A : ~~ (A <= 0)%VS. Proof. by rewrite subv0 -dimv_eq0 -lt0n adim_gt0. Qed. Lemma adim1P {A} : reflect (A = <[algid A]>%VS :> {vspace aT}) (\dim A == 1%N). Proof. rewrite eqn_leq adim_gt0 -(memv_algid A) andbC -(dim_algid A) -eqEdim eq_sym. exact: eqP. Qed. Lemma asubv A : (A * A <= A)%VS. Proof. by have /andP[] := valP A. Qed. Lemma memvM A : {in A &, forall u v, u * v \in A}. Proof. exact/prodvP/asubv. Qed. Lemma prodv_id A : (A * A)%VS = A. Proof. apply/eqP; rewrite eqEsubv asubv; apply/subvP=> u Au. by rewrite -(algidl Au) memv_mul // memv_algid. Qed. Lemma prodv_sub U V A : (U <= A -> V <= A -> U * V <= A)%VS. Proof. by move=> sUA sVA; rewrite -prodv_id prodvS. Qed. Lemma expv_id A n : (A ^+ n.+1)%VS = A. Proof. by elim: n => // n IHn; rewrite !expvSl prodvA prodv_id -expvSl. Qed. Lemma limg_amulr U v : (amulr v @: U = U * <[v]>)%VS. Proof. rewrite -(span_basis (vbasisP U)) limg_span !span_def big_distrl /= big_map. by apply: eq_bigr => u; rewrite prodv_line lfunE. Qed. Lemma memv_cosetP {U v w} : reflect (exists2 u, u\in U & w = u * v) (w \in U * <[v]>)%VS. Proof. rewrite -limg_amulr. by apply: (iffP memv_imgP) => [] [u] Uu ->; exists u; rewrite ?lfunE. Qed. Lemma dim_cosetv_unit V u : u \is a GRing.unit -> \dim (V * <[u]>) = \dim V. Proof. by move/lker0_amulr/eqP=> Uu; rewrite -limg_amulr limg_dim_eq // Uu capv0. Qed. Lemma memvV A u : (u^-1 \in A) = (u \in A). Proof. suffices{u} invA: invr_closed A by apply/idP/idP=> /invA; rewrite ?invrK. move=> u Au; have [Uu | /invr_out-> //] := boolP (u \is a GRing.unit). rewrite memvE -(limg_ker0 _ _ (lker0_amulr Uu)) limg_line lfunE /= mulVr //. suff ->: (amulr u @: A)%VS = A by rewrite -memvE -algid_eq1 (unitr_algid1 Au). by apply/eqP; rewrite limg_amulr -dimv_leqif_eq ?prodv_sub ?dim_cosetv_unit. Qed. Fact aspace_cap_subproof A B : algid A \in B -> is_aspace (A :&: B). Proof. move=> BeA; apply/andP. split; [apply/has_algidP | by rewrite subv_cap !prodv_sub ?capvSl ?capvSr]. exists (algid A); rewrite /is_algid algid_neq0 memv_cap memv_algid. by split=> // u /memv_capP[Au _]; rewrite ?algidl ?algidr. Qed. Definition aspace_cap A B BeA := ASpace (@aspace_cap_subproof A B BeA). Fact centraliser1_is_aspace u : is_aspace 'C[u]. Proof. rewrite /is_aspace has_algid1 ?cent1v1 //=. apply/prodvP=> v w /cent1vP-cuv /cent1vP-cuw. by apply/cent1vP; rewrite -mulrA cuw !mulrA cuv. Qed. Canonical centraliser1_aspace u := ASpace (centraliser1_is_aspace u). Fact centraliser_is_aspace V : is_aspace 'C(V). Proof. rewrite /is_aspace has_algid1 ?centv1 //=. apply/prodvP=> u w /centvP-cVu /centvP-cVw. by apply/centvP=> v Vv; rewrite /= -mulrA cVw // !mulrA cVu. Qed. Canonical centraliser_aspace V := ASpace (centraliser_is_aspace V). Lemma centv_algid A : algid A \in 'C(A)%VS. Proof. by apply/centvP=> u Au; rewrite algidl ?algidr. Qed. Canonical center_aspace A := [aspace of 'Z(A) for aspace_cap (centv_algid A)]. Lemma algid_center A : algid 'Z(A) = algid A. Proof. rewrite -(algidl (subvP (centerv_sub A) _ (memv_algid _))) algidr //=. by rewrite memv_cap memv_algid centv_algid. Qed. Lemma Falgebra_FieldMixin : GRing.IntegralDomain.axiom aT -> GRing.Field.mixin_of aT. Proof. move=> domT u nz_u; apply/unitrP. have kerMu: lker (amulr u) == 0%VS. rewrite eqEsubv sub0v andbT; apply/subvP=> v; rewrite memv_ker lfunE /=. by move/eqP/domT; rewrite (negPf nz_u) orbF memv0. have /memv_imgP[v _ vu1]: 1 \in limg (amulr u); last rewrite lfunE /= in vu1. suffices /eqP->: limg (amulr u) == fullv by rewrite memvf. by rewrite -dimv_leqif_eq ?subvf ?limg_dim_eq // (eqP kerMu) capv0. exists v; split=> //; apply: (lker0P kerMu). by rewrite !lfunE /= -mulrA -vu1 mulr1 mul1r. Qed. Section SkewField. Hypothesis fieldT : GRing.Field.mixin_of aT. Lemma skew_field_algid1 A : algid A = 1. Proof. by rewrite (unitr_algid1 (memv_algid A)) ?fieldT ?algid_neq0. Qed. Lemma skew_field_module_semisimple A M : let sumA X := (\sum_(x <- X) A * <[x]>)%VS in (A * M <= M)%VS -> {X | [/\ sumA X = M, directv (sumA X) & 0 \notin X]}. Proof. move=> sumA sAM_M; pose X := Nil aT; pose k := (\dim (A * M) - \dim (sumA X))%N. have: (\dim (A * M) - \dim (sumA X) < k.+1)%N by []. have: [/\ (sumA X <= A * M)%VS, directv (sumA X) & 0 \notin X]. by rewrite /sumA directvE /= !big_nil sub0v dimv0. elim: {X k}k.+1 (X) => // k IHk X [sAX_AM dxAX nzX]; rewrite ltnS => leAXk. have [sM_AX | /subvPn/sig2W[y My notAXy]] := boolP (M <= sumA X)%VS. by exists X; split=> //; apply/eqP; rewrite eqEsubv (subv_trans sAX_AM). have nz_y: y != 0 by rewrite (memPnC notAXy) ?mem0v. pose AY := sumA (y :: X). have sAY_AM: (AY <= A * M)%VS by rewrite [AY]big_cons subv_add ?prodvSr. have dxAY: directv AY. rewrite directvE /= !big_cons [_ == _]directv_addE dxAX directvE eqxx /=. rewrite -/(sumA X) eqEsubv sub0v andbT -limg_amulr. apply/subvP=> _ /memv_capP[/memv_imgP[a Aa ->]]; rewrite lfunE /= => AXay. rewrite memv0 (mulIr_eq0 a (mulIr _)) ?fieldT //. apply: contraR notAXy => /fieldT-Ua; rewrite -[y](mulKr Ua) /sumA. by rewrite -big_distrr -(prodv_id A) /= -prodvA big_distrr memv_mul ?memvV. apply: (IHk (y :: X)); first by rewrite !inE eq_sym negb_or nz_y. rewrite -subSn ?dimvS // (directvP dxAY) /= big_cons -(directvP dxAX) /=. rewrite subnDA (leq_trans _ leAXk) ?leq_sub2r // leq_subLR -add1n leq_add2r. by rewrite dim_cosetv_unit ?fieldT ?adim_gt0. Qed. Lemma skew_field_module_dimS A M : (A * M <= M)%VS -> \dim A %| \dim M. Proof. case/skew_field_module_semisimple=> X [<- /directvP-> nzX] /=. rewrite big_seq prime.dvdn_sum // => x /(memPn nzX)nz_x. by rewrite dim_cosetv_unit ?fieldT. Qed. Lemma skew_field_dimS A B : (A <= B)%VS -> \dim A %| \dim B. Proof. by move=> sAB; rewrite skew_field_module_dimS ?prodv_sub. Qed. End SkewField. End AspaceTheory. (* Note that local centraliser might not be proper sub-algebras. *) Notation "'C [ u ]" := (centraliser1_aspace u) : aspace_scope. Notation "'C ( V )" := (centraliser_aspace V) : aspace_scope. Notation "'Z ( A )" := (center_aspace A) : aspace_scope. Implicit Arguments adim1P [K aT A]. Implicit Arguments memv_cosetP [K aT U v w]. Section Closure. Variables (K : fieldType) (aT : FalgType K). Implicit Types (u v : aT) (U V W : {vspace aT}). (* Subspaces of an F-algebra form a Kleene algebra *) Definition agenv U := (\sum_(i < \dim {:aT}) U ^+ i)%VS. Local Notation "<< U & vs >>" := (agenv (U + <>)) : vspace_scope. Local Notation "<< U ; x >>" := (agenv (U + <[x]>)) : vspace_scope. Lemma agenvEl U : agenv U = (1 + U * agenv U)%VS. Proof. pose f V := (1 + U * V)%VS; rewrite -/(f _); pose n := \dim {:aT}. have ->: agenv U = iter n f 0%VS. rewrite /agenv -/n; elim: n => [|n IHn]; first by rewrite big_ord0. rewrite big_ord_recl /= -{}IHn; congr (1 + _)%VS; rewrite big_distrr /=. by apply: eq_bigr => i; rewrite expvSl. have fS i j: i <= j -> (iter i f 0 <= iter j f 0)%VS. by elim: i j => [|i IHi] [|j] leij; rewrite ?sub0v //= addvS ?prodvSr ?IHi. suffices /(@trajectP _ f _ n.+1)[i le_i_n Dfi]: looping f 0%VS n.+1. by apply/eqP; rewrite eqEsubv -iterS fS // Dfi fS. apply: contraLR (dimvS (subvf (iter n.+1 f 0%VS))); rewrite -/n -ltnNge. rewrite -looping_uniq; elim: n.+1 => // i IHi; rewrite trajectSr rcons_uniq. rewrite {1}trajectSr mem_rcons inE negb_or eq_sym eqEdim fS ?leqW // -ltnNge. by rewrite -andbA => /and3P[lt_fi _ /IHi/leq_ltn_trans->]. Qed. Lemma agenvEr U : agenv U = (1 + agenv U * U)%VS. Proof. rewrite [lhs in lhs = _]agenvEl big_distrr big_distrl /=; congr (_ + _)%VS. by apply: eq_bigr => i _ /=; rewrite -expvSr -expvSl. Qed. Lemma agenv_modl U V : (U * V <= V -> agenv U * V <= V)%VS. Proof. rewrite big_distrl /= => idlU_V; apply/subv_sumP=> [[i _] /= _]. elim: i => [|i]; first by rewrite expv0 prod1v. by apply: subv_trans; rewrite expvSr -prodvA prodvSr. Qed. Lemma agenv_modr U V : (V * U <= V -> V * agenv U <= V)%VS. Proof. rewrite big_distrr /= => idrU_V; apply/subv_sumP=> [[i _] /= _]. elim: i => [|i]; first by rewrite expv0 prodv1. by apply: subv_trans; rewrite expvSl prodvA prodvSl. Qed. Fact agenv_is_aspace U : is_aspace (agenv U). Proof. rewrite /is_aspace has_algid1; last by rewrite memvE agenvEl addvSl. by rewrite agenv_modl // [V in (_ <= V)%VS]agenvEl addvSr. Qed. Canonical agenv_aspace U : {aspace aT} := ASpace (agenv_is_aspace U). Lemma agenvE U : agenv U = agenv_aspace U. Proof. by []. Qed. (* Kleene algebra properties *) Lemma agenvM U : (agenv U * agenv U)%VS = agenv U. Proof. exact: prodv_id. Qed. Lemma agenvX n U : (agenv U ^+ n.+1)%VS = agenv U. Proof. exact: expv_id. Qed. Lemma sub1_agenv U : (1 <= agenv U)%VS. Proof. by rewrite agenvEl addvSl. Qed. Lemma sub_agenv U : (U <= agenv U)%VS. Proof. by rewrite 2!agenvEl addvC prodvDr prodv1 -addvA addvSl. Qed. Lemma subX_agenv U n : (U ^+ n <= agenv U)%VS. Proof. by case: n => [|n]; rewrite ?sub1_agenv // -(agenvX n) expvS // sub_agenv. Qed. Lemma agenv_sub_modl U V : (1 <= V -> U * V <= V -> agenv U <= V)%VS. Proof. move=> s1V /agenv_modl; apply: subv_trans. by rewrite -[Us in (Us <= _)%VS]prodv1 prodvSr. Qed. Lemma agenv_sub_modr U V : (1 <= V -> V * U <= V -> agenv U <= V)%VS. Proof. move=> s1V /agenv_modr; apply: subv_trans. by rewrite -[Us in (Us <= _)%VS]prod1v prodvSl. Qed. Lemma agenv_id U : agenv (agenv U) = agenv U. Proof. apply/eqP; rewrite eqEsubv sub_agenv andbT. by rewrite agenv_sub_modl ?sub1_agenv ?agenvM. Qed. Lemma agenvS U V : (U <= V -> agenv U <= agenv V)%VS. Proof. move=> sUV; rewrite agenv_sub_modl ?sub1_agenv //. by rewrite -[Vs in (_ <= Vs)%VS]agenvM prodvSl ?(subv_trans sUV) ?sub_agenv. Qed. Lemma agenv_add_id U V : agenv (agenv U + V) = agenv (U + V). Proof. apply/eqP; rewrite eqEsubv andbC agenvS ?addvS ?sub_agenv //=. rewrite agenv_sub_modl ?sub1_agenv //. rewrite -[rhs in (_ <= rhs)%VS]agenvM prodvSl // subv_add agenvS ?addvSl //=. exact: subv_trans (addvSr U V) (sub_agenv _). Qed. Lemma subv_adjoin U x : (U <= <>)%VS. Proof. by rewrite (subv_trans (sub_agenv _)) ?agenvS ?addvSl. Qed. Lemma subv_adjoin_seq U xs : (U <= <>)%VS. Proof. by rewrite (subv_trans (sub_agenv _)) // ?agenvS ?addvSl. Qed. Lemma memv_adjoin U x : x \in <>%VS. Proof. by rewrite memvE (subv_trans (sub_agenv _)) ?agenvS ?addvSr. Qed. Lemma seqv_sub_adjoin U xs : {subset xs <= <>%VS}. Proof. by apply/span_subvP; rewrite (subv_trans (sub_agenv _)) ?agenvS ?addvSr. Qed. Lemma subvP_adjoin U x y : y \in U -> y \in <>%VS. Proof. exact/subvP/subv_adjoin. Qed. Lemma adjoin_nil V : <>%VS = agenv V. Proof. by rewrite span_nil addv0. Qed. Lemma adjoin_cons V x rs : <>%VS = << <> & rs>>%VS. Proof. by rewrite span_cons addvA agenv_add_id. Qed. Lemma adjoin_rcons V rs x : <>%VS = << <>%VS; x>>%VS. Proof. by rewrite -cats1 span_cat addvA span_seq1 agenv_add_id. Qed. Lemma adjoin_seq1 V x : <>%VS = <>%VS. Proof. by rewrite adjoin_cons adjoin_nil agenv_id. Qed. Lemma adjoinC V x y : << <>; y>>%VS = << <>; x>>%VS. Proof. by rewrite !agenv_add_id -!addvA (addvC <[x]>%VS). Qed. Lemma adjoinSl U V x : (U <= V -> <> <= <>)%VS. Proof. by move=> sUV; rewrite agenvS ?addvS. Qed. Lemma adjoin_seqSl U V rs : (U <= V -> <> <= <>)%VS. Proof. by move=> sUV; rewrite agenvS ?addvS. Qed. Lemma adjoin_seqSr U rs1 rs2 : {subset rs1 <= rs2} -> (<> <= <>)%VS. Proof. by move/sub_span=> s_rs12; rewrite agenvS ?addvS. Qed. End Closure. Notation "<< U >>" := (agenv_aspace U) : aspace_scope. Notation "<< U & vs >>" := (agenv (U + <>)) : vspace_scope. Notation "<< U ; x >>" := (agenv (U + <[x]>)) : vspace_scope. Notation "<< U & vs >>" := << U + <> >>%AS : aspace_scope. Notation "<< U ; x >>" := << U + <[x]> >>%AS : aspace_scope. Section SubFalgType. (* The FalgType structure of subvs_of A for A : {aspace aT}. *) (* We can't use the rpred-based mixin, because A need not contain 1. *) Variable (K : fieldType) (aT : FalgType K) (A : {aspace aT}). Definition subvs_one := Subvs (memv_algid A). Definition subvs_mul (u v : subvs_of A) := Subvs (subv_trans (memv_mul (subvsP u) (subvsP v)) (asubv _)). Fact subvs_mulA : associative subvs_mul. Proof. by move=> x y z; apply/val_inj/mulrA. Qed. Fact subvs_mu1l : left_id subvs_one subvs_mul. Proof. by move=> x; apply/val_inj/algidl/(valP x). Qed. Fact subvs_mul1 : right_id subvs_one subvs_mul. Proof. by move=> x; apply/val_inj/algidr/(valP x). Qed. Fact subvs_mulDl : left_distributive subvs_mul +%R. Proof. move=> x y z; apply/val_inj/mulrDl. Qed. Fact subvs_mulDr : right_distributive subvs_mul +%R. Proof. move=> x y z; apply/val_inj/mulrDr. Qed. Definition subvs_ringMixin := RingMixin subvs_mulA subvs_mu1l subvs_mul1 subvs_mulDl subvs_mulDr (algid_neq0 _). Canonical subvs_ringType := Eval hnf in RingType (subvs_of A) subvs_ringMixin. Lemma subvs_scaleAl k (x y : subvs_of A) : k *: (x * y) = (k *: x) * y. Proof. exact/val_inj/scalerAl. Qed. Canonical subvs_lalgType := Eval hnf in LalgType K (subvs_of A) subvs_scaleAl. Lemma subvs_scaleAr k (x y : subvs_of A) : k *: (x * y) = x * (k *: y). Proof. exact/val_inj/scalerAr. Qed. Canonical subvs_algType := Eval hnf in AlgType K (subvs_of A) subvs_scaleAr. Canonical subvs_unitRingType := Eval hnf in FalgUnitRingType (subvs_of A). Canonical subvs_unitAlgType := Eval hnf in [unitAlgType K of subvs_of A]. Canonical subvs_FalgType := Eval hnf in [FalgType K of subvs_of A]. Implicit Type w : subvs_of A. Lemma vsval_unitr w : vsval w \is a GRing.unit -> w \is a GRing.unit. Proof. case: w => /= u Au Uu; have Au1: u^-1 \in A by rewrite memvV. apply/unitrP; exists (Subvs Au1). by split; apply: val_inj; rewrite /= ?mulrV ?mulVr ?(unitr_algid1 Au). Qed. Lemma vsval_invr w : vsval w \is a GRing.unit -> val w^-1 = (val w)^-1. Proof. move=> Uu; have def_w: w / w * w = w by rewrite divrK ?vsval_unitr. by apply: (mulrI Uu); rewrite -[in u in u / _]def_w ?mulrK. Qed. End SubFalgType. Section AHom. Variable K : fieldType. Section Class_Def. Variables aT rT : FalgType K. Definition ahom_in (U : {vspace aT}) (f : 'Hom(aT, rT)) := let fM_at x y := f (x * y) == f x * f y in all (fun x => all (fM_at x) (vbasis U)) (vbasis U) && (f 1 == 1). Lemma ahom_inP {f : 'Hom(aT, rT)} {U : {vspace aT}} : reflect ({in U &, {morph f : x y / x * y >-> x * y}} * (f 1 = 1)) (ahom_in U f). Proof. apply: (iffP andP) => [[/allP fM /eqP f1] | [fM f1]]; last first. rewrite f1; split=> //; apply/allP=> x Ax; apply/allP=> y Ay. by rewrite fM // vbasis_mem. split=> // x y /coord_vbasis -> /coord_vbasis ->. rewrite !mulr_suml ![f _]linear_sum mulr_suml; apply: eq_bigr => i _ /=. rewrite !mulr_sumr linear_sum; apply: eq_bigr => j _ /=. rewrite !linearZ -!scalerAr -!scalerAl 2!linearZ /=; congr (_ *: (_ *: _)). by apply/eqP/(allP (fM _ _)); apply: memt_nth. Qed. Lemma ahomP {f : 'Hom(aT, rT)} : reflect (lrmorphism f) (ahom_in {:aT} f). Proof. apply: (iffP ahom_inP) => [[fM f1] | fRM_P]; last first. pose fRM := LRMorphism fRM_P. by split; [apply: in2W (rmorphM fRM) | apply: (rmorph1 fRM)]. split; last exact: linearZZ; split; first exact: linearB. by split=> // x y; rewrite fM ?memvf. Qed. Structure ahom := AHom {ahval :> 'Hom(aT, rT); _ : ahom_in {:aT} ahval}. Canonical ahom_subType := Eval hnf in [subType for ahval]. Definition ahom_eqMixin := [eqMixin of ahom by <:]. Canonical ahom_eqType := Eval hnf in EqType ahom ahom_eqMixin. Definition ahom_choiceMixin := [choiceMixin of ahom by <:]. Canonical ahom_choiceType := Eval hnf in ChoiceType ahom ahom_choiceMixin. Fact linfun_is_ahom (f : {lrmorphism aT -> rT}) : ahom_in {:aT} (linfun f). Proof. by apply/ahom_inP; split=> [x y|]; rewrite !lfunE ?rmorphM ?rmorph1. Qed. Canonical linfun_ahom f := AHom (linfun_is_ahom f). End Class_Def. Implicit Arguments ahom_in [aT rT]. Implicit Arguments ahom_inP [aT rT f U]. Implicit Arguments ahomP [aT rT f]. Section LRMorphism. Variables aT rT sT : FalgType K. Fact ahom_is_lrmorphism (f : ahom aT rT) : lrmorphism f. Proof. by apply/ahomP; case: f. Qed. Canonical ahom_rmorphism f := Eval hnf in AddRMorphism (ahom_is_lrmorphism f). Canonical ahom_lrmorphism f := Eval hnf in AddLRMorphism (ahom_is_lrmorphism f). Lemma ahomWin (f : ahom aT rT) U : ahom_in U f. Proof. by apply/ahom_inP; split; [apply: in2W (rmorphM _) | apply: rmorph1]. Qed. Lemma id_is_ahom (V : {vspace aT}) : ahom_in V \1. Proof. by apply/ahom_inP; split=> [x y|] /=; rewrite !id_lfunE. Qed. Canonical id_ahom := AHom (id_is_ahom (aspacef aT)). Lemma comp_is_ahom (V : {vspace aT}) (f : 'Hom(rT, sT)) (g : 'Hom(aT, rT)) : ahom_in {:rT} f -> ahom_in V g -> ahom_in V (f \o g). Proof. move=> /ahom_inP fM /ahom_inP gM; apply/ahom_inP. by split=> [x y Vx Vy|] /=; rewrite !comp_lfunE gM // fM ?memvf. Qed. Canonical comp_ahom (f : ahom rT sT) (g : ahom aT rT) := AHom (comp_is_ahom (valP f) (valP g)). Lemma aimgM (f : ahom aT rT) U V : (f @: (U * V) = f @: U * f @: V)%VS. Proof. apply/eqP; rewrite eqEsubv; apply/andP; split; last first. apply/prodvP=> _ _ /memv_imgP[u Hu ->] /memv_imgP[v Hv ->]. by rewrite -rmorphM memv_img // memv_mul. apply/subvP=> _ /memv_imgP[w UVw ->]; rewrite memv_preim (subvP _ w UVw) //. by apply/prodvP=> u v Uu Vv; rewrite -memv_preim rmorphM memv_mul // memv_img. Qed. Lemma aimg1 (f : ahom aT rT) : (f @: 1 = 1)%VS. Proof. by rewrite limg_line rmorph1. Qed. Lemma aimgX (f : ahom aT rT) U n : (f @: (U ^+ n) = f @: U ^+ n)%VS. Proof. elim: n => [|n IH]; first by rewrite !expv0 aimg1. by rewrite !expvSl aimgM IH. Qed. Lemma aimg_agen (f : ahom aT rT) U : (f @: agenv U)%VS = agenv (f @: U). Proof. apply/eqP; rewrite eqEsubv; apply/andP; split. by rewrite limg_sum; apply/subv_sumP => i _; rewrite aimgX subX_agenv. apply: agenv_sub_modl; first by rewrite -(aimg1 f) limgS // sub1_agenv. by rewrite -aimgM limgS // [rhs in (_ <= rhs)%VS]agenvEl addvSr. Qed. Lemma aimg_adjoin (f : ahom aT rT) U x : (f @: <> = <>)%VS. Proof. by rewrite aimg_agen limg_add limg_line. Qed. Lemma aimg_adjoin_seq (f : ahom aT rT) U xs : (f @: <> = <>)%VS. Proof. by rewrite aimg_agen limg_add limg_span. Qed. Fact ker_sub_ahom_is_aspace (f g : ahom aT rT) : is_aspace (lker (ahval f - ahval g)). Proof. rewrite /is_aspace has_algid1; last by apply/eqlfunP; rewrite !rmorph1. apply/prodvP=> a b /eqlfunP Dfa /eqlfunP Dfb. by apply/eqlfunP; rewrite !rmorphM /= Dfa Dfb. Qed. Canonical ker_sub_ahom_aspace f g := ASpace (ker_sub_ahom_is_aspace f g). End LRMorphism. Canonical fixedSpace_aspace aT (f : ahom aT aT) := [aspace of fixedSpace f]. End AHom. Implicit Arguments ahom_in [K aT rT]. Notation "''AHom' ( aT , rT )" := (ahom aT rT) : type_scope. Notation "''AEnd' ( aT )" := (ahom aT aT) : type_scope. Delimit Scope lrfun_scope with AF. Bind Scope lrfun_scope with ahom. Notation "\1" := (@id_ahom _ _) : lrfun_scope. Notation "f \o g" := (comp_ahom f g) : lrfun_scope. mathcomp-1.5/theories/perm.v0000644000175000017500000005714012307636117015144 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq path choice fintype. Require Import tuple finfun bigop finset binomial fingroup. (******************************************************************************) (* This file contains the definition and properties associated to the group *) (* of permutations of an arbitrary finite type. *) (* {perm T} == the type of permutations of a finite type T, i.e., *) (* injective (finite) functions from T to T. Permutations *) (* coerce to CiC functions. *) (* 'S_n == the set of all permutations of 'I_n, i.e., of {0,.., n-1} *) (* perm_on A u == u is a permutation with support A, i.e., u only displaces *) (* elements of A (u x != x implies x \in A). *) (* tperm x y == the transposition of x, y *) (* aperm x s == the image of x under the action of the permutation s *) (* := s x *) (* pcycle s x == the set of all elements that are in the same cycle of the *) (* permutation s as x, i.e., {x, s x, (s ^+ 2) x, ...} *) (* pcycles s == the set of all the cycles of the permutation s *) (* (s : bool) == s is an odd permutation (the coercion is called odd_perm) *) (* dpair u == u is a pair (x, y) of distinct objects (i.e., x != y) *) (* lift_perm i j s == the permutation obtained by lifting s : 'S_n.-1 over *) (* (i |-> j), that maps i to j and lift i k to lift j (s k). *) (* Canonical structures are defined allowing permutations to be an eqType, *) (* choiceType, countType, finType, subType, finGroupType; permutations with *) (* composition form a group, therefore inherit all generic group notations: *) (* 1 == identity permutation, * == composition, ^-1 == inverse permutation. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section PermDefSection. Variable T : finType. Inductive perm_type : predArgType := Perm (pval : {ffun T -> T}) & injectiveb pval. Definition pval p := let: Perm f _ := p in f. Definition perm_of of phant T := perm_type. Identity Coercion type_of_perm : perm_of >-> perm_type. Notation pT := (perm_of (Phant T)). Canonical perm_subType := Eval hnf in [subType for pval]. Definition perm_eqMixin := Eval hnf in [eqMixin of perm_type by <:]. Canonical perm_eqType := Eval hnf in EqType perm_type perm_eqMixin. Definition perm_choiceMixin := [choiceMixin of perm_type by <:]. Canonical perm_choiceType := Eval hnf in ChoiceType perm_type perm_choiceMixin. Definition perm_countMixin := [countMixin of perm_type by <:]. Canonical perm_countType := Eval hnf in CountType perm_type perm_countMixin. Canonical perm_subCountType := Eval hnf in [subCountType of perm_type]. Definition perm_finMixin := [finMixin of perm_type by <:]. Canonical perm_finType := Eval hnf in FinType perm_type perm_finMixin. Canonical perm_subFinType := Eval hnf in [subFinType of perm_type]. Canonical perm_for_subType := Eval hnf in [subType of pT]. Canonical perm_for_eqType := Eval hnf in [eqType of pT]. Canonical perm_for_choiceType := Eval hnf in [choiceType of pT]. Canonical perm_for_countType := Eval hnf in [countType of pT]. Canonical perm_for_subCountType := Eval hnf in [subCountType of pT]. Canonical perm_for_finType := Eval hnf in [finType of pT]. Canonical perm_for_subFinType := Eval hnf in [subFinType of pT]. Lemma perm_proof (f : T -> T) : injective f -> injectiveb (finfun f). Proof. by move=> f_inj; apply/injectiveP; apply: eq_inj f_inj _ => x; rewrite ffunE. Qed. End PermDefSection. Notation "{ 'perm' T }" := (perm_of (Phant T)) (at level 0, format "{ 'perm' T }") : type_scope. Arguments Scope pval [_ group_scope]. Bind Scope group_scope with perm_type. Bind Scope group_scope with perm_of. Notation "''S_' n" := {perm 'I_n} (at level 8, n at level 2, format "''S_' n"). Notation Local fun_of_perm_def := (fun T (u : perm_type T) => val u : T -> T). Notation Local perm_def := (fun T f injf => Perm (@perm_proof T f injf)). Module Type PermDefSig. Parameter fun_of_perm : forall T, perm_type T -> T -> T. Parameter perm : forall (T : finType) (f : T -> T), injective f -> {perm T}. Axiom fun_of_permE : fun_of_perm = fun_of_perm_def. Axiom permE : perm = perm_def. End PermDefSig. Module PermDef : PermDefSig. Definition fun_of_perm := fun_of_perm_def. Definition perm := perm_def. Lemma fun_of_permE : fun_of_perm = fun_of_perm_def. Proof. by []. Qed. Lemma permE : perm = perm_def. Proof. by []. Qed. End PermDef. Notation fun_of_perm := PermDef.fun_of_perm. Notation "@ 'perm'" := (@PermDef.perm) (at level 10, format "@ 'perm'"). Notation perm := (@PermDef.perm _ _). Canonical fun_of_perm_unlock := Unlockable PermDef.fun_of_permE. Canonical perm_unlock := Unlockable PermDef.permE. Coercion fun_of_perm : perm_type >-> Funclass. Section Theory. Variable T : finType. Implicit Types (x y : T) (s t : {perm T}) (S : {set T}). Lemma permP s t : s =1 t <-> s = t. Proof. by split=> [| -> //]; rewrite unlock => eq_sv; exact/val_inj/ffunP. Qed. Lemma pvalE s : pval s = s :> (T -> T). Proof. by rewrite [@fun_of_perm]unlock. Qed. Lemma permE f f_inj : @perm T f f_inj =1 f. Proof. by move=> x; rewrite -pvalE [@perm]unlock ffunE. Qed. Lemma perm_inj s : injective s. Proof. by rewrite -!pvalE; exact: (injectiveP _ (valP s)). Qed. Implicit Arguments perm_inj []. Hint Resolve perm_inj. Lemma perm_onto s : codom s =i predT. Proof. by apply/subset_cardP; rewrite ?card_codom ?subset_predT. Qed. Definition perm_one := perm (@inj_id T). Lemma perm_invK s : cancel (fun x => iinv (perm_onto s x)) s. Proof. by move=> x /=; rewrite f_iinv. Qed. Definition perm_inv s := perm (can_inj (perm_invK s)). Definition perm_mul s t := perm (inj_comp (perm_inj t) (perm_inj s)). Lemma perm_oneP : left_id perm_one perm_mul. Proof. by move=> s; apply/permP => x; rewrite permE /= permE. Qed. Lemma perm_invP : left_inverse perm_one perm_inv perm_mul. Proof. by move=> s; apply/permP=> x; rewrite !permE /= permE f_iinv. Qed. Lemma perm_mulP : associative perm_mul. Proof. by move=> s t u; apply/permP=> x; do !rewrite permE /=. Qed. Definition perm_of_baseFinGroupMixin : FinGroup.mixin_of (perm_type T) := FinGroup.Mixin perm_mulP perm_oneP perm_invP. Canonical perm_baseFinGroupType := Eval hnf in BaseFinGroupType (perm_type T) perm_of_baseFinGroupMixin. Canonical perm_finGroupType := @FinGroupType perm_baseFinGroupType perm_invP. Canonical perm_of_baseFinGroupType := Eval hnf in [baseFinGroupType of {perm T}]. Canonical perm_of_finGroupType := Eval hnf in [finGroupType of {perm T} ]. Lemma perm1 x : (1 : {perm T}) x = x. Proof. by rewrite permE. Qed. Lemma permM s t x : (s * t) x = t (s x). Proof. by rewrite permE. Qed. Lemma permK s : cancel s s^-1. Proof. by move=> x; rewrite -permM mulgV perm1. Qed. Lemma permKV s : cancel s^-1 s. Proof. by have:= permK s^-1; rewrite invgK. Qed. Lemma permJ s t x : (s ^ t) (t x) = t (s x). Proof. by rewrite !permM permK. Qed. Lemma permX s x n : (s ^+ n) x = iter n s x. Proof. by elim: n => [|n /= <-]; rewrite ?perm1 // -permM expgSr. Qed. Lemma im_permV s S : s^-1 @: S = s @^-1: S. Proof. exact: can2_imset_pre (permKV s) (permK s). Qed. Lemma preim_permV s S : s^-1 @^-1: S = s @: S. Proof. by rewrite -im_permV invgK. Qed. Definition perm_on S : pred {perm T} := fun s => [pred x | s x != x] \subset S. Lemma perm_closed S s x : perm_on S s -> (s x \in S) = (x \in S). Proof. move/subsetP=> s_on_S; have [-> // | nfix_s_x] := eqVneq (s x) x. by rewrite !s_on_S // inE /= ?(inj_eq (perm_inj s)). Qed. Lemma perm_on1 H : perm_on H 1. Proof. by apply/subsetP=> x; rewrite inE /= perm1 eqxx. Qed. Lemma perm_onM H s t : perm_on H s -> perm_on H t -> perm_on H (s * t). Proof. move/subsetP=> sH /subsetP tH; apply/subsetP => x; rewrite inE /= permM. by have [-> /tH | /sH] := eqVneq (s x) x. Qed. Lemma out_perm S u x : perm_on S u -> x \notin S -> u x = x. Proof. by move=> uS; exact: contraNeq (subsetP uS x). Qed. Lemma im_perm_on u S : perm_on S u -> u @: S = S. Proof. move=> Su; rewrite -preim_permV; apply/setP=> x. by rewrite !inE -(perm_closed _ Su) permKV. Qed. Lemma tperm_proof x y : involutive [fun z => z with x |-> y, y |-> x]. Proof. move=> z /=; case: (z =P x) => [-> | ne_zx]; first by rewrite eqxx; case: eqP. by case: (z =P y) => [->| ne_zy]; [rewrite eqxx | do 2?case: eqP]. Qed. Definition tperm x y := perm (can_inj (tperm_proof x y)). CoInductive tperm_spec x y z : T -> Type := | TpermFirst of z = x : tperm_spec x y z y | TpermSecond of z = y : tperm_spec x y z x | TpermNone of z <> x & z <> y : tperm_spec x y z z. Lemma tpermP x y z : tperm_spec x y z (tperm x y z). Proof. by rewrite permE /=; do 2?[case: eqP => /=]; constructor; auto. Qed. Lemma tpermL x y : tperm x y x = y. Proof. by case: tpermP. Qed. Lemma tpermR x y : tperm x y y = x. Proof. by case: tpermP. Qed. Lemma tpermD x y z : x != z -> y != z -> tperm x y z = z. Proof. by case: tpermP => // ->; rewrite eqxx. Qed. Lemma tpermC x y : tperm x y = tperm y x. Proof. by apply/permP => z; do 2![case: tpermP => //] => ->. Qed. Lemma tperm1 x : tperm x x = 1. Proof. by apply/permP => z; rewrite perm1; case: tpermP. Qed. Lemma tpermK x y : involutive (tperm x y). Proof. by move=> z; rewrite !permE tperm_proof. Qed. Lemma tpermKg x y : involutive (mulg (tperm x y)). Proof. by move=> s; apply/permP=> z; rewrite !permM tpermK. Qed. Lemma tpermV x y : (tperm x y)^-1 = tperm x y. Proof. by set t := tperm x y; rewrite -{2}(mulgK t t) -mulgA tpermKg. Qed. Lemma tperm2 x y : tperm x y * tperm x y = 1. Proof. by rewrite -{1}tpermV mulVg. Qed. Lemma card_perm A : #|perm_on A| = (#|A|)`!. Proof. pose ffA := {ffun {x | x \in A} -> T}. rewrite -ffactnn -{2}(card_sig (mem A)) /= -card_inj_ffuns_on. pose fT (f : ffA) := [ffun x => oapp f x (insub x)]. pose pfT f := insubd (1 : {perm T}) (fT f). pose fA s : ffA := [ffun u => s (val u)]. rewrite -!sum1dep_card -sum1_card (reindex_onto fA pfT) => [|f]. apply: eq_bigl => p; rewrite andbC; apply/idP/and3P=> [onA | []]; first split. - apply/eqP; suffices fTAp: fT (fA p) = pval p. by apply/permP=> x; rewrite -!pvalE insubdK fTAp //; exact: (valP p). apply/ffunP=> x; rewrite ffunE pvalE. by case: insubP => [u _ <- | /out_perm->] //=; rewrite ffunE. - by apply/forallP=> [[x Ax]]; rewrite ffunE /= perm_closed. - by apply/injectiveP=> u v; rewrite !ffunE => /perm_inj; exact: val_inj. move/eqP=> <- _ _; apply/subsetP=> x; rewrite !inE -pvalE val_insubd fun_if. by rewrite if_arg ffunE; case: insubP; rewrite // pvalE perm1 if_same eqxx. case/andP=> /forallP-onA /injectiveP-f_inj. apply/ffunP=> u; rewrite ffunE -pvalE insubdK; first by rewrite ffunE valK. apply/injectiveP=> {u} x y; rewrite !ffunE. case: insubP => [u _ <-|]; case: insubP => [v _ <-|] //=; first by move/f_inj->. by move=> Ay' def_y; rewrite -def_y [_ \in A]onA in Ay'. by move=> Ax' def_x; rewrite def_x [_ \in A]onA in Ax'. Qed. End Theory. Prenex Implicits tperm. Lemma inj_tperm (T T' : finType) (f : T -> T') x y z : injective f -> f (tperm x y z) = tperm (f x) (f y) (f z). Proof. by move=> injf; rewrite !permE /= !(inj_eq injf) !(fun_if f). Qed. Lemma tpermJ (T : finType) x y (s : {perm T}) : (tperm x y) ^ s = tperm (s x) (s y). Proof. apply/permP => z; rewrite -(permKV s z) permJ; apply: inj_tperm. exact: perm_inj. Qed. Lemma tuple_perm_eqP {T : eqType} {n} {s : seq T} {t : n.-tuple T} : reflect (exists p : 'S_n, s = [tuple tnth t (p i) | i < n]) (perm_eq s t). Proof. apply: (iffP idP) => [|[p ->]]; last first. rewrite /= (map_comp (tnth t)) -{1}(map_tnth_enum t) perm_map //. apply: uniq_perm_eq => [||i]; rewrite ?enum_uniq //. by apply/injectiveP; apply: perm_inj. by rewrite mem_enum -[i](permKV p) image_f. case: n => [|n] in t *; last have x0 := tnth t ord0. rewrite tuple0 => /perm_eq_small-> //. by exists 1; rewrite [mktuple _]tuple0. case/(perm_eq_iotaP x0); rewrite size_tuple => Is eqIst ->{s}. have uniqIs: uniq Is by rewrite (perm_eq_uniq eqIst) iota_uniq. have szIs: size Is == n.+1 by rewrite (perm_eq_size eqIst) !size_tuple. have pP i : tnth (Tuple szIs) i < n.+1. by rewrite -[_ < _](mem_iota 0) -(perm_eq_mem eqIst) mem_tnth. have inj_p: injective (fun i => Ordinal (pP i)). by apply/injectiveP/(@map_uniq _ _ val); rewrite -map_comp map_tnth_enum. exists (perm inj_p); rewrite -[Is]/(tval (Tuple szIs)); congr (tval _). by apply: eq_from_tnth => i; rewrite tnth_map tnth_mktuple permE (tnth_nth x0). Qed. Section PermutationParity. Variable T : finType. Implicit Types (s t u v : {perm T}) (x y z a b : T). (* Note that pcycle s x is the orbit of x by <[s]> under the action aperm. *) (* Hence, the pcycle lemmas below are special cases of more general lemmas *) (* on orbits that will be stated in action.v. *) (* Defining pcycle directly here avoids a dependency of matrix.v on *) (* action.v and hence morphism.v. *) Definition aperm x s := s x. Definition pcycle s x := aperm x @: <[s]>. Definition pcycles s := pcycle s @: T. Definition odd_perm (s : perm_type T) := odd #|T| (+) odd #|pcycles s|. Lemma apermE x s : aperm x s = s x. Proof. by []. Qed. Lemma mem_pcycle s i x : (s ^+ i) x \in pcycle s x. Proof. by rewrite (mem_imset (aperm x)) ?mem_cycle. Qed. Lemma pcycle_id s x : x \in pcycle s x. Proof. by rewrite -{1}[x]perm1 (mem_pcycle s 0). Qed. Lemma uniq_traject_pcycle s x : uniq (traject s x #|pcycle s x|). Proof. case def_n: #|_| => // [n]; rewrite looping_uniq. apply: contraL (card_size (traject s x n)) => /loopingP t_sx. rewrite -ltnNge size_traject -def_n ?subset_leq_card //. by apply/subsetP=> _ /imsetP[_ /cycleP[i ->] ->]; rewrite /aperm permX t_sx. Qed. Lemma pcycle_traject s x : pcycle s x =i traject s x #|pcycle s x|. Proof. apply: fsym; apply/subset_cardP. by rewrite (card_uniqP _) ?size_traject ?uniq_traject_pcycle. by apply/subsetP=> _ /trajectP[i _ ->]; rewrite -permX mem_pcycle. Qed. Lemma iter_pcycle s x : iter #|pcycle s x| s x = x. Proof. case def_n: #|_| (uniq_traject_pcycle s x) => [//|n] Ut. have: looping s x n.+1. by rewrite -def_n -[looping _ _ _]pcycle_traject -permX mem_pcycle. rewrite /looping => /trajectP[[|i] //= lt_i_n /perm_inj eq_i_n_sx]. move: lt_i_n; rewrite ltnS ltn_neqAle andbC => /andP[le_i_n /negP[]]. by rewrite -(nth_uniq x _ _ Ut) ?size_traject ?nth_traject // eq_i_n_sx. Qed. Lemma eq_pcycle_mem s x y : (pcycle s x == pcycle s y) = (x \in pcycle s y). Proof. apply/eqP/idP=> [<- | /imsetP[si s_si ->]]; first exact: pcycle_id. apply/setP => z; apply/imsetP/imsetP=> [] [sj s_sj ->]. by exists (si * sj); rewrite ?groupM /aperm ?permM. exists (si^-1 * sj); first by rewrite groupM ?groupV. by rewrite /aperm permM permK. Qed. Lemma pcycle_sym s x y : (x \in pcycle s y) = (y \in pcycle s x). Proof. by rewrite -!eq_pcycle_mem eq_sym. Qed. Lemma pcycle_perm s i x : pcycle s ((s ^+ i) x) = pcycle s x. Proof. by apply/eqP; rewrite eq_pcycle_mem mem_pcycle. Qed. Lemma ncycles_mul_tperm s x y : let t := tperm x y in #|pcycles (t * s)| + (x \notin pcycle s y).*2 = #|pcycles s| + (x != y). Proof. pose xf a b u := find (pred2 a b) (traject u (u a) #|pcycle u a|). have xf_size a b u: xf a b u <= #|pcycle u a|. by rewrite (leq_trans (find_size _ _)) ?size_traject. have lt_xf a b u n : n < xf a b u -> ~~ pred2 a b ((u ^+ n.+1) a). move=> lt_n; apply: contraFN (before_find (u a) lt_n). by rewrite permX iterSr nth_traject // (leq_trans lt_n). pose t a b u := tperm a b * u. have tC a b u : t a b u = t b a u by rewrite /t tpermC. have tK a b: involutive (t a b) by move=> u; exact: tpermKg. have tXC a b u n: n <= xf a b u -> (t a b u ^+ n.+1) b = (u ^+ n.+1) a. elim: n => [|n IHn] lt_n_f; first by rewrite permM tpermR. rewrite !(expgSr _ n.+1) !permM {}IHn 1?ltnW //; congr (u _). by case/lt_xf/norP: lt_n_f => ne_a ne_b; rewrite tpermD // eq_sym. have eq_xf a b u: pred2 a b ((u ^+ (xf a b u).+1) a). have ua_a: a \in pcycle u (u a) by rewrite pcycle_sym (mem_pcycle _ 1). have has_f: has (pred2 a b) (traject u (u a) #|pcycle u (u a)|). by apply/hasP; exists a; rewrite /= ?eqxx -?pcycle_traject. have:= nth_find (u a) has_f; rewrite has_find size_traject in has_f. rewrite -eq_pcycle_mem in ua_a. by rewrite nth_traject // -iterSr -permX -(eqP ua_a). have xfC a b u: xf b a (t a b u) = xf a b u. without loss lt_a: a b u / xf b a (t a b u) < xf a b u. move=> IHab; set m := xf b a _; set n := xf a b u. by case: (ltngtP m n) => // ltx; [exact: IHab | rewrite -[m]IHab tC tK]. by move/lt_xf: (lt_a); rewrite -(tXC a b) 1?ltnW //= orbC [_ || _]eq_xf. pose ts := t x y s; rewrite /= -[_ * s]/ts. pose dp u := #|pcycles u :\ pcycle u y :\ pcycle u x|. rewrite !(addnC #|_|) (cardsD1 (pcycle ts y)) mem_imset ?inE //. rewrite (cardsD1 (pcycle ts x)) inE mem_imset ?inE //= -/(dp ts) {}/ts. rewrite (cardsD1 (pcycle s y)) (cardsD1 (pcycle s x)) !(mem_imset, inE) //. rewrite -/(dp s) !addnA !eq_pcycle_mem andbT; congr (_ + _); last first. wlog suffices: s / dp s <= dp (t x y s). by move=> IHs; apply/eqP; rewrite eqn_leq -{2}(tK x y s) !IHs. apply/subset_leq_card/subsetP=> {dp} C. rewrite !inE andbA andbC !(eq_sym C) => /and3P[/imsetP[z _ ->{C}]]. rewrite 2!eq_pcycle_mem => sxz syz. suffices ts_z: pcycle (t x y s) z = pcycle s z. by rewrite -ts_z !eq_pcycle_mem {1 2}ts_z sxz syz mem_imset ?inE. suffices exp_id n: ((t x y s) ^+ n) z = (s ^+ n) z. apply/setP=> u; apply/idP/idP=> /imsetP[_ /cycleP[i ->] ->]. by rewrite /aperm exp_id mem_pcycle. by rewrite /aperm -exp_id mem_pcycle. elim: n => // n IHn; rewrite !expgSr !permM {}IHn tpermD //. apply: contraNneq sxz => ->; exact: mem_pcycle. apply: contraNneq syz => ->; exact: mem_pcycle. case: eqP {dp} => [<- | ne_xy]; first by rewrite /t tperm1 mul1g pcycle_id. suff ->: (x \in pcycle (t x y s) y) = (x \notin pcycle s y) by case: (x \in _). without loss xf_x: s x y ne_xy / (s ^+ (xf x y s).+1) x = x. move=> IHs; have ne_yx := nesym ne_xy; have:= eq_xf x y s; set n := xf x y s. case/pred2P=> [|snx]; first exact: IHs. by rewrite -[x \in _]negbK ![x \in _]pcycle_sym -{}IHs ?xfC ?tXC // tC tK. rewrite -{1}xf_x -(tXC _ _ _ _ (leqnn _)) mem_pcycle; symmetry. rewrite -eq_pcycle_mem eq_sym eq_pcycle_mem pcycle_traject. apply/trajectP=> [[n _ snx]]. have: looping s x (xf x y s).+1 by rewrite /looping -permX xf_x inE eqxx. move/loopingP/(_ n); rewrite -{n}snx. case/trajectP=> [[_|i]]; first exact: nesym; rewrite ltnS -permX => lt_i def_y. by move/lt_xf: lt_i; rewrite def_y /= eqxx orbT. Qed. Lemma odd_perm1 : odd_perm 1 = false. Proof. rewrite /odd_perm card_imset ?addbb // => x y; move/eqP. by rewrite eq_pcycle_mem /pcycle cycle1 imset_set1 /aperm perm1; move/set1P. Qed. Lemma odd_mul_tperm x y s : odd_perm (tperm x y * s) = (x != y) (+) odd_perm s. Proof. rewrite addbC -addbA -[~~ _]oddb -odd_add -ncycles_mul_tperm. by rewrite odd_add odd_double addbF. Qed. Lemma odd_tperm x y : odd_perm (tperm x y) = (x != y). Proof. by rewrite -[_ y]mulg1 odd_mul_tperm odd_perm1 addbF. Qed. Definition dpair (eT : eqType) := [pred t | t.1 != t.2 :> eT]. Implicit Arguments dpair [eT]. Lemma prod_tpermP s : {ts : seq (T * T) | s = \prod_(t <- ts) tperm t.1 t.2 & all dpair ts}. Proof. elim: {s}_.+1 {-2}s (ltnSn #|[pred x | s x != x]|) => // n IHn s. rewrite ltnS => le_s_n; case: (pickP (fun x => s x != x)) => [x s_x | s_id]. have [|ts def_s ne_ts] := IHn (tperm x (s^-1 x) * s). rewrite (cardD1 x) !inE s_x in le_s_n; apply: leq_ltn_trans le_s_n. apply: subset_leq_card; apply/subsetP=> y. rewrite !inE permM permE /= -(canF_eq (permK _)). have [-> | ne_yx] := altP (y =P x); first by rewrite permKV eqxx. by case: (s y =P x) => // -> _; rewrite eq_sym. exists ((x, s^-1 x) :: ts); last by rewrite /= -(canF_eq (permK _)) s_x. by rewrite big_cons -def_s mulgA tperm2 mul1g. exists nil; rewrite // big_nil; apply/permP=> x. by apply/eqP/idPn; rewrite perm1 s_id. Qed. Lemma odd_perm_prod ts : all dpair ts -> odd_perm (\prod_(t <- ts) tperm t.1 t.2) = odd (size ts). Proof. elim: ts => [_|t ts IHts] /=; first by rewrite big_nil odd_perm1. by case/andP=> dt12 dts; rewrite big_cons odd_mul_tperm dt12 IHts. Qed. Lemma odd_permM : {morph odd_perm : s1 s2 / s1 * s2 >-> s1 (+) s2}. Proof. move=> s1 s2; case: (prod_tpermP s1) => ts1 ->{s1} dts1. case: (prod_tpermP s2) => ts2 ->{s2} dts2. by rewrite -big_cat !odd_perm_prod ?all_cat ?dts1 // size_cat odd_add. Qed. Lemma odd_permV s : odd_perm s^-1 = odd_perm s. Proof. by rewrite -{2}(mulgK s s) !odd_permM -addbA addKb. Qed. Lemma odd_permJ s1 s2 : odd_perm (s1 ^ s2) = odd_perm s1. Proof. by rewrite !odd_permM odd_permV addbC addbK. Qed. End PermutationParity. Coercion odd_perm : perm_type >-> bool. Implicit Arguments dpair [eT]. Prenex Implicits pcycle dpair pcycles aperm. Section LiftPerm. (* Somewhat more specialised constructs for permutations on ordinals. *) Variable n : nat. Implicit Types i j : 'I_n.+1. Implicit Types s t : 'S_n. Definition lift_perm_fun i j s k := if unlift i k is Some k' then lift j (s k') else j. Lemma lift_permK i j s : cancel (lift_perm_fun i j s) (lift_perm_fun j i s^-1). Proof. rewrite /lift_perm_fun => k. by case: (unliftP i k) => [j'|] ->; rewrite (liftK, unlift_none) ?permK. Qed. Definition lift_perm i j s := perm (can_inj (lift_permK i j s)). Lemma lift_perm_id i j s : lift_perm i j s i = j. Proof. by rewrite permE /lift_perm_fun unlift_none. Qed. Lemma lift_perm_lift i j s k' : lift_perm i j s (lift i k') = lift j (s k') :> 'I_n.+1. Proof. by rewrite permE /lift_perm_fun liftK. Qed. Lemma lift_permM i j k s t : lift_perm i j s * lift_perm j k t = lift_perm i k (s * t). Proof. apply/permP=> i1; case: (unliftP i i1) => [i2|] ->{i1}. by rewrite !(permM, lift_perm_lift). by rewrite permM !lift_perm_id. Qed. Lemma lift_perm1 i : lift_perm i i 1 = 1. Proof. by apply: (mulgI (lift_perm i i 1)); rewrite lift_permM !mulg1. Qed. Lemma lift_permV i j s : (lift_perm i j s)^-1 = lift_perm j i s^-1. Proof. by apply/eqP; rewrite eq_invg_mul lift_permM mulgV lift_perm1. Qed. Lemma odd_lift_perm i j s : lift_perm i j s = odd i (+) odd j (+) s :> bool. Proof. rewrite -{1}(mul1g s) -(lift_permM _ j) odd_permM. congr (_ (+) _); last first. case: (prod_tpermP s) => ts ->{s} _. elim: ts => [|t ts IHts] /=; first by rewrite big_nil lift_perm1 !odd_perm1. rewrite big_cons odd_mul_tperm -(lift_permM _ j) odd_permM {}IHts //. congr (_ (+) _); rewrite (_ : _ j _ = tperm (lift j t.1) (lift j t.2)). by rewrite odd_tperm (inj_eq (@lift_inj _ _)). apply/permP=> k; case: (unliftP j k) => [k'|] ->. rewrite lift_perm_lift inj_tperm //; exact: lift_inj. by rewrite lift_perm_id tpermD // eq_sym neq_lift. suff{i j s} odd_lift0 (k : 'I_n.+1): lift_perm ord0 k 1 = odd k :> bool. rewrite -!odd_lift0 -{2}invg1 -lift_permV odd_permV -odd_permM. by rewrite lift_permM mulg1. elim: {k}(k : nat) {1 3}k (erefl (k : nat)) => [|m IHm] k def_k. rewrite (_ : k = ord0) ?lift_perm1 ?odd_perm1 //; exact: val_inj. have le_mn: m < n.+1 by [rewrite -def_k ltnW]; pose j := Ordinal le_mn. rewrite -(mulg1 1)%g -(lift_permM _ j) odd_permM {}IHm // addbC. rewrite (_ : _ 1 = tperm j k); first by rewrite odd_tperm neq_ltn def_k leqnn. apply/permP=> i; case: (unliftP j i) => [i'|] ->; last first. by rewrite lift_perm_id tpermL. apply: ord_inj; rewrite lift_perm_lift !permE /= eq_sym -if_neg neq_lift. rewrite fun_if -val_eqE /= def_k /bump ltn_neqAle andbC. case: leqP => [_ | lt_i'm] /=; last by rewrite -if_neg neq_ltn leqW. by rewrite add1n eqSS eq_sym; case: eqP. Qed. End LiftPerm. mathcomp-1.5/theories/finalg.v0000644000175000017500000014206112307636117015436 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq choice fintype. Require Import ssralg finset fingroup morphism perm action. (*****************************************************************************) (* This file clones the entire ssralg hierachy for finite types; this allows *) (* type inference to function properly on expressions that mix combinatorial *) (* and algebraic operators (e.g., [set x + y | x in A, y in A]). *) (* finZmodType, finRingType, finComRingType, finUnitRingType, *) (* finComUnitRingType, finIdomType, finFieldType finLmodType, *) (* finLalgType finAlgType finUnitAlgType *) (* == the finite counterparts of zmodType, etc. *) (* Note that a finFieldType is canonically decidable. All these structures *) (* can be derived using [xxxType of T] forms, e.g., if R has both canonical *) (* finType and ringType structures, then *) (* Canonical R_finRingType := Eval hnf in [finRingType of R]. *) (* declares the derived finRingType structure for R. As the implementation *) (* of the derivation is somewhat involved, the Eval hnf normalization is *) (* strongly recommended. *) (* This file also provides direct tie-ins with finite group theory: *) (* [baseFinGroupType of R for +%R] == the (canonical) additive group *) (* [finGroupType of R for +%R] structures for R *) (* {unit R} == the type of units of R, which has a *) (* canonical group structure. *) (* FinRing.unit R Ux == the element of {unit R} corresponding *) (* to x, where Ux : x \in GRing.unit. *) (* 'U%act == the action by right multiplication of *) (* {unit R} on R, via FinRing.unit_act. *) (* (This is also a group action.) *) (*****************************************************************************) Local Open Scope ring_scope. Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Module FinRing. Local Notation mixin_of T b := (Finite.mixin_of (EqType T b)). Section Generic. (* Implicits *) Variables (type base_type : Type) (class_of base_of : Type -> Type). Variable to_choice : forall T, base_of T -> Choice.class_of T. Variable base_sort : base_type -> Type. (* Explicits *) Variable Pack : forall T, class_of T -> Type -> type. Variable Class : forall T b, mixin_of T (to_choice b) -> class_of T. Variable base_class : forall bT, base_of (base_sort bT). Definition gen_pack T := fun bT b & phant_id (base_class bT) b => fun fT m & phant_id (Finite.class fT) (Finite.Class m) => Pack (@Class T b m) T. End Generic. Implicit Arguments gen_pack [type base_type class_of base_of to_choice base_sort]. Local Notation fin_ c := (@Finite.Class _ c c). Local Notation do_pack pack T := (pack T _ _ id _ _ id). Import GRing.Theory. Definition groupMixin V := FinGroup.Mixin (@addrA V) (@add0r V) (@addNr V). Local Notation base_group T vT fT := (@FinGroup.PackBase T (groupMixin vT) (Finite.class fT)). Local Notation fin_group B V := (@FinGroup.Pack B (@addNr V)). Module Zmodule. Section ClassDef. Record class_of M := Class { base : GRing.Zmodule.class_of M; mixin : mixin_of M base }. Local Coercion base : class_of >-> GRing.Zmodule.class_of. Local Coercion mixin : class_of >-> mixin_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.Zmodule.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition join_finType := @Finite.Pack zmodType (fin_ xclass) xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.Zmodule.class_of. Coercion mixin : class_of >-> mixin_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Canonical join_finType. Notation finZmodType := type. Notation "[ 'finZmodType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'finZmodType' 'of' T ]") : form_scope. Coercion baseFinGroupType : type >-> FinGroup.base_type. Canonical baseFinGroupType. Coercion finGroupType : type >-> FinGroup.type. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. Notation "[ 'baseFinGroupType' 'of' R 'for' +%R ]" := (BaseFinGroupType R (groupMixin _)) (at level 0, format "[ 'baseFinGroupType' 'of' R 'for' +%R ]") : form_scope. Notation "[ 'finGroupType' 'of' R 'for' +%R ]" := (@FinGroup.clone R _ (finGroupType _) id _ id) (at level 0, format "[ 'finGroupType' 'of' R 'for' +%R ]") : form_scope. End Exports. End Zmodule. Import Zmodule.Exports. Section AdditiveGroup. Variable U : finZmodType. Implicit Types x y : U. Lemma zmod1gE : 1%g = 0 :> U. Proof. by []. Qed. Lemma zmodVgE x : x^-1%g = - x. Proof. by []. Qed. Lemma zmodMgE x y : (x * y)%g = x + y. Proof. by []. Qed. Lemma zmodXgE n x : (x ^+ n)%g = x *+ n. Proof. by []. Qed. Lemma zmod_mulgC x y : commute x y. Proof. exact: GRing.addrC. Qed. Lemma zmod_abelian (A : {set U}) : abelian A. Proof. by apply/centsP=> x _ y _; exact: zmod_mulgC. Qed. End AdditiveGroup. Module Ring. Section ClassDef. Record class_of R := Class { base : GRing.Ring.class_of R; mixin : mixin_of R base }. Definition base2 R (c : class_of R) := Zmodule.Class (mixin c). Local Coercion base : class_of >-> GRing.Ring.class_of. Local Coercion base2 : class_of >-> Zmodule.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.Ring.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) cT. Definition zmodType := @GRing.Zmodule.Pack cT xclass cT. Definition finZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition join_finType := @Finite.Pack ringType (fin_ xclass) xT. Definition join_finZmodType := @Zmodule.Pack ringType xclass xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Import Exports. Coercion base : class_of >-> GRing.Ring.class_of. Coercion base2 : class_of >-> Zmodule.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion finZmodType : type >-> Zmodule.type. Canonical finZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Canonical join_finType. Canonical join_finZmodType. Notation finRingType := type. Notation "[ 'finRingType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'finRingType' 'of' T ]") : form_scope. Canonical baseFinGroupType. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. End Exports. Section Unit. Variable R : finRingType. Definition is_inv (x y : R) := (x * y == 1) && (y * x == 1). Definition unit := [qualify a x : R | [exists y, is_inv x y]]. Definition inv x := odflt x (pick (is_inv x)). Lemma mulVr : {in unit, left_inverse 1 inv *%R}. Proof. rewrite /inv => x Ux; case: pickP => [y | no_y]; last by case/pred0P: Ux. by case/andP=> _; move/eqP. Qed. Lemma mulrV : {in unit, right_inverse 1 inv *%R}. Proof. rewrite /inv => x Ux; case: pickP => [y | no_y]; last by case/pred0P: Ux. by case/andP; move/eqP. Qed. Lemma intro_unit x y : y * x = 1 /\ x * y = 1 -> x \is a unit. Proof. by case=> yx1 xy1; apply/existsP; exists y; rewrite /is_inv xy1 yx1 !eqxx. Qed. Lemma invr_out : {in [predC unit], inv =1 id}. Proof. rewrite /inv => x nUx; case: pickP => // y invxy. by case/existsP: nUx; exists y. Qed. Definition UnitMixin := GRing.UnitRing.Mixin mulVr mulrV intro_unit invr_out. End Unit. End Ring. Import Ring.Exports. Module ComRing. Section ClassDef. Record class_of R := Class { base : GRing.ComRing.class_of R; mixin : mixin_of R base }. Definition base2 R (c : class_of R) := Ring.Class (mixin c). Local Coercion base : class_of >-> GRing.ComRing.class_of. Local Coercion base2 : class_of >-> Ring.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.ComRing.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition finZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition finRingType := @Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition join_finType := @Finite.Pack comRingType (fin_ xclass) xT. Definition join_finZmodType := @Zmodule.Pack comRingType xclass xT. Definition join_finRingType := @Ring.Pack comRingType xclass xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.ComRing.class_of. Coercion base2 : class_of >-> Ring.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion finZmodType : type >-> Zmodule.type. Canonical finZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion finRingType : type >-> Ring.type. Canonical finRingType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Canonical join_finType. Canonical join_finZmodType. Canonical join_finRingType. Notation finComRingType := FinRing.ComRing.type. Notation "[ 'finComRingType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'finComRingType' 'of' T ]") : form_scope. Canonical baseFinGroupType. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. End Exports. End ComRing. Import ComRing.Exports. Module UnitRing. Section ClassDef. Record class_of R := Class { base : GRing.UnitRing.class_of R; mixin : mixin_of R base }. Definition base2 R (c : class_of R) := Ring.Class (mixin c). Local Coercion base : class_of >-> GRing.UnitRing.class_of. Local Coercion base2 : class_of >-> Ring.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.UnitRing.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition finZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition finRingType := @Ring.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition join_finType := @Finite.Pack unitRingType (fin_ xclass) xT. Definition join_finZmodType := @Zmodule.Pack unitRingType xclass xT. Definition join_finRingType := @Ring.Pack unitRingType xclass xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.UnitRing.class_of. Coercion base2 : class_of >-> Ring.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion finZmodType : type >-> Zmodule.type. Canonical finZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion finRingType : type >-> Ring.type. Canonical finRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Canonical join_finType. Canonical join_finZmodType. Canonical join_finRingType. Notation finUnitRingType := FinRing.UnitRing.type. Notation "[ 'finUnitRingType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'finUnitRingType' 'of' T ]") : form_scope. Canonical baseFinGroupType. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. End Exports. End UnitRing. Import UnitRing.Exports. Section UnitsGroup. Variable R : finUnitRingType. Inductive unit_of (phR : phant R) := Unit (x : R) of x \is a GRing.unit. Bind Scope group_scope with unit_of. Let phR := Phant R. Local Notation uT := (unit_of phR). Implicit Types u v : uT. Definition uval u := let: Unit x _ := u in x. Canonical unit_subType := [subType for uval]. Definition unit_eqMixin := Eval hnf in [eqMixin of uT by <:]. Canonical unit_eqType := Eval hnf in EqType uT unit_eqMixin. Definition unit_choiceMixin := [choiceMixin of uT by <:]. Canonical unit_choiceType := Eval hnf in ChoiceType uT unit_choiceMixin. Definition unit_countMixin := [countMixin of uT by <:]. Canonical unit_countType := Eval hnf in CountType uT unit_countMixin. Canonical unit_subCountType := Eval hnf in [subCountType of uT]. Definition unit_finMixin := [finMixin of uT by <:]. Canonical unit_finType := Eval hnf in FinType uT unit_finMixin. Canonical unit_subFinType := Eval hnf in [subFinType of uT]. Definition unit1 := Unit phR (@GRing.unitr1 _). Lemma unit_inv_proof u : (val u)^-1 \is a GRing.unit. Proof. by rewrite GRing.unitrV ?(valP u). Qed. Definition unit_inv u := Unit phR (unit_inv_proof u). Lemma unit_mul_proof u v : val u * val v \is a GRing.unit. Proof. by rewrite (GRing.unitrMr _ (valP u)) ?(valP v). Qed. Definition unit_mul u v := Unit phR (unit_mul_proof u v). Lemma unit_muluA : associative unit_mul. Proof. move=> u v w; apply: val_inj; exact: GRing.mulrA. Qed. Lemma unit_mul1u : left_id unit1 unit_mul. Proof. move=> u; apply: val_inj; exact: GRing.mul1r. Qed. Lemma unit_mulVu : left_inverse unit1 unit_inv unit_mul. Proof. move=> u; apply: val_inj; exact: GRing.mulVr (valP u). Qed. Definition unit_GroupMixin := FinGroup.Mixin unit_muluA unit_mul1u unit_mulVu. Canonical unit_baseFinGroupType := Eval hnf in BaseFinGroupType uT unit_GroupMixin. Canonical unit_finGroupType := Eval hnf in FinGroupType unit_mulVu. Lemma val_unit1 : val (1%g : uT) = 1. Proof. by []. Qed. Lemma val_unitM x y : val (x * y : uT)%g = val x * val y. Proof. by []. Qed. Lemma val_unitV x : val (x^-1 : uT)%g = (val x)^-1. Proof. by []. Qed. Lemma val_unitX n x : val (x ^+ n : uT)%g = val x ^+ n. Proof. by case: n; last by elim=> //= n ->. Qed. Definition unit_act x u := x * val u. Lemma unit_actE x u : unit_act x u = x * val u. Proof. by []. Qed. Canonical unit_action := @TotalAction _ _ unit_act (@GRing.mulr1 _) (fun _ _ _ => GRing.mulrA _ _ _). Lemma unit_is_groupAction : @is_groupAction _ R setT setT unit_action. Proof. move=> u _ /=; rewrite inE; apply/andP; split. by apply/subsetP=> x _; rewrite inE. by apply/morphicP=> x y _ _; rewrite !actpermE /= [_ u]GRing.mulrDl. Qed. Canonical unit_groupAction := GroupAction unit_is_groupAction. End UnitsGroup. Module Import UnitsGroupExports. Bind Scope group_scope with unit_of. Canonical unit_subType. Canonical unit_eqType. Canonical unit_choiceType. Canonical unit_countType. Canonical unit_subCountType. Canonical unit_finType. Canonical unit_subFinType. Canonical unit_baseFinGroupType. Canonical unit_finGroupType. Canonical unit_action. Canonical unit_groupAction. End UnitsGroupExports. Notation unit R Ux := (Unit (Phant R) Ux). Module ComUnitRing. Section ClassDef. Record class_of R := Class { base : GRing.ComUnitRing.class_of R; mixin : mixin_of R base }. Definition base2 R (c : class_of R) := ComRing.Class (mixin c). Definition base3 R (c : class_of R) := @UnitRing.Class R (base c) (mixin c). Local Coercion base : class_of >-> GRing.ComUnitRing.class_of. Local Coercion base2 : class_of >-> ComRing.class_of. Local Coercion base3 : class_of >-> UnitRing.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.ComUnitRing.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition finZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition finRingType := @Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition finComRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition finUnitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition join_finType := @Finite.Pack comUnitRingType (fin_ xclass) xT. Definition join_finZmodType := @Zmodule.Pack comUnitRingType xclass xT. Definition join_finRingType := @Ring.Pack comUnitRingType xclass xT. Definition join_finComRingType := @ComRing.Pack comUnitRingType xclass xT. Definition join_finUnitRingType := @UnitRing.Pack comUnitRingType xclass xT. Definition ujoin_finComRingType := @ComRing.Pack unitRingType xclass xT. Definition cjoin_finUnitRingType := @UnitRing.Pack comRingType xclass xT. Definition fcjoin_finUnitRingType := @UnitRing.Pack finComRingType xclass xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.ComUnitRing.class_of. Coercion base2 : class_of >-> ComRing.class_of. Coercion base3 : class_of >-> UnitRing.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion finZmodType : type >-> Zmodule.type. Canonical finZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion finRingType : type >-> Ring.type. Canonical finRingType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion finComRingType : type >-> ComRing.type. Canonical finComRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion finUnitRingType : type >-> UnitRing.type. Canonical finUnitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Canonical join_finType. Canonical join_finZmodType. Canonical join_finRingType. Canonical join_finComRingType. Canonical join_finUnitRingType. Canonical ujoin_finComRingType. Canonical cjoin_finUnitRingType. Canonical fcjoin_finUnitRingType. Notation finComUnitRingType := FinRing.ComUnitRing.type. Notation "[ 'finComUnitRingType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'finComUnitRingType' 'of' T ]") : form_scope. Canonical baseFinGroupType. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. End Exports. End ComUnitRing. Import ComUnitRing.Exports. Module IntegralDomain. Section ClassDef. Record class_of R := Class { base : GRing.IntegralDomain.class_of R; mixin : mixin_of R base }. Definition base2 R (c : class_of R) := ComUnitRing.Class (mixin c). Local Coercion base : class_of >-> GRing.IntegralDomain.class_of. Local Coercion base2 : class_of >-> ComUnitRing.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.IntegralDomain.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition finZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition finRingType := @Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition finComRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition finUnitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition finComUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition join_finType := @Finite.Pack idomainType (fin_ xclass) xT. Definition join_finZmodType := @Zmodule.Pack idomainType xclass xT. Definition join_finRingType := @Ring.Pack idomainType xclass xT. Definition join_finUnitRingType := @UnitRing.Pack idomainType xclass xT. Definition join_finComRingType := @ComRing.Pack idomainType xclass xT. Definition join_finComUnitRingType := @ComUnitRing.Pack idomainType xclass xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.IntegralDomain.class_of. Coercion base2 : class_of >-> ComUnitRing.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion finZmodType : type >-> Zmodule.type. Canonical finZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion finRingType : type >-> Ring.type. Canonical finRingType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion finComRingType : type >-> ComRing.type. Canonical finComRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion finUnitRingType : type >-> UnitRing.type. Canonical finUnitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion finComUnitRingType : type >-> ComUnitRing.type. Canonical finComUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Canonical join_finType. Canonical join_finZmodType. Canonical join_finRingType. Canonical join_finComRingType. Canonical join_finUnitRingType. Canonical join_finComUnitRingType. Notation finIdomainType := FinRing.IntegralDomain.type. Notation "[ 'finIdomainType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'finIdomainType' 'of' T ]") : form_scope. Canonical baseFinGroupType. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. End Exports. End IntegralDomain. Import IntegralDomain.Exports. Module Field. Section ClassDef. Record class_of R := Class { base : GRing.Field.class_of R; mixin : mixin_of R base }. Definition base2 R (c : class_of R) := IntegralDomain.Class (mixin c). Local Coercion base : class_of >-> GRing.Field.class_of. Local Coercion base2 : class_of >-> IntegralDomain.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.Field.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition finZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition finRingType := @Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition finComRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition finUnitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition finComUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition finIdomainType := @IntegralDomain.Pack cT xclass xT. Definition fieldType := @GRing.Field.Pack cT xclass xT. Definition join_finType := @Finite.Pack fieldType (fin_ xclass) xT. Definition join_finZmodType := @Zmodule.Pack fieldType xclass xT. Definition join_finRingType := @Ring.Pack fieldType xclass xT. Definition join_finUnitRingType := @UnitRing.Pack fieldType xclass xT. Definition join_finComRingType := @ComRing.Pack fieldType xclass xT. Definition join_finComUnitRingType := @ComUnitRing.Pack fieldType xclass xT. Definition join_finIdomainType := @IntegralDomain.Pack fieldType xclass xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.Field.class_of. Coercion base2 : class_of >-> IntegralDomain.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion finZmodType : type >-> Zmodule.type. Canonical finZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion finRingType : type >-> Ring.type. Canonical finRingType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion finComRingType : type >-> ComRing.type. Canonical finComRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion finUnitRingType : type >-> UnitRing.type. Canonical finUnitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion finComUnitRingType : type >-> ComUnitRing.type. Canonical finComUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Coercion finIdomainType : type >-> IntegralDomain.type. Canonical finIdomainType. Coercion fieldType : type >-> GRing.Field.type. Canonical fieldType. Canonical join_finType. Canonical join_finZmodType. Canonical join_finRingType. Canonical join_finComRingType. Canonical join_finUnitRingType. Canonical join_finComUnitRingType. Canonical join_finIdomainType. Notation finFieldType := FinRing.Field.type. Notation "[ 'finFieldType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'finFieldType' 'of' T ]") : form_scope. Canonical baseFinGroupType. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. End Exports. End Field. Import Field.Exports. Section DecideField. Variable F : Field.type. Fixpoint sat e f := match f with | GRing.Bool b => b | t1 == t2 => (GRing.eval e t1 == GRing.eval e t2)%bool | GRing.Unit t => GRing.eval e t \is a GRing.unit | f1 /\ f2 => sat e f1 && sat e f2 | f1 \/ f2 => sat e f1 || sat e f2 | f1 ==> f2 => (sat e f1 ==> sat e f2)%bool | ~ f1 => ~~ sat e f1 | ('exists 'X_k, f1) => [exists x : F, sat (set_nth 0%R e k x) f1] | ('forall 'X_k, f1) => [forall x : F, sat (set_nth 0%R e k x) f1] end%T. Lemma decidable : GRing.DecidableField.axiom sat. Proof. move=> e f; elim: f e; try by move=> f1 IH1 f2 IH2 e /=; case IH1; case IH2; constructor; tauto. - by move=> b e; exact: idP. - by move=> t1 t2 e; exact: eqP. - by move=> t e; exact: idP. - by move=> f IH e /=; case: IH; constructor. - by move=> i f IH e; apply: (iffP existsP) => [] [x fx]; exists x; exact/IH. by move=> i f IH e; apply: (iffP forallP) => f_ x; exact/IH. Qed. Definition DecidableFieldMixin := DecFieldMixin decidable. End DecideField. Module DecField. Section Joins. Variable cT : Field.type. Let xT := let: Field.Pack T _ _ := cT in T. Let xclass : Field.class_of xT := Field.class cT. Definition type := Eval hnf in DecFieldType cT (DecidableFieldMixin cT). Definition finType := @Finite.Pack type (fin_ xclass) xT. Definition finZmodType := @Zmodule.Pack type xclass xT. Definition finRingType := @Ring.Pack type xclass xT. Definition finUnitRingType := @UnitRing.Pack type xclass xT. Definition finComRingType := @ComRing.Pack type xclass xT. Definition finComUnitRingType := @ComUnitRing.Pack type xclass xT. Definition finIdomainType := @IntegralDomain.Pack type xclass xT. Definition baseFinGroupType := base_group type finZmodType finZmodType. Definition finGroupType := fin_group baseFinGroupType cT. End Joins. Module Exports. Coercion type : Field.type >-> GRing.DecidableField.type. Canonical type. Canonical finType. Canonical finZmodType. Canonical finRingType. Canonical finUnitRingType. Canonical finComRingType. Canonical finComUnitRingType. Canonical finIdomainType. Canonical baseFinGroupType. Canonical finGroupType. End Exports. End DecField. Module Lmodule. Section ClassDef. Variable R : ringType. Record class_of M := Class { base : GRing.Lmodule.class_of R M ; mixin : mixin_of M base }. Definition base2 R (c : class_of R) := Zmodule.Class (mixin c). Local Coercion base : class_of >-> GRing.Lmodule.class_of. Local Coercion base2 : class_of >-> Zmodule.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (phR : phant R) (cT : type phR). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition pack := gen_pack (Pack phR) Class (@GRing.Lmodule.class R phR). Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition finZmodType := @Zmodule.Pack cT xclass xT. Definition lmodType := @GRing.Lmodule.Pack R phR cT xclass xT. Definition join_finType := @Finite.Pack lmodType (fin_ xclass) xT. Definition join_finZmodType := @Zmodule.Pack lmodType xclass xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Import Exports. Coercion base : class_of >-> GRing.Lmodule.class_of. Coercion base2 : class_of >-> Zmodule.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion finZmodType : type >-> Zmodule.type. Canonical finZmodType. Coercion lmodType : type >-> GRing.Lmodule.type. Canonical lmodType. Canonical join_finType. Canonical join_finZmodType. Notation finLmodType R := (FinRing.Lmodule.type (Phant R)). Notation "[ 'finLmodType' R 'of' T ]" := (do_pack (@pack _ (Phant R)) T) (at level 0, format "[ 'finLmodType' R 'of' T ]") : form_scope. Canonical baseFinGroupType. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. End Exports. End Lmodule. Import Lmodule.Exports. Module Lalgebra. Section ClassDef. Variable R : ringType. Record class_of M := Class { base : GRing.Lalgebra.class_of R M; mixin : mixin_of M base }. Definition base2 M (c : class_of M) := Ring.Class (mixin c). Definition base3 M (c : class_of M) := @Lmodule.Class _ _ (base c) (mixin c). Local Coercion base : class_of >-> GRing.Lalgebra.class_of. Local Coercion base2 : class_of >-> Ring.class_of. Local Coercion base3 : class_of >-> Lmodule.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (phR : phant R) (cT : type phR). Definition pack := gen_pack (Pack phR) Class (@GRing.Lalgebra.class R phR). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition finZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition finRingType := @Ring.Pack cT xclass xT. Definition lmodType := @GRing.Lmodule.Pack R phR cT xclass xT. Definition finLmodType := @Lmodule.Pack R phR cT xclass xT. Definition lalgType := @GRing.Lalgebra.Pack R phR cT xclass xT. Definition join_finType := @Finite.Pack lalgType (fin_ xclass) xT. Definition join_finZmodType := @Zmodule.Pack lalgType xclass xT. Definition join_finLmodType := @Lmodule.Pack R phR lalgType xclass xT. Definition join_finRingType := @Ring.Pack lalgType xclass xT. Definition rjoin_finLmodType := @Lmodule.Pack R phR ringType xclass xT. Definition ljoin_finRingType := @Ring.Pack lmodType xclass xT. Definition fljoin_finRingType := @Ring.Pack finLmodType xclass xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.Lalgebra.class_of. Coercion base2 : class_of >-> Ring.class_of. Coercion base3 : class_of >-> Lmodule.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion finZmodType : type >-> Zmodule.type. Canonical finZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion finRingType : type >-> Ring.type. Canonical finRingType. Coercion lmodType : type >-> GRing.Lmodule.type. Canonical lmodType. Coercion finLmodType : type >-> Lmodule.type. Canonical finLmodType. Coercion lalgType : type >-> GRing.Lalgebra.type. Canonical lalgType. Canonical join_finType. Canonical join_finZmodType. Canonical join_finLmodType. Canonical join_finRingType. Canonical rjoin_finLmodType. Canonical ljoin_finRingType. Canonical fljoin_finRingType. Notation finLalgType R := (FinRing.Lalgebra.type (Phant R)). Notation "[ 'finLalgType' R 'of' T ]" := (do_pack (@pack _ (Phant R)) T) (at level 0, format "[ 'finLalgType' R 'of' T ]") : form_scope. Canonical baseFinGroupType. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. End Exports. End Lalgebra. Import Lalgebra.Exports. Module Algebra. Section ClassDef. Variable R : ringType. Record class_of M := Class { base : GRing.Algebra.class_of R M; mixin : mixin_of M base }. Definition base2 M (c : class_of M) := Lalgebra.Class (mixin c). Local Coercion base : class_of >-> GRing.Algebra.class_of. Local Coercion base2 : class_of >->Lalgebra.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (phR : phant R) (cT : type phR). Definition pack := gen_pack (Pack phR) Class (@GRing.Algebra.class R phR). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition finZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition finRingType := @Ring.Pack cT xclass xT. Definition lmodType := @GRing.Lmodule.Pack R phR cT xclass xT. Definition finLmodType := @Lmodule.Pack R phR cT xclass xT. Definition lalgType := @GRing.Lalgebra.Pack R phR cT xclass xT. Definition finLalgType := @Lalgebra.Pack R phR cT xclass xT. Definition algType := @GRing.Algebra.Pack R phR cT xclass xT. Definition join_finType := @Finite.Pack algType (fin_ xclass) xT. Definition join_finZmodType := @Zmodule.Pack algType xclass xT. Definition join_finRingType := @Ring.Pack algType xclass xT. Definition join_finLmodType := @Lmodule.Pack R phR algType xclass xT. Definition join_finLalgType := @Lalgebra.Pack R phR algType xclass xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.Algebra.class_of. Coercion base2 : class_of >-> Lalgebra.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion finZmodType : type >-> Zmodule.type. Canonical finZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion finRingType : type >-> Ring.type. Canonical finRingType. Coercion lmodType : type >-> GRing.Lmodule.type. Canonical lmodType. Coercion finLmodType : type >-> Lmodule.type. Canonical finLmodType. Coercion lalgType : type >-> GRing.Lalgebra.type. Canonical lalgType. Coercion finLalgType : type >-> Lalgebra.type. Canonical finLalgType. Coercion algType : type >-> GRing.Algebra.type. Canonical algType. Canonical join_finType. Canonical join_finZmodType. Canonical join_finLmodType. Canonical join_finRingType. Canonical join_finLalgType. Notation finAlgType R := (type (Phant R)). Notation "[ 'finAlgType' R 'of' T ]" := (do_pack (@pack _ (Phant R)) T) (at level 0, format "[ 'finAlgType' R 'of' T ]") : form_scope. Canonical baseFinGroupType. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. End Exports. End Algebra. Import Algebra.Exports. Module UnitAlgebra. Section ClassDef. Variable R : unitRingType. Record class_of M := Class { base : GRing.UnitAlgebra.class_of R M ; mixin : mixin_of M base }. Definition base2 M (c : class_of M) := Algebra.Class (mixin c). Definition base3 M (c : class_of M) := @UnitRing.Class _ (base c) (mixin c). Local Coercion base : class_of >-> GRing.UnitAlgebra.class_of. Local Coercion base2 : class_of >-> Algebra.class_of. Local Coercion base3 : class_of >-> UnitRing.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (phR : phant R) (cT : type phR). Definition pack := gen_pack (Pack phR) Class (@GRing.UnitAlgebra.class R phR). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (fin_ xclass) xT. Definition finType := @Finite.Pack cT (fin_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition finZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition finRingType := @Ring.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition finUnitRingType := @UnitRing.Pack cT xclass xT. Definition lmodType := @GRing.Lmodule.Pack R phR cT xclass xT. Definition finLmodType := @Lmodule.Pack R phR cT xclass xT. Definition lalgType := @GRing.Lalgebra.Pack R phR cT xclass xT. Definition finLalgType := @Lalgebra.Pack R phR cT xclass xT. Definition algType := @GRing.Algebra.Pack R phR cT xclass xT. Definition finAlgType := @Algebra.Pack R phR cT xclass xT. Definition unitAlgType := @GRing.UnitAlgebra.Pack R phR cT xclass xT. Definition join_finType := @Finite.Pack unitAlgType (fin_ xclass) xT. Definition join_finZmodType := @Zmodule.Pack unitAlgType xclass xT. Definition join_finRingType := @Ring.Pack unitAlgType xclass xT. Definition join_finUnitRingType := @UnitRing.Pack unitAlgType xclass xT. Definition join_finLmodType := @Lmodule.Pack R phR unitAlgType xclass xT. Definition join_finLalgType := @Lalgebra.Pack R phR unitAlgType xclass xT. Definition join_finAlgType := @Algebra.Pack R phR unitAlgType xclass xT. Definition ljoin_finUnitRingType := @UnitRing.Pack lmodType xclass xT. Definition fljoin_finUnitRingType := @UnitRing.Pack finLmodType xclass xT. Definition njoin_finUnitRingType := @UnitRing.Pack lalgType xclass xT. Definition fnjoin_finUnitRingType := @UnitRing.Pack finLalgType xclass xT. Definition ajoin_finUnitRingType := @UnitRing.Pack algType xclass xT. Definition fajoin_finUnitRingType := @UnitRing.Pack finAlgType xclass xT. Definition ujoin_finLmodType := @Lmodule.Pack R phR unitRingType xclass xT. Definition ujoin_finLalgType := @Lalgebra.Pack R phR unitRingType xclass xT. Definition ujoin_finAlgType := @Algebra.Pack R phR unitRingType xclass xT. Definition baseFinGroupType := base_group cT zmodType finType. Definition finGroupType := fin_group baseFinGroupType zmodType. Definition join_baseFinGroupType := base_group zmodType zmodType finType. Definition join_finGroupType := fin_group join_baseFinGroupType zmodType. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.UnitAlgebra.class_of. Coercion base2 : class_of >-> Algebra.class_of. Coercion base3 : class_of >-> UnitRing.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion finType : type >-> Finite.type. Canonical finType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion finZmodType : type >-> Zmodule.type. Canonical finZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion finRingType : type >-> Ring.type. Canonical finRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion finUnitRingType : type >-> UnitRing.type. Canonical finUnitRingType. Coercion lmodType : type >-> GRing.Lmodule.type. Canonical lmodType. Coercion finLmodType : type >-> Lmodule.type. Canonical finLmodType. Coercion lalgType : type >-> GRing.Lalgebra.type. Canonical lalgType. Coercion finLalgType : type >-> Lalgebra.type. Canonical finLalgType. Coercion algType : type >-> GRing.Algebra.type. Canonical algType. Coercion finAlgType : type >-> Algebra.type. Canonical finAlgType. Coercion unitAlgType : type >-> GRing.UnitAlgebra.type. Canonical unitAlgType. Canonical join_finType. Canonical join_finZmodType. Canonical join_finLmodType. Canonical join_finRingType. Canonical join_finLalgType. Canonical join_finAlgType. Canonical ljoin_finUnitRingType. Canonical fljoin_finUnitRingType. Canonical njoin_finUnitRingType. Canonical fnjoin_finUnitRingType. Canonical ajoin_finUnitRingType. Canonical fajoin_finUnitRingType. Canonical ujoin_finLmodType. Canonical ujoin_finLalgType. Canonical ujoin_finAlgType. Notation finUnitAlgType R := (type (Phant R)). Notation "[ 'finUnitAlgType' R 'of' T ]" := (do_pack (@pack _ (Phant R)) T) (at level 0, format "[ 'finUnitAlgType' R 'of' T ]") : form_scope. Canonical baseFinGroupType. Canonical finGroupType. Canonical join_baseFinGroupType. Canonical join_finGroupType. End Exports. End UnitAlgebra. Import UnitAlgebra.Exports. Module Theory. Definition zmod1gE := zmod1gE. Definition zmodVgE := zmodVgE. Definition zmodMgE := zmodMgE. Definition zmodXgE := zmodXgE. Definition zmod_mulgC := zmod_mulgC. Definition zmod_abelian := zmod_abelian. Definition val_unit1 := val_unit1. Definition val_unitM := val_unitM. Definition val_unitX := val_unitX. Definition val_unitV := val_unitV. Definition unit_actE := unit_actE. End Theory. End FinRing. Import FinRing. Export Zmodule.Exports Ring.Exports ComRing.Exports. Export UnitRing.Exports UnitsGroupExports ComUnitRing.Exports. Export IntegralDomain.Exports Field.Exports DecField.Exports. Export Lmodule.Exports Lalgebra.Exports Algebra.Exports UnitAlgebra.Exports. Notation "{ 'unit' R }" := (unit_of (Phant R)) (at level 0, format "{ 'unit' R }") : type_scope. Prenex Implicits FinRing.uval. Notation "''U'" := (unit_action _) (at level 8) : action_scope. Notation "''U'" := (unit_groupAction _) (at level 8) : groupAction_scope. mathcomp-1.5/theories/vcharacter.v0000644000175000017500000011470012307636117016317 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. Require Import fintype tuple finfun bigop prime ssralg poly finset. Require Import fingroup morphism perm automorphism quotient finalg action. Require Import gproduct zmodp commutator cyclic center pgroup sylow frobenius. Require Import vector ssrnum ssrint intdiv algC algnum. Require Import classfun character integral_char. Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope GRing.Theory Num.Theory. Local Open Scope ring_scope. (******************************************************************************) (* This file provides basic notions of virtual character theory: *) (* 'Z[S, A] == collective predicate for the phi that are Z-linear *) (* combinations of elements of S : seq 'CF(G) and have *) (* support in A : {set gT}. *) (* 'Z[S] == collective predicate for the Z-linear combinations of *) (* elements of S. *) (* 'Z[irr G] == the collective predicate for virtual characters. *) (* dirr G == the collective predicate for normal virtual characters, *) (* i.e., virtual characters of norm 1: *) (* mu \in dirr G <=> m \in 'Z[irr G] and '[mu] = 1 *) (* <=> mu or - mu \in irr G. *) (* --> othonormal subsets of 'Z[irr G] are contained in dirr G. *) (* dIirr G == an index type for normal virtual characters. *) (* dchi i == the normal virtual character of index i. *) (* of_irr i == the (unique) irreducible constituent of dchi i: *) (* dchi i = 'chi_(of_irr i) or - 'chi_(of_irr i). *) (* ndirr i == the index of - dchi i. *) (* dirr1 G == the normal virtual character index of 1 : 'CF(G), the *) (* principal character. *) (* dirr_dIirr j f == the index i (or dirr1 G if it does not exist) such that *) (* dchi i = f j. *) (* dirr_constt phi == the normal virtual character constituents of phi: *) (* i \in dirr_constt phi <=> [dchi i, phi] > 0. *) (* to_dirr phi i == the normal virtual character constituent of phi with an *) (* irreducible constituent i, when i \in irr_constt phi. *) (******************************************************************************) Section Basics. Variables (gT : finGroupType) (B : {set gT}) (S : seq 'CF(B)) (A : {set gT}). Definition Zchar : pred_class := [pred phi in 'CF(B, A) | dec_Cint_span (in_tuple S) phi]. Fact Zchar_key : pred_key Zchar. Proof. by []. Qed. Canonical Zchar_keyed := KeyedPred Zchar_key. Lemma cfun0_zchar : 0 \in Zchar. Proof. rewrite inE mem0v; apply/sumboolP; exists 0. by rewrite big1 // => i _; rewrite ffunE. Qed. Fact Zchar_zmod : zmod_closed Zchar. Proof. split; first exact: cfun0_zchar. move=> phi xi /andP[Aphi /sumboolP[a Da]] /andP[Axi /sumboolP[b Db]]. rewrite inE rpredB // Da Db -sumrB; apply/sumboolP; exists (a - b). by apply: eq_bigr => i _; rewrite -mulrzBr !ffunE. Qed. Canonical Zchar_opprPred := OpprPred Zchar_zmod. Canonical Zchar_addrPred := AddrPred Zchar_zmod. Canonical Zchar_zmodPred := ZmodPred Zchar_zmod. Lemma scale_zchar a phi : a \in Cint -> phi \in Zchar -> a *: phi \in Zchar. Proof. by case/CintP=> m -> Zphi; rewrite scaler_int rpredMz. Qed. End Basics. Notation "''Z[' S , A ]" := (Zchar S A) (at level 8, format "''Z[' S , A ]") : group_scope. Notation "''Z[' S ]" := 'Z[S, setT] (at level 8, format "''Z[' S ]") : group_scope. Section Zchar. Variables (gT : finGroupType) (G : {group gT}). Implicit Types (A B : {set gT}) (S : seq 'CF(G)). Lemma zchar_split S A phi : phi \in 'Z[S, A] = (phi \in 'Z[S]) && (phi \in 'CF(G, A)). Proof. by rewrite !inE cfun_onT andbC. Qed. Lemma zcharD1E phi S : (phi \in 'Z[S, G^#]) = (phi \in 'Z[S]) && (phi 1%g == 0). Proof. by rewrite zchar_split cfunD1E. Qed. Lemma zcharD1 phi S A : (phi \in 'Z[S, A^#]) = (phi \in 'Z[S, A]) && (phi 1%g == 0). Proof. by rewrite zchar_split cfun_onD1 andbA -zchar_split. Qed. Lemma zcharW S A : {subset 'Z[S, A] <= 'Z[S]}. Proof. by move=> phi; rewrite zchar_split => /andP[]. Qed. Lemma zchar_on S A : {subset 'Z[S, A] <= 'CF(G, A)}. Proof. by move=> phi /andP[]. Qed. Lemma zchar_onS A B S : A \subset B -> {subset 'Z[S, A] <= 'Z[S, B]}. Proof. move=> sAB phi; rewrite zchar_split (zchar_split _ B) => /andP[->]. exact: cfun_onS. Qed. Lemma zchar_onG S : 'Z[S, G] =i 'Z[S]. Proof. by move=> phi; rewrite zchar_split cfun_onG andbT. Qed. Lemma irr_vchar_on A : {subset 'Z[irr G, A] <= 'CF(G, A)}. Proof. exact: zchar_on. Qed. Lemma support_zchar S A phi : phi \in 'Z[S, A] -> support phi \subset A. Proof. by move/zchar_on; rewrite cfun_onE. Qed. Lemma mem_zchar_on S A phi : phi \in 'CF(G, A) -> phi \in S -> phi \in 'Z[S, A]. Proof. move=> Aphi /(@tnthP _ _ (in_tuple S))[i Dphi]; rewrite inE /= {}Aphi {phi}Dphi. apply/sumboolP; exists [ffun j => (j == i)%:Z]. rewrite (bigD1 i) //= ffunE eqxx (tnth_nth 0) big1 ?addr0 // => j i'j. by rewrite ffunE (negPf i'j). Qed. (* A special lemma is needed because trivial fails to use the cfun_onT Hint. *) Lemma mem_zchar S phi : phi \in S -> phi \in 'Z[S]. Proof. by move=> Sphi; rewrite mem_zchar_on ?cfun_onT. Qed. Lemma zchar_nth_expansion S A phi : phi \in 'Z[S, A] -> {z | forall i, z i \in Cint & phi = \sum_(i < size S) z i *: S`_i}. Proof. case/andP=> _ /sumboolP/sig_eqW[/= z ->]. exists (intr \o z) => [i|]; first exact: Cint_int. by apply: eq_bigr => i _; rewrite scaler_int. Qed. Lemma zchar_tuple_expansion n (S : n.-tuple 'CF(G)) A phi : phi \in 'Z[S, A] -> {z | forall i, z i \in Cint & phi = \sum_(i < n) z i *: S`_i}. Proof. by move/zchar_nth_expansion; rewrite size_tuple. Qed. (* A pure seq version with the extra hypothesis of S's unicity. *) Lemma zchar_expansion S A phi : uniq S -> phi \in 'Z[S, A] -> {z | forall xi, z xi \in Cint & phi = \sum_(xi <- S) z xi *: xi}. Proof. move=> Suniq /zchar_nth_expansion[z Zz ->] /=. pose zS xi := oapp z 0 (insub (index xi S)). exists zS => [xi | ]; rewrite {}/zS; first by case: (insub _). rewrite (big_nth 0) big_mkord; apply: eq_bigr => i _; congr (_ *: _). by rewrite index_uniq // valK. Qed. Lemma zchar_span S A : {subset 'Z[S, A] <= <>%VS}. Proof. move=> _ /zchar_nth_expansion[z Zz ->] /=. by apply: rpred_sum => i _; rewrite rpredZ // memv_span ?mem_nth. Qed. Lemma zchar_trans S1 S2 A B : {subset S1 <= 'Z[S2, B]} -> {subset 'Z[S1, A] <= 'Z[S2, A]}. Proof. move=> sS12 phi; rewrite !(zchar_split _ A) andbC => /andP[->]; rewrite andbT. case/zchar_nth_expansion=> z Zz ->; apply: rpred_sum => i _. by rewrite scale_zchar // (@zcharW _ B) ?sS12 ?mem_nth. Qed. Lemma zchar_trans_on S1 S2 A : {subset S1 <= 'Z[S2, A]} -> {subset 'Z[S1] <= 'Z[S2, A]}. Proof. move=> sS12 _ /zchar_nth_expansion[z Zz ->]; apply: rpred_sum => i _. by rewrite scale_zchar // sS12 ?mem_nth. Qed. Lemma zchar_sub_irr S A : {subset S <= 'Z[irr G]} -> {subset 'Z[S, A] <= 'Z[irr G, A]}. Proof. exact: zchar_trans. Qed. Lemma zchar_subset S1 S2 A : {subset S1 <= S2} -> {subset 'Z[S1, A] <= 'Z[S2, A]}. Proof. move=> sS12; apply: zchar_trans setT _ => // f /sS12 S2f. by rewrite mem_zchar. Qed. Lemma zchar_subseq S1 S2 A : subseq S1 S2 -> {subset 'Z[S1, A] <= 'Z[S2, A]}. Proof. move=> sS12; exact: zchar_subset (mem_subseq sS12). Qed. Lemma zchar_filter S A (p : pred 'CF(G)) : {subset 'Z[filter p S, A] <= 'Z[S, A]}. Proof. by apply: zchar_subset=> f; rewrite mem_filter => /andP[]. Qed. End Zchar. Section VChar. Variables (gT : finGroupType) (G : {group gT}). Implicit Types (A B : {set gT}) (phi chi : 'CF(G)) (S : seq 'CF(G)). Lemma char_vchar chi : chi \is a character -> chi \in 'Z[irr G]. Proof. case/char_sum_irr=> r ->; apply: rpred_sum => i _. by rewrite mem_zchar ?mem_tnth. Qed. Lemma irr_vchar i : 'chi[G]_i \in 'Z[irr G]. Proof. exact/char_vchar/irr_char. Qed. Lemma cfun1_vchar : 1 \in 'Z[irr G]. Proof. by rewrite -irr0 irr_vchar. Qed. Lemma vcharP phi : reflect (exists2 chi1, chi1 \is a character & exists2 chi2, chi2 \is a character & phi = chi1 - chi2) (phi \in 'Z[irr G]). Proof. apply: (iffP idP) => [| [a Na [b Nb ->]]]; last by rewrite rpredB ?char_vchar. case/zchar_tuple_expansion=> z Zz ->; rewrite (bigID (fun i => 0 <= z i)) /=. set chi1 := \sum_(i | _) _; set nchi2 := \sum_(i | _) _. exists chi1; last exists (- nchi2); last by rewrite opprK. apply: rpred_sum => i zi_ge0; rewrite -tnth_nth rpredZ_Cnat ?irr_char //. by rewrite CnatEint Zz. rewrite -sumrN rpred_sum // => i zi_lt0; rewrite -scaleNr -tnth_nth. rewrite rpredZ_Cnat ?irr_char // CnatEint rpredN Zz oppr_ge0 ltrW //. by rewrite real_ltrNge ?Creal_Cint. Qed. Lemma Aint_vchar phi x : phi \in 'Z[irr G] -> phi x \in Aint. Proof. case/vcharP=> [chi1 Nchi1 [chi2 Nchi2 ->]]. by rewrite !cfunE rpredB ?Aint_char. Qed. Lemma Cint_vchar1 phi : phi \in 'Z[irr G] -> phi 1%g \in Cint. Proof. case/vcharP=> phi1 Nphi1 [phi2 Nphi2 ->]. by rewrite !cfunE rpredB // rpred_Cnat ?Cnat_char1. Qed. Lemma Cint_cfdot_vchar_irr i phi : phi \in 'Z[irr G] -> '[phi, 'chi_i] \in Cint. Proof. case/vcharP=> chi1 Nchi1 [chi2 Nchi2 ->]. by rewrite cfdotBl rpredB // rpred_Cnat ?Cnat_cfdot_char_irr. Qed. Lemma cfdot_vchar_r phi psi : psi \in 'Z[irr G] -> '[phi, psi] = \sum_i '[phi, 'chi_i] * '[psi, 'chi_i]. Proof. move=> Zpsi; rewrite cfdot_sum_irr; apply: eq_bigr => i _; congr (_ * _). by rewrite aut_Cint ?Cint_cfdot_vchar_irr. Qed. Lemma Cint_cfdot_vchar : {in 'Z[irr G] &, forall phi psi, '[phi, psi] \in Cint}. Proof. move=> phi psi Zphi Zpsi; rewrite /= cfdot_vchar_r // rpred_sum // => k _. by rewrite rpredM ?Cint_cfdot_vchar_irr. Qed. Lemma Cnat_cfnorm_vchar : {in 'Z[irr G], forall phi, '[phi] \in Cnat}. Proof. by move=> phi Zphi; rewrite /= CnatEint cfnorm_ge0 Cint_cfdot_vchar. Qed. Fact vchar_mulr_closed : mulr_closed 'Z[irr G]. Proof. split; first exact: cfun1_vchar. move=> _ _ /vcharP[xi1 Nxi1 [xi2 Nxi2 ->]] /vcharP[xi3 Nxi3 [xi4 Nxi4 ->]]. by rewrite mulrBl !mulrBr !(rpredB, rpredD) // char_vchar ?rpredM. Qed. Canonical vchar_mulrPred := MulrPred vchar_mulr_closed. Canonical vchar_smulrPred := SmulrPred vchar_mulr_closed. Canonical vchar_semiringPred := SemiringPred vchar_mulr_closed. Canonical vchar_subringPred := SubringPred vchar_mulr_closed. Lemma mul_vchar A : {in 'Z[irr G, A] &, forall phi psi, phi * psi \in 'Z[irr G, A]}. Proof. move=> phi psi; rewrite zchar_split => /andP[Zphi Aphi] /zcharW Zpsi. rewrite zchar_split rpredM //; apply/cfun_onP=> x A'x. by rewrite cfunE (cfun_onP Aphi) ?mul0r. Qed. Section CfdotPairwiseOrthogonal. Variables (M : {group gT}) (S : seq 'CF(G)) (nu : 'CF(G) -> 'CF(M)). Hypotheses (Inu : {in 'Z[S] &, isometry nu}) (oSS : pairwise_orthogonal S). Let freeS := orthogonal_free oSS. Let uniqS : uniq S := free_uniq freeS. Let Z_S : {subset S <= 'Z[S]}. Proof. by move=> phi; exact: mem_zchar. Qed. Let notS0 : 0 \notin S. Proof. by case/andP: oSS. Qed. Let dotSS := proj2 (pairwise_orthogonalP oSS). Lemma map_pairwise_orthogonal : pairwise_orthogonal (map nu S). Proof. have inj_nu: {in S &, injective nu}. move=> phi psi Sphi Spsi /= eq_nu; apply: contraNeq (memPn notS0 _ Sphi). by rewrite -cfnorm_eq0 -Inu ?Z_S // {2}eq_nu Inu ?Z_S // => /dotSS->. have notSnu0: 0 \notin map nu S. apply: contra notS0 => /mapP[phi Sphi /esym/eqP]. by rewrite -cfnorm_eq0 Inu ?Z_S // cfnorm_eq0 => /eqP <-. apply/pairwise_orthogonalP; split; first by rewrite /= notSnu0 map_inj_in_uniq. move=>_ _ /mapP[phi Sphi ->] /mapP[psi Spsi ->]. by rewrite (inj_in_eq inj_nu) // Inu ?Z_S //; exact: dotSS. Qed. Lemma cfproj_sum_orthogonal P z phi : phi \in S -> '[\sum_(xi <- S | P xi) z xi *: nu xi, nu phi] = if P phi then z phi * '[phi] else 0. Proof. move=> Sphi; have defS := perm_to_rem Sphi. rewrite cfdot_suml (eq_big_perm _ defS) big_cons /= cfdotZl Inu ?Z_S //. rewrite big1_seq ?addr0 // => xi; rewrite mem_rem_uniq ?inE //. by case/and3P=> _ neq_xi Sxi; rewrite cfdotZl Inu ?Z_S // dotSS ?mulr0. Qed. Lemma cfdot_sum_orthogonal z1 z2 : '[\sum_(xi <- S) z1 xi *: nu xi, \sum_(xi <- S) z2 xi *: nu xi] = \sum_(xi <- S) z1 xi * (z2 xi)^* * '[xi]. Proof. rewrite cfdot_sumr; apply: eq_big_seq => phi Sphi. by rewrite cfdotZr cfproj_sum_orthogonal // mulrCA mulrA. Qed. Lemma cfnorm_sum_orthogonal z : '[\sum_(xi <- S) z xi *: nu xi] = \sum_(xi <- S) `|z xi| ^+ 2 * '[xi]. Proof. by rewrite cfdot_sum_orthogonal; apply: eq_bigr => xi _; rewrite normCK. Qed. Lemma cfnorm_orthogonal : '[\sum_(xi <- S) nu xi] = \sum_(xi <- S) '[xi]. Proof. rewrite -(eq_bigr _ (fun _ _ => scale1r _)) cfnorm_sum_orthogonal. by apply: eq_bigr => xi; rewrite normCK conjC1 !mul1r. Qed. End CfdotPairwiseOrthogonal. Lemma orthogonal_span S phi : pairwise_orthogonal S -> phi \in <>%VS -> {z | z = fun xi => '[phi, xi] / '[xi] & phi = \sum_(xi <- S) z xi *: xi}. Proof. move=> oSS /free_span[|c -> _]; first exact: orthogonal_free. set z := fun _ => _ : algC; exists z => //; apply: eq_big_seq => u Su. rewrite /z cfproj_sum_orthogonal // mulfK // cfnorm_eq0. by rewrite (memPn _ u Su); case/andP: oSS. Qed. Section CfDotOrthonormal. Variables (M : {group gT}) (S : seq 'CF(G)) (nu : 'CF(G) -> 'CF(M)). Hypotheses (Inu : {in 'Z[S] &, isometry nu}) (onS : orthonormal S). Let oSS := orthonormal_orthogonal onS. Let freeS := orthogonal_free oSS. Let nS1 : {in S, forall phi, '[phi] = 1}. Proof. by move=> phi Sphi; case/orthonormalP: onS => _ -> //; rewrite eqxx. Qed. Lemma map_orthonormal : orthonormal (map nu S). Proof. rewrite !orthonormalE map_pairwise_orthogonal // andbT. by apply/allP=> _ /mapP[xi Sxi ->]; rewrite /= Inu ?nS1 // mem_zchar. Qed. Lemma cfproj_sum_orthonormal z phi : phi \in S -> '[\sum_(xi <- S) z xi *: nu xi, nu phi] = z phi. Proof. by move=> Sphi; rewrite cfproj_sum_orthogonal // nS1 // mulr1. Qed. Lemma cfdot_sum_orthonormal z1 z2 : '[\sum_(xi <- S) z1 xi *: xi, \sum_(xi <- S) z2 xi *: xi] = \sum_(xi <- S) z1 xi * (z2 xi)^*. Proof. rewrite cfdot_sum_orthogonal //; apply: eq_big_seq => phi /nS1->. by rewrite mulr1. Qed. Lemma cfnorm_sum_orthonormal z : '[\sum_(xi <- S) z xi *: nu xi] = \sum_(xi <- S) `|z xi| ^+ 2. Proof. rewrite cfnorm_sum_orthogonal //. by apply: eq_big_seq => xi /nS1->; rewrite mulr1. Qed. Lemma cfnorm_map_orthonormal : '[\sum_(xi <- S) nu xi] = (size S)%:R. Proof. by rewrite cfnorm_orthogonal // (eq_big_seq _ nS1) big_tnth sumr_const card_ord. Qed. Lemma orthonormal_span phi : phi \in <>%VS -> {z | z = fun xi => '[phi, xi] & phi = \sum_(xi <- S) z xi *: xi}. Proof. case/orthogonal_span=> // _ -> {2}->; set z := fun _ => _ : algC. by exists z => //; apply: eq_big_seq => xi /nS1->; rewrite divr1. Qed. End CfDotOrthonormal. Lemma cfnorm_orthonormal S : orthonormal S -> '[\sum_(xi <- S) xi] = (size S)%:R. Proof. exact: cfnorm_map_orthonormal. Qed. Lemma zchar_orthonormalP S : {subset S <= 'Z[irr G]} -> reflect (exists I : {set Iirr G}, exists b : Iirr G -> bool, perm_eq S [seq (-1) ^+ b i *: 'chi_i | i in I]) (orthonormal S). Proof. move=> vcS; apply: (equivP orthonormalP). split=> [[uniqS oSS] | [I [b defS]]]; last first. split=> [|xi1 xi2]; rewrite ?(perm_eq_mem defS). rewrite (perm_eq_uniq defS) map_inj_uniq ?enum_uniq // => i j /eqP. by rewrite eq_signed_irr => /andP[_ /eqP]. case/mapP=> [i _ ->] /mapP[j _ ->]; rewrite eq_signed_irr. rewrite cfdotZl cfdotZr rmorph_sign mulrA cfdot_irr -signr_addb mulr_natr. by rewrite mulrb andbC; case: eqP => //= ->; rewrite addbb eqxx. pose I := [set i | ('chi_i \in S) || (- 'chi_i \in S)]. pose b i := - 'chi_i \in S; exists I, b. apply: uniq_perm_eq => // [|xi]. rewrite map_inj_uniq ?enum_uniq // => i j /eqP. by rewrite eq_signed_irr => /andP[_ /eqP]. apply/idP/mapP=> [Sxi | [i Ii ->{xi}]]; last first. move: Ii; rewrite mem_enum inE orbC -/(b i). by case b_i: (b i); rewrite (scale1r, scaleN1r). have: '[xi] = 1 by rewrite oSS ?eqxx. have vc_xi := vcS _ Sxi; rewrite cfdot_sum_irr. case/Cnat_sum_eq1 => [i _ | i [_ /eqP norm_xi_i xi_i'_0]]. by rewrite -normCK rpredX // Cnat_norm_Cint ?Cint_cfdot_vchar_irr. suffices def_xi: xi = (-1) ^+ b i *: 'chi_i. exists i; rewrite // mem_enum inE -/(b i) orbC. by case: (b i) def_xi Sxi => // ->; rewrite scale1r. move: Sxi; rewrite [xi]cfun_sum_cfdot (bigD1 i) //. rewrite big1 //= ?addr0 => [|j ne_ji]; last first. apply/eqP; rewrite scaler_eq0 -normr_eq0 -[_ == 0](expf_eq0 _ 2) normCK. by rewrite xi_i'_0 ?eqxx. have:= norm_xi_i; rewrite (aut_Cint _ (Cint_cfdot_vchar_irr _ _)) //. rewrite -subr_eq0 subr_sqr_1 mulf_eq0 subr_eq0 addr_eq0 /b scaler_sign. case/pred2P=> ->; last by rewrite scaleN1r => ->. rewrite scale1r => Sxi; case: ifP => // SNxi. have:= oSS _ _ Sxi SNxi; rewrite cfdotNr cfdot_irr eqxx; case: eqP => // _. by move/eqP; rewrite oppr_eq0 oner_eq0. Qed. Lemma vchar_norm1P phi : phi \in 'Z[irr G] -> '[phi] = 1 -> exists b : bool, exists i : Iirr G, phi = (-1) ^+ b *: 'chi_i. Proof. move=> Zphi phiN1. have: orthonormal phi by rewrite /orthonormal/= phiN1 eqxx. case/zchar_orthonormalP=> [xi /predU1P[->|] // | I [b def_phi]]. have: phi \in (phi : seq _) := mem_head _ _. by rewrite (perm_eq_mem def_phi) => /mapP[i _ ->]; exists (b i), i. Qed. Lemma zchar_small_norm phi n : phi \in 'Z[irr G] -> '[phi] = n%:R -> (n < 4)%N -> {S : n.-tuple 'CF(G) | [/\ orthonormal S, {subset S <= 'Z[irr G]} & phi = \sum_(xi <- S) xi]}. Proof. move=> Zphi def_n lt_n_4. pose S := [seq '[phi, 'chi_i] *: 'chi_i | i in irr_constt phi]. have def_phi: phi = \sum_(xi <- S) xi. rewrite big_map /= big_filter big_mkcond {1}[phi]cfun_sum_cfdot. by apply: eq_bigr => i _; rewrite if_neg; case: eqP => // ->; rewrite scale0r. have orthS: orthonormal S. apply/orthonormalP; split=> [|_ _ /mapP[i phi_i ->] /mapP[j _ ->]]. rewrite map_inj_in_uniq ?enum_uniq // => i j; rewrite mem_enum => phi_i _. by move/eqP; rewrite eq_scaled_irr (negbTE phi_i) => /andP[_ /= /eqP]. rewrite eq_scaled_irr cfdotZl cfdotZr cfdot_irr mulrA mulr_natr mulrb. rewrite mem_enum in phi_i; rewrite (negbTE phi_i) andbC; case: eqP => // <-. have /CnatP[m def_m] := Cnat_norm_Cint (Cint_cfdot_vchar_irr i Zphi). apply/eqP; rewrite eqxx /= -normCK def_m -natrX eqr_nat eqn_leq lt0n. rewrite expn_eq0 andbT -eqC_nat -def_m normr_eq0 [~~ _]phi_i andbT. rewrite (leq_exp2r _ 1) // -ltnS -(@ltn_exp2r _ _ 2) //. apply: leq_ltn_trans lt_n_4; rewrite -leC_nat -def_n natrX. rewrite cfdot_sum_irr (bigD1 i) //= -normCK def_m addrC -subr_ge0 addrK. by rewrite sumr_ge0 // => ? _; exact: mul_conjC_ge0. have <-: size S = n. by apply/eqP; rewrite -eqC_nat -def_n def_phi cfnorm_orthonormal. exists (in_tuple S); split=> // _ /mapP[i _ ->]. by rewrite scale_zchar ?irr_vchar // Cint_cfdot_vchar_irr. Qed. Lemma vchar_norm2 phi : phi \in 'Z[irr G, G^#] -> '[phi] = 2%:R -> exists i, exists2 j, j != i & phi = 'chi_i - 'chi_j. Proof. rewrite zchar_split cfunD1E => /andP[Zphi phi1_0]. case/zchar_small_norm => // [[[|chi [|xi [|?]]] //= S2]]. case=> /andP[/and3P[Nchi Nxi _] /= ochi] /allP/and3P[Zchi Zxi _]. rewrite big_cons big_seq1 => def_phi. have [b [i def_chi]] := vchar_norm1P Zchi (eqP Nchi). have [c [j def_xi]] := vchar_norm1P Zxi (eqP Nxi). have neq_ji: j != i. apply: contraTneq ochi; rewrite !andbT def_chi def_xi => ->. rewrite cfdotZl cfdotZr rmorph_sign cfnorm_irr mulr1 -signr_addb. by rewrite signr_eq0. have neq_bc: b != c. apply: contraTneq phi1_0; rewrite def_phi def_chi def_xi => ->. rewrite -scalerDr !cfunE mulf_eq0 signr_eq0 eqr_le ltr_geF //. by rewrite ltr_paddl ?ltrW ?irr1_gt0. rewrite {}def_phi {}def_chi {}def_xi !scaler_sign. case: b c neq_bc => [|] [|] // _; last by exists i, j. by exists j, i; rewrite 1?eq_sym // addrC. Qed. End VChar. Section Isometries. Variables (gT : finGroupType) (L G : {group gT}) (S : seq 'CF(L)). Implicit Type nu : {additive 'CF(L) -> 'CF(G)}. Lemma Zisometry_of_cfnorm (tauS : seq 'CF(G)) : pairwise_orthogonal S -> pairwise_orthogonal tauS -> map cfnorm tauS = map cfnorm S -> {subset tauS <= 'Z[irr G]} -> {tau : {linear 'CF(L) -> 'CF(G)} | map tau S = tauS & {in 'Z[S], isometry tau, to 'Z[irr G]}}. Proof. move=> oSS oTT /isometry_of_cfnorm[||tau defT Itau] // Z_T; exists tau => //. split=> [|_ /zchar_nth_expansion[u Zu ->]]. by apply: sub_in2 Itau; apply: zchar_span. rewrite big_seq linear_sum rpred_sum // => xi Sxi. by rewrite linearZ scale_zchar ?Z_T // -defT map_f ?mem_nth. Qed. Lemma Zisometry_of_iso f : pairwise_orthogonal S -> {in S, isometry f, to 'Z[irr G]} -> {tau : {linear 'CF(L) -> 'CF(G)} | {in S, tau =1 f} & {in 'Z[S], isometry tau, to 'Z[irr G]}}. Proof. move=> oS [If Zf]; have [/=/andP[S'0 uS] oSS] := pairwise_orthogonalP oS. have injf: {in S &, injective f}. move=> xi1 xi2 Sxi1 Sxi2 /=/(congr1 (cfdot (f xi1)))/eqP; rewrite !If //. by apply: contraTeq => /oSS-> //; rewrite cfnorm_eq0 (memPn S'0). have{injf} oSf: pairwise_orthogonal (map f S). apply/pairwise_orthogonalP; split=> /=. rewrite map_inj_in_uniq // uS (contra _ S'0) // => /mapP[chi Schi /eqP]. by rewrite eq_sym -cfnorm_eq0 If // cfnorm_eq0 => /eqP <-. move=> _ _ /mapP[xi1 Xxi1 ->] /mapP[xi2 Xxi2 ->]. by rewrite If ?(inj_in_eq injf) // => /oSS->. have{If} nSf: map cfnorm (map f S) = map cfnorm S. by rewrite -map_comp; apply/eq_in_map=> xi Sxi; rewrite /= If. have{Zf} ZSf: {subset map f S <= 'Z[irr G]} by move=> _ /mapP[xi /Zf Zfxi ->]. by have [tau /eq_in_map] := Zisometry_of_cfnorm oS oSf nSf ZSf; exists tau. Qed. Lemma Zisometry_inj A nu : {in 'Z[S, A] &, isometry nu} -> {in 'Z[S, A] &, injective nu}. Proof. by move/isometry_raddf_inj; apply; apply: rpredB. Qed. Lemma isometry_in_zchar nu : {in S &, isometry nu} -> {in 'Z[S] &, isometry nu}. Proof. move=> Inu _ _ /zchar_nth_expansion[u Zu ->] /zchar_nth_expansion[v Zv ->]. rewrite !raddf_sum; apply: eq_bigr => j _ /=. rewrite !cfdot_suml; apply: eq_bigr => i _. by rewrite !raddfZ_Cint //= !cfdotZl !cfdotZr Inu ?mem_nth. Qed. End Isometries. Section AutVchar. Variables (u : {rmorphism algC -> algC}) (gT : finGroupType) (G : {group gT}). Local Notation "alpha ^u" := (cfAut u alpha). Implicit Type (S : seq 'CF(G)) (phi chi : 'CF(G)). Lemma cfAut_zchar S A psi : cfAut_closed u S -> psi \in 'Z[S, A] -> psi^u \in 'Z[S, A]. Proof. rewrite zchar_split => SuS /andP[/zchar_nth_expansion[z Zz Dpsi] Apsi]. rewrite zchar_split cfAut_on {}Apsi {psi}Dpsi rmorph_sum rpred_sum //= => i _. by rewrite cfAutZ_Cint // scale_zchar // mem_zchar ?SuS ?mem_nth. Qed. Lemma cfAut_vchar A psi : psi \in 'Z[irr G, A] -> psi^u \in 'Z[irr G, A]. Proof. by apply: cfAut_zchar; exact: irr_aut_closed. Qed. Lemma sub_aut_zchar S A psi : {subset S <= 'Z[irr G]} -> psi \in 'Z[S, A] -> psi^u \in 'Z[S, A] -> psi - psi^u \in 'Z[S, A^#]. Proof. move=> Z_S Spsi Spsi_u; rewrite zcharD1 !cfunE subr_eq0 rpredB //=. by rewrite aut_Cint // Cint_vchar1 // (zchar_trans Z_S) ?(zcharW Spsi). Qed. Lemma conjC_vcharAut chi x : chi \in 'Z[irr G] -> (u (chi x))^* = u (chi x)^*. Proof. case/vcharP=> chi1 Nchi1 [chi2 Nchi2 ->]. by rewrite !cfunE !rmorphB !conjC_charAut. Qed. Lemma cfdot_aut_vchar phi chi : chi \in 'Z[irr G] -> '[phi^u , chi^u] = u '[phi, chi]. Proof. case/vcharP=> chi1 Nchi1 [chi2 Nchi2 ->]. by rewrite !raddfB /= !cfdot_aut_char. Qed. Lemma vchar_aut A chi : (chi^u \in 'Z[irr G, A]) = (chi \in 'Z[irr G, A]). Proof. rewrite !(zchar_split _ A) cfAut_on; congr (_ && _). apply/idP/idP=> [Zuchi|]; last exact: cfAut_vchar. rewrite [chi]cfun_sum_cfdot rpred_sum // => i _. rewrite scale_zchar ?irr_vchar //. by rewrite -(Cint_aut u) -cfdot_aut_irr -aut_IirrE Cint_cfdot_vchar_irr. Qed. End AutVchar. Definition cfConjC_vchar := cfAut_vchar conjC. Section MoreVchar. Variables (gT : finGroupType) (G H : {group gT}). Lemma cfRes_vchar phi : phi \in 'Z[irr G] -> 'Res[H] phi \in 'Z[irr H]. Proof. case/vcharP=> xi1 Nx1 [xi2 Nxi2 ->]. by rewrite raddfB rpredB ?char_vchar ?cfRes_char. Qed. Lemma cfRes_vchar_on A phi : H \subset G -> phi \in 'Z[irr G, A] -> 'Res[H] phi \in 'Z[irr H, A]. Proof. rewrite zchar_split => sHG /andP[Zphi Aphi]; rewrite zchar_split cfRes_vchar //. apply/cfun_onP=> x /(cfun_onP Aphi); rewrite !cfunElock !genGid sHG => ->. exact: mul0rn. Qed. Lemma cfInd_vchar phi : phi \in 'Z[irr H] -> 'Ind[G] phi \in 'Z[irr G]. Proof. move=> /vcharP[xi1 Nx1 [xi2 Nxi2 ->]]. by rewrite raddfB rpredB ?char_vchar ?cfInd_char. Qed. Lemma sub_conjC_vchar A phi : phi \in 'Z[irr G, A] -> phi - (phi^*)%CF \in 'Z[irr G, A^#]. Proof. move=> Zphi; rewrite sub_aut_zchar ?cfAut_zchar // => _ /irrP[i ->]. exact: irr_vchar. exact: cfConjC_irr. Qed. Lemma Frobenius_kernel_exists : [Frobenius G with complement H] -> {K : {group gT} | [Frobenius G = K ><| H]}. Proof. move=> frobG; have [_ ntiHG] := andP frobG. have [[_ sHG regGH][_ tiHG /eqP defNH]] := (normedTI_memJ_P ntiHG, and3P ntiHG). suffices /sigW[K defG]: exists K, gval K ><| H == G by exists K; apply/andP. pose K1 := G :\: cover (H^# :^: G). have oK1: #|K1| = #|G : H|. rewrite cardsD (setIidPr _); last first. rewrite cover_imset; apply/bigcupsP=> x Gx. by rewrite sub_conjg conjGid ?groupV // (subset_trans (subsetDl _ _)). rewrite (cover_partition (partition_normedTI ntiHG)) -(Lagrange sHG). by rewrite (card_support_normedTI ntiHG) (cardsD1 1%g) group1 mulSn addnK. suffices extG i: {j | {in H, 'chi[G]_j =1 'chi[H]_i} & K1 \subset cfker 'chi_j}. pose K := [group of \bigcap_i cfker 'chi_(s2val (extG i))]. have nKH: H \subset 'N(K). by apply/norms_bigcap/bigcapsP=> i _; apply: subset_trans (cfker_norm _). have tiKH: K :&: H = 1%g. apply/trivgP; rewrite -(TI_cfker_irr H) /= setIC; apply/bigcapsP=> i _. apply/subsetP=> x /setIP[Hx /bigcapP/(_ i isT)/=]; rewrite !cfkerEirr !inE. by case: (extG i) => /= j def_j _; rewrite !def_j. exists K; rewrite sdprodE // eqEcard TI_cardMg // mul_subG //=; last first. by rewrite (bigcap_min (0 : Iirr H)) ?cfker_sub. rewrite -(Lagrange sHG) mulnC leq_pmul2r // -oK1 subset_leq_card //. by apply/bigcapsP=> i _; case: (extG i). case i0: (i == 0). exists 0 => [x Hx|]; last by rewrite irr0 cfker_cfun1 subsetDl. by rewrite (eqP i0) !irr0 !cfun1E // (subsetP sHG) ?Hx. have ochi1: '['chi_i, 1] = 0 by rewrite -irr0 cfdot_irr i0. pose a := 'chi_i 1%g; have Za: a \in Cint by rewrite CintE Cnat_irr1. pose theta := 'chi_i - a%:A; pose phi := 'Ind[G] theta + a%:A. have /cfun_onP theta0: theta \in 'CF(H, H^#). by rewrite cfunD1E !cfunE cfun11 mulr1 subrr. have RItheta: 'Res ('Ind[G] theta) = theta. apply/cfun_inP=> x Hx; rewrite cfResE ?cfIndE // (big_setID H) /= addrC. apply: canLR (mulKf (neq0CG H)) _; rewrite (setIidPr sHG) mulr_natl. rewrite big1 ?add0r => [|y /setDP[/regGH tiHy H'y]]; last first. have [-> | ntx] := eqVneq x 1%g; first by rewrite conj1g theta0 ?inE ?eqxx. by rewrite theta0 ?tiHy // !inE ntx. by rewrite -sumr_const; apply: eq_bigr => y Hy; rewrite cfunJ. have ophi1: '[phi, 1] = 0. rewrite cfdotDl -cfdot_Res_r cfRes_cfun1 // cfdotBl !cfdotZl !cfnorm1. by rewrite ochi1 add0r addNr. have{ochi1} n1phi: '[phi] = 1. have: '[phi - a%:A] = '[theta] by rewrite addrK -cfdot_Res_l RItheta. rewrite !cfnormBd ?cfnormZ ?cfdotZr ?ophi1 ?ochi1 ?mulr0 //. by rewrite !cfnorm1 cfnorm_irr => /addIr. have Zphi: phi \in 'Z[irr G]. by rewrite rpredD ?cfInd_vchar ?rpredB ?irr_vchar // scale_zchar ?rpred1. have def_phi: {in H, phi =1 'chi_i}. move=> x Hx /=; rewrite !cfunE -[_ x](cfResE _ sHG) ?RItheta //. by rewrite !cfunE !cfun1E ?(subsetP sHG) ?Hx ?subrK. have [j def_chi_j]: {j | 'chi_j = phi}. apply/sig_eqW; have [[] [j]] := vchar_norm1P Zphi n1phi; last first. by rewrite scale1r; exists j. move/cfunP/(_ 1%g)/eqP; rewrite scaleN1r def_phi // cfunE -addr_eq0 eqr_le. by rewrite ltr_geF // ltr_paddl ?ltrW ?irr1_gt0. exists j; rewrite ?cfkerEirr def_chi_j //; apply/subsetP => x /setDP[Gx notHx]. rewrite inE cfunE def_phi // cfunE -/a cfun1E // Gx mulr1 cfIndE //. rewrite big1 ?mulr0 ?add0r // => y Gy; apply/theta0/(contra _ notHx) => Hxy. by rewrite -(conjgK y x) cover_imset -class_supportEr mem_imset2 ?groupV. Qed. End MoreVchar. Definition dirr (gT : finGroupType) (B : {set gT}) : pred_class := [pred f : 'CF(B) | (f \in irr B) || (- f \in irr B)]. Implicit Arguments dirr [[gT]]. Section Norm1vchar. Variables (gT : finGroupType) (G : {group gT}). Fact dirr_key : pred_key (dirr G). Proof. by []. Qed. Canonical dirr_keyed := KeyedPred dirr_key. Fact dirr_oppr_closed : oppr_closed (dirr G). Proof. by move=> xi; rewrite !inE opprK orbC. Qed. Canonical dirr_opprPred := OpprPred dirr_oppr_closed. Lemma dirr_opp v : (- v \in dirr G) = (v \in dirr G). Proof. exact: rpredN. Qed. Lemma dirr_sign n v : ((-1)^+ n *: v \in dirr G) = (v \in dirr G). Proof. exact: rpredZsign. Qed. Lemma irr_dirr i : 'chi_i \in dirr G. Proof. by rewrite !inE mem_irr. Qed. Lemma dirrP f : reflect (exists b : bool, exists i, f = (-1) ^+ b *: 'chi_i) (f \in dirr G). Proof. apply: (iffP idP) => [| [b [i ->]]]; last by rewrite dirr_sign irr_dirr. case/orP=> /irrP[i Hf]; first by exists false, i; rewrite scale1r. by exists true, i; rewrite scaleN1r -Hf opprK. Qed. (* This should perhaps be the definition of dirr. *) Lemma dirrE phi : phi \in dirr G = (phi \in 'Z[irr G]) && ('[phi] == 1). Proof. apply/dirrP/andP=> [[b [i ->]] | [Zphi /eqP/vchar_norm1P]]; last exact. by rewrite rpredZsign irr_vchar cfnorm_sign cfnorm_irr. Qed. Lemma cfdot_dirr f g : f \in dirr G -> g \in dirr G -> '[f, g] = (if f == - g then -1 else (f == g)%:R). Proof. case/dirrP=> [b1 [i1 ->]] /dirrP[b2 [i2 ->]]. rewrite cfdotZl cfdotZr rmorph_sign mulrA -signr_addb cfdot_irr. rewrite -scaleNr -signrN !eq_scaled_irr signr_eq0 !(inj_eq (@signr_inj _)) /=. by rewrite -!negb_add addbN mulr_sign -mulNrn mulrb; case: ifP. Qed. Lemma dirr_norm1 phi : phi \in 'Z[irr G] -> '[phi] = 1 -> phi \in dirr G. Proof. by rewrite dirrE => -> -> /=. Qed. Lemma dirr_aut u phi : (cfAut u phi \in dirr G) = (phi \in dirr G). Proof. rewrite !dirrE vchar_aut; apply: andb_id2l => /cfdot_aut_vchar->. exact: fmorph_eq1. Qed. Definition dIirr (B : {set gT}) := (bool * (Iirr B))%type. Definition dirr1 (B : {set gT}) : dIirr B := (false, 0). Definition ndirr (B : {set gT}) (i : dIirr B) : dIirr B := (~~ i.1, i.2). Lemma ndirr_diff (i : dIirr G) : ndirr i != i. Proof. by case: i => [] [|] i. Qed. Lemma ndirrK : involutive (@ndirr G). Proof. by move=> [b i]; rewrite /ndirr /= negbK. Qed. Lemma ndirr_inj : injective (@ndirr G). Proof. exact: (inv_inj ndirrK). Qed. Definition dchi (B : {set gT}) (i : dIirr B) : 'CF(B) := (-1)^+ i.1 *: 'chi_i.2. Lemma dchi1 : dchi (dirr1 G) = 1. Proof. by rewrite /dchi scale1r irr0. Qed. Lemma dirr_dchi i : dchi i \in dirr G. Proof. by apply/dirrP; exists i.1; exists i.2. Qed. Lemma dIrrP (phi : 'CF(G)) : reflect (exists i , phi = dchi i) (phi \in dirr G). Proof. by apply: (iffP idP)=> [/dirrP [b [i ->]]| [i ->]]; [exists (b, i) | exact: dirr_dchi]. Qed. Lemma dchi_ndirrE (i : dIirr G) : dchi (ndirr i) = - dchi i. Proof. by case: i => [b i]; rewrite /ndirr /dchi signrN scaleNr. Qed. Lemma cfdot_dchi (i j : dIirr G) : '[dchi i, dchi j] = (i == j)%:R - (i == ndirr j)%:R. Proof. case: i => bi i; case: j => bj j; rewrite cfdot_dirr ?dirr_dchi // !xpair_eqE. rewrite -dchi_ndirrE !eq_scaled_irr signr_eq0 !(inj_eq (@signr_inj _)) /=. by rewrite -!negb_add addbN negbK; case: andP => [[->]|]; rewrite ?subr0 ?add0r. Qed. Lemma dchi_vchar i : dchi i \in 'Z[irr G]. Proof. by case: i => b i; rewrite rpredZsign irr_vchar. Qed. Lemma cfnorm_dchi (i : dIirr G) : '[dchi i] = 1. Proof. by case: i => b i; rewrite cfnorm_sign cfnorm_irr. Qed. Lemma dirr_inj : injective (@dchi G). Proof. case=> b1 i1 [b2 i2] /eqP; rewrite eq_scaled_irr (inj_eq (@signr_inj _)) /=. by rewrite signr_eq0 -xpair_eqE => /eqP. Qed. Definition dirr_dIirr (B : {set gT}) J (f : J -> 'CF(B)) j : dIirr B := odflt (dirr1 B) [pick i | dchi i == f j]. Lemma dirr_dIirrPE J (f : J -> 'CF(G)) (P : pred J) : (forall j, P j -> f j \in dirr G) -> forall j, P j -> dchi (dirr_dIirr f j) = f j. Proof. rewrite /dirr_dIirr => dirrGf j Pj; case: pickP => [i /eqP //|]. by have /dIrrP[i-> /(_ i)/eqP] := dirrGf j Pj. Qed. Lemma dirr_dIirrE J (f : J -> 'CF(G)) : (forall j, f j \in dirr G) -> forall j, dchi (dirr_dIirr f j) = f j. Proof. by move=> dirrGf j; exact: (@dirr_dIirrPE _ _ xpredT). Qed. Definition dirr_constt (B : {set gT}) (phi: 'CF(B)) : {set (dIirr B)} := [set i | 0 < '[phi, dchi i]]. Lemma dirr_consttE (phi : 'CF(G)) (i : dIirr G) : (i \in dirr_constt phi) = (0 < '[phi, dchi i]). Proof. by rewrite inE. Qed. Lemma Cnat_dirr (phi : 'CF(G)) i : phi \in 'Z[irr G] -> i \in dirr_constt phi -> '[phi, dchi i] \in Cnat. Proof. move=> PiZ; rewrite CnatEint dirr_consttE andbC => /ltrW -> /=. by case: i => b i; rewrite cfdotZr rmorph_sign rpredMsign Cint_cfdot_vchar_irr. Qed. Lemma dirr_constt_oppr (i : dIirr G) (phi : 'CF(G)) : (i \in dirr_constt (-phi)) = (ndirr i \in dirr_constt phi). Proof. by rewrite !dirr_consttE dchi_ndirrE cfdotNl cfdotNr. Qed. Lemma dirr_constt_oppI (phi: 'CF(G)) : dirr_constt phi :&: dirr_constt (-phi) = set0. Proof. apply/setP=> i; rewrite inE !dirr_consttE cfdotNl inE. apply/idP=> /andP [L1 L2]; have := ltr_paddl (ltrW L1) L2. by rewrite subrr ltr_def eqxx. Qed. Lemma dirr_constt_oppl (phi: 'CF(G)) i : i \in dirr_constt phi -> (ndirr i) \notin dirr_constt phi. Proof. rewrite !dirr_consttE dchi_ndirrE cfdotNr oppr_gt0. by move/ltrW=> /ler_gtF ->. Qed. Definition to_dirr (B : {set gT}) (phi : 'CF(B)) (i : Iirr B) : dIirr B := ('[phi, 'chi_i] < 0, i). Definition of_irr (B : {set gT}) (i : dIirr B) : Iirr B := i.2. Lemma irr_constt_to_dirr (phi: 'CF(G)) i : phi \in 'Z[irr G] -> (i \in irr_constt phi) = (to_dirr phi i \in dirr_constt phi). Proof. move=> Zphi; rewrite irr_consttE dirr_consttE cfdotZr rmorph_sign /=. by rewrite -real_normrEsign ?normr_gt0 ?Creal_Cint // Cint_cfdot_vchar_irr. Qed. Lemma to_dirrK (phi: 'CF(G)) : cancel (to_dirr phi) (@of_irr G). Proof. by []. Qed. Lemma of_irrK (phi: 'CF(G)) : {in dirr_constt phi, cancel (@of_irr G) (to_dirr phi)}. Proof. case=> b i; rewrite dirr_consttE cfdotZr rmorph_sign /= /to_dirr mulr_sign. by rewrite fun_if oppr_gt0; case: b => [|/ltrW/ler_gtF] ->. Qed. Lemma cfdot_todirrE (phi: 'CF(G)) i (phi_i := dchi (to_dirr phi i)) : '[phi, phi_i] *: phi_i = '[phi, 'chi_i] *: 'chi_i. Proof. by rewrite cfdotZr rmorph_sign mulrC -scalerA signrZK. Qed. Lemma cfun_sum_dconstt (phi : 'CF(G)) : phi \in 'Z[irr G] -> phi = \sum_(i in dirr_constt phi) '[phi, dchi i] *: dchi i. Proof. (* GG -- rewrite pattern fails in trunk move=> PiZ; rewrite [X in X = _]cfun_sum_constt. *) move=> PiZ; rewrite {1}[phi]cfun_sum_constt. rewrite (reindex (to_dirr phi))=> [/= |]; last first. by exists (@of_irr _)=> //; exact: of_irrK . by apply: eq_big=> i; rewrite ?irr_constt_to_dirr // cfdot_todirrE. Qed. Lemma cnorm_dconstt (phi : 'CF(G)) : phi \in 'Z[irr G] -> '[phi] = \sum_(i in dirr_constt phi) '[phi, dchi i] ^+ 2. Proof. move=> PiZ; rewrite {1 2}(cfun_sum_dconstt PiZ). rewrite cfdot_suml; apply: eq_bigr=> i IiD. rewrite cfdot_sumr (bigD1 i) //= big1 ?addr0 => [|j /andP [JiD IdJ]]. rewrite cfdotZr cfdotZl cfdot_dchi eqxx eq_sym (negPf (ndirr_diff i)). by rewrite subr0 mulr1 aut_Cnat ?Cnat_dirr. rewrite cfdotZr cfdotZl cfdot_dchi eq_sym (negPf IdJ) -natrB ?mulr0 //. by rewrite (negPf (contraNneq _ (dirr_constt_oppl JiD))) => // <-. Qed. Lemma dirr_small_norm (phi : 'CF(G)) n : phi \in 'Z[irr G] -> '[phi] = n%:R -> (n < 4)%N -> [/\ #|dirr_constt phi| = n, dirr_constt phi :&: dirr_constt (- phi) = set0 & phi = \sum_(i in dirr_constt phi) dchi i]. Proof. move=> PiZ Pln; rewrite ltnNge -leC_nat => Nl4. suffices Fd i: i \in dirr_constt phi -> '[phi, dchi i] = 1. split; last 2 [by apply/setP=> u; rewrite !inE cfdotNl oppr_gt0 ltr_asym]. apply/eqP; rewrite -eqC_nat -sumr_const -Pln (cnorm_dconstt PiZ). by apply/eqP/eq_bigr=> i Hi; rewrite Fd // expr1n. rewrite {1}[phi]cfun_sum_dconstt //. by apply: eq_bigr => i /Fd->; rewrite scale1r. move=> IiD; apply: contraNeq Nl4 => phi_i_neq1. rewrite -Pln cnorm_dconstt // (bigD1 i) ?ler_paddr ?sumr_ge0 //=. by move=> j /andP[JiD _]; rewrite exprn_ge0 ?Cnat_ge0 ?Cnat_dirr. have /CnatP[m Dm] := Cnat_dirr PiZ IiD; rewrite Dm -natrX ler_nat (leq_sqr 2). by rewrite ltn_neqAle eq_sym -eqC_nat -ltC_nat -Dm phi_i_neq1 -dirr_consttE. Qed. Lemma cfdot_sum_dchi (phi1 phi2 : 'CF(G)) : '[\sum_(i in dirr_constt phi1) dchi i, \sum_(i in dirr_constt phi2) dchi i] = #|dirr_constt phi1 :&: dirr_constt phi2|%:R - #|dirr_constt phi1 :&: dirr_constt (- phi2)|%:R. Proof. rewrite addrC (big_setID (dirr_constt (- phi2))) /= cfdotDl; congr (_ + _). rewrite cfdot_suml -sumr_const -sumrN; apply: eq_bigr => i /setIP[p1i p2i]. rewrite cfdot_sumr (bigD1 (ndirr i)) -?dirr_constt_oppr //= dchi_ndirrE. rewrite cfdotNr cfnorm_dchi big1 ?addr0 // => j /andP[p2j i'j]. rewrite cfdot_dchi -(inv_eq ndirrK) [in rhs in - rhs]eq_sym (negPf i'j) subr0. rewrite (negPf (contraTneq _ p2i)) // => ->. by rewrite dirr_constt_oppr dirr_constt_oppl. rewrite cfdot_sumr (big_setID (dirr_constt phi1)) setIC /= addrC. rewrite big1 ?add0r => [|j /setDP[p2j p1'j]]; last first. rewrite cfdot_suml big1 // => i /setDP[p1i p2'i]. rewrite cfdot_dchi (negPf (contraTneq _ p1i)) => [|-> //]. rewrite (negPf (contraNneq _ p2'i)) ?subrr // => ->. by rewrite dirr_constt_oppr ndirrK. rewrite -sumr_const; apply: eq_bigr => i /setIP[p1i p2i]; rewrite cfdot_suml. rewrite (bigD1 i) /=; last by rewrite inE dirr_constt_oppr dirr_constt_oppl. rewrite cfnorm_dchi big1 ?addr0 // => j /andP[/setDP[p1j _] i'j]. rewrite cfdot_dchi (negPf i'j) (negPf (contraTneq _ p1j)) ?subrr // => ->. exact: dirr_constt_oppl. Qed. Lemma cfdot_dirr_eq1 : {in dirr G &, forall phi psi, ('[phi, psi] == 1) = (phi == psi)}. Proof. move=> _ _ /dirrP[b1 [i1 ->]] /dirrP[b2 [i2 ->]]. rewrite eq_signed_irr cfdotZl cfdotZr rmorph_sign cfdot_irr mulrA -signr_addb. rewrite pmulrn -rmorphMsign (eqr_int _ _ 1) -negb_add. by case: (b1 (+) b2) (i1 == i2) => [] []. Qed. Lemma cfdot_add_dirr_eq1 : {in dirr G & &, forall phi1 phi2 psi, '[phi1 + phi2, psi] = 1 -> psi = phi1 \/ psi = phi2}. Proof. move=> _ _ _ /dirrP[b1 [i1 ->]] /dirrP[b2 [i2 ->]] /dirrP[c [j ->]] /eqP. rewrite cfdotDl !cfdotZl !cfdotZr !rmorph_sign !cfdot_irr !mulrA -!signr_addb. rewrite 2!{1}signrE !mulrBl !mul1r -!natrM addrCA -subr_eq0 -!addrA. rewrite -!opprD addrA subr_eq0 -mulrSr -!natrD eqr_nat => eq_phi_psi. apply/pred2P; rewrite /= !eq_signed_irr -!negb_add !(eq_sym j) !(addbC c). by case: (i1 == j) eq_phi_psi; case: (i2 == j); do 2!case: (_ (+) c). Qed. End Norm1vchar. mathcomp-1.5/theories/mxalgebra.v0000644000175000017500000035133512307636117016146 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div choice fintype. Require Import finfun bigop prime binomial ssralg finset fingroup finalg. Require Import perm zmodp matrix. (*****************************************************************************) (* In this file we develop the rank and row space theory of matrices, based *) (* on an extended Gaussian elimination procedure similar to LUP *) (* decomposition. This provides us with a concrete but generic model of *) (* finite dimensional vector spaces and F-algebras, in which vectors, linear *) (* functions, families, bases, subspaces, ideals and subrings are all *) (* represented using matrices. This model can be used as a foundation for *) (* the usual theory of abstract linear algebra, but it can also be used to *) (* develop directly substantial theories, such as the theory of finite group *) (* linear representation. *) (* Here we define the following concepts and notations: *) (* Gaussian_elimination A == a permuted triangular decomposition (L, U, r) *) (* of A, with L a column permutation of a lower triangular *) (* invertible matrix, U a row permutation of an upper *) (* triangular invertible matrix, and r the rank of A, all *) (* satisfying the identity L *m pid_mx r *m U = A. *) (* \rank A == the rank of A. *) (* row_free A <=> the rows of A are linearly free (i.e., the rank and *) (* height of A are equal). *) (* row_full A <=> the row-space of A spans all row-vectors (i.e., the *) (* rank and width of A are equal). *) (* col_ebase A == the extended column basis of A (the first matrix L *) (* returned by Gaussian_elimination A). *) (* row_ebase A == the extended row base of A (the second matrix U *) (* returned by Gaussian_elimination A). *) (* col_base A == a basis for the columns of A: a row-full matrix *) (* consisting of the first \rank A columns of col_ebase A. *) (* row_base A == a basis for the rows of A: a row-free matrix consisting *) (* of the first \rank A rows of row_ebase A. *) (* pinvmx A == a partial inverse for A in its row space (or on its *) (* column space, equivalently). In particular, if u is a *) (* row vector in the row_space of A, then u *m pinvmx A is *) (* the row vector of the coefficients of a decomposition *) (* of u as a sub of rows of A. *) (* kermx A == the row kernel of A : a square matrix whose row space *) (* consists of all u such that u *m A = 0 (it consists of *) (* the inverse of col_ebase A, with the top \rank A rows *) (* zeroed out). Also, kermx A is a partial right inverse *) (* to col_ebase A, in the row space anihilated by A. *) (* cokermx A == the cokernel of A : a square matrix whose column space *) (* consists of all v such that A *m v = 0 (it consists of *) (* the inverse of row_ebase A, with the leftmost \rank A *) (* columns zeroed out). *) (* eigenvalue g a <=> a is an eigenvalue of the square matrix g. *) (* eigenspace g a == a square matrix whose row space is the eigenspace of *) (* the eigenvalue a of g (or 0 if a is not an eigenvalue). *) (* We use a different scope %MS for matrix row-space set-like operations; to *) (* avoid confusion, this scope should not be opened globally. Note that the *) (* the arguments of \rank _ and the operations below have default scope %MS. *) (* (A <= B)%MS <=> the row-space of A is included in the row-space of B. *) (* We test for this by testing if cokermx B anihilates A. *) (* (A < B)%MS <=> the row-space of A is properly included in the *) (* row-space of B. *) (* (A <= B <= C)%MS == (A <= B)%MS && (B <= C)%MS, and similarly for *) (* (A < B <= C)%MS, (A < B <= C)%MS and (A < B < C)%MS. *) (* (A == B)%MS == (A <= B <= A)%MS (A and B have the same row-space). *) (* (A :=: B)%MS == A and B behave identically wrt. \rank and <=. This *) (* triple rewrite rule is the Prop version of (A == B)%MS. *) (* Note that :=: cannot be treated as a setoid-style *) (* Equivalence because its arguments can have different *) (* types: A and B need not have the same number of rows, *) (* and often don't (e.g., in row_base A :=: A). *) (* <>%MS == a square matrix with the same row-space as A; <>%MS *) (* is a canonical representation of the subspace generated *) (* by A, viewed as a list of row-vectors: if (A == B)%MS, *) (* then <>%MS = <>%MS. *) (* (A + B)%MS == a square matrix whose row-space is the sum of the *) (* row-spaces of A and B; thus (A + B == col_mx A B)%MS. *) (* (\sum_i )%MS == the "big" version of (_ + _)%MS; as the latter *) (* has a canonical abelian monoid structure, most generic *) (* bigop lemmas apply (the other bigop indexing notations *) (* are also defined). *) (* (A :&: B)%MS == a square matrix whose row-space is the intersection of *) (* the row-spaces of A and B. *) (* (\bigcap_i )%MS == the "big" version of (_ :&: _)%MS, which also *) (* has a canonical abelian monoid structure. *) (* A^C%MS == a square matrix whose row-space is a complement to the *) (* the row-space of A (it consists of row_ebase A with the *) (* top \rank A rows zeroed out). *) (* (A :\: B)%MS == a square matrix whose row-space is a complement of the *) (* the row-space of (A :&: B)%MS in the row-space of A. *) (* We have (A :\: B := A :&: (capmx_gen A B)^C)%MS, where *) (* capmx_gen A B is a rectangular matrix equivalent to *) (* (A :&: B)%MS, i.e., (capmx_gen A B == A :&: B)%MS. *) (* proj_mx A B == a square matrix that projects (A + B)%MS onto A *) (* parellel to B, when (A :&: B)%MS = 0 (A and B must also *) (* be square). *) (* mxdirect S == the sum expression S is a direct sum. This is a NON *) (* EXTENSIONAL notation: the exact boolean expression is *) (* inferred from the syntactic form of S (expanding *) (* definitions, however); both (\sum_(i | _) _)%MS and *) (* (_ + _)%MS sums are recognized. This construct uses a *) (* variant of the reflexive ("quote") canonical structure, *) (* mxsum_expr. The structure also recognizes sums of *) (* matrix ranks, so that lemmas concerning the rank of *) (* direct sums can be used bidirectionally. *) (* The next set of definitions let us represent F-algebras using matrices: *) (* 'A[F]_(m, n) == the type of matrices encoding (sub)algebras of square *) (* n x n matrices, via mxvec; as in the matrix type *) (* notation, m and F can be omitted (m defaults to n ^ 2). *) (* := 'M[F]_(m, n ^ 2). *) (* (A \in R)%MS <=> the square matrix A belongs to the linear set of *) (* matrices (most often, a sub-algebra) encoded by the *) (* row space of R. This is simply notation, so all the *) (* lemmas and rewrite rules for (_ <= _)%MS can apply. *) (* := (mxvec A <= R)%MS. *) (* (R * S)%MS == a square n^2 x n^2 matrix whose row-space encodes the *) (* linear set of n x n matrices generated by the pointwise *) (* product of the sets of matrices encoded by R and S. *) (* 'C(R)%MS == a square matric encoding the centraliser of the set of *) (* square matrices encoded by R. *) (* 'C_S(R)%MS := (S :&: 'C(R))%MS (the centraliser of R in S). *) (* 'Z(R)%MS == the center of R (i.e., 'C_R(R)%MS). *) (* left_mx_ideal R S <=> S is a left ideal for R (R * S <= S)%MS. *) (* right_mx_ideal R S <=> S is a right ideal for R (S * R <= S)%MS. *) (* mx_ideal R S <=> S is a bilateral ideal for R. *) (* mxring_id R e <-> e is an identity element for R (Prop predicate). *) (* has_mxring_id R <=> R has a nonzero identity element (bool predicate). *) (* mxring R <=> R encodes a nontrivial subring. *) (*****************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Import GRing.Theory. Open Local Scope ring_scope. Reserved Notation "\rank A" (at level 10, A at level 8, format "\rank A"). Reserved Notation "A ^C" (at level 8, format "A ^C"). Notation "''A_' ( m , n )" := 'M_(m, n ^ 2) (at level 8, format "''A_' ( m , n )") : type_scope. Notation "''A_' ( n )" := 'A_(n ^ 2, n) (at level 8, only parsing) : type_scope. Notation "''A_' n" := 'A_(n) (at level 8, n at next level, format "''A_' n") : type_scope. Notation "''A' [ F ]_ ( m , n )" := 'M[F]_(m, n ^ 2) (at level 8, only parsing) : type_scope. Notation "''A' [ F ]_ ( n )" := 'A[F]_(n ^ 2, n) (at level 8, only parsing) : type_scope. Notation "''A' [ F ]_ n" := 'A[F]_(n) (at level 8, n at level 2, only parsing) : type_scope. Delimit Scope matrix_set_scope with MS. Notation Local simp := (Monoid.Theory.simpm, oppr0). (*****************************************************************************) (******************** Rank and row-space theory ******************************) (*****************************************************************************) Section RowSpaceTheory. Variable F : fieldType. Implicit Types m n p r : nat. Local Notation "''M_' ( m , n )" := 'M[F]_(m, n) : type_scope. Local Notation "''M_' n" := 'M[F]_(n, n) : type_scope. (* Decomposition with double pivoting; computes the rank, row and column *) (* images, kernels, and complements of a matrix. *) Fixpoint Gaussian_elimination {m n} : 'M_(m, n) -> 'M_m * 'M_n * nat := match m, n with | _.+1, _.+1 => fun A : 'M_(1 + _, 1 + _) => if [pick ij | A ij.1 ij.2 != 0] is Some (i, j) then let a := A i j in let A1 := xrow i 0 (xcol j 0 A) in let u := ursubmx A1 in let v := a^-1 *: dlsubmx A1 in let: (L, U, r) := Gaussian_elimination (drsubmx A1 - v *m u) in (xrow i 0 (block_mx 1 0 v L), xcol j 0 (block_mx a%:M u 0 U), r.+1) else (1%:M, 1%:M, 0%N) | _, _ => fun _ => (1%:M, 1%:M, 0%N) end. Section Defs. Variables (m n : nat) (A : 'M_(m, n)). Fact Gaussian_elimination_key : unit. Proof. by []. Qed. Let LUr := locked_with Gaussian_elimination_key (@Gaussian_elimination) m n A. Definition col_ebase := LUr.1.1. Definition row_ebase := LUr.1.2. Definition mxrank := if [|| m == 0 | n == 0]%N then 0%N else LUr.2. Definition row_free := mxrank == m. Definition row_full := mxrank == n. Definition row_base : 'M_(mxrank, n) := pid_mx mxrank *m row_ebase. Definition col_base : 'M_(m, mxrank) := col_ebase *m pid_mx mxrank. Definition complmx : 'M_n := copid_mx mxrank *m row_ebase. Definition kermx : 'M_m := copid_mx mxrank *m invmx col_ebase. Definition cokermx : 'M_n := invmx row_ebase *m copid_mx mxrank. Definition pinvmx : 'M_(n, m) := invmx row_ebase *m pid_mx mxrank *m invmx col_ebase. End Defs. Arguments Scope mxrank [nat_scope nat_scope matrix_set_scope]. Local Notation "\rank A" := (mxrank A) : nat_scope. Arguments Scope complmx [nat_scope nat_scope matrix_set_scope]. Local Notation "A ^C" := (complmx A) : matrix_set_scope. Definition submx_def := idfun (fun m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) => A *m cokermx B == 0). Fact submx_key : unit. Proof. by []. Qed. Definition submx := locked_with submx_key submx_def. Canonical submx_unlockable := [unlockable fun submx]. Arguments Scope submx [nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Prenex Implicits submx. Local Notation "A <= B" := (submx A B) : matrix_set_scope. Local Notation "A <= B <= C" := ((A <= B) && (B <= C))%MS : matrix_set_scope. Local Notation "A == B" := (A <= B <= A)%MS : matrix_set_scope. Definition ltmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) := (A <= B)%MS && ~~ (B <= A)%MS. Arguments Scope ltmx [nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Prenex Implicits ltmx. Local Notation "A < B" := (ltmx A B) : matrix_set_scope. Definition eqmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) := prod (\rank A = \rank B) (forall m3 (C : 'M_(m3, n)), ((A <= C) = (B <= C)) * ((C <= A) = (C <= B)))%MS. Arguments Scope eqmx [nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Local Notation "A :=: B" := (eqmx A B) : matrix_set_scope. Section LtmxIdentities. Variables (m1 m2 n : nat) (A : 'M_(m1, n)) (B : 'M_(m2, n)). Lemma ltmxE : (A < B)%MS = ((A <= B)%MS && ~~ (B <= A)%MS). Proof. by []. Qed. Lemma ltmxW : (A < B)%MS -> (A <= B)%MS. Proof. by case/andP. Qed. Lemma ltmxEneq : (A < B)%MS = (A <= B)%MS && ~~ (A == B)%MS. Proof. by apply: andb_id2l => ->. Qed. Lemma submxElt : (A <= B)%MS = (A == B)%MS || (A < B)%MS. Proof. by rewrite -andb_orr orbN andbT. Qed. End LtmxIdentities. (* The definition of the row-space operator is rigged to return the identity *) (* matrix for full matrices. To allow for further tweaks that will make the *) (* row-space intersection operator strictly commutative and monoidal, we *) (* slightly generalize some auxiliary definitions: we parametrize the *) (* "equivalent subspace and identity" choice predicate equivmx by a boolean *) (* determining whether the matrix should be the identity (so for genmx A its *) (* value is row_full A), and introduce a "quasi-identity" predicate qidmx *) (* that selects non-square full matrices along with the identity matrix 1%:M *) (* (this does not affect genmx, which chooses a square matrix). *) (* The choice witness for genmx A is either 1%:M for a row-full A, or else *) (* row_base A padded with null rows. *) Let qidmx m n (A : 'M_(m, n)) := if m == n then A == pid_mx n else row_full A. Let equivmx m n (A : 'M_(m, n)) idA (B : 'M_n) := (B == A)%MS && (qidmx B == idA). Let equivmx_spec m n (A : 'M_(m, n)) idA (B : 'M_n) := prod (B :=: A)%MS (qidmx B = idA). Definition genmx_witness m n (A : 'M_(m, n)) : 'M_n := if row_full A then 1%:M else pid_mx (\rank A) *m row_ebase A. Definition genmx_def := idfun (fun m n (A : 'M_(m, n)) => choose (equivmx A (row_full A)) (genmx_witness A) : 'M_n). Fact genmx_key : unit. Proof. by []. Qed. Definition genmx := locked_with genmx_key genmx_def. Canonical genmx_unlockable := [unlockable fun genmx]. Local Notation "<< A >>" := (genmx A) : matrix_set_scope. (* The setwise sum is tweaked so that 0 is a strict identity element for *) (* square matrices, because this lets us use the bigop component. As a result *) (* setwise sum is not quite strictly extensional. *) Let addsmx_nop m n (A : 'M_(m, n)) := conform_mx <>%MS A. Definition addsmx_def := idfun (fun m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) => if A == 0 then addsmx_nop B else if B == 0 then addsmx_nop A else <>%MS : 'M_n). Fact addsmx_key : unit. Proof. by []. Qed. Definition addsmx := locked_with addsmx_key addsmx_def. Canonical addsmx_unlockable := [unlockable fun addsmx]. Arguments Scope addsmx [nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Prenex Implicits addsmx. Local Notation "A + B" := (addsmx A B) : matrix_set_scope. Local Notation "\sum_ ( i | P ) B" := (\big[addsmx/0]_(i | P) B%MS) : matrix_set_scope. Local Notation "\sum_ ( i <- r | P ) B" := (\big[addsmx/0]_(i <- r | P) B%MS) : matrix_set_scope. (* The set intersection is similarly biased so that the identity matrix is a *) (* strict identity. This is somewhat more delicate than for the sum, because *) (* the test for the identity is non-extensional. This forces us to actually *) (* bias the choice operator so that it does not accidentally map an *) (* intersection of non-identity matrices to 1%:M; this would spoil *) (* associativity: if B :&: C = 1%:M but B and C are not identity, then for a *) (* square matrix A we have A :&: (B :&: C) = A != (A :&: B) :&: C in general. *) (* To complicate matters there may not be a square non-singular matrix *) (* different than 1%:M, since we could be dealing with 'M['F_2]_1. We *) (* sidestep the issue by making all non-square row-full matrices identities, *) (* and choosing a normal representative that preserves the qidmx property. *) (* Thus A :&: B = 1%:M iff A and B are both identities, and this suffices for *) (* showing that associativity is strict. *) Let capmx_witness m n (A : 'M_(m, n)) := if row_full A then conform_mx 1%:M A else <>%MS. Let capmx_norm m n (A : 'M_(m, n)) := choose (equivmx A (qidmx A)) (capmx_witness A). Let capmx_nop m n (A : 'M_(m, n)) := conform_mx (capmx_norm A) A. Definition capmx_gen m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) := lsubmx (kermx (col_mx A B)) *m A. Definition capmx_def := idfun (fun m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) => if qidmx A then capmx_nop B else if qidmx B then capmx_nop A else if row_full B then capmx_norm A else capmx_norm (capmx_gen A B) : 'M_n). Fact capmx_key : unit. Proof. by []. Qed. Definition capmx := locked_with capmx_key capmx_def. Canonical capmx_unlockable := [unlockable fun capmx]. Arguments Scope capmx [nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Prenex Implicits capmx. Local Notation "A :&: B" := (capmx A B) : matrix_set_scope. Local Notation "\bigcap_ ( i | P ) B" := (\big[capmx/1%:M]_(i | P) B) : matrix_set_scope. Definition diffmx_def := idfun (fun m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) => <>%MS : 'M_n). Fact diffmx_key : unit. Proof. by []. Qed. Definition diffmx := locked_with diffmx_key diffmx_def. Canonical diffmx_unlockable := [unlockable fun diffmx]. Arguments Scope diffmx [nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Prenex Implicits diffmx. Local Notation "A :\: B" := (diffmx A B) : matrix_set_scope. Definition proj_mx n (U V : 'M_n) : 'M_n := pinvmx (col_mx U V) *m col_mx U 0. Local Notation GaussE := Gaussian_elimination. Fact mxrankE m n (A : 'M_(m, n)) : \rank A = (GaussE A).2. Proof. by rewrite /mxrank unlock /=; case: m n A => [|m] [|n]. Qed. Lemma rank_leq_row m n (A : 'M_(m, n)) : \rank A <= m. Proof. rewrite mxrankE. elim: m n A => [|m IHm] [|n] //= A; case: pickP => [[i j] _|] //=. by move: (_ - _) => B; case: GaussE (IHm _ B) => [[L U] r] /=. Qed. Lemma row_leq_rank m n (A : 'M_(m, n)) : (m <= \rank A) = row_free A. Proof. by rewrite /row_free eqn_leq rank_leq_row. Qed. Lemma rank_leq_col m n (A : 'M_(m, n)) : \rank A <= n. Proof. rewrite mxrankE. elim: m n A => [|m IHm] [|n] //= A; case: pickP => [[i j] _|] //=. by move: (_ - _) => B; case: GaussE (IHm _ B) => [[L U] r] /=. Qed. Lemma col_leq_rank m n (A : 'M_(m, n)) : (n <= \rank A) = row_full A. Proof. by rewrite /row_full eqn_leq rank_leq_col. Qed. Let unitmx1F := @unitmx1 F. Lemma row_ebase_unit m n (A : 'M_(m, n)) : row_ebase A \in unitmx. Proof. rewrite /row_ebase unlock; elim: m n A => [|m IHm] [|n] //= A. case: pickP => [[i j] /= nzAij | //=]; move: (_ - _) => B. case: GaussE (IHm _ B) => [[L U] r] /= uU. rewrite unitmxE xcolE det_mulmx (@det_ublock _ 1) det_scalar1 !unitrM. by rewrite unitfE nzAij -!unitmxE uU unitmx_perm. Qed. Lemma col_ebase_unit m n (A : 'M_(m, n)) : col_ebase A \in unitmx. Proof. rewrite /col_ebase unlock; elim: m n A => [|m IHm] [|n] //= A. case: pickP => [[i j] _|] //=; move: (_ - _) => B. case: GaussE (IHm _ B) => [[L U] r] /= uL. rewrite unitmxE xrowE det_mulmx (@det_lblock _ 1) det1 mul1r unitrM. by rewrite -unitmxE unitmx_perm. Qed. Hint Resolve rank_leq_row rank_leq_col row_ebase_unit col_ebase_unit. Lemma mulmx_ebase m n (A : 'M_(m, n)) : col_ebase A *m pid_mx (\rank A) *m row_ebase A = A. Proof. rewrite mxrankE /col_ebase /row_ebase unlock. elim: m n A => [n A | m IHm]; first by rewrite [A]flatmx0 [_ *m _]flatmx0. case=> [A | n]; first by rewrite [_ *m _]thinmx0 [A]thinmx0. rewrite -(add1n m) -?(add1n n) => A /=. case: pickP => [[i0 j0] | A0] /=; last first. apply/matrixP=> i j; rewrite pid_mx_0 mulmx0 mul0mx mxE. by move/eqP: (A0 (i, j)). set a := A i0 j0 => nz_a; set A1 := xrow _ _ _. set u := ursubmx _; set v := _ *: _; set B : 'M_(m, n) := _ - _. move: (rank_leq_col B) (rank_leq_row B) {IHm}(IHm n B); rewrite mxrankE. case: (GaussE B) => [[L U] r] /= r_m r_n defB. have ->: pid_mx (1 + r) = block_mx 1 0 0 (pid_mx r) :> 'M[F]_(1 + m, 1 + n). rewrite -(subnKC r_m) -(subnKC r_n) pid_mx_block -col_mx0 -row_mx0. by rewrite block_mxA castmx_id col_mx0 row_mx0 -scalar_mx_block -pid_mx_block. rewrite xcolE xrowE mulmxA -xcolE -!mulmxA. rewrite !(addr0, add0r, mulmx0, mul0mx, mulmx_block, mul1mx) mulmxA defB. rewrite addrC subrK mul_mx_scalar scalerA divff // scale1r. have ->: a%:M = ulsubmx A1 by rewrite [_ A1]mx11_scalar !mxE !lshift0 !tpermR. rewrite submxK /A1 xrowE !xcolE -!mulmxA mulmxA -!perm_mxM !tperm2 !perm_mx1. by rewrite mulmx1 mul1mx. Qed. Lemma mulmx_base m n (A : 'M_(m, n)) : col_base A *m row_base A = A. Proof. by rewrite mulmxA -[col_base A *m _]mulmxA pid_mx_id ?mulmx_ebase. Qed. Lemma mulmx1_min_rank r m n (A : 'M_(m, n)) M N : M *m A *m N = 1%:M :> 'M_r -> r <= \rank A. Proof. by rewrite -{1}(mulmx_base A) mulmxA -mulmxA; move/mulmx1_min. Qed. Implicit Arguments mulmx1_min_rank [r m n A]. Lemma mulmx_max_rank r m n (M : 'M_(m, r)) (N : 'M_(r, n)) : \rank (M *m N) <= r. Proof. set MN := M *m N; set rMN := \rank _. pose L : 'M_(rMN, m) := pid_mx rMN *m invmx (col_ebase MN). pose U : 'M_(n, rMN) := invmx (row_ebase MN) *m pid_mx rMN. suffices: L *m M *m (N *m U) = 1%:M by exact: mulmx1_min. rewrite mulmxA -(mulmxA L) -[M *m N]mulmx_ebase -/MN. by rewrite !mulmxA mulmxKV // mulmxK // !pid_mx_id /rMN ?pid_mx_1. Qed. Implicit Arguments mulmx_max_rank [r m n]. Lemma mxrank_tr m n (A : 'M_(m, n)) : \rank A^T = \rank A. Proof. apply/eqP; rewrite eqn_leq -{3}[A]trmxK -{1}(mulmx_base A) -{1}(mulmx_base A^T). by rewrite !trmx_mul !mulmx_max_rank. Qed. Lemma mxrank_add m n (A B : 'M_(m, n)) : \rank (A + B)%R <= \rank A + \rank B. Proof. by rewrite -{1}(mulmx_base A) -{1}(mulmx_base B) -mul_row_col mulmx_max_rank. Qed. Lemma mxrankM_maxl m n p (A : 'M_(m, n)) (B : 'M_(n, p)) : \rank (A *m B) <= \rank A. Proof. by rewrite -{1}(mulmx_base A) -mulmxA mulmx_max_rank. Qed. Lemma mxrankM_maxr m n p (A : 'M_(m, n)) (B : 'M_(n, p)) : \rank (A *m B) <= \rank B. Proof. by rewrite -mxrank_tr -(mxrank_tr B) trmx_mul mxrankM_maxl. Qed. Lemma mxrank_scale m n a (A : 'M_(m, n)) : \rank (a *: A) <= \rank A. Proof. by rewrite -mul_scalar_mx mxrankM_maxr. Qed. Lemma mxrank_scale_nz m n a (A : 'M_(m, n)) : a != 0 -> \rank (a *: A) = \rank A. Proof. move=> nza; apply/eqP; rewrite eqn_leq -{3}[A]scale1r -(mulVf nza). by rewrite -scalerA !mxrank_scale. Qed. Lemma mxrank_opp m n (A : 'M_(m, n)) : \rank (- A) = \rank A. Proof. by rewrite -scaleN1r mxrank_scale_nz // oppr_eq0 oner_eq0. Qed. Lemma mxrank0 m n : \rank (0 : 'M_(m, n)) = 0%N. Proof. by apply/eqP; rewrite -leqn0 -(@mulmx0 _ m 0 n 0) mulmx_max_rank. Qed. Lemma mxrank_eq0 m n (A : 'M_(m, n)) : (\rank A == 0%N) = (A == 0). Proof. apply/eqP/eqP=> [rA0 | ->{A}]; last exact: mxrank0. move: (col_base A) (row_base A) (mulmx_base A); rewrite rA0 => Ac Ar <-. by rewrite [Ac]thinmx0 mul0mx. Qed. Lemma mulmx_coker m n (A : 'M_(m, n)) : A *m cokermx A = 0. Proof. by rewrite -{1}[A]mulmx_ebase -!mulmxA mulKVmx // mul_pid_mx_copid ?mulmx0. Qed. Lemma submxE m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A <= B)%MS = (A *m cokermx B == 0). Proof. by rewrite unlock. Qed. Lemma mulmxKpV m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A <= B)%MS -> A *m pinvmx B *m B = A. Proof. rewrite submxE !mulmxA mulmxBr mulmx1 subr_eq0 => /eqP defA. rewrite -{4}[B]mulmx_ebase -!mulmxA mulKmx //. by rewrite (mulmxA (pid_mx _)) pid_mx_id // !mulmxA -{}defA mulmxKV. Qed. Lemma submxP m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : reflect (exists D, A = D *m B) (A <= B)%MS. Proof. apply: (iffP idP) => [/mulmxKpV | [D ->]]; first by exists (A *m pinvmx B). by rewrite submxE -mulmxA mulmx_coker mulmx0. Qed. Implicit Arguments submxP [m1 m2 n A B]. Lemma submx_refl m n (A : 'M_(m, n)) : (A <= A)%MS. Proof. by rewrite submxE mulmx_coker. Qed. Hint Resolve submx_refl. Lemma submxMl m n p (D : 'M_(m, n)) (A : 'M_(n, p)) : (D *m A <= A)%MS. Proof. by rewrite submxE -mulmxA mulmx_coker mulmx0. Qed. Lemma submxMr m1 m2 n p (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(n, p)) : (A <= B)%MS -> (A *m C <= B *m C)%MS. Proof. by case/submxP=> D ->; rewrite -mulmxA submxMl. Qed. Lemma mulmx_sub m n1 n2 p (C : 'M_(m, n1)) A (B : 'M_(n2, p)) : (A <= B -> C *m A <= B)%MS. Proof. by case/submxP=> D ->; rewrite mulmxA submxMl. Qed. Lemma submx_trans m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) : (A <= B -> B <= C -> A <= C)%MS. Proof. by case/submxP=> D ->{A}; exact: mulmx_sub. Qed. Lemma ltmx_sub_trans m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) : (A < B)%MS -> (B <= C)%MS -> (A < C)%MS. Proof. case/andP=> sAB ltAB sBC; rewrite ltmxE (submx_trans sAB) //. by apply: contra ltAB; exact: submx_trans. Qed. Lemma sub_ltmx_trans m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) : (A <= B)%MS -> (B < C)%MS -> (A < C)%MS. Proof. move=> sAB /andP[sBC ltBC]; rewrite ltmxE (submx_trans sAB) //. by apply: contra ltBC => sCA; exact: submx_trans sAB. Qed. Lemma ltmx_trans m n : transitive (@ltmx m m n). Proof. by move=> A B C; move/ltmxW; exact: sub_ltmx_trans. Qed. Lemma ltmx_irrefl m n : irreflexive (@ltmx m m n). Proof. by move=> A; rewrite /ltmx submx_refl andbF. Qed. Lemma sub0mx m1 m2 n (A : 'M_(m2, n)) : ((0 : 'M_(m1, n)) <= A)%MS. Proof. by rewrite submxE mul0mx. Qed. Lemma submx0null m1 m2 n (A : 'M[F]_(m1, n)) : (A <= (0 : 'M_(m2, n)))%MS -> A = 0. Proof. by case/submxP=> D; rewrite mulmx0. Qed. Lemma submx0 m n (A : 'M_(m, n)) : (A <= (0 : 'M_n))%MS = (A == 0). Proof. by apply/idP/eqP=> [|->]; [exact: submx0null | exact: sub0mx]. Qed. Lemma lt0mx m n (A : 'M_(m, n)) : ((0 : 'M_n) < A)%MS = (A != 0). Proof. by rewrite /ltmx sub0mx submx0. Qed. Lemma ltmx0 m n (A : 'M[F]_(m, n)) : (A < (0 : 'M_n))%MS = false. Proof. by rewrite /ltmx sub0mx andbF. Qed. Lemma eqmx0P m n (A : 'M_(m, n)) : reflect (A = 0) (A == (0 : 'M_n))%MS. Proof. by rewrite submx0 sub0mx andbT; exact: eqP. Qed. Lemma eqmx_eq0 m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :=: B)%MS -> (A == 0) = (B == 0). Proof. by move=> eqAB; rewrite -!submx0 eqAB. Qed. Lemma addmx_sub m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m1, n)) (C : 'M_(m2, n)) : (A <= C)%MS -> (B <= C)%MS -> ((A + B)%R <= C)%MS. Proof. by case/submxP=> A' ->; case/submxP=> B' ->; rewrite -mulmxDl submxMl. Qed. Lemma summx_sub m1 m2 n (B : 'M_(m2, n)) I (r : seq I) (P : pred I) (A_ : I -> 'M_(m1, n)) : (forall i, P i -> A_ i <= B)%MS -> ((\sum_(i <- r | P i) A_ i)%R <= B)%MS. Proof. move=> leAB; elim/big_ind: _ => // [|A1 A2]; [exact: sub0mx | exact: addmx_sub]. Qed. Lemma scalemx_sub m1 m2 n a (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A <= B)%MS -> (a *: A <= B)%MS. Proof. by case/submxP=> A' ->; rewrite scalemxAl submxMl. Qed. Lemma row_sub m n i (A : 'M_(m, n)) : (row i A <= A)%MS. Proof. by rewrite rowE submxMl. Qed. Lemma eq_row_sub m n v (A : 'M_(m, n)) i : row i A = v -> (v <= A)%MS. Proof. by move <-; rewrite row_sub. Qed. Lemma nz_row_sub m n (A : 'M_(m, n)) : (nz_row A <= A)%MS. Proof. by rewrite /nz_row; case: pickP => [i|] _; rewrite ?row_sub ?sub0mx. Qed. Lemma row_subP m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : reflect (forall i, row i A <= B)%MS (A <= B)%MS. Proof. apply: (iffP idP) => [sAB i|sAB]. by apply: submx_trans sAB; exact: row_sub. rewrite submxE; apply/eqP/row_matrixP=> i; apply/eqP. by rewrite row_mul row0 -submxE. Qed. Implicit Arguments row_subP [m1 m2 n A B]. Lemma rV_subP m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : reflect (forall v : 'rV_n, v <= A -> v <= B)%MS (A <= B)%MS. Proof. apply: (iffP idP) => [sAB v Av | sAB]; first exact: submx_trans sAB. by apply/row_subP=> i; rewrite sAB ?row_sub. Qed. Implicit Arguments rV_subP [m1 m2 n A B]. Lemma row_subPn m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : reflect (exists i, ~~ (row i A <= B)%MS) (~~ (A <= B)%MS). Proof. by rewrite (sameP row_subP forallP) negb_forall; exact: existsP. Qed. Lemma sub_rVP n (u v : 'rV_n) : reflect (exists a, u = a *: v) (u <= v)%MS. Proof. apply: (iffP submxP) => [[w ->] | [a ->]]. by exists (w 0 0); rewrite -mul_scalar_mx -mx11_scalar. by exists a%:M; rewrite mul_scalar_mx. Qed. Lemma rank_rV n (v : 'rV_n) : \rank v = (v != 0). Proof. case: eqP => [-> | nz_v]; first by rewrite mxrank0. by apply/eqP; rewrite eqn_leq rank_leq_row lt0n mxrank_eq0; exact/eqP. Qed. Lemma rowV0Pn m n (A : 'M_(m, n)) : reflect (exists2 v : 'rV_n, v <= A & v != 0)%MS (A != 0). Proof. rewrite -submx0; apply: (iffP idP) => [| [v svA]]; last first. by rewrite -submx0; exact: contra (submx_trans _). by case/row_subPn=> i; rewrite submx0; exists (row i A); rewrite ?row_sub. Qed. Lemma rowV0P m n (A : 'M_(m, n)) : reflect (forall v : 'rV_n, v <= A -> v = 0)%MS (A == 0). Proof. rewrite -[A == 0]negbK; case: rowV0Pn => IH. by right; case: IH => v svA nzv IH; case/eqP: nzv; exact: IH. by left=> v svA; apply/eqP; apply/idPn=> nzv; case: IH; exists v. Qed. Lemma submx_full m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : row_full B -> (A <= B)%MS. Proof. by rewrite submxE /cokermx =>/eqnP->; rewrite /copid_mx pid_mx_1 subrr !mulmx0. Qed. Lemma row_fullP m n (A : 'M_(m, n)) : reflect (exists B, B *m A = 1%:M) (row_full A). Proof. apply: (iffP idP) => [Afull | [B kA]]. by exists (1%:M *m pinvmx A); apply: mulmxKpV (submx_full _ Afull). by rewrite [_ A]eqn_leq rank_leq_col (mulmx1_min_rank B 1%:M) ?mulmx1. Qed. Implicit Arguments row_fullP [m n A]. Lemma row_full_inj m n p A : row_full A -> injective (@mulmx _ m n p A). Proof. case/row_fullP=> A' A'K; apply: can_inj (mulmx A') _ => B. by rewrite mulmxA A'K mul1mx. Qed. Lemma row_freeP m n (A : 'M_(m, n)) : reflect (exists B, A *m B = 1%:M) (row_free A). Proof. rewrite /row_free -mxrank_tr. apply: (iffP row_fullP) => [] [B kA]; by exists B^T; rewrite -trmx1 -kA trmx_mul ?trmxK. Qed. Lemma row_free_inj m n p A : row_free A -> injective ((@mulmx _ m n p)^~ A). Proof. case/row_freeP=> A' AK; apply: can_inj (mulmx^~ A') _ => B. by rewrite -mulmxA AK mulmx1. Qed. Lemma row_free_unit n (A : 'M_n) : row_free A = (A \in unitmx). Proof. apply/row_fullP/idP=> [[A'] | uA]; first by case/mulmx1_unit. by exists (invmx A); rewrite mulVmx. Qed. Lemma row_full_unit n (A : 'M_n) : row_full A = (A \in unitmx). Proof. exact: row_free_unit. Qed. Lemma mxrank_unit n (A : 'M_n) : A \in unitmx -> \rank A = n. Proof. by rewrite -row_full_unit =>/eqnP. Qed. Lemma mxrank1 n : \rank (1%:M : 'M_n) = n. Proof. by apply: mxrank_unit; exact: unitmx1. Qed. Lemma mxrank_delta m n i j : \rank (delta_mx i j : 'M_(m, n)) = 1%N. Proof. apply/eqP; rewrite eqn_leq lt0n mxrank_eq0. rewrite -{1}(mul_delta_mx (0 : 'I_1)) mulmx_max_rank. by apply/eqP; move/matrixP; move/(_ i j); move/eqP; rewrite !mxE !eqxx oner_eq0. Qed. Lemma mxrankS m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A <= B)%MS -> \rank A <= \rank B. Proof. by case/submxP=> D ->; rewrite mxrankM_maxr. Qed. Lemma submx1 m n (A : 'M_(m, n)) : (A <= 1%:M)%MS. Proof. by rewrite submx_full // row_full_unit unitmx1. Qed. Lemma sub1mx m n (A : 'M_(m, n)) : (1%:M <= A)%MS = row_full A. Proof. apply/idP/idP; last exact: submx_full. by move/mxrankS; rewrite mxrank1 col_leq_rank. Qed. Lemma ltmx1 m n (A : 'M_(m, n)) : (A < 1%:M)%MS = ~~ row_full A. Proof. by rewrite /ltmx sub1mx submx1. Qed. Lemma lt1mx m n (A : 'M_(m, n)) : (1%:M < A)%MS = false. Proof. by rewrite /ltmx submx1 andbF. Qed. Lemma eqmxP m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : reflect (A :=: B)%MS (A == B)%MS. Proof. apply: (iffP andP) => [[sAB sBA] | eqAB]; last by rewrite !eqAB. split=> [|m3 C]; first by apply/eqP; rewrite eqn_leq !mxrankS. split; first by apply/idP/idP; exact: submx_trans. by apply/idP/idP=> sC; exact: submx_trans sC _. Qed. Implicit Arguments eqmxP [m1 m2 n A B]. Lemma rV_eqP m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : reflect (forall u : 'rV_n, (u <= A) = (u <= B))%MS (A == B)%MS. Proof. apply: (iffP idP) => [eqAB u | eqAB]; first by rewrite (eqmxP eqAB). by apply/andP; split; apply/rV_subP=> u; rewrite eqAB. Qed. Lemma eqmx_refl m1 n (A : 'M_(m1, n)) : (A :=: A)%MS. Proof. by []. Qed. Lemma eqmx_sym m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :=: B)%MS -> (B :=: A)%MS. Proof. by move=> eqAB; split=> [|m3 C]; rewrite !eqAB. Qed. Lemma eqmx_trans m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) : (A :=: B)%MS -> (B :=: C)%MS -> (A :=: C)%MS. Proof. by move=> eqAB eqBC; split=> [|m4 D]; rewrite !eqAB !eqBC. Qed. Lemma eqmx_rank m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A == B)%MS -> \rank A = \rank B. Proof. by move/eqmxP->. Qed. Lemma lt_eqmx m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :=: B)%MS -> forall C : 'M_(m3, n), (((A < C) = (B < C))%MS * ((C < A) = (C < B))%MS)%type. Proof. by move=> eqAB C; rewrite /ltmx !eqAB. Qed. Lemma eqmxMr m1 m2 n p (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(n, p)) : (A :=: B)%MS -> (A *m C :=: B *m C)%MS. Proof. by move=> eqAB; apply/eqmxP; rewrite !submxMr ?eqAB. Qed. Lemma eqmxMfull m n p (A : 'M_(m, n)) (B : 'M_(n, p)) : row_full A -> (A *m B :=: B)%MS. Proof. case/row_fullP=> A' A'A; apply/eqmxP; rewrite submxMl /=. by apply/submxP; exists A'; rewrite mulmxA A'A mul1mx. Qed. Lemma eqmx0 m n : ((0 : 'M[F]_(m, n)) :=: (0 : 'M_n))%MS. Proof. by apply/eqmxP; rewrite !sub0mx. Qed. Lemma eqmx_scale m n a (A : 'M_(m, n)) : a != 0 -> (a *: A :=: A)%MS. Proof. move=> nz_a; apply/eqmxP; rewrite scalemx_sub //. by rewrite -{1}[A]scale1r -(mulVf nz_a) -scalerA scalemx_sub. Qed. Lemma eqmx_opp m n (A : 'M_(m, n)) : (- A :=: A)%MS. Proof. by rewrite -scaleN1r; apply: eqmx_scale => //; rewrite oppr_eq0 oner_eq0. Qed. Lemma submxMfree m1 m2 n p (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(n, p)) : row_free C -> (A *m C <= B *m C)%MS = (A <= B)%MS. Proof. case/row_freeP=> C' C_C'_1; apply/idP/idP=> sAB; last exact: submxMr. by rewrite -[A]mulmx1 -[B]mulmx1 -C_C'_1 !mulmxA submxMr. Qed. Lemma eqmxMfree m1 m2 n p (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(n, p)) : row_free C -> (A *m C :=: B *m C)%MS -> (A :=: B)%MS. Proof. by move=> Cfree eqAB; apply/eqmxP; move/eqmxP: eqAB; rewrite !submxMfree. Qed. Lemma mxrankMfree m n p (A : 'M_(m, n)) (B : 'M_(n, p)) : row_free B -> \rank (A *m B) = \rank A. Proof. by move=> Bfree; rewrite -mxrank_tr trmx_mul eqmxMfull /row_full mxrank_tr. Qed. Lemma eq_row_base m n (A : 'M_(m, n)) : (row_base A :=: A)%MS. Proof. apply/eqmxP; apply/andP; split; apply/submxP. exists (pid_mx (\rank A) *m invmx (col_ebase A)). by rewrite -{8}[A]mulmx_ebase !mulmxA mulmxKV // pid_mx_id. exists (col_ebase A *m pid_mx (\rank A)). by rewrite mulmxA -(mulmxA _ _ (pid_mx _)) pid_mx_id // mulmx_ebase. Qed. Let qidmx_eq1 n (A : 'M_n) : qidmx A = (A == 1%:M). Proof. by rewrite /qidmx eqxx pid_mx_1. Qed. Let genmx_witnessP m n (A : 'M_(m, n)) : equivmx A (row_full A) (genmx_witness A). Proof. rewrite /equivmx qidmx_eq1 /genmx_witness. case fullA: (row_full A); first by rewrite eqxx sub1mx submx1 fullA. set B := _ *m _; have defB : (B == A)%MS. apply/andP; split; apply/submxP. exists (pid_mx (\rank A) *m invmx (col_ebase A)). by rewrite -{3}[A]mulmx_ebase !mulmxA mulmxKV // pid_mx_id. exists (col_ebase A *m pid_mx (\rank A)). by rewrite mulmxA -(mulmxA _ _ (pid_mx _)) pid_mx_id // mulmx_ebase. rewrite defB -negb_add addbF; case: eqP defB => // ->. by rewrite sub1mx fullA. Qed. Lemma genmxE m n (A : 'M_(m, n)) : (<> :=: A)%MS. Proof. by rewrite unlock; apply/eqmxP; case/andP: (chooseP (genmx_witnessP A)). Qed. Lemma eq_genmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :=: B -> <> = <>)%MS. Proof. move=> eqAB; rewrite unlock. have{eqAB} eqAB: equivmx A (row_full A) =1 equivmx B (row_full B). by move=> C; rewrite /row_full /equivmx !eqAB. rewrite (eq_choose eqAB) (choose_id _ (genmx_witnessP B)) //. by rewrite -eqAB genmx_witnessP. Qed. Lemma genmxP m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : reflect (<> = <>)%MS (A == B)%MS. Proof. apply: (iffP idP) => eqAB; first exact: eq_genmx (eqmxP _). by rewrite -!(genmxE A) eqAB !genmxE andbb. Qed. Implicit Arguments genmxP [m1 m2 n A B]. Lemma genmx0 m n : <<0 : 'M_(m, n)>>%MS = 0. Proof. by apply/eqP; rewrite -submx0 genmxE sub0mx. Qed. Lemma genmx1 n : <<1%:M : 'M_n>>%MS = 1%:M. Proof. rewrite unlock; case/andP: (chooseP (@genmx_witnessP n n 1%:M)) => _ /eqP. by rewrite qidmx_eq1 row_full_unit unitmx1 => /eqP. Qed. Lemma genmx_id m n (A : 'M_(m, n)) : (<<<>>> = <>)%MS. Proof. by apply: eq_genmx; exact: genmxE. Qed. Lemma row_base_free m n (A : 'M_(m, n)) : row_free (row_base A). Proof. by apply/eqnP; rewrite eq_row_base. Qed. Lemma mxrank_gen m n (A : 'M_(m, n)) : \rank <> = \rank A. Proof. by rewrite genmxE. Qed. Lemma col_base_full m n (A : 'M_(m, n)) : row_full (col_base A). Proof. apply/row_fullP; exists (pid_mx (\rank A) *m invmx (col_ebase A)). by rewrite !mulmxA mulmxKV // pid_mx_id // pid_mx_1. Qed. Hint Resolve row_base_free col_base_full. Lemma mxrank_leqif_sup m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A <= B)%MS -> \rank A <= \rank B ?= iff (B <= A)%MS. Proof. move=> sAB; split; first by rewrite mxrankS. apply/idP/idP=> [| sBA]; last by rewrite eqn_leq !mxrankS. case/submxP: sAB => D ->; rewrite -{-2}(mulmx_base B) mulmxA. rewrite mxrankMfree // => /row_fullP[E kE]. by rewrite -{1}[row_base B]mul1mx -kE -(mulmxA E) (mulmxA _ E) submxMl. Qed. Lemma mxrank_leqif_eq m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A <= B)%MS -> \rank A <= \rank B ?= iff (A == B)%MS. Proof. by move=> sAB; rewrite sAB; exact: mxrank_leqif_sup. Qed. Lemma ltmxErank m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A < B)%MS = (A <= B)%MS && (\rank A < \rank B). Proof. by apply: andb_id2l => sAB; rewrite (ltn_leqif (mxrank_leqif_sup sAB)). Qed. Lemma rank_ltmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A < B)%MS -> \rank A < \rank B. Proof. by rewrite ltmxErank => /andP[]. Qed. Lemma eqmx_cast m1 m2 n (A : 'M_(m1, n)) e : ((castmx e A : 'M_(m2, n)) :=: A)%MS. Proof. by case: e A; case: m2 / => A e; rewrite castmx_id. Qed. Lemma eqmx_conform m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (conform_mx A B :=: A \/ conform_mx A B :=: B)%MS. Proof. case: (eqVneq m2 m1) => [-> | neqm12] in B *. by right; rewrite conform_mx_id. by left; rewrite nonconform_mx ?neqm12. Qed. Let eqmx_sum_nop m n (A : 'M_(m, n)) : (addsmx_nop A :=: A)%MS. Proof. case: (eqmx_conform <>%MS A) => // eq_id_gen. exact: eqmx_trans (genmxE A). Qed. Section AddsmxSub. Variable (m1 m2 n : nat) (A : 'M[F]_(m1, n)) (B : 'M[F]_(m2, n)). Lemma col_mx_sub m3 (C : 'M_(m3, n)) : (col_mx A B <= C)%MS = (A <= C)%MS && (B <= C)%MS. Proof. rewrite !submxE mul_col_mx -col_mx0. by apply/eqP/andP; [case/eq_col_mx=> -> -> | case; do 2!move/eqP->]. Qed. Lemma addsmxE : (A + B :=: col_mx A B)%MS. Proof. have:= submx_refl (col_mx A B); rewrite col_mx_sub; case/andP=> sAS sBS. rewrite unlock; do 2?case: eqP => [AB0 | _]; last exact: genmxE. by apply/eqmxP; rewrite !eqmx_sum_nop sBS col_mx_sub AB0 sub0mx /=. by apply/eqmxP; rewrite !eqmx_sum_nop sAS col_mx_sub AB0 sub0mx andbT /=. Qed. Lemma addsmx_sub m3 (C : 'M_(m3, n)) : (A + B <= C)%MS = (A <= C)%MS && (B <= C)%MS. Proof. by rewrite addsmxE col_mx_sub. Qed. Lemma addsmxSl : (A <= A + B)%MS. Proof. by have:= submx_refl (A + B)%MS; rewrite addsmx_sub; case/andP. Qed. Lemma addsmxSr : (B <= A + B)%MS. Proof. by have:= submx_refl (A + B)%MS; rewrite addsmx_sub; case/andP. Qed. Lemma addsmx_idPr : reflect (A + B :=: B)%MS (A <= B)%MS. Proof. have:= @eqmxP _ _ _ (A + B)%MS B. by rewrite addsmxSr addsmx_sub submx_refl !andbT. Qed. Lemma addsmx_idPl : reflect (A + B :=: A)%MS (B <= A)%MS. Proof. have:= @eqmxP _ _ _ (A + B)%MS A. by rewrite addsmxSl addsmx_sub submx_refl !andbT. Qed. End AddsmxSub. Lemma adds0mx m1 m2 n (B : 'M_(m2, n)) : ((0 : 'M_(m1, n)) + B :=: B)%MS. Proof. by apply/eqmxP; rewrite addsmx_sub sub0mx addsmxSr /= andbT. Qed. Lemma addsmx0 m1 m2 n (A : 'M_(m1, n)) : (A + (0 : 'M_(m2, n)) :=: A)%MS. Proof. by apply/eqmxP; rewrite addsmx_sub sub0mx addsmxSl /= !andbT. Qed. Let addsmx_nop_eq0 m n (A : 'M_(m, n)) : (addsmx_nop A == 0) = (A == 0). Proof. by rewrite -!submx0 eqmx_sum_nop. Qed. Let addsmx_nop0 m n : addsmx_nop (0 : 'M_(m, n)) = 0. Proof. by apply/eqP; rewrite addsmx_nop_eq0. Qed. Let addsmx_nop_id n (A : 'M_n) : addsmx_nop A = A. Proof. exact: conform_mx_id. Qed. Lemma addsmxC m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A + B = B + A)%MS. Proof. have: (A + B == B + A)%MS. by apply/andP; rewrite !addsmx_sub andbC -addsmx_sub andbC -addsmx_sub. move/genmxP; rewrite [@addsmx]unlock -!submx0 !submx0. by do 2!case: eqP => [// -> | _]; rewrite ?genmx_id ?addsmx_nop0. Qed. Lemma adds0mx_id m1 n (B : 'M_n) : ((0 : 'M_(m1, n)) + B)%MS = B. Proof. by rewrite unlock eqxx addsmx_nop_id. Qed. Lemma addsmx0_id m2 n (A : 'M_n) : (A + (0 : 'M_(m2, n)))%MS = A. Proof. by rewrite addsmxC adds0mx_id. Qed. Lemma addsmxA m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) : (A + (B + C) = A + B + C)%MS. Proof. have: (A + (B + C) :=: A + B + C)%MS. by apply/eqmxP/andP; rewrite !addsmx_sub -andbA andbA -!addsmx_sub. rewrite {1 3}[in @addsmx m1]unlock [in @addsmx n]unlock !addsmx_nop_id -!submx0. rewrite !addsmx_sub ![@addsmx]unlock -!submx0; move/eq_genmx. by do 3!case: (_ <= 0)%MS; rewrite //= !genmx_id. Qed. Canonical addsmx_monoid n := Monoid.Law (@addsmxA n n n n) (@adds0mx_id n n) (@addsmx0_id n n). Canonical addsmx_comoid n := Monoid.ComLaw (@addsmxC n n n). Lemma addsmxMr m1 m2 n p (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(n, p)) : ((A + B)%MS *m C :=: A *m C + B *m C)%MS. Proof. by apply/eqmxP; rewrite !addsmxE -!mul_col_mx !submxMr ?addsmxE. Qed. Lemma addsmxS m1 m2 m3 m4 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) (D : 'M_(m4, n)) : (A <= C -> B <= D -> A + B <= C + D)%MS. Proof. move=> sAC sBD. by rewrite addsmx_sub {1}addsmxC !(submx_trans _ (addsmxSr _ _)). Qed. Lemma addmx_sub_adds m m1 m2 n (A : 'M_(m, n)) (B : 'M_(m, n)) (C : 'M_(m1, n)) (D : 'M_(m2, n)) : (A <= C -> B <= D -> (A + B)%R <= C + D)%MS. Proof. move=> sAC; move/(addsmxS sAC); apply: submx_trans. by rewrite addmx_sub ?addsmxSl ?addsmxSr. Qed. Lemma addsmx_addKl n m1 m2 (A : 'M_(m1, n)) (B C : 'M_(m2, n)) : (B <= A)%MS -> (A + (B + C)%R :=: A + C)%MS. Proof. move=> sBA; apply/eqmxP; rewrite !addsmx_sub !addsmxSl. by rewrite -{3}[C](addKr B) !addmx_sub_adds ?eqmx_opp. Qed. Lemma addsmx_addKr n m1 m2 (A B : 'M_(m1, n)) (C : 'M_(m2, n)) : (B <= C)%MS -> ((A + B)%R + C :=: A + C)%MS. Proof. by rewrite -!(addsmxC C) addrC; exact: addsmx_addKl. Qed. Lemma adds_eqmx m1 m2 m3 m4 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) (D : 'M_(m4, n)) : (A :=: C -> B :=: D -> A + B :=: C + D)%MS. Proof. by move=> eqAC eqBD; apply/eqmxP; rewrite !addsmxS ?eqAC ?eqBD. Qed. Lemma genmx_adds m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (<<(A + B)%MS>> = <> + <>)%MS. Proof. rewrite -(eq_genmx (adds_eqmx (genmxE A) (genmxE B))). by rewrite [@addsmx]unlock !addsmx_nop_id !(fun_if (@genmx _ _)) !genmx_id. Qed. Lemma sub_addsmxP m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) : reflect (exists u, A = u.1 *m B + u.2 *m C) (A <= B + C)%MS. Proof. apply: (iffP idP) => [|[u ->]]; last by rewrite addmx_sub_adds ?submxMl. rewrite addsmxE; case/submxP=> u ->; exists (lsubmx u, rsubmx u). by rewrite -mul_row_col hsubmxK. Qed. Implicit Arguments sub_addsmxP [m1 m2 m3 n A B C]. Variable I : finType. Implicit Type P : pred I. Lemma genmx_sums P n (B_ : I -> 'M_n) : <<(\sum_(i | P i) B_ i)%MS>>%MS = (\sum_(i | P i) <>)%MS. Proof. exact: (big_morph _ (@genmx_adds n n n) (@genmx0 n n)). Qed. Lemma sumsmx_sup i0 P m n (A : 'M_(m, n)) (B_ : I -> 'M_n) : P i0 -> (A <= B_ i0)%MS -> (A <= \sum_(i | P i) B_ i)%MS. Proof. by move=> Pi0 sAB; apply: submx_trans sAB _; rewrite (bigD1 i0) // addsmxSl. Qed. Implicit Arguments sumsmx_sup [P m n A B_]. Lemma sumsmx_subP P m n (A_ : I -> 'M_n) (B : 'M_(m, n)) : reflect (forall i, P i -> A_ i <= B)%MS (\sum_(i | P i) A_ i <= B)%MS. Proof. apply: (iffP idP) => [sAB i Pi | sAB]. by apply: submx_trans sAB; apply: sumsmx_sup Pi _. by elim/big_rec: _ => [|i Ai Pi sAiB]; rewrite ?sub0mx // addsmx_sub sAB. Qed. Lemma summx_sub_sums P m n (A : I -> 'M[F]_(m, n)) B : (forall i, P i -> A i <= B i)%MS -> ((\sum_(i | P i) A i)%R <= \sum_(i | P i) B i)%MS. Proof. by move=> sAB; apply: summx_sub => i Pi; rewrite (sumsmx_sup i) ?sAB. Qed. Lemma sumsmxS P n (A B : I -> 'M[F]_n) : (forall i, P i -> A i <= B i)%MS -> (\sum_(i | P i) A i <= \sum_(i | P i) B i)%MS. Proof. by move=> sAB; apply/sumsmx_subP=> i Pi; rewrite (sumsmx_sup i) ?sAB. Qed. Lemma eqmx_sums P n (A B : I -> 'M[F]_n) : (forall i, P i -> A i :=: B i)%MS -> (\sum_(i | P i) A i :=: \sum_(i | P i) B i)%MS. Proof. by move=> eqAB; apply/eqmxP; rewrite !sumsmxS // => i; move/eqAB->. Qed. Lemma sub_sumsmxP P m n (A : 'M_(m, n)) (B_ : I -> 'M_n) : reflect (exists u_, A = \sum_(i | P i) u_ i *m B_ i) (A <= \sum_(i | P i) B_ i)%MS. Proof. apply: (iffP idP) => [| [u_ ->]]; last first. by apply: summx_sub_sums => i _; exact: submxMl. elim: {P}_.+1 {-2}P A (ltnSn #|P|) => // b IHb P A. case: (pickP P) => [i Pi | P0 _]; last first. rewrite big_pred0 //; move/submx0null->. by exists (fun _ => 0); rewrite big_pred0. rewrite (cardD1x Pi) (bigD1 i) //= => /IHb{b IHb} /= IHi /sub_addsmxP[u ->]. have [u_ ->] := IHi _ (submxMl u.2 _). exists [eta u_ with i |-> u.1]; rewrite (bigD1 i Pi) /= eqxx; congr (_ + _). by apply: eq_bigr => j /andP[_ /negPf->]. Qed. Lemma sumsmxMr_gen P m n A (B : 'M[F]_(m, n)) : ((\sum_(i | P i) A i)%MS *m B :=: \sum_(i | P i) <>)%MS. Proof. apply/eqmxP/andP; split; last first. by apply/sumsmx_subP=> i Pi; rewrite genmxE submxMr ?(sumsmx_sup i). have [u ->] := sub_sumsmxP _ _ _ (submx_refl (\sum_(i | P i) A i)%MS). by rewrite mulmx_suml summx_sub_sums // => i _; rewrite genmxE -mulmxA submxMl. Qed. Lemma sumsmxMr P n (A_ : I -> 'M[F]_n) (B : 'M_n) : ((\sum_(i | P i) A_ i)%MS *m B :=: \sum_(i | P i) (A_ i *m B))%MS. Proof. by apply: eqmx_trans (sumsmxMr_gen _ _ _) (eqmx_sums _) => i _; exact: genmxE. Qed. Lemma rank_pid_mx m n r : r <= m -> r <= n -> \rank (pid_mx r : 'M_(m, n)) = r. Proof. do 2!move/subnKC <-; rewrite pid_mx_block block_mxEv row_mx0 -addsmxE addsmx0. by rewrite -mxrank_tr tr_row_mx trmx0 trmx1 -addsmxE addsmx0 mxrank1. Qed. Lemma rank_copid_mx n r : r <= n -> \rank (copid_mx r : 'M_n) = (n - r)%N. Proof. move/subnKC <-; rewrite /copid_mx pid_mx_block scalar_mx_block. rewrite opp_block_mx !oppr0 add_block_mx !addr0 subrr block_mxEv row_mx0. rewrite -addsmxE adds0mx -mxrank_tr tr_row_mx trmx0 trmx1. by rewrite -addsmxE adds0mx mxrank1 addKn. Qed. Lemma mxrank_compl m n (A : 'M_(m, n)) : \rank A^C = (n - \rank A)%N. Proof. by rewrite mxrankMfree ?row_free_unit ?rank_copid_mx. Qed. Lemma mxrank_ker m n (A : 'M_(m, n)) : \rank (kermx A) = (m - \rank A)%N. Proof. by rewrite mxrankMfree ?row_free_unit ?unitmx_inv ?rank_copid_mx. Qed. Lemma kermx_eq0 n m (A : 'M_(m, n)) : (kermx A == 0) = row_free A. Proof. by rewrite -mxrank_eq0 mxrank_ker subn_eq0 row_leq_rank. Qed. Lemma mxrank_coker m n (A : 'M_(m, n)) : \rank (cokermx A) = (n - \rank A)%N. Proof. by rewrite eqmxMfull ?row_full_unit ?unitmx_inv ?rank_copid_mx. Qed. Lemma cokermx_eq0 n m (A : 'M_(m, n)) : (cokermx A == 0) = row_full A. Proof. by rewrite -mxrank_eq0 mxrank_coker subn_eq0 col_leq_rank. Qed. Lemma mulmx_ker m n (A : 'M_(m, n)) : kermx A *m A = 0. Proof. by rewrite -{2}[A]mulmx_ebase !mulmxA mulmxKV // mul_copid_mx_pid ?mul0mx. Qed. Lemma mulmxKV_ker m n p (A : 'M_(n, p)) (B : 'M_(m, n)) : B *m A = 0 -> B *m col_ebase A *m kermx A = B. Proof. rewrite mulmxA mulmxBr mulmx1 mulmxBl mulmxK //. rewrite -{1}[A]mulmx_ebase !mulmxA => /(canRL (mulmxK (row_ebase_unit A))). rewrite mul0mx // => BA0; apply: (canLR (addrK _)). by rewrite -(pid_mx_id _ _ n (rank_leq_col A)) mulmxA BA0 !mul0mx addr0. Qed. Lemma sub_kermxP p m n (A : 'M_(m, n)) (B : 'M_(p, m)) : reflect (B *m A = 0) (B <= kermx A)%MS. Proof. apply: (iffP submxP) => [[D ->]|]; first by rewrite -mulmxA mulmx_ker mulmx0. by move/mulmxKV_ker; exists (B *m col_ebase A). Qed. Lemma mulmx0_rank_max m n p (A : 'M_(m, n)) (B : 'M_(n, p)) : A *m B = 0 -> \rank A + \rank B <= n. Proof. move=> AB0; rewrite -{3}(subnK (rank_leq_row B)) leq_add2r. rewrite -mxrank_ker mxrankS //; exact/sub_kermxP. Qed. Lemma mxrank_Frobenius m n p q (A : 'M_(m, n)) B (C : 'M_(p, q)) : \rank (A *m B) + \rank (B *m C) <= \rank B + \rank (A *m B *m C). Proof. rewrite -{2}(mulmx_base (A *m B)) -mulmxA (eqmxMfull _ (col_base_full _)). set C2 := row_base _ *m C. rewrite -{1}(subnK (rank_leq_row C2)) -(mxrank_ker C2) addnAC leq_add2r. rewrite addnC -{1}(mulmx_base B) -mulmxA eqmxMfull //. set C1 := _ *m C; rewrite -{2}(subnKC (rank_leq_row C1)) leq_add2l -mxrank_ker. rewrite -(mxrankMfree _ (row_base_free (A *m B))). have: (row_base (A *m B) <= row_base B)%MS by rewrite !eq_row_base submxMl. case/submxP=> D defD; rewrite defD mulmxA mxrankMfree ?mxrankS //. by apply/sub_kermxP; rewrite -mulmxA (mulmxA D) -defD -/C2 mulmx_ker. Qed. Lemma mxrank_mul_min m n p (A : 'M_(m, n)) (B : 'M_(n, p)) : \rank A + \rank B - n <= \rank (A *m B). Proof. by have:= mxrank_Frobenius A 1%:M B; rewrite mulmx1 mul1mx mxrank1 leq_subLR. Qed. Lemma addsmx_compl_full m n (A : 'M_(m, n)) : row_full (A + A^C)%MS. Proof. rewrite /row_full addsmxE; apply/row_fullP. exists (row_mx (pinvmx A) (cokermx A)); rewrite mul_row_col. rewrite -{2}[A]mulmx_ebase -!mulmxA mulKmx // -mulmxDr !mulmxA. by rewrite pid_mx_id ?copid_mx_id // -mulmxDl addrC subrK mul1mx mulVmx. Qed. Lemma sub_capmx_gen m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) : (A <= capmx_gen B C)%MS = (A <= B)%MS && (A <= C)%MS. Proof. apply/idP/andP=> [sAI | [/submxP[B' ->{A}] /submxP[C' eqBC']]]. rewrite !(submx_trans sAI) ?submxMl // /capmx_gen. have:= mulmx_ker (col_mx B C); set K := kermx _. rewrite -{1}[K]hsubmxK mul_row_col; move/(canRL (addrK _))->. by rewrite add0r -mulNmx submxMl. have: (row_mx B' (- C') <= kermx (col_mx B C))%MS. by apply/sub_kermxP; rewrite mul_row_col eqBC' mulNmx subrr. case/submxP=> D; rewrite -[kermx _]hsubmxK mul_mx_row. by case/eq_row_mx=> -> _; rewrite -mulmxA submxMl. Qed. Let capmx_witnessP m n (A : 'M_(m, n)) : equivmx A (qidmx A) (capmx_witness A). Proof. rewrite /equivmx qidmx_eq1 /qidmx /capmx_witness. rewrite -sub1mx; case s1A: (1%:M <= A)%MS => /=; last first. rewrite !genmxE submx_refl /= -negb_add; apply: contra {s1A}(negbT s1A). case: eqP => [<- _| _]; first by rewrite genmxE. by case: eqP A => //= -> A; move/eqP->; rewrite pid_mx_1. case: (m =P n) => [-> | ne_mn] in A s1A *. by rewrite conform_mx_id submx_refl pid_mx_1 eqxx. by rewrite nonconform_mx ?submx1 ?s1A ?eqxx //; case: eqP. Qed. Let capmx_normP m n (A : 'M_(m, n)) : equivmx_spec A (qidmx A) (capmx_norm A). Proof. by case/andP: (chooseP (capmx_witnessP A)) => /eqmxP defN /eqP. Qed. Let capmx_norm_eq m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : qidmx A = qidmx B -> (A == B)%MS -> capmx_norm A = capmx_norm B. Proof. move=> eqABid /eqmxP eqAB. have{eqABid eqAB} eqAB: equivmx A (qidmx A) =1 equivmx B (qidmx B). by move=> C; rewrite /equivmx eqABid !eqAB. rewrite {1}/capmx_norm (eq_choose eqAB). by apply: choose_id; first rewrite -eqAB; exact: capmx_witnessP. Qed. Let capmx_nopP m n (A : 'M_(m, n)) : equivmx_spec A (qidmx A) (capmx_nop A). Proof. rewrite /capmx_nop; case: (eqVneq m n) => [-> | ne_mn] in A *. by rewrite conform_mx_id. rewrite nonconform_mx ?ne_mn //; exact: capmx_normP. Qed. Let sub_qidmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : qidmx B -> (A <= B)%MS. Proof. rewrite /qidmx => idB; apply: {A}submx_trans (submx1 A) _. by case: eqP B idB => [-> _ /eqP-> | _ B]; rewrite (=^~ sub1mx, pid_mx_1). Qed. Let qidmx_cap m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : qidmx (A :&: B)%MS = qidmx A && qidmx B. Proof. rewrite unlock -sub1mx. case idA: (qidmx A); case idB: (qidmx B); try by rewrite capmx_nopP. case s1B: (_ <= B)%MS; first by rewrite capmx_normP. apply/idP=> /(sub_qidmx 1%:M). by rewrite capmx_normP sub_capmx_gen s1B andbF. Qed. Let capmx_eq_norm m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : qidmx A = qidmx B -> (A :&: B)%MS = capmx_norm (A :&: B)%MS. Proof. move=> eqABid; rewrite unlock -sub1mx {}eqABid. have norm_id m (C : 'M_(m, n)) (N := capmx_norm C) : capmx_norm N = N. by apply: capmx_norm_eq; rewrite ?capmx_normP ?andbb. case idB: (qidmx B); last by case: ifP; rewrite norm_id. rewrite /capmx_nop; case: (eqVneq m2 n) => [-> | neqm2n] in B idB *. have idN := idB; rewrite -{1}capmx_normP !qidmx_eq1 in idN idB. by rewrite conform_mx_id (eqP idN) (eqP idB). by rewrite nonconform_mx ?neqm2n ?norm_id. Qed. Lemma capmxE m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :&: B :=: capmx_gen A B)%MS. Proof. rewrite unlock -sub1mx; apply/eqmxP. have:= submx_refl (capmx_gen A B); rewrite !sub_capmx_gen => /andP[sIA sIB]. case idA: (qidmx A); first by rewrite !capmx_nopP submx_refl sub_qidmx. case idB: (qidmx B); first by rewrite !capmx_nopP submx_refl sub_qidmx. case s1B: (1%:M <= B)%MS; rewrite !capmx_normP ?sub_capmx_gen sIA ?sIB //=. by rewrite submx_refl (submx_trans (submx1 _)). Qed. Lemma capmxSl m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :&: B <= A)%MS. Proof. by rewrite capmxE submxMl. Qed. Lemma sub_capmx m m1 m2 n (A : 'M_(m, n)) (B : 'M_(m1, n)) (C : 'M_(m2, n)) : (A <= B :&: C)%MS = (A <= B)%MS && (A <= C)%MS. Proof. by rewrite capmxE sub_capmx_gen. Qed. Lemma capmxC m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :&: B = B :&: A)%MS. Proof. have [eqAB|] := eqVneq (qidmx A) (qidmx B). rewrite (capmx_eq_norm eqAB) (capmx_eq_norm (esym eqAB)). apply: capmx_norm_eq; first by rewrite !qidmx_cap andbC. by apply/andP; split; rewrite !sub_capmx andbC -sub_capmx. by rewrite negb_eqb !unlock => /addbP <-; case: (qidmx A). Qed. Lemma capmxSr m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :&: B <= B)%MS. Proof. by rewrite capmxC capmxSl. Qed. Lemma capmx_idPr n m1 m2 (A : 'M_(m1, n)) (B : 'M_(m2, n)) : reflect (A :&: B :=: B)%MS (B <= A)%MS. Proof. have:= @eqmxP _ _ _ (A :&: B)%MS B. by rewrite capmxSr sub_capmx submx_refl !andbT. Qed. Lemma capmx_idPl n m1 m2 (A : 'M_(m1, n)) (B : 'M_(m2, n)) : reflect (A :&: B :=: A)%MS (A <= B)%MS. Proof. by rewrite capmxC; exact: capmx_idPr. Qed. Lemma capmxS m1 m2 m3 m4 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) (D : 'M_(m4, n)) : (A <= C -> B <= D -> A :&: B <= C :&: D)%MS. Proof. by move=> sAC sBD; rewrite sub_capmx {1}capmxC !(submx_trans (capmxSr _ _)). Qed. Lemma cap_eqmx m1 m2 m3 m4 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) (D : 'M_(m4, n)) : (A :=: C -> B :=: D -> A :&: B :=: C :&: D)%MS. Proof. by move=> eqAC eqBD; apply/eqmxP; rewrite !capmxS ?eqAC ?eqBD. Qed. Lemma capmxMr m1 m2 n p (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(n, p)) : ((A :&: B) *m C <= A *m C :&: B *m C)%MS. Proof. by rewrite sub_capmx !submxMr ?capmxSl ?capmxSr. Qed. Lemma cap0mx m1 m2 n (A : 'M_(m2, n)) : ((0 : 'M_(m1, n)) :&: A)%MS = 0. Proof. exact: submx0null (capmxSl _ _). Qed. Lemma capmx0 m1 m2 n (A : 'M_(m1, n)) : (A :&: (0 : 'M_(m2, n)))%MS = 0. Proof. exact: submx0null (capmxSr _ _). Qed. Lemma capmxT m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : row_full B -> (A :&: B :=: A)%MS. Proof. rewrite -sub1mx => s1B; apply/eqmxP. by rewrite capmxSl sub_capmx submx_refl (submx_trans (submx1 A)). Qed. Lemma capTmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : row_full A -> (A :&: B :=: B)%MS. Proof. by move=> Afull; apply/eqmxP; rewrite capmxC !capmxT ?andbb. Qed. Let capmx_nop_id n (A : 'M_n) : capmx_nop A = A. Proof. by rewrite /capmx_nop conform_mx_id. Qed. Lemma cap1mx n (A : 'M_n) : (1%:M :&: A = A)%MS. Proof. by rewrite unlock qidmx_eq1 eqxx capmx_nop_id. Qed. Lemma capmx1 n (A : 'M_n) : (A :&: 1%:M = A)%MS. Proof. by rewrite capmxC cap1mx. Qed. Lemma genmx_cap m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : <>%MS = (<> :&: <>)%MS. Proof. rewrite -(eq_genmx (cap_eqmx (genmxE A) (genmxE B))). case idAB: (qidmx <> || qidmx <>)%MS. rewrite [@capmx]unlock !capmx_nop_id !(fun_if (@genmx _ _)) !genmx_id. by case: (qidmx _) idAB => //= ->. case idA: (qidmx _) idAB => //= idB; rewrite {2}capmx_eq_norm ?idA //. set C := (_ :&: _)%MS; have eq_idC: row_full C = qidmx C. rewrite qidmx_cap idA -sub1mx sub_capmx genmxE; apply/andP=> [[s1A]]. by case/idP: idA; rewrite qidmx_eq1 -genmx1 (sameP eqP genmxP) submx1. rewrite unlock /capmx_norm eq_idC. by apply: choose_id (capmx_witnessP _); rewrite -eq_idC genmx_witnessP. Qed. Lemma capmxA m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) : (A :&: (B :&: C) = A :&: B :&: C)%MS. Proof. rewrite (capmxC A B) capmxC; wlog idA: m1 m3 A C / qidmx A. move=> IH; case idA: (qidmx A); first exact: IH. case idC: (qidmx C); first by rewrite -IH. rewrite (@capmx_eq_norm n m3) ?qidmx_cap ?idA ?idC ?andbF //. rewrite capmx_eq_norm ?qidmx_cap ?idA ?idC ?andbF //. apply: capmx_norm_eq; first by rewrite !qidmx_cap andbAC. by apply/andP; split; rewrite !sub_capmx andbAC -!sub_capmx. rewrite -!(capmxC A) [in @capmx m1]unlock idA capmx_nop_id. have [eqBC |] :=eqVneq (qidmx B) (qidmx C). rewrite (@capmx_eq_norm n) ?capmx_nopP // capmx_eq_norm //. by apply: capmx_norm_eq; rewrite ?qidmx_cap ?capmxS ?capmx_nopP. by rewrite !unlock capmx_nopP capmx_nop_id; do 2?case: (qidmx _) => //. Qed. Canonical capmx_monoid n := Monoid.Law (@capmxA n n n n) (@cap1mx n) (@capmx1 n). Canonical capmx_comoid n := Monoid.ComLaw (@capmxC n n n). Lemma bigcapmx_inf i0 P m n (A_ : I -> 'M_n) (B : 'M_(m, n)) : P i0 -> (A_ i0 <= B -> \bigcap_(i | P i) A_ i <= B)%MS. Proof. by move=> Pi0; apply: submx_trans; rewrite (bigD1 i0) // capmxSl. Qed. Lemma sub_bigcapmxP P m n (A : 'M_(m, n)) (B_ : I -> 'M_n) : reflect (forall i, P i -> A <= B_ i)%MS (A <= \bigcap_(i | P i) B_ i)%MS. Proof. apply: (iffP idP) => [sAB i Pi | sAB]. by apply: (submx_trans sAB); rewrite (bigcapmx_inf Pi). by elim/big_rec: _ => [|i Pi C sAC]; rewrite ?submx1 // sub_capmx sAB. Qed. Lemma genmx_bigcap P n (A_ : I -> 'M_n) : (<<\bigcap_(i | P i) A_ i>> = \bigcap_(i | P i) <>)%MS. Proof. exact: (big_morph _ (@genmx_cap n n n) (@genmx1 n)). Qed. Lemma matrix_modl m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) : (A <= C -> A + (B :&: C) :=: (A + B) :&: C)%MS. Proof. move=> sAC; set D := ((A + B) :&: C)%MS; apply/eqmxP. rewrite sub_capmx addsmxS ?capmxSl // addsmx_sub sAC capmxSr /=. have: (D <= B + A)%MS by rewrite addsmxC capmxSl. case/sub_addsmxP=> u defD; rewrite defD addrC addmx_sub_adds ?submxMl //. rewrite sub_capmx submxMl -[_ *m B](addrK (u.2 *m A)) -defD. by rewrite addmx_sub ?capmxSr // eqmx_opp mulmx_sub. Qed. Lemma matrix_modr m1 m2 m3 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) (C : 'M_(m3, n)) : (C <= A -> (A :&: B) + C :=: A :&: (B + C))%MS. Proof. by rewrite !(capmxC A) -!(addsmxC C); exact: matrix_modl. Qed. Lemma capmx_compl m n (A : 'M_(m, n)) : (A :&: A^C)%MS = 0. Proof. set D := (A :&: A^C)%MS; have: (D <= D)%MS by []. rewrite sub_capmx andbC => /andP[/submxP[B defB]]. rewrite submxE => /eqP; rewrite defB -!mulmxA mulKVmx ?copid_mx_id //. by rewrite mulmxA => ->; rewrite mul0mx. Qed. Lemma mxrank_mul_ker m n p (A : 'M_(m, n)) (B : 'M_(n, p)) : (\rank (A *m B) + \rank (A :&: kermx B))%N = \rank A. Proof. apply/eqP; set K := kermx B; set C := (A :&: K)%MS. rewrite -(eqmxMr B (eq_row_base A)); set K' := _ *m B. rewrite -{2}(subnKC (rank_leq_row K')) -mxrank_ker eqn_add2l. rewrite -(mxrankMfree _ (row_base_free A)) mxrank_leqif_sup. rewrite sub_capmx -(eq_row_base A) submxMl. by apply/sub_kermxP; rewrite -mulmxA mulmx_ker. have /submxP[C' defC]: (C <= row_base A)%MS by rewrite eq_row_base capmxSl. rewrite defC submxMr //; apply/sub_kermxP. by rewrite mulmxA -defC; apply/sub_kermxP; rewrite capmxSr. Qed. Lemma mxrank_injP m n p (A : 'M_(m, n)) (f : 'M_(n, p)) : reflect (\rank (A *m f) = \rank A) ((A :&: kermx f)%MS == 0). Proof. rewrite -mxrank_eq0 -(eqn_add2l (\rank (A *m f))). by rewrite mxrank_mul_ker addn0 eq_sym; exact: eqP. Qed. Lemma mxrank_disjoint_sum m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :&: B)%MS = 0 -> \rank (A + B)%MS = (\rank A + \rank B)%N. Proof. move=> AB0; pose Ar := row_base A; pose Br := row_base B. have [Afree Bfree]: row_free Ar /\ row_free Br by rewrite !row_base_free. have: (Ar :&: Br <= A :&: B)%MS by rewrite capmxS ?eq_row_base. rewrite {}AB0 submx0 -mxrank_eq0 capmxE mxrankMfree //. set Cr := col_mx Ar Br; set Crl := lsubmx _; rewrite mxrank_eq0 => /eqP Crl0. rewrite -(adds_eqmx (eq_row_base _) (eq_row_base _)) addsmxE -/Cr. suffices K0: kermx Cr = 0. by apply/eqP; rewrite eqn_leq rank_leq_row -subn_eq0 -mxrank_ker K0 mxrank0. move/eqP: (mulmx_ker Cr); rewrite -[kermx Cr]hsubmxK mul_row_col -/Crl Crl0. rewrite mul0mx add0r -mxrank_eq0 mxrankMfree // mxrank_eq0 => /eqP->. exact: row_mx0. Qed. Lemma diffmxE m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :\: B :=: A :&: (capmx_gen A B)^C)%MS. Proof. by rewrite unlock; apply/eqmxP; rewrite !genmxE !capmxE andbb. Qed. Lemma genmx_diff m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (<> = A :\: B)%MS. Proof. by rewrite [@diffmx]unlock genmx_id. Qed. Lemma diffmxSl m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :\: B <= A)%MS. Proof. by rewrite diffmxE capmxSl. Qed. Lemma capmx_diff m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : ((A :\: B) :&: B)%MS = 0. Proof. apply/eqP; pose C := capmx_gen A B; rewrite -submx0 -(capmx_compl C). by rewrite sub_capmx -capmxE sub_capmx andbAC -sub_capmx -diffmxE -sub_capmx. Qed. Lemma addsmx_diff_cap_eq m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :\: B + A :&: B :=: A)%MS. Proof. apply/eqmxP; rewrite addsmx_sub capmxSl diffmxSl /=. set C := (A :\: B)%MS; set D := capmx_gen A B. suffices sACD: (A <= C + D)%MS. by rewrite (submx_trans sACD) ?addsmxS ?capmxE. have:= addsmx_compl_full D; rewrite /row_full addsmxE. case/row_fullP=> U /(congr1 (mulmx A)); rewrite mulmx1. rewrite -[U]hsubmxK mul_row_col mulmxDr addrC 2!mulmxA. set V := _ *m _ => defA; rewrite -defA; move/(canRL (addrK _)): defA => defV. suffices /submxP[W ->]: (V <= C)%MS by rewrite -mul_row_col addsmxE submxMl. rewrite diffmxE sub_capmx {1}defV -mulNmx addmx_sub 1?mulmx_sub //. by rewrite -capmxE capmxSl. Qed. Lemma mxrank_cap_compl m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (\rank (A :&: B) + \rank (A :\: B))%N = \rank A. Proof. rewrite addnC -mxrank_disjoint_sum ?addsmx_diff_cap_eq //. by rewrite (capmxC A) capmxA capmx_diff cap0mx. Qed. Lemma mxrank_sum_cap m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (\rank (A + B) + \rank (A :&: B) = \rank A + \rank B)%N. Proof. set C := (A :&: B)%MS; set D := (A :\: B)%MS. have rDB: \rank (A + B)%MS = \rank (D + B)%MS. apply/eqP; rewrite mxrank_leqif_sup; first by rewrite addsmxS ?diffmxSl. by rewrite addsmx_sub addsmxSr -(addsmx_diff_cap_eq A B) addsmxS ?capmxSr. rewrite {1}rDB mxrank_disjoint_sum ?capmx_diff //. by rewrite addnC addnA mxrank_cap_compl. Qed. Lemma mxrank_adds_leqif m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : \rank (A + B) <= \rank A + \rank B ?= iff (A :&: B <= (0 : 'M_n))%MS. Proof. rewrite -mxrank_sum_cap; split; first exact: leq_addr. by rewrite addnC (@eqn_add2r _ 0) eq_sym mxrank_eq0 -submx0. Qed. (* Subspace projection matrix *) Lemma proj_mx_sub m n U V (W : 'M_(m, n)) : (W *m proj_mx U V <= U)%MS. Proof. by rewrite !mulmx_sub // -addsmxE addsmx0. Qed. Lemma proj_mx_compl_sub m n U V (W : 'M_(m, n)) : (W <= U + V -> W - W *m proj_mx U V <= V)%MS. Proof. rewrite addsmxE => sWUV; rewrite mulmxA -{1}(mulmxKpV sWUV) -mulmxBr. by rewrite mulmx_sub // opp_col_mx add_col_mx subrr subr0 -addsmxE adds0mx. Qed. Lemma proj_mx_id m n U V (W : 'M_(m, n)) : (U :&: V = 0)%MS -> (W <= U)%MS -> W *m proj_mx U V = W. Proof. move=> dxUV sWU; apply/eqP; rewrite -subr_eq0 -submx0 -dxUV. rewrite sub_capmx addmx_sub ?eqmx_opp ?proj_mx_sub //= -eqmx_opp opprB. by rewrite proj_mx_compl_sub // (submx_trans sWU) ?addsmxSl. Qed. Lemma proj_mx_0 m n U V (W : 'M_(m, n)) : (U :&: V = 0)%MS -> (W <= V)%MS -> W *m proj_mx U V = 0. Proof. move=> dxUV sWV; apply/eqP; rewrite -submx0 -dxUV. rewrite sub_capmx proj_mx_sub /= -[_ *m _](subrK W) addmx_sub // -eqmx_opp. by rewrite opprB proj_mx_compl_sub // (submx_trans sWV) ?addsmxSr. Qed. Lemma add_proj_mx m n U V (W : 'M_(m, n)) : (U :&: V = 0)%MS -> (W <= U + V)%MS -> W *m proj_mx U V + W *m proj_mx V U = W. Proof. move=> dxUV sWUV; apply/eqP; rewrite -subr_eq0 -submx0 -dxUV. rewrite -addrA sub_capmx {2}addrCA -!(opprB W). by rewrite !{1}addmx_sub ?proj_mx_sub ?eqmx_opp ?proj_mx_compl_sub // addsmxC. Qed. Lemma proj_mx_proj n (U V : 'M_n) : let P := proj_mx U V in (U :&: V = 0)%MS -> P *m P = P. Proof. by move=> P dxUV; rewrite -{-2}[P]mul1mx proj_mx_id ?proj_mx_sub. Qed. (* Completing a partially injective matrix to get a unit matrix. *) Lemma complete_unitmx m n (U : 'M_(m, n)) (f : 'M_n) : \rank (U *m f) = \rank U -> {g : 'M_n | g \in unitmx & U *m f = U *m g}. Proof. move=> injfU; pose V := <>%MS; pose W := V *m f. pose g := proj_mx V (V^C)%MS *m f + cokermx V *m row_ebase W. have defW: V *m g = W. rewrite mulmxDr mulmxA proj_mx_id ?genmxE ?capmx_compl //. by rewrite mulmxA mulmx_coker mul0mx addr0. exists g; last first. have /submxP[u ->]: (U <= V)%MS by rewrite genmxE. by rewrite -!mulmxA defW. rewrite -row_full_unit -sub1mx; apply/submxP. have: (invmx (col_ebase W) *m W <= V *m g)%MS by rewrite defW submxMl. case/submxP=> v def_v; exists (invmx (row_ebase W) *m (v *m V + (V^C)%MS)). rewrite -mulmxA mulmxDl -mulmxA -def_v -{3}[W]mulmx_ebase -mulmxA. rewrite mulKmx ?col_ebase_unit // [_ *m g]mulmxDr mulmxA. rewrite (proj_mx_0 (capmx_compl _)) // mul0mx add0r 2!mulmxA. rewrite mulmxK ?row_ebase_unit // copid_mx_id ?rank_leq_row //. rewrite (eqmxMr _ (genmxE U)) injfU genmxE addrC -mulmxDl subrK. by rewrite mul1mx mulVmx ?row_ebase_unit. Qed. (* Mapping between two subspaces with the same dimension. *) Lemma eq_rank_unitmx m1 m2 n (U : 'M_(m1, n)) (V : 'M_(m2, n)) : \rank U = \rank V -> {f : 'M_n | f \in unitmx & V :=: U *m f}%MS. Proof. move=> eqrUV; pose f := invmx (row_ebase <>%MS) *m row_ebase <>%MS. have defUf: (<> *m f :=: <>)%MS. rewrite -[<>%MS]mulmx_ebase mulmxA mulmxK ?row_ebase_unit // -mulmxA. rewrite genmxE eqrUV -genmxE -{3}[<>%MS]mulmx_ebase -mulmxA. move: (pid_mx _ *m _) => W; apply/eqmxP. by rewrite !eqmxMfull ?andbb // row_full_unit col_ebase_unit. have{defUf} defV: (V :=: U *m f)%MS. by apply/eqmxP; rewrite -!(eqmxMr f (genmxE U)) !defUf !genmxE andbb. have injfU: \rank (U *m f) = \rank U by rewrite -defV eqrUV. by have [g injg defUg] := complete_unitmx injfU; exists g; rewrite -?defUg. Qed. Section SumExpr. (* This is the infrastructure to support the mxdirect predicate. We use a *) (* bespoke canonical structure to decompose a matrix expression into binary *) (* and n-ary products, using some of the "quote" technology. This lets us *) (* characterize direct sums as set sums whose rank is equal to the sum of the *) (* ranks of the individual terms. The mxsum_expr/proper_mxsum_expr structures *) (* below supply both the decomposition and the calculation of the rank sum. *) (* The mxsum_spec dependent predicate family expresses the consistency of *) (* these two decompositions. *) (* The main technical difficulty we need to overcome is the fact that *) (* the "catch-all" case of canonical structures has a priority lower than *) (* constant expansion. However, it is undesireable that local abbreviations *) (* be opaque for the direct-sum predicate, e.g., not be able to handle *) (* let S := (\sum_(i | P i) LargeExpression i)%MS in mxdirect S -> ...). *) (* As in "quote", we use the interleaving of constant expansion and *) (* canonical projection matching to achieve our goal: we use a "wrapper" type *) (* (indeed, the wrapped T type defined in ssrfun.v) with a self-inserting *) (* non-primitive constructor to gain finer control over the type and *) (* structure inference process. The innermost, primitive, constructor flags *) (* trivial sums; it is initially hidden by an eta-expansion, which has been *) (* made into a (default) canonical structure -- this lets type inference *) (* automatically insert this outer tag. *) (* In detail, we define three types *) (* mxsum_spec S r <-> There exists a finite list of matrices A1, ..., Ak *) (* such that S is the set sum of the Ai, and r is the sum *) (* of the ranks of the Ai, i.e., S = (A1 + ... + Ak)%MS *) (* and r = \rank A1 + ... + \rank Ak. Note that *) (* mxsum_spec is a recursive dependent predicate family *) (* whose elimination rewrites simultaneaously S, r and *) (* the height of S. *) (* proper_mxsum_expr n == The interface for proper sum expressions; this is *) (* a double-entry interface, keyed on both the matrix sum *) (* value and the rank sum. The matrix value is restricted *) (* to square matrices, as the "+"%MS operator always *) (* returns a square matrix. This interface has two *) (* canonical insances, for binary and n-ary sums. *) (* mxsum_expr m n == The interface for general sum expressions, comprising *) (* both proper sums and trivial sums consisting of a *) (* single matrix. The key values are WRAPPED as this lets *) (* us give priority to the "proper sum" interpretation *) (* (see below). To allow for trivial sums, the matrix key *) (* can have any dimension. The mxsum_expr interface has *) (* two canonical instances, for trivial and proper sums, *) (* keyed to the Wrap and wrap constructors, respectively. *) (* The projections for the two interfaces above are *) (* proper_mxsum_val, mxsum_val : these are respectively coercions to 'M_n *) (* and wrapped 'M_(m, n); thus, the matrix sum for an *) (* S : mxsum_expr m n can be written unwrap S. *) (* proper_mxsum_rank, mxsum_rank : projections to the nat and wrapped nat, *) (* respectively; the rank sum for S : mxsum_expr m n is *) (* thus written unwrap (mxsum_rank S). *) (* The mxdirect A predicate actually gets A in a phantom argument, which is *) (* used to infer an (implicit) S : mxsum_expr such that unwrap S = A; the *) (* actual definition is \rank (unwrap S) == unwrap (mxsum_rank S). *) (* Note that the inference of S is inherently ambiguous: ANY matrix can be *) (* viewed as a trivial sum, including one whose description is manifestly a *) (* proper sum. We use the wrapped type and the interaction between delta *) (* reduction and canonical structure inference to resolve this ambiguity in *) (* favor of proper sums, as follows: *) (* - The phantom type sets up a unification problem of the form *) (* unwrap (mxsum_val ?S) = A *) (* with unknown evar ?S : mxsum_expr m n. *) (* - As the constructor wrap is also a default Canonical instance for the *) (* wrapped type, so A is immediately replaced with unwrap (wrap A) and *) (* we get the residual unification problem *) (* mxsum_val ?S = wrap A *) (* - Now Coq tries to apply the proper sum Canonical instance, which has *) (* key projection wrap (proper_mxsum_val ?PS) where ?PS is a fresh evar *) (* (of type proper_mxsum_expr n). This can only succeed if m = n, and if *) (* a solution can be found to the recursive unification problem *) (* proper_mxsum_val ?PS = A *) (* This causes Coq to look for one of the two canonical constants for *) (* proper_mxsum_val (addsmx or bigop) at the head of A, delta-expanding *) (* A as needed, and then inferring recursively mxsum_expr structures for *) (* the last argument(s) of that constant. *) (* - If the above step fails then the wrap constant is expanded, revealing *) (* the primitive Wrap constructor; the unification problem now becomes *) (* mxsum_val ?S = Wrap A *) (* which fits perfectly the trivial sum canonical structure, whose key *) (* projection is Wrap ?B where ?B is a fresh evar. Thus the inference *) (* succeeds, and returns the trivial sum. *) (* Note that the rank projections also register canonical values, so that the *) (* same process can be used to infer a sum structure from the rank sum. In *) (* that case, however, there is no ambiguity and the inference can fail, *) (* because the rank sum for a trivial sum is not an arbitrary integer -- it *) (* must be of the form \rank ?B. It is nevertheless necessary to use the *) (* wrapped nat type for the rank sums, because in the non-trivial case the *) (* head constant of the nat expression is determined by the proper_mxsum_expr *) (* canonical structure, so the mxsum_expr structure must use a generic *) (* constant, namely wrap. *) Inductive mxsum_spec n : forall m, 'M[F]_(m, n) -> nat -> Prop := | TrivialMxsum m A : @mxsum_spec n m A (\rank A) | ProperMxsum m1 m2 T1 T2 r1 r2 of @mxsum_spec n m1 T1 r1 & @mxsum_spec n m2 T2 r2 : mxsum_spec (T1 + T2)%MS (r1 + r2)%N. Arguments Scope mxsum_spec [nat_scope nat_scope matrix_set_scope nat_scope]. Structure mxsum_expr m n := Mxsum { mxsum_val :> wrapped 'M_(m, n); mxsum_rank : wrapped nat; _ : mxsum_spec (unwrap mxsum_val) (unwrap mxsum_rank) }. Canonical trivial_mxsum m n A := @Mxsum m n (Wrap A) (Wrap (\rank A)) (TrivialMxsum A). Structure proper_mxsum_expr n := ProperMxsumExpr { proper_mxsum_val :> 'M_n; proper_mxsum_rank : nat; _ : mxsum_spec proper_mxsum_val proper_mxsum_rank }. Definition proper_mxsumP n (S : proper_mxsum_expr n) := let: ProperMxsumExpr _ _ termS := S return mxsum_spec S (proper_mxsum_rank S) in termS. Canonical sum_mxsum n (S : proper_mxsum_expr n) := @Mxsum n n (wrap (S : 'M_n)) (wrap (proper_mxsum_rank S)) (proper_mxsumP S). Section Binary. Variable (m1 m2 n : nat) (S1 : mxsum_expr m1 n) (S2 : mxsum_expr m2 n). Fact binary_mxsum_proof : mxsum_spec (unwrap S1 + unwrap S2) (unwrap (mxsum_rank S1) + unwrap (mxsum_rank S2)). Proof. by case: S1 S2 => [A1 r1 A1P] [A2 r2 A2P]; right. Qed. Canonical binary_mxsum_expr := ProperMxsumExpr binary_mxsum_proof. End Binary. Section Nary. Context J (r : seq J) (P : pred J) n (S_ : J -> mxsum_expr n n). Fact nary_mxsum_proof : mxsum_spec (\sum_(j <- r | P j) unwrap (S_ j)) (\sum_(j <- r | P j) unwrap (mxsum_rank (S_ j))). Proof. elim/big_rec2: _ => [|j]; first by rewrite -(mxrank0 n n); left. by case: (S_ j); right. Qed. Canonical nary_mxsum_expr := ProperMxsumExpr nary_mxsum_proof. End Nary. Definition mxdirect_def m n T of phantom 'M_(m, n) (unwrap (mxsum_val T)) := \rank (unwrap T) == unwrap (mxsum_rank T). End SumExpr. Notation mxdirect A := (mxdirect_def (Phantom 'M_(_,_) A%MS)). Lemma mxdirectP n (S : proper_mxsum_expr n) : reflect (\rank S = proper_mxsum_rank S) (mxdirect S). Proof. exact: eqnP. Qed. Implicit Arguments mxdirectP [n S]. Lemma mxdirect_trivial m n A : mxdirect (unwrap (@trivial_mxsum m n A)). Proof. exact: eqxx. Qed. Lemma mxrank_sum_leqif m n (S : mxsum_expr m n) : \rank (unwrap S) <= unwrap (mxsum_rank S) ?= iff mxdirect (unwrap S). Proof. rewrite /mxdirect_def; case: S => [[A] [r] /= defAr]; split=> //=. elim: m A r / defAr => // m1 m2 A1 A2 r1 r2 _ leAr1 _ leAr2. by apply: leq_trans (leq_add leAr1 leAr2); rewrite mxrank_adds_leqif. Qed. Lemma mxdirectE m n (S : mxsum_expr m n) : mxdirect (unwrap S) = (\rank (unwrap S) == unwrap (mxsum_rank S)). Proof. by []. Qed. Lemma mxdirectEgeq m n (S : mxsum_expr m n) : mxdirect (unwrap S) = (\rank (unwrap S) >= unwrap (mxsum_rank S)). Proof. by rewrite (geq_leqif (mxrank_sum_leqif S)). Qed. Section BinaryDirect. Variables m1 m2 n : nat. Lemma mxdirect_addsE (S1 : mxsum_expr m1 n) (S2 : mxsum_expr m2 n) : mxdirect (unwrap S1 + unwrap S2) = [&& mxdirect (unwrap S1), mxdirect (unwrap S2) & unwrap S1 :&: unwrap S2 == 0]%MS. Proof. rewrite (@mxdirectE n) /=. have:= leqif_add (mxrank_sum_leqif S1) (mxrank_sum_leqif S2). move/(leqif_trans (mxrank_adds_leqif (unwrap S1) (unwrap S2)))=> ->. by rewrite andbC -andbA submx0. Qed. Lemma mxdirect_addsP (A : 'M_(m1, n)) (B : 'M_(m2, n)) : reflect (A :&: B = 0)%MS (mxdirect (A + B)). Proof. by rewrite mxdirect_addsE !mxdirect_trivial; exact: eqP. Qed. End BinaryDirect. Section NaryDirect. Variables (P : pred I) (n : nat). Let TIsum A_ i := (A_ i :&: (\sum_(j | P j && (j != i)) A_ j) = 0 :> 'M_n)%MS. Let mxdirect_sums_recP (S_ : I -> mxsum_expr n n) : reflect (forall i, P i -> mxdirect (unwrap (S_ i)) /\ TIsum (unwrap \o S_) i) (mxdirect (\sum_(i | P i) (unwrap (S_ i)))). Proof. rewrite /TIsum; apply: (iffP eqnP) => /= [dxS i Pi | dxS]. set Si' := (\sum_(j | _) unwrap (S_ j))%MS. have: mxdirect (unwrap (S_ i) + Si') by apply/eqnP; rewrite /= -!(bigD1 i). by rewrite mxdirect_addsE => /and3P[-> _ /eqP]. elim: _.+1 {-2 4}P (subxx P) (ltnSn #|P|) => // m IHm Q; move/subsetP=> sQP. case: (pickP Q) => [i Qi | Q0]; last by rewrite !big_pred0 ?mxrank0. rewrite (cardD1x Qi) !((bigD1 i) Q) //=. move/IHm=> <- {IHm}/=; last by apply/subsetP=> j /andP[/sQP]. case: (dxS i (sQP i Qi)) => /eqnP=> <- TiQ_0; rewrite mxrank_disjoint_sum //. apply/eqP; rewrite -submx0 -{2}TiQ_0 capmxS //=. by apply/sumsmx_subP=> j /= /andP[Qj i'j]; rewrite (sumsmx_sup j) ?[P j]sQP. Qed. Lemma mxdirect_sumsP (A_ : I -> 'M_n) : reflect (forall i, P i -> A_ i :&: (\sum_(j | P j && (j != i)) A_ j) = 0)%MS (mxdirect (\sum_(i | P i) A_ i)). Proof. apply: (iffP (mxdirect_sums_recP _)) => dxA i /dxA; first by case. by rewrite mxdirect_trivial. Qed. Lemma mxdirect_sumsE (S_ : I -> mxsum_expr n n) (xunwrap := unwrap) : reflect (and (forall i, P i -> mxdirect (unwrap (S_ i))) (mxdirect (\sum_(i | P i) (xunwrap (S_ i))))) (mxdirect (\sum_(i | P i) (unwrap (S_ i)))). Proof. apply: (iffP (mxdirect_sums_recP _)) => [dxS | [dxS_ dxS] i Pi]. by do [split; last apply/mxdirect_sumsP] => i; case/dxS. by split; [exact: dxS_ | exact: mxdirect_sumsP Pi]. Qed. End NaryDirect. Section SubDaddsmx. Variables m m1 m2 n : nat. Variables (A : 'M[F]_(m, n)) (B1 : 'M[F]_(m1, n)) (B2 : 'M[F]_(m2, n)). CoInductive sub_daddsmx_spec : Prop := SubDaddsmxSpec A1 A2 of (A1 <= B1)%MS & (A2 <= B2)%MS & A = A1 + A2 & forall C1 C2, (C1 <= B1)%MS -> (C2 <= B2)%MS -> A = C1 + C2 -> C1 = A1 /\ C2 = A2. Lemma sub_daddsmx : (B1 :&: B2 = 0)%MS -> (A <= B1 + B2)%MS -> sub_daddsmx_spec. Proof. move=> dxB /sub_addsmxP[u defA]. exists (u.1 *m B1) (u.2 *m B2); rewrite ?submxMl // => C1 C2 sCB1 sCB2. move/(canLR (addrK _)) => defC1. suffices: (C2 - u.2 *m B2 <= B1 :&: B2)%MS. by rewrite dxB submx0 subr_eq0 -defC1 defA; move/eqP->; rewrite addrK. rewrite sub_capmx -opprB -{1}(canLR (addKr _) defA) -addrA defC1. by rewrite !(eqmx_opp, addmx_sub) ?submxMl. Qed. End SubDaddsmx. Section SubDsumsmx. Variables (P : pred I) (m n : nat) (A : 'M[F]_(m, n)) (B : I -> 'M[F]_n). CoInductive sub_dsumsmx_spec : Prop := SubDsumsmxSpec A_ of forall i, P i -> (A_ i <= B i)%MS & A = \sum_(i | P i) A_ i & forall C, (forall i, P i -> C i <= B i)%MS -> A = \sum_(i | P i) C i -> {in SimplPred P, C =1 A_}. Lemma sub_dsumsmx : mxdirect (\sum_(i | P i) B i) -> (A <= \sum_(i | P i) B i)%MS -> sub_dsumsmx_spec. Proof. move/mxdirect_sumsP=> dxB /sub_sumsmxP[u defA]. pose A_ i := u i *m B i. exists A_ => //= [i _ | C sCB defAC i Pi]; first exact: submxMl. apply/eqP; rewrite -subr_eq0 -submx0 -{dxB}(dxB i Pi) /=. rewrite sub_capmx addmx_sub ?eqmx_opp ?submxMl ?sCB //=. rewrite -(subrK A (C i)) -addrA -opprB addmx_sub ?eqmx_opp //. rewrite addrC defAC (bigD1 i) // addKr /= summx_sub // => j Pi'j. by rewrite (sumsmx_sup j) ?sCB //; case/andP: Pi'j. rewrite addrC defA (bigD1 i) // addKr /= summx_sub // => j Pi'j. by rewrite (sumsmx_sup j) ?submxMl. Qed. End SubDsumsmx. Section Eigenspace. Variables (n : nat) (g : 'M_n). Definition eigenspace a := kermx (g - a%:M). Definition eigenvalue : pred F := fun a => eigenspace a != 0. Lemma eigenspaceP a m (W : 'M_(m, n)) : reflect (W *m g = a *: W) (W <= eigenspace a)%MS. Proof. rewrite (sameP (sub_kermxP _ _) eqP). by rewrite mulmxBr subr_eq0 mul_mx_scalar; exact: eqP. Qed. Lemma eigenvalueP a : reflect (exists2 v : 'rV_n, v *m g = a *: v & v != 0) (eigenvalue a). Proof. by apply: (iffP (rowV0Pn _)) => [] [v]; move/eigenspaceP; exists v. Qed. Lemma mxdirect_sum_eigenspace (P : pred I) a_ : {in P &, injective a_} -> mxdirect (\sum_(i | P i) eigenspace (a_ i)). Proof. elim: {P}_.+1 {-2}P (ltnSn #|P|) => // m IHm P lePm inj_a. apply/mxdirect_sumsP=> i Pi; apply/eqP/rowV0P => v. rewrite sub_capmx => /andP[/eigenspaceP def_vg]. set Vi' := (\sum_(i | _) _)%MS => Vi'v. have dxVi': mxdirect Vi'. rewrite (cardD1x Pi) in lePm; apply: IHm => //. by apply: sub_in2 inj_a => j /andP[]. case/sub_dsumsmx: Vi'v => // u Vi'u def_v _. rewrite def_v big1 // => j Pi'j; apply/eqP. have nz_aij: a_ i - a_ j != 0. by case/andP: Pi'j => Pj ne_ji; rewrite subr_eq0 eq_sym (inj_in_eq inj_a). case: (sub_dsumsmx dxVi' (sub0mx 1 _)) => C _ _ uniqC. rewrite -(eqmx_eq0 (eqmx_scale _ nz_aij)). rewrite (uniqC (fun k => (a_ i - a_ k) *: u k)) => // [|k Pi'k|]. - by rewrite -(uniqC (fun _ => 0)) ?big1 // => k Pi'k; exact: sub0mx. - by rewrite scalemx_sub ?Vi'u. rewrite -{1}(subrr (v *m g)) {1}def_vg def_v scaler_sumr mulmx_suml -sumrB. by apply: eq_bigr => k /Vi'u/eigenspaceP->; rewrite scalerBl. Qed. End Eigenspace. End RowSpaceTheory. Hint Resolve submx_refl. Implicit Arguments submxP [F m1 m2 n A B]. Implicit Arguments eq_row_sub [F m n v A]. Implicit Arguments row_subP [F m1 m2 n A B]. Implicit Arguments rV_subP [F m1 m2 n A B]. Implicit Arguments row_subPn [F m1 m2 n A B]. Implicit Arguments sub_rVP [F n u v]. Implicit Arguments rV_eqP [F m1 m2 n A B]. Implicit Arguments rowV0Pn [F m n A]. Implicit Arguments rowV0P [F m n A]. Implicit Arguments eqmx0P [F m n A]. Implicit Arguments row_fullP [F m n A]. Implicit Arguments row_freeP [F m n A]. Implicit Arguments eqmxP [F m1 m2 n A B]. Implicit Arguments genmxP [F m1 m2 n A B]. Implicit Arguments addsmx_idPr [F m1 m2 n A B]. Implicit Arguments addsmx_idPl [F m1 m2 n A B]. Implicit Arguments sub_addsmxP [F m1 m2 m3 n A B C]. Implicit Arguments sumsmx_sup [F I P m n A B_]. Implicit Arguments sumsmx_subP [F I P m n A_ B]. Implicit Arguments sub_sumsmxP [F I P m n A B_]. Implicit Arguments sub_kermxP [F p m n A B]. Implicit Arguments capmx_idPr [F m1 m2 n A B]. Implicit Arguments capmx_idPl [F m1 m2 n A B]. Implicit Arguments bigcapmx_inf [F I P m n A_ B]. Implicit Arguments sub_bigcapmxP [F I P m n A B_]. Implicit Arguments mxrank_injP [F m n A f]. Implicit Arguments mxdirectP [F n S]. Implicit Arguments mxdirect_addsP [F m1 m2 n A B]. Implicit Arguments mxdirect_sumsP [F I P n A_]. Implicit Arguments mxdirect_sumsE [F I P n S_]. Implicit Arguments eigenspaceP [F n g a m W]. Implicit Arguments eigenvalueP [F n g a]. Arguments Scope mxrank [_ nat_scope nat_scope matrix_set_scope]. Arguments Scope complmx [_ nat_scope nat_scope matrix_set_scope]. Arguments Scope row_full [_ nat_scope nat_scope matrix_set_scope]. Arguments Scope submx [_ nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Arguments Scope ltmx [_ nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Arguments Scope eqmx [_ nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Arguments Scope addsmx [_ nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Arguments Scope capmx [_ nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Arguments Scope diffmx [_ nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Prenex Implicits mxrank genmx complmx submx ltmx addsmx capmx. Notation "\rank A" := (mxrank A) : nat_scope. Notation "<< A >>" := (genmx A) : matrix_set_scope. Notation "A ^C" := (complmx A) : matrix_set_scope. Notation "A <= B" := (submx A B) : matrix_set_scope. Notation "A < B" := (ltmx A B) : matrix_set_scope. Notation "A <= B <= C" := ((submx A B) && (submx B C)) : matrix_set_scope. Notation "A < B <= C" := (ltmx A B && submx B C) : matrix_set_scope. Notation "A <= B < C" := (submx A B && ltmx B C) : matrix_set_scope. Notation "A < B < C" := (ltmx A B && ltmx B C) : matrix_set_scope. Notation "A == B" := ((submx A B) && (submx B A)) : matrix_set_scope. Notation "A :=: B" := (eqmx A B) : matrix_set_scope. Notation "A + B" := (addsmx A B) : matrix_set_scope. Notation "A :&: B" := (capmx A B) : matrix_set_scope. Notation "A :\: B" := (diffmx A B) : matrix_set_scope. Notation mxdirect S := (mxdirect_def (Phantom 'M_(_,_) S%MS)). Notation "\sum_ ( i <- r | P ) B" := (\big[addsmx/0%R]_(i <- r | P%B) B%MS) : matrix_set_scope. Notation "\sum_ ( i <- r ) B" := (\big[addsmx/0%R]_(i <- r) B%MS) : matrix_set_scope. Notation "\sum_ ( m <= i < n | P ) B" := (\big[addsmx/0%R]_(m <= i < n | P%B) B%MS) : matrix_set_scope. Notation "\sum_ ( m <= i < n ) B" := (\big[addsmx/0%R]_(m <= i < n) B%MS) : matrix_set_scope. Notation "\sum_ ( i | P ) B" := (\big[addsmx/0%R]_(i | P%B) B%MS) : matrix_set_scope. Notation "\sum_ i B" := (\big[addsmx/0%R]_i B%MS) : matrix_set_scope. Notation "\sum_ ( i : t | P ) B" := (\big[addsmx/0%R]_(i : t | P%B) B%MS) (only parsing) : matrix_set_scope. Notation "\sum_ ( i : t ) B" := (\big[addsmx/0%R]_(i : t) B%MS) (only parsing) : matrix_set_scope. Notation "\sum_ ( i < n | P ) B" := (\big[addsmx/0%R]_(i < n | P%B) B%MS) : matrix_set_scope. Notation "\sum_ ( i < n ) B" := (\big[addsmx/0%R]_(i < n) B%MS) : matrix_set_scope. Notation "\sum_ ( i 'in' A | P ) B" := (\big[addsmx/0%R]_(i in A | P%B) B%MS) : matrix_set_scope. Notation "\sum_ ( i 'in' A ) B" := (\big[addsmx/0%R]_(i in A) B%MS) : matrix_set_scope. Notation "\bigcap_ ( i <- r | P ) B" := (\big[capmx/1%:M]_(i <- r | P%B) B%MS) : matrix_set_scope. Notation "\bigcap_ ( i <- r ) B" := (\big[capmx/1%:M]_(i <- r) B%MS) : matrix_set_scope. Notation "\bigcap_ ( m <= i < n | P ) B" := (\big[capmx/1%:M]_(m <= i < n | P%B) B%MS) : matrix_set_scope. Notation "\bigcap_ ( m <= i < n ) B" := (\big[capmx/1%:M]_(m <= i < n) B%MS) : matrix_set_scope. Notation "\bigcap_ ( i | P ) B" := (\big[capmx/1%:M]_(i | P%B) B%MS) : matrix_set_scope. Notation "\bigcap_ i B" := (\big[capmx/1%:M]_i B%MS) : matrix_set_scope. Notation "\bigcap_ ( i : t | P ) B" := (\big[capmx/1%:M]_(i : t | P%B) B%MS) (only parsing) : matrix_set_scope. Notation "\bigcap_ ( i : t ) B" := (\big[capmx/1%:M]_(i : t) B%MS) (only parsing) : matrix_set_scope. Notation "\bigcap_ ( i < n | P ) B" := (\big[capmx/1%:M]_(i < n | P%B) B%MS) : matrix_set_scope. Notation "\bigcap_ ( i < n ) B" := (\big[capmx/1%:M]_(i < n) B%MS) : matrix_set_scope. Notation "\bigcap_ ( i 'in' A | P ) B" := (\big[capmx/1%:M]_(i in A | P%B) B%MS) : matrix_set_scope. Notation "\bigcap_ ( i 'in' A ) B" := (\big[capmx/1%:M]_(i in A) B%MS) : matrix_set_scope. Section CardGL. Variable F : finFieldType. Lemma card_GL n : n > 0 -> #|'GL_n[F]| = (#|F| ^ 'C(n, 2) * \prod_(1 <= i < n.+1) (#|F| ^ i - 1))%N. Proof. case: n => // n' _; set n := n'.+1; set p := #|F|. rewrite big_nat_rev big_add1 -triangular_sum expn_sum -big_split /=. pose fr m := [pred A : 'M[F]_(m, n) | \rank A == m]. set m := {-7}n; transitivity #|fr m|. by rewrite cardsT /= card_sub; apply: eq_card => A; rewrite -row_free_unit. elim: m (leqnn m : m <= n) => [_|m IHm]; last move/ltnW=> le_mn. rewrite (@eq_card1 _ (0 : 'M_(0, n))) ?big_geq //= => A. by rewrite flatmx0 !inE !eqxx. rewrite big_nat_recr // -{}IHm //= !subSS mulnBr muln1 -expnD subnKC //. rewrite -sum_nat_const /= -sum1_card -add1n. rewrite (partition_big dsubmx (fr m)) /= => [|A]; last first. rewrite !inE -{1}(vsubmxK A); move: {A}(_ A) (_ A) => Ad Au Afull. rewrite eqn_leq rank_leq_row -(leq_add2l (\rank Au)) -mxrank_sum_cap. rewrite {1 3}[@mxrank]lock addsmxE (eqnP Afull) -lock -addnA. by rewrite leq_add ?rank_leq_row ?leq_addr. apply: eq_bigr => A rAm; rewrite (reindex (col_mx^~ A)) /=; last first. exists usubmx => [v _ | vA]; first by rewrite col_mxKu. by case/andP=> _ /eqP <-; rewrite vsubmxK. transitivity #|~: [set v *m A | v in 'rV_m]|; last first. rewrite cardsCs setCK card_imset ?card_matrix ?card_ord ?mul1n //. have [B AB1] := row_freeP rAm; apply: can_inj (mulmx^~ B) _ => v. by rewrite -mulmxA AB1 mulmx1. rewrite -sum1_card; apply: eq_bigl => v; rewrite !inE col_mxKd eqxx. rewrite andbT eqn_leq rank_leq_row /= -(leq_add2r (\rank (v :&: A)%MS)). rewrite -addsmxE mxrank_sum_cap (eqnP rAm) addnAC leq_add2r. rewrite (ltn_leqif (mxrank_leqif_sup _)) ?capmxSl // sub_capmx submx_refl. by congr (~~ _); apply/submxP/imsetP=> [] [u]; exists u. Qed. (* An alternate, somewhat more elementary proof, that does not rely on the *) (* row-space theory, but directly performs the LUP decomposition. *) Lemma LUP_card_GL n : n > 0 -> #|'GL_n[F]| = (#|F| ^ 'C(n, 2) * \prod_(1 <= i < n.+1) (#|F| ^ i - 1))%N. Proof. case: n => // n' _; set n := n'.+1; set p := #|F|. rewrite cardsT /= card_sub /GRing.unit /= big_add1 /= -triangular_sum -/n. elim: {n'}n => [|n IHn]. rewrite !big_geq // mul1n (@eq_card _ _ predT) ?card_matrix //= => M. by rewrite {1}[M]flatmx0 -(flatmx0 1%:M) unitmx1. rewrite !big_nat_recr //= expnD mulnAC mulnA -{}IHn -mulnA mulnC. set LHS := #|_|; rewrite -[n.+1]muln1 -{2}[n]mul1n {}/LHS. rewrite -!card_matrix subn1 -(cardC1 0) -mulnA; set nzC := predC1 _. rewrite -sum1_card (partition_big lsubmx nzC) => [|A]; last first. rewrite unitmxE unitfE; apply: contra; move/eqP=> v0. rewrite -[A]hsubmxK v0 -[n.+1]/(1 + n)%N -col_mx0. rewrite -[rsubmx _]vsubmxK -det_tr tr_row_mx !tr_col_mx !trmx0. by rewrite det_lblock [0]mx11_scalar det_scalar1 mxE mul0r. rewrite -sum_nat_const; apply: eq_bigr; rewrite /= -[n.+1]/(1 + n)%N => v nzv. case: (pickP (fun i => v i 0 != 0)) => [k nza | v0]; last first. by case/eqP: nzv; apply/colP=> i; move/eqP: (v0 i); rewrite mxE. have xrkK: involutive (@xrow F _ _ 0 k). by move=> m A /=; rewrite /xrow -row_permM tperm2 row_perm1. rewrite (reindex_inj (inv_inj (xrkK (1 + n)%N))) /= -[n.+1]/(1 + n)%N. rewrite (partition_big ursubmx xpredT) //= -sum_nat_const. apply: eq_bigr => u _; set a : F := v _ _ in nza. set v1 : 'cV_(1 + n) := xrow 0 k v. have def_a: usubmx v1 = a%:M. by rewrite [_ v1]mx11_scalar mxE lshift0 mxE tpermL. pose Schur := dsubmx v1 *m (a^-1 *: u). pose L : 'M_(1 + n) := block_mx a%:M 0 (dsubmx v1) 1%:M. pose U B : 'M_(1 + n) := block_mx 1 (a^-1 *: u) 0 B. rewrite (reindex (fun B => L *m U B)); last first. exists (fun A1 => drsubmx A1 - Schur) => [B _ | A1]. by rewrite mulmx_block block_mxKdr mul1mx addrC addKr. rewrite !inE mulmx_block !mulmx0 mul0mx !mulmx1 !addr0 mul1mx addrC subrK. rewrite mul_scalar_mx scalerA divff // scale1r andbC; case/and3P => /eqP <- _. rewrite -{1}(hsubmxK A1) xrowE mul_mx_row row_mxKl -xrowE => /eqP def_v. rewrite -def_a block_mxEh vsubmxK /v1 -def_v xrkK. apply: trmx_inj; rewrite tr_row_mx tr_col_mx trmx_ursub trmx_drsub trmx_lsub. by rewrite hsubmxK vsubmxK. rewrite -sum1_card; apply: eq_bigl => B; rewrite xrowE unitmxE. rewrite !det_mulmx unitrM -unitmxE unitmx_perm det_lblock det_ublock. rewrite !det_scalar1 det1 mulr1 mul1r unitrM unitfE nza -unitmxE. rewrite mulmx_block !mulmx0 mul0mx !addr0 !mulmx1 mul1mx block_mxKur. rewrite mul_scalar_mx scalerA divff // scale1r eqxx andbT. by rewrite block_mxEh mul_mx_row row_mxKl -def_a vsubmxK -xrowE xrkK eqxx andbT. Qed. Lemma card_GL_1 : #|'GL_1[F]| = #|F|.-1. Proof. by rewrite card_GL // mul1n big_nat1 expn1 subn1. Qed. Lemma card_GL_2 : #|'GL_2[F]| = (#|F| * #|F|.-1 ^ 2 * #|F|.+1)%N. Proof. rewrite card_GL // big_ltn // big_nat1 expn1 -(addn1 #|F|) -subn1 -!mulnA. by rewrite -subn_sqr. Qed. End CardGL. Lemma logn_card_GL_p n p : prime p -> logn p #|'GL_n(p)| = 'C(n, 2). Proof. move=> p_pr; have p_gt1 := prime_gt1 p_pr. have p_i_gt0: p ^ _ > 0 by move=> i; rewrite expn_gt0 ltnW. rewrite (card_GL _ (ltn0Sn n.-1)) card_ord Fp_cast // big_add1 /=. pose p'gt0 m := m > 0 /\ logn p m = 0%N. suffices [Pgt0 p'P]: p'gt0 (\prod_(0 <= i < n.-1.+1) (p ^ i.+1 - 1))%N. by rewrite lognM // p'P pfactorK //; case n. apply big_ind => [|m1 m2 [m10 p'm1] [m20]|i _]; rewrite {}/p'gt0 ?logn1 //. by rewrite muln_gt0 m10 lognM ?p'm1. rewrite lognE -if_neg subn_gt0 p_pr /= -{1 2}(exp1n i.+1) ltn_exp2r // p_gt1. by rewrite dvdn_subr ?dvdn_exp // gtnNdvd. Qed. Section MatrixAlgebra. Variables F : fieldType. Local Notation "A \in R" := (@submx F _ _ _ (mxvec A) R). Lemma mem0mx m n (R : 'A_(m, n)) : 0 \in R. Proof. by rewrite linear0 sub0mx. Qed. Lemma memmx0 n A : (A \in (0 : 'A_n)) -> A = 0. Proof. by rewrite submx0 mxvec_eq0; move/eqP. Qed. Lemma memmx1 n (A : 'M_n) : (A \in mxvec 1%:M) = is_scalar_mx A. Proof. apply/sub_rVP/is_scalar_mxP=> [[a] | [a ->]]. by rewrite -linearZ scale_scalar_mx mulr1 => /(can_inj mxvecK); exists a. by exists a; rewrite -linearZ scale_scalar_mx mulr1. Qed. Lemma memmx_subP m1 m2 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) : reflect (forall A, A \in R1 -> A \in R2) (R1 <= R2)%MS. Proof. apply: (iffP idP) => [sR12 A R1_A | sR12]; first exact: submx_trans sR12. by apply/rV_subP=> vA; rewrite -(vec_mxK vA); exact: sR12. Qed. Implicit Arguments memmx_subP [m1 m2 n R1 R2]. Lemma memmx_eqP m1 m2 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) : reflect (forall A, (A \in R1) = (A \in R2)) (R1 == R2)%MS. Proof. apply: (iffP eqmxP) => [eqR12 A | eqR12]; first by rewrite eqR12. by apply/eqmxP; apply/rV_eqP=> vA; rewrite -(vec_mxK vA) eqR12. Qed. Implicit Arguments memmx_eqP [m1 m2 n R1 R2]. Lemma memmx_addsP m1 m2 n A (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) : reflect (exists D, [/\ D.1 \in R1, D.2 \in R2 & A = D.1 + D.2]) (A \in R1 + R2)%MS. Proof. apply: (iffP sub_addsmxP) => [[u /(canRL mxvecK)->] | [D []]]. exists (vec_mx (u.1 *m R1), vec_mx (u.2 *m R2)). by rewrite /= linearD !vec_mxK !submxMl. case/submxP=> u1 defD1 /submxP[u2 defD2] ->. by exists (u1, u2); rewrite linearD /= defD1 defD2. Qed. Implicit Arguments memmx_addsP [m1 m2 n A R1 R2]. Lemma memmx_sumsP (I : finType) (P : pred I) n (A : 'M_n) R_ : reflect (exists2 A_, A = \sum_(i | P i) A_ i & forall i, A_ i \in R_ i) (A \in \sum_(i | P i) R_ i)%MS. Proof. apply: (iffP sub_sumsmxP) => [[C defA] | [A_ -> R_A] {A}]. exists (fun i => vec_mx (C i *m R_ i)) => [|i]. by rewrite -linear_sum -defA /= mxvecK. by rewrite vec_mxK submxMl. exists (fun i => mxvec (A_ i) *m pinvmx (R_ i)). by rewrite linear_sum; apply: eq_bigr => i _; rewrite mulmxKpV. Qed. Implicit Arguments memmx_sumsP [I P n A R_]. Lemma has_non_scalar_mxP m n (R : 'A_(m, n)) : (1%:M \in R)%MS -> reflect (exists2 A, A \in R & ~~ is_scalar_mx A)%MS (1 < \rank R). Proof. case: (posnP n) => [-> | n_gt0] in R *; set S := mxvec _ => sSR. by rewrite [R]thinmx0 mxrank0; right; case; rewrite /is_scalar_mx ?insubF. have rankS: \rank S = 1%N. apply/eqP; rewrite eqn_leq rank_leq_row lt0n mxrank_eq0 mxvec_eq0. by rewrite -mxrank_eq0 mxrank1 -lt0n. rewrite -{2}rankS (ltn_leqif (mxrank_leqif_sup sSR)). apply: (iffP idP) => [/row_subPn[i] | [A sAR]]. rewrite -[row i R]vec_mxK memmx1; set A := vec_mx _ => nsA. by exists A; rewrite // vec_mxK row_sub. by rewrite -memmx1; apply: contra; exact: submx_trans. Qed. Definition mulsmx m1 m2 n (R1 : 'A[F]_(m1, n)) (R2 : 'A_(m2, n)) := (\sum_i <>)%MS. Arguments Scope mulsmx [nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Local Notation "R1 * R2" := (mulsmx R1 R2) : matrix_set_scope. Lemma genmx_muls m1 m2 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) : <<(R1 * R2)%MS>>%MS = (R1 * R2)%MS. Proof. by rewrite genmx_sums; apply: eq_bigr => i; rewrite genmx_id. Qed. Lemma mem_mulsmx m1 m2 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) A1 A2 : (A1 \in R1 -> A2 \in R2 -> A1 *m A2 \in R1 * R2)%MS. Proof. move=> R_A1 R_A2; rewrite -[A2]mxvecK; case/submxP: R_A2 => a ->{A2}. rewrite mulmx_sum_row !linear_sum summx_sub // => i _. rewrite !linearZ scalemx_sub {a}//= (sumsmx_sup i) // genmxE. rewrite -[A1]mxvecK; case/submxP: R_A1 => a ->{A1}. by apply/submxP; exists a; rewrite mulmxA mul_rV_lin. Qed. Lemma mulsmx_subP m1 m2 m n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) (R : 'A_(m, n)) : reflect (forall A1 A2, A1 \in R1 -> A2 \in R2 -> A1 *m A2 \in R) (R1 * R2 <= R)%MS. Proof. apply: (iffP memmx_subP) => [sR12R A1 A2 R_A1 R_A2 | sR12R A]. by rewrite sR12R ?mem_mulsmx. case/memmx_sumsP=> A_ -> R_A; rewrite linear_sum summx_sub //= => j _. rewrite (submx_trans (R_A _)) // genmxE; apply/row_subP=> i. by rewrite row_mul mul_rV_lin sR12R ?vec_mxK ?row_sub. Qed. Implicit Arguments mulsmx_subP [m1 m2 m n R1 R2 R]. Lemma mulsmxS m1 m2 m3 m4 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) (R3 : 'A_(m3, n)) (R4 : 'A_(m4, n)) : (R1 <= R3 -> R2 <= R4 -> R1 * R2 <= R3 * R4)%MS. Proof. move=> sR13 sR24; apply/mulsmx_subP=> A1 A2 R_A1 R_A2. by apply: mem_mulsmx; [exact: submx_trans sR13 | exact: submx_trans sR24]. Qed. Lemma muls_eqmx m1 m2 m3 m4 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) (R3 : 'A_(m3, n)) (R4 : 'A_(m4, n)) : (R1 :=: R3 -> R2 :=: R4 -> R1 * R2 = R3 * R4)%MS. Proof. move=> eqR13 eqR24; rewrite -(genmx_muls R1 R2) -(genmx_muls R3 R4). by apply/genmxP; rewrite !mulsmxS ?eqR13 ?eqR24. Qed. Lemma mulsmxP m1 m2 n A (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) : reflect (exists2 A1, forall i, A1 i \in R1 & exists2 A2, forall i, A2 i \in R2 & A = \sum_(i < n ^ 2) A1 i *m A2 i) (A \in R1 * R2)%MS. Proof. apply: (iffP idP) => [R_A|[A1 R_A1 [A2 R_A2 ->{A}]]]; last first. by rewrite linear_sum summx_sub // => i _; rewrite mem_mulsmx. have{R_A}: (A \in R1 * <>)%MS. by apply: memmx_subP R_A; rewrite mulsmxS ?genmxE. case/memmx_sumsP=> A_ -> R_A; pose A2_ i := vec_mx (row i <>%MS). pose A1_ i := mxvec (A_ i) *m pinvmx (R1 *m lin_mx (mulmxr (A2_ i))) *m R1. exists (vec_mx \o A1_) => [i|]; first by rewrite vec_mxK submxMl. exists A2_ => [i|]; first by rewrite vec_mxK -(genmxE R2) row_sub. apply: eq_bigr => i _; rewrite -[_ *m _](mx_rV_lin (mulmxr_linear _ _)). by rewrite -mulmxA mulmxKpV ?mxvecK // -(genmxE (_ *m _)) R_A. Qed. Implicit Arguments mulsmxP [m1 m2 n A R1 R2]. Lemma mulsmxA m1 m2 m3 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) (R3 : 'A_(m3, n)) : (R1 * (R2 * R3) = R1 * R2 * R3)%MS. Proof. rewrite -(genmx_muls (_ * _)%MS) -genmx_muls; apply/genmxP; apply/andP; split. apply/mulsmx_subP=> A1 A23 R_A1; case/mulsmxP=> A2 R_A2 [A3 R_A3 ->{A23}]. by rewrite !linear_sum summx_sub //= => i _; rewrite mulmxA !mem_mulsmx. apply/mulsmx_subP=> _ A3 /mulsmxP[A1 R_A1 [A2 R_A2 ->]] R_A3. rewrite mulmx_suml linear_sum summx_sub //= => i _. by rewrite -mulmxA !mem_mulsmx. Qed. Lemma mulsmx_addl m1 m2 m3 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) (R3 : 'A_(m3, n)) : ((R1 + R2) * R3 = R1 * R3 + R2 * R3)%MS. Proof. rewrite -(genmx_muls R2 R3) -(genmx_muls R1 R3) -genmx_muls -genmx_adds. apply/genmxP; rewrite andbC addsmx_sub !mulsmxS ?addsmxSl ?addsmxSr //=. apply/mulsmx_subP=> _ A3 /memmx_addsP[A [R_A1 R_A2 ->]] R_A3. by rewrite mulmxDl linearD addmx_sub_adds ?mem_mulsmx. Qed. Lemma mulsmx_addr m1 m2 m3 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) (R3 : 'A_(m3, n)) : (R1 * (R2 + R3) = R1 * R2 + R1 * R3)%MS. Proof. rewrite -(genmx_muls R1 R3) -(genmx_muls R1 R2) -genmx_muls -genmx_adds. apply/genmxP; rewrite andbC addsmx_sub !mulsmxS ?addsmxSl ?addsmxSr //=. apply/mulsmx_subP=> A1 _ R_A1 /memmx_addsP[A [R_A2 R_A3 ->]]. by rewrite mulmxDr linearD addmx_sub_adds ?mem_mulsmx. Qed. Lemma mulsmx0 m1 m2 n (R1 : 'A_(m1, n)) : (R1 * (0 : 'A_(m2, n)) = 0)%MS. Proof. apply/eqP; rewrite -submx0; apply/mulsmx_subP=> A1 A0 _. by rewrite [A0 \in 0]eqmx0 => /memmx0->; rewrite mulmx0 mem0mx. Qed. Lemma muls0mx m1 m2 n (R2 : 'A_(m2, n)) : ((0 : 'A_(m1, n)) * R2 = 0)%MS. Proof. apply/eqP; rewrite -submx0; apply/mulsmx_subP=> A0 A2. by rewrite [A0 \in 0]eqmx0 => /memmx0->; rewrite mul0mx mem0mx. Qed. Definition left_mx_ideal m1 m2 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) := (R1 * R2 <= R2)%MS. Definition right_mx_ideal m1 m2 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) := (R2 * R1 <= R2)%MS. Definition mx_ideal m1 m2 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) := left_mx_ideal R1 R2 && right_mx_ideal R1 R2. Definition mxring_id m n (R : 'A_(m, n)) e := [/\ e != 0, e \in R, forall A, A \in R -> e *m A = A & forall A, A \in R -> A *m e = A]%MS. Definition has_mxring_id m n (R : 'A[F]_(m , n)) := (R != 0) && (row_mx 0 (row_mx (mxvec R) (mxvec R)) <= row_mx (cokermx R) (row_mx (lin_mx (mulmx R \o lin_mulmx)) (lin_mx (mulmx R \o lin_mulmxr))))%MS. Definition mxring m n (R : 'A_(m, n)) := left_mx_ideal R R && has_mxring_id R. Lemma mxring_idP m n (R : 'A_(m, n)) : reflect (exists e, mxring_id R e) (has_mxring_id R). Proof. apply: (iffP andP) => [[nzR] | [e [nz_e Re ideR idRe]]]. case/submxP=> v; rewrite -[v]vec_mxK; move/vec_mx: v => e. rewrite !mul_mx_row; case/eq_row_mx => /eqP. rewrite eq_sym -submxE => Re. case/eq_row_mx; rewrite !{1}mul_rV_lin1 /= mxvecK. set u := (_ *m _) => /(can_inj mxvecK) idRe /(can_inj mxvecK) ideR. exists e; split=> // [ | A /submxP[a defA] | A /submxP[a defA]]. - by apply: contra nzR; rewrite ideR => /eqP->; rewrite !linear0. - by rewrite -{2}[A]mxvecK defA idRe mulmxA mx_rV_lin -defA /= mxvecK. by rewrite -{2}[A]mxvecK defA ideR mulmxA mx_rV_lin -defA /= mxvecK. split. by apply: contraNneq nz_e => R0; rewrite R0 eqmx0 in Re; rewrite (memmx0 Re). apply/submxP; exists (mxvec e); rewrite !mul_mx_row !{1}mul_rV_lin1. rewrite submxE in Re; rewrite {Re}(eqP Re). congr (row_mx 0 (row_mx (mxvec _) (mxvec _))); apply/row_matrixP=> i. by rewrite !row_mul !mul_rV_lin1 /= mxvecK ideR vec_mxK ?row_sub. by rewrite !row_mul !mul_rV_lin1 /= mxvecK idRe vec_mxK ?row_sub. Qed. Implicit Arguments mxring_idP [m n R]. Section CentMxDef. Variables (m n : nat) (R : 'A[F]_(m, n)). Definition cent_mx_fun (B : 'M[F]_n) := R *m lin_mx (mulmxr B \- mulmx B). Lemma cent_mx_fun_is_linear : linear cent_mx_fun. Proof. move=> a A B; apply/row_matrixP=> i; rewrite linearP row_mul mul_rV_lin. rewrite /= {-3}[row]lock row_mul mul_rV_lin -lock row_mul mul_rV_lin. by rewrite -linearP -(linearP [linear of mulmx _ \- mulmxr _]). Qed. Canonical cent_mx_fun_additive := Additive cent_mx_fun_is_linear. Canonical cent_mx_fun_linear := Linear cent_mx_fun_is_linear. Definition cent_mx := kermx (lin_mx cent_mx_fun). Definition center_mx := (R :&: cent_mx)%MS. End CentMxDef. Local Notation "''C' ( R )" := (cent_mx R) : matrix_set_scope. Local Notation "''Z' ( R )" := (center_mx R) : matrix_set_scope. Lemma cent_rowP m n B (R : 'A_(m, n)) : reflect (forall i (A := vec_mx (row i R)), A *m B = B *m A) (B \in 'C(R))%MS. Proof. apply: (iffP sub_kermxP); rewrite mul_vec_lin => cBE. move/(canRL mxvecK): cBE => cBE i A /=; move/(congr1 (row i)): cBE. rewrite row_mul mul_rV_lin -/A; move/(canRL mxvecK). by move/(canRL (subrK _)); rewrite !linear0 add0r. apply: (canLR vec_mxK); apply/row_matrixP=> i. by rewrite row_mul mul_rV_lin /= cBE subrr !linear0. Qed. Implicit Arguments cent_rowP [m n B R]. Lemma cent_mxP m n B (R : 'A_(m, n)) : reflect (forall A, A \in R -> A *m B = B *m A) (B \in 'C(R))%MS. Proof. apply: (iffP cent_rowP) => cEB => [A sAE | i A]. rewrite -[A]mxvecK -(mulmxKpV sAE); move: (mxvec A *m _) => u. rewrite !mulmx_sum_row !linear_sum mulmx_suml; apply: eq_bigr => i _ /=. by rewrite !linearZ -scalemxAl /= cEB. by rewrite cEB // vec_mxK row_sub. Qed. Implicit Arguments cent_mxP [m n B R]. Lemma scalar_mx_cent m n a (R : 'A_(m, n)) : (a%:M \in 'C(R))%MS. Proof. by apply/cent_mxP=> A _; exact: scalar_mxC. Qed. Lemma center_mx_sub m n (R : 'A_(m, n)) : ('Z(R) <= R)%MS. Proof. exact: capmxSl. Qed. Lemma center_mxP m n A (R : 'A_(m, n)) : reflect (A \in R /\ forall B, B \in R -> B *m A = A *m B) (A \in 'Z(R))%MS. Proof. rewrite sub_capmx; case R_A: (A \in R); last by right; case. by apply: (iffP cent_mxP) => [cAR | [_ cAR]]. Qed. Implicit Arguments center_mxP [m n A R]. Lemma mxring_id_uniq m n (R : 'A_(m, n)) e1 e2 : mxring_id R e1 -> mxring_id R e2 -> e1 = e2. Proof. by case=> [_ Re1 idRe1 _] [_ Re2 _ ide2R]; rewrite -(idRe1 _ Re2) ide2R. Qed. Lemma cent_mx_ideal m n (R : 'A_(m, n)) : left_mx_ideal 'C(R)%MS 'C(R)%MS. Proof. apply/mulsmx_subP=> A1 A2 C_A1 C_A2; apply/cent_mxP=> B R_B. by rewrite mulmxA (cent_mxP C_A1) // -!mulmxA (cent_mxP C_A2). Qed. Lemma cent_mx_ring m n (R : 'A_(m, n)) : n > 0 -> mxring 'C(R)%MS. Proof. move=> n_gt0; rewrite /mxring cent_mx_ideal; apply/mxring_idP. exists 1%:M; split=> [||A _|A _]; rewrite ?mulmx1 ?mul1mx ?scalar_mx_cent //. by rewrite -mxrank_eq0 mxrank1 -lt0n. Qed. Lemma mxdirect_adds_center m1 m2 n (R1 : 'A_(m1, n)) (R2 : 'A_(m2, n)) : mx_ideal (R1 + R2)%MS R1 -> mx_ideal (R1 + R2)%MS R2 -> mxdirect (R1 + R2) -> ('Z((R1 + R2)%MS) :=: 'Z(R1) + 'Z(R2))%MS. Proof. case/andP=> idlR1 idrR1 /andP[idlR2 idrR2] /mxdirect_addsP dxR12. apply/eqmxP/andP; split. apply/memmx_subP=> z0; rewrite sub_capmx => /andP[]. case/memmx_addsP=> z [R1z1 R2z2 ->{z0}] Cz. rewrite linearD addmx_sub_adds //= ?sub_capmx ?R1z1 ?R2z2 /=. apply/cent_mxP=> A R1_A; have R_A := submx_trans R1_A (addsmxSl R1 R2). have Rz2 := submx_trans R2z2 (addsmxSr R1 R2). rewrite -{1}[z.1](addrK z.2) mulmxBr (cent_mxP Cz) // mulmxDl. rewrite [A *m z.2]memmx0 1?[z.2 *m A]memmx0 ?addrK //. by rewrite -dxR12 sub_capmx (mulsmx_subP idlR1) // (mulsmx_subP idrR2). by rewrite -dxR12 sub_capmx (mulsmx_subP idrR1) // (mulsmx_subP idlR2). apply/cent_mxP=> A R2_A; have R_A := submx_trans R2_A (addsmxSr R1 R2). have Rz1 := submx_trans R1z1 (addsmxSl R1 R2). rewrite -{1}[z.2](addKr z.1) mulmxDr (cent_mxP Cz) // mulmxDl. rewrite mulmxN [A *m z.1]memmx0 1?[z.1 *m A]memmx0 ?addKr //. by rewrite -dxR12 sub_capmx (mulsmx_subP idrR1) // (mulsmx_subP idlR2). by rewrite -dxR12 sub_capmx (mulsmx_subP idlR1) // (mulsmx_subP idrR2). rewrite addsmx_sub; apply/andP; split. apply/memmx_subP=> z; rewrite sub_capmx => /andP[R1z cR1z]. have Rz := submx_trans R1z (addsmxSl R1 R2). rewrite sub_capmx Rz; apply/cent_mxP=> A0. case/memmx_addsP=> A [R1_A1 R2_A2] ->{A0}. have R_A2 := submx_trans R2_A2 (addsmxSr R1 R2). rewrite mulmxDl mulmxDr (cent_mxP cR1z) //; congr (_ + _). rewrite [A.2 *m z]memmx0 1?[z *m A.2]memmx0 //. by rewrite -dxR12 sub_capmx (mulsmx_subP idrR1) // (mulsmx_subP idlR2). by rewrite -dxR12 sub_capmx (mulsmx_subP idlR1) // (mulsmx_subP idrR2). apply/memmx_subP=> z; rewrite !sub_capmx => /andP[R2z cR2z]. have Rz := submx_trans R2z (addsmxSr R1 R2); rewrite Rz. apply/cent_mxP=> _ /memmx_addsP[A [R1_A1 R2_A2 ->]]. rewrite mulmxDl mulmxDr (cent_mxP cR2z _ R2_A2) //; congr (_ + _). have R_A1 := submx_trans R1_A1 (addsmxSl R1 R2). rewrite [A.1 *m z]memmx0 1?[z *m A.1]memmx0 //. by rewrite -dxR12 sub_capmx (mulsmx_subP idlR1) // (mulsmx_subP idrR2). by rewrite -dxR12 sub_capmx (mulsmx_subP idrR1) // (mulsmx_subP idlR2). Qed. Lemma mxdirect_sums_center (I : finType) m n (R : 'A_(m, n)) R_ : (\sum_i R_ i :=: R)%MS -> mxdirect (\sum_i R_ i) -> (forall i : I, mx_ideal R (R_ i)) -> ('Z(R) :=: \sum_i 'Z(R_ i))%MS. Proof. move=> defR dxR idealR. have sR_R: (R_ _ <= R)%MS by move=> i; rewrite -defR (sumsmx_sup i). have anhR i j A B : i != j -> A \in R_ i -> B \in R_ j -> A *m B = 0. move=> ne_ij RiA RjB; apply: memmx0. have [[_ idRiR] [idRRj _]] := (andP (idealR i), andP (idealR j)). rewrite -(mxdirect_sumsP dxR j) // sub_capmx (sumsmx_sup i) //. by rewrite (mulsmx_subP idRRj) // (memmx_subP (sR_R i)). by rewrite (mulsmx_subP idRiR) // (memmx_subP (sR_R j)). apply/eqmxP/andP; split. apply/memmx_subP=> Z; rewrite sub_capmx => /andP[]. rewrite -{1}defR => /memmx_sumsP[z ->{Z} Rz cRz]. apply/memmx_sumsP; exists z => // i; rewrite sub_capmx Rz. apply/cent_mxP=> A RiA; have:= cent_mxP cRz A (memmx_subP (sR_R i) A RiA). rewrite (bigD1 i) //= mulmxDl mulmxDr mulmx_suml mulmx_sumr. by rewrite !big1 ?addr0 // => j; last rewrite eq_sym; move/anhR->. apply/sumsmx_subP => i _; apply/memmx_subP=> z; rewrite sub_capmx. case/andP=> Riz cRiz; rewrite sub_capmx (memmx_subP (sR_R i)) //=. apply/cent_mxP=> A; rewrite -{1}defR; case/memmx_sumsP=> a -> R_a. rewrite (bigD1 i) // mulmxDl mulmxDr mulmx_suml mulmx_sumr. rewrite !big1 => [|j|j]; first by rewrite !addr0 (cent_mxP cRiz). by rewrite eq_sym => /anhR->. by move/anhR->. Qed. End MatrixAlgebra. Arguments Scope mulsmx [_ nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Arguments Scope left_mx_ideal [_ nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Arguments Scope right_mx_ideal [_ nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Arguments Scope mx_ideal [_ nat_scope nat_scope nat_scope matrix_set_scope matrix_set_scope]. Arguments Scope mxring_id [_ nat_scope nat_scope ring_scope matrix_set_scope]. Arguments Scope has_mxring_id [_ nat_scope nat_scope ring_scope matrix_set_scope]. Arguments Scope mxring [_ nat_scope nat_scope matrix_set_scope]. Arguments Scope cent_mx [_ nat_scope nat_scope matrix_set_scope]. Arguments Scope center_mx [_ nat_scope nat_scope matrix_set_scope]. Prenex Implicits mulsmx. Notation "A \in R" := (submx (mxvec A) R) : matrix_set_scope. Notation "R * S" := (mulsmx R S) : matrix_set_scope. Notation "''C' ( R )" := (cent_mx R) : matrix_set_scope. Notation "''C_' R ( S )" := (R :&: 'C(S))%MS : matrix_set_scope. Notation "''C_' ( R ) ( S )" := ('C_R(S))%MS (only parsing) : matrix_set_scope. Notation "''Z' ( R )" := (center_mx R) : matrix_set_scope. Implicit Arguments memmx_subP [F m1 m2 n R1 R2]. Implicit Arguments memmx_eqP [F m1 m2 n R1 R2]. Implicit Arguments memmx_addsP [F m1 m2 n R1 R2]. Implicit Arguments memmx_sumsP [F I P n A R_]. Implicit Arguments mulsmx_subP [F m1 m2 m n R1 R2 R]. Implicit Arguments mulsmxP [F m1 m2 n A R1 R2]. Implicit Arguments mxring_idP [m n R]. Implicit Arguments cent_rowP [F m n B R]. Implicit Arguments cent_mxP [F m n B R]. Implicit Arguments center_mxP [F m n A R]. (* Parametricity for the row-space/F-algebra theory. *) Section MapMatrixSpaces. Variables (aF rF : fieldType) (f : {rmorphism aF -> rF}). Local Notation "A ^f" := (map_mx f A) : ring_scope. Lemma Gaussian_elimination_map m n (A : 'M_(m, n)) : Gaussian_elimination A^f = ((col_ebase A)^f, (row_ebase A)^f, \rank A). Proof. rewrite mxrankE /row_ebase /col_ebase unlock. elim: m n A => [|m IHm] [|n] A /=; rewrite ?map_mx1 //. set pAnz := [pred k | A k.1 k.2 != 0]. rewrite (@eq_pick _ _ pAnz) => [|k]; last by rewrite /= mxE fmorph_eq0. case: {+}(pick _) => [[i j]|]; last by rewrite !map_mx1. rewrite mxE -fmorphV -map_xcol -map_xrow -map_dlsubmx -map_drsubmx. rewrite -map_ursubmx -map_mxZ -map_mxM -map_mx_sub {}IHm /=. case: {+}(Gaussian_elimination _) => [[L U] r] /=; rewrite map_xrow map_xcol. by rewrite !(@map_block_mx _ _ f 1 _ 1) !map_mx0 ?map_mx1 ?map_scalar_mx. Qed. Lemma mxrank_map m n (A : 'M_(m, n)) : \rank A^f = \rank A. Proof. by rewrite mxrankE Gaussian_elimination_map. Qed. Lemma row_free_map m n (A : 'M_(m, n)) : row_free A^f = row_free A. Proof. by rewrite /row_free mxrank_map. Qed. Lemma row_full_map m n (A : 'M_(m, n)) : row_full A^f = row_full A. Proof. by rewrite /row_full mxrank_map. Qed. Lemma map_row_ebase m n (A : 'M_(m, n)) : (row_ebase A)^f = row_ebase A^f. Proof. by rewrite {2}/row_ebase unlock Gaussian_elimination_map. Qed. Lemma map_col_ebase m n (A : 'M_(m, n)) : (col_ebase A)^f = col_ebase A^f. Proof. by rewrite {2}/col_ebase unlock Gaussian_elimination_map. Qed. Lemma map_row_base m n (A : 'M_(m, n)) : (row_base A)^f = castmx (mxrank_map A, erefl n) (row_base A^f). Proof. move: (mxrank_map A); rewrite {2}/row_base mxrank_map => eqrr. by rewrite castmx_id map_mxM map_pid_mx map_row_ebase. Qed. Lemma map_col_base m n (A : 'M_(m, n)) : (col_base A)^f = castmx (erefl m, mxrank_map A) (col_base A^f). Proof. move: (mxrank_map A); rewrite {2}/col_base mxrank_map => eqrr. by rewrite castmx_id map_mxM map_pid_mx map_col_ebase. Qed. Lemma map_pinvmx m n (A : 'M_(m, n)) : (pinvmx A)^f = pinvmx A^f. Proof. rewrite !map_mxM !map_invmx map_row_ebase map_col_ebase. by rewrite map_pid_mx -mxrank_map. Qed. Lemma map_kermx m n (A : 'M_(m, n)) : (kermx A)^f = kermx A^f. Proof. by rewrite !map_mxM map_invmx map_col_ebase -mxrank_map map_copid_mx. Qed. Lemma map_cokermx m n (A : 'M_(m, n)) : (cokermx A)^f = cokermx A^f. Proof. by rewrite !map_mxM map_invmx map_row_ebase -mxrank_map map_copid_mx. Qed. Lemma map_submx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A^f <= B^f)%MS = (A <= B)%MS. Proof. by rewrite !submxE -map_cokermx -map_mxM map_mx_eq0. Qed. Lemma map_ltmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A^f < B^f)%MS = (A < B)%MS. Proof. by rewrite /ltmx !map_submx. Qed. Lemma map_eqmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A^f :=: B^f)%MS <-> (A :=: B)%MS. Proof. split=> [/eqmxP|eqAB]; first by rewrite !map_submx => /eqmxP. by apply/eqmxP; rewrite !map_submx !eqAB !submx_refl. Qed. Lemma map_genmx m n (A : 'M_(m, n)) : (<>^f :=: <>)%MS. Proof. by apply/eqmxP; rewrite !(genmxE, map_submx) andbb. Qed. Lemma map_addsmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (((A + B)%MS)^f :=: A^f + B^f)%MS. Proof. by apply/eqmxP; rewrite !addsmxE -map_col_mx !map_submx !addsmxE andbb. Qed. Lemma map_capmx_gen m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (capmx_gen A B)^f = capmx_gen A^f B^f. Proof. by rewrite map_mxM map_lsubmx map_kermx map_col_mx. Qed. Lemma map_capmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : ((A :&: B)^f :=: A^f :&: B^f)%MS. Proof. by apply/eqmxP; rewrite !capmxE -map_capmx_gen !map_submx -!capmxE andbb. Qed. Lemma map_complmx m n (A : 'M_(m, n)) : (A^C^f = A^f^C)%MS. Proof. by rewrite map_mxM map_row_ebase -mxrank_map map_copid_mx. Qed. Lemma map_diffmx m1 m2 n (A : 'M_(m1, n)) (B : 'M_(m2, n)) : ((A :\: B)^f :=: A^f :\: B^f)%MS. Proof. apply/eqmxP; rewrite !diffmxE -map_capmx_gen -map_complmx. by rewrite -!map_capmx !map_submx -!diffmxE andbb. Qed. Lemma map_eigenspace n (g : 'M_n) a : (eigenspace g a)^f = eigenspace g^f (f a). Proof. by rewrite map_kermx map_mx_sub ?map_scalar_mx. Qed. Lemma eigenvalue_map n (g : 'M_n) a : eigenvalue g^f (f a) = eigenvalue g a. Proof. by rewrite /eigenvalue -map_eigenspace map_mx_eq0. Qed. Lemma memmx_map m n A (E : 'A_(m, n)) : (A^f \in E^f)%MS = (A \in E)%MS. Proof. by rewrite -map_mxvec map_submx. Qed. Lemma map_mulsmx m1 m2 n (E1 : 'A_(m1, n)) (E2 : 'A_(m2, n)) : ((E1 * E2)%MS^f :=: E1^f * E2^f)%MS. Proof. rewrite /mulsmx; elim/big_rec2: _ => [|i A Af _ eqA]; first by rewrite map_mx0. apply: (eqmx_trans (map_addsmx _ _)); apply: adds_eqmx {A Af}eqA. apply/eqmxP; rewrite !map_genmx !genmxE map_mxM. apply/rV_eqP=> u; congr (u <= _ *m _)%MS. by apply: map_lin_mx => //= A; rewrite map_mxM // map_vec_mx map_row. Qed. Lemma map_cent_mx m n (E : 'A_(m, n)) : ('C(E)%MS)^f = 'C(E^f)%MS. Proof. rewrite map_kermx //; congr (kermx _); apply: map_lin_mx => // A. rewrite map_mxM //; congr (_ *m _); apply: map_lin_mx => //= B. by rewrite map_mx_sub ? map_mxM. Qed. Lemma map_center_mx m n (E : 'A_(m, n)) : (('Z(E))^f :=: 'Z(E^f))%MS. Proof. by rewrite /center_mx -map_cent_mx; exact: map_capmx. Qed. End MapMatrixSpaces. mathcomp-1.5/theories/matrix.v0000644000175000017500000033220112307636117015477 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div choice fintype. Require Import finfun bigop prime binomial ssralg finset fingroup finalg. Require Import perm zmodp. (******************************************************************************) (* Basic concrete linear algebra : definition of type for matrices, and all *) (* basic matrix operations including determinant, trace and support for block *) (* decomposition. Matrices are represented by a row-major list of their *) (* coefficients but this implementation is hidden by three levels of wrappers *) (* (Matrix/Finfun/Tuple) so the matrix type should be treated as abstract and *) (* handled using only the operations described below: *) (* 'M[R]_(m, n) == the type of m rows by n columns matrices with *) (* 'M_(m, n) coefficients in R; the [R] is optional and is usually *) (* omitted. *) (* 'M[R]_n, 'M_n == the type of n x n square matrices. *) (* 'rV[R]_n, 'rV_n == the type of 1 x n row vectors. *) (* 'cV[R]_n, 'cV_n == the type of n x 1 column vectors. *) (* \matrix_(i < m, j < n) Expr(i, j) == *) (* the m x n matrix with general coefficient Expr(i, j), *) (* with i : 'I_m and j : 'I_n. the < m bound can be omitted *) (* if it is equal to n, though usually both bounds are *) (* omitted as they can be inferred from the context. *) (* \row_(j < n) Expr(j), \col_(i < m) Expr(i) *) (* the row / column vectors with general term Expr; the *) (* parentheses can be omitted along with the bound. *) (* \matrix_(i < m) RowExpr(i) == *) (* the m x n matrix with row i given by RowExpr(i) : 'rV_n. *) (* A i j == the coefficient of matrix A : 'M_(m, n) in column j of *) (* row i, where i : 'I_m, and j : 'I_n (via the coercion *) (* fun_of_matrix : matrix >-> Funclass). *) (* const_mx a == the constant matrix whose entries are all a (dimensions *) (* should be determined by context). *) (* map_mx f A == the pointwise image of A by f, i.e., the matrix Af *) (* congruent to A with Af i j = f (A i j) for all i and j. *) (* A^T == the matrix transpose of A. *) (* row i A == the i'th row of A (this is a row vector). *) (* col j A == the j'th column of A (a column vector). *) (* row' i A == A with the i'th row spliced out. *) (* col' i A == A with the j'th column spliced out. *) (* xrow i1 i2 A == A with rows i1 and i2 interchanged. *) (* xcol j1 j2 A == A with columns j1 and j2 interchanged. *) (* row_perm s A == A : 'M_(m, n) with rows permuted by s : 'S_m. *) (* col_perm s A == A : 'M_(m, n) with columns permuted by s : 'S_n. *) (* row_mx Al Ar == the row block matrix obtained by contatenating *) (* two matrices Al and Ar of the same height. *) (* col_mx Au Ad == the column block matrix / Au \ (Au and Ad must have the *) (* same width). \ Ad / *) (* block_mx Aul Aur Adl Adr == the block matrix / Aul Aur \ *) (* \ Adl Adr / *) (* [l|r]submx A == the left/right submatrices of a row block matrix A. *) (* Note that the type of A, 'M_(m, n1 + n2) indicates how A *) (* should be decomposed. *) (* [u|d]submx A == the up/down submatrices of a column block matrix A. *) (* [u|d][l|r]submx A == the upper left, etc submatrices of a block matrix A. *) (* castmx eq_mn A == A : 'M_(m, n) cast to 'M_(m', n') using the equation *) (* pair eq_mn : (m = m') * (n = n'). This is the usual *) (* workaround for the syntactic limitations of dependent *) (* types in Coq, and can be used to introduce a block *) (* decomposition. It simplifies to A when eq_mn is the *) (* pair (erefl m, erefl n) (using rewrite /castmx /=). *) (* conform_mx B A == A if A and B have the same dimensions, else B. *) (* mxvec A == a row vector of width m * n holding all the entries of *) (* the m x n matrix A. *) (* mxvec_index i j == the index of A i j in mxvec A. *) (* vec_mx v == the inverse of mxvec, reshaping a vector of width m * n *) (* back into into an m x n rectangular matrix. *) (* In 'M[R]_(m, n), R can be any type, but 'M[R]_(m, n) inherits the eqType, *) (* choiceType, countType, finType, zmodType structures of R; 'M[R]_(m, n) *) (* also has a natural lmodType R structure when R has a ringType structure. *) (* Because the type of matrices specifies their dimension, only non-trivial *) (* square matrices (of type 'M[R]_n.+1) can inherit the ring structure of R; *) (* indeed they then have an algebra structure (lalgType R, or algType R if R *) (* is a comRingType, or even unitAlgType if R is a comUnitRingType). *) (* We thus provide separate syntax for the general matrix multiplication, *) (* and other operations for matrices over a ringType R: *) (* A *m B == the matrix product of A and B; the width of A must be *) (* equal to the height of B. *) (* a%:M == the scalar matrix with a's on the main diagonal; in *) (* particular 1%:M denotes the identity matrix, and is is *) (* equal to 1%R when n is of the form n'.+1 (e.g., n >= 1). *) (* is_scalar_mx A <=> A is a scalar matrix (A = a%:M for some A). *) (* diag_mx d == the diagonal matrix whose main diagonal is d : 'rV_n. *) (* delta_mx i j == the matrix with a 1 in row i, column j and 0 elsewhere. *) (* pid_mx r == the partial identity matrix with 1s only on the r first *) (* coefficients of the main diagonal; the dimensions of *) (* pid_mx r are determined by the context, and pid_mx r can *) (* be rectangular. *) (* copid_mx r == the complement to 1%:M of pid_mx r: a square diagonal *) (* matrix with 1s on all but the first r coefficients on *) (* its main diagonal. *) (* perm_mx s == the n x n permutation matrix for s : 'S_n. *) (* tperm_mx i1 i2 == the permutation matrix that exchanges i1 i2 : 'I_n. *) (* is_perm_mx A == A is a permutation matrix. *) (* lift0_mx A == the 1 + n square matrix block_mx 1 0 0 A when A : 'M_n. *) (* \tr A == the trace of a square matrix A. *) (* \det A == the determinant of A, using the Leibnitz formula. *) (* cofactor i j A == the i, j cofactor of A (the signed i, j minor of A), *) (* \adj A == the adjugate matrix of A (\adj A i j = cofactor j i A). *) (* A \in unitmx == A is invertible (R must be a comUnitRingType). *) (* invmx A == the inverse matrix of A if A \in unitmx A, otherwise A. *) (* The following operations provide a correspondance between linear functions *) (* and matrices: *) (* lin1_mx f == the m x n matrix that emulates via right product *) (* a (linear) function f : 'rV_m -> 'rV_n on ROW VECTORS *) (* lin_mx f == the (m1 * n1) x (m2 * n2) matrix that emulates, via the *) (* right multiplication on the mxvec encodings, a linear *) (* function f : 'M_(m1, n1) -> 'M_(m2, n2) *) (* lin_mul_row u := lin1_mx (mulmx u \o vec_mx) (applies a row-encoded *) (* function to the row-vector u). *) (* mulmx A == partially applied matrix multiplication (mulmx A B is *) (* displayed as A *m B), with, for A : 'M_(m, n), a *) (* canonical {linear 'M_(n, p) -> 'M(m, p}} structure. *) (* mulmxr A == self-simplifying right-hand matrix multiplication, i.e., *) (* mulmxr A B simplifies to B *m A, with, for A : 'M_(n, p), *) (* a canonical {linear 'M_(m, n) -> 'M(m, p}} structure. *) (* lin_mulmx A := lin_mx (mulmx A). *) (* lin_mulmxr A := lin_mx (mulmxr A). *) (* We also extend any finType structure of R to 'M[R]_(m, n), and define: *) (* {'GL_n[R]} == the finGroupType of units of 'M[R]_n.-1.+1. *) (* 'GL_n[R] == the general linear group of all matrices in {'GL_n(R)}. *) (* 'GL_n(p) == 'GL_n['F_p], the general linear group of a prime field. *) (* GLval u == the coercion of u : {'GL_n(R)} to a matrix. *) (* In addition to the lemmas relevant to these definitions, this file also *) (* proves several classic results, including : *) (* - The determinant is a multilinear alternate form. *) (* - The Laplace determinant expansion formulas: expand_det_[row|col]. *) (* - The Cramer rule : mul_mx_adj & mul_adj_mx. *) (* Finally, as an example of the use of block products, we program and prove *) (* the correctness of a classical linear algebra algorithm: *) (* cormenLUP A == the triangular decomposition (L, U, P) of a nontrivial *) (* square matrix A into a lower triagular matrix L with 1s *) (* on the main diagonal, an upper matrix U, and a *) (* permutation matrix P, such that P * A = L * U. *) (* This is example only; we use a different, more precise algorithm to *) (* develop the theory of matrix ranks and row spaces in mxalgebra.v *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Import GRing.Theory. Open Local Scope ring_scope. Reserved Notation "''M_' n" (at level 8, n at level 2, format "''M_' n"). Reserved Notation "''rV_' n" (at level 8, n at level 2, format "''rV_' n"). Reserved Notation "''cV_' n" (at level 8, n at level 2, format "''cV_' n"). Reserved Notation "''M_' ( n )" (at level 8, only parsing). Reserved Notation "''M_' ( m , n )" (at level 8, format "''M_' ( m , n )"). Reserved Notation "''M[' R ]_ n" (at level 8, n at level 2, only parsing). Reserved Notation "''rV[' R ]_ n" (at level 8, n at level 2, only parsing). Reserved Notation "''cV[' R ]_ n" (at level 8, n at level 2, only parsing). Reserved Notation "''M[' R ]_ ( n )" (at level 8, only parsing). Reserved Notation "''M[' R ]_ ( m , n )" (at level 8, only parsing). Reserved Notation "\matrix_ i E" (at level 36, E at level 36, i at level 2, format "\matrix_ i E"). Reserved Notation "\matrix_ ( i < n ) E" (at level 36, E at level 36, i, n at level 50, only parsing). Reserved Notation "\matrix_ ( i , j ) E" (at level 36, E at level 36, i, j at level 50, format "\matrix_ ( i , j ) E"). Reserved Notation "\matrix[ k ]_ ( i , j ) E" (at level 36, E at level 36, i, j at level 50, format "\matrix[ k ]_ ( i , j ) E"). Reserved Notation "\matrix_ ( i < m , j < n ) E" (at level 36, E at level 36, i, m, j, n at level 50, only parsing). Reserved Notation "\matrix_ ( i , j < n ) E" (at level 36, E at level 36, i, j, n at level 50, only parsing). Reserved Notation "\row_ j E" (at level 36, E at level 36, j at level 2, format "\row_ j E"). Reserved Notation "\row_ ( j < n ) E" (at level 36, E at level 36, j, n at level 50, only parsing). Reserved Notation "\col_ j E" (at level 36, E at level 36, j at level 2, format "\col_ j E"). Reserved Notation "\col_ ( j < n ) E" (at level 36, E at level 36, j, n at level 50, only parsing). Reserved Notation "x %:M" (at level 8, format "x %:M"). Reserved Notation "A *m B" (at level 40, left associativity, format "A *m B"). Reserved Notation "A ^T" (at level 8, format "A ^T"). Reserved Notation "\tr A" (at level 10, A at level 8, format "\tr A"). Reserved Notation "\det A" (at level 10, A at level 8, format "\det A"). Reserved Notation "\adj A" (at level 10, A at level 8, format "\adj A"). Notation Local simp := (Monoid.Theory.simpm, oppr0). (*****************************************************************************) (****************************Type Definition**********************************) (*****************************************************************************) Section MatrixDef. Variable R : Type. Variables m n : nat. (* Basic linear algebra (matrices). *) (* We use dependent types (ordinals) for the indices so that ranges are *) (* mostly inferred automatically *) Inductive matrix : predArgType := Matrix of {ffun 'I_m * 'I_n -> R}. Definition mx_val A := let: Matrix g := A in g. Canonical matrix_subType := Eval hnf in [newType for mx_val]. Fact matrix_key : unit. Proof. by []. Qed. Definition matrix_of_fun_def F := Matrix [ffun ij => F ij.1 ij.2]. Definition matrix_of_fun k := locked_with k matrix_of_fun_def. Canonical matrix_unlockable k := [unlockable fun matrix_of_fun k]. Definition fun_of_matrix A (i : 'I_m) (j : 'I_n) := mx_val A (i, j). Coercion fun_of_matrix : matrix >-> Funclass. Lemma mxE k F : matrix_of_fun k F =2 F. Proof. by move=> i j; rewrite unlock /fun_of_matrix /= ffunE. Qed. Lemma matrixP (A B : matrix) : A =2 B <-> A = B. Proof. rewrite /fun_of_matrix; split=> [/= eqAB | -> //]. by apply/val_inj/ffunP=> [[i j]]; exact: eqAB. Qed. End MatrixDef. Bind Scope ring_scope with matrix. Notation "''M[' R ]_ ( m , n )" := (matrix R m n) (only parsing): type_scope. Notation "''rV[' R ]_ n" := 'M[R]_(1, n) (only parsing) : type_scope. Notation "''cV[' R ]_ n" := 'M[R]_(n, 1) (only parsing) : type_scope. Notation "''M[' R ]_ n" := 'M[R]_(n, n) (only parsing) : type_scope. Notation "''M[' R ]_ ( n )" := 'M[R]_n (only parsing) : type_scope. Notation "''M_' ( m , n )" := 'M[_]_(m, n) : type_scope. Notation "''rV_' n" := 'M_(1, n) : type_scope. Notation "''cV_' n" := 'M_(n, 1) : type_scope. Notation "''M_' n" := 'M_(n, n) : type_scope. Notation "''M_' ( n )" := 'M_n (only parsing) : type_scope. Notation "\matrix[ k ]_ ( i , j ) E" := (matrix_of_fun k (fun i j => E)) (at level 36, E at level 36, i, j at level 50): ring_scope. Notation "\matrix_ ( i < m , j < n ) E" := (@matrix_of_fun _ m n matrix_key (fun i j => E)) (only parsing) : ring_scope. Notation "\matrix_ ( i , j < n ) E" := (\matrix_(i < n, j < n) E) (only parsing) : ring_scope. Notation "\matrix_ ( i , j ) E" := (\matrix_(i < _, j < _) E) : ring_scope. Notation "\matrix_ ( i < m ) E" := (\matrix_(i < m, j < _) @fun_of_matrix _ 1 _ E 0 j) (only parsing) : ring_scope. Notation "\matrix_ i E" := (\matrix_(i < _) E) : ring_scope. Notation "\col_ ( i < n ) E" := (@matrix_of_fun _ n 1 matrix_key (fun i _ => E)) (only parsing) : ring_scope. Notation "\col_ i E" := (\col_(i < _) E) : ring_scope. Notation "\row_ ( j < n ) E" := (@matrix_of_fun _ 1 n matrix_key (fun _ j => E)) (only parsing) : ring_scope. Notation "\row_ j E" := (\row_(j < _) E) : ring_scope. Definition matrix_eqMixin (R : eqType) m n := Eval hnf in [eqMixin of 'M[R]_(m, n) by <:]. Canonical matrix_eqType (R : eqType) m n:= Eval hnf in EqType 'M[R]_(m, n) (matrix_eqMixin R m n). Definition matrix_choiceMixin (R : choiceType) m n := [choiceMixin of 'M[R]_(m, n) by <:]. Canonical matrix_choiceType (R : choiceType) m n := Eval hnf in ChoiceType 'M[R]_(m, n) (matrix_choiceMixin R m n). Definition matrix_countMixin (R : countType) m n := [countMixin of 'M[R]_(m, n) by <:]. Canonical matrix_countType (R : countType) m n := Eval hnf in CountType 'M[R]_(m, n) (matrix_countMixin R m n). Canonical matrix_subCountType (R : countType) m n := Eval hnf in [subCountType of 'M[R]_(m, n)]. Definition matrix_finMixin (R : finType) m n := [finMixin of 'M[R]_(m, n) by <:]. Canonical matrix_finType (R : finType) m n := Eval hnf in FinType 'M[R]_(m, n) (matrix_finMixin R m n). Canonical matrix_subFinType (R : finType) m n := Eval hnf in [subFinType of 'M[R]_(m, n)]. Lemma card_matrix (F : finType) m n : (#|{: 'M[F]_(m, n)}| = #|F| ^ (m * n))%N. Proof. by rewrite card_sub card_ffun card_prod !card_ord. Qed. (*****************************************************************************) (****** Matrix structural operations (transpose, permutation, blocks) ********) (*****************************************************************************) Section MatrixStructural. Variable R : Type. (* Constant matrix *) Fact const_mx_key : unit. Proof. by []. Qed. Definition const_mx m n a : 'M[R]_(m, n) := \matrix[const_mx_key]_(i, j) a. Implicit Arguments const_mx [[m] [n]]. Section FixedDim. (* Definitions and properties for which we can work with fixed dimensions. *) Variables m n : nat. Implicit Type A : 'M[R]_(m, n). (* Reshape a matrix, to accomodate the block functions for instance. *) Definition castmx m' n' (eq_mn : (m = m') * (n = n')) A : 'M_(m', n') := let: erefl in _ = m' := eq_mn.1 return 'M_(m', n') in let: erefl in _ = n' := eq_mn.2 return 'M_(m, n') in A. Definition conform_mx m' n' B A := match m =P m', n =P n' with | ReflectT eq_m, ReflectT eq_n => castmx (eq_m, eq_n) A | _, _ => B end. (* Transpose a matrix *) Fact trmx_key : unit. Proof. by []. Qed. Definition trmx A := \matrix[trmx_key]_(i, j) A j i. (* Permute a matrix vertically (rows) or horizontally (columns) *) Fact row_perm_key : unit. Proof. by []. Qed. Definition row_perm (s : 'S_m) A := \matrix[row_perm_key]_(i, j) A (s i) j. Fact col_perm_key : unit. Proof. by []. Qed. Definition col_perm (s : 'S_n) A := \matrix[col_perm_key]_(i, j) A i (s j). (* Exchange two rows/columns of a matrix *) Definition xrow i1 i2 := row_perm (tperm i1 i2). Definition xcol j1 j2 := col_perm (tperm j1 j2). (* Row/Column sub matrices of a matrix *) Definition row i0 A := \row_j A i0 j. Definition col j0 A := \col_i A i j0. (* Removing a row/column from a matrix *) Definition row' i0 A := \matrix_(i, j) A (lift i0 i) j. Definition col' j0 A := \matrix_(i, j) A i (lift j0 j). Lemma castmx_const m' n' (eq_mn : (m = m') * (n = n')) a : castmx eq_mn (const_mx a) = const_mx a. Proof. by case: eq_mn; case: m' /; case: n' /. Qed. Lemma trmx_const a : trmx (const_mx a) = const_mx a. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma row_perm_const s a : row_perm s (const_mx a) = const_mx a. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma col_perm_const s a : col_perm s (const_mx a) = const_mx a. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma xrow_const i1 i2 a : xrow i1 i2 (const_mx a) = const_mx a. Proof. exact: row_perm_const. Qed. Lemma xcol_const j1 j2 a : xcol j1 j2 (const_mx a) = const_mx a. Proof. exact: col_perm_const. Qed. Lemma rowP (u v : 'rV[R]_n) : u 0 =1 v 0 <-> u = v. Proof. by split=> [eq_uv | -> //]; apply/matrixP=> i; rewrite ord1. Qed. Lemma rowK u_ i0 : row i0 (\matrix_i u_ i) = u_ i0. Proof. by apply/rowP=> i'; rewrite !mxE. Qed. Lemma row_matrixP A B : (forall i, row i A = row i B) <-> A = B. Proof. split=> [eqAB | -> //]; apply/matrixP=> i j. by move/rowP/(_ j): (eqAB i); rewrite !mxE. Qed. Lemma colP (u v : 'cV[R]_m) : u^~ 0 =1 v^~ 0 <-> u = v. Proof. by split=> [eq_uv | -> //]; apply/matrixP=> i j; rewrite ord1. Qed. Lemma row_const i0 a : row i0 (const_mx a) = const_mx a. Proof. by apply/rowP=> j; rewrite !mxE. Qed. Lemma col_const j0 a : col j0 (const_mx a) = const_mx a. Proof. by apply/colP=> i; rewrite !mxE. Qed. Lemma row'_const i0 a : row' i0 (const_mx a) = const_mx a. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma col'_const j0 a : col' j0 (const_mx a) = const_mx a. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma col_perm1 A : col_perm 1 A = A. Proof. by apply/matrixP=> i j; rewrite mxE perm1. Qed. Lemma row_perm1 A : row_perm 1 A = A. Proof. by apply/matrixP=> i j; rewrite mxE perm1. Qed. Lemma col_permM s t A : col_perm (s * t) A = col_perm s (col_perm t A). Proof. by apply/matrixP=> i j; rewrite !mxE permM. Qed. Lemma row_permM s t A : row_perm (s * t) A = row_perm s (row_perm t A). Proof. by apply/matrixP=> i j; rewrite !mxE permM. Qed. Lemma col_row_permC s t A : col_perm s (row_perm t A) = row_perm t (col_perm s A). Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. End FixedDim. Local Notation "A ^T" := (trmx A) : ring_scope. Lemma castmx_id m n erefl_mn (A : 'M_(m, n)) : castmx erefl_mn A = A. Proof. by case: erefl_mn => e_m e_n; rewrite [e_m]eq_axiomK [e_n]eq_axiomK. Qed. Lemma castmx_comp m1 n1 m2 n2 m3 n3 (eq_m1 : m1 = m2) (eq_n1 : n1 = n2) (eq_m2 : m2 = m3) (eq_n2 : n2 = n3) A : castmx (eq_m2, eq_n2) (castmx (eq_m1, eq_n1) A) = castmx (etrans eq_m1 eq_m2, etrans eq_n1 eq_n2) A. Proof. by case: m2 / eq_m1 eq_m2; case: m3 /; case: n2 / eq_n1 eq_n2; case: n3 /. Qed. Lemma castmxK m1 n1 m2 n2 (eq_m : m1 = m2) (eq_n : n1 = n2) : cancel (castmx (eq_m, eq_n)) (castmx (esym eq_m, esym eq_n)). Proof. by case: m2 / eq_m; case: n2 / eq_n. Qed. Lemma castmxKV m1 n1 m2 n2 (eq_m : m1 = m2) (eq_n : n1 = n2) : cancel (castmx (esym eq_m, esym eq_n)) (castmx (eq_m, eq_n)). Proof. by case: m2 / eq_m; case: n2 / eq_n. Qed. (* This can be use to reverse an equation that involves a cast. *) Lemma castmx_sym m1 n1 m2 n2 (eq_m : m1 = m2) (eq_n : n1 = n2) A1 A2 : A1 = castmx (eq_m, eq_n) A2 -> A2 = castmx (esym eq_m, esym eq_n) A1. Proof. by move/(canLR (castmxK _ _)). Qed. Lemma castmxE m1 n1 m2 n2 (eq_mn : (m1 = m2) * (n1 = n2)) A i j : castmx eq_mn A i j = A (cast_ord (esym eq_mn.1) i) (cast_ord (esym eq_mn.2) j). Proof. by do [case: eq_mn; case: m2 /; case: n2 /] in A i j *; rewrite !cast_ord_id. Qed. Lemma conform_mx_id m n (B A : 'M_(m, n)) : conform_mx B A = A. Proof. by rewrite /conform_mx; do 2!case: eqP => // *; rewrite castmx_id. Qed. Lemma nonconform_mx m m' n n' (B : 'M_(m', n')) (A : 'M_(m, n)) : (m != m') || (n != n') -> conform_mx B A = B. Proof. by rewrite /conform_mx; do 2!case: eqP. Qed. Lemma conform_castmx m1 n1 m2 n2 m3 n3 (e_mn : (m2 = m3) * (n2 = n3)) (B : 'M_(m1, n1)) A : conform_mx B (castmx e_mn A) = conform_mx B A. Proof. by do [case: e_mn; case: m3 /; case: n3 /] in A *. Qed. Lemma trmxK m n : cancel (@trmx m n) (@trmx n m). Proof. by move=> A; apply/matrixP=> i j; rewrite !mxE. Qed. Lemma trmx_inj m n : injective (@trmx m n). Proof. exact: can_inj (@trmxK m n). Qed. Lemma trmx_cast m1 n1 m2 n2 (eq_mn : (m1 = m2) * (n1 = n2)) A : (castmx eq_mn A)^T = castmx (eq_mn.2, eq_mn.1) A^T. Proof. by case: eq_mn => eq_m eq_n; apply/matrixP=> i j; rewrite !(mxE, castmxE). Qed. Lemma tr_row_perm m n s (A : 'M_(m, n)) : (row_perm s A)^T = col_perm s A^T. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma tr_col_perm m n s (A : 'M_(m, n)) : (col_perm s A)^T = row_perm s A^T. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma tr_xrow m n i1 i2 (A : 'M_(m, n)) : (xrow i1 i2 A)^T = xcol i1 i2 A^T. Proof. exact: tr_row_perm. Qed. Lemma tr_xcol m n j1 j2 (A : 'M_(m, n)) : (xcol j1 j2 A)^T = xrow j1 j2 A^T. Proof. exact: tr_col_perm. Qed. Lemma row_id n i (V : 'rV_n) : row i V = V. Proof. by apply/rowP=> j; rewrite mxE [i]ord1. Qed. Lemma col_id n j (V : 'cV_n) : col j V = V. Proof. by apply/colP=> i; rewrite mxE [j]ord1. Qed. Lemma row_eq m1 m2 n i1 i2 (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : row i1 A1 = row i2 A2 -> A1 i1 =1 A2 i2. Proof. by move/rowP=> eqA12 j; have:= eqA12 j; rewrite !mxE. Qed. Lemma col_eq m n1 n2 j1 j2 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : col j1 A1 = col j2 A2 -> A1^~ j1 =1 A2^~ j2. Proof. by move/colP=> eqA12 i; have:= eqA12 i; rewrite !mxE. Qed. Lemma row'_eq m n i0 (A B : 'M_(m, n)) : row' i0 A = row' i0 B -> {in predC1 i0, A =2 B}. Proof. move/matrixP=> eqAB' i; rewrite !inE eq_sym; case/unlift_some=> i' -> _ j. by have:= eqAB' i' j; rewrite !mxE. Qed. Lemma col'_eq m n j0 (A B : 'M_(m, n)) : col' j0 A = col' j0 B -> forall i, {in predC1 j0, A i =1 B i}. Proof. move/matrixP=> eqAB' i j; rewrite !inE eq_sym; case/unlift_some=> j' -> _. by have:= eqAB' i j'; rewrite !mxE. Qed. Lemma tr_row m n i0 (A : 'M_(m, n)) : (row i0 A)^T = col i0 A^T. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma tr_row' m n i0 (A : 'M_(m, n)) : (row' i0 A)^T = col' i0 A^T. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma tr_col m n j0 (A : 'M_(m, n)) : (col j0 A)^T = row j0 A^T. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma tr_col' m n j0 (A : 'M_(m, n)) : (col' j0 A)^T = row' j0 A^T. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Ltac split_mxE := apply/matrixP=> i j; do ![rewrite mxE | case: split => ?]. Section CutPaste. Variables m m1 m2 n n1 n2 : nat. (* Concatenating two matrices, in either direction. *) Fact row_mx_key : unit. Proof. by []. Qed. Definition row_mx (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : 'M[R]_(m, n1 + n2) := \matrix[row_mx_key]_(i, j) match split j with inl j1 => A1 i j1 | inr j2 => A2 i j2 end. Fact col_mx_key : unit. Proof. by []. Qed. Definition col_mx (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : 'M[R]_(m1 + m2, n) := \matrix[col_mx_key]_(i, j) match split i with inl i1 => A1 i1 j | inr i2 => A2 i2 j end. (* Left/Right | Up/Down submatrices of a rows | columns matrix. *) (* The shape of the (dependent) width parameters of the type of A *) (* determines which submatrix is selected. *) Fact lsubmx_key : unit. Proof. by []. Qed. Definition lsubmx (A : 'M[R]_(m, n1 + n2)) := \matrix[lsubmx_key]_(i, j) A i (lshift n2 j). Fact rsubmx_key : unit. Proof. by []. Qed. Definition rsubmx (A : 'M[R]_(m, n1 + n2)) := \matrix[rsubmx_key]_(i, j) A i (rshift n1 j). Fact usubmx_key : unit. Proof. by []. Qed. Definition usubmx (A : 'M[R]_(m1 + m2, n)) := \matrix[usubmx_key]_(i, j) A (lshift m2 i) j. Fact dsubmx_key : unit. Proof. by []. Qed. Definition dsubmx (A : 'M[R]_(m1 + m2, n)) := \matrix[dsubmx_key]_(i, j) A (rshift m1 i) j. Lemma row_mxEl A1 A2 i j : row_mx A1 A2 i (lshift n2 j) = A1 i j. Proof. by rewrite mxE (unsplitK (inl _ _)). Qed. Lemma row_mxKl A1 A2 : lsubmx (row_mx A1 A2) = A1. Proof. by apply/matrixP=> i j; rewrite mxE row_mxEl. Qed. Lemma row_mxEr A1 A2 i j : row_mx A1 A2 i (rshift n1 j) = A2 i j. Proof. by rewrite mxE (unsplitK (inr _ _)). Qed. Lemma row_mxKr A1 A2 : rsubmx (row_mx A1 A2) = A2. Proof. by apply/matrixP=> i j; rewrite mxE row_mxEr. Qed. Lemma hsubmxK A : row_mx (lsubmx A) (rsubmx A) = A. Proof. apply/matrixP=> i j; rewrite !mxE. case: splitP => k Dk //=; rewrite !mxE //=; congr (A _ _); exact: val_inj. Qed. Lemma col_mxEu A1 A2 i j : col_mx A1 A2 (lshift m2 i) j = A1 i j. Proof. by rewrite mxE (unsplitK (inl _ _)). Qed. Lemma col_mxKu A1 A2 : usubmx (col_mx A1 A2) = A1. Proof. by apply/matrixP=> i j; rewrite mxE col_mxEu. Qed. Lemma col_mxEd A1 A2 i j : col_mx A1 A2 (rshift m1 i) j = A2 i j. Proof. by rewrite mxE (unsplitK (inr _ _)). Qed. Lemma col_mxKd A1 A2 : dsubmx (col_mx A1 A2) = A2. Proof. by apply/matrixP=> i j; rewrite mxE col_mxEd. Qed. Lemma eq_row_mx A1 A2 B1 B2 : row_mx A1 A2 = row_mx B1 B2 -> A1 = B1 /\ A2 = B2. Proof. move=> eqAB; move: (congr1 lsubmx eqAB) (congr1 rsubmx eqAB). by rewrite !(row_mxKl, row_mxKr). Qed. Lemma eq_col_mx A1 A2 B1 B2 : col_mx A1 A2 = col_mx B1 B2 -> A1 = B1 /\ A2 = B2. Proof. move=> eqAB; move: (congr1 usubmx eqAB) (congr1 dsubmx eqAB). by rewrite !(col_mxKu, col_mxKd). Qed. Lemma row_mx_const a : row_mx (const_mx a) (const_mx a) = const_mx a. Proof. by split_mxE. Qed. Lemma col_mx_const a : col_mx (const_mx a) (const_mx a) = const_mx a. Proof. by split_mxE. Qed. End CutPaste. Lemma trmx_lsub m n1 n2 (A : 'M_(m, n1 + n2)) : (lsubmx A)^T = usubmx A^T. Proof. by split_mxE. Qed. Lemma trmx_rsub m n1 n2 (A : 'M_(m, n1 + n2)) : (rsubmx A)^T = dsubmx A^T. Proof. by split_mxE. Qed. Lemma tr_row_mx m n1 n2 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : (row_mx A1 A2)^T = col_mx A1^T A2^T. Proof. by split_mxE. Qed. Lemma tr_col_mx m1 m2 n (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : (col_mx A1 A2)^T = row_mx A1^T A2^T. Proof. by split_mxE. Qed. Lemma trmx_usub m1 m2 n (A : 'M_(m1 + m2, n)) : (usubmx A)^T = lsubmx A^T. Proof. by split_mxE. Qed. Lemma trmx_dsub m1 m2 n (A : 'M_(m1 + m2, n)) : (dsubmx A)^T = rsubmx A^T. Proof. by split_mxE. Qed. Lemma vsubmxK m1 m2 n (A : 'M_(m1 + m2, n)) : col_mx (usubmx A) (dsubmx A) = A. Proof. by apply: trmx_inj; rewrite tr_col_mx trmx_usub trmx_dsub hsubmxK. Qed. Lemma cast_row_mx m m' n1 n2 (eq_m : m = m') A1 A2 : castmx (eq_m, erefl _) (row_mx A1 A2) = row_mx (castmx (eq_m, erefl n1) A1) (castmx (eq_m, erefl n2) A2). Proof. by case: m' / eq_m. Qed. Lemma cast_col_mx m1 m2 n n' (eq_n : n = n') A1 A2 : castmx (erefl _, eq_n) (col_mx A1 A2) = col_mx (castmx (erefl m1, eq_n) A1) (castmx (erefl m2, eq_n) A2). Proof. by case: n' / eq_n. Qed. (* This lemma has Prenex Implicits to help RL rewrititng with castmx_sym. *) Lemma row_mxA m n1 n2 n3 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) (A3 : 'M_(m, n3)) : let cast := (erefl m, esym (addnA n1 n2 n3)) in row_mx A1 (row_mx A2 A3) = castmx cast (row_mx (row_mx A1 A2) A3). Proof. apply: (canRL (castmxKV _ _)); apply/matrixP=> i j. rewrite castmxE !mxE cast_ord_id; case: splitP => j1 /= def_j. have: (j < n1 + n2) && (j < n1) by rewrite def_j lshift_subproof /=. by move: def_j; do 2![case: splitP => // ? ->; rewrite ?mxE] => /ord_inj->. case: splitP def_j => j2 ->{j} def_j; rewrite !mxE. have: ~~ (j2 < n1) by rewrite -leqNgt def_j leq_addr. have: j1 < n2 by rewrite -(ltn_add2l n1) -def_j. by move: def_j; do 2![case: splitP => // ? ->] => /addnI/val_inj->. have: ~~ (j1 < n2) by rewrite -leqNgt -(leq_add2l n1) -def_j leq_addr. by case: splitP def_j => // ? ->; rewrite addnA => /addnI/val_inj->. Qed. Definition row_mxAx := row_mxA. (* bypass Prenex Implicits. *) (* This lemma has Prenex Implicits to help RL rewrititng with castmx_sym. *) Lemma col_mxA m1 m2 m3 n (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) (A3 : 'M_(m3, n)) : let cast := (esym (addnA m1 m2 m3), erefl n) in col_mx A1 (col_mx A2 A3) = castmx cast (col_mx (col_mx A1 A2) A3). Proof. by apply: trmx_inj; rewrite trmx_cast !tr_col_mx -row_mxA. Qed. Definition col_mxAx := col_mxA. (* bypass Prenex Implicits. *) Lemma row_row_mx m n1 n2 i0 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : row i0 (row_mx A1 A2) = row_mx (row i0 A1) (row i0 A2). Proof. by apply/matrixP=> i j; rewrite !mxE; case: (split j) => j'; rewrite mxE. Qed. Lemma col_col_mx m1 m2 n j0 (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : col j0 (col_mx A1 A2) = col_mx (col j0 A1) (col j0 A2). Proof. by apply: trmx_inj; rewrite !(tr_col, tr_col_mx, row_row_mx). Qed. Lemma row'_row_mx m n1 n2 i0 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : row' i0 (row_mx A1 A2) = row_mx (row' i0 A1) (row' i0 A2). Proof. by apply/matrixP=> i j; rewrite !mxE; case: (split j) => j'; rewrite mxE. Qed. Lemma col'_col_mx m1 m2 n j0 (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : col' j0 (col_mx A1 A2) = col_mx (col' j0 A1) (col' j0 A2). Proof. by apply: trmx_inj; rewrite !(tr_col', tr_col_mx, row'_row_mx). Qed. Lemma colKl m n1 n2 j1 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : col (lshift n2 j1) (row_mx A1 A2) = col j1 A1. Proof. by apply/matrixP=> i j; rewrite !(row_mxEl, mxE). Qed. Lemma colKr m n1 n2 j2 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : col (rshift n1 j2) (row_mx A1 A2) = col j2 A2. Proof. by apply/matrixP=> i j; rewrite !(row_mxEr, mxE). Qed. Lemma rowKu m1 m2 n i1 (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : row (lshift m2 i1) (col_mx A1 A2) = row i1 A1. Proof. by apply/matrixP=> i j; rewrite !(col_mxEu, mxE). Qed. Lemma rowKd m1 m2 n i2 (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : row (rshift m1 i2) (col_mx A1 A2) = row i2 A2. Proof. by apply/matrixP=> i j; rewrite !(col_mxEd, mxE). Qed. Lemma col'Kl m n1 n2 j1 (A1 : 'M_(m, n1.+1)) (A2 : 'M_(m, n2)) : col' (lshift n2 j1) (row_mx A1 A2) = row_mx (col' j1 A1) A2. Proof. apply/matrixP=> i /= j; symmetry; rewrite 2!mxE. case: splitP => j' def_j'. rewrite mxE -(row_mxEl _ A2); congr (row_mx _ _ _); apply: ord_inj. by rewrite /= def_j'. rewrite -(row_mxEr A1); congr (row_mx _ _ _); apply: ord_inj => /=. by rewrite /bump def_j' -ltnS -addSn ltn_addr. Qed. Lemma row'Ku m1 m2 n i1 (A1 : 'M_(m1.+1, n)) (A2 : 'M_(m2, n)) : row' (lshift m2 i1) (@col_mx m1.+1 m2 n A1 A2) = col_mx (row' i1 A1) A2. Proof. by apply: trmx_inj; rewrite tr_col_mx !(@tr_row' _.+1) (@tr_col_mx _.+1) col'Kl. Qed. Lemma mx'_cast m n : 'I_n -> (m + n.-1)%N = (m + n).-1. Proof. by case=> j /ltn_predK <-; rewrite addnS. Qed. Lemma col'Kr m n1 n2 j2 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : col' (rshift n1 j2) (@row_mx m n1 n2 A1 A2) = castmx (erefl m, mx'_cast n1 j2) (row_mx A1 (col' j2 A2)). Proof. apply/matrixP=> i j; symmetry; rewrite castmxE mxE cast_ord_id. case: splitP => j' /= def_j. rewrite mxE -(row_mxEl _ A2); congr (row_mx _ _ _); apply: ord_inj. by rewrite /= def_j /bump leqNgt ltn_addr. rewrite 2!mxE -(row_mxEr A1); congr (row_mx _ _ _ _); apply: ord_inj. by rewrite /= def_j /bump leq_add2l addnCA. Qed. Lemma row'Kd m1 m2 n i2 (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : row' (rshift m1 i2) (col_mx A1 A2) = castmx (mx'_cast m1 i2, erefl n) (col_mx A1 (row' i2 A2)). Proof. by apply: trmx_inj; rewrite trmx_cast !(tr_row', tr_col_mx) col'Kr. Qed. Section Block. Variables m1 m2 n1 n2 : nat. (* Building a block matrix from 4 matrices : *) (* up left, up right, down left and down right components *) Definition block_mx Aul Aur Adl Adr : 'M_(m1 + m2, n1 + n2) := col_mx (row_mx Aul Aur) (row_mx Adl Adr). Lemma eq_block_mx Aul Aur Adl Adr Bul Bur Bdl Bdr : block_mx Aul Aur Adl Adr = block_mx Bul Bur Bdl Bdr -> [/\ Aul = Bul, Aur = Bur, Adl = Bdl & Adr = Bdr]. Proof. by case/eq_col_mx; do 2!case/eq_row_mx=> -> ->. Qed. Lemma block_mx_const a : block_mx (const_mx a) (const_mx a) (const_mx a) (const_mx a) = const_mx a. Proof. by split_mxE. Qed. Section CutBlock. Variable A : matrix R (m1 + m2) (n1 + n2). Definition ulsubmx := lsubmx (usubmx A). Definition ursubmx := rsubmx (usubmx A). Definition dlsubmx := lsubmx (dsubmx A). Definition drsubmx := rsubmx (dsubmx A). Lemma submxK : block_mx ulsubmx ursubmx dlsubmx drsubmx = A. Proof. by rewrite /block_mx !hsubmxK vsubmxK. Qed. End CutBlock. Section CatBlock. Variables (Aul : 'M[R]_(m1, n1)) (Aur : 'M[R]_(m1, n2)). Variables (Adl : 'M[R]_(m2, n1)) (Adr : 'M[R]_(m2, n2)). Let A := block_mx Aul Aur Adl Adr. Lemma block_mxEul i j : A (lshift m2 i) (lshift n2 j) = Aul i j. Proof. by rewrite col_mxEu row_mxEl. Qed. Lemma block_mxKul : ulsubmx A = Aul. Proof. by rewrite /ulsubmx col_mxKu row_mxKl. Qed. Lemma block_mxEur i j : A (lshift m2 i) (rshift n1 j) = Aur i j. Proof. by rewrite col_mxEu row_mxEr. Qed. Lemma block_mxKur : ursubmx A = Aur. Proof. by rewrite /ursubmx col_mxKu row_mxKr. Qed. Lemma block_mxEdl i j : A (rshift m1 i) (lshift n2 j) = Adl i j. Proof. by rewrite col_mxEd row_mxEl. Qed. Lemma block_mxKdl : dlsubmx A = Adl. Proof. by rewrite /dlsubmx col_mxKd row_mxKl. Qed. Lemma block_mxEdr i j : A (rshift m1 i) (rshift n1 j) = Adr i j. Proof. by rewrite col_mxEd row_mxEr. Qed. Lemma block_mxKdr : drsubmx A = Adr. Proof. by rewrite /drsubmx col_mxKd row_mxKr. Qed. Lemma block_mxEv : A = col_mx (row_mx Aul Aur) (row_mx Adl Adr). Proof. by []. Qed. End CatBlock. End Block. Section TrCutBlock. Variables m1 m2 n1 n2 : nat. Variable A : 'M[R]_(m1 + m2, n1 + n2). Lemma trmx_ulsub : (ulsubmx A)^T = ulsubmx A^T. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma trmx_ursub : (ursubmx A)^T = dlsubmx A^T. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma trmx_dlsub : (dlsubmx A)^T = ursubmx A^T. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma trmx_drsub : (drsubmx A)^T = drsubmx A^T. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. End TrCutBlock. Section TrBlock. Variables m1 m2 n1 n2 : nat. Variables (Aul : 'M[R]_(m1, n1)) (Aur : 'M[R]_(m1, n2)). Variables (Adl : 'M[R]_(m2, n1)) (Adr : 'M[R]_(m2, n2)). Lemma tr_block_mx : (block_mx Aul Aur Adl Adr)^T = block_mx Aul^T Adl^T Aur^T Adr^T. Proof. rewrite -[_^T]submxK -trmx_ulsub -trmx_ursub -trmx_dlsub -trmx_drsub. by rewrite block_mxKul block_mxKur block_mxKdl block_mxKdr. Qed. Lemma block_mxEh : block_mx Aul Aur Adl Adr = row_mx (col_mx Aul Adl) (col_mx Aur Adr). Proof. by apply: trmx_inj; rewrite tr_block_mx tr_row_mx 2!tr_col_mx. Qed. End TrBlock. (* This lemma has Prenex Implicits to help RL rewrititng with castmx_sym. *) Lemma block_mxA m1 m2 m3 n1 n2 n3 (A11 : 'M_(m1, n1)) (A12 : 'M_(m1, n2)) (A13 : 'M_(m1, n3)) (A21 : 'M_(m2, n1)) (A22 : 'M_(m2, n2)) (A23 : 'M_(m2, n3)) (A31 : 'M_(m3, n1)) (A32 : 'M_(m3, n2)) (A33 : 'M_(m3, n3)) : let cast := (esym (addnA m1 m2 m3), esym (addnA n1 n2 n3)) in let row1 := row_mx A12 A13 in let col1 := col_mx A21 A31 in let row3 := row_mx A31 A32 in let col3 := col_mx A13 A23 in block_mx A11 row1 col1 (block_mx A22 A23 A32 A33) = castmx cast (block_mx (block_mx A11 A12 A21 A22) col3 row3 A33). Proof. rewrite /= block_mxEh !col_mxA -cast_row_mx -block_mxEv -block_mxEh. rewrite block_mxEv block_mxEh !row_mxA -cast_col_mx -block_mxEh -block_mxEv. by rewrite castmx_comp etrans_id. Qed. Definition block_mxAx := block_mxA. (* Bypass Prenex Implicits *) (* Bijections mxvec : 'M_(m, n) <----> 'rV_(m * n) : vec_mx *) Section VecMatrix. Variables m n : nat. Lemma mxvec_cast : #|{:'I_m * 'I_n}| = (m * n)%N. Proof. by rewrite card_prod !card_ord. Qed. Definition mxvec_index (i : 'I_m) (j : 'I_n) := cast_ord mxvec_cast (enum_rank (i, j)). CoInductive is_mxvec_index : 'I_(m * n) -> Type := IsMxvecIndex i j : is_mxvec_index (mxvec_index i j). Lemma mxvec_indexP k : is_mxvec_index k. Proof. rewrite -[k](cast_ordK (esym mxvec_cast)) esymK. by rewrite -[_ k]enum_valK; case: (enum_val _). Qed. Coercion pair_of_mxvec_index k (i_k : is_mxvec_index k) := let: IsMxvecIndex i j := i_k in (i, j). Definition mxvec (A : 'M[R]_(m, n)) := castmx (erefl _, mxvec_cast) (\row_k A (enum_val k).1 (enum_val k).2). Fact vec_mx_key : unit. Proof. by []. Qed. Definition vec_mx (u : 'rV[R]_(m * n)) := \matrix[vec_mx_key]_(i, j) u 0 (mxvec_index i j). Lemma mxvecE A i j : mxvec A 0 (mxvec_index i j) = A i j. Proof. by rewrite castmxE mxE cast_ordK enum_rankK. Qed. Lemma mxvecK : cancel mxvec vec_mx. Proof. by move=> A; apply/matrixP=> i j; rewrite mxE mxvecE. Qed. Lemma vec_mxK : cancel vec_mx mxvec. Proof. by move=> u; apply/rowP=> k; case/mxvec_indexP: k => i j; rewrite mxvecE mxE. Qed. Lemma curry_mxvec_bij : {on 'I_(m * n), bijective (prod_curry mxvec_index)}. Proof. exists (enum_val \o cast_ord (esym mxvec_cast)) => [[i j] _ | k _] /=. by rewrite cast_ordK enum_rankK. by case/mxvec_indexP: k => i j /=; rewrite cast_ordK enum_rankK. Qed. End VecMatrix. End MatrixStructural. Implicit Arguments const_mx [R m n]. Implicit Arguments row_mxA [R m n1 n2 n3 A1 A2 A3]. Implicit Arguments col_mxA [R m1 m2 m3 n A1 A2 A3]. Implicit Arguments block_mxA [R m1 m2 m3 n1 n2 n3 A11 A12 A13 A21 A22 A23 A31 A32 A33]. Prenex Implicits const_mx castmx trmx lsubmx rsubmx usubmx dsubmx row_mx col_mx. Prenex Implicits block_mx ulsubmx ursubmx dlsubmx drsubmx. Prenex Implicits row_mxA col_mxA block_mxA. Prenex Implicits mxvec vec_mx mxvec_indexP mxvecK vec_mxK. Notation "A ^T" := (trmx A) : ring_scope. (* Matrix parametricity. *) Section MapMatrix. Variables (aT rT : Type) (f : aT -> rT). Fact map_mx_key : unit. Proof. by []. Qed. Definition map_mx m n (A : 'M_(m, n)) := \matrix[map_mx_key]_(i, j) f (A i j). Notation "A ^f" := (map_mx A) : ring_scope. Section OneMatrix. Variables (m n : nat) (A : 'M[aT]_(m, n)). Lemma map_trmx : A^f^T = A^T^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_const_mx a : (const_mx a)^f = const_mx (f a) :> 'M_(m, n). Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_row i : (row i A)^f = row i A^f. Proof. by apply/rowP=> j; rewrite !mxE. Qed. Lemma map_col j : (col j A)^f = col j A^f. Proof. by apply/colP=> i; rewrite !mxE. Qed. Lemma map_row' i0 : (row' i0 A)^f = row' i0 A^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_col' j0 : (col' j0 A)^f = col' j0 A^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_row_perm s : (row_perm s A)^f = row_perm s A^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_col_perm s : (col_perm s A)^f = col_perm s A^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_xrow i1 i2 : (xrow i1 i2 A)^f = xrow i1 i2 A^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_xcol j1 j2 : (xcol j1 j2 A)^f = xcol j1 j2 A^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_castmx m' n' c : (castmx c A)^f = castmx c A^f :> 'M_(m', n'). Proof. by apply/matrixP=> i j; rewrite !(castmxE, mxE). Qed. Lemma map_conform_mx m' n' (B : 'M_(m', n')) : (conform_mx B A)^f = conform_mx B^f A^f. Proof. move: B; have [[<- <-] B|] := eqVneq (m, n) (m', n'). by rewrite !conform_mx_id. by rewrite negb_and => neq_mn B; rewrite !nonconform_mx. Qed. Lemma map_mxvec : (mxvec A)^f = mxvec A^f. Proof. by apply/rowP=> i; rewrite !(castmxE, mxE). Qed. Lemma map_vec_mx (v : 'rV_(m * n)) : (vec_mx v)^f = vec_mx v^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. End OneMatrix. Section Block. Variables m1 m2 n1 n2 : nat. Variables (Aul : 'M[aT]_(m1, n1)) (Aur : 'M[aT]_(m1, n2)). Variables (Adl : 'M[aT]_(m2, n1)) (Adr : 'M[aT]_(m2, n2)). Variables (Bh : 'M[aT]_(m1, n1 + n2)) (Bv : 'M[aT]_(m1 + m2, n1)). Variable B : 'M[aT]_(m1 + m2, n1 + n2). Lemma map_row_mx : (row_mx Aul Aur)^f = row_mx Aul^f Aur^f. Proof. by apply/matrixP=> i j; do 2![rewrite !mxE //; case: split => ?]. Qed. Lemma map_col_mx : (col_mx Aul Adl)^f = col_mx Aul^f Adl^f. Proof. by apply/matrixP=> i j; do 2![rewrite !mxE //; case: split => ?]. Qed. Lemma map_block_mx : (block_mx Aul Aur Adl Adr)^f = block_mx Aul^f Aur^f Adl^f Adr^f. Proof. by apply/matrixP=> i j; do 3![rewrite !mxE //; case: split => ?]. Qed. Lemma map_lsubmx : (lsubmx Bh)^f = lsubmx Bh^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_rsubmx : (rsubmx Bh)^f = rsubmx Bh^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_usubmx : (usubmx Bv)^f = usubmx Bv^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_dsubmx : (dsubmx Bv)^f = dsubmx Bv^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_ulsubmx : (ulsubmx B)^f = ulsubmx B^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_ursubmx : (ursubmx B)^f = ursubmx B^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_dlsubmx : (dlsubmx B)^f = dlsubmx B^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma map_drsubmx : (drsubmx B)^f = drsubmx B^f. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. End Block. End MapMatrix. (*****************************************************************************) (********************* Matrix Zmodule (additive) structure *******************) (*****************************************************************************) Section MatrixZmodule. Variable V : zmodType. Section FixedDim. Variables m n : nat. Implicit Types A B : 'M[V]_(m, n). Fact oppmx_key : unit. Proof. by []. Qed. Fact addmx_key : unit. Proof. by []. Qed. Definition oppmx A := \matrix[oppmx_key]_(i, j) (- A i j). Definition addmx A B := \matrix[addmx_key]_(i, j) (A i j + B i j). (* In principle, diag_mx and scalar_mx could be defined here, but since they *) (* only make sense with the graded ring operations, we defer them to the *) (* next section. *) Lemma addmxA : associative addmx. Proof. by move=> A B C; apply/matrixP=> i j; rewrite !mxE addrA. Qed. Lemma addmxC : commutative addmx. Proof. by move=> A B; apply/matrixP=> i j; rewrite !mxE addrC. Qed. Lemma add0mx : left_id (const_mx 0) addmx. Proof. by move=> A; apply/matrixP=> i j; rewrite !mxE add0r. Qed. Lemma addNmx : left_inverse (const_mx 0) oppmx addmx. Proof. by move=> A; apply/matrixP=> i j; rewrite !mxE addNr. Qed. Definition matrix_zmodMixin := ZmodMixin addmxA addmxC add0mx addNmx. Canonical matrix_zmodType := Eval hnf in ZmodType 'M[V]_(m, n) matrix_zmodMixin. Lemma mulmxnE A d i j : (A *+ d) i j = A i j *+ d. Proof. by elim: d => [|d IHd]; rewrite ?mulrS mxE ?IHd. Qed. Lemma summxE I r (P : pred I) (E : I -> 'M_(m, n)) i j : (\sum_(k <- r | P k) E k) i j = \sum_(k <- r | P k) E k i j. Proof. by apply: (big_morph (fun A => A i j)) => [A B|]; rewrite mxE. Qed. Lemma const_mx_is_additive : additive const_mx. Proof. by move=> a b; apply/matrixP=> i j; rewrite !mxE. Qed. Canonical const_mx_additive := Additive const_mx_is_additive. End FixedDim. Section Additive. Variables (m n p q : nat) (f : 'I_p -> 'I_q -> 'I_m) (g : 'I_p -> 'I_q -> 'I_n). Definition swizzle_mx k (A : 'M[V]_(m, n)) := \matrix[k]_(i, j) A (f i j) (g i j). Lemma swizzle_mx_is_additive k : additive (swizzle_mx k). Proof. by move=> A B; apply/matrixP=> i j; rewrite !mxE. Qed. Canonical swizzle_mx_additive k := Additive (swizzle_mx_is_additive k). End Additive. Local Notation SwizzleAdd op := [additive of op as swizzle_mx _ _ _]. Canonical trmx_additive m n := SwizzleAdd (@trmx V m n). Canonical row_additive m n i := SwizzleAdd (@row V m n i). Canonical col_additive m n j := SwizzleAdd (@col V m n j). Canonical row'_additive m n i := SwizzleAdd (@row' V m n i). Canonical col'_additive m n j := SwizzleAdd (@col' V m n j). Canonical row_perm_additive m n s := SwizzleAdd (@row_perm V m n s). Canonical col_perm_additive m n s := SwizzleAdd (@col_perm V m n s). Canonical xrow_additive m n i1 i2 := SwizzleAdd (@xrow V m n i1 i2). Canonical xcol_additive m n j1 j2 := SwizzleAdd (@xcol V m n j1 j2). Canonical lsubmx_additive m n1 n2 := SwizzleAdd (@lsubmx V m n1 n2). Canonical rsubmx_additive m n1 n2 := SwizzleAdd (@rsubmx V m n1 n2). Canonical usubmx_additive m1 m2 n := SwizzleAdd (@usubmx V m1 m2 n). Canonical dsubmx_additive m1 m2 n := SwizzleAdd (@dsubmx V m1 m2 n). Canonical vec_mx_additive m n := SwizzleAdd (@vec_mx V m n). Canonical mxvec_additive m n := Additive (can2_additive (@vec_mxK V m n) mxvecK). Lemma flatmx0 n : all_equal_to (0 : 'M_(0, n)). Proof. by move=> A; apply/matrixP=> [] []. Qed. Lemma thinmx0 n : all_equal_to (0 : 'M_(n, 0)). Proof. by move=> A; apply/matrixP=> i []. Qed. Lemma trmx0 m n : (0 : 'M_(m, n))^T = 0. Proof. exact: trmx_const. Qed. Lemma row0 m n i0 : row i0 (0 : 'M_(m, n)) = 0. Proof. exact: row_const. Qed. Lemma col0 m n j0 : col j0 (0 : 'M_(m, n)) = 0. Proof. exact: col_const. Qed. Lemma mxvec_eq0 m n (A : 'M_(m, n)) : (mxvec A == 0) = (A == 0). Proof. by rewrite (can2_eq mxvecK vec_mxK) raddf0. Qed. Lemma vec_mx_eq0 m n (v : 'rV_(m * n)) : (vec_mx v == 0) = (v == 0). Proof. by rewrite (can2_eq vec_mxK mxvecK) raddf0. Qed. Lemma row_mx0 m n1 n2 : row_mx 0 0 = 0 :> 'M_(m, n1 + n2). Proof. exact: row_mx_const. Qed. Lemma col_mx0 m1 m2 n : col_mx 0 0 = 0 :> 'M_(m1 + m2, n). Proof. exact: col_mx_const. Qed. Lemma block_mx0 m1 m2 n1 n2 : block_mx 0 0 0 0 = 0 :> 'M_(m1 + m2, n1 + n2). Proof. exact: block_mx_const. Qed. Ltac split_mxE := apply/matrixP=> i j; do ![rewrite mxE | case: split => ?]. Lemma opp_row_mx m n1 n2 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : - row_mx A1 A2 = row_mx (- A1) (- A2). Proof. by split_mxE. Qed. Lemma opp_col_mx m1 m2 n (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : - col_mx A1 A2 = col_mx (- A1) (- A2). Proof. by split_mxE. Qed. Lemma opp_block_mx m1 m2 n1 n2 (Aul : 'M_(m1, n1)) Aur Adl (Adr : 'M_(m2, n2)) : - block_mx Aul Aur Adl Adr = block_mx (- Aul) (- Aur) (- Adl) (- Adr). Proof. by rewrite opp_col_mx !opp_row_mx. Qed. Lemma add_row_mx m n1 n2 (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) B1 B2 : row_mx A1 A2 + row_mx B1 B2 = row_mx (A1 + B1) (A2 + B2). Proof. by split_mxE. Qed. Lemma add_col_mx m1 m2 n (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) B1 B2 : col_mx A1 A2 + col_mx B1 B2 = col_mx (A1 + B1) (A2 + B2). Proof. by split_mxE. Qed. Lemma add_block_mx m1 m2 n1 n2 (Aul : 'M_(m1, n1)) Aur Adl (Adr : 'M_(m2, n2)) Bul Bur Bdl Bdr : let A := block_mx Aul Aur Adl Adr in let B := block_mx Bul Bur Bdl Bdr in A + B = block_mx (Aul + Bul) (Aur + Bur) (Adl + Bdl) (Adr + Bdr). Proof. by rewrite /= add_col_mx !add_row_mx. Qed. Definition nz_row m n (A : 'M_(m, n)) := oapp (fun i => row i A) 0 [pick i | row i A != 0]. Lemma nz_row_eq0 m n (A : 'M_(m, n)) : (nz_row A == 0) = (A == 0). Proof. rewrite /nz_row; symmetry; case: pickP => [i /= nzAi | Ai0]. by rewrite (negbTE nzAi); apply: contraTF nzAi => /eqP->; rewrite row0 eqxx. by rewrite eqxx; apply/eqP/row_matrixP=> i; move/eqP: (Ai0 i) ->; rewrite row0. Qed. End MatrixZmodule. Section FinZmodMatrix. Variables (V : finZmodType) (m n : nat). Local Notation MV := 'M[V]_(m, n). Canonical matrix_finZmodType := Eval hnf in [finZmodType of MV]. Canonical matrix_baseFinGroupType := Eval hnf in [baseFinGroupType of MV for +%R]. Canonical matrix_finGroupType := Eval hnf in [finGroupType of MV for +%R]. End FinZmodMatrix. (* Parametricity over the additive structure. *) Section MapZmodMatrix. Variables (aR rR : zmodType) (f : {additive aR -> rR}) (m n : nat). Local Notation "A ^f" := (map_mx f A) : ring_scope. Implicit Type A : 'M[aR]_(m, n). Lemma map_mx0 : 0^f = 0 :> 'M_(m, n). Proof. by rewrite map_const_mx raddf0. Qed. Lemma map_mxN A : (- A)^f = - A^f. Proof. by apply/matrixP=> i j; rewrite !mxE raddfN. Qed. Lemma map_mxD A B : (A + B)^f = A^f + B^f. Proof. by apply/matrixP=> i j; rewrite !mxE raddfD. Qed. Lemma map_mx_sub A B : (A - B)^f = A^f - B^f. Proof. by rewrite map_mxD map_mxN. Qed. Definition map_mx_sum := big_morph _ map_mxD map_mx0. Canonical map_mx_additive := Additive map_mx_sub. End MapZmodMatrix. (*****************************************************************************) (*********** Matrix ring module, graded ring, and ring structures ************) (*****************************************************************************) Section MatrixAlgebra. Variable R : ringType. Section RingModule. (* The ring module/vector space structure *) Variables m n : nat. Implicit Types A B : 'M[R]_(m, n). Fact scalemx_key : unit. Proof. by []. Qed. Definition scalemx x A := \matrix[scalemx_key]_(i, j) (x * A i j). (* Basis *) Fact delta_mx_key : unit. Proof. by []. Qed. Definition delta_mx i0 j0 : 'M[R]_(m, n) := \matrix[delta_mx_key]_(i, j) ((i == i0) && (j == j0))%:R. Local Notation "x *m: A" := (scalemx x A) (at level 40) : ring_scope. Lemma scale1mx A : 1 *m: A = A. Proof. by apply/matrixP=> i j; rewrite !mxE mul1r. Qed. Lemma scalemxDl A x y : (x + y) *m: A = x *m: A + y *m: A. Proof. by apply/matrixP=> i j; rewrite !mxE mulrDl. Qed. Lemma scalemxDr x A B : x *m: (A + B) = x *m: A + x *m: B. Proof. by apply/matrixP=> i j; rewrite !mxE mulrDr. Qed. Lemma scalemxA x y A : x *m: (y *m: A) = (x * y) *m: A. Proof. by apply/matrixP=> i j; rewrite !mxE mulrA. Qed. Definition matrix_lmodMixin := LmodMixin scalemxA scale1mx scalemxDr scalemxDl. Canonical matrix_lmodType := Eval hnf in LmodType R 'M[R]_(m, n) matrix_lmodMixin. Lemma scalemx_const a b : a *: const_mx b = const_mx (a * b). Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma matrix_sum_delta A : A = \sum_(i < m) \sum_(j < n) A i j *: delta_mx i j. Proof. apply/matrixP=> i j. rewrite summxE (bigD1 i) // summxE (bigD1 j) //= !mxE !eqxx mulr1. rewrite !big1 ?addr0 //= => [i' | j']; rewrite eq_sym => /negbTE diff. by rewrite summxE big1 // => j' _; rewrite !mxE diff mulr0. by rewrite !mxE eqxx diff mulr0. Qed. End RingModule. Section StructuralLinear. Lemma swizzle_mx_is_scalable m n p q f g k : scalable (@swizzle_mx R m n p q f g k). Proof. by move=> a A; apply/matrixP=> i j; rewrite !mxE. Qed. Canonical swizzle_mx_scalable m n p q f g k := AddLinear (@swizzle_mx_is_scalable m n p q f g k). Local Notation SwizzleLin op := [linear of op as swizzle_mx _ _ _]. Canonical trmx_linear m n := SwizzleLin (@trmx R m n). Canonical row_linear m n i := SwizzleLin (@row R m n i). Canonical col_linear m n j := SwizzleLin (@col R m n j). Canonical row'_linear m n i := SwizzleLin (@row' R m n i). Canonical col'_linear m n j := SwizzleLin (@col' R m n j). Canonical row_perm_linear m n s := SwizzleLin (@row_perm R m n s). Canonical col_perm_linear m n s := SwizzleLin (@col_perm R m n s). Canonical xrow_linear m n i1 i2 := SwizzleLin (@xrow R m n i1 i2). Canonical xcol_linear m n j1 j2 := SwizzleLin (@xcol R m n j1 j2). Canonical lsubmx_linear m n1 n2 := SwizzleLin (@lsubmx R m n1 n2). Canonical rsubmx_linear m n1 n2 := SwizzleLin (@rsubmx R m n1 n2). Canonical usubmx_linear m1 m2 n := SwizzleLin (@usubmx R m1 m2 n). Canonical dsubmx_linear m1 m2 n := SwizzleLin (@dsubmx R m1 m2 n). Canonical vec_mx_linear m n := SwizzleLin (@vec_mx R m n). Definition mxvec_is_linear m n := can2_linear (@vec_mxK R m n) mxvecK. Canonical mxvec_linear m n := AddLinear (@mxvec_is_linear m n). End StructuralLinear. Lemma trmx_delta m n i j : (delta_mx i j)^T = delta_mx j i :> 'M[R]_(n, m). Proof. by apply/matrixP=> i' j'; rewrite !mxE andbC. Qed. Lemma row_sum_delta n (u : 'rV_n) : u = \sum_(j < n) u 0 j *: delta_mx 0 j. Proof. by rewrite {1}[u]matrix_sum_delta big_ord1. Qed. Lemma delta_mx_lshift m n1 n2 i j : delta_mx i (lshift n2 j) = row_mx (delta_mx i j) 0 :> 'M_(m, n1 + n2). Proof. apply/matrixP=> i' j'; rewrite !mxE -(can_eq (@splitK _ _)). by rewrite (unsplitK (inl _ _)); case: split => ?; rewrite mxE ?andbF. Qed. Lemma delta_mx_rshift m n1 n2 i j : delta_mx i (rshift n1 j) = row_mx 0 (delta_mx i j) :> 'M_(m, n1 + n2). Proof. apply/matrixP=> i' j'; rewrite !mxE -(can_eq (@splitK _ _)). by rewrite (unsplitK (inr _ _)); case: split => ?; rewrite mxE ?andbF. Qed. Lemma delta_mx_ushift m1 m2 n i j : delta_mx (lshift m2 i) j = col_mx (delta_mx i j) 0 :> 'M_(m1 + m2, n). Proof. apply/matrixP=> i' j'; rewrite !mxE -(can_eq (@splitK _ _)). by rewrite (unsplitK (inl _ _)); case: split => ?; rewrite mxE. Qed. Lemma delta_mx_dshift m1 m2 n i j : delta_mx (rshift m1 i) j = col_mx 0 (delta_mx i j) :> 'M_(m1 + m2, n). Proof. apply/matrixP=> i' j'; rewrite !mxE -(can_eq (@splitK _ _)). by rewrite (unsplitK (inr _ _)); case: split => ?; rewrite mxE. Qed. Lemma vec_mx_delta m n i j : vec_mx (delta_mx 0 (mxvec_index i j)) = delta_mx i j :> 'M_(m, n). Proof. by apply/matrixP=> i' j'; rewrite !mxE /= [_ == _](inj_eq enum_rank_inj). Qed. Lemma mxvec_delta m n i j : mxvec (delta_mx i j) = delta_mx 0 (mxvec_index i j) :> 'rV_(m * n). Proof. by rewrite -vec_mx_delta vec_mxK. Qed. Ltac split_mxE := apply/matrixP=> i j; do ![rewrite mxE | case: split => ?]. Lemma scale_row_mx m n1 n2 a (A1 : 'M_(m, n1)) (A2 : 'M_(m, n2)) : a *: row_mx A1 A2 = row_mx (a *: A1) (a *: A2). Proof. by split_mxE. Qed. Lemma scale_col_mx m1 m2 n a (A1 : 'M_(m1, n)) (A2 : 'M_(m2, n)) : a *: col_mx A1 A2 = col_mx (a *: A1) (a *: A2). Proof. by split_mxE. Qed. Lemma scale_block_mx m1 m2 n1 n2 a (Aul : 'M_(m1, n1)) (Aur : 'M_(m1, n2)) (Adl : 'M_(m2, n1)) (Adr : 'M_(m2, n2)) : a *: block_mx Aul Aur Adl Adr = block_mx (a *: Aul) (a *: Aur) (a *: Adl) (a *: Adr). Proof. by rewrite scale_col_mx !scale_row_mx. Qed. (* Diagonal matrices *) Fact diag_mx_key : unit. Proof. by []. Qed. Definition diag_mx n (d : 'rV[R]_n) := \matrix[diag_mx_key]_(i, j) (d 0 i *+ (i == j)). Lemma tr_diag_mx n (d : 'rV_n) : (diag_mx d)^T = diag_mx d. Proof. by apply/matrixP=> i j; rewrite !mxE eq_sym; case: eqP => // ->. Qed. Lemma diag_mx_is_linear n : linear (@diag_mx n). Proof. by move=> a A B; apply/matrixP=> i j; rewrite !mxE mulrnAr mulrnDl. Qed. Canonical diag_mx_additive n := Additive (@diag_mx_is_linear n). Canonical diag_mx_linear n := Linear (@diag_mx_is_linear n). Lemma diag_mx_sum_delta n (d : 'rV_n) : diag_mx d = \sum_i d 0 i *: delta_mx i i. Proof. apply/matrixP=> i j; rewrite summxE (bigD1 i) //= !mxE eqxx /=. rewrite eq_sym mulr_natr big1 ?addr0 // => i' ne_i'i. by rewrite !mxE eq_sym (negbTE ne_i'i) mulr0. Qed. (* Scalar matrix : a diagonal matrix with a constant on the diagonal *) Section ScalarMx. Variable n : nat. Fact scalar_mx_key : unit. Proof. by []. Qed. Definition scalar_mx x : 'M[R]_n := \matrix[scalar_mx_key]_(i , j) (x *+ (i == j)). Notation "x %:M" := (scalar_mx x) : ring_scope. Lemma diag_const_mx a : diag_mx (const_mx a) = a%:M :> 'M_n. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma tr_scalar_mx a : (a%:M)^T = a%:M. Proof. by apply/matrixP=> i j; rewrite !mxE eq_sym. Qed. Lemma trmx1 : (1%:M)^T = 1%:M. Proof. exact: tr_scalar_mx. Qed. Lemma scalar_mx_is_additive : additive scalar_mx. Proof. by move=> a b; rewrite -!diag_const_mx !raddfB. Qed. Canonical scalar_mx_additive := Additive scalar_mx_is_additive. Lemma scale_scalar_mx a1 a2 : a1 *: a2%:M = (a1 * a2)%:M :> 'M_n. Proof. by apply/matrixP=> i j; rewrite !mxE mulrnAr. Qed. Lemma scalemx1 a : a *: 1%:M = a%:M. Proof. by rewrite scale_scalar_mx mulr1. Qed. Lemma scalar_mx_sum_delta a : a%:M = \sum_i a *: delta_mx i i. Proof. by rewrite -diag_const_mx diag_mx_sum_delta; apply: eq_bigr => i _; rewrite mxE. Qed. Lemma mx1_sum_delta : 1%:M = \sum_i delta_mx i i. Proof. by rewrite [1%:M]scalar_mx_sum_delta -scaler_sumr scale1r. Qed. Lemma row1 i : row i 1%:M = delta_mx 0 i. Proof. by apply/rowP=> j; rewrite !mxE eq_sym. Qed. Definition is_scalar_mx (A : 'M[R]_n) := if insub 0%N is Some i then A == (A i i)%:M else true. Lemma is_scalar_mxP A : reflect (exists a, A = a%:M) (is_scalar_mx A). Proof. rewrite /is_scalar_mx; case: insubP => [i _ _ | ]. by apply: (iffP eqP) => [|[a ->]]; [exists (A i i) | rewrite mxE eqxx]. rewrite -eqn0Ngt => /eqP n0; left; exists 0. by rewrite raddf0; rewrite n0 in A *; rewrite [A]flatmx0. Qed. Lemma scalar_mx_is_scalar a : is_scalar_mx a%:M. Proof. by apply/is_scalar_mxP; exists a. Qed. Lemma mx0_is_scalar : is_scalar_mx 0. Proof. by apply/is_scalar_mxP; exists 0; rewrite raddf0. Qed. End ScalarMx. Notation "x %:M" := (scalar_mx _ x) : ring_scope. Lemma mx11_scalar (A : 'M_1) : A = (A 0 0)%:M. Proof. by apply/rowP=> j; rewrite ord1 mxE. Qed. Lemma scalar_mx_block n1 n2 a : a%:M = block_mx a%:M 0 0 a%:M :> 'M_(n1 + n2). Proof. apply/matrixP=> i j; rewrite !mxE -val_eqE /=. by do 2![case: splitP => ? ->; rewrite !mxE]; rewrite ?eqn_add2l // -?(eq_sym (n1 + _)%N) eqn_leq leqNgt lshift_subproof. Qed. (* Matrix multiplication using bigops. *) Fact mulmx_key : unit. Proof. by []. Qed. Definition mulmx {m n p} (A : 'M_(m, n)) (B : 'M_(n, p)) : 'M[R]_(m, p) := \matrix[mulmx_key]_(i, k) \sum_j (A i j * B j k). Local Notation "A *m B" := (mulmx A B) : ring_scope. Lemma mulmxA m n p q (A : 'M_(m, n)) (B : 'M_(n, p)) (C : 'M_(p, q)) : A *m (B *m C) = A *m B *m C. Proof. apply/matrixP=> i l; rewrite !mxE. transitivity (\sum_j (\sum_k (A i j * (B j k * C k l)))). by apply: eq_bigr => j _; rewrite mxE big_distrr. rewrite exchange_big; apply: eq_bigr => j _; rewrite mxE big_distrl /=. by apply: eq_bigr => k _; rewrite mulrA. Qed. Lemma mul0mx m n p (A : 'M_(n, p)) : 0 *m A = 0 :> 'M_(m, p). Proof. by apply/matrixP=> i k; rewrite !mxE big1 //= => j _; rewrite mxE mul0r. Qed. Lemma mulmx0 m n p (A : 'M_(m, n)) : A *m 0 = 0 :> 'M_(m, p). Proof. by apply/matrixP=> i k; rewrite !mxE big1 // => j _; rewrite mxE mulr0. Qed. Lemma mulmxN m n p (A : 'M_(m, n)) (B : 'M_(n, p)) : A *m (- B) = - (A *m B). Proof. apply/matrixP=> i k; rewrite !mxE -sumrN. by apply: eq_bigr => j _; rewrite mxE mulrN. Qed. Lemma mulNmx m n p (A : 'M_(m, n)) (B : 'M_(n, p)) : - A *m B = - (A *m B). Proof. apply/matrixP=> i k; rewrite !mxE -sumrN. by apply: eq_bigr => j _; rewrite mxE mulNr. Qed. Lemma mulmxDl m n p (A1 A2 : 'M_(m, n)) (B : 'M_(n, p)) : (A1 + A2) *m B = A1 *m B + A2 *m B. Proof. apply/matrixP=> i k; rewrite !mxE -big_split /=. by apply: eq_bigr => j _; rewrite !mxE -mulrDl. Qed. Lemma mulmxDr m n p (A : 'M_(m, n)) (B1 B2 : 'M_(n, p)) : A *m (B1 + B2) = A *m B1 + A *m B2. Proof. apply/matrixP=> i k; rewrite !mxE -big_split /=. by apply: eq_bigr => j _; rewrite mxE mulrDr. Qed. Lemma mulmxBl m n p (A1 A2 : 'M_(m, n)) (B : 'M_(n, p)) : (A1 - A2) *m B = A1 *m B - A2 *m B. Proof. by rewrite mulmxDl mulNmx. Qed. Lemma mulmxBr m n p (A : 'M_(m, n)) (B1 B2 : 'M_(n, p)) : A *m (B1 - B2) = A *m B1 - A *m B2. Proof. by rewrite mulmxDr mulmxN. Qed. Lemma mulmx_suml m n p (A : 'M_(n, p)) I r P (B_ : I -> 'M_(m, n)) : (\sum_(i <- r | P i) B_ i) *m A = \sum_(i <- r | P i) B_ i *m A. Proof. by apply: (big_morph (mulmx^~ A)) => [B C|]; rewrite ?mul0mx ?mulmxDl. Qed. Lemma mulmx_sumr m n p (A : 'M_(m, n)) I r P (B_ : I -> 'M_(n, p)) : A *m (\sum_(i <- r | P i) B_ i) = \sum_(i <- r | P i) A *m B_ i. Proof. by apply: (big_morph (mulmx A)) => [B C|]; rewrite ?mulmx0 ?mulmxDr. Qed. Lemma scalemxAl m n p a (A : 'M_(m, n)) (B : 'M_(n, p)) : a *: (A *m B) = (a *: A) *m B. Proof. apply/matrixP=> i k; rewrite !mxE big_distrr /=. by apply: eq_bigr => j _; rewrite mulrA mxE. Qed. (* Right scaling associativity requires a commutative ring *) Lemma rowE m n i (A : 'M_(m, n)) : row i A = delta_mx 0 i *m A. Proof. apply/rowP=> j; rewrite !mxE (bigD1 i) //= mxE !eqxx mul1r. by rewrite big1 ?addr0 // => i' ne_i'i; rewrite mxE /= (negbTE ne_i'i) mul0r. Qed. Lemma row_mul m n p (i : 'I_m) A (B : 'M_(n, p)) : row i (A *m B) = row i A *m B. Proof. by rewrite !rowE mulmxA. Qed. Lemma mulmx_sum_row m n (u : 'rV_m) (A : 'M_(m, n)) : u *m A = \sum_i u 0 i *: row i A. Proof. by apply/rowP=> j; rewrite mxE summxE; apply: eq_bigr => i _; rewrite !mxE. Qed. Lemma mul_delta_mx_cond m n p (j1 j2 : 'I_n) (i1 : 'I_m) (k2 : 'I_p) : delta_mx i1 j1 *m delta_mx j2 k2 = delta_mx i1 k2 *+ (j1 == j2). Proof. apply/matrixP=> i k; rewrite !mxE (bigD1 j1) //=. rewrite mulmxnE !mxE !eqxx andbT -natrM -mulrnA !mulnb !andbA andbAC. by rewrite big1 ?addr0 // => j; rewrite !mxE andbC -natrM; move/negbTE->. Qed. Lemma mul_delta_mx m n p (j : 'I_n) (i : 'I_m) (k : 'I_p) : delta_mx i j *m delta_mx j k = delta_mx i k. Proof. by rewrite mul_delta_mx_cond eqxx. Qed. Lemma mul_delta_mx_0 m n p (j1 j2 : 'I_n) (i1 : 'I_m) (k2 : 'I_p) : j1 != j2 -> delta_mx i1 j1 *m delta_mx j2 k2 = 0. Proof. by rewrite mul_delta_mx_cond => /negbTE->. Qed. Lemma mul_diag_mx m n d (A : 'M_(m, n)) : diag_mx d *m A = \matrix_(i, j) (d 0 i * A i j). Proof. apply/matrixP=> i j; rewrite !mxE (bigD1 i) //= mxE eqxx big1 ?addr0 // => i'. by rewrite mxE eq_sym mulrnAl => /negbTE->. Qed. Lemma mul_mx_diag m n (A : 'M_(m, n)) d : A *m diag_mx d = \matrix_(i, j) (A i j * d 0 j). Proof. apply/matrixP=> i j; rewrite !mxE (bigD1 j) //= mxE eqxx big1 ?addr0 // => i'. by rewrite mxE eq_sym mulrnAr; move/negbTE->. Qed. Lemma mulmx_diag n (d e : 'rV_n) : diag_mx d *m diag_mx e = diag_mx (\row_j (d 0 j * e 0 j)). Proof. by apply/matrixP=> i j; rewrite mul_diag_mx !mxE mulrnAr. Qed. Lemma mul_scalar_mx m n a (A : 'M_(m, n)) : a%:M *m A = a *: A. Proof. by rewrite -diag_const_mx mul_diag_mx; apply/matrixP=> i j; rewrite !mxE. Qed. Lemma scalar_mxM n a b : (a * b)%:M = a%:M *m b%:M :> 'M_n. Proof. by rewrite mul_scalar_mx scale_scalar_mx. Qed. Lemma mul1mx m n (A : 'M_(m, n)) : 1%:M *m A = A. Proof. by rewrite mul_scalar_mx scale1r. Qed. Lemma mulmx1 m n (A : 'M_(m, n)) : A *m 1%:M = A. Proof. rewrite -diag_const_mx mul_mx_diag. by apply/matrixP=> i j; rewrite !mxE mulr1. Qed. Lemma mul_col_perm m n p s (A : 'M_(m, n)) (B : 'M_(n, p)) : col_perm s A *m B = A *m row_perm s^-1 B. Proof. apply/matrixP=> i k; rewrite !mxE (reindex_inj (@perm_inj _ s^-1)). by apply: eq_bigr => j _ /=; rewrite !mxE permKV. Qed. Lemma mul_row_perm m n p s (A : 'M_(m, n)) (B : 'M_(n, p)) : A *m row_perm s B = col_perm s^-1 A *m B. Proof. by rewrite mul_col_perm invgK. Qed. Lemma mul_xcol m n p j1 j2 (A : 'M_(m, n)) (B : 'M_(n, p)) : xcol j1 j2 A *m B = A *m xrow j1 j2 B. Proof. by rewrite mul_col_perm tpermV. Qed. (* Permutation matrix *) Definition perm_mx n s : 'M_n := row_perm s 1%:M. Definition tperm_mx n i1 i2 : 'M_n := perm_mx (tperm i1 i2). Lemma col_permE m n s (A : 'M_(m, n)) : col_perm s A = A *m perm_mx s^-1. Proof. by rewrite mul_row_perm mulmx1 invgK. Qed. Lemma row_permE m n s (A : 'M_(m, n)) : row_perm s A = perm_mx s *m A. Proof. by rewrite -[perm_mx _]mul1mx mul_row_perm mulmx1 -mul_row_perm mul1mx. Qed. Lemma xcolE m n j1 j2 (A : 'M_(m, n)) : xcol j1 j2 A = A *m tperm_mx j1 j2. Proof. by rewrite /xcol col_permE tpermV. Qed. Lemma xrowE m n i1 i2 (A : 'M_(m, n)) : xrow i1 i2 A = tperm_mx i1 i2 *m A. Proof. exact: row_permE. Qed. Lemma tr_perm_mx n (s : 'S_n) : (perm_mx s)^T = perm_mx s^-1. Proof. by rewrite -[_^T]mulmx1 tr_row_perm mul_col_perm trmx1 mul1mx. Qed. Lemma tr_tperm_mx n i1 i2 : (tperm_mx i1 i2)^T = tperm_mx i1 i2 :> 'M_n. Proof. by rewrite tr_perm_mx tpermV. Qed. Lemma perm_mx1 n : perm_mx 1 = 1%:M :> 'M_n. Proof. exact: row_perm1. Qed. Lemma perm_mxM n (s t : 'S_n) : perm_mx (s * t) = perm_mx s *m perm_mx t. Proof. by rewrite -row_permE -row_permM. Qed. Definition is_perm_mx n (A : 'M_n) := [exists s, A == perm_mx s]. Lemma is_perm_mxP n (A : 'M_n) : reflect (exists s, A = perm_mx s) (is_perm_mx A). Proof. by apply: (iffP existsP) => [] [s /eqP]; exists s. Qed. Lemma perm_mx_is_perm n (s : 'S_n) : is_perm_mx (perm_mx s). Proof. by apply/is_perm_mxP; exists s. Qed. Lemma is_perm_mx1 n : is_perm_mx (1%:M : 'M_n). Proof. by rewrite -perm_mx1 perm_mx_is_perm. Qed. Lemma is_perm_mxMl n (A B : 'M_n) : is_perm_mx A -> is_perm_mx (A *m B) = is_perm_mx B. Proof. case/is_perm_mxP=> s ->. apply/is_perm_mxP/is_perm_mxP=> [[t def_t] | [t ->]]; last first. by exists (s * t)%g; rewrite perm_mxM. exists (s^-1 * t)%g. by rewrite perm_mxM -def_t -!row_permE -row_permM mulVg row_perm1. Qed. Lemma is_perm_mx_tr n (A : 'M_n) : is_perm_mx A^T = is_perm_mx A. Proof. apply/is_perm_mxP/is_perm_mxP=> [[t def_t] | [t ->]]; exists t^-1%g. by rewrite -tr_perm_mx -def_t trmxK. by rewrite tr_perm_mx. Qed. Lemma is_perm_mxMr n (A B : 'M_n) : is_perm_mx B -> is_perm_mx (A *m B) = is_perm_mx A. Proof. case/is_perm_mxP=> s ->. rewrite -[s]invgK -col_permE -is_perm_mx_tr tr_col_perm row_permE. by rewrite is_perm_mxMl (perm_mx_is_perm, is_perm_mx_tr). Qed. (* Partial identity matrix (used in rank decomposition). *) Fact pid_mx_key : unit. Proof. by []. Qed. Definition pid_mx {m n} r : 'M[R]_(m, n) := \matrix[pid_mx_key]_(i, j) ((i == j :> nat) && (i < r))%:R. Lemma pid_mx_0 m n : pid_mx 0 = 0 :> 'M_(m, n). Proof. by apply/matrixP=> i j; rewrite !mxE andbF. Qed. Lemma pid_mx_1 r : pid_mx r = 1%:M :> 'M_r. Proof. by apply/matrixP=> i j; rewrite !mxE ltn_ord andbT. Qed. Lemma pid_mx_row n r : pid_mx r = row_mx 1%:M 0 :> 'M_(r, r + n). Proof. apply/matrixP=> i j; rewrite !mxE ltn_ord andbT. case: splitP => j' ->; rewrite !mxE // . by rewrite eqn_leq andbC leqNgt lshift_subproof. Qed. Lemma pid_mx_col m r : pid_mx r = col_mx 1%:M 0 :> 'M_(r + m, r). Proof. apply/matrixP=> i j; rewrite !mxE andbC. by case: splitP => i' ->; rewrite !mxE // eq_sym. Qed. Lemma pid_mx_block m n r : pid_mx r = block_mx 1%:M 0 0 0 :> 'M_(r + m, r + n). Proof. apply/matrixP=> i j; rewrite !mxE row_mx0 andbC. case: splitP => i' ->; rewrite !mxE //; case: splitP => j' ->; rewrite !mxE //=. by rewrite eqn_leq andbC leqNgt lshift_subproof. Qed. Lemma tr_pid_mx m n r : (pid_mx r)^T = pid_mx r :> 'M_(n, m). Proof. by apply/matrixP=> i j; rewrite !mxE eq_sym; case: eqP => // ->. Qed. Lemma pid_mx_minv m n r : pid_mx (minn m r) = pid_mx r :> 'M_(m, n). Proof. by apply/matrixP=> i j; rewrite !mxE leq_min ltn_ord. Qed. Lemma pid_mx_minh m n r : pid_mx (minn n r) = pid_mx r :> 'M_(m, n). Proof. by apply: trmx_inj; rewrite !tr_pid_mx pid_mx_minv. Qed. Lemma mul_pid_mx m n p q r : (pid_mx q : 'M_(m, n)) *m (pid_mx r : 'M_(n, p)) = pid_mx (minn n (minn q r)). Proof. apply/matrixP=> i k; rewrite !mxE !leq_min. have [le_n_i | lt_i_n] := leqP n i. rewrite andbF big1 // => j _. by rewrite -pid_mx_minh !mxE leq_min ltnNge le_n_i andbF mul0r. rewrite (bigD1 (Ordinal lt_i_n)) //= big1 ?addr0 => [|j]. by rewrite !mxE eqxx /= -natrM mulnb andbCA. by rewrite -val_eqE /= !mxE eq_sym -natrM => /negbTE->. Qed. Lemma pid_mx_id m n p r : r <= n -> (pid_mx r : 'M_(m, n)) *m (pid_mx r : 'M_(n, p)) = pid_mx r. Proof. by move=> le_r_n; rewrite mul_pid_mx minnn (minn_idPr _). Qed. Definition copid_mx {n} r : 'M_n := 1%:M - pid_mx r. Lemma mul_copid_mx_pid m n r : r <= m -> copid_mx r *m pid_mx r = 0 :> 'M_(m, n). Proof. by move=> le_r_m; rewrite mulmxBl mul1mx pid_mx_id ?subrr. Qed. Lemma mul_pid_mx_copid m n r : r <= n -> pid_mx r *m copid_mx r = 0 :> 'M_(m, n). Proof. by move=> le_r_n; rewrite mulmxBr mulmx1 pid_mx_id ?subrr. Qed. Lemma copid_mx_id n r : r <= n -> copid_mx r *m copid_mx r = copid_mx r :> 'M_n. Proof. by move=> le_r_n; rewrite mulmxBl mul1mx mul_pid_mx_copid // oppr0 addr0. Qed. (* Block products; we cover all 1 x 2, 2 x 1, and 2 x 2 block products. *) Lemma mul_mx_row m n p1 p2 (A : 'M_(m, n)) (Bl : 'M_(n, p1)) (Br : 'M_(n, p2)) : A *m row_mx Bl Br = row_mx (A *m Bl) (A *m Br). Proof. apply/matrixP=> i k; rewrite !mxE. by case defk: (split k); rewrite mxE; apply: eq_bigr => j _; rewrite mxE defk. Qed. Lemma mul_col_mx m1 m2 n p (Au : 'M_(m1, n)) (Ad : 'M_(m2, n)) (B : 'M_(n, p)) : col_mx Au Ad *m B = col_mx (Au *m B) (Ad *m B). Proof. apply/matrixP=> i k; rewrite !mxE. by case defi: (split i); rewrite mxE; apply: eq_bigr => j _; rewrite mxE defi. Qed. Lemma mul_row_col m n1 n2 p (Al : 'M_(m, n1)) (Ar : 'M_(m, n2)) (Bu : 'M_(n1, p)) (Bd : 'M_(n2, p)) : row_mx Al Ar *m col_mx Bu Bd = Al *m Bu + Ar *m Bd. Proof. apply/matrixP=> i k; rewrite !mxE big_split_ord /=. congr (_ + _); apply: eq_bigr => j _; first by rewrite row_mxEl col_mxEu. by rewrite row_mxEr col_mxEd. Qed. Lemma mul_col_row m1 m2 n p1 p2 (Au : 'M_(m1, n)) (Ad : 'M_(m2, n)) (Bl : 'M_(n, p1)) (Br : 'M_(n, p2)) : col_mx Au Ad *m row_mx Bl Br = block_mx (Au *m Bl) (Au *m Br) (Ad *m Bl) (Ad *m Br). Proof. by rewrite mul_col_mx !mul_mx_row. Qed. Lemma mul_row_block m n1 n2 p1 p2 (Al : 'M_(m, n1)) (Ar : 'M_(m, n2)) (Bul : 'M_(n1, p1)) (Bur : 'M_(n1, p2)) (Bdl : 'M_(n2, p1)) (Bdr : 'M_(n2, p2)) : row_mx Al Ar *m block_mx Bul Bur Bdl Bdr = row_mx (Al *m Bul + Ar *m Bdl) (Al *m Bur + Ar *m Bdr). Proof. by rewrite block_mxEh mul_mx_row !mul_row_col. Qed. Lemma mul_block_col m1 m2 n1 n2 p (Aul : 'M_(m1, n1)) (Aur : 'M_(m1, n2)) (Adl : 'M_(m2, n1)) (Adr : 'M_(m2, n2)) (Bu : 'M_(n1, p)) (Bd : 'M_(n2, p)) : block_mx Aul Aur Adl Adr *m col_mx Bu Bd = col_mx (Aul *m Bu + Aur *m Bd) (Adl *m Bu + Adr *m Bd). Proof. by rewrite mul_col_mx !mul_row_col. Qed. Lemma mulmx_block m1 m2 n1 n2 p1 p2 (Aul : 'M_(m1, n1)) (Aur : 'M_(m1, n2)) (Adl : 'M_(m2, n1)) (Adr : 'M_(m2, n2)) (Bul : 'M_(n1, p1)) (Bur : 'M_(n1, p2)) (Bdl : 'M_(n2, p1)) (Bdr : 'M_(n2, p2)) : block_mx Aul Aur Adl Adr *m block_mx Bul Bur Bdl Bdr = block_mx (Aul *m Bul + Aur *m Bdl) (Aul *m Bur + Aur *m Bdr) (Adl *m Bul + Adr *m Bdl) (Adl *m Bur + Adr *m Bdr). Proof. by rewrite mul_col_mx !mul_row_block. Qed. (* Correspondance between matrices and linear function on row vectors. *) Section LinRowVector. Variables m n : nat. Fact lin1_mx_key : unit. Proof. by []. Qed. Definition lin1_mx (f : 'rV[R]_m -> 'rV[R]_n) := \matrix[lin1_mx_key]_(i, j) f (delta_mx 0 i) 0 j. Variable f : {linear 'rV[R]_m -> 'rV[R]_n}. Lemma mul_rV_lin1 u : u *m lin1_mx f = f u. Proof. rewrite {2}[u]matrix_sum_delta big_ord1 linear_sum; apply/rowP=> i. by rewrite mxE summxE; apply: eq_bigr => j _; rewrite linearZ !mxE. Qed. End LinRowVector. (* Correspondance between matrices and linear function on matrices. *) Section LinMatrix. Variables m1 n1 m2 n2 : nat. Definition lin_mx (f : 'M[R]_(m1, n1) -> 'M[R]_(m2, n2)) := lin1_mx (mxvec \o f \o vec_mx). Variable f : {linear 'M[R]_(m1, n1) -> 'M[R]_(m2, n2)}. Lemma mul_rV_lin u : u *m lin_mx f = mxvec (f (vec_mx u)). Proof. exact: mul_rV_lin1. Qed. Lemma mul_vec_lin A : mxvec A *m lin_mx f = mxvec (f A). Proof. by rewrite mul_rV_lin mxvecK. Qed. Lemma mx_rV_lin u : vec_mx (u *m lin_mx f) = f (vec_mx u). Proof. by rewrite mul_rV_lin mxvecK. Qed. Lemma mx_vec_lin A : vec_mx (mxvec A *m lin_mx f) = f A. Proof. by rewrite mul_rV_lin !mxvecK. Qed. End LinMatrix. Canonical mulmx_additive m n p A := Additive (@mulmxBr m n p A). Section Mulmxr. Variables m n p : nat. Implicit Type A : 'M[R]_(m, n). Implicit Type B : 'M[R]_(n, p). Definition mulmxr_head t B A := let: tt := t in A *m B. Local Notation mulmxr := (mulmxr_head tt). Definition lin_mulmxr B := lin_mx (mulmxr B). Lemma mulmxr_is_linear B : linear (mulmxr B). Proof. by move=> a A1 A2; rewrite /= mulmxDl scalemxAl. Qed. Canonical mulmxr_additive B := Additive (mulmxr_is_linear B). Canonical mulmxr_linear B := Linear (mulmxr_is_linear B). Lemma lin_mulmxr_is_linear : linear lin_mulmxr. Proof. move=> a A B; apply/row_matrixP; case/mxvec_indexP=> i j. rewrite linearP /= !rowE !mul_rV_lin /= vec_mx_delta -linearP mulmxDr. congr (mxvec (_ + _)); apply/row_matrixP=> k. rewrite linearZ /= !row_mul rowE mul_delta_mx_cond. by case: (k == i); [rewrite -!rowE linearZ | rewrite !mul0mx raddf0]. Qed. Canonical lin_mulmxr_additive := Additive lin_mulmxr_is_linear. Canonical lin_mulmxr_linear := Linear lin_mulmxr_is_linear. End Mulmxr. (* The trace. *) Section Trace. Variable n : nat. Definition mxtrace (A : 'M[R]_n) := \sum_i A i i. Local Notation "'\tr' A" := (mxtrace A) : ring_scope. Lemma mxtrace_tr A : \tr A^T = \tr A. Proof. by apply: eq_bigr=> i _; rewrite mxE. Qed. Lemma mxtrace_is_scalar : scalar mxtrace. Proof. move=> a A B; rewrite mulr_sumr -big_split /=; apply: eq_bigr=> i _. by rewrite !mxE. Qed. Canonical mxtrace_additive := Additive mxtrace_is_scalar. Canonical mxtrace_linear := Linear mxtrace_is_scalar. Lemma mxtrace0 : \tr 0 = 0. Proof. exact: raddf0. Qed. Lemma mxtraceD A B : \tr (A + B) = \tr A + \tr B. Proof. exact: raddfD. Qed. Lemma mxtraceZ a A : \tr (a *: A) = a * \tr A. Proof. exact: scalarZ. Qed. Lemma mxtrace_diag D : \tr (diag_mx D) = \sum_j D 0 j. Proof. by apply: eq_bigr => j _; rewrite mxE eqxx. Qed. Lemma mxtrace_scalar a : \tr a%:M = a *+ n. Proof. rewrite -diag_const_mx mxtrace_diag. by rewrite (eq_bigr _ (fun j _ => mxE _ _ 0 j)) sumr_const card_ord. Qed. Lemma mxtrace1 : \tr 1%:M = n%:R. Proof. exact: mxtrace_scalar. Qed. End Trace. Local Notation "'\tr' A" := (mxtrace A) : ring_scope. Lemma trace_mx11 (A : 'M_1) : \tr A = A 0 0. Proof. by rewrite {1}[A]mx11_scalar mxtrace_scalar. Qed. Lemma mxtrace_block n1 n2 (Aul : 'M_n1) Aur Adl (Adr : 'M_n2) : \tr (block_mx Aul Aur Adl Adr) = \tr Aul + \tr Adr. Proof. rewrite /(\tr _) big_split_ord /=. by congr (_ + _); apply: eq_bigr => i _; rewrite (block_mxEul, block_mxEdr). Qed. (* The matrix ring structure requires a strutural condition (dimension of the *) (* form n.+1) to statisfy the nontriviality condition we have imposed. *) Section MatrixRing. Variable n' : nat. Local Notation n := n'.+1. Lemma matrix_nonzero1 : 1%:M != 0 :> 'M_n. Proof. by apply/eqP=> /matrixP/(_ 0 0)/eqP; rewrite !mxE oner_eq0. Qed. Definition matrix_ringMixin := RingMixin (@mulmxA n n n n) (@mul1mx n n) (@mulmx1 n n) (@mulmxDl n n n) (@mulmxDr n n n) matrix_nonzero1. Canonical matrix_ringType := Eval hnf in RingType 'M[R]_n matrix_ringMixin. Canonical matrix_lAlgType := Eval hnf in LalgType R 'M[R]_n (@scalemxAl n n n). Lemma mulmxE : mulmx = *%R. Proof. by []. Qed. Lemma idmxE : 1%:M = 1 :> 'M_n. Proof. by []. Qed. Lemma scalar_mx_is_multiplicative : multiplicative (@scalar_mx n). Proof. by split=> //; exact: scalar_mxM. Qed. Canonical scalar_mx_rmorphism := AddRMorphism scalar_mx_is_multiplicative. End MatrixRing. Section LiftPerm. (* Block expresssion of a lifted permutation matrix, for the Cormen LUP. *) Variable n : nat. (* These could be in zmodp, but that would introduce a dependency on perm. *) Definition lift0_perm s : 'S_n.+1 := lift_perm 0 0 s. Lemma lift0_perm0 s : lift0_perm s 0 = 0. Proof. exact: lift_perm_id. Qed. Lemma lift0_perm_lift s k' : lift0_perm s (lift 0 k') = lift (0 : 'I_n.+1) (s k'). Proof. exact: lift_perm_lift. Qed. Lemma lift0_permK s : cancel (lift0_perm s) (lift0_perm s^-1). Proof. by move=> i; rewrite /lift0_perm -lift_permV permK. Qed. Lemma lift0_perm_eq0 s i : (lift0_perm s i == 0) = (i == 0). Proof. by rewrite (canF_eq (lift0_permK s)) lift0_perm0. Qed. (* Block expresssion of a lifted permutation matrix *) Definition lift0_mx A : 'M_(1 + n) := block_mx 1 0 0 A. Lemma lift0_mx_perm s : lift0_mx (perm_mx s) = perm_mx (lift0_perm s). Proof. apply/matrixP=> /= i j; rewrite !mxE split1 /=; case: unliftP => [i'|] -> /=. rewrite lift0_perm_lift !mxE split1 /=. by case: unliftP => [j'|] ->; rewrite ?(inj_eq (@lift_inj _ _)) /= !mxE. rewrite lift0_perm0 !mxE split1 /=. by case: unliftP => [j'|] ->; rewrite /= mxE. Qed. Lemma lift0_mx_is_perm s : is_perm_mx (lift0_mx (perm_mx s)). Proof. by rewrite lift0_mx_perm perm_mx_is_perm. Qed. End LiftPerm. (* Determinants and adjugates are defined here, but most of their properties *) (* only hold for matrices over a commutative ring, so their theory is *) (* deferred to that section. *) (* The determinant, in one line with the Leibniz Formula *) Definition determinant n (A : 'M_n) : R := \sum_(s : 'S_n) (-1) ^+ s * \prod_i A i (s i). (* The cofactor of a matrix on the indexes i and j *) Definition cofactor n A (i j : 'I_n) : R := (-1) ^+ (i + j) * determinant (row' i (col' j A)). (* The adjugate matrix : defined as the transpose of the matrix of cofactors *) Fact adjugate_key : unit. Proof. by []. Qed. Definition adjugate n (A : 'M_n) := \matrix[adjugate_key]_(i, j) cofactor A j i. End MatrixAlgebra. Implicit Arguments delta_mx [R m n]. Implicit Arguments scalar_mx [R n]. Implicit Arguments perm_mx [R n]. Implicit Arguments tperm_mx [R n]. Implicit Arguments pid_mx [R m n]. Implicit Arguments copid_mx [R n]. Implicit Arguments lin_mulmxr [R m n p]. Prenex Implicits delta_mx diag_mx scalar_mx is_scalar_mx perm_mx tperm_mx. Prenex Implicits pid_mx copid_mx mulmx lin_mulmxr. Prenex Implicits mxtrace determinant cofactor adjugate. Implicit Arguments is_scalar_mxP [R n A]. Implicit Arguments mul_delta_mx [R m n p]. Prenex Implicits mul_delta_mx. Notation "a %:M" := (scalar_mx a) : ring_scope. Notation "A *m B" := (mulmx A B) : ring_scope. Notation mulmxr := (mulmxr_head tt). Notation "\tr A" := (mxtrace A) : ring_scope. Notation "'\det' A" := (determinant A) : ring_scope. Notation "'\adj' A" := (adjugate A) : ring_scope. (* Non-commutative transpose requires multiplication in the converse ring. *) Lemma trmx_mul_rev (R : ringType) m n p (A : 'M[R]_(m, n)) (B : 'M[R]_(n, p)) : (A *m B)^T = (B : 'M[R^c]_(n, p))^T *m (A : 'M[R^c]_(m, n))^T. Proof. by apply/matrixP=> k i; rewrite !mxE; apply: eq_bigr => j _; rewrite !mxE. Qed. Canonical matrix_finRingType (R : finRingType) n' := Eval hnf in [finRingType of 'M[R]_n'.+1]. (* Parametricity over the algebra structure. *) Section MapRingMatrix. Variables (aR rR : ringType) (f : {rmorphism aR -> rR}). Local Notation "A ^f" := (map_mx f A) : ring_scope. Section FixedSize. Variables m n p : nat. Implicit Type A : 'M[aR]_(m, n). Lemma map_mxZ a A : (a *: A)^f = f a *: A^f. Proof. by apply/matrixP=> i j; rewrite !mxE rmorphM. Qed. Lemma map_mxM A B : (A *m B)^f = A^f *m B^f :> 'M_(m, p). Proof. apply/matrixP=> i k; rewrite !mxE rmorph_sum //. by apply: eq_bigr => j; rewrite !mxE rmorphM. Qed. Lemma map_delta_mx i j : (delta_mx i j)^f = delta_mx i j :> 'M_(m, n). Proof. by apply/matrixP=> i' j'; rewrite !mxE rmorph_nat. Qed. Lemma map_diag_mx d : (diag_mx d)^f = diag_mx d^f :> 'M_n. Proof. by apply/matrixP=> i j; rewrite !mxE rmorphMn. Qed. Lemma map_scalar_mx a : a%:M^f = (f a)%:M :> 'M_n. Proof. by apply/matrixP=> i j; rewrite !mxE rmorphMn. Qed. Lemma map_mx1 : 1%:M^f = 1%:M :> 'M_n. Proof. by rewrite map_scalar_mx rmorph1. Qed. Lemma map_perm_mx (s : 'S_n) : (perm_mx s)^f = perm_mx s. Proof. by apply/matrixP=> i j; rewrite !mxE rmorph_nat. Qed. Lemma map_tperm_mx (i1 i2 : 'I_n) : (tperm_mx i1 i2)^f = tperm_mx i1 i2. Proof. exact: map_perm_mx. Qed. Lemma map_pid_mx r : (pid_mx r)^f = pid_mx r :> 'M_(m, n). Proof. by apply/matrixP=> i j; rewrite !mxE rmorph_nat. Qed. Lemma trace_map_mx (A : 'M_n) : \tr A^f = f (\tr A). Proof. by rewrite rmorph_sum; apply: eq_bigr => i _; rewrite mxE. Qed. Lemma det_map_mx n' (A : 'M_n') : \det A^f = f (\det A). Proof. rewrite rmorph_sum //; apply: eq_bigr => s _. rewrite rmorphM rmorph_sign rmorph_prod; congr (_ * _). by apply: eq_bigr => i _; rewrite mxE. Qed. Lemma cofactor_map_mx (A : 'M_n) i j : cofactor A^f i j = f (cofactor A i j). Proof. by rewrite rmorphM rmorph_sign -det_map_mx map_row' map_col'. Qed. Lemma map_mx_adj (A : 'M_n) : (\adj A)^f = \adj A^f. Proof. by apply/matrixP=> i j; rewrite !mxE cofactor_map_mx. Qed. End FixedSize. Lemma map_copid_mx n r : (copid_mx r)^f = copid_mx r :> 'M_n. Proof. by rewrite map_mx_sub map_mx1 map_pid_mx. Qed. Lemma map_mx_is_multiplicative n' (n := n'.+1) : multiplicative ((map_mx f) n n). Proof. by split; [exact: map_mxM | exact: map_mx1]. Qed. Canonical map_mx_rmorphism n' := AddRMorphism (map_mx_is_multiplicative n'). Lemma map_lin1_mx m n (g : 'rV_m -> 'rV_n) gf : (forall v, (g v)^f = gf v^f) -> (lin1_mx g)^f = lin1_mx gf. Proof. by move=> def_gf; apply/matrixP=> i j; rewrite !mxE -map_delta_mx -def_gf mxE. Qed. Lemma map_lin_mx m1 n1 m2 n2 (g : 'M_(m1, n1) -> 'M_(m2, n2)) gf : (forall A, (g A)^f = gf A^f) -> (lin_mx g)^f = lin_mx gf. Proof. move=> def_gf; apply: map_lin1_mx => A /=. by rewrite map_mxvec def_gf map_vec_mx. Qed. End MapRingMatrix. Section ComMatrix. (* Lemmas for matrices with coefficients in a commutative ring *) Variable R : comRingType. Section AssocLeft. Variables m n p : nat. Implicit Type A : 'M[R]_(m, n). Implicit Type B : 'M[R]_(n, p). Lemma trmx_mul A B : (A *m B)^T = B^T *m A^T. Proof. rewrite trmx_mul_rev; apply/matrixP=> k i; rewrite !mxE. by apply: eq_bigr => j _; rewrite mulrC. Qed. Lemma scalemxAr a A B : a *: (A *m B) = A *m (a *: B). Proof. by apply: trmx_inj; rewrite trmx_mul !linearZ /= trmx_mul scalemxAl. Qed. Lemma mulmx_is_scalable A : scalable (@mulmx _ m n p A). Proof. by move=> a B; rewrite scalemxAr. Qed. Canonical mulmx_linear A := AddLinear (mulmx_is_scalable A). Definition lin_mulmx A : 'M[R]_(n * p, m * p) := lin_mx (mulmx A). Lemma lin_mulmx_is_linear : linear lin_mulmx. Proof. move=> a A B; apply/row_matrixP=> i; rewrite linearP /= !rowE !mul_rV_lin /=. by rewrite [_ *m _](linearP (mulmxr_linear _ _)) linearP. Qed. Canonical lin_mulmx_additive := Additive lin_mulmx_is_linear. Canonical lin_mulmx_linear := Linear lin_mulmx_is_linear. End AssocLeft. Section LinMulRow. Variables m n : nat. Definition lin_mul_row u : 'M[R]_(m * n, n) := lin1_mx (mulmx u \o vec_mx). Lemma lin_mul_row_is_linear : linear lin_mul_row. Proof. move=> a u v; apply/row_matrixP=> i; rewrite linearP /= !rowE !mul_rV_lin1 /=. by rewrite [_ *m _](linearP (mulmxr_linear _ _)). Qed. Canonical lin_mul_row_additive := Additive lin_mul_row_is_linear. Canonical lin_mul_row_linear := Linear lin_mul_row_is_linear. Lemma mul_vec_lin_row A u : mxvec A *m lin_mul_row u = u *m A. Proof. by rewrite mul_rV_lin1 /= mxvecK. Qed. End LinMulRow. Lemma mxvec_dotmul m n (A : 'M[R]_(m, n)) u v : mxvec (u^T *m v) *m (mxvec A)^T = u *m A *m v^T. Proof. transitivity (\sum_i \sum_j (u 0 i * A i j *: row j v^T)). apply/rowP=> i; rewrite {i}ord1 mxE (reindex _ (curry_mxvec_bij _ _)) /=. rewrite pair_bigA summxE; apply: eq_bigr => [[i j]] /= _. by rewrite !mxE !mxvecE mxE big_ord1 mxE mulrAC. rewrite mulmx_sum_row exchange_big; apply: eq_bigr => j _ /=. by rewrite mxE -scaler_suml. Qed. Section MatrixAlgType. Variable n' : nat. Local Notation n := n'.+1. Canonical matrix_algType := Eval hnf in AlgType R 'M[R]_n (fun k => scalemxAr k). End MatrixAlgType. Lemma diag_mxC n (d e : 'rV[R]_n) : diag_mx d *m diag_mx e = diag_mx e *m diag_mx d. Proof. by rewrite !mulmx_diag; congr (diag_mx _); apply/rowP=> i; rewrite !mxE mulrC. Qed. Lemma diag_mx_comm n' (d e : 'rV[R]_n'.+1) : GRing.comm (diag_mx d) (diag_mx e). Proof. exact: diag_mxC. Qed. Lemma scalar_mxC m n a (A : 'M[R]_(m, n)) : A *m a%:M = a%:M *m A. Proof. by apply: trmx_inj; rewrite trmx_mul tr_scalar_mx !mul_scalar_mx linearZ. Qed. Lemma scalar_mx_comm n' a (A : 'M[R]_n'.+1) : GRing.comm A a%:M. Proof. exact: scalar_mxC. Qed. Lemma mul_mx_scalar m n a (A : 'M[R]_(m, n)) : A *m a%:M = a *: A. Proof. by rewrite scalar_mxC mul_scalar_mx. Qed. Lemma mxtrace_mulC m n (A : 'M[R]_(m, n)) B : \tr (A *m B) = \tr (B *m A). Proof. have expand_trM C D: \tr (C *m D) = \sum_i \sum_j C i j * D j i. by apply: eq_bigr => i _; rewrite mxE. rewrite !{}expand_trM exchange_big /=. by do 2!apply: eq_bigr => ? _; apply: mulrC. Qed. (* The theory of determinants *) Lemma determinant_multilinear n (A B C : 'M[R]_n) i0 b c : row i0 A = b *: row i0 B + c *: row i0 C -> row' i0 B = row' i0 A -> row' i0 C = row' i0 A -> \det A = b * \det B + c * \det C. Proof. rewrite -[_ + _](row_id 0); move/row_eq=> ABC. move/row'_eq=> BA; move/row'_eq=> CA. rewrite !big_distrr -big_split; apply: eq_bigr => s _ /=. rewrite -!(mulrCA (_ ^+s)) -mulrDr; congr (_ * _). rewrite !(bigD1 i0 (_ : predT i0)) //= {}ABC !mxE mulrDl !mulrA. by congr (_ * _ + _ * _); apply: eq_bigr => i i0i; rewrite ?BA ?CA. Qed. Lemma determinant_alternate n (A : 'M[R]_n) i1 i2 : i1 != i2 -> A i1 =1 A i2 -> \det A = 0. Proof. move=> neq_i12 eqA12; pose t := tperm i1 i2. have oddMt s: (t * s)%g = ~~ s :> bool by rewrite odd_permM odd_tperm neq_i12. rewrite [\det A](bigID (@odd_perm _)) /=. apply: canLR (subrK _) _; rewrite add0r -sumrN. rewrite (reindex_inj (mulgI t)); apply: eq_big => //= s. rewrite oddMt => /negPf->; rewrite mulN1r mul1r; congr (- _). rewrite (reindex_inj (@perm_inj _ t)); apply: eq_bigr => /= i _. by rewrite permM tpermK /t; case: tpermP => // ->; rewrite eqA12. Qed. Lemma det_tr n (A : 'M[R]_n) : \det A^T = \det A. Proof. rewrite [\det A^T](reindex_inj (@invg_inj _)) /=. apply: eq_bigr => s _ /=; rewrite !odd_permV (reindex_inj (@perm_inj _ s)) /=. by congr (_ * _); apply: eq_bigr => i _; rewrite mxE permK. Qed. Lemma det_perm n (s : 'S_n) : \det (perm_mx s) = (-1) ^+ s :> R. Proof. rewrite [\det _](bigD1 s) //= big1 => [|i _]; last by rewrite /= !mxE eqxx. rewrite mulr1 big1 ?addr0 => //= t Dst. case: (pickP (fun i => s i != t i)) => [i ist | Est]. by rewrite (bigD1 i) // mulrCA /= !mxE (negbTE ist) mul0r. by case/eqP: Dst; apply/permP => i; move/eqP: (Est i). Qed. Lemma det1 n : \det (1%:M : 'M[R]_n) = 1. Proof. by rewrite -perm_mx1 det_perm odd_perm1. Qed. Lemma det_mx00 (A : 'M[R]_0) : \det A = 1. Proof. by rewrite flatmx0 -(flatmx0 1%:M) det1. Qed. Lemma detZ n a (A : 'M[R]_n) : \det (a *: A) = a ^+ n * \det A. Proof. rewrite big_distrr /=; apply: eq_bigr => s _; rewrite mulrCA; congr (_ * _). rewrite -[n in a ^+ n]card_ord -prodr_const -big_split /=. by apply: eq_bigr=> i _; rewrite mxE. Qed. Lemma det0 n' : \det (0 : 'M[R]_n'.+1) = 0. Proof. by rewrite -(scale0r 0) detZ exprS !mul0r. Qed. Lemma det_scalar n a : \det (a%:M : 'M[R]_n) = a ^+ n. Proof. by rewrite -{1}(mulr1 a) -scale_scalar_mx detZ det1 mulr1. Qed. Lemma det_scalar1 a : \det (a%:M : 'M[R]_1) = a. Proof. exact: det_scalar. Qed. Lemma det_mulmx n (A B : 'M[R]_n) : \det (A *m B) = \det A * \det B. Proof. rewrite big_distrl /=. pose F := ('I_n ^ n)%type; pose AB s i j := A i j * B j (s i). transitivity (\sum_(f : F) \sum_(s : 'S_n) (-1) ^+ s * \prod_i AB s i (f i)). rewrite exchange_big; apply: eq_bigr => /= s _; rewrite -big_distrr /=. congr (_ * _); rewrite -(bigA_distr_bigA (AB s)) /=. by apply: eq_bigr => x _; rewrite mxE. rewrite (bigID (fun f : F => injectiveb f)) /= addrC big1 ?add0r => [|f Uf]. rewrite (reindex (@pval _)) /=; last first. pose in_Sn := insubd (1%g : 'S_n). by exists in_Sn => /= f Uf; first apply: val_inj; exact: insubdK. apply: eq_big => /= [s | s _]; rewrite ?(valP s) // big_distrr /=. rewrite (reindex_inj (mulgI s)); apply: eq_bigr => t _ /=. rewrite big_split /= mulrA mulrCA mulrA mulrCA mulrA. rewrite -signr_addb odd_permM !pvalE; congr (_ * _); symmetry. by rewrite (reindex_inj (@perm_inj _ s)); apply: eq_bigr => i; rewrite permM. transitivity (\det (\matrix_(i, j) B (f i) j) * \prod_i A i (f i)). rewrite mulrC big_distrr /=; apply: eq_bigr => s _. rewrite mulrCA big_split //=; congr (_ * (_ * _)). by apply: eq_bigr => x _; rewrite mxE. case/injectivePn: Uf => i1 [i2 Di12 Ef12]. by rewrite (determinant_alternate Di12) ?simp //= => j; rewrite !mxE Ef12. Qed. Lemma detM n' (A B : 'M[R]_n'.+1) : \det (A * B) = \det A * \det B. Proof. exact: det_mulmx. Qed. Lemma det_diag n (d : 'rV[R]_n) : \det (diag_mx d) = \prod_i d 0 i. Proof. rewrite /(\det _) (bigD1 1%g) //= addrC big1 => [|p p1]. by rewrite add0r odd_perm1 mul1r; apply: eq_bigr => i; rewrite perm1 mxE eqxx. have{p1}: ~~ perm_on set0 p. apply: contra p1; move/subsetP=> p1; apply/eqP; apply/permP=> i. by rewrite perm1; apply/eqP; apply/idPn; move/p1; rewrite inE. case/subsetPn=> i; rewrite !inE eq_sym; move/negbTE=> p_i _. by rewrite (bigD1 i) //= mulrCA mxE p_i mul0r. Qed. (* Laplace expansion lemma *) Lemma expand_cofactor n (A : 'M[R]_n) i j : cofactor A i j = \sum_(s : 'S_n | s i == j) (-1) ^+ s * \prod_(k | i != k) A k (s k). Proof. case: n A i j => [|n] A i0 j0; first by case: i0. rewrite (reindex (lift_perm i0 j0)); last first. pose ulsf i (s : 'S_n.+1) k := odflt k (unlift (s i) (s (lift i k))). have ulsfK i (s : 'S_n.+1) k: lift (s i) (ulsf i s k) = s (lift i k). rewrite /ulsf; have:= neq_lift i k. by rewrite -(inj_eq (@perm_inj _ s)) => /unlift_some[] ? ? ->. have inj_ulsf: injective (ulsf i0 _). move=> s; apply: can_inj (ulsf (s i0) s^-1%g) _ => k'. by rewrite {1}/ulsf ulsfK !permK liftK. exists (fun s => perm (inj_ulsf s)) => [s _ | s]. by apply/permP=> k'; rewrite permE /ulsf lift_perm_lift lift_perm_id liftK. move/(s _ =P _) => si0; apply/permP=> k. case: (unliftP i0 k) => [k'|] ->; rewrite ?lift_perm_id //. by rewrite lift_perm_lift -si0 permE ulsfK. rewrite /cofactor big_distrr /=. apply: eq_big => [s | s _]; first by rewrite lift_perm_id eqxx. rewrite -signr_odd mulrA -signr_addb odd_add -odd_lift_perm; congr (_ * _). case: (pickP 'I_n) => [k0 _ | n0]; last first. by rewrite !big1 // => [j /unlift_some[i] | i _]; have:= n0 i. rewrite (reindex (lift i0)). by apply: eq_big => [k | k _] /=; rewrite ?neq_lift // !mxE lift_perm_lift. exists (fun k => odflt k0 (unlift i0 k)) => k; first by rewrite liftK. by case/unlift_some=> k' -> ->. Qed. Lemma expand_det_row n (A : 'M[R]_n) i0 : \det A = \sum_j A i0 j * cofactor A i0 j. Proof. rewrite /(\det A) (partition_big (fun s : 'S_n => s i0) predT) //=. apply: eq_bigr => j0 _; rewrite expand_cofactor big_distrr /=. apply: eq_bigr => s /eqP Dsi0. rewrite mulrCA (bigID (pred1 i0)) /= big_pred1_eq Dsi0; congr (_ * (_ * _)). by apply: eq_bigl => i; rewrite eq_sym. Qed. Lemma cofactor_tr n (A : 'M[R]_n) i j : cofactor A^T i j = cofactor A j i. Proof. rewrite /cofactor addnC; congr (_ * _). rewrite -tr_row' -tr_col' det_tr; congr (\det _). by apply/matrixP=> ? ?; rewrite !mxE. Qed. Lemma cofactorZ n a (A : 'M[R]_n) i j : cofactor (a *: A) i j = a ^+ n.-1 * cofactor A i j. Proof. by rewrite {1}/cofactor !linearZ detZ mulrCA mulrA. Qed. Lemma expand_det_col n (A : 'M[R]_n) j0 : \det A = \sum_i (A i j0 * cofactor A i j0). Proof. rewrite -det_tr (expand_det_row _ j0). by apply: eq_bigr => i _; rewrite cofactor_tr mxE. Qed. Lemma trmx_adj n (A : 'M[R]_n) : (\adj A)^T = \adj A^T. Proof. by apply/matrixP=> i j; rewrite !mxE cofactor_tr. Qed. Lemma adjZ n a (A : 'M[R]_n) : \adj (a *: A) = a^+n.-1 *: \adj A. Proof. by apply/matrixP=> i j; rewrite !mxE cofactorZ. Qed. (* Cramer Rule : adjugate on the left *) Lemma mul_mx_adj n (A : 'M[R]_n) : A *m \adj A = (\det A)%:M. Proof. apply/matrixP=> i1 i2; rewrite !mxE; case Di: (i1 == i2). rewrite (eqP Di) (expand_det_row _ i2) //=. by apply: eq_bigr => j _; congr (_ * _); rewrite mxE. pose B := \matrix_(i, j) (if i == i2 then A i1 j else A i j). have EBi12: B i1 =1 B i2 by move=> j; rewrite /= !mxE Di eq_refl. rewrite -[_ *+ _](determinant_alternate (negbT Di) EBi12) (expand_det_row _ i2). apply: eq_bigr => j _; rewrite !mxE eq_refl; congr (_ * (_ * _)). apply: eq_bigr => s _; congr (_ * _); apply: eq_bigr => i _. by rewrite !mxE eq_sym -if_neg neq_lift. Qed. (* Cramer rule : adjugate on the right *) Lemma mul_adj_mx n (A : 'M[R]_n) : \adj A *m A = (\det A)%:M. Proof. by apply: trmx_inj; rewrite trmx_mul trmx_adj mul_mx_adj det_tr tr_scalar_mx. Qed. Lemma adj1 n : \adj (1%:M) = 1%:M :> 'M[R]_n. Proof. by rewrite -{2}(det1 n) -mul_adj_mx mulmx1. Qed. (* Left inverses are right inverses. *) Lemma mulmx1C n (A B : 'M[R]_n) : A *m B = 1%:M -> B *m A = 1%:M. Proof. move=> AB1; pose A' := \det B *: \adj A. suffices kA: A' *m A = 1%:M by rewrite -[B]mul1mx -kA -(mulmxA A') AB1 mulmx1. by rewrite -scalemxAl mul_adj_mx scale_scalar_mx mulrC -det_mulmx AB1 det1. Qed. (* Only tall matrices have inverses. *) Lemma mulmx1_min m n (A : 'M[R]_(m, n)) B : A *m B = 1%:M -> m <= n. Proof. move=> AB1; rewrite leqNgt; apply/negP=> /subnKC; rewrite addSnnS. move: (_ - _)%N => m' def_m; move: AB1; rewrite -{m}def_m in A B *. rewrite -(vsubmxK A) -(hsubmxK B) mul_col_row scalar_mx_block. case/eq_block_mx=> /mulmx1C BlAu1 AuBr0 _ => /eqP/idPn[]. by rewrite -[_ B]mul1mx -BlAu1 -mulmxA AuBr0 !mulmx0 eq_sym oner_neq0. Qed. Lemma det_ublock n1 n2 Aul (Aur : 'M[R]_(n1, n2)) Adr : \det (block_mx Aul Aur 0 Adr) = \det Aul * \det Adr. Proof. elim: n1 => [|n1 IHn1] in Aul Aur *. have ->: Aul = 1%:M by apply/matrixP=> i []. rewrite det1 mul1r; congr (\det _); apply/matrixP=> i j. by do 2![rewrite !mxE; case: splitP => [[]|k] //=; move/val_inj=> <- {k}]. rewrite (expand_det_col _ (lshift n2 0)) big_split_ord /=. rewrite addrC big1 1?simp => [|i _]; last by rewrite block_mxEdl mxE simp. rewrite (expand_det_col _ 0) big_distrl /=; apply eq_bigr=> i _. rewrite block_mxEul -!mulrA; do 2!congr (_ * _). by rewrite col'_col_mx !col'Kl raddf0 row'Ku row'_row_mx IHn1. Qed. Lemma det_lblock n1 n2 Aul (Adl : 'M[R]_(n2, n1)) Adr : \det (block_mx Aul 0 Adl Adr) = \det Aul * \det Adr. Proof. by rewrite -det_tr tr_block_mx trmx0 det_ublock !det_tr. Qed. End ComMatrix. Implicit Arguments lin_mul_row [R m n]. Implicit Arguments lin_mulmx [R m n p]. Prenex Implicits lin_mul_row lin_mulmx. (*****************************************************************************) (********************** Matrix unit ring and inverse matrices ****************) (*****************************************************************************) Section MatrixInv. Variables R : comUnitRingType. Section Defs. Variable n : nat. Implicit Type A : 'M[R]_n. Definition unitmx : pred 'M[R]_n := fun A => \det A \is a GRing.unit. Definition invmx A := if A \in unitmx then (\det A)^-1 *: \adj A else A. Lemma unitmxE A : (A \in unitmx) = (\det A \is a GRing.unit). Proof. by []. Qed. Lemma unitmx1 : 1%:M \in unitmx. Proof. by rewrite unitmxE det1 unitr1. Qed. Lemma unitmx_perm s : perm_mx s \in unitmx. Proof. by rewrite unitmxE det_perm unitrX ?unitrN ?unitr1. Qed. Lemma unitmx_tr A : (A^T \in unitmx) = (A \in unitmx). Proof. by rewrite unitmxE det_tr. Qed. Lemma unitmxZ a A : a \is a GRing.unit -> (a *: A \in unitmx) = (A \in unitmx). Proof. by move=> Ua; rewrite !unitmxE detZ unitrM unitrX. Qed. Lemma invmx1 : invmx 1%:M = 1%:M. Proof. by rewrite /invmx det1 invr1 scale1r adj1 if_same. Qed. Lemma invmxZ a A : a *: A \in unitmx -> invmx (a *: A) = a^-1 *: invmx A. Proof. rewrite /invmx !unitmxE detZ unitrM => /andP[Ua U_A]. rewrite Ua U_A adjZ !scalerA invrM {U_A}//=. case: (posnP n) A => [-> | n_gt0] A; first by rewrite flatmx0 [_ *: _]flatmx0. rewrite unitrX_pos // in Ua; rewrite -[_ * _](mulrK Ua) mulrC -!mulrA. by rewrite -exprSr prednK // !mulrA divrK ?unitrX. Qed. Lemma invmx_scalar a : invmx (a%:M) = a^-1%:M. Proof. case Ua: (a%:M \in unitmx). by rewrite -scalemx1 in Ua *; rewrite invmxZ // invmx1 scalemx1. rewrite /invmx Ua; have [->|n_gt0] := posnP n; first by rewrite ![_%:M]flatmx0. by rewrite unitmxE det_scalar unitrX_pos // in Ua; rewrite invr_out ?Ua. Qed. Lemma mulVmx : {in unitmx, left_inverse 1%:M invmx mulmx}. Proof. by move=> A nsA; rewrite /invmx nsA -scalemxAl mul_adj_mx scale_scalar_mx mulVr. Qed. Lemma mulmxV : {in unitmx, right_inverse 1%:M invmx mulmx}. Proof. by move=> A nsA; rewrite /invmx nsA -scalemxAr mul_mx_adj scale_scalar_mx mulVr. Qed. Lemma mulKmx m : {in unitmx, @left_loop _ 'M_(n, m) invmx mulmx}. Proof. by move=> A uA /= B; rewrite mulmxA mulVmx ?mul1mx. Qed. Lemma mulKVmx m : {in unitmx, @rev_left_loop _ 'M_(n, m) invmx mulmx}. Proof. by move=> A uA /= B; rewrite mulmxA mulmxV ?mul1mx. Qed. Lemma mulmxK m : {in unitmx, @right_loop 'M_(m, n) _ invmx mulmx}. Proof. by move=> A uA /= B; rewrite -mulmxA mulmxV ?mulmx1. Qed. Lemma mulmxKV m : {in unitmx, @rev_right_loop 'M_(m, n) _ invmx mulmx}. Proof. by move=> A uA /= B; rewrite -mulmxA mulVmx ?mulmx1. Qed. Lemma det_inv A : \det (invmx A) = (\det A)^-1. Proof. case uA: (A \in unitmx); last by rewrite /invmx uA invr_out ?negbT. by apply: (mulrI uA); rewrite -det_mulmx mulmxV ?divrr ?det1. Qed. Lemma unitmx_inv A : (invmx A \in unitmx) = (A \in unitmx). Proof. by rewrite !unitmxE det_inv unitrV. Qed. Lemma unitmx_mul A B : (A *m B \in unitmx) = (A \in unitmx) && (B \in unitmx). Proof. by rewrite -unitrM -det_mulmx. Qed. Lemma trmx_inv (A : 'M_n) : (invmx A)^T = invmx (A^T). Proof. by rewrite (fun_if trmx) linearZ /= trmx_adj -unitmx_tr -det_tr. Qed. Lemma invmxK : involutive invmx. Proof. move=> A; case uA : (A \in unitmx); last by rewrite /invmx !uA. by apply: (can_inj (mulKVmx uA)); rewrite mulVmx // mulmxV ?unitmx_inv. Qed. Lemma mulmx1_unit A B : A *m B = 1%:M -> A \in unitmx /\ B \in unitmx. Proof. by move=> AB1; apply/andP; rewrite -unitmx_mul AB1 unitmx1. Qed. Lemma intro_unitmx A B : B *m A = 1%:M /\ A *m B = 1%:M -> unitmx A. Proof. by case=> _ /mulmx1_unit[]. Qed. Lemma invmx_out : {in [predC unitmx], invmx =1 id}. Proof. by move=> A; rewrite inE /= /invmx -if_neg => ->. Qed. End Defs. Variable n' : nat. Local Notation n := n'.+1. Definition matrix_unitRingMixin := UnitRingMixin (@mulVmx n) (@mulmxV n) (@intro_unitmx n) (@invmx_out n). Canonical matrix_unitRing := Eval hnf in UnitRingType 'M[R]_n matrix_unitRingMixin. Canonical matrix_unitAlg := Eval hnf in [unitAlgType R of 'M[R]_n]. (* Lemmas requiring that the coefficients are in a unit ring *) Lemma detV (A : 'M_n) : \det A^-1 = (\det A)^-1. Proof. exact: det_inv. Qed. Lemma unitr_trmx (A : 'M_n) : (A^T \is a GRing.unit) = (A \is a GRing.unit). Proof. exact: unitmx_tr. Qed. Lemma trmxV (A : 'M_n) : A^-1^T = (A^T)^-1. Proof. exact: trmx_inv. Qed. Lemma perm_mxV (s : 'S_n) : perm_mx s^-1 = (perm_mx s)^-1. Proof. rewrite -[_^-1]mul1r; apply: (canRL (mulmxK (unitmx_perm s))). by rewrite -perm_mxM mulVg perm_mx1. Qed. Lemma is_perm_mxV (A : 'M_n) : is_perm_mx A^-1 = is_perm_mx A. Proof. apply/is_perm_mxP/is_perm_mxP=> [] [s defA]; exists s^-1%g. by rewrite -(invrK A) defA perm_mxV. by rewrite defA perm_mxV. Qed. End MatrixInv. Prenex Implicits unitmx invmx. (* Finite inversible matrices and the general linear group. *) Section FinUnitMatrix. Variables (n : nat) (R : finComUnitRingType). Canonical matrix_finUnitRingType n' := Eval hnf in [finUnitRingType of 'M[R]_n'.+1]. Definition GLtype of phant R := {unit 'M[R]_n.-1.+1}. Coercion GLval ph (u : GLtype ph) : 'M[R]_n.-1.+1 := let: FinRing.Unit A _ := u in A. End FinUnitMatrix. Bind Scope group_scope with GLtype. Arguments Scope GLval [nat_scope _ _ group_scope]. Prenex Implicits GLval. Notation "{ ''GL_' n [ R ] }" := (GLtype n (Phant R)) (at level 0, n at level 2, format "{ ''GL_' n [ R ] }") : type_scope. Notation "{ ''GL_' n ( p ) }" := {'GL_n['F_p]} (at level 0, n at level 2, p at level 10, format "{ ''GL_' n ( p ) }") : type_scope. Section GL_unit. Variables (n : nat) (R : finComUnitRingType). Canonical GL_subType := [subType of {'GL_n[R]} for GLval]. Definition GL_eqMixin := Eval hnf in [eqMixin of {'GL_n[R]} by <:]. Canonical GL_eqType := Eval hnf in EqType {'GL_n[R]} GL_eqMixin. Canonical GL_choiceType := Eval hnf in [choiceType of {'GL_n[R]}]. Canonical GL_countType := Eval hnf in [countType of {'GL_n[R]}]. Canonical GL_subCountType := Eval hnf in [subCountType of {'GL_n[R]}]. Canonical GL_finType := Eval hnf in [finType of {'GL_n[R]}]. Canonical GL_subFinType := Eval hnf in [subFinType of {'GL_n[R]}]. Canonical GL_baseFinGroupType := Eval hnf in [baseFinGroupType of {'GL_n[R]}]. Canonical GL_finGroupType := Eval hnf in [finGroupType of {'GL_n[R]}]. Definition GLgroup of phant R := [set: {'GL_n[R]}]. Canonical GLgroup_group ph := Eval hnf in [group of GLgroup ph]. Implicit Types u v : {'GL_n[R]}. Lemma GL_1E : GLval 1 = 1. Proof. by []. Qed. Lemma GL_VE u : GLval u^-1 = (GLval u)^-1. Proof. by []. Qed. Lemma GL_VxE u : GLval u^-1 = invmx u. Proof. by []. Qed. Lemma GL_ME u v : GLval (u * v) = GLval u * GLval v. Proof. by []. Qed. Lemma GL_MxE u v : GLval (u * v) = u *m v. Proof. by []. Qed. Lemma GL_unit u : GLval u \is a GRing.unit. Proof. exact: valP. Qed. Lemma GL_unitmx u : val u \in unitmx. Proof. exact: GL_unit. Qed. Lemma GL_det u : \det u != 0. Proof. by apply: contraL (GL_unitmx u); rewrite unitmxE => /eqP->; rewrite unitr0. Qed. End GL_unit. Notation "''GL_' n [ R ]" := (GLgroup n (Phant R)) (at level 8, n at level 2, format "''GL_' n [ R ]") : group_scope. Notation "''GL_' n ( p )" := 'GL_n['F_p] (at level 8, n at level 2, p at level 10, format "''GL_' n ( p )") : group_scope. Notation "''GL_' n [ R ]" := (GLgroup_group n (Phant R)) : Group_scope. Notation "''GL_' n ( p )" := (GLgroup_group n (Phant 'F_p)) : Group_scope. (*****************************************************************************) (********************** Matrices over a domain *******************************) (*****************************************************************************) Section MatrixDomain. Variable R : idomainType. Lemma scalemx_eq0 m n a (A : 'M[R]_(m, n)) : (a *: A == 0) = (a == 0) || (A == 0). Proof. case nz_a: (a == 0) / eqP => [-> | _]; first by rewrite scale0r eqxx. apply/eqP/eqP=> [aA0 | ->]; last exact: scaler0. apply/matrixP=> i j; apply/eqP; move/matrixP/(_ i j)/eqP: aA0. by rewrite !mxE mulf_eq0 nz_a. Qed. Lemma scalemx_inj m n a : a != 0 -> injective ( *:%R a : 'M[R]_(m, n) -> 'M[R]_(m, n)). Proof. move=> nz_a A B eq_aAB; apply: contraNeq nz_a. rewrite -[A == B]subr_eq0 -[a == 0]orbF => /negPf<-. by rewrite -scalemx_eq0 linearB subr_eq0 /= eq_aAB. Qed. Lemma det0P n (A : 'M[R]_n) : reflect (exists2 v : 'rV[R]_n, v != 0 & v *m A = 0) (\det A == 0). Proof. apply: (iffP eqP) => [detA0 | [v n0v vA0]]; last first. apply: contraNeq n0v => nz_detA; rewrite -(inj_eq (scalemx_inj nz_detA)). by rewrite scaler0 -mul_mx_scalar -mul_mx_adj mulmxA vA0 mul0mx. elim: n => [|n IHn] in A detA0 *. by case/idP: (oner_eq0 R); rewrite -detA0 [A]thinmx0 -(thinmx0 1%:M) det1. have [{detA0}A'0 | nzA'] := eqVneq (row 0 (\adj A)) 0; last first. exists (row 0 (\adj A)) => //; rewrite rowE -mulmxA mul_adj_mx detA0. by rewrite mul_mx_scalar scale0r. pose A' := col' 0 A; pose vA := col 0 A. have defA: A = row_mx vA A'. apply/matrixP=> i j; rewrite !mxE. case: splitP => j' def_j; rewrite mxE; congr (A i _); apply: val_inj => //=. by rewrite def_j [j']ord1. have{IHn} w_ j : exists w : 'rV_n.+1, [/\ w != 0, w 0 j = 0 & w *m A' = 0]. have [|wj nzwj wjA'0] := IHn (row' j A'). by apply/eqP; move/rowP/(_ j)/eqP: A'0; rewrite !mxE mulf_eq0 signr_eq0. exists (\row_k oapp (wj 0) 0 (unlift j k)). rewrite !mxE unlift_none -wjA'0; split=> //. apply: contraNneq nzwj => w0; apply/eqP/rowP=> k'. by move/rowP/(_ (lift j k')): w0; rewrite !mxE liftK. apply/rowP=> k; rewrite !mxE (bigD1 j) //= mxE unlift_none mul0r add0r. rewrite (reindex_onto (lift j) (odflt k \o unlift j)) /= => [|k']. by apply: eq_big => k'; rewrite ?mxE liftK eq_sym neq_lift eqxx. by rewrite eq_sym; case/unlift_some=> ? ? ->. have [w0 [nz_w0 w00_0 w0A']] := w_ 0; pose a0 := (w0 *m vA) 0 0. have [j {nz_w0}/= nz_w0j | w00] := pickP [pred j | w0 0 j != 0]; last first. by case/eqP: nz_w0; apply/rowP=> j; rewrite mxE; move/eqP: (w00 j). have{w_} [wj [nz_wj wj0_0 wjA']] := w_ j; pose aj := (wj *m vA) 0 0. have [aj0 | nz_aj] := eqVneq aj 0. exists wj => //; rewrite defA (@mul_mx_row _ _ _ 1) [_ *m _]mx11_scalar -/aj. by rewrite aj0 raddf0 wjA' row_mx0. exists (aj *: w0 - a0 *: wj). apply: contraNneq nz_aj; move/rowP/(_ j)/eqP; rewrite !mxE wj0_0 mulr0 subr0. by rewrite mulf_eq0 (negPf nz_w0j) orbF. rewrite defA (@mul_mx_row _ _ _ 1) !mulmxBl -!scalemxAl w0A' wjA' !linear0. by rewrite -mul_mx_scalar -mul_scalar_mx -!mx11_scalar subrr addr0 row_mx0. Qed. End MatrixDomain. Implicit Arguments det0P [R n A]. (* Parametricity at the field level (mx_is_scalar, unit and inverse are only *) (* mapped at this level). *) Section MapFieldMatrix. Variables (aF : fieldType) (rF : comUnitRingType) (f : {rmorphism aF -> rF}). Local Notation "A ^f" := (map_mx f A) : ring_scope. Lemma map_mx_inj m n : injective ((map_mx f) m n). Proof. move=> A B eq_AB; apply/matrixP=> i j. by move/matrixP/(_ i j): eq_AB; rewrite !mxE; exact: fmorph_inj. Qed. Lemma map_mx_is_scalar n (A : 'M_n) : is_scalar_mx A^f = is_scalar_mx A. Proof. rewrite /is_scalar_mx; case: (insub _) => // i. by rewrite mxE -map_scalar_mx inj_eq //; exact: map_mx_inj. Qed. Lemma map_unitmx n (A : 'M_n) : (A^f \in unitmx) = (A \in unitmx). Proof. by rewrite unitmxE det_map_mx // fmorph_unit // -unitfE. Qed. Lemma map_mx_unit n' (A : 'M_n'.+1) : (A^f \is a GRing.unit) = (A \is a GRing.unit). Proof. exact: map_unitmx. Qed. Lemma map_invmx n (A : 'M_n) : (invmx A)^f = invmx A^f. Proof. rewrite /invmx map_unitmx (fun_if ((map_mx f) n n)). by rewrite map_mxZ map_mx_adj det_map_mx fmorphV. Qed. Lemma map_mx_inv n' (A : 'M_n'.+1) : A^-1^f = A^f^-1. Proof. exact: map_invmx. Qed. Lemma map_mx_eq0 m n (A : 'M_(m, n)) : (A^f == 0) = (A == 0). Proof. by rewrite -(inj_eq (@map_mx_inj m n)) raddf0. Qed. End MapFieldMatrix. (*****************************************************************************) (****************************** LUP decomposion ******************************) (*****************************************************************************) Section CormenLUP. Variable F : fieldType. (* Decomposition of the matrix A to P A = L U with *) (* - P a permutation matrix *) (* - L a unipotent lower triangular matrix *) (* - U an upper triangular matrix *) Fixpoint cormen_lup {n} := match n return let M := 'M[F]_n.+1 in M -> M * M * M with | 0 => fun A => (1, 1, A) | _.+1 => fun A => let k := odflt 0 [pick k | A k 0 != 0] in let A1 : 'M_(1 + _) := xrow 0 k A in let P1 : 'M_(1 + _) := tperm_mx 0 k in let Schur := ((A k 0)^-1 *: dlsubmx A1) *m ursubmx A1 in let: (P2, L2, U2) := cormen_lup (drsubmx A1 - Schur) in let P := block_mx 1 0 0 P2 *m P1 in let L := block_mx 1 0 ((A k 0)^-1 *: (P2 *m dlsubmx A1)) L2 in let U := block_mx (ulsubmx A1) (ursubmx A1) 0 U2 in (P, L, U) end. Lemma cormen_lup_perm n (A : 'M_n.+1) : is_perm_mx (cormen_lup A).1.1. Proof. elim: n => [|n IHn] /= in A *; first exact: is_perm_mx1. set A' := _ - _; move/(_ A'): IHn; case: cormen_lup => [[P L U]] {A'}/=. rewrite (is_perm_mxMr _ (perm_mx_is_perm _ _)). case/is_perm_mxP => s ->; exact: lift0_mx_is_perm. Qed. Lemma cormen_lup_correct n (A : 'M_n.+1) : let: (P, L, U) := cormen_lup A in P * A = L * U. Proof. elim: n => [|n IHn] /= in A *; first by rewrite !mul1r. set k := odflt _ _; set A1 : 'M_(1 + _) := xrow _ _ _. set A' := _ - _; move/(_ A'): IHn; case: cormen_lup => [[P' L' U']] /= IHn. rewrite -mulrA -!mulmxE -xrowE -/A1 /= -[n.+2]/(1 + n.+1)%N -{1}(submxK A1). rewrite !mulmx_block !mul0mx !mulmx0 !add0r !addr0 !mul1mx -{L' U'}[L' *m _]IHn. rewrite -scalemxAl !scalemxAr -!mulmxA addrC -mulrDr {A'}subrK. congr (block_mx _ _ (_ *m _) _). rewrite [_ *: _]mx11_scalar !mxE lshift0 tpermL {}/A1 {}/k. case: pickP => /= [k nzAk0 | no_k]; first by rewrite mulVf ?mulmx1. rewrite (_ : dlsubmx _ = 0) ?mul0mx //; apply/colP=> i. by rewrite !mxE lshift0 (elimNf eqP (no_k _)). Qed. Lemma cormen_lup_detL n (A : 'M_n.+1) : \det (cormen_lup A).1.2 = 1. Proof. elim: n => [|n IHn] /= in A *; first by rewrite det1. set A' := _ - _; move/(_ A'): IHn; case: cormen_lup => [[P L U]] {A'}/= detL. by rewrite (@det_lblock _ 1) det1 mul1r. Qed. Lemma cormen_lup_lower n A (i j : 'I_n.+1) : i <= j -> (cormen_lup A).1.2 i j = (i == j)%:R. Proof. elim: n => [|n IHn] /= in A i j *; first by rewrite [i]ord1 [j]ord1 mxE. set A' := _ - _; move/(_ A'): IHn; case: cormen_lup => [[P L U]] {A'}/= Ll. rewrite !mxE split1; case: unliftP => [i'|] -> /=; rewrite !mxE split1. by case: unliftP => [j'|] -> //; exact: Ll. by case: unliftP => [j'|] ->; rewrite /= mxE. Qed. Lemma cormen_lup_upper n A (i j : 'I_n.+1) : j < i -> (cormen_lup A).2 i j = 0 :> F. Proof. elim: n => [|n IHn] /= in A i j *; first by rewrite [i]ord1. set A' := _ - _; move/(_ A'): IHn; case: cormen_lup => [[P L U]] {A'}/= Uu. rewrite !mxE split1; case: unliftP => [i'|] -> //=; rewrite !mxE split1. by case: unliftP => [j'|] ->; [exact: Uu | rewrite /= mxE]. Qed. End CormenLUP. mathcomp-1.5/theories/vector.v0000644000175000017500000022736612307636117015514 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq choice fintype bigop. Require Import finfun tuple ssralg matrix mxalgebra zmodp. (******************************************************************************) (* * Finite dimensional vector spaces *) (* vectType R == interface structure for finite dimensional (more *) (* precisely, detachable) vector spaces over R, which *) (* should be at least a ringType. *) (* Vector.axiom n M <-> type M is linearly isomorphic to 'rV_n. *) (* := {v2r : M -> 'rV_n| linear v2r & bijective v2r}. *) (* VectMixin isoM == packages a proof isoV of Vector.axiom n M as the *) (* vectType mixin for an n-dimensional R-space *) (* structure on a type M that is an lmodType R. *) (* VectType K M mT == packs the vectType mixin mT to into a vectType K *) (* instance for T; T should have an lmodType K *) (* canonical instance. *) (* [vectType R of T for vS] == a copy of the vS : vectType R structure where *) (* the sort is replaced by T; vS : lmodType R should *) (* be convertible to a canonical lmodType for T. *) (* [vectType R of V] == a clone of an existing vectType R structure on V. *) (* {vspace vT} == the type of (detachable) subspaces of vT; vT *) (* should have a vectType structure over a fieldType. *) (* subvs_of U == the subtype of elements of V in the subspace U. *) (* This is canonically a vectType. *) (* vsval u == linear injection of u : subvs_of U into V. *) (* vsproj U v == linear projection of v : V in subvs U. *) (* 'Hom(aT, rT) == the type of linear functions (homomorphisms) from *) (* aT to rT, where aT and rT ARE vectType structures. *) (* Elements of 'Hom(aT, rT) coerce to Coq functions. *) (* --> Caveat: aT and rT must denote actual vectType structures, not their *) (* projections on Type. *) (* linfun f == a vector linear function in 'Hom(aT, rT) that *) (* coincides with f : aT -> rT when f is linear. *) (* 'End(vT) == endomorphisms of vT (:= 'Hom(vT, vT)). *) (* --> The types subvs_of U, 'Hom(aT, rT), 'End(vT), K^o, 'M[K]_(m, n), *) (* vT * wT, {ffun I -> vT}, vT ^ n all have canonical vectType instances. *) (* *) (* Functions: *) (* <[v]>%VS == the vector space generated by v (a line if v != 0).*) (* 0%VS == the trivial vector subspace. *) (* fullv, {:vT} == the complete vector subspace (displays as fullv). *) (* (U + V)%VS == the join (sum) of two subspaces U and V. *) (* (U :&: V)%VS == intersection of vector subspaces U and V. *) (* (U^C)%VS == a complement of the vector subspace U. *) (* (U :\: V)%VS == a local complement to U :& V in the subspace U. *) (* \dim U == dimension of a vector space U. *) (* span X, <>%VS == the subspace spanned by the vector sequence X. *) (* coord X i v == i'th coordinate of v on X, when v \in <>%VS and *) (* where X : n.-tuple vT and i : 'I_n. Note that *) (* coord X i is a scalar function. *) (* vpick U == a nonzero element of U if U= 0%VS, or 0 if U = 0. *) (* vbasis U == a (\dim U).-tuple that is a basis of U. *) (* \1%VF == the identity linear function. *) (* (f \o g)%VF == the composite of two linear functions f and g. *) (* (f^-1)%VF == a linear function that is a right inverse to the *) (* linear function f on the codomain of f. *) (* (f @: U)%VS == the image of vs by the linear function f. *) (* (f @^-1: U)%VS == the pre-image of vs by the linear function f. *) (* lker f == the kernel of the linear function f. *) (* limg f == the image of the linear function f. *) (* fixedSpace f == the fixed space of a linear endomorphism f *) (* daddv_pi U V == projection onto U along V if U and V are disjoint; *) (* daddv_pi U V + daddv_pi V U is then a projection *) (* onto the direct sum (U + V)%VS. *) (* projv U == projection onto U (along U^C, := daddv_pi U U^C). *) (* addv_pi1 U V == projection onto the subspace U :\: V of U along V. *) (* addv_pi2 U V == projection onto V along U :\: V; note that *) (* addv_pi1 U V and addv_pi2 U V are (asymmetrical) *) (* complementary projections on (U + V)%VS. *) (* sumv_pi_for defV i == for defV : V = (V \sum_(j <- r | P j) Vs j)%VS, *) (* j ranging over an eqType, this is a projection on *) (* a subspace of Vs i, along a complement in V, such *) (* that \sum_(j <- r | P j) sumv_pi_for defV j is a *) (* projection onto V if filter P r is duplicate-free *) (* (e.g., when V := \sum_(j | P j) Vs j). *) (* sumv_pi V i == notation the above when defV == erefl V, and V is *) (* convertible to \sum_(j <- r | P j) Vs j)%VS. *) (* *) (* Predicates: *) (* v \in U == v belongs to U (:= (<[v]> <= U)%VS). *) (* (U <= V)%VS == U is a subspace of V. *) (* free B == B is a sequence of nonzero linearly independent *) (* vectors. *) (* basis_of U b == b is a basis of the subspace U. *) (* directv S == S is the expression for a direct sum of subspaces. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Open Local Scope ring_scope. Reserved Notation "{ 'vspace' T }" (at level 0, format "{ 'vspace' T }"). Reserved Notation "''Hom' ( T , rT )" (at level 8, format "''Hom' ( T , rT )"). Reserved Notation "''End' ( T )" (at level 8, format "''End' ( T )"). Reserved Notation "\dim A" (at level 10, A at level 8, format "\dim A"). Delimit Scope vspace_scope with VS. Import GRing.Theory. (* Finite dimension vector space *) Module Vector. Section ClassDef. Variable R : ringType. Definition axiom_def n (V : lmodType R) of phant V := {v2r : V -> 'rV[R]_n | linear v2r & bijective v2r}. Inductive mixin_of (V : lmodType R) := Mixin dim & axiom_def dim (Phant V). Structure class_of V := Class { base : GRing.Lmodule.class_of R V; mixin : mixin_of (GRing.Lmodule.Pack _ base V) }. Local Coercion base : class_of >-> GRing.Lmodule.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (phR : phant R) (T : Type) (cT : type phR). Definition class := let: Pack _ c _ := cT return class_of cT in c. Definition clone c of phant_id class c := @Pack phR T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition dim := let: Mixin n _ := mixin class in n. Definition pack b0 (m0 : mixin_of (@GRing.Lmodule.Pack R _ T b0 T)) := fun bT b & phant_id (@GRing.Lmodule.class _ phR bT) b => fun m & phant_id m0 m => Pack phR (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition lmodType := @GRing.Lmodule.Pack R phR cT xclass xT. End ClassDef. Notation axiom n V := (axiom_def n (Phant V)). Section OtherDefs. Local Coercion sort : type >-> Sortclass. Local Coercion dim : type >-> nat. Inductive space (K : fieldType) (vT : type (Phant K)) (phV : phant vT) := Space (mx : 'M[K]_vT) & <>%MS == mx. Inductive hom (R : ringType) (vT wT : type (Phant R)) := Hom of 'M[R]_(vT, wT). End OtherDefs. Module Import Exports. Coercion base : class_of >-> GRing.Lmodule.class_of. Coercion mixin : class_of >-> mixin_of. Coercion sort : type >-> Sortclass. Coercion eqType: type >-> Equality.type. Bind Scope ring_scope with sort. Canonical eqType. Coercion choiceType: type >-> Choice.type. Canonical choiceType. Coercion zmodType: type >-> GRing.Zmodule.type. Canonical zmodType. Coercion lmodType: type>-> GRing.Lmodule.type. Canonical lmodType. Notation vectType R := (@type _ (Phant R)). Notation VectType R V mV := (@pack _ (Phant R) V _ mV _ _ id _ id). Notation VectMixin := Mixin. Notation "[ 'vectType' R 'of' T 'for' cT ]" := (@clone _ (Phant R) T cT _ idfun) (at level 0, format "[ 'vectType' R 'of' T 'for' cT ]") : form_scope. Notation "[ 'vectType' R 'of' T ]" := (@clone _ (Phant R) T _ _ idfun) (at level 0, format "[ 'vectType' R 'of' T ]") : form_scope. Notation "{ 'vspace' vT }" := (space (Phant vT)) : type_scope. Notation "''Hom' ( aT , rT )" := (hom aT rT) : type_scope. Notation "''End' ( vT )" := (hom vT vT) : type_scope. Prenex Implicits Hom. Delimit Scope vspace_scope with VS. Bind Scope vspace_scope with space. Delimit Scope lfun_scope with VF. Bind Scope lfun_scope with hom. End Exports. (* The contents of this module exposes the matrix encodings, and should *) (* therefore not be used outside of the vector library implementation. *) Module InternalTheory. Section Iso. Variables (R : ringType) (vT rT : vectType R). Local Coercion dim : vectType >-> nat. Fact v2r_subproof : axiom vT vT. Proof. by case: vT => T [bT []]. Qed. Definition v2r := s2val v2r_subproof. Let v2r_bij : bijective v2r := s2valP' v2r_subproof. Fact r2v_subproof : {r2v | cancel r2v v2r}. Proof. have r2vP r: {v | v2r v = r}. by apply: sig_eqW; have [v _ vK] := v2r_bij; exists (v r). by exists (fun r => sval (r2vP r)) => r; case: (r2vP r). Qed. Definition r2v := sval r2v_subproof. Lemma r2vK : cancel r2v v2r. Proof. exact: (svalP r2v_subproof). Qed. Lemma r2v_inj : injective r2v. Proof. exact: can_inj r2vK. Qed. Lemma v2rK : cancel v2r r2v. Proof. by have/bij_can_sym:= r2vK; apply. Qed. Lemma v2r_inj : injective v2r. Proof. exact: can_inj v2rK. Qed. Canonical v2r_linear := Linear (s2valP v2r_subproof : linear v2r). Canonical r2v_linear := Linear (can2_linear v2rK r2vK). End Iso. Section Vspace. Variables (K : fieldType) (vT : vectType K). Local Coercion dim : vectType >-> nat. Definition b2mx n (X : n.-tuple vT) := \matrix_i v2r (tnth X i). Lemma b2mxK n (X : n.-tuple vT) i : r2v (row i (b2mx X)) = X`_i. Proof. by rewrite rowK v2rK -tnth_nth. Qed. Definition vs2mx {phV} (U : @space K vT phV) := let: Space mx _ := U in mx. Lemma gen_vs2mx (U : {vspace vT}) : <>%MS = vs2mx U. Proof. by apply/eqP; rewrite /vs2mx; case: U. Qed. Fact mx2vs_subproof m (A : 'M[K]_(m, vT)) : <<(<>)>>%MS == <>%MS. Proof. by rewrite genmx_id. Qed. Definition mx2vs {m} A : {vspace vT} := Space _ (@mx2vs_subproof m A). Canonical space_subType := [subType for @vs2mx (Phant vT)]. Lemma vs2mxK : cancel vs2mx mx2vs. Proof. by move=> v; apply: val_inj; rewrite /= gen_vs2mx. Qed. Lemma mx2vsK m (M : 'M_(m, vT)) : (vs2mx (mx2vs M) :=: M)%MS. Proof. exact: genmxE. Qed. End Vspace. Section Hom. Variables (R : ringType) (aT rT : vectType R). Definition f2mx (f : 'Hom(aT, rT)) := let: Hom A := f in A. Canonical hom_subType := [newType for f2mx]. End Hom. Arguments Scope mx2vs [_ _ nat_scope matrix_set_scope]. Prenex Implicits v2r r2v v2rK r2vK b2mx vs2mx vs2mxK f2mx. End InternalTheory. End Vector. Export Vector.Exports. Import Vector.InternalTheory. Section VspaceDefs. Variables (K : fieldType) (vT : vectType K). Implicit Types (u : vT) (X : seq vT) (U V : {vspace vT}). Definition space_eqMixin := Eval hnf in [eqMixin of {vspace vT} by <:]. Canonical space_eqType := EqType {vspace vT} space_eqMixin. Definition space_choiceMixin := Eval hnf in [choiceMixin of {vspace vT} by <:]. Canonical space_choiceType := ChoiceType {vspace vT} space_choiceMixin. Definition dimv U := \rank (vs2mx U). Definition subsetv U V := (vs2mx U <= vs2mx V)%MS. Definition vline u := mx2vs (v2r u). (* Vspace membership is defined as line inclusion. *) Definition pred_of_vspace phV (U : Vector.space phV) : pred_class := fun v => (vs2mx (vline v) <= vs2mx U)%MS. Canonical vspace_predType := @mkPredType _ (unkeyed {vspace vT}) (@pred_of_vspace _). Definition fullv : {vspace vT} := mx2vs 1%:M. Definition addv U V := mx2vs (vs2mx U + vs2mx V). Definition capv U V := mx2vs (vs2mx U :&: vs2mx V). Definition complv U := mx2vs (vs2mx U)^C. Definition diffv U V := mx2vs (vs2mx U :\: vs2mx V). Definition vpick U := r2v (nz_row (vs2mx U)). Fact span_key : unit. Proof. by []. Qed. Definition span_expanded_def X := mx2vs (b2mx (in_tuple X)). Definition span := locked_with span_key span_expanded_def. Canonical span_unlockable := [unlockable fun span]. Definition vbasis_def U := [tuple r2v (row i (row_base (vs2mx U))) | i < dimv U]. Definition vbasis := locked_with span_key vbasis_def. Canonical vbasis_unlockable := [unlockable fun vbasis]. (* coord and directv are defined in the VectorTheory section. *) Definition free X := dimv (span X) == size X. Definition basis_of U X := (span X == U) && free X. End VspaceDefs. Coercion pred_of_vspace : Vector.space >-> pred_class. Notation "\dim U" := (dimv U) : nat_scope. Notation "U <= V" := (subsetv U V) : vspace_scope. Notation "U <= V <= W" := (subsetv U V && subsetv V W) : vspace_scope. Notation "<[ v ] >" := (vline v) : vspace_scope. Notation "<< X >>" := (span X) : vspace_scope. Notation "0" := (vline 0) : vspace_scope. Implicit Arguments fullv [[K] [vT]]. Prenex Implicits subsetv addv capv complv diffv span free basis_of. Notation "U + V" := (addv U V) : vspace_scope. Notation "U :&: V" := (capv U V) : vspace_scope. Notation "U ^C" := (complv U) (at level 8, format "U ^C") : vspace_scope. Notation "U :\: V" := (diffv U V) : vspace_scope. Notation "{ : vT }" := (@fullv _ vT) (only parsing) : vspace_scope. Notation "\sum_ ( i <- r | P ) U" := (\big[addv/0%VS]_(i <- r | P%B) U%VS) : vspace_scope. Notation "\sum_ ( i <- r ) U" := (\big[addv/0%VS]_(i <- r) U%VS) : vspace_scope. Notation "\sum_ ( m <= i < n | P ) U" := (\big[addv/0%VS]_(m <= i < n | P%B) U%VS) : vspace_scope. Notation "\sum_ ( m <= i < n ) U" := (\big[addv/0%VS]_(m <= i < n) U%VS) : vspace_scope. Notation "\sum_ ( i | P ) U" := (\big[addv/0%VS]_(i | P%B) U%VS) : vspace_scope. Notation "\sum_ i U" := (\big[addv/0%VS]_i U%VS) : vspace_scope. Notation "\sum_ ( i : t | P ) U" := (\big[addv/0%VS]_(i : t | P%B) U%VS) (only parsing) : vspace_scope. Notation "\sum_ ( i : t ) U" := (\big[addv/0%VS]_(i : t) U%VS) (only parsing) : vspace_scope. Notation "\sum_ ( i < n | P ) U" := (\big[addv/0%VS]_(i < n | P%B) U%VS) : vspace_scope. Notation "\sum_ ( i < n ) U" := (\big[addv/0%VS]_(i < n) U%VS) : vspace_scope. Notation "\sum_ ( i 'in' A | P ) U" := (\big[addv/0%VS]_(i in A | P%B) U%VS) : vspace_scope. Notation "\sum_ ( i 'in' A ) U" := (\big[addv/0%VS]_(i in A) U%VS) : vspace_scope. Notation "\bigcap_ ( i <- r | P ) U" := (\big[capv/fullv]_(i <- r | P%B) U%VS) : vspace_scope. Notation "\bigcap_ ( i <- r ) U" := (\big[capv/fullv]_(i <- r) U%VS) : vspace_scope. Notation "\bigcap_ ( m <= i < n | P ) U" := (\big[capv/fullv]_(m <= i < n | P%B) U%VS) : vspace_scope. Notation "\bigcap_ ( m <= i < n ) U" := (\big[capv/fullv]_(m <= i < n) U%VS) : vspace_scope. Notation "\bigcap_ ( i | P ) U" := (\big[capv/fullv]_(i | P%B) U%VS) : vspace_scope. Notation "\bigcap_ i U" := (\big[capv/fullv]_i U%VS) : vspace_scope. Notation "\bigcap_ ( i : t | P ) U" := (\big[capv/fullv]_(i : t | P%B) U%VS) (only parsing) : vspace_scope. Notation "\bigcap_ ( i : t ) U" := (\big[capv/fullv]_(i : t) U%VS) (only parsing) : vspace_scope. Notation "\bigcap_ ( i < n | P ) U" := (\big[capv/fullv]_(i < n | P%B) U%VS) : vspace_scope. Notation "\bigcap_ ( i < n ) U" := (\big[capv/fullv]_(i < n) U%VS) : vspace_scope. Notation "\bigcap_ ( i 'in' A | P ) U" := (\big[capv/fullv]_(i in A | P%B) U%VS) : vspace_scope. Notation "\bigcap_ ( i 'in' A ) U" := (\big[capv/fullv]_(i in A) U%VS) : vspace_scope. Section VectorTheory. Variables (K : fieldType) (vT : vectType K). Implicit Types (a : K) (u v w : vT) (X Y : seq vT) (U V W : {vspace vT}). Local Notation subV := (@subsetv K vT) (only parsing). Local Notation addV := (@addv K vT) (only parsing). Local Notation capV := (@capv K vT) (only parsing). (* begin hide *) (* Internal theory facts *) Let vs2mxP U V : reflect (U = V) (vs2mx U == vs2mx V)%MS. Proof. by rewrite (sameP genmxP eqP) !gen_vs2mx; apply: eqP. Qed. Let memvK v U : (v \in U) = (v2r v <= vs2mx U)%MS. Proof. by rewrite -genmxE. Qed. Let mem_r2v rv U : (r2v rv \in U) = (rv <= vs2mx U)%MS. Proof. by rewrite memvK r2vK. Qed. Let vs2mx0 : @vs2mx K vT _ 0 = 0. Proof. by rewrite /= linear0 genmx0. Qed. Let vs2mxD U V : vs2mx (U + V) = (vs2mx U + vs2mx V)%MS. Proof. by rewrite /= genmx_adds !gen_vs2mx. Qed. Let vs2mx_sum := big_morph _ vs2mxD vs2mx0. Let vs2mxI U V : vs2mx (U :&: V) = (vs2mx U :&: vs2mx V)%MS. Proof. by rewrite /= genmx_cap !gen_vs2mx. Qed. Let vs2mxF : vs2mx {:vT} = 1%:M. Proof. by rewrite /= genmx1. Qed. Let row_b2mx n (X : n.-tuple vT) i : row i (b2mx X) = v2r X`_i. Proof. by rewrite -tnth_nth rowK. Qed. Let span_b2mx n (X : n.-tuple vT) : span X = mx2vs (b2mx X). Proof. by rewrite unlock tvalK; case: _ / (esym _). Qed. Let mul_b2mx n (X : n.-tuple vT) (rk : 'rV_n) : \sum_i rk 0 i *: X`_i = r2v (rk *m b2mx X). Proof. rewrite mulmx_sum_row linear_sum; apply: eq_bigr => i _. by rewrite row_b2mx linearZ /= v2rK. Qed. Let lin_b2mx n (X : n.-tuple vT) k : \sum_(i < n) k i *: X`_i = r2v (\row_i k i *m b2mx X). Proof. by rewrite -mul_b2mx; apply: eq_bigr => i _; rewrite mxE. Qed. Let free_b2mx n (X : n.-tuple vT) : free X = row_free (b2mx X). Proof. by rewrite /free /dimv span_b2mx genmxE size_tuple. Qed. (* end hide *) Fact vspace_key U : pred_key U. Proof. by []. Qed. Canonical vspace_keyed U := KeyedPred (vspace_key U). Lemma memvE v U : (v \in U) = (<[v]> <= U)%VS. Proof. by []. Qed. Lemma vlineP v1 v2 : reflect (exists k, v1 = k *: v2) (v1 \in <[v2]>)%VS. Proof. apply: (iffP idP) => [|[k ->]]; rewrite memvK genmxE ?linearZ ?scalemx_sub //. by case/sub_rVP=> k; rewrite -linearZ => /v2r_inj->; exists k. Qed. Fact memv_submod_closed U : submod_closed U. Proof. split=> [|a u v]; rewrite !memvK ?linear0 ?sub0mx // => Uu Uv. by rewrite linearP addmx_sub ?scalemx_sub. Qed. Canonical memv_opprPred U := OpprPred (memv_submod_closed U). Canonical memv_addrPred U := AddrPred (memv_submod_closed U). Canonical memv_zmodPred U := ZmodPred (memv_submod_closed U). Canonical memv_submodPred U := SubmodPred (memv_submod_closed U). Lemma mem0v U : 0 \in U. Proof. exact : rpred0. Qed. Lemma memvN U v : (- v \in U) = (v \in U). Proof. exact: rpredN. Qed. Lemma memvD U : {in U &, forall u v, u + v \in U}. Proof. exact : rpredD. Qed. Lemma memvB U : {in U &, forall u v, u - v \in U}. Proof. exact : rpredB. Qed. Lemma memvZ U k : {in U, forall v, k *: v \in U}. Proof. exact : rpredZ. Qed. Lemma memv_suml I r (P : pred I) vs U : (forall i, P i -> vs i \in U) -> \sum_(i <- r | P i) vs i \in U. Proof. exact: rpred_sum. Qed. Lemma memv_line u : u \in <[u]>%VS. Proof. by apply/vlineP; exists 1; rewrite scale1r. Qed. Lemma subvP U V : reflect {subset U <= V} (U <= V)%VS. Proof. apply: (iffP rV_subP) => sU12 u. by rewrite !memvE /subsetv !genmxE => /sU12. by have:= sU12 (r2v u); rewrite !memvE /subsetv !genmxE r2vK. Qed. Lemma subvv U : (U <= U)%VS. Proof. exact/subvP. Qed. Hint Resolve subvv. Lemma subv_trans : transitive subV. Proof. by move=> U V W /subvP sUV /subvP sVW; apply/subvP=> u /sUV/sVW. Qed. Lemma subv_anti : antisymmetric subV. Proof. by move=> U V; apply/vs2mxP. Qed. Lemma eqEsubv U V : (U == V) = (U <= V <= U)%VS. Proof. by apply/eqP/idP=> [-> | /subv_anti//]; rewrite subvv. Qed. Lemma vspaceP U V : U =i V <-> U = V. Proof. split=> [eqUV | -> //]; apply/subv_anti/andP. by split; apply/subvP=> v; rewrite eqUV. Qed. Lemma subvPn {U V} : reflect (exists2 u, u \in U & u \notin V) (~~ (U <= V)%VS). Proof. apply: (iffP idP) => [|[u Uu]]; last by apply: contra => /subvP->. case/row_subPn=> i; set vi := row i _ => V'vi. by exists (r2v vi); rewrite memvK r2vK ?row_sub. Qed. (* Empty space. *) Lemma sub0v U : (0 <= U)%VS. Proof. exact: mem0v. Qed. Lemma subv0 U : (U <= 0)%VS = (U == 0%VS). Proof. by rewrite eqEsubv sub0v andbT. Qed. Lemma memv0 v : v \in 0%VS = (v == 0). Proof. by apply/idP/eqP=> [/vlineP[k ->] | ->]; rewrite (scaler0, mem0v). Qed. (* Full space *) Lemma subvf U : (U <= fullv)%VS. Proof. by rewrite /subsetv vs2mxF submx1. Qed. Lemma memvf v : v \in fullv. Proof. exact: subvf. Qed. (* Picking a non-zero vector in a subspace. *) Lemma memv_pick U : vpick U \in U. Proof. by rewrite mem_r2v nz_row_sub. Qed. Lemma vpick0 U : (vpick U == 0) = (U == 0%VS). Proof. by rewrite -memv0 mem_r2v -subv0 /subV vs2mx0 !submx0 nz_row_eq0. Qed. (* Sum of subspaces. *) Lemma subv_add U V W : (U + V <= W)%VS = (U <= W)%VS && (V <= W)%VS. Proof. by rewrite /subV vs2mxD addsmx_sub. Qed. Lemma addvS U1 U2 V1 V2 : (U1 <= U2 -> V1 <= V2 -> U1 + V1 <= U2 + V2)%VS. Proof. by rewrite /subV !vs2mxD; apply: addsmxS. Qed. Lemma addvSl U V : (U <= U + V)%VS. Proof. by rewrite /subV vs2mxD addsmxSl. Qed. Lemma addvSr U V : (V <= U + V)%VS. Proof. by rewrite /subV vs2mxD addsmxSr. Qed. Lemma addvC : commutative addV. Proof. by move=> U V; apply/vs2mxP; rewrite !vs2mxD addsmxC submx_refl. Qed. Lemma addvA : associative addV. Proof. by move=> U V W; apply/vs2mxP; rewrite !vs2mxD addsmxA submx_refl. Qed. Lemma addv_idPl {U V}: reflect (U + V = U)%VS (V <= U)%VS. Proof. by rewrite /subV (sameP addsmx_idPl eqmxP) -vs2mxD; apply: vs2mxP. Qed. Lemma addv_idPr {U V} : reflect (U + V = V)%VS (U <= V)%VS. Proof. by rewrite addvC; apply: addv_idPl. Qed. Lemma addvv : idempotent addV. Proof. by move=> U; apply/addv_idPl. Qed. Lemma add0v : left_id 0%VS addV. Proof. by move=> U; apply/addv_idPr/sub0v. Qed. Lemma addv0 : right_id 0%VS addV. Proof. by move=> U; apply/addv_idPl/sub0v. Qed. Lemma sumfv : left_zero fullv addV. Proof. by move=> U; apply/addv_idPl/subvf. Qed. Lemma addvf : right_zero fullv addV. Proof. by move=> U; apply/addv_idPr/subvf. Qed. Canonical addv_monoid := Monoid.Law addvA add0v addv0. Canonical addv_comoid := Monoid.ComLaw addvC. Lemma memv_add u v U V : u \in U -> v \in V -> u + v \in (U + V)%VS. Proof. by rewrite !memvK genmxE linearD; apply: addmx_sub_adds. Qed. Lemma memv_addP {w U V} : reflect (exists2 u, u \in U & exists2 v, v \in V & w = u + v) (w \in U + V)%VS. Proof. apply: (iffP idP) => [|[u Uu [v Vv ->]]]; last exact: memv_add. rewrite memvK genmxE => /sub_addsmxP[r /(canRL v2rK)->]. rewrite linearD /=; set u := r2v _; set v := r2v _. by exists u; last exists v; rewrite // mem_r2v submxMl. Qed. Section BigSum. Variable I : finType. Implicit Type P : pred I. Lemma sumv_sup i0 P U Vs : P i0 -> (U <= Vs i0)%VS -> (U <= \sum_(i | P i) Vs i)%VS. Proof. by move=> Pi0 /subv_trans-> //; rewrite (bigD1 i0) ?addvSl. Qed. Implicit Arguments sumv_sup [P U Vs]. Lemma subv_sumP {P Us V} : reflect (forall i, P i -> Us i <= V)%VS (\sum_(i | P i) Us i <= V)%VS. Proof. apply: (iffP idP) => [sUV i Pi | sUV]. by apply: subv_trans sUV; apply: sumv_sup Pi _. by elim/big_rec: _ => [|i W Pi sWV]; rewrite ?sub0v // subv_add sUV. Qed. Lemma memv_sumr P vs (Us : I -> {vspace vT}) : (forall i, P i -> vs i \in Us i) -> \sum_(i | P i) vs i \in (\sum_(i | P i) Us i)%VS. Proof. by move=> Uv; apply/rpred_sum=> i Pi; apply/(sumv_sup i Pi)/Uv. Qed. Lemma memv_sumP {P} {Us : I -> {vspace vT}} {v} : reflect (exists2 vs, forall i, P i -> vs i \in Us i & v = \sum_(i | P i) vs i) (v \in \sum_(i | P i) Us i)%VS. Proof. apply: (iffP idP) => [|[vs Uv ->]]; last exact: memv_sumr. rewrite memvK vs2mx_sum => /sub_sumsmxP[r /(canRL v2rK)->]. pose f i := r2v (r i *m vs2mx (Us i)); rewrite linear_sum /=. by exists f => //= i _; rewrite mem_r2v submxMl. Qed. End BigSum. (* Intersection *) Lemma subv_cap U V W : (U <= V :&: W)%VS = (U <= V)%VS && (U <= W)%VS. Proof. by rewrite /subV vs2mxI sub_capmx. Qed. Lemma capvS U1 U2 V1 V2 : (U1 <= U2 -> V1 <= V2 -> U1 :&: V1 <= U2 :&: V2)%VS. Proof. by rewrite /subV !vs2mxI; apply: capmxS. Qed. Lemma capvSl U V : (U :&: V <= U)%VS. Proof. by rewrite /subV vs2mxI capmxSl. Qed. Lemma capvSr U V : (U :&: V <= V)%VS. Proof. by rewrite /subV vs2mxI capmxSr. Qed. Lemma capvC : commutative capV. Proof. by move=> U V; apply/vs2mxP; rewrite !vs2mxI capmxC submx_refl. Qed. Lemma capvA : associative capV. Proof. by move=> U V W; apply/vs2mxP; rewrite !vs2mxI capmxA submx_refl. Qed. Lemma capv_idPl {U V} : reflect (U :&: V = U)%VS (U <= V)%VS. Proof. by rewrite /subV(sameP capmx_idPl eqmxP) -vs2mxI; apply: vs2mxP. Qed. Lemma capv_idPr {U V} : reflect (U :&: V = V)%VS (V <= U)%VS. Proof. by rewrite capvC; apply: capv_idPl. Qed. Lemma capvv : idempotent capV. Proof. by move=> U; apply/capv_idPl. Qed. Lemma cap0v : left_zero 0%VS capV. Proof. by move=> U; apply/capv_idPl/sub0v. Qed. Lemma capv0 : right_zero 0%VS capV. Proof. by move=> U; apply/capv_idPr/sub0v. Qed. Lemma capfv : left_id fullv capV. Proof. by move=> U; apply/capv_idPr/subvf. Qed. Lemma capvf : right_id fullv capV. Proof. by move=> U; apply/capv_idPl/subvf. Qed. Canonical capv_monoid := Monoid.Law capvA capfv capvf. Canonical capv_comoid := Monoid.ComLaw capvC. Lemma memv_cap w U V : (w \in U :&: V)%VS = (w \in U) && (w \in V). Proof. by rewrite !memvE subv_cap. Qed. Lemma memv_capP {w U V} : reflect (w \in U /\ w \in V) (w \in U :&: V)%VS. Proof. by rewrite memv_cap; apply: andP. Qed. Lemma vspace_modl U V W : (U <= W -> U + (V :&: W) = (U + V) :&: W)%VS. Proof. by move=> sUV; apply/vs2mxP; rewrite !(vs2mxD, vs2mxI); exact/eqmxP/matrix_modl. Qed. Lemma vspace_modr U V W : (W <= U -> (U :&: V) + W = U :&: (V + W))%VS. Proof. by rewrite -!(addvC W) !(capvC U); apply: vspace_modl. Qed. Section BigCap. Variable I : finType. Implicit Type P : pred I. Lemma bigcapv_inf i0 P Us V : P i0 -> (Us i0 <= V -> \bigcap_(i | P i) Us i <= V)%VS. Proof. by move=> Pi0; apply: subv_trans; rewrite (bigD1 i0) ?capvSl. Qed. Lemma subv_bigcapP {P U Vs} : reflect (forall i, P i -> U <= Vs i)%VS (U <= \bigcap_(i | P i) Vs i)%VS. Proof. apply: (iffP idP) => [sUV i Pi | sUV]. by rewrite (subv_trans sUV) ?(bigcapv_inf Pi). by elim/big_rec: _ => [|i W Pi]; rewrite ?subvf // subv_cap sUV. Qed. End BigCap. (* Complement *) Lemma addv_complf U : (U + U^C)%VS = fullv. Proof. apply/vs2mxP; rewrite vs2mxD -gen_vs2mx -genmx_adds !genmxE submx1 sub1mx. exact: addsmx_compl_full. Qed. Lemma capv_compl U : (U :&: U^C = 0)%VS. Proof. apply/val_inj; rewrite [val]/= vs2mx0 vs2mxI -gen_vs2mx -genmx_cap. by rewrite capmx_compl genmx0. Qed. (* Difference *) Lemma diffvSl U V : (U :\: V <= U)%VS. Proof. by rewrite /subV genmxE diffmxSl. Qed. Lemma capv_diff U V : ((U :\: V) :&: V = 0)%VS. Proof. apply/val_inj; rewrite [val]/= vs2mx0 vs2mxI -(gen_vs2mx V) -genmx_cap. by rewrite capmx_diff genmx0. Qed. Lemma addv_diff_cap U V : (U :\: V + U :&: V)%VS = U. Proof. apply/vs2mxP; rewrite vs2mxD -genmx_adds !genmxE. exact/eqmxP/addsmx_diff_cap_eq. Qed. Lemma addv_diff U V : (U :\: V + V = U + V)%VS. Proof. by rewrite -{2}(addv_diff_cap U V) -addvA (addv_idPr (capvSr U V)). Qed. (* Subspace dimension. *) Lemma dimv0 : \dim (0%VS : {vspace vT}) = 0%N. Proof. by rewrite /dimv vs2mx0 mxrank0. Qed. Lemma dimv_eq0 U : (\dim U == 0%N) = (U == 0%VS). Proof. by rewrite /dimv /= mxrank_eq0 {2}/eq_op /= linear0 genmx0. Qed. Lemma dimvf : \dim {:vT} = Vector.dim vT. Proof. by rewrite /dimv vs2mxF mxrank1. Qed. Lemma dim_vline v : \dim <[v]> = (v != 0). Proof. by rewrite /dimv mxrank_gen rank_rV (can2_eq v2rK r2vK) linear0. Qed. Lemma dimvS U V : (U <= V)%VS -> \dim U <= \dim V. Proof. exact: mxrankS. Qed. Lemma dimv_leqif_sup U V : (U <= V)%VS -> \dim U <= \dim V ?= iff (V <= U)%VS. Proof. exact: mxrank_leqif_sup. Qed. Lemma dimv_leqif_eq U V : (U <= V)%VS -> \dim U <= \dim V ?= iff (U == V). Proof. by rewrite eqEsubv; apply: mxrank_leqif_eq. Qed. Lemma eqEdim U V : (U == V) = (U <= V)%VS && (\dim V <= \dim U). Proof. by apply/idP/andP=> [/eqP | [/dimv_leqif_eq/geq_leqif]] ->. Qed. Lemma dimv_compl U : \dim U^C = (\dim {:vT} - \dim U)%N. Proof. by rewrite dimvf /dimv mxrank_gen mxrank_compl. Qed. Lemma dimv_cap_compl U V : (\dim (U :&: V) + \dim (U :\: V))%N = \dim U. Proof. by rewrite /dimv !mxrank_gen mxrank_cap_compl. Qed. Lemma dimv_sum_cap U V : (\dim (U + V) + \dim (U :&: V) = \dim U + \dim V)%N. Proof. by rewrite /dimv !mxrank_gen mxrank_sum_cap. Qed. Lemma dimv_disjoint_sum U V : (U :&: V = 0)%VS -> \dim (U + V) = (\dim U + \dim V)%N. Proof. by move=> dxUV; rewrite -dimv_sum_cap dxUV dimv0 addn0. Qed. Lemma dimv_add_leqif U V : \dim (U + V) <= \dim U + \dim V ?= iff (U :&: V <= 0)%VS. Proof. by rewrite /dimv /subV !mxrank_gen vs2mx0 genmxE; apply: mxrank_adds_leqif. Qed. Lemma diffv_eq0 U V : (U :\: V == 0)%VS = (U <= V)%VS. Proof. rewrite -dimv_eq0 -(eqn_add2l (\dim (U :&: V))) addn0 dimv_cap_compl eq_sym. by rewrite (dimv_leqif_eq (capvSl _ _)) (sameP capv_idPl eqP). Qed. Lemma dimv_leq_sum I r (P : pred I) (Us : I -> {vspace vT}) : \dim (\sum_(i <- r | P i) Us i) <= \sum_(i <- r | P i) \dim (Us i). Proof. elim/big_rec2: _ => [|i d vs _ le_vs_d]; first by rewrite dim_vline eqxx. by apply: (leq_trans (dimv_add_leqif _ _)); rewrite leq_add2l. Qed. Section SumExpr. (* The vector direct sum theory clones the interface types of the matrix *) (* direct sum theory (see mxalgebra for the technical details), but *) (* nevetheless reuses much of the matrix theory. *) Structure addv_expr := Sumv { addv_val :> wrapped {vspace vT}; addv_dim : wrapped nat; _ : mxsum_spec (vs2mx (unwrap addv_val)) (unwrap addv_dim) }. (* Piggyback on mxalgebra theory. *) Definition vs2mx_sum_expr_subproof (S : addv_expr) : mxsum_spec (vs2mx (unwrap S)) (unwrap (addv_dim S)). Proof. by case: S. Qed. Canonical vs2mx_sum_expr S := ProperMxsumExpr (vs2mx_sum_expr_subproof S). Canonical trivial_addv U := @Sumv (Wrap U) (Wrap (\dim U)) (TrivialMxsum _). Structure proper_addv_expr := ProperSumvExpr { proper_addv_val :> {vspace vT}; proper_addv_dim :> nat; _ : mxsum_spec (vs2mx proper_addv_val) proper_addv_dim }. Definition proper_addvP (S : proper_addv_expr) := let: ProperSumvExpr _ _ termS := S return mxsum_spec (vs2mx S) S in termS. Canonical proper_addv (S : proper_addv_expr) := @Sumv (wrap (S : {vspace vT})) (wrap (S : nat)) (proper_addvP S). Section Binary. Variables S1 S2 : addv_expr. Fact binary_addv_subproof : mxsum_spec (vs2mx (unwrap S1 + unwrap S2)) (unwrap (addv_dim S1) + unwrap (addv_dim S2)). Proof. by rewrite vs2mxD; apply: proper_mxsumP. Qed. Canonical binary_addv_expr := ProperSumvExpr binary_addv_subproof. End Binary. Section Nary. Variables (I : Type) (r : seq I) (P : pred I) (S_ : I -> addv_expr). Fact nary_addv_subproof : mxsum_spec (vs2mx (\sum_(i <- r | P i) unwrap (S_ i))) (\sum_(i <- r | P i) unwrap (addv_dim (S_ i))). Proof. by rewrite vs2mx_sum; apply: proper_mxsumP. Qed. Canonical nary_addv_expr := ProperSumvExpr nary_addv_subproof. End Nary. Definition directv_def S of phantom {vspace vT} (unwrap (addv_val S)) := \dim (unwrap S) == unwrap (addv_dim S). End SumExpr. Local Notation directv A := (directv_def (Phantom {vspace _} A%VS)). Lemma directvE (S : addv_expr) : directv (unwrap S) = (\dim (unwrap S) == unwrap (addv_dim S)). Proof. by []. Qed. Lemma directvP {S : proper_addv_expr} : reflect (\dim S = S :> nat) (directv S). Proof. exact: eqnP. Qed. Lemma directv_trivial U : directv (unwrap (@trivial_addv U)). Proof. exact: eqxx. Qed. Lemma dimv_sum_leqif (S : addv_expr) : \dim (unwrap S) <= unwrap (addv_dim S) ?= iff directv (unwrap S). Proof. rewrite directvE; case: S => [[U] [d] /= defUd]; split=> //=. rewrite /dimv; elim: {1}_ {U}_ d / defUd => // m1 m2 A1 A2 r1 r2 _ leA1 _ leA2. by apply: leq_trans (leq_add leA1 leA2); rewrite mxrank_adds_leqif. Qed. Lemma directvEgeq (S : addv_expr) : directv (unwrap S) = (\dim (unwrap S) >= unwrap (addv_dim S)). Proof. by rewrite leq_eqVlt ltnNge eq_sym !dimv_sum_leqif orbF. Qed. Section BinaryDirect. Lemma directv_addE (S1 S2 : addv_expr) : directv (unwrap S1 + unwrap S2) = [&& directv (unwrap S1), directv (unwrap S2) & unwrap S1 :&: unwrap S2 == 0]%VS. Proof. by rewrite /directv_def /dimv vs2mxD -mxdirectE mxdirect_addsE -vs2mxI -vs2mx0. Qed. Lemma directv_addP {U V} : reflect (U :&: V = 0)%VS (directv (U + V)). Proof. by rewrite directv_addE !directv_trivial; apply: eqP. Qed. Lemma directv_add_unique {U V} : reflect (forall u1 u2 v1 v2, u1 \in U -> u2 \in U -> v1 \in V -> v2 \in V -> (u1 + v1 == u2 + v2) = ((u1, v1) == (u2, v2))) (directv (U + V)). Proof. apply: (iffP directv_addP) => [dxUV u1 u2 v1 v2 Uu1 Uu2 Vv1 Vv2 | dxUV]. apply/idP/idP=> [| /eqP[-> ->] //]; rewrite -subr_eq0 opprD addrACA addr_eq0. move/eqP=> eq_uv; rewrite xpair_eqE -subr_eq0 eq_uv oppr_eq0 subr_eq0 andbb. by rewrite -subr_eq0 -memv0 -dxUV memv_cap -memvN -eq_uv !memvB. apply/eqP; rewrite -subv0; apply/subvP=> v /memv_capP[U1v U2v]. by rewrite memv0 -[v == 0]andbb {1}eq_sym -xpair_eqE -dxUV ?mem0v // addrC. Qed. End BinaryDirect. Section NaryDirect. Context {I : finType} {P : pred I}. Lemma directv_sumP {Us : I -> {vspace vT}} : reflect (forall i, P i -> Us i :&: (\sum_(j | P j && (j != i)) Us j) = 0)%VS (directv (\sum_(i | P i) Us i)). Proof. rewrite directvE /= /dimv vs2mx_sum -mxdirectE; apply: (equivP mxdirect_sumsP). by do [split=> dxU i /dxU; rewrite -vs2mx_sum -vs2mxI -vs2mx0] => [/val_inj|->]. Qed. Lemma directv_sumE {Ss : I -> addv_expr} (xunwrap := unwrap) : reflect [/\ forall i, P i -> directv (unwrap (Ss i)) & directv (\sum_(i | P i) xunwrap (Ss i))] (directv (\sum_(i | P i) unwrap (Ss i))). Proof. by rewrite !directvE /= /dimv 2!{1}vs2mx_sum -!mxdirectE; apply: mxdirect_sumsE. Qed. Lemma directv_sum_independent {Us : I -> {vspace vT}} : reflect (forall us, (forall i, P i -> us i \in Us i) -> \sum_(i | P i) us i = 0 -> (forall i, P i -> us i = 0)) (directv (\sum_(i | P i) Us i)). Proof. apply: (iffP directv_sumP) => [dxU us Uu u_0 i Pi | dxU i Pi]. apply/eqP; rewrite -memv0 -(dxU i Pi) memv_cap Uu //= -memvN -sub0r -{1}u_0. by rewrite (bigD1 i) //= addrC addKr memv_sumr // => j /andP[/Uu]. apply/eqP; rewrite -subv0; apply/subvP=> v. rewrite memv_cap memv0 => /andP[Uiv /memv_sumP[us Uu Dv]]. have: \sum_(j | P j) [eta us with i |-> - v] j = 0. rewrite (bigD1 i) //= eqxx {1}Dv addrC -sumrB big1 // => j /andP[_ i'j]. by rewrite (negPf i'j) subrr. move/dxU/(_ i Pi); rewrite /= eqxx -oppr_eq0 => -> // j Pj. by have [-> | i'j] := altP eqP; rewrite ?memvN // Uu ?Pj. Qed. Lemma directv_sum_unique {Us : I -> {vspace vT}} : reflect (forall us vs, (forall i, P i -> us i \in Us i) -> (forall i, P i -> vs i \in Us i) -> (\sum_(i | P i) us i == \sum_(i | P i) vs i) = [forall (i | P i), us i == vs i]) (directv (\sum_(i | P i) Us i)). Proof. apply: (iffP directv_sum_independent) => [dxU us vs Uu Uv | dxU us Uu u_0 i Pi]. apply/idP/forall_inP=> [|eq_uv]; last by apply/eqP/eq_bigr => i /eq_uv/eqP. rewrite -subr_eq0 -sumrB => /eqP/dxU eq_uv i Pi. by rewrite -subr_eq0 eq_uv // => j Pj; apply: memvB; move: j Pj. apply/eqP; have:= esym (dxU us \0 Uu _); rewrite u_0 big1_eq eqxx. by move/(_ _)/forall_inP=> -> // j _; apply: mem0v. Qed. End NaryDirect. (* Linear span generated by a list of vectors *) Lemma memv_span X v : v \in X -> v \in <>%VS. Proof. by case/seq_tnthP=> i {v}->; rewrite unlock memvK genmxE (eq_row_sub i) // rowK. Qed. Lemma memv_span1 v : v \in <<[:: v]>>%VS. Proof. by rewrite memv_span ?mem_head. Qed. Lemma dim_span X : \dim <> <= size X. Proof. by rewrite unlock /dimv genmxE rank_leq_row. Qed. Lemma span_subvP {X U} : reflect {subset X <= U} (<> <= U)%VS. Proof. rewrite /subV [@span _ _]unlock genmxE. apply: (iffP row_subP) => /= [sXU | sXU i]. by move=> _ /seq_tnthP[i ->]; have:= sXU i; rewrite rowK memvK. by rewrite rowK -memvK sXU ?mem_tnth. Qed. Lemma sub_span X Y : {subset X <= Y} -> (<> <= <>)%VS. Proof. by move=> sXY; apply/span_subvP=> v /sXY/memv_span. Qed. Lemma eq_span X Y : X =i Y -> (<> = <>)%VS. Proof. by move=> eqXY; apply: subv_anti; rewrite !sub_span // => u; rewrite eqXY. Qed. Lemma span_def X : span X = (\sum_(u <- X) <[u]>)%VS. Proof. apply/subv_anti/andP; split. by apply/span_subvP=> v Xv; rewrite (big_rem v) // memvE addvSl. by rewrite big_tnth; apply/subv_sumP=> i _; rewrite -memvE memv_span ?mem_tnth. Qed. Lemma span_nil : (<> = 0)%VS. Proof. by rewrite span_def big_nil. Qed. Lemma span_seq1 v : (<<[:: v]>> = <[v]>)%VS. Proof. by rewrite span_def big_seq1. Qed. Lemma span_cons v X : (<> = <[v]> + <>)%VS. Proof. by rewrite !span_def big_cons. Qed. Lemma span_cat X Y : (<> = <> + <>)%VS. Proof. by rewrite !span_def big_cat. Qed. (* Coordinates function; should perhaps be generalized to nat indices. *) Definition coord_expanded_def n (X : n.-tuple vT) i v := (v2r v *m pinvmx (b2mx X)) 0 i. Definition coord := locked_with span_key coord_expanded_def. Canonical coord_unlockable := [unlockable fun coord]. Fact coord_is_scalar n (X : n.-tuple vT) i : scalar (coord X i). Proof. by move=> k u v; rewrite unlock linearP mulmxDl -scalemxAl !mxE. Qed. Canonical coord_addidive n Xn i := Additive (@coord_is_scalar n Xn i). Canonical coord_linear n Xn i := AddLinear (@coord_is_scalar n Xn i). Lemma coord_span n (X : n.-tuple vT) v : v \in span X -> v = \sum_i coord X i v *: X`_i. Proof. rewrite memvK span_b2mx genmxE => Xv. by rewrite unlock_with mul_b2mx mulmxKpV ?v2rK. Qed. Lemma coord0 i v : coord [tuple 0] i v = 0. Proof. rewrite unlock /pinvmx rank_rV; case: negP => [[] | _]. by apply/eqP/rowP=> j; rewrite !mxE (tnth_nth 0) /= linear0 mxE. by rewrite pid_mx_0 !(mulmx0, mul0mx) mxE. Qed. (* Free generator sequences. *) Lemma nil_free : free (Nil vT). Proof. by rewrite /free span_nil dimv0. Qed. Lemma seq1_free v : free [:: v] = (v != 0). Proof. by rewrite /free span_seq1 dim_vline; case: (~~ _). Qed. Lemma perm_free X Y : perm_eq X Y -> free X = free Y. Proof. by move=> eqX; rewrite /free (perm_eq_size eqX) (eq_span (perm_eq_mem eqX)). Qed. Lemma free_directv X : free X = (0 \notin X) && directv (\sum_(v <- X) <[v]>). Proof. have leXi i (v := tnth (in_tuple X) i): true -> \dim <[v]> <= 1 ?= iff (v != 0). by rewrite -seq1_free -span_seq1 => _; apply/leqif_eq/dim_span. have [_ /=] := leqif_trans (dimv_sum_leqif _) (leqif_sum leXi). rewrite sum1_card card_ord !directvE /= /free andbC span_def !(big_tnth _ _ X). by congr (_ = _ && _); rewrite -has_pred1 -all_predC -big_all big_tnth big_andE. Qed. Lemma free_not0 v X : free X -> v \in X -> v != 0. Proof. by rewrite free_directv andbC => /andP[_ /memPn]; apply. Qed. Lemma freeP n (X : n.-tuple vT) : reflect (forall k, \sum_(i < n) k i *: X`_i = 0 -> (forall i, k i = 0)) (free X). Proof. rewrite free_b2mx; apply: (iffP idP) => [t_free k kt0 i | t_free]. suffices /rowP/(_ i): \row_i k i = 0 by rewrite !mxE. by apply/(row_free_inj t_free)/r2v_inj; rewrite mul0mx -lin_b2mx kt0 linear0. rewrite -kermx_eq0; apply/rowV0P=> rk /sub_kermxP kt0. by apply/rowP=> i; rewrite mxE {}t_free // mul_b2mx kt0 linear0. Qed. Lemma coord_free n (X : n.-tuple vT) (i j : 'I_n) : free X -> coord X j (X`_i) = (i == j)%:R. Proof. rewrite unlock free_b2mx => /row_freeP[Ct CtK]; rewrite -row_b2mx. by rewrite -row_mul -[pinvmx _]mulmx1 -CtK 2!mulmxA mulmxKpV // CtK !mxE. Qed. Lemma coord_sum_free n (X : n.-tuple vT) k j : free X -> coord X j (\sum_(i < n) k i *: X`_i) = k j. Proof. move=> Xfree; rewrite linear_sum (bigD1 j) ?linearZ //= coord_free // eqxx. rewrite mulr1 big1 ?addr0 // => i /negPf j'i. by rewrite linearZ /= coord_free // j'i mulr0. Qed. Lemma cat_free X Y : free (X ++ Y) = [&& free X, free Y & directv (<> + <>)]. Proof. rewrite !free_directv mem_cat directvE /= !big_cat -directvE directv_addE /=. rewrite negb_or -!andbA; do !bool_congr; rewrite -!span_def. by rewrite (sameP eqP directv_addP). Qed. Lemma catl_free Y X : free (X ++ Y) -> free X. Proof. by rewrite cat_free => /and3P[]. Qed. Lemma catr_free X Y : free (X ++ Y) -> free Y. Proof. by rewrite cat_free => /and3P[]. Qed. Lemma filter_free p X : free X -> free (filter p X). Proof. rewrite -(perm_free (etrans (perm_filterC p X _) (perm_eq_refl X))). exact: catl_free. Qed. Lemma free_cons v X : free (v :: X) = (v \notin <>)%VS && free X. Proof. rewrite (cat_free [:: v]) seq1_free directvEgeq /= span_seq1 dim_vline. case: eqP => [-> | _] /=; first by rewrite mem0v. rewrite andbC ltnNge (geq_leqif (dimv_leqif_sup _)) ?addvSr //. by rewrite subv_add subvv andbT -memvE. Qed. Lemma freeE n (X : n.-tuple vT) : free X = [forall i : 'I_n, X`_i \notin <>%VS]. Proof. case: X => X /= /eqP <-{n}; rewrite -(big_andE xpredT) /=. elim: X => [|v X IH_X] /=; first by rewrite nil_free big_ord0. by rewrite free_cons IH_X big_ord_recl drop0. Qed. Lemma freeNE n (X : n.-tuple vT) : ~~ free X = [exists i : 'I_n, X`_i \in <>%VS]. Proof. by rewrite freeE -negb_exists negbK. Qed. Lemma free_uniq X : free X -> uniq X. Proof. elim: X => //= v b IH_X; rewrite free_cons => /andP[X'v /IH_X->]. by rewrite (contra _ X'v) // => /memv_span. Qed. Lemma free_span X v (sumX := fun k => \sum_(x <- X) k x *: x) : free X -> v \in <>%VS -> {k | v = sumX k & forall k1, v = sumX k1 -> {in X, k1 =1 k}}. Proof. rewrite -{2}[X]in_tupleE => freeX /coord_span def_v. pose k x := oapp (fun i => coord (in_tuple X) i v) 0 (insub (index x X)). exists k => [|k1 {def_v}def_v _ /(nthP 0)[i ltiX <-]]. rewrite /sumX (big_nth 0) big_mkord def_v; apply: eq_bigr => i _. by rewrite /k index_uniq ?free_uniq // valK. rewrite /k /= index_uniq ?free_uniq // insubT //= def_v. by rewrite /sumX (big_nth 0) big_mkord coord_sum_free. Qed. Lemma linear_of_free (rT : lmodType K) X (fX : seq rT) : {f : {linear vT -> rT} | free X -> size fX = size X -> map f X = fX}. Proof. pose f u := \sum_i coord (in_tuple X) i u *: fX`_i. have lin_f: linear f. move=> k u v; rewrite scaler_sumr -big_split; apply: eq_bigr => i _. by rewrite /= scalerA -scalerDl linearP. exists (Linear lin_f) => freeX eq_szX. apply/esym/(@eq_from_nth _ 0); rewrite ?size_map eq_szX // => i ltiX. rewrite (nth_map 0) //= /f (bigD1 (Ordinal ltiX)) //=. rewrite big1 => [|j /negbTE neqji]; rewrite (coord_free (Ordinal _)) //. by rewrite eqxx scale1r addr0. by rewrite eq_sym neqji scale0r. Qed. (* Subspace bases *) Lemma span_basis U X : basis_of U X -> <>%VS = U. Proof. by case/andP=> /eqP. Qed. Lemma basis_free U X : basis_of U X -> free X. Proof. by case/andP. Qed. Lemma coord_basis U n (X : n.-tuple vT) v : basis_of U X -> v \in U -> v = \sum_i coord X i v *: X`_i. Proof. by move/span_basis <-; apply: coord_span. Qed. Lemma nil_basis : basis_of 0 (Nil vT). Proof. by rewrite /basis_of span_nil eqxx nil_free. Qed. Lemma seq1_basis v : v != 0 -> basis_of <[v]> [:: v]. Proof. by move=> nz_v; rewrite /basis_of span_seq1 // eqxx seq1_free. Qed. Lemma basis_not0 x U X : basis_of U X -> x \in X -> x != 0. Proof. by move/basis_free/free_not0; apply. Qed. Lemma basis_mem x U X : basis_of U X -> x \in X -> x \in U. Proof. by move/span_basis=> <- /memv_span. Qed. Lemma cat_basis U V X Y : directv (U + V) -> basis_of U X -> basis_of V Y -> basis_of (U + V) (X ++ Y). Proof. move=> dxUV /andP[/eqP defU freeX] /andP[/eqP defV freeY]. by rewrite /basis_of span_cat cat_free defU defV // eqxx freeX freeY. Qed. Lemma size_basis U n (X : n.-tuple vT) : basis_of U X -> \dim U = n. Proof. by case/andP=> /eqP <- /eqnP->; apply: size_tuple. Qed. Lemma basisEdim X U : basis_of U X = (U <= <>)%VS && (size X <= \dim U). Proof. apply/andP/idP=> [[defU /eqnP <-]| ]; first by rewrite -eqEdim eq_sym. case/andP=> sUX leXU; have leXX := dim_span X. rewrite /free eq_sym eqEdim sUX eqn_leq !(leq_trans leXX) //. by rewrite (leq_trans leXU) ?dimvS. Qed. Lemma basisEfree X U : basis_of U X = [&& free X, (<> <= U)%VS & \dim U <= size X]. Proof. by rewrite andbC; apply: andb_id2r => freeX; rewrite eqEdim (eqnP freeX). Qed. Lemma perm_basis X Y U : perm_eq X Y -> basis_of U X = basis_of U Y. Proof. move=> eqXY; congr ((_ == _) && _); last exact: perm_free. by apply/eq_span; apply: perm_eq_mem. Qed. Lemma vbasisP U : basis_of U (vbasis U). Proof. rewrite /basis_of free_b2mx span_b2mx (sameP eqP (vs2mxP _ _)) !genmxE. have ->: b2mx (vbasis U) = row_base (vs2mx U). by apply/row_matrixP=> i; rewrite unlock rowK tnth_mktuple r2vK. by rewrite row_base_free !eq_row_base submx_refl. Qed. Lemma vbasis_mem v U : v \in (vbasis U) -> v \in U. Proof. exact: (basis_mem (vbasisP _)). Qed. Lemma coord_vbasis v U : v \in U -> v = \sum_(i < \dim U) coord (vbasis U) i v *: (vbasis U)`_i. Proof. exact: coord_basis (vbasisP U). Qed. Section BigSumBasis. Variables (I : finType) (P : pred I) (Xs : I -> seq vT). Lemma span_bigcat : (<<\big[cat/[::]]_(i | P i) Xs i>> = \sum_(i | P i) <>)%VS. Proof. by rewrite (big_morph _ span_cat span_nil). Qed. Lemma bigcat_free : directv (\sum_(i | P i) <>) -> (forall i, P i -> free (Xs i)) -> free (\big[cat/[::]]_(i | P i) Xs i). Proof. rewrite /free directvE /= span_bigcat => /directvP-> /= freeXs. rewrite (big_morph _ (@size_cat _) (erefl _)) /=. by apply/eqP/eq_bigr=> i /freeXs/eqP. Qed. Lemma bigcat_basis Us (U := (\sum_(i | P i) Us i)%VS) : directv U -> (forall i, P i -> basis_of (Us i) (Xs i)) -> basis_of U (\big[cat/[::]]_(i | P i) Xs i). Proof. move=> dxU XsUs; rewrite /basis_of span_bigcat. have defUs i: P i -> span (Xs i) = Us i by case/XsUs/andP=> /eqP. rewrite (eq_bigr _ defUs) eqxx bigcat_free // => [|_ /XsUs/andP[]//]. apply/directvP; rewrite /= (eq_bigr _ defUs) (directvP dxU) /=. by apply/eq_bigr=> i /defUs->. Qed. End BigSumBasis. End VectorTheory. Hint Resolve subvv. Implicit Arguments subvP [K vT U V]. Implicit Arguments addv_idPl [K vT U V]. Implicit Arguments addv_idPr [K vT U V]. Implicit Arguments memv_addP [K vT U V w]. Implicit Arguments sumv_sup [K vT I P U Vs]. Implicit Arguments memv_sumP [K vT I P Us v]. Implicit Arguments subv_sumP [K vT I P Us V]. Implicit Arguments capv_idPl [K vT U V]. Implicit Arguments capv_idPr [K vT U V]. Implicit Arguments memv_capP [K vT U V w]. Implicit Arguments bigcapv_inf [K vT I P Us V]. Implicit Arguments subv_bigcapP [K vT I P U Vs]. Implicit Arguments directvP [K vT S]. Implicit Arguments directv_addP [K vT U V]. Implicit Arguments directv_add_unique [K vT U V]. Implicit Arguments directv_sumP [K vT I P Us]. Implicit Arguments directv_sumE [K vT I P Ss]. Implicit Arguments directv_sum_independent [K vT I P Us]. Implicit Arguments directv_sum_unique [K vT I P Us]. Implicit Arguments span_subvP [K vT X U]. Implicit Arguments freeP [K vT n X]. Prenex Implicits coord. Notation directv S := (directv_def (Phantom _ S%VS)). (* Linear functions over a vectType *) Section LfunDefs. Variable R : ringType. Implicit Types aT vT rT : vectType R. Fact lfun_key : unit. Proof. by []. Qed. Definition fun_of_lfun_def aT rT (f : 'Hom(aT, rT)) := r2v \o mulmxr (f2mx f) \o v2r. Definition fun_of_lfun := locked_with lfun_key fun_of_lfun_def. Canonical fun_of_lfun_unlockable := [unlockable fun fun_of_lfun]. Definition linfun_def aT rT (f : aT -> rT) := Vector.Hom (lin1_mx (v2r \o f \o r2v)). Definition linfun := locked_with lfun_key linfun_def. Canonical linfun_unlockable := [unlockable fun linfun]. Definition id_lfun vT := @linfun vT vT idfun. Definition comp_lfun aT vT rT (f : 'Hom(vT, rT)) (g : 'Hom(aT, vT)) := linfun (fun_of_lfun f \o fun_of_lfun g). End LfunDefs. Coercion fun_of_lfun : Vector.hom >-> Funclass. Notation "\1" := (@id_lfun _ _) : lfun_scope. Notation "f \o g" := (comp_lfun f g) : lfun_scope. Section LfunVspaceDefs. Variable K : fieldType. Implicit Types aT rT : vectType K. Definition inv_lfun aT rT (f : 'Hom(aT, rT)) := Vector.Hom (pinvmx (f2mx f)). Definition lker aT rT (f : 'Hom(aT, rT)) := mx2vs (kermx (f2mx f)). Fact lfun_img_key : unit. Proof. by []. Qed. Definition lfun_img_def aT rT f (U : {vspace aT}) : {vspace rT} := mx2vs (vs2mx U *m f2mx f). Definition lfun_img := locked_with lfun_img_key lfun_img_def. Canonical lfun_img_unlockable := [unlockable fun lfun_img]. Definition lfun_preim aT rT (f : 'Hom(aT, rT)) W := (lfun_img (inv_lfun f) (W :&: lfun_img f fullv) + lker f)%VS. End LfunVspaceDefs. Prenex Implicits linfun lfun_img lker lfun_preim. Notation "f ^-1" := (inv_lfun f) : lfun_scope. Notation "f @: U" := (lfun_img f%VF%R U) (at level 24) : vspace_scope. Notation "f @^-1: W" := (lfun_preim f%VF%R W) (at level 24) : vspace_scope. Notation limg f := (lfun_img f fullv). Section LfunZmodType. Variables (R : ringType) (aT rT : vectType R). Implicit Types f g h : 'Hom(aT, rT). Canonical lfun_eqMixin := Eval hnf in [eqMixin of 'Hom(aT, rT) by <:]. Canonical lfun_eqType := EqType 'Hom(aT, rT) lfun_eqMixin. Definition lfun_choiceMixin := [choiceMixin of 'Hom(aT, rT) by <:]. Canonical lfun_choiceType := ChoiceType 'Hom(aT, rT) lfun_choiceMixin. Fact lfun_is_linear f : linear f. Proof. by rewrite unlock; apply: linearP. Qed. Canonical lfun_additive f := Additive (lfun_is_linear f). Canonical lfun_linear f := AddLinear (lfun_is_linear f). Lemma lfunE (ff : {linear aT -> rT}) : linfun ff =1 ff. Proof. by move=> v; rewrite 2!unlock /= mul_rV_lin1 /= !v2rK. Qed. Lemma fun_of_lfunK : cancel (@fun_of_lfun R aT rT) linfun. Proof. move=> f; apply/val_inj/row_matrixP=> i. by rewrite 2!unlock /= !rowE mul_rV_lin1 /= !r2vK. Qed. Lemma lfunP f g : f =1 g <-> f = g. Proof. split=> [eq_fg | -> //]; rewrite -[f]fun_of_lfunK -[g]fun_of_lfunK unlock. by apply/val_inj/row_matrixP=> i; rewrite !rowE !mul_rV_lin1 /= eq_fg. Qed. Definition zero_lfun : 'Hom(aT, rT) := linfun \0. Definition add_lfun f g := linfun (f \+ g). Definition opp_lfun f := linfun (-%R \o f). Fact lfun_addA : associative add_lfun. Proof. by move=> f g h; apply/lfunP=> v; rewrite !lfunE /= !lfunE addrA. Qed. Fact lfun_addC : commutative add_lfun. Proof. by move=> f g; apply/lfunP=> v; rewrite !lfunE /= addrC. Qed. Fact lfun_add0 : left_id zero_lfun add_lfun. Proof. by move=> f; apply/lfunP=> v; rewrite lfunE /= lfunE add0r. Qed. Lemma lfun_addN : left_inverse zero_lfun opp_lfun add_lfun. Proof. by move=> f; apply/lfunP=> v; rewrite !lfunE /= lfunE addNr. Qed. Definition lfun_zmodMixin := ZmodMixin lfun_addA lfun_addC lfun_add0 lfun_addN. Canonical lfun_zmodType := Eval hnf in ZmodType 'Hom(aT, rT) lfun_zmodMixin. Lemma zero_lfunE x : (0 : 'Hom(aT, rT)) x = 0. Proof. exact: lfunE. Qed. Lemma add_lfunE f g x : (f + g) x = f x + g x. Proof. exact: lfunE. Qed. Lemma opp_lfunE f x : (- f) x = - f x. Proof. exact: lfunE. Qed. Lemma sum_lfunE I (r : seq I) (P : pred I) (fs : I -> 'Hom(aT, rT)) x : (\sum_(i <- r | P i) fs i) x = \sum_(i <- r | P i) fs i x. Proof. by elim/big_rec2: _ => [|i _ f _ <-]; rewrite lfunE. Qed. End LfunZmodType. Section LfunVectType. Variables (R : comRingType) (aT rT : vectType R). Implicit Types f : 'Hom(aT, rT). Definition scale_lfun k f := linfun (k \*: f). Local Infix "*:l" := scale_lfun (at level 40). Fact lfun_scaleA k1 k2 f : k1 *:l (k2 *:l f) = (k1 * k2) *:l f. Proof. by apply/lfunP=> v; rewrite !lfunE /= lfunE scalerA. Qed. Fact lfun_scale1 f : 1 *:l f = f. Proof. by apply/lfunP=> v; rewrite lfunE /= scale1r. Qed. Fact lfun_scaleDr k f1 f2 : k *:l (f1 + f2) = k *:l f1 + k *:l f2. Proof. by apply/lfunP=> v; rewrite !lfunE /= !lfunE scalerDr. Qed. Fact lfun_scaleDl f k1 k2 : (k1 + k2) *:l f = k1 *:l f + k2 *:l f. Proof. by apply/lfunP=> v; rewrite !lfunE /= !lfunE scalerDl. Qed. Definition lfun_lmodMixin := LmodMixin lfun_scaleA lfun_scale1 lfun_scaleDr lfun_scaleDl. Canonical lfun_lmodType := Eval hnf in LmodType R 'Hom(aT, rT) lfun_lmodMixin. Lemma scale_lfunE k f x : (k *: f) x = k *: f x. Proof. exact: lfunE. Qed. (* GG: exists (Vector.Hom \o vec_mx) fails in the proof below in 8.3, *) (* probably because of incomplete type unification. Will it work in 8.4? *) Fact lfun_vect_iso : Vector.axiom (Vector.dim aT * Vector.dim rT) 'Hom(aT, rT). Proof. exists (mxvec \o f2mx) => [a f g|]. rewrite /= -linearP /= -[A in _ = mxvec A]/(f2mx (Vector.Hom _)). congr (mxvec (f2mx _)); apply/lfunP=> v; do 2!rewrite lfunE /=. by rewrite unlock /= -linearP mulmxDr scalemxAr. apply: Bijective (Vector.Hom \o vec_mx) _ _ => [[A]|A] /=; last exact: vec_mxK. by rewrite mxvecK. Qed. Definition lfun_vectMixin := VectMixin lfun_vect_iso. Canonical lfun_vectType := VectType R 'Hom(aT, rT) lfun_vectMixin. End LfunVectType. Section CompLfun. Variables (R : ringType) (wT aT vT rT : vectType R). Implicit Types (f : 'Hom(vT, rT)) (g : 'Hom(aT, vT)) (h : 'Hom(wT, aT)). Lemma id_lfunE u: \1%VF u = u :> aT. Proof. exact: lfunE. Qed. Lemma comp_lfunE f g u : (f \o g)%VF u = f (g u). Proof. exact: lfunE. Qed. Lemma comp_lfunA f g h : (f \o (g \o h) = (f \o g) \o h)%VF. Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. Lemma comp_lfun1l f : (\1 \o f)%VF = f. Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. Lemma comp_lfun1r f : (f \o \1)%VF = f. Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. Lemma comp_lfun0l g : (0 \o g)%VF = 0 :> 'Hom(aT, rT). Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. Lemma comp_lfun0r f : (f \o 0)%VF = 0 :> 'Hom(aT, rT). Proof. by apply/lfunP=> u; do !rewrite lfunE /=; rewrite linear0. Qed. Lemma comp_lfunDl f1 f2 g : ((f1 + f2) \o g = (f1 \o g) + (f2 \o g))%VF. Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. Lemma comp_lfunDr f g1 g2 : (f \o (g1 + g2) = (f \o g1) + (f \o g2))%VF. Proof. by apply/lfunP=> u; do !rewrite lfunE /=; rewrite linearD. Qed. Lemma comp_lfunNl f g : ((- f) \o g = - (f \o g))%VF. Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. Lemma comp_lfunNr f g : (f \o (- g) = - (f \o g))%VF. Proof. by apply/lfunP=> u; do !rewrite lfunE /=; rewrite linearN. Qed. End CompLfun. Definition lfun_simp := (comp_lfunE, scale_lfunE, opp_lfunE, add_lfunE, sum_lfunE, lfunE). Section ScaleCompLfun. Variables (R : comRingType) (aT vT rT : vectType R). Implicit Types (f : 'Hom(vT, rT)) (g : 'Hom(aT, vT)). Lemma comp_lfunZl k f g : (k *: (f \o g) = (k *: f) \o g)%VF. Proof. by apply/lfunP=> u; do !rewrite lfunE /=. Qed. Lemma comp_lfunZr k f g : (k *: (f \o g) = f \o (k *: g))%VF. Proof. by apply/lfunP=> u; do !rewrite lfunE /=; rewrite linearZ. Qed. End ScaleCompLfun. Section LinearImage. Variables (K : fieldType) (aT rT : vectType K). Implicit Types (f g : 'Hom(aT, rT)) (U V : {vspace aT}) (W : {vspace rT}). Lemma limgS f U V : (U <= V)%VS -> (f @: U <= f @: V)%VS. Proof. by rewrite unlock /subsetv !genmxE; apply: submxMr. Qed. Lemma limg_line f v : (f @: <[v]> = <[f v]>)%VS. Proof. apply/eqP; rewrite 2!unlock eqEsubv /subsetv /= r2vK !genmxE. by rewrite !(eqmxMr _ (genmxE _)) submx_refl. Qed. Lemma limg0 f : (f @: 0 = 0)%VS. Proof. by rewrite limg_line linear0. Qed. Lemma memv_img f v U : v \in U -> f v \in (f @: U)%VS. Proof. by move=> Uv; rewrite memvE -limg_line limgS. Qed. Lemma memv_imgP f w U : reflect (exists2 u, u \in U & w = f u) (w \in f @: U)%VS. Proof. apply: (iffP idP) => [|[u Uu ->]]; last exact: memv_img. rewrite 2!unlock memvE /subsetv !genmxE => /submxP[ku Drw]. exists (r2v (ku *m vs2mx U)); last by rewrite /= r2vK -mulmxA -Drw v2rK. by rewrite memvE /subsetv !genmxE r2vK submxMl. Qed. Lemma lim0g U : (0 @: U = 0 :> {vspace rT})%VS. Proof. apply/eqP; rewrite -subv0; apply/subvP=> _ /memv_imgP[u _ ->]. by rewrite lfunE rpred0. Qed. Lemma eq_in_limg V f g : {in V, f =1 g} -> (f @: V = g @: V)%VS. Proof. move=> eq_fg; apply/vspaceP=> y. by apply/memv_imgP/memv_imgP=> [][x Vx ->]; exists x; rewrite ?eq_fg. Qed. Lemma limg_add f : {morph lfun_img f : U V / U + V}%VS. Proof. move=> U V; apply/eqP; rewrite unlock eqEsubv /subsetv /= -genmx_adds. by rewrite !genmxE !(eqmxMr _ (genmxE _)) !addsmxMr submx_refl. Qed. Lemma limg_sum f I r (P : pred I) Us : (f @: (\sum_(i <- r | P i) Us i) = \sum_(i <- r | P i) f @: Us i)%VS. Proof. exact: (big_morph _ (limg_add f) (limg0 f)). Qed. Lemma limg_cap f U V : (f @: (U :&: V) <= f @: U :&: f @: V)%VS. Proof. by rewrite subv_cap !limgS ?capvSl ?capvSr. Qed. Lemma limg_bigcap f I r (P : pred I) Us : (f @: (\bigcap_(i <- r | P i) Us i) <= \bigcap_(i <- r | P i) f @: Us i)%VS. Proof. elim/big_rec2: _ => [|i V U _ sUV]; first exact: subvf. by rewrite (subv_trans (limg_cap f _ U)) ?capvS. Qed. Lemma limg_span f X : (f @: <> = <>)%VS. Proof. by rewrite !span_def big_map limg_sum; apply: eq_bigr => x _; rewrite limg_line. Qed. Lemma lfunPn f g : reflect (exists u, f u != g u) (f != g). Proof. apply: (iffP idP) => [f'g|[x]]; last by apply: contraNneq => /lfunP->. suffices /subvPn[_ /memv_imgP[u _ ->]]: ~~ (limg (f - g) <= 0)%VS. by rewrite lfunE /= lfunE /= memv0 subr_eq0; exists u. apply: contra f'g => /subvP fg0; apply/eqP/lfunP=> u; apply/eqP. by rewrite -subr_eq0 -opp_lfunE -add_lfunE -memv0 fg0 ?memv_img ?memvf. Qed. Lemma inv_lfun_def f : (f \o f^-1 \o f)%VF = f. Proof. apply/lfunP=> u; do !rewrite lfunE /=; rewrite unlock /= !r2vK. by rewrite mulmxKpV ?submxMl. Qed. Lemma limg_lfunVK f : {in limg f, cancel f^-1%VF f}. Proof. by move=> _ /memv_imgP[u _ ->]; rewrite -!comp_lfunE inv_lfun_def. Qed. Lemma lkerE f U : (U <= lker f)%VS = (f @: U == 0)%VS. Proof. rewrite unlock -dimv_eq0 /dimv /subsetv !genmxE mxrank_eq0. by rewrite (sameP sub_kermxP eqP). Qed. Lemma memv_ker f v : (v \in lker f) = (f v == 0). Proof. by rewrite -memv0 !memvE subv0 lkerE limg_line. Qed. Lemma eqlfunP f g v : reflect (f v = g v) (v \in lker (f - g)). Proof. by rewrite memv_ker !lfun_simp subr_eq0; apply: eqP. Qed. Lemma eqlfun_inP V f g : reflect {in V, f =1 g} (V <= lker (f - g))%VS. Proof. by apply: (iffP subvP) => E x /E/eqlfunP. Qed. Lemma limg_ker_compl f U : (f @: (U :\: lker f) = f @: U)%VS. Proof. rewrite -{2}(addv_diff_cap U (lker f)) limg_add; apply/esym/addv_idPl. by rewrite (subv_trans _ (sub0v _)) // subv0 -lkerE capvSr. Qed. Lemma limg_ker_dim f U : (\dim (U :&: lker f) + \dim (f @: U) = \dim U)%N. Proof. rewrite unlock /dimv /= genmx_cap genmx_id -genmx_cap !genmxE. by rewrite addnC mxrank_mul_ker. Qed. Lemma limg_dim_eq f U : (U :&: lker f = 0)%VS -> \dim (f @: U) = \dim U. Proof. by rewrite -(limg_ker_dim f U) => ->; rewrite dimv0. Qed. Lemma limg_basis_of f U X : (U :&: lker f = 0)%VS -> basis_of U X -> basis_of (f @: U) (map f X). Proof. move=> injUf /andP[/eqP defU /eqnP freeX]. by rewrite /basis_of /free size_map -limg_span -freeX defU limg_dim_eq ?eqxx. Qed. Lemma lker0P f : reflect (injective f) (lker f == 0%VS). Proof. rewrite -subv0; apply: (iffP subvP) => [injf u v eq_fuv | injf u]. apply/eqP; rewrite -subr_eq0 -memv0 injf //. by rewrite memv_ker linearB /= eq_fuv subrr. by rewrite memv_ker memv0 -(inj_eq injf) linear0. Qed. Lemma limg_ker0 f U V : lker f == 0%VS -> (f @: U <= f @: V)%VS = (U <= V)%VS. Proof. move/lker0P=> injf; apply/idP/idP=> [/subvP sfUV | ]; last exact: limgS. by apply/subvP=> u Uu; have /memv_imgP[v Vv /injf->] := sfUV _ (memv_img f Uu). Qed. Lemma eq_limg_ker0 f U V : lker f == 0%VS -> (f @: U == f @: V)%VS = (U == V). Proof. by move=> injf; rewrite !eqEsubv !limg_ker0. Qed. Lemma lker0_lfunK f : lker f == 0%VS -> cancel f f^-1%VF. Proof. by move/lker0P=> injf u; apply: injf; rewrite limg_lfunVK ?memv_img ?memvf. Qed. Lemma lker0_compVf f : lker f == 0%VS -> (f^-1 \o f = \1)%VF. Proof. by move/lker0_lfunK=> fK; apply/lfunP=> u; rewrite !lfunE /= fK. Qed. End LinearImage. Implicit Arguments memv_imgP [K aT rT f U w]. Implicit Arguments lfunPn [K aT rT f g]. Implicit Arguments lker0P [K aT rT f]. Implicit Arguments eqlfunP [K aT rT f g v]. Implicit Arguments eqlfun_inP [K aT rT f g V]. Section FixedSpace. Variables (K : fieldType) (vT : vectType K). Implicit Types (f : 'End(vT)) (U : {vspace vT}). Definition fixedSpace f : {vspace vT} := lker (f - \1%VF). Lemma fixedSpaceP f a : reflect (f a = a) (a \in fixedSpace f). Proof. by rewrite memv_ker add_lfunE opp_lfunE id_lfunE subr_eq0; apply: eqP. Qed. Lemma fixedSpacesP f U : reflect {in U, f =1 id} (U <= fixedSpace f)%VS. Proof. by apply: (iffP subvP) => cUf x /cUf/fixedSpaceP. Qed. Lemma fixedSpace_limg f U : (U <= fixedSpace f -> f @: U = U)%VS. Proof. move/fixedSpacesP=> cUf; apply/vspaceP=> x. by apply/memv_imgP/idP=> [[{x} x Ux ->] | Ux]; last exists x; rewrite ?cUf. Qed. Lemma fixedSpace_id : fixedSpace \1 = {:vT}%VS. Proof. by apply/vspaceP=> x; rewrite memvf; apply/fixedSpaceP; rewrite lfunE. Qed. End FixedSpace. Implicit Arguments fixedSpaceP [K vT f a]. Implicit Arguments fixedSpacesP [K vT f U]. Section LinAut. Variables (K : fieldType) (vT : vectType K) (f : 'End(vT)). Hypothesis kerf0 : lker f == 0%VS. Lemma lker0_limgf : limg f = fullv. Proof. by apply/eqP; rewrite eqEdim subvf limg_dim_eq //= (eqP kerf0) capv0. Qed. Lemma lker0_lfunVK : cancel f^-1%VF f. Proof. by move=> u; rewrite limg_lfunVK // lker0_limgf memvf. Qed. Lemma lker0_compfV : (f \o f^-1 = \1)%VF. Proof. by apply/lfunP=> u; rewrite !lfunE /= lker0_lfunVK. Qed. Lemma lker0_compVKf aT g : (f \o (f^-1 \o g))%VF = g :> 'Hom(aT, vT). Proof. by rewrite comp_lfunA lker0_compfV comp_lfun1l. Qed. Lemma lker0_compKf aT g : (f^-1 \o (f \o g))%VF = g :> 'Hom(aT, vT). Proof. by rewrite comp_lfunA lker0_compVf ?comp_lfun1l. Qed. Lemma lker0_compfK rT h : ((h \o f) \o f^-1)%VF = h :> 'Hom(vT, rT). Proof. by rewrite -comp_lfunA lker0_compfV comp_lfun1r. Qed. Lemma lker0_compfVK rT h : ((h \o f^-1) \o f)%VF = h :> 'Hom(vT, rT). Proof. by rewrite -comp_lfunA lker0_compVf ?comp_lfun1r. Qed. End LinAut. Section LinearImageComp. Variables (K : fieldType) (aT vT rT : vectType K). Implicit Types (f : 'Hom(aT, vT)) (g : 'Hom(vT, rT)) (U : {vspace aT}). Lemma lim1g U : (\1 @: U)%VS = U. Proof. have /andP[/eqP <- _] := vbasisP U; rewrite limg_span map_id_in // => u _. by rewrite lfunE. Qed. Lemma limg_comp f g U : ((g \o f) @: U = g @: (f @: U))%VS. Proof. have /andP[/eqP <- _] := vbasisP U; rewrite !limg_span; congr (span _). by rewrite -map_comp; apply/eq_map => u; rewrite lfunE. Qed. End LinearImageComp. Section LinearPreimage. Variables (K : fieldType) (aT rT : vectType K). Implicit Types (f : 'Hom(aT, rT)) (U : {vspace aT}) (V W : {vspace rT}). Lemma lpreim_cap_limg f W : (f @^-1: (W :&: limg f))%VS = (f @^-1: W)%VS. Proof. by rewrite /lfun_preim -capvA capvv. Qed. Lemma lpreim0 f : (f @^-1: 0)%VS = lker f. Proof. by rewrite /lfun_preim cap0v limg0 add0v. Qed. Lemma lpreimS f V W : (V <= W)%VS-> (f @^-1: V <= f @^-1: W)%VS. Proof. by move=> sVW; rewrite addvS // limgS // capvS. Qed. Lemma lpreimK f W : (W <= limg f)%VS -> (f @: (f @^-1: W))%VS = W. Proof. move=> sWf; rewrite limg_add (capv_idPl sWf) // -limg_comp. have /eqP->: (f @: lker f == 0)%VS by rewrite -lkerE. have /andP[/eqP defW _] := vbasisP W; rewrite addv0 -defW limg_span. rewrite map_id_in // => x Xx; rewrite lfunE /= limg_lfunVK //. by apply: span_subvP Xx; rewrite defW. Qed. Lemma memv_preim f u W : (f u \in W) = (u \in f @^-1: W)%VS. Proof. apply/idP/idP=> [Wfu | /(memv_img f)]; last first. by rewrite -lpreim_cap_limg lpreimK ?capvSr // => /memv_capP[]. rewrite -[u](addNKr (f^-1%VF (f u))) memv_add ?memv_img //. by rewrite memv_cap Wfu memv_img ?memvf. by rewrite memv_ker addrC linearB /= subr_eq0 limg_lfunVK ?memv_img ?memvf. Qed. End LinearPreimage. Section LfunAlgebra. (* This section is a bit of a place holder: the instances we build here can't *) (* be canonical because we are missing an interface for proper vectTypes, *) (* would sit between Vector and Falgebra. For now, we just supply structure *) (* definitions here and supply actual instances for F-algebras in a submodule *) (* of the algebra library (there is currently no actual use of the End(vT) *) (* algebra structure). Also note that the unit ring structure is missing. *) Variables (R : comRingType) (vT : vectType R). Hypothesis vT_proper : Vector.dim vT > 0. Fact lfun1_neq0 : \1%VF != 0 :> 'End(vT). Proof. apply/eqP=> /lfunP/(_ (r2v (const_mx 1))); rewrite !lfunE /= => /(canRL r2vK). by move=> /rowP/(_ (Ordinal vT_proper))/eqP; rewrite linear0 !mxE oner_eq0. Qed. Prenex Implicits comp_lfunA comp_lfun1l comp_lfun1r comp_lfunDl comp_lfunDr. Definition lfun_comp_ringMixin := RingMixin comp_lfunA comp_lfun1l comp_lfun1r comp_lfunDl comp_lfunDr lfun1_neq0. Definition lfun_comp_ringType := RingType 'End(vT) lfun_comp_ringMixin. (* In the standard endomorphism ring product is categorical composition. *) Definition lfun_ringMixin : GRing.Ring.mixin_of (lfun_zmodType vT vT) := GRing.converse_ringMixin lfun_comp_ringType. Definition lfun_ringType := Eval hnf in RingType 'End(vT) lfun_ringMixin. Definition lfun_lalgType := Eval hnf in [lalgType R of 'End(vT) for LalgType R lfun_ringType (fun k x y => comp_lfunZr k y x)]. Definition lfun_algType := Eval hnf in [algType R of 'End(vT) for AlgType R _ (fun k (x y : lfun_lalgType) => comp_lfunZl k y x)]. End LfunAlgebra. Section Projection. Variables (K : fieldType) (vT : vectType K). Implicit Types U V : {vspace vT}. Definition daddv_pi U V := Vector.Hom (proj_mx (vs2mx U) (vs2mx V)). Definition projv U := daddv_pi U U^C. Definition addv_pi1 U V := daddv_pi (U :\: V) V. Definition addv_pi2 U V := daddv_pi V (U :\: V). Lemma memv_pi U V w : (daddv_pi U V) w \in U. Proof. by rewrite unlock memvE /subsetv genmxE /= r2vK proj_mx_sub. Qed. Lemma memv_proj U w : projv U w \in U. Proof. exact: memv_pi. Qed. Lemma memv_pi1 U V w : (addv_pi1 U V) w \in U. Proof. by rewrite (subvP (diffvSl U V)) ?memv_pi. Qed. Lemma memv_pi2 U V w : (addv_pi2 U V) w \in V. Proof. exact: memv_pi. Qed. Lemma daddv_pi_id U V u : (U :&: V = 0)%VS -> u \in U -> daddv_pi U V u = u. Proof. move/eqP; rewrite -dimv_eq0 memvE /subsetv /dimv !genmxE mxrank_eq0 => /eqP. by move=> dxUV Uu; rewrite unlock /= proj_mx_id ?v2rK. Qed. Lemma daddv_pi_proj U V w (pi := daddv_pi U V) : (U :&: V = 0)%VS -> pi (pi w) = pi w. Proof. by move/daddv_pi_id=> -> //; apply: memv_pi. Qed. Lemma daddv_pi_add U V w : (U :&: V = 0)%VS -> (w \in U + V)%VS -> daddv_pi U V w + daddv_pi V U w = w. Proof. move/eqP; rewrite -dimv_eq0 memvE /subsetv /dimv !genmxE mxrank_eq0 => /eqP. by move=> dxUW UVw; rewrite unlock /= -linearD /= add_proj_mx ?v2rK. Qed. Lemma projv_id U u : u \in U -> projv U u = u. Proof. exact: daddv_pi_id (capv_compl _). Qed. Lemma projv_proj U w : projv U (projv U w) = projv U w. Proof. exact: daddv_pi_proj (capv_compl _). Qed. Lemma memv_projC U w : w - projv U w \in (U^C)%VS. Proof. rewrite -{1}[w](daddv_pi_add (capv_compl U)) ?addv_complf ?memvf //. by rewrite addrC addKr memv_pi. Qed. Lemma limg_proj U : limg (projv U) = U. Proof. apply/vspaceP=> u; apply/memv_imgP/idP=> [[u1 _ ->] | ]; first exact: memv_proj. by exists (projv U u); rewrite ?projv_id ?memv_img ?memvf. Qed. Lemma lker_proj U : lker (projv U) = (U^C)%VS. Proof. apply/eqP; rewrite eqEdim andbC; apply/andP; split. by rewrite dimv_compl -(limg_ker_dim (projv U) fullv) limg_proj addnK capfv. by apply/subvP=> v; rewrite memv_ker -{2}[v]subr0 => /eqP <-; apply: memv_projC. Qed. Lemma addv_pi1_proj U V w (pi1 := addv_pi1 U V) : pi1 (pi1 w) = pi1 w. Proof. by rewrite daddv_pi_proj // capv_diff. Qed. Lemma addv_pi2_id U V v : v \in V -> addv_pi2 U V v = v. Proof. by apply: daddv_pi_id; rewrite capvC capv_diff. Qed. Lemma addv_pi2_proj U V w (pi2 := addv_pi2 U V) : pi2 (pi2 w) = pi2 w. Proof. by rewrite addv_pi2_id ?memv_pi2. Qed. Lemma addv_pi1_pi2 U V w : w \in (U + V)%VS -> addv_pi1 U V w + addv_pi2 U V w = w. Proof. by rewrite -addv_diff; apply: daddv_pi_add; apply: capv_diff. Qed. Section Sumv_Pi. Variables (I : eqType) (r0 : seq I) (P : pred I) (Vs : I -> {vspace vT}). Let sumv_pi_rec i := fix loop r := if r is j :: r1 then let V1 := (\sum_(k <- r1) Vs k)%VS in if j == i then addv_pi1 (Vs j) V1 else (loop r1 \o addv_pi2 (Vs j) V1)%VF else 0. Notation sumV := (\sum_(i <- r0 | P i) Vs i)%VS. Definition sumv_pi_for V of V = sumV := fun i => sumv_pi_rec i (filter P r0). Variables (V : {vspace vT}) (defV : V = sumV). Lemma memv_sum_pi i v : sumv_pi_for defV i v \in Vs i. Proof. rewrite /sumv_pi_for. elim: (filter P r0) v => [|j r IHr] v /=; first by rewrite lfunE mem0v. by case: eqP => [->|_]; rewrite ?lfunE ?memv_pi1 /=. Qed. Lemma sumv_pi_uniq_sum v : uniq (filter P r0) -> v \in V -> \sum_(i <- r0 | P i) sumv_pi_for defV i v = v. Proof. rewrite /sumv_pi_for defV -!(big_filter r0 P). elim: (filter P r0) v => [|i r IHr] v /= => [_ | /andP[r'i /IHr{IHr}IHr]]. by rewrite !big_nil memv0 => /eqP. rewrite !big_cons eqxx => /addv_pi1_pi2; congr (_ + _ = v). rewrite -[_ v]IHr ?memv_pi2 //; apply: eq_big_seq => j /=. by case: eqP => [<- /idPn | _]; rewrite ?lfunE. Qed. End Sumv_Pi. End Projection. Prenex Implicits daddv_pi projv addv_pi1 addv_pi2. Notation sumv_pi V := (sumv_pi_for (erefl V)). Section SumvPi. Variable (K : fieldType) (vT : vectType K). Lemma sumv_pi_sum (I : finType) (P : pred I) Vs v (V : {vspace vT}) (defV : V = (\sum_(i | P i) Vs i)%VS) : v \in V -> \sum_(i | P i) sumv_pi_for defV i v = v :> vT. Proof. by apply: sumv_pi_uniq_sum; apply: enum_uniq. Qed. Lemma sumv_pi_nat_sum m n (P : pred nat) Vs v (V : {vspace vT}) (defV : V = (\sum_(m <= i < n | P i) Vs i)%VS) : v \in V -> \sum_(m <= i < n | P i) sumv_pi_for defV i v = v :> vT. Proof. by apply: sumv_pi_uniq_sum; apply/filter_uniq/iota_uniq. Qed. End SumvPi. Section SubVector. (* Turn a {vspace V} into a vectType *) Variable (K : fieldType) (vT : vectType K) (U : {vspace vT}). Inductive subvs_of : predArgType := Subvs u & u \in U. Definition vsval w := let: Subvs u _ := w in u. Canonical subvs_subType := Eval hnf in [subType for vsval]. Definition subvs_eqMixin := Eval hnf in [eqMixin of subvs_of by <:]. Canonical subvs_eqType := Eval hnf in EqType subvs_of subvs_eqMixin. Definition subvs_choiceMixin := [choiceMixin of subvs_of by <:]. Canonical subvs_choiceType := ChoiceType subvs_of subvs_choiceMixin. Definition subvs_zmodMixin := [zmodMixin of subvs_of by <:]. Canonical subvs_zmodType := ZmodType subvs_of subvs_zmodMixin. Definition subvs_lmodMixin := [lmodMixin of subvs_of by <:]. Canonical subvs_lmodType := LmodType K subvs_of subvs_lmodMixin. Lemma subvsP w : vsval w \in U. Proof. exact: valP. Qed. Lemma subvs_inj : injective vsval. Proof. exact: val_inj. Qed. Lemma congr_subvs u v : u = v -> vsval u = vsval v. Proof. exact: congr1. Qed. Lemma vsval_is_linear : linear vsval. Proof. by []. Qed. Canonical vsval_additive := Additive vsval_is_linear. Canonical vsval_linear := AddLinear vsval_is_linear. Fact vsproj_key : unit. Proof. by []. Qed. Definition vsproj_def u := Subvs (memv_proj U u). Definition vsproj := locked_with vsproj_key vsproj_def. Canonical vsproj_unlockable := [unlockable fun vsproj]. Lemma vsprojK : {in U, cancel vsproj vsval}. Proof. by rewrite unlock; apply: projv_id. Qed. Lemma vsvalK : cancel vsval vsproj. Proof. by move=> w; exact/val_inj/vsprojK/subvsP. Qed. Lemma vsproj_is_linear : linear vsproj. Proof. by move=> k w1 w2; apply: val_inj; rewrite unlock /= linearP. Qed. Canonical vsproj_additive := Additive vsproj_is_linear. Canonical vsproj_linear := AddLinear vsproj_is_linear. Fact subvs_vect_iso : Vector.axiom (\dim U) subvs_of. Proof. exists (fun w => \row_i coord (vbasis U) i (vsval w)). by move=> k w1 w2; apply/rowP=> i; rewrite !mxE linearP. exists (fun rw : 'rV_(\dim U) => vsproj (\sum_i rw 0 i *: (vbasis U)`_i)). move=> w /=; congr (vsproj _ = w): (vsvalK w). by rewrite {1}(coord_vbasis (subvsP w)); apply: eq_bigr => i _; rewrite mxE. move=> rw; apply/rowP=> i; rewrite mxE vsprojK. by rewrite coord_sum_free ?(basis_free (vbasisP U)). by apply: rpred_sum => j _; rewrite rpredZ ?vbasis_mem ?memt_nth. Qed. Definition subvs_vectMixin := VectMixin subvs_vect_iso. Canonical subvs_vectType := VectType K subvs_of subvs_vectMixin. End SubVector. Prenex Implicits vsval vsproj vsvalK. Implicit Arguments subvs_inj [[K] [vT] [U] x1 x2]. Implicit Arguments vsprojK [[K] [vT] [U] x]. Section MatrixVectType. Variables (R : ringType) (m n : nat). (* The apparently useless => /= in line 1 of the proof performs some evar *) (* expansions that the Ltac interpretation of exists is incapable of doing. *) Fact matrix_vect_iso : Vector.axiom (m * n) 'M[R]_(m, n). Proof. exists mxvec => /=; first exact: linearP. by exists vec_mx; [apply: mxvecK | apply: vec_mxK]. Qed. Definition matrix_vectMixin := VectMixin matrix_vect_iso. Canonical matrix_vectType := VectType R 'M[R]_(m, n) matrix_vectMixin. End MatrixVectType. (* A ring is a one-dimension vector space *) Section RegularVectType. Variable R : ringType. Fact regular_vect_iso : Vector.axiom 1 R^o. Proof. exists (fun a => a%:M) => [a b c|]; first by rewrite rmorphD scale_scalar_mx. by exists (fun A : 'M_1 => A 0 0) => [a | A]; rewrite ?mxE // -mx11_scalar. Qed. Definition regular_vectMixin := VectMixin regular_vect_iso. Canonical regular_vectType := VectType R R^o regular_vectMixin. End RegularVectType. (* External direct product of two vectTypes. *) Section ProdVector. Variables (R : ringType) (vT1 vT2 : vectType R). Fact pair_vect_iso : Vector.axiom (Vector.dim vT1 + Vector.dim vT2) (vT1 * vT2). Proof. pose p2r (u : vT1 * vT2) := row_mx (v2r u.1) (v2r u.2). pose r2p w := (r2v (lsubmx w) : vT1, r2v (rsubmx w) : vT2). have r2pK : cancel r2p p2r by move=> w; rewrite /p2r !r2vK hsubmxK. have p2rK : cancel p2r r2p by case=> u v; rewrite /r2p row_mxKl row_mxKr !v2rK. have r2p_lin: linear r2p by move=> a u v; congr (_ , _); rewrite /= !linearP. by exists p2r; [apply: (@can2_linear _ _ _ (Linear r2p_lin)) | exists r2p]. Qed. Definition pair_vectMixin := VectMixin pair_vect_iso. Canonical pair_vectType := VectType R (vT1 * vT2) pair_vectMixin. End ProdVector. (* Function from a finType into a ring form a vectype. *) Section FunVectType. Variable (I : finType) (R : ringType) (vT : vectType R). (* Type unification with exist is again a problem in this proof. *) Fact ffun_vect_iso : Vector.axiom (#|I| * Vector.dim vT) {ffun I -> vT}. Proof. pose fr (f : {ffun I -> vT}) := mxvec (\matrix_(i < #|I|) v2r (f (enum_val i))). exists fr => /= [k f g|]. rewrite /fr -linearP; congr (mxvec _); apply/matrixP=> i j. by rewrite !mxE /= !ffunE linearP !mxE. exists (fun r => [ffun i => r2v (row (enum_rank i) (vec_mx r)) : vT]) => [g|r]. by apply/ffunP=> i; rewrite ffunE mxvecK rowK v2rK enum_rankK. by apply/(canLR vec_mxK)/matrixP=> i j; rewrite mxE ffunE r2vK enum_valK mxE. Qed. Definition ffun_vectMixin := VectMixin ffun_vect_iso. Canonical ffun_vectType := VectType R {ffun I -> vT} ffun_vectMixin. End FunVectType. Canonical exp_vectType (K : fieldType) (vT : vectType K) n := [vectType K of vT ^ n]. (* Solving a tuple of linear equations. *) Section Solver. Variable (K : fieldType) (vT : vectType K). Variables (n : nat) (lhs : n.-tuple 'End(vT)) (rhs : n.-tuple vT). Let lhsf u := finfun ((tnth lhs)^~ u). Definition vsolve_eq U := finfun (tnth rhs) \in (linfun lhsf @: U)%VS. Lemma vsolve_eqP (U : {vspace vT}) : reflect (exists2 u, u \in U & forall i, tnth lhs i u = tnth rhs i) (vsolve_eq U). Proof. have lhsZ: linear lhsf by move=> a u v; apply/ffunP=> i; rewrite !ffunE linearP. apply: (iffP memv_imgP) => [] [u Uu sol_u]; exists u => //. by move=> i; rewrite -[tnth rhs i]ffunE sol_u (lfunE (Linear lhsZ)) ffunE. by apply/ffunP=> i; rewrite (lfunE (Linear lhsZ)) !ffunE sol_u. Qed. End Solver. mathcomp-1.5/theories/mxpoly.v0000644000175000017500000013411512307636117015527 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq div fintype tuple. Require Import finfun bigop fingroup perm ssralg zmodp matrix mxalgebra. Require Import poly polydiv. (******************************************************************************) (* This file provides basic support for formal computation with matrices, *) (* mainly results combining matrices and univariate polynomials, such as the *) (* Cayley-Hamilton theorem; it also contains an extension of the first order *) (* representation of algebra introduced in ssralg (GRing.term/formula). *) (* rVpoly v == the little-endian decoding of the row vector v as a *) (* polynomial p = \sum_i (v 0 i)%:P * 'X^i. *) (* poly_rV p == the partial inverse to rVpoly, for polynomials of degree *) (* less than d to 'rV_d (d is inferred from the context). *) (* Sylvester_mx p q == the Sylvester matrix of p and q. *) (* resultant p q == the resultant of p and q, i.e., \det (Sylvester_mx p q). *) (* horner_mx A == the morphism from {poly R} to 'M_n (n of the form n'.+1) *) (* mapping a (scalar) polynomial p to the value of its *) (* scalar matrix interpretation at A (this is an instance of *) (* the generic horner_morph construct defined in poly). *) (* powers_mx A d == the d x (n ^ 2) matrix whose rows are the mxvec encodings *) (* of the first d powers of A (n of the form n'.+1). Thus, *) (* vec_mx (v *m powers_mx A d) = horner_mx A (rVpoly v). *) (* char_poly A == the characteristic polynomial of A. *) (* char_poly_mx A == a matrix whose detereminant is char_poly A. *) (* mxminpoly A == the minimal polynomial of A, i.e., the smallest monic *) (* polynomial that annihilates A (A must be nontrivial). *) (* degree_mxminpoly A == the (positive) degree of mxminpoly A. *) (* mx_inv_horner A == the inverse of horner_mx A for polynomials of degree *) (* smaller than degree_mxminpoly A. *) (* integralOver RtoK u <-> u is in the integral closure of the image of R *) (* under RtoK : R -> K, i.e. u is a root of the image of a *) (* monic polynomial in R. *) (* algebraicOver FtoE u <-> u : E is algebraic over E; it is a root of the *) (* image of a nonzero polynomial under FtoE; as F must be a *) (* fieldType, this is equivalent to integralOver FtoE u. *) (* integralRange RtoK <-> the integral closure of the image of R contains *) (* all of K (:= forall u, integralOver RtoK u). *) (* This toolkit for building formal matrix expressions is packaged in the *) (* MatrixFormula submodule, and comprises the following: *) (* eval_mx e == GRing.eval lifted to matrices (:= map_mx (GRing.eval e)). *) (* mx_term A == GRing.Const lifted to matrices. *) (* mulmx_term A B == the formal product of two matrices of terms. *) (* mxrank_form m A == a GRing.formula asserting that the interpretation of *) (* the term matrix A has rank m. *) (* submx_form A B == a GRing.formula asserting that the row space of the *) (* interpretation of the term matrix A is included in the *) (* row space of the interpretation of B. *) (* seq_of_rV v == the seq corresponding to a row vector. *) (* row_env e == the flattening of a tensored environment e : seq 'rV_d. *) (* row_var F d k == the term vector of width d such that for e : seq 'rV[F]_d *) (* we have eval e 'X_k = eval_mx (row_env e) (row_var d k). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GRing.Theory. Import Monoid.Theory. Open Local Scope ring_scope. Import Pdiv.Idomain. (* Row vector <-> bounded degree polynomial bijection *) Section RowPoly. Variables (R : ringType) (d : nat). Implicit Types u v : 'rV[R]_d. Implicit Types p q : {poly R}. Definition rVpoly v := \poly_(k < d) (if insub k is Some i then v 0 i else 0). Definition poly_rV p := \row_(i < d) p`_i. Lemma coef_rVpoly v k : (rVpoly v)`_k = if insub k is Some i then v 0 i else 0. Proof. by rewrite coef_poly; case: insubP => [i ->|]; rewrite ?if_same. Qed. Lemma coef_rVpoly_ord v (i : 'I_d) : (rVpoly v)`_i = v 0 i. Proof. by rewrite coef_rVpoly valK. Qed. Lemma rVpoly_delta i : rVpoly (delta_mx 0 i) = 'X^i. Proof. apply/polyP=> j; rewrite coef_rVpoly coefXn. case: insubP => [k _ <- | j_ge_d]; first by rewrite mxE. by case: eqP j_ge_d => // ->; rewrite ltn_ord. Qed. Lemma rVpolyK : cancel rVpoly poly_rV. Proof. by move=> u; apply/rowP=> i; rewrite mxE coef_rVpoly_ord. Qed. Lemma poly_rV_K p : size p <= d -> rVpoly (poly_rV p) = p. Proof. move=> le_p_d; apply/polyP=> k; rewrite coef_rVpoly. case: insubP => [i _ <- | ]; first by rewrite mxE. by rewrite -ltnNge => le_d_l; rewrite nth_default ?(leq_trans le_p_d). Qed. Lemma poly_rV_is_linear : linear poly_rV. Proof. by move=> a p q; apply/rowP=> i; rewrite !mxE coefD coefZ. Qed. Canonical poly_rV_additive := Additive poly_rV_is_linear. Canonical poly_rV_linear := Linear poly_rV_is_linear. Lemma rVpoly_is_linear : linear rVpoly. Proof. move=> a u v; apply/polyP=> k; rewrite coefD coefZ !coef_rVpoly. by case: insubP => [i _ _ | _]; rewrite ?mxE // mulr0 addr0. Qed. Canonical rVpoly_additive := Additive rVpoly_is_linear. Canonical rVpoly_linear := Linear rVpoly_is_linear. End RowPoly. Implicit Arguments poly_rV [R d]. Prenex Implicits rVpoly poly_rV. Section Resultant. Variables (R : ringType) (p q : {poly R}). Let dS := ((size q).-1 + (size p).-1)%N. Local Notation band r := (lin1_mx (poly_rV \o r \o* rVpoly)). Definition Sylvester_mx : 'M[R]_dS := col_mx (band p) (band q). Lemma Sylvester_mxE (i j : 'I_dS) : let S_ r k := r`_(j - k) *+ (k <= j) in Sylvester_mx i j = match split i with inl k => S_ p k | inr k => S_ q k end. Proof. move=> S_; rewrite mxE; case: {i}(split i) => i; rewrite !mxE /=; by rewrite rVpoly_delta coefXnM ltnNge if_neg -mulrb. Qed. Definition resultant := \det Sylvester_mx. End Resultant. Lemma resultant_in_ideal (R : comRingType) (p q : {poly R}) : size p > 1 -> size q > 1 -> {uv : {poly R} * {poly R} | size uv.1 < size q /\ size uv.2 < size p & (resultant p q)%:P = uv.1 * p + uv.2 * q}. Proof. move=> p_nc q_nc; pose dp := (size p).-1; pose dq := (size q).-1. pose S := Sylvester_mx p q; pose dS := (dq + dp)%N. have dS_gt0: dS > 0 by rewrite /dS /dq -(subnKC q_nc). pose j0 := Ordinal dS_gt0. pose Ss0 := col_mx (p *: \col_(i < dq) 'X^i) (q *: \col_(i < dp) 'X^i). pose Ss := \matrix_(i, j) (if j == j0 then Ss0 i 0 else (S i j)%:P). pose u ds s := \sum_(i < ds) cofactor Ss (s i) j0 * 'X^i. exists (u _ (lshift dp), u _ ((rshift dq) _)). suffices sz_u ds s: ds > 1 -> size (u ds.-1 s) < ds by rewrite !sz_u. move/ltn_predK=> {2}<-; apply: leq_trans (size_sum _ _ _) _. apply/bigmax_leqP=> i _. have ->: cofactor Ss (s i) j0 = (cofactor S (s i) j0)%:P. rewrite rmorphM rmorph_sign -det_map_mx; congr (_ * \det _). by apply/matrixP=> i' j'; rewrite !mxE. apply: leq_trans (size_mul_leq _ _) (leq_trans _ (valP i)). by rewrite size_polyC size_polyXn addnS /= -add1n leq_add2r leq_b1. transitivity (\det Ss); last first. rewrite (expand_det_col Ss j0) big_split_ord !big_distrl /=. by congr (_ + _); apply: eq_bigr => i _; rewrite mxE eqxx (col_mxEu, col_mxEd) !mxE mulrC mulrA mulrAC. pose S_ j1 := map_mx polyC (\matrix_(i, j) S i (if j == j0 then j1 else j)). pose Ss0_ i dj := \poly_(j < dj) S i (insubd j0 j). pose Ss_ dj := \matrix_(i, j) (if j == j0 then Ss0_ i dj else (S i j)%:P). have{Ss u} ->: Ss = Ss_ dS. apply/matrixP=> i j; rewrite mxE [in X in _ = X]mxE; case: (j == j0) => {j}//. apply/polyP=> k; rewrite coef_poly Sylvester_mxE mxE. have [k_ge_dS | k_lt_dS] := leqP dS k. case: (split i) => {i}i; rewrite !mxE coefMXn; case: ifP => // /negbT; rewrite -ltnNge ltnS => hi. apply: (leq_sizeP _ _ (leqnn (size p))); rewrite -(ltn_predK p_nc). by rewrite ltn_subRL (leq_trans _ k_ge_dS) // ltn_add2r. - apply: (leq_sizeP _ _ (leqnn (size q))); rewrite -(ltn_predK q_nc). by rewrite ltn_subRL (leq_trans _ k_ge_dS) // addnC ltn_add2l. by rewrite insubdK //; case: (split i) => {i}i; rewrite !mxE coefMXn; case: leqP. elim: {-2}dS (leqnn dS) (dS_gt0) => // dj IHj dj_lt_dS _. pose j1 := Ordinal dj_lt_dS; pose rj0T (A : 'M[{poly R}]_dS) := row j0 A^T. have: rj0T (Ss_ dj.+1) = 'X^dj *: rj0T (S_ j1) + 1 *: rj0T (Ss_ dj). apply/rowP=> i; apply/polyP=> k; rewrite scale1r !(Sylvester_mxE, mxE) eqxx. rewrite coefD coefXnM coefC !coef_poly ltnS subn_eq0 ltn_neqAle andbC. case: (leqP k dj) => [k_le_dj | k_gt_dj] /=; last by rewrite addr0. rewrite Sylvester_mxE insubdK; last exact: leq_ltn_trans (dj_lt_dS). by case: eqP => [-> | _]; rewrite (addr0, add0r). rewrite -det_tr => /determinant_multilinear->; try by apply/matrixP=> i j; rewrite !mxE eq_sym (negPf (neq_lift _ _)). have [dj0 | dj_gt0] := posnP dj; rewrite ?dj0 !mul1r. rewrite !det_tr det_map_mx addrC (expand_det_col _ j0) big1 => [|i _]. rewrite add0r; congr (\det _)%:P. apply/matrixP=> i j; rewrite [in X in _ = X]mxE; case: eqP => // ->. by congr (S i _); apply: val_inj. by rewrite mxE /= [Ss0_ _ _]poly_def big_ord0 mul0r. have /determinant_alternate->: j1 != j0 by rewrite -val_eqE -lt0n. by rewrite mulr0 add0r det_tr IHj // ltnW. by move=> i; rewrite !mxE if_same. Qed. Lemma resultant_eq0 (R : idomainType) (p q : {poly R}) : (resultant p q == 0) = (size (gcdp p q) > 1). Proof. have dvdpp := dvdpp; set r := gcdp p q. pose dp := (size p).-1; pose dq := (size q).-1. have /andP[r_p r_q]: (r %| p) && (r %| q) by rewrite -dvdp_gcd. apply/det0P/idP=> [[uv nz_uv] | r_nonC]. have [p0 _ | p_nz] := eqVneq p 0. have: dq + dp > 0. rewrite lt0n; apply: contraNneq nz_uv => dqp0. by rewrite dqp0 in uv *; rewrite [uv]thinmx0. by rewrite /dp /dq /r p0 size_poly0 addn0 gcd0p -subn1 subn_gt0. do [rewrite -[uv]hsubmxK -{1}row_mx0 mul_row_col !mul_rV_lin1 /=] in nz_uv *. set u := rVpoly _; set v := rVpoly _; pose m := gcdp (v * p) (v * q). have lt_vp: size v < size p by rewrite (polySpred p_nz) ltnS size_poly. move/(congr1 rVpoly)/eqP; rewrite -linearD linear0 poly_rV_K; last first. rewrite (leq_trans (size_add _ _)) // geq_max. rewrite !(leq_trans (size_mul_leq _ _)) // -subn1 leq_subLR. by rewrite addnC addnA leq_add ?leqSpred ?size_poly. by rewrite addnCA leq_add ?leqSpred ?size_poly. rewrite addrC addr_eq0 => /eqP vq_up. have nz_v: v != 0. apply: contraNneq nz_uv => v0; apply/eqP. congr row_mx; apply: (can_inj (@rVpolyK _ _)); rewrite linear0 // -/u. by apply: contra_eq vq_up; rewrite v0 mul0r -addr_eq0 add0r => /mulf_neq0->. have r_nz: r != 0 := dvdpN0 r_p p_nz. have /dvdpP [[c w] /= nz_c wv]: v %| m by rewrite dvdp_gcd !dvdp_mulr. have m_wd d: m %| v * d -> w %| d. case/dvdpP=> [[k f]] /= nz_k /(congr1 ( *:%R c)). rewrite mulrC scalerA scalerAl scalerAr wv mulrA => /(mulIf nz_v)def_fw. by apply/dvdpP; exists (c * k, f); rewrite //= mulf_neq0. have w_r: w %| r by rewrite dvdp_gcd !m_wd ?dvdp_gcdl ?dvdp_gcdr. have w_nz: w != 0 := dvdpN0 w_r r_nz. have p_m: p %| m by rewrite dvdp_gcd vq_up -mulNr !dvdp_mull. rewrite (leq_trans _ (dvdp_leq r_nz w_r)) // -(ltn_add2l (size v)). rewrite addnC -ltn_subRL subn1 -size_mul // mulrC -wv size_scale //. rewrite (leq_trans lt_vp) // dvdp_leq // -size_poly_eq0. by rewrite -(size_scale _ nz_c) size_poly_eq0 wv mulf_neq0. have [[c p'] /= nz_c p'r] := dvdpP _ _ r_p. have [[k q'] /= nz_k q'r] := dvdpP _ _ r_q. have def_r := subnKC r_nonC; have r_nz: r != 0 by rewrite -size_poly_eq0 -def_r. have le_p'_dp: size p' <= dp. have [-> | nz_p'] := eqVneq p' 0; first by rewrite size_poly0. by rewrite /dp -(size_scale p nz_c) p'r size_mul // addnC -def_r leq_addl. have le_q'_dq: size q' <= dq. have [-> | nz_q'] := eqVneq q' 0; first by rewrite size_poly0. by rewrite /dq -(size_scale q nz_k) q'r size_mul // addnC -def_r leq_addl. exists (row_mx (- c *: poly_rV q') (k *: poly_rV p')). apply: contraNneq r_nz; rewrite -row_mx0; case/eq_row_mx=> q0 p0. have{p0} p0: p = 0. apply/eqP; rewrite -size_poly_eq0 -(size_scale p nz_c) p'r. rewrite -(size_scale _ nz_k) scalerAl -(poly_rV_K le_p'_dp) -linearZ p0. by rewrite linear0 mul0r size_poly0. rewrite /r p0 gcd0p -size_poly_eq0 -(size_scale q nz_k) q'r. rewrite -(size_scale _ nz_c) scalerAl -(poly_rV_K le_q'_dq) -linearZ. by rewrite -[c]opprK scaleNr q0 !linear0 mul0r size_poly0. rewrite mul_row_col scaleNr mulNmx !mul_rV_lin1 /= !linearZ /= !poly_rV_K //. by rewrite !scalerCA p'r q'r mulrCA addNr. Qed. Section HornerMx. Variables (R : comRingType) (n' : nat). Local Notation n := n'.+1. Variable A : 'M[R]_n. Implicit Types p q : {poly R}. Definition horner_mx := horner_morph (fun a => scalar_mx_comm a A). Canonical horner_mx_additive := [additive of horner_mx]. Canonical horner_mx_rmorphism := [rmorphism of horner_mx]. Lemma horner_mx_C a : horner_mx a%:P = a%:M. Proof. exact: horner_morphC. Qed. Lemma horner_mx_X : horner_mx 'X = A. Proof. exact: horner_morphX. Qed. Lemma horner_mxZ : scalable horner_mx. Proof. move=> a p /=; rewrite -mul_polyC rmorphM /=. by rewrite horner_mx_C [_ * _]mul_scalar_mx. Qed. Canonical horner_mx_linear := AddLinear horner_mxZ. Canonical horner_mx_lrmorphism := [lrmorphism of horner_mx]. Definition powers_mx d := \matrix_(i < d) mxvec (A ^+ i). Lemma horner_rVpoly m (u : 'rV_m) : horner_mx (rVpoly u) = vec_mx (u *m powers_mx m). Proof. rewrite mulmx_sum_row linear_sum [rVpoly u]poly_def rmorph_sum. apply: eq_bigr => i _. by rewrite valK !linearZ rmorphX /= horner_mx_X rowK /= mxvecK. Qed. End HornerMx. Section CharPoly. Variables (R : ringType) (n : nat) (A : 'M[R]_n). Implicit Types p q : {poly R}. Definition char_poly_mx := 'X%:M - map_mx (@polyC R) A. Definition char_poly := \det char_poly_mx. Let diagA := [seq A i i | i : 'I_n]. Let size_diagA : size diagA = n. Proof. by rewrite size_image card_ord. Qed. Let split_diagA : exists2 q, \prod_(x <- diagA) ('X - x%:P) + q = char_poly & size q <= n.-1. Proof. rewrite [char_poly](bigD1 1%g) //=; set q := \sum_(s | _) _; exists q. congr (_ + _); rewrite odd_perm1 mul1r big_map enumT; apply: eq_bigr => i _. by rewrite !mxE perm1 eqxx. apply: leq_trans {q}(size_sum _ _ _) _; apply/bigmax_leqP=> s nt_s. have{nt_s} [i nfix_i]: exists i, s i != i. apply/existsP; rewrite -negb_forall; apply: contra nt_s => s_1. by apply/eqP; apply/permP=> i; apply/eqP; rewrite perm1 (forallP s_1). apply: leq_trans (_ : #|[pred j | s j == j]|.+1 <= n.-1). rewrite -sum1_card (@big_mkcond nat) /= size_Msign. apply: (big_ind2 (fun p m => size p <= m.+1)) => [| p mp q mq IHp IHq | j _]. - by rewrite size_poly1. - apply: leq_trans (size_mul_leq _ _) _. by rewrite -subn1 -addnS leq_subLR addnA leq_add. rewrite !mxE eq_sym !inE; case: (s j == j); first by rewrite polyseqXsubC. by rewrite sub0r size_opp size_polyC leq_b1. rewrite -{8}[n]card_ord -(cardC (pred2 (s i) i)) card2 nfix_i !ltnS. apply: subset_leq_card; apply/subsetP=> j; move/(_ =P j)=> fix_j. rewrite !inE -{1}fix_j (inj_eq (@perm_inj _ s)) orbb. by apply: contraNneq nfix_i => <-; rewrite fix_j. Qed. Lemma size_char_poly : size char_poly = n.+1. Proof. have [q <- lt_q_n] := split_diagA; have le_q_n := leq_trans lt_q_n (leq_pred n). by rewrite size_addl size_prod_XsubC size_diagA. Qed. Lemma char_poly_monic : char_poly \is monic. Proof. rewrite monicE -(monicP (monic_prod_XsubC diagA xpredT id)). rewrite !lead_coefE size_char_poly. have [q <- lt_q_n] := split_diagA; have le_q_n := leq_trans lt_q_n (leq_pred n). by rewrite size_prod_XsubC size_diagA coefD (nth_default 0 le_q_n) addr0. Qed. Lemma char_poly_trace : n > 0 -> char_poly`_n.-1 = - \tr A. Proof. move=> n_gt0; have [q <- lt_q_n] := split_diagA; set p := \prod_(x <- _) _. rewrite coefD {q lt_q_n}(nth_default 0 lt_q_n) addr0. have{n_gt0} ->: p`_n.-1 = ('X * p)`_n by rewrite coefXM eqn0Ngt n_gt0. have ->: \tr A = \sum_(x <- diagA) x by rewrite big_map enumT. rewrite -size_diagA {}/p; elim: diagA => [|x d IHd]. by rewrite !big_nil mulr1 coefX oppr0. rewrite !big_cons coefXM mulrBl coefB IHd opprD addrC; congr (- _ + _). rewrite mul_polyC coefZ [size _]/= -(size_prod_XsubC _ id) -lead_coefE. by rewrite (monicP _) ?monic_prod_XsubC ?mulr1. Qed. Lemma char_poly_det : char_poly`_0 = (- 1) ^+ n * \det A. Proof. rewrite big_distrr coef_sum [0%N]lock /=; apply: eq_bigr => s _. rewrite -{1}rmorphN -rmorphX mul_polyC coefZ /=. rewrite mulrA -exprD addnC exprD -mulrA -lock; congr (_ * _). transitivity (\prod_(i < n) - A i (s i)); last by rewrite prodrN card_ord. elim: (index_enum _) => [|i e IHe]; rewrite !(big_nil, big_cons) ?coef1 //. by rewrite coefM big_ord1 IHe !mxE coefB coefC coefMn coefX mul0rn sub0r. Qed. End CharPoly. Lemma mx_poly_ring_isom (R : ringType) n' (n := n'.+1) : exists phi : {rmorphism 'M[{poly R}]_n -> {poly 'M[R]_n}}, [/\ bijective phi, forall p, phi p%:M = map_poly scalar_mx p, forall A, phi (map_mx polyC A) = A%:P & forall A i j k, (phi A)`_k i j = (A i j)`_k]. Proof. set M_RX := 'M[{poly R}]_n; set MR_X := ({poly 'M[R]_n}). pose Msize (A : M_RX) := \max_i \max_j size (A i j). pose phi (A : M_RX) := \poly_(k < Msize A) \matrix_(i, j) (A i j)`_k. have coef_phi A i j k: (phi A)`_k i j = (A i j)`_k. rewrite coef_poly; case: (ltnP k _) => le_m_k; rewrite mxE // nth_default //. apply: leq_trans (leq_trans (leq_bigmax i) le_m_k); exact: (leq_bigmax j). have phi_is_rmorphism : rmorphism phi. do 2?[split=> [A B|]]; apply/polyP=> k; apply/matrixP=> i j; last 1 first. - rewrite coef_phi mxE coefMn !coefC. by case: (k == _); rewrite ?mxE ?mul0rn. - by rewrite !(coef_phi, mxE, coefD, coefN). rewrite !coef_phi !mxE !coefM summxE coef_sum. pose F k1 k2 := (A i k1)`_k2 * (B k1 j)`_(k - k2). transitivity (\sum_k1 \sum_(k2 < k.+1) F k1 k2); rewrite {}/F. by apply: eq_bigr=> k1 _; rewrite coefM. rewrite exchange_big /=; apply: eq_bigr => k2 _. by rewrite mxE; apply: eq_bigr => k1 _; rewrite !coef_phi. have bij_phi: bijective phi. exists (fun P : MR_X => \matrix_(i, j) \poly_(k < size P) P`_k i j) => [A|P]. apply/matrixP=> i j; rewrite mxE; apply/polyP=> k. rewrite coef_poly -coef_phi. by case: leqP => // P_le_k; rewrite nth_default ?mxE. apply/polyP=> k; apply/matrixP=> i j; rewrite coef_phi mxE coef_poly. by case: leqP => // P_le_k; rewrite nth_default ?mxE. exists (RMorphism phi_is_rmorphism). split=> // [p | A]; apply/polyP=> k; apply/matrixP=> i j. by rewrite coef_phi coef_map !mxE coefMn. by rewrite coef_phi !mxE !coefC; case k; last rewrite /= mxE. Qed. Theorem Cayley_Hamilton (R : comRingType) n' (A : 'M[R]_n'.+1) : horner_mx A (char_poly A) = 0. Proof. have [phi [_ phiZ phiC _]] := mx_poly_ring_isom R n'. apply/rootP/factor_theorem; rewrite -phiZ -mul_adj_mx rmorphM. by move: (phi _) => q; exists q; rewrite rmorphB phiC phiZ map_polyX. Qed. Lemma eigenvalue_root_char (F : fieldType) n (A : 'M[F]_n) a : eigenvalue A a = root (char_poly A) a. Proof. transitivity (\det (a%:M - A) == 0). apply/eigenvalueP/det0P=> [[v Av_av v_nz] | [v v_nz Av_av]]; exists v => //. by rewrite mulmxBr Av_av mul_mx_scalar subrr. by apply/eqP; rewrite -mul_mx_scalar eq_sym -subr_eq0 -mulmxBr Av_av. congr (_ == 0); rewrite horner_sum; apply: eq_bigr => s _. rewrite hornerM horner_exp !hornerE; congr (_ * _). rewrite (big_morph _ (fun p q => hornerM p q a) (hornerC 1 a)). by apply: eq_bigr => i _; rewrite !mxE !(hornerE, hornerMn). Qed. Section MinPoly. Variables (F : fieldType) (n' : nat). Local Notation n := n'.+1. Variable A : 'M[F]_n. Implicit Types p q : {poly F}. Fact degree_mxminpoly_proof : exists d, \rank (powers_mx A d.+1) <= d. Proof. by exists (n ^ 2)%N; rewrite rank_leq_col. Qed. Definition degree_mxminpoly := ex_minn degree_mxminpoly_proof. Local Notation d := degree_mxminpoly. Local Notation Ad := (powers_mx A d). Lemma mxminpoly_nonconstant : d > 0. Proof. rewrite /d; case: ex_minnP; case=> //; rewrite leqn0 mxrank_eq0; move/eqP. move/row_matrixP; move/(_ 0); move/eqP; rewrite rowK row0 mxvec_eq0. by rewrite -mxrank_eq0 mxrank1. Qed. Lemma minpoly_mx1 : (1%:M \in Ad)%MS. Proof. by apply: (eq_row_sub (Ordinal mxminpoly_nonconstant)); rewrite rowK. Qed. Lemma minpoly_mx_free : row_free Ad. Proof. have:= mxminpoly_nonconstant; rewrite /d; case: ex_minnP; case=> // d' _. move/(_ d'); move/implyP; rewrite ltnn implybF -ltnS ltn_neqAle. by rewrite rank_leq_row andbT negbK. Qed. Lemma horner_mx_mem p : (horner_mx A p \in Ad)%MS. Proof. elim/poly_ind: p => [|p a IHp]; first by rewrite rmorph0 // linear0 sub0mx. rewrite rmorphD rmorphM /= horner_mx_C horner_mx_X. rewrite addrC -scalemx1 linearP /= -(mul_vec_lin (mulmxr_linear _ A)). case/submxP: IHp => u ->{p}. have: (powers_mx A (1 + d) <= Ad)%MS. rewrite -(geq_leqif (mxrank_leqif_sup _)). by rewrite (eqnP minpoly_mx_free) /d; case: ex_minnP. rewrite addnC; apply/row_subP=> i. by apply: eq_row_sub (lshift 1 i) _; rewrite !rowK. apply: submx_trans; rewrite addmx_sub ?scalemx_sub //. by apply: (eq_row_sub 0); rewrite rowK. rewrite -mulmxA mulmx_sub {u}//; apply/row_subP=> i. rewrite row_mul rowK mul_vec_lin /= mulmxE -exprSr. by apply: (eq_row_sub (rshift 1 i)); rewrite rowK. Qed. Definition mx_inv_horner B := rVpoly (mxvec B *m pinvmx Ad). Lemma mx_inv_horner0 : mx_inv_horner 0 = 0. Proof. by rewrite /mx_inv_horner !(linear0, mul0mx). Qed. Lemma mx_inv_hornerK B : (B \in Ad)%MS -> horner_mx A (mx_inv_horner B) = B. Proof. by move=> sBAd; rewrite horner_rVpoly mulmxKpV ?mxvecK. Qed. Lemma minpoly_mxM B C : (B \in Ad -> C \in Ad -> B * C \in Ad)%MS. Proof. move=> AdB AdC; rewrite -(mx_inv_hornerK AdB) -(mx_inv_hornerK AdC). by rewrite -rmorphM ?horner_mx_mem. Qed. Lemma minpoly_mx_ring : mxring Ad. Proof. apply/andP; split; first by apply/mulsmx_subP; exact: minpoly_mxM. apply/mxring_idP; exists 1%:M; split=> *; rewrite ?mulmx1 ?mul1mx //. by rewrite -mxrank_eq0 mxrank1. exact: minpoly_mx1. Qed. Definition mxminpoly := 'X^d - mx_inv_horner (A ^+ d). Local Notation p_A := mxminpoly. Lemma size_mxminpoly : size p_A = d.+1. Proof. by rewrite size_addl ?size_polyXn // size_opp ltnS size_poly. Qed. Lemma mxminpoly_monic : p_A \is monic. Proof. rewrite monicE /lead_coef size_mxminpoly coefB coefXn eqxx /=. by rewrite nth_default ?size_poly // subr0. Qed. Lemma size_mod_mxminpoly p : size (p %% p_A) <= d. Proof. by rewrite -ltnS -size_mxminpoly ltn_modp // -size_poly_eq0 size_mxminpoly. Qed. Lemma mx_root_minpoly : horner_mx A p_A = 0. Proof. rewrite rmorphB -{3}(horner_mx_X A) -rmorphX /=. by rewrite mx_inv_hornerK ?subrr ?horner_mx_mem. Qed. Lemma horner_rVpolyK (u : 'rV_d) : mx_inv_horner (horner_mx A (rVpoly u)) = rVpoly u. Proof. congr rVpoly; rewrite horner_rVpoly vec_mxK. by apply: (row_free_inj minpoly_mx_free); rewrite mulmxKpV ?submxMl. Qed. Lemma horner_mxK p : mx_inv_horner (horner_mx A p) = p %% p_A. Proof. rewrite {1}(Pdiv.IdomainMonic.divp_eq mxminpoly_monic p) rmorphD rmorphM /=. rewrite mx_root_minpoly mulr0 add0r. by rewrite -(poly_rV_K (size_mod_mxminpoly _)) horner_rVpolyK. Qed. Lemma mxminpoly_min p : horner_mx A p = 0 -> p_A %| p. Proof. by move=> pA0; rewrite /dvdp -horner_mxK pA0 mx_inv_horner0. Qed. Lemma horner_rVpoly_inj : @injective 'M_n 'rV_d (horner_mx A \o rVpoly). Proof. apply: can_inj (poly_rV \o mx_inv_horner) _ => u. by rewrite /= horner_rVpolyK rVpolyK. Qed. Lemma mxminpoly_linear_is_scalar : (d <= 1) = is_scalar_mx A. Proof. have scalP := has_non_scalar_mxP minpoly_mx1. rewrite leqNgt -(eqnP minpoly_mx_free); apply/scalP/idP=> [|[[B]]]. case scalA: (is_scalar_mx A); [by right | left]. by exists A; rewrite ?scalA // -{1}(horner_mx_X A) horner_mx_mem. move/mx_inv_hornerK=> <- nsB; case/is_scalar_mxP=> a defA; case/negP: nsB. move: {B}(_ B); apply: poly_ind => [|p c]. by rewrite rmorph0 ?mx0_is_scalar. rewrite rmorphD ?rmorphM /= horner_mx_X defA; case/is_scalar_mxP=> b ->. by rewrite -rmorphM horner_mx_C -rmorphD /= scalar_mx_is_scalar. Qed. Lemma mxminpoly_dvd_char : p_A %| char_poly A. Proof. by apply: mxminpoly_min; exact: Cayley_Hamilton. Qed. Lemma eigenvalue_root_min a : eigenvalue A a = root p_A a. Proof. apply/idP/idP=> Aa; last first. rewrite eigenvalue_root_char !root_factor_theorem in Aa *. exact: dvdp_trans Aa mxminpoly_dvd_char. have{Aa} [v Av_av v_nz] := eigenvalueP Aa. apply: contraR v_nz => pa_nz; rewrite -{pa_nz}(eqmx_eq0 (eqmx_scale _ pa_nz)). apply/eqP; rewrite -(mulmx0 _ v) -mx_root_minpoly. elim/poly_ind: p_A => [|p c IHp]. by rewrite rmorph0 horner0 scale0r mulmx0. rewrite !hornerE rmorphD rmorphM /= horner_mx_X horner_mx_C scalerDl. by rewrite -scalerA mulmxDr mul_mx_scalar mulmxA -IHp -scalemxAl Av_av. Qed. End MinPoly. (* Parametricity. *) Section MapRingMatrix. Variables (aR rR : ringType) (f : {rmorphism aR -> rR}). Local Notation "A ^f" := (map_mx (GRing.RMorphism.apply f) A) : ring_scope. Local Notation fp := (map_poly (GRing.RMorphism.apply f)). Variables (d n : nat) (A : 'M[aR]_n). Lemma map_rVpoly (u : 'rV_d) : fp (rVpoly u) = rVpoly u^f. Proof. apply/polyP=> k; rewrite coef_map !coef_rVpoly. by case: (insub k) => [i|]; rewrite /= ?rmorph0 // mxE. Qed. Lemma map_poly_rV p : (poly_rV p)^f = poly_rV (fp p) :> 'rV_d. Proof. by apply/rowP=> j; rewrite !mxE coef_map. Qed. Lemma map_char_poly_mx : map_mx fp (char_poly_mx A) = char_poly_mx A^f. Proof. rewrite raddfB /= map_scalar_mx /= map_polyX; congr (_ - _). by apply/matrixP=> i j; rewrite !mxE map_polyC. Qed. Lemma map_char_poly : fp (char_poly A) = char_poly A^f. Proof. by rewrite -det_map_mx map_char_poly_mx. Qed. End MapRingMatrix. Section MapResultant. Lemma map_resultant (aR rR : ringType) (f : {rmorphism {poly aR} -> rR}) p q : f (lead_coef p) != 0 -> f (lead_coef q) != 0 -> f (resultant p q)= resultant (map_poly f p) (map_poly f q). Proof. move=> nz_fp nz_fq; rewrite /resultant /Sylvester_mx !size_map_poly_id0 //. rewrite -det_map_mx /= map_col_mx; congr (\det (col_mx _ _)); by apply: map_lin1_mx => v; rewrite map_poly_rV rmorphM /= map_rVpoly. Qed. End MapResultant. Section MapComRing. Variables (aR rR : comRingType) (f : {rmorphism aR -> rR}). Local Notation "A ^f" := (map_mx f A) : ring_scope. Local Notation fp := (map_poly f). Variables (n' : nat) (A : 'M[aR]_n'.+1). Lemma map_powers_mx e : (powers_mx A e)^f = powers_mx A^f e. Proof. by apply/row_matrixP=> i; rewrite -map_row !rowK map_mxvec rmorphX. Qed. Lemma map_horner_mx p : (horner_mx A p)^f = horner_mx A^f (fp p). Proof. rewrite -[p](poly_rV_K (leqnn _)) map_rVpoly. by rewrite !horner_rVpoly map_vec_mx map_mxM map_powers_mx. Qed. End MapComRing. Section MapField. Variables (aF rF : fieldType) (f : {rmorphism aF -> rF}). Local Notation "A ^f" := (map_mx f A) : ring_scope. Local Notation fp := (map_poly f). Variables (n' : nat) (A : 'M[aF]_n'.+1). Lemma degree_mxminpoly_map : degree_mxminpoly A^f = degree_mxminpoly A. Proof. by apply: eq_ex_minn => e; rewrite -map_powers_mx mxrank_map. Qed. Lemma mxminpoly_map : mxminpoly A^f = fp (mxminpoly A). Proof. rewrite rmorphB; congr (_ - _). by rewrite /= map_polyXn degree_mxminpoly_map. rewrite degree_mxminpoly_map -rmorphX /=. apply/polyP=> i; rewrite coef_map //= !coef_rVpoly degree_mxminpoly_map. case/insub: i => [i|]; last by rewrite rmorph0. by rewrite -map_powers_mx -map_pinvmx // -map_mxvec -map_mxM // mxE. Qed. Lemma map_mx_inv_horner u : fp (mx_inv_horner A u) = mx_inv_horner A^f u^f. Proof. rewrite map_rVpoly map_mxM map_mxvec map_pinvmx map_powers_mx. by rewrite /mx_inv_horner degree_mxminpoly_map. Qed. End MapField. Section IntegralOverRing. Definition integralOver (R K : ringType) (RtoK : R -> K) (z : K) := exists2 p, p \is monic & root (map_poly RtoK p) z. Definition integralRange R K RtoK := forall z, @integralOver R K RtoK z. Variables (B R K : ringType) (BtoR : B -> R) (RtoK : {rmorphism R -> K}). Lemma integral_rmorph x : integralOver BtoR x -> integralOver (RtoK \o BtoR) (RtoK x). Proof. by case=> p; exists p; rewrite // map_poly_comp rmorph_root. Qed. Lemma integral_id x : integralOver RtoK (RtoK x). Proof. by exists ('X - x%:P); rewrite ?monicXsubC ?rmorph_root ?root_XsubC. Qed. Lemma integral_nat n : integralOver RtoK n%:R. Proof. by rewrite -(rmorph_nat RtoK); apply: integral_id. Qed. Lemma integral0 : integralOver RtoK 0. Proof. exact: (integral_nat 0). Qed. Lemma integral1 : integralOver RtoK 1. Proof. exact: (integral_nat 1). Qed. Lemma integral_poly (p : {poly K}) : (forall i, integralOver RtoK p`_i) <-> {in p : seq K, integralRange RtoK}. Proof. split=> intRp => [_ /(nthP 0)[i _ <-] // | i]; rewrite -[p]coefK coef_poly. by case: ifP => [ltip | _]; [apply/intRp/mem_nth | apply: integral0]. Qed. End IntegralOverRing. Section IntegralOverComRing. Variables (R K : comRingType) (RtoK : {rmorphism R -> K}). Lemma integral_horner_root w (p q : {poly K}) : p \is monic -> root p w -> {in p : seq K, integralRange RtoK} -> {in q : seq K, integralRange RtoK} -> integralOver RtoK q.[w]. Proof. move=> mon_p pw0 intRp intRq. pose memR y := exists x, y = RtoK x. have memRid x: memR (RtoK x) by exists x. have memR_nat n: memR n%:R by rewrite -(rmorph_nat RtoK). have [memR0 memR1]: memR 0 * memR 1 := (memR_nat 0%N, memR_nat 1%N). have memRN1: memR (- 1) by exists (- 1); rewrite rmorphN1. pose rVin (E : K -> Prop) n (a : 'rV[K]_n) := forall i, E (a 0 i). pose pXin (E : K -> Prop) (r : {poly K}) := forall i, E r`_i. pose memM E n (X : 'rV_n) y := exists a, rVin E n a /\ y = (a *m X^T) 0 0. pose finM E S := exists n, exists X, forall y, memM E n X y <-> S y. have tensorM E n1 n2 X Y: finM E (memM (memM E n2 Y) n1 X). exists (n1 * n2)%N, (mxvec (X^T *m Y)) => y. split=> [[a [Ea Dy]] | [a1 [/fin_all_exists[a /all_and2[Ea Da1]] ->]]]. exists (Y *m (vec_mx a)^T); split=> [i|]. exists (row i (vec_mx a)); split=> [j|]; first by rewrite !mxE; apply: Ea. by rewrite -row_mul -{1}[Y]trmxK -trmx_mul !mxE. by rewrite -[Y]trmxK -!trmx_mul mulmxA -mxvec_dotmul trmx_mul trmxK vec_mxK. exists (mxvec (\matrix_i a i)); split. by case/mxvec_indexP=> i j; rewrite mxvecE mxE; apply: Ea. rewrite -[mxvec _]trmxK -trmx_mul mxvec_dotmul -mulmxA trmx_mul !mxE. apply: eq_bigr => i _; rewrite Da1 !mxE; congr (_ * _). by apply: eq_bigr => j _; rewrite !mxE. suffices [m [X [[u [_ Du]] idealM]]]: exists m, exists X, let M := memM memR m X in M 1 /\ forall y, M y -> M (q.[w] * y). - do [set M := memM _ m X; move: q.[w] => z] in idealM *. have MX i: M (X 0 i). by exists (delta_mx 0 i); split=> [j|]; rewrite -?rowE !mxE. have /fin_all_exists[a /all_and2[Fa Da1]] i := idealM _ (MX i). have /fin_all_exists[r Dr] i := fin_all_exists (Fa i). pose A := \matrix_(i, j) r j i; pose B := z%:M - map_mx RtoK A. have XB0: X *m B = 0. apply/eqP; rewrite mulmxBr mul_mx_scalar subr_eq0; apply/eqP/rowP=> i. by rewrite !mxE Da1 mxE; apply: eq_bigr=> j _; rewrite !mxE mulrC Dr. exists (char_poly A); first exact: char_poly_monic. have: (\det B *: (u *m X^T)) 0 0 == 0. rewrite scalemxAr -linearZ -mul_mx_scalar -mul_mx_adj mulmxA XB0 /=. by rewrite mul0mx trmx0 mulmx0 mxE. rewrite mxE -Du mulr1 rootE -horner_evalE -!det_map_mx; congr (\det _ == 0). rewrite !raddfB /= !map_scalar_mx /= map_polyX horner_evalE hornerX. by apply/matrixP=> i j; rewrite !mxE map_polyC /horner_eval hornerC. pose gen1 x E y := exists2 r, pXin E r & y = r.[x]; pose gen := foldr gen1 memR. have gen1S (E : K -> Prop) x y: E 0 -> E y -> gen1 x E y. by exists y%:P => [i|]; rewrite ?hornerC ?coefC //; case: ifP. have genR S y: memR y -> gen S y. by elim: S => //= x S IH in y * => /IH; apply: gen1S; apply: IH. have gen0 := genR _ 0 memR0; have gen_1 := genR _ 1 memR1. have{gen1S} genS S y: y \in S -> gen S y. elim: S => //= x S IH /predU1P[-> | /IH//]; last exact: gen1S. by exists 'X => [i|]; rewrite ?hornerX // coefX; apply: genR. pose propD (R : K -> Prop) := forall x y, R x -> R y -> R (x + y). have memRD: propD memR. by move=> _ _ [a ->] [b ->]; exists (a + b); rewrite rmorphD. have genD S: propD (gen S). elim: S => //= x S IH _ _ [r1 Sr1 ->] [r2 Sr2 ->]; rewrite -hornerD. by exists (r1 + r2) => // i; rewrite coefD; apply: IH. have gen_sum S := big_ind _ (gen0 S) (genD S). pose propM (R : K -> Prop) := forall x y, R x -> R y -> R (x * y). have memRM: propM memR. by move=> _ _ [a ->] [b ->]; exists (a * b); rewrite rmorphM. have genM S: propM (gen S). elim: S => //= x S IH _ _ [r1 Sr1 ->] [r2 Sr2 ->]; rewrite -hornerM. by exists (r1 * r2) => // i; rewrite coefM; apply: gen_sum => j _; apply: IH. have gen_horner S r y: pXin (gen S) r -> gen S y -> gen S r.[y]. move=> Sq Sy; rewrite horner_coef; apply: gen_sum => [[i _] /= _]. by elim: {2}i => [|n IHn]; rewrite ?mulr1 // exprSr mulrA; apply: genM. pose S := w :: q ++ p; suffices [m [X defX]]: finM memR (gen S). exists m, X => M; split=> [|y /defX Xy]; first exact/defX. apply/defX/genM => //; apply: gen_horner => // [i|]; last exact/genS/mem_head. rewrite -[q]coefK coef_poly; case: ifP => // lt_i_q. by apply: genS; rewrite inE mem_cat mem_nth ?orbT. pose intR R y := exists r, [/\ r \is monic, root r y & pXin R r]. pose fix genI s := if s is y :: s1 then intR (gen s1) y /\ genI s1 else True. have{mon_p pw0 intRp intRq}: genI S. split; set S1 := _ ++ _; first exists p. split=> // i; rewrite -[p]coefK coef_poly; case: ifP => // lt_i_p. by apply: genS; rewrite mem_cat orbC mem_nth. have: all (mem S1) S1 by exact/allP. elim: {-1}S1 => //= y S2 IH /andP[S1y S12]; split; last exact: IH. have{q S S1 IH S1y S12 intRp intRq} [q mon_q qx0]: integralOver RtoK y. by move: S1y; rewrite mem_cat => /orP[]; [apply: intRq | apply: intRp]. exists (map_poly RtoK q); split=> // [|i]; first exact: monic_map. by rewrite coef_map /=; apply: genR. elim: {w p q}S => /= [_|x S IH [[p [mon_p px0 Sp]] /IH{IH}[m2 [X2 defS]]]]. exists 1%N, 1 => y; split=> [[a [Fa ->]] | Fy]. by rewrite tr_scalar_mx mulmx1; apply: Fa. by exists y%:M; split=> [i|]; rewrite 1?ord1 ?tr_scalar_mx ?mulmx1 mxE. pose m1 := (size p).-1; pose X1 := \row_(i < m1) x ^+ i. have [m [X defM]] := tensorM memR m1 m2 X1 X2; set M := memM _ _ _ in defM. exists m, X => y; rewrite -/M; split=> [/defM[a [M2a]] | [q Sq]] -> {y}. exists (rVpoly a) => [i|]. by rewrite coef_rVpoly; case/insub: i => // i; apply/defS/M2a. rewrite mxE (horner_coef_wide _ (size_poly _ _)) -/(rVpoly a). by apply: eq_bigr => i _; rewrite coef_rVpoly_ord !mxE. have M_0: M 0 by exists 0; split=> [i|]; rewrite ?mul0mx mxE. have M_D: propD M. move=> _ _ [a [Fa ->]] [b [Fb ->]]; exists (a + b). by rewrite mulmxDl !mxE; split=> // i; rewrite mxE; apply: memRD. have{M_0 M_D} Msum := big_ind _ M_0 M_D. rewrite horner_coef; apply: (Msum) => i _; case: i q`_i {Sq}(Sq i) => /=. elim: {q}(size q) => // n IHn i i_le_n y Sy. have [i_lt_m1 | m1_le_i] := ltnP i m1. apply/defM; exists (y *: delta_mx 0 (Ordinal i_lt_m1)); split=> [j|]. by apply/defS; rewrite !mxE /= mulr_natr; case: eqP. by rewrite -scalemxAl -rowE !mxE. rewrite -(subnK m1_le_i) exprD -[x ^+ m1]subr0 -(rootP px0) horner_coef. rewrite polySpred ?monic_neq0 // -/m1 big_ord_recr /= -lead_coefE. rewrite opprD addrC (monicP mon_p) mul1r subrK !mulrN -mulNr !mulr_sumr. apply: Msum => j _; rewrite mulrA mulrACA -exprD; apply: IHn. by rewrite -addnS addnC addnBA // leq_subLR leq_add. by rewrite -mulN1r; do 2!apply: (genM) => //; apply: genR. Qed. Lemma integral_root_monic u p : p \is monic -> root p u -> {in p : seq K, integralRange RtoK} -> integralOver RtoK u. Proof. move=> mon_p pu0 intRp; rewrite -[u]hornerX. apply: integral_horner_root mon_p pu0 intRp _. by apply/integral_poly => i; rewrite coefX; apply: integral_nat. Qed. Hint Resolve (integral0 RtoK) (integral1 RtoK) (@monicXsubC K). Let XsubC0 (u : K) : root ('X - u%:P) u. Proof. by rewrite root_XsubC. Qed. Let intR_XsubC u : integralOver RtoK (- u) -> {in 'X - u%:P : seq K, integralRange RtoK}. Proof. by move=> intRu v; rewrite polyseqXsubC !inE => /pred2P[]->. Qed. Lemma integral_opp u : integralOver RtoK u -> integralOver RtoK (- u). Proof. by rewrite -{1}[u]opprK => /intR_XsubC/integral_root_monic; apply. Qed. Lemma integral_horner (p : {poly K}) u : {in p : seq K, integralRange RtoK} -> integralOver RtoK u -> integralOver RtoK p.[u]. Proof. by move=> ? /integral_opp/intR_XsubC/integral_horner_root; apply. Qed. Lemma integral_sub u v : integralOver RtoK u -> integralOver RtoK v -> integralOver RtoK (u - v). Proof. move=> intRu /integral_opp/intR_XsubC/integral_horner/(_ intRu). by rewrite !hornerE. Qed. Lemma integral_add u v : integralOver RtoK u -> integralOver RtoK v -> integralOver RtoK (u + v). Proof. by rewrite -{2}[v]opprK => intRu /integral_opp; apply: integral_sub. Qed. Lemma integral_mul u v : integralOver RtoK u -> integralOver RtoK v -> integralOver RtoK (u * v). Proof. rewrite -{2}[v]hornerX -hornerZ => intRu; apply: integral_horner. by apply/integral_poly=> i; rewrite coefZ coefX mulr_natr mulrb; case: ifP. Qed. End IntegralOverComRing. Section IntegralOverField. Variables (F E : fieldType) (FtoE : {rmorphism F -> E}). Definition algebraicOver (fFtoE : F -> E) u := exists2 p, p != 0 & root (map_poly fFtoE p) u. Notation mk_mon p := ((lead_coef p)^-1 *: p). Lemma integral_algebraic u : algebraicOver FtoE u <-> integralOver FtoE u. Proof. split=> [] [p p_nz pu0]; last by exists p; rewrite ?monic_neq0. exists (mk_mon p); first by rewrite monicE lead_coefZ mulVf ?lead_coef_eq0. by rewrite linearZ rootE hornerZ (rootP pu0) mulr0. Qed. Lemma algebraic_id a : algebraicOver FtoE (FtoE a). Proof. exact/integral_algebraic/integral_id. Qed. Lemma algebraic0 : algebraicOver FtoE 0. Proof. exact/integral_algebraic/integral0. Qed. Lemma algebraic1 : algebraicOver FtoE 1. Proof. exact/integral_algebraic/integral1. Qed. Lemma algebraic_opp x : algebraicOver FtoE x -> algebraicOver FtoE (- x). Proof. by move/integral_algebraic/integral_opp/integral_algebraic. Qed. Lemma algebraic_add x y : algebraicOver FtoE x -> algebraicOver FtoE y -> algebraicOver FtoE (x + y). Proof. move/integral_algebraic=> intFx /integral_algebraic intFy. exact/integral_algebraic/integral_add. Qed. Lemma algebraic_sub x y : algebraicOver FtoE x -> algebraicOver FtoE y -> algebraicOver FtoE (x - y). Proof. by move=> algFx /algebraic_opp; apply: algebraic_add. Qed. Lemma algebraic_mul x y : algebraicOver FtoE x -> algebraicOver FtoE y -> algebraicOver FtoE (x * y). Proof. move/integral_algebraic=> intFx /integral_algebraic intFy. exact/integral_algebraic/integral_mul. Qed. Lemma algebraic_inv u : algebraicOver FtoE u -> algebraicOver FtoE u^-1. Proof. have [-> | /expf_neq0 nz_u_n] := eqVneq u 0; first by rewrite invr0. case=> p nz_p pu0; exists (Poly (rev p)). apply/eqP=> /polyP/(_ 0%N); rewrite coef_Poly coef0 nth_rev ?size_poly_gt0 //. by apply/eqP; rewrite subn1 lead_coef_eq0. apply/eqP/(mulfI (nz_u_n (size p).-1)); rewrite mulr0 -(rootP pu0). rewrite (@horner_coef_wide _ (size p)); last first. by rewrite size_map_poly -(size_rev p) size_Poly. rewrite horner_coef mulr_sumr size_map_poly. rewrite [rhs in _ = rhs](reindex_inj rev_ord_inj) /=. apply: eq_bigr => i _; rewrite !coef_map coef_Poly nth_rev // mulrCA. by congr (_ * _); rewrite -{1}(subnKC (valP i)) addSn addnC exprD exprVn ?mulfK. Qed. Lemma algebraic_div x y : algebraicOver FtoE x -> algebraicOver FtoE y -> algebraicOver FtoE (x / y). Proof. by move=> algFx /algebraic_inv; apply: algebraic_mul. Qed. Lemma integral_inv x : integralOver FtoE x -> integralOver FtoE x^-1. Proof. by move/integral_algebraic/algebraic_inv/integral_algebraic. Qed. Lemma integral_div x y : integralOver FtoE x -> integralOver FtoE y -> integralOver FtoE (x / y). Proof. by move=> algFx /integral_inv; apply: integral_mul. Qed. Lemma integral_root p u : p != 0 -> root p u -> {in p : seq E, integralRange FtoE} -> integralOver FtoE u. Proof. move=> nz_p pu0 algFp. have mon_p1: mk_mon p \is monic. by rewrite monicE lead_coefZ mulVf ?lead_coef_eq0. have p1u0: root (mk_mon p) u by rewrite rootE hornerZ (rootP pu0) mulr0. apply: integral_root_monic mon_p1 p1u0 _ => _ /(nthP 0)[i ltip <-]. rewrite coefZ mulrC; rewrite size_scale ?invr_eq0 ?lead_coef_eq0 // in ltip. by apply: integral_div; apply/algFp/mem_nth; rewrite -?polySpred. Qed. End IntegralOverField. (* Lifting term, formula, envs and eval to matrices. Wlog, and for the sake *) (* of simplicity, we only lift (tensor) envs to row vectors; we can always *) (* use mxvec/vec_mx to store and retrieve matrices. *) (* We don't provide definitions for addition, substraction, scaling, etc, *) (* because they have simple matrix expressions. *) Module MatrixFormula. Section MatrixFormula. Variable F : fieldType. Local Notation False := GRing.False. Local Notation True := GRing.True. Local Notation And := GRing.And (only parsing). Local Notation Add := GRing.Add (only parsing). Local Notation Bool b := (GRing.Bool b%bool). Local Notation term := (GRing.term F). Local Notation form := (GRing.formula F). Local Notation eval := GRing.eval. Local Notation holds := GRing.holds. Local Notation qf_form := GRing.qf_form. Local Notation qf_eval := GRing.qf_eval. Definition eval_mx (e : seq F) := map_mx (eval e). Definition mx_term := map_mx (@GRing.Const F). Lemma eval_mx_term e m n (A : 'M_(m, n)) : eval_mx e (mx_term A) = A. Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Definition mulmx_term m n p (A : 'M[term]_(m, n)) (B : 'M_(n, p)) := \matrix_(i, k) (\big[Add/0]_j (A i j * B j k))%T. Lemma eval_mulmx e m n p (A : 'M[term]_(m, n)) (B : 'M_(n, p)) : eval_mx e (mulmx_term A B) = eval_mx e A *m eval_mx e B. Proof. apply/matrixP=> i k; rewrite !mxE /= ((big_morph (eval e)) 0 +%R) //=. by apply: eq_bigr => j _; rewrite /= !mxE. Qed. Local Notation morphAnd f := ((big_morph f) true andb). Let Schur m n (A : 'M[term]_(1 + m, 1 + n)) (a := A 0 0) := \matrix_(i, j) (drsubmx A i j - a^-1 * dlsubmx A i 0%R * ursubmx A 0%R j)%T. Fixpoint mxrank_form (r m n : nat) : 'M_(m, n) -> form := match m, n return 'M_(m, n) -> form with | m'.+1, n'.+1 => fun A : 'M_(1 + m', 1 + n') => let nzA k := A k.1 k.2 != 0 in let xSchur k := Schur (xrow k.1 0%R (xcol k.2 0%R A)) in let recf k := Bool (r > 0) /\ mxrank_form r.-1 (xSchur k) in GRing.Pick nzA recf (Bool (r == 0%N)) | _, _ => fun _ => Bool (r == 0%N) end%T. Lemma mxrank_form_qf r m n (A : 'M_(m, n)) : qf_form (mxrank_form r A). Proof. by elim: m r n A => [|m IHm] r [|n] A //=; rewrite GRing.Pick_form_qf /=. Qed. Lemma eval_mxrank e r m n (A : 'M_(m, n)) : qf_eval e (mxrank_form r A) = (\rank (eval_mx e A) == r). Proof. elim: m r n A => [|m IHm] r [|n] A /=; try by case r. rewrite GRing.eval_Pick /mxrank unlock /=; set pf := fun _ => _. rewrite -(@eq_pick _ pf) => [|k]; rewrite {}/pf ?mxE // eq_sym. case: pick => [[i j]|] //=; set B := _ - _; have:= mxrankE B. case: (Gaussian_elimination B) r => [[_ _] _] [|r] //= <-; rewrite {}IHm eqSS. by congr (\rank _ == r); apply/matrixP=> k l; rewrite !(mxE, big_ord1) !tpermR. Qed. Lemma eval_vec_mx e m n (u : 'rV_(m * n)) : eval_mx e (vec_mx u) = vec_mx (eval_mx e u). Proof. by apply/matrixP=> i j; rewrite !mxE. Qed. Lemma eval_mxvec e m n (A : 'M_(m, n)) : eval_mx e (mxvec A) = mxvec (eval_mx e A). Proof. by rewrite -{2}[A]mxvecK eval_vec_mx vec_mxK. Qed. Section Subsetmx. Variables (m1 m2 n : nat) (A : 'M[term]_(m1, n)) (B : 'M[term]_(m2, n)). Definition submx_form := \big[And/True]_(r < n.+1) (mxrank_form r (col_mx A B) ==> mxrank_form r B)%T. Lemma eval_col_mx e : eval_mx e (col_mx A B) = col_mx (eval_mx e A) (eval_mx e B). Proof. by apply/matrixP=> i j; do 2![rewrite !mxE //; case: split => ?]. Qed. Lemma submx_form_qf : qf_form submx_form. Proof. by rewrite (morphAnd (@qf_form _)) ?big1 //= => r _; rewrite !mxrank_form_qf. Qed. Lemma eval_submx e : qf_eval e submx_form = (eval_mx e A <= eval_mx e B)%MS. Proof. rewrite (morphAnd (qf_eval e)) //= big_andE /=. apply/forallP/idP=> /= [|sAB d]; last first. rewrite !eval_mxrank eval_col_mx -addsmxE; apply/implyP=> /eqP <-. by rewrite mxrank_leqif_sup ?addsmxSr // addsmx_sub sAB /=. move/(_ (inord (\rank (eval_mx e (col_mx A B))))). rewrite inordK ?ltnS ?rank_leq_col // !eval_mxrank eqxx /= eval_col_mx. by rewrite -addsmxE mxrank_leqif_sup ?addsmxSr // addsmx_sub; case/andP. Qed. End Subsetmx. Section Env. Variable d : nat. Definition seq_of_rV (v : 'rV_d) : seq F := fgraph [ffun i => v 0 i]. Lemma size_seq_of_rV v : size (seq_of_rV v) = d. Proof. by rewrite tuple.size_tuple card_ord. Qed. Lemma nth_seq_of_rV x0 v (i : 'I_d) : nth x0 (seq_of_rV v) i = v 0 i. Proof. by rewrite nth_fgraph_ord ffunE. Qed. Definition row_var k : 'rV[term]_d := \row_i ('X_(k * d + i))%T. Definition row_env (e : seq 'rV_d) := flatten (map seq_of_rV e). Lemma nth_row_env e k (i : 'I_d) : (row_env e)`_(k * d + i) = e`_k 0 i. Proof. elim: e k => [|v e IHe] k; first by rewrite !nth_nil mxE. rewrite /row_env /= nth_cat size_seq_of_rV. case: k => [|k]; first by rewrite (valP i) nth_seq_of_rV. by rewrite mulSn -addnA -if_neg -leqNgt leq_addr addKn IHe. Qed. Lemma eval_row_var e k : eval_mx (row_env e) (row_var k) = e`_k :> 'rV_d. Proof. by apply/rowP=> i; rewrite !mxE /= nth_row_env. Qed. Definition Exists_row_form k (f : form) := foldr GRing.Exists f (codom (fun i : 'I_d => k * d + i)%N). Lemma Exists_rowP e k f : d > 0 -> ((exists v : 'rV[F]_d, holds (row_env (set_nth 0 e k v)) f) <-> holds (row_env e) (Exists_row_form k f)). Proof. move=> d_gt0; pose i_ j := Ordinal (ltn_pmod j d_gt0). have d_eq j: (j = j %/ d * d + i_ j)%N := divn_eq j d. split=> [[v f_v] | ]; last case/GRing.foldExistsP=> e' ee' f_e'. apply/GRing.foldExistsP; exists (row_env (set_nth 0 e k v)) => {f f_v}// j. rewrite [j]d_eq !nth_row_env nth_set_nth /=; case: eqP => // ->. by case/imageP; exists (i_ j). exists (\row_i e'`_(k * d + i)); apply: eq_holds f_e' => j /=. move/(_ j): ee'; rewrite [j]d_eq !nth_row_env nth_set_nth /=. case: eqP => [-> | ne_j_k -> //]; first by rewrite mxE. apply/mapP=> [[r lt_r_d]]; rewrite -d_eq => def_j; case: ne_j_k. by rewrite def_j divnMDl // divn_small ?addn0. Qed. End Env. End MatrixFormula. End MatrixFormula. mathcomp-1.5/theories/sylow.v0000644000175000017500000006647412307636117015370 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div fintype prime. Require Import bigop finset fingroup morphism automorphism quotient action. Require Import cyclic gproduct commutator pgroup center nilpotent. (******************************************************************************) (* The Sylow theorem and its consequences, including the Frattini argument, *) (* the nilpotence of p-groups, and the Baer-Suzuki theorem. *) (* This file also defines: *) (* Zgroup G == G is a Z-group, i.e., has only cyclic Sylow p-subgroups. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. (* The mod p lemma for the action of p-groups. *) Section ModP. Variable (aT : finGroupType) (sT : finType) (D : {group aT}). Variable to : action D sT. Lemma pgroup_fix_mod (p : nat) (G : {group aT}) (S : {set sT}) : p.-group G -> [acts G, on S | to] -> #|S| = #|'Fix_(S | to)(G)| %[mod p]. Proof. move=> pG nSG; have sGD: G \subset D := acts_dom nSG. apply/eqP; rewrite -(cardsID 'Fix_to(G)) eqn_mod_dvd (leq_addr, addKn) //. have: [acts G, on S :\: 'Fix_to(G) | to]; last move/acts_sum_card_orbit <-. rewrite actsD // -(setIidPr sGD); apply: subset_trans (acts_subnorm_fix _ _). by rewrite setIS ?normG. apply: dvdn_sum => _ /imsetP[x /setDP[_ nfx] ->]. have [k oGx]: {k | #|orbit to G x| = (p ^ k)%N}. by apply: p_natP; apply: pnat_dvd pG; rewrite card_orbit_in ?dvdn_indexg. case: k oGx => [/card_orbit1 fix_x | k ->]; last by rewrite expnS dvdn_mulr. by case/afixP: nfx => a Ga; apply/set1P; rewrite -fix_x mem_orbit. Qed. End ModP. Section ModularGroupAction. Variables (aT rT : finGroupType) (D : {group aT}) (R : {group rT}). Variables (to : groupAction D R) (p : nat). Implicit Types (G H : {group aT}) (M : {group rT}). Lemma nontrivial_gacent_pgroup G M : p.-group G -> p.-group M -> {acts G, on group M | to} -> M :!=: 1 -> 'C_(M | to)(G) :!=: 1. Proof. move=> pG pM [nMG sMR] ntM; have [p_pr p_dv_M _] := pgroup_pdiv pM ntM. rewrite -cardG_gt1 (leq_trans (prime_gt1 p_pr)) 1?dvdn_leq ?cardG_gt0 //= /dvdn. by rewrite gacentE ?(acts_dom nMG) // setIA (setIidPl sMR) -pgroup_fix_mod. Qed. Lemma pcore_sub_astab_irr G M : p.-group M -> M \subset R -> acts_irreducibly G M to -> 'O_p(G) \subset 'C_G(M | to). Proof. move=> pM sMR /mingroupP[/andP[ntM nMG] minM]. have [sGpG nGpG]:= andP (pcore_normal p G). have sGD := acts_dom nMG; have sGpD := subset_trans sGpG sGD. rewrite subsetI sGpG -gacentC //=; apply/setIidPl; apply: minM (subsetIl _ _). rewrite nontrivial_gacent_pgroup ?pcore_pgroup //=; last first. by split; rewrite ?(subset_trans sGpG). by apply: subset_trans (acts_subnorm_subgacent sGpD nMG); rewrite subsetI subxx. Qed. Lemma pcore_faithful_irr_act G M : p.-group M -> M \subset R -> acts_irreducibly G M to -> [faithful G, on M | to] -> 'O_p(G) = 1. Proof. move=> pM sMR irrG ffulG; apply/trivgP; apply: subset_trans ffulG. exact: pcore_sub_astab_irr. Qed. End ModularGroupAction. Section Sylow. Variables (p : nat) (gT : finGroupType) (G : {group gT}). Implicit Types P Q H K : {group gT}. Theorem Sylow's_theorem : [/\ forall P, [max P | p.-subgroup(G) P] = p.-Sylow(G) P, [transitive G, on 'Syl_p(G) | 'JG], forall P, p.-Sylow(G) P -> #|'Syl_p(G)| = #|G : 'N_G(P)| & prime p -> #|'Syl_p(G)| %% p = 1%N]. Proof. pose maxp A P := [max P | p.-subgroup(A) P]; pose S := [set P | maxp G P]. pose oG := orbit 'JG%act G. have actS: [acts G, on S | 'JG]. apply/subsetP=> x Gx; rewrite 3!inE; apply/subsetP=> P; rewrite 3!inE. exact: max_pgroupJ. have S_pG P: P \in S -> P \subset G /\ p.-group P. by rewrite inE => /maxgroupp/andP[]. have SmaxN P Q: Q \in S -> Q \subset 'N(P) -> maxp 'N_G(P) Q. rewrite inE => /maxgroupP[/andP[sQG pQ] maxQ] nPQ. apply/maxgroupP; rewrite /psubgroup subsetI sQG nPQ. by split=> // R; rewrite subsetI -andbA andbCA => /andP[_]; exact: maxQ. have nrmG P: P \subset G -> P <| 'N_G(P). by move=> sPG; rewrite /normal subsetIr subsetI sPG normG. have sylS P: P \in S -> p.-Sylow('N_G(P)) P. move=> S_P; have [sPG pP] := S_pG P S_P. by rewrite normal_max_pgroup_Hall ?nrmG //; apply: SmaxN; rewrite ?normG. have{SmaxN} defCS P: P \in S -> 'Fix_(S |'JG)(P) = [set P]. move=> S_P; apply/setP=> Q; rewrite {1}in_setI {1}afixJG. apply/andP/set1P=> [[S_Q nQP]|->{Q}]; last by rewrite normG. apply/esym/val_inj; case: (S_pG Q) => //= sQG _. by apply: uniq_normal_Hall (SmaxN Q _ _ _) => //=; rewrite ?sylS ?nrmG. have{defCS} oG_mod: {in S &, forall P Q, #|oG P| = (Q \in oG P) %[mod p]}. move=> P Q S_P S_Q; have [sQG pQ] := S_pG _ S_Q. have soP_S: oG P \subset S by rewrite acts_sub_orbit. have /pgroup_fix_mod-> //: [acts Q, on oG P | 'JG]. apply/actsP=> x /(subsetP sQG) Gx R; apply: orbit_transr. exact: mem_orbit. rewrite -{1}(setIidPl soP_S) -setIA defCS // (cardsD1 Q) setDE. by rewrite -setIA setICr setI0 cards0 addn0 inE set11 andbT. have [P S_P]: exists P, P \in S. have: p.-subgroup(G) 1 by rewrite /psubgroup sub1G pgroup1. by case/(@maxgroup_exists _ (p.-subgroup(G))) => P; exists P; rewrite inE. have trS: [transitive G, on S | 'JG]. apply/imsetP; exists P => //; apply/eqP. rewrite eqEsubset andbC acts_sub_orbit // S_P; apply/subsetP=> Q S_Q. have:= S_P; rewrite inE => /maxgroupP[/andP[_ pP]]. have [-> max1 | ntP _] := eqVneq P 1%G. move/andP/max1: (S_pG _ S_Q) => Q1. by rewrite (group_inj (Q1 (sub1G Q))) orbit_refl. have:= oG_mod _ _ S_P S_P; rewrite (oG_mod _ Q) // orbit_refl. have p_gt1: p > 1 by apply: prime_gt1; case/pgroup_pdiv: pP. by case: (Q \in oG P) => //; rewrite mod0n modn_small. have oS1: prime p -> #|S| %% p = 1%N. move/prime_gt1 => p_gt1. by rewrite -(atransP trS P S_P) (oG_mod P P) // orbit_refl modn_small. have oSiN Q: Q \in S -> #|S| = #|G : 'N_G(Q)|. by move=> S_Q; rewrite -(atransP trS Q S_Q) card_orbit astab1JG. have sylP: p.-Sylow(G) P. rewrite pHallE; case: (S_pG P) => // -> /= pP. case p_pr: (prime p); last first. rewrite p_part lognE p_pr /= -trivg_card1; apply/idPn=> ntP. by case/pgroup_pdiv: pP p_pr => // ->. rewrite -(LagrangeI G 'N(P)) /= mulnC partnM ?cardG_gt0 // part_p'nat. by rewrite mul1n (card_Hall (sylS P S_P)). by rewrite p'natE // -indexgI -oSiN // /dvdn oS1. have eqS Q: maxp G Q = p.-Sylow(G) Q. apply/idP/idP=> [S_Q|]; last exact: Hall_max. have{S_Q} S_Q: Q \in S by rewrite inE. rewrite pHallE -(card_Hall sylP); case: (S_pG Q) => // -> _ /=. by case: (atransP2 trS S_P S_Q) => x _ ->; rewrite cardJg. have ->: 'Syl_p(G) = S by apply/setP=> Q; rewrite 2!inE. by split=> // Q sylQ; rewrite -oSiN ?inE ?eqS. Qed. Lemma max_pgroup_Sylow P : [max P | p.-subgroup(G) P] = p.-Sylow(G) P. Proof. by case Sylow's_theorem. Qed. Lemma Sylow_superset Q : Q \subset G -> p.-group Q -> {P : {group gT} | p.-Sylow(G) P & Q \subset P}. Proof. move=> sQG pQ. have [|P] := @maxgroup_exists _ (p.-subgroup(G)) Q; first exact/andP. by rewrite max_pgroup_Sylow; exists P. Qed. Lemma Sylow_exists : {P : {group gT} | p.-Sylow(G) P}. Proof. by case: (Sylow_superset (sub1G G) (pgroup1 _ p)) => P; exists P. Qed. Lemma Syl_trans : [transitive G, on 'Syl_p(G) | 'JG]. Proof. by case Sylow's_theorem. Qed. Lemma Sylow_trans P Q : p.-Sylow(G) P -> p.-Sylow(G) Q -> exists2 x, x \in G & Q :=: P :^ x. Proof. move=> sylP sylQ; have:= (atransP2 Syl_trans) P Q; rewrite !inE. by case=> // x Gx ->; exists x. Qed. Lemma Sylow_subJ P Q : p.-Sylow(G) P -> Q \subset G -> p.-group Q -> exists2 x, x \in G & Q \subset P :^ x. Proof. move=> sylP sQG pQ; have [Px sylPx] := Sylow_superset sQG pQ. by have [x Gx ->] := Sylow_trans sylP sylPx; exists x. Qed. Lemma Sylow_Jsub P Q : p.-Sylow(G) P -> Q \subset G -> p.-group Q -> exists2 x, x \in G & Q :^ x \subset P. Proof. move=> sylP sQG pQ; have [x Gx] := Sylow_subJ sylP sQG pQ. by exists x^-1; rewrite (groupV, sub_conjgV). Qed. Lemma card_Syl P : p.-Sylow(G) P -> #|'Syl_p(G)| = #|G : 'N_G(P)|. Proof. by case: Sylow's_theorem P. Qed. Lemma card_Syl_dvd : #|'Syl_p(G)| %| #|G|. Proof. by case Sylow_exists => P /card_Syl->; exact: dvdn_indexg. Qed. Lemma card_Syl_mod : prime p -> #|'Syl_p(G)| %% p = 1%N. Proof. by case Sylow's_theorem. Qed. Lemma Frattini_arg H P : G <| H -> p.-Sylow(G) P -> G * 'N_H(P) = H. Proof. case/andP=> sGH nGH sylP; rewrite -normC ?subIset ?nGH ?orbT // -astab1JG. move/subgroup_transitiveP: Syl_trans => ->; rewrite ?inE //. apply/imsetP; exists P; rewrite ?inE //. apply/eqP; rewrite eqEsubset -{1}((atransP Syl_trans) P) ?inE // imsetS //=. by apply/subsetP=> _ /imsetP[x Hx ->]; rewrite inE -(normsP nGH x Hx) pHallJ2. Qed. End Sylow. Section MoreSylow. Variables (gT : finGroupType) (p : nat). Implicit Types G H P : {group gT}. Lemma Sylow_setI_normal G H P : G <| H -> p.-Sylow(H) P -> p.-Sylow(G) (G :&: P). Proof. case/normalP=> sGH nGH sylP; have [Q sylQ] := Sylow_exists p G. have /maxgroupP[/andP[sQG pQ] maxQ] := Hall_max sylQ. have [R sylR sQR] := Sylow_superset (subset_trans sQG sGH) pQ. have [[x Hx ->] pR] := (Sylow_trans sylR sylP, pHall_pgroup sylR). rewrite -(nGH x Hx) -conjIg pHallJ2. have /maxQ-> //: Q \subset G :&: R by rewrite subsetI sQG. by rewrite /psubgroup subsetIl (pgroupS _ pR) ?subsetIr. Qed. Lemma normal_sylowP G : reflect (exists2 P : {group gT}, p.-Sylow(G) P & P <| G) (#|'Syl_p(G)| == 1%N). Proof. apply: (iffP idP) => [syl1 | [P sylP nPG]]; last first. by rewrite (card_Syl sylP) (setIidPl _) (indexgg, normal_norm). have [P sylP] := Sylow_exists p G; exists P => //. rewrite /normal (pHall_sub sylP); apply/setIidPl; apply/eqP. rewrite eqEcard subsetIl -(LagrangeI G 'N(P)) -indexgI /=. by rewrite -(card_Syl sylP) (eqP syl1) muln1. Qed. Lemma trivg_center_pgroup P : p.-group P -> 'Z(P) = 1 -> P :=: 1. Proof. move=> pP Z1; apply/eqP/idPn=> ntP. have{ntP} [p_pr p_dv_P _] := pgroup_pdiv pP ntP. suff: p %| #|'Z(P)| by rewrite Z1 cards1 gtnNdvd ?prime_gt1. by rewrite /center /dvdn -afixJ -pgroup_fix_mod // astabsJ normG. Qed. Lemma p2group_abelian P : p.-group P -> logn p #|P| <= 2 -> abelian P. Proof. move=> pP lePp2; pose Z := 'Z(P); have sZP: Z \subset P := center_sub P. case: (eqVneq Z 1); first by move/(trivg_center_pgroup pP)->; exact: abelian1. case/(pgroup_pdiv (pgroupS sZP pP)) => p_pr _ [k oZ]. apply: cyclic_center_factor_abelian. case: (eqVneq (P / Z) 1) => [-> |]; first exact: cyclic1. have pPq := quotient_pgroup 'Z(P) pP; case/(pgroup_pdiv pPq) => _ _ [j oPq]. rewrite prime_cyclic // oPq; case: j oPq lePp2 => //= j. rewrite card_quotient ?gfunctor.gFnorm //. by rewrite -(Lagrange sZP) lognM // => ->; rewrite oZ !pfactorK ?addnS. Qed. Lemma card_p2group_abelian P : prime p -> #|P| = (p ^ 2)%N -> abelian P. Proof. move=> primep oP; have pP: p.-group P by rewrite /pgroup oP pnat_exp pnat_id. by rewrite (p2group_abelian pP) // oP pfactorK. Qed. Lemma Sylow_transversal_gen (T : {set {group gT}}) G : (forall P, P \in T -> P \subset G) -> (forall p, p \in \pi(G) -> exists2 P, P \in T & p.-Sylow(G) P) -> << \bigcup_(P in T) P >> = G. Proof. move=> G_T T_G; apply/eqP; rewrite eqEcard gen_subG. apply/andP; split; first exact/bigcupsP. apply: dvdn_leq (cardG_gt0 _) _; apply/dvdn_partP=> // q /T_G[P T_P sylP]. by rewrite -(card_Hall sylP); apply: cardSg; rewrite sub_gen // bigcup_sup. Qed. Lemma Sylow_gen G : <<\bigcup_(P : {group gT} | Sylow G P) P>> = G. Proof. set T := [set P : {group gT} | Sylow G P]. rewrite -{2}(@Sylow_transversal_gen T G) => [|P | q _]. - by congr <<_>>; apply: eq_bigl => P; rewrite inE. - by rewrite inE => /and3P[]. by case: (Sylow_exists q G) => P sylP; exists P; rewrite // inE (p_Sylow sylP). Qed. End MoreSylow. Section SomeHall. Variable gT : finGroupType. Implicit Types (p : nat) (pi : nat_pred) (G H K P R : {group gT}). Lemma Hall_pJsub p pi G H P : pi.-Hall(G) H -> p \in pi -> P \subset G -> p.-group P -> exists2 x, x \in G & P :^ x \subset H. Proof. move=> hallH pi_p sPG pP. have [S sylS] := Sylow_exists p H; have sylS_G := subHall_Sylow hallH pi_p sylS. have [x Gx sPxS] := Sylow_Jsub sylS_G sPG pP; exists x => //. exact: subset_trans sPxS (pHall_sub sylS). Qed. Lemma Hall_psubJ p pi G H P : pi.-Hall(G) H -> p \in pi -> P \subset G -> p.-group P -> exists2 x, x \in G & P \subset H :^ x. Proof. move=> hallH pi_p sPG pP; have [x Gx sPxH] := Hall_pJsub hallH pi_p sPG pP. by exists x^-1; rewrite ?groupV -?sub_conjg. Qed. Lemma Hall_setI_normal pi G K H : K <| G -> pi.-Hall(G) H -> pi.-Hall(K) (H :&: K). Proof. move=> nsKG hallH; have [sHG piH _] := and3P hallH. have [sHK_H sHK_K] := (subsetIl H K, subsetIr H K). rewrite pHallE sHK_K /= -(part_pnat_id (pgroupS sHK_H piH)); apply/eqP. rewrite (widen_partn _ (subset_leq_card sHK_K)); apply: eq_bigr => p pi_p. have [P sylP] := Sylow_exists p H. have sylPK := Sylow_setI_normal nsKG (subHall_Sylow hallH pi_p sylP). rewrite -!p_part -(card_Hall sylPK); symmetry; apply: card_Hall. by rewrite (pHall_subl _ sHK_K) //= setIC setSI ?(pHall_sub sylP). Qed. Lemma coprime_mulG_setI_norm H G K R : K * R = G -> G \subset 'N(H) -> coprime #|K| #|R| -> (K :&: H) * (R :&: H) = G :&: H. Proof. move=> defG nHG coKR; apply/eqP; rewrite eqEcard mulG_subG /= -defG. rewrite !setSI ?mulG_subl ?mulG_subr //=. rewrite coprime_cardMg ?(coKR, coprimeSg (subsetIl _ _), coprime_sym) //=. pose pi := \pi(K); have piK: pi.-group K by exact: pgroup_pi. have pi'R: pi^'.-group R by rewrite /pgroup -coprime_pi' /=. have [hallK hallR] := coprime_mulpG_Hall defG piK pi'R. have nsHG: H :&: G <| G by rewrite /normal subsetIr normsI ?normG. rewrite -!(setIC H) defG -(partnC pi (cardG_gt0 _)). rewrite -(card_Hall (Hall_setI_normal nsHG hallR)) /= setICA. rewrite -(card_Hall (Hall_setI_normal nsHG hallK)) /= setICA. by rewrite -defG (setIidPl (mulG_subl _ _)) (setIidPl (mulG_subr _ _)). Qed. End SomeHall. Section Nilpotent. Variable gT : finGroupType. Implicit Types (G H K P L : {group gT}) (p q : nat). Lemma pgroup_nil p P : p.-group P -> nilpotent P. Proof. move: {2}_.+1 (ltnSn #|P|) => n. elim: n gT P => // n IHn pT P; rewrite ltnS=> lePn pP. have [Z1 | ntZ] := eqVneq 'Z(P) 1. by rewrite (trivg_center_pgroup pP Z1) nilpotent1. rewrite -quotient_center_nil IHn ?morphim_pgroup // (leq_trans _ lePn) //. rewrite card_quotient ?normal_norm ?center_normal // -divgS ?subsetIl //. by rewrite ltn_Pdiv // ltnNge -trivg_card_le1. Qed. Lemma pgroup_sol p P : p.-group P -> solvable P. Proof. by move/pgroup_nil; exact: nilpotent_sol. Qed. Lemma small_nil_class G : nil_class G <= 5 -> nilpotent G. Proof. move=> leK5; case: (ltnP 5 #|G|) => [lt5G | leG5 {leK5}]. by rewrite nilpotent_class (leq_ltn_trans leK5). apply: pgroup_nil (pdiv #|G|) _ _; apply/andP; split=> //. by case: #|G| leG5 => //; do 5!case=> //. Qed. Lemma nil_class2 G : (nil_class G <= 2) = (G^`(1) \subset 'Z(G)). Proof. rewrite subsetI der_sub; apply/idP/commG1P=> [clG2 | L3G1]. by apply/(lcn_nil_classP 2); rewrite ?small_nil_class ?(leq_trans clG2). by apply/(lcn_nil_classP 2) => //; apply/lcnP; exists 2. Qed. Lemma nil_class3 G : (nil_class G <= 3) = ('L_3(G) \subset 'Z(G)). Proof. rewrite subsetI lcn_sub; apply/idP/commG1P=> [clG3 | L4G1]. by apply/(lcn_nil_classP 3); rewrite ?small_nil_class ?(leq_trans clG3). by apply/(lcn_nil_classP 3) => //; apply/lcnP; exists 3. Qed. Lemma nilpotent_maxp_normal pi G H : nilpotent G -> [max H | pi.-subgroup(G) H] -> H <| G. Proof. move=> nilG /maxgroupP[/andP[sHG piH] maxH]. have nHN: H <| 'N_G(H) by rewrite normal_subnorm. have{maxH} hallH: pi.-Hall('N_G(H)) H. apply: normal_max_pgroup_Hall => //; apply/maxgroupP. rewrite /psubgroup normal_sub // piH; split=> // K. by rewrite subsetI -andbA andbCA => /andP[_]; exact: maxH. rewrite /normal sHG; apply/setIidPl; symmetry. apply: nilpotent_sub_norm; rewrite ?subsetIl ?setIS //=. by rewrite char_norms // -{1}(normal_Hall_pcore hallH) // pcore_char. Qed. Lemma nilpotent_Hall_pcore pi G H : nilpotent G -> pi.-Hall(G) H -> H :=: 'O_pi(G). Proof. move=> nilG hallH; have maxH := Hall_max hallH; apply/eqP. rewrite eqEsubset pcore_max ?(pHall_pgroup hallH) //. by rewrite (normal_sub_max_pgroup maxH) ?pcore_pgroup ?pcore_normal. exact: nilpotent_maxp_normal maxH. Qed. Lemma nilpotent_pcore_Hall pi G : nilpotent G -> pi.-Hall(G) 'O_pi(G). Proof. move=> nilG; case: (@maxgroup_exists _ (psubgroup pi G) 1) => [|H maxH _]. by rewrite /psubgroup sub1G pgroup1. have hallH := normal_max_pgroup_Hall maxH (nilpotent_maxp_normal nilG maxH). by rewrite -(nilpotent_Hall_pcore nilG hallH). Qed. Lemma nilpotent_pcoreC pi G : nilpotent G -> 'O_pi(G) \x 'O_pi^'(G) = G. Proof. move=> nilG; have trO: 'O_pi(G) :&: 'O_pi^'(G) = 1. by apply: coprime_TIg; apply: (@pnat_coprime pi); exact: pcore_pgroup. rewrite dprodE //. apply/eqP; rewrite eqEcard mul_subG ?pcore_sub // (TI_cardMg trO). by rewrite !(card_Hall (nilpotent_pcore_Hall _ _)) // partnC ?leqnn. rewrite (sameP commG1P trivgP) -trO subsetI commg_subl commg_subr. by rewrite !(subset_trans (pcore_sub _ _)) ?normal_norm ?pcore_normal. Qed. Lemma sub_nilpotent_cent2 H K G : nilpotent G -> K \subset G -> H \subset G -> coprime #|K| #|H| -> H \subset 'C(K). Proof. move=> nilG sKG sHG; rewrite coprime_pi' // => p'H. have sub_Gp := sub_Hall_pcore (nilpotent_pcore_Hall _ nilG). have [_ _ cGpp' _] := dprodP (nilpotent_pcoreC \pi(K) nilG). by apply: centSS cGpp'; rewrite sub_Gp ?pgroup_pi. Qed. Lemma pi_center_nilpotent G : nilpotent G -> \pi('Z(G)) = \pi(G). Proof. move=> nilG; apply/eq_piP => /= p. apply/idP/idP=> [|pG]; first exact: (piSg (center_sub _)). move: (pG); rewrite !mem_primes !cardG_gt0; case/andP=> p_pr _. pose Z := 'O_p(G) :&: 'Z(G); have ntZ: Z != 1. rewrite meet_center_nil ?pcore_normal // trivg_card_le1 -ltnNge. rewrite (card_Hall (nilpotent_pcore_Hall p nilG)) p_part. by rewrite (ltn_exp2l 0 _ (prime_gt1 p_pr)) logn_gt0. have pZ: p.-group Z := pgroupS (subsetIl _ _) (pcore_pgroup _ _). have{ntZ pZ} [_ pZ _] := pgroup_pdiv pZ ntZ. by rewrite p_pr (dvdn_trans pZ) // cardSg ?subsetIr. Qed. Lemma Sylow_subnorm p G P : p.-Sylow('N_G(P)) P = p.-Sylow(G) P. Proof. apply/idP/idP=> sylP; last first. apply: pHall_subl (subsetIl _ _) (sylP). by rewrite subsetI normG (pHall_sub sylP). have [/subsetIP[sPG sPN] pP _] := and3P sylP. have [Q sylQ sPQ] := Sylow_superset sPG pP; have [sQG pQ _] := and3P sylQ. rewrite -(nilpotent_sub_norm (pgroup_nil pQ) sPQ) {sylQ}//. rewrite subEproper eq_sym eqEcard subsetI sPQ sPN dvdn_leq //. rewrite -(part_pnat_id (pgroupS (subsetIl _ _) pQ)) (card_Hall sylP). by rewrite partn_dvd // cardSg ?setSI. Qed. End Nilpotent. Lemma nil_class_pgroup (gT : finGroupType) (p : nat) (P : {group gT}) : p.-group P -> nil_class P <= maxn 1 (logn p #|P|).-1. Proof. move=> pP; move def_c: (nil_class P) => c. elim: c => // c IHc in gT P def_c pP *; set e := logn p _. have nilP := pgroup_nil pP; have sZP := center_sub P. have [e_le2 | e_gt2] := leqP e 2. by rewrite -def_c leq_max nil_class1 (p2group_abelian pP). have pPq: p.-group (P / 'Z(P)) by exact: quotient_pgroup. rewrite -(subnKC e_gt2) ltnS (leq_trans (IHc _ _ _ pPq)) //. by rewrite nil_class_quotient_center ?def_c. rewrite geq_max /= -add1n -leq_subLR -subn1 -subnDA -subSS leq_sub2r //. rewrite ltn_log_quotient //= -(setIidPr sZP) meet_center_nil //. by rewrite -nil_class0 def_c. Qed. Definition Zgroup (gT : finGroupType) (A : {set gT}) := [forall (V : {group gT} | Sylow A V), cyclic V]. Section Zgroups. Variables (gT rT : finGroupType) (D : {group gT}) (f : {morphism D >-> rT}). Implicit Types G H K : {group gT}. Lemma ZgroupS G H : H \subset G -> Zgroup G -> Zgroup H. Proof. move=> sHG /forallP zgG; apply/forall_inP=> V /SylowP[p p_pr /and3P[sVH]]. case/(Sylow_superset (subset_trans sVH sHG))=> P sylP sVP _. by have:= zgG P; rewrite (p_Sylow sylP); apply: cyclicS. Qed. Lemma morphim_Zgroup G : Zgroup G -> Zgroup (f @* G). Proof. move=> zgG; wlog sGD: G zgG / G \subset D. by rewrite -morphimIdom; apply; rewrite (ZgroupS _ zgG, subsetIl) ?subsetIr. apply/forall_inP=> fV /SylowP[p pr_p sylfV]. have [P sylP] := Sylow_exists p G. have [|z _ ->] := @Sylow_trans p _ _ (f @* P)%G _ _ sylfV. by apply: morphim_pHall (sylP); apply: subset_trans (pHall_sub sylP) sGD. by rewrite cyclicJ morphim_cyclic ?(forall_inP zgG) //; apply/SylowP; exists p. Qed. Lemma nil_Zgroup_cyclic G : Zgroup G -> nilpotent G -> cyclic G. Proof. elim: {G}_.+1 {-2}G (ltnSn #|G|) => // n IHn G; rewrite ltnS => leGn ZgG nilG. have [->|[p pr_p pG]] := trivgVpdiv G; first by rewrite -cycle1 cycle_cyclic. have /dprodP[_ defG Cpp' _] := nilpotent_pcoreC p nilG. have /cyclicP[x def_p]: cyclic 'O_p(G). have:= forallP ZgG 'O_p(G)%G. by rewrite (p_Sylow (nilpotent_pcore_Hall p nilG)). have /cyclicP[x' def_p']: cyclic 'O_p^'(G). have sp'G := pcore_sub p^' G. apply: IHn (leq_trans _ leGn) (ZgroupS sp'G _) (nilpotentS sp'G _) => //. rewrite proper_card // properEneq sp'G andbT; case: eqP => //= def_p'. by have:= pcore_pgroup p^' G; rewrite def_p' /pgroup p'natE ?pG. apply/cyclicP; exists (x * x'); rewrite -{}defG def_p def_p' cycleM //. by red; rewrite -(centsP Cpp') // (def_p, def_p') cycle_id. rewrite /order -def_p -def_p' (@pnat_coprime p) //; exact: pcore_pgroup. Qed. End Zgroups. Arguments Scope Zgroup [_ group_scope]. Prenex Implicits Zgroup. Section NilPGroups. Variables (p : nat) (gT : finGroupType). Implicit Type G P N : {group gT}. (* B & G 1.22 p.9 *) Lemma normal_pgroup r P N : p.-group P -> N <| P -> r <= logn p #|N| -> exists Q : {group gT}, [/\ Q \subset N, Q <| P & #|Q| = (p ^ r)%N]. Proof. elim: r gT P N => [|r IHr] gTr P N pP nNP le_r. by exists (1%G : {group gTr}); rewrite sub1G normal1 cards1. have [NZ_1 | ntNZ] := eqVneq (N :&: 'Z(P)) 1. by rewrite (TI_center_nil (pgroup_nil pP)) // cards1 logn1 in le_r. have: p.-group (N :&: 'Z(P)) by apply: pgroupS pP; rewrite /= setICA subsetIl. case/pgroup_pdiv=> // p_pr /Cauchy[// | z]. rewrite -cycle_subG !subsetI => /and3P[szN szP cPz] ozp _. have{cPz} nzP: P \subset 'N(<[z]>) by rewrite cents_norm // centsC. have: N / <[z]> <| P / <[z]> by rewrite morphim_normal. case/IHr=> [||Qb [sQNb nQPb]]; first exact: morphim_pgroup. rewrite card_quotient ?(subset_trans (normal_sub nNP)) // -ltnS. apply: (leq_trans le_r); rewrite -(Lagrange szN) [#|_|]ozp. by rewrite lognM // ?prime_gt0 // logn_prime ?eqxx. case/(inv_quotientN _): nQPb sQNb => [|Q -> szQ nQP]; first exact/andP. have nzQ := subset_trans (normal_sub nQP) nzP. rewrite quotientSGK // card_quotient // => sQN izQ. by exists Q; split=> //; rewrite expnS -izQ -ozp Lagrange. Qed. Theorem Baer_Suzuki x G : x \in G -> (forall y, y \in G -> p.-group <<[set x; x ^ y]>>) -> x \in 'O_p(G). Proof. elim: {G}_.+1 {-2}G x (ltnSn #|G|) => // n IHn G x; rewrite ltnS. set E := x ^: G => leGn Gx pE. have{pE} pE: {in E &, forall x1 x2, p.-group <<[set x1; x2]>>}. move=> _ _ /imsetP[y1 Gy1 ->] /imsetP[y2 Gy2 ->]. rewrite -(mulgKV y1 y2) conjgM -2!conjg_set1 -conjUg genJ pgroupJ. by rewrite pE // groupMl ?groupV. have sEG: <> \subset G by rewrite gen_subG class_subG. have nEG: G \subset 'N(E) by exact: class_norm. have Ex: x \in E by exact: class_refl. have [P Px sylP]: exists2 P : {group gT}, x \in P & p.-Sylow(<>) P. have sxxE: <<[set x; x]>> \subset <> by rewrite genS // setUid sub1set. have{sxxE} [P sylP sxxP] := Sylow_superset sxxE (pE _ _ Ex Ex). by exists P => //; rewrite (subsetP sxxP) ?mem_gen ?setU11. case sEP: (E \subset P). apply: subsetP Ex; rewrite -gen_subG; apply: pcore_max. by apply: pgroupS (pHall_pgroup sylP); rewrite gen_subG. by rewrite /normal gen_subG class_subG // norms_gen. pose P_yD D := [pred y in E :\: P | p.-group <>]. pose P_D := [pred D : {set gT} | D \subset P :&: E & [exists y, P_yD D y]]. have{Ex Px}: P_D [set x]. rewrite /= sub1set inE Px Ex; apply/existsP=> /=. by case/subsetPn: sEP => y Ey Py; exists y; rewrite inE Ey Py pE. case/(@maxset_exists _ P_D)=> D /maxsetP[]; rewrite {P_yD P_D}/=. rewrite subsetI sub1set -andbA => /and3P[sDP sDE /existsP[y0]]. set B := _ |: D; rewrite inE -andbA => /and3P[Py0 Ey0 pB] maxD Dx. have sDgE: D \subset <> by exact: sub_gen. have sDG: D \subset G by exact: subset_trans sEG. have sBE: B \subset E by rewrite subUset sub1set Ey0. have sBG: <> \subset G by exact: subset_trans (genS _) sEG. have sDB: D \subset B by rewrite subsetUr. have defD: D :=: P :&: <> :&: E. apply/eqP; rewrite eqEsubset ?subsetI sDP sDE sub_gen //=. apply/setUidPl; apply: maxD; last exact: subsetUl. rewrite subUset subsetI sDP sDE setIAC subsetIl. apply/existsP; exists y0; rewrite inE Py0 Ey0 /= setUA -/B. by rewrite -[<<_>>]joing_idl joingE setKI genGid. have nDD: D \subset 'N(D). apply/subsetP=> z Dz; rewrite inE defD. apply/subsetP=> _ /imsetP[y /setIP[PBy Ey] ->]. rewrite inE groupJ // ?inE ?(subsetP sDP) ?mem_gen ?setU1r //= memJ_norm //. exact: (subsetP (subset_trans sDG nEG)). case nDG: (G \subset 'N(D)). apply: subsetP Dx; rewrite -gen_subG pcore_max ?(pgroupS (genS _) pB) //. by rewrite /normal gen_subG sDG norms_gen. have{n leGn IHn nDG} pN: p.-group <<'N_E(D)>>. apply: pgroupS (pcore_pgroup p 'N_G(D)); rewrite gen_subG /=. apply/subsetP=> x1 /setIP[Ex1 Nx1]; apply: IHn => [||y Ny]. - apply: leq_trans leGn; rewrite proper_card // /proper subsetIl. by rewrite subsetI nDG andbF. - by rewrite inE Nx1 (subsetP sEG) ?mem_gen. have Ex1y: x1 ^ y \in E. by rewrite -mem_conjgV (normsP nEG) // groupV; case/setIP: Ny. apply: pgroupS (genS _) (pE _ _ Ex1 Ex1y). by apply/subsetP=> u; rewrite !inE. have [y1 Ny1 Py1]: exists2 y1, y1 \in 'N_E(D) & y1 \notin P. case sNN: ('N_<>('N_<>(D)) \subset 'N_<>(D)). exists y0 => //; have By0: y0 \in <> by rewrite mem_gen ?setU11. rewrite inE Ey0 -By0 -in_setI. by rewrite -['N__(D)](nilpotent_sub_norm (pgroup_nil pB)) ?subsetIl. case/subsetPn: sNN => z /setIP[Bz NNz]; rewrite inE Bz inE. case/subsetPn=> y; rewrite mem_conjg => Dzy Dy. have:= Dzy; rewrite {1}defD; do 2![case/setIP]=> _ Bzy Ezy. have Ey: y \in E by rewrite -(normsP nEG _ (subsetP sBG z Bz)) mem_conjg. have /setIP[By Ny]: y \in 'N_<>(D). by rewrite -(normP NNz) mem_conjg inE Bzy ?(subsetP nDD). exists y; first by rewrite inE Ey. by rewrite defD 2!inE Ey By !andbT in Dy. have [y2 Ny2 Dy2]: exists2 y2, y2 \in 'N_(P :&: E)(D) & y2 \notin D. case sNN: ('N_P('N_P(D)) \subset 'N_P(D)). have [z /= Ez sEzP] := Sylow_Jsub sylP (genS sBE) pB. have Gz: z \in G by exact: subsetP Ez. have /subsetPn[y Bzy Dy]: ~~ (B :^ z \subset D). apply/negP; move/subset_leq_card; rewrite cardJg cardsU1. by rewrite {1}defD 2!inE (negPf Py0) ltnn. exists y => //; apply: subsetP Bzy. rewrite -setIA setICA subsetI sub_conjg (normsP nEG) ?groupV // sBE. have nilP := pgroup_nil (pHall_pgroup sylP). by rewrite -['N__(_)](nilpotent_sub_norm nilP) ?subsetIl // -gen_subG genJ. case/subsetPn: sNN => z /setIP[Pz NNz]; rewrite 2!inE Pz. case/subsetPn=> y Dzy Dy; exists y => //; apply: subsetP Dzy. rewrite -setIA setICA subsetI sub_conjg (normsP nEG) ?groupV //. by rewrite sDE -(normP NNz); rewrite conjSg subsetI sDP. apply: subsetP Pz; exact: (subset_trans (pHall_sub sylP)). suff{Dy2} Dy2D: y2 |: D = D by rewrite -Dy2D setU11 in Dy2. apply: maxD; last by rewrite subsetUr. case/setIP: Ny2 => PEy2 Ny2; case/setIP: Ny1 => Ey1 Ny1. rewrite subUset sub1set PEy2 subsetI sDP sDE. apply/existsP; exists y1; rewrite inE Ey1 Py1; apply: pgroupS pN. rewrite genS // !subUset !sub1set !in_setI Ey1 Ny1. by case/setIP: PEy2 => _ ->; rewrite Ny2 subsetI sDE. Qed. End NilPGroups. mathcomp-1.5/theories/rat.v0000644000175000017500000006764412307636117015001 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq choice fintype. Require Import bigop ssralg div ssrnum ssrint. (******************************************************************************) (* This file defines a datatype for rational numbers and equips it with a *) (* structure of archimedean, real field, with int and nat declared as closed *) (* subrings. *) (* rat == the type of rational number, with single constructor Rat *) (* Rat p h == the element of type rat build from p a pair of integers and*) (* h a proof of (0 < p.2) && coprime `|p.1| `|p.2| *) (* n%:Q == explicit cast from int to rat, postfix notation for the *) (* ratz constant *) (* numq r == numerator of (r : rat) *) (* denq r == denominator of (r : rat) *) (* x \is a Qint == x is an element of rat whose denominator is equal to 1 *) (* x \is a Qnat == x is a positive element of rat whose denominator is equal *) (* to 1 *) (* ratr x == generic embedding of (r : R) into an arbitrary unitring. *) (******************************************************************************) Import GRing.Theory. Import Num.Theory. Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Local Open Scope ring_scope. Local Notation sgr := Num.sg. Record rat : Set := Rat { valq : (int * int) ; _ : (0 < valq.2) && coprime `|valq.1| `|valq.2| }. Bind Scope ring_scope with rat. Delimit Scope rat_scope with Q. Definition ratz (n : int) := @Rat (n, 1) (coprimen1 _). (* Coercion ratz (n : int) := @Rat (n, 1) (coprimen1 _). *) Canonical rat_subType := Eval hnf in [subType for valq]. Definition rat_eqMixin := [eqMixin of rat by <:]. Canonical rat_eqType := EqType rat rat_eqMixin. Definition rat_choiceMixin := [choiceMixin of rat by <:]. Canonical rat_choiceType := ChoiceType rat rat_choiceMixin. Definition rat_countMixin := [countMixin of rat by <:]. Canonical rat_countType := CountType rat rat_countMixin. Canonical rat_subCountType := [subCountType of rat]. Definition numq x := nosimpl ((valq x).1). Definition denq x := nosimpl ((valq x).2). Lemma denq_gt0 x : 0 < denq x. Proof. by rewrite /denq; case: x=> [[a b] /= /andP []]. Qed. Hint Resolve denq_gt0. Definition denq_ge0 x := ltrW (denq_gt0 x). Lemma denq_lt0 x : (denq x < 0) = false. Proof. by rewrite ltr_gtF. Qed. Lemma denq_neq0 x : denq x != 0. Proof. by rewrite /denq gtr_eqF ?denq_gt0. Qed. Hint Resolve denq_neq0. Lemma denq_eq0 x : (denq x == 0) = false. Proof. exact: negPf (denq_neq0 _). Qed. Lemma coprime_num_den x : coprime `|numq x| `|denq x|. Proof. by rewrite /numq /denq; case: x=> [[a b] /= /andP []]. Qed. Fact RatK x P : @Rat (numq x, denq x) P = x. Proof. by move:x P => [[a b] P'] P; apply: val_inj. Qed. Fact fracq_subproof : forall x : int * int, let n := if x.2 == 0 then 0 else (-1) ^ ((x.2 < 0) (+) (x.1 < 0)) * (`|x.1| %/ gcdn `|x.1| `|x.2|)%:Z in let d := if x.2 == 0 then 1 else (`|x.2| %/ gcdn `|x.1| `|x.2|)%:Z in (0 < d) && (coprime `|n| `|d|). Proof. move=> [m n] /=; case: (altP (n =P 0))=> [//|n0]. rewrite ltz_nat divn_gt0 ?gcdn_gt0 ?absz_gt0 ?n0 ?orbT //. rewrite dvdn_leq ?absz_gt0 ?dvdn_gcdr //= !abszM absz_sign mul1n. have [->|m0] := altP (m =P 0); first by rewrite div0n gcd0n divnn absz_gt0 n0. move: n0 m0; rewrite -!absz_gt0 absz_nat. move: `|_|%N `|_|%N => {m n} [|m] [|n] // _ _. rewrite /coprime -(@eqn_pmul2l (gcdn m.+1 n.+1)) ?gcdn_gt0 //. rewrite muln_gcdr; do 2!rewrite muln_divCA ?(dvdn_gcdl, dvdn_gcdr) ?divnn //. by rewrite ?gcdn_gt0 ?muln1. Qed. Definition fracq (x : int * int) := nosimpl (@Rat (_, _) (fracq_subproof x)). Fact ratz_frac n : ratz n = fracq (n, 1). Proof. by apply: val_inj; rewrite /= gcdn1 !divn1 abszE mulr_sign_norm. Qed. Fact valqK x : fracq (valq x) = x. Proof. move:x => [[n d] /= Pnd]; apply: val_inj=> /=. move: Pnd; rewrite /coprime /fracq /=; case/andP=> hd; move/eqP=> hnd. by rewrite ltr_gtF ?gtr_eqF //= hnd !divn1 mulz_sign_abs abszE gtr0_norm. Qed. Fact scalq_key : unit. Proof. by []. Qed. Definition scalq_def x := sgr x.2 * (gcdn `|x.1| `|x.2|)%:Z. Definition scalq := locked_with scalq_key scalq_def. Canonical scalq_unlockable := [unlockable fun scalq]. Fact scalq_eq0 x : (scalq x == 0) = (x.2 == 0). Proof. case: x => n d; rewrite unlock /= mulf_eq0 sgr_eq0 /= eqz_nat. rewrite -[gcdn _ _ == 0%N]negbK -lt0n gcdn_gt0 ?absz_gt0 [X in ~~ X]orbC. by case: sgrP. Qed. Lemma sgr_scalq x : sgr (scalq x) = sgr x.2. Proof. rewrite unlock sgrM sgr_id -[(gcdn _ _)%:Z]intz sgr_nat. by rewrite -lt0n gcdn_gt0 ?absz_gt0 orbC; case: sgrP; rewrite // mul0r. Qed. Lemma signr_scalq x : (scalq x < 0) = (x.2 < 0). Proof. by rewrite -!sgr_cp0 sgr_scalq. Qed. Lemma scalqE x : x.2 != 0 -> scalq x = (-1) ^+ (x.2 < 0)%R * (gcdn `|x.1| `|x.2|)%:Z. Proof. by rewrite unlock; case: sgrP. Qed. Fact valq_frac x : x.2 != 0 -> x = (scalq x * numq (fracq x), scalq x * denq (fracq x)). Proof. case: x => [n d] /= d_neq0; rewrite /denq /numq scalqE //= (negPf d_neq0). rewrite mulr_signM -mulrA -!PoszM addKb. do 2!rewrite muln_divCA ?(dvdn_gcdl, dvdn_gcdr) // divnn. by rewrite gcdn_gt0 !absz_gt0 d_neq0 orbT !muln1 !mulz_sign_abs. Qed. Definition zeroq := fracq (0, 1). Definition oneq := fracq (1, 1). Fact frac0q x : fracq (0, x) = zeroq. Proof. apply: val_inj; rewrite //= div0n !gcd0n !mulr0 !divnn. by have [//|x_neq0] := altP eqP; rewrite absz_gt0 x_neq0. Qed. Fact fracq0 x : fracq (x, 0) = zeroq. Proof. exact/eqP. Qed. CoInductive fracq_spec (x : int * int) : int * int -> rat -> Type := | FracqSpecN of x.2 = 0 : fracq_spec x (x.1, 0) zeroq | FracqSpecP k fx of k != 0 : fracq_spec x (k * numq fx, k * denq fx) fx. Fact fracqP x : fracq_spec x x (fracq x). Proof. case: x => n d /=; have [d_eq0 | d_neq0] := eqVneq d 0. by rewrite d_eq0 fracq0; constructor. by rewrite {2}[(_, _)]valq_frac //; constructor; rewrite scalq_eq0. Qed. Lemma rat_eqE x y : (x == y) = (numq x == numq y) && (denq x == denq y). Proof. rewrite -val_eqE [val x]surjective_pairing [val y]surjective_pairing /=. by rewrite xpair_eqE. Qed. Lemma sgr_denq x : sgr (denq x) = 1. Proof. by apply/eqP; rewrite sgr_cp0. Qed. Lemma normr_denq x : `|denq x| = denq x. Proof. by rewrite gtr0_norm. Qed. Lemma absz_denq x : `|denq x|%N = denq x :> int. Proof. by rewrite abszE normr_denq. Qed. Lemma rat_eq x y : (x == y) = (numq x * denq y == numq y * denq x). Proof. symmetry; rewrite rat_eqE andbC. have [->|] /= := altP (denq _ =P _); first by rewrite (inj_eq (mulIf _)). apply: contraNF => /eqP hxy; rewrite -absz_denq -[X in _ == X]absz_denq. rewrite eqz_nat /= eqn_dvd. rewrite -(@Gauss_dvdr _ `|numq x|) 1?coprime_sym ?coprime_num_den // andbC. rewrite -(@Gauss_dvdr _ `|numq y|) 1?coprime_sym ?coprime_num_den //. by rewrite -!abszM hxy -{1}hxy !abszM !dvdn_mull ?dvdnn. Qed. Fact fracq_eq x y : x.2 != 0 -> y.2 != 0 -> (fracq x == fracq y) = (x.1 * y.2 == y.1 * x.2). Proof. case: fracqP=> //= u fx u_neq0 _; case: fracqP=> //= v fy v_neq0 _; symmetry. rewrite [X in (_ == X)]mulrC mulrACA [X in (_ == X)]mulrACA. by rewrite [denq _ * _]mulrC (inj_eq (mulfI _)) ?mulf_neq0 // rat_eq. Qed. Fact fracq_eq0 x : (fracq x == zeroq) = (x.1 == 0) || (x.2 == 0). Proof. move: x=> [n d] /=; have [->|d0] := altP (d =P 0). by rewrite fracq0 eqxx orbT. by rewrite orbF fracq_eq ?d0 //= mulr1 mul0r. Qed. Fact fracqMM x n d : x != 0 -> fracq (x * n, x * d) = fracq (n, d). Proof. move=> x_neq0; apply/eqP. have [->|d_neq0] := eqVneq d 0; first by rewrite mulr0 !fracq0. by rewrite fracq_eq ?mulf_neq0 //= mulrCA mulrA. Qed. Definition addq_subdef (x y : int * int) := (x.1 * y.2 + y.1 * x.2, x.2 * y.2). Definition addq (x y : rat) := nosimpl fracq (addq_subdef (valq x) (valq y)). Definition oppq_subdef (x : int * int) := (- x.1, x.2). Definition oppq (x : rat) := nosimpl fracq (oppq_subdef (valq x)). Fact addq_subdefC : commutative addq_subdef. Proof. by move=> x y; rewrite /addq_subdef addrC [_.2 * _]mulrC. Qed. Fact addq_subdefA : associative addq_subdef. Proof. move=> x y z; rewrite /addq_subdef. by rewrite !mulrA !mulrDl addrA ![_ * x.2]mulrC !mulrA. Qed. Fact addq_frac x y : x.2 != 0 -> y.2 != 0 -> (addq (fracq x) (fracq y)) = fracq (addq_subdef x y). Proof. case: fracqP => // u fx u_neq0 _; case: fracqP => // v fy v_neq0 _. rewrite /addq_subdef /= ![(_ * numq _) * _]mulrACA [(_ * denq _) * _]mulrACA. by rewrite [v * _]mulrC -mulrDr fracqMM ?mulf_neq0. Qed. Fact ratzD : {morph ratz : x y / x + y >-> addq x y}. Proof. by move=> x y /=; rewrite !ratz_frac addq_frac // /addq_subdef /= !mulr1. Qed. Fact oppq_frac x : oppq (fracq x) = fracq (oppq_subdef x). Proof. rewrite /oppq_subdef; case: fracqP => /= [|u fx u_neq0]. by rewrite fracq0. by rewrite -mulrN fracqMM. Qed. Fact ratzN : {morph ratz : x / - x >-> oppq x}. Proof. by move=> x /=; rewrite !ratz_frac oppq_frac // /add /= !mulr1. Qed. Fact addqC : commutative addq. Proof. by move=> x y; rewrite /addq /=; rewrite addq_subdefC. Qed. Fact addqA : associative addq. Proof. move=> x y z; rewrite -[x]valqK -[y]valqK -[z]valqK. by rewrite !addq_frac ?mulf_neq0 ?denq_neq0 // addq_subdefA. Qed. Fact add0q : left_id zeroq addq. Proof. move=> x; rewrite -[x]valqK addq_frac ?denq_neq0 // /addq_subdef /=. by rewrite mul0r add0r mulr1 mul1r -surjective_pairing. Qed. Fact addNq : left_inverse (fracq (0, 1)) oppq addq. Proof. move=> x; rewrite -[x]valqK !(addq_frac, oppq_frac) ?denq_neq0 //. rewrite /addq_subdef /oppq_subdef //= mulNr addNr; apply/eqP. by rewrite fracq_eq ?mulf_neq0 ?denq_neq0 //= !mul0r. Qed. Definition rat_ZmodMixin := ZmodMixin addqA addqC add0q addNq. Canonical rat_ZmodType := ZmodType rat rat_ZmodMixin. Definition mulq_subdef (x y : int * int) := nosimpl (x.1 * y.1, x.2 * y.2). Definition mulq (x y : rat) := nosimpl fracq (mulq_subdef (valq x) (valq y)). Fact mulq_subdefC : commutative mulq_subdef. Proof. by move=> x y; rewrite /mulq_subdef mulrC [_ * x.2]mulrC. Qed. Fact mul_subdefA : associative mulq_subdef. Proof. by move=> x y z; rewrite /mulq_subdef !mulrA. Qed. Definition invq_subdef (x : int * int) := nosimpl (x.2, x.1). Definition invq (x : rat) := nosimpl fracq (invq_subdef (valq x)). Fact mulq_frac x y : (mulq (fracq x) (fracq y)) = fracq (mulq_subdef x y). Proof. rewrite /mulq_subdef; case: fracqP => /= [|u fx u_neq0]. by rewrite mul0r fracq0 /mulq /mulq_subdef /= mul0r frac0q. case: fracqP=> /= [|v fy v_neq0]. by rewrite mulr0 fracq0 /mulq /mulq_subdef /= mulr0 frac0q. by rewrite ![_ * (v * _)]mulrACA fracqMM ?mulf_neq0. Qed. Fact ratzM : {morph ratz : x y / x * y >-> mulq x y}. Proof. by move=> x y /=; rewrite !ratz_frac mulq_frac // /= !mulr1. Qed. Fact invq_frac x : x.1 != 0 -> x.2 != 0 -> invq (fracq x) = fracq (invq_subdef x). Proof. by rewrite /invq_subdef; case: fracqP => // k {x} x k0; rewrite fracqMM. Qed. Fact mulqC : commutative mulq. Proof. by move=> x y; rewrite /mulq mulq_subdefC. Qed. Fact mulqA : associative mulq. Proof. by move=> x y z; rewrite -[x]valqK -[y]valqK -[z]valqK !mulq_frac mul_subdefA. Qed. Fact mul1q : left_id oneq mulq. Proof. move=> x; rewrite -[x]valqK; rewrite mulq_frac /mulq_subdef. by rewrite !mul1r -surjective_pairing. Qed. Fact mulq_addl : left_distributive mulq addq. Proof. move=> x y z; rewrite -[x]valqK -[y]valqK -[z]valqK /=. rewrite !(mulq_frac, addq_frac) ?mulf_neq0 ?denq_neq0 //=. apply/eqP; rewrite fracq_eq ?mulf_neq0 ?denq_neq0 //= !mulrDl; apply/eqP. by rewrite !mulrA ![_ * (valq z).1]mulrC !mulrA ![_ * (valq x).2]mulrC !mulrA. Qed. Fact nonzero1q : oneq != zeroq. Proof. by []. Qed. Definition rat_comRingMixin := ComRingMixin mulqA mulqC mul1q mulq_addl nonzero1q. Canonical rat_Ring := Eval hnf in RingType rat rat_comRingMixin. Canonical rat_comRing := Eval hnf in ComRingType rat mulqC. Fact mulVq x : x != 0 -> mulq (invq x) x = 1. Proof. rewrite -[x]valqK fracq_eq ?denq_neq0 //= mulr1 mul0r=> nx0. rewrite !(mulq_frac, invq_frac) ?denq_neq0 //. by apply/eqP; rewrite fracq_eq ?mulf_neq0 ?denq_neq0 //= mulr1 mul1r mulrC. Qed. Fact invq0 : invq 0 = 0. Proof. by apply/eqP. Qed. Definition RatFieldUnitMixin := FieldUnitMixin mulVq invq0. Canonical rat_unitRing := Eval hnf in UnitRingType rat RatFieldUnitMixin. Canonical rat_comUnitRing := Eval hnf in [comUnitRingType of rat]. Fact rat_field_axiom : GRing.Field.mixin_of rat_unitRing. Proof. exact. Qed. Definition RatFieldIdomainMixin := (FieldIdomainMixin rat_field_axiom). Canonical rat_iDomain := Eval hnf in IdomainType rat (FieldIdomainMixin rat_field_axiom). Canonical rat_fieldType := FieldType rat rat_field_axiom. Lemma numq_eq0 x : (numq x == 0) = (x == 0). Proof. rewrite -[x]valqK fracq_eq0; case: fracqP=> /= [|k {x} x k0]. by rewrite eqxx orbT. by rewrite !mulf_eq0 (negPf k0) /= denq_eq0 orbF. Qed. Notation "n %:Q" := ((n : int)%:~R : rat) (at level 2, left associativity, format "n %:Q") : ring_scope. Hint Resolve denq_neq0 denq_gt0 denq_ge0. Definition subq (x y : rat) : rat := (addq x (oppq y)). Definition divq (x y : rat) : rat := (mulq x (invq y)). Notation "0" := zeroq : rat_scope. Notation "1" := oneq : rat_scope. Infix "+" := addq : rat_scope. Notation "- x" := (oppq x) : rat_scope. Infix "*" := mulq : rat_scope. Notation "x ^-1" := (invq x) : rat_scope. Infix "-" := subq : rat_scope. Infix "/" := divq : rat_scope. (* ratz should not be used, %:Q should be used instead *) Lemma ratzE n : ratz n = n%:Q. Proof. elim: n=> [|n ihn|n ihn]; first by rewrite mulr0z ratz_frac. by rewrite intS mulrzDl ratzD ihn. by rewrite intS opprD mulrzDl ratzD ihn. Qed. Lemma numq_int n : numq n%:Q = n. Proof. by rewrite -ratzE. Qed. Lemma denq_int n : denq n%:Q = 1. Proof. by rewrite -ratzE. Qed. Lemma rat0 : 0%:Q = 0. Proof. by []. Qed. Lemma rat1 : 1%:Q = 1. Proof. by []. Qed. Lemma numqN x : numq (- x) = - numq x. Proof. rewrite /numq; case: x=> [[a b] /= /andP [hb]]; rewrite /coprime=> /eqP hab. by rewrite ltr_gtF ?gtr_eqF // {2}abszN hab divn1 mulz_sign_abs. Qed. Lemma denqN x : denq (- x) = denq x. Proof. rewrite /denq; case: x=> [[a b] /= /andP [hb]]; rewrite /coprime=> /eqP hab. by rewrite gtr_eqF // abszN hab divn1 gtz0_abs. Qed. (* Will be subsumed by pnatr_eq0 *) Fact intq_eq0 n : (n%:~R == 0 :> rat) = (n == 0)%N. Proof. by rewrite -ratzE /ratz rat_eqE /numq /denq /= mulr0 eqxx andbT. Qed. (* fracq should never appear, its canonical form is _%:Q / _%:Q *) Lemma fracqE x : fracq x = x.1%:Q / x.2%:Q. Proof. move:x => [m n] /=. case n0: (n == 0); first by rewrite (eqP n0) fracq0 rat0 invr0 mulr0. rewrite -[m%:Q]valqK -[n%:Q]valqK. rewrite [_^-1]invq_frac ?(denq_neq0, numq_eq0, n0, intq_eq0) //. rewrite [_ / _]mulq_frac /= /invq_subdef /mulq_subdef /=. by rewrite -!/(numq _) -!/(denq _) !numq_int !denq_int mul1r mulr1. Qed. Lemma divq_num_den x : (numq x)%:Q / (denq x)%:Q = x. Proof. by rewrite -{3}[x]valqK [valq _]surjective_pairing /= fracqE. Qed. CoInductive divq_spec (n d : int) : int -> int -> rat -> Type := | DivqSpecN of d = 0 : divq_spec n d n 0 0 | DivqSpecP k x of k != 0 : divq_spec n d (k * numq x) (k * denq x) x. (* replaces fracqP *) Lemma divqP n d : divq_spec n d n d (n%:Q / d%:Q). Proof. set x := (n, d); rewrite -[n]/x.1 -[d]/x.2 -fracqE. by case: fracqP => [_|k fx k_neq0] /=; constructor. Qed. Lemma divq_eq (nx dx ny dy : rat) : dx != 0 -> dy != 0 -> (nx / dx == ny / dy) = (nx * dy == ny * dx). Proof. move=> dx_neq0 dy_neq0; rewrite -(inj_eq (@mulIf _ (dx * dy) _)) ?mulf_neq0 //. by rewrite mulrA divfK // mulrCA divfK // [dx * _ ]mulrC. Qed. CoInductive rat_spec (* (x : rat) *) : rat -> int -> int -> Type := Rat_spec (n : int) (d : nat) & coprime `|n| d.+1 : rat_spec (* x *) (n%:Q / d.+1%:Q) n d.+1. Lemma ratP x : rat_spec x (numq x) (denq x). Proof. rewrite -{1}[x](divq_num_den); case hd: denq => [p|n]. have: 0 < p%:Z by rewrite -hd denq_gt0. case: p hd=> //= n hd; constructor; rewrite -?hd ?divq_num_den //. by rewrite -[n.+1]/`|n.+1|%N -hd coprime_num_den. by move: (denq_gt0 x); rewrite hd. Qed. Lemma coprimeq_num n d : coprime `|n| `|d| -> numq (n%:~R / d%:~R) = sgr d * n. Proof. move=> cnd /=; have <- := fracqE (n, d). rewrite /numq /= (eqP (cnd : _ == 1%N)) divn1. have [|d_gt0|d_lt0] := sgrP d; by rewrite (mul0r, mul1r, mulN1r) //= ?[_ ^ _]signrN ?mulNr mulz_sign_abs. Qed. Lemma coprimeq_den n d : coprime `|n| `|d| -> denq (n%:~R / d%:~R) = (if d == 0 then 1 else `|d|). Proof. move=> cnd; have <- := fracqE (n, d). by rewrite /denq /= (eqP (cnd : _ == 1%N)) divn1; case: d {cnd}. Qed. Lemma denqVz (i : int) : i != 0 -> denq (i%:~R^-1) = `|i|. Proof. by move=> h; rewrite -div1r -[1]/(1%:~R) coprimeq_den /= ?coprime1n // (negPf h). Qed. Lemma numqE x : (numq x)%:~R = x * (denq x)%:~R. Proof. by rewrite -{2}[x]divq_num_den divfK // intq_eq0 denq_eq0. Qed. Lemma denqP x : {d | denq x = d.+1}. Proof. by rewrite /denq; case: x => [[_ [[|d]|]] //= _]; exists d. Qed. Definition normq (x : rat) : rat := `|numq x|%:~R / (denq x)%:~R. Definition le_rat (x y : rat) := numq x * denq y <= numq y * denq x. Definition lt_rat (x y : rat) := numq x * denq y < numq y * denq x. Lemma gt_rat0 x : lt_rat 0 x = (0 < numq x). Proof. by rewrite /lt_rat mul0r mulr1. Qed. Lemma lt_rat0 x : lt_rat x 0 = (numq x < 0). Proof. by rewrite /lt_rat mul0r mulr1. Qed. Lemma ge_rat0 x : le_rat 0 x = (0 <= numq x). Proof. by rewrite /le_rat mul0r mulr1. Qed. Lemma le_rat0 x : le_rat x 0 = (numq x <= 0). Proof. by rewrite /le_rat mul0r mulr1. Qed. Fact le_rat0D x y : le_rat 0 x -> le_rat 0 y -> le_rat 0 (x + y). Proof. rewrite !ge_rat0 => hnx hny. have hxy: (0 <= numq x * denq y + numq y * denq x). by rewrite addr_ge0 ?mulr_ge0. by rewrite /numq /= -!/(denq _) ?mulf_eq0 ?denq_eq0 !ler_gtF ?mulr_ge0. Qed. Fact le_rat0M x y : le_rat 0 x -> le_rat 0 y -> le_rat 0 (x * y). Proof. rewrite !ge_rat0 => hnx hny. have hxy: (0 <= numq x * denq y + numq y * denq x). by rewrite addr_ge0 ?mulr_ge0. by rewrite /numq /= -!/(denq _) ?mulf_eq0 ?denq_eq0 !ler_gtF ?mulr_ge0. Qed. Fact le_rat0_anti x : le_rat 0 x -> le_rat x 0 -> x = 0. Proof. by move=> hx hy; apply/eqP; rewrite -numq_eq0 eqr_le -ge_rat0 -le_rat0 hx hy. Qed. Lemma sgr_numq_div (n d : int) : sgr (numq (n%:Q / d%:Q)) = sgr n * sgr d. Proof. set x := (n, d); rewrite -[n]/x.1 -[d]/x.2 -fracqE. case: fracqP => [|k fx k_neq0] /=; first by rewrite mulr0. by rewrite !sgrM mulrACA -expr2 sqr_sg k_neq0 sgr_denq mulr1 mul1r. Qed. Fact subq_ge0 x y : le_rat 0 (y - x) = le_rat x y. Proof. symmetry; rewrite ge_rat0 /le_rat -subr_ge0. case: ratP => nx dx cndx; case: ratP => ny dy cndy. rewrite -!mulNr addf_div ?intq_eq0 // !mulNr -!rmorphM -rmorphB /=. symmetry; rewrite !lerNgt -sgr_cp0 sgr_numq_div mulrC gtr0_sg //. by rewrite mul1r sgr_cp0. Qed. Fact le_rat_total : total le_rat. Proof. by move=> x y; apply: ler_total. Qed. Fact numq_sign_mul (b : bool) x : numq ((-1) ^+ b * x) = (-1) ^+ b * numq x. Proof. by case: b; rewrite ?(mul1r, mulN1r) // numqN. Qed. Fact numq_div_lt0 n d : n != 0 -> d != 0 -> (numq (n%:~R / d%:~R) < 0)%R = (n < 0)%R (+) (d < 0)%R. Proof. move=> n0 d0; rewrite -sgr_cp0 sgr_numq_div !sgr_def n0 d0. by rewrite !mulr1n -signr_addb; case: (_ (+) _). Qed. Lemma normr_num_div n d : `|numq (n%:~R / d%:~R)| = numq (`|n|%:~R / `|d|%:~R). Proof. rewrite (normrEsg n) (normrEsg d) !rmorphM /= invfM mulrACA !sgr_def. have [->|n_neq0] := altP eqP; first by rewrite mul0r mulr0. have [->|d_neq0] := altP eqP; first by rewrite invr0 !mulr0. rewrite !intr_sign invr_sign -signr_addb numq_sign_mul -numq_div_lt0 //. by apply: (canRL (signrMK _)); rewrite mulz_sign_abs. Qed. Fact norm_ratN x : normq (- x) = normq x. Proof. by rewrite /normq numqN denqN normrN. Qed. Fact ge_rat0_norm x : le_rat 0 x -> normq x = x. Proof. rewrite ge_rat0; case: ratP=> [] // n d cnd n_ge0. by rewrite /normq /= normr_num_div ?ger0_norm // divq_num_den. Qed. Fact lt_rat_def x y : (lt_rat x y) = (y != x) && (le_rat x y). Proof. by rewrite /lt_rat ltr_def rat_eq. Qed. Definition ratLeMixin := RealLeMixin le_rat0D le_rat0M le_rat0_anti subq_ge0 (@le_rat_total 0) norm_ratN ge_rat0_norm lt_rat_def. Canonical rat_numDomainType := NumDomainType rat ratLeMixin. Canonical rat_numFieldType := [numFieldType of rat]. Canonical rat_realDomainType := RealDomainType rat (@le_rat_total 0). Canonical rat_realFieldType := [realFieldType of rat]. Lemma numq_ge0 x : (0 <= numq x) = (0 <= x). Proof. by case: ratP => n d cnd; rewrite ?pmulr_lge0 ?invr_gt0 (ler0z, ltr0z). Qed. Lemma numq_le0 x : (numq x <= 0) = (x <= 0). Proof. by rewrite -oppr_ge0 -numqN numq_ge0 oppr_ge0. Qed. Lemma numq_gt0 x : (0 < numq x) = (0 < x). Proof. by rewrite !ltrNge numq_le0. Qed. Lemma numq_lt0 x : (numq x < 0) = (x < 0). Proof. by rewrite !ltrNge numq_ge0. Qed. Lemma sgr_numq x : sgz (numq x) = sgz x. Proof. apply/eqP; case: (sgzP x); rewrite sgz_cp0 ?(numq_gt0, numq_lt0) //. by move->. Qed. Lemma denq_mulr_sign (b : bool) x : denq ((-1) ^+ b * x) = denq x. Proof. by case: b; rewrite ?(mul1r, mulN1r) // denqN. Qed. Lemma denq_norm x : denq `|x| = denq x. Proof. by rewrite normrEsign denq_mulr_sign. Qed. Fact rat_archimedean : Num.archimedean_axiom [numDomainType of rat]. Proof. move=> x; exists `|numq x|.+1; rewrite mulrS ltr_spaddl //. rewrite pmulrn abszE intr_norm numqE normrM ler_pemulr ?norm_ge0 //. by rewrite -intr_norm ler1n absz_gt0 denq_eq0. Qed. Canonical archiType := ArchiFieldType rat rat_archimedean. Section QintPred. Definition Qint := [qualify a x : rat | denq x == 1]. Fact Qint_key : pred_key Qint. Proof. by []. Qed. Canonical Qint_keyed := KeyedQualifier Qint_key. Lemma Qint_def x : (x \is a Qint) = (denq x == 1). Proof. by []. Qed. Lemma numqK : {in Qint, cancel (fun x => numq x) intr}. Proof. by move=> x /(_ =P 1 :> int) Zx; rewrite numqE Zx rmorph1 mulr1. Qed. Lemma QintP x : reflect (exists z, x = z%:~R) (x \in Qint). Proof. apply: (iffP idP) => [/numqK <- | [z ->]]; first by exists (numq x). by rewrite Qint_def denq_int. Qed. Fact Qint_subring_closed : subring_closed Qint. Proof. split=> // _ _ /QintP[x ->] /QintP[y ->]; apply/QintP. by exists (x - y); rewrite -rmorphB. by exists (x * y); rewrite -rmorphM. Qed. Canonical Qint_opprPred := OpprPred Qint_subring_closed. Canonical Qint_addrPred := AddrPred Qint_subring_closed. Canonical Qint_mulrPred := MulrPred Qint_subring_closed. Canonical Qint_zmodPred := ZmodPred Qint_subring_closed. Canonical Qint_semiringPred := SemiringPred Qint_subring_closed. Canonical Qint_smulrPred := SmulrPred Qint_subring_closed. Canonical Qint_subringPred := SubringPred Qint_subring_closed. End QintPred. Section QnatPred. Definition Qnat := [qualify a x : rat | (x \is a Qint) && (0 <= x)]. Fact Qnat_key : pred_key Qnat. Proof. by []. Qed. Canonical Qnat_keyed := KeyedQualifier Qnat_key. Lemma Qnat_def x : (x \is a Qnat) = (x \is a Qint) && (0 <= x). Proof. by []. Qed. Lemma QnatP x : reflect (exists n : nat, x = n%:R) (x \in Qnat). Proof. rewrite Qnat_def; apply: (iffP idP) => [/andP []|[n ->]]; last first. by rewrite Qint_def pmulrn denq_int eqxx ler0z. by move=> /QintP [] [] n ->; rewrite ?ler0z // => _; exists n. Qed. Fact Qnat_semiring_closed : semiring_closed Qnat. Proof. do 2?split; move => // x y; rewrite !Qnat_def => /andP[xQ hx] /andP[yQ hy]. by rewrite rpredD // addr_ge0. by rewrite rpredM // mulr_ge0. Qed. Canonical Qnat_addrPred := AddrPred Qnat_semiring_closed. Canonical Qnat_mulrPred := MulrPred Qnat_semiring_closed. Canonical Qnat_semiringPred := SemiringPred Qnat_semiring_closed. End QnatPred. Lemma natq_div m n : n %| m -> (m %/ n)%:R = m%:R / n%:R :> rat. Proof. by apply: char0_natf_div; apply: char_num. Qed. Section InRing. Variable R : unitRingType. Definition ratr x : R := (numq x)%:~R / (denq x)%:~R. Lemma ratr_int z : ratr z%:~R = z%:~R. Proof. by rewrite /ratr numq_int denq_int divr1. Qed. Lemma ratr_nat n : ratr n%:R = n%:R. Proof. exact: (ratr_int n). Qed. Lemma rpred_rat S (ringS : @divringPred R S) (kS : keyed_pred ringS) a : ratr a \in kS. Proof. by rewrite rpred_div ?rpred_int. Qed. End InRing. Section Fmorph. Implicit Type rR : unitRingType. Lemma fmorph_rat (aR : fieldType) rR (f : {rmorphism aR -> rR}) a : f (ratr _ a) = ratr _ a. Proof. by rewrite fmorph_div !rmorph_int. Qed. Lemma fmorph_eq_rat rR (f : {rmorphism rat -> rR}) : f =1 ratr _. Proof. by move=> a; rewrite -{1}[a]divq_num_den fmorph_div !rmorph_int. Qed. End Fmorph. Section Linear. Implicit Types (U V : lmodType rat) (A B : lalgType rat). Lemma rat_linear U V (f : U -> V) : additive f -> linear f. Proof. move=> fB a u v; pose phi := Additive fB; rewrite [f _](raddfD phi). congr (_ + _); rewrite -{2}[a]divq_num_den mulrC -scalerA. apply: canRL (scalerK _) _; first by rewrite intr_eq0 denq_neq0. by rewrite !scaler_int -raddfMz scalerMzl -mulrzr -numqE scaler_int raddfMz. Qed. Lemma rat_lrmorphism A B (f : A -> B) : rmorphism f -> lrmorphism f. Proof. by case=> /rat_linear fZ fM; do ?split=> //; apply: fZ. Qed. End Linear. Section InPrealField. Variable F : numFieldType. Fact ratr_is_rmorphism : rmorphism (@ratr F). Proof. have injZtoQ: @injective rat int intr by exact: intr_inj. have nz_den x: (denq x)%:~R != 0 :> F by rewrite intr_eq0 denq_eq0. do 2?split; rewrite /ratr ?divr1 // => x y; last first. rewrite mulrC mulrAC; apply: canLR (mulKf (nz_den _)) _; rewrite !mulrA. do 2!apply: canRL (mulfK (nz_den _)) _; rewrite -!rmorphM; congr _%:~R. apply: injZtoQ; rewrite !rmorphM [x * y]lock /= !numqE -lock. by rewrite -!mulrA mulrA mulrCA -!mulrA (mulrCA y). apply: (canLR (mulfK (nz_den _))); apply: (mulIf (nz_den x)). rewrite mulrAC mulrBl divfK ?nz_den // mulrAC -!rmorphM. apply: (mulIf (nz_den y)); rewrite mulrAC mulrBl divfK ?nz_den //. rewrite -!(rmorphM, rmorphB); congr _%:~R; apply: injZtoQ. rewrite !(rmorphM, rmorphB) [_ - _]lock /= -lock !numqE. by rewrite (mulrAC y) -!mulrBl -mulrA mulrAC !mulrA. Qed. Canonical ratr_additive := Additive ratr_is_rmorphism. Canonical ratr_rmorphism := RMorphism ratr_is_rmorphism. Lemma ler_rat : {mono (@ratr F) : x y / x <= y}. Proof. move=> x y /=; case: (ratP x) => nx dx cndx; case: (ratP y) => ny dy cndy. rewrite !fmorph_div /= !ratr_int !ler_pdivl_mulr ?ltr0z //. by rewrite ![_ / _ * _]mulrAC !ler_pdivr_mulr ?ltr0z // -!rmorphM /= !ler_int. Qed. Lemma ltr_rat : {mono (@ratr F) : x y / x < y}. Proof. exact: lerW_mono ler_rat. Qed. Lemma ler0q x : (0 <= ratr F x) = (0 <= x). Proof. by rewrite (_ : 0 = ratr F 0) ?ler_rat ?rmorph0. Qed. Lemma lerq0 x : (ratr F x <= 0) = (x <= 0). Proof. by rewrite (_ : 0 = ratr F 0) ?ler_rat ?rmorph0. Qed. Lemma ltr0q x : (0 < ratr F x) = (0 < x). Proof. by rewrite (_ : 0 = ratr F 0) ?ltr_rat ?rmorph0. Qed. Lemma ltrq0 x : (ratr F x < 0) = (x < 0). Proof. by rewrite (_ : 0 = ratr F 0) ?ltr_rat ?rmorph0. Qed. Lemma ratr_sg x : ratr F (sgr x) = sgr (ratr F x). Proof. by rewrite !sgr_def fmorph_eq0 ltrq0 rmorphMn rmorph_sign. Qed. Lemma ratr_norm x : ratr F `|x| = `|ratr F x|. Proof. rewrite {2}[x]numEsign rmorphMsign normrMsign [`|ratr F _|]ger0_norm //. by rewrite ler0q ?normr_ge0. Qed. End InPrealField. Implicit Arguments ratr [[R]]. (* Conntecting rationals to the ring an field tactics *) Ltac rat_to_ring := rewrite -?[0%Q]/(0 : rat)%R -?[1%Q]/(1 : rat)%R -?[(_ - _)%Q]/(_ - _ : rat)%R -?[(_ / _)%Q]/(_ / _ : rat)%R -?[(_ + _)%Q]/(_ + _ : rat)%R -?[(_ * _)%Q]/(_ * _ : rat)%R -?[(- _)%Q]/(- _ : rat)%R -?[(_ ^-1)%Q]/(_ ^-1 : rat)%R /=. Ltac ring_to_rat := rewrite -?[0%R]/0%Q -?[1%R]/1%Q -?[(_ - _)%R]/(_ - _)%Q -?[(_ / _)%R]/(_ / _)%Q -?[(_ + _)%R]/(_ + _)%Q -?[(_ * _)%R]/(_ * _)%Q -?[(- _)%R]/(- _)%Q -?[(_ ^-1)%R]/(_ ^-1)%Q /=. Lemma rat_ring_theory : (ring_theory 0%Q 1%Q addq mulq subq oppq eq). Proof. split => * //; rat_to_ring; by rewrite ?(add0r, addrA, mul1r, mulrA, mulrDl, subrr) // (addrC, mulrC). Qed. Require setoid_ring.Field_theory setoid_ring.Field_tac. Lemma rat_field_theory : Field_theory.field_theory 0%Q 1%Q addq mulq subq oppq divq invq eq. Proof. split => //; first exact rat_ring_theory. by move=> p /eqP p_neq0; rat_to_ring; rewrite mulVf. Qed. Add Field rat_field : rat_field_theory. mathcomp-1.5/theories/algC.v0000644000175000017500000022105412307636117015044 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun ssrnat eqtype seq choice div fintype. Require Import path bigop finset prime ssralg poly polydiv mxpoly. Require Import generic_quotient countalg ssrnum ssrint rat intdiv. Require Import algebraics_fundamentals. (******************************************************************************) (* This file provides an axiomatic construction of the algebraic numbers. *) (* The construction only assumes the existence of an algebraically closed *) (* filed with an automorphism of order 2; this amounts to the purely *) (* algebraic contents of the Fundamenta Theorem of Algebra. *) (* algC == the closed, countable field of algebraic numbers. *) (* algCeq, algCring, ..., algCnumField == structures for algC. *) (* z^* == the complex conjugate of z (:= conjC z). *) (* sqrtC z == a nonnegative square root of z, i.e., 0 <= sqrt x if 0 <= x. *) (* n.-root z == more generally, for n > 0, an nth root of z, chosen with a *) (* minimal non-negative argument for n > 1 (i.e., with a *) (* maximal real part subject to a nonnegative imaginary part). *) (* Note that n.-root (-1) is a primitive 2nth root of unity, *) (* an thus not equal to -1 for n odd > 1 (this will be shown in *) (* file cyclotomic.v). *) (* The ssrnum interfaces are implemented for algC as follows: *) (* x <= y <=> (y - x) is a nonnegative real *) (* x < y <=> (y - x) is a (strictly) positive real *) (* `|z| == the complex norm of z, i.e., sqrtC (z * z^* ). *) (* Creal == the subset of real numbers (:= Num.real for algC). *) (* In addition, we provide: *) (* 'i == the imaginary number (:= sqrtC (-1)). *) (* 'Re z == the real component of z. *) (* 'Im z == the imaginary component of z. *) (* Crat == the subset of rational numbers. *) (* Cint == the subset of integers. *) (* Cnat == the subset of natural integers. *) (* getCrat z == some a : rat such that ratr a = z, provided z \in Crat. *) (* floorC z == for z \in Creal, an m : int s.t. m%:~R <= z < (m + 1)%:~R. *) (* truncC z == for z >= 0, an n : nat s.t. n%:R <= z < n.+1%:R, else 0%N. *) (* minCpoly z == the minimal (monic) polynomial over Crat with root z. *) (* algC_invaut nu == an inverse of nu : {rmorphism algC -> algC}. *) (* (x %| y)%C <=> y is an integer (Cint) multiple of x; if x or y are *) (* (x %| y)%Cx of type nat or int they are coerced to algC here. *) (* The (x %| y)%Cx display form is a workaround for *) (* design limitations of the Coq Notation facilities. *) (* (x == y %[mod z])%C <=> x and y differ by an integer (Cint) multiple of z; *) (* as above, arguments of type nat or int are cast to algC. *) (* (x != y %[mod z])%C <=> x and y do not differ by an integer multiple of z. *) (* Note that in file algnum we give an alternative definition of divisibility *) (* based on algebraic integers, overloading the notation in the %A scope. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GRing.Theory Num.Theory. Local Open Scope ring_scope. (* The Num mixin for an algebraically closed field with an automorphism of *) (* order 2, making it into a field of complex numbers. *) Lemma ComplexNumMixin (L : closedFieldType) (conj : {rmorphism L -> L}) : involutive conj -> ~ conj =1 id -> {numL | forall x : NumDomainType L numL, `|x| ^+ 2 = x * conj x}. Proof. move=> conjK conj_nt. have nz2: 2%:R != 0 :> L. apply/eqP=> char2; apply: conj_nt => e; apply/eqP/idPn=> eJ. have opp_id x: - x = x :> L. by apply/esym/eqP; rewrite -addr_eq0 -mulr2n -mulr_natl char2 mul0r. have{char2} char2: 2 \in [char L] by exact/eqP. without loss{eJ} eJ: e / conj e = e + 1. move/(_ (e / (e + conj e))); apply. rewrite fmorph_div rmorphD conjK -{1}[conj e](addNKr e) mulrDl. by rewrite opp_id (addrC e) divff // addr_eq0 opp_id. pose a := e * conj e; have aJ: conj a = a by rewrite rmorphM conjK mulrC. have [w Dw] := @solve_monicpoly _ 2 (nth 0 [:: e * a; - 1]) isT. have{Dw} Dw: w ^+ 2 + w = e * a. by rewrite Dw !big_ord_recl big_ord0 /= mulr1 mulN1r addr0 subrK. pose b := w + conj w; have bJ: conj b = b by rewrite rmorphD conjK addrC. have Db2: b ^+ 2 + b = a. rewrite -Frobenius_autE // rmorphD addrACA Dw /= Frobenius_autE -rmorphX. by rewrite -rmorphD Dw rmorphM aJ eJ -mulrDl -{1}[e]opp_id addKr mul1r. have /eqP[] := oner_eq0 L; apply: (addrI b); rewrite addr0 -{2}bJ. have: (b + e) * (b + conj e) == 0. rewrite mulrDl 2!mulrDr -/a addrA addr_eq0 opp_id (mulrC e) -addrA. by rewrite -mulrDr eJ addrAC -{2}[e]opp_id subrr add0r mulr1 Db2. rewrite mulf_eq0 !addr_eq0 !opp_id => /pred2P[] -> //. by rewrite {2}eJ rmorphD rmorph1. have mul2I: injective (fun z : L => z *+ 2). by move=> x y; rewrite /= -mulr_natl -(mulr_natl y) => /mulfI->. pose sqrt x : L := sval (sig_eqW (@solve_monicpoly _ 2 (nth 0 [:: x]) isT)). have sqrtK x: sqrt x ^+ 2 = x. rewrite /sqrt; case: sig_eqW => /= y ->. by rewrite !big_ord_recl big_ord0 /= mulr1 mul0r !addr0. have sqrtE x y: y ^+ 2 = x -> {b : bool | y = (-1) ^+ b * sqrt x}. move=> Dx; exists (y != sqrt x); apply/eqP; rewrite mulr_sign if_neg. by case: ifPn => //; apply/implyP; rewrite implyNb -eqf_sqr Dx sqrtK. pose i := sqrt (- 1). have sqrMi x: (i * x) ^+ 2 = - x ^+ 2 by rewrite exprMn sqrtK mulN1r. have iJ : conj i = - i. have /sqrtE[b]: conj i ^+ 2 = - 1 by rewrite -rmorphX sqrtK rmorphN1. rewrite mulr_sign -/i; case: b => // Ri. case: conj_nt => z; wlog zJ: z / conj z = - z. move/(_ (z - conj z)); rewrite !rmorphB conjK opprB => zJ. by apply/mul2I/(canRL (subrK _)); rewrite -addrA zJ // addrC subrK. have [-> | nz_z] := eqVneq z 0; first exact: rmorph0. have [u Ru [v Rv Dz]]: exists2 u, conj u = u & exists2 v, conj v = v & (u + z * v) ^+ 2 = z. - pose y := sqrt z; exists ((y + conj y) / 2%:R). by rewrite fmorph_div rmorphD conjK addrC rmorph_nat. exists ((y - conj y) / (z *+ 2)). rewrite fmorph_div rmorphMn zJ mulNrn invrN mulrN -mulNr rmorphB opprB. by rewrite conjK. rewrite -(mulr_natl z) invfM (mulrC z) !mulrA divfK // -mulrDl addrACA. by rewrite subrr addr0 -mulr2n -mulr_natr mulfK ?Neq0 ?sqrtK. suffices u0: u = 0 by rewrite -Dz u0 add0r rmorphX rmorphM Rv zJ mulNr sqrrN. suffices [b Du]: exists b : bool, u = (-1) ^+ b * i * z * v. apply: mul2I; rewrite mul0rn mulr2n -{2}Ru. by rewrite Du !rmorphM rmorph_sign Rv Ri zJ !mulrN mulNr subrr. have/eqP:= zJ; rewrite -addr_eq0 -{1 2}Dz rmorphX rmorphD rmorphM Ru Rv zJ. rewrite mulNr sqrrB sqrrD addrACA (addrACA (u ^+ 2)) addNr addr0 -!mulr2n. rewrite -mulrnDl -(mul0rn _ 2) (inj_eq mul2I) /= -[rhs in _ + rhs]opprK. rewrite -sqrMi subr_eq0 eqf_sqr -mulNr !mulrA. by case/pred2P=> ->; [exists false | exists true]; rewrite mulr_sign. pose norm x := sqrt x * conj (sqrt x). have normK x : norm x ^+ 2 = x * conj x by rewrite exprMn -rmorphX sqrtK. have normE x y : y ^+ 2 = x -> norm x = y * conj y. rewrite /norm => /sqrtE[b /(canLR (signrMK b)) <-]. by rewrite !rmorphM rmorph_sign mulrACA -mulrA signrMK. have norm_eq0 x : norm x = 0 -> x = 0. by move/eqP; rewrite mulf_eq0 fmorph_eq0 -mulf_eq0 -expr2 sqrtK => /eqP. have normM x y : norm (x * y) = norm x * norm y. by rewrite mulrACA -rmorphM; apply: normE; rewrite exprMn !sqrtK. have normN x : norm (- x) = norm x. by rewrite -mulN1r normM {1}/norm iJ mulrN -expr2 sqrtK opprK mul1r. pose le x y := norm (y - x) == y - x; pose lt x y := (y != x) && le x y. have posE x: le 0 x = (norm x == x) by rewrite /le subr0. have leB x y: le x y = le 0 (y - x) by rewrite posE. have posP x : reflect (exists y, x = y * conj y) (le 0 x). rewrite posE; apply: (iffP eqP) => [Dx | [y {x}->]]; first by exists (sqrt x). by rewrite (normE _ _ (normK y)) rmorphM conjK (mulrC (conj _)) -expr2 normK. have posJ x : le 0 x -> conj x = x. by case/posP=> {x}u ->; rewrite rmorphM conjK mulrC. have pos_linear x y : le 0 x -> le 0 y -> le x y || le y x. move=> pos_x pos_y; rewrite leB -opprB orbC leB !posE normN -eqf_sqr. by rewrite normK rmorphB !posJ ?subrr. have sposDl x y : lt 0 x -> le 0 y -> lt 0 (x + y). have sqrtJ z : le 0 z -> conj (sqrt z) = sqrt z. rewrite posE -{2}[z]sqrtK -subr_eq0 -mulrBr mulf_eq0 subr_eq0. by case/pred2P=> ->; rewrite ?rmorph0. case/andP=> nz_x /sqrtJ uJ /sqrtJ vJ. set u := sqrt x in uJ; set v := sqrt y in vJ; pose w := u + i * v. have ->: x + y = w * conj w. rewrite rmorphD rmorphM iJ uJ vJ mulNr mulrC -subr_sqr sqrMi opprK. by rewrite !sqrtK. apply/andP; split; last by apply/posP; exists w. rewrite -normK expf_eq0 //=; apply: contraNneq nz_x => /norm_eq0 w0. rewrite -[x]sqrtK expf_eq0 /= -/u -(inj_eq mul2I) !mulr2n -{2}(rmorph0 conj). by rewrite -w0 rmorphD rmorphM iJ uJ vJ mulNr addrACA subrr addr0. have sposD x y : lt 0 x -> lt 0 y -> lt 0 (x + y). by move=> x_gt0 /andP[_]; apply: sposDl. have normD x y : le (norm (x + y)) (norm x + norm y). have sposM u v: lt 0 u -> le 0 (u * v) -> le 0 v. by rewrite /lt !posE normM andbC => /andP[/eqP-> /mulfI/inj_eq->]. have posD u v: le 0 u -> le 0 v -> le 0 (u + v). have [-> | nz_u u_ge0 v_ge0] := eqVneq u 0; first by rewrite add0r. by have /andP[]: lt 0 (u + v) by rewrite sposDl // /lt nz_u. have le_sqr u v: conj u = u -> le 0 v -> le (u ^+ 2) (v ^+ 2) -> le u v. move=> Ru v_ge0; have [-> // | nz_u] := eqVneq u 0. have [u_gt0 | u_le0 _] := boolP (lt 0 u). by rewrite leB (leB u) subr_sqr mulrC addrC; apply: sposM; apply: sposDl. rewrite leB posD // posE normN -addr_eq0; apply/eqP. rewrite /lt nz_u posE -subr_eq0 in u_le0; apply: (mulfI u_le0). by rewrite mulr0 -subr_sqr normK Ru subrr. have pos_norm z: le 0 (norm z) by apply/posP; exists (sqrt z). rewrite le_sqr ?posJ ?posD // sqrrD !normK -normM rmorphD mulrDl !mulrDr. rewrite addrA addrC !addrA -(addrC (y * conj y)) !addrA. move: (y * _ + _) => u; rewrite -!addrA leB opprD addrACA {u}subrr add0r -leB. rewrite {}le_sqr ?posD //. by rewrite rmorphD !rmorphM !conjK addrC mulrC (mulrC y). rewrite -mulr2n -mulr_natr exprMn normK -natrX mulr_natr sqrrD mulrACA. rewrite -rmorphM (mulrC y x) addrAC leB mulrnA mulr2n opprD addrACA. rewrite subrr addr0 {2}(mulrC x) rmorphM mulrACA -opprB addrAC -sqrrB -sqrMi. apply/posP; exists (i * (x * conj y - y * conj x)); congr (_ * _). rewrite !(rmorphM, rmorphB) iJ !conjK mulNr -mulrN opprB. by rewrite (mulrC x) (mulrC y). by exists (Num.Mixin normD sposD norm_eq0 pos_linear normM (rrefl _) (rrefl _)). Qed. Module Algebraics. Module Type Specification. Parameter type : Type. Parameter eqMixin : Equality.class_of type. Canonical eqType := EqType type eqMixin. Parameter choiceMixin : Choice.mixin_of type. Canonical choiceType := ChoiceType type choiceMixin. Parameter countMixin : Countable.mixin_of type. Canonical countType := CountType type countMixin. Parameter zmodMixin : GRing.Zmodule.mixin_of type. Canonical zmodType := ZmodType type zmodMixin. Canonical countZmodType := [countZmodType of type]. Parameter ringMixin : GRing.Ring.mixin_of zmodType. Canonical ringType := RingType type ringMixin. Canonical countRingType := [countRingType of type]. Parameter unitRingMixin : GRing.UnitRing.mixin_of ringType. Canonical unitRingType := UnitRingType type unitRingMixin. Axiom mulC : @commutative ringType ringType *%R. Canonical comRingType := ComRingType type mulC. Canonical comUnitRingType := [comUnitRingType of type]. Axiom idomainAxiom : GRing.IntegralDomain.axiom ringType. Canonical idomainType := IdomainType type idomainAxiom. Axiom fieldMixin : GRing.Field.mixin_of unitRingType. Canonical fieldType := FieldType type fieldMixin. Parameter decFieldMixin : GRing.DecidableField.mixin_of unitRingType. Canonical decFieldType := DecFieldType type decFieldMixin. Axiom closedFieldAxiom : GRing.ClosedField.axiom ringType. Canonical closedFieldType := ClosedFieldType type closedFieldAxiom. Parameter numMixin : Num.mixin_of ringType. Canonical numDomainType := NumDomainType type numMixin. Canonical numFieldType := [numFieldType of type]. Parameter conj : {rmorphism type -> type}. Axiom conjK : involutive conj. Axiom normK : forall x, `|x| ^+ 2 = x * conj x. Axiom algebraic : integralRange (@ratr unitRingType). End Specification. Module Implementation : Specification. Definition L := tag Fundamental_Theorem_of_Algebraics. Definition conjL : {rmorphism L -> L} := s2val (tagged Fundamental_Theorem_of_Algebraics). Fact conjL_K : involutive conjL. Proof. exact: s2valP (tagged Fundamental_Theorem_of_Algebraics). Qed. Fact conjL_nt : ~ conjL =1 id. Proof. exact: s2valP' (tagged Fundamental_Theorem_of_Algebraics). Qed. Definition LnumMixin := ComplexNumMixin conjL_K conjL_nt. Definition Lnum := NumDomainType L (sval LnumMixin). Definition QtoL := [rmorphism of @ratr [numFieldType of Lnum]]. Notation pQtoL := (map_poly QtoL). Definition rootQtoL p_j := if p_j.1 == 0 then 0 else (sval (closed_field_poly_normal (pQtoL p_j.1)))`_p_j.2. Definition eq_root p_j q_k := rootQtoL p_j == rootQtoL q_k. Fact eq_root_is_equiv : equiv_class_of eq_root. Proof. by rewrite /eq_root; split=> [ ? | ? ? | ? ? ? ] // /eqP->. Qed. Canonical eq_root_equiv := EquivRelPack eq_root_is_equiv. Definition type : Type := {eq_quot eq_root}%qT. Definition eqMixin : Equality.class_of type := EquivQuot.eqMixin _. Canonical eqType := EqType type eqMixin. Definition choiceMixin : Choice.mixin_of type := EquivQuot.choiceMixin _. Canonical choiceType := ChoiceType type choiceMixin. Definition countMixin : Countable.mixin_of type := CanCountMixin (@reprK _ _). Canonical countType := CountType type countMixin. Definition CtoL (u : type) := rootQtoL (repr u). Fact CtoL_inj : injective CtoL. Proof. by move=> u v /eqP eq_uv; rewrite -[u]reprK -[v]reprK; apply/eqmodP. Qed. Fact CtoL_P u : integralOver QtoL (CtoL u). Proof. rewrite /CtoL /rootQtoL; case: (repr u) => p j /=. case: (closed_field_poly_normal _) => r Dp /=. case: ifPn => [_ | nz_p]; first exact: integral0. have [/(nth_default 0)-> | lt_j_r] := leqP (size r) j; first exact: integral0. apply/integral_algebraic; exists p; rewrite // Dp -mul_polyC rootM orbC. by rewrite root_prod_XsubC mem_nth. Qed. Fact LtoC_subproof z : integralOver QtoL z -> {u | CtoL u = z}. Proof. case/sig2_eqW=> p mon_p pz0; rewrite /CtoL. pose j := index z (sval (closed_field_poly_normal (pQtoL p))). pose u := \pi_type%qT (p, j); exists u; have /eqmodP/eqP-> := reprK u. rewrite /rootQtoL -if_neg monic_neq0 //; apply: nth_index => /=. case: (closed_field_poly_normal _) => r /= Dp. by rewrite Dp (monicP _) ?(monic_map QtoL) // scale1r root_prod_XsubC in pz0. Qed. Definition LtoC z Az := sval (@LtoC_subproof z Az). Fact LtoC_K z Az : CtoL (@LtoC z Az) = z. Proof. exact: (svalP (LtoC_subproof Az)). Qed. Fact CtoL_K u : LtoC (CtoL_P u) = u. Proof. by apply: CtoL_inj; rewrite LtoC_K. Qed. Definition zero := LtoC (integral0 _). Definition add u v := LtoC (integral_add (CtoL_P u) (CtoL_P v)). Definition opp u := LtoC (integral_opp (CtoL_P u)). Fact addA : associative add. Proof. by move=> u v w; apply: CtoL_inj; rewrite !LtoC_K addrA. Qed. Fact addC : commutative add. Proof. by move=> u v; apply: CtoL_inj; rewrite !LtoC_K addrC. Qed. Fact add0 : left_id zero add. Proof. by move=> u; apply: CtoL_inj; rewrite !LtoC_K add0r. Qed. Fact addN : left_inverse zero opp add. Proof. by move=> u; apply: CtoL_inj; rewrite !LtoC_K addNr. Qed. Definition zmodMixin := ZmodMixin addA addC add0 addN. Canonical zmodType := ZmodType type zmodMixin. Canonical countZmodType := [countZmodType of type]. Fact CtoL_is_additive : additive CtoL. Proof. by move=> u v; rewrite !LtoC_K. Qed. Canonical CtoL_additive := Additive CtoL_is_additive. Definition one := LtoC (integral1 _). Definition mul u v := LtoC (integral_mul (CtoL_P u) (CtoL_P v)). Definition inv u := LtoC (integral_inv (CtoL_P u)). Fact mulA : associative mul. Proof. by move=> u v w; apply: CtoL_inj; rewrite !LtoC_K mulrA. Qed. Fact mulC : commutative mul. Proof. by move=> u v; apply: CtoL_inj; rewrite !LtoC_K mulrC. Qed. Fact mul1 : left_id one mul. Proof. by move=> u; apply: CtoL_inj; rewrite !LtoC_K mul1r. Qed. Fact mulD : left_distributive mul +%R. Proof. by move=> u v w; apply: CtoL_inj; rewrite !LtoC_K mulrDl. Qed. Fact one_nz : one != 0 :> type. Proof. by rewrite -(inj_eq CtoL_inj) !LtoC_K oner_eq0. Qed. Definition ringMixin := ComRingMixin mulA mulC mul1 mulD one_nz. Canonical ringType := RingType type ringMixin. Canonical comRingType := ComRingType type mulC. Canonical countRingType := [countRingType of type]. Fact CtoL_is_multiplicative : multiplicative CtoL. Proof. by split=> [u v|]; rewrite !LtoC_K. Qed. Canonical CtoL_rmorphism := AddRMorphism CtoL_is_multiplicative. Fact mulVf : GRing.Field.axiom inv. Proof. move=> u; rewrite -(inj_eq CtoL_inj) rmorph0 => nz_u. by apply: CtoL_inj; rewrite !LtoC_K mulVf. Qed. Fact inv0 : inv 0 = 0. Proof. by apply: CtoL_inj; rewrite !LtoC_K invr0. Qed. Definition unitRingMixin := FieldUnitMixin mulVf inv0. Canonical unitRingType := UnitRingType type unitRingMixin. Canonical comUnitRingType := [comUnitRingType of type]. Definition fieldMixin := @FieldMixin _ _ mulVf inv0. Definition idomainAxiom := FieldIdomainMixin fieldMixin. Canonical idomainType := IdomainType type idomainAxiom. Canonical fieldType := FieldType type fieldMixin. Fact closedFieldAxiom : GRing.ClosedField.axiom ringType. Proof. move=> n a n_gt0; pose p := 'X^n - \poly_(i < n) CtoL (a i). have Ap: {in p : seq L, integralRange QtoL}. move=> _ /(nthP 0)[j _ <-]; rewrite coefB coefXn coef_poly. apply: integral_sub; first exact: integral_nat. by case: ifP => _; [apply: CtoL_P | apply: integral0]. have sz_p: size p = n.+1. by rewrite size_addl size_polyXn // size_opp ltnS size_poly. have [z pz0]: exists z, root p z by apply/closed_rootP; rewrite sz_p eqSS -lt0n. have Az: integralOver ratr z. by apply: integral_root Ap; rewrite // -size_poly_gt0 sz_p. exists (LtoC Az); apply/CtoL_inj; rewrite -[CtoL _]subr0 -(rootP pz0). rewrite rmorphX /= LtoC_K hornerD hornerXn hornerN opprD addNKr opprK. rewrite horner_poly rmorph_sum; apply: eq_bigr => k _. by rewrite rmorphM rmorphX /= LtoC_K. Qed. Definition decFieldMixin := closed_field.closed_fields_QEMixin closedFieldAxiom. Canonical decFieldType := DecFieldType type decFieldMixin. Canonical closedFieldType := ClosedFieldType type closedFieldAxiom. Fact conj_subproof u : integralOver QtoL (conjL (CtoL u)). Proof. have [p mon_p pu0] := CtoL_P u; exists p => //. rewrite -(fmorph_root conjL) conjL_K map_poly_id // => _ /(nthP 0)[j _ <-]. by rewrite coef_map fmorph_rat. Qed. Fact conj_is_rmorphism : rmorphism (fun u => LtoC (conj_subproof u)). Proof. do 2?split=> [u v|]; apply: CtoL_inj; last by rewrite !LtoC_K rmorph1. - by rewrite LtoC_K 3!{1}rmorphB /= !LtoC_K. by rewrite LtoC_K 3!{1}rmorphM /= !LtoC_K. Qed. Definition conj : {rmorphism type -> type} := RMorphism conj_is_rmorphism. Lemma conjK : involutive conj. Proof. by move=> u; apply: CtoL_inj; rewrite !LtoC_K conjL_K. Qed. Fact conj_nt : ~ conj =1 id. Proof. have [i i2]: exists i : type, i ^+ 2 = -1. have [i] := @solve_monicpoly _ 2 (nth 0 [:: -1 : type]) isT. by rewrite !big_ord_recl big_ord0 /= mul0r mulr1 !addr0; exists i. move/(_ i)/(congr1 CtoL); rewrite LtoC_K => iL_J. have/ltr_geF/idP[] := @ltr01 Lnum; rewrite -oppr_ge0 -(rmorphN1 CtoL_rmorphism). rewrite -i2 rmorphX /= expr2 -{2}iL_J -(svalP LnumMixin). by rewrite exprn_ge0 ?normr_ge0. Qed. Definition numMixin := sval (ComplexNumMixin conjK conj_nt). Canonical numDomainType := NumDomainType type numMixin. Canonical numFieldType := [numFieldType of type]. Lemma normK u : `|u| ^+ 2 = u * conj u. Proof. exact: svalP (ComplexNumMixin conjK conj_nt) u. Qed. Lemma algebraic : integralRange (@ratr unitRingType). Proof. move=> u; have [p mon_p pu0] := CtoL_P u; exists p => {mon_p}//. rewrite -(fmorph_root CtoL_rmorphism) -map_poly_comp; congr (root _ _): pu0. by apply/esym/eq_map_poly; apply: fmorph_eq_rat. Qed. End Implementation. Definition divisor := Implementation.type. Module Internals. Import Implementation. Local Notation algC := type. Local Notation "z ^*" := (conj z) (at level 2, format "z ^*") : ring_scope. Local Notation QtoC := (ratr : rat -> algC). Local Notation QtoCm := [rmorphism of QtoC]. Local Notation pQtoC := (map_poly QtoC). Local Notation ZtoQ := (intr : int -> rat). Local Notation ZtoC := (intr : int -> algC). Local Notation Creal := (Num.real : qualifier 0 algC). Fact algCi_subproof : {i : algC | i ^+ 2 = -1}. Proof. exact: imaginary_exists. Qed. Let Re2 z := z + z^*. Definition nnegIm z := 0 <= sval algCi_subproof * (z^* - z). Definition argCle y z := nnegIm z ==> nnegIm y && (Re2 z <= Re2 y). CoInductive rootC_spec n (x : algC) : Type := RootCspec (y : algC) of if (n > 0)%N then y ^+ n = x else y = 0 & forall z, (n > 0)%N -> z ^+ n = x -> argCle y z. Fact rootC_subproof n x : rootC_spec n x. Proof. have realRe2 u : Re2 u \is Creal. rewrite realEsqr expr2 {2}/Re2 -{2}[u]conjK addrC -rmorphD -normK. by rewrite exprn_ge0 ?normr_ge0. have argCtotal : total argCle. move=> u v; rewrite /total /argCle. by do 2!case: (nnegIm _) => //; rewrite ?orbT //= real_leVge. have argCtrans : transitive argCle. move=> u v w /implyP geZuv /implyP geZvw; apply/implyP. by case/geZvw/andP=> /geZuv/andP[-> geRuv] /ler_trans->. pose p := 'X^n - (x *+ (n > 0))%:P; have [r0 Dp] := closed_field_poly_normal p. have sz_p: size p = n.+1. rewrite size_addl ?size_polyXn // ltnS size_opp size_polyC mulrn_eq0. by case: posnP => //; case: negP. pose r := sort argCle r0; have r_arg: sorted argCle r by apply: sort_sorted. have{Dp} Dp: p = \prod_(z <- r) ('X - z%:P). rewrite Dp lead_coefE sz_p coefB coefXn coefC -mulrb -mulrnA mulnb lt0n andNb. rewrite subr0 eqxx scale1r; apply: eq_big_perm. by rewrite perm_eq_sym perm_sort. have mem_rP z: (n > 0)%N -> reflect (z ^+ n = x) (z \in r). move=> n_gt0; rewrite -root_prod_XsubC -Dp rootE !hornerE hornerXn n_gt0. by rewrite subr_eq0; apply: eqP. exists r`_0 => [|z n_gt0 /(mem_rP z n_gt0) r_z]. have sz_r: size r = n by apply: succn_inj; rewrite -sz_p Dp size_prod_XsubC. case: posnP => [n0 | n_gt0]; first by rewrite nth_default // sz_r n0. by apply/mem_rP=> //; rewrite mem_nth ?sz_r. case: {Dp mem_rP}r r_z r_arg => // y r1; rewrite inE => /predU1P[-> _|r1z]. by apply/implyP=> ->; rewrite lerr. by move/(order_path_min argCtrans)/allP->. Qed. CoInductive getCrat_spec : Type := GetCrat_spec CtoQ of cancel QtoC CtoQ. Fact getCrat_subproof : getCrat_spec. Proof. have isQ := rat_algebraic_decidable algebraic. exists (fun z => if isQ z is left Qz then sval (sig_eqW Qz) else 0) => a. case: (isQ _) => [Qa | []]; last by exists a. by case: (sig_eqW _) => b /= /fmorph_inj. Qed. Fact floorC_subproof x : {m | x \is Creal -> ZtoC m <= x < ZtoC (m + 1)}. Proof. have [Rx | _] := boolP (x \is Creal); last by exists 0. without loss x_ge0: x Rx / x >= 0. have [x_ge0 | /ltrW x_le0] := real_ger0P Rx; first exact. case/(_ (- x)) => [||m /(_ isT)]; rewrite ?rpredN ?oppr_ge0 //. rewrite ler_oppr ltr_oppl -!rmorphN opprD /= ltr_neqAle ler_eqVlt. case: eqP => [-> _ | _ /and3P[lt_x_m _ le_m_x]]. by exists (- m) => _; rewrite lerr rmorphD ltr_addl ltr01. by exists (- m - 1); rewrite le_m_x subrK. have /ex_minnP[n lt_x_n1 min_n]: exists n, x < n.+1%:R. have [n le_x_n] := rat_algebraic_archimedean algebraic x. by exists n; rewrite -(ger0_norm x_ge0) (ltr_trans le_x_n) ?ltr_nat. exists n%:Z => _; rewrite addrC -intS lt_x_n1 andbT. case Dn: n => // [n1]; rewrite -Dn. have [||//|] := @real_lerP _ n%:R x; rewrite ?rpred_nat //. by rewrite Dn => /min_n; rewrite Dn ltnn. Qed. Fact minCpoly_subproof (x : algC) : {p | p \is monic & forall q, root (pQtoC q) x = (p %| q)%R}. Proof. have isQ := rat_algebraic_decidable algebraic. have [p [mon_p px0 irr_p]] := minPoly_decidable_closure isQ (algebraic x). exists p => // q; apply/idP/idP=> [qx0 | /dvdpP[r ->]]; last first. by rewrite rmorphM rootM px0 orbT. suffices /eqp_dvdl <-: gcdp p q %= p by apply: dvdp_gcdr. rewrite irr_p ?dvdp_gcdl ?gtn_eqF // -(size_map_poly QtoCm) gcdp_map /=. rewrite (@root_size_gt1 _ x) ?root_gcd ?px0 //. by rewrite gcdp_eq0 negb_and map_poly_eq0 monic_neq0. Qed. Definition algC_divisor (x : algC) := x : divisor. Definition int_divisor m := m%:~R : divisor. Definition nat_divisor n := n%:R : divisor. End Internals. Module Import Exports. Import Implementation Internals. Notation algC := type. Notation conjC := conj. Delimit Scope C_scope with C. Delimit Scope C_core_scope with Cc. Delimit Scope C_expanded_scope with Cx. Open Scope C_core_scope. Notation "x ^*" := (conjC x) (at level 2, format "x ^*") : C_core_scope. Notation "x ^*" := x^* (only parsing) : C_scope. Canonical eqType. Canonical choiceType. Canonical countType. Canonical zmodType. Canonical countZmodType. Canonical ringType. Canonical countRingType. Canonical unitRingType. Canonical comRingType. Canonical comUnitRingType. Canonical idomainType. Canonical numDomainType. Canonical fieldType. Canonical numFieldType. Canonical decFieldType. Canonical closedFieldType. Notation algCeq := eqType. Notation algCzmod := zmodType. Notation algCring := ringType. Notation algCuring := unitRingType. Notation algCnum := numDomainType. Notation algCfield := fieldType. Notation algCnumField := numFieldType. Definition rootC n x := let: RootCspec y _ _ := rootC_subproof n x in y. Notation "n .-root" := (rootC n) (at level 2, format "n .-root") : C_core_scope. Notation "n .-root" := (rootC n) (only parsing) : C_scope. Notation sqrtC := 2.-root. Definition algCi := sqrtC (-1). Notation "'i" := algCi (at level 0) : C_core_scope. Notation "'i" := 'i (only parsing) : C_scope. Definition algRe x := (x + x^*) / 2%:R. Definition algIm x := 'i * (x^* - x) / 2%:R. Notation "'Re z" := (algRe z) (at level 10, z at level 8) : C_core_scope. Notation "'Im z" := (algIm z) (at level 10, z at level 8) : C_core_scope. Notation "'Re z" := ('Re z) (only parsing) : C_scope. Notation "'Im z" := ('Im z) (only parsing) : C_scope. Notation Creal := (@Num.Def.Rreal numDomainType). Definition getCrat := let: GetCrat_spec CtoQ _ := getCrat_subproof in CtoQ. Definition Crat : pred_class := fun x : algC => ratr (getCrat x) == x. Definition floorC x := sval (floorC_subproof x). Definition Cint : pred_class := fun x : algC => (floorC x)%:~R == x. Definition truncC x := if x >= 0 then `|floorC x|%N else 0%N. Definition Cnat : pred_class := fun x : algC => (truncC x)%:R == x. Definition minCpoly x : {poly algC} := let: exist2 p _ _ := minCpoly_subproof x in map_poly ratr p. Coercion nat_divisor : nat >-> divisor. Coercion int_divisor : int >-> divisor. Coercion algC_divisor : algC >-> divisor. Lemma nCdivE (p : nat) : p = p%:R :> divisor. Proof. by []. Qed. Lemma zCdivE (p : int) : p = p%:~R :> divisor. Proof. by []. Qed. Definition CdivE := (nCdivE, zCdivE). Definition dvdC (x : divisor) : pred_class := fun y : algC => if x == 0 then y == 0 else y / x \in Cint. Notation "x %| y" := (y \in dvdC x) : C_expanded_scope. Notation "x %| y" := (@in_mem divisor y (mem (dvdC x))) : C_scope. Definition eqCmod (e x y : divisor) := (e %| x - y)%C. Notation "x == y %[mod e ]" := (eqCmod e x y) : C_scope. Notation "x != y %[mod e ]" := (~~ (x == y %[mod e])%C) : C_scope. End Exports. End Algebraics. Export Algebraics.Exports. Section AlgebraicsTheory. Implicit Types (x y z : algC) (n : nat) (m : int) (b : bool). Import Algebraics.Internals. Local Notation ZtoQ := (intr : int -> rat). Local Notation ZtoC := (intr : int -> algC). Local Notation QtoC := (ratr : rat -> algC). Local Notation QtoCm := [rmorphism of QtoC]. Local Notation CtoQ := getCrat. Local Notation intrp := (map_poly intr). Local Notation pZtoQ := (map_poly ZtoQ). Local Notation pZtoC := (map_poly ZtoC). Local Notation pQtoC := (map_poly ratr). Local Hint Resolve (@intr_inj _ : injective ZtoC). (* Specialization of a few basic ssrnum order lemmas. *) Definition eqC_nat n p : (n%:R == p%:R :> algC) = (n == p) := eqr_nat _ n p. Definition leC_nat n p : (n%:R <= p%:R :> algC) = (n <= p)%N := ler_nat _ n p. Definition ltC_nat n p : (n%:R < p%:R :> algC) = (n < p)%N := ltr_nat _ n p. Definition Cchar : [char algC] =i pred0 := @char_num _. (* This can be used in the converse direction to evaluate assertions over *) (* manifest rationals, such as 3%:R^-1 + 7%:%^-1 < 2%:%^-1 :> algC. *) (* Missing norm and integer exponent, due to gaps in ssrint and rat. *) Definition CratrE := let CnF := Algebraics.Implementation.numFieldType in let QtoCm := ratr_rmorphism CnF in ((rmorph0 QtoCm, rmorph1 QtoCm, rmorphMn QtoCm, rmorphN QtoCm, rmorphD QtoCm), (rmorphM QtoCm, rmorphX QtoCm, fmorphV QtoCm), (rmorphMz QtoCm, rmorphXz QtoCm, @ratr_norm CnF, @ratr_sg CnF), =^~ (@ler_rat CnF, @ltr_rat CnF, (inj_eq (fmorph_inj QtoCm)))). Definition CintrE := let CnF := Algebraics.Implementation.numFieldType in let ZtoCm := intmul1_rmorphism CnF in ((rmorph0 ZtoCm, rmorph1 ZtoCm, rmorphMn ZtoCm, rmorphN ZtoCm, rmorphD ZtoCm), (rmorphM ZtoCm, rmorphX ZtoCm), (rmorphMz ZtoCm, @intr_norm CnF, @intr_sg CnF), =^~ (@ler_int CnF, @ltr_int CnF, (inj_eq (@intr_inj CnF)))). Let nz2 : 2%:R != 0 :> algC. Proof. by rewrite -!CintrE. Qed. (* Conjugation and norm. *) Definition conjCK : involutive conjC := Algebraics.Implementation.conjK. Definition normCK x : `|x| ^+ 2 = x * x^* := Algebraics.Implementation.normK x. Definition algC_algebraic x := Algebraics.Implementation.algebraic x. Lemma normCKC x : `|x| ^+ 2 = x^* * x. Proof. by rewrite normCK mulrC. Qed. Lemma mul_conjC_ge0 x : 0 <= x * x^*. Proof. by rewrite -normCK exprn_ge0 ?normr_ge0. Qed. Lemma mul_conjC_gt0 x : (0 < x * x^*) = (x != 0). Proof. have [->|x_neq0] := altP eqP; first by rewrite rmorph0 mulr0. by rewrite -normCK exprn_gt0 ?normr_gt0. Qed. Lemma mul_conjC_eq0 x : (x * x^* == 0) = (x == 0). Proof. by rewrite -normCK expf_eq0 normr_eq0. Qed. Lemma conjC_ge0 x : (0 <= x^*) = (0 <= x). Proof. wlog suffices: x / 0 <= x -> 0 <= x^*. by move=> IH; apply/idP/idP=> /IH; rewrite ?conjCK. rewrite le0r => /predU1P[-> | x_gt0]; first by rewrite rmorph0. by rewrite -(pmulr_rge0 _ x_gt0) mul_conjC_ge0. Qed. Lemma conjC_nat n : (n%:R)^* = n%:R. Proof. exact: rmorph_nat. Qed. Lemma conjC0 : 0^* = 0. Proof. exact: rmorph0. Qed. Lemma conjC1 : 1^* = 1. Proof. exact: rmorph1. Qed. Lemma conjC_eq0 x : (x^* == 0) = (x == 0). Proof. exact: fmorph_eq0. Qed. Lemma invC_norm x : x^-1 = `|x| ^- 2 * x^*. Proof. have [-> | nx_x] := eqVneq x 0; first by rewrite conjC0 mulr0 invr0. by rewrite normCK invfM divfK ?conjC_eq0. Qed. (* Real number subset. *) Lemma Creal0 : 0 \is Creal. Proof. exact: rpred0. Qed. Lemma Creal1 : 1 \is Creal. Proof. exact: rpred1. Qed. Hint Resolve Creal0 Creal1. (* Trivial cannot resolve a general real0 hint. *) Lemma CrealE x : (x \is Creal) = (x^* == x). Proof. rewrite realEsqr ger0_def normrX normCK. by have [-> | /mulfI/inj_eq-> //] := eqVneq x 0; rewrite rmorph0 !eqxx. Qed. Lemma CrealP {x} : reflect (x^* = x) (x \is Creal). Proof. by rewrite CrealE; apply: eqP. Qed. Lemma conj_Creal x : x \is Creal -> x^* = x. Proof. by move/CrealP. Qed. Lemma conj_normC z : `|z|^* = `|z|. Proof. by rewrite conj_Creal ?normr_real. Qed. Lemma geC0_conj x : 0 <= x -> x^* = x. Proof. by move=> /ger0_real/CrealP. Qed. Lemma geC0_unit_exp x n : 0 <= x -> (x ^+ n.+1 == 1) = (x == 1). Proof. by move=> x_ge0; rewrite pexpr_eq1. Qed. (* Elementary properties of roots. *) Ltac case_rootC := rewrite /rootC; case: (rootC_subproof _ _). Lemma root0C x : 0.-root x = 0. Proof. by case_rootC. Qed. Lemma rootCK n : (n > 0)%N -> cancel n.-root (fun x => x ^+ n). Proof. by case: n => //= n _ x; case_rootC. Qed. Lemma root1C x : 1.-root x = x. Proof. exact: (@rootCK 1). Qed. Lemma rootC0 n : n.-root 0 = 0. Proof. have [-> | n_gt0] := posnP n; first by rewrite root0C. by have /eqP := rootCK n_gt0 0; rewrite expf_eq0 n_gt0 /= => /eqP. Qed. Lemma rootC_inj n : (n > 0)%N -> injective n.-root. Proof. by move/rootCK/can_inj. Qed. Lemma eqr_rootC n : (n > 0)%N -> {mono n.-root : x y / x == y}. Proof. by move/rootC_inj/inj_eq. Qed. Lemma rootC_eq0 n x : (n > 0)%N -> (n.-root x == 0) = (x == 0). Proof. by move=> n_gt0; rewrite -{1}(rootC0 n) eqr_rootC. Qed. (* Rectangular coordinates. *) Lemma sqrCi : 'i ^+ 2 = -1. Proof. exact: rootCK. Qed. Lemma nonRealCi : 'i \isn't Creal. Proof. by rewrite realEsqr sqrCi oppr_ge0 ltr_geF ?ltr01. Qed. Lemma neq0Ci : 'i != 0. Proof. by apply: contraNneq nonRealCi => ->; apply: real0. Qed. Lemma normCi : `|'i| = 1. Proof. apply/eqP; rewrite -(@pexpr_eq1 _ _ 2) ?normr_ge0 //. by rewrite -normrX sqrCi normrN1. Qed. Lemma invCi : 'i^-1 = - 'i. Proof. by rewrite -div1r -[1]opprK -sqrCi mulNr mulfK ?neq0Ci. Qed. Lemma conjCi : 'i^* = - 'i. Proof. by rewrite -invCi invC_norm normCi expr1n invr1 mul1r. Qed. Lemma algCrect x : x = 'Re x + 'i * 'Im x. Proof. rewrite 2!mulrA -expr2 sqrCi mulN1r opprB -mulrDl addrACA subrr addr0. by rewrite -mulr2n -mulr_natr mulfK. Qed. Lemma Creal_Re x : 'Re x \is Creal. Proof. by rewrite CrealE fmorph_div rmorph_nat rmorphD conjCK addrC. Qed. Lemma Creal_Im x : 'Im x \is Creal. Proof. rewrite CrealE fmorph_div rmorph_nat rmorphM rmorphB conjCK. by rewrite conjCi -opprB mulrNN. Qed. Hint Resolve Creal_Re Creal_Im. Fact algRe_is_additive : additive algRe. Proof. by move=> x y; rewrite /algRe rmorphB addrACA -opprD mulrBl. Qed. Canonical algRe_additive := Additive algRe_is_additive. Fact algIm_is_additive : additive algIm. Proof. by move=> x y; rewrite /algIm rmorphB opprD addrACA -opprD mulrBr mulrBl. Qed. Canonical algIm_additive := Additive algIm_is_additive. Lemma Creal_ImP z : reflect ('Im z = 0) (z \is Creal). Proof. rewrite CrealE -subr_eq0 -(can_eq (mulKf neq0Ci)) mulr0. by rewrite -(can_eq (divfK nz2)) mul0r; apply: eqP. Qed. Lemma Creal_ReP z : reflect ('Re z = z) (z \in Creal). Proof. rewrite (sameP (Creal_ImP z) eqP) -(can_eq (mulKf neq0Ci)) mulr0. by rewrite -(inj_eq (addrI ('Re z))) addr0 -algCrect eq_sym; apply: eqP. Qed. Lemma algReMl : {in Creal, forall x, {morph algRe : z / x * z}}. Proof. by move=> x Rx z /=; rewrite /algRe rmorphM (conj_Creal Rx) -mulrDr -mulrA. Qed. Lemma algReMr : {in Creal, forall x, {morph algRe : z / z * x}}. Proof. by move=> x Rx z /=; rewrite mulrC algReMl // mulrC. Qed. Lemma algImMl : {in Creal, forall x, {morph algIm : z / x * z}}. Proof. by move=> x Rx z; rewrite /algIm rmorphM (conj_Creal Rx) -mulrBr mulrCA !mulrA. Qed. Lemma algImMr : {in Creal, forall x, {morph algIm : z / z * x}}. Proof. by move=> x Rx z /=; rewrite mulrC algImMl // mulrC. Qed. Lemma algRe_i : 'Re 'i = 0. Proof. by rewrite /algRe conjCi subrr mul0r. Qed. Lemma algIm_i : 'Im 'i = 1. Proof. rewrite /algIm conjCi -opprD mulrN -mulr2n mulrnAr ['i * _]sqrCi. by rewrite mulNrn opprK divff. Qed. Lemma algRe_conj z : 'Re z^* = 'Re z. Proof. by rewrite /algRe addrC conjCK. Qed. Lemma algIm_conj z : 'Im z^* = - 'Im z. Proof. by rewrite /algIm -mulNr -mulrN opprB conjCK. Qed. Lemma algRe_rect : {in Creal &, forall x y, 'Re (x + 'i * y) = x}. Proof. move=> x y Rx Ry; rewrite /= raddfD /= (Creal_ReP x Rx). by rewrite algReMr // algRe_i mul0r addr0. Qed. Lemma algIm_rect : {in Creal &, forall x y, 'Im (x + 'i * y) = y}. Proof. move=> x y Rx Ry; rewrite /= raddfD /= (Creal_ImP x Rx) add0r. by rewrite algImMr // algIm_i mul1r. Qed. Lemma conjC_rect : {in Creal &, forall x y, (x + 'i * y)^* = x - 'i * y}. Proof. by move=> x y Rx Ry; rewrite /= rmorphD rmorphM conjCi mulNr !conj_Creal. Qed. Lemma addC_rect x1 y1 x2 y2 : (x1 + 'i * y1) + (x2 + 'i * y2) = x1 + x2 + 'i * (y1 + y2). Proof. by rewrite addrACA -mulrDr. Qed. Lemma oppC_rect x y : - (x + 'i * y) = - x + 'i * (- y). Proof. by rewrite mulrN -opprD. Qed. Lemma subC_rect x1 y1 x2 y2 : (x1 + 'i * y1) - (x2 + 'i * y2) = x1 - x2 + 'i * (y1 - y2). Proof. by rewrite oppC_rect addC_rect. Qed. Lemma mulC_rect x1 y1 x2 y2 : (x1 + 'i * y1) * (x2 + 'i * y2) = x1 * x2 - y1 * y2 + 'i * (x1 * y2 + x2 * y1). Proof. rewrite mulrDl !mulrDr mulrCA -!addrA mulrAC -mulrA; congr (_ + _). by rewrite mulrACA -expr2 sqrCi mulN1r addrA addrC. Qed. Lemma normC2_rect : {in Creal &, forall x y, `|x + 'i * y| ^+ 2 = x ^+ 2 + y ^+ 2}. Proof. move=> x y Rx Ry; rewrite /= normCK rmorphD rmorphM conjCi !conj_Creal //. by rewrite mulrC mulNr -subr_sqr exprMn sqrCi mulN1r opprK. Qed. Lemma normC2_Re_Im z : `|z| ^+ 2 = 'Re z ^+ 2 + 'Im z ^+ 2. Proof. by rewrite -normC2_rect -?algCrect. Qed. Lemma invC_rect : {in Creal &, forall x y, (x + 'i * y)^-1 = (x - 'i * y) / (x ^+ 2 + y ^+ 2)}. Proof. by move=> x y Rx Ry; rewrite /= invC_norm conjC_rect // mulrC normC2_rect. Qed. Lemma lerif_normC_Re_Creal z : `|'Re z| <= `|z| ?= iff (z \is Creal). Proof. rewrite -(mono_in_lerif ler_sqr); try by rewrite qualifE normr_ge0. rewrite normCK conj_Creal // normC2_Re_Im -expr2. rewrite addrC -lerif_subLR subrr (sameP (Creal_ImP _) eqP) -sqrf_eq0 eq_sym. by apply: lerif_eq; rewrite -realEsqr. Qed. Lemma lerif_Re_Creal z : 'Re z <= `|z| ?= iff (0 <= z). Proof. have ubRe: 'Re z <= `|'Re z| ?= iff (0 <= 'Re z). by rewrite ger0_def eq_sym; apply/lerif_eq/real_ler_norm. congr (_ <= _ ?= iff _): (lerif_trans ubRe (lerif_normC_Re_Creal z)). apply/andP/idP=> [[zRge0 /Creal_ReP <- //] | z_ge0]. by have Rz := ger0_real z_ge0; rewrite (Creal_ReP _ _). Qed. (* Equality from polar coordinates, for the upper plane. *) Lemma eqC_semipolar x y : `|x| = `|y| -> 'Re x = 'Re y -> 0 <= 'Im x * 'Im y -> x = y. Proof. move=> eq_norm eq_Re sign_Im. rewrite [x]algCrect [y]algCrect eq_Re; congr (_ + 'i * _). have /eqP := congr1 (fun z => z ^+ 2) eq_norm. rewrite !normC2_Re_Im eq_Re (can_eq (addKr _)) eqf_sqr => /pred2P[] // eq_Im. rewrite eq_Im mulNr -expr2 oppr_ge0 real_exprn_even_le0 //= in sign_Im. by rewrite eq_Im (eqP sign_Im) oppr0. Qed. (* Nth roots. *) Let argCleP y z : reflect (0 <= 'Im z -> 0 <= 'Im y /\ 'Re z <= 'Re y) (argCle y z). Proof. suffices dIm x: nnegIm x = (0 <= 'Im x). rewrite /argCle !dIm ler_pmul2r ?invr_gt0 ?ltr0n //. by apply: (iffP implyP) => geZyz /geZyz/andP. rewrite /('Im x) pmulr_lge0 ?invr_gt0 ?ltr0n //; congr (0 <= _ * _). case Du: algCi_subproof => [u u2N1] /=. have/eqP := u2N1; rewrite -sqrCi eqf_sqr => /pred2P[] //. have:= conjCi; rewrite /'i; case_rootC => /= v v2n1 min_v conj_v Duv. have{min_v} /idPn[] := min_v u isT u2N1; rewrite negb_imply /nnegIm Du /= Duv. rewrite rmorphN conj_v opprK -opprD mulrNN mulNr -mulr2n mulrnAr -expr2 v2n1. by rewrite mulNrn opprK ler0n oppr_ge0 (leC_nat 2 0). Qed. Lemma rootC_Re_max n x y : (n > 0)%N -> y ^+ n = x -> 0 <= 'Im y -> 'Re y <= 'Re (n.-root%C x). Proof. by move=> n_gt0 yn_x leI0y; case_rootC=> z /= _ /(_ y n_gt0 yn_x)/argCleP[]. Qed. Let neg_unity_root n : (n > 1)%N -> exists2 w : algC, w ^+ n = 1 & 'Re w < 0. Proof. move=> n_gt1; have [|w /eqP pw_0] := closed_rootP (\poly_(i < n) (1 : algC)) _. by rewrite size_poly_eq ?oner_eq0 // -(subnKC n_gt1). rewrite horner_poly (eq_bigr _ (fun _ _ => mul1r _)) in pw_0. have wn1: w ^+ n = 1 by apply/eqP; rewrite -subr_eq0 subrX1 pw_0 mulr0. suffices /existsP[i ltRwi0]: [exists i : 'I_n, 'Re (w ^+ i) < 0]. by exists (w ^+ i) => //; rewrite exprAC wn1 expr1n. apply: contra_eqT (congr1 algRe pw_0); rewrite negb_exists => /forallP geRw0. rewrite raddf_sum raddf0 /= (bigD1 (Ordinal (ltnW n_gt1))) //=. rewrite (Creal_ReP _ _) ?rpred1 // gtr_eqF ?ltr_paddr ?ltr01 //=. by apply: sumr_ge0 => i _; rewrite real_lerNgt. Qed. Lemma Im_rootC_ge0 n x : (n > 1)%N -> 0 <= 'Im (n.-root x). Proof. set y := n.-root x => n_gt1; have n_gt0 := ltnW n_gt1. apply: wlog_neg; rewrite -real_ltrNge // => ltIy0. suffices [z zn_x leI0z]: exists2 z, z ^+ n = x & 'Im z >= 0. by rewrite /y; case_rootC => /= y1 _ /(_ z n_gt0 zn_x)/argCleP[]. have [w wn1 ltRw0] := neg_unity_root n_gt1. wlog leRI0yw: w wn1 ltRw0 / 0 <= 'Re y * 'Im w. move=> IHw; have: 'Re y * 'Im w \is Creal by rewrite rpredM. case/real_ger0P=> [|/ltrW leRIyw0]; first exact: IHw. apply: (IHw w^*); rewrite ?algRe_conj ?algIm_conj ?mulrN ?oppr_ge0 //. by rewrite -rmorphX wn1 rmorph1. exists (w * y); first by rewrite exprMn wn1 mul1r rootCK. rewrite [w]algCrect [y]algCrect mulC_rect. by rewrite algIm_rect ?rpredD ?rpredN 1?rpredM // addr_ge0 // ltrW ?nmulr_rgt0. Qed. Lemma rootC_lt0 n x : (1 < n)%N -> (n.-root x < 0) = false. Proof. set y := n.-root x => n_gt1; have n_gt0 := ltnW n_gt1. apply: negbTE; apply: wlog_neg => /negbNE lt0y; rewrite ler_gtF //. have Rx: x \is Creal by rewrite -[x](rootCK n_gt0) rpredX // ltr0_real. have Re_y: 'Re y = y by apply/Creal_ReP; rewrite ltr0_real. have [z zn_x leR0z]: exists2 z, z ^+ n = x & 'Re z >= 0. have [w wn1 ltRw0] := neg_unity_root n_gt1. exists (w * y); first by rewrite exprMn wn1 mul1r rootCK. by rewrite algReMr ?ltr0_real // ltrW // nmulr_lgt0. without loss leI0z: z zn_x leR0z / 'Im z >= 0. move=> IHz; have: 'Im z \is Creal by []. case/real_ger0P=> [|/ltrW leIz0]; first exact: IHz. apply: (IHz z^*); rewrite ?algRe_conj ?algIm_conj ?oppr_ge0 //. by rewrite -rmorphX zn_x conj_Creal. by apply: ler_trans leR0z _; rewrite -Re_y ?rootC_Re_max ?ltr0_real. Qed. Lemma rootC_ge0 n x : (n > 0)%N -> (0 <= n.-root x) = (0 <= x). Proof. set y := n.-root x => n_gt0. apply/idP/idP=> [/(exprn_ge0 n) | x_ge0]; first by rewrite rootCK. rewrite -(ger_lerif (lerif_Re_Creal y)). have Ray: `|y| \is Creal by apply: normr_real. rewrite -(Creal_ReP _ Ray) rootC_Re_max ?(Creal_ImP _ Ray) //. by rewrite -normrX rootCK // ger0_norm. Qed. Lemma rootC_gt0 n x : (n > 0)%N -> (n.-root x > 0) = (x > 0). Proof. by move=> n_gt0; rewrite !lt0r rootC_ge0 ?rootC_eq0. Qed. Lemma rootC_le0 n x : (1 < n)%N -> (n.-root x <= 0) = (x == 0). Proof. by move=> n_gt1; rewrite ler_eqVlt rootC_lt0 // orbF rootC_eq0 1?ltnW. Qed. Lemma ler_rootCl n : (n > 0)%N -> {in Num.nneg, {mono n.-root : x y / x <= y}}. Proof. move=> n_gt0 x x_ge0 y; have [y_ge0 | not_y_ge0] := boolP (0 <= y). by rewrite -(ler_pexpn2r n_gt0) ?qualifE ?rootC_ge0 ?rootCK. rewrite (contraNF (@ler_trans _ _ 0 _ _)) ?rootC_ge0 //. by rewrite (contraNF (ler_trans x_ge0)). Qed. Lemma ler_rootC n : (n > 0)%N -> {in Num.nneg &, {mono n.-root : x y / x <= y}}. Proof. by move=> n_gt0 x y x_ge0 _; apply: ler_rootCl. Qed. Lemma ltr_rootCl n : (n > 0)%N -> {in Num.nneg, {mono n.-root : x y / x < y}}. Proof. by move=> n_gt0 x x_ge0 y; rewrite !ltr_def ler_rootCl ?eqr_rootC. Qed. Lemma ltr_rootC n : (n > 0)%N -> {in Num.nneg &, {mono n.-root : x y / x < y}}. Proof. by move/ler_rootC/lerW_mono_in. Qed. Lemma exprCK n x : (0 < n)%N -> 0 <= x -> n.-root (x ^+ n) = x. Proof. move=> n_gt0 x_ge0; apply/eqP. by rewrite -(eqr_expn2 n_gt0) ?rootC_ge0 ?exprn_ge0 ?rootCK. Qed. Lemma norm_rootC n x : `|n.-root x| = n.-root `|x|. Proof. have [-> | n_gt0] := posnP n; first by rewrite !root0C normr0. apply/eqP; rewrite -(eqr_expn2 n_gt0) ?rootC_ge0 ?normr_ge0 //. by rewrite -normrX !rootCK. Qed. Lemma rootCX n x k : (n > 0)%N -> 0 <= x -> n.-root (x ^+ k) = n.-root x ^+ k. Proof. move=> n_gt0 x_ge0; apply/eqP. by rewrite -(eqr_expn2 n_gt0) ?(exprn_ge0, rootC_ge0) // 1?exprAC !rootCK. Qed. Lemma rootC1 n : (n > 0)%N -> n.-root 1 = 1. Proof. by move/(rootCX 0)/(_ ler01). Qed. Lemma rootCpX n x k : (k > 0)%N -> 0 <= x -> n.-root (x ^+ k) = n.-root x ^+ k. Proof. by case: n => [|n] k_gt0; [rewrite !root0C expr0n gtn_eqF | exact: rootCX]. Qed. Lemma rootCV n x : (n > 0)%N -> 0 <= x -> n.-root x^-1 = (n.-root x)^-1. Proof. move=> n_gt0 x_ge0; apply/eqP. by rewrite -(eqr_expn2 n_gt0) ?(invr_ge0, rootC_ge0) // !exprVn !rootCK. Qed. Lemma rootC_eq1 n x : (n > 0)%N -> (n.-root x == 1) = (x == 1). Proof. by move=> n_gt0; rewrite -{1}(rootC1 n_gt0) eqr_rootC. Qed. Lemma rootC_ge1 n x : (n > 0)%N -> (n.-root x >= 1) = (x >= 1). Proof. by move=> n_gt0; rewrite -{1}(rootC1 n_gt0) ler_rootCl // qualifE ler01. Qed. Lemma rootC_gt1 n x : (n > 0)%N -> (n.-root x > 1) = (x > 1). Proof. by move=> n_gt0; rewrite !ltr_def rootC_eq1 ?rootC_ge1. Qed. Lemma rootC_le1 n x : (n > 0)%N -> 0 <= x -> (n.-root x <= 1) = (x <= 1). Proof. by move=> n_gt0 x_ge0; rewrite -{1}(rootC1 n_gt0) ler_rootCl. Qed. Lemma rootC_lt1 n x : (n > 0)%N -> 0 <= x -> (n.-root x < 1) = (x < 1). Proof. by move=> n_gt0 x_ge0; rewrite !ltr_neqAle rootC_eq1 ?rootC_le1. Qed. Lemma rootCMl n x z : 0 <= x -> n.-root (x * z) = n.-root x * n.-root z. Proof. rewrite le0r => /predU1P[-> | x_gt0]; first by rewrite !(mul0r, rootC0). have [| n_gt1 | ->] := ltngtP n 1; last by rewrite !root1C. by case: n => //; rewrite !root0C mul0r. have [x_ge0 n_gt0] := (ltrW x_gt0, ltnW n_gt1). have nx_gt0: 0 < n.-root x by rewrite rootC_gt0. have Rnx: n.-root x \is Creal by rewrite ger0_real ?ltrW. apply: eqC_semipolar; last 1 first; try apply/eqP. - by rewrite algImMl // !(Im_rootC_ge0, mulr_ge0, rootC_ge0). - by rewrite -(eqr_expn2 n_gt0) ?normr_ge0 // -!normrX exprMn !rootCK. rewrite eqr_le; apply/andP; split; last first. rewrite rootC_Re_max ?exprMn ?rootCK ?algImMl //. by rewrite mulr_ge0 ?Im_rootC_ge0 ?ltrW. rewrite -[n.-root _](mulVKf (negbT (gtr_eqF nx_gt0))) !(algReMl Rnx) //. rewrite ler_pmul2l // rootC_Re_max ?exprMn ?exprVn ?rootCK ?mulKf ?gtr_eqF //. by rewrite algImMl ?rpredV // mulr_ge0 ?invr_ge0 ?Im_rootC_ge0 ?ltrW. Qed. Lemma rootCMr n x z : 0 <= x -> n.-root (z * x) = n.-root z * n.-root x. Proof. by move=> x_ge0; rewrite mulrC rootCMl // mulrC. Qed. (* More properties of n.-root will be established in cyclotomic.v. *) (* The proper form of the Arithmetic - Geometric Mean inequality. *) Lemma lerif_rootC_AGM (I : finType) (A : pred I) (n := #|A|) E : {in A, forall i, 0 <= E i} -> n.-root (\prod_(i in A) E i) <= (\sum_(i in A) E i) / n%:R ?= iff [forall i in A, forall j in A, E i == E j]. Proof. move=> Ege0; have [n0 | n_gt0] := posnP n. rewrite n0 root0C invr0 mulr0; apply/lerif_refl/forall_inP=> i. by rewrite (card0_eq n0). rewrite -(mono_in_lerif (ler_pexpn2r n_gt0)) ?rootCK //=; first 1 last. - by rewrite qualifE rootC_ge0 // prodr_ge0. - by rewrite rpred_div ?rpred_nat ?rpred_sum. exact: lerif_AGM. Qed. (* Square root. *) Lemma sqrtC0 : sqrtC 0 = 0. Proof. exact: rootC0. Qed. Lemma sqrtC1 : sqrtC 1 = 1. Proof. exact: rootC1. Qed. Lemma sqrtCK x : sqrtC x ^+ 2 = x. Proof. exact: rootCK. Qed. Lemma sqrCK x : 0 <= x -> sqrtC (x ^+ 2) = x. Proof. exact: exprCK. Qed. Lemma sqrtC_ge0 x : (0 <= sqrtC x) = (0 <= x). Proof. exact: rootC_ge0. Qed. Lemma sqrtC_eq0 x : (sqrtC x == 0) = (x == 0). Proof. exact: rootC_eq0. Qed. Lemma sqrtC_gt0 x : (sqrtC x > 0) = (x > 0). Proof. exact: rootC_gt0. Qed. Lemma sqrtC_lt0 x : (sqrtC x < 0) = false. Proof. exact: rootC_lt0. Qed. Lemma sqrtC_le0 x : (sqrtC x <= 0) = (x == 0). Proof. exact: rootC_le0. Qed. Lemma ler_sqrtC : {in Num.nneg &, {mono sqrtC : x y / x <= y}}. Proof. exact: ler_rootC. Qed. Lemma ltr_sqrtC : {in Num.nneg &, {mono sqrtC : x y / x < y}}. Proof. exact: ltr_rootC. Qed. Lemma eqr_sqrtC : {mono sqrtC : x y / x == y}. Proof. exact: eqr_rootC. Qed. Lemma sqrtC_inj : injective sqrtC. Proof. exact: rootC_inj. Qed. Lemma sqrtCM : {in Num.nneg &, {morph sqrtC : x y / x * y}}. Proof. by move=> x y _; apply: rootCMr. Qed. Lemma sqrCK_P x : reflect (sqrtC (x ^+ 2) = x) ((0 <= 'Im x) && ~~ (x < 0)). Proof. apply: (iffP andP) => [[leI0x not_gt0x] | <-]; last first. by rewrite sqrtC_lt0 Im_rootC_ge0. have /eqP := sqrtCK (x ^+ 2); rewrite eqf_sqr => /pred2P[] // defNx. apply: sqrCK; rewrite -real_lerNgt // in not_gt0x; apply/Creal_ImP/ler_anti; by rewrite leI0x -oppr_ge0 -raddfN -defNx Im_rootC_ge0. Qed. Lemma normC_def x : `|x| = sqrtC (x * x^*). Proof. by rewrite -normCK sqrCK ?normr_ge0. Qed. Lemma norm_conjC x : `|x^*| = `|x|. Proof. by rewrite !normC_def conjCK mulrC. Qed. Lemma normC_rect : {in Creal &, forall x y, `|x + 'i * y| = sqrtC (x ^+ 2 + y ^+ 2)}. Proof. by move=> x y Rx Ry; rewrite /= normC_def -normCK normC2_rect. Qed. Lemma normC_Re_Im z : `|z| = sqrtC ('Re z ^+ 2 + 'Im z ^+ 2). Proof. by rewrite normC_def -normCK normC2_Re_Im. Qed. (* Norm sum (in)equalities. *) Lemma normC_add_eq x y : `|x + y| = `|x| + `|y| -> {t : algC | `|t| == 1 & (x, y) = (`|x| * t, `|y| * t)}. Proof. move=> lin_xy; apply: sig2_eqW; pose u z := if z == 0 then 1 else z / `|z|. have uE z: (`|u z| = 1) * (`|z| * u z = z). rewrite /u; have [->|nz_z] := altP eqP; first by rewrite normr0 normr1 mul0r. by rewrite normf_div normr_id mulrCA divff ?mulr1 ?normr_eq0. have [->|nz_x] := eqVneq x 0; first by exists (u y); rewrite uE ?normr0 ?mul0r. exists (u x); rewrite uE // /u (negPf nz_x); congr (_ , _). have{lin_xy} def2xy: `|x| * `|y| *+ 2 = x * y ^* + y * x ^*. apply/(addrI (x * x^*))/(addIr (y * y^*)); rewrite -2!{1}normCK -sqrrD. by rewrite addrA -addrA -!mulrDr -mulrDl -rmorphD -normCK lin_xy. have def_xy: x * y^* = y * x^*. apply/eqP; rewrite -subr_eq0 -[_ == 0](@expf_eq0 _ _ 2). rewrite (canRL (subrK _) (subr_sqrDB _ _)) opprK -def2xy exprMn_n exprMn. by rewrite mulrN mulrAC mulrA -mulrA mulrACA -!normCK mulNrn addNr. have{def_xy def2xy} def_yx: `|y * x| = y * x^*. by apply: (mulIf nz2); rewrite !mulr_natr mulrC normrM def2xy def_xy. rewrite -{1}(divfK nz_x y) invC_norm mulrCA -{}def_yx !normrM invfM. by rewrite mulrCA divfK ?normr_eq0 // mulrAC mulrA. Qed. Lemma normC_sum_eq (I : finType) (P : pred I) (F : I -> algC) : `|\sum_(i | P i) F i| = \sum_(i | P i) `|F i| -> {t : algC | `|t| == 1 & forall i, P i -> F i = `|F i| * t}. Proof. have [i /andP[Pi nzFi] | F0] := pickP [pred i | P i & F i != 0]; last first. exists 1 => [|i Pi]; first by rewrite normr1. by case/nandP: (F0 i) => [/negP[]// | /negbNE/eqP->]; rewrite normr0 mul0r. rewrite !(bigD1 i Pi) /= => norm_sumF; pose Q j := P j && (j != i). rewrite -normr_eq0 in nzFi; set c := F i / `|F i|; exists c => [|j Pj]. by rewrite normrM normfV normr_id divff. have [Qj | /nandP[/negP[]// | /negbNE/eqP->]] := boolP (Q j); last first. by rewrite mulrC divfK. have: `|F i + F j| = `|F i| + `|F j|. do [rewrite !(bigD1 j Qj) /=; set z := \sum_(k | _) `|_|] in norm_sumF. apply/eqP; rewrite eqr_le ler_norm_add -(ler_add2r z) -addrA -norm_sumF addrA. by rewrite (ler_trans (ler_norm_add _ _)) // ler_add2l ler_norm_sum. by case/normC_add_eq=> k _ [/(canLR (mulKf nzFi)) <-]; rewrite -(mulrC (F i)). Qed. Lemma normC_sum_eq1 (I : finType) (P : pred I) (F : I -> algC) : `|\sum_(i | P i) F i| = (\sum_(i | P i) `|F i|) -> (forall i, P i -> `|F i| = 1) -> {t : algC | `|t| == 1 & forall i, P i -> F i = t}. Proof. case/normC_sum_eq=> t t1 defF normF. by exists t => // i Pi; rewrite defF // normF // mul1r. Qed. Lemma normC_sum_upper (I : finType) (P : pred I) (F G : I -> algC) : (forall i, P i -> `|F i| <= G i) -> \sum_(i | P i) F i = \sum_(i | P i) G i -> forall i, P i -> F i = G i. Proof. set sumF := \sum_(i | _) _; set sumG := \sum_(i | _) _ => leFG eq_sumFG. have posG i: P i -> 0 <= G i by move/leFG; apply: ler_trans; exact: normr_ge0. have norm_sumG: `|sumG| = sumG by rewrite ger0_norm ?sumr_ge0. have norm_sumF: `|sumF| = \sum_(i | P i) `|F i|. apply/eqP; rewrite eqr_le ler_norm_sum eq_sumFG norm_sumG -subr_ge0 -sumrB. by rewrite sumr_ge0 // => i Pi; rewrite subr_ge0 ?leFG. have [t _ defF] := normC_sum_eq norm_sumF. have [/(psumr_eq0P posG) G0 i Pi | nz_sumG] := eqVneq sumG 0. by apply/eqP; rewrite G0 // -normr_eq0 eqr_le normr_ge0 -(G0 i Pi) leFG. have t1: t = 1. apply: (mulfI nz_sumG); rewrite mulr1 -{1}norm_sumG -eq_sumFG norm_sumF. by rewrite mulr_suml -(eq_bigr _ defF). have /psumr_eq0P eqFG i: P i -> 0 <= G i - F i. by move=> Pi; rewrite subr_ge0 defF // t1 mulr1 leFG. move=> i /eqFG/(canRL (subrK _))->; rewrite ?add0r //. by rewrite sumrB -/sumF eq_sumFG subrr. Qed. Lemma normC_sub_eq x y : `|x - y| = `|x| - `|y| -> {t | `|t| == 1 & (x, y) = (`|x| * t, `|y| * t)}. Proof. rewrite -{-1}(subrK y x) => /(canLR (subrK _))/esym-Dx; rewrite Dx. by have [t ? [Dxy Dy]] := normC_add_eq Dx; exists t; rewrite // mulrDl -Dxy -Dy. Qed. (* Integer subset. *) (* Not relying on the undocumented interval library, for now. *) Lemma floorC_itv x : x \is Creal -> (floorC x)%:~R <= x < (floorC x + 1)%:~R. Proof. by rewrite /floorC => Rx; case: (floorC_subproof x) => //= m; apply. Qed. Lemma floorC_def x m : m%:~R <= x < (m + 1)%:~R -> floorC x = m. Proof. case/andP=> lemx ltxm1; apply/eqP; rewrite eqr_le -!ltz_addr1. have /floorC_itv/andP[lefx ltxf1]: x \is Creal. by rewrite -[x](subrK m%:~R) rpredD ?realz ?ler_sub_real. by rewrite -!(ltr_int [numFieldType of algC]) 2?(@ler_lt_trans _ x). Qed. Lemma intCK : cancel intr floorC. Proof. by move=> m; apply: floorC_def; rewrite ler_int ltr_int ltz_addr1 lerr. Qed. Lemma floorCK : {in Cint, cancel floorC intr}. Proof. by move=> z /eqP. Qed. Lemma floorC0 : floorC 0 = 0. Proof. exact: (intCK 0). Qed. Lemma floorC1 : floorC 1 = 1. Proof. exact: (intCK 1). Qed. Hint Resolve floorC0 floorC1. Lemma floorCpK (p : {poly algC}) : p \is a polyOver Cint -> map_poly intr (map_poly floorC p) = p. Proof. move/(all_nthP 0)=> Zp; apply/polyP=> i. rewrite coef_map coef_map_id0 //= -[p]coefK coef_poly. by case: ifP => [/Zp/floorCK // | _]; rewrite floorC0. Qed. Lemma floorCpP (p : {poly algC}) : p \is a polyOver Cint -> {q | p = map_poly intr q}. Proof. by exists (map_poly floorC p); rewrite floorCpK. Qed. Lemma Cint_int m : m%:~R \in Cint. Proof. by rewrite unfold_in intCK. Qed. Lemma CintP x : reflect (exists m, x = m%:~R) (x \in Cint). Proof. by apply: (iffP idP) => [/eqP<-|[m ->]]; [exists (floorC x) | apply: Cint_int]. Qed. Lemma floorCD : {in Cint & Creal, {morph floorC : x y / x + y}}. Proof. move=> _ y /CintP[m ->] Ry; apply: floorC_def. by rewrite -addrA 2!rmorphD /= intCK ler_add2l ltr_add2l floorC_itv. Qed. Lemma floorCN : {in Cint, {morph floorC : x / - x}}. Proof. by move=> _ /CintP[m ->]; rewrite -rmorphN !intCK. Qed. Lemma floorCM : {in Cint &, {morph floorC : x y / x * y}}. Proof. by move=> _ _ /CintP[m1 ->] /CintP[m2 ->]; rewrite -rmorphM !intCK. Qed. Lemma floorCX n : {in Cint, {morph floorC : x / x ^+ n}}. Proof. by move=> _ /CintP[m ->]; rewrite -rmorphX !intCK. Qed. Lemma rpred_Cint S (ringS : subringPred S) (kS : keyed_pred ringS) x : x \in Cint -> x \in kS. Proof. by case/CintP=> m ->; apply: rpred_int. Qed. Lemma Cint0 : 0 \in Cint. Proof. exact: (Cint_int 0). Qed. Lemma Cint1 : 1 \in Cint. Proof. exact: (Cint_int 1). Qed. Hint Resolve Cint0 Cint1. Fact Cint_key : pred_key Cint. Proof. by []. Qed. Fact Cint_subring : subring_closed Cint. Proof. by split=> // _ _ /CintP[m ->] /CintP[p ->]; rewrite -(rmorphB, rmorphM) Cint_int. Qed. Canonical Cint_keyed := KeyedPred Cint_key. Canonical Cint_opprPred := OpprPred Cint_subring. Canonical Cint_addrPred := AddrPred Cint_subring. Canonical Cint_mulrPred := MulrPred Cint_subring. Canonical Cint_zmodPred := ZmodPred Cint_subring. Canonical Cint_semiringPred := SemiringPred Cint_subring. Canonical Cint_smulrPred := SmulrPred Cint_subring. Canonical Cint_subringPred := SubringPred Cint_subring. Lemma Creal_Cint : {subset Cint <= Creal}. Proof. by move=> _ /CintP[m ->]; apply: realz. Qed. Lemma conj_Cint x : x \in Cint -> x^* = x. Proof. by move/Creal_Cint/conj_Creal. Qed. Lemma Cint_normK x : x \in Cint -> `|x| ^+ 2 = x ^+ 2. Proof. by move/Creal_Cint/real_normK. Qed. Lemma CintEsign x : x \in Cint -> x = (-1) ^+ (x < 0)%C * `|x|. Proof. by move/Creal_Cint/realEsign. Qed. (* Natural integer subset. *) Lemma truncC_itv x : 0 <= x -> (truncC x)%:R <= x < (truncC x).+1%:R. Proof. move=> x_ge0; have /andP[lemx ltxm1] := floorC_itv (ger0_real x_ge0). rewrite /truncC x_ge0 -addn1 !pmulrn PoszD gez0_abs ?lemx //. by rewrite -ltz_addr1 -(ltr_int [numFieldType of algC]) (ler_lt_trans x_ge0). Qed. Lemma truncC_def x n : n%:R <= x < n.+1%:R -> truncC x = n. Proof. move=> ivt_n_x; have /andP[lenx _] := ivt_n_x. by rewrite /truncC (ler_trans (ler0n _ n)) // (@floorC_def _ n) // addrC -intS. Qed. Lemma natCK n : truncC n%:R = n. Proof. by apply: truncC_def; rewrite lerr ltr_nat /=. Qed. Lemma CnatP x : reflect (exists n, x = n%:R) (x \in Cnat). Proof. by apply: (iffP eqP) => [<- | [n ->]]; [exists (truncC x) | rewrite natCK]. Qed. Lemma truncCK : {in Cnat, cancel truncC (GRing.natmul 1)}. Proof. by move=> x /eqP. Qed. Lemma truncC_gt0 x : (0 < truncC x)%N = (1 <= x). Proof. apply/idP/idP=> [m_gt0 | x_ge1]. have /truncC_itv/andP[lemx _]: 0 <= x. by move: m_gt0; rewrite /truncC; case: ifP. by apply: ler_trans lemx; rewrite ler1n. have /truncC_itv/andP[_ ltxm1]:= ler_trans ler01 x_ge1. by rewrite -ltnS -ltC_nat (ler_lt_trans x_ge1). Qed. Lemma truncC0Pn x : reflect (truncC x = 0%N) (~~ (1 <= x)). Proof. by rewrite -truncC_gt0 -eqn0Ngt; apply: eqP. Qed. Lemma truncC0 : truncC 0 = 0%N. Proof. exact: (natCK 0). Qed. Lemma truncC1 : truncC 1 = 1%N. Proof. exact: (natCK 1). Qed. Lemma truncCD : {in Cnat & Num.nneg, {morph truncC : x y / x + y >-> (x + y)%N}}. Proof. move=> _ y /CnatP[n ->] y_ge0; apply: truncC_def. by rewrite -addnS !natrD !natCK ler_add2l ltr_add2l truncC_itv. Qed. Lemma truncCM : {in Cnat &, {morph truncC : x y / x * y >-> (x * y)%N}}. Proof. by move=> _ _ /CnatP[n1 ->] /CnatP[n2 ->]; rewrite -natrM !natCK. Qed. Lemma truncCX n : {in Cnat, {morph truncC : x / x ^+ n >-> (x ^ n)%N}}. Proof. by move=> _ /CnatP[n1 ->]; rewrite -natrX !natCK. Qed. Lemma rpred_Cnat S (ringS : semiringPred S) (kS : keyed_pred ringS) x : x \in Cnat -> x \in kS. Proof. by case/CnatP=> n ->; apply: rpred_nat. Qed. Lemma Cnat_nat n : n%:R \in Cnat. Proof. by apply/CnatP; exists n. Qed. Lemma Cnat0 : 0 \in Cnat. Proof. exact: (Cnat_nat 0). Qed. Lemma Cnat1 : 1 \in Cnat. Proof. exact: (Cnat_nat 1). Qed. Hint Resolve Cnat_nat Cnat0 Cnat1. Fact Cnat_key : pred_key Cnat. Proof. by []. Qed. Fact Cnat_semiring : semiring_closed Cnat. Proof. by do 2![split] => //= _ _ /CnatP[n ->] /CnatP[m ->]; rewrite -(natrD, natrM). Qed. Canonical Cnat_keyed := KeyedPred Cnat_key. Canonical Cnat_addrPred := AddrPred Cnat_semiring. Canonical Cnat_mulrPred := MulrPred Cnat_semiring. Canonical Cnat_semiringPred := SemiringPred Cnat_semiring. Lemma Cnat_ge0 x : x \in Cnat -> 0 <= x. Proof. by case/CnatP=> n ->; apply: ler0n. Qed. Lemma Cnat_gt0 x : x \in Cnat -> (0 < x) = (x != 0). Proof. by case/CnatP=> n ->; rewrite pnatr_eq0 ltr0n lt0n. Qed. Lemma conj_Cnat x : x \in Cnat -> x^* = x. Proof. by case/CnatP=> n ->; apply: rmorph_nat. Qed. Lemma norm_Cnat x : x \in Cnat -> `|x| = x. Proof. by move/Cnat_ge0/ger0_norm. Qed. Lemma Creal_Cnat : {subset Cnat <= Creal}. Proof. by move=> z /conj_Cnat/CrealP. Qed. Lemma Cnat_sum_eq1 (I : finType) (P : pred I) (F : I -> algC) : (forall i, P i -> F i \in Cnat) -> \sum_(i | P i) F i = 1 -> {i : I | [/\ P i, F i = 1 & forall j, j != i -> P j -> F j = 0]}. Proof. move=> natF sumF1; pose nF i := truncC (F i). have{natF} defF i: P i -> F i = (nF i)%:R by move/natF/eqP. have{sumF1} /eqP sumF1: (\sum_(i | P i) nF i == 1)%N. by rewrite -eqC_nat natr_sum -(eq_bigr _ defF) sumF1. have [i Pi nZfi]: {i : I | P i & nF i != 0%N}. by apply/sig2W/exists_inP; rewrite -negb_forall_in -sum_nat_eq0 sumF1. have F'ge0 := (leq0n _, etrans (eq_sym _ _) (sum_nat_eq0 (predD1 P i) nF)). rewrite -lt0n in nZfi; have [_] := (leqif_add (leqif_eq nZfi) (F'ge0 _)). rewrite /= big_andbC -bigD1 // sumF1 => /esym/andP/=[/eqP Fi1 /forall_inP Fi'0]. exists i; split=> // [|j neq_ji Pj]; first by rewrite defF // -Fi1. by rewrite defF // (eqP (Fi'0 j _)) // neq_ji. Qed. Lemma Cnat_mul_eq1 x y : x \in Cnat -> y \in Cnat -> (x * y == 1) = (x == 1) && (y == 1). Proof. by do 2!move/truncCK <-; rewrite -natrM !pnatr_eq1 muln_eq1. Qed. Lemma Cnat_prod_eq1 (I : finType) (P : pred I) (F : I -> algC) : (forall i, P i -> F i \in Cnat) -> \prod_(i | P i) F i = 1 -> forall i, P i -> F i = 1. Proof. move=> natF prodF1; apply/eqfun_inP; rewrite -big_andE. move: prodF1; elim/(big_load (fun x => x \in Cnat)): _. elim/big_rec2: _ => // i all1x x /natF N_Fi [Nx x1all1]. by split=> [|/eqP]; rewrite ?rpredM ?Cnat_mul_eq1 // => /andP[-> /eqP]. Qed. (* Relating Cint and Cnat. *) Lemma Cint_Cnat : {subset Cnat <= Cint}. Proof. by move=> _ /CnatP[n ->]; rewrite pmulrn Cint_int. Qed. Lemma CintE x : (x \in Cint) = (x \in Cnat) || (- x \in Cnat). Proof. apply/idP/idP=> [/CintP[[n | n] ->] | ]; first by rewrite Cnat_nat. by rewrite NegzE opprK Cnat_nat orbT. by case/pred2P=> [<- | /(canLR (@opprK _)) <-]; rewrite ?rpredN rpred_nat. Qed. Lemma Cnat_norm_Cint x : x \in Cint -> `|x| \in Cnat. Proof. case/CintP=> [m ->]; rewrite [m]intEsign rmorphM rmorph_sign. by rewrite normrM normr_sign mul1r normr_nat rpred_nat. Qed. Lemma CnatEint x : (x \in Cnat) = (x \in Cint) && (0 <= x). Proof. apply/idP/andP=> [Nx | [Zx x_ge0]]; first by rewrite Cint_Cnat ?Cnat_ge0. by rewrite -(ger0_norm x_ge0) Cnat_norm_Cint. Qed. Lemma CintEge0 x : 0 <= x -> (x \in Cint) = (x \in Cnat). Proof. by rewrite CnatEint andbC => ->. Qed. Lemma Cnat_exp_even x n : ~~ odd n -> x \in Cint -> x ^+ n \in Cnat. Proof. rewrite -dvdn2 => /dvdnP[m ->] Zx; rewrite mulnC exprM -Cint_normK ?rpredX //. exact: Cnat_norm_Cint. Qed. Lemma norm_Cint_ge1 x : x \in Cint -> x != 0 -> 1 <= `|x|. Proof. rewrite -normr_eq0 => /Cnat_norm_Cint/CnatP[n ->]. by rewrite pnatr_eq0 ler1n lt0n. Qed. Lemma sqr_Cint_ge1 x : x \in Cint -> x != 0 -> 1 <= x ^+ 2. Proof. by move=> Zx nz_x; rewrite -Cint_normK // expr_ge1 ?normr_ge0 ?norm_Cint_ge1. Qed. Lemma Cint_ler_sqr x : x \in Cint -> x <= x ^+ 2. Proof. move=> Zx; have [-> | nz_x] := eqVneq x 0; first by rewrite expr0n. apply: ler_trans (_ : `|x| <= _); first by rewrite real_ler_norm ?Creal_Cint. by rewrite -Cint_normK // ler_eexpr // norm_Cint_ge1. Qed. (* Integer divisibility. *) Lemma dvdCP x y : reflect (exists2 z, z \in Cint & y = z * x) (x %| y)%C. Proof. rewrite unfold_in; have [-> | nz_x] := altP eqP. by apply: (iffP eqP) => [-> | [z _ ->]]; first exists 0; rewrite ?mulr0. apply: (iffP idP) => [Zyx | [z Zz ->]]; last by rewrite mulfK. by exists (y / x); rewrite ?divfK. Qed. Lemma dvdCP_nat x y : 0 <= x -> 0 <= y -> (x %| y)%C -> {n | y = n%:R * x}. Proof. move=> x_ge0 y_ge0 x_dv_y; apply: sig_eqW. case/dvdCP: x_dv_y => z Zz -> in y_ge0 *; move: x_ge0 y_ge0 Zz. rewrite ler_eqVlt => /predU1P[<- | ]; first by exists 22; rewrite !mulr0. by move=> /pmulr_lge0-> /CintEge0-> /CnatP[n ->]; exists n. Qed. Lemma dvdC0 x : (x %| 0)%C. Proof. by apply/dvdCP; exists 0; rewrite ?mul0r. Qed. Lemma dvd0C x : (0 %| x)%C = (x == 0). Proof. by rewrite unfold_in eqxx. Qed. Lemma dvdC_mull x y z : y \in Cint -> (x %| z)%C -> (x %| y * z)%C. Proof. move=> Zy /dvdCP[m Zm ->]; apply/dvdCP. by exists (y * m); rewrite ?mulrA ?rpredM. Qed. Lemma dvdC_mulr x y z : y \in Cint -> (x %| z)%C -> (x %| z * y)%C. Proof. by rewrite mulrC; apply: dvdC_mull. Qed. Lemma dvdC_mul2r x y z : y != 0 -> (x * y %| z * y)%C = (x %| z)%C. Proof. move=> nz_y; rewrite !unfold_in !(mulIr_eq0 _ (mulIf nz_y)). by rewrite mulrAC invfM mulrA divfK. Qed. Lemma dvdC_mul2l x y z : y != 0 -> (y * x %| y * z)%C = (x %| z)%C. Proof. by rewrite !(mulrC y); apply: dvdC_mul2r. Qed. Lemma dvdC_trans x y z : (x %| y)%C -> (y %| z)%C -> (x %| z)%C. Proof. by move=> x_dv_y /dvdCP[m Zm ->]; apply: dvdC_mull. Qed. Lemma dvdC_refl x : (x %| x)%C. Proof. by apply/dvdCP; exists 1; rewrite ?mul1r. Qed. Hint Resolve dvdC_refl. Fact dvdC_key x : pred_key (dvdC x). Proof. by []. Qed. Lemma dvdC_zmod x : zmod_closed (dvdC x). Proof. split=> [| _ _ /dvdCP[y Zy ->] /dvdCP[z Zz ->]]; first exact: dvdC0. by rewrite -mulrBl dvdC_mull ?rpredB. Qed. Canonical dvdC_keyed x := KeyedPred (dvdC_key x). Canonical dvdC_opprPred x := OpprPred (dvdC_zmod x). Canonical dvdC_addrPred x := AddrPred (dvdC_zmod x). Canonical dvdC_zmodPred x := ZmodPred (dvdC_zmod x). Lemma dvdC_nat (p n : nat) : (p %| n)%C = (p %| n)%N. Proof. rewrite unfold_in CintEge0 ?divr_ge0 ?invr_ge0 ?ler0n // !pnatr_eq0. have [-> | nz_p] := altP eqP; first by rewrite dvd0n. apply/CnatP/dvdnP=> [[q def_q] | [q ->]]; exists q. by apply/eqP; rewrite -eqC_nat natrM -def_q divfK ?pnatr_eq0. by rewrite [num in num / _]natrM mulfK ?pnatr_eq0. Qed. Lemma dvdC_int (p : nat) x : x \in Cint -> (p %| x)%C = (p %| `|floorC x|)%N. Proof. move=> Zx; rewrite -{1}(floorCK Zx) {1}[floorC x]intEsign. by rewrite rmorphMsign rpredMsign dvdC_nat. Qed. (* Elementary modular arithmetic. *) Lemma eqCmod_refl e x : (x == x %[mod e])%C. Proof. by rewrite /eqCmod subrr rpred0. Qed. Lemma eqCmodm0 e : (e == 0 %[mod e])%C. Proof. by rewrite /eqCmod subr0. Qed. Hint Resolve eqCmod_refl eqCmodm0. Lemma eqCmod0 e x : (x == 0 %[mod e])%C = (e %| x)%C. Proof. by rewrite /eqCmod subr0. Qed. Lemma eqCmod_sym e x y : ((x == y %[mod e]) = (y == x %[mod e]))%C. Proof. by rewrite /eqCmod -opprB rpredN. Qed. Lemma eqCmod_trans e y x z : (x == y %[mod e] -> y == z %[mod e] -> x == z %[mod e])%C. Proof. by move=> Exy Eyz; rewrite /eqCmod -[x](subrK y) -addrA rpredD. Qed. Lemma eqCmod_transl e x y z : (x == y %[mod e])%C -> (x == z %[mod e])%C = (y == z %[mod e])%C. Proof. by move/(sym_left_transitive (eqCmod_sym e) (@eqCmod_trans e)). Qed. Lemma eqCmod_transr e x y z : (x == y %[mod e])%C -> (z == x %[mod e])%C = (z == y %[mod e])%C. Proof. by move/(sym_right_transitive (eqCmod_sym e) (@eqCmod_trans e)). Qed. Lemma eqCmodN e x y : (- x == y %[mod e])%C = (x == - y %[mod e])%C. Proof. by rewrite eqCmod_sym /eqCmod !opprK addrC. Qed. Lemma eqCmodDr e x y z : (y + x == z + x %[mod e])%C = (y == z %[mod e])%C. Proof. by rewrite /eqCmod addrAC opprD !addrA subrK. Qed. Lemma eqCmodDl e x y z : (x + y == x + z %[mod e])%C = (y == z %[mod e])%C. Proof. by rewrite !(addrC x) eqCmodDr. Qed. Lemma eqCmodD e x1 x2 y1 y2 : (x1 == x2 %[mod e] -> y1 == y2 %[mod e] -> x1 + y1 == x2 + y2 %[mod e])%C. Proof. rewrite -(eqCmodDl e x2 y1) -(eqCmodDr e y1); exact: eqCmod_trans. Qed. Lemma eqCmod_nat (e m n : nat) : (m == n %[mod e])%C = (m == n %[mod e]). Proof. without loss lenm: m n / (n <= m)%N. by move=> IH; case/orP: (leq_total m n) => /IH //; rewrite eqCmod_sym eq_sym. by rewrite /eqCmod -natrB // dvdC_nat eqn_mod_dvd. Qed. Lemma eqCmod0_nat (e m : nat) : (m == 0 %[mod e])%C = (e %| m)%N. Proof. by rewrite eqCmod0 dvdC_nat. Qed. Lemma eqCmodMr e : {in Cint, forall z x y, x == y %[mod e] -> x * z == y * z %[mod e]}%C. Proof. by move=> z Zz x y; rewrite /eqCmod -mulrBl => /dvdC_mulr->. Qed. Lemma eqCmodMl e : {in Cint, forall z x y, x == y %[mod e] -> z * x == z * y %[mod e]}%C. Proof. by move=> z Zz x y Exy; rewrite !(mulrC z) eqCmodMr. Qed. Lemma eqCmodMl0 e : {in Cint, forall x, x * e == 0 %[mod e]}%C. Proof. by move=> x Zx; rewrite -(mulr0 x) eqCmodMl. Qed. Lemma eqCmodMr0 e : {in Cint, forall x, e * x == 0 %[mod e]}%C. Proof. by move=> x Zx; rewrite /= mulrC eqCmodMl0. Qed. Lemma eqCmod_addl_mul e : {in Cint, forall x y, x * e + y == y %[mod e]}%C. Proof. by move=> x Zx y; rewrite -{2}[y]add0r eqCmodDr eqCmodMl0. Qed. Lemma eqCmodM e : {in Cint & Cint, forall x1 y2 x2 y1, x1 == x2 %[mod e] -> y1 == y2 %[mod e] -> x1 * y1 == x2 * y2 %[mod e]}%C. Proof. move=> x1 y2 Zx1 Zy2 x2 y1 eq_x /(eqCmodMl Zx1)/eqCmod_trans-> //. exact: eqCmodMr. Qed. (* Rational number subset. *) Lemma ratCK : cancel QtoC CtoQ. Proof. by rewrite /getCrat; case: getCrat_subproof. Qed. Lemma getCratK : {in Crat, cancel CtoQ QtoC}. Proof. by move=> x /eqP. Qed. Lemma Crat_rat (a : rat) : QtoC a \in Crat. Proof. by rewrite unfold_in ratCK. Qed. Lemma CratP x : reflect (exists a, x = QtoC a) (x \in Crat). Proof. by apply: (iffP eqP) => [<- | [a ->]]; [exists (CtoQ x) | rewrite ratCK]. Qed. Lemma Crat0 : 0 \in Crat. Proof. by apply/CratP; exists 0; rewrite rmorph0. Qed. Lemma Crat1 : 1 \in Crat. Proof. by apply/CratP; exists 1; rewrite rmorph1. Qed. Hint Resolve Crat0 Crat1. Fact Crat_key : pred_key Crat. Proof. by []. Qed. Fact Crat_divring_closed : divring_closed Crat. Proof. split=> // _ _ /CratP[x ->] /CratP[y ->]. by rewrite -rmorphB Crat_rat. by rewrite -fmorph_div Crat_rat. Qed. Canonical Crat_keyed := KeyedPred Crat_key. Canonical Crat_opprPred := OpprPred Crat_divring_closed. Canonical Crat_addrPred := AddrPred Crat_divring_closed. Canonical Crat_mulrPred := MulrPred Crat_divring_closed. Canonical Crat_zmodPred := ZmodPred Crat_divring_closed. Canonical Crat_semiringPred := SemiringPred Crat_divring_closed. Canonical Crat_smulrPred := SmulrPred Crat_divring_closed. Canonical Crat_divrPred := DivrPred Crat_divring_closed. Canonical Crat_subringPred := SubringPred Crat_divring_closed. Canonical Crat_sdivrPred := SdivrPred Crat_divring_closed. Canonical Crat_divringPred := DivringPred Crat_divring_closed. Lemma rpred_Crat S (ringS : divringPred S) (kS : keyed_pred ringS) : {subset Crat <= kS}. Proof. by move=> _ /CratP[a ->]; apply: rpred_rat. Qed. Lemma conj_Crat z : z \in Crat -> z^* = z. Proof. by move/getCratK <-; rewrite fmorph_div !rmorph_int. Qed. Lemma Creal_Crat : {subset Crat <= Creal}. Proof. by move=> x /conj_Crat/CrealP. Qed. Lemma Cint_rat a : (QtoC a \in Cint) = (a \in Qint). Proof. apply/idP/idP=> [Za | /numqK <-]; last by rewrite rmorph_int Cint_int. apply/QintP; exists (floorC (QtoC a)); apply: (can_inj ratCK). by rewrite rmorph_int floorCK. Qed. Lemma minCpolyP x : {p | minCpoly x = pQtoC p /\ p \is monic & forall q, root (pQtoC q) x = (p %| q)%R}. Proof. by rewrite /minCpoly; case: (minCpoly_subproof x) => p; exists p. Qed. Lemma minCpoly_monic x : minCpoly x \is monic. Proof. by have [p [-> mon_p] _] := minCpolyP x; rewrite map_monic. Qed. Lemma minCpoly_eq0 x : (minCpoly x == 0) = false. Proof. exact/negbTE/monic_neq0/minCpoly_monic. Qed. Lemma root_minCpoly x : root (minCpoly x) x. Proof. by have [p [-> _] ->] := minCpolyP x. Qed. Lemma size_minCpoly x : (1 < size (minCpoly x))%N. Proof. by apply: root_size_gt1 (root_minCpoly x); rewrite ?minCpoly_eq0. Qed. (* Basic properties of automorphisms. *) Section AutC. Implicit Type nu : {rmorphism algC -> algC}. Lemma aut_Cnat nu : {in Cnat, nu =1 id}. Proof. by move=> _ /CnatP[n ->]; apply: rmorph_nat. Qed. Lemma aut_Cint nu : {in Cint, nu =1 id}. Proof. by move=> _ /CintP[m ->]; apply: rmorph_int. Qed. Lemma aut_Crat nu : {in Crat, nu =1 id}. Proof. by move=> _ /CratP[a ->]; apply: fmorph_rat. Qed. Lemma Cnat_aut nu x : (nu x \in Cnat) = (x \in Cnat). Proof. by do [apply/idP/idP=> Nx; have:= aut_Cnat nu Nx] => [/fmorph_inj <- | ->]. Qed. Lemma Cint_aut nu x : (nu x \in Cint) = (x \in Cint). Proof. by rewrite !CintE -rmorphN !Cnat_aut. Qed. Lemma Crat_aut nu x : (nu x \in Crat) = (x \in Crat). Proof. apply/idP/idP=> /CratP[a] => [|->]; last by rewrite fmorph_rat Crat_rat. by rewrite -(fmorph_rat nu) => /fmorph_inj->; apply: Crat_rat. Qed. Lemma algC_invaut_subproof nu x : {y | nu y = x}. Proof. have [r Dp] := closed_field_poly_normal (minCpoly x). suffices /mapP/sig2_eqW[y _ ->]: x \in map nu r by exists y. rewrite -root_prod_XsubC; congr (root _ x): (root_minCpoly x). have [q [Dq _] _] := minCpolyP x; rewrite Dq -(eq_map_poly (fmorph_rat nu)). rewrite (map_poly_comp nu) -{q}Dq Dp (monicP (minCpoly_monic x)) scale1r. rewrite rmorph_prod big_map; apply: eq_bigr => z _. by rewrite rmorphB /= map_polyX map_polyC. Qed. Definition algC_invaut nu x := sval (algC_invaut_subproof nu x). Lemma algC_invautK nu : cancel (algC_invaut nu) nu. Proof. by move=> x; rewrite /algC_invaut; case: algC_invaut_subproof. Qed. Lemma algC_autK nu : cancel nu (algC_invaut nu). Proof. exact: inj_can_sym (algC_invautK nu) (fmorph_inj nu). Qed. Fact algC_invaut_is_rmorphism nu : rmorphism (algC_invaut nu). Proof. exact: can2_rmorphism (algC_autK nu) (algC_invautK nu). Qed. Canonical algC_invaut_additive nu := Additive (algC_invaut_is_rmorphism nu). Canonical algC_invaut_rmorphism nu := RMorphism (algC_invaut_is_rmorphism nu). Lemma minCpoly_aut nu x : minCpoly (nu x) = minCpoly x. Proof. wlog suffices dvd_nu: nu x / (minCpoly x %| minCpoly (nu x))%R. apply/eqP; rewrite -eqp_monic ?minCpoly_monic //; apply/andP; split=> //. by rewrite -{2}(algC_autK nu x) dvd_nu. have [[q [Dq _] min_q] [q1 [Dq1 _] _]] := (minCpolyP x, minCpolyP (nu x)). rewrite Dq Dq1 dvdp_map -min_q -(fmorph_root nu) -map_poly_comp. by rewrite (eq_map_poly (fmorph_rat nu)) -Dq1 root_minCpoly. Qed. End AutC. Section AutLmodC. Variables (U V : lmodType algC) (f : {additive U -> V}). Lemma raddfZ_Cnat a u : a \in Cnat -> f (a *: u) = a *: f u. Proof. by case/CnatP=> n ->; exact: raddfZnat. Qed. Lemma raddfZ_Cint a u : a \in Cint -> f (a *: u) = a *: f u. Proof. by case/CintP=> m ->; rewrite !scaler_int raddfMz. Qed. End AutLmodC. Section PredCmod. Variable V : lmodType algC. Lemma rpredZ_Cnat S (addS : @addrPred V S) (kS : keyed_pred addS) : {in Cnat & kS, forall z u, z *: u \in kS}. Proof. by move=> _ u /CnatP[n ->]; apply: rpredZnat. Qed. Lemma rpredZ_Cint S (subS : @zmodPred V S) (kS : keyed_pred subS) : {in Cint & kS, forall z u, z *: u \in kS}. Proof. by move=> _ u /CintP[m ->]; apply: rpredZint. Qed. End PredCmod. End AlgebraicsTheory. Hint Resolve Creal0 Creal1 Cnat_nat Cnat0 Cnat1 Cint0 Cint1 floorC0 Crat0 Crat1. Hint Resolve dvdC0 dvdC_refl eqCmod_refl eqCmodm0. mathcomp-1.5/theories/extremal.v0000644000175000017500000036011512307636117016021 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div choice fintype. Require Import bigop finset prime binomial fingroup morphism perm automorphism. Require Import presentation quotient action commutator gproduct gfunctor. Require Import ssralg finalg zmodp cyclic pgroup center gseries. Require Import nilpotent sylow abelian finmodule matrix maximal. (******************************************************************************) (* This file contains the definition and properties of extremal p-groups; *) (* it covers and is mostly based on the beginning of Aschbacher, section 23, *) (* as well as several exercises of this section. *) (* We define canonical representatives for the group classes that cover the *) (* extremal p-groups (non-abelian p-groups with a cyclic maximal subgroup): *) (* 'Mod_m == the modular group of order m, for m = p ^ n, p prime and n >= 3. *) (* 'D_m == the dihedral group of order m, for m = 2n >= 4. *) (* 'Q_m == the generalized quaternion group of order m, for m = 2 ^ n >= 8. *) (* 'SD_m == the semi-dihedral group of order m, for m = 2 ^ n >= 16. *) (* In each case the notation is defined in the %type, %g and %G scopes, where *) (* it denotes a finGroupType, a full gset and the full group for that type. *) (* However each notation is only meaningful under the given conditions, in *) (* 'D_m is only an extremal group for m = 2 ^ n >= 8, and 'D_8 = 'Mod_8 (they *) (* are, in fact, beta-convertible). *) (* We also define *) (* extremal_generators G p n (x, y) <-> G has order p ^ n, x in G has order *) (* p ^ n.-1, and y is in G \ <[x]>: thus <[x]> has index p in G, *) (* so if p is prime, <[x]> is maximal in G, G is generated by x *) (* and y, and G is extremal or abelian. *) (* extremal_class G == the class of extremal groups G belongs to: one of *) (* ModularGroup, Dihedral, Quaternion, SemiDihedral or NotExtremal. *) (* extremal2 G <=> extremal_class G is one of Dihedral, Quaternion, or *) (* SemiDihedral; this allows 'D_4 and 'D_8, but excludes 'Mod_(2^n) *) (* for n > 3. *) (* modular_group_generators p n (x, y) <-> y has order p and acts on x via *) (* x ^ y = x ^+ (p ^ n.-2).+1. This is the complement to *) (* extremal_generators G p n (x, y) for modular groups. *) (* We provide cardinality, presentation, generator and structure theorems for *) (* each class of extremal group. The extremal_generators predicate is used to *) (* supply structure theorems with all the required data about G; this is *) (* completed by an isomorphism assumption (e.g., G \isog 'D_(2 ^ n)), and *) (* sometimes other properties (e.g., #[y] == 2 in the semidihedral case). The *) (* generators assumption can be deduced generically from the isomorphism *) (* assumption, or it can be proved manually for a specific choice of x and y. *) (* The extremal_class function is used to formulate synthetic theorems that *) (* cover several classes of extremal groups (e.g., Aschbacher ex. 8.3). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Local Open Scope ring_scope. Import GroupScope GRing.Theory. Reserved Notation "''Mod_' m" (at level 8, m at level 2, format "''Mod_' m"). Reserved Notation "''D_' m" (at level 8, m at level 2, format "''D_' m"). Reserved Notation "''SD_' m" (at level 8, m at level 2, format "''SD_' m"). Reserved Notation "''Q_' m" (at level 8, m at level 2, format "''Q_' m"). Module Extremal. Section Construction. Variables q p e : nat. (* Construct the semi-direct product of 'Z_q by 'Z_p with 1%R ^ 1%R = e%R, *) (* if possible, i.e., if p, q > 1 and there is s \in Aut 'Z_p such that *) (* #[s] %| p and s 1%R = 1%R ^+ e. *) Let a : 'Z_p := Zp1. Let b : 'Z_q := Zp1. Local Notation B := <[b]>. Definition aut_of := odflt 1 [pick s in Aut B | p > 1 & (#[s] %| p) && (s b == b ^+ e)]. Lemma aut_dvdn : #[aut_of] %| #[a]. Proof. rewrite order_Zp1 /aut_of; case: pickP => [s | _]; last by rewrite order1. by case/and4P=> _ p_gt1 p_s _; rewrite Zp_cast. Qed. Definition act_morphism := eltm_morphism aut_dvdn. Definition base_act := ([Aut B] \o act_morphism)%gact. Lemma act_dom : <[a]> \subset act_dom base_act. Proof. rewrite cycle_subG 2!inE cycle_id /= eltm_id /aut_of. by case: pickP => [op /andP[] | _] //=; rewrite group1. Qed. Definition gact := (base_act \ act_dom)%gact. Fact gtype_key : unit. Proof. by []. Qed. Definition gtype := locked_with gtype_key (sdprod_groupType gact). Hypotheses (p_gt1 : p > 1) (q_gt1 : q > 1). Lemma card : #|[set: gtype]| = (p * q)%N. Proof. rewrite [gtype]unlock -(sdprod_card (sdprod_sdpair _)). rewrite !card_injm ?injm_sdpair1 ?injm_sdpair2 //. by rewrite mulnC -!orderE !order_Zp1 !Zp_cast. Qed. Lemma Grp : (exists s, [/\ s \in Aut B, #[s] %| p & s b = b ^+ e]) -> [set: gtype] \isog Grp (x : y : (x ^+ q, y ^+ p, x ^ y = x ^+ e)). Proof. rewrite [gtype]unlock => [[s [AutBs dvd_s_p sb]]]. have memB: _ \in B by move=> c; rewrite -Zp_cycle inE. have Aa: a \in <[a]> by rewrite !cycle_id. have [oa ob]: #[a] = p /\ #[b] = q by rewrite !order_Zp1 !Zp_cast. have def_s: aut_of = s. rewrite /aut_of; case: pickP => /= [t | ]; last first. by move/(_ s); case/and4P; rewrite sb. case/and4P=> AutBt _ _ tb; apply: (eq_Aut AutBt) => // b_i. case/cycleP=> i ->; rewrite -(autmE AutBt) -(autmE AutBs) !morphX //=. by rewrite !autmE // sb (eqP tb). apply: intro_isoGrp => [|gT G]. apply/existsP; exists (sdpair1 _ b, sdpair2 _ a); rewrite /= !xpair_eqE. rewrite -!morphim_cycle ?norm_joinEr ?im_sdpair ?im_sdpair_norm ?eqxx //=. rewrite -!order_dvdn !order_injm ?injm_sdpair1 ?injm_sdpair2 // oa ob !dvdnn. by rewrite -sdpair_act // [act _ _ _]apermE /= eltm_id -morphX // -sb -def_s. case/existsP=> -[x y] /= /eqP[defG xq1 yp1 xy]. have fxP: #[x] %| #[b] by rewrite order_dvdn ob xq1. have fyP: #[y] %| #[a] by rewrite order_dvdn oa yp1. have fP: {in <[b]> & <[a]>, morph_act gact 'J (eltm fxP) (eltm fyP)}. move=> bj ai; case/cycleP=> j ->{bj}; case/cycleP=> i ->{ai}. rewrite /= !eltmE def_s gactX ?groupX // conjXg morphX //=; congr (_ ^+ j). rewrite /autact /= apermE; elim: i {j} => /= [|i IHi]. by rewrite perm1 eltm_id conjg1. rewrite !expgS permM sb -(autmE (groupX i AutBs)) !morphX //= {}IHi. by rewrite -conjXg -xy -conjgM. apply/homgP; exists (xsdprod_morphism fP). rewrite im_xsdprodm !morphim_cycle //= !eltm_id -norm_joinEr //. by rewrite norms_cycle xy mem_cycle. Qed. End Construction. End Extremal. Section SpecializeExtremals. Import Extremal. Variable m : nat. Let p := pdiv m. Let q := m %/ p. Definition modular_gtype := gtype q p (q %/ p).+1. Definition dihedral_gtype := gtype q 2 q.-1. Definition semidihedral_gtype := gtype q 2 (q %/ p).-1. Definition quaternion_kernel := <<[set u | u ^+ 2 == 1] :\: [set u ^+ 2 | u in [set: gtype q 4 q.-1]]>>. Definition quaternion_gtype := locked_with gtype_key (coset_groupType quaternion_kernel). End SpecializeExtremals. Notation "''Mod_' m" := (modular_gtype m) : type_scope. Notation "''Mod_' m" := [set: gsort 'Mod_m] : group_scope. Notation "''Mod_' m" := [set: gsort 'Mod_m]%G : Group_scope. Notation "''D_' m" := (dihedral_gtype m) : type_scope. Notation "''D_' m" := [set: gsort 'D_m] : group_scope. Notation "''D_' m" := [set: gsort 'D_m]%G : Group_scope. Notation "''SD_' m" := (semidihedral_gtype m) : type_scope. Notation "''SD_' m" := [set: gsort 'SD_m] : group_scope. Notation "''SD_' m" := [set: gsort 'SD_m]%G : Group_scope. Notation "''Q_' m" := (quaternion_gtype m) : type_scope. Notation "''Q_' m" := [set: gsort 'Q_m] : group_scope. Notation "''Q_' m" := [set: gsort 'Q_m]%G : Group_scope. Section ExtremalTheory. Implicit Types (gT : finGroupType) (p q m n : nat). (* This is Aschbacher (23.3), with the isomorphism made explicit, and a *) (* slightly reworked case analysis on the prime and exponent; in particular *) (* the inverting involution is available for all non-trivial p-cycles. *) Lemma cyclic_pgroup_Aut_structure gT p (G : {group gT}) : p.-group G -> cyclic G -> G :!=: 1 -> let q := #|G| in let n := (logn p q).-1 in let A := Aut G in let P := 'O_p(A) in let F := 'O_p^'(A) in exists m : {perm gT} -> 'Z_q, [/\ [/\ {in A & G, forall a x, x ^+ m a = a x}, m 1 = 1%R /\ {in A &, {morph m : a b / a * b >-> (a * b)%R}}, {in A &, injective m} /\ image m A =i GRing.unit, forall k, {in A, {morph m : a / a ^+ k >-> (a ^+ k)%R}} & {in A, {morph m : a / a^-1 >-> (a^-1)%R}}], [/\ abelian A, cyclic F, #|F| = p.-1 & [faithful F, on 'Ohm_1(G) | [Aut G]]] & if n == 0%N then A = F else exists t, [/\ t \in A, #[t] = 2, m t = - 1%R & if odd p then [/\ cyclic A /\ cyclic P, exists s, [/\ s \in A, #[s] = (p ^ n)%N, m s = p.+1%:R & P = <[s]>] & exists s0, [/\ s0 \in A, #[s0] = p, m s0 = (p ^ n).+1%:R & 'Ohm_1(P) = <[s0]>]] else if n == 1%N then A = <[t]> else exists s, [/\ s \in A, #[s] = (2 ^ n.-1)%N, m s = 5%:R, <[s]> \x <[t]> = A & exists s0, [/\ s0 \in A, #[s0] = 2, m s0 = (2 ^ n).+1%:R, m (s0 * t) = (2 ^ n).-1%:R & 'Ohm_1(<[s]>) = <[s0]>]]]]. Proof. move=> pG cycG ntG q n0 A P F; have [p_pr p_dvd_G [n oG]] := pgroup_pdiv pG ntG. have [x0 defG] := cyclicP cycG; have Gx0: x0 \in G by rewrite defG cycle_id. rewrite {1}/q oG pfactorK //= in n0 *; rewrite {}/n0. have [p_gt1 min_p] := primeP p_pr; have p_gt0 := ltnW p_gt1. have q_gt1: q > 1 by rewrite cardG_gt1. have cAA: abelian A := Aut_cyclic_abelian cycG; have nilA := abelian_nil cAA. have oA: #|A| = (p.-1 * p ^ n)%N. by rewrite card_Aut_cyclic // oG totient_pfactor. have [sylP hallF]: p.-Sylow(A) P /\ p^'.-Hall(A) F. by rewrite !nilpotent_pcore_Hall. have [defPF tiPF]: P * F = A /\ P :&: F = 1. by case/dprodP: (nilpotent_pcoreC p nilA). have oP: #|P| = (p ^ n)%N. by rewrite (card_Hall sylP) oA p_part logn_Gauss ?coprimenP ?pfactorK. have oF: #|F| = p.-1. apply/eqP; rewrite -(@eqn_pmul2l #|P|) ?cardG_gt0 // -TI_cardMg // defPF. by rewrite oA oP mulnC. have [m' [inj_m' defA def_m']]: exists m' : {morphism units_Zp q >-> {perm gT}}, [/\ 'injm m', m' @* setT = A & {in G, forall x u, m' u x = x ^+ val u}]. - rewrite /A /q defG; exists (Zp_unit_morphism x0). by have [->]:= isomP (Zp_unit_isom x0); split=> // y Gy u; rewrite permE Gy. pose m (a : {perm gT}) : 'Z_q := val (invm inj_m' a). have{def_m'} def_m: {in A & G, forall a x, x ^+ m a = a x}. by move=> a x Aa Gx /=; rewrite -{2}[a](invmK inj_m') ?defA ?def_m'. have m1: m 1 = 1%R by rewrite /m morph1. have mM: {in A &, {morph m : a b / a * b >-> (a * b)%R}}. by move=> a b Aa Ab; rewrite /m morphM ?defA. have mX k: {in A, {morph m : a / a ^+ k >-> (a ^+ k)%R}}. by elim: k => // k IHk a Aa; rewrite expgS exprS mM ?groupX ?IHk. have inj_m: {in A &, injective m}. apply: can_in_inj (fun u => m' (insubd (1 : {unit 'Z_q}) u)) _ => a Aa. by rewrite valKd invmK ?defA. have{defA} im_m: image m A =i GRing.unit. move=> u; apply/imageP/idP=> [[a Aa ->]| Uu]; first exact: valP. exists (m' (Sub u Uu)) => /=; first by rewrite -defA mem_morphim ?inE. by rewrite /m invmE ?inE. have mV: {in A, {morph m : a / a^-1 >-> (a^-1)%R}}. move=> a Aa /=; rewrite -div1r; apply: canRL (mulrK (valP _)) _. by rewrite -mM ?groupV ?mulVg. have inv_m (u : 'Z_q) : coprime q u -> {a | a \in A & m a = u}. rewrite -?unitZpE // natr_Zp -im_m => m_u. by exists (iinv m_u); [exact: mem_iinv | rewrite f_iinv]. have [cycF ffulF]: cyclic F /\ [faithful F, on 'Ohm_1(G) | [Aut G]]. have Um0 a: ((m a)%:R : 'F_p) \in GRing.unit. have: m a \in GRing.unit by exact: valP. by rewrite -{1}[m a]natr_Zp unitFpE ?unitZpE // {1}/q oG coprime_pexpl. pose fm0 a := FinRing.unit 'F_p (Um0 a). have natZqp u: (u%:R : 'Z_q)%:R = u %:R :> 'F_p. by rewrite val_Zp_nat // -Fp_nat_mod // modn_dvdm ?Fp_nat_mod. have m0M: {in A &, {morph fm0 : a b / a * b}}. move=> a b Aa Ab; apply: val_inj; rewrite /= -natrM mM //. by rewrite -[(_ * _)%R]Zp_nat natZqp. pose m0 : {morphism A >-> {unit 'F_p}} := Morphism m0M. have im_m0: m0 @* A = [set: {unit 'F_p}]. apply/setP=> [[/= u Uu]]; rewrite in_setT morphimEdom; apply/imsetP. have [|a Aa m_a] := inv_m u%:R. by rewrite {1}[q]oG coprime_pexpl // -unitFpE // natZqp natr_Zp. by exists a => //; apply: val_inj; rewrite /= m_a natZqp natr_Zp. have [x1 defG1]: exists x1, 'Ohm_1(G) = <[x1]>. by apply/cyclicP; exact: cyclicS (Ohm_sub _ _) cycG. have ox1: #[x1] = p by rewrite orderE -defG1 (Ohm1_cyclic_pgroup_prime _ pG). have Gx1: x1 \in G by rewrite -cycle_subG -defG1 Ohm_sub. have ker_m0: 'ker m0 = 'C('Ohm_1(G) | [Aut G]). apply/setP=> a; rewrite inE in_setI; apply: andb_id2l => Aa. rewrite 3!inE /= -2!val_eqE /= val_Fp_nat // [1 %% _]modn_small // defG1. apply/idP/subsetP=> [ma1 x1i | ma1]. case/cycleP=> i ->{x1i}; rewrite inE gactX // -[_ a]def_m //. by rewrite -(expg_mod_order x1) ox1 (eqP ma1). have:= ma1 x1 (cycle_id x1); rewrite inE -[_ a]def_m //. by rewrite (eq_expg_mod_order x1 _ 1) ox1 (modn_small p_gt1). have card_units_Fp: #|[set: {unit 'F_p}]| = p.-1. by rewrite card_units_Zp // pdiv_id // (@totient_pfactor p 1) ?muln1. have ker_m0_P: 'ker m0 = P. apply: nilpotent_Hall_pcore nilA _. rewrite pHallE -(card_Hall sylP) oP subsetIl /=. rewrite -(@eqn_pmul2r #|m0 @* A|) ?cardG_gt0 //; apply/eqP. rewrite -{1}(card_isog (first_isog _)) card_quotient ?ker_norm //. by rewrite Lagrange ?subsetIl // oA im_m0 mulnC card_units_Fp. have inj_m0: 'ker_F m0 \subset [1] by rewrite setIC ker_m0_P tiPF. split; last by rewrite /faithful -ker_m0. have isogF: F \isog [set: {unit 'F_p}]. have sFA: F \subset A by exact: pcore_sub. apply/isogP; exists (restrm_morphism sFA m0); first by rewrite ker_restrm. apply/eqP; rewrite eqEcard subsetT card_injm ?ker_restrm //= oF. by rewrite card_units_Fp. rewrite (isog_cyclic isogF) pdiv_id // -ox1 (isog_cyclic (Zp_unit_isog x1)). by rewrite Aut_prime_cyclic // -orderE ox1. exists m; split=> {im_m mV}//; have [n0 | n_gt0] := posnP n. by apply/eqP; rewrite eq_sym eqEcard pcore_sub oF oA n0 muln1 /=. have [t At mt]: {t | t \in A & m t = -1}. apply: inv_m; rewrite /= Zp_cast // coprime_modr modn_small // subn1. by rewrite coprimenP // ltnW. have ot: #[t] = 2. apply/eqP; rewrite eqn_leq order_gt1 dvdn_leq ?order_dvdn //=. apply/eqP; move/(congr1 m); apply/eqP; rewrite mt m1 eq_sym -subr_eq0. rewrite opprK -val_eqE /= Zp_cast ?modn_small // /q oG ltnW //. by rewrite (leq_trans (_ : 2 ^ 2 <= p ^ 2)) ?leq_sqr ?leq_exp2l. by apply/eqP; apply: inj_m; rewrite ?groupX ?group1 ?mX // mt -signr_odd. exists t; split=> //. case G4: (~~ odd p && (n == 1%N)). case: (even_prime p_pr) G4 => [p2 | -> //]; rewrite p2 /=; move/eqP=> n1. rewrite n1 /=; apply/eqP; rewrite eq_sym eqEcard cycle_subG At /=. by rewrite -orderE oA ot p2 n1. pose e0 : nat := ~~ odd p. have{inv_m} [s As ms]: {s | s \in A & m s = (p ^ e0.+1).+1%:R}. apply: inv_m; rewrite val_Zp_nat // coprime_modr /q oG coprime_pexpl //. by rewrite -(@coprime_pexpl e0.+1) // coprimenS. have lt_e0_n: e0 < n. by rewrite /e0; case: (~~ _) G4 => //=; rewrite ltn_neqAle eq_sym => ->. pose s0 := s ^+ (p ^ (n - e0.+1)). have [ms0 os0]: m s0 = (p ^ n).+1%:R /\ #[s0] = p. have m_se e: exists2 k, k = 1 %[mod p] & m (s ^+ (p ^ e)) = (k * p ^ (e + e0.+1)).+1%:R. - elim: e => [|e [k k1 IHe]]; first by exists 1%N; rewrite ?mul1n. rewrite expnSr expgM mX ?groupX // {}IHe -natrX -(add1n (k * _)). rewrite expnDn -(prednK p_gt0) 2!big_ord_recl /= prednK // !exp1n bin1. rewrite bin0 muln1 mul1n mulnCA -expnS (addSn e). set f := (e + _)%N; set sum := (\sum_i _)%N. exists (sum %/ p ^ f.+2 * p + k)%N; first by rewrite modnMDl. rewrite -(addnC k) mulnDl -mulnA -expnS divnK // {}/sum. apply big_ind => [||[i _] /= _]; [exact: dvdn0 | exact: dvdn_add |]. rewrite exp1n mul1n /bump !add1n expnMn mulnCA dvdn_mull // -expnM. case: (ltnP f.+1 (f * i.+2)) => [le_f_fi|]. by rewrite dvdn_mull ?dvdn_exp2l. rewrite {1}mulnS -(addn1 f) leq_add2l {}/f addnS /e0. case: i e => [] // [] //; case odd_p: (odd p) => //= _. by rewrite bin2odd // mulnAC dvdn_mulr. have [[|d]] := m_se (n - e0.+1)%N; first by rewrite mod0n modn_small. move/eqP; rewrite -/s0 eqn_mod_dvd ?subn1 //=; case/dvdnP=> f -> {d}. rewrite subnK // mulSn -mulnA -expnS -addSn natrD natrM -oG char_Zp //. rewrite mulr0 addr0 => m_s0; split => //. have [d _] := m_se (n - e0)%N; rewrite -subnSK // expnSr expgM -/s0. rewrite addSn subnK // -oG mulrS natrM char_Zp // {d}mulr0 addr0. move/eqP; rewrite -m1 (inj_in_eq inj_m) ?group1 ?groupX // -order_dvdn. move/min_p; rewrite order_eq1; case/predU1P=> [s0_1 | ]; last by move/eqP. move/eqP: m_s0; rewrite eq_sym s0_1 m1 -subr_eq0 mulrSr addrK -val_eqE /=. have pf_gt0: p ^ _ > 0 by move=> e; rewrite expn_gt0 p_gt0. by rewrite val_Zp_nat // /q oG [_ == _]pfactor_dvdn // pfactorK ?ltnn. have os: #[s] = (p ^ (n - e0))%N. have: #[s] %| p ^ (n - e0). by rewrite order_dvdn -subnSK // expnSr expgM -order_dvdn os0. case/dvdn_pfactor=> // d; rewrite leq_eqVlt. case/predU1P=> [-> // | lt_d os]; case/idPn: (p_gt1); rewrite -os0. by rewrite order_gt1 negbK -order_dvdn os dvdn_exp2l // -ltnS -subSn. have p_s: p.-elt s by rewrite /p_elt os pnat_exp ?pnat_id. have defS1: 'Ohm_1(<[s]>) = <[s0]>. apply/eqP; rewrite eq_sym eqEcard cycle_subG -orderE os0. rewrite (Ohm1_cyclic_pgroup_prime _ p_s) ?cycle_cyclic ?leqnn ?cycle_eq1 //=. rewrite (OhmE _ p_s) mem_gen ?groupX //= !inE mem_cycle //. by rewrite -order_dvdn os0 ?dvdnn. by apply/eqP=> s1; rewrite -os0 /s0 s1 expg1n order1 in p_gt1. case: (even_prime p_pr) => [p2 | oddp]; last first. rewrite {+}/e0 oddp subn0 in s0 os0 ms0 os ms defS1 *. have [f defF] := cyclicP cycF; have defP: P = <[s]>. apply/eqP; rewrite eq_sym eqEcard -orderE oP os leqnn andbT. by rewrite cycle_subG (mem_normal_Hall sylP) ?pcore_normal. rewrite defP; split; last 1 [by exists s | by exists s0; rewrite ?groupX]. rewrite -defPF defP defF -cycleM ?cycle_cyclic // /order. by red; rewrite (centsP cAA) // -cycle_subG -defF pcore_sub. by rewrite -defF -defP (pnat_coprime (pcore_pgroup _ _) (pcore_pgroup _ _)). rewrite {+}/e0 p2 subn1 /= in s0 os0 ms0 os ms G4 defS1 lt_e0_n *. rewrite G4; exists s; split=> //; last first. exists s0; split; rewrite ?groupX //; apply/eqP; rewrite mM ?groupX //. rewrite ms0 mt eq_sym mulrN1 -subr_eq0 opprK -natrD -addSnnS. by rewrite prednK ?expn_gt0 // addnn -mul2n -expnS -p2 -oG char_Zp. suffices TIst: <[s]> :&: <[t]> = 1. rewrite dprodE //; last by rewrite (sub_abelian_cent2 cAA) ?cycle_subG. apply/eqP; rewrite eqEcard mulG_subG !cycle_subG As At oA. by rewrite TI_cardMg // -!orderE os ot p2 mul1n /= -expnSr prednK. rewrite setIC; apply: prime_TIg; first by rewrite -orderE ot. rewrite cycle_subG; apply/negP=> St. have: t \in <[s0]>. by rewrite -defS1 (OhmE _ p_s) mem_gen // !inE St -order_dvdn ot p2. have ->: <[s0]> = [set 1; s0]. apply/eqP; rewrite eq_sym eqEcard subUset !sub1set group1 cycle_id /=. by rewrite -orderE cards2 eq_sym -order_gt1 os0. rewrite !inE -order_eq1 ot /=; move/eqP; move/(congr1 m); move/eqP. rewrite mt ms0 eq_sym -subr_eq0 opprK -mulrSr. rewrite -val_eqE [val _]val_Zp_nat //= /q oG p2 modn_small //. by rewrite -addn3 expnS mul2n -addnn leq_add2l (ltn_exp2l 1). Qed. Definition extremal_generators gT (A : {set gT}) p n xy := let: (x, y) := xy in [/\ #|A| = (p ^ n)%N, x \in A, #[x] = (p ^ n.-1)%N & y \in A :\: <[x]>]. Lemma extremal_generators_facts gT (G : {group gT}) p n x y : prime p -> extremal_generators G p n (x, y) -> [/\ p.-group G, maximal <[x]> G, <[x]> <| G, <[x]> * <[y]> = G & <[y]> \subset 'N(<[x]>)]. Proof. move=> p_pr [oG Gx ox] /setDP[Gy notXy]. have pG: p.-group G by rewrite /pgroup oG pnat_exp pnat_id. have maxX: maximal <[x]> G. rewrite p_index_maximal -?divgS ?cycle_subG // -orderE oG ox. case: (n) oG => [|n' _]; last by rewrite -expnB ?subSnn ?leqnSn ?prime_gt0. move/eqP; rewrite -trivg_card1; case/trivgPn. by exists y; rewrite // (group1_contra notXy). have nsXG := p_maximal_normal pG maxX; split=> //. by apply: mulg_normal_maximal; rewrite ?cycle_subG. by rewrite cycle_subG (subsetP (normal_norm nsXG)). Qed. Section ModularGroup. Variables p n : nat. Let m := (p ^ n)%N. Let q := (p ^ n.-1)%N. Let r := (p ^ n.-2)%N. Hypotheses (p_pr : prime p) (n_gt2 : n > 2). Let p_gt1 := prime_gt1 p_pr. Let p_gt0 := ltnW p_gt1. Let def_n := esym (subnKC n_gt2). Let def_p : pdiv m = p. Proof. by rewrite /m def_n pdiv_pfactor. Qed. Let def_q : m %/ p = q. Proof. by rewrite /m /q def_n expnS mulKn. Qed. Let def_r : q %/ p = r. Proof. by rewrite /r /q def_n expnS mulKn. Qed. Let ltqm : q < m. Proof. by rewrite ltn_exp2l // def_n. Qed. Let ltrq : r < q. Proof. by rewrite ltn_exp2l // def_n. Qed. Let r_gt0 : 0 < r. Proof. by rewrite expn_gt0 ?p_gt0. Qed. Let q_gt1 : q > 1. Proof. exact: leq_ltn_trans r_gt0 ltrq. Qed. Lemma card_modular_group : #|'Mod_(p ^ n)| = (p ^ n)%N. Proof. by rewrite Extremal.card def_p ?def_q // -expnS def_n. Qed. Lemma Grp_modular_group : 'Mod_(p ^ n) \isog Grp (x : y : (x ^+ q, y ^+ p, x ^ y = x ^+ r.+1)). Proof. rewrite /modular_gtype def_p def_q def_r; apply: Extremal.Grp => //. set B := <[_]>; have Bb: Zp1 \in B by exact: cycle_id. have oB: #|B| = q by rewrite -orderE order_Zp1 Zp_cast. have cycB: cyclic B by rewrite cycle_cyclic. have pB: p.-group B by rewrite /pgroup oB pnat_exp ?pnat_id. have ntB: B != 1 by rewrite -cardG_gt1 oB. have [] := cyclic_pgroup_Aut_structure pB cycB ntB. rewrite oB pfactorK //= -/B -(expg_znat r.+1 Bb) oB => mB [[def_mB _ _ _ _] _]. rewrite {1}def_n /= => [[t [At ot mBt]]]. have [p2 | ->] := even_prime p_pr; last first. by case=> _ _ [s [As os mBs _]]; exists s; rewrite os -mBs def_mB. rewrite {1}p2 /= -2!eqSS -addn2 -2!{1}subn1 -subnDA subnK 1?ltnW //. case: eqP => [n3 _ | _ [_ [_ _ _ _ [s [As os mBs _ _]{t At ot mBt}]]]]. by exists t; rewrite At ot -def_mB // mBt /q /r p2 n3. by exists s; rewrite As os -def_mB // mBs /r p2. Qed. Definition modular_group_generators gT (xy : gT * gT) := let: (x, y) := xy in #[y] = p /\ x ^ y = x ^+ r.+1. Lemma generators_modular_group gT (G : {group gT}) : G \isog 'Mod_m -> exists2 xy, extremal_generators G p n xy & modular_group_generators xy. Proof. case/(isoGrpP _ Grp_modular_group); rewrite card_modular_group // -/m => oG. case/existsP=> -[x y] /= /eqP[defG xq yp xy]. rewrite norm_joinEr ?norms_cycle ?xy ?mem_cycle // in defG. have [Gx Gy]: x \in G /\ y \in G. by apply/andP; rewrite -!cycle_subG -mulG_subG defG. have notXy: y \notin <[x]>. apply: contraL ltqm; rewrite -cycle_subG -oG -defG; move/mulGidPl->. by rewrite -leqNgt dvdn_leq ?(ltnW q_gt1) // order_dvdn xq. have oy: #[y] = p by exact: nt_prime_order (group1_contra notXy). exists (x, y) => //=; split; rewrite ?inE ?notXy //. apply/eqP; rewrite -(eqn_pmul2r p_gt0) -expnSr -{1}oy (ltn_predK n_gt2) -/m. by rewrite -TI_cardMg ?defG ?oG // setIC prime_TIg ?cycle_subG // -orderE oy. Qed. (* This is an adaptation of Aschbacher, exercise 8.2: *) (* - We allow an alternative to the #[x] = p ^ n.-1 condition that meshes *) (* better with the modular_Grp lemma above. *) (* - We state explicitly some "obvious" properties of G, namely that G is *) (* the non-abelian semi-direct product <[x]> ><| <[y]> and that y ^+ j *) (* acts on <[x]> via z |-> z ^+ (j * p ^ n.-2).+1 *) (* - We also give the values of the 'Mho^k(G). *) (* - We corrected a pair of typos. *) Lemma modular_group_structure gT (G : {group gT}) x y : extremal_generators G p n (x, y) -> G \isog 'Mod_m -> modular_group_generators (x, y) -> let X := <[x]> in [/\ [/\ X ><| <[y]> = G, ~~ abelian G & {in X, forall z j, z ^ (y ^+ j) = z ^+ (j * r).+1}], [/\ 'Z(G) = <[x ^+ p]>, 'Phi(G) = 'Z(G) & #|'Z(G)| = r], [/\ G^`(1) = <[x ^+ r]>, #|G^`(1)| = p & nil_class G = 2], forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (p ^ k)]> & if (p, n) == (2, 3) then 'Ohm_1(G) = G else forall k, 0 < k < n.-1 -> <[x ^+ (p ^ (n - k.+1))]> \x <[y]> = 'Ohm_k(G) /\ #|'Ohm_k(G)| = (p ^ k.+1)%N]. Proof. move=> genG isoG [oy xy] X. have [oG Gx ox /setDP[Gy notXy]] := genG; rewrite -/m -/q in ox oG. have [pG _ nsXG defXY nXY] := extremal_generators_facts p_pr genG. have [sXG nXG] := andP nsXG; have sYG: <[y]> \subset G by rewrite cycle_subG. have n1_gt1: n.-1 > 1 by [rewrite def_n]; have n1_gt0 := ltnW n1_gt1. have def_n1 := prednK n1_gt0. have def_m: (q * p)%N = m by rewrite -expnSr /m def_n. have notcxy: y \notin 'C[x]. apply: contraL (introT eqP xy); move/cent1P=> cxy. rewrite /conjg -cxy // eq_mulVg1 expgS !mulKg -order_dvdn ox. by rewrite pfactor_dvdn ?expn_gt0 ?p_gt0 // pfactorK // -ltnNge prednK. have tiXY: <[x]> :&: <[y]> = 1. rewrite setIC prime_TIg -?orderE ?oy //; apply: contra notcxy. by rewrite cycle_subG; apply: subsetP; rewrite cycle_subG cent1id. have notcGG: ~~ abelian G. by rewrite -defXY abelianM !cycle_abelian cent_cycle cycle_subG. have cXpY: <[y]> \subset 'C(<[x ^+ p]>). rewrite cent_cycle cycle_subG cent1C (sameP cent1P commgP) /commg conjXg xy. by rewrite -expgM mulSn expgD mulKg -expnSr def_n1 -/q -ox expg_order. have oxp: #[x ^+ p] = r by rewrite orderXdiv ox ?dvdn_exp //. have [sZG nZG] := andP (center_normal G). have defZ: 'Z(G) = <[x ^+ p]>. apply/eqP; rewrite eq_sym eqEcard subsetI -{2}defXY centM subsetI cent_cycle. rewrite 2!cycle_subG !groupX ?cent1id //= centsC cXpY /= -orderE oxp leqNgt. apply: contra notcGG => gtZr; apply: cyclic_center_factor_abelian. rewrite (dvdn_prime_cyclic p_pr) // card_quotient //. rewrite -(dvdn_pmul2l (cardG_gt0 'Z(G))) Lagrange // oG -def_m dvdn_pmul2r //. case/p_natP: (pgroupS sZG pG) gtZr => k ->. by rewrite ltn_exp2l // def_n1; exact: dvdn_exp2l. have Zxr: x ^+ r \in 'Z(G) by rewrite /r def_n expnS expgM defZ mem_cycle. have rxy: [~ x, y] = x ^+ r by rewrite /commg xy expgS mulKg. have defG': G^`(1) = <[x ^+ r]>. case/setIP: Zxr => _; rewrite -rxy -defXY -(norm_joinEr nXY). exact: der1_joing_cycles. have oG': #|G^`(1)| = p. by rewrite defG' -orderE orderXdiv ox /q -def_n1 ?dvdn_exp2l // expnS mulnK. have sG'Z: G^`(1) \subset 'Z(G) by rewrite defG' cycle_subG. have nil2_G: nil_class G = 2. by apply/eqP; rewrite eqn_leq andbC ltnNge nil_class1 notcGG nil_class2. have XYp: {in X & <[y]>, forall z t, (z * t) ^+ p \in z ^+ p *: <[x ^+ r ^+ 'C(p, 2)]>}. - move=> z t Xz Yt; have Gz := subsetP sXG z Xz; have Gt := subsetP sYG t Yt. have Rtz: [~ t, z] \in G^`(1) by exact: mem_commg. have cGtz: [~ t, z] \in 'C(G) by case/setIP: (subsetP sG'Z _ Rtz). rewrite expMg_Rmul /commute ?(centP cGtz) //. have ->: t ^+ p = 1 by apply/eqP; rewrite -order_dvdn -oy order_dvdG. rewrite defG' in Rtz; case/cycleP: Rtz => i ->. by rewrite mem_lcoset mulg1 mulKg expgAC mem_cycle. have defMho: 'Mho^1(G) = <[x ^+ p]>. apply/eqP; rewrite eqEsubset cycle_subG (Mho_p_elt 1) ?(mem_p_elt pG) //. rewrite andbT (MhoE 1 pG) gen_subG -defXY; apply/subsetP=> ztp. case/imsetP=> zt; case/imset2P=> z t Xz Yt -> -> {zt ztp}. apply: subsetP (XYp z t Xz Yt); case/cycleP: Xz => i ->. by rewrite expgAC mul_subG ?sub1set ?mem_cycle //= -defZ cycle_subG groupX. split=> //; try exact: extend_cyclic_Mho. - rewrite sdprodE //; split=> // z; case/cycleP=> i ->{z} j. rewrite conjXg -expgM mulnC expgM actX; congr (_ ^+ i). elim: j {i} => //= j ->; rewrite conjXg xy -!expgM mulnS mulSn addSn. rewrite addnA -mulSn -addSn expgD mulnCA (mulnC j). rewrite {3}/r def_n expnS mulnA -expnSr def_n1 -/q -ox -mulnA expgM. by rewrite expg_order expg1n mulg1. - by rewrite (Phi_joing pG) defMho -defZ (joing_idPr _) ?defZ. have G1y: y \in 'Ohm_1(G). by rewrite (OhmE _ pG) mem_gen // !inE Gy -order_dvdn oy /=. case: eqP => [[p2 n3] | notG8 k]; last case/andP=> k_gt0 lt_k_n1. apply/eqP; rewrite eqEsubset Ohm_sub -{1}defXY mulG_subG !cycle_subG. rewrite G1y -(groupMr _ G1y) /= (OhmE _ pG) mem_gen // !inE groupM //. rewrite /q /r p2 n3 in oy ox xy *. by rewrite expgS -mulgA -{1}(invg2id oy) -conjgE xy -expgS -order_dvdn ox. have le_k_n2: k <= n.-2 by rewrite -def_n1 in lt_k_n1. suffices{lt_k_n1} defGk: <[x ^+ (p ^ (n - k.+1))]> \x <[y]> = 'Ohm_k(G). split=> //; case/dprodP: defGk => _ <- _ tiXkY; rewrite expnSr TI_cardMg //. rewrite -!orderE oy (subnDA 1) subn1 orderXdiv ox ?dvdn_exp2l ?leq_subr //. by rewrite /q -{1}(subnK (ltnW lt_k_n1)) expnD mulKn // expn_gt0 p_gt0. suffices{k k_gt0 le_k_n2} defGn2: <[x ^+ p]> \x <[y]> = 'Ohm_(n.-2)(G). have:= Ohm_dprod k defGn2; have p_xp := mem_p_elt pG (groupX p Gx). rewrite (Ohm_p_cycle _ p_xp) (Ohm_p_cycle _ (mem_p_elt pG Gy)) oxp oy. rewrite pfactorK ?(pfactorK 1) // (eqnP k_gt0) expg1 -expgM -expnS. rewrite -subSn // -subSS def_n1 def_n => -> /=; rewrite subnSK // subn2. by apply/eqP; rewrite eqEsubset OhmS ?Ohm_sub //= -{1}Ohm_id OhmS ?Ohm_leq. rewrite dprodEY //=; last by apply/trivgP; rewrite -tiXY setSI ?cycleX. apply/eqP; rewrite eqEsubset join_subG !cycle_subG /= {-2}(OhmE _ pG) -/r. rewrite def_n (subsetP (Ohm_leq G (ltn0Sn _))) // mem_gen /=; last first. by rewrite !inE -order_dvdn oxp groupX /=. rewrite gen_subG /= cent_joinEr // -defXY; apply/subsetP=> uv; case/setIP. case/imset2P=> u v Xu Yv ->{uv}; rewrite /r inE def_n expnS expgM. case/lcosetP: (XYp u v Xu Yv) => _ /cycleP[j ->] ->. case/cycleP: Xu => i ->{u}; rewrite -!(expgM, expgD) -order_dvdn ox. rewrite (mulnC r) /r {1}def_n expnSr mulnA -mulnDl -mulnA -expnS. rewrite subnSK // subn2 /q -def_n1 expnS dvdn_pmul2r // dvdn_addl. by case/dvdnP=> k ->; rewrite mulnC expgM mem_mulg ?mem_cycle. case: (ltngtP n 3) => [|n_gt3|n3]; first by rewrite ltnNge n_gt2. by rewrite -subnSK // expnSr mulnA dvdn_mull. case: (even_prime p_pr) notG8 => [-> | oddp _]; first by rewrite n3. by rewrite bin2odd // -!mulnA dvdn_mulr. Qed. End ModularGroup. (* Basic properties of dihedral groups; these will be refined for dihedral *) (* 2-groups in the section on extremal 2-groups. *) Section DihedralGroup. Variable q : nat. Hypothesis q_gt1 : q > 1. Let m := q.*2. Let def2 : pdiv m = 2. Proof. apply/eqP; rewrite /m -mul2n eqn_leq pdiv_min_dvd ?dvdn_mulr //. by rewrite prime_gt1 // pdiv_prime // (@leq_pmul2l 2 1) ltnW. Qed. Let def_q : m %/ pdiv m = q. Proof. by rewrite def2 divn2 half_double. Qed. Section Dihedral_extension. Variable p : nat. Hypotheses (p_gt1 : p > 1) (even_p : 2 %| p). Local Notation ED := [set: gsort (Extremal.gtype q p q.-1)]. Lemma card_ext_dihedral : #|ED| = (p./2 * m)%N. Proof. by rewrite Extremal.card // /m -mul2n -divn2 mulnA divnK. Qed. Lemma Grp_ext_dihedral : ED \isog Grp (x : y : (x ^+ q, y ^+ p, x ^ y = x^-1)). Proof. suffices isoED: ED \isog Grp (x : y : (x ^+ q, y ^+ p, x ^ y = x ^+ q.-1)). move=> gT G; rewrite isoED. apply: eq_existsb => [[x y]] /=; rewrite !xpair_eqE. congr (_ && _); apply: andb_id2l; move/eqP=> xq1; congr (_ && (_ == _)). by apply/eqP; rewrite eq_sym eq_invg_mul -expgS (ltn_predK q_gt1) xq1. have unitrN1 : - 1 \in GRing.unit by move=> R; rewrite unitrN unitr1. pose uN1 := FinRing.unit ('Z_#[Zp1 : 'Z_q]) (unitrN1 _). apply: Extremal.Grp => //; exists (Zp_unitm uN1). rewrite Aut_aut order_injm ?injm_Zp_unitm ?in_setT //; split=> //. by rewrite (dvdn_trans _ even_p) // order_dvdn -val_eqE /= mulrNN. apply/eqP; rewrite autE ?cycle_id // eq_expg_mod_order /=. by rewrite order_Zp1 !Zp_cast // !modn_mod (modn_small q_gt1) subn1. Qed. End Dihedral_extension. Lemma card_dihedral : #|'D_m| = m. Proof. by rewrite /('D_m)%type def_q card_ext_dihedral ?mul1n. Qed. Lemma Grp_dihedral : 'D_m \isog Grp (x : y : (x ^+ q, y ^+ 2, x ^ y = x^-1)). Proof. by rewrite /('D_m)%type def_q; exact: Grp_ext_dihedral. Qed. Lemma Grp'_dihedral : 'D_m \isog Grp (x : y : (x ^+ 2, y ^+ 2, (x * y) ^+ q)). Proof. move=> gT G; rewrite Grp_dihedral; apply/existsP/existsP=> [] [[x y]] /=. case/eqP=> <- xq1 y2 xy; exists (x * y, y); rewrite !xpair_eqE /= eqEsubset. rewrite !join_subG !joing_subr !cycle_subG -{3}(mulgK y x) /=. rewrite 2?groupM ?groupV ?mem_gen ?inE ?cycle_id ?orbT //= -mulgA expgS. by rewrite {1}(conjgC x) xy -mulgA mulKg -(expgS y 1) y2 mulg1 xq1 !eqxx. case/eqP=> <- x2 y2 xyq; exists (x * y, y); rewrite !xpair_eqE /= eqEsubset. rewrite !join_subG !joing_subr !cycle_subG -{3}(mulgK y x) /=. rewrite 2?groupM ?groupV ?mem_gen ?inE ?cycle_id ?orbT //= xyq y2 !eqxx /=. by rewrite eq_sym eq_invg_mul !mulgA mulgK -mulgA -!(expgS _ 1) x2 y2 mulg1. Qed. End DihedralGroup. Lemma involutions_gen_dihedral gT (x y : gT) : let G := <<[set x; y]>> in #[x] = 2 -> #[y] = 2 -> x != y -> G \isog 'D_#|G|. Proof. move=> G ox oy ne_x_y; pose q := #[x * y]. have q_gt1: q > 1 by rewrite order_gt1 -eq_invg_mul invg_expg ox. have homG: G \homg 'D_q.*2. rewrite Grp'_dihedral //; apply/existsP; exists (x, y); rewrite /= !xpair_eqE. by rewrite joing_idl joing_idr -{1}ox -oy !expg_order !eqxx. suff oG: #|G| = q.*2 by rewrite oG isogEcard oG card_dihedral ?leqnn ?andbT. have: #|G| %| q.*2 by rewrite -card_dihedral ?card_homg. have Gxy: <[x * y]> \subset G. by rewrite cycle_subG groupM ?mem_gen ?set21 ?set22. have[k oG]: exists k, #|G| = (k * q)%N by apply/dvdnP; rewrite cardSg. rewrite oG -mul2n dvdn_pmul2r ?order_gt0 ?dvdn_divisors // !inE /=. case/pred2P=> [k1 | -> //]; case/negP: ne_x_y. have cycG: cyclic G. apply/cyclicP; exists (x * y); apply/eqP. by rewrite eq_sym eqEcard Gxy oG k1 mul1n leqnn. have: <[x]> == <[y]>. by rewrite (eq_subG_cyclic cycG) ?genS ?subsetUl ?subsetUr -?orderE ?ox ?oy. by rewrite eqEcard cycle_subG /= cycle2g // !inE -order_eq1 ox; case/andP. Qed. Lemma Grp_2dihedral n : n > 1 -> 'D_(2 ^ n) \isog Grp (x : y : (x ^+ (2 ^ n.-1), y ^+ 2, x ^ y = x^-1)). Proof. move=> n_gt1; rewrite -(ltn_predK n_gt1) expnS mul2n /=. by apply: Grp_dihedral; rewrite (ltn_exp2l 0) // -(subnKC n_gt1). Qed. Lemma card_2dihedral n : n > 1 -> #|'D_(2 ^ n)| = (2 ^ n)%N. Proof. move=> n_gt1; rewrite -(ltn_predK n_gt1) expnS mul2n /= card_dihedral //. by rewrite (ltn_exp2l 0) // -(subnKC n_gt1). Qed. Lemma card_semidihedral n : n > 3 -> #|'SD_(2 ^ n)| = (2 ^ n)%N. Proof. move=> n_gt3. rewrite /('SD__)%type -(subnKC (ltnW (ltnW n_gt3))) pdiv_pfactor //. by rewrite // !expnS !mulKn -?expnS ?Extremal.card //= (ltn_exp2l 0). Qed. Lemma Grp_semidihedral n : n > 3 -> 'SD_(2 ^ n) \isog Grp (x : y : (x ^+ (2 ^ n.-1), y ^+ 2, x ^ y = x ^+ (2 ^ n.-2).-1)). Proof. move=> n_gt3. rewrite /('SD__)%type -(subnKC (ltnW (ltnW n_gt3))) pdiv_pfactor //. rewrite !expnS !mulKn // -!expnS /=; set q := (2 ^ _)%N. have q_gt1: q > 1 by rewrite (ltn_exp2l 0). apply: Extremal.Grp => //; set B := <[_]>. have oB: #|B| = q by rewrite -orderE order_Zp1 Zp_cast. have pB: 2.-group B by rewrite /pgroup oB pnat_exp. have ntB: B != 1 by rewrite -cardG_gt1 oB. have [] := cyclic_pgroup_Aut_structure pB (cycle_cyclic _) ntB. rewrite oB /= pfactorK //= -/B => m [[def_m _ _ _ _] _]. rewrite -{1 2}(subnKC n_gt3) => [[t [At ot _ [s [_ _ _ defA]]]]]. case/dprodP: defA => _ defA cst _. have{cst defA} cAt: t \in 'C(Aut B). rewrite -defA centM inE -sub_cent1 -cent_cycle centsC cst /=. by rewrite cent_cycle cent1id. case=> s0 [As0 os0 _ def_s0t _]; exists (s0 * t). rewrite -def_m ?groupM ?cycle_id // def_s0t !Zp_expg !mul1n valZpK Zp_nat. rewrite order_dvdn expgMn /commute 1?(centP cAt) // -{1}os0 -{1}ot. by rewrite !expg_order mul1g. Qed. Section Quaternion. Variable n : nat. Hypothesis n_gt2 : n > 2. Let m := (2 ^ n)%N. Let q := (2 ^ n.-1)%N. Let r := (2 ^ n.-2)%N. Let GrpQ := 'Q_m \isog Grp (x : y : (x ^+ q, y ^+ 2 = x ^+ r, x ^ y = x^-1)). Let defQ : #|'Q_m| = m /\ GrpQ. Proof. have q_gt1 : q > 1 by rewrite (ltn_exp2l 0) // -(subnKC n_gt2). have def_m : (2 * q)%N = m by rewrite -expnS (ltn_predK n_gt2). have def_q : m %/ pdiv m = q by rewrite /m -(ltn_predK n_gt2) pdiv_pfactor // expnS mulKn. have r_gt1 : r > 1 by rewrite (ltn_exp2l 0) // -(subnKC n_gt2). have def2r : (2 * r)%N = q by rewrite -expnS /q -(subnKC n_gt2). rewrite /GrpQ [@quaternion_gtype _]unlock /quaternion_kernel {}def_q. set B := [set: _]; have: B \homg Grp (u : v : (u ^+ q, v ^+ 4, u ^ v = u^-1)). by rewrite -Grp_ext_dihedral ?homg_refl. have: #|B| = (q * 4)%N by rewrite card_ext_dihedral // mulnC -muln2 -mulnA. rewrite {}/B; move: (Extremal.gtype q 4 _) => gT. set B := [set: gT] => oB; set K := _ :\: _. case/existsP=> -[u v] /= /eqP[defB uq v4 uv]. have nUV: <[v]> \subset 'N(<[u]>) by rewrite norms_cycle uv groupV cycle_id. rewrite norm_joinEr // in defB. have le_ou: #[u] <= q by rewrite dvdn_leq ?expn_gt0 // order_dvdn uq. have le_ov: #[v] <= 4 by rewrite dvdn_leq // order_dvdn v4. have tiUV: <[u]> :&: <[v]> = 1 by rewrite cardMg_TI // defB oB leq_mul. have{le_ou le_ov} [ou ov]: #[u] = q /\ #[v] = 4. have:= esym (leqif_mul (leqif_eq le_ou) (leqif_eq le_ov)).2. by rewrite -TI_cardMg // defB -oB eqxx eqn0Ngt cardG_gt0; do 2!case: eqP=> //. have sdB: <[u]> ><| <[v]> = B by rewrite sdprodE. have uvj j: u ^ (v ^+ j) = (if odd j then u^-1 else u). elim: j => [|j IHj]; first by rewrite conjg1. by rewrite expgS conjgM uv conjVg IHj (fun_if invg) invgK if_neg. have sqrB i j: (u ^+ i * v ^+ j) ^+ 2 = (if odd j then v ^+ 2 else u ^+ i.*2). rewrite expgS; case: ifP => odd_j. rewrite {1}(conjgC (u ^+ i)) conjXg uvj odd_j expgVn -mulgA mulKg. rewrite -expgD addnn -(odd_double_half j) odd_j doubleD addnC /=. by rewrite -(expg_mod _ v4) -!muln2 -mulnA modnMDl. rewrite {2}(conjgC (u ^+ i)) conjXg uvj odd_j mulgA -(mulgA (u ^+ i)). rewrite -expgD addnn -(odd_double_half j) odd_j -2!mul2n mulnA. by rewrite expgM v4 expg1n mulg1 -expgD addnn. pose w := u ^+ r * v ^+ 2. have Kw: w \in K. rewrite !inE sqrB /= -mul2n def2r uq eqxx andbT -defB. apply/imsetP=> [[_]] /imset2P[_ _ /cycleP[i ->] /cycleP[j ->] ->]. apply/eqP; rewrite sqrB; case: ifP => _. rewrite eq_mulgV1 mulgK -order_dvdn ou pfactor_dvdn ?expn_gt0 ?pfactorK //. by rewrite -ltnNge -(subnKC n_gt2). rewrite (canF_eq (mulKg _)); apply/eqP=> def_v2. suffices: v ^+ 2 \in <[u]> :&: <[v]> by rewrite tiUV inE -order_dvdn ov. by rewrite inE {1}def_v2 groupM ?groupV !mem_cycle. have ow: #[w] = 2. case/setDP: Kw; rewrite inE -order_dvdn dvdn_divisors // !inE /= order_eq1. by case/orP=> /eqP-> // /imsetP[]; exists 1; rewrite ?inE ?expg1n. have defK: K = [set w]. apply/eqP; rewrite eqEsubset sub1set Kw andbT subDset setUC. apply/subsetP=> uivj; have: uivj \in B by rewrite inE. rewrite -{1}defB => /imset2P[_ _ /cycleP[i ->] /cycleP[j ->] ->] {uivj}. rewrite !inE sqrB -{-1}[j]odd_double_half. case: (odd j); rewrite -order_dvdn ?ov // ou -def2r -mul2n dvdn_pmul2l //. case/dvdnP=> k ->{i}; apply/orP. rewrite add0n -[j./2]odd_double_half addnC doubleD -!muln2 -mulnA. rewrite -(expg_mod_order v) ov modnMDl; case: (odd _); last first. right; rewrite mulg1 /r -(subnKC n_gt2) expnSr mulnA expgM. by apply: mem_imset; rewrite inE. rewrite (inj_eq (mulIg _)) -expg_mod_order ou -[k]odd_double_half. rewrite addnC -muln2 mulnDl -mulnA def2r modnMDl -ou expg_mod_order. case: (odd k); [left | right]; rewrite ?mul1n ?mul1g //. by apply/imsetP; exists v; rewrite ?inE. have nKB: 'N(<>) = B. apply/setP=> b; rewrite !inE -genJ genS // {1}defK conjg_set1 sub1set. have:= Kw; rewrite !inE -!order_dvdn orderJ ow !andbT; apply: contra. case/imsetP=> z _ def_wb; apply/imsetP; exists (z ^ b^-1); rewrite ?inE //. by rewrite -conjXg -def_wb conjgK. rewrite -im_quotient card_quotient // nKB -divgS ?subsetT //. split; first by rewrite oB defK -orderE ow (mulnA q 2 2) mulnK // mulnC. apply: intro_isoGrp => [|rT H]. apply/existsP; exists (coset _ u, coset _ v); rewrite /= !xpair_eqE. rewrite -!morphX -?morphJ -?morphV /= ?nKB ?in_setT // uq uv morph1 !eqxx. rewrite -/B -defB -norm_joinEr // quotientY ?nKB ?subsetT //= andbT. rewrite !quotient_cycle /= ?nKB ?in_setT ?eqxx //=. by rewrite -(coset_kerl _ (mem_gen Kw)) -mulgA -expgD v4 mulg1. case/existsP=> -[x y] /= /eqP[defH xq y2 xy]. have ox: #[x] %| #[u] by rewrite ou order_dvdn xq. have oy: #[y] %| #[v]. by rewrite ov order_dvdn (expgM y 2 2) y2 -expgM mulnC def2r xq. have actB: {in <[u]> & <[v]>, morph_act 'J 'J (eltm ox) (eltm oy)}. move=> _ _ /cycleP[i ->] /cycleP[j ->] /=. rewrite conjXg uvj fun_if if_arg fun_if expgVn morphV ?mem_cycle //= !eltmE. rewrite -expgVn -if_arg -fun_if conjXg; congr (_ ^+ i). rewrite -{2}[j]odd_double_half addnC expgD -mul2n expgM y2. rewrite -expgM conjgM (conjgE x) commuteX // mulKg. by case: (odd j); rewrite ?conjg1. pose f := sdprodm sdB actB. have Kf: 'ker (coset <>) \subset 'ker f. rewrite ker_coset defK cycle_subG /= ker_sdprodm. apply/imset2P; exists (u ^+ r) (v ^+ 2); first exact: mem_cycle. by rewrite inE mem_cycle /= !eltmE y2. by apply: canRL (mulgK _) _; rewrite -mulgA -expgD v4 mulg1. have Df: 'dom f \subset 'dom (coset <>) by rewrite /dom nKB subsetT. apply/homgP; exists (factm_morphism Kf Df); rewrite morphim_factm /= -/B. rewrite -{2}defB morphim_sdprodm // !morphim_cycle ?cycle_id //= !eltm_id. by rewrite -norm_joinEr // norms_cycle xy groupV cycle_id. Qed. Lemma card_quaternion : #|'Q_m| = m. Proof. by case defQ. Qed. Lemma Grp_quaternion : GrpQ. Proof. by case defQ. Qed. End Quaternion. Lemma eq_Mod8_D8 : 'Mod_8 = 'D_8. Proof. by []. Qed. Section ExtremalStructure. Variables (gT : finGroupType) (G : {group gT}) (n : nat). Implicit Type H : {group gT}. Let m := (2 ^ n)%N. Let q := (2 ^ n.-1)%N. Let q_gt0: q > 0. Proof. by rewrite expn_gt0. Qed. Let r := (2 ^ n.-2)%N. Let r_gt0: r > 0. Proof. by rewrite expn_gt0. Qed. Let def2qr : n > 1 -> [/\ 2 * q = m, 2 * r = q, q < m & r < q]%N. Proof. by rewrite /q /m /r; move/subnKC=> <-; rewrite !ltn_exp2l ?expnS. Qed. Lemma generators_2dihedral : n > 1 -> G \isog 'D_m -> exists2 xy, extremal_generators G 2 n xy & let: (x, y) := xy in #[y] = 2 /\ x ^ y = x^-1. Proof. move=> n_gt1; have [def2q _ ltqm _] := def2qr n_gt1. case/(isoGrpP _ (Grp_2dihedral n_gt1)); rewrite card_2dihedral // -/ m => oG. case/existsP=> -[x y] /=; rewrite -/q => /eqP[defG xq y2 xy]. have{defG} defG: <[x]> * <[y]> = G. by rewrite -norm_joinEr // norms_cycle xy groupV cycle_id. have notXy: y \notin <[x]>. apply: contraL ltqm => Xy; rewrite -leqNgt -oG -defG mulGSid ?cycle_subG //. by rewrite dvdn_leq // order_dvdn xq. have oy: #[y] = 2 by exact: nt_prime_order (group1_contra notXy). have ox: #[x] = q. apply: double_inj; rewrite -muln2 -oy -mul2n def2q -oG -defG TI_cardMg //. by rewrite setIC prime_TIg ?cycle_subG // -orderE oy. exists (x, y) => //=. by rewrite oG ox !inE notXy -!cycle_subG /= -defG mulG_subl mulG_subr. Qed. Lemma generators_semidihedral : n > 3 -> G \isog 'SD_m -> exists2 xy, extremal_generators G 2 n xy & let: (x, y) := xy in #[y] = 2 /\ x ^ y = x ^+ r.-1. Proof. move=> n_gt3; have [def2q _ ltqm _] := def2qr (ltnW (ltnW n_gt3)). case/(isoGrpP _ (Grp_semidihedral n_gt3)). rewrite card_semidihedral // -/m => oG. case/existsP=> -[x y] /=; rewrite -/q -/r => /eqP[defG xq y2 xy]. have{defG} defG: <[x]> * <[y]> = G. by rewrite -norm_joinEr // norms_cycle xy mem_cycle. have notXy: y \notin <[x]>. apply: contraL ltqm => Xy; rewrite -leqNgt -oG -defG mulGSid ?cycle_subG //. by rewrite dvdn_leq // order_dvdn xq. have oy: #[y] = 2 by exact: nt_prime_order (group1_contra notXy). have ox: #[x] = q. apply: double_inj; rewrite -muln2 -oy -mul2n def2q -oG -defG TI_cardMg //. by rewrite setIC prime_TIg ?cycle_subG // -orderE oy. exists (x, y) => //=. by rewrite oG ox !inE notXy -!cycle_subG /= -defG mulG_subl mulG_subr. Qed. Lemma generators_quaternion : n > 2 -> G \isog 'Q_m -> exists2 xy, extremal_generators G 2 n xy & let: (x, y) := xy in [/\ #[y] = 4, y ^+ 2 = x ^+ r & x ^ y = x^-1]. Proof. move=> n_gt2; have [def2q def2r ltqm _] := def2qr (ltnW n_gt2). case/(isoGrpP _ (Grp_quaternion n_gt2)); rewrite card_quaternion // -/m => oG. case/existsP=> -[x y] /=; rewrite -/q -/r => /eqP[defG xq y2 xy]. have{defG} defG: <[x]> * <[y]> = G. by rewrite -norm_joinEr // norms_cycle xy groupV cycle_id. have notXy: y \notin <[x]>. apply: contraL ltqm => Xy; rewrite -leqNgt -oG -defG mulGSid ?cycle_subG //. by rewrite dvdn_leq // order_dvdn xq. have ox: #[x] = q. apply/eqP; rewrite eqn_leq dvdn_leq ?order_dvdn ?xq //=. rewrite -(leq_pmul2r (order_gt0 y)) mul_cardG defG oG -def2q mulnAC mulnC. rewrite leq_pmul2r // dvdn_leq ?muln_gt0 ?cardG_gt0 // order_dvdn expgM. by rewrite -order_dvdn order_dvdG //= inE {1}y2 !mem_cycle. have oy2: #[y ^+ 2] = 2 by rewrite y2 orderXdiv ox -def2r ?dvdn_mull ?mulnK. exists (x, y) => /=; last by rewrite (orderXprime oy2). by rewrite oG !inE notXy -!cycle_subG /= -defG mulG_subl mulG_subr. Qed. Variables x y : gT. Implicit Type M : {group gT}. Let X := <[x]>. Let Y := <[y]>. Let yG := y ^: G. Let xyG := (x * y) ^: G. Let My := <>. Let Mxy := <>. Theorem dihedral2_structure : n > 1 -> extremal_generators G 2 n (x, y) -> G \isog 'D_m -> [/\ [/\ X ><| Y = G, {in G :\: X, forall t, #[t] = 2} & {in X & G :\: X, forall z t, z ^ t = z^-1}], [/\ G ^`(1) = <[x ^+ 2]>, 'Phi(G) = G ^`(1), #|G^`(1)| = r & nil_class G = n.-1], 'Ohm_1(G) = G /\ (forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (2 ^ k)]>), [/\ yG :|: xyG = G :\: X, [disjoint yG & xyG] & forall M, maximal M G = pred3 X My Mxy M] & if n == 2 then (2.-abelem G : Prop) else [/\ 'Z(G) = <[x ^+ r]>, #|'Z(G)| = 2, My \isog 'D_q, Mxy \isog 'D_q & forall U, cyclic U -> U \subset G -> #|G : U| = 2 -> U = X]]. Proof. move=> n_gt1 genG isoG; have [def2q def2r ltqm ltrq] := def2qr n_gt1. have [oG Gx ox X'y] := genG; rewrite -/m -/q -/X in oG ox X'y. case/extremal_generators_facts: genG; rewrite -/X // => pG maxX nsXG defXY nXY. have [sXG nXG]:= andP nsXG; have [Gy notXy]:= setDP X'y. have ox2: #[x ^+ 2] = r by rewrite orderXdiv ox -def2r ?dvdn_mulr ?mulKn. have oxr: #[x ^+ r] = 2 by rewrite orderXdiv ox -def2r ?dvdn_mull ?mulnK. have [[u v] [_ Gu ou U'v] [ov uv]] := generators_2dihedral n_gt1 isoG. have defUv: <[u]> :* v = G :\: <[u]>. apply: rcoset_index2; rewrite -?divgS ?cycle_subG //. by rewrite oG -orderE ou -def2q mulnK. have invUV: {in <[u]> & <[u]> :* v, forall z t, z ^ t = z^-1}. move=> z t; case/cycleP=> i ->; case/rcosetP=> z'; case/cycleP=> j -> ->{z t}. by rewrite conjgM {2}/conjg commuteX2 // mulKg conjXg uv expgVn. have oU': {in <[u]> :* v, forall t, #[t] = 2}. move=> t Uvt; apply: nt_prime_order => //; last first. by case: eqP Uvt => // ->; rewrite defUv !inE group1. case/rcosetP: Uvt => z Uz ->{t}; rewrite expgS {1}(conjgC z) -mulgA. by rewrite invUV ?rcoset_refl // mulKg -(expgS v 1) -ov expg_order. have defU: n > 2 -> {in G, forall z, #[z] = q -> <[z]> = <[u]>}. move=> n_gt2 z Gz oz; apply/eqP; rewrite eqEcard -!orderE oz cycle_subG. apply: contraLR n_gt2; rewrite ou leqnn andbT -(ltn_predK n_gt1) => notUz. by rewrite ltnS -(@ltn_exp2l 2) // -/q -oz oU' // defUv inE notUz. have n2_abelG: (n > 2) || 2.-abelem G. rewrite ltn_neqAle eq_sym n_gt1; case: eqP => //= n2. apply/abelemP=> //; split=> [|z Gz]. by apply: (p2group_abelian pG); rewrite oG pfactorK ?n2. case Uz: (z \in <[u]>); last by rewrite -expg_mod_order oU' // defUv inE Uz. apply/eqP; rewrite -order_dvdn (dvdn_trans (order_dvdG Uz)) // -orderE. by rewrite ou /q n2. have{oU'} oX': {in G :\: X, forall t, #[t] = 2}. have [n_gt2 | abelG] := orP n2_abelG; first by rewrite [X]defU // -defUv. move=> t /setDP[Gt notXt]; apply: nt_prime_order (group1_contra notXt) => //. by case/abelemP: abelG => // _ ->. have{invUV} invXX': {in X & G :\: X, forall z t, z ^ t = z^-1}. have [n_gt2 | abelG] := orP n2_abelG; first by rewrite [X]defU // -defUv. have [//|cGG oG2] := abelemP _ abelG. move=> t z Xt /setDP[Gz _]; apply/eqP; rewrite eq_sym eq_invg_mul. by rewrite /conjg -(centsP cGG z) // ?mulKg ?[t * t]oG2 ?(subsetP sXG). have nXiG k: G \subset 'N(<[x ^+ k]>). apply: char_norm_trans nXG. by rewrite cycle_subgroup_char // cycle_subG mem_cycle. have memL i: x ^+ (2 ^ i) \in 'L_i.+1(G). elim: i => // i IHi; rewrite -groupV expnSr expgM invMg. by rewrite -{2}(invXX' _ y) ?mem_cycle ?cycle_id ?mem_commg. have defG': G^`(1) = <[x ^+ 2]>. apply/eqP; rewrite eqEsubset cycle_subG (memL 1%N) ?der1_min //=. rewrite (p2group_abelian (quotient_pgroup _ pG)) ?card_quotient //=. rewrite -divgS ?cycle_subG ?groupX // oG -orderE ox2. by rewrite -def2q -def2r mulnA mulnK. have defG1: 'Mho^1(G) = <[x ^+ 2]>. apply/eqP; rewrite (MhoE _ pG) eqEsubset !gen_subG sub1set andbC. rewrite mem_gen; last exact: mem_imset. apply/subsetP=> z2; case/imsetP=> z Gz ->{z2}. case Xz: (z \in X); last by rewrite -{1}(oX' z) ?expg_order ?group1 // inE Xz. by case/cycleP: Xz => i ->; rewrite expgAC mem_cycle. have defPhi: 'Phi(G) = <[x ^+ 2]>. by rewrite (Phi_joing pG) defG' defG1 (joing_idPl _). have def_tG: {in G :\: X, forall t, t ^: G = <[x ^+ 2]> :* t}. move=> t X't; have [Gt notXt] := setDP X't. have defJt: {in X, forall z, t ^ z = z ^- 2 * t}. move=> z Xz; rewrite /= invMg -mulgA (conjgC _ t). by rewrite (invXX' _ t) ?groupV ?invgK. have defGt: X * <[t]> = G by rewrite (mulg_normal_maximal nsXG) ?cycle_subG. apply/setP=> tz; apply/imsetP/rcosetP=> [[t'z] | [z]]. rewrite -defGt -normC ?cycle_subG ?(subsetP nXG) //. case/imset2P=> _ z /cycleP[j ->] Xz -> -> {tz t'z}. exists (z ^- 2); last by rewrite conjgM {2}/conjg commuteX // mulKg defJt. case/cycleP: Xz => i ->{z}. by rewrite groupV -expgM mulnC expgM mem_cycle. case/cycleP=> i -> -> {z tz}; exists (x ^- i); first by rewrite groupV groupX. by rewrite defJt ?groupV ?mem_cycle // expgVn invgK expgAC. have defMt: {in G :\: X, forall t, <[x ^+ 2]> ><| <[t]> = <>}. move=> t X't; have [Gt notXt] := setDP X't. rewrite sdprodEY ?cycle_subG ?(subsetP (nXiG 2)) //; first 1 last. rewrite setIC prime_TIg -?orderE ?oX' // cycle_subG. by apply: contra notXt; apply: subsetP; rewrite cycleX. apply/eqP; have: t \in <> by rewrite mem_gen ?class_refl. rewrite def_tG // eqEsubset join_subG !cycle_subG !gen_subG => tGt. rewrite tGt -(groupMr _ tGt) mem_gen ?mem_mulg ?cycle_id ?set11 //=. by rewrite mul_subG ?joing_subl // -gen_subG joing_subr. have oMt: {in G :\: X, forall t, #|<>| = q}. move=> t X't /=; rewrite -(sdprod_card (defMt t X't)) -!orderE ox2 oX' //. by rewrite mulnC. have sMtG: {in G :\: X, forall t, <> \subset G}. by move=> t; case/setDP=> Gt _; rewrite gen_subG class_subG. have maxMt: {in G :\: X, forall t, maximal <> G}. move=> t X't /=; rewrite p_index_maximal -?divgS ?sMtG ?oMt //. by rewrite oG -def2q mulnK. have X'xy: x * y \in G :\: X by rewrite !inE !groupMl ?cycle_id ?notXy. have ti_yG_xyG: [disjoint yG & xyG]. apply/pred0P=> t; rewrite /= /yG /xyG !def_tG //; apply/andP=> [[yGt]]. rewrite rcoset_sym (rcoset_transl yGt) mem_rcoset mulgK; move/order_dvdG. by rewrite -orderE ox2 ox gtnNdvd. have s_tG_X': {in G :\: X, forall t, t ^: G \subset G :\: X}. by move=> t X't /=; rewrite class_sub_norm // normsD ?normG. have defX': yG :|: xyG = G :\: X. apply/eqP; rewrite eqEcard subUset !s_tG_X' //= -(leq_add2l q) -{1}ox orderE. rewrite -/X -{1}(setIidPr sXG) cardsID oG -def2q mul2n -addnn leq_add2l. rewrite -(leq_add2r #|yG :&: xyG|) cardsUI disjoint_setI0 // cards0 addn0. by rewrite /yG /xyG !def_tG // !card_rcoset addnn -mul2n -orderE ox2 def2r. split. - by rewrite ?sdprodE // setIC // prime_TIg ?cycle_subG // -orderE ?oX'. - rewrite defG'; split=> //. apply/eqP; rewrite eqn_leq (leq_trans (nil_class_pgroup pG)); last first. by rewrite oG pfactorK // geq_max leqnn -(subnKC n_gt1). rewrite -(subnKC n_gt1) subn2 ltnNge. rewrite (sameP (lcn_nil_classP _ (pgroup_nil pG)) eqP). by apply/trivgPn; exists (x ^+ r); rewrite ?memL // -order_gt1 oxr. - split; last exact: extend_cyclic_Mho. have sX'G1: {subset G :\: X <= 'Ohm_1(G)}. move=> t X't; have [Gt _] := setDP X't. by rewrite (OhmE 1 pG) mem_gen // !inE Gt -(oX' t) //= expg_order. apply/eqP; rewrite eqEsubset Ohm_sub -{1}defXY mulG_subG !cycle_subG. by rewrite -(groupMr _ (sX'G1 y X'y)) !sX'G1. - split=> //= H; apply/idP/idP=> [maxH |]; last first. by case/or3P; move/eqP->; rewrite ?maxMt. have [sHG nHG]:= andP (p_maximal_normal pG maxH). have oH: #|H| = q. apply: double_inj; rewrite -muln2 -(p_maximal_index pG maxH) Lagrange //. by rewrite oG -mul2n. rewrite !(eq_sym (gval H)) -eq_sym !eqEcard oH -orderE ox !oMt // !leqnn. case sHX: (H \subset X) => //=; case/subsetPn: sHX => t Ht notXt. have: t \in yG :|: xyG by rewrite defX' inE notXt (subsetP sHG). rewrite !andbT !gen_subG /yG /xyG. by case/setUP; move/class_transr <-; rewrite !class_sub_norm ?Ht ?orbT. rewrite eqn_leq n_gt1; case: leqP n2_abelG => //= n_gt2 _. have ->: 'Z(G) = <[x ^+ r]>. apply/eqP; rewrite eqEcard andbC -orderE oxr -{1}(setIidPr (center_sub G)). rewrite cardG_gt1 /= meet_center_nil ?(pgroup_nil pG) //; last first. by rewrite -cardG_gt1 oG (leq_trans _ ltqm). apply/subsetP=> t; case/setIP=> Gt cGt. case X't: (t \in G :\: X). move/eqP: (invXX' _ _ (cycle_id x) X't). rewrite /conjg -(centP cGt) // mulKg eq_sym eq_invg_mul -order_eq1 ox2. by rewrite (eqn_exp2l _ 0) // -(subnKC n_gt2). move/idPn: X't; rewrite inE Gt andbT negbK => Xt. have:= Ohm_p_cycle 1 (mem_p_elt pG Gx); rewrite ox pfactorK // subn1 => <-. rewrite (OhmE _ (pgroupS sXG pG)) mem_gen // !inE Xt /=. by rewrite -eq_invg_mul -(invXX' _ y) // /conjg (centP cGt) // mulKg. have isoMt: {in G :\: X, forall t, <> \isog 'D_q}. have n1_gt1: n.-1 > 1 by rewrite -(subnKC n_gt2). move=> t X't /=; rewrite isogEcard card_2dihedral ?oMt // leqnn andbT. rewrite Grp_2dihedral //; apply/existsP; exists (x ^+ 2, t) => /=. have [_ <- nX2T _] := sdprodP (defMt t X't); rewrite norm_joinEr //. rewrite -/q -/r !xpair_eqE eqxx -expgM def2r -ox -{1}(oX' t X't). by rewrite !expg_order !eqxx /= invXX' ?mem_cycle. rewrite !isoMt //; split=> // C; case/cyclicP=> z ->{C} sCG iCG. rewrite [X]defU // defU -?cycle_subG //. by apply: double_inj; rewrite -muln2 -iCG Lagrange // oG -mul2n. Qed. Theorem quaternion_structure : n > 2 -> extremal_generators G 2 n (x, y) -> G \isog 'Q_m -> [/\ [/\ pprod X Y = G, {in G :\: X, forall t, #[t] = 4} & {in X & G :\: X, forall z t, z ^ t = z^-1}], [/\ G ^`(1) = <[x ^+ 2]>, 'Phi(G) = G ^`(1), #|G^`(1)| = r & nil_class G = n.-1], [/\ 'Z(G) = <[x ^+ r]>, #|'Z(G)| = 2, forall u, u \in G -> #[u] = 2 -> u = x ^+ r, 'Ohm_1(G) = <[x ^+ r]> /\ 'Ohm_2(G) = G & forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (2 ^ k)]>], [/\ yG :|: xyG = G :\: X /\ [disjoint yG & xyG] & forall M, maximal M G = pred3 X My Mxy M] & n > 3 -> [/\ My \isog 'Q_q, Mxy \isog 'Q_q & forall U, cyclic U -> U \subset G -> #|G : U| = 2 -> U = X]]. Proof. move=> n_gt2 genG isoG; have [def2q def2r ltqm ltrq] := def2qr (ltnW n_gt2). have [oG Gx ox X'y] := genG; rewrite -/m -/q -/X in oG ox X'y. case/extremal_generators_facts: genG; rewrite -/X // => pG maxX nsXG defXY nXY. have [sXG nXG]:= andP nsXG; have [Gy notXy]:= setDP X'y. have oxr: #[x ^+ r] = 2 by rewrite orderXdiv ox -def2r ?dvdn_mull ?mulnK. have ox2: #[x ^+ 2] = r by rewrite orderXdiv ox -def2r ?dvdn_mulr ?mulKn. have [[u v] [_ Gu ou U'v] [ov v2 uv]] := generators_quaternion n_gt2 isoG. have defUv: <[u]> :* v = G :\: <[u]>. apply: rcoset_index2; rewrite -?divgS ?cycle_subG //. by rewrite oG -orderE ou -def2q mulnK. have invUV: {in <[u]> & <[u]> :* v, forall z t, z ^ t = z^-1}. move=> z t; case/cycleP=> i ->; case/rcosetP=> ?; case/cycleP=> j -> ->{z t}. by rewrite conjgM {2}/conjg commuteX2 // mulKg conjXg uv expgVn. have U'2: {in <[u]> :* v, forall t, t ^+ 2 = u ^+ r}. move=> t; case/rcosetP=> z Uz ->; rewrite expgS {1}(conjgC z) -mulgA. by rewrite invUV ?rcoset_refl // mulKg -(expgS v 1) v2. have our: #[u ^+ r] = 2 by rewrite orderXdiv ou -/q -def2r ?dvdn_mull ?mulnK. have def_ur: {in G, forall t, #[t] = 2 -> t = u ^+ r}. move=> t Gt /= ot; case Ut: (t \in <[u]>); last first. move/eqP: ot; rewrite eqn_dvd order_dvdn -order_eq1 U'2 ?our //. by rewrite defUv inE Ut. have p2u: 2.-elt u by rewrite /p_elt ou pnat_exp. have: t \in 'Ohm_1(<[u]>). by rewrite (OhmE _ p2u) mem_gen // !inE Ut -order_dvdn ot. rewrite (Ohm_p_cycle _ p2u) ou pfactorK // subn1 -/r cycle_traject our !inE. by rewrite -order_eq1 ot /= mulg1; move/eqP. have defU: n > 3 -> {in G, forall z, #[z] = q -> <[z]> = <[u]>}. move=> n_gt3 z Gz oz; apply/eqP; rewrite eqEcard -!orderE oz cycle_subG. rewrite ou leqnn andbT; apply: contraLR n_gt3 => notUz. rewrite -(ltn_predK n_gt2) ltnS -(@ltn_exp2l 2) // -/q -oz. by rewrite (@orderXprime _ 2 2) // U'2 // defUv inE notUz. have def_xr: x ^+ r = u ^+ r by apply: def_ur; rewrite ?groupX. have X'2: {in G :\: X, forall t, t ^+ 2 = u ^+ r}. case: (ltngtP n 3) => [|n_gt3|n3 t]; first by rewrite ltnNge n_gt2. by rewrite /X defU // -defUv. case/setDP=> Gt notXt. case Ut: (t \in <[u]>); last by rewrite U'2 // defUv inE Ut. rewrite [t ^+ 2]def_ur ?groupX //. have:= order_dvdG Ut; rewrite -orderE ou /q n3 dvdn_divisors ?inE //=. rewrite order_eq1 (negbTE (group1_contra notXt)) /=. case/pred2P=> oz; last by rewrite orderXdiv oz. by rewrite [t]def_ur // -def_xr mem_cycle in notXt. have oX': {in G :\: X, forall z, #[z] = 4}. by move=> t X't /=; rewrite (@orderXprime _ 2 2) // X'2. have defZ: 'Z(G) = <[x ^+ r]>. apply/eqP; rewrite eqEcard andbC -orderE oxr -{1}(setIidPr (center_sub G)). rewrite cardG_gt1 /= meet_center_nil ?(pgroup_nil pG) //; last first. by rewrite -cardG_gt1 oG (leq_trans _ ltqm). apply/subsetP=> z; case/setIP=> Gz cGz; have [Gv _]:= setDP U'v. case Uvz: (z \in <[u]> :* v). move/eqP: (invUV _ _ (cycle_id u) Uvz). rewrite /conjg -(centP cGz) // mulKg eq_sym eq_invg_mul -(order_dvdn _ 2). by rewrite ou pfactor_dvdn // -(subnKC n_gt2). move/idPn: Uvz; rewrite defUv inE Gz andbT negbK def_xr => Uz. have p_u: 2.-elt u := mem_p_elt pG Gu. suff: z \in 'Ohm_1(<[u]>) by rewrite (Ohm_p_cycle 1 p_u) ou pfactorK // subn1. rewrite (OhmE _ p_u) mem_gen // !inE Uz /= -eq_invg_mul. by rewrite -(invUV _ v) ?rcoset_refl // /conjg (centP cGz) ?mulKg. have{invUV} invXX': {in X & G :\: X, forall z t, z ^ t = z^-1}. case: (ltngtP n 3) => [|n_gt3|n3 t z Xt]; first by rewrite ltnNge n_gt2. by rewrite /X defU // -defUv. case/setDP=> Gz notXz; rewrite /q /r n3 /= in oxr ox. suff xz: x ^ z = x^-1 by case/cycleP: Xt => i ->; rewrite conjXg xz expgVn. have: x ^ z \in X by rewrite memJ_norm ?cycle_id ?(subsetP nXG). rewrite invg_expg /X cycle_traject ox !inE /= !mulg1 -order_eq1 orderJ ox /=. case/or3P; move/eqP=> //; last by move/(congr1 order); rewrite orderJ ox oxr. move/conjg_fixP; rewrite (sameP commgP cent1P) cent1C -cent_cycle -/X => cXz. have defXz: X * <[z]> = G by rewrite (mulg_normal_maximal nsXG) ?cycle_subG. have: z \in 'Z(G) by rewrite inE Gz -defXz centM inE cXz cent_cycle cent1id. by rewrite defZ => Xr_z; rewrite (subsetP (cycleX x r)) in notXz. have nXiG k: G \subset 'N(<[x ^+ k]>). apply: char_norm_trans nXG. by rewrite cycle_subgroup_char // cycle_subG mem_cycle. have memL i: x ^+ (2 ^ i) \in 'L_i.+1(G). elim: i => // i IHi; rewrite -groupV expnSr expgM invMg. by rewrite -{2}(invXX' _ y) ?mem_cycle ?cycle_id ?mem_commg. have defG': G^`(1) = <[x ^+ 2]>. apply/eqP; rewrite eqEsubset cycle_subG (memL 1%N) ?der1_min //=. rewrite (p2group_abelian (quotient_pgroup _ pG)) ?card_quotient //=. rewrite -divgS ?cycle_subG ?groupX // oG -orderE ox2. by rewrite -def2q -def2r mulnA mulnK. have defG1: 'Mho^1(G) = <[x ^+ 2]>. apply/eqP; rewrite (MhoE _ pG) eqEsubset !gen_subG sub1set andbC. rewrite mem_gen; last exact: mem_imset. apply/subsetP=> z2; case/imsetP=> z Gz ->{z2}. case Xz: (z \in X). by case/cycleP: Xz => i ->; rewrite -expgM mulnC expgM mem_cycle. rewrite (X'2 z) ?inE ?Xz // -def_xr. by rewrite /r -(subnKC n_gt2) expnS expgM mem_cycle. have defPhi: 'Phi(G) = <[x ^+ 2]>. by rewrite (Phi_joing pG) defG' defG1 (joing_idPl _). have def_tG: {in G :\: X, forall t, t ^: G = <[x ^+ 2]> :* t}. move=> t X't; have [Gt notXt] := setDP X't. have defJt: {in X, forall z, t ^ z = z ^- 2 * t}. move=> z Xz; rewrite /= invMg -mulgA (conjgC _ t). by rewrite (invXX' _ t) ?groupV ?invgK. have defGt: X * <[t]> = G by rewrite (mulg_normal_maximal nsXG) ?cycle_subG. apply/setP=> tz; apply/imsetP/rcosetP=> [[t'z] | [z]]. rewrite -defGt -normC ?cycle_subG ?(subsetP nXG) //. case/imset2P=> t' z; case/cycleP=> j -> Xz -> -> {tz t'z t'}. exists (z ^- 2); last by rewrite conjgM {2}/conjg commuteX // mulKg defJt. case/cycleP: Xz => i ->{z}. by rewrite groupV -expgM mulnC expgM mem_cycle. case/cycleP=> i -> -> {z tz}; exists (x ^- i); first by rewrite groupV groupX. by rewrite defJt ?groupV ?mem_cycle // expgVn invgK -!expgM mulnC. have defMt: {in G :\: X, forall t, <[x ^+ 2]> <*> <[t]> = <>}. move=> t X't; have [Gt notXt] := setDP X't. apply/eqP; have: t \in <> by rewrite mem_gen ?class_refl. rewrite def_tG // eqEsubset join_subG !cycle_subG !gen_subG => tGt. rewrite tGt -(groupMr _ tGt) mem_gen ?mem_mulg ?cycle_id ?set11 //=. by rewrite mul_subG ?joing_subl // -gen_subG joing_subr. have sMtG: {in G :\: X, forall t, <> \subset G}. by move=> t; case/setDP=> Gt _; rewrite gen_subG class_subG. have oMt: {in G :\: X, forall t, #|<>| = q}. move=> t X't; have [Gt notXt] := setDP X't. rewrite -defMt // -(Lagrange (joing_subl _ _)) -orderE ox2 -def2r mulnC. congr (_ * r)%N; rewrite -card_quotient /=; last first. by rewrite defMt // (subset_trans _ (nXiG 2)) ?sMtG. rewrite joingC quotientYidr ?(subset_trans _ (nXiG 2)) ?cycle_subG //. rewrite quotient_cycle ?(subsetP (nXiG 2)) //= -defPhi. rewrite -orderE (abelem_order_p (Phi_quotient_abelem pG)) ?mem_quotient //. apply: contraNneq notXt; move/coset_idr; move/implyP=> /=. by rewrite defPhi ?(subsetP (nXiG 2)) //; apply: subsetP; exact: cycleX. have maxMt: {in G :\: X, forall t, maximal <> G}. move=> t X't; rewrite /= p_index_maximal -?divgS ?sMtG ?oMt //. by rewrite oG -def2q mulnK. have X'xy: x * y \in G :\: X by rewrite !inE !groupMl ?cycle_id ?notXy. have ti_yG_xyG: [disjoint yG & xyG]. apply/pred0P=> t; rewrite /= /yG /xyG !def_tG //; apply/andP=> [[yGt]]. rewrite rcoset_sym (rcoset_transl yGt) mem_rcoset mulgK; move/order_dvdG. by rewrite -orderE ox2 ox gtnNdvd. have s_tG_X': {in G :\: X, forall t, t ^: G \subset G :\: X}. by move=> t X't /=; rewrite class_sub_norm // normsD ?normG. have defX': yG :|: xyG = G :\: X. apply/eqP; rewrite eqEcard subUset !s_tG_X' //= -(leq_add2l q) -{1}ox orderE. rewrite -/X -{1}(setIidPr sXG) cardsID oG -def2q mul2n -addnn leq_add2l. rewrite -(leq_add2r #|yG :&: xyG|) cardsUI disjoint_setI0 // cards0 addn0. by rewrite /yG /xyG !def_tG // !card_rcoset addnn -mul2n -orderE ox2 def2r. rewrite pprodE //; split=> // [|||n_gt3]. - rewrite defG'; split=> //; apply/eqP; rewrite eqn_leq. rewrite (leq_trans (nil_class_pgroup pG)); last first. by rewrite oG pfactorK // -(subnKC n_gt2). rewrite -(subnKC (ltnW n_gt2)) subn2 ltnNge. rewrite (sameP (lcn_nil_classP _ (pgroup_nil pG)) eqP). by apply/trivgPn; exists (x ^+ r); rewrite ?memL // -order_gt1 oxr. - rewrite {2}def_xr defZ; split=> //; last exact: extend_cyclic_Mho. split; apply/eqP; last first. have sX'G2: {subset G :\: X <= 'Ohm_2(G)}. move=> z X'z; have [Gz _] := setDP X'z. by rewrite (OhmE 2 pG) mem_gen // !inE Gz -order_dvdn oX'. rewrite eqEsubset Ohm_sub -{1}defXY mulG_subG !cycle_subG. by rewrite -(groupMr _ (sX'G2 y X'y)) !sX'G2. rewrite eqEsubset (OhmE 1 pG) cycle_subG gen_subG andbC. rewrite mem_gen ?inE ?groupX -?order_dvdn ?oxr //=. apply/subsetP=> t; case/setIP=> Gt; rewrite inE -order_dvdn /=. rewrite dvdn_divisors ?inE //= order_eq1. case/pred2P=> [->|]; first exact: group1. by move/def_ur=> -> //; rewrite def_xr cycle_id. - split=> //= H; apply/idP/idP=> [maxH |]; last first. by case/or3P=> /eqP->; rewrite ?maxMt. have [sHG nHG]:= andP (p_maximal_normal pG maxH). have oH: #|H| = q. apply: double_inj; rewrite -muln2 -(p_maximal_index pG maxH) Lagrange //. by rewrite oG -mul2n. rewrite !(eq_sym (gval H)) -eq_sym !eqEcard oH -orderE ox !oMt // !leqnn. case sHX: (H \subset X) => //=; case/subsetPn: sHX => z Hz notXz. have: z \in yG :|: xyG by rewrite defX' inE notXz (subsetP sHG). rewrite !andbT !gen_subG /yG /xyG. by case/setUP=> /class_transr <-; rewrite !class_sub_norm ?Hz ?orbT. have isoMt: {in G :\: X, forall z, <> \isog 'Q_q}. have n1_gt2: n.-1 > 2 by rewrite -(subnKC n_gt3). move=> z X'z /=; rewrite isogEcard card_quaternion ?oMt // leqnn andbT. rewrite Grp_quaternion //; apply/existsP; exists (x ^+ 2, z) => /=. rewrite defMt // -/q -/r !xpair_eqE -!expgM def2r -order_dvdn ox dvdnn. rewrite -expnS prednK; last by rewrite -subn2 subn_gt0. by rewrite X'2 // def_xr !eqxx /= invXX' ?mem_cycle. rewrite !isoMt //; split=> // C; case/cyclicP=> z ->{C} sCG iCG. rewrite [X]defU // defU -?cycle_subG //. by apply: double_inj; rewrite -muln2 -iCG Lagrange // oG -mul2n. Qed. Theorem semidihedral_structure : n > 3 -> extremal_generators G 2 n (x, y) -> G \isog 'SD_m -> #[y] = 2 -> [/\ [/\ X ><| Y = G, #[x * y] = 4 & {in X & G :\: X, forall z t, z ^ t = z ^+ r.-1}], [/\ G ^`(1) = <[x ^+ 2]>, 'Phi(G) = G ^`(1), #|G^`(1)| = r & nil_class G = n.-1], [/\ 'Z(G) = <[x ^+ r]>, #|'Z(G)| = 2, 'Ohm_1(G) = My /\ 'Ohm_2(G) = G & forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (2 ^ k)]>], [/\ yG :|: xyG = G :\: X /\ [disjoint yG & xyG] & forall H, maximal H G = pred3 X My Mxy H] & [/\ My \isog 'D_q, Mxy \isog 'Q_q & forall U, cyclic U -> U \subset G -> #|G : U| = 2 -> U = X]]. Proof. move=> n_gt3 genG isoG oy. have [def2q def2r ltqm ltrq] := def2qr (ltnW (ltnW n_gt3)). have [oG Gx ox X'y] := genG; rewrite -/m -/q -/X in oG ox X'y. case/extremal_generators_facts: genG; rewrite -/X // => pG maxX nsXG defXY nXY. have [sXG nXG]:= andP nsXG; have [Gy notXy]:= setDP X'y. have ox2: #[x ^+ 2] = r by rewrite orderXdiv ox -def2r ?dvdn_mulr ?mulKn. have oxr: #[x ^+ r] = 2 by rewrite orderXdiv ox -def2r ?dvdn_mull ?mulnK. have [[u v] [_ Gu ou U'v] [ov uv]] := generators_semidihedral n_gt3 isoG. have defUv: <[u]> :* v = G :\: <[u]>. apply: rcoset_index2; rewrite -?divgS ?cycle_subG //. by rewrite oG -orderE ou -def2q mulnK. have invUV: {in <[u]> & <[u]> :* v, forall z t, z ^ t = z ^+ r.-1}. move=> z t; case/cycleP=> i ->; case/rcosetP=> ?; case/cycleP=> j -> ->{z t}. by rewrite conjgM {2}/conjg commuteX2 // mulKg conjXg uv -!expgM mulnC. have [vV yV]: v^-1 = v /\ y^-1 = y by rewrite !invg_expg ov oy. have defU: {in G, forall z, #[z] = q -> <[z]> = <[u]>}. move=> z Gz /= oz; apply/eqP; rewrite eqEcard -!orderE oz ou leqnn andbT. apply: contraLR (n_gt3) => notUz; rewrite -leqNgt -(ltn_predK n_gt3) ltnS. rewrite -(@dvdn_Pexp2l 2) // -/q -{}oz order_dvdn expgM (expgS z). have{Gz notUz} [z' Uz' ->{z}]: exists2 z', z' \in <[u]> & z = z' * v. by apply/rcosetP; rewrite defUv inE -cycle_subG notUz Gz. rewrite {2}(conjgC z') invUV ?rcoset_refl // mulgA -{2}vV mulgK -expgS. by rewrite prednK // -expgM mulnC def2r -order_dvdn /q -ou order_dvdG. have{invUV} invXX': {in X & G :\: X, forall z t, z ^ t = z ^+ r.-1}. by rewrite /X defU -?defUv. have xy2: (x * y) ^+ 2 = x ^+ r. rewrite expgS {2}(conjgC x) invXX' ?cycle_id // mulgA -{2}yV mulgK -expgS. by rewrite prednK. have oxy: #[x * y] = 4 by rewrite (@orderXprime _ 2 2) ?xy2. have r_gt2: r > 2 by rewrite (ltn_exp2l 1) // -(subnKC n_gt3). have coXr1: coprime #[x] (2 ^ (n - 3)).-1. rewrite ox coprime_expl // -(@coprime_pexpl (n - 3)) ?coprimenP ?subn_gt0 //. by rewrite expn_gt0. have def2r1: (2 * (2 ^ (n - 3)).-1).+1 = r.-1. rewrite -!subn1 mulnBr -expnS [_.+1]subnSK ?(ltn_exp2l 0) //. by rewrite /r -(subnKC n_gt3). have defZ: 'Z(G) = <[x ^+ r]>. apply/eqP; rewrite eqEcard andbC -orderE oxr -{1}(setIidPr (center_sub G)). rewrite cardG_gt1 /= meet_center_nil ?(pgroup_nil pG) //; last first. by rewrite -cardG_gt1 oG (leq_trans _ ltqm). apply/subsetP=> z /setIP[Gz cGz]. case X'z: (z \in G :\: X). move/eqP: (invXX' _ _ (cycle_id x) X'z). rewrite /conjg -(centP cGz) // mulKg -def2r1 eq_mulVg1 expgS mulKg mulnC. rewrite -order_dvdn Gauss_dvdr // order_dvdn -order_eq1. by rewrite ox2 -(subnKC r_gt2). move/idPn: X'z; rewrite inE Gz andbT negbK => Xz. have:= Ohm_p_cycle 1 (mem_p_elt pG Gx); rewrite ox pfactorK // subn1 => <-. rewrite (OhmE _ (mem_p_elt pG Gx)) mem_gen // !inE Xz /=. rewrite -(expgK coXr1 Xz) -!expgM mulnCA -order_dvdn dvdn_mull //. rewrite mulnC order_dvdn -(inj_eq (mulgI z)) -expgS mulg1 def2r1. by rewrite -(invXX' z y) // /conjg (centP cGz) ?mulKg. have nXiG k: G \subset 'N(<[x ^+ k]>). apply: char_norm_trans nXG. by rewrite cycle_subgroup_char // cycle_subG mem_cycle. have memL i: x ^+ (2 ^ i) \in 'L_i.+1(G). elim: i => // i IHi; rewrite -(expgK coXr1 (mem_cycle _ _)) groupX //. rewrite -expgM expnSr -mulnA expgM -(mulKg (x ^+ (2 ^ i)) (_ ^+ _)). by rewrite -expgS def2r1 -(invXX' _ y) ?mem_cycle ?mem_commg. have defG': G^`(1) = <[x ^+ 2]>. apply/eqP; rewrite eqEsubset cycle_subG (memL 1%N) ?der1_min //=. rewrite (p2group_abelian (quotient_pgroup _ pG)) ?card_quotient //=. rewrite -divgS ?cycle_subG ?groupX // oG -orderE ox2. by rewrite -def2q -def2r mulnA mulnK. have defG1: 'Mho^1(G) = <[x ^+ 2]>. apply/eqP; rewrite (MhoE _ pG) eqEsubset !gen_subG sub1set andbC. rewrite mem_gen; last exact: mem_imset. apply/subsetP=> z2; case/imsetP=> z Gz ->{z2}. case Xz: (z \in X). by case/cycleP: Xz => i ->; rewrite -expgM mulnC expgM mem_cycle. have{Xz Gz} [xi Xxi ->{z}]: exists2 xi, xi \in X & z = xi * y. have Uvy: y \in <[u]> :* v by rewrite defUv -(defU x). apply/rcosetP; rewrite /X defU // (rcoset_transl Uvy) defUv. by rewrite inE -(defU x) ?Xz. rewrite expn1 expgS {2}(conjgC xi) -{2}[y]/(y ^+ 2.-1) -{1}oy -invg_expg. rewrite mulgA mulgK invXX' // -expgS prednK // /r -(subnKC n_gt3) expnS. by case/cycleP: Xxi => i ->; rewrite -expgM mulnCA expgM mem_cycle. have defPhi: 'Phi(G) = <[x ^+ 2]>. by rewrite (Phi_joing pG) defG' defG1 (joing_idPl _). have def_tG: {in G :\: X, forall t, t ^: G = <[x ^+ 2]> :* t}. move=> t X't; have [Gt notXt] := setDP X't. have defJt: {in X, forall z, t ^ z = z ^+ r.-2 * t}. move=> z Xz /=; rewrite -(mulKg z (z ^+ _)) -expgS -subn2. have X'tV: t^-1 \in G :\: X by rewrite inE !groupV notXt. by rewrite subnSK 1?ltnW // subn1 -(invXX' _ t^-1) // -mulgA -conjgCV. have defGt: X * <[t]> = G by rewrite (mulg_normal_maximal nsXG) ?cycle_subG. apply/setP=> tz; apply/imsetP/rcosetP=> [[t'z] | [z]]. rewrite -defGt -normC ?cycle_subG ?(subsetP nXG) //. case/imset2P=> t' z; case/cycleP=> j -> Xz -> -> {t' t'z tz}. exists (z ^+ r.-2); last first. by rewrite conjgM {2}/conjg commuteX // mulKg defJt. case/cycleP: Xz => i ->{z}. by rewrite -def2r1 -expgM mulnCA expgM mem_cycle. case/cycleP=> i -> -> {z tz}. exists (x ^+ (i * expg_invn X (2 ^ (n - 3)).-1)); first by rewrite groupX. rewrite defJt ?mem_cycle // -def2r1 -!expgM. by rewrite mulnAC mulnA mulnC muln2 !expgM expgK ?mem_cycle. have defMt: {in G :\: X, forall t, <[x ^+ 2]> <*> <[t]> = <>}. move=> t X't; have [Gt notXt] := setDP X't. apply/eqP; have: t \in <> by rewrite mem_gen ?class_refl. rewrite def_tG // eqEsubset join_subG !cycle_subG !gen_subG => tGt. rewrite tGt -(groupMr _ tGt) mem_gen ?mem_mulg ?cycle_id ?set11 //=. by rewrite mul_subG ?joing_subl // -gen_subG joing_subr. have sMtG: {in G :\: X, forall t, <> \subset G}. by move=> t; case/setDP=> Gt _; rewrite gen_subG class_subG. have oMt: {in G :\: X, forall t, #|<>| = q}. move=> t X't; have [Gt notXt] := setDP X't. rewrite -defMt // -(Lagrange (joing_subl _ _)) -orderE ox2 -def2r mulnC. congr (_ * r)%N; rewrite -card_quotient /=; last first. by rewrite defMt // (subset_trans _ (nXiG 2)) ?sMtG. rewrite joingC quotientYidr ?(subset_trans _ (nXiG 2)) ?cycle_subG //. rewrite quotient_cycle ?(subsetP (nXiG 2)) //= -defPhi -orderE. rewrite (abelem_order_p (Phi_quotient_abelem pG)) ?mem_quotient //. apply: contraNneq notXt; move/coset_idr; move/implyP=> /=. by rewrite /= defPhi (subsetP (nXiG 2)) //; apply: subsetP; exact: cycleX. have maxMt: {in G :\: X, forall t, maximal <> G}. move=> t X't /=; rewrite p_index_maximal -?divgS ?sMtG ?oMt //. by rewrite oG -def2q mulnK. have X'xy: x * y \in G :\: X by rewrite !inE !groupMl ?cycle_id ?notXy. have ti_yG_xyG: [disjoint yG & xyG]. apply/pred0P=> t; rewrite /= /yG /xyG !def_tG //; apply/andP=> [[yGt]]. rewrite rcoset_sym (rcoset_transl yGt) mem_rcoset mulgK; move/order_dvdG. by rewrite -orderE ox2 ox gtnNdvd. have s_tG_X': {in G :\: X, forall t, t ^: G \subset G :\: X}. by move=> t X't /=; rewrite class_sub_norm // normsD ?normG. have defX': yG :|: xyG = G :\: X. apply/eqP; rewrite eqEcard subUset !s_tG_X' //= -(leq_add2l q) -{1}ox orderE. rewrite -/X -{1}(setIidPr sXG) cardsID oG -def2q mul2n -addnn leq_add2l. rewrite -(leq_add2r #|yG :&: xyG|) cardsUI disjoint_setI0 // cards0 addn0. by rewrite /yG /xyG !def_tG // !card_rcoset addnn -mul2n -orderE ox2 def2r. split. - by rewrite sdprodE // setIC prime_TIg ?cycle_subG // -orderE oy. - rewrite defG'; split=> //. apply/eqP; rewrite eqn_leq (leq_trans (nil_class_pgroup pG)); last first. by rewrite oG pfactorK // -(subnKC n_gt3). rewrite -(subnKC (ltnW (ltnW n_gt3))) subn2 ltnNge. rewrite (sameP (lcn_nil_classP _ (pgroup_nil pG)) eqP). by apply/trivgPn; exists (x ^+ r); rewrite ?memL // -order_gt1 oxr. - rewrite defZ; split=> //; last exact: extend_cyclic_Mho. split; apply/eqP; last first. have sX'G2: {subset G :\: X <= 'Ohm_2(G)}. move=> t X't; have [Gt _] := setDP X't; rewrite -defX' in X't. rewrite (OhmE 2 pG) mem_gen // !inE Gt -order_dvdn. by case/setUP: X't; case/imsetP=> z _ ->; rewrite orderJ ?oy ?oxy. rewrite eqEsubset Ohm_sub -{1}defXY mulG_subG !cycle_subG. by rewrite -(groupMr _ (sX'G2 y X'y)) !sX'G2. rewrite eqEsubset andbC gen_subG class_sub_norm ?gFnorm //. rewrite (OhmE 1 pG) mem_gen ?inE ?Gy -?order_dvdn ?oy // gen_subG /= -/My. apply/subsetP=> t; rewrite !inE; case/andP=> Gt t2. have pX := pgroupS sXG pG. case Xt: (t \in X). have: t \in 'Ohm_1(X) by rewrite (OhmE 1 pX) mem_gen // !inE Xt. apply: subsetP; rewrite (Ohm_p_cycle 1 pX) ox pfactorK //. rewrite -(subnKC n_gt3) expgM (subset_trans (cycleX _ _)) //. by rewrite /My -defMt ?joing_subl. have{Xt}: t \in yG :|: xyG by rewrite defX' inE Xt. case/setUP; first exact: mem_gen. by case/imsetP=> z _ def_t; rewrite -order_dvdn def_t orderJ oxy in t2. - split=> //= H; apply/idP/idP=> [maxH |]; last first. by case/or3P=> /eqP->; rewrite ?maxMt. have [sHG nHG]:= andP (p_maximal_normal pG maxH). have oH: #|H| = q. apply: double_inj; rewrite -muln2 -(p_maximal_index pG maxH) Lagrange //. by rewrite oG -mul2n. rewrite !(eq_sym (gval H)) -eq_sym !eqEcard oH -orderE ox !oMt // !leqnn. case sHX: (H \subset X) => //=; case/subsetPn: sHX => t Ht notXt. have: t \in yG :|: xyG by rewrite defX' inE notXt (subsetP sHG). rewrite !andbT !gen_subG /yG /xyG. by case/setUP=> /class_transr <-; rewrite !class_sub_norm ?Ht ?orbT. have n1_gt2: n.-1 > 2 by [rewrite -(subnKC n_gt3)]; have n1_gt1 := ltnW n1_gt2. rewrite !isogEcard card_2dihedral ?card_quaternion ?oMt // leqnn !andbT. have invX2X': {in G :\: X, forall t, x ^+ 2 ^ t == x ^- 2}. move=> t X't; rewrite /= invXX' ?mem_cycle // eq_sym eq_invg_mul -expgS. by rewrite prednK // -order_dvdn ox2. rewrite Grp_2dihedral ?Grp_quaternion //; split=> [||C]. - apply/existsP; exists (x ^+ 2, y); rewrite /= defMt // !xpair_eqE. by rewrite -!expgM def2r -!order_dvdn ox oy dvdnn eqxx /= invX2X'. - apply/existsP; exists (x ^+ 2, x * y); rewrite /= defMt // !xpair_eqE. rewrite -!expgM def2r -order_dvdn ox xy2 dvdnn eqxx invX2X' //=. by rewrite andbT /r -(subnKC n_gt3). case/cyclicP=> z ->{C} sCG iCG; rewrite [X]defU // defU -?cycle_subG //. by apply: double_inj; rewrite -muln2 -iCG Lagrange // oG -mul2n. Qed. End ExtremalStructure. Section ExtremalClass. Variables (gT : finGroupType) (G : {group gT}). Inductive extremal_group_type := ModularGroup | Dihedral | SemiDihedral | Quaternion | NotExtremal. Definition index_extremal_group_type c := match c with | ModularGroup => 0 | Dihedral => 1 | SemiDihedral => 2 | Quaternion => 3 | NotExtremal => 4 end%N. Definition enum_extremal_groups := [:: ModularGroup; Dihedral; SemiDihedral; Quaternion]. Lemma cancel_index_extremal_groups : cancel index_extremal_group_type (nth NotExtremal enum_extremal_groups). Proof. by case. Qed. Local Notation extgK := cancel_index_extremal_groups. Import choice. Definition extremal_group_eqMixin := CanEqMixin extgK. Canonical extremal_group_eqType := EqType _ extremal_group_eqMixin. Definition extremal_group_choiceMixin := CanChoiceMixin extgK. Canonical extremal_group_choiceType := ChoiceType _ extremal_group_choiceMixin. Definition extremal_group_countMixin := CanCountMixin extgK. Canonical extremal_group_countType := CountType _ extremal_group_countMixin. Lemma bound_extremal_groups (c : extremal_group_type) : pickle c < 6. Proof. by case: c. Qed. Definition extremal_group_finMixin := Finite.CountMixin bound_extremal_groups. Canonical extremal_group_finType := FinType _ extremal_group_finMixin. Definition extremal_class (A : {set gT}) := let m := #|A| in let p := pdiv m in let n := logn p m in if (n > 1) && (A \isog 'D_(2 ^ n)) then Dihedral else if (n > 2) && (A \isog 'Q_(2 ^ n)) then Quaternion else if (n > 3) && (A \isog 'SD_(2 ^ n)) then SemiDihedral else if (n > 2) && (A \isog 'Mod_(p ^ n)) then ModularGroup else NotExtremal. Definition extremal2 A := extremal_class A \in behead enum_extremal_groups. Lemma dihedral_classP : extremal_class G = Dihedral <-> (exists2 n, n > 1 & G \isog 'D_(2 ^ n)). Proof. rewrite /extremal_class; split=> [ | [n n_gt1 isoG]]. by move: (logn _ _) => n; do 4?case: ifP => //; case/andP; exists n. rewrite (card_isog isoG) card_2dihedral // -(ltn_predK n_gt1) pdiv_pfactor //. by rewrite pfactorK // (ltn_predK n_gt1) n_gt1 isoG. Qed. Lemma quaternion_classP : extremal_class G = Quaternion <-> (exists2 n, n > 2 & G \isog 'Q_(2 ^ n)). Proof. rewrite /extremal_class; split=> [ | [n n_gt2 isoG]]. by move: (logn _ _) => n; do 4?case: ifP => //; case/andP; exists n. rewrite (card_isog isoG) card_quaternion // -(ltn_predK n_gt2) pdiv_pfactor //. rewrite pfactorK // (ltn_predK n_gt2) n_gt2 isoG. case: andP => // [[n_gt1 isoGD]]. have [[x y] genG [oy _ _]]:= generators_quaternion n_gt2 isoG. have [_ _ _ X'y] := genG. by case/dihedral2_structure: genG oy => // [[_ ->]]. Qed. Lemma semidihedral_classP : extremal_class G = SemiDihedral <-> (exists2 n, n > 3 & G \isog 'SD_(2 ^ n)). Proof. rewrite /extremal_class; split=> [ | [n n_gt3 isoG]]. by move: (logn _ _) => n; do 4?case: ifP => //; case/andP; exists n. rewrite (card_isog isoG) card_semidihedral //. rewrite -(ltn_predK n_gt3) pdiv_pfactor // pfactorK // (ltn_predK n_gt3) n_gt3. have [[x y] genG [oy _]]:= generators_semidihedral n_gt3 isoG. have [_ Gx _ X'y]:= genG. case: andP => [[n_gt1 isoGD]|_]. have [[_ oxy _ _] _ _ _]:= semidihedral_structure n_gt3 genG isoG oy. case: (dihedral2_structure n_gt1 genG isoGD) oxy => [[_ ->]] //. by rewrite !inE !groupMl ?cycle_id in X'y *. case: andP => // [[n_gt2 isoGQ]|]; last by rewrite isoG. by case: (quaternion_structure n_gt2 genG isoGQ) oy => [[_ ->]]. Qed. Lemma odd_not_extremal2 : odd #|G| -> ~~ extremal2 G. Proof. rewrite /extremal2 /extremal_class; case: logn => // n'. case: andP => [[n_gt1 isoG] | _]. by rewrite (card_isog isoG) card_2dihedral ?odd_exp. case: andP => [[n_gt2 isoG] | _]. by rewrite (card_isog isoG) card_quaternion ?odd_exp. case: andP => [[n_gt3 isoG] | _]. by rewrite (card_isog isoG) card_semidihedral ?odd_exp. by case: ifP. Qed. Lemma modular_group_classP : extremal_class G = ModularGroup <-> (exists2 p, prime p & exists2 n, n >= (p == 2) + 3 & G \isog 'Mod_(p ^ n)). Proof. rewrite /extremal_class; split=> [ | [p p_pr [n n_gt23 isoG]]]. move: (pdiv _) => p; set n := logn p _; do 4?case: ifP => //. case/andP=> n_gt2 isoG _ _; rewrite ltnW //= => not_isoG _. exists p; first by move: n_gt2; rewrite /n lognE; case (prime p). exists n => //; case: eqP => // p2; rewrite ltn_neqAle; case: eqP => // n3. by case/idP: not_isoG; rewrite p2 -n3 in isoG *. have n_gt2 := leq_trans (leq_addl _ _) n_gt23; have n_gt1 := ltnW n_gt2. have n_gt0 := ltnW n_gt1; have def_n := prednK n_gt0. have [[x y] genG mod_xy] := generators_modular_group p_pr n_gt2 isoG. case/modular_group_structure: (genG) => // _ _ [_ _ nil2G] _ _. have [oG _ _ _] := genG; have [oy _] := mod_xy. rewrite oG -def_n pdiv_pfactor // def_n pfactorK // n_gt1 n_gt2 {}isoG /=. case: (ltngtP p 2) => [|p_gt2|p2]; first by rewrite ltnNge prime_gt1. rewrite !(isog_sym G) !isogEcard card_2dihedral ?card_quaternion //= oG. rewrite leq_exp2r // leqNgt p_gt2 !andbF; case: and3P=> // [[n_gt3 _]]. by rewrite card_semidihedral // leq_exp2r // leqNgt p_gt2. rewrite p2 in genG oy n_gt23; rewrite n_gt23. have: nil_class G <> n.-1. by apply/eqP; rewrite neq_ltn -ltnS nil2G def_n n_gt23. case: ifP => [isoG | _]; first by case/dihedral2_structure: genG => // _ []. case: ifP => [isoG | _]; first by case/quaternion_structure: genG => // _ []. by case: ifP => // isoG; case/semidihedral_structure: genG => // _ []. Qed. End ExtremalClass. Theorem extremal2_structure (gT : finGroupType) (G : {group gT}) n x y : let cG := extremal_class G in let m := (2 ^ n)%N in let q := (2 ^ n.-1)%N in let r := (2 ^ n.-2)%N in let X := <[x]> in let yG := y ^: G in let xyG := (x * y) ^: G in let My := <> in let Mxy := <> in extremal_generators G 2 n (x, y) -> extremal2 G -> (cG == SemiDihedral) ==> (#[y] == 2) -> [/\ [/\ (if cG == Quaternion then pprod X <[y]> else X ><| <[y]>) = G, if cG == SemiDihedral then #[x * y] = 4 else {in G :\: X, forall z, #[z] = (if cG == Dihedral then 2 else 4)}, if cG != Quaternion then True else {in G, forall z, #[z] = 2 -> z = x ^+ r} & {in X & G :\: X, forall t z, t ^ z = (if cG == SemiDihedral then t ^+ r.-1 else t^-1)}], [/\ G ^`(1) = <[x ^+ 2]>, 'Phi(G) = G ^`(1), #|G^`(1)| = r & nil_class G = n.-1], [/\ if n > 2 then 'Z(G) = <[x ^+ r]> /\ #|'Z(G)| = 2 else 2.-abelem G, 'Ohm_1(G) = (if cG == Quaternion then <[x ^+ r]> else if cG == SemiDihedral then My else G), 'Ohm_2(G) = G & forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (2 ^ k)]>], [/\ yG :|: xyG = G :\: X, [disjoint yG & xyG] & forall H : {group gT}, maximal H G = (gval H \in pred3 X My Mxy)] & if n <= (cG == Quaternion) + 2 then True else [/\ forall U, cyclic U -> U \subset G -> #|G : U| = 2 -> U = X, if cG == Quaternion then My \isog 'Q_q else My \isog 'D_q, extremal_class My = (if cG == Quaternion then cG else Dihedral), if cG == Dihedral then Mxy \isog 'D_q else Mxy \isog 'Q_q & extremal_class Mxy = (if cG == Dihedral then cG else Quaternion)]]. Proof. move=> cG m q r X yG xyG My Mxy genG; have [oG _ _ _] := genG. have logG: logn (pdiv #|G|) #|G| = n by rewrite oG pfactorKpdiv. rewrite /extremal2 -/cG; do [rewrite {1}/extremal_class /= {}logG] in cG *. case: ifP => [isoG | _] in cG * => [_ _ /=|]. case/andP: isoG => n_gt1 isoG. have:= dihedral2_structure n_gt1 genG isoG; rewrite -/X -/q -/r -/yG -/xyG. case=> [[defG oX' invXX'] nilG [defOhm defMho] maxG defZ]. rewrite eqn_leq n_gt1 andbT add0n in defZ *; split=> //. split=> //; first by case: leqP defZ => // _ []. by apply/eqP; rewrite eqEsubset Ohm_sub -{1}defOhm Ohm_leq. case: leqP defZ => // n_gt2 [_ _ isoMy isoMxy defX]. have n1_gt1: n.-1 > 1 by rewrite -(subnKC n_gt2). by split=> //; apply/dihedral_classP; exists n.-1. case: ifP => [isoG | _] in cG * => [_ _ /=|]. case/andP: isoG => n_gt2 isoG; rewrite n_gt2 add1n. have:= quaternion_structure n_gt2 genG isoG; rewrite -/X -/q -/r -/yG -/xyG. case=> [[defG oX' invXX'] nilG [defZ oZ def2 [-> ->] defMho]]. case=> [[-> ->] maxG] isoM; split=> //. case: leqP isoM => // n_gt3 [//|isoMy isoMxy defX]. have n1_gt2: n.-1 > 2 by rewrite -(subnKC n_gt3). by split=> //; apply/quaternion_classP; exists n.-1. do [case: ifP => [isoG | _]; last by case: ifP] in cG * => /= _; move/eqnP=> oy. case/andP: isoG => n_gt3 isoG; rewrite (leqNgt n) (ltnW n_gt3) /=. have n1_gt2: n.-1 > 2 by rewrite -(subnKC n_gt3). have:= semidihedral_structure n_gt3 genG isoG oy. rewrite -/X -/q -/r -/yG -/xyG -/My -/Mxy. case=> [[defG oxy invXX'] nilG [defZ oZ [-> ->] defMho] [[defX' tiX'] maxG]]. case=> isoMy isoMxy defX; do 2!split=> //. by apply/dihedral_classP; exists n.-1; first exact: ltnW. by apply/quaternion_classP; exists n.-1. Qed. (* This is Aschbacher (23.4). *) Lemma maximal_cycle_extremal gT p (G X : {group gT}) : p.-group G -> ~~ abelian G -> cyclic X -> X \subset G -> #|G : X| = p -> (extremal_class G == ModularGroup) || (p == 2) && extremal2 G. Proof. move=> pG not_cGG cycX sXG iXG; rewrite /extremal2; set cG := extremal_class G. have [|p_pr _ _] := pgroup_pdiv pG. by case: eqP not_cGG => // ->; rewrite abelian1. have p_gt1 := prime_gt1 p_pr; have p_gt0 := ltnW p_gt1. have [n oG] := p_natP pG; have n_gt2: n > 2. apply: contraR not_cGG; rewrite -leqNgt => n_le2. by rewrite (p2group_abelian pG) // oG pfactorK. have def_n := subnKC n_gt2; have n_gt1 := ltnW n_gt2; have n_gt0 := ltnW n_gt1. pose q := (p ^ n.-1)%N; pose r := (p ^ n.-2)%N. have q_gt1: q > 1 by rewrite (ltn_exp2l 0) // -(subnKC n_gt2). have r_gt0: r > 0 by rewrite expn_gt0 p_gt0. have def_pr: (p * r)%N = q by rewrite /q /r -def_n. have oX: #|X| = q by rewrite -(divg_indexS sXG) oG iXG /q -def_n mulKn. have ntX: X :!=: 1 by rewrite -cardG_gt1 oX. have maxX: maximal X G by rewrite p_index_maximal ?iXG. have nsXG: X <| G := p_maximal_normal pG maxX; have [_ nXG] := andP nsXG. have cXX: abelian X := cyclic_abelian cycX. have scXG: 'C_G(X) = X. apply/eqP; rewrite eqEsubset subsetI sXG -abelianE cXX !andbT. apply: contraR not_cGG; case/subsetPn=> y; case/setIP=> Gy cXy notXy. rewrite -!cycle_subG in Gy notXy; rewrite -(mulg_normal_maximal nsXG _ Gy) //. by rewrite abelianM cycle_abelian cyclic_abelian ?cycle_subG. have [x defX] := cyclicP cycX; have pX := pgroupS sXG pG. have Xx: x \in X by [rewrite defX cycle_id]; have Gx := subsetP sXG x Xx. have [ox p_x]: #[x] = q /\ p.-elt x by rewrite defX in pX oX. pose Z := <[x ^+ r]>. have defZ: Z = 'Ohm_1(X) by rewrite defX (Ohm_p_cycle _ p_x) ox subn1 pfactorK. have oZ: #|Z| = p by rewrite -orderE orderXdiv ox -def_pr ?dvdn_mull ?mulnK. have cGZ: Z \subset 'C(G). have nsZG: Z <| G by rewrite defZ (char_normal_trans (Ohm_char 1 _)). move/implyP: (meet_center_nil (pgroup_nil pG) nsZG). rewrite -cardG_gt1 oZ p_gt1 setIA (setIidPl (normal_sub nsZG)). by apply: contraR; move/prime_TIg=> -> //; rewrite oZ. have X_Gp y: y \in G -> y ^+ p \in X. move=> Gy; have nXy: y \in 'N(X) := subsetP nXG y Gy. rewrite coset_idr ?groupX // morphX //; apply/eqP. by rewrite -order_dvdn -iXG -card_quotient // order_dvdG ?mem_quotient. have [y X'y]: exists2 y, y \in G :\: X & (p == 2) + 3 <= n /\ x ^ y = x ^+ r.+1 \/ p = 2 /\ x * x ^ y \in Z. - have [y Gy notXy]: exists2 y, y \in G & y \notin X. by apply/subsetPn; rewrite proper_subn ?(maxgroupp maxX). have nXy: y \in 'N(X) := subsetP nXG y Gy; pose ay := conj_aut X y. have oay: #[ay] = p. apply: nt_prime_order => //. by rewrite -morphX // mker // ker_conj_aut (subsetP cXX) ?X_Gp. rewrite (sameP eqP (kerP _ nXy)) ker_conj_aut. by apply: contra notXy => cXy; rewrite -scXG inE Gy. have [m []]:= cyclic_pgroup_Aut_structure pX cycX ntX. set Ap := 'O_p(_); case=> def_m [m1 _] [m_inj _] _ _ _. have sylAp: p.-Sylow(Aut X) Ap. by rewrite nilpotent_pcore_Hall // abelian_nil // Aut_cyclic_abelian. have Ap1ay: ay \in 'Ohm_1(Ap). rewrite (OhmE _ (pcore_pgroup _ _)) mem_gen // !inE -order_dvdn oay dvdnn. rewrite (mem_normal_Hall sylAp) ?pcore_normal ?Aut_aut //. by rewrite /p_elt oay pnat_id. rewrite {1}oX pfactorK // -{1}def_n /=. have [p2 | odd_p] := even_prime p_pr; last first. rewrite (sameP eqP (prime_oddPn p_pr)) odd_p n_gt2. case=> _ [_ _ _] [_ _ [s [As os m_s defAp1]]]. have [j def_s]: exists j, s = ay ^+ j. apply/cycleP; rewrite -cycle_subG subEproper eq_sym eqEcard -!orderE. by rewrite -defAp1 cycle_subG Ap1ay oay os leqnn . exists (y ^+ j); last first. left; rewrite -(norm_conj_autE _ Xx) ?groupX // morphX // -def_s. by rewrite -def_m // m_s expg_znat // oX pfactorK ?eqxx. rewrite -scXG !inE groupX //= andbT -ker_conj_aut !inE morphX // -def_s. rewrite andbC -(inj_in_eq m_inj) ?group1 // m_s m1 oX pfactorK // -/r. rewrite mulrSr -subr_eq0 addrK -val_eqE /= val_Zp_nat //. by rewrite [_ == 0%N]dvdn_Pexp2l // -def_n ltnn. rewrite {1}p2 /= => [[t [At ot m_t]]]; rewrite {1}oX pfactorK // -{1}def_n. rewrite eqSS subn_eq0 => defA; exists y; rewrite ?inE ?notXy //. rewrite p2 -(norm_conj_autE _ Xx) //= -/ay -def_m ?Aut_aut //. case Tay: (ay \in <[t]>). rewrite cycle2g // !inE -order_eq1 oay p2 /= in Tay. by right; rewrite (eqP Tay) m_t expg_zneg // mulgV group1. case: leqP defA => [_ defA|le3n [a [Aa _ _ defA [s [As os m_s m_st defA1]]]]]. by rewrite -defA Aut_aut in Tay. have: ay \in [set s; s * t]. have: ay \in 'Ohm_1(Aut X) := subsetP (OhmS 1 (pcore_sub _ _)) ay Ap1ay. case/dprodP: (Ohm_dprod 1 defA) => _ <- _ _. rewrite defA1 (@Ohm_p_cycle _ _ 2) /p_elt ot //= expg1 cycle2g //. by rewrite mulUg mul1g inE Tay cycle2g // mulgU mulg1 mulg_set1. case/set2P=> ->; [left | right]. by rewrite ?le3n m_s expg_znat // oX pfactorK // -p2. by rewrite m_st expg_znat // oX pfactorK // -p2 -/r -expgS prednK ?cycle_id. have [Gy notXy] := setDP X'y; have nXy := subsetP nXG y Gy. have defG j: <[x]> <*> <[x ^+ j * y]> = G. rewrite -defX -genM_join. by rewrite (mulg_normal_maximal nsXG) ?cycle_subG ?groupMl ?groupX ?genGid. have[i def_yp]: exists i, y ^- p = x ^+ i. by apply/cycleP; rewrite -defX groupV X_Gp. have p_i: p %| i. apply: contraR notXy; rewrite -prime_coprime // => co_p_j. have genX: generator X (y ^- p). by rewrite def_yp defX generator_coprime ox coprime_expl. rewrite -scXG (setIidPl _) // centsC ((X :=P: _) genX) cycle_subG groupV. rewrite /= -(defG 0%N) mul1g centY inE -defX (subsetP cXX) ?X_Gp //. by rewrite (subsetP (cycle_abelian y)) ?mem_cycle. case=> [[n_gt23 xy] | [p2 Z_xxy]]. suffices ->: cG = ModularGroup by []; apply/modular_group_classP. exists p => //; exists n => //; rewrite isogEcard card_modular_group //. rewrite oG leqnn andbT Grp_modular_group // -/q -/r. have{i def_yp p_i} [i def_yp]: exists i, y ^- p = x ^+ i ^+ p. by case/dvdnP: p_i => j def_i; exists j; rewrite -expgM -def_i. have Zyx: [~ y, x] \in Z. by rewrite -groupV invg_comm commgEl xy expgS mulKg cycle_id. have def_yxj j: [~ y, x ^+ j] = [~ y, x] ^+ j. by rewrite commgX /commute ?(centsP cGZ _ Zyx). have Zyxj j: [~ y, x ^+ j] \in Z by rewrite def_yxj groupX. have x_xjy j: x ^ (x ^+ j * y) = x ^+ r.+1. by rewrite conjgM {2}/conjg commuteX //= mulKg. have [cyxi | not_cyxi] := eqVneq ([~ y, x ^+ i] ^+ 'C(p, 2)) 1. apply/existsP; exists (x, x ^+ i * y); rewrite /= !xpair_eqE. rewrite defG x_xjy -order_dvdn ox dvdnn !eqxx andbT /=. rewrite expMg_Rmul /commute ?(centsP cGZ _ (Zyxj _)) ?groupX // cyxi. by rewrite -def_yp -mulgA mulKg. have [p2 | odd_p] := even_prime p_pr; last first. by rewrite -order_dvdn bin2odd ?dvdn_mulr // -oZ order_dvdG in not_cyxi. have def_yxi: [~ y, x ^+ i] = x ^+ r. have:= Zyxj i; rewrite /Z cycle_traject orderE oZ p2 !inE mulg1. by case/pred2P=> // cyxi; rewrite cyxi p2 eqxx in not_cyxi. apply/existsP; exists (x, x ^+ (i + r %/ 2) * y); rewrite /= !xpair_eqE. rewrite defG x_xjy -order_dvdn ox dvdnn !eqxx andbT /=. rewrite expMg_Rmul /commute ?(centsP cGZ _ (Zyxj _)) ?groupX // def_yxj. rewrite -expgM mulnDl addnC !expgD (expgM x i) -def_yp mulgKV. rewrite -def_yxj def_yxi p2 mulgA -expgD in n_gt23 *. rewrite -expg_mod_order ox /q /r p2 -(subnKC n_gt23) mulnC !expnS mulKn //. rewrite addnn -mul2n modnn mul1g -order_dvdn dvdn_mulr //. by rewrite -p2 -oZ order_dvdG. have{i def_yp p_i} Zy2: y ^+ 2 \in Z. rewrite defZ (OhmE _ pX) -groupV -p2 def_yp mem_gen // !inE groupX //= p2. rewrite expgS -{2}def_yp -(mulKg y y) -conjgE -conjXg -conjVg def_yp conjXg. rewrite -expgMn //; last by apply: (centsP cXX); rewrite ?memJ_norm. by rewrite -order_dvdn (dvdn_trans (order_dvdG Z_xxy)) ?oZ. rewrite !cycle_traject !orderE oZ p2 !inE !mulg1 /= in Z_xxy Zy2 *. rewrite -eq_invg_mul eq_sym -[r]prednK // expgS (inj_eq (mulgI _)) in Z_xxy. case/pred2P: Z_xxy => xy; last first. suffices ->: cG = SemiDihedral by []; apply/semidihedral_classP. have n_gt3: n > 3. case: ltngtP notXy => // [|n3]; first by rewrite ltnNge n_gt2. rewrite -scXG inE Gy defX cent_cycle; case/cent1P; red. by rewrite (conjgC x) xy /r p2 n3. exists n => //; rewrite isogEcard card_semidihedral // oG p2 leqnn andbT. rewrite Grp_semidihedral //; apply/existsP=> /=. case/pred2P: Zy2 => y2; [exists (x, y) | exists (x, x * y)]. by rewrite /= -{1}[y]mul1g (defG 0%N) y2 xy -p2 -/q -ox expg_order. rewrite /= (defG 1%N) conjgM {2}/conjg mulKg -p2 -/q -ox expg_order -xy. rewrite !xpair_eqE !eqxx /= andbT p2 expgS {2}(conjgC x) xy mulgA -(mulgA x). rewrite [y * y]y2 -expgS -expgD addSnnS prednK // addnn -mul2n -p2 def_pr. by rewrite -ox expg_order. case/pred2P: Zy2 => y2. suffices ->: cG = Dihedral by []; apply/dihedral_classP. exists n => //; rewrite isogEcard card_2dihedral // oG p2 leqnn andbT. rewrite Grp_2dihedral //; apply/existsP; exists (x, y) => /=. by rewrite /= -{1}[y]mul1g (defG 0%N) y2 xy -p2 -/q -ox expg_order. suffices ->: cG = Quaternion by []; apply/quaternion_classP. exists n => //; rewrite isogEcard card_quaternion // oG p2 leqnn andbT. rewrite Grp_quaternion //; apply/existsP; exists (x, y) => /=. by rewrite /= -{1}[y]mul1g (defG 0%N) y2 xy -p2 -/q -ox expg_order. Qed. (* This is Aschbacher (23.5) *) Lemma cyclic_SCN gT p (G U : {group gT}) : p.-group G -> U \in 'SCN(G) -> ~~ abelian G -> cyclic U -> [/\ p = 2, #|G : U| = 2 & extremal2 G] \/ exists M : {group gT}, [/\ M :=: 'C_G('Mho^1(U)), #|M : U| = p, extremal_class M = ModularGroup, 'Ohm_1(M)%G \in 'E_p^2(G) & 'Ohm_1(M) \char G]. Proof. move=> pG /SCN_P[nsUG scUG] not_cGG cycU; have [sUG nUG] := andP nsUG. have [cUU pU] := (cyclic_abelian cycU, pgroupS sUG pG). have ltUG: ~~ (G \subset U). by apply: contra not_cGG => sGU; exact: abelianS cUU. have ntU: U :!=: 1. by apply: contra ltUG; move/eqP=> U1; rewrite -(setIidPl (cents1 G)) -U1 scUG. have [p_pr _ [n oU]] := pgroup_pdiv pU ntU. have p_gt1 := prime_gt1 p_pr; have p_gt0 := ltnW p_gt1. have [u defU] := cyclicP cycU; have Uu: u \in U by rewrite defU cycle_id. have Gu := subsetP sUG u Uu; have p_u := mem_p_elt pG Gu. have defU1: 'Mho^1(U) = <[u ^+ p]> by rewrite defU (Mho_p_cycle _ p_u). have modM1 (M : {group gT}): [/\ U \subset M, #|M : U| = p & extremal_class M = ModularGroup] -> M :=: 'C_M('Mho^1(U)) /\ 'Ohm_1(M)%G \in 'E_p^2(M). - case=> sUM iUM /modular_group_classP[q q_pr {n oU}[n n_gt23 isoM]]. have n_gt2: n > 2 by exact: leq_trans (leq_addl _ _) n_gt23. have def_n: n = (n - 3).+3 by rewrite -{1}(subnKC n_gt2). have oM: #|M| = (q ^ n)%N by rewrite (card_isog isoM) card_modular_group. have pM: q.-group M by rewrite /pgroup oM pnat_exp pnat_id. have def_q: q = p; last rewrite {q q_pr}def_q in oM pM isoM n_gt23. by apply/eqP; rewrite eq_sym [p == q](pgroupP pM) // -iUM dvdn_indexg. have [[x y] genM modM] := generators_modular_group p_pr n_gt2 isoM. case/modular_group_structure: genM => // _ [defZ _ oZ] _ defMho. have ->: 'Mho^1(U) = 'Z(M). apply/eqP; rewrite eqEcard oZ defZ -(defMho 1%N) ?MhoS //= defU1 -orderE. suff ou: #[u] = (p * p ^ n.-2)%N by rewrite orderXdiv ou ?dvdn_mulr ?mulKn. by rewrite orderE -defU -(divg_indexS sUM) iUM oM def_n mulKn. case: eqP => [[p2 n3] | _ defOhm]; first by rewrite p2 n3 in n_gt23. have{defOhm} [|defM1 oM1] := defOhm 1%N; first by rewrite def_n. split; rewrite ?(setIidPl _) //; first by rewrite centsC subsetIr. rewrite inE oM1 pfactorK // andbT inE Ohm_sub abelem_Ohm1 //. exact: (card_p2group_abelian p_pr oM1). have ou: #[u] = (p ^ n.+1)%N by rewrite defU in oU. pose Gs := G / U; have pGs: p.-group Gs by rewrite quotient_pgroup. have ntGs: Gs != 1 by rewrite -subG1 quotient_sub1. have [_ _ [[|k] oGs]] := pgroup_pdiv pGs ntGs. have iUG: #|G : U| = p by rewrite -card_quotient ?oGs. case: (predU1P (maximal_cycle_extremal _ _ _ _ iUG)) => // [modG | ext2G]. by right; exists G; case: (modM1 G) => // <- ->; rewrite Ohm_char. by left; case: eqP ext2G => // <-. pose M := 'C_G('Mho^1(U)); right; exists [group of M]. have sMG: M \subset G by exact: subsetIl. have [pM nUM] := (pgroupS sMG pG, subset_trans sMG nUG). have sUM: U \subset M by rewrite subsetI sUG sub_abelian_cent ?Mho_sub. pose A := Aut U; have cAA: abelian A by rewrite Aut_cyclic_abelian. have sylAp: p.-Sylow(A) 'O_p(A) by rewrite nilpotent_pcore_Hall ?abelian_nil. have [f [injf sfGsA fG]]: exists f : {morphism Gs >-> {perm gT}}, [/\ 'injm f, f @* Gs \subset A & {in G, forall y, f (coset U y) u = u ^ y}]. - have [] := first_isom_loc [morphism of conj_aut U] nUG. rewrite ker_conj_aut scUG /= -/Gs => f injf im_f. exists f; rewrite im_f ?Aut_conj_aut //. split=> // y Gy; have nUy := subsetP nUG y Gy. suffices ->: f (coset U y) = conj_aut U y by rewrite norm_conj_autE. by apply: set1_inj; rewrite -!morphim_set1 ?mem_quotient // im_f ?sub1set. have cGsGs: abelian Gs by rewrite -(injm_abelian injf) // (abelianS sfGsA). have p_fGs: p.-group (f @* Gs) by rewrite morphim_pgroup. have sfGsAp: f @* Gs \subset 'O_p(A) by rewrite (sub_Hall_pcore sylAp). have [a [fGa oa au n_gt01 cycGs]]: exists a, [/\ a \in f @* Gs, #[a] = p, a u = u ^+ (p ^ n).+1, (p == 2) + 1 <= n & cyclic Gs \/ p = 2 /\ (exists2 c, c \in f @* Gs & c u = u^-1)]. - have [m [[def_m _ _ _ _] _]] := cyclic_pgroup_Aut_structure pU cycU ntU. have ->: logn p #|U| = n.+1 by rewrite oU pfactorK. rewrite /= -/A; case: posnP => [_ defA | n_gt0 [c [Ac oc m_c defA]]]. have:= cardSg sfGsAp; rewrite (card_Hall sylAp) /= -/A defA card_injm //. by rewrite oGs (part_p'nat (pcore_pgroup _ _)) pfactor_dvdn // logn1. have [p2 | odd_p] := even_prime p_pr; last first. case: eqP => [-> // | _] in odd_p *; rewrite odd_p in defA. have [[cycA _] _ [a [Aa oa m_a defA1]]] := defA. exists a; rewrite -def_m // oa m_a expg_znat //. split=> //; last by left; rewrite -(injm_cyclic injf) ?(cyclicS sfGsA). have: f @* Gs != 1 by rewrite morphim_injm_eq1. rewrite -cycle_subG; apply: contraR => not_sfGs_a. by rewrite -(setIidPl sfGsAp) TI_Ohm1 // defA1 setIC prime_TIg -?orderE ?oa. do [rewrite {1}p2 /= eqn_leq n_gt0; case: leqP => /= [_ | n_gt1]] in defA. have:= cardSg sfGsAp; rewrite (card_Hall sylAp) /= -/A defA -orderE oc p2. by rewrite card_injm // oGs p2 pfactor_dvdn // p_part. have{defA} [s [As os _ defA [a [Aa oa m_a _ defA1]]]] := defA; exists a. have fGs_a: a \in f @* Gs. suffices: f @* Gs :&: <[s]> != 1. apply: contraR => not_fGs_a; rewrite TI_Ohm1 // defA1 setIC. by rewrite prime_TIg -?orderE ?oa // cycle_subG. have: (f @* Gs) * <[s]> \subset A by rewrite mulG_subG cycle_subG sfGsA. move/subset_leq_card; apply: contraL; move/eqP; move/TI_cardMg->. rewrite -(dprod_card defA) -ltnNge mulnC -!orderE ltn_pmul2r // oc. by rewrite card_injm // oGs p2 (ltn_exp2l 1%N). rewrite -def_m // oa m_a expg_znat // p2; split=> //. rewrite abelian_rank1_cyclic // (rank_pgroup pGs) //. rewrite -(injm_p_rank injf) // p_rank_abelian 1?morphim_abelian //= p2 -/Gs. case: leqP => [|fGs1_gt1]; [by left | right]. split=> //; exists c; last by rewrite -def_m // m_c expg_zneg. have{defA1} defA1: <[a]> \x <[c]> = 'Ohm_1(Aut U). by rewrite -(Ohm_dprod 1 defA) defA1 (@Ohm_p_cycle 1 _ 2) /p_elt oc. have def_fGs1: 'Ohm_1(f @* Gs) = 'Ohm_1(A). apply/eqP; rewrite eqEcard OhmS // -(dprod_card defA1) -!orderE oa oc. by rewrite dvdn_leq ?(@pfactor_dvdn 2 2) ?cardG_gt0. rewrite (subsetP (Ohm_sub 1 _)) // def_fGs1 -cycle_subG. by case/dprodP: defA1 => _ <- _ _; rewrite mulG_subr. have n_gt0: n > 0 := leq_trans (leq_addl _ _) n_gt01. have [ys Gys _ def_a] := morphimP fGa. have oys: #[ys] = p by rewrite -(order_injm injf) // -def_a oa. have defMs: M / U = <[ys]>. apply/eqP; rewrite eq_sym eqEcard -orderE oys cycle_subG; apply/andP; split. have [y nUy Gy /= def_ys] := morphimP Gys. rewrite def_ys mem_quotient //= inE Gy defU1 cent_cycle cent1C. rewrite (sameP cent1P commgP) commgEl conjXg -fG //= -def_ys -def_a au. by rewrite -expgM mulSn expgD mulKg -expnSr -ou expg_order. rewrite card_quotient // -(setIidPr sUM) -scUG setIA (setIidPl sMG). rewrite defU cent_cycle index_cent1 -(card_imset _ (mulgI u^-1)) -imset_comp. have <-: #|'Ohm_1(U)| = p. rewrite defU (Ohm_p_cycle 1 p_u) -orderE (orderXexp _ ou) ou pfactorK //. by rewrite subKn. rewrite (OhmE 1 pU) subset_leq_card ?sub_gen //. apply/subsetP=> _ /imsetP[z /setIP[/(subsetP nUG) nUz cU1z] ->]. have Uv' := groupVr Uu; have Uuz: u ^ z \in U by rewrite memJ_norm. rewrite !inE groupM // expgMn /commute 1?(centsP cUU u^-1) //= expgVn -conjXg. by rewrite (sameP commgP cent1P) cent1C -cent_cycle -defU1. have iUM: #|M : U| = p by rewrite -card_quotient ?defMs. have not_cMM: ~~ abelian M. apply: contraL p_pr => cMM; rewrite -iUM -indexgI /= -/M. by rewrite (setIidPl _) ?indexgg // -scUG subsetI sMG sub_abelian_cent. have modM: extremal_class M = ModularGroup. have sU1Z: 'Mho^1(U) \subset 'Z(M). by rewrite subsetI (subset_trans (Mho_sub 1 U)) // centsC subsetIr. case: (predU1P (maximal_cycle_extremal _ _ _ _ iUM)) => //=; rewrite -/M. case/andP; move/eqP=> p2 ext2M; rewrite p2 add1n in n_gt01. suffices{sU1Z}: #|'Z(M)| = 2. move/eqP; rewrite eqn_leq leqNgt (leq_trans _ (subset_leq_card sU1Z)) //. by rewrite defU1 -orderE (orderXexp 1 ou) subn1 p2 (ltn_exp2l 1). move: ext2M; rewrite /extremal2 !inE orbC -orbA; case/or3P; move/eqP. - case/semidihedral_classP=> m m_gt3 isoM. have [[x z] genM [oz _]] := generators_semidihedral m_gt3 isoM. by case/semidihedral_structure: genM => // _ _ []. - case/quaternion_classP=> m m_gt2 isoM. have [[x z] genM _] := generators_quaternion m_gt2 isoM. by case/quaternion_structure: genM => // _ _ []. case/dihedral_classP=> m m_gt1 isoM. have [[x z] genM _] := generators_2dihedral m_gt1 isoM. case/dihedral2_structure: genM not_cMM => // _ _ _ _. by case: (m == 2) => [|[]//]; move/abelem_abelian->. split=> //. have [//|_] := modM1 [group of M]; rewrite !inE -andbA /=. by case/andP; move/subset_trans->. have{cycGs} [cycGs | [p2 [c fGs_c u_c]]] := cycGs. suffices ->: 'Ohm_1(M) = 'Ohm_1(G) by exact: Ohm_char. suffices sG1M: 'Ohm_1(G) \subset M. by apply/eqP; rewrite eqEsubset -{2}(Ohm_id 1 G) !OhmS. rewrite -(quotientSGK _ sUM) ?(subset_trans (Ohm_sub _ G)) //= defMs. suffices ->: <[ys]> = 'Ohm_1(Gs) by rewrite morphim_Ohm. apply/eqP; rewrite eqEcard -orderE cycle_subG /= {1}(OhmE 1 pGs) /=. rewrite mem_gen ?inE ?Gys -?order_dvdn oys //=. rewrite -(part_pnat_id (pgroupS (Ohm_sub _ _) pGs)) p_part (leq_exp2l _ 1) //. by rewrite -p_rank_abelian -?rank_pgroup -?abelian_rank1_cyclic. suffices charU1: 'Mho^1(U) \char G^`(1). rewrite (char_trans (Ohm_char _ _)) // subcent_char ?char_refl //. exact: char_trans (der_char 1 G). suffices sUiG': 'Mho^1(U) \subset G^`(1). have cycG': cyclic G^`(1) by rewrite (cyclicS _ cycU) // der1_min. by case/cyclicP: cycG' sUiG' => zs ->; exact: cycle_subgroup_char. rewrite defU1 cycle_subG p2 -groupV invMg -{2}u_c. by case/morphimP: fGs_c => _ _ /morphimP[z _ Gz ->] ->; rewrite fG ?mem_commg. Qed. (* This is Aschbacher, exercise (8.4) *) Lemma normal_rank1_structure gT p (G : {group gT}) : p.-group G -> (forall X : {group gT}, X <| G -> abelian X -> cyclic X) -> cyclic G \/ [&& p == 2, extremal2 G & (#|G| >= 16) || (G \isog 'Q_8)]. Proof. move=> pG dn_G_1. have [cGG | not_cGG] := boolP (abelian G); first by left; rewrite dn_G_1. have [X maxX]: {X | [max X | X <| G & abelian X]}. by apply: ex_maxgroup; exists 1%G; rewrite normal1 abelian1. have cycX: cyclic X by rewrite dn_G_1; case/andP: (maxgroupp maxX). have scX: X \in 'SCN(G) := max_SCN pG maxX. have [[p2 _ cG] | [M [_ _ _]]] := cyclic_SCN pG scX not_cGG cycX; last first. rewrite 2!inE -andbA; case/and3P=> sEG abelE dimE_2 charE. have:= dn_G_1 _ (char_normal charE) (abelem_abelian abelE). by rewrite (abelem_cyclic abelE) (eqP dimE_2). have [n oG] := p_natP pG; right; rewrite p2 cG /= in oG *. rewrite oG (@leq_exp2l 2 4) //. rewrite /extremal2 /extremal_class oG pfactorKpdiv // in cG. case: andP cG => [[n_gt1 isoG] _ | _]; last first. by rewrite leq_eqVlt; case: (3 < n); case: eqP => //= <-; do 2?case: ifP. have [[x y] genG _] := generators_2dihedral n_gt1 isoG. have [_ _ _ [_ _ maxG]] := dihedral2_structure n_gt1 genG isoG. rewrite 2!ltn_neqAle n_gt1 !(eq_sym _ n). case: eqP => [_ abelG| _]; first by rewrite (abelem_abelian abelG) in not_cGG. case: eqP => // -> [_ _ isoY _ _]; set Y := <<_>> in isoY. have nxYG: Y <| G by rewrite (p_maximal_normal pG) // maxG !inE eqxx orbT. have [// | [u v] genY _] := generators_2dihedral _ isoY. case/dihedral2_structure: (genY) => //= _ _ _ _ abelY. have:= dn_G_1 _ nxYG (abelem_abelian abelY). by rewrite (abelem_cyclic abelY); case: genY => ->. Qed. (* Replacement for Section 4 proof. *) Lemma odd_pgroup_rank1_cyclic gT p (G : {group gT}) : p.-group G -> odd #|G| -> cyclic G = ('r_p(G) <= 1). Proof. move=> pG oddG; rewrite -rank_pgroup //; apply/idP/idP=> [cycG | dimG1]. by rewrite -abelian_rank1_cyclic ?cyclic_abelian. have [X nsXG cXX|//|] := normal_rank1_structure pG; last first. by rewrite (negPf (odd_not_extremal2 oddG)) andbF. by rewrite abelian_rank1_cyclic // (leq_trans (rankS (normal_sub nsXG))). Qed. (* This is the second part of Aschbacher, exercise (8.4). *) Lemma prime_Ohm1P gT p (G : {group gT}) : p.-group G -> G :!=: 1 -> reflect (#|'Ohm_1(G)| = p) (cyclic G || (p == 2) && (extremal_class G == Quaternion)). Proof. move=> pG ntG; have [p_pr p_dvd_G _] := pgroup_pdiv pG ntG. apply: (iffP idP) => [|oG1p]. case/orP=> [cycG|]; first exact: Ohm1_cyclic_pgroup_prime. case/andP=> /eqP p2 /eqP/quaternion_classP[n n_gt2 isoG]. rewrite p2; have [[x y]] := generators_quaternion n_gt2 isoG. by case/quaternion_structure=> // _ _ [<- oZ _ [->]]. have [X nsXG cXX|-> //|]:= normal_rank1_structure pG. have [sXG _] := andP nsXG; have pX := pgroupS sXG pG. rewrite abelian_rank1_cyclic // (rank_pgroup pX) p_rank_abelian //. rewrite -{2}(pfactorK 1 p_pr) -{3}oG1p dvdn_leq_log ?cardG_gt0 //. by rewrite cardSg ?OhmS. case/and3P=> /eqP p2; rewrite p2 (orbC (cyclic G)) /extremal2. case cG: (extremal_class G) => //; case: notF. case/dihedral_classP: cG => n n_gt1 isoG. have [[x y] genG _] := generators_2dihedral n_gt1 isoG. have [oG _ _ _] := genG; case/dihedral2_structure: genG => // _ _ [defG1 _] _. by case/idPn: n_gt1; rewrite -(@ltn_exp2l 2) // -oG -defG1 oG1p p2. case/semidihedral_classP: cG => n n_gt3 isoG. have [[x y] genG [oy _]] := generators_semidihedral n_gt3 isoG. case/semidihedral_structure: genG => // _ _ [_ _ [defG1 _] _] _ [isoG1 _ _]. case/idPn: (n_gt3); rewrite -(ltn_predK n_gt3) ltnS -leqNgt -(@leq_exp2l 2) //. rewrite -card_2dihedral //; last by rewrite -(subnKC n_gt3). by rewrite -(card_isog isoG1) /= -defG1 oG1p p2. Qed. (* This is Aschbacher (23.9) *) Theorem symplectic_type_group_structure gT p (G : {group gT}) : p.-group G -> (forall X : {group gT}, X \char G -> abelian X -> cyclic X) -> exists2 E : {group gT}, E :=: 1 \/ extraspecial E & exists R : {group gT}, [/\ cyclic R \/ [/\ p = 2, extremal2 R & #|R| >= 16], E \* R = G & E :&: R = 'Z(E)]. Proof. move=> pG sympG; have [H [charH]] := Thompson_critical pG. have sHG := char_sub charH; have pH := pgroupS sHG pG. set U := 'Z(H) => sPhiH_U sHG_U defU; set Z := 'Ohm_1(U). have sZU: Z \subset U by rewrite Ohm_sub. have charU: U \char G := char_trans (center_char H) charH. have cUU: abelian U := center_abelian H. have cycU: cyclic U by exact: sympG. have pU: p.-group U := pgroupS (char_sub charU) pG. have cHU: U \subset 'C(H) by rewrite subsetIr. have cHsHs: abelian (H / Z). rewrite sub_der1_abelian //= (OhmE _ pU) genS //= -/U. apply/subsetP=> _ /imset2P[h k Hh Hk ->]. have Uhk: [~ h, k] \in U by rewrite (subsetP sHG_U) ?mem_commg ?(subsetP sHG). rewrite inE Uhk inE -commXg; last by red; rewrite -(centsP cHU). apply/commgP; red; rewrite (centsP cHU) // (subsetP sPhiH_U) //. by rewrite (Phi_joing pH) mem_gen // inE orbC (Mho_p_elt 1) ?(mem_p_elt pH). have nsZH: Z <| H by rewrite sub_center_normal. have [K /=] := inv_quotientS nsZH (Ohm_sub 1 (H / Z)); fold Z => defKs sZK sKH. have nsZK: Z <| K := normalS sZK sKH nsZH; have [_ nZK] := andP nsZK. have abelKs: p.-abelem (K / Z) by rewrite -defKs Ohm1_abelem ?quotient_pgroup. have charK: K \char G. have charZ: Z \char H := char_trans (Ohm_char _ _) (center_char H). rewrite (char_trans _ charH) // (char_from_quotient nsZK) //. by rewrite -defKs Ohm_char. have cycZK: cyclic 'Z(K). by rewrite sympG ?center_abelian ?(char_trans (center_char _)). have [cKK | not_cKK] := orP (orbN (abelian K)). have defH: U = H. apply: center_idP; apply: cyclic_factor_abelian (Ohm_sub 1 _) _. rewrite /= -/Z abelian_rank1_cyclic //. have cKsKs: abelian (K / Z) by rewrite -defKs (abelianS (Ohm_sub 1 _)). have cycK: cyclic K by rewrite -(center_idP cKK). by rewrite -rank_Ohm1 defKs -abelian_rank1_cyclic ?quotient_cyclic. have scH: H \in 'SCN(G) by apply/SCN_P; rewrite defU char_normal. have [cGG | not_cGG] := orP (orbN (abelian G)). exists 1%G; [by left | exists G; rewrite cprod1g (setIidPl _) ?sub1G //]. by split; first left; rewrite ?center1 // sympG ?char_refl. have cycH: cyclic H by rewrite -{}defH. have [[p2 _ cG2]|[M [_ _ _]]] := cyclic_SCN pG scH not_cGG cycH; last first. do 2![case/setIdP] => _ abelE dimE_2 charE. have:= sympG _ charE (abelem_abelian abelE). by rewrite (abelem_cyclic abelE) (eqP dimE_2). have [n oG] := p_natP pG; rewrite p2 in oG. have [n_gt3 | n_le3] := ltnP 3 n. exists 1%G; [by left | exists G; rewrite cprod1g (setIidPl _) ?sub1G //]. by split; first right; rewrite ?center1 // oG (@leq_exp2l 2 4). have esG: extraspecial G. by apply: (p3group_extraspecial pG); rewrite // p2 oG pfactorK. exists G; [by right | exists ('Z(G))%G; rewrite cprod_center_id setIA setIid]. by split=> //; left; rewrite prime_cyclic; case: esG. have ntK: K :!=: 1 by apply: contra not_cKK; move/eqP->; exact: abelian1. have [p_pr _ _] := pgroup_pdiv (pgroupS sKH pH) ntK. have p_gt1 := prime_gt1 p_pr; have p_gt0 := ltnW p_gt1. have oZ: #|Z| = p. apply: Ohm1_cyclic_pgroup_prime => //=; apply: contra ntK; move/eqP. by move/(trivg_center_pgroup pH)=> GH; rewrite -subG1 -GH. have sZ_ZK: Z \subset 'Z(K). by rewrite subsetI sZK (subset_trans (Ohm_sub _ _ )) // subIset ?centS ?orbT. have sZsKs: 'Z(K) / Z \subset K / Z by rewrite quotientS ?center_sub. have [Es /= splitKs] := abelem_split_dprod abelKs sZsKs. have [_ /= defEsZs cEsZs tiEsZs] := dprodP splitKs. have sEsKs: Es \subset K / Z by rewrite -defEsZs mulG_subr. have [E defEs sZE sEK] := inv_quotientS nsZK sEsKs; rewrite /= -/Z in defEs sZE. have [nZE nZ_ZK] := (subset_trans sEK nZK, subset_trans (center_sub K) nZK). have defK: 'Z(K) * E = K. rewrite -(mulSGid sZ_ZK) -mulgA -quotientK ?mul_subG ?quotientMl //. by rewrite -defEs defEsZs quotientGK. have defZE: 'Z(E) = Z. have cEZK: 'Z(K) \subset 'C(E) by rewrite subIset // orbC centS. have cE_Z: E \subset 'C(Z) by rewrite centsC (subset_trans sZ_ZK). apply/eqP; rewrite eqEsubset andbC subsetI sZE centsC cE_Z /=. rewrite -quotient_sub1 ?subIset ?nZE //= -/Z -tiEsZs subsetI defEs. rewrite !quotientS ?center_sub //= subsetI subIset ?sEK //=. by rewrite -defK centM setSI // centsC. have sEH := subset_trans sEK sKH; have pE := pgroupS sEH pH. have esE: extraspecial E. split; last by rewrite defZE oZ. have sPhiZ: 'Phi(E) \subset Z. rewrite -quotient_sub1 ?(subset_trans (Phi_sub _)) ?(quotient_Phi pE) //. rewrite subG1 (trivg_Phi (quotient_pgroup _ pE)) /= -defEs. by rewrite (abelemS sEsKs) //= -defKs Ohm1_abelem ?quotient_pgroup. have sE'Phi: E^`(1) \subset 'Phi(E) by rewrite (Phi_joing pE) joing_subl. have ntE': E^`(1) != 1. rewrite (sameP eqP commG1P) -abelianE; apply: contra not_cKK => cEE. by rewrite -defK mulGSid ?center_abelian // -(center_idP cEE) defZE. have defE': E^`(1) = Z. apply/eqP; rewrite eqEcard (subset_trans sE'Phi) //= oZ. have [_ _ [n ->]] := pgroup_pdiv (pgroupS (der_sub _ _) pE) ntE'. by rewrite (leq_exp2l 1) ?prime_gt1. by split; rewrite defZE //; apply/eqP; rewrite eqEsubset sPhiZ -defE'. have [spE _] := esE; have [defPhiE defE'] := spE. have{defE'} sEG_E': [~: E, G] \subset E^`(1). rewrite defE' defZE /Z (OhmE _ pU) commGC genS //. apply/subsetP=> _ /imset2P[g e Gg Ee ->]. have He: e \in H by rewrite (subsetP sKH) ?(subsetP sEK). have Uge: [~ g, e] \in U by rewrite (subsetP sHG_U) ?mem_commg. rewrite inE Uge inE -commgX; last by red; rewrite -(centsP cHU). have sZ_ZG: Z \subset 'Z(G). have charZ: Z \char G := char_trans (Ohm_char _ _) charU. move/implyP: (meet_center_nil (pgroup_nil pG) (char_normal charZ)). rewrite -cardG_gt1 oZ prime_gt1 //=; apply: contraR => not_sZ_ZG. by rewrite prime_TIg ?oZ. have: e ^+ p \in 'Z(G). rewrite (subsetP sZ_ZG) // -defZE -defPhiE (Phi_joing pE) mem_gen //. by rewrite inE orbC (Mho_p_elt 1) ?(mem_p_elt pE). by case/setIP=> _ /centP cGep; apply/commgP; red; rewrite cGep. have sEG: E \subset G := subset_trans sEK (char_sub charK). set R := 'C_G(E). have{sEG_E'} defG: E \* R = G by exact: (critical_extraspecial pG). have [_ defER cRE] := cprodP defG. have defH: E \* 'C_H(E) = H by rewrite -(setIidPr sHG) setIAC (cprod_modl defG). have{defH} [_ defH cRH_E] := cprodP defH. have cRH_RH: abelian 'C_H(E). have sZ_ZRH: Z \subset 'Z('C_H(E)). rewrite subsetI -{1}defZE setSI //= (subset_trans sZU) // centsC. by rewrite subIset // centsC cHU. rewrite (cyclic_factor_abelian sZ_ZRH) //= -/Z. have defHs: Es \x ('C_H(E) / Z) = H / Z. rewrite defEs dprodE ?quotient_cents // -?quotientMl ?defH -?quotientGI //=. by rewrite setIA (setIidPl sEH) ['C_E(E)]defZE trivg_quotient. have:= Ohm_dprod 1 defHs; rewrite /= defKs (Ohm1_id (abelemS sEsKs abelKs)). rewrite dprodC; case/dprodP=> _ defEsRHs1 cRHs1Es tiRHs1Es. have sRHsHs: 'C_H(E) / Z \subset H / Z by rewrite quotientS ?subsetIl. have cRHsRHs: abelian ('C_H(E) / Z) by exact: abelianS cHsHs. have pHs: p.-group (H / Z) by rewrite quotient_pgroup. rewrite abelian_rank1_cyclic // (rank_pgroup (pgroupS sRHsHs pHs)). rewrite p_rank_abelian // -(leq_add2r (logn p #|Es|)) -lognM ?cardG_gt0 //. rewrite -TI_cardMg // defEsRHs1 /= -defEsZs TI_cardMg ?lognM ?cardG_gt0 //. by rewrite leq_add2r -abelem_cyclic ?(abelemS sZsKs) // quotient_cyclic. have{cRH_RH} defRH: 'C_H(E) = U. apply/eqP; rewrite eqEsubset andbC setIS ?centS // subsetI subsetIl /=. by rewrite -{2}defH centM subsetI subsetIr. have scUR: 'C_R(U) = U by rewrite -setIA -{1}defRH -centM defH. have sUR: U \subset R by rewrite -defRH setSI. have tiER: E :&: R = 'Z(E) by rewrite setIA (setIidPl (subset_trans sEH sHG)). have [cRR | not_cRR] := boolP (abelian R). exists E; [by right | exists [group of R]; split=> //; left]. by rewrite /= -(setIidPl (sub_abelian_cent cRR sUR)) scUR. have{scUR} scUR: [group of U] \in 'SCN(R). by apply/SCN_P; rewrite (normalS sUR (subsetIl _ _)) // char_normal. have pR: p.-group R := pgroupS (subsetIl _ _) pG. have [R_le_3 | R_gt_3] := leqP (logn p #|R|) 3. have esR: extraspecial R := p3group_extraspecial pR not_cRR R_le_3. have esG: extraspecial G := cprod_extraspecial pG defG tiER esE esR. exists G; [by right | exists ('Z(G))%G; rewrite cprod_center_id setIA setIid]. by split=> //; left; rewrite prime_cyclic; case: esG. have [[p2 _ ext2R] | [M []]] := cyclic_SCN pR scUR not_cRR cycU. exists E; [by right | exists [group of R]; split=> //; right]. by rewrite dvdn_leq ?(@pfactor_dvdn 2 4) ?cardG_gt0 // -{2}p2. rewrite /= -/R => defM iUM modM _ _; pose N := 'C_G('Mho^1(U)). have charZN2: 'Z('Ohm_2(N)) \char G. rewrite (char_trans (center_char _)) // (char_trans (Ohm_char _ _)) //. by rewrite subcent_char ?char_refl // (char_trans (Mho_char _ _)). have:= sympG _ charZN2 (center_abelian _). rewrite abelian_rank1_cyclic ?center_abelian // leqNgt; case/negP. have defN: E \* M = N. rewrite defM (cprod_modl defG) // centsC (subset_trans (Mho_sub 1 _)) //. by rewrite /= -/U -defRH subsetIr. case/modular_group_classP: modM => q q_pr [n n_gt23 isoM]. have{n_gt23} n_gt2 := leq_trans (leq_addl _ _) n_gt23. have n_gt1 := ltnW n_gt2; have n_gt0 := ltnW n_gt1. have [[x y] genM modM] := generators_modular_group q_pr n_gt2 isoM. have{q_pr} defq: q = p; last rewrite {q}defq in genM modM isoM. have: p %| #|M| by rewrite -iUM dvdn_indexg. by have [-> _ _ _] := genM; rewrite Euclid_dvdX // dvdn_prime2 //; case: eqP. have [oM Mx ox X'y] := genM; have [My _] := setDP X'y; have [oy _] := modM. have [sUM sMR]: U \subset M /\ M \subset R. by rewrite defM subsetI sUR subsetIl centsC (subset_trans (Mho_sub _ _)). have oU1: #|'Mho^1(U)| = (p ^ n.-2)%N. have oU: #|U| = (p ^ n.-1)%N. by rewrite -(divg_indexS sUM) iUM oM -subn1 expnB. case/cyclicP: cycU pU oU => u -> p_u ou. by rewrite (Mho_p_cycle 1 p_u) -orderE (orderXexp 1 ou) subn1. have sZU1: Z \subset 'Mho^1(U). rewrite -(cardSg_cyclic cycU) ?Ohm_sub ?Mho_sub // oZ oU1. by rewrite -(subnKC n_gt2) expnS dvdn_mulr. case/modular_group_structure: genM => // _ [defZM _ oZM] _ _. have:= n_gt2; rewrite leq_eqVlt eq_sym !xpair_eqE andbC. case: eqP => [n3 _ _ | _ /= n_gt3 defOhmM]. have eqZU1: Z = 'Mho^1(U) by apply/eqP; rewrite eqEcard sZU1 oZ oU1 n3 /=. rewrite (setIidPl _) in defM; first by rewrite -defM oM n3 pfactorK in R_gt_3. by rewrite -eqZU1 subIset ?centS ?orbT. have{defOhmM} [|defM2 _] := defOhmM 2; first by rewrite -subn1 ltn_subRL. do [set xpn3 := x ^+ _; set X2 := <[_]>] in defM2. have oX2: #|X2| = (p ^ 2)%N. by rewrite -orderE (orderXexp _ ox) -{1}(subnKC n_gt2) addSn addnK. have sZX2: Z \subset X2. have cycXp: cyclic <[x ^+ p]> := cycle_cyclic _. rewrite -(cardSg_cyclic cycXp) /=; first by rewrite oZ oX2 dvdn_mull. rewrite -defZM subsetI (subset_trans (Ohm_sub _ _)) //=. by rewrite (subset_trans sZU1) // centsC defM subsetIr. by rewrite /xpn3 -subnSK //expnS expgM cycleX. have{defM2} [_ /= defM2 cYX2 tiX2Y] := dprodP defM2. have{defN} [_ defN cME] := cprodP defN. have cEM2: E \subset 'C('Ohm_2(M)). by rewrite centsC (subset_trans _ cME) ?centS ?Ohm_sub. have [cEX2 cYE]: X2 \subset 'C(E) /\ E \subset 'C(<[y]>). by apply/andP; rewrite centsC -subsetI -centM defM2. have pN: p.-group N := pgroupS (subsetIl _ _) pG. have defN2: (E <*> X2) \x <[y]> = 'Ohm_2(N). rewrite dprodE ?centY ?subsetI 1?centsC ?cYE //=; last first. rewrite -cycle_subG in My; rewrite joingC cent_joinEl //= -/X2. rewrite -(setIidPr My) setIA -group_modl ?cycle_subG ?groupX //. by rewrite mulGSid // (subset_trans _ sZX2) // -defZE -tiER setIS. apply/eqP; rewrite cent_joinEr // -mulgA defM2 eqEsubset mulG_subG. rewrite OhmS ?andbT; last by rewrite -defN mulG_subr. have expE: exponent E %| p ^ 2 by rewrite exponent_special ?(pgroupS sEG). rewrite /= (OhmE 2 pN) sub_gen /=; last 1 first. by rewrite subsetI -defN mulG_subl sub_LdivT expE. rewrite -cent_joinEl // -genM_join genS // -defN. apply/subsetP=> ez; case/setIP; case/imset2P=> e z Ee Mz ->{ez}. rewrite inE expgMn; last by red; rewrite -(centsP cME). rewrite (exponentP expE) // mul1g => zp2; rewrite mem_mulg //=. by rewrite (OhmE 2 (pgroupS sMR pR)) mem_gen // !inE Mz. have{defN2} defZN2: X2 \x <[y]> = 'Z('Ohm_2(N)). rewrite -[X2](mulSGid sZX2) /= -/Z -defZE -(center_dprod defN2). do 2!rewrite -{1}(center_idP (cycle_abelian _)) -/X2; congr (_ \x _). by case/cprodP: (center_cprod (cprodEY cEX2)). have{defZN2} strZN2: \big[dprod/1]_(z <- [:: xpn3; y]) <[z]> = 'Z('Ohm_2(N)). by rewrite unlock /= dprodg1. rewrite -size_abelian_type ?center_abelian //. have pZN2: p.-group 'Z('Ohm_2(N)) by rewrite (pgroupS _ pN) // subIset ?Ohm_sub. rewrite -(perm_eq_size (perm_eq_abelian_type pZN2 strZN2 _)) //= !inE. rewrite !(eq_sym 1) -!order_eq1 oy orderE oX2. by rewrite (eqn_exp2l 2 0) // (eqn_exp2l 1 0). Qed. End ExtremalTheory. mathcomp-1.5/theories/finfun.v0000644000175000017500000002753012307636117015466 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq choice fintype tuple. (******************************************************************************) (* This file implements a type for functions with a finite domain: *) (* {ffun aT -> rT} where aT should have a finType structure. *) (* Any eqType, choiceType, countType and finType structures on rT extend to *) (* {ffun aT -> rT} as Leibnitz equality and extensional equalities coincide. *) (* (T ^ n)%type is notation for {ffun 'I_n -> T}, which is isomorphic *) (* ot n.-tuple T. *) (* For f : {ffun aT -> rT}, we define *) (* f x == the image of x under f (f coerces to a CiC function) *) (* fgraph f == the graph of f, i.e., the #|aT|.-tuple rT of the *) (* values of f over enum aT. *) (* finfun lam == the f such that f =1 lam; this is the RECOMMENDED *) (* interface to build an element of {ffun aT -> rT}. *) (* [ffun x => expr] == finfun (fun x => expr) *) (* [ffun => expr] == finfun (fun _ => expr) *) (* f \in ffun_on R == the range of f is a subset of R *) (* f \in family F == f belongs to the family F (f x \in F x for all x) *) (* y.-support f == the y-support of f, i.e., [pred x | f x != y]. *) (* Thus, y.-support f \subset D means f has y-support D. *) (* We will put Notation support := 0.-support in ssralg. *) (* f \in pffun_on y D R == f is a y-partial function from D to R: *) (* f has y-support D and f x \in R for all x \in D. *) (* f \in pfamily y D F == f belongs to the y-partial family from D to F: *) (* f has y-support D and f x \in F x for all x \in D. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Section Def. Variables (aT : finType) (rT : Type). Inductive finfun_type : predArgType := Finfun of #|aT|.-tuple rT. Definition finfun_of of phant (aT -> rT) := finfun_type. Identity Coercion type_of_finfun : finfun_of >-> finfun_type. Definition fgraph f := let: Finfun t := f in t. Canonical finfun_subType := Eval hnf in [newType for fgraph]. End Def. Notation "{ 'ffun' fT }" := (finfun_of (Phant fT)) (at level 0, format "{ 'ffun' '[hv' fT ']' }") : type_scope. Definition finexp_domFinType n := ordinal_finType n. Notation "T ^ n" := (@finfun_of (finexp_domFinType n) T (Phant _)) : type_scope. Notation Local fun_of_fin_def := (fun aT rT f x => tnth (@fgraph aT rT f) (enum_rank x)). Notation Local finfun_def := (fun aT rT f => @Finfun aT rT (codom_tuple f)). Module Type FunFinfunSig. Parameter fun_of_fin : forall aT rT, finfun_type aT rT -> aT -> rT. Parameter finfun : forall (aT : finType) rT, (aT -> rT) -> {ffun aT -> rT}. Axiom fun_of_finE : fun_of_fin = fun_of_fin_def. Axiom finfunE : finfun = finfun_def. End FunFinfunSig. Module FunFinfun : FunFinfunSig. Definition fun_of_fin := fun_of_fin_def. Definition finfun := finfun_def. Lemma fun_of_finE : fun_of_fin = fun_of_fin_def. Proof. by []. Qed. Lemma finfunE : finfun = finfun_def. Proof. by []. Qed. End FunFinfun. Notation fun_of_fin := FunFinfun.fun_of_fin. Notation finfun := FunFinfun.finfun. Coercion fun_of_fin : finfun_type >-> Funclass. Canonical fun_of_fin_unlock := Unlockable FunFinfun.fun_of_finE. Canonical finfun_unlock := Unlockable FunFinfun.finfunE. Notation "[ 'ffun' x : aT => F ]" := (finfun (fun x : aT => F)) (at level 0, x ident, only parsing) : fun_scope. Notation "[ 'ffun' : aT => F ]" := (finfun (fun _ : aT => F)) (at level 0, only parsing) : fun_scope. Notation "[ 'ffun' x => F ]" := [ffun x : _ => F] (at level 0, x ident, format "[ 'ffun' x => F ]") : fun_scope. Notation "[ 'ffun' => F ]" := [ffun : _ => F] (at level 0, format "[ 'ffun' => F ]") : fun_scope. (* Helper for defining notation for function families. *) Definition fmem aT rT (pT : predType rT) (f : aT -> pT) := [fun x => mem (f x)]. (* Lemmas on the correspondance between finfun_type and CiC functions. *) Section PlainTheory. Variables (aT : finType) (rT : Type). Notation fT := {ffun aT -> rT}. Implicit Types (f : fT) (R : pred rT). Canonical finfun_of_subType := Eval hnf in [subType of fT]. Lemma tnth_fgraph f i : tnth (fgraph f) i = f (enum_val i). Proof. by rewrite [@fun_of_fin]unlock enum_valK. Qed. Lemma ffunE (g : aT -> rT) : finfun g =1 g. Proof. move=> x; rewrite [@finfun]unlock unlock tnth_map. by rewrite -[tnth _ _]enum_val_nth enum_rankK. Qed. Lemma fgraph_codom f : fgraph f = codom_tuple f. Proof. apply: eq_from_tnth => i; rewrite [@fun_of_fin]unlock tnth_map. by congr tnth; rewrite -[tnth _ _]enum_val_nth enum_valK. Qed. Lemma codom_ffun f : codom f = val f. Proof. by rewrite /= fgraph_codom. Qed. Lemma ffunP f1 f2 : f1 =1 f2 <-> f1 = f2. Proof. split=> [eq_f12 | -> //]; do 2!apply: val_inj => /=. by rewrite !fgraph_codom /= (eq_codom eq_f12). Qed. Lemma ffunK : cancel (@fun_of_fin aT rT) (@finfun aT rT). Proof. by move=> f; apply/ffunP/ffunE. Qed. Definition family_mem mF := [pred f : fT | [forall x, in_mem (f x) (mF x)]]. Lemma familyP (pT : predType rT) (F : aT -> pT) f : reflect (forall x, f x \in F x) (f \in family_mem (fmem F)). Proof. exact: forallP. Qed. Definition ffun_on_mem mR := family_mem (fun _ => mR). Lemma ffun_onP R f : reflect (forall x, f x \in R) (f \in ffun_on_mem (mem R)). Proof. exact: forallP. Qed. End PlainTheory. Notation family F := (family_mem (fun_of_simpl (fmem F))). Notation ffun_on R := (ffun_on_mem _ (mem R)). Implicit Arguments familyP [aT rT pT F f]. Implicit Arguments ffun_onP [aT rT R f]. (*****************************************************************************) Lemma nth_fgraph_ord T n (x0 : T) (i : 'I_n) f : nth x0 (fgraph f) i = f i. Proof. by rewrite -{2}(enum_rankK i) -tnth_fgraph (tnth_nth x0) enum_rank_ord. Qed. Section Support. Variables (aT : Type) (rT : eqType). Definition support_for y (f : aT -> rT) := [pred x | f x != y]. Lemma supportE x y f : (x \in support_for y f) = (f x != y). Proof. by []. Qed. End Support. Notation "y .-support" := (support_for y) (at level 2, format "y .-support") : fun_scope. Section EqTheory. Variables (aT : finType) (rT : eqType). Notation fT := {ffun aT -> rT}. Implicit Types (y : rT) (D : pred aT) (R : pred rT) (f : fT). Lemma supportP y D g : reflect (forall x, x \notin D -> g x = y) (y.-support g \subset D). Proof. by apply: (iffP subsetP) => Dg x; [apply: contraNeq | apply: contraR] => /Dg->. Qed. Definition finfun_eqMixin := Eval hnf in [eqMixin of finfun_type aT rT by <:]. Canonical finfun_eqType := Eval hnf in EqType _ finfun_eqMixin. Canonical finfun_of_eqType := Eval hnf in [eqType of fT]. Definition pfamily_mem y mD (mF : aT -> mem_pred rT) := family (fun i : aT => if in_mem i mD then pred_of_simpl (mF i) else pred1 y). Lemma pfamilyP (pT : predType rT) y D (F : aT -> pT) f : reflect (y.-support f \subset D /\ {in D, forall x, f x \in F x}) (f \in pfamily_mem y (mem D) (fmem F)). Proof. apply: (iffP familyP) => [/= f_pfam | [/supportP f_supp f_fam] x]. split=> [|x Ax]; last by have:= f_pfam x; rewrite Ax. by apply/subsetP=> x; case: ifP (f_pfam x) => //= _ fx0 /negP[]. by case: ifPn => Ax /=; rewrite inE /= (f_fam, f_supp). Qed. Definition pffun_on_mem y mD mR := pfamily_mem y mD (fun _ => mR). Lemma pffun_onP y D R f : reflect (y.-support f \subset D /\ {subset image f D <= R}) (f \in pffun_on_mem y (mem D) (mem R)). Proof. apply: (iffP (pfamilyP y D (fun _ => R) f)) => [] [-> f_fam]; split=> //. by move=> _ /imageP[x Ax ->]; exact: f_fam. by move=> x Ax; apply: f_fam; apply/imageP; exists x. Qed. End EqTheory. Canonical exp_eqType (T : eqType) n := [eqType of T ^ n]. Implicit Arguments supportP [aT rT y D g]. Notation pfamily y D F := (pfamily_mem y (mem D) (fun_of_simpl (fmem F))). Notation pffun_on y D R := (pffun_on_mem y (mem D) (mem R)). Definition finfun_choiceMixin aT (rT : choiceType) := [choiceMixin of finfun_type aT rT by <:]. Canonical finfun_choiceType aT rT := Eval hnf in ChoiceType _ (finfun_choiceMixin aT rT). Canonical finfun_of_choiceType (aT : finType) (rT : choiceType) := Eval hnf in [choiceType of {ffun aT -> rT}]. Canonical exp_choiceType (T : choiceType) n := [choiceType of T ^ n]. Definition finfun_countMixin aT (rT : countType) := [countMixin of finfun_type aT rT by <:]. Canonical finfun_countType aT (rT : countType) := Eval hnf in CountType _ (finfun_countMixin aT rT). Canonical finfun_of_countType (aT : finType) (rT : countType) := Eval hnf in [countType of {ffun aT -> rT}]. Canonical finfun_subCountType aT (rT : countType) := Eval hnf in [subCountType of finfun_type aT rT]. Canonical finfun_of_subCountType (aT : finType) (rT : countType) := Eval hnf in [subCountType of {ffun aT -> rT}]. (*****************************************************************************) Section FinTheory. Variables aT rT : finType. Notation fT := {ffun aT -> rT}. Notation ffT := (finfun_type aT rT). Implicit Types (D : pred aT) (R : pred rT) (F : aT -> pred rT). Definition finfun_finMixin := [finMixin of ffT by <:]. Canonical finfun_finType := Eval hnf in FinType ffT finfun_finMixin. Canonical finfun_subFinType := Eval hnf in [subFinType of ffT]. Canonical finfun_of_finType := Eval hnf in [finType of fT for finfun_finType]. Canonical finfun_of_subFinType := Eval hnf in [subFinType of fT]. Lemma card_pfamily y0 D F : #|pfamily y0 D F| = foldr muln 1 [seq #|F x| | x in D]. Proof. rewrite /image_mem; transitivity #|pfamily y0 (enum D) F|. by apply/eq_card=> f; apply/eq_forallb=> x /=; rewrite mem_enum. elim: {D}(enum D) (enum_uniq D) => /= [_|x0 s IHs /andP[s'x0 /IHs<-{IHs}]]. apply: eq_card1 [ffun=> y0] _ _ => f. apply/familyP/eqP=> [y0_f|-> x]; last by rewrite ffunE inE. by apply/ffunP=> x; rewrite ffunE (eqP (y0_f x)). pose g (xf : rT * fT) := finfun [eta xf.2 with x0 |-> xf.1]. have gK: cancel (fun f : fT => (f x0, g (y0, f))) g. by move=> f; apply/ffunP=> x; do !rewrite ffunE /=; case: eqP => // ->. rewrite -cardX -(card_image (can_inj gK)); apply: eq_card => [] [y f] /=. apply/imageP/andP=> [[f0 /familyP/=Ff0] [{f}-> ->]| [Fy /familyP/=Ff]]. split; first by have:= Ff0 x0; rewrite /= mem_head. apply/familyP=> x; have:= Ff0 x; rewrite ffunE inE /=. by case: eqP => //= -> _; rewrite ifN ?inE. exists (g (y, f)). by apply/familyP=> x; have:= Ff x; rewrite ffunE /= inE; case: eqP => // ->. congr (_, _); last apply/ffunP=> x; do !rewrite ffunE /= ?eqxx //. by case: eqP => // ->{x}; apply/eqP; have:= Ff x0; rewrite ifN. Qed. Lemma card_family F : #|family F| = foldr muln 1 [seq #|F x| | x : aT]. Proof. have [y0 _ | rT0] := pickP rT; first exact: (card_pfamily y0 aT). rewrite /image_mem; case DaT: (enum aT) => [{rT0}|x0 e] /=; last first. by rewrite !eq_card0 // => [f | y]; [have:= rT0 (f x0) | have:= rT0 y]. have{DaT} no_aT P (x : aT) : P by have:= mem_enum aT x; rewrite DaT. apply: eq_card1 [ffun x => no_aT rT x] _ _ => f. by apply/familyP/eqP=> _; [apply/ffunP | ] => x; apply: no_aT. Qed. Lemma card_pffun_on y0 D R : #|pffun_on y0 D R| = #|R| ^ #|D|. Proof. rewrite (cardE D) card_pfamily /image_mem. by elim: (enum D) => //= _ e ->; rewrite expnS. Qed. Lemma card_ffun_on R : #|ffun_on R| = #|R| ^ #|aT|. Proof. rewrite card_family /image_mem cardT. by elim: (enum aT) => //= _ e ->; rewrite expnS. Qed. Lemma card_ffun : #|fT| = #|rT| ^ #|aT|. Proof. by rewrite -card_ffun_on; apply/esym/eq_card=> f; apply/forallP. Qed. End FinTheory. Canonical exp_finType (T : finType) n := [finType of T ^ n]. mathcomp-1.5/theories/character.v0000644000175000017500000034005012307636117016130 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. Require Import fintype tuple finfun bigop prime ssralg poly finset gproduct. Require Import fingroup morphism perm automorphism quotient finalg action. Require Import zmodp commutator cyclic center pgroup nilpotent sylow abelian. Require Import matrix mxalgebra mxpoly mxrepresentation vector ssrnum algC. Require Import classfun. Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope GRing.Theory Num.Theory. Local Open Scope ring_scope. (******************************************************************************) (* This file contains the basic notions of character theory, based on Isaacs. *) (* irr G == tuple of the elements of 'CF(G) that are irreducible *) (* characters of G. *) (* Nirr G == number of irreducible characters of G. *) (* Iirr G == index type for the irreducible characters of G. *) (* := 'I_(Nirr G). *) (* 'chi_i == the i-th element of irr G, for i : Iirr G. *) (* 'chi[G]_i Note that 'chi_0 = 1, the principal character of G. *) (* 'Chi_i == an irreducible representation that affords 'chi_i. *) (* socle_of_Iirr i == the Wedderburn component of the regular representation *) (* of G, corresponding to 'Chi_i. *) (* Iirr_of_socle == the inverse of socle_of_Iirr (which is one-to-one). *) (* phi.[A]%CF == the image of A \in group_ring G under phi : 'CF(G). *) (* cfRepr rG == the character afforded by the representation rG of G. *) (* cfReg G == the regular character, afforded by the regular *) (* representation of G. *) (* detRepr rG == the linear character afforded by the determinant of rG. *) (* cfDet phi == the linear character afforded by the determinant of a *) (* representation affording phi. *) (* 'o(phi) == the "determinential order" of phi (the multiplicative *) (* order of cfDet phi. *) (* phi \is a character <=> phi : 'CF(G) is a character of G or 0. *) (* i \in irr_constt phi <=> 'chi_i is an irreducible constituent of phi: phi *) (* has a non-zero coordinate on 'chi_i over the basis irr G. *) (* xi \is a linear_char xi <=> xi : 'CF(G) is a linear character of G. *) (* 'Z(chi)%CF == the center of chi when chi is a character of G, i.e., *) (* rcenter rG where rG is a representation that affords phi. *) (* If phi is not a character then 'Z(chi)%CF = cfker phi. *) (* aut_Iirr u i == the index of cfAut u 'chi_i in irr G. *) (* conjC_Iirr i == the index of 'chi_i^*%CF in irr G. *) (* morph_Iirr i == the index of cfMorph 'chi[f @* G]_i in irr G. *) (* isom_Iirr isoG i == the index of cfIsom isoG 'chi[G]_i in irr R. *) (* mod_Iirr i == the index of ('chi[G / H]_i %% H)%CF in irr G. *) (* quo_Iirr i == the index of ('chi[G]_i / H)%CF in irr (G / H). *) (* Ind_Iirr G i == the index of 'Ind[G, H] 'chi_i, provided it is an *) (* irreducible character (such as when if H is the inertia *) (* group of 'chi_i). *) (* Res_Iirr H i == the index of 'Res[H, G] 'chi_i, provided it is an *) (* irreducible character (such as when 'chi_i is linear). *) (* sdprod_Iirr defG i == the index of cfSdprod defG 'chi_i in irr G, given *) (* defG : K ><| H = G. *) (* And, for KxK : K \x H = G. *) (* dprodl_Iirr KxH i == the index of cfDprodl KxH 'chi[K]_i in irr G. *) (* dprodr_Iirr KxH j == the index of cfDprodr KxH 'chi[H]_j in irr G. *) (* dprod_Iirr KxH (i, j) == the index of cfDprod KxH 'chi[K]_i 'chi[H]_j. *) (* inv_dprod_Iirr KxH == the inverse of dprod_Iirr KxH. *) (* The following are used to define and exploit the character table: *) (* character_table G == the character table of G, whose i-th row lists the *) (* values taken by 'chi_i on the conjugacy classes *) (* of G; this is a square Nirr G x NirrG matrix. *) (* irr_class i == the conjugacy class of G with index i : Iirr G. *) (* class_Iirr xG == the index of xG \in classes G, in Iirr G. *) (******************************************************************************) Local Notation algCF := [fieldType of algC]. Section AlgC. Variable (gT : finGroupType). Lemma groupC : group_closure_field algCF gT. Proof. exact: group_closure_closed_field. Qed. End AlgC. Section Tensor. Variable (F : fieldType). Fixpoint trow (n1 : nat) : forall (A : 'rV[F]_n1) m2 n2 (B : 'M[F]_(m2,n2)), 'M[F]_(m2,n1 * n2) := if n1 is n'1.+1 then fun (A : 'M[F]_(1,(1 + n'1))) m2 n2 (B : 'M[F]_(m2,n2)) => (row_mx (lsubmx A 0 0 *: B) (trow (rsubmx A) B)) else (fun _ _ _ _ => 0). Lemma trow0 n1 m2 n2 B : @trow n1 0 m2 n2 B = 0. Proof. elim: n1=> //= n1 IH. rewrite !mxE scale0r linear0. rewrite IH //; apply/matrixP=> i j; rewrite !mxE. by case: split=> *; rewrite mxE. Qed. Definition trowb n1 m2 n2 B A := @trow n1 A m2 n2 B. Lemma trowbE n1 m2 n2 A B : trowb B A = @trow n1 A m2 n2 B. Proof. by []. Qed. Lemma trowb_is_linear n1 m2 n2 (B : 'M_(m2,n2)) : linear (@trowb n1 m2 n2 B). Proof. elim: n1=> [|n1 IH] //= k A1 A2 /=; first by rewrite scaler0 add0r. rewrite linearD /= linearZ. apply/matrixP=> i j. rewrite !mxE. case: split=> a. by rewrite !mxE mulrDl mulrA. by rewrite linearD /= linearZ IH !mxE. Qed. Canonical Structure trowb_linear n1 m2 n2 B := Linear (@trowb_is_linear n1 m2 n2 B). Lemma trow_is_linear n1 m2 n2 (A : 'rV_n1) : linear (@trow n1 A m2 n2). Proof. elim: n1 A => [|n1 IH] //= A k A1 A2 /=; first by rewrite scaler0 add0r. rewrite linearD /= linearZ /=. apply/matrixP=> i j; rewrite !mxE. by case: split=> a; rewrite ?IH !mxE. Qed. Canonical Structure trow_linear n1 m2 n2 A := Linear (@trow_is_linear n1 m2 n2 A). Fixpoint tprod (m1 : nat) : forall n1 (A : 'M[F]_(m1,n1)) m2 n2 (B : 'M[F]_(m2,n2)), 'M[F]_(m1 * m2,n1 * n2) := if m1 is m'1.+1 return forall n1 (A : 'M[F]_(m1,n1)) m2 n2 (B : 'M[F]_(m2,n2)), 'M[F]_(m1 * m2,n1 * n2) then fun n1 (A : 'M[F]_(1 + m'1,n1)) m2 n2 B => (col_mx (trow (usubmx A) B) (tprod (dsubmx A) B)) else (fun _ _ _ _ _ => 0). Lemma dsumx_mul m1 m2 n p A B : dsubmx ((A *m B) : 'M[F]_(m1 + m2, n)) = dsubmx (A : 'M_(m1 + m2, p)) *m B. Proof. apply/matrixP=> i j; rewrite !mxE; apply: eq_bigr=> k _. by rewrite !mxE. Qed. Lemma usumx_mul m1 m2 n p A B : usubmx ((A *m B) : 'M[F]_(m1 + m2, n)) = usubmx (A : 'M_(m1 + m2, p)) *m B. Proof. by apply/matrixP=> i j; rewrite !mxE; apply: eq_bigr=> k _; rewrite !mxE. Qed. Let trow_mul (m1 m2 n2 p2 : nat) (A : 'rV_m1) (B1: 'M[F]_(m2,n2)) (B2 :'M[F]_(n2,p2)) : trow A (B1 *m B2) = B1 *m trow A B2. Proof. elim: m1 A => [|m1 IH] A /=; first by rewrite mulmx0. by rewrite IH mul_mx_row -scalemxAr. Qed. Lemma tprodE m1 n1 p1 (A1 :'M[F]_(m1,n1)) (A2 :'M[F]_(n1,p1)) m2 n2 p2 (B1 :'M[F]_(m2,n2)) (B2 :'M[F]_(n2,p2)) : tprod (A1 *m A2) (B1 *m B2) = (tprod A1 B1) *m (tprod A2 B2). Proof. elim: m1 n1 p1 A1 A2 m2 n2 p2 B1 B2 => /= [|m1 IH]. by move=> *; rewrite mul0mx. move=> n1 p1 A1 A2 m2 n2 p2 B1 B2. rewrite mul_col_mx -IH. congr col_mx; last by rewrite dsumx_mul. rewrite usumx_mul. elim: n1 {A1}(usubmx (A1: 'M_(1 + m1, n1))) p1 A2=> //= [u p1 A2|]. by rewrite [A2](flatmx0) !mulmx0 -trowbE linear0. move=> n1 IH1 A p1 A2 //=. set Al := lsubmx _; set Ar := rsubmx _. set Su := usubmx _; set Sd := dsubmx _. rewrite mul_row_col -IH1. rewrite -{1}(@hsubmxK F 1 1 n1 A). rewrite -{1}(@vsubmxK F 1 n1 p1 A2). rewrite (@mul_row_col F 1 1 n1 p1). rewrite -trowbE linearD /= trowbE -/Al. congr (_ + _). rewrite {1}[Al]mx11_scalar mul_scalar_mx. by rewrite -trowbE linearZ /= trowbE -/Su trow_mul scalemxAl. Qed. Let tprod_tr m1 n1 (A :'M[F]_(m1, 1 + n1)) m2 n2 (B :'M[F]_(m2, n2)) : tprod A B = row_mx (trow (lsubmx A)^T B^T)^T (tprod (rsubmx A) B). Proof. elim: m1 n1 A m2 n2 B=> [|m1 IH] n1 A m2 n2 B //=. by rewrite trmx0 row_mx0. rewrite !IH. pose A1 := A : 'M_(1 + m1, 1 + n1). have F1: dsubmx (rsubmx A1) = rsubmx (dsubmx A1). by apply/matrixP=> i j; rewrite !mxE. have F2: rsubmx (usubmx A1) = usubmx (rsubmx A1). by apply/matrixP=> i j; rewrite !mxE. have F3: lsubmx (dsubmx A1) = dsubmx (lsubmx A1). by apply/matrixP=> i j; rewrite !mxE. rewrite tr_row_mx -block_mxEv -block_mxEh !(F1,F2,F3); congr block_mx. - by rewrite !mxE linearZ /= trmxK. by rewrite -trmx_dsub. Qed. Lemma tprod1 m n : tprod (1%:M : 'M[F]_(m,m)) (1%:M : 'M[F]_(n,n)) = 1%:M. Proof. elim: m n => [|m IH] n //=; first by rewrite [1%:M]flatmx0. rewrite tprod_tr. set u := rsubmx _; have->: u = 0. apply/matrixP=> i j; rewrite !mxE. by case: i; case: j=> /= j Hj; case. set v := lsubmx (dsubmx _); have->: v = 0. apply/matrixP=> i j; rewrite !mxE. by case: i; case: j; case. set w := rsubmx _; have->: w = 1%:M. apply/matrixP=> i j; rewrite !mxE. by case: i; case: j; case. rewrite IH -!trowbE !linear0. rewrite -block_mxEv. set z := (lsubmx _) 0 0; have->: z = 1. by rewrite /z !mxE eqxx. by rewrite scale1r scalar_mx_block. Qed. Lemma mxtrace_prod m n (A :'M[F]_(m)) (B :'M[F]_(n)) : \tr (tprod A B) = \tr A * \tr B. Proof. elim: m n A B => [|m IH] n A B //=. by rewrite [A]flatmx0 mxtrace0 mul0r. rewrite tprod_tr -block_mxEv mxtrace_block IH. rewrite linearZ /= -mulrDl; congr (_ * _). rewrite -trace_mx11 . pose A1 := A : 'M_(1 + m). rewrite -{3}[A](@submxK _ 1 m 1 m A1). by rewrite (@mxtrace_block _ _ _ (ulsubmx A1)). Qed. End Tensor. (* Representation sigma type and standard representations. *) Section StandardRepresentation. Variables (R : fieldType) (gT : finGroupType) (G : {group gT}). Local Notation reprG := (mx_representation R G). Record representation := Representation {rdegree; mx_repr_of_repr :> reprG rdegree}. Lemma mx_repr0 : mx_repr G (fun _ : gT => 1%:M : 'M[R]_0). Proof. by split=> // g h Hg Hx; rewrite mulmx1. Qed. Definition grepr0 := Representation (MxRepresentation mx_repr0). Lemma add_mx_repr (rG1 rG2 : representation) : mx_repr G (fun g => block_mx (rG1 g) 0 0 (rG2 g)). Proof. split=> [|x y Hx Hy]; first by rewrite !repr_mx1 -scalar_mx_block. by rewrite mulmx_block !(mulmx0, mul0mx, addr0, add0r, repr_mxM). Qed. Definition dadd_grepr rG1 rG2 := Representation (MxRepresentation (add_mx_repr rG1 rG2)). Section DsumRepr. Variables (n : nat) (rG : reprG n). Lemma mx_rsim_dadd (U V W : 'M_n) (rU rV : representation) (modU : mxmodule rG U) (modV : mxmodule rG V) (modW : mxmodule rG W) : (U + V :=: W)%MS -> mxdirect (U + V) -> mx_rsim (submod_repr modU) rU -> mx_rsim (submod_repr modV) rV -> mx_rsim (submod_repr modW) (dadd_grepr rU rV). Proof. case: rU; case: rV=> nV rV nU rU defW dxUV /=. have tiUV := mxdirect_addsP dxUV. move=> [fU def_nU]; rewrite -{nU}def_nU in rU fU * => inv_fU hom_fU. move=> [fV def_nV]; rewrite -{nV}def_nV in rV fV * => inv_fV hom_fV. pose pU := in_submod U (proj_mx U V) *m fU. pose pV := in_submod V (proj_mx V U) *m fV. exists (val_submod 1%:M *m row_mx pU pV) => [||g Gg]. - by rewrite -defW (mxdirectP dxUV). - apply/row_freeP. pose pU' := invmx fU *m val_submod 1%:M. pose pV' := invmx fV *m val_submod 1%:M. exists (in_submod _ (col_mx pU' pV')). rewrite in_submodE mulmxA -in_submodE -mulmxA mul_row_col mulmxDr. rewrite -[pU *m _]mulmxA -[pV *m _]mulmxA !mulKVmx -?row_free_unit //. rewrite addrC (in_submodE V) 2![val_submod 1%:M *m _]mulmxA -in_submodE. rewrite addrC (in_submodE U) 2![val_submod 1%:M *m _]mulmxA -in_submodE. rewrite -!val_submodE !in_submodK ?proj_mx_sub //. by rewrite add_proj_mx ?val_submodK // val_submod1 defW. rewrite mulmxA -val_submodE -[submod_repr _ g]mul1mx val_submodJ //. rewrite -(mulmxA _ (rG g)) mul_mx_row -mulmxA mul_row_block !mulmx0 addr0 add0r. rewrite !mul_mx_row; set W' := val_submod 1%:M; congr (row_mx _ _). rewrite 3!mulmxA in_submodE mulmxA. have hom_pU: (W' <= dom_hom_mx rG (proj_mx U V))%MS. by rewrite val_submod1 -defW proj_mx_hom. rewrite (hom_mxP hom_pU) // -in_submodE (in_submodJ modU) ?proj_mx_sub //. rewrite -(mulmxA _ _ fU) hom_fU // in_submodE -2!(mulmxA W') -in_submodE. by rewrite -mulmxA (mulmxA _ fU). rewrite 3!mulmxA in_submodE mulmxA. have hom_pV: (W' <= dom_hom_mx rG (proj_mx V U))%MS. by rewrite val_submod1 -defW addsmxC proj_mx_hom // capmxC. rewrite (hom_mxP hom_pV) // -in_submodE (in_submodJ modV) ?proj_mx_sub //. rewrite -(mulmxA _ _ fV) hom_fV // in_submodE -2!(mulmxA W') -in_submodE. by rewrite -mulmxA (mulmxA _ fV). Qed. Lemma mx_rsim_dsum (I : finType) (P : pred I) U rU (W : 'M_n) (modU : forall i, mxmodule rG (U i)) (modW : mxmodule rG W) : let S := (\sum_(i | P i) U i)%MS in (S :=: W)%MS -> mxdirect S -> (forall i, mx_rsim (submod_repr (modU i)) (rU i : representation)) -> mx_rsim (submod_repr modW) (\big[dadd_grepr/grepr0]_(i | P i) rU i). Proof. move=> /= defW dxW rsimU. rewrite mxdirectE /= -!(big_filter _ P) in dxW defW *. elim: {P}(filter P _) => [|i e IHe] in W modW dxW defW *. rewrite !big_nil /= in defW *. by exists 0 => [||? _]; rewrite ?mul0mx ?mulmx0 // /row_free -defW !mxrank0. rewrite !big_cons /= in dxW defW *. rewrite 2!(big_nth i) !big_mkord /= in IHe dxW defW. set Wi := (\sum_i _)%MS in defW dxW IHe. rewrite -mxdirectE mxdirect_addsE !mxdirectE eqxx /= -/Wi in dxW. have modWi: mxmodule rG Wi by exact: sumsmx_module. case/andP: dxW; move/(IHe Wi modWi) {IHe}; move/(_ (eqmx_refl _))=> rsimWi. by move/eqP; move/mxdirect_addsP=> dxUiWi; exact: mx_rsim_dadd (rsimU i) rsimWi. Qed. Definition muln_grepr rW k := \big[dadd_grepr/grepr0]_(i < k) rW. Lemma mx_rsim_socle (sG : socleType rG) (W : sG) (rW : representation) : let modW : mxmodule rG W := component_mx_module rG (socle_base W) in mx_rsim (socle_repr W) rW -> mx_rsim (submod_repr modW) (muln_grepr rW (socle_mult W)). Proof. set M := socle_base W => modW rsimM. have simM: mxsimple rG M := socle_simple W. have rankM_gt0: (\rank M > 0)%N by rewrite lt0n mxrank_eq0; case: simM. have [I /= U_I simU]: mxsemisimple rG W by exact: component_mx_semisimple. pose U (i : 'I_#|I|) := U_I (enum_val i). have reindexI := reindex _ (onW_bij I (enum_val_bij I)). rewrite mxdirectE /= !reindexI -mxdirectE /= => defW dxW. have isoU: forall i, mx_iso rG M (U i). move=> i; have sUiW: (U i <= W)%MS by rewrite -defW (sumsmx_sup i). exact: component_mx_iso (simU _) sUiW. have ->: socle_mult W = #|I|. rewrite -(mulnK #|I| rankM_gt0); congr (_ %/ _)%N. rewrite -defW (mxdirectP dxW) /= -sum_nat_const reindexI /=. by apply: eq_bigr => i _; rewrite -(mxrank_iso (isoU i)). have modU: mxmodule rG (U _) := mxsimple_module (simU _). suff: mx_rsim (submod_repr (modU _)) rW by exact: mx_rsim_dsum defW dxW. by move=> i; apply: mx_rsim_trans (mx_rsim_sym _) rsimM; exact/mx_rsim_iso. Qed. End DsumRepr. Section ProdRepr. Variables (n1 n2 : nat) (rG1 : reprG n1) (rG2 : reprG n2). Lemma prod_mx_repr : mx_repr G (fun g => tprod (rG1 g) (rG2 g)). Proof. split=>[|i j InG JnG]; first by rewrite !repr_mx1 tprod1. by rewrite !repr_mxM // tprodE. Qed. Definition prod_repr := MxRepresentation prod_mx_repr. End ProdRepr. Lemma prod_repr_lin n2 (rG1 : reprG 1) (rG2 : reprG n2) : {in G, forall x, let cast_n2 := esym (mul1n n2) in prod_repr rG1 rG2 x = castmx (cast_n2, cast_n2) (rG1 x 0 0 *: rG2 x)}. Proof. move=> x Gx cast_n2; rewrite /prod_repr /= !mxE !lshift0. apply/matrixP=> i j; rewrite castmxE /=. do 2![rewrite mxE; case: splitP => [? ? | []//]]. by congr ((_ *: rG2 x) _ _); apply: val_inj. Qed. End StandardRepresentation. Implicit Arguments grepr0 [R gT G]. Prenex Implicits grepr0 dadd_grepr. Section Char. Variables (gT : finGroupType) (G : {group gT}). Fact cfRepr_subproof n (rG : mx_representation algCF G n) : is_class_fun <> [ffun x => \tr (rG x) *+ (x \in G)]. Proof. rewrite genGid; apply: intro_class_fun => [x y Gx Gy | _ /negbTE-> //]. by rewrite groupJr // !repr_mxM ?groupM ?groupV // mxtrace_mulC repr_mxK. Qed. Definition cfRepr n rG := Cfun 0 (@cfRepr_subproof n rG). Lemma cfRepr1 n rG : @cfRepr n rG 1%g = n%:R. Proof. by rewrite cfunE group1 repr_mx1 mxtrace1. Qed. Lemma cfRepr_sim n1 n2 rG1 rG2 : mx_rsim rG1 rG2 -> @cfRepr n1 rG1 = @cfRepr n2 rG2. Proof. case/mx_rsim_def=> f12 [f21] fK def_rG1; apply/cfun_inP=> x Gx. by rewrite !cfunE def_rG1 // mxtrace_mulC mulmxA fK mul1mx. Qed. Lemma cfRepr0 : cfRepr grepr0 = 0. Proof. by apply/cfun_inP=> x Gx; rewrite !cfunE Gx mxtrace1. Qed. Lemma cfRepr_dadd rG1 rG2 : cfRepr (dadd_grepr rG1 rG2) = cfRepr rG1 + cfRepr rG2. Proof. by apply/cfun_inP=> x Gx; rewrite !cfunE Gx mxtrace_block. Qed. Lemma cfRepr_dsum I r (P : pred I) rG : cfRepr (\big[dadd_grepr/grepr0]_(i <- r | P i) rG i) = \sum_(i <- r | P i) cfRepr (rG i). Proof. exact: (big_morph _ cfRepr_dadd cfRepr0). Qed. Lemma cfRepr_muln rG k : cfRepr (muln_grepr rG k) = cfRepr rG *+ k. Proof. by rewrite cfRepr_dsum /= sumr_const card_ord. Qed. Section StandardRepr. Variables (n : nat) (rG : mx_representation algCF G n). Let sG := DecSocleType rG. Let iG : irrType algCF G := DecSocleType _. Definition standard_irr (W : sG) := irr_comp iG (socle_repr W). Definition standard_socle i := pick [pred W | standard_irr W == i]. Local Notation soc := standard_socle. Definition standard_irr_coef i := oapp (fun W => socle_mult W) 0%N (soc i). Definition standard_grepr := \big[dadd_grepr/grepr0]_i muln_grepr (Representation (socle_repr i)) (standard_irr_coef i). Lemma mx_rsim_standard : mx_rsim rG standard_grepr. Proof. pose W i := oapp val 0 (soc i); pose S := (\sum_i W i)%MS. have C'G: [char algC]^'.-group G := algC'G G. have [defS dxS]: (S :=: 1%:M)%MS /\ mxdirect S. rewrite /S mxdirectE /= !(bigID soc xpredT) /=. rewrite addsmxC big1 => [|i]; last by rewrite /W; case (soc i). rewrite adds0mx_id addnC (@big1 nat) ?add0n => [|i]; last first. by rewrite /W; case: (soc i); rewrite ?mxrank0. have <-: Socle sG = 1%:M := reducible_Socle1 sG (mx_Maschke rG C'G). have [W0 _ | noW] := pickP sG; last first. suff no_i: (soc : pred iG) =1 xpred0 by rewrite /Socle !big_pred0 ?mxrank0. by move=> i; rewrite /soc; case: pickP => // W0; have:= noW W0. have irrK Wi: soc (standard_irr Wi) = Some Wi. rewrite /soc; case: pickP => [W' | /(_ Wi)] /= /eqP // eqWi. apply/eqP/socle_rsimP. apply: mx_rsim_trans (rsim_irr_comp iG C'G (socle_irr _)) (mx_rsim_sym _). by rewrite [irr_comp _ _]eqWi; exact: rsim_irr_comp (socle_irr _). have bij_irr: {on [pred i | soc i], bijective standard_irr}. exists (odflt W0 \o soc) => [Wi _ | i]; first by rewrite /= irrK. by rewrite inE /soc /=; case: pickP => //= Wi; move/eqP. rewrite !(reindex standard_irr) {bij_irr}//=. have all_soc Wi: soc (standard_irr Wi) by rewrite irrK. rewrite (eq_bigr val) => [|Wi _]; last by rewrite /W irrK. rewrite !(eq_bigl _ _ all_soc); split=> //. rewrite (eq_bigr (mxrank \o val)) => [|Wi _]; last by rewrite /W irrK. by rewrite -mxdirectE /= Socle_direct. pose modW i : mxmodule rG (W i) := if soc i is Some Wi as oWi return mxmodule rG (oapp val 0 oWi) then component_mx_module rG (socle_base Wi) else mxmodule0 rG n. apply: mx_rsim_trans (mx_rsim_sym (rsim_submod1 (mxmodule1 rG) _)) _ => //. apply: mx_rsim_dsum (modW) _ defS dxS _ => i. rewrite /W /standard_irr_coef /modW /soc; case: pickP => [Wi|_] /=; last first. rewrite /muln_grepr big_ord0. by exists 0 => [||x _]; rewrite ?mxrank0 ?mulmx0 ?mul0mx. by move/eqP=> <-; apply: mx_rsim_socle; exact: rsim_irr_comp (socle_irr Wi). Qed. End StandardRepr. Definition cfReg (B : {set gT}) : 'CF(B) := #|B|%:R *: '1_[1]. Lemma cfRegE x : @cfReg G x = #|G|%:R *+ (x == 1%g). Proof. by rewrite cfunE cfuniE ?normal1 // inE mulr_natr. Qed. (* This is Isaacs, Lemma (2.10). *) Lemma cfReprReg : cfRepr (regular_repr algCF G) = cfReg G. Proof. apply/cfun_inP=> x Gx; rewrite cfRegE. have [-> | ntx] := altP (x =P 1%g); first by rewrite cfRepr1. rewrite cfunE Gx [\tr _]big1 // => i _; rewrite 2!mxE /=. rewrite -(inj_eq enum_val_inj) gring_indexK ?groupM ?enum_valP //. by rewrite eq_mulVg1 mulKg (negbTE ntx). Qed. Definition xcfun (chi : 'CF(G)) A := (gring_row A *m (\col_(i < #|G|) chi (enum_val i))) 0 0. Lemma xcfun_is_additive phi : additive (xcfun phi). Proof. by move=> A B; rewrite /xcfun linearB mulmxBl !mxE. Qed. Canonical xcfun_additive phi := Additive (xcfun_is_additive phi). Lemma xcfunZr a phi A : xcfun phi (a *: A) = a * xcfun phi A. Proof. by rewrite /xcfun linearZ -scalemxAl mxE. Qed. (* In order to add a second canonical structure on xcfun *) Definition xcfun_r_head k A phi := let: tt := k in xcfun phi A. Local Notation xcfun_r A := (xcfun_r_head tt A). Lemma xcfun_rE A chi : xcfun_r A chi = xcfun chi A. Proof. by []. Qed. Fact xcfun_r_is_additive A : additive (xcfun_r A). Proof. move=> phi psi; rewrite /= /xcfun !mxE -sumrB; apply: eq_bigr => i _. by rewrite !mxE !cfunE mulrBr. Qed. Canonical xcfun_r_additive A := Additive (xcfun_r_is_additive A). Lemma xcfunZl a phi A : xcfun (a *: phi) A = a * xcfun phi A. Proof. rewrite /xcfun !mxE big_distrr; apply: eq_bigr => i _ /=. by rewrite !mxE cfunE mulrCA. Qed. Lemma xcfun_repr n rG A : xcfun (@cfRepr n rG) A = \tr (gring_op rG A). Proof. rewrite gring_opE [gring_row A]row_sum_delta !linear_sum /xcfun !mxE. apply: eq_bigr => i _; rewrite !mxE /= !linearZ cfunE enum_valP /=. by congr (_ * \tr _) => {A} /=; rewrite /gring_mx /= -rowE rowK mxvecK. Qed. End Char. Notation xcfun_r A := (xcfun_r_head tt A). Notation "phi .[ A ]" := (xcfun phi A) : cfun_scope. Definition pred_Nirr gT B := #|@classes gT B|.-1. Arguments Scope pred_Nirr [_ group_scope]. Notation Nirr G := (pred_Nirr G).+1. Notation Iirr G := 'I_(Nirr G). Section IrrClassDef. Variables (gT : finGroupType) (G : {group gT}). Let sG := DecSocleType (regular_repr algCF G). Lemma NirrE : Nirr G = #|classes G|. Proof. by rewrite /pred_Nirr (cardD1 [1]) classes1. Qed. Fact Iirr_cast : Nirr G = #|sG|. Proof. by rewrite NirrE ?card_irr ?algC'G //; exact: groupC. Qed. Let offset := cast_ord (esym Iirr_cast) (enum_rank [1 sG]%irr). Definition socle_of_Iirr (i : Iirr G) : sG := enum_val (cast_ord Iirr_cast (i + offset)). Definition irr_of_socle (Wi : sG) : Iirr G := cast_ord (esym Iirr_cast) (enum_rank Wi) - offset. Local Notation W := socle_of_Iirr. Lemma socle_Iirr0 : W 0 = [1 sG]%irr. Proof. by rewrite /W add0r cast_ordKV enum_rankK. Qed. Lemma socle_of_IirrK : cancel W irr_of_socle. Proof. by move=> i; rewrite /irr_of_socle enum_valK cast_ordK addrK. Qed. Lemma irr_of_socleK : cancel irr_of_socle W. Proof. by move=> Wi; rewrite /W subrK cast_ordKV enum_rankK. Qed. Hint Resolve socle_of_IirrK irr_of_socleK. Lemma irr_of_socle_bij (A : pred (Iirr G)) : {on A, bijective irr_of_socle}. Proof. by apply: onW_bij; exists W. Qed. Lemma socle_of_Iirr_bij (A : pred sG) : {on A, bijective W}. Proof. by apply: onW_bij; exists irr_of_socle. Qed. End IrrClassDef. Prenex Implicits socle_of_IirrK irr_of_socleK. Arguments Scope socle_of_Iirr [_ ring_scope]. Notation "''Chi_' i" := (irr_repr (socle_of_Iirr i)) (at level 8, i at level 2, format "''Chi_' i"). Fact irr_key : unit. Proof. by []. Qed. Definition irr_def gT B : (Nirr B).-tuple 'CF(B) := let irr_of i := 'Res[B, <>] (@cfRepr gT _ _ 'Chi_(inord i)) in [tuple of mkseq irr_of (Nirr B)]. Definition irr := locked_with irr_key irr_def. Arguments Scope irr [_ group_scope]. Notation "''chi_' i" := (tnth (irr _) i%R) (at level 8, i at level 2, format "''chi_' i") : ring_scope. Notation "''chi[' G ]_ i" := (tnth (irr G) i%R) (at level 8, i at level 2, only parsing) : ring_scope. Section IrrClass. Variable (gT : finGroupType) (G : {group gT}). Implicit Types (i : Iirr G) (B : {set gT}). Open Scope group_ring_scope. Lemma congr_irr i1 i2 : i1 = i2 -> 'chi_i1 = 'chi_i2. Proof. by move->. Qed. Lemma Iirr1_neq0 : G :!=: 1%g -> inord 1 != 0 :> Iirr G. Proof. by rewrite -classes_gt1 -NirrE -val_eqE /= => /inordK->. Qed. Lemma has_nonprincipal_irr : G :!=: 1%g -> {i : Iirr G | i != 0}. Proof. by move/Iirr1_neq0; exists (inord 1). Qed. Lemma irrRepr i : cfRepr 'Chi_i = 'chi_i. Proof. rewrite [irr]unlock (tnth_nth 0) nth_mkseq // -[<>]/(gval _) genGidG. by rewrite cfRes_id inord_val. Qed. Lemma irr0 : 'chi[G]_0 = 1. Proof. apply/cfun_inP=> x Gx; rewrite -irrRepr cfun1E cfunE Gx. by rewrite socle_Iirr0 irr1_repr // mxtrace1 degree_irr1. Qed. Lemma cfun1_irr : 1 \in irr G. Proof. by rewrite -irr0 mem_tnth. Qed. Lemma mem_irr i : 'chi_i \in irr G. Proof. exact: mem_tnth. Qed. Lemma irrP xi : reflect (exists i, xi = 'chi_i) (xi \in irr G). Proof. apply: (iffP idP) => [/(nthP 0)[i] | [i ->]]; last exact: mem_irr. rewrite size_tuple => lt_i_G <-. by exists (Ordinal lt_i_G); rewrite (tnth_nth 0). Qed. Let sG := DecSocleType (regular_repr algCF G). Let C'G := algC'G G. Let closG := @groupC _ G. Local Notation W i := (@socle_of_Iirr _ G i). Local Notation "''n_' i" := 'n_(W i). Local Notation "''R_' i" := 'R_(W i). Local Notation "''e_' i" := 'e_(W i). Lemma irr1_degree i : 'chi_i 1%g = ('n_i)%:R. Proof. by rewrite -irrRepr cfRepr1. Qed. Lemma Cnat_irr1 i : 'chi_i 1%g \in Cnat. Proof. by rewrite irr1_degree rpred_nat. Qed. Lemma irr1_gt0 i : 0 < 'chi_i 1%g. Proof. by rewrite irr1_degree ltr0n irr_degree_gt0. Qed. Lemma irr1_neq0 i : 'chi_i 1%g != 0. Proof. by rewrite eqr_le ltr_geF ?irr1_gt0. Qed. Lemma irr_neq0 i : 'chi_i != 0. Proof. by apply: contraNneq (irr1_neq0 i) => ->; rewrite cfunE. Qed. Definition cfIirr B (chi : 'CF(B)) : Iirr B := inord (index chi (irr B)). Lemma cfIirrE chi : chi \in irr G -> 'chi_(cfIirr chi) = chi. Proof. move=> chi_irr; rewrite (tnth_nth 0) inordK ?nth_index //. by rewrite -index_mem size_tuple in chi_irr. Qed. Lemma cfIirrPE J (f : J -> 'CF(G)) (P : pred J) : (forall j, P j -> f j \in irr G) -> forall j, P j -> 'chi_(cfIirr (f j)) = f j. Proof. by move=> irr_f j /irr_f; apply: cfIirrE. Qed. (* This is Isaacs, Corollary (2.7). *) Corollary irr_sum_square : \sum_i ('chi[G]_i 1%g) ^+ 2 = #|G|%:R. Proof. rewrite -(sum_irr_degree sG) // natr_sum (reindex _ (socle_of_Iirr_bij _)) /=. by apply: eq_bigr => i _; rewrite irr1_degree natrX. Qed. (* This is Isaacs, Lemma (2.11). *) Lemma cfReg_sum : cfReg G = \sum_i 'chi_i 1%g *: 'chi_i. Proof. apply/cfun_inP=> x Gx; rewrite -cfReprReg cfunE Gx (mxtrace_regular sG) //=. rewrite sum_cfunE (reindex _ (socle_of_Iirr_bij _)); apply: eq_bigr => i _. by rewrite -irrRepr cfRepr1 !cfunE Gx mulr_natl. Qed. Let aG := regular_repr algCF G. Let R_G := group_ring algCF G. Lemma xcfun_annihilate i j A : i != j -> (A \in 'R_j)%MS -> ('chi_i).[A]%CF = 0. Proof. move=> neq_ij RjA; rewrite -irrRepr xcfun_repr. by rewrite (irr_repr'_op0 _ _ RjA) ?raddf0 // eq_sym (can_eq socle_of_IirrK). Qed. Lemma xcfunG phi x : x \in G -> phi.[aG x]%CF = phi x. Proof. by move=> Gx; rewrite /xcfun /gring_row rowK -rowE !mxE !(gring_indexK, mul1g). Qed. Lemma xcfun_mul_id i A : (A \in R_G)%MS -> ('chi_i).['e_i *m A]%CF = ('chi_i).[A]%CF. Proof. move=> RG_A; rewrite -irrRepr !xcfun_repr gring_opM //. by rewrite op_Wedderburn_id ?mul1mx. Qed. Lemma xcfun_id i j : ('chi_i).['e_j]%CF = 'chi_i 1%g *+ (i == j). Proof. have [<-{j} | /xcfun_annihilate->//] := altP eqP; last exact: Wedderburn_id_mem. by rewrite -xcfunG // repr_mx1 -(xcfun_mul_id _ (envelop_mx1 _)) mulmx1. Qed. Lemma irr_free : free (irr G). Proof. apply/freeP=> s s0 i; apply: (mulIf (irr1_neq0 i)). rewrite mul0r -(raddf0 (xcfun_r_additive 'e_i)) -{}s0 raddf_sum /=. rewrite (bigD1 i) //= -tnth_nth xcfunZl xcfun_id eqxx big1 ?addr0 // => j ne_ji. by rewrite -tnth_nth xcfunZl xcfun_id (negbTE ne_ji) mulr0. Qed. Lemma irr_inj : injective (tnth (irr G)). Proof. by apply/injectiveP/free_uniq; rewrite map_tnth_enum irr_free. Qed. Lemma irrK : cancel (tnth (irr G)) (@cfIirr G). Proof. by move=> i; apply: irr_inj; rewrite cfIirrE ?mem_irr. Qed. Lemma irr_eq1 i : ('chi_i == 1) = (i == 0). Proof. by rewrite -irr0 (inj_eq irr_inj). Qed. Lemma cforder_irr_eq1 i : (#['chi_i]%CF == 1%N) = (i == 0). Proof. by rewrite -dvdn1 dvdn_cforder irr_eq1. Qed. Lemma irr_basis : basis_of 'CF(G)%VS (irr G). Proof. rewrite /basis_of irr_free andbT -dimv_leqif_eq ?subvf //. by rewrite dim_cfun (eqnP irr_free) size_tuple NirrE. Qed. Lemma eq_sum_nth_irr a : \sum_i a i *: 'chi[G]_i = \sum_i a i *: (irr G)`_i. Proof. by apply: eq_bigr => i; rewrite -tnth_nth. Qed. (* This is Isaacs, Theorem (2.8). *) Theorem cfun_irr_sum phi : {a | phi = \sum_i a i *: 'chi[G]_i}. Proof. rewrite (coord_basis irr_basis (memvf phi)) -eq_sum_nth_irr. by exists ((coord (irr G))^~ phi). Qed. Lemma cfRepr_standard n (rG : mx_representation algCF G n) : cfRepr (standard_grepr rG) = \sum_i (standard_irr_coef rG (W i))%:R *: 'chi_i. Proof. rewrite cfRepr_dsum (reindex _ (socle_of_Iirr_bij _)). by apply: eq_bigr => i _; rewrite scaler_nat cfRepr_muln irrRepr. Qed. Lemma cfRepr_inj n1 n2 rG1 rG2 : @cfRepr _ G n1 rG1 = @cfRepr _ G n2 rG2 -> mx_rsim rG1 rG2. Proof. move=> eq_repr12; pose c i : algC := (standard_irr_coef _ (W i))%:R. have [rsim1 rsim2] := (mx_rsim_standard rG1, mx_rsim_standard rG2). apply: mx_rsim_trans (rsim1) (mx_rsim_sym _). suffices ->: standard_grepr rG1 = standard_grepr rG2 by []. apply: eq_bigr => Wi _; congr (muln_grepr _ _); apply/eqP; rewrite -eqC_nat. rewrite -[Wi]irr_of_socleK -!/(c _ _ _) -!(coord_sum_free (c _ _) _ irr_free). rewrite -!eq_sum_nth_irr -!cfRepr_standard. by rewrite -(cfRepr_sim rsim1) -(cfRepr_sim rsim2) eq_repr12. Qed. Lemma cfRepr_rsimP n1 n2 rG1 rG2 : reflect (mx_rsim rG1 rG2) (@cfRepr _ G n1 rG1 == @cfRepr _ G n2 rG2). Proof. by apply: (iffP eqP) => [/cfRepr_inj | /cfRepr_sim]. Qed. Lemma irr_reprP xi : reflect (exists2 rG : representation _ G, mx_irreducible rG & xi = cfRepr rG) (xi \in irr G). Proof. apply: (iffP (irrP xi)) => [[i ->] | [[n rG] irr_rG ->]]. by exists (Representation 'Chi_i); [exact: socle_irr | rewrite irrRepr]. exists (irr_of_socle (irr_comp sG rG)); rewrite -irrRepr irr_of_socleK /=. exact/cfRepr_sim/rsim_irr_comp. Qed. (* This is Isaacs, Theorem (2.12). *) Lemma Wedderburn_id_expansion i : 'e_i = #|G|%:R^-1 *: \sum_(x in G) 'chi_i 1%g * 'chi_i x^-1%g *: aG x. Proof. have Rei: ('e_i \in 'R_i)%MS by exact: Wedderburn_id_mem. have /envelop_mxP[a def_e]: ('e_i \in R_G)%MS; last rewrite -/aG in def_e. by move: Rei; rewrite genmxE mem_sub_gring => /andP[]. apply: canRL (scalerK (neq0CG _)) _; rewrite def_e linear_sum /=. apply: eq_bigr => x Gx; have Gx' := groupVr Gx; rewrite scalerA; congr (_ *: _). transitivity (cfReg G).['e_i *m aG x^-1%g]%CF. rewrite def_e mulmx_suml raddf_sum (bigD1 x) //= -scalemxAl xcfunZr. rewrite -repr_mxM // mulgV xcfunG // cfRegE eqxx mulrC big1 ?addr0 //. move=> y /andP[Gy /negbTE neq_xy]; rewrite -scalemxAl xcfunZr -repr_mxM //. by rewrite xcfunG ?groupM // cfRegE -eq_mulgV1 neq_xy mulr0. rewrite cfReg_sum -xcfun_rE raddf_sum /= (bigD1 i) //= xcfunZl. rewrite xcfun_mul_id ?envelop_mx_id ?xcfunG ?groupV ?big1 ?addr0 // => j ne_ji. rewrite xcfunZl (xcfun_annihilate ne_ji) ?mulr0 //. have /andP[_ /(submx_trans _)-> //] := Wedderburn_ideal (W i). by rewrite mem_mulsmx // envelop_mx_id ?groupV. Qed. End IrrClass. Arguments Scope cfReg [_ group_scope]. Prenex Implicits cfIirr. Implicit Arguments irr_inj [[gT] [G] x1 x2]. Section IsChar. Variable gT : finGroupType. Definition character {G : {set gT}} := [qualify a phi : 'CF(G) | [forall i, coord (irr G) i phi \in Cnat]]. Fact character_key G : pred_key (@character G). Proof. by []. Qed. Canonical character_keyed G := KeyedQualifier (character_key G). Variable G : {group gT}. Implicit Types (phi chi xi : 'CF(G)) (i : Iirr G). Lemma irr_char i : 'chi_i \is a character. Proof. by apply/forallP=> j; rewrite (tnth_nth 0) coord_free ?irr_free ?isNatC_nat. Qed. Lemma cfun1_char : (1 : 'CF(G)) \is a character. Proof. by rewrite -irr0 irr_char. Qed. Lemma cfun0_char : (0 : 'CF(G)) \is a character. Proof. by apply/forallP=> i; rewrite linear0 rpred0. Qed. Fact add_char : addr_closed (@character G). Proof. split=> [|chi xi /forallP-Nchi /forallP-Nxi]; first exact: cfun0_char. by apply/forallP=> i; rewrite linearD rpredD /=. Qed. Canonical character_addrPred := AddrPred add_char. Lemma char_sum_irrP {phi} : reflect (exists n, phi = \sum_i (n i)%:R *: 'chi_i) (phi \is a character). Proof. apply: (iffP idP)=> [/forallP-Nphi | [n ->]]; last first. by apply: rpred_sum => i _; rewrite scaler_nat rpredMn // irr_char. do [have [a ->] := cfun_irr_sum phi] in Nphi *; exists (truncC \o a). apply: eq_bigr => i _; congr (_ *: _); have:= eqP (Nphi i). by rewrite eq_sum_nth_irr coord_sum_free ?irr_free. Qed. Lemma char_sum_irr chi : chi \is a character -> {r | chi = \sum_(i <- r) 'chi_i}. Proof. move=> Nchi; apply: sig_eqW; case/char_sum_irrP: Nchi => n {chi}->. elim/big_rec: _ => [|i _ _ [r ->]]; first by exists nil; rewrite big_nil. exists (ncons (n i) i r); rewrite scaler_nat. by elim: {n}(n i) => [|n IHn]; rewrite ?add0r //= big_cons mulrS -addrA IHn. Qed. Lemma Cnat_char1 chi : chi \is a character -> chi 1%g \in Cnat. Proof. case/char_sum_irr=> r ->{chi}. by elim/big_rec: _ => [|i chi _ Nchi1]; rewrite cfunE ?rpredD // Cnat_irr1. Qed. Lemma char1_ge0 chi : chi \is a character -> 0 <= chi 1%g. Proof. by move/Cnat_char1/Cnat_ge0. Qed. Lemma char1_eq0 chi : chi \is a character -> (chi 1%g == 0) = (chi == 0). Proof. case/char_sum_irr=> r ->; apply/idP/idP=> [|/eqP->]; last by rewrite cfunE. case: r => [|i r]; rewrite ?big_nil // sum_cfunE big_cons. rewrite paddr_eq0 ?sumr_ge0 => // [||j _]; rewrite 1?ltrW ?irr1_gt0 //. by rewrite (negbTE (irr1_neq0 i)). Qed. Lemma char1_gt0 chi : chi \is a character -> (0 < chi 1%g) = (chi != 0). Proof. by move=> Nchi; rewrite -char1_eq0 // Cnat_gt0 ?Cnat_char1. Qed. Lemma char_reprP phi : reflect (exists rG : representation algCF G, phi = cfRepr rG) (phi \is a character). Proof. apply: (iffP char_sum_irrP) => [[n ->] | [[n rG] ->]]; last first. exists (fun i => standard_irr_coef rG (socle_of_Iirr i)). by rewrite -cfRepr_standard (cfRepr_sim (mx_rsim_standard rG)). exists (\big[dadd_grepr/grepr0]_i muln_grepr (Representation 'Chi_i) (n i)). rewrite cfRepr_dsum; apply: eq_bigr => i _. by rewrite cfRepr_muln irrRepr scaler_nat. Qed. Local Notation reprG := (mx_representation algCF G). Lemma cfRepr_char n (rG : reprG n) : cfRepr rG \is a character. Proof. by apply/char_reprP; exists (Representation rG). Qed. Lemma cfReg_char : cfReg G \is a character. Proof. by rewrite -cfReprReg cfRepr_char. Qed. Lemma cfRepr_prod n1 n2 (rG1 : reprG n1) (rG2 : reprG n2) : cfRepr rG1 * cfRepr rG2 = cfRepr (prod_repr rG1 rG2). Proof. by apply/cfun_inP=> x Gx; rewrite !cfunE /= Gx mxtrace_prod. Qed. Lemma mul_char : mulr_closed (@character G). Proof. split=> [|_ _ /char_reprP[rG1 ->] /char_reprP[rG2 ->]]; first exact: cfun1_char. apply/char_reprP; exists (Representation (prod_repr rG1 rG2)). by rewrite cfRepr_prod. Qed. Canonical char_mulrPred := MulrPred mul_char. Canonical char_semiringPred := SemiringPred mul_char. End IsChar. Prenex Implicits character. Implicit Arguments char_reprP [gT G phi]. Section AutChar. Variables (gT : finGroupType) (G : {group gT}). Implicit Type u : {rmorphism algC -> algC}. Lemma cfRepr_map u n (rG : mx_representation algCF G n) : cfRepr (map_repr u rG) = cfAut u (cfRepr rG). Proof. by apply/cfun_inP=> x Gx; rewrite !cfunE Gx map_reprE trace_map_mx. Qed. Lemma cfAut_char u (chi : 'CF(G)) : chi \is a character -> cfAut u chi \is a character. Proof. case/char_reprP=> rG ->; apply/char_reprP. by exists (Representation (map_repr u rG)); rewrite cfRepr_map. Qed. Lemma cfConjC_char (chi : 'CF(G)) : chi \is a character -> chi^*%CF \is a character. Proof. exact: cfAut_char. Qed. Lemma cfAut_char1 u (chi : 'CF(G)) : chi \is a character -> cfAut u chi 1%g = chi 1%g. Proof. by move/Cnat_char1=> Nchi1; rewrite cfunE aut_Cnat. Qed. Lemma cfAut_irr1 u i : (cfAut u 'chi[G]_i) 1%g = 'chi_i 1%g. Proof. exact: cfAut_char1 (irr_char i). Qed. Lemma cfConjC_char1 (chi : 'CF(G)) : chi \is a character -> chi^*%CF 1%g = chi 1%g. Proof. exact: cfAut_char1. Qed. Lemma cfConjC_irr1 u i : ('chi[G]_i)^*%CF 1%g = 'chi_i 1%g. Proof. exact: cfAut_irr1. Qed. End AutChar. Section Linear. Variables (gT : finGroupType) (G : {group gT}). Definition linear_char {B : {set gT}} := [qualify a phi : 'CF(B) | (phi \is a character) && (phi 1%g == 1)]. Section OneChar. Variable xi : 'CF(G). Hypothesis CFxi : xi \is a linear_char. Lemma lin_char1: xi 1%g = 1. Proof. by case/andP: CFxi => _ /eqP. Qed. Lemma lin_charW : xi \is a character. Proof. by case/andP: CFxi. Qed. Lemma cfun1_lin_char : (1 : 'CF(G)) \is a linear_char. Proof. by rewrite qualifE cfun1_char /= cfun11. Qed. Lemma lin_charM : {in G &, {morph xi : x y / (x * y)%g >-> x * y}}. Proof. move=> x y Gx Gy; case/andP: CFxi => /char_reprP[[n rG] -> /=]. rewrite cfRepr1 pnatr_eq1 => /eqP n1; rewrite {n}n1 in rG *. rewrite !cfunE Gx Gy groupM //= !mulr1n repr_mxM //. by rewrite [rG x]mx11_scalar [rG y]mx11_scalar -scalar_mxM !mxtrace_scalar. Qed. Lemma lin_char_prod I r (P : pred I) (x : I -> gT) : (forall i, P i -> x i \in G) -> xi (\prod_(i <- r | P i) x i)%g = \prod_(i <- r | P i) xi (x i). Proof. move=> Gx; elim/(big_load (fun y => y \in G)): _. elim/big_rec2: _ => [|i a y Pi [Gy <-]]; first by rewrite lin_char1. by rewrite groupM ?lin_charM ?Gx. Qed. Let xiMV x : x \in G -> xi x * xi (x^-1)%g = 1. Proof. by move=> Gx; rewrite -lin_charM ?groupV // mulgV lin_char1. Qed. Lemma lin_char_neq0 x : x \in G -> xi x != 0. Proof. by move/xiMV/(congr1 (predC1 0)); rewrite /= oner_eq0 mulf_eq0 => /norP[]. Qed. Lemma lin_charV x : x \in G -> xi x^-1%g = (xi x)^-1. Proof. by move=> Gx; rewrite -[_^-1]mulr1 -(xiMV Gx) mulKf ?lin_char_neq0. Qed. Lemma lin_charX x n : x \in G -> xi (x ^+ n)%g = xi x ^+ n. Proof. move=> Gx; elim: n => [|n IHn]; first exact: lin_char1. by rewrite expgS exprS lin_charM ?groupX ?IHn. Qed. Lemma lin_char_unity_root x : x \in G -> xi x ^+ #[x] = 1. Proof. by move=> Gx; rewrite -lin_charX // expg_order lin_char1. Qed. Lemma normC_lin_char x : x \in G -> `|xi x| = 1. Proof. move=> Gx; apply/eqP; rewrite -(@pexpr_eq1 _ _ #[x]) ?normr_ge0 //. by rewrite -normrX // lin_char_unity_root ?normr1. Qed. Lemma lin_charV_conj x : x \in G -> xi x^-1%g = (xi x)^*. Proof. move=> Gx; rewrite lin_charV // invC_norm mulrC normC_lin_char //. by rewrite expr1n divr1. Qed. Lemma lin_char_irr : xi \in irr G. Proof. case/andP: CFxi => /char_reprP[rG ->]; rewrite cfRepr1 pnatr_eq1 => /eqP n1. by apply/irr_reprP; exists rG => //; exact/mx_abs_irrW/linear_mx_abs_irr. Qed. Lemma mul_conjC_lin_char : xi * xi^*%CF = 1. Proof. apply/cfun_inP=> x Gx. by rewrite !cfunE cfun1E Gx -normCK normC_lin_char ?expr1n. Qed. Lemma lin_char_unitr : xi \in GRing.unit. Proof. by apply/unitrPr; exists xi^*%CF; apply: mul_conjC_lin_char. Qed. Lemma invr_lin_char : xi^-1 = xi^*%CF. Proof. by rewrite -[_^-1]mulr1 -mul_conjC_lin_char mulKr ?lin_char_unitr. Qed. Lemma cfAut_lin_char u : cfAut u xi \is a linear_char. Proof. by rewrite qualifE cfunE lin_char1 rmorph1 cfAut_char ?lin_charW /=. Qed. Lemma cfConjC_lin_char : xi^*%CF \is a linear_char. Proof. exact: cfAut_lin_char. Qed. Lemma fful_lin_char_inj : cfaithful xi -> {in G &, injective xi}. Proof. move=> fful_phi x y Gx Gy xi_xy; apply/eqP; rewrite eq_mulgV1 -in_set1. rewrite (subsetP fful_phi) // inE groupM ?groupV //=; apply/forallP=> z. have [Gz | G'z] := boolP (z \in G); last by rewrite !cfun0 ?groupMl ?groupV. by rewrite -mulgA lin_charM ?xi_xy -?lin_charM ?groupM ?groupV // mulKVg. Qed. End OneChar. Lemma card_Iirr_abelian : abelian G -> #|Iirr G| = #|G|. Proof. by rewrite card_ord NirrE card_classes_abelian => /eqP. Qed. Lemma card_Iirr_cyclic : cyclic G -> #|Iirr G| = #|G|. Proof. by move/cyclic_abelian/card_Iirr_abelian. Qed. Lemma char_abelianP : reflect (forall i : Iirr G, 'chi_i \is a linear_char) (abelian G). Proof. apply: (iffP idP) => [cGG i | CF_G]. rewrite qualifE irr_char /= irr1_degree. by rewrite irr_degree_abelian //; last exact: groupC. rewrite card_classes_abelian -NirrE -eqC_nat -irr_sum_square //. rewrite -{1}[Nirr G]card_ord -sumr_const; apply/eqP/eq_bigr=> i _. by rewrite lin_char1 ?expr1n ?CF_G. Qed. Lemma irr_repr_lin_char (i : Iirr G) x : x \in G -> 'chi_i \is a linear_char -> irr_repr (socle_of_Iirr i) x = ('chi_i x)%:M. Proof. move=> Gx CFi; rewrite -irrRepr cfunE Gx. move: (_ x); rewrite -[irr_degree _]natCK -irr1_degree lin_char1 //. by rewrite (natCK 1) => A; rewrite trace_mx11 -mx11_scalar. Qed. Fact linear_char_key B : pred_key (@linear_char B). Proof. by []. Qed. Canonical linear_char_keted B := KeyedQualifier (linear_char_key B). Fact linear_char_divr : divr_closed (@linear_char G). Proof. split=> [|chi xi Lchi Lxi]; first exact: cfun1_lin_char. rewrite invr_lin_char // qualifE cfunE. by rewrite rpredM ?lin_char1 ?mulr1 ?lin_charW //= cfConjC_lin_char. Qed. Canonical lin_char_mulrPred := MulrPred linear_char_divr. Canonical lin_char_divrPred := DivrPred linear_char_divr. Lemma irr_cyclic_lin i : cyclic G -> 'chi[G]_i \is a linear_char. Proof. by move/cyclic_abelian/char_abelianP. Qed. Lemma irr_prime_lin i : prime #|G| -> 'chi[G]_i \is a linear_char. Proof. by move/prime_cyclic/irr_cyclic_lin. Qed. End Linear. Prenex Implicits linear_char. Section Restrict. Variable (gT : finGroupType) (G H : {group gT}). Lemma cfRepr_sub n (rG : mx_representation algCF G n) (sHG : H \subset G) : cfRepr (subg_repr rG sHG) = 'Res[H] (cfRepr rG). Proof. by apply/cfun_inP => x Hx; rewrite cfResE // !cfunE Hx (subsetP sHG). Qed. Lemma cfRes_char chi : chi \is a character -> 'Res[H, G] chi \is a character. Proof. have [sHG | not_sHG] := boolP (H \subset G). by case/char_reprP=> rG ->; rewrite -(cfRepr_sub rG sHG) cfRepr_char. by move/Cnat_char1=> Nchi1; rewrite cfResEout // rpredZ_Cnat ?rpred1. Qed. Lemma cfRes_eq0 phi : phi \is a character -> ('Res[H, G] phi == 0) = (phi == 0). Proof. by move=> Nchi; rewrite -!char1_eq0 ?cfRes_char // cfRes1. Qed. Lemma cfRes_lin_char chi : chi \is a linear_char -> 'Res[H, G] chi \is a linear_char. Proof. by case/andP=> Nchi; rewrite qualifE cfRes_char ?cfRes1. Qed. Lemma Res_irr_neq0 i : 'Res[H, G] 'chi_i != 0. Proof. by rewrite cfRes_eq0 ?irr_neq0 ?irr_char. Qed. Lemma cfRes_lin_lin (chi : 'CF(G)) : chi \is a character -> 'Res[H] chi \is a linear_char -> chi \is a linear_char. Proof. by rewrite !qualifE cfRes1 => -> /andP[]. Qed. Lemma cfRes_irr_irr chi : chi \is a character -> 'Res[H] chi \in irr H -> chi \in irr G. Proof. have [sHG /char_reprP[rG ->] | not_sHG Nchi] := boolP (H \subset G). rewrite -(cfRepr_sub _ sHG) => /irr_reprP[rH irrH def_rH]; apply/irr_reprP. suffices /subg_mx_irr: mx_irreducible (subg_repr rG sHG) by exists rG. by apply: mx_rsim_irr irrH; exact/cfRepr_rsimP/eqP. rewrite cfResEout // => /irrP[j Dchi_j]; apply/lin_char_irr/cfRes_lin_lin=> //. suffices j0: j = 0 by rewrite cfResEout // Dchi_j j0 irr0 rpred1. apply: contraNeq (irr1_neq0 j) => nz_j. have:= xcfun_id j 0; rewrite -Dchi_j cfunE xcfunZl -irr0 xcfun_id eqxx => ->. by rewrite (negPf nz_j). Qed. Definition Res_Iirr (A B : {set gT}) i := cfIirr ('Res[B, A] 'chi_i). Lemma Res_Iirr0 : Res_Iirr H (0 : Iirr G) = 0. Proof. by rewrite /Res_Iirr irr0 rmorph1 -irr0 irrK. Qed. Lemma lin_Res_IirrE i : 'chi[G]_i 1%g = 1 -> 'chi_(Res_Iirr H i) = 'Res 'chi_i. Proof. move=> chi1; rewrite cfIirrE ?lin_char_irr ?cfRes_lin_char //. by rewrite qualifE irr_char /= chi1. Qed. End Restrict. Arguments Scope Res_Iirr [_ group_scope group_scope ring_scope]. Section Morphim. Variables (aT rT : finGroupType) (G D : {group aT}) (f : {morphism D >-> rT}). Implicit Type chi : 'CF(f @* G). Lemma cfRepr_morphim n (rfG : mx_representation algCF (f @* G) n) sGD : cfRepr (morphim_repr rfG sGD) = cfMorph (cfRepr rfG). Proof. apply/cfun_inP=> x Gx; have Dx: x \in D := subsetP sGD x Gx. by rewrite cfMorphE // !cfunE ?mem_morphim ?Gx. Qed. Lemma cfMorph_char chi : chi \is a character -> cfMorph chi \is a character. Proof. have [sGD /char_reprP[rG ->] | outGD Nchi] := boolP (G \subset D); last first. by rewrite cfMorphEout // rpredZ_Cnat ?rpred1 ?Cnat_char1. apply/char_reprP; exists (Representation (morphim_repr rG sGD)). by rewrite cfRepr_morphim. Qed. Lemma cfMorph_lin_char chi : chi \is a linear_char -> cfMorph chi \is a linear_char. Proof. by case/andP=> Nchi; rewrite qualifE cfMorph_char ?cfMorph1. Qed. Lemma cfMorph_irr chi : G \subset D -> chi \in irr (f @* G) -> cfMorph chi \in irr G. Proof. move=> sGD /irr_reprP[rG irrG ->]; apply/irr_reprP. exists (Representation (morphim_repr rG sGD)); first exact/morphim_mx_irr. apply/cfun_inP=> x Gx; rewrite !cfunElock /= sGD Gx. by rewrite mem_morphim ?(subsetP sGD). Qed. Definition morph_Iirr i := cfIirr (cfMorph 'chi[f @* G]_i). Lemma morph_Iirr0 : morph_Iirr 0 = 0. Proof. by rewrite /morph_Iirr irr0 rmorph1 -irr0 irrK. Qed. Hypothesis sGD : G \subset D. Lemma morph_IirrE i : 'chi_(morph_Iirr i) = cfMorph 'chi_i. Proof. by rewrite cfIirrE ?cfMorph_irr ?mem_irr. Qed. Lemma morph_Iirr_inj : injective morph_Iirr. Proof. by move=> i j eq_ij; apply/irr_inj/cfMorph_inj; rewrite // -!morph_IirrE eq_ij. Qed. Lemma morph_Iirr_eq0 i : (morph_Iirr i == 0) = (i == 0). Proof. by rewrite -!irr_eq1 morph_IirrE cfMorph_eq1. Qed. End Morphim. Section Isom. Variables (aT rT : finGroupType) (G : {group aT}) (f : {morphism G >-> rT}). Variables (R : {group rT}) (isoGR : isom G R f). Implicit Type chi : 'CF(G). Lemma cfIsom_char chi : chi \is a character -> cfIsom isoGR chi \is a character. Proof. by move=> Nchi; rewrite [cfIsom _]locked_withE cfMorph_char ?cfRes_char. Qed. Lemma cfIsom_lin_char chi : chi \is a linear_char -> cfIsom isoGR chi \is a linear_char. Proof. by case/andP=> Nchi; rewrite qualifE cfIsom_char ?cfIsom1. Qed. Lemma cfIsom_irr chi : chi \in irr G -> cfIsom isoGR chi \in irr R. Proof. move=> irr_chi; rewrite [cfIsom _]locked_withE cfMorph_irr //. by rewrite (isom_im (isom_sym isoGR)) cfRes_id. Qed. Definition isom_Iirr i := cfIirr (cfIsom isoGR 'chi_i). Lemma isom_IirrE i : 'chi_(isom_Iirr i) = cfIsom isoGR 'chi_i. Proof. by rewrite cfIirrE ?cfIsom_irr ?mem_irr. Qed. Lemma isom_Iirr_inj : injective isom_Iirr. Proof. by move=> i j eqij; apply/irr_inj/(cfIsom_inj isoGR); rewrite -!isom_IirrE eqij. Qed. Lemma isom_Iirr_eq0 i : (isom_Iirr i == 0) = (i == 0). Proof. by rewrite -!irr_eq1 isom_IirrE cfIsom_eq1. Qed. Lemma isom_Iirr0 : isom_Iirr 0 = 0. Proof. by apply/eqP; rewrite isom_Iirr_eq0. Qed. End Isom. Implicit Arguments isom_Iirr_inj [aT rT G f R x1 x2]. Section IsomInv. Variables (aT rT : finGroupType) (G : {group aT}) (f : {morphism G >-> rT}). Variables (R : {group rT}) (isoGR : isom G R f). Lemma isom_IirrK : cancel (isom_Iirr isoGR) (isom_Iirr (isom_sym isoGR)). Proof. by move=> i; apply: irr_inj; rewrite !isom_IirrE cfIsomK. Qed. Lemma isom_IirrKV : cancel (isom_Iirr (isom_sym isoGR)) (isom_Iirr isoGR). Proof. by move=> i; apply: irr_inj; rewrite !isom_IirrE cfIsomKV. Qed. End IsomInv. Section OrthogonalityRelations. Variables aT gT : finGroupType. (* This is Isaacs, Lemma (2.15) *) Lemma repr_rsim_diag (G : {group gT}) f (rG : mx_representation algCF G f) x : x \in G -> let chi := cfRepr rG in exists e, [/\ (*a*) exists2 B, B \in unitmx & rG x = invmx B *m diag_mx e *m B, (*b*) (forall i, e 0 i ^+ #[x] = 1) /\ (forall i, `|e 0 i| = 1), (*c*) chi x = \sum_i e 0 i /\ `|chi x| <= chi 1%g & (*d*) chi x^-1%g = (chi x)^*]. Proof. move=> Gx; without loss cGG: G rG Gx / abelian G. have sXG: <[x]> \subset G by rewrite cycle_subG. move/(_ _ (subg_repr rG sXG) (cycle_id x) (cycle_abelian x)). by rewrite /= !cfunE !groupV Gx (cycle_id x) !group1. have [I U W simU W1 dxW]: mxsemisimple rG 1%:M. rewrite -(reducible_Socle1 (DecSocleType rG) (mx_Maschke _ (algC'G G))). exact: Socle_semisimple. have linU i: \rank (U i) = 1%N. by apply: mxsimple_abelian_linear cGG (simU i); exact: groupC. have castI: f = #|I|. by rewrite -(mxrank1 algCF f) -W1 (eqnP dxW) /= -sum1_card; exact/eq_bigr. pose B := \matrix_j nz_row (U (enum_val (cast_ord castI j))). have rowU i: (nz_row (U i) :=: U i)%MS. apply/eqmxP; rewrite -(geq_leqif (mxrank_leqif_eq (nz_row_sub _))) linU. by rewrite lt0n mxrank_eq0 (nz_row_mxsimple (simU i)). have unitB: B \in unitmx. rewrite -row_full_unit -sub1mx -W1; apply/sumsmx_subP=> i _. pose j := cast_ord (esym castI) (enum_rank i). by rewrite (submx_trans _ (row_sub j B)) // rowK cast_ordKV enum_rankK rowU. pose e := \row_j row j (B *m rG x *m invmx B) 0 j. have rGx: rG x = invmx B *m diag_mx e *m B. rewrite -mulmxA; apply: canRL (mulKmx unitB) _. apply/row_matrixP=> j; rewrite 2!row_mul; set u := row j B. have /sub_rVP[a def_ux]: (u *m rG x <= u)%MS. rewrite /u rowK rowU (eqmxMr _ (rowU _)). exact: (mxmoduleP (mxsimple_module (simU _))). rewrite def_ux [u]rowE scalemxAl; congr (_ *m _). apply/rowP=> k; rewrite 5!mxE !row_mul def_ux [u]rowE scalemxAl mulmxK //. by rewrite !mxE !eqxx !mulr_natr eq_sym. have exp_e j: e 0 j ^+ #[x] = 1. suffices: (diag_mx e j j) ^+ #[x] = (B *m rG (x ^+ #[x])%g *m invmx B) j j. by rewrite expg_order repr_mx1 mulmx1 mulmxV // [e]lock !mxE eqxx. elim: #[x] => [|n IHn]; first by rewrite repr_mx1 mulmx1 mulmxV // !mxE eqxx. rewrite expgS repr_mxM ?groupX // {1}rGx -!mulmxA mulKVmx //. by rewrite mul_diag_mx mulmxA [M in _ = M]mxE -IHn exprS {1}mxE eqxx. have norm1_e j: `|e 0 j| = 1. apply/eqP; rewrite -(@pexpr_eq1 _ _ #[x]) ?normr_ge0 //. by rewrite -normrX exp_e normr1. exists e; split=> //; first by exists B. rewrite cfRepr1 !cfunE Gx rGx mxtrace_mulC mulKVmx // mxtrace_diag. split=> //=; apply: (ler_trans (ler_norm_sum _ _ _)). by rewrite (eq_bigr _ (in1W norm1_e)) sumr_const card_ord lerr. rewrite !cfunE groupV !mulrb Gx rGx mxtrace_mulC mulKVmx //. rewrite -trace_map_mx map_diag_mx; set d' := diag_mx _. rewrite -[d'](mulKVmx unitB) mxtrace_mulC -[_ *m _](repr_mxK rG Gx) rGx. rewrite -!mulmxA mulKVmx // (mulmxA d'). suffices->: d' *m diag_mx e = 1%:M by rewrite mul1mx mulKmx. rewrite mulmx_diag -diag_const_mx; congr diag_mx; apply/rowP=> j. by rewrite [e]lock !mxE mulrC -normCK -lock norm1_e expr1n. Qed. Variables (A : {group aT}) (G : {group gT}). (* This is Isaacs, Lemma (2.15) (d). *) Lemma char_inv (chi : 'CF(G)) x : chi \is a character -> chi x^-1%g = (chi x)^*. Proof. case Gx: (x \in G); last by rewrite !cfun0 ?rmorph0 ?groupV ?Gx. by case/char_reprP=> rG ->; have [e [_ _ _]] := repr_rsim_diag rG Gx. Qed. Lemma irr_inv i x : 'chi[G]_i x^-1%g = ('chi_i x)^*. Proof. exact/char_inv/irr_char. Qed. (* This is Isaacs, Theorem (2.13). *) Theorem generalized_orthogonality_relation y (i j : Iirr G) : #|G|%:R^-1 * (\sum_(x in G) 'chi_i (x * y)%g * 'chi_j x^-1%g) = (i == j)%:R * ('chi_i y / 'chi_i 1%g). Proof. pose W := @socle_of_Iirr _ G; pose e k := Wedderburn_id (W k). pose aG := regular_repr algCF G. have [Gy | notGy] := boolP (y \in G); last first. rewrite cfun0 // mul0r big1 ?mulr0 // => x Gx. by rewrite cfun0 ?groupMl ?mul0r. transitivity (('chi_i).[e j *m aG y]%CF / 'chi_j 1%g). rewrite [e j]Wedderburn_id_expansion -scalemxAl xcfunZr -mulrA; congr (_ * _). rewrite mulmx_suml raddf_sum big_distrl; apply: eq_bigr => x Gx /=. rewrite -scalemxAl xcfunZr -repr_mxM // xcfunG ?groupM // mulrAC mulrC. by congr (_ * _); rewrite mulrC mulKf ?irr1_neq0. rewrite mulr_natl mulrb; have [<-{j} | neq_ij] := altP eqP. by congr (_ / _); rewrite xcfun_mul_id ?envelop_mx_id ?xcfunG. rewrite (xcfun_annihilate neq_ij) ?mul0r //. case/andP: (Wedderburn_ideal (W j)) => _; apply: submx_trans. by rewrite mem_mulsmx ?Wedderburn_id_mem ?envelop_mx_id. Qed. (* This is Isaacs, Corollary (2.14). *) Corollary first_orthogonality_relation (i j : Iirr G) : #|G|%:R^-1 * (\sum_(x in G) 'chi_i x * 'chi_j x^-1%g) = (i == j)%:R. Proof. have:= generalized_orthogonality_relation 1 i j. rewrite mulrA mulfK ?irr1_neq0 // => <-; congr (_ * _). by apply: eq_bigr => x; rewrite mulg1. Qed. (* The character table. *) Definition irr_class i := enum_val (cast_ord (NirrE G) i). Definition class_Iirr xG := cast_ord (esym (NirrE G)) (enum_rank_in (classes1 G) xG). Local Notation c := irr_class. Local Notation g i := (repr (c i)). Local Notation iC := class_Iirr. Definition character_table := \matrix_(i, j) 'chi[G]_i (g j). Local Notation X := character_table. Lemma irr_classP i : c i \in classes G. Proof. exact: enum_valP. Qed. Lemma repr_irr_classK i : g i ^: G = c i. Proof. by case/repr_classesP: (irr_classP i). Qed. Lemma irr_classK : cancel c iC. Proof. by move=> i; rewrite /iC enum_valK_in cast_ordK. Qed. Lemma class_IirrK : {in classes G, cancel iC c}. Proof. by move=> xG GxG; rewrite /c cast_ordKV enum_rankK_in. Qed. Lemma reindex_irr_class R idx (op : @Monoid.com_law R idx) F : \big[op/idx]_(xG in classes G) F xG = \big[op/idx]_i F (c i). Proof. rewrite (reindex c); first by apply: eq_bigl => i; exact: enum_valP. by exists iC; [apply: in1W; exact: irr_classK | exact: class_IirrK]. Qed. (* The explicit value of the inverse is needed for the proof of the second *) (* orthogonality relation. *) Let X' := \matrix_(i, j) (#|'C_G[g i]|%:R^-1 * ('chi[G]_j (g i))^*). Let XX'_1: X *m X' = 1%:M. Proof. apply/matrixP=> i j; rewrite !mxE -first_orthogonality_relation mulr_sumr. rewrite sum_by_classes => [|u v Gu Gv]; last by rewrite -conjVg !cfunJ. rewrite reindex_irr_class /=; apply/esym/eq_bigr=> k _. rewrite !mxE irr_inv // -/(g k) -divg_index -indexgI /=. rewrite (char0_natf_div Cchar) ?dvdn_indexg // index_cent1 invfM invrK. by rewrite repr_irr_classK mulrCA mulrA mulrCA. Qed. Lemma character_table_unit : X \in unitmx. Proof. by case/mulmx1_unit: XX'_1. Qed. Let uX := character_table_unit. (* This is Isaacs, Theorem (2.18). *) Theorem second_orthogonality_relation x y : y \in G -> \sum_i 'chi[G]_i x * ('chi_i y)^* = #|'C_G[x]|%:R *+ (x \in y ^: G). Proof. move=> Gy; pose i_x := iC (x ^: G); pose i_y := iC (y ^: G). have [Gx | notGx] := boolP (x \in G); last first. rewrite (contraNF (subsetP _ x) notGx) ?class_subG ?big1 // => i _. by rewrite cfun0 ?mul0r. transitivity ((#|'C_G[repr (y ^: G)]|%:R *: (X' *m X)) i_y i_x). rewrite scalemxAl !mxE; apply: eq_bigr => k _; rewrite !mxE mulrC -!mulrA. by rewrite !class_IirrK ?mem_classes // !cfun_repr mulVKf ?neq0CG. rewrite mulmx1C // !mxE -!divg_index !(index_cent1, =^~ indexgI). rewrite (class_transr (mem_repr y _)) ?class_refl // mulr_natr. rewrite (can_in_eq class_IirrK) ?mem_classes //. have [-> | not_yGx] := altP eqP; first by rewrite class_refl. by rewrite [x \in _](contraNF _ not_yGx) // => /class_transr->. Qed. Lemma eq_irr_mem_classP x y : y \in G -> reflect (forall i, 'chi[G]_i x = 'chi_i y) (x \in y ^: G). Proof. move=> Gy; apply: (iffP idP) => [/imsetP[z Gz ->] i | xGy]; first exact: cfunJ. have Gx: x \in G. congr is_true: Gy; apply/eqP; rewrite -(can_eq oddb) -eqC_nat -!cfun1E. by rewrite -irr0 xGy. congr is_true: (class_refl G x); apply/eqP; rewrite -(can_eq oddb). rewrite -(eqn_pmul2l (cardG_gt0 'C_G[x])) -eqC_nat !mulrnA; apply/eqP. by rewrite -!second_orthogonality_relation //; apply/eq_bigr=> i _; rewrite xGy. Qed. (* This is Isaacs, Theorem (6.32) (due to Brauer). *) Lemma card_afix_irr_classes (ito : action A (Iirr G)) (cto : action A _) a : a \in A -> [acts A, on classes G | cto] -> (forall i x y, x \in G -> y \in cto (x ^: G) a -> 'chi_i x = 'chi_(ito i a) y) -> #|'Fix_ito[a]| = #|'Fix_(classes G | cto)[a]|. Proof. move=> Aa actsAG stabAchi; apply/eqP; rewrite -eqC_nat; apply/eqP. have [[cP cK] iCK] := (irr_classP, irr_classK, class_IirrK). pose icto b i := iC (cto (c i) b). have Gca i: cto (c i) a \in classes G by rewrite (acts_act actsAG). have inj_qa: injective (icto a). by apply: can_inj (icto a^-1%g) _ => i; rewrite /icto iCK ?actKin ?cK. pose Pa : 'M[algC]_(Nirr G) := perm_mx (actperm ito a). pose qa := perm inj_qa; pose Qa : 'M[algC]_(Nirr G) := perm_mx qa^-1^-1%g. transitivity (\tr Pa). rewrite -sumr_const big_mkcond; apply: eq_bigr => i _. by rewrite !mxE permE inE sub1set inE; case: ifP. symmetry; transitivity (\tr Qa). rewrite cardsE -sumr_const -big_filter_cond big_mkcond big_filter /=. rewrite reindex_irr_class; apply: eq_bigr => i _; rewrite !mxE invgK permE. by rewrite inE sub1set inE -(can_eq cK) iCK //; case: ifP. rewrite -[Pa](mulmxK uX) -[Qa](mulKmx uX) mxtrace_mulC; congr (\tr(_ *m _)). rewrite -row_permE -col_permE; apply/matrixP=> i j; rewrite !mxE. rewrite -{2}[j](permKV qa); move: {j}(_ j) => j; rewrite !permE iCK //. apply: stabAchi; first by case/repr_classesP: (cP j). by rewrite repr_irr_classK (mem_repr_classes (Gca _)). Qed. End OrthogonalityRelations. Arguments Scope character_table [_ group_scope]. Section InnerProduct. Variable (gT : finGroupType) (G : {group gT}). Lemma cfdot_irr i j : '['chi_i, 'chi_j]_G = (i == j)%:R. Proof. rewrite -first_orthogonality_relation; congr (_ * _). by apply: eq_bigr => x Gx; rewrite irr_inv. Qed. Lemma cfnorm_irr i : '['chi[G]_i] = 1. Proof. by rewrite cfdot_irr eqxx. Qed. Lemma irr_orthonormal : orthonormal (irr G). Proof. apply/orthonormalP; split; first exact: free_uniq (irr_free G). move=> _ _ /irrP[i ->] /irrP[j ->]. by rewrite cfdot_irr (inj_eq (@irr_inj _ G)). Qed. Lemma coord_cfdot phi i : coord (irr G) i phi = '[phi, 'chi_i]. Proof. rewrite {2}(coord_basis (irr_basis G) (memvf phi)). rewrite cfdot_suml (bigD1 i) // cfdotZl /= -tnth_nth cfdot_irr eqxx mulr1. rewrite big1 ?addr0 // => j neq_ji; rewrite cfdotZl /= -tnth_nth cfdot_irr. by rewrite (negbTE neq_ji) mulr0. Qed. Lemma cfun_sum_cfdot phi : phi = \sum_i '[phi, 'chi_i]_G *: 'chi_i. Proof. rewrite {1}(coord_basis (irr_basis G) (memvf phi)). by apply: eq_bigr => i _; rewrite coord_cfdot -tnth_nth. Qed. Lemma cfdot_sum_irr phi psi : '[phi, psi]_G = \sum_i '[phi, 'chi_i] * '[psi, 'chi_i]^*. Proof. rewrite {1}[phi]cfun_sum_cfdot cfdot_suml; apply: eq_bigr => i _. by rewrite cfdotZl -cfdotC. Qed. Lemma Cnat_cfdot_char_irr i phi : phi \is a character -> '[phi, 'chi_i]_G \in Cnat. Proof. by move/forallP/(_ i); rewrite coord_cfdot. Qed. Lemma cfdot_char_r phi chi : chi \is a character -> '[phi, chi]_G = \sum_i '[phi, 'chi_i] * '[chi, 'chi_i]. Proof. move=> Nchi; rewrite cfdot_sum_irr; apply: eq_bigr => i _; congr (_ * _). by rewrite conj_Cnat ?Cnat_cfdot_char_irr. Qed. Lemma Cnat_cfdot_char chi xi : chi \is a character -> xi \is a character -> '[chi, xi]_G \in Cnat. Proof. move=> Nchi Nxi; rewrite cfdot_char_r ?rpred_sum // => i _. by rewrite rpredM ?Cnat_cfdot_char_irr. Qed. Lemma cfdotC_char chi xi : chi \is a character-> xi \is a character -> '[chi, xi]_G = '[xi, chi]. Proof. by move=> Nchi Nxi; rewrite cfdotC conj_Cnat ?Cnat_cfdot_char. Qed. Lemma irrEchar chi : (chi \in irr G) = (chi \is a character) && ('[chi] == 1). Proof. apply/irrP/andP=> [[i ->] | [Nchi]]; first by rewrite irr_char cfnorm_irr. rewrite cfdot_sum_irr => /eqP/Cnat_sum_eq1[i _| i [_ ci1 cj0]]. by rewrite rpredM // ?conj_Cnat ?Cnat_cfdot_char_irr. exists i; rewrite [chi]cfun_sum_cfdot (bigD1 i) //=. rewrite -(@normr_idP _ _ (@Cnat_ge0 _ (Cnat_cfdot_char_irr i Nchi))). rewrite normC_def {}ci1 sqrtC1 scale1r big1 ?addr0 // => j neq_ji. by rewrite (('[_] =P 0) _) ?scale0r // -normr_eq0 normC_def cj0 ?sqrtC0. Qed. Lemma irrWchar chi : chi \in irr G -> chi \is a character. Proof. by rewrite irrEchar => /andP[]. Qed. Lemma irrWnorm chi : chi \in irr G -> '[chi] = 1. Proof. by rewrite irrEchar => /andP[_ /eqP]. Qed. Lemma mul_lin_irr xi chi : xi \is a linear_char -> chi \in irr G -> xi * chi \in irr G. Proof. move=> Lxi; rewrite !irrEchar => /andP[Nphi /eqP <-]. rewrite rpredM // ?lin_charW //=; apply/eqP; congr (_ * _). apply: eq_bigr => x Gx; rewrite !cfunE rmorphM mulrACA -(lin_charV_conj Lxi) //. by rewrite -lin_charM ?groupV // mulgV lin_char1 ?mul1r. Qed. Lemma eq_scaled_irr a b i j : (a *: 'chi[G]_i == b *: 'chi_j) = (a == b) && ((a == 0) || (i == j)). Proof. apply/eqP/andP=> [|[/eqP-> /pred2P[]-> //]]; last by rewrite !scale0r. move/(congr1 (cfdotr 'chi__)) => /= eq_ai_bj. move: {eq_ai_bj}(eq_ai_bj i) (esym (eq_ai_bj j)); rewrite !cfdotZl !cfdot_irr. by rewrite !mulr_natr !mulrb !eqxx eq_sym orbC; case: ifP => _ -> //= ->. Qed. Lemma eq_signed_irr (s t : bool) i j : ((-1) ^+ s *: 'chi[G]_i == (-1) ^+ t *: 'chi_j) = (s == t) && (i == j). Proof. by rewrite eq_scaled_irr signr_eq0 (inj_eq (@signr_inj _)). Qed. Lemma eq_scale_irr a (i j : Iirr G) : (a *: 'chi_i == a *: 'chi_j) = (a == 0) || (i == j). Proof. by rewrite eq_scaled_irr eqxx. Qed. Lemma eq_addZ_irr a b (i j r t : Iirr G) : (a *: 'chi_i + b *: 'chi_j == a *: 'chi_r + b *: 'chi_t) = [|| [&& (a == 0) || (i == r) & (b == 0) || (j == t)], [&& i == t, j == r & a == b] | [&& i == j, r == t & a == - b]]. Proof. rewrite -!eq_scale_irr; apply/eqP/idP; last first. case/orP; first by case/andP=> /eqP-> /eqP->. case/orP=> /and3P[/eqP-> /eqP-> /eqP->]; first by rewrite addrC. by rewrite !scaleNr !addNr. have [-> /addrI/eqP-> // | /= ] := altP eqP. rewrite eq_scale_irr => /norP[/negP nz_a /negPf neq_ir]. move/(congr1 (cfdotr 'chi__))/esym/eqP => /= eq_cfdot. move: {eq_cfdot}(eq_cfdot i) (eq_cfdot r); rewrite eq_sym !cfdotDl !cfdotZl. rewrite !cfdot_irr !mulr_natr !mulrb !eqxx -!(eq_sym i) neq_ir !add0r. have [<- _ | _] := i =P t; first by rewrite neq_ir addr0; case: ifP => // _ ->. rewrite 2!fun_if if_arg addr0 addr_eq0; case: eqP => //= <- ->. by rewrite neq_ir 2!fun_if if_arg eq_sym addr0; case: ifP. Qed. Lemma eq_subZnat_irr (a b : nat) (i j r t : Iirr G) : (a%:R *: 'chi_i - b%:R *: 'chi_j == a%:R *: 'chi_r - b%:R *: 'chi_t) = [|| a == 0%N | i == r] && [|| b == 0%N | j == t] || [&& i == j, r == t & a == b]. Proof. rewrite -!scaleNr eq_addZ_irr oppr_eq0 opprK -addr_eq0 -natrD eqr_nat. by rewrite !pnatr_eq0 addn_eq0; case: a b => [|a] [|b]; rewrite ?andbF. Qed. End InnerProduct. Section Sdprod. Variables (gT : finGroupType) (K H G : {group gT}). Hypothesis defG : K ><| H = G. Lemma cfSdprod_char chi : chi \is a character -> cfSdprod defG chi \is a character. Proof. by move=> Nchi; rewrite unlock cfMorph_char ?cfIsom_char. Qed. Lemma cfSdprod_lin_char chi : chi \is a linear_char -> cfSdprod defG chi \is a linear_char. Proof. by move=> Nphi; rewrite unlock cfMorph_lin_char ?cfIsom_lin_char. Qed. Lemma cfSdprod_irr chi : chi \in irr H -> cfSdprod defG chi \in irr G. Proof. have [/andP[_ nKG] _ _ _ _] := sdprod_context defG. by move=> Nphi; rewrite unlock cfMorph_irr ?cfIsom_irr. Qed. Definition sdprod_Iirr j := cfIirr (cfSdprod defG 'chi_j). Lemma sdprod_IirrE j : 'chi_(sdprod_Iirr j) = cfSdprod defG 'chi_j. Proof. by rewrite cfIirrE ?cfSdprod_irr ?mem_irr. Qed. Lemma sdprod_IirrK : cancel sdprod_Iirr (Res_Iirr H). Proof. by move=> j; rewrite /Res_Iirr sdprod_IirrE cfSdprodK irrK. Qed. Lemma sdprod_Iirr_inj : injective sdprod_Iirr. Proof. exact: can_inj sdprod_IirrK. Qed. Lemma sdprod_Iirr_eq0 i : (sdprod_Iirr i == 0) = (i == 0). Proof. by rewrite -!irr_eq1 sdprod_IirrE cfSdprod_eq1. Qed. Lemma sdprod_Iirr0 : sdprod_Iirr 0 = 0. Proof. by apply/eqP; rewrite sdprod_Iirr_eq0. Qed. Lemma Res_sdprod_irr phi : K \subset cfker phi -> phi \in irr G -> 'Res phi \in irr H. Proof. move=> kerK /irrP[i Dphi]; rewrite irrEchar -(cfSdprod_iso defG). by rewrite cfRes_sdprodK // Dphi cfnorm_irr cfRes_char ?irr_char /=. Qed. Lemma sdprod_Res_IirrE i : K \subset cfker 'chi[G]_i -> 'chi_(Res_Iirr H i) = 'Res 'chi_i. Proof. by move=> kerK; rewrite cfIirrE ?Res_sdprod_irr ?mem_irr. Qed. Lemma sdprod_Res_IirrK i : K \subset cfker 'chi_i -> sdprod_Iirr (Res_Iirr H i) = i. Proof. by move=> kerK; rewrite /sdprod_Iirr sdprod_Res_IirrE ?cfRes_sdprodK ?irrK. Qed. End Sdprod. Implicit Arguments sdprod_Iirr_inj [gT K H G x1 x2]. Section DProd. Variables (gT : finGroupType) (G K H : {group gT}). Hypothesis KxH : K \x H = G. Lemma cfDprodKl_abelian j : abelian H -> cancel ((cfDprod KxH)^~ 'chi_j) 'Res. Proof. by move=> cHH; apply: cfDprodKl; apply/lin_char1/char_abelianP. Qed. Lemma cfDprodKr_abelian i : abelian K -> cancel (cfDprod KxH 'chi_i) 'Res. Proof. by move=> cKK; apply: cfDprodKr; apply/lin_char1/char_abelianP. Qed. Lemma cfDprodl_char phi : phi \is a character -> cfDprodl KxH phi \is a character. Proof. exact: cfSdprod_char. Qed. Lemma cfDprodr_char psi : psi \is a character -> cfDprodr KxH psi \is a character. Proof. exact: cfSdprod_char. Qed. Lemma cfDprod_char phi psi : phi \is a character -> psi \is a character -> cfDprod KxH phi psi \is a character. Proof. by move=> /cfDprodl_char Nphi /cfDprodr_char; apply: rpredM. Qed. Lemma cfDprod_eq1 phi psi : phi \is a character -> psi \is a character -> (cfDprod KxH phi psi == 1) = (phi == 1) && (psi == 1). Proof. move=> /Cnat_char1 Nphi /Cnat_char1 Npsi. apply/eqP/andP=> [phi_psi_1 | [/eqP-> /eqP->]]; last by rewrite cfDprod_cfun1. have /andP[/eqP phi1 /eqP psi1]: (phi 1%g == 1) && (psi 1%g == 1). by rewrite -Cnat_mul_eq1 // -(cfDprod1 KxH) phi_psi_1 cfun11. rewrite -[phi](cfDprodKl KxH psi1) -{2}[psi](cfDprodKr KxH phi1) phi_psi_1. by rewrite !rmorph1. Qed. Lemma cfDprodl_lin_char phi : phi \is a linear_char -> cfDprodl KxH phi \is a linear_char. Proof. exact: cfSdprod_lin_char. Qed. Lemma cfDprodr_lin_char psi : psi \is a linear_char -> cfDprodr KxH psi \is a linear_char. Proof. exact: cfSdprod_lin_char. Qed. Lemma cfDprod_lin_char phi psi : phi \is a linear_char -> psi \is a linear_char -> cfDprod KxH phi psi \is a linear_char. Proof. by move=> /cfDprodl_lin_char Lphi /cfDprodr_lin_char; apply: rpredM. Qed. Lemma cfDprodl_irr chi : chi \in irr K -> cfDprodl KxH chi \in irr G. Proof. exact: cfSdprod_irr. Qed. Lemma cfDprodr_irr chi : chi \in irr H -> cfDprodr KxH chi \in irr G. Proof. exact: cfSdprod_irr. Qed. Definition dprodl_Iirr i := cfIirr (cfDprodl KxH 'chi_i). Lemma dprodl_IirrE i : 'chi_(dprodl_Iirr i) = cfDprodl KxH 'chi_i. Proof. exact: sdprod_IirrE. Qed. Lemma dprodl_IirrK : cancel dprodl_Iirr (Res_Iirr K). Proof. exact: sdprod_IirrK. Qed. Lemma dprodl_Iirr_eq0 i : (dprodl_Iirr i == 0) = (i == 0). Proof. exact: sdprod_Iirr_eq0. Qed. Lemma dprodl_Iirr0 : dprodl_Iirr 0 = 0. Proof. exact: sdprod_Iirr0. Qed. Definition dprodr_Iirr j := cfIirr (cfDprodr KxH 'chi_j). Lemma dprodr_IirrE j : 'chi_(dprodr_Iirr j) = cfDprodr KxH 'chi_j. Proof. exact: sdprod_IirrE. Qed. Lemma dprodr_IirrK : cancel dprodr_Iirr (Res_Iirr H). Proof. exact: sdprod_IirrK. Qed. Lemma dprodr_Iirr_eq0 j : (dprodr_Iirr j == 0) = (j == 0). Proof. exact: sdprod_Iirr_eq0. Qed. Lemma dprodr_Iirr0 : dprodr_Iirr 0 = 0. Proof. exact: sdprod_Iirr0. Qed. Lemma cfDprod_irr i j : cfDprod KxH 'chi_i 'chi_j \in irr G. Proof. rewrite irrEchar cfDprod_char ?irr_char //=. by rewrite cfdot_dprod !cfdot_irr !eqxx mul1r. Qed. Definition dprod_Iirr ij := cfIirr (cfDprod KxH 'chi_ij.1 'chi_ij.2). Lemma dprod_IirrE i j : 'chi_(dprod_Iirr (i, j)) = cfDprod KxH 'chi_i 'chi_j. Proof. by rewrite cfIirrE ?cfDprod_irr. Qed. Lemma dprod_IirrEl i : 'chi_(dprod_Iirr (i, 0)) = cfDprodl KxH 'chi_i. Proof. by rewrite dprod_IirrE /cfDprod irr0 rmorph1 mulr1. Qed. Lemma dprod_IirrEr j : 'chi_(dprod_Iirr (0, j)) = cfDprodr KxH 'chi_j. Proof. by rewrite dprod_IirrE /cfDprod irr0 rmorph1 mul1r. Qed. Lemma dprod_Iirr_inj : injective dprod_Iirr. Proof. move=> [i1 j1] [i2 j2] /eqP; rewrite -[_ == _]oddb -(natCK (_ == _)). rewrite -cfdot_irr !dprod_IirrE cfdot_dprod !cfdot_irr -natrM mulnb. by rewrite natCK oddb -xpair_eqE => /eqP. Qed. Lemma dprod_Iirr0 : dprod_Iirr (0, 0) = 0. Proof. by apply/irr_inj; rewrite dprod_IirrE !irr0 cfDprod_cfun1. Qed. Lemma dprod_Iirr0l j : dprod_Iirr (0, j) = dprodr_Iirr j. Proof. by apply/irr_inj; rewrite dprod_IirrE irr0 dprodr_IirrE cfDprod_cfun1l. Qed. Lemma dprod_Iirr0r i : dprod_Iirr (i, 0) = dprodl_Iirr i. Proof. by apply/irr_inj; rewrite dprod_IirrE irr0 dprodl_IirrE cfDprod_cfun1r. Qed. Lemma dprod_Iirr_eq0 i j : (dprod_Iirr (i, j) == 0) = (i == 0) && (j == 0). Proof. by rewrite -xpair_eqE -(inj_eq dprod_Iirr_inj) dprod_Iirr0. Qed. Lemma cfdot_dprod_irr i1 i2 j1 j2 : '['chi_(dprod_Iirr (i1, j1)), 'chi_(dprod_Iirr (i2, j2))] = ((i1 == i2) && (j1 == j2))%:R. Proof. by rewrite cfdot_irr (inj_eq dprod_Iirr_inj). Qed. Lemma dprod_Iirr_onto k : k \in codom dprod_Iirr. Proof. set D := codom _; have Df: dprod_Iirr _ \in D := codom_f dprod_Iirr _. have: 'chi_k 1%g ^+ 2 != 0 by rewrite mulf_neq0 ?irr1_neq0. apply: contraR => notDk; move/eqP: (irr_sum_square G). rewrite (bigID (mem D)) (reindex _ (bij_on_codom dprod_Iirr_inj (0, 0))) /=. have ->: #|G|%:R = \sum_i \sum_j 'chi_(dprod_Iirr (i, j)) 1%g ^+ 2. rewrite -(dprod_card KxH) natrM. do 2![rewrite -irr_sum_square (mulr_suml, mulr_sumr); apply: eq_bigr => ? _]. by rewrite dprod_IirrE -exprMn -{3}(mulg1 1%g) cfDprodE. rewrite (eq_bigl _ _ Df) pair_bigA addrC -subr_eq0 addrK. by move/eqP/psumr_eq0P=> -> //= i _; rewrite irr1_degree -natrX ler0n. Qed. Definition inv_dprod_Iirr i := iinv (dprod_Iirr_onto i). Lemma dprod_IirrK : cancel dprod_Iirr inv_dprod_Iirr. Proof. by move=> p; exact: (iinv_f dprod_Iirr_inj). Qed. Lemma inv_dprod_IirrK : cancel inv_dprod_Iirr dprod_Iirr. Proof. by move=> i; exact: f_iinv. Qed. Lemma inv_dprod_Iirr0 : inv_dprod_Iirr 0 = (0, 0). Proof. by apply/(canLR dprod_IirrK); rewrite dprod_Iirr0. Qed. End DProd. Implicit Arguments dprod_Iirr_inj [gT G K H x1 x2]. Lemma dprod_IirrC (gT : finGroupType) (G K H : {group gT}) (KxH : K \x H = G) (HxK : H \x K = G) i j : dprod_Iirr KxH (i, j) = dprod_Iirr HxK (j, i). Proof. by apply: irr_inj; rewrite !dprod_IirrE; apply: cfDprodC. Qed. Section BigDprod. Variables (gT : finGroupType) (I : finType) (P : pred I). Variables (A : I -> {group gT}) (G : {group gT}). Hypothesis defG : \big[dprod/1%g]_(i | P i) A i = G. Let sAG i : P i -> A i \subset G. Proof. by move=> Pi; rewrite -(bigdprodWY defG) (bigD1 i) ?joing_subl. Qed. Lemma cfBigdprodi_char i (phi : 'CF(A i)) : phi \is a character -> cfBigdprodi defG phi \is a character. Proof. by move=> Nphi; rewrite cfDprodl_char ?cfRes_char. Qed. Lemma cfBigdprod_char phi : (forall i, P i -> phi i \is a character) -> cfBigdprod defG phi \is a character. Proof. by move=> Nphi; apply: rpred_prod => i /Nphi; apply: cfBigdprodi_char. Qed. Lemma cfBigdprodi_lin_char i (phi : 'CF(A i)) : phi \is a linear_char -> cfBigdprodi defG phi \is a linear_char. Proof. by move=> Lphi; rewrite cfDprodl_lin_char ?cfRes_lin_char. Qed. Lemma cfBigdprod_lin_char phi : (forall i, P i -> phi i \is a linear_char) -> cfBigdprod defG phi \is a linear_char. Proof. by move=> Lphi; apply/rpred_prod=> i /Lphi; apply: cfBigdprodi_lin_char. Qed. Lemma cfBigdprodi_irr i chi : P i -> chi \in irr (A i) -> cfBigdprodi defG chi \in irr G. Proof. by move=> Pi Nchi; rewrite cfDprodl_irr // Pi cfRes_id. Qed. Lemma cfBigdprod_irr chi : (forall i, P i -> chi i \in irr (A i)) -> cfBigdprod defG chi \in irr G. Proof. move=> Nchi; rewrite irrEchar cfBigdprod_char => [|i /Nchi/irrWchar] //=. by rewrite cfdot_bigdprod big1 // => i /Nchi/irrWnorm. Qed. Lemma cfBigdprod_eq1 phi : (forall i, P i -> phi i \is a character) -> (cfBigdprod defG phi == 1) = [forall (i | P i), phi i == 1]. Proof. move=> Nphi; set Phi := cfBigdprod defG phi. apply/eqP/eqfun_inP=> [Phi1 i Pi | phi1]; last first. by apply: big1 => i /phi1->; rewrite rmorph1. have Phi1_1: Phi 1%g = 1 by rewrite Phi1 cfun1E group1. have nz_Phi1: Phi 1%g != 0 by rewrite Phi1_1 oner_eq0. have [_ <-] := cfBigdprodK nz_Phi1 Pi. rewrite Phi1_1 divr1 -/Phi Phi1 rmorph1. rewrite prod_cfunE // in Phi1_1; have := Cnat_prod_eq1 _ Phi1_1 Pi. rewrite -(cfRes1 (A i)) cfBigdprodiK // => ->; first by rewrite scale1r. by move=> {i Pi} j /Nphi Nphi_j; rewrite Cnat_char1 ?cfBigdprodi_char. Qed. Lemma cfBigdprod_Res_lin chi : chi \is a linear_char -> cfBigdprod defG (fun i => 'Res[A i] chi) = chi. Proof. move=> Lchi; apply/cfun_inP=> _ /(mem_bigdprod defG)[x [Ax -> _]]. rewrite (lin_char_prod Lchi) ?cfBigdprodE // => [|i Pi]; last first. by rewrite (subsetP (sAG Pi)) ?Ax. by apply/eq_bigr=> i Pi; rewrite cfResE ?sAG ?Ax. Qed. Lemma cfBigdprodKlin phi : (forall i, P i -> phi i \is a linear_char) -> forall i, P i -> 'Res (cfBigdprod defG phi) = phi i. Proof. move=> Lphi i Pi; have Lpsi := cfBigdprod_lin_char Lphi. have [_ <-] := cfBigdprodK (lin_char_neq0 Lpsi (group1 G)) Pi. by rewrite !lin_char1 ?Lphi // divr1 scale1r. Qed. Lemma cfBigdprodKabelian Iphi (phi := fun i => 'chi_(Iphi i)) : abelian G -> forall i, P i -> 'Res (cfBigdprod defG phi) = 'chi_(Iphi i). Proof. move=> /(abelianS _) cGG. by apply: cfBigdprodKlin => i /sAG/cGG/char_abelianP->. Qed. End BigDprod. Section Aut. Variables (gT : finGroupType) (G : {group gT}). Implicit Type u : {rmorphism algC -> algC}. Lemma conjC_charAut u (chi : 'CF(G)) x : chi \is a character -> (u (chi x))^* = u (chi x)^*. Proof. have [Gx | /cfun0->] := boolP (x \in G); last by rewrite !rmorph0. case/char_reprP=> rG ->; have [e [_ [en1 _] [-> _] _]] := repr_rsim_diag rG Gx. by rewrite !rmorph_sum; apply: eq_bigr => i _; exact: aut_unity_rootC (en1 i). Qed. Lemma conjC_irrAut u i x : (u ('chi[G]_i x))^* = u ('chi_i x)^*. Proof. exact: conjC_charAut (irr_char i). Qed. Lemma cfdot_aut_char u (phi chi : 'CF(G)) : chi \is a character -> '[cfAut u phi, cfAut u chi] = u '[phi, chi]. Proof. by move/conjC_charAut=> Nchi; apply: cfdot_cfAut => _ /mapP[x _ ->]. Qed. Lemma cfdot_aut_irr u phi i : '[cfAut u phi, cfAut u 'chi[G]_i] = u '[phi, 'chi_i]. Proof. exact: cfdot_aut_char (irr_char i). Qed. Lemma cfAut_irr u chi : chi \in irr G -> cfAut u chi \in irr G. Proof. case/irrP=> i ->; rewrite irrEchar cfAut_char ?irr_char //=. by rewrite cfdot_aut_irr // cfdot_irr eqxx rmorph1. Qed. Lemma cfConjC_irr i : (('chi_i)^*)%CF \in irr G. Proof. by rewrite cfAut_irr ?mem_irr. Qed. Lemma irr_aut_closed u : cfAut_closed u (irr G). Proof. exact: cfAut_irr. Qed. Definition aut_Iirr u i := cfIirr (cfAut u 'chi[G]_i). Lemma aut_IirrE u i : 'chi_(aut_Iirr u i) = cfAut u 'chi_i. Proof. by rewrite cfIirrE ?cfAut_irr ?mem_irr. Qed. Definition conjC_Iirr := aut_Iirr conjC. Lemma conjC_IirrE i : 'chi[G]_(conjC_Iirr i) = ('chi_i)^*%CF. Proof. exact: aut_IirrE. Qed. Lemma conjC_IirrK : involutive conjC_Iirr. Proof. by move=> i; apply: irr_inj; rewrite !conjC_IirrE cfConjCK. Qed. Lemma aut_Iirr0 u : aut_Iirr u 0 = 0 :> Iirr G. Proof. by apply/irr_inj; rewrite aut_IirrE irr0 cfAut_cfun1. Qed. Lemma conjC_Iirr0 : conjC_Iirr 0 = 0 :> Iirr G. Proof. exact: aut_Iirr0. Qed. Lemma aut_Iirr_eq0 u i : (aut_Iirr u i == 0) = (i == 0). Proof. by rewrite -!irr_eq1 aut_IirrE cfAut_eq1. Qed. Lemma conjC_Iirr_eq0 i : (conjC_Iirr i == 0 :> Iirr G) = (i == 0). Proof. exact: aut_Iirr_eq0. Qed. Lemma aut_Iirr_inj u : injective (aut_Iirr u). Proof. by move=> i j eq_ij; apply/irr_inj/(cfAut_inj u); rewrite -!aut_IirrE eq_ij. Qed. Lemma char_aut u (chi : 'CF(G)) : (cfAut u chi \is a character) = (chi \is a character). Proof. apply/idP/idP=> [Nuchi|]; last exact: cfAut_char. rewrite [chi]cfun_sum_cfdot rpred_sum // => i _. rewrite rpredZ_Cnat ?irr_char // -(Cnat_aut u) -cfdot_aut_irr. by rewrite -aut_IirrE Cnat_cfdot_char_irr. Qed. Lemma irr_aut u chi : (cfAut u chi \in irr G) = (chi \in irr G). Proof. rewrite !irrEchar char_aut; apply/andb_id2l=> /cfdot_aut_char->. by rewrite fmorph_eq1. Qed. End Aut. Section IrrConstt. Variable (gT : finGroupType) (G H : {group gT}). Lemma char1_ge_norm (chi : 'CF(G)) x : chi \is a character -> `|chi x| <= chi 1%g. Proof. case/char_reprP=> rG ->; case Gx: (x \in G); last first. by rewrite cfunE cfRepr1 Gx normr0 ler0n. by have [e [_ _ []]] := repr_rsim_diag rG Gx. Qed. Lemma max_cfRepr_norm_scalar n (rG : mx_representation algCF G n) x : x \in G -> `|cfRepr rG x| = cfRepr rG 1%g -> exists2 c, `|c| = 1 & rG x = c%:M. Proof. move=> Gx; have [e [[B uB def_x] [_ e1] [-> _] _]] := repr_rsim_diag rG Gx. rewrite cfRepr1 -[n in n%:R]card_ord -sumr_const -(eq_bigr _ (in1W e1)). case/normC_sum_eq1=> [i _ | c /eqP norm_c_1 def_e]; first by rewrite e1. have{def_e} def_e: e = const_mx c by apply/rowP=> i; rewrite mxE def_e ?andbT. by exists c => //; rewrite def_x def_e diag_const_mx scalar_mxC mulmxKV. Qed. Lemma max_cfRepr_mx1 n (rG : mx_representation algCF G n) x : x \in G -> cfRepr rG x = cfRepr rG 1%g -> rG x = 1%:M. Proof. move=> Gx kerGx; have [|c _ def_x] := @max_cfRepr_norm_scalar n rG x Gx. by rewrite kerGx cfRepr1 normr_nat. move/eqP: kerGx; rewrite cfRepr1 cfunE Gx {rG}def_x mxtrace_scalar. case: n => [_|n]; first by rewrite ![_%:M]flatmx0. rewrite mulrb -subr_eq0 -mulrnBl -mulr_natl mulf_eq0 pnatr_eq0 /=. by rewrite subr_eq0 => /eqP->. Qed. Definition irr_constt (B : {set gT}) phi := [pred i | '[phi, 'chi_i]_B != 0]. Lemma irr_consttE i phi : (i \in irr_constt phi) = ('[phi, 'chi_i]_G != 0). Proof. by []. Qed. Lemma constt_charP (i : Iirr G) chi : chi \is a character -> reflect (exists2 chi', chi' \is a character & chi = 'chi_i + chi') (i \in irr_constt chi). Proof. move=> Nchi; apply: (iffP idP) => [i_in_chi| [chi' Nchi' ->]]; last first. rewrite inE /= cfdotDl cfdot_irr eqxx -(eqP (Cnat_cfdot_char_irr i Nchi')). by rewrite -natrD pnatr_eq0. exists (chi - 'chi_i); last by rewrite addrC subrK. apply/forallP=> j; rewrite coord_cfdot cfdotBl cfdot_irr. have [<- | _] := eqP; last by rewrite subr0 Cnat_cfdot_char_irr. have := i_in_chi; rewrite inE /= -(eqP (Cnat_cfdot_char_irr i Nchi)) pnatr_eq0. by case: (truncC _) => // n _; rewrite mulrSr addrK ?isNatC_nat. Qed. Lemma cfun_sum_constt (phi : 'CF(G)) : phi = \sum_(i in irr_constt phi) '[phi, 'chi_i] *: 'chi_i. Proof. rewrite {1}[phi]cfun_sum_cfdot (bigID [pred i | '[phi, 'chi_i] == 0]) /=. by rewrite big1 ?add0r // => i /eqP->; rewrite scale0r. Qed. Lemma neq0_has_constt (phi : 'CF(G)) : phi != 0 -> exists i, i \in irr_constt phi. Proof. move=> nz_phi; apply/existsP; apply: contra nz_phi => /pred0P phi0. by rewrite [phi]cfun_sum_constt big_pred0. Qed. Lemma constt_irr i : irr_constt 'chi[G]_i =i pred1 i. Proof. by move=> j; rewrite !inE cfdot_irr pnatr_eq0 (eq_sym j); case: (i == j). Qed. Lemma char1_ge_constt (i : Iirr G) chi : chi \is a character -> i \in irr_constt chi -> 'chi_i 1%g <= chi 1%g. Proof. move=> {chi} _ /constt_charP[// | chi Nchi ->]. by rewrite cfunE addrC -subr_ge0 addrK char1_ge0. Qed. Lemma constt_ortho_char (phi psi : 'CF(G)) i j : phi \is a character -> psi \is a character -> i \in irr_constt phi -> j \in irr_constt psi -> '[phi, psi] = 0 -> '['chi_i, 'chi_j] = 0. Proof. move=> _ _ /constt_charP[//|phi1 Nphi1 ->] /constt_charP[//|psi1 Npsi1 ->]. rewrite cfdot_irr; case: eqP => // -> /eqP/idPn[]. rewrite cfdotDl !cfdotDr cfnorm_irr -addrA gtr_eqF ?ltr_paddr ?ltr01 //. by rewrite Cnat_ge0 ?rpredD ?Cnat_cfdot_char ?irr_char. Qed. End IrrConstt. Arguments Scope irr_constt [_ group_scope cfun_scope]. Implicit Arguments aut_Iirr_inj [gT G x1 x2]. Section MoreConstt. Variables (gT : finGroupType) (G H : {group gT}). Lemma constt_Ind_Res i j : i \in irr_constt ('Ind[G] 'chi_j) = (j \in irr_constt ('Res[H] 'chi_i)). Proof. by rewrite !irr_consttE cfdotC conjC_eq0 -cfdot_Res_l. Qed. Lemma cfdot_Res_ge_constt i j psi : psi \is a character -> j \in irr_constt psi -> '['Res[H, G] 'chi_j, 'chi_i] <= '['Res[H] psi, 'chi_i]. Proof. move=> {psi} _ /constt_charP[// | psi Npsi ->]. rewrite linearD cfdotDl addrC -subr_ge0 addrK Cnat_ge0 //=. by rewrite Cnat_cfdot_char_irr // cfRes_char. Qed. Lemma constt_Res_trans j psi : psi \is a character -> j \in irr_constt psi -> {subset irr_constt ('Res[H, G] 'chi_j) <= irr_constt ('Res[H] psi)}. Proof. move=> Npsi Cj i; apply: contraNneq; rewrite eqr_le => {1}<-. rewrite cfdot_Res_ge_constt ?Cnat_ge0 ?Cnat_cfdot_char_irr //. by rewrite cfRes_char ?irr_char. Qed. End MoreConstt. Section Kernel. Variable (gT : finGroupType) (G : {group gT}). Implicit Types (phi chi xi : 'CF(G)) (H : {group gT}). Lemma cfker_repr n (rG : mx_representation algCF G n) : cfker (cfRepr rG) = rker rG. Proof. apply/esym/setP=> x; rewrite inE mul1mx /=. case Gx: (x \in G); last by rewrite inE Gx. apply/eqP/idP=> Kx; last by rewrite max_cfRepr_mx1 // cfker1. rewrite inE Gx; apply/forallP=> y; rewrite !cfunE !mulrb groupMl //. by case: ifP => // Gy; rewrite repr_mxM // Kx mul1mx. Qed. Lemma cfkerEchar chi : chi \is a character -> cfker chi = [set x in G | chi x == chi 1%g]. Proof. move=> Nchi; apply/setP=> x; apply/idP/setIdP=> [Kx | [Gx /eqP chi_x]]. by rewrite (subsetP (cfker_sub chi)) // cfker1. case/char_reprP: Nchi => rG -> in chi_x *; rewrite inE Gx; apply/forallP=> y. rewrite !cfunE groupMl // !mulrb; case: ifP => // Gy. by rewrite repr_mxM // max_cfRepr_mx1 ?mul1mx. Qed. Lemma cfker_nzcharE chi : chi \is a character -> chi != 0 -> cfker chi = [set x | chi x == chi 1%g]. Proof. move=> Nchi nzchi; apply/setP=> x; rewrite cfkerEchar // !inE andb_idl //. by apply: contraLR => /cfun0-> //; rewrite eq_sym char1_eq0. Qed. Lemma cfkerEirr i : cfker 'chi[G]_i = [set x | 'chi_i x == 'chi_i 1%g]. Proof. by rewrite cfker_nzcharE ?irr_char ?irr_neq0. Qed. Lemma cfker_irr0 : cfker 'chi[G]_0 = G. Proof. by rewrite irr0 cfker_cfun1. Qed. Lemma cfaithful_reg : cfaithful (cfReg G). Proof. apply/subsetP=> x; rewrite cfkerEchar ?cfReg_char // !inE !cfRegE eqxx. by case/andP=> _; apply: contraLR => /negbTE->; rewrite eq_sym neq0CG. Qed. Lemma cfkerE chi : chi \is a character -> cfker chi = G :&: \bigcap_(i in irr_constt chi) cfker 'chi_i. Proof. move=> Nchi; rewrite cfkerEchar //; apply/setP=> x; rewrite !inE. apply: andb_id2l => Gx; rewrite {1 2}[chi]cfun_sum_constt !sum_cfunE. apply/eqP/bigcapP=> [Kx i Ci | Kx]; last first. by apply: eq_bigr => i /Kx Kx_i; rewrite !cfunE cfker1. rewrite cfkerEirr inE /= -(inj_eq (mulfI Ci)). have:= (normC_sum_upper _ Kx) i; rewrite !cfunE => -> // {i Ci} i _. have chi_i_ge0: 0 <= '[chi, 'chi_i]. by rewrite Cnat_ge0 ?Cnat_cfdot_char_irr. by rewrite !cfunE normrM (normr_idP _) ?ler_wpmul2l ?char1_ge_norm ?irr_char. Qed. Lemma TI_cfker_irr : \bigcap_i cfker 'chi[G]_i = [1]. Proof. apply/trivgP; apply: subset_trans cfaithful_reg; rewrite cfkerE ?cfReg_char //. rewrite subsetI (bigcap_min 0) //=; last by rewrite cfker_irr0. by apply/bigcapsP=> i _; rewrite bigcap_inf. Qed. Lemma cfker_constt i chi : chi \is a character -> i \in irr_constt chi -> cfker chi \subset cfker 'chi[G]_i. Proof. by move=> Nchi Ci; rewrite cfkerE ?subIset ?(bigcap_min i) ?orbT. Qed. Section KerLin. Variable xi : 'CF(G). Hypothesis lin_xi : xi \is a linear_char. Let Nxi: xi \is a character. Proof. by have [] := andP lin_xi. Qed. Lemma lin_char_der1 : G^`(1)%g \subset cfker xi. Proof. rewrite gen_subG /=; apply/subsetP=> _ /imset2P[x y Gx Gy ->]. rewrite cfkerEchar // inE groupR //= !lin_charM ?lin_charV ?in_group //. by rewrite mulrCA mulKf ?mulVf ?lin_char_neq0 // lin_char1. Qed. Lemma cforder_lin_char : #[xi]%CF = exponent (G / cfker xi)%g. Proof. apply/eqP; rewrite eqn_dvd; apply/andP; split. apply/dvdn_cforderP=> x Gx; rewrite -lin_charX // -cfQuoEker ?groupX //. rewrite morphX ?(subsetP (cfker_norm xi)) //= expg_exponent ?mem_quotient //. by rewrite cfQuo1 ?cfker_normal ?lin_char1. have abGbar: abelian (G / cfker xi) := sub_der1_abelian lin_char_der1. have [_ /morphimP[x Nx Gx ->] ->] := exponent_witness (abelian_nil abGbar). rewrite order_dvdn -morphX //= coset_id cfkerEchar // !inE groupX //=. by rewrite lin_charX ?lin_char1 // (dvdn_cforderP _ _ _). Qed. Lemma cforder_lin_char_dvdG : #[xi]%CF %| #|G|. Proof. by rewrite cforder_lin_char (dvdn_trans (exponent_dvdn _)) ?dvdn_morphim. Qed. Lemma cforder_lin_char_gt0 : (0 < #[xi]%CF)%N. Proof. by rewrite cforder_lin_char exponent_gt0. Qed. End KerLin. End Kernel. Section Coset. Variable (gT : finGroupType). Implicit Types G H : {group gT}. Lemma cfQuo_char G H (chi : 'CF(G)) : chi \is a character -> (chi / H)%CF \is a character. Proof. move=> Nchi; case KchiH: (H \subset cfker chi); last first. suffices ->: (chi / H)%CF = (chi 1%g)%:A. by rewrite rpredZ_Cnat ?Cnat_char1 ?rpred1. by apply/cfunP=> x; rewrite cfunE cfun1E mulr_natr cfunElock KchiH. have sHG := subset_trans KchiH (cfker_sub _). pose N := 'N_G(H); pose phi := 'Res[N] chi. have nsHN: H <| N by [rewrite normal_subnorm]; have [sHN nHN] := andP nsHN. have{Nchi} Nphi: phi \is a character by apply: cfRes_char. have KphiH: H \subset cfker phi. apply/subsetP=> x Hx; have [Kx Nx] := (subsetP KchiH x Hx, subsetP sHN x Hx). by rewrite cfkerEchar // inE Nx cfRes1 cfResE ?subsetIl //= cfker1. pose psi := 'Res[(N / H)%g] (chi / H)%CF. have ->: (chi / H)%CF = 'Res psi by rewrite /psi quotientInorm !cfRes_id. have{KchiH} ->: psi = (phi / H)%CF. apply/cfun_inP => _ /morphimP[x nHx Nx ->]; have [Gx _] := setIP Nx. rewrite cfResE ?mem_quotient ?quotientS ?subsetIl // cfQuoEnorm //. by rewrite cfQuoE ?cfResE ?subsetIl. have [rG Dphi] := char_reprP Nphi; rewrite {phi Nphi}Dphi cfker_repr in KphiH *. apply/cfRes_char/char_reprP; exists (Representation (quo_repr KphiH nHN)). apply/cfun_inP=> _ /morphimP[x nHx Nx ->]; rewrite cfQuoE ?cfker_repr //=. by rewrite !cfunE Nx quo_repr_coset ?mem_quotient. Qed. Lemma cfQuo_lin_char G H (chi : 'CF(G)) : chi \is a linear_char -> (chi / H)%CF \is a linear_char. Proof. by case/andP=> Nchi; rewrite qualifE cfQuo_char ?cfQuo1. Qed. Lemma cfMod_char G H (chi : 'CF(G / H)) : chi \is a character -> (chi %% H)%CF \is a character. Proof. exact: cfMorph_char. Qed. Lemma cfMod_lin_char G H (chi : 'CF(G / H)) : chi \is a linear_char -> (chi %% H)%CF \is a linear_char. Proof. exact: cfMorph_lin_char. Qed. Lemma cfMod_irr G H chi : H <| G -> chi \in irr (G / H) -> (chi %% H)%CF \in irr G. Proof. by case/andP=> _; apply: cfMorph_irr. Qed. Definition mod_Iirr G H i := cfIirr ('chi[G / H]_i %% H)%CF. Lemma mod_Iirr0 G H : mod_Iirr (0 : Iirr (G / H)) = 0. Proof. exact: morph_Iirr0. Qed. Lemma mod_IirrE G H i : H <| G -> 'chi_(mod_Iirr i) = ('chi[G / H]_i %% H)%CF. Proof. by move=> nsHG; rewrite cfIirrE ?cfMod_irr ?mem_irr. Qed. Lemma mod_Iirr_eq0 G H i : H <| G -> (mod_Iirr i == 0) = (i == 0 :> Iirr (G / H)). Proof. by case/andP=> _ /morph_Iirr_eq0->. Qed. Lemma cfQuo_irr G H chi : H <| G -> H \subset cfker chi -> chi \in irr G -> (chi / H)%CF \in irr (G / H). Proof. move=> nsHG sHK /irr_reprP[rG irrG Dchi]; have [sHG nHG] := andP nsHG. have sHKr: H \subset rker rG by rewrite -cfker_repr -Dchi. apply/irr_reprP; exists (Representation (quo_repr sHKr nHG)). exact/quo_mx_irr. apply/cfun_inP=> _ /morphimP[x Nx Gx ->]. by rewrite cfQuoE //= Dchi !cfunE Gx quo_repr_coset ?mem_quotient. Qed. Definition quo_Iirr G H i := cfIirr ('chi[G]_i / H)%CF. Lemma quo_Iirr0 G H : quo_Iirr H (0 : Iirr G) = 0. Proof. by rewrite /quo_Iirr irr0 cfQuo_cfun1 -irr0 irrK. Qed. Lemma quo_IirrE G H i : H <| G -> H \subset cfker 'chi[G]_i -> 'chi_(quo_Iirr H i) = ('chi_i / H)%CF. Proof. by move=> nsHG kerH; rewrite cfIirrE ?cfQuo_irr ?mem_irr. Qed. Lemma quo_Iirr_eq0 G H i : H <| G -> H \subset cfker 'chi[G]_i -> (quo_Iirr H i == 0) = (i == 0). Proof. by move=> nsHG kerH; rewrite -!irr_eq1 quo_IirrE ?cfQuo_eq1. Qed. Lemma mod_IirrK G H : H <| G -> cancel (@mod_Iirr G H) (@quo_Iirr G H). Proof. move=> nsHG i; apply: irr_inj. by rewrite quo_IirrE ?mod_IirrE ?cfker_mod // cfModK. Qed. Lemma quo_IirrK G H i : H <| G -> H \subset cfker 'chi[G]_i -> mod_Iirr (quo_Iirr H i) = i. Proof. by move=> nsHG kerH; apply: irr_inj; rewrite mod_IirrE ?quo_IirrE ?cfQuoK. Qed. Lemma quo_IirrKeq G H : H <| G -> forall i, (mod_Iirr (quo_Iirr H i) == i) = (H \subset cfker 'chi[G]_i). Proof. move=> nsHG i; apply/eqP/idP=> [<- | ]; last exact: quo_IirrK. by rewrite mod_IirrE ?cfker_mod. Qed. Lemma mod_Iirr_bij H G : H <| G -> {on [pred i | H \subset cfker 'chi_i], bijective (@mod_Iirr G H)}. Proof. by exists (quo_Iirr H) => [i _ | i]; [exact: mod_IirrK | exact: quo_IirrK]. Qed. Lemma sum_norm_irr_quo H G x : x \in G -> H <| G -> \sum_i `|'chi[G / H]_i (coset H x)| ^+ 2 = \sum_(i | H \subset cfker 'chi_i) `|'chi[G]_i x| ^+ 2. Proof. move=> Gx nsHG; rewrite (reindex _ (mod_Iirr_bij nsHG)) /=. by apply/esym/eq_big=> [i | i _]; rewrite mod_IirrE ?cfker_mod ?cfModE. Qed. Lemma cap_cfker_normal G H : H <| G -> \bigcap_(i | H \subset cfker 'chi[G]_i) (cfker 'chi_i) = H. Proof. move=> nsHG; have [sHG nHG] := andP nsHG; set lhs := \bigcap_(i | _) _. have nHlhs: lhs \subset 'N(H) by rewrite (bigcap_min 0) ?cfker_irr0. apply/esym/eqP; rewrite eqEsubset (introT bigcapsP) //= -quotient_sub1 //. rewrite -(TI_cfker_irr (G / H)); apply/bigcapsP=> i _. rewrite sub_quotient_pre // (bigcap_min (mod_Iirr i)) ?mod_IirrE ?cfker_mod //. by rewrite cfker_morph ?subsetIr. Qed. Lemma cfker_reg_quo G H : H <| G -> cfker (cfReg (G / H)%g %% H) = H. Proof. move=> nsHG; have [sHG nHG] := andP nsHG. apply/setP=> x; rewrite cfkerEchar ?cfMod_char ?cfReg_char //. rewrite -[in RHS in _ = RHS](setIidPr sHG) !inE; apply: andb_id2l => Gx. rewrite !cfModE // !cfRegE // morph1 eqxx. rewrite (sameP eqP (kerP _ (subsetP nHG x Gx))) ker_coset. by rewrite -!mulrnA eqr_nat eqn_pmul2l ?cardG_gt0 // (can_eq oddb) eqb_id. Qed. End Coset. Section Derive. Variable gT : finGroupType. Implicit Types G H : {group gT}. Lemma lin_irr_der1 G i : ('chi_i \is a linear_char) = (G^`(1)%g \subset cfker 'chi[G]_i). Proof. apply/idP/idP=> [|sG'K]; first by apply: lin_char_der1. have nsG'G: G^`(1) <| G := der_normal 1 G. rewrite qualifE irr_char -[i](quo_IirrK nsG'G) // mod_IirrE //=. by rewrite cfModE // morph1 lin_char1 //; exact/char_abelianP/der_abelian. Qed. Lemma subGcfker G i : (G \subset cfker 'chi[G]_i) = (i == 0). Proof. rewrite -irr_eq1; apply/idP/eqP=> [chiG1 | ->]; last by rewrite cfker_cfun1. apply/cfun_inP=> x Gx; rewrite cfun1E Gx cfker1 ?(subsetP chiG1) ?lin_char1 //. by rewrite lin_irr_der1 (subset_trans (der_sub 1 G)). Qed. Lemma irr_prime_injP G i : prime #|G| -> reflect {in G &, injective 'chi[G]_i} (i != 0). Proof. move=> pr_G; apply: (iffP idP) => [nz_i | inj_chi]. apply: fful_lin_char_inj (irr_prime_lin i pr_G) _. by rewrite cfaithfulE -(setIidPr (cfker_sub _)) prime_TIg // subGcfker. have /trivgPn[x Gx ntx]: G :!=: 1%g by rewrite -cardG_gt1 prime_gt1. apply: contraNneq ntx => i0; apply/eqP/inj_chi=> //. by rewrite i0 irr0 !cfun1E Gx group1. Qed. (* This is Isaacs (2.23)(a). *) Lemma cap_cfker_lin_irr G : \bigcap_(i | 'chi[G]_i \is a linear_char) (cfker 'chi_i) = G^`(1)%g. Proof. rewrite -(cap_cfker_normal (der_normal 1 G)). by apply: eq_bigl => i; rewrite lin_irr_der1. Qed. (* This is Isaacs (2.23)(b) *) Lemma card_lin_irr G : #|[pred i | 'chi[G]_i \is a linear_char]| = #|G : G^`(1)%g|. Proof. have nsG'G := der_normal 1 G; rewrite (eq_card (@lin_irr_der1 G)). rewrite -(on_card_preimset (mod_Iirr_bij nsG'G)). rewrite -card_quotient ?normal_norm //. move: (der_abelian 0 G); rewrite card_classes_abelian; move/eqP<-. rewrite -NirrE -[X in _ = X]card_ord. by apply: eq_card => i; rewrite !inE mod_IirrE ?cfker_mod. (* Alternative: use the equivalent result in modular representation theory transitivity #|@socle_of_Iirr _ G @^-1: linear_irr _|; last first. rewrite (on_card_preimset (socle_of_Iirr_bij _)). by rewrite card_linear_irr ?algC'G; last exact: groupC. by apply: eq_card => i; rewrite !inE /lin_char irr_char irr1_degree -eqC_nat. *) Qed. (* A non-trivial solvable group has a nonprincipal linear character. *) Lemma solvable_has_lin_char G : G :!=: 1%g -> solvable G -> exists2 i, 'chi[G]_i \is a linear_char & 'chi_i != 1. Proof. move=> ntG solG. suff /subsetPn[i]: ~~ ([pred i | 'chi[G]_i \is a linear_char] \subset pred1 0). by rewrite !inE -(inj_eq irr_inj) irr0; exists i. rewrite (contra (@subset_leq_card _ _ _)) // -ltnNge card1 card_lin_irr. by rewrite indexg_gt1 proper_subn // (sol_der1_proper solG). Qed. (* A combinatorial group isommorphic to the linear characters. *) Lemma lin_char_group G : {linG : finGroupType & {cF : linG -> 'CF(G) | [/\ injective cF, #|linG| = #|G : G^`(1)|, forall u, cF u \is a linear_char & forall phi, phi \is a linear_char -> exists u, phi = cF u] & [/\ cF 1%g = 1%R, {morph cF : u v / (u * v)%g >-> (u * v)%R}, forall k, {morph cF : u / (u^+ k)%g >-> u ^+ k}, {morph cF: u / u^-1%g >-> u^-1%CF} & {mono cF: u / #[u]%g >-> #[u]%CF} ]}}. Proof. pose linT := {i : Iirr G | 'chi_i \is a linear_char}. pose cF (u : linT) := 'chi_(sval u). have cFlin u: cF u \is a linear_char := svalP u. have cFinj: injective cF := inj_comp irr_inj val_inj. have inT xi : xi \is a linear_char -> {u | cF u = xi}. move=> lin_xi; have /irrP/sig_eqW[i Dxi] := lin_char_irr lin_xi. by apply: (exist _ (Sub i _)) => //; rewrite -Dxi. have [one cFone] := inT 1 (rpred1 _). pose inv u := sval (inT _ (rpredVr (cFlin u))). pose mul u v := sval (inT _ (rpredM (cFlin u) (cFlin v))). have cFmul u v: cF (mul u v) = cF u * cF v := svalP (inT _ _). have cFinv u: cF (inv u) = (cF u)^-1 := svalP (inT _ _). have mulA: associative mul by move=> u v w; apply: cFinj; rewrite !cFmul mulrA. have mul1: left_id one mul by move=> u; apply: cFinj; rewrite cFmul cFone mul1r. have mulV: left_inverse one inv mul. by move=> u; apply: cFinj; rewrite cFmul cFinv cFone mulVr ?lin_char_unitr. pose linGm := FinGroup.Mixin mulA mul1 mulV. pose linG := @FinGroupType (BaseFinGroupType linT linGm) mulV. have cFexp k: {morph cF : u / ((u : linG) ^+ k)%g >-> u ^+ k}. by move=> u; elim: k => // k IHk; rewrite expgS exprS cFmul IHk. do [exists linG, cF; split=> //] => [|xi /inT[u <-]|u]; first 2 [by exists u]. have inj_cFI: injective (cfIirr \o cF). apply: can_inj (insubd one) _ => u; apply: val_inj. by rewrite insubdK /= ?irrK //; apply: cFlin. rewrite -(card_image inj_cFI) -card_lin_irr. apply/eq_card=> i; rewrite inE; apply/codomP/idP=> [[u ->] | /inT[u Du]]. by rewrite /= irrK; apply: cFlin. by exists u; apply: irr_inj; rewrite /= irrK. apply/eqP; rewrite eqn_dvd; apply/andP; split. by rewrite dvdn_cforder; rewrite -cFexp expg_order cFone. by rewrite order_dvdn -(inj_eq cFinj) cFone cFexp exp_cforder. Qed. Lemma cfExp_prime_transitive G (i j : Iirr G) : prime #|G| -> i != 0 -> j != 0 -> exists2 k, coprime k #['chi_i]%CF & 'chi_j = 'chi_i ^+ k. Proof. set p := #|G| => pr_p nz_i nz_j; have cycG := prime_cyclic pr_p. have [L [h [injh oL Lh h_ontoL]] [h1 hM hX _ o_h]] := lin_char_group G. rewrite (derG1P (cyclic_abelian cycG)) indexg1 -/p in oL. have /fin_all_exists[h' h'K] := h_ontoL _ (irr_cyclic_lin _ cycG). have o_h' k: k != 0 -> #[h' k] = p. rewrite -cforder_irr_eq1 h'K -o_h => nt_h'k. by apply/prime_nt_dvdP=> //; rewrite cforder_lin_char_dvdG. have{oL} genL k: k != 0 -> generator [set: L] (h' k). move=> /o_h' o_h'k; rewrite /generator eq_sym eqEcard subsetT /=. by rewrite cardsT oL -o_h'k. have [/(_ =P <[_]>)-> gen_j] := (genL i nz_i, genL j nz_j). have /cycleP[k Dj] := cycle_generator gen_j. by rewrite !h'K Dj o_h hX generator_coprime coprime_sym in gen_j *; exists k. Qed. (* This is Isaacs (2.24). *) Lemma card_subcent1_coset G H x : x \in G -> H <| G -> (#|'C_(G / H)[coset H x]| <= #|'C_G[x]|)%N. Proof. move=> Gx nsHG; rewrite -leC_nat. move: (second_orthogonality_relation x Gx); rewrite mulrb class_refl => <-. have GHx: coset H x \in (G / H)%g by apply: mem_quotient. move: (second_orthogonality_relation (coset H x) GHx). rewrite mulrb class_refl => <-. rewrite -2!(eq_bigr _ (fun _ _ => normCK _)) sum_norm_irr_quo // -subr_ge0. rewrite (bigID (fun i => H \subset cfker 'chi[G]_i)) //= addrC addKr. by apply: sumr_ge0 => i _; rewrite normCK mul_conjC_ge0. Qed. End Derive. Implicit Arguments irr_prime_injP [gT G i]. (* Determinant characters and determinential order. *) Section DetOrder. Variables (gT : finGroupType) (G : {group gT}). Section DetRepr. Variables (n : nat) (rG : mx_representation [fieldType of algC] G n). Definition det_repr_mx x : 'M_1 := (\det (rG x))%:M. Fact det_is_repr : mx_repr G det_repr_mx. Proof. split=> [|g h Gg Gh]; first by rewrite /det_repr_mx repr_mx1 det1. by rewrite /det_repr_mx repr_mxM // det_mulmx !mulmxE scalar_mxM. Qed. Canonical det_repr := MxRepresentation det_is_repr. Definition detRepr := cfRepr det_repr. Lemma detRepr_lin_char : detRepr \is a linear_char. Proof. by rewrite qualifE cfRepr_char cfunE group1 repr_mx1 mxtrace1 mulr1n /=. Qed. End DetRepr. Definition cfDet phi := \prod_i detRepr 'Chi_i ^+ truncC '[phi, 'chi[G]_i]. Lemma cfDet_lin_char phi : cfDet phi \is a linear_char. Proof. by apply: rpred_prod => i _; apply: rpredX; apply: detRepr_lin_char. Qed. Lemma cfDetD : {in character &, {morph cfDet : phi psi / phi + psi >-> phi * psi}}. Proof. move=> phi psi Nphi Npsi; rewrite /= -big_split; apply: eq_bigr => i _ /=. by rewrite -exprD cfdotDl truncCD ?nnegrE ?Cnat_ge0 // Cnat_cfdot_char_irr. Qed. Lemma cfDet0 : cfDet 0 = 1. Proof. by rewrite /cfDet big1 // => i _; rewrite cfdot0l truncC0. Qed. Lemma cfDetMn k : {in character, {morph cfDet : phi / phi *+ k >-> phi ^+ k}}. Proof. move=> phi Nphi; elim: k => [|k IHk]; rewrite ?cfDet0 // mulrS exprS -{}IHk. by rewrite cfDetD ?rpredMn. Qed. Lemma cfDetRepr n rG : cfDet (cfRepr rG) = @detRepr n rG. Proof. transitivity (\prod_W detRepr (socle_repr W) ^+ standard_irr_coef rG W). rewrite (reindex _ (socle_of_Iirr_bij _)) /cfDet /=. apply: eq_bigr => i _; congr (_ ^+ _). rewrite (cfRepr_sim (mx_rsim_standard rG)) cfRepr_standard. rewrite cfdot_suml (bigD1 i) ?big1 //= => [|j i'j]; last first. by rewrite cfdotZl cfdot_irr (negPf i'j) mulr0. by rewrite cfdotZl cfnorm_irr mulr1 addr0 natCK. apply/cfun_inP=> x Gx; rewrite prod_cfunE //. transitivity (detRepr (standard_grepr rG) x); last first. rewrite !cfunE Gx !trace_mx11 !mxE eqxx !mulrb. case: (standard_grepr rG) (mx_rsim_standard rG) => /= n1 rG1 [B Dn1]. rewrite -{n1}Dn1 in rG1 B *; rewrite row_free_unit => uB rG_B. by rewrite -[rG x](mulmxK uB) rG_B // !det_mulmx mulrC -!det_mulmx mulKmx. rewrite /standard_grepr; elim/big_rec2: _ => [|W y _ _ ->]. by rewrite cfunE trace_mx11 mxE Gx det1. rewrite !cfunE Gx /= !{1}trace_mx11 !{1}mxE det_ublock; congr (_ * _). rewrite exp_cfunE //; elim: (standard_irr_coef rG W) => /= [|k IHk]. by rewrite /muln_grepr big_ord0 det1. rewrite exprS /muln_grepr big_ord_recl det_ublock -IHk; congr (_ * _). by rewrite cfunE trace_mx11 mxE Gx. Qed. Lemma cfDet_id xi : xi \is a linear_char -> cfDet xi = xi. Proof. move=> lin_xi; have /irrP[i Dxi] := lin_char_irr lin_xi. apply/cfun_inP=> x Gx; rewrite Dxi -irrRepr cfDetRepr !cfunE trace_mx11 mxE. move: lin_xi (_ x) => /andP[_]; rewrite Dxi irr1_degree pnatr_eq1 => /eqP-> X. by rewrite {1}[X]mx11_scalar det_scalar1 trace_mx11. Qed. Definition cfDet_order phi := #[cfDet phi]%CF. Definition cfDet_order_lin xi : xi \is a linear_char -> cfDet_order xi = #[xi]%CF. Proof. by rewrite /cfDet_order => /cfDet_id->. Qed. Definition cfDet_order_dvdG phi : cfDet_order phi %| #|G|. Proof. by rewrite cforder_lin_char_dvdG ?cfDet_lin_char. Qed. End DetOrder. Notation "''o' ( phi )" := (cfDet_order phi) (at level 8, format "''o' ( phi )") : cfun_scope. Section CfDetOps. Implicit Types gT aT rT : finGroupType. Lemma cfDetRes gT (G H : {group gT}) phi : phi \is a character -> cfDet ('Res[H, G] phi) = 'Res (cfDet phi). Proof. move=> Nphi; have [sGH | not_sHG] := boolP (H \subset G); last first. have /CnatP[n Dphi1] := Cnat_char1 Nphi. rewrite !cfResEout // Dphi1 lin_char1 ?cfDet_lin_char // scale1r. by rewrite scaler_nat cfDetMn ?cfDet_id ?rpred1 // expr1n. have [rG ->] := char_reprP Nphi; rewrite !(=^~ cfRepr_sub, cfDetRepr) //. apply: cfRepr_sim; exists 1%:M; rewrite ?row_free_unit ?unitmx1 // => x Hx. by rewrite mulmx1 mul1mx. Qed. Lemma cfDetMorph aT rT (D G : {group aT}) (f : {morphism D >-> rT}) (phi : 'CF(f @* G)) : phi \is a character -> cfDet (cfMorph phi) = cfMorph (cfDet phi). Proof. move=> Nphi; have [sGD | not_sGD] := boolP (G \subset D); last first. have /CnatP[n Dphi1] := Cnat_char1 Nphi. rewrite !cfMorphEout // Dphi1 lin_char1 ?cfDet_lin_char // scale1r. by rewrite scaler_nat cfDetMn ?cfDet_id ?rpred1 // expr1n. have [rG ->] := char_reprP Nphi; rewrite !(=^~ cfRepr_morphim, cfDetRepr) //. apply: cfRepr_sim; exists 1%:M; rewrite ?row_free_unit ?unitmx1 // => x Hx. by rewrite mulmx1 mul1mx. Qed. Lemma cfDetIsom aT rT (G : {group aT}) (R : {group rT}) (f : {morphism G >-> rT}) (isoGR : isom G R f) phi : cfDet (cfIsom isoGR phi) = cfIsom isoGR (cfDet phi). Proof. rewrite rmorph_prod /cfDet (reindex (isom_Iirr isoGR)); last first. by exists (isom_Iirr (isom_sym isoGR)) => i; rewrite ?isom_IirrK ?isom_IirrKV. apply: eq_bigr => i; rewrite -!cfDetRepr !irrRepr isom_IirrE rmorphX cfIsom_iso. by rewrite /= ![in cfIsom _]unlock cfDetMorph ?cfRes_char ?cfDetRes ?irr_char. Qed. Lemma cfDet_mul_lin gT (G : {group gT}) (lambda phi : 'CF(G)) : lambda \is a linear_char -> phi \is a character -> cfDet (lambda * phi) = lambda ^+ truncC (phi 1%g) * cfDet phi. Proof. case/andP=> /char_reprP[[n1 rG1] ->] /= n1_1 /char_reprP[[n2 rG2] ->] /=. do [rewrite !cfRepr1 pnatr_eq1 natCK; move/eqP] in n1_1 *. rewrite {n1}n1_1 in rG1 *; rewrite cfRepr_prod cfDetRepr. apply/cfun_inP=> x Gx; rewrite !cfunE cfDetRepr cfunE Gx !mulrb !trace_mx11. rewrite !mxE prod_repr_lin ?mulrb //=; case: _ / (esym _); rewrite detZ. congr (_ * _); case: {rG2}n2 => [|n2]; first by rewrite cfun1E Gx. by rewrite expS_cfunE //= cfunE Gx trace_mx11. Qed. End CfDetOps. Definition cfcenter (gT : finGroupType) (G : {set gT}) (phi : 'CF(G)) := if phi \is a character then [set g in G | `|phi g| == phi 1%g] else cfker phi. Notation "''Z' ( phi )" := (cfcenter phi) : cfun_scope. Section Center. Variable (gT : finGroupType) (G : {group gT}). Implicit Types (phi chi : 'CF(G)) (H : {group gT}). (* This is Isaacs (2.27)(a). *) Lemma cfcenter_repr n (rG : mx_representation algCF G n) : 'Z(cfRepr rG)%CF = rcenter rG. Proof. rewrite /cfcenter /rcenter cfRepr_char /=. apply/setP=> x; rewrite !inE; apply/andb_id2l=> Gx. apply/eqP/is_scalar_mxP=> [|[c rG_c]]. by case/max_cfRepr_norm_scalar=> // c; exists c. rewrite -(sqrCK (char1_ge0 (cfRepr_char rG))) normC_def; congr (sqrtC _). rewrite expr2 -{2}(mulgV x) -char_inv ?cfRepr_char ?cfunE ?groupM ?groupV //. rewrite Gx group1 repr_mx1 repr_mxM ?repr_mxV ?groupV // !mulrb rG_c. by rewrite invmx_scalar -scalar_mxM !mxtrace_scalar mulrnAr mulrnAl mulr_natl. Qed. (* This is part of Isaacs (2.27)(b). *) Fact cfcenter_group_set phi : group_set ('Z(phi))%CF. Proof. have [[rG ->] | /negbTE notNphi] := altP (@char_reprP _ G phi). by rewrite cfcenter_repr groupP. by rewrite /cfcenter notNphi groupP. Qed. Canonical cfcenter_group f := Group (cfcenter_group_set f). Lemma char_cfcenterE chi x : chi \is a character -> x \in G -> (x \in ('Z(chi))%CF) = (`|chi x| == chi 1%g). Proof. by move=> Nchi Gx; rewrite /cfcenter Nchi inE Gx. Qed. Lemma irr_cfcenterE i x : x \in G -> (x \in 'Z('chi[G]_i)%CF) = (`|'chi_i x| == 'chi_i 1%g). Proof. by move/char_cfcenterE->; rewrite ?irr_char. Qed. (* This is also Isaacs (2.27)(b). *) Lemma cfcenter_sub phi : ('Z(phi))%CF \subset G. Proof. by rewrite /cfcenter /cfker !setIdE -fun_if subsetIl. Qed. Lemma cfker_center_normal phi : cfker phi <| 'Z(phi)%CF. Proof. apply: normalS (cfcenter_sub phi) (cfker_normal phi). rewrite /= /cfcenter; case: ifP => // Hphi; rewrite cfkerEchar //. apply/subsetP=> x; rewrite !inE => /andP[-> /eqP->] /=. by rewrite ger0_norm ?char1_ge0. Qed. Lemma cfcenter_normal phi : 'Z(phi)%CF <| G. Proof. have [[rG ->] | /negbTE notNphi] := altP (@char_reprP _ _ phi). by rewrite cfcenter_repr rcenter_normal. by rewrite /cfcenter notNphi cfker_normal. Qed. (* This is Isaacs (2.27)(c). *) Lemma cfcenter_Res chi : exists2 chi1, chi1 \is a linear_char & 'Res['Z(chi)%CF] chi = chi 1%g *: chi1. Proof. have [[rG ->] | /negbTE notNphi] := altP (@char_reprP _ _ chi); last first. exists 1; first exact: cfun1_lin_char. rewrite /cfcenter notNphi; apply/cfun_inP=> x Kx. by rewrite cfunE cfun1E Kx mulr1 cfResE ?cfker_sub // cfker1. rewrite cfcenter_repr -(cfRepr_sub _ (normal_sub (rcenter_normal _))). case: rG => [[|n] rG] /=; rewrite cfRepr1. exists 1; first exact: cfun1_lin_char. by apply/cfun_inP=> x Zx; rewrite scale0r !cfunE flatmx0 raddf0 Zx. pose rZmx x := ((rG x 0 0)%:M : 'M_(1,1)). have rZmxP: mx_repr [group of rcenter rG] rZmx. split=> [|x y]; first by rewrite /rZmx repr_mx1 mxE eqxx. move=> /setIdP[Gx /is_scalar_mxP[a rGx]] /setIdP[Gy /is_scalar_mxP[b rGy]]. by rewrite /rZmx repr_mxM // rGx rGy -!scalar_mxM !mxE. exists (cfRepr (MxRepresentation rZmxP)). by rewrite qualifE cfRepr_char cfRepr1 eqxx. apply/cfun_inP=> x Zx; rewrite !cfunE Zx /= /rZmx mulr_natl. by case/setIdP: Zx => Gx /is_scalar_mxP[a ->]; rewrite mxE !mxtrace_scalar. Qed. (* This is Isaacs (2.27)(d). *) Lemma cfcenter_cyclic chi : cyclic ('Z(chi)%CF / cfker chi)%g. Proof. case Nchi: (chi \is a character); last first. by rewrite /cfcenter Nchi trivg_quotient cyclic1. have [-> | nz_chi] := eqVneq chi 0. rewrite quotientS1 ?cyclic1 //= /cfcenter cfkerEchar ?cfun0_char //. by apply/subsetP=> x /setIdP[Gx _]; rewrite inE Gx /= !cfunE. have [xi Lxi def_chi] := cfcenter_Res chi. set Z := ('Z(_))%CF in xi Lxi def_chi *. have sZG: Z \subset G by exact: cfcenter_sub. have ->: cfker chi = cfker xi. rewrite -(setIidPr (normal_sub (cfker_center_normal _))) -/Z. rewrite !cfkerEchar // ?lin_charW //= -/Z. apply/setP=> x; rewrite !inE; apply: andb_id2l => Zx. rewrite (subsetP sZG) //= -!(cfResE chi sZG) ?group1 // def_chi !cfunE. by rewrite (inj_eq (mulfI _)) ?char1_eq0. have: abelian (Z / cfker xi) by rewrite sub_der1_abelian ?lin_char_der1. have [rG irrG ->] := irr_reprP _ (lin_char_irr Lxi); rewrite cfker_repr. apply: mx_faithful_irr_abelian_cyclic (kquo_mx_faithful rG) _. exact/quo_mx_irr. Qed. (* This is Isaacs (2.27)(e). *) Lemma cfcenter_subset_center chi : ('Z(chi)%CF / cfker chi)%g \subset 'Z(G / cfker chi)%g. Proof. case Nchi: (chi \is a character); last first. by rewrite /cfcenter Nchi trivg_quotient sub1G. rewrite subsetI quotientS ?cfcenter_sub // quotient_cents2r //=. case/char_reprP: Nchi => rG ->{chi}; rewrite cfker_repr cfcenter_repr gen_subG. apply/subsetP=> _ /imset2P[x y /setIdP[Gx /is_scalar_mxP[c rGx]] Gy ->]. rewrite inE groupR //= !repr_mxM ?groupM ?groupV // rGx -(scalar_mxC c) -rGx. by rewrite !mulmxA !repr_mxKV. Qed. (* This is Isaacs (2.27)(f). *) Lemma cfcenter_eq_center (i : Iirr G) : ('Z('chi_i)%CF / cfker 'chi_i)%g = 'Z(G / cfker 'chi_i)%g. Proof. apply/eqP; rewrite eqEsubset; rewrite cfcenter_subset_center ?irr_char //. apply/subsetP=> _ /setIP[/morphimP[x /= _ Gx ->] cGx]; rewrite mem_quotient //=. rewrite -irrRepr cfker_repr cfcenter_repr inE Gx in cGx *. apply: mx_abs_irr_cent_scalar 'Chi_i _ _ _. by apply: groupC; apply: socle_irr. have nKG: G \subset 'N(rker 'Chi_i) by exact: rker_norm. (* GG -- locking here is critical to prevent Coq kernel divergence. *) apply/centgmxP=> y Gy; rewrite [eq]lock -2?(quo_repr_coset (subxx _) nKG) //. move: (quo_repr _ _) => rG; rewrite -2?repr_mxM ?mem_quotient // -lock. by rewrite (centP cGx) // mem_quotient. Qed. (* This is Isaacs (2.28). *) Lemma cap_cfcenter_irr : \bigcap_i 'Z('chi[G]_i)%CF = 'Z(G). Proof. apply/esym/eqP; rewrite eqEsubset (introT bigcapsP) /= => [|i _]; last first. rewrite -(quotientSGK _ (normal_sub (cfker_center_normal _))). by rewrite cfcenter_eq_center morphim_center. by rewrite subIset // normal_norm // cfker_normal. set Z := \bigcap_i _. have sZG: Z \subset G by rewrite (bigcap_min 0) ?cfcenter_sub. rewrite subsetI sZG (sameP commG1P trivgP) -(TI_cfker_irr G). apply/bigcapsP=> i _; have nKiG := normal_norm (cfker_normal 'chi_i). rewrite -quotient_cents2 ?(subset_trans sZG) //. rewrite (subset_trans (quotientS _ (bigcap_inf i _))) //. by rewrite cfcenter_eq_center subsetIr. Qed. (* This is Isaacs (2.29). *) Lemma cfnorm_Res_lerif H phi : H \subset G -> '['Res[H] phi] <= #|G : H|%:R * '[phi] ?= iff (phi \in 'CF(G, H)). Proof. move=> sHG; rewrite cfun_onE mulrCA natf_indexg // -mulrA mulKf ?neq0CG //. rewrite (big_setID H) (setIidPr sHG) /= addrC. rewrite (mono_lerif (ler_pmul2l _)) ?invr_gt0 ?gt0CG // -lerif_subLR -sumrB. rewrite big1 => [|x Hx]; last by rewrite !cfResE ?subrr. have ->: (support phi \subset H) = (G :\: H \subset [set x | phi x == 0]). rewrite subDset setUC -subDset; apply: eq_subset => x. by rewrite !inE (andb_idr (contraR _)) // => /cfun0->. rewrite (sameP subsetP forall_inP); apply: lerif_0_sum => x _. by rewrite !inE /] := cfcenter_Res 'chi_i. have /irrP[j ->] := lin_char_irr Lxi; rewrite cfdotZl cfdotZr cfdot_irr eqxx. by rewrite mulr1 irr1_degree conjC_nat. by rewrite cfdot_irr eqxx mulr1. Qed. (* This is Isaacs (2.31). *) Lemma irr1_abelian_bound (i : Iirr G) : abelian (G / 'Z('chi_i)%CF) -> ('chi_i 1%g) ^+ 2 = #|G : 'Z('chi_i)%CF|%:R. Proof. move=> AbGc; apply/eqP; rewrite irr1_bound cfun_onE; apply/subsetP=> x nz_chi_x. have Gx: x \in G by apply: contraR nz_chi_x => /cfun0->. have nKx := subsetP (normal_norm (cfker_normal 'chi_i)) _ Gx. rewrite -(quotientGK (cfker_center_normal _)) inE nKx inE /=. rewrite cfcenter_eq_center inE mem_quotient //=. apply/centP=> _ /morphimP[y nKy Gy ->]; apply/commgP; rewrite -morphR //=. set z := [~ x, y]; rewrite coset_id //. have: z \in 'Z('chi_i)%CF. apply: subsetP (mem_commg Gx Gy). by rewrite der1_min // normal_norm ?cfcenter_normal. rewrite -irrRepr cfker_repr cfcenter_repr !inE in nz_chi_x *. case/andP=> Gz /is_scalar_mxP[c Chi_z]; rewrite Gz Chi_z mul1mx /=. apply/eqP; congr _%:M; apply: (mulIf nz_chi_x); rewrite mul1r. rewrite -{2}(cfunJ _ x Gy) conjg_mulR -/z !cfunE Gx groupM // !{1}mulrb. by rewrite repr_mxM // Chi_z mul_mx_scalar mxtraceZ. Qed. (* This is Isaacs (2.32)(a). *) Lemma irr_faithful_center i : cfaithful 'chi[G]_i -> cyclic 'Z(G). Proof. rewrite (isog_cyclic (isog_center (quotient1_isog G))) /=. by move/trivgP <-; rewrite -cfcenter_eq_center cfcenter_cyclic. Qed. Lemma cfcenter_fful_irr i : cfaithful 'chi[G]_i -> 'Z('chi_i)%CF = 'Z(G). Proof. move/trivgP=> Ki1; have:= cfcenter_eq_center i; rewrite {}Ki1. have inj1: 'injm (@coset gT 1%g) by rewrite ker_coset. by rewrite -injm_center; first apply: injm_morphim_inj; rewrite ?norms1. Qed. (* This is Isaacs (2.32)(b). *) Lemma pgroup_cyclic_faithful (p : nat) : p.-group G -> cyclic 'Z(G) -> exists i, cfaithful 'chi[G]_i. Proof. pose Z := 'Ohm_1('Z(G)) => pG cycZG; have nilG := pgroup_nil pG. have [-> | ntG] := eqsVneq G [1]; first by exists 0; exact: cfker_sub. have{pG} [[p_pr _ _] pZ] := (pgroup_pdiv pG ntG, pgroupS (center_sub G) pG). have ntZ: 'Z(G) != [1] by rewrite center_nil_eq1. have{pZ} oZ: #|Z| = p by exact: Ohm1_cyclic_pgroup_prime. apply/existsP; apply: contraR ntZ; rewrite negb_exists => /forallP-not_ffulG. rewrite -Ohm1_eq1 -subG1 /= -/Z -(TI_cfker_irr G); apply/bigcapsP=> i _. rewrite prime_meetG ?oZ // setIC meet_Ohm1 // meet_center_nil ?cfker_normal //. by rewrite -subG1 not_ffulG. Qed. End Center. Section Induced. Variables (gT : finGroupType) (G H : {group gT}). Implicit Types (phi : 'CF(G)) (chi : 'CF(H)). Lemma cfInd_char chi : chi \is a character -> 'Ind[G] chi \is a character. Proof. move=> Nchi; apply/forallP=> i; rewrite coord_cfdot -Frobenius_reciprocity //. by rewrite Cnat_cfdot_char ?cfRes_char ?irr_char. Qed. Lemma cfInd_eq0 chi : H \subset G -> chi \is a character -> ('Ind[G] chi == 0) = (chi == 0). Proof. move=> sHG Nchi; rewrite -!(char1_eq0) ?cfInd_char // cfInd1 //. by rewrite (mulrI_eq0 _ (mulfI _)) ?neq0CiG. Qed. Lemma Ind_irr_neq0 i : H \subset G -> 'Ind[G, H] 'chi_i != 0. Proof. by move/cfInd_eq0->; rewrite ?irr_neq0 ?irr_char. Qed. Definition Ind_Iirr (A B : {set gT}) i := cfIirr ('Ind[B, A] 'chi_i). Lemma constt_cfRes_irr i : {j | j \in irr_constt ('Res[H, G] 'chi_i)}. Proof. apply/sigW/neq0_has_constt/Res_irr_neq0. Qed. Lemma constt_cfInd_irr i : H \subset G -> {j | j \in irr_constt ('Ind[G, H] 'chi_i)}. Proof. by move=> sHG; apply/sigW/neq0_has_constt/Ind_irr_neq0. Qed. Lemma cfker_Res phi : H \subset G -> phi \is a character -> cfker ('Res[H] phi) = H :&: cfker phi. Proof. move=> sHG Nphi; apply/setP=> x; rewrite !cfkerEchar ?cfRes_char // !inE. by apply/andb_id2l=> Hx; rewrite (subsetP sHG) ?cfResE. Qed. (* This is Isaacs Lemma (5.11). *) Lemma cfker_Ind chi : H \subset G -> chi \is a character -> chi != 0 -> cfker ('Ind[G, H] chi) = gcore (cfker chi) G. Proof. move=> sHG Nchi nzchi; rewrite !cfker_nzcharE ?cfInd_char ?cfInd_eq0 //. apply/setP=> x; rewrite inE cfIndE // (can2_eq (mulVKf _) (mulKf _)) ?neq0CG //. rewrite cfInd1 // mulrA -natrM Lagrange // mulr_natl -sumr_const. apply/eqP/bigcapP=> [/normC_sum_upper ker_chiG_x y Gy | ker_chiG_x]. by rewrite mem_conjg inE ker_chiG_x ?groupV // => z _; exact: char1_ge_norm. by apply: eq_bigr => y /groupVr/ker_chiG_x; rewrite mem_conjgV inE => /eqP. Qed. Lemma cfker_Ind_irr i : H \subset G -> cfker ('Ind[G, H] 'chi_i) = gcore (cfker 'chi_i) G. Proof. by move/cfker_Ind->; rewrite ?irr_neq0 ?irr_char. Qed. End Induced. Arguments Scope Ind_Iirr [_ group_scope group_scope ring_scope].mathcomp-1.5/theories/mxrepresentation.v0000644000175000017500000073153412307636117017616 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. Require Import fintype tuple finfun bigop prime ssralg poly polydiv finset. Require Import fingroup morphism perm automorphism quotient finalg action zmodp. Require Import commutator cyclic center pgroup matrix mxalgebra mxpoly. (******************************************************************************) (* This file provides linkage between classic Group Theory and commutative *) (* algebra -- representation theory. Since general abstract linear algebra is *) (* still being sorted out, we develop the required theory here on the *) (* assumption that all vector spaces are matrix spaces, indeed that most are *) (* row matrix spaces; our representation theory is specialized to the latter *) (* case. We provide many definitions and results of representation theory: *) (* enveloping algebras, reducible, irreducible and absolutely irreducible *) (* representations, representation centralisers, submodules and kernels, *) (* simple and semisimple modules, the Schur lemmas, Maschke's theorem, *) (* components, socles, homomorphisms and isomorphisms, the Jacobson density *) (* theorem, similar representations, the Jordan-Holder theorem, Clifford's *) (* theorem and Wedderburn components, regular representations and the *) (* Wedderburn structure theorem for semisimple group rings, and the *) (* construction of a splitting field of an irreducible representation, and of *) (* reduced, tensored, and factored representations. *) (* mx_representation F G n == the Structure type for representations of G *) (* with n x n matrices with coefficients in F. Note that *) (* rG : mx_representation F G n coerces to a function from *) (* the element type of G to 'M_n, and conversely all such *) (* functions have a Canonical mx_representation. *) (* mx_repr G r <-> r : gT -> 'M_n defines a (matrix) group representation *) (* on G : {set gT} (Prop predicate). *) (* enveloping_algebra_mx rG == a #|G| x (n ^ 2) matrix whose rows are the *) (* mxvec encodings of the image of G under rG, and whose *) (* row space therefore encodes the enveloping algebra of *) (* the representation of G. *) (* rker rG == the kernel of the representation of r on G, i.e., the *) (* subgroup of elements of G mapped to the identity by rG. *) (* mx_faithful rG == the representation rG of G is faithful (its kernel is *) (* trivial). *) (* rfix_mx rG H == an n x n matrix whose row space is the set of vectors *) (* fixed (centralised) by the representation of H by rG. *) (* rcent rG A == the subgroup of G whose representation via rG commutes *) (* with the square matrix A. *) (* rcenter rG == the subgroup of G whose representation via rG consists of *) (* scalar matrices. *) (* mxcentg rG f <=> f commutes with every matrix in the representation of G *) (* (i.e., f is a total rG-homomorphism). *) (* rstab rG U == the subgroup of G whose representation via r fixes all *) (* vectors in U, pointwise. *) (* rstabs rG U == the subgroup of G whose representation via r fixes the row *) (* space of U globally. *) (* mxmodule rG U <=> the row-space of the matrix U is a module (globally *) (* invariant) under the representation rG of G. *) (* max_submod rG U V <-> U < V is not a proper is a proper subset of any *) (* proper rG-submodule of V (if both U and V are modules, *) (* then U is a maximal proper submodule of V). *) (* mx_subseries rG Us <=> Us : seq 'M_n is a list of rG-modules *) (* mx_composition_series rG Us <-> Us is an increasing composition series *) (* for an rG-module (namely, last 0 Us). *) (* mxsimple rG M <-> M is a simple rG-module (i.e., minimal and nontrivial) *) (* This is a Prop predicate on square matrices. *) (* mxnonsimple rG U <-> U is constructively not a submodule, that is, U *) (* contains a proper nontrivial submodule. *) (* mxnonsimple_sat rG U == U is not a simple as an rG-module. *) (* This is a bool predicate, which requires a decField *) (* structure on the scalar field. *) (* mxsemisimple rG W <-> W is constructively a direct sum of simple modules. *) (* mxsplits rG V U <-> V splits over U in rG, i.e., U has an rG-invariant *) (* complement in V. *) (* mx_completely_reducible rG V <-> V splits over all its submodules; note *) (* that this is only classically equivalent to stating that *) (* V is semisimple. *) (* mx_irreducible rG <-> the representation rG is irreducible, i.e., the full *) (* module 1%:M of rG is simple. *) (* mx_absolutely_irreducible rG == the representation rG of G is absolutely *) (* irreducible: its enveloping algebra is the full matrix *) (* ring. This is only classically equivalent to the more *) (* standard ``rG does not reduce in any field extension''. *) (* group_splitting_field F G <-> F is a splitting field for the group G: *) (* every irreducible representation of G is absolutely *) (* irreducible. Any field can be embedded classically into a *) (* splitting field. *) (* group_closure_field F gT <-> F is a splitting field for every group *) (* G : {group gT}, and indeed for any section of such a *) (* group. This is a convenient constructive substitute for *) (* algebraic closures, that can be constructed classically. *) (* dom_hom_mx rG f == a square matrix encoding the set of vectors for which *) (* multiplication by the n x n matrix f commutes with the *) (* representation of G, i.e., the largest domain on which *) (* f is an rG homomorphism. *) (* mx_iso rG U V <-> U and V are (constructively) rG-isomorphic; this is *) (* a Prop predicate. *) (* mx_simple_iso rG U V == U and V are rG-isomorphic if one of them is *) (* simple; this is a bool predicate. *) (* cyclic_mx rG u == the cyclic rG-module generated by the row vector u *) (* annihilator_mx rG u == the annihilator of the row vector u in the *) (* enveloping algebra the representation rG. *) (* row_hom_mx rG u == the image of u by the set of all rG-homomorphisms on *) (* its cyclic module, or, equivalently, the null-space of the *) (* annihilator of u. *) (* component_mx rG M == when M is a simple rG-module, the component of M in *) (* the representation rG, i.e. the module generated by all *) (* the (simple) modules rG-isomorphic to M. *) (* socleType rG == a Structure that represents the type of all components *) (* of rG (more precisely, it coerces to such a type via *) (* socle_sort). For sG : socleType, values of type sG (to be *) (* exact, socle_sort sG) coerce to square matrices. For any *) (* representation rG we can construct sG : socleType rG *) (* classically; the socleType structure encapsulates this *) (* use of classical logic. *) (* DecSocleType rG == a socleType rG structure, for a representation over a *) (* decidable field type. *) (* socle_base W == for W : (sG : socleType), a simple module whose *) (* component is W; socle_simple W and socle_module W are *) (* proofs that socle_base W is a simple module. *) (* socle_mult W == the multiplicity of socle_base W in W : sG. *) (* := \rank W %/ \rank (socle_base W) *) (* Socle sG == the Socle of rG, given sG : socleType rG, i.e., the *) (* (direct) sum of all the components of rG. *) (* mx_rsim rG rG' <-> rG and rG' are similar representations of the same *) (* group G. Note that rG and rG' must then have equal, but *) (* not necessarily convertible, degree. *) (* submod_repr modU == a representation of G on 'rV_(\rank U) equivalent to *) (* the restriction of rG to U (here modU : mxmodule rG U). *) (* socle_repr W := submod_repr (socle_module W) *) (* val/in_submod rG U == the projections resp. from/onto 'rV_(\rank U), *) (* that correspond to submod_repr r G U (these work both on *) (* vectors and row spaces). *) (* factmod_repr modV == a representation of G on 'rV_(\rank (cokermx V)) that *) (* is equivalent to the factor module 'rV_n / V induced by V *) (* and rG (here modV : mxmodule rG V). *) (* val/in_factmod rG U == the projections for factmod_repr r G U. *) (* section_repr modU modV == the restriction to in_factmod V U of the factor *) (* representation factmod_repr modV (for modU : mxmodule rG U *) (* and modV : mxmodule rG V); section_repr modU modV is *) (* irreducible iff max_submod rG U V. *) (* subseries_repr modUs i == the representation for the section module *) (* in_factmod (0 :: Us)`_i Us`_i, where *) (* modUs : mx_subseries rG Us. *) (* series_repr compUs i == the representation for the section module *) (* in_factmod (0 :: Us)`_i Us`_i, where *) (* compUs : mx_composition_series rG Us. The Jordan-Holder *) (* theorem asserts the uniqueness of the set of such *) (* representations, up to similarity and permutation. *) (* regular_repr F G == the regular F-representation of the group G. *) (* group_ring F G == a #|G| x #|G|^2 matrix that encodes the free group *) (* ring of G -- that is, the enveloping algebra of the *) (* regular F-representation of G. *) (* gring_index x == the index corresponding to x \in G in the matrix *) (* encoding of regular_repr and group_ring. *) (* gring_row A == the row vector corresponding to A \in group_ring F G in *) (* the regular FG-module. *) (* gring_proj x A == the 1 x 1 matrix holding the coefficient of x \in G in *) (* (A \in group_ring F G)%MS. *) (* gring_mx rG u == the image of a row vector u of the regular FG-module, *) (* in the enveloping algebra of another representation rG. *) (* gring_op rG A == the image of a matrix of the free group ring of G, *) (* in the enveloping algebra of rG. *) (* gset_mx F G C == the group sum of C in the free group ring of G -- the *) (* sum of the images of all the x \in C in group_ring F G. *) (* classg_base F G == a #|classes G| x #|G|^2 matrix whose rows encode the *) (* group sums of the conjugacy classes of G -- this is a *) (* basis of 'Z(group_ring F G)%MS. *) (* irrType F G == a type indexing irreducible representations of G over a *) (* field F, provided its characteristic does not divide the *) (* order of G; it also indexes Wedderburn subrings. *) (* := socleType (regular_repr F G) *) (* irr_repr i == the irreducible representation corresponding to the *) (* index i : irrType sG *) (* := socle_repr i as i coerces to a component matrix. *) (* 'n_i, irr_degree i == the degree of irr_repr i; the notation is only *) (* active after Open Scope group_ring_scope. *) (* linear_irr sG == the set of sG-indices of linear irreducible *) (* representations of G. *) (* irr_comp sG rG == the sG-index of the unique irreducible representation *) (* similar to rG, at least when rG is irreducible and the *) (* characteristic is coprime. *) (* irr_mode i z == the unique eigenvalue of irr_repr i z, at least when *) (* irr_repr i z is scalar (e.g., when z \in 'Z(G)). *) (* [1 sG]%irr == the index of the principal representation of G, in *) (* sG : irrType F G. The i argument ot irr_repr, irr_degree *) (* and irr_mode is in the %irr scope. This notation may be *) (* replaced locally by an interpretation of 1%irr as [1 sG] *) (* for some specific irrType sG. *) (* 'R_i, Wedderburn_subring i == the subring (indeed, the component) of the *) (* free group ring of G corresponding to the component i : sG *) (* of the regular FG-module, where sG : irrType F g. In *) (* coprime characteristic the Wedderburn structure theorem *) (* asserts that the free group ring is the direct sum of *) (* these subrings; as with 'n_i above, the notation is only *) (* active in group_ring_scope. *) (* 'e_i, Wedderburn_id i == the projection of the identity matrix 1%:M on the *) (* Wedderburn subring of i : sG (with sG a socleType). In *) (* coprime characteristic this is the identity element of *) (* the subring, and the basis of its center if the field F is *) (* a splitting field. As 'R_i, 'e_i is in group_ring_scope. *) (* subg_repr rG sHG == the restriction to H of the representation rG of G; *) (* here sHG : H \subset G. *) (* eqg_repr rG eqHG == the representation rG of G viewed a a representation *) (* of H; here eqHG : G == H. *) (* morphpre_repr f rG == the representation of f @*^-1 G obtained by *) (* composing the group morphism f with rG. *) (* morphim_repr rGf sGD == the representation of G induced by a *) (* representation rGf of f @* G; here sGD : G \subset D where *) (* D is the domain of the group morphism f. *) (* rconj_repr rG uB == the conjugate representation x |-> B * rG x * B^-1; *) (* here uB : B \in unitmx. *) (* quo_repr sHK nHG == the representation of G / H induced by rG, given *) (* sHK : H \subset rker rG, and nHG : G \subset 'N(H). *) (* kquo_repr rG == the representation induced on G / rker rG by rG. *) (* map_repr f rG == the representation f \o rG, whose module is the tensor *) (* product of the module of rG with the extension field into *) (* which f : {rmorphism F -> Fstar} embeds F. *) (* 'Cl%act == the transitive action of G on the Wedderburn components of *) (* H, with nsGH : H <| G, given by Clifford's theorem. More *) (* precisely this is a total action of G on socle_sort sH, *) (* where sH : socleType (subg_repr rG (normal_sub sGH)). *) (* More involved constructions are encapsulated in two Coq submodules: *) (* MatrixGenField == a module that encapsulates the lengthy details of the *) (* construction of appropriate extension fields. We assume we *) (* have an irreducible representation r of a group G, and a *) (* non-scalar matrix A that centralises an r(G), as this data *) (* is readily extracted from the Jacobson density theorem. It *) (* then follows from Schur's lemma that the ring generated by *) (* A is a field on which the extension of the representation *) (* r of G is reducible. Note that this is equivalent to the *) (* more traditional quotient of the polynomial ring by an *) (* irreducible polynomial (the minimal polynomial of A), but *) (* much better suited to our needs. *) (* Here are the main definitions of MatrixGenField; they all have three *) (* proofs as arguments: rG : mx_repr r G, irrG : mx_irreducible rG, and *) (* cGA : mxcentg rG A, which ensure the validity of the construction and *) (* allow us to define Canonical instances (the ~~ is_scalar_mx A assumption *) (* is only needed to prove reducibility). *) (* + gen_of irrG cGA == the carrier type of the field generated by A. It is *) (* at least equipped with a fieldType structure; we also *) (* propagate any decFieldType/finFieldType structures on the *) (* original field. *) (* + gen irrG cGA == the morphism injecting into gen_of rG irrG cGA. *) (* + groot irrG cGA == the root of mxminpoly A in the gen_of field. *) (* + gen_repr irrG cGA == an alternative to the field extension *) (* representation, which consists in reconsidering the *) (* original module as a module over the new gen_of field, *) (* thereby DIVIDING the original dimension n by the degree of *) (* the minimal polynomial of A. This can be simpler than the *) (* extension method, and is actually required by the proof *) (* that odd groups are p-stable (B & G 6.1-2, and Appendix A) *) (* but is only applicable if G is the LARGEST group *) (* represented by rG (e.g., NOT for B & G 2.6). *) (* + val_gen/in_gen rG irrG cGA : the bijections from/to the module *) (* corresponding to gen_repr. *) (* + rowval_gen rG irrG cGA : the projection of row spaces in the module *) (* corresponding to gen_repr to row spaces in 'rV_n. *) (* We build on the MatrixFormula toolkit to define decision procedures for *) (* the reducibility property: *) (* + mxmodule_form rG U == a formula asserting that the interpretation of U *) (* is a module of the representation rG of G via r. *) (* + mxnonsimple_form rG U == a formula asserting that the interpretation *) (* of U contains a proper nontrivial rG-module. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope GRing.Theory. Local Open Scope ring_scope. Reserved Notation "''n_' i" (at level 8, i at level 2, format "''n_' i"). Reserved Notation "''R_' i" (at level 8, i at level 2, format "''R_' i"). Reserved Notation "''e_' i" (at level 8, i at level 2, format "''e_' i"). Delimit Scope irrType_scope with irr. Section RingRepr. Variable R : comUnitRingType. Section OneRepresentation. Variable gT : finGroupType. Definition mx_repr (G : {set gT}) n (r : gT -> 'M[R]_n) := r 1%g = 1%:M /\ {in G &, {morph r : x y / (x * y)%g >-> x *m y}}. Structure mx_representation G n := MxRepresentation { repr_mx :> gT -> 'M_n; _ : mx_repr G repr_mx }. Variables (G : {group gT}) (n : nat) (rG : mx_representation G n). Arguments Scope rG [group_scope]. Lemma repr_mx1 : rG 1 = 1%:M. Proof. by case: rG => r []. Qed. Lemma repr_mxM : {in G &, {morph rG : x y / (x * y)%g >-> x *m y}}. Proof. by case: rG => r []. Qed. Lemma repr_mxK m x : x \in G -> cancel ((@mulmx _ m n n)^~ (rG x)) (mulmx^~ (rG x^-1)). Proof. by move=> Gx U; rewrite -mulmxA -repr_mxM ?groupV // mulgV repr_mx1 mulmx1. Qed. Lemma repr_mxKV m x : x \in G -> cancel ((@mulmx _ m n n)^~ (rG x^-1)) (mulmx^~ (rG x)). Proof. by rewrite -groupV -{3}[x]invgK; exact: repr_mxK. Qed. Lemma repr_mx_unit x : x \in G -> rG x \in unitmx. Proof. by move=> Gx; case/mulmx1_unit: (repr_mxKV Gx 1%:M). Qed. Lemma repr_mxV : {in G, {morph rG : x / x^-1%g >-> invmx x}}. Proof. by move=> x Gx /=; rewrite -[rG x^-1](mulKmx (repr_mx_unit Gx)) mulmxA repr_mxK. Qed. (* This is only used in the group ring construction below, as we only have *) (* developped the theory of matrix subalgebras for F-algebras. *) Definition enveloping_algebra_mx := \matrix_(i < #|G|) mxvec (rG (enum_val i)). Section Stabiliser. Variables (m : nat) (U : 'M[R]_(m, n)). Definition rstab := [set x in G | U *m rG x == U]. Lemma rstab_sub : rstab \subset G. Proof. by apply/subsetP=> x; case/setIdP. Qed. Lemma rstab_group_set : group_set rstab. Proof. apply/group_setP; rewrite inE group1 repr_mx1 mulmx1; split=> //= x y. case/setIdP=> Gx cUx; case/setIdP=> Gy cUy; rewrite inE repr_mxM ?groupM //. by rewrite mulmxA (eqP cUx). Qed. Canonical rstab_group := Group rstab_group_set. End Stabiliser. (* Centralizer subgroup and central homomorphisms. *) Section CentHom. Variable f : 'M[R]_n. Definition rcent := [set x in G | f *m rG x == rG x *m f]. Lemma rcent_sub : rcent \subset G. Proof. by apply/subsetP=> x; case/setIdP. Qed. Lemma rcent_group_set : group_set rcent. Proof. apply/group_setP; rewrite inE group1 repr_mx1 mulmx1 mul1mx; split=> //= x y. case/setIdP=> Gx; move/eqP=> cfx; case/setIdP=> Gy; move/eqP=> cfy. by rewrite inE repr_mxM ?groupM //= -mulmxA -cfy !mulmxA cfx. Qed. Canonical rcent_group := Group rcent_group_set. Definition centgmx := G \subset rcent. Lemma centgmxP : reflect (forall x, x \in G -> f *m rG x = rG x *m f) centgmx. Proof. apply: (iffP subsetP) => cGf x Gx; by have:= cGf x Gx; rewrite !inE Gx /=; move/eqP. Qed. End CentHom. (* Representation kernel, and faithful representations. *) Definition rker := rstab 1%:M. Canonical rker_group := Eval hnf in [group of rker]. Lemma rkerP x : reflect (x \in G /\ rG x = 1%:M) (x \in rker). Proof. by apply: (iffP setIdP) => [] [->]; move/eqP; rewrite mul1mx. Qed. Lemma rker_norm : G \subset 'N(rker). Proof. apply/subsetP=> x Gx; rewrite inE sub_conjg; apply/subsetP=> y. case/rkerP=> Gy ry1; rewrite mem_conjgV !inE groupJ //=. by rewrite !repr_mxM ?groupM ?groupV // ry1 !mulmxA mulmx1 repr_mxKV. Qed. Lemma rker_normal : rker <| G. Proof. by rewrite /normal rstab_sub rker_norm. Qed. Definition mx_faithful := rker \subset [1]. Lemma mx_faithful_inj : mx_faithful -> {in G &, injective rG}. Proof. move=> ffulG x y Gx Gy eq_rGxy; apply/eqP; rewrite eq_mulgV1 -in_set1. rewrite (subsetP ffulG) // inE groupM ?repr_mxM ?groupV //= eq_rGxy. by rewrite mulmxA repr_mxK. Qed. Lemma rker_linear : n = 1%N -> G^`(1)%g \subset rker. Proof. move=> n1; rewrite gen_subG; apply/subsetP=> xy; case/imset2P=> x y Gx Gy ->. rewrite !inE groupR //= /commg mulgA -invMg repr_mxM ?groupV ?groupM //. rewrite mulmxA (can2_eq (repr_mxK _) (repr_mxKV _)) ?groupM //. rewrite !repr_mxV ?repr_mxM ?groupM //; move: (rG x) (rG y). by rewrite n1 => rx ry; rewrite (mx11_scalar rx) scalar_mxC. Qed. (* Representation center. *) Definition rcenter := [set g in G | is_scalar_mx (rG g)]. Fact rcenter_group_set : group_set rcenter. Proof. apply/group_setP; split=> [|x y]. by rewrite inE group1 repr_mx1 scalar_mx_is_scalar. move=> /setIdP[Gx /is_scalar_mxP[a defx]] /setIdP[Gy /is_scalar_mxP[b defy]]. by rewrite !inE groupM ?repr_mxM // defx defy -scalar_mxM ?scalar_mx_is_scalar. Qed. Canonical rcenter_group := Group rcenter_group_set. Lemma rcenter_normal : rcenter <| G. Proof. rewrite /normal /rcenter {1}setIdE subsetIl; apply/subsetP=> x Gx; rewrite inE. apply/subsetP=> _ /imsetP[y /setIdP[Gy /is_scalar_mxP[c rGy]] ->]. rewrite inE !repr_mxM ?groupM ?groupV //= mulmxA rGy scalar_mxC repr_mxKV //. exact: scalar_mx_is_scalar. Qed. End OneRepresentation. Implicit Arguments rkerP [gT G n rG x]. Section Proper. Variables (gT : finGroupType) (G : {group gT}) (n' : nat). Local Notation n := n'.+1. Variable rG : mx_representation G n. Lemma repr_mxMr : {in G &, {morph rG : x y / (x * y)%g >-> x * y}}. Proof. exact: repr_mxM. Qed. Lemma repr_mxVr : {in G, {morph rG : x / (x^-1)%g >-> x^-1}}. Proof. exact: repr_mxV. Qed. Lemma repr_mx_unitr x : x \in G -> rG x \is a GRing.unit. Proof. exact: repr_mx_unit. Qed. Lemma repr_mxX m : {in G, {morph rG : x / (x ^+ m)%g >-> x ^+ m}}. Proof. elim: m => [|m IHm] x Gx; rewrite /= ?repr_mx1 // expgS exprS -IHm //. by rewrite repr_mxM ?groupX. Qed. End Proper. Section ChangeGroup. Variables (gT : finGroupType) (G H : {group gT}) (n : nat). Variables (rG : mx_representation G n). Section SubGroup. Hypothesis sHG : H \subset G. Lemma subg_mx_repr : mx_repr H rG. Proof. by split=> [|x y Hx Hy]; rewrite (repr_mx1, repr_mxM) ?(subsetP sHG). Qed. Definition subg_repr := MxRepresentation subg_mx_repr. Local Notation rH := subg_repr. Lemma rcent_subg U : rcent rH U = H :&: rcent rG U. Proof. by apply/setP=> x; rewrite !inE andbA -in_setI (setIidPl sHG). Qed. Section Stabiliser. Variables (m : nat) (U : 'M[R]_(m, n)). Lemma rstab_subg : rstab rH U = H :&: rstab rG U. Proof. by apply/setP=> x; rewrite !inE andbA -in_setI (setIidPl sHG). Qed. End Stabiliser. Lemma rker_subg : rker rH = H :&: rker rG. Proof. exact: rstab_subg. Qed. Lemma subg_mx_faithful : mx_faithful rG -> mx_faithful rH. Proof. by apply: subset_trans; rewrite rker_subg subsetIr. Qed. End SubGroup. Section SameGroup. Hypothesis eqGH : G :==: H. Lemma eqg_repr_proof : H \subset G. Proof. by rewrite (eqP eqGH). Qed. Definition eqg_repr := subg_repr eqg_repr_proof. Local Notation rH := eqg_repr. Lemma rcent_eqg U : rcent rH U = rcent rG U. Proof. by rewrite rcent_subg -(eqP eqGH) (setIidPr _) ?rcent_sub. Qed. Section Stabiliser. Variables (m : nat) (U : 'M[R]_(m, n)). Lemma rstab_eqg : rstab rH U = rstab rG U. Proof. by rewrite rstab_subg -(eqP eqGH) (setIidPr _) ?rstab_sub. Qed. End Stabiliser. Lemma rker_eqg : rker rH = rker rG. Proof. exact: rstab_eqg. Qed. Lemma eqg_mx_faithful : mx_faithful rH = mx_faithful rG. Proof. by rewrite /mx_faithful rker_eqg. Qed. End SameGroup. End ChangeGroup. Section Morphpre. Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}). Variables (G : {group rT}) (n : nat) (rG : mx_representation G n). Lemma morphpre_mx_repr : mx_repr (f @*^-1 G) (rG \o f). Proof. split=> [|x y]; first by rewrite /= morph1 repr_mx1. case/morphpreP=> Dx Gfx; case/morphpreP=> Dy Gfy. by rewrite /= morphM ?repr_mxM. Qed. Canonical morphpre_repr := MxRepresentation morphpre_mx_repr. Local Notation rGf := morphpre_repr. Section Stabiliser. Variables (m : nat) (U : 'M[R]_(m, n)). Lemma rstab_morphpre : rstab rGf U = f @*^-1 (rstab rG U). Proof. by apply/setP=> x; rewrite !inE andbA. Qed. End Stabiliser. Lemma rker_morphpre : rker rGf = f @*^-1 (rker rG). Proof. exact: rstab_morphpre. Qed. End Morphpre. Section Morphim. Variables (aT rT : finGroupType) (G D : {group aT}) (f : {morphism D >-> rT}). Variables (n : nat) (rGf : mx_representation (f @* G) n). Definition morphim_mx of G \subset D := fun x => rGf (f x). Hypothesis sGD : G \subset D. Lemma morphim_mxE x : morphim_mx sGD x = rGf (f x). Proof. by []. Qed. Let sG_f'fG : G \subset f @*^-1 (f @* G). Proof. by rewrite -sub_morphim_pre. Qed. Lemma morphim_mx_repr : mx_repr G (morphim_mx sGD). Proof. exact: subg_mx_repr (morphpre_repr f rGf) sG_f'fG. Qed. Canonical morphim_repr := MxRepresentation morphim_mx_repr. Local Notation rG := morphim_repr. Section Stabiliser. Variables (m : nat) (U : 'M[R]_(m, n)). Lemma rstab_morphim : rstab rG U = G :&: f @*^-1 rstab rGf U. Proof. by rewrite -rstab_morphpre -(rstab_subg _ sG_f'fG). Qed. End Stabiliser. Lemma rker_morphim : rker rG = G :&: f @*^-1 (rker rGf). Proof. exact: rstab_morphim. Qed. End Morphim. Section Conjugate. Variables (gT : finGroupType) (G : {group gT}) (n : nat). Variables (rG : mx_representation G n) (B : 'M[R]_n). Definition rconj_mx of B \in unitmx := fun x => B *m rG x *m invmx B. Hypothesis uB : B \in unitmx. Lemma rconj_mx_repr : mx_repr G (rconj_mx uB). Proof. split=> [|x y Gx Gy]; rewrite /rconj_mx ?repr_mx1 ?mulmx1 ?mulmxV ?repr_mxM //. by rewrite !mulmxA mulmxKV. Qed. Canonical rconj_repr := MxRepresentation rconj_mx_repr. Local Notation rGB := rconj_repr. Lemma rconj_mxE x : rGB x = B *m rG x *m invmx B. Proof. by []. Qed. Lemma rconj_mxJ m (W : 'M_(m, n)) x : W *m rGB x *m B = W *m B *m rG x. Proof. by rewrite !mulmxA mulmxKV. Qed. Lemma rcent_conj A : rcent rGB A = rcent rG (invmx B *m A *m B). Proof. apply/setP=> x; rewrite !inE /= rconj_mxE !mulmxA. rewrite (can2_eq (mulmxKV uB) (mulmxK uB)) -!mulmxA. by rewrite -(can2_eq (mulKVmx uB) (mulKmx uB)). Qed. Lemma rstab_conj m (U : 'M_(m, n)) : rstab rGB U = rstab rG (U *m B). Proof. apply/setP=> x; rewrite !inE /= rconj_mxE !mulmxA. by rewrite (can2_eq (mulmxKV uB) (mulmxK uB)). Qed. Lemma rker_conj : rker rGB = rker rG. Proof. apply/setP=> x; rewrite !inE /= mulmxA (can2_eq (mulmxKV uB) (mulmxK uB)). by rewrite mul1mx -scalar_mxC (inj_eq (can_inj (mulKmx uB))) mul1mx. Qed. Lemma conj_mx_faithful : mx_faithful rGB = mx_faithful rG. Proof. by rewrite /mx_faithful rker_conj. Qed. End Conjugate. Section Quotient. Variables (gT : finGroupType) (G : {group gT}) (n : nat). Variable rG : mx_representation G n. Definition quo_mx (H : {set gT}) of H \subset rker rG & G \subset 'N(H) := fun Hx : coset_of H => rG (repr Hx). Section SubQuotient. Variable H : {group gT}. Hypotheses (krH : H \subset rker rG) (nHG : G \subset 'N(H)). Let nHGs := subsetP nHG. Lemma quo_mx_coset x : x \in G -> quo_mx krH nHG (coset H x) = rG x. Proof. move=> Gx; rewrite /quo_mx val_coset ?nHGs //; case: repr_rcosetP => z Hz. by case/rkerP: (subsetP krH z Hz) => Gz rz1; rewrite repr_mxM // rz1 mul1mx. Qed. Lemma quo_mx_repr : mx_repr (G / H)%g (quo_mx krH nHG). Proof. split=> [|Hx Hy]; first by rewrite /quo_mx repr_coset1 repr_mx1. case/morphimP=> x Nx Gx ->{Hx}; case/morphimP=> y Ny Gy ->{Hy}. by rewrite -morphM // !quo_mx_coset ?groupM ?repr_mxM. Qed. Canonical quo_repr := MxRepresentation quo_mx_repr. Local Notation rGH := quo_repr. Lemma quo_repr_coset x : x \in G -> rGH (coset H x) = rG x. Proof. exact: quo_mx_coset. Qed. Lemma rcent_quo A : rcent rGH A = (rcent rG A / H)%g. Proof. apply/setP=> Hx; rewrite !inE. apply/andP/idP=> [[]|]; case/morphimP=> x Nx Gx ->{Hx}. by rewrite quo_repr_coset // => cAx; rewrite mem_morphim // inE Gx. by case/setIdP: Gx => Gx cAx; rewrite quo_repr_coset ?mem_morphim. Qed. Lemma rstab_quo m (U : 'M_(m, n)) : rstab rGH U = (rstab rG U / H)%g. Proof. apply/setP=> Hx; rewrite !inE. apply/andP/idP=> [[]|]; case/morphimP=> x Nx Gx ->{Hx}. by rewrite quo_repr_coset // => nUx; rewrite mem_morphim // inE Gx. by case/setIdP: Gx => Gx nUx; rewrite quo_repr_coset ?mem_morphim. Qed. Lemma rker_quo : rker rGH = (rker rG / H)%g. Proof. exact: rstab_quo. Qed. End SubQuotient. Definition kquo_mx := quo_mx (subxx (rker rG)) (rker_norm rG). Lemma kquo_mxE : kquo_mx = quo_mx (subxx (rker rG)) (rker_norm rG). Proof. by []. Qed. Canonical kquo_repr := @MxRepresentation _ _ _ kquo_mx (quo_mx_repr _ _). Lemma kquo_repr_coset x : x \in G -> kquo_repr (coset (rker rG) x) = rG x. Proof. exact: quo_repr_coset. Qed. Lemma kquo_mx_faithful : mx_faithful kquo_repr. Proof. by rewrite /mx_faithful rker_quo trivg_quotient. Qed. End Quotient. Section Regular. Variables (gT : finGroupType) (G : {group gT}). Local Notation nG := #|pred_of_set (gval G)|. Definition gring_index (x : gT) := enum_rank_in (group1 G) x. Lemma gring_valK : cancel enum_val gring_index. Proof. exact: enum_valK_in. Qed. Lemma gring_indexK : {in G, cancel gring_index enum_val}. Proof. exact: enum_rankK_in. Qed. Definition regular_mx x : 'M[R]_nG := \matrix_i delta_mx 0 (gring_index (enum_val i * x)). Lemma regular_mx_repr : mx_repr G regular_mx. Proof. split=> [|x y Gx Gy]; apply/row_matrixP=> i; rewrite !rowK. by rewrite mulg1 row1 gring_valK. by rewrite row_mul rowK -rowE rowK mulgA gring_indexK // groupM ?enum_valP. Qed. Canonical regular_repr := MxRepresentation regular_mx_repr. Local Notation aG := regular_repr. Definition group_ring := enveloping_algebra_mx aG. Local Notation R_G := group_ring. Definition gring_row : 'M[R]_nG -> 'rV_nG := row (gring_index 1). Canonical gring_row_linear := [linear of gring_row]. Lemma gring_row_mul A B : gring_row (A *m B) = gring_row A *m B. Proof. exact: row_mul. Qed. Definition gring_proj x := row (gring_index x) \o trmx \o gring_row. Canonical gring_proj_linear x := [linear of gring_proj x]. Lemma gring_projE : {in G &, forall x y, gring_proj x (aG y) = (x == y)%:R}. Proof. move=> x y Gx Gy; rewrite /gring_proj /= /gring_row rowK gring_indexK //=. rewrite mul1g trmx_delta rowE mul_delta_mx_cond [delta_mx 0 0]mx11_scalar !mxE. by rewrite /= -(inj_eq (can_inj gring_valK)) !gring_indexK. Qed. Lemma regular_mx_faithful : mx_faithful aG. Proof. apply/subsetP=> x /setIdP[Gx]. rewrite mul1mx inE => /eqP/(congr1 (gring_proj 1%g)). rewrite -(repr_mx1 aG) !gring_projE ?group1 // eqxx eq_sym. by case: (x == _) => // /eqP; rewrite eq_sym oner_eq0. Qed. Section GringMx. Variables (n : nat) (rG : mx_representation G n). Definition gring_mx := vec_mx \o mulmxr (enveloping_algebra_mx rG). Canonical gring_mx_linear := [linear of gring_mx]. Lemma gring_mxJ a x : x \in G -> gring_mx (a *m aG x) = gring_mx a *m rG x. Proof. move=> Gx; rewrite /gring_mx /= ![a *m _]mulmx_sum_row. rewrite !(mulmx_suml, linear_sum); apply: eq_bigr => i _. rewrite linearZ -!scalemxAl linearZ /=; congr (_ *: _) => {a}. rewrite !rowK /= !mxvecK -rowE rowK mxvecK. by rewrite gring_indexK ?groupM ?repr_mxM ?enum_valP. Qed. End GringMx. Lemma gring_mxK : cancel (gring_mx aG) gring_row. Proof. move=> a; rewrite /gring_mx /= mulmx_sum_row !linear_sum. rewrite {2}[a]row_sum_delta; apply: eq_bigr => i _. rewrite !linearZ /= /gring_row !(rowK, mxvecK). by rewrite gring_indexK // mul1g gring_valK. Qed. Section GringOp. Variables (n : nat) (rG : mx_representation G n). Definition gring_op := gring_mx rG \o gring_row. Canonical gring_op_linear := [linear of gring_op]. Lemma gring_opE a : gring_op a = gring_mx rG (gring_row a). Proof. by []. Qed. Lemma gring_opG x : x \in G -> gring_op (aG x) = rG x. Proof. move=> Gx; rewrite gring_opE /gring_row rowK gring_indexK // mul1g. by rewrite /gring_mx /= -rowE rowK mxvecK gring_indexK. Qed. Lemma gring_op1 : gring_op 1%:M = 1%:M. Proof. by rewrite -(repr_mx1 aG) gring_opG ?repr_mx1. Qed. Lemma gring_opJ A b : gring_op (A *m gring_mx aG b) = gring_op A *m gring_mx rG b. Proof. rewrite /gring_mx /= ![b *m _]mulmx_sum_row !linear_sum. apply: eq_bigr => i _; rewrite !linearZ /= !rowK !mxvecK. by rewrite gring_opE gring_row_mul gring_mxJ ?enum_valP. Qed. Lemma gring_op_mx b : gring_op (gring_mx aG b) = gring_mx rG b. Proof. by rewrite -[_ b]mul1mx gring_opJ gring_op1 mul1mx. Qed. Lemma gring_mxA a b : gring_mx rG (a *m gring_mx aG b) = gring_mx rG a *m gring_mx rG b. Proof. by rewrite -(gring_op_mx a) -gring_opJ gring_opE gring_row_mul gring_mxK. Qed. End GringOp. End Regular. End RingRepr. Arguments Scope mx_representation [_ _ group_scope nat_scope]. Arguments Scope mx_repr [_ _ group_scope nat_scope _]. Arguments Scope group_ring [_ _ group_scope]. Arguments Scope regular_repr [_ _ group_scope]. Implicit Arguments centgmxP [R gT G n rG f]. Implicit Arguments rkerP [R gT G n rG x]. Prenex Implicits gring_mxK. Section ChangeOfRing. Variables (aR rR : comUnitRingType) (f : {rmorphism aR -> rR}). Local Notation "A ^f" := (map_mx (GRing.RMorphism.apply f) A) : ring_scope. Variables (gT : finGroupType) (G : {group gT}). Lemma map_regular_mx x : (regular_mx aR G x)^f = regular_mx rR G x. Proof. by apply/matrixP=> i j; rewrite !mxE rmorph_nat. Qed. Lemma map_gring_row (A : 'M_#|G|) : (gring_row A)^f = gring_row A^f. Proof. by rewrite map_row. Qed. Lemma map_gring_proj x (A : 'M_#|G|) : (gring_proj x A)^f = gring_proj x A^f. Proof. by rewrite map_row -map_trmx map_gring_row. Qed. Section OneRepresentation. Variables (n : nat) (rG : mx_representation aR G n). Definition map_repr_mx (f0 : aR -> rR) rG0 (g : gT) : 'M_n := map_mx f0 (rG0 g). Lemma map_mx_repr : mx_repr G (map_repr_mx f rG). Proof. split=> [|x y Gx Gy]; first by rewrite /map_repr_mx repr_mx1 map_mx1. by rewrite -map_mxM -repr_mxM. Qed. Canonical map_repr := MxRepresentation map_mx_repr. Local Notation rGf := map_repr. Lemma map_reprE x : rGf x = (rG x)^f. Proof. by []. Qed. Lemma map_reprJ m (A : 'M_(m, n)) x : (A *m rG x)^f = A^f *m rGf x. Proof. exact: map_mxM. Qed. Lemma map_enveloping_algebra_mx : (enveloping_algebra_mx rG)^f = enveloping_algebra_mx rGf. Proof. by apply/row_matrixP=> i; rewrite -map_row !rowK map_mxvec. Qed. Lemma map_gring_mx a : (gring_mx rG a)^f = gring_mx rGf a^f. Proof. by rewrite map_vec_mx map_mxM map_enveloping_algebra_mx. Qed. Lemma map_gring_op A : (gring_op rG A)^f = gring_op rGf A^f. Proof. by rewrite map_gring_mx map_gring_row. Qed. End OneRepresentation. Lemma map_regular_repr : map_repr (regular_repr aR G) =1 regular_repr rR G. Proof. exact: map_regular_mx. Qed. Lemma map_group_ring : (group_ring aR G)^f = group_ring rR G. Proof. rewrite map_enveloping_algebra_mx; apply/row_matrixP=> i. by rewrite !rowK map_regular_repr. Qed. (* Stabilisers, etc, are only mapped properly for fields. *) End ChangeOfRing. Section FieldRepr. Variable F : fieldType. Section OneRepresentation. Variable gT : finGroupType. Variables (G : {group gT}) (n : nat) (rG : mx_representation F G n). Arguments Scope rG [group_scope]. Local Notation E_G := (enveloping_algebra_mx rG). Lemma repr_mx_free x : x \in G -> row_free (rG x). Proof. by move=> Gx; rewrite row_free_unit repr_mx_unit. Qed. Section Stabilisers. Variables (m : nat) (U : 'M[F]_(m, n)). Definition rstabs := [set x in G | U *m rG x <= U]%MS. Lemma rstabs_sub : rstabs \subset G. Proof. by apply/subsetP=> x /setIdP[]. Qed. Lemma rstabs_group_set : group_set rstabs. Proof. apply/group_setP; rewrite inE group1 repr_mx1 mulmx1. split=> //= x y /setIdP[Gx nUx] /setIdP[Gy]; rewrite inE repr_mxM ?groupM //. by apply: submx_trans; rewrite mulmxA submxMr. Qed. Canonical rstabs_group := Group rstabs_group_set. Lemma rstab_act x m1 (W : 'M_(m1, n)) : x \in rstab rG U -> (W <= U)%MS -> W *m rG x = W. Proof. by case/setIdP=> _ /eqP cUx /submxP[w ->]; rewrite -mulmxA cUx. Qed. Lemma rstabs_act x m1 (W : 'M_(m1, n)) : x \in rstabs -> (W <= U)%MS -> (W *m rG x <= U)%MS. Proof. by case/setIdP=> [_ nUx] sWU; apply: submx_trans nUx; exact: submxMr. Qed. Definition mxmodule := G \subset rstabs. Lemma mxmoduleP : reflect {in G, forall x, U *m rG x <= U}%MS mxmodule. Proof. by apply: (iffP subsetP) => modU x Gx; have:= modU x Gx; rewrite !inE ?Gx. Qed. End Stabilisers. Implicit Arguments mxmoduleP [m U]. Lemma rstabS m1 m2 (U : 'M_(m1, n)) (V : 'M_(m2, n)) : (U <= V)%MS -> rstab rG V \subset rstab rG U. Proof. case/submxP=> u ->; apply/subsetP=> x. by rewrite !inE => /andP[-> /= /eqP cVx]; rewrite -mulmxA cVx. Qed. Lemma eqmx_rstab m1 m2 (U : 'M_(m1, n)) (V : 'M_(m2, n)) : (U :=: V)%MS -> rstab rG U = rstab rG V. Proof. by move=> eqUV; apply/eqP; rewrite eqEsubset !rstabS ?eqUV. Qed. Lemma eqmx_rstabs m1 m2 (U : 'M_(m1, n)) (V : 'M_(m2, n)) : (U :=: V)%MS -> rstabs U = rstabs V. Proof. by move=> eqUV; apply/setP=> x; rewrite !inE eqUV (eqmxMr _ eqUV). Qed. Lemma eqmx_module m1 m2 (U : 'M_(m1, n)) (V : 'M_(m2, n)) : (U :=: V)%MS -> mxmodule U = mxmodule V. Proof. by move=> eqUV; rewrite /mxmodule (eqmx_rstabs eqUV). Qed. Lemma mxmodule0 m : mxmodule (0 : 'M_(m, n)). Proof. by apply/mxmoduleP=> x _; rewrite mul0mx. Qed. Lemma mxmodule1 : mxmodule 1%:M. Proof. by apply/mxmoduleP=> x _; rewrite submx1. Qed. Lemma mxmodule_trans m1 m2 (U : 'M_(m1, n)) (W : 'M_(m2, n)) x : mxmodule U -> x \in G -> (W <= U -> W *m rG x <= U)%MS. Proof. by move=> modU Gx sWU; apply: submx_trans (mxmoduleP modU x Gx); exact: submxMr. Qed. Lemma mxmodule_eigenvector m (U : 'M_(m, n)) : mxmodule U -> \rank U = 1%N -> {u : 'rV_n & {a | (U :=: u)%MS & {in G, forall x, u *m rG x = a x *: u}}}. Proof. move=> modU linU; set u := nz_row U; exists u. have defU: (U :=: u)%MS. apply/eqmxP; rewrite andbC -(geq_leqif (mxrank_leqif_eq _)) ?nz_row_sub //. by rewrite linU lt0n mxrank_eq0 nz_row_eq0 -mxrank_eq0 linU. pose a x := (u *m rG x *m pinvmx u) 0 0; exists a => // x Gx. by rewrite -mul_scalar_mx -mx11_scalar mulmxKpV // -defU mxmodule_trans ?defU. Qed. Lemma addsmx_module m1 m2 U V : @mxmodule m1 U -> @mxmodule m2 V -> mxmodule (U + V)%MS. Proof. move=> modU modV; apply/mxmoduleP=> x Gx. by rewrite addsmxMr addsmxS ?(mxmoduleP _ x Gx). Qed. Lemma sumsmx_module I r (P : pred I) U : (forall i, P i -> mxmodule (U i)) -> mxmodule (\sum_(i <- r | P i) U i)%MS. Proof. by move=> modU; elim/big_ind: _; [exact: mxmodule0 | exact: addsmx_module | ]. Qed. Lemma capmx_module m1 m2 U V : @mxmodule m1 U -> @mxmodule m2 V -> mxmodule (U :&: V)%MS. Proof. move=> modU modV; apply/mxmoduleP=> x Gx. by rewrite sub_capmx !mxmodule_trans ?capmxSl ?capmxSr. Qed. Lemma bigcapmx_module I r (P : pred I) U : (forall i, P i -> mxmodule (U i)) -> mxmodule (\bigcap_(i <- r | P i) U i)%MS. Proof. by move=> modU; elim/big_ind: _; [exact: mxmodule1 | exact: capmx_module | ]. Qed. (* Sub- and factor representations induced by a (sub)module. *) Section Submodule. Variable U : 'M[F]_n. Definition val_submod m : 'M_(m, \rank U) -> 'M_(m, n) := mulmxr (row_base U). Definition in_submod m : 'M_(m, n) -> 'M_(m, \rank U) := mulmxr (invmx (row_ebase U) *m pid_mx (\rank U)). Canonical val_submod_linear m := [linear of @val_submod m]. Canonical in_submod_linear m := [linear of @in_submod m]. Lemma val_submodE m W : @val_submod m W = W *m val_submod 1%:M. Proof. by rewrite mulmxA mulmx1. Qed. Lemma in_submodE m W : @in_submod m W = W *m in_submod 1%:M. Proof. by rewrite mulmxA mulmx1. Qed. Lemma val_submod1 : (val_submod 1%:M :=: U)%MS. Proof. by rewrite /val_submod /= mul1mx; exact: eq_row_base. Qed. Lemma val_submodP m W : (@val_submod m W <= U)%MS. Proof. by rewrite mulmx_sub ?eq_row_base. Qed. Lemma val_submodK m : cancel (@val_submod m) (@in_submod m). Proof. move=> W; rewrite /in_submod /= -!mulmxA mulKVmx ?row_ebase_unit //. by rewrite pid_mx_id ?rank_leq_row // pid_mx_1 mulmx1. Qed. Lemma val_submod_inj m : injective (@val_submod m). Proof. exact: can_inj (@val_submodK m). Qed. Lemma val_submodS m1 m2 (V : 'M_(m1, \rank U)) (W : 'M_(m2, \rank U)) : (val_submod V <= val_submod W)%MS = (V <= W)%MS. Proof. apply/idP/idP=> sVW; last exact: submxMr. by rewrite -[V]val_submodK -[W]val_submodK submxMr. Qed. Lemma in_submodK m W : (W <= U)%MS -> val_submod (@in_submod m W) = W. Proof. case/submxP=> w ->; rewrite /val_submod /= -!mulmxA. congr (_ *m _); rewrite -{1}[U]mulmx_ebase !mulmxA mulmxK ?row_ebase_unit //. by rewrite -2!(mulmxA (col_ebase U)) !pid_mx_id ?rank_leq_row // mulmx_ebase. Qed. Lemma val_submod_eq0 m W : (@val_submod m W == 0) = (W == 0). Proof. by rewrite -!submx0 -val_submodS linear0 !(submx0, eqmx0). Qed. Lemma in_submod_eq0 m W : (@in_submod m W == 0) = (W <= U^C)%MS. Proof. apply/eqP/submxP=> [W_U0 | [w ->{W}]]. exists (W *m invmx (row_ebase U)). rewrite mulmxA mulmxBr mulmx1 -(pid_mx_id _ _ _ (leqnn _)). rewrite mulmxA -(mulmxA W) [W *m (_ *m _)]W_U0 mul0mx subr0. by rewrite mulmxKV ?row_ebase_unit. rewrite /in_submod /= -!mulmxA mulKVmx ?row_ebase_unit //. by rewrite mul_copid_mx_pid ?rank_leq_row ?mulmx0. Qed. Lemma mxrank_in_submod m (W : 'M_(m, n)) : (W <= U)%MS -> \rank (in_submod W) = \rank W. Proof. by move=> sWU; apply/eqP; rewrite eqn_leq -{3}(in_submodK sWU) !mxrankM_maxl. Qed. Definition val_factmod m : _ -> 'M_(m, n) := mulmxr (row_base (cokermx U) *m row_ebase U). Definition in_factmod m : 'M_(m, n) -> _ := mulmxr (col_base (cokermx U)). Canonical val_factmod_linear m := [linear of @val_factmod m]. Canonical in_factmod_linear m := [linear of @in_factmod m]. Lemma val_factmodE m W : @val_factmod m W = W *m val_factmod 1%:M. Proof. by rewrite mulmxA mulmx1. Qed. Lemma in_factmodE m W : @in_factmod m W = W *m in_factmod 1%:M. Proof. by rewrite mulmxA mulmx1. Qed. Lemma val_factmodP m W : (@val_factmod m W <= U^C)%MS. Proof. by rewrite mulmx_sub {m W}// (eqmxMr _ (eq_row_base _)) -mulmxA submxMl. Qed. Lemma val_factmodK m : cancel (@val_factmod m) (@in_factmod m). Proof. move=> W /=; rewrite /in_factmod /=; set Uc := cokermx U. apply: (row_free_inj (row_base_free Uc)); rewrite -mulmxA mulmx_base. rewrite /val_factmod /= 2!mulmxA -/Uc mulmxK ?row_ebase_unit //. have /submxP[u ->]: (row_base Uc <= Uc)%MS by rewrite eq_row_base. by rewrite -!mulmxA copid_mx_id ?rank_leq_row. Qed. Lemma val_factmod_inj m : injective (@val_factmod m). Proof. exact: can_inj (@val_factmodK m). Qed. Lemma val_factmodS m1 m2 (V : 'M_(m1, _)) (W : 'M_(m2, _)) : (val_factmod V <= val_factmod W)%MS = (V <= W)%MS. Proof. apply/idP/idP=> sVW; last exact: submxMr. by rewrite -[V]val_factmodK -[W]val_factmodK submxMr. Qed. Lemma val_factmod_eq0 m W : (@val_factmod m W == 0) = (W == 0). Proof. by rewrite -!submx0 -val_factmodS linear0 !(submx0, eqmx0). Qed. Lemma in_factmod_eq0 m (W : 'M_(m, n)) : (in_factmod W == 0) = (W <= U)%MS. Proof. rewrite submxE -!mxrank_eq0 -{2}[_ U]mulmx_base mulmxA. by rewrite (mxrankMfree _ (row_base_free _)). Qed. Lemma in_factmodK m (W : 'M_(m, n)) : (W <= U^C)%MS -> val_factmod (in_factmod W) = W. Proof. case/submxP=> w ->{W}; rewrite /val_factmod /= -2!mulmxA. congr (_ *m _); rewrite (mulmxA (col_base _)) mulmx_base -2!mulmxA. by rewrite mulKVmx ?row_ebase_unit // mulmxA copid_mx_id ?rank_leq_row. Qed. Lemma in_factmod_addsK m (W : 'M_(m, n)) : (in_factmod (U + W)%MS :=: in_factmod W)%MS. Proof. apply: eqmx_trans (addsmxMr _ _ _) _. by rewrite ((_ *m _ =P 0) _) ?in_factmod_eq0 //; exact: adds0mx. Qed. Lemma add_sub_fact_mod m (W : 'M_(m, n)) : val_submod (in_submod W) + val_factmod (in_factmod W) = W. Proof. rewrite /val_submod /val_factmod /= -!mulmxA -mulmxDr. rewrite addrC (mulmxA (pid_mx _)) pid_mx_id // (mulmxA (col_ebase _)). rewrite (mulmxA _ _ (row_ebase _)) mulmx_ebase. rewrite (mulmxA (pid_mx _)) pid_mx_id // mulmxA -mulmxDl -mulmxDr. by rewrite subrK mulmx1 mulmxA mulmxKV ?row_ebase_unit. Qed. Lemma proj_factmodS m (W : 'M_(m, n)) : (val_factmod (in_factmod W) <= U + W)%MS. Proof. by rewrite -{2}[W]add_sub_fact_mod addsmx_addKl ?val_submodP ?addsmxSr. Qed. Lemma in_factmodsK m (W : 'M_(m, n)) : (U <= W)%MS -> (U + val_factmod (in_factmod W) :=: W)%MS. Proof. move/addsmx_idPr; apply: eqmx_trans (eqmx_sym _). by rewrite -{1}[W]add_sub_fact_mod; apply: addsmx_addKl; exact: val_submodP. Qed. Lemma mxrank_in_factmod m (W : 'M_(m, n)) : (\rank (in_factmod W) + \rank U)%N = \rank (U + W). Proof. rewrite -in_factmod_addsK in_factmodE; set fU := in_factmod 1%:M. suffices <-: ((U + W) :&: kermx fU :=: U)%MS by rewrite mxrank_mul_ker. apply: eqmx_trans (capmx_idPr (addsmxSl U W)). apply: cap_eqmx => //; apply/eqmxP/rV_eqP => u. by rewrite (sameP sub_kermxP eqP) -in_factmodE in_factmod_eq0. Qed. Definition submod_mx of mxmodule U := fun x => in_submod (val_submod 1%:M *m rG x). Definition factmod_mx of mxmodule U := fun x => in_factmod (val_factmod 1%:M *m rG x). Hypothesis Umod : mxmodule U. Lemma in_submodJ m (W : 'M_(m, n)) x : (W <= U)%MS -> in_submod (W *m rG x) = in_submod W *m submod_mx Umod x. Proof. move=> sWU; rewrite mulmxA; congr (in_submod _). by rewrite mulmxA -val_submodE in_submodK. Qed. Lemma val_submodJ m (W : 'M_(m, \rank U)) x : x \in G -> val_submod (W *m submod_mx Umod x) = val_submod W *m rG x. Proof. move=> Gx; rewrite 2!(mulmxA W) -val_submodE in_submodK //. by rewrite mxmodule_trans ?val_submodP. Qed. Lemma submod_mx_repr : mx_repr G (submod_mx Umod). Proof. rewrite /submod_mx; split=> [|x y Gx Gy /=]. by rewrite repr_mx1 mulmx1 val_submodK. rewrite -in_submodJ; first by rewrite repr_mxM ?mulmxA. by rewrite mxmodule_trans ?val_submodP. Qed. Canonical submod_repr := MxRepresentation submod_mx_repr. Lemma in_factmodJ m (W : 'M_(m, n)) x : x \in G -> in_factmod (W *m rG x) = in_factmod W *m factmod_mx Umod x. Proof. move=> Gx; rewrite -{1}[W]add_sub_fact_mod mulmxDl linearD /=. apply: (canLR (subrK _)); apply: etrans (_ : 0 = _). apply/eqP; rewrite in_factmod_eq0 (submx_trans _ (mxmoduleP Umod x Gx)) //. by rewrite submxMr ?val_submodP. by rewrite /in_factmod /val_factmod /= !mulmxA mulmx1 ?subrr. Qed. Lemma val_factmodJ m (W : 'M_(m, \rank (cokermx U))) x : x \in G -> val_factmod (W *m factmod_mx Umod x) = val_factmod (in_factmod (val_factmod W *m rG x)). Proof. by move=> Gx; rewrite -{1}[W]val_factmodK -in_factmodJ. Qed. Lemma factmod_mx_repr : mx_repr G (factmod_mx Umod). Proof. split=> [|x y Gx Gy /=]. by rewrite /factmod_mx repr_mx1 mulmx1 val_factmodK. by rewrite -in_factmodJ // -mulmxA -repr_mxM. Qed. Canonical factmod_repr := MxRepresentation factmod_mx_repr. (* For character theory. *) Lemma mxtrace_sub_fact_mod x : \tr (submod_repr x) + \tr (factmod_repr x) = \tr (rG x). Proof. rewrite -[submod_repr x]mulmxA mxtrace_mulC -val_submodE addrC. rewrite -[factmod_repr x]mulmxA mxtrace_mulC -val_factmodE addrC. by rewrite -mxtraceD add_sub_fact_mod. Qed. End Submodule. (* Properties of enveloping algebra as a subspace of 'rV_(n ^ 2). *) Lemma envelop_mx_id x : x \in G -> (rG x \in E_G)%MS. Proof. by move=> Gx; rewrite (eq_row_sub (enum_rank_in Gx x)) // rowK enum_rankK_in. Qed. Lemma envelop_mx1 : (1%:M \in E_G)%MS. Proof. by rewrite -(repr_mx1 rG) envelop_mx_id. Qed. Lemma envelop_mxP A : reflect (exists a, A = \sum_(x in G) a x *: rG x) (A \in E_G)%MS. Proof. have G_1 := group1 G; have bijG := enum_val_bij_in G_1. set h := enum_val in bijG; have Gh: h _ \in G by exact: enum_valP. apply: (iffP submxP) => [[u defA] | [a ->]]. exists (fun x => u 0 (enum_rank_in G_1 x)); apply: (can_inj mxvecK). rewrite defA mulmx_sum_row linear_sum (reindex h) //=. by apply: eq_big => [i | i _]; rewrite ?Gh // rowK linearZ enum_valK_in. exists (\row_i a (h i)); rewrite mulmx_sum_row linear_sum (reindex h) //=. by apply: eq_big => [i | i _]; rewrite ?Gh // mxE rowK linearZ. Qed. Lemma envelop_mxM A B : (A \in E_G -> B \in E_G -> A *m B \in E_G)%MS. Proof. case/envelop_mxP=> a ->{A}; case/envelop_mxP=> b ->{B}. rewrite mulmx_suml !linear_sum summx_sub //= => x Gx. rewrite !linear_sum summx_sub //= => y Gy. rewrite -scalemxAl !(linearZ, scalemx_sub) //= -repr_mxM //. by rewrite envelop_mx_id ?groupM. Qed. Lemma mxmodule_envelop m1 m2 (U : 'M_(m1, n)) (W : 'M_(m2, n)) A : (mxmodule U -> mxvec A <= E_G -> W <= U -> W *m A <= U)%MS. Proof. move=> modU /envelop_mxP[a ->] sWU; rewrite linear_sum summx_sub // => x Gx. by rewrite linearZ scalemx_sub ?mxmodule_trans. Qed. (* Module homomorphisms; any square matrix f defines a module homomorphism *) (* over some domain, namely, dom_hom_mx f. *) Definition dom_hom_mx f : 'M_n := kermx (lin1_mx (mxvec \o mulmx (cent_mx_fun E_G f) \o lin_mul_row)). Lemma hom_mxP m f (W : 'M_(m, n)) : reflect (forall x, x \in G -> W *m rG x *m f = W *m f *m rG x) (W <= dom_hom_mx f)%MS. Proof. apply: (iffP row_subP) => [cGf x Gx | cGf i]. apply/row_matrixP=> i; apply/eqP; rewrite -subr_eq0 -!mulmxA -!linearB /=. have:= sub_kermxP (cGf i); rewrite mul_rV_lin1 /=. move/(canRL mxvecK)/row_matrixP/(_ (enum_rank_in Gx x))/eqP; rewrite !linear0. by rewrite !row_mul rowK mul_vec_lin /= mul_vec_lin_row enum_rankK_in. apply/sub_kermxP; rewrite mul_rV_lin1 /=; apply: (canLR vec_mxK). apply/row_matrixP=> j; rewrite !row_mul rowK mul_vec_lin /= mul_vec_lin_row. by rewrite -!row_mul mulmxBr !mulmxA cGf ?enum_valP // subrr !linear0. Qed. Implicit Arguments hom_mxP [m f W]. Lemma hom_envelop_mxC m f (W : 'M_(m, n)) A : (W <= dom_hom_mx f -> A \in E_G -> W *m A *m f = W *m f *m A)%MS. Proof. move/hom_mxP=> cWfG /envelop_mxP[a ->]; rewrite !linear_sum mulmx_suml. by apply: eq_bigr => x Gx; rewrite !linearZ -scalemxAl /= cWfG. Qed. Lemma dom_hom_invmx f : f \in unitmx -> (dom_hom_mx (invmx f) :=: dom_hom_mx f *m f)%MS. Proof. move=> injf; set U := dom_hom_mx _; apply/eqmxP. rewrite -{1}[U](mulmxKV injf) submxMr; apply/hom_mxP=> x Gx. by rewrite -[_ *m rG x](hom_mxP _) ?mulmxK. by rewrite -[_ *m rG x](hom_mxP _) ?mulmxKV. Qed. Lemma dom_hom_mx_module f : mxmodule (dom_hom_mx f). Proof. apply/mxmoduleP=> x Gx; apply/hom_mxP=> y Gy. rewrite -[_ *m rG y]mulmxA -repr_mxM // 2?(hom_mxP _) ?groupM //. by rewrite repr_mxM ?mulmxA. Qed. Lemma hom_mxmodule m (U : 'M_(m, n)) f : (U <= dom_hom_mx f)%MS -> mxmodule U -> mxmodule (U *m f). Proof. move/hom_mxP=> cGfU modU; apply/mxmoduleP=> x Gx. by rewrite -cGfU // submxMr // (mxmoduleP modU). Qed. Lemma kermx_hom_module m (U : 'M_(m, n)) f : (U <= dom_hom_mx f)%MS -> mxmodule U -> mxmodule (U :&: kermx f)%MS. Proof. move=> homUf modU; apply/mxmoduleP=> x Gx. rewrite sub_capmx mxmodule_trans ?capmxSl //=. apply/sub_kermxP; rewrite (hom_mxP _) ?(submx_trans (capmxSl _ _)) //. by rewrite (sub_kermxP (capmxSr _ _)) mul0mx. Qed. Lemma scalar_mx_hom a m (U : 'M_(m, n)) : (U <= dom_hom_mx a%:M)%MS. Proof. by apply/hom_mxP=> x Gx; rewrite -!mulmxA scalar_mxC. Qed. Lemma proj_mx_hom (U V : 'M_n) : (U :&: V = 0)%MS -> mxmodule U -> mxmodule V -> (U + V <= dom_hom_mx (proj_mx U V))%MS. Proof. move=> dxUV modU modV; apply/hom_mxP=> x Gx. rewrite -{1}(add_proj_mx dxUV (submx_refl _)) !mulmxDl addrC. rewrite {1}[_ *m _]proj_mx_0 ?add0r //; last first. by rewrite mxmodule_trans ?proj_mx_sub. by rewrite [_ *m _](proj_mx_id dxUV) // mxmodule_trans ?proj_mx_sub. Qed. (* The subspace fixed by a subgroup H of G; it is a module if H <| G. *) (* The definition below is extensionally equivalent to the straightforward *) (* \bigcap_(x in H) kermx (rG x - 1%:M) *) (* but it avoids the dependency on the choice function; this allows it to *) (* commute with ring morphisms. *) Definition rfix_mx (H : {set gT}) := let commrH := \matrix_(i < #|H|) mxvec (rG (enum_val i) - 1%:M) in kermx (lin1_mx (mxvec \o mulmx commrH \o lin_mul_row)). Lemma rfix_mxP m (W : 'M_(m, n)) (H : {set gT}) : reflect (forall x, x \in H -> W *m rG x = W) (W <= rfix_mx H)%MS. Proof. rewrite /rfix_mx; set C := \matrix_i _. apply: (iffP row_subP) => [cHW x Hx | cHW j]. apply/row_matrixP=> j; apply/eqP; rewrite -subr_eq0 row_mul. move/sub_kermxP: {cHW}(cHW j); rewrite mul_rV_lin1 /=; move/(canRL mxvecK). move/row_matrixP/(_ (enum_rank_in Hx x)); rewrite row_mul rowK !linear0. by rewrite enum_rankK_in // mul_vec_lin_row mulmxBr mulmx1 => ->. apply/sub_kermxP; rewrite mul_rV_lin1 /=; apply: (canLR vec_mxK). apply/row_matrixP=> i; rewrite row_mul rowK mul_vec_lin_row -row_mul. by rewrite mulmxBr mulmx1 cHW ?enum_valP // subrr !linear0. Qed. Implicit Arguments rfix_mxP [m W]. Lemma rfix_mx_id (H : {set gT}) x : x \in H -> rfix_mx H *m rG x = rfix_mx H. Proof. exact/rfix_mxP. Qed. Lemma rfix_mxS (H K : {set gT}) : H \subset K -> (rfix_mx K <= rfix_mx H)%MS. Proof. by move=> sHK; apply/rfix_mxP=> x Hx; exact: rfix_mxP (subsetP sHK x Hx). Qed. Lemma rfix_mx_conjsg (H : {set gT}) x : x \in G -> H \subset G -> (rfix_mx (H :^ x) :=: rfix_mx H *m rG x)%MS. Proof. move=> Gx sHG; pose rf y := rfix_mx (H :^ y). suffices{x Gx} IH: {in G &, forall y z, rf y *m rG z <= rf (y * z)%g}%MS. apply/eqmxP; rewrite -/(rf x) -[H]conjsg1 -/(rf 1%g). rewrite -{4}[x] mul1g -{1}[rf x](repr_mxKV rG Gx) -{1}(mulgV x). by rewrite submxMr IH ?groupV. move=> x y Gx Gy; apply/rfix_mxP=> zxy; rewrite actM => /imsetP[zx Hzx ->]. have Gzx: zx \in G by apply: subsetP Hzx; rewrite conj_subG. rewrite -mulmxA -repr_mxM ?groupM ?groupV // -conjgC repr_mxM // mulmxA. by rewrite rfix_mx_id. Qed. Lemma norm_sub_rstabs_rfix_mx (H : {set gT}) : H \subset G -> 'N_G(H) \subset rstabs (rfix_mx H). Proof. move=> sHG; apply/subsetP=> x /setIP[Gx nHx]; rewrite inE Gx. apply/rfix_mxP=> y Hy; have Gy := subsetP sHG y Hy. have Hyx: (y ^ x^-1)%g \in H by rewrite memJ_norm ?groupV. rewrite -mulmxA -repr_mxM // conjgCV repr_mxM ?(subsetP sHG _ Hyx) // mulmxA. by rewrite (rfix_mx_id Hyx). Qed. Lemma normal_rfix_mx_module H : H <| G -> mxmodule (rfix_mx H). Proof. case/andP=> sHG nHG. by rewrite /mxmodule -{1}(setIidPl nHG) norm_sub_rstabs_rfix_mx. Qed. Lemma rfix_mx_module : mxmodule (rfix_mx G). Proof. exact: normal_rfix_mx_module. Qed. Lemma rfix_mx_rstabC (H : {set gT}) m (U : 'M[F]_(m, n)) : H \subset G -> (H \subset rstab rG U) = (U <= rfix_mx H)%MS. Proof. move=> sHG; apply/subsetP/rfix_mxP=> cHU x Hx. by rewrite (rstab_act (cHU x Hx)). by rewrite !inE (subsetP sHG) //= cHU. Qed. (* The cyclic module generated by a single vector. *) Definition cyclic_mx u := <>%MS. Lemma cyclic_mxP u v : reflect (exists2 A, A \in E_G & v = u *m A)%MS (v <= cyclic_mx u)%MS. Proof. rewrite genmxE; apply: (iffP submxP) => [[a] | [A /submxP[a defA]]] -> {v}. exists (vec_mx (a *m E_G)); last by rewrite mulmxA mul_rV_lin1. by rewrite vec_mxK submxMl. by exists a; rewrite mulmxA mul_rV_lin1 /= -defA mxvecK. Qed. Implicit Arguments cyclic_mxP [u v]. Lemma cyclic_mx_id u : (u <= cyclic_mx u)%MS. Proof. by apply/cyclic_mxP; exists 1%:M; rewrite ?mulmx1 ?envelop_mx1. Qed. Lemma cyclic_mx_eq0 u : (cyclic_mx u == 0) = (u == 0). Proof. rewrite -!submx0; apply/idP/idP. by apply: submx_trans; exact: cyclic_mx_id. move/submx0null->; rewrite genmxE; apply/row_subP=> i. by rewrite row_mul mul_rV_lin1 /= mul0mx ?sub0mx. Qed. Lemma cyclic_mx_module u : mxmodule (cyclic_mx u). Proof. apply/mxmoduleP=> x Gx; apply/row_subP=> i; rewrite row_mul. have [A E_A ->{i}] := @cyclic_mxP u _ (row_sub i _); rewrite -mulmxA. by apply/cyclic_mxP; exists (A *m rG x); rewrite ?envelop_mxM ?envelop_mx_id. Qed. Lemma cyclic_mx_sub m u (W : 'M_(m, n)) : mxmodule W -> (u <= W)%MS -> (cyclic_mx u <= W)%MS. Proof. move=> modU Wu; rewrite genmxE; apply/row_subP=> i. by rewrite row_mul mul_rV_lin1 /= mxmodule_envelop // vec_mxK row_sub. Qed. Lemma hom_cyclic_mx u f : (u <= dom_hom_mx f)%MS -> (cyclic_mx u *m f :=: cyclic_mx (u *m f))%MS. Proof. move=> domf_u; apply/eqmxP; rewrite !(eqmxMr _ (genmxE _)). apply/genmxP; rewrite genmx_id; congr <<_>>%MS; apply/row_matrixP=> i. by rewrite !row_mul !mul_rV_lin1 /= hom_envelop_mxC // vec_mxK row_sub. Qed. (* The annihilator of a single vector. *) Definition annihilator_mx u := (E_G :&: kermx (lin_mul_row u))%MS. Lemma annihilator_mxP u A : reflect (A \in E_G /\ u *m A = 0)%MS (A \in annihilator_mx u)%MS. Proof. rewrite sub_capmx; apply: (iffP andP) => [[-> /sub_kermxP]|[-> uA0]]. by rewrite mul_rV_lin1 /= mxvecK. by split=> //; apply/sub_kermxP; rewrite mul_rV_lin1 /= mxvecK. Qed. (* The subspace of homomorphic images of a row vector. *) Definition row_hom_mx u := (\bigcap_j kermx (vec_mx (row j (annihilator_mx u))))%MS. Lemma row_hom_mxP u v : reflect (exists2 f, u <= dom_hom_mx f & u *m f = v)%MS (v <= row_hom_mx u)%MS. Proof. apply: (iffP sub_bigcapmxP) => [iso_uv | [f hom_uf <-] i _]. have{iso_uv} uv0 A: (A \in E_G)%MS /\ u *m A = 0 -> v *m A = 0. move/annihilator_mxP=> /submxP[a defA]. rewrite -[A]mxvecK {A}defA [a *m _]mulmx_sum_row !linear_sum big1 // => i _. by rewrite !linearZ /= (sub_kermxP _) ?scaler0 ?iso_uv. pose U := E_G *m lin_mul_row u; pose V := E_G *m lin_mul_row v. pose f := pinvmx U *m V. have hom_uv_f x: x \in G -> u *m rG x *m f = v *m rG x. move=> Gx; apply/eqP; rewrite 2!mulmxA mul_rV_lin1 -subr_eq0 -mulmxBr. rewrite uv0 // 2!linearB /= vec_mxK; split. by rewrite addmx_sub ?submxMl // eqmx_opp envelop_mx_id. have Uux: (u *m rG x <= U)%MS. by rewrite -(genmxE U) mxmodule_trans ?cyclic_mx_id ?cyclic_mx_module. by rewrite -{2}(mulmxKpV Uux) [_ *m U]mulmxA mul_rV_lin1 subrr. have def_uf: u *m f = v. by rewrite -[u]mulmx1 -[v]mulmx1 -(repr_mx1 rG) hom_uv_f. by exists f => //; apply/hom_mxP=> x Gx; rewrite def_uf hom_uv_f. apply/sub_kermxP; set A := vec_mx _. have: (A \in annihilator_mx u)%MS by rewrite vec_mxK row_sub. by case/annihilator_mxP => E_A uA0; rewrite -hom_envelop_mxC // uA0 mul0mx. Qed. (* Sub-, isomorphic, simple, semisimple and completely reducible modules. *) (* All these predicates are intuitionistic (since, e.g., testing simplicity *) (* requires a splitting algorithm fo r the mas field). They are all *) (* specialized to square matrices, to avoid spurrious height parameters. *) (* Module isomorphism is an intentional property in general, but it can be *) (* decided when one of the two modules is known to be simple. *) CoInductive mx_iso (U V : 'M_n) : Prop := MxIso f of f \in unitmx & (U <= dom_hom_mx f)%MS & (U *m f :=: V)%MS. Lemma eqmx_iso U V : (U :=: V)%MS -> mx_iso U V. Proof. by move=> eqUV; exists 1%:M; rewrite ?unitmx1 ?scalar_mx_hom ?mulmx1. Qed. Lemma mx_iso_refl U : mx_iso U U. Proof. exact: eqmx_iso. Qed. Lemma mx_iso_sym U V : mx_iso U V -> mx_iso V U. Proof. case=> f injf homUf defV; exists (invmx f); first by rewrite unitmx_inv. by rewrite dom_hom_invmx // -defV submxMr. by rewrite -[U](mulmxK injf); exact: eqmxMr (eqmx_sym _). Qed. Lemma mx_iso_trans U V W : mx_iso U V -> mx_iso V W -> mx_iso U W. Proof. case=> f injf homUf defV [g injg homVg defW]. exists (f *m g); first by rewrite unitmx_mul injf. by apply/hom_mxP=> x Gx; rewrite !mulmxA 2?(hom_mxP _) ?defV. by rewrite mulmxA; exact: eqmx_trans (eqmxMr g defV) defW. Qed. Lemma mxrank_iso U V : mx_iso U V -> \rank U = \rank V. Proof. by case=> f injf _ <-; rewrite mxrankMfree ?row_free_unit. Qed. Lemma mx_iso_module U V : mx_iso U V -> mxmodule U -> mxmodule V. Proof. by case=> f _ homUf defV; rewrite -(eqmx_module defV); exact: hom_mxmodule. Qed. (* Simple modules (we reserve the term "irreducible" for representations). *) Definition mxsimple (V : 'M_n) := [/\ mxmodule V, V != 0 & forall U : 'M_n, mxmodule U -> (U <= V)%MS -> U != 0 -> (V <= U)%MS]. Definition mxnonsimple (U : 'M_n) := exists V : 'M_n, [&& mxmodule V, (V <= U)%MS, V != 0 & \rank V < \rank U]. Lemma mxsimpleP U : [/\ mxmodule U, U != 0 & ~ mxnonsimple U] <-> mxsimple U. Proof. do [split => [] [modU nzU simU]; split] => // [V modV sVU nzV | [V]]. apply/idPn; rewrite -(ltn_leqif (mxrank_leqif_sup sVU)) => ltVU. by case: simU; exists V; exact/and4P. by case/and4P=> modV sVU nzV; apply/negP; rewrite -leqNgt mxrankS ?simU. Qed. Lemma mxsimple_module U : mxsimple U -> mxmodule U. Proof. by case. Qed. Lemma mxsimple_exists m (U : 'M_(m, n)) : mxmodule U -> U != 0 -> classically (exists2 V, mxsimple V & V <= U)%MS. Proof. move=> modU nzU [] // simU; move: {2}_.+1 (ltnSn (\rank U)) => r leUr. elim: r => // r IHr in m U leUr modU nzU simU. have genU := genmxE U; apply simU; exists <>%MS; last by rewrite genU. apply/mxsimpleP; split; rewrite ?(eqmx_eq0 genU) ?(eqmx_module genU) //. case=> V; rewrite !genU=> /and4P[modV sVU nzV ltVU]; case: notF. apply: IHr nzV _ => // [|[W simW sWV]]; first exact: leq_trans ltVU _. by apply: simU; exists W => //; exact: submx_trans sWV sVU. Qed. Lemma mx_iso_simple U V : mx_iso U V -> mxsimple U -> mxsimple V. Proof. move=> isoUV [modU nzU simU]; have [f injf homUf defV] := isoUV. split=> [||W modW sWV nzW]; first by rewrite (mx_iso_module isoUV). by rewrite -(eqmx_eq0 defV) -(mul0mx n f) (can_eq (mulmxK injf)). rewrite -defV -[W](mulmxKV injf) submxMr //; set W' := W *m _. have sW'U: (W' <= U)%MS by rewrite -[U](mulmxK injf) submxMr ?defV. rewrite (simU W') //; last by rewrite -(can_eq (mulmxK injf)) mul0mx mulmxKV. rewrite hom_mxmodule ?dom_hom_invmx // -[W](mulmxKV injf) submxMr //. exact: submx_trans sW'U homUf. Qed. Lemma mxsimple_cyclic u U : mxsimple U -> u != 0 -> (u <= U)%MS -> (U :=: cyclic_mx u)%MS. Proof. case=> [modU _ simU] nz_u Uu; apply/eqmxP; set uG := cyclic_mx u. have s_uG_U: (uG <= U)%MS by rewrite cyclic_mx_sub. by rewrite simU ?cyclic_mx_eq0 ?submx_refl // cyclic_mx_module. Qed. (* The surjective part of Schur's lemma. *) Lemma mx_Schur_onto m (U : 'M_(m, n)) V f : mxmodule U -> mxsimple V -> (U <= dom_hom_mx f)%MS -> (U *m f <= V)%MS -> U *m f != 0 -> (U *m f :=: V)%MS. Proof. move=> modU [modV _ simV] homUf sUfV nzUf. apply/eqmxP; rewrite sUfV -(genmxE (U *m f)). rewrite simV ?(eqmx_eq0 (genmxE _)) ?genmxE //. by rewrite (eqmx_module (genmxE _)) hom_mxmodule. Qed. (* The injective part of Schur's lemma. *) Lemma mx_Schur_inj U f : mxsimple U -> (U <= dom_hom_mx f)%MS -> U *m f != 0 -> (U :&: kermx f)%MS = 0. Proof. case=> [modU _ simU] homUf nzUf; apply/eqP; apply: contraR nzUf => nz_ker. rewrite (sameP eqP sub_kermxP) (sameP capmx_idPl eqmxP) simU ?capmxSl //. exact: kermx_hom_module. Qed. (* The injectve part of Schur's lemma, stated as isomorphism with the image. *) Lemma mx_Schur_inj_iso U f : mxsimple U -> (U <= dom_hom_mx f)%MS -> U *m f != 0 -> mx_iso U (U *m f). Proof. move=> simU homUf nzUf; have [modU _ _] := simU. have eqUfU: \rank (U *m f) = \rank U by apply/mxrank_injP; rewrite mx_Schur_inj. have{eqUfU} [g invg defUf] := complete_unitmx eqUfU. suffices homUg: (U <= dom_hom_mx g)%MS by exists g; rewrite ?defUf. apply/hom_mxP=> x Gx; have [ux defUx] := submxP (mxmoduleP modU x Gx). by rewrite -defUf -(hom_mxP homUf) // defUx -!(mulmxA ux) defUf. Qed. (* The isomorphism part of Schur's lemma. *) Lemma mx_Schur_iso U V f : mxsimple U -> mxsimple V -> (U <= dom_hom_mx f)%MS -> (U *m f <= V)%MS -> U *m f != 0 -> mx_iso U V. Proof. move=> simU simV homUf sUfV nzUf; have [modU _ _] := simU. have [g invg homUg defUg] := mx_Schur_inj_iso simU homUf nzUf. exists g => //; apply: mx_Schur_onto; rewrite ?defUg //. by rewrite -!submx0 defUg in nzUf *. Qed. (* A boolean test for module isomorphism that is only valid for simple *) (* modules; this is the only case that matters in practice. *) Lemma nz_row_mxsimple U : mxsimple U -> nz_row U != 0. Proof. by case=> _ nzU _; rewrite nz_row_eq0. Qed. Definition mxsimple_iso (U V : 'M_n) := [&& mxmodule V, (V :&: row_hom_mx (nz_row U))%MS != 0 & \rank V <= \rank U]. Lemma mxsimple_isoP U V : mxsimple U -> reflect (mx_iso U V) (mxsimple_iso U V). Proof. move=> simU; pose u := nz_row U. have [Uu nz_u]: (u <= U)%MS /\ u != 0 by rewrite nz_row_sub nz_row_mxsimple. apply: (iffP and3P) => [[modV] | isoUV]; last first. split; last by rewrite (mxrank_iso isoUV). by case: (mx_iso_simple isoUV simU). have [f injf homUf defV] := isoUV; apply/rowV0Pn; exists (u *m f). rewrite sub_capmx -defV submxMr //. by apply/row_hom_mxP; exists f; first exact: (submx_trans Uu). by rewrite -(mul0mx _ f) (can_eq (mulmxK injf)) nz_u. case/rowV0Pn=> v; rewrite sub_capmx => /andP[Vv]. case/row_hom_mxP => f homMf def_v nz_v eqrUV. pose uG := cyclic_mx u; pose vG := cyclic_mx v. have def_vG: (uG *m f :=: vG)%MS by rewrite /vG -def_v; exact: hom_cyclic_mx. have defU: (U :=: uG)%MS by exact: mxsimple_cyclic. have mod_uG: mxmodule uG by rewrite cyclic_mx_module. have homUf: (U <= dom_hom_mx f)%MS. by rewrite defU cyclic_mx_sub ?dom_hom_mx_module. have isoUf: mx_iso U (U *m f). apply: mx_Schur_inj_iso => //; apply: contra nz_v; rewrite -!submx0. by rewrite (eqmxMr f defU) def_vG; exact: submx_trans (cyclic_mx_id v). apply: mx_iso_trans (isoUf) (eqmx_iso _); apply/eqmxP. have sUfV: (U *m f <= V)%MS by rewrite (eqmxMr f defU) def_vG cyclic_mx_sub. by rewrite -mxrank_leqif_eq ?eqn_leq 1?mxrankS // -(mxrank_iso isoUf). Qed. Lemma mxsimple_iso_simple U V : mxsimple_iso U V -> mxsimple U -> mxsimple V. Proof. by move=> isoUV simU; apply: mx_iso_simple (simU); exact/mxsimple_isoP. Qed. (* For us, "semisimple" means "sum of simple modules"; this is classically, *) (* but not intuitionistically, equivalent to the "completely reducible" *) (* alternate characterization. *) Implicit Type I : finType. CoInductive mxsemisimple (V : 'M_n) := MxSemisimple I U (W := (\sum_(i : I) U i)%MS) of forall i, mxsimple (U i) & (W :=: V)%MS & mxdirect W. (* This is a slight generalization of Aschbacher 12.5 for finite sets. *) Lemma sum_mxsimple_direct_compl m I W (U : 'M_(m, n)) : let V := (\sum_(i : I) W i)%MS in (forall i : I, mxsimple (W i)) -> mxmodule U -> (U <= V)%MS -> {J : {set I} | let S := U + \sum_(i in J) W i in S :=: V /\ mxdirect S}%MS. Proof. move=> V simW modU sUV; pose V_ (J : {set I}) := (\sum_(i in J) W i)%MS. pose dxU (J : {set I}) := mxdirect (U + V_ J). have [J maxJ]: {J | maxset dxU J}; last case/maxsetP: maxJ => dxUVJ maxJ. apply: ex_maxset; exists set0. by rewrite /dxU mxdirectE /V_ /= !big_set0 addn0 addsmx0 /=. have modWJ: mxmodule (V_ J) by apply: sumsmx_module => i _; case: (simW i). exists J; split=> //; apply/eqmxP; rewrite addsmx_sub sUV; apply/andP; split. by apply/sumsmx_subP=> i Ji; rewrite (sumsmx_sup i). rewrite -/(V_ J); apply/sumsmx_subP=> i _. case Ji: (i \in J). by apply: submx_trans (addsmxSr _ _); exact: (sumsmx_sup i). have [modWi nzWi simWi] := simW i. rewrite (sameP capmx_idPl eqmxP) simWi ?capmxSl ?capmx_module ?addsmx_module //. apply: contraFT (Ji); rewrite negbK => dxWiUVJ. rewrite -(maxJ (i |: J)) ?setU11 ?subsetUr // /dxU. rewrite mxdirectE /= !big_setU1 ?Ji //=. rewrite addnCA addsmxA (addsmxC U) -addsmxA -mxdirectE /=. by rewrite mxdirect_addsE /= mxdirect_trivial -/(dxU _) dxUVJ. Qed. Lemma sum_mxsimple_direct_sub I W (V : 'M_n) : (forall i : I, mxsimple (W i)) -> (\sum_i W i :=: V)%MS -> {J : {set I} | let S := \sum_(i in J) W i in S :=: V /\ mxdirect S}%MS. Proof. move=> simW defV. have [|J [defS dxS]] := sum_mxsimple_direct_compl simW (mxmodule0 n). exact: sub0mx. exists J; split; last by rewrite mxdirectE /= adds0mx mxrank0 in dxS. by apply: eqmx_trans defV; rewrite adds0mx_id in defS. Qed. Lemma mxsemisimple0 : mxsemisimple 0. Proof. exists [finType of 'I_0] (fun _ => 0); [by case | by rewrite big_ord0 | ]. by rewrite mxdirectE /= !big_ord0 mxrank0. Qed. Lemma intro_mxsemisimple (I : Type) r (P : pred I) W V : (\sum_(i <- r | P i) W i :=: V)%MS -> (forall i, P i -> W i != 0 -> mxsimple (W i)) -> mxsemisimple V. Proof. move=> defV simW; pose W_0 := [pred i | W i == 0]. have [-> | nzV] := eqVneq V 0; first exact: mxsemisimple0. case def_r: r => [| i0 r'] => [|{r' def_r}]. by rewrite -mxrank_eq0 -defV def_r big_nil mxrank0 in nzV. move: defV; rewrite (bigID W_0) /= addsmxC -big_filter !(big_nth i0) !big_mkord. rewrite addsmxC big1 ?adds0mx_id => [|i /andP[_ /eqP] //]. set tI := 'I_(_); set r_ := nth _ _ => defV. have{simW} simWr (i : tI) : mxsimple (W (r_ i)). case: i => m /=; set Pr := fun i => _ => lt_m_r /=. suffices: (Pr (r_ m)) by case/andP; exact: simW. apply: all_nthP m lt_m_r; apply/all_filterP. by rewrite -filter_predI; apply: eq_filter => i; rewrite /= andbb. have [J []] := sum_mxsimple_direct_sub simWr defV. case: (set_0Vmem J) => [-> V0 | [j0 Jj0]]. by rewrite -mxrank_eq0 -V0 big_set0 mxrank0 in nzV. pose K := {j | j \in J}; pose k0 : K := Sub j0 Jj0. have bij_KJ: {on J, bijective (sval : K -> _)}. by exists (insubd k0) => [k _ | j Jj]; rewrite ?valKd ?insubdK. have J_K (k : K) : sval k \in J by exact: valP k. rewrite mxdirectE /= !(reindex _ bij_KJ) !(eq_bigl _ _ J_K) -mxdirectE /= -/tI. exact: MxSemisimple. Qed. Lemma mxsimple_semisimple U : mxsimple U -> mxsemisimple U. Proof. move=> simU; apply: (intro_mxsemisimple (_ : \sum_(i < 1) U :=: U))%MS => //. by rewrite big_ord1. Qed. Lemma addsmx_semisimple U V : mxsemisimple U -> mxsemisimple V -> mxsemisimple (U + V)%MS. Proof. case=> [I W /= simW defU _] [J T /= simT defV _]. have defUV: (\sum_ij sum_rect (fun _ => 'M_n) W T ij :=: U + V)%MS. by rewrite big_sumType /=; exact: adds_eqmx. by apply: intro_mxsemisimple defUV _; case=> /=. Qed. Lemma sumsmx_semisimple (I : finType) (P : pred I) V : (forall i, P i -> mxsemisimple (V i)) -> mxsemisimple (\sum_(i | P i) V i)%MS. Proof. move=> ssimV; elim/big_ind: _ => //; first exact: mxsemisimple0. exact: addsmx_semisimple. Qed. Lemma eqmx_semisimple U V : (U :=: V)%MS -> mxsemisimple U -> mxsemisimple V. Proof. by move=> eqUV [I W S simW defU dxS]; exists I W => //; exact: eqmx_trans eqUV. Qed. Lemma hom_mxsemisimple (V f : 'M_n) : mxsemisimple V -> (V <= dom_hom_mx f)%MS -> mxsemisimple (V *m f). Proof. case=> I W /= simW defV _; rewrite -defV => /sumsmx_subP homWf. have{defV} defVf: (\sum_i W i *m f :=: V *m f)%MS. by apply: eqmx_trans (eqmx_sym _) (eqmxMr f defV); exact: sumsmxMr. apply: (intro_mxsemisimple defVf) => i _ nzWf. by apply: mx_iso_simple (simW i); apply: mx_Schur_inj_iso; rewrite ?homWf. Qed. Lemma mxsemisimple_module U : mxsemisimple U -> mxmodule U. Proof. case=> I W /= simW defU _. by rewrite -(eqmx_module defU) sumsmx_module // => i _; case: (simW i). Qed. (* Completely reducible modules, and Maeschke's Theorem. *) CoInductive mxsplits (V U : 'M_n) := MxSplits (W : 'M_n) of mxmodule W & (U + W :=: V)%MS & mxdirect (U + W). Definition mx_completely_reducible V := forall U, mxmodule U -> (U <= V)%MS -> mxsplits V U. Lemma mx_reducibleS U V : mxmodule U -> (U <= V)%MS -> mx_completely_reducible V -> mx_completely_reducible U. Proof. move=> modU sUV redV U1 modU1 sU1U. have [W modW defV dxU1W] := redV U1 modU1 (submx_trans sU1U sUV). exists (W :&: U)%MS; first exact: capmx_module. by apply/eqmxP; rewrite !matrix_modl // capmxSr sub_capmx defV sUV /=. by apply/mxdirect_addsP; rewrite capmxA (mxdirect_addsP dxU1W) cap0mx. Qed. Lemma mx_Maschke : [char F]^'.-group G -> mx_completely_reducible 1%:M. Proof. rewrite /pgroup charf'_nat; set nG := _%:R => nzG U => /mxmoduleP Umod _. pose phi := nG^-1 *: (\sum_(x in G) rG x^-1 *m pinvmx U *m U *m rG x). have phiG x: x \in G -> phi *m rG x = rG x *m phi. move=> Gx; rewrite -scalemxAl -scalemxAr; congr (_ *: _). rewrite {2}(reindex_acts 'R _ Gx) ?astabsR //= mulmx_suml mulmx_sumr. apply: eq_bigr => y Gy; rewrite !mulmxA -repr_mxM ?groupV ?groupM //. by rewrite invMg mulKVg repr_mxM ?mulmxA. have Uphi: U *m phi = U. rewrite -scalemxAr mulmx_sumr (eq_bigr (fun _ => U)) => [|x Gx]. by rewrite sumr_const -scaler_nat !scalerA mulVf ?scale1r. by rewrite 3!mulmxA mulmxKpV ?repr_mxKV ?Umod ?groupV. have tiUker: (U :&: kermx phi = 0)%MS. apply/eqP/rowV0P=> v; rewrite sub_capmx => /andP[/submxP[u ->] /sub_kermxP]. by rewrite -mulmxA Uphi. exists (kermx phi); last exact/mxdirect_addsP. apply/mxmoduleP=> x Gx; apply/sub_kermxP. by rewrite -mulmxA -phiG // mulmxA mulmx_ker mul0mx. apply/eqmxP; rewrite submx1 sub1mx. rewrite /row_full mxrank_disjoint_sum //= mxrank_ker. suffices ->: (U :=: phi)%MS by rewrite subnKC ?rank_leq_row. apply/eqmxP; rewrite -{1}Uphi submxMl scalemx_sub //. by rewrite summx_sub // => x Gx; rewrite -mulmxA mulmx_sub ?Umod. Qed. Lemma mxsemisimple_reducible V : mxsemisimple V -> mx_completely_reducible V. Proof. case=> [I W /= simW defV _] U modU sUV; rewrite -defV in sUV. have [J [defV' dxV]] := sum_mxsimple_direct_compl simW modU sUV. exists (\sum_(i in J) W i)%MS. - by apply: sumsmx_module => i _; case: (simW i). - exact: eqmx_trans defV' defV. by rewrite mxdirect_addsE (sameP eqP mxdirect_addsP) /= in dxV; case/and3P: dxV. Qed. Lemma mx_reducible_semisimple V : mxmodule V -> mx_completely_reducible V -> classically (mxsemisimple V). Proof. move=> modV redV [] // nssimV; move: {-1}_.+1 (ltnSn (\rank V)) => r leVr. elim: r => // r IHr in V leVr modV redV nssimV. have [V0 | nzV] := eqVneq V 0. by rewrite nssimV ?V0 //; exact: mxsemisimple0. apply (mxsimple_exists modV nzV) => [[U simU sUV]]; have [modU nzU _] := simU. have [W modW defUW dxUW] := redV U modU sUV. have sWV: (W <= V)%MS by rewrite -defUW addsmxSr. apply: IHr (mx_reducibleS modW sWV redV) _ => // [|ssimW]. rewrite ltnS -defUW (mxdirectP dxUW) /= in leVr; apply: leq_trans leVr. by rewrite -add1n leq_add2r lt0n mxrank_eq0. apply: nssimV (eqmx_semisimple defUW (addsmx_semisimple _ ssimW)). exact: mxsimple_semisimple. Qed. Lemma mxsemisimpleS U V : mxmodule U -> (U <= V)%MS -> mxsemisimple V -> mxsemisimple U. Proof. move=> modU sUV ssimV. have [W modW defUW dxUW]:= mxsemisimple_reducible ssimV modU sUV. move/mxdirect_addsP: dxUW => dxUW. have defU : (V *m proj_mx U W :=: U)%MS. by apply/eqmxP; rewrite proj_mx_sub -{1}[U](proj_mx_id dxUW) ?submxMr. apply: eqmx_semisimple defU _; apply: hom_mxsemisimple ssimV _. by rewrite -defUW proj_mx_hom. Qed. Lemma hom_mxsemisimple_iso I P U W f : let V := (\sum_(i : I | P i) W i)%MS in mxsimple U -> (forall i, P i -> W i != 0 -> mxsimple (W i)) -> (V <= dom_hom_mx f)%MS -> (U <= V *m f)%MS -> {i | P i & mx_iso (W i) U}. Proof. move=> V simU simW homVf sUVf; have [modU nzU _] := simU. have ssimVf: mxsemisimple (V *m f). by apply: hom_mxsemisimple homVf; exact: intro_mxsemisimple (eqmx_refl _) _. have [U' modU' defVf] := mxsemisimple_reducible ssimVf modU sUVf. move/mxdirect_addsP=> dxUU'; pose p := f *m proj_mx U U'. case: (pickP (fun i => P i && (W i *m p != 0))) => [i /andP[Pi nzWip] | no_i]. have sWiV: (W i <= V)%MS by rewrite (sumsmx_sup i). have sWipU: (W i *m p <= U)%MS by rewrite mulmxA proj_mx_sub. exists i => //; apply: (mx_Schur_iso (simW i Pi _) simU _ sWipU nzWip). by apply: contraNneq nzWip => ->; rewrite mul0mx. apply: (submx_trans sWiV); apply/hom_mxP=> x Gx. by rewrite mulmxA [_ *m p]mulmxA 2?(hom_mxP _) -?defVf ?proj_mx_hom. case/negP: nzU; rewrite -submx0 -[U](proj_mx_id dxUU') //. rewrite (submx_trans (submxMr _ sUVf)) // -mulmxA -/p sumsmxMr. by apply/sumsmx_subP=> i Pi; move/negbT: (no_i i); rewrite Pi negbK submx0. Qed. (* The component associated to a given irreducible module. *) Section Components. Fact component_mx_key : unit. Proof. by []. Qed. Definition component_mx_expr (U : 'M[F]_n) := (\sum_i cyclic_mx (row i (row_hom_mx (nz_row U))))%MS. Definition component_mx := locked_with component_mx_key component_mx_expr. Canonical component_mx_unfoldable := [unlockable fun component_mx]. Variable U : 'M[F]_n. Hypothesis simU : mxsimple U. Let u := nz_row U. Let iso_u := row_hom_mx u. Let nz_u : u != 0 := nz_row_mxsimple simU. Let Uu : (u <= U)%MS := nz_row_sub U. Let defU : (U :=: cyclic_mx u)%MS := mxsimple_cyclic simU nz_u Uu. Local Notation compU := (component_mx U). Lemma component_mx_module : mxmodule compU. Proof. by rewrite unlock sumsmx_module // => i; rewrite cyclic_mx_module. Qed. Lemma genmx_component : <>%MS = compU. Proof. by rewrite [in compU]unlock genmx_sums; apply: eq_bigr => i; rewrite genmx_id. Qed. Lemma component_mx_def : {I : finType & {W : I -> 'M_n | forall i, mx_iso U (W i) & compU = \sum_i W i}}%MS. Proof. pose r i := row i iso_u; pose r_nz i := r i != 0; pose I := {i | r_nz i}. exists [finType of I]; exists (fun i => cyclic_mx (r (sval i))) => [i|]. apply/mxsimple_isoP=> //; apply/and3P. split; first by rewrite cyclic_mx_module. apply/rowV0Pn; exists (r (sval i)); last exact: (svalP i). by rewrite sub_capmx cyclic_mx_id row_sub. have [f hom_u_f <-] := @row_hom_mxP u (r (sval i)) (row_sub _ _). by rewrite defU -hom_cyclic_mx ?mxrankM_maxl. rewrite -(eq_bigr _ (fun _ _ => genmx_id _)) -genmx_sums -genmx_component. rewrite [in compU]unlock; apply/genmxP/andP; split; last first. by apply/sumsmx_subP => i _; rewrite (sumsmx_sup (sval i)). apply/sumsmx_subP => i _. case i0: (r_nz i); first by rewrite (sumsmx_sup (Sub i i0)). by move/negbFE: i0; rewrite -cyclic_mx_eq0 => /eqP->; exact: sub0mx. Qed. Lemma component_mx_semisimple : mxsemisimple compU. Proof. have [I [W isoUW ->]] := component_mx_def. apply: intro_mxsemisimple (eqmx_refl _) _ => i _ _. exact: mx_iso_simple (isoUW i) simU. Qed. Lemma mx_iso_component V : mx_iso U V -> (V <= compU)%MS. Proof. move=> isoUV; have [f injf homUf defV] := isoUV. have simV := mx_iso_simple isoUV simU. have hom_u_f := submx_trans Uu homUf. have ->: (V :=: cyclic_mx (u *m f))%MS. apply: eqmx_trans (hom_cyclic_mx hom_u_f). exact: eqmx_trans (eqmx_sym defV) (eqmxMr _ defU). have iso_uf: (u *m f <= iso_u)%MS by apply/row_hom_mxP; exists f. rewrite genmxE; apply/row_subP=> j; rewrite row_mul mul_rV_lin1 /=. set a := vec_mx _; apply: submx_trans (submxMr _ iso_uf) _. apply/row_subP=> i; rewrite row_mul [in compU]unlock (sumsmx_sup i) //. by apply/cyclic_mxP; exists a; rewrite // vec_mxK row_sub. Qed. Lemma component_mx_id : (U <= compU)%MS. Proof. exact: mx_iso_component (mx_iso_refl U). Qed. Lemma hom_component_mx_iso f V : mxsimple V -> (compU <= dom_hom_mx f)%MS -> (V <= compU *m f)%MS -> mx_iso U V. Proof. have [I [W isoUW ->]] := component_mx_def => simV homWf sVWf. have [i _ _|i _ ] := hom_mxsemisimple_iso simV _ homWf sVWf. exact: mx_iso_simple (simU). exact: mx_iso_trans. Qed. Lemma component_mx_iso V : mxsimple V -> (V <= compU)%MS -> mx_iso U V. Proof. move=> simV; rewrite -[compU]mulmx1. exact: hom_component_mx_iso (scalar_mx_hom _ _). Qed. Lemma hom_component_mx f : (compU <= dom_hom_mx f)%MS -> (compU *m f <= compU)%MS. Proof. move=> hom_f. have [I W /= simW defW _] := hom_mxsemisimple component_mx_semisimple hom_f. rewrite -defW; apply/sumsmx_subP=> i _; apply: mx_iso_component. by apply: hom_component_mx_iso hom_f _ => //; rewrite -defW (sumsmx_sup i). Qed. End Components. Lemma component_mx_isoP U V : mxsimple U -> mxsimple V -> reflect (mx_iso U V) (component_mx U == component_mx V). Proof. move=> simU simV; apply: (iffP eqP) => isoUV. by apply: component_mx_iso; rewrite ?isoUV ?component_mx_id. rewrite -(genmx_component U) -(genmx_component V); apply/genmxP. wlog suffices: U V simU simV isoUV / (component_mx U <= component_mx V)%MS. by move=> IH; rewrite !IH //; exact: mx_iso_sym. have [I [W isoWU ->]] := component_mx_def simU. apply/sumsmx_subP => i _; apply: mx_iso_component => //. exact: mx_iso_trans (mx_iso_sym isoUV) (isoWU i). Qed. Lemma component_mx_disjoint U V : mxsimple U -> mxsimple V -> component_mx U != component_mx V -> (component_mx U :&: component_mx V = 0)%MS. Proof. move=> simU simV neUV; apply: contraNeq neUV => ntUV. apply: (mxsimple_exists _ ntUV) => [|[W simW]]. by rewrite capmx_module ?component_mx_module. rewrite sub_capmx => /andP[sWU sWV]; apply/component_mx_isoP=> //. by apply: mx_iso_trans (_ : mx_iso U W) (mx_iso_sym _); exact: component_mx_iso. Qed. Section Socle. Record socleType := EnumSocle { socle_base_enum : seq 'M[F]_n; _ : forall M, M \in socle_base_enum -> mxsimple M; _ : forall M, mxsimple M -> has (mxsimple_iso M) socle_base_enum }. Lemma socle_exists : classically socleType. Proof. pose V : 'M[F]_n := 0; have: mxsemisimple V by exact: mxsemisimple0. have: n - \rank V < n.+1 by rewrite mxrank0 subn0. elim: _.+1 V => // n' IHn' V; rewrite ltnS => le_nV_n' ssimV. case=> // maxV; apply: (maxV); have [I /= U simU defV _] := ssimV. exists (codom U) => [M | M simM]; first by case/mapP=> i _ ->. suffices sMV: (M <= V)%MS. rewrite -defV -(mulmx1 (\sum_i _)%MS) in sMV. have [//| i _] := hom_mxsemisimple_iso simM _ (scalar_mx_hom _ _) sMV. move/mx_iso_sym=> isoM; apply/hasP. exists (U i); [exact: codom_f | exact/mxsimple_isoP]. have ssimMV := addsmx_semisimple (mxsimple_semisimple simM) ssimV. apply: contraLR isT => nsMV; apply: IHn' ssimMV _ maxV. apply: leq_trans le_nV_n'; rewrite ltn_sub2l //. rewrite ltn_neqAle rank_leq_row andbT -[_ == _]sub1mx. apply: contra nsMV; apply: submx_trans; exact: submx1. rewrite (ltn_leqif (mxrank_leqif_sup _)) ?addsmxSr //. by rewrite addsmx_sub submx_refl andbT. Qed. Section SocleDef. Variable sG0 : socleType. Definition socle_enum := map component_mx (socle_base_enum sG0). Lemma component_socle M : mxsimple M -> component_mx M \in socle_enum. Proof. rewrite /socle_enum; case: sG0 => e0 /= sim_e mem_e simM. have /hasP[M' e0M' isoMM'] := mem_e M simM; apply/mapP; exists M' => //. by apply/eqP/component_mx_isoP; [|exact: sim_e | exact/mxsimple_isoP]. Qed. Inductive socle_sort : predArgType := PackSocle W of W \in socle_enum. Local Notation sG := socle_sort. Local Notation e0 := (socle_base_enum sG0). Definition socle_base W := let: PackSocle W _ := W in e0`_(index W socle_enum). Coercion socle_val W : 'M[F]_n := component_mx (socle_base W). Definition socle_mult (W : sG) := (\rank W %/ \rank (socle_base W))%N. Lemma socle_simple W : mxsimple (socle_base W). Proof. case: W => M /=; rewrite /= /socle_enum /=; case: sG0 => e sim_e _ /= e_M. by apply: sim_e; rewrite mem_nth // -(size_map component_mx) index_mem. Qed. Definition socle_module (W : sG) := mxsimple_module (socle_simple W). Definition socle_repr W := submod_repr (socle_module W). Lemma nz_socle (W : sG) : W != 0 :> 'M_n. Proof. have simW := socle_simple W; have [_ nzW _] := simW; apply: contra nzW. by rewrite -!submx0; exact: submx_trans (component_mx_id simW). Qed. Lemma socle_mem (W : sG) : (W : 'M_n) \in socle_enum. Proof. exact: component_socle (socle_simple _). Qed. Lemma PackSocleK W e0W : @PackSocle W e0W = W :> 'M_n. Proof. rewrite /socle_val /= in e0W *; rewrite -(nth_map _ 0) ?nth_index //. by rewrite -(size_map component_mx) index_mem. Qed. Canonical socle_subType := SubType _ _ _ socle_sort_rect PackSocleK. Definition socle_eqMixin := Eval hnf in [eqMixin of sG by <:]. Canonical socle_eqType := Eval hnf in EqType sG socle_eqMixin. Definition socle_choiceMixin := Eval hnf in [choiceMixin of sG by <:]. Canonical socle_choiceType := ChoiceType sG socle_choiceMixin. Lemma socleP (W W' : sG) : reflect (W = W') (W == W')%MS. Proof. by rewrite (sameP genmxP eqP) !{1}genmx_component; exact: (W =P _). Qed. Fact socle_finType_subproof : cancel (fun W => SeqSub (socle_mem W)) (fun s => PackSocle (valP s)). Proof. by move=> W /=; apply: val_inj; rewrite /= PackSocleK. Qed. Definition socle_countMixin := CanCountMixin socle_finType_subproof. Canonical socle_countType := CountType sG socle_countMixin. Canonical socle_subCountType := [subCountType of sG]. Definition socle_finMixin := CanFinMixin socle_finType_subproof. Canonical socle_finType := FinType sG socle_finMixin. Canonical socle_subFinType := [subFinType of sG]. End SocleDef. Coercion socle_sort : socleType >-> predArgType. Variable sG : socleType. Section SubSocle. Variable P : pred sG. Notation S := (\sum_(W : sG | P W) socle_val W)%MS. Lemma subSocle_module : mxmodule S. Proof. by rewrite sumsmx_module // => W _; exact: component_mx_module. Qed. Lemma subSocle_semisimple : mxsemisimple S. Proof. apply: sumsmx_semisimple => W _; apply: component_mx_semisimple. exact: socle_simple. Qed. Local Notation ssimS := subSocle_semisimple. Lemma subSocle_iso M : mxsimple M -> (M <= S)%MS -> {W : sG | P W & mx_iso (socle_base W) M}. Proof. move=> simM sMS; have [modM nzM _] := simM. have [V /= modV defMV] := mxsemisimple_reducible ssimS modM sMS. move/mxdirect_addsP=> dxMV; pose p := proj_mx M V; pose Sp (W : sG) := W *m p. case: (pickP [pred i | P i & Sp i != 0]) => [/= W | Sp0]; last first. case/negP: nzM; rewrite -submx0 -[M](proj_mx_id dxMV) //. rewrite (submx_trans (submxMr _ sMS)) // sumsmxMr big1 // => W P_W. by apply/eqP; move/negbT: (Sp0 W); rewrite /= P_W negbK. rewrite {}/Sp /= => /andP[P_W nzSp]; exists W => //. have homWp: (W <= dom_hom_mx p)%MS. apply: submx_trans (proj_mx_hom dxMV modM modV). by rewrite defMV (sumsmx_sup W). have simWP := socle_simple W; apply: hom_component_mx_iso (homWp) _ => //. by rewrite (mx_Schur_onto _ simM) ?proj_mx_sub ?component_mx_module. Qed. Lemma capmx_subSocle m (M : 'M_(m, n)) : mxmodule M -> (M :&: S :=: \sum_(W : sG | P W) (M :&: W))%MS. Proof. move=> modM; apply/eqmxP/andP; split; last first. by apply/sumsmx_subP=> W P_W; rewrite capmxS // (sumsmx_sup W). have modMS: mxmodule (M :&: S)%MS by rewrite capmx_module ?subSocle_module. have [J /= U simU defMS _] := mxsemisimpleS modMS (capmxSr M S) ssimS. rewrite -defMS; apply/sumsmx_subP=> j _. have [sUjV sUjS]: (U j <= M /\ U j <= S)%MS. by apply/andP; rewrite -sub_capmx -defMS (sumsmx_sup j). have [W P_W isoWU] := subSocle_iso (simU j) sUjS. rewrite (sumsmx_sup W) // sub_capmx sUjV mx_iso_component //. exact: socle_simple. Qed. End SubSocle. Lemma subSocle_direct P : mxdirect (\sum_(W : sG | P W) W). Proof. apply/mxdirect_sumsP=> W _; apply/eqP. rewrite -submx0 capmx_subSocle ?component_mx_module //. apply/sumsmx_subP=> W' /andP[_ neWW']. by rewrite capmxC component_mx_disjoint //; exact: socle_simple. Qed. Definition Socle := (\sum_(W : sG) W)%MS. Lemma simple_Socle M : mxsimple M -> (M <= Socle)%MS. Proof. move=> simM; have socM := component_socle sG simM. by rewrite (sumsmx_sup (PackSocle socM)) // PackSocleK component_mx_id. Qed. Lemma semisimple_Socle U : mxsemisimple U -> (U <= Socle)%MS. Proof. by case=> I M /= simM <- _; apply/sumsmx_subP=> i _; exact: simple_Socle. Qed. Lemma reducible_Socle U : mxmodule U -> mx_completely_reducible U -> (U <= Socle)%MS. Proof. move=> modU redU; apply: (mx_reducible_semisimple modU redU). exact: semisimple_Socle. Qed. Lemma genmx_Socle : <>%MS = Socle. Proof. by rewrite genmx_sums; apply: eq_bigr => W; rewrite genmx_component. Qed. Lemma reducible_Socle1 : mx_completely_reducible 1%:M -> Socle = 1%:M. Proof. move=> redG; rewrite -genmx1 -genmx_Socle; apply/genmxP. by rewrite submx1 reducible_Socle ?mxmodule1. Qed. Lemma Socle_module : mxmodule Socle. Proof. exact: subSocle_module. Qed. Lemma Socle_semisimple : mxsemisimple Socle. Proof. exact: subSocle_semisimple. Qed. Lemma Socle_direct : mxdirect Socle. Proof. exact: subSocle_direct. Qed. Lemma Socle_iso M : mxsimple M -> {W : sG | mx_iso (socle_base W) M}. Proof. by move=> simM; case/subSocle_iso: (simple_Socle simM) => // W _; exists W. Qed. End Socle. (* Centralizer subgroup and central homomorphisms. *) Section CentHom. Variable f : 'M[F]_n. Lemma row_full_dom_hom : row_full (dom_hom_mx f) = centgmx rG f. Proof. by rewrite -sub1mx; apply/hom_mxP/centgmxP=> cfG x /cfG; rewrite !mul1mx. Qed. Lemma memmx_cent_envelop : (f \in 'C(E_G))%MS = centgmx rG f. Proof. apply/cent_rowP/centgmxP=> [cfG x Gx | cfG i]. by have:= cfG (enum_rank_in Gx x); rewrite rowK mxvecK enum_rankK_in. by rewrite rowK mxvecK /= cfG ?enum_valP. Qed. Lemma kermx_centg_module : centgmx rG f -> mxmodule (kermx f). Proof. move/centgmxP=> cGf; apply/mxmoduleP=> x Gx; apply/sub_kermxP. by rewrite -mulmxA -cGf // mulmxA mulmx_ker mul0mx. Qed. Lemma centgmx_hom m (U : 'M_(m, n)) : centgmx rG f -> (U <= dom_hom_mx f)%MS. Proof. by rewrite -row_full_dom_hom -sub1mx; exact: submx_trans (submx1 _). Qed. End CentHom. (* (Globally) irreducible, and absolutely irreducible representations. Note *) (* that unlike "reducible", "absolutely irreducible" can easily be decided. *) Definition mx_irreducible := mxsimple 1%:M. Lemma mx_irrP : mx_irreducible <-> n > 0 /\ (forall U, @mxmodule n U -> U != 0 -> row_full U). Proof. rewrite /mx_irreducible /mxsimple mxmodule1 -mxrank_eq0 mxrank1 -lt0n. do [split=> [[_ -> irrG] | [-> irrG]]; split=> // U] => [modU | modU _] nzU. by rewrite -sub1mx (irrG U) ?submx1. by rewrite sub1mx irrG. Qed. (* Schur's lemma for endomorphisms. *) Lemma mx_Schur : mx_irreducible -> forall f, centgmx rG f -> f != 0 -> f \in unitmx. Proof. move/mx_Schur_onto=> irrG f. rewrite -row_full_dom_hom -!row_full_unit -!sub1mx => cGf nz. by rewrite -[f]mul1mx irrG ?submx1 ?mxmodule1 ?mul1mx. Qed. Definition mx_absolutely_irreducible := (n > 0) && row_full E_G. Lemma mx_abs_irrP : reflect (n > 0 /\ exists a_, forall A, A = \sum_(x in G) a_ x A *: rG x) mx_absolutely_irreducible. Proof. have G_1 := group1 G; have bijG := enum_val_bij_in G_1. set h := enum_val in bijG; have Gh : h _ \in G by exact: enum_valP. rewrite /mx_absolutely_irreducible; case: (n > 0); last by right; case. apply: (iffP row_fullP) => [[E' E'G] | [_ [a_ a_G]]]. split=> //; exists (fun x B => (mxvec B *m E') 0 (enum_rank_in G_1 x)) => B. apply: (can_inj mxvecK); rewrite -{1}[mxvec B]mulmx1 -{}E'G mulmxA. move: {B E'}(_ *m E') => u; apply/rowP=> j. rewrite linear_sum (reindex h) //= mxE summxE. by apply: eq_big => [k| k _]; rewrite ?Gh // enum_valK_in mxE linearZ !mxE. exists (\matrix_(j, i) a_ (h i) (vec_mx (row j 1%:M))). apply/row_matrixP=> i; rewrite -[row i 1%:M]vec_mxK {}[vec_mx _]a_G. apply/rowP=> j; rewrite linear_sum (reindex h) //= 2!mxE summxE. by apply: eq_big => [k| k _]; [rewrite Gh | rewrite linearZ !mxE]. Qed. Lemma mx_abs_irr_cent_scalar : mx_absolutely_irreducible -> forall A, centgmx rG A -> is_scalar_mx A. Proof. case/mx_abs_irrP=> n_gt0 [a_ a_G] A /centgmxP cGA. have{cGA a_G} cMA B: A *m B = B *m A. rewrite {}[B]a_G mulmx_suml mulmx_sumr. by apply: eq_bigr => x Gx; rewrite -scalemxAl -scalemxAr cGA. pose i0 := Ordinal n_gt0; apply/is_scalar_mxP; exists (A i0 i0). apply/matrixP=> i j; move/matrixP/(_ i0 j): (esym (cMA (delta_mx i0 i))). rewrite -[A *m _]trmxK trmx_mul trmx_delta -!(@mul_delta_mx _ n 1 n 0) -!mulmxA. by rewrite -!rowE !mxE !big_ord1 !mxE !eqxx !mulr_natl /= andbT eq_sym. Qed. Lemma mx_abs_irrW : mx_absolutely_irreducible -> mx_irreducible. Proof. case/mx_abs_irrP=> n_gt0 [a_ a_G]; apply/mx_irrP; split=> // U Umod. case/rowV0Pn=> u Uu; rewrite -mxrank_eq0 -lt0n row_leq_rank -sub1mx. case/submxP: Uu => v ->{u} /row_freeP[u' vK]; apply/row_subP=> i. rewrite rowE scalar_mxC -{}vK -2![_ *m _]mulmxA; move: {u' i}(u' *m _) => A. rewrite mulmx_sub {v}// [A]a_G linear_sum summx_sub //= => x Gx. by rewrite linearZ /= scalemx_sub // (mxmoduleP Umod). Qed. Lemma linear_mx_abs_irr : n = 1%N -> mx_absolutely_irreducible. Proof. move=> n1; rewrite /mx_absolutely_irreducible /row_full eqn_leq rank_leq_col. rewrite {1 2 3}n1 /= lt0n mxrank_eq0; apply: contraTneq envelop_mx1 => ->. by rewrite eqmx0 submx0 mxvec_eq0 -mxrank_eq0 mxrank1 n1. Qed. Lemma abelian_abs_irr : abelian G -> mx_absolutely_irreducible = (n == 1%N). Proof. move=> cGG; apply/idP/eqP=> [absG|]; last exact: linear_mx_abs_irr. have [n_gt0 _] := andP absG. pose M := <>%MS. have rM: \rank M = 1%N by rewrite genmxE mxrank_delta. suffices defM: (M == 1%:M)%MS by rewrite (eqmxP defM) mxrank1 in rM. case: (mx_abs_irrW absG) => _ _ ->; rewrite ?submx1 -?mxrank_eq0 ?rM //. apply/mxmoduleP=> x Gx; suffices: is_scalar_mx (rG x). by case/is_scalar_mxP=> a ->; rewrite mul_mx_scalar scalemx_sub. apply: (mx_abs_irr_cent_scalar absG). by apply/centgmxP=> y Gy; rewrite -!repr_mxM // (centsP cGG). Qed. End OneRepresentation. Implicit Arguments mxmoduleP [gT G n rG m U]. Implicit Arguments envelop_mxP [gT G n rG A]. Implicit Arguments hom_mxP [gT G n rG m f W]. Implicit Arguments rfix_mxP [gT G n rG m W]. Implicit Arguments cyclic_mxP [gT G n rG u v]. Implicit Arguments annihilator_mxP [gT G n rG u A]. Implicit Arguments row_hom_mxP [gT G n rG u v]. Implicit Arguments mxsimple_isoP [gT G n rG U V]. Implicit Arguments socleP [gT G n rG sG0 W W']. Implicit Arguments mx_abs_irrP [gT G n rG]. Implicit Arguments val_submod_inj [n U m]. Implicit Arguments val_factmod_inj [n U m]. Prenex Implicits val_submod_inj val_factmod_inj. Section Proper. Variables (gT : finGroupType) (G : {group gT}) (n' : nat). Local Notation n := n'.+1. Variable rG : mx_representation F G n. Lemma envelop_mx_ring : mxring (enveloping_algebra_mx rG). Proof. apply/andP; split; first by apply/mulsmx_subP; exact: envelop_mxM. apply/mxring_idP; exists 1%:M; split=> *; rewrite ?mulmx1 ?mul1mx //. by rewrite -mxrank_eq0 mxrank1. exact: envelop_mx1. Qed. End Proper. Section JacobsonDensity. Variables (gT : finGroupType) (G : {group gT}) (n : nat). Variable rG : mx_representation F G n. Hypothesis irrG : mx_irreducible rG. Local Notation E_G := (enveloping_algebra_mx rG). Local Notation Hom_G := 'C(E_G)%MS. Lemma mx_Jacobson_density : ('C(Hom_G) <= E_G)%MS. Proof. apply/row_subP=> iB; rewrite -[row iB _]vec_mxK; move defB: (vec_mx _) => B. have{defB} cBcE: (B \in 'C(Hom_G))%MS by rewrite -defB vec_mxK row_sub. have rGnP: mx_repr G (fun x => lin_mx (mulmxr (rG x)) : 'A_n). split=> [|x y Gx Gy]; apply/row_matrixP=> i. by rewrite !rowE mul_rV_lin repr_mx1 /= !mulmx1 vec_mxK. by rewrite !rowE mulmxA !mul_rV_lin repr_mxM //= mxvecK mulmxA. move def_rGn: (MxRepresentation rGnP) => rGn. pose E_Gn := enveloping_algebra_mx rGn. pose e1 : 'rV[F]_(n ^ 2) := mxvec 1%:M; pose U := cyclic_mx rGn e1. have U_e1: (e1 <= U)%MS by rewrite cyclic_mx_id. have modU: mxmodule rGn U by rewrite cyclic_mx_module. pose Bn : 'M_(n ^ 2) := lin_mx (mulmxr B). suffices U_e1Bn: (e1 *m Bn <= U)%MS. rewrite mul_vec_lin /= mul1mx in U_e1Bn; apply: submx_trans U_e1Bn _. rewrite genmxE; apply/row_subP=> i; rewrite row_mul rowK mul_vec_lin_row. by rewrite -def_rGn mul_vec_lin /= mul1mx (eq_row_sub i) ?rowK. have{cBcE} cBncEn A: centgmx rGn A -> A *m Bn = Bn *m A. rewrite -def_rGn => cAG; apply/row_matrixP; case/mxvec_indexP=> j k /=. rewrite !rowE !mulmxA -mxvec_delta -(mul_delta_mx (0 : 'I_1)). rewrite mul_rV_lin mul_vec_lin /= -mulmxA; apply: (canLR vec_mxK). apply/row_matrixP=> i; set dj0 := delta_mx j 0. pose Aij := row i \o vec_mx \o mulmxr A \o mxvec \o mulmx dj0. have defAij := mul_rV_lin1 [linear of Aij]; rewrite /= {2}/Aij /= in defAij. rewrite -defAij row_mul -defAij -!mulmxA (cent_mxP cBcE) {k}//. rewrite memmx_cent_envelop; apply/centgmxP=> x Gx; apply/row_matrixP=> k. rewrite !row_mul !rowE !{}defAij /= -row_mul mulmxA mul_delta_mx. congr (row i _); rewrite -(mul_vec_lin (mulmxr_linear _ _)) -mulmxA. by rewrite -(centgmxP cAG) // mulmxA mx_rV_lin. suffices redGn: mx_completely_reducible rGn 1%:M. have [V modV defUV] := redGn _ modU (submx1 _); move/mxdirect_addsP=> dxUV. rewrite -(proj_mx_id dxUV U_e1) -mulmxA {}cBncEn 1?mulmxA ?proj_mx_sub //. by rewrite -row_full_dom_hom -sub1mx -defUV proj_mx_hom. pose W i : 'M[F]_(n ^ 2) := <>%MS. have defW: (\sum_i W i :=: 1%:M)%MS. apply/eqmxP; rewrite submx1; apply/row_subP; case/mxvec_indexP=> i j. rewrite row1 -mxvec_delta (sumsmx_sup i) // genmxE; apply/submxP. by exists (delta_mx 0 j); rewrite mul_rV_lin1 /= mul_delta_mx. apply: mxsemisimple_reducible; apply: (intro_mxsemisimple defW) => i _ nzWi. split=> // [|Vi modVi sViWi nzVi]. apply/mxmoduleP=> x Gx; rewrite genmxE (eqmxMr _ (genmxE _)) -def_rGn. apply/row_subP=> j; rewrite rowE mulmxA !mul_rV_lin1 /= mxvecK -mulmxA. by apply/submxP; move: (_ *m rG x) => v; exists v; rewrite mul_rV_lin1. do [rewrite !genmxE; set f := lin1_mx _] in sViWi *. have f_free: row_free f. apply/row_freeP; exists (lin1_mx (row i \o vec_mx)); apply/row_matrixP=> j. by rewrite row1 rowE mulmxA !mul_rV_lin1 /= mxvecK rowE !mul_delta_mx. pose V := <>%MS; have Vidf := mulmxKpV sViWi. suffices: (1%:M <= V)%MS by rewrite genmxE -(submxMfree _ _ f_free) mul1mx Vidf. case: irrG => _ _ ->; rewrite ?submx1 //; last first. by rewrite -mxrank_eq0 genmxE -(mxrankMfree _ f_free) Vidf mxrank_eq0. apply/mxmoduleP=> x Gx; rewrite genmxE (eqmxMr _ (genmxE _)). rewrite -(submxMfree _ _ f_free) Vidf. apply: submx_trans (mxmoduleP modVi x Gx); rewrite -{2}Vidf. apply/row_subP=> j; apply: (eq_row_sub j); rewrite row_mul -def_rGn. by rewrite !(row_mul _ _ f) !mul_rV_lin1 /= mxvecK !row_mul !mulmxA. Qed. Lemma cent_mx_scalar_abs_irr : \rank Hom_G <= 1 -> mx_absolutely_irreducible rG. Proof. rewrite leqNgt => /(has_non_scalar_mxP (scalar_mx_cent _ _)) scal_cE. apply/andP; split; first by case/mx_irrP: irrG. rewrite -sub1mx; apply: submx_trans mx_Jacobson_density. apply/memmx_subP=> B _; apply/cent_mxP=> A cGA. case scalA: (is_scalar_mx A); last by case: scal_cE; exists A; rewrite ?scalA. by case/is_scalar_mxP: scalA => a ->; rewrite scalar_mxC. Qed. End JacobsonDensity. Section ChangeGroup. Variables (gT : finGroupType) (G H : {group gT}) (n : nat). Variables (rG : mx_representation F G n). Section SubGroup. Hypothesis sHG : H \subset G. Local Notation rH := (subg_repr rG sHG). Lemma rfix_subg : rfix_mx rH = rfix_mx rG. Proof. by []. Qed. Section Stabilisers. Variables (m : nat) (U : 'M[F]_(m, n)). Lemma rstabs_subg : rstabs rH U = H :&: rstabs rG U. Proof. by apply/setP=> x; rewrite !inE andbA -in_setI (setIidPl sHG). Qed. Lemma mxmodule_subg : mxmodule rG U -> mxmodule rH U. Proof. by rewrite /mxmodule rstabs_subg subsetI subxx; exact: subset_trans. Qed. End Stabilisers. Lemma mxsimple_subg M : mxmodule rG M -> mxsimple rH M -> mxsimple rG M. Proof. by move=> modM [_ nzM minM]; split=> // U /mxmodule_subg; exact: minM. Qed. Lemma subg_mx_irr : mx_irreducible rH -> mx_irreducible rG. Proof. by apply: mxsimple_subg; exact: mxmodule1. Qed. Lemma subg_mx_abs_irr : mx_absolutely_irreducible rH -> mx_absolutely_irreducible rG. Proof. rewrite /mx_absolutely_irreducible -!sub1mx => /andP[-> /submx_trans-> //]. apply/row_subP=> i; rewrite rowK /= envelop_mx_id //. by rewrite (subsetP sHG) ?enum_valP. Qed. End SubGroup. Section SameGroup. Hypothesis eqGH : G :==: H. Local Notation rH := (eqg_repr rG eqGH). Lemma rfix_eqg : rfix_mx rH = rfix_mx rG. Proof. by []. Qed. Section Stabilisers. Variables (m : nat) (U : 'M[F]_(m, n)). Lemma rstabs_eqg : rstabs rH U = rstabs rG U. Proof. by rewrite rstabs_subg -(eqP eqGH) (setIidPr _) ?rstabs_sub. Qed. Lemma mxmodule_eqg : mxmodule rH U = mxmodule rG U. Proof. by rewrite /mxmodule rstabs_eqg -(eqP eqGH). Qed. End Stabilisers. Lemma mxsimple_eqg M : mxsimple rH M <-> mxsimple rG M. Proof. rewrite /mxsimple mxmodule_eqg. split=> [] [-> -> minM]; split=> // U modU; by apply: minM; rewrite mxmodule_eqg in modU *. Qed. Lemma eqg_mx_irr : mx_irreducible rH <-> mx_irreducible rG. Proof. exact: mxsimple_eqg. Qed. Lemma eqg_mx_abs_irr : mx_absolutely_irreducible rH = mx_absolutely_irreducible rG. Proof. by congr (_ && (_ == _)); rewrite /enveloping_algebra_mx /= -(eqP eqGH). Qed. End SameGroup. End ChangeGroup. Section Morphpre. Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}). Variables (G : {group rT}) (n : nat) (rG : mx_representation F G n). Local Notation rGf := (morphpre_repr f rG). Section Stabilisers. Variables (m : nat) (U : 'M[F]_(m, n)). Lemma rstabs_morphpre : rstabs rGf U = f @*^-1 (rstabs rG U). Proof. by apply/setP=> x; rewrite !inE andbA. Qed. Lemma mxmodule_morphpre : G \subset f @* D -> mxmodule rGf U = mxmodule rG U. Proof. by move=> sGf; rewrite /mxmodule rstabs_morphpre morphpreSK. Qed. End Stabilisers. Lemma rfix_morphpre (H : {set aT}) : H \subset D -> (rfix_mx rGf H :=: rfix_mx rG (f @* H))%MS. Proof. move=> sHD; apply/eqmxP/andP; split. by apply/rfix_mxP=> _ /morphimP[x _ Hx ->]; rewrite rfix_mx_id. by apply/rfix_mxP=> x Hx; rewrite rfix_mx_id ?mem_morphim ?(subsetP sHD). Qed. Lemma morphpre_mx_irr : G \subset f @* D -> (mx_irreducible rGf <-> mx_irreducible rG). Proof. move/mxmodule_morphpre=> modG; split=> /mx_irrP[n_gt0 irrG]; by apply/mx_irrP; split=> // U modU; apply: irrG; rewrite modG in modU *. Qed. Lemma morphpre_mx_abs_irr : G \subset f @* D -> mx_absolutely_irreducible rGf = mx_absolutely_irreducible rG. Proof. move=> sGfD; congr (_ && (_ == _)); apply/eqP; rewrite mxrank_leqif_sup //. apply/row_subP=> i; rewrite rowK. case/morphimP: (subsetP sGfD _ (enum_valP i)) => x Dx _ def_i. by rewrite def_i (envelop_mx_id rGf) // !inE Dx -def_i enum_valP. apply/row_subP=> i; rewrite rowK (envelop_mx_id rG) //. by case/morphpreP: (enum_valP i). Qed. End Morphpre. Section Morphim. Variables (aT rT : finGroupType) (G D : {group aT}) (f : {morphism D >-> rT}). Variables (n : nat) (rGf : mx_representation F (f @* G) n). Hypothesis sGD : G \subset D. Let sG_f'fG : G \subset f @*^-1 (f @* G). Proof. by rewrite -sub_morphim_pre. Qed. Local Notation rG := (morphim_repr rGf sGD). Section Stabilisers. Variables (m : nat) (U : 'M[F]_(m, n)). Lemma rstabs_morphim : rstabs rG U = G :&: f @*^-1 rstabs rGf U. Proof. by rewrite -rstabs_morphpre -(rstabs_subg _ sG_f'fG). Qed. Lemma mxmodule_morphim : mxmodule rG U = mxmodule rGf U. Proof. by rewrite /mxmodule rstabs_morphim subsetI subxx -sub_morphim_pre. Qed. End Stabilisers. Lemma rfix_morphim (H : {set aT}) : H \subset D -> (rfix_mx rG H :=: rfix_mx rGf (f @* H))%MS. Proof. exact: rfix_morphpre. Qed. Lemma mxsimple_morphim M : mxsimple rG M <-> mxsimple rGf M. Proof. rewrite /mxsimple mxmodule_morphim. split=> [] [-> -> minM]; split=> // U modU; by apply: minM; rewrite mxmodule_morphim in modU *. Qed. Lemma morphim_mx_irr : (mx_irreducible rG <-> mx_irreducible rGf). Proof. exact: mxsimple_morphim. Qed. Lemma morphim_mx_abs_irr : mx_absolutely_irreducible rG = mx_absolutely_irreducible rGf. Proof. have fG_onto: f @* G \subset restrm sGD f @* G. by rewrite morphim_restrm setIid. rewrite -(morphpre_mx_abs_irr _ fG_onto); congr (_ && (_ == _)). by rewrite /enveloping_algebra_mx /= morphpre_restrm (setIidPl _). Qed. End Morphim. Section Submodule. Variables (gT : finGroupType) (G : {group gT}) (n : nat). Variables (rG : mx_representation F G n) (U : 'M[F]_n) (Umod : mxmodule rG U). Local Notation rU := (submod_repr Umod). Local Notation rU' := (factmod_repr Umod). Lemma rfix_submod (H : {set gT}) : H \subset G -> (rfix_mx rU H :=: in_submod U (U :&: rfix_mx rG H))%MS. Proof. move=> sHG; apply/eqmxP/andP; split; last first. apply/rfix_mxP=> x Hx; rewrite -in_submodJ ?capmxSl //. by rewrite (rfix_mxP H _) ?capmxSr. rewrite -val_submodS in_submodK ?capmxSl // sub_capmx val_submodP //=. apply/rfix_mxP=> x Hx. by rewrite -(val_submodJ Umod) ?(subsetP sHG) ?rfix_mx_id. Qed. Lemma rfix_factmod (H : {set gT}) : H \subset G -> (in_factmod U (rfix_mx rG H) <= rfix_mx rU' H)%MS. Proof. move=> sHG; apply/rfix_mxP=> x Hx. by rewrite -(in_factmodJ Umod) ?(subsetP sHG) ?rfix_mx_id. Qed. Lemma rstab_submod m (W : 'M_(m, \rank U)) : rstab rU W = rstab rG (val_submod W). Proof. apply/setP=> x; rewrite !inE; apply: andb_id2l => Gx. by rewrite -(inj_eq val_submod_inj) val_submodJ. Qed. Lemma rstabs_submod m (W : 'M_(m, \rank U)) : rstabs rU W = rstabs rG (val_submod W). Proof. apply/setP=> x; rewrite !inE; apply: andb_id2l => Gx. by rewrite -val_submodS val_submodJ. Qed. Lemma val_submod_module m (W : 'M_(m, \rank U)) : mxmodule rG (val_submod W) = mxmodule rU W. Proof. by rewrite /mxmodule rstabs_submod. Qed. Lemma in_submod_module m (V : 'M_(m, n)) : (V <= U)%MS -> mxmodule rU (in_submod U V) = mxmodule rG V. Proof. by move=> sVU; rewrite -val_submod_module in_submodK. Qed. Lemma rstab_factmod m (W : 'M_(m, n)) : rstab rG W \subset rstab rU' (in_factmod U W). Proof. by apply/subsetP=> x /setIdP[Gx /eqP cUW]; rewrite inE Gx -in_factmodJ //= cUW. Qed. Lemma rstabs_factmod m (W : 'M_(m, \rank (cokermx U))) : rstabs rU' W = rstabs rG (U + val_factmod W)%MS. Proof. apply/setP=> x; rewrite !inE; apply: andb_id2l => Gx. rewrite addsmxMr addsmx_sub (submx_trans (mxmoduleP Umod x Gx)) ?addsmxSl //. rewrite -val_factmodS val_factmodJ //= val_factmodS; apply/idP/idP=> nWx. rewrite (submx_trans (addsmxSr U _)) // -(in_factmodsK (addsmxSl U _)) //. by rewrite addsmxS // val_factmodS in_factmod_addsK. rewrite in_factmodE (submx_trans (submxMr _ nWx)) // -in_factmodE. by rewrite in_factmod_addsK val_factmodK. Qed. Lemma val_factmod_module m (W : 'M_(m, \rank (cokermx U))) : mxmodule rG (U + val_factmod W)%MS = mxmodule rU' W. Proof. by rewrite /mxmodule rstabs_factmod. Qed. Lemma in_factmod_module m (V : 'M_(m, n)) : mxmodule rU' (in_factmod U V) = mxmodule rG (U + V)%MS. Proof. rewrite -(eqmx_module _ (in_factmodsK (addsmxSl U V))). by rewrite val_factmod_module (eqmx_module _ (in_factmod_addsK _ _)). Qed. Lemma rker_submod : rker rU = rstab rG U. Proof. by rewrite /rker rstab_submod; exact: eqmx_rstab (val_submod1 U). Qed. Lemma rstab_norm : G \subset 'N(rstab rG U). Proof. by rewrite -rker_submod rker_norm. Qed. Lemma rstab_normal : rstab rG U <| G. Proof. by rewrite -rker_submod rker_normal. Qed. Lemma submod_mx_faithful : mx_faithful rU -> mx_faithful rG. Proof. by apply: subset_trans; rewrite rker_submod rstabS ?submx1. Qed. Lemma rker_factmod : rker rG \subset rker rU'. Proof. apply/subsetP=> x /rkerP[Gx cVx]. by rewrite inE Gx /= /factmod_mx cVx mul1mx mulmx1 val_factmodK. Qed. Lemma factmod_mx_faithful : mx_faithful rU' -> mx_faithful rG. Proof. exact: subset_trans rker_factmod. Qed. Lemma submod_mx_irr : mx_irreducible rU <-> mxsimple rG U. Proof. split=> [] [_ nzU simU]. rewrite -mxrank_eq0 mxrank1 mxrank_eq0 in nzU; split=> // V modV sVU nzV. rewrite -(in_submodK sVU) -val_submod1 val_submodS. rewrite -(genmxE (in_submod U V)) simU ?genmxE ?submx1 //=. by rewrite (eqmx_module _ (genmxE _)) in_submod_module. rewrite -submx0 genmxE -val_submodS in_submodK //. by rewrite linear0 eqmx0 submx0. apply/mx_irrP; rewrite lt0n mxrank_eq0; split=> // V modV. rewrite -(inj_eq val_submod_inj) linear0 -(eqmx_eq0 (genmxE _)) => nzV. rewrite -sub1mx -val_submodS val_submod1 -(genmxE (val_submod V)). rewrite simU ?genmxE ?val_submodP //=. by rewrite (eqmx_module _ (genmxE _)) val_submod_module. Qed. End Submodule. Section Conjugate. Variables (gT : finGroupType) (G : {group gT}) (n : nat). Variables (rG : mx_representation F G n) (B : 'M[F]_n). Hypothesis uB : B \in unitmx. Local Notation rGB := (rconj_repr rG uB). Lemma rfix_conj (H : {set gT}) : (rfix_mx rGB H :=: B *m rfix_mx rG H *m invmx B)%MS. Proof. apply/eqmxP/andP; split. rewrite -mulmxA (eqmxMfull (_ *m _)) ?row_full_unit //. rewrite -[rfix_mx rGB H](mulmxK uB) submxMr //; apply/rfix_mxP=> x Hx. apply: (canRL (mulmxKV uB)); rewrite -(rconj_mxJ _ uB) mulmxK //. by rewrite rfix_mx_id. apply/rfix_mxP=> x Gx; rewrite -3!mulmxA; congr (_ *m _). by rewrite !mulmxA mulmxKV // rfix_mx_id. Qed. Lemma rstabs_conj m (U : 'M_(m, n)) : rstabs rGB U = rstabs rG (U *m B). Proof. apply/setP=> x; rewrite !inE rconj_mxE !mulmxA. by rewrite -{2}[U](mulmxK uB) submxMfree // row_free_unit unitmx_inv. Qed. Lemma mxmodule_conj m (U : 'M_(m, n)) : mxmodule rGB U = mxmodule rG (U *m B). Proof. by rewrite /mxmodule rstabs_conj. Qed. Lemma conj_mx_irr : mx_irreducible rGB <-> mx_irreducible rG. Proof. have Bfree: row_free B by rewrite row_free_unit. split => /mx_irrP[n_gt0 irrG]; apply/mx_irrP; split=> // U. rewrite -[U](mulmxKV uB) -mxmodule_conj -mxrank_eq0 /row_full mxrankMfree //. by rewrite mxrank_eq0; exact: irrG. rewrite -mxrank_eq0 /row_full -(mxrankMfree _ Bfree) mxmodule_conj mxrank_eq0. exact: irrG. Qed. End Conjugate. Section Quotient. Variables (gT : finGroupType) (G : {group gT}) (n : nat). Variables (rG : mx_representation F G n) (H : {group gT}). Hypotheses (krH : H \subset rker rG) (nHG : G \subset 'N(H)). Let nHGs := subsetP nHG. Local Notation rGH := (quo_repr krH nHG). Local Notation E_ r := (enveloping_algebra_mx r). Lemma quo_mx_quotient : (E_ rGH :=: E_ rG)%MS. Proof. apply/eqmxP/andP; split; apply/row_subP=> i. rewrite rowK; case/morphimP: (enum_valP i) => x _ Gx ->{i}. rewrite quo_repr_coset // (eq_row_sub (enum_rank_in Gx x)) // rowK. by rewrite enum_rankK_in. rewrite rowK -(quo_mx_coset krH nHG) ?enum_valP //; set Hx := coset H _. have GHx: Hx \in (G / H)%g by rewrite mem_quotient ?enum_valP. by rewrite (eq_row_sub (enum_rank_in GHx Hx)) // rowK enum_rankK_in. Qed. Lemma rfix_quo (K : {group gT}) : K \subset G -> (rfix_mx rGH (K / H)%g :=: rfix_mx rG K)%MS. Proof. move=> sKG; apply/eqmxP/andP; (split; apply/rfix_mxP) => [x Kx | Hx]. have Gx := subsetP sKG x Kx; rewrite -(quo_mx_coset krH nHG) // rfix_mx_id //. by rewrite mem_morphim ?(subsetP nHG). case/morphimP=> x _ Kx ->; have Gx := subsetP sKG x Kx. by rewrite quo_repr_coset ?rfix_mx_id. Qed. Lemma rstabs_quo m (U : 'M_(m, n)) : rstabs rGH U = (rstabs rG U / H)%g. Proof. apply/setP=> Hx; rewrite !inE; apply/andP/idP=> [[]|] /morphimP[x Nx Gx ->{Hx}]. by rewrite quo_repr_coset // => nUx; rewrite mem_morphim // inE Gx. by case/setIdP: Gx => Gx nUx; rewrite quo_repr_coset ?mem_morphim. Qed. Lemma mxmodule_quo m (U : 'M_(m, n)) : mxmodule rGH U = mxmodule rG U. Proof. rewrite /mxmodule rstabs_quo quotientSGK // ?(subset_trans krH) //. apply/subsetP=> x; rewrite !inE mul1mx => /andP[-> /eqP->]. by rewrite /= mulmx1. Qed. Lemma quo_mx_irr : mx_irreducible rGH <-> mx_irreducible rG. Proof. split; case/mx_irrP=> n_gt0 irrG; apply/mx_irrP; split=> // U modU; by apply: irrG; rewrite mxmodule_quo in modU *. Qed. End Quotient. Section SplittingField. Implicit Type gT : finGroupType. Definition group_splitting_field gT (G : {group gT}) := forall n (rG : mx_representation F G n), mx_irreducible rG -> mx_absolutely_irreducible rG. Definition group_closure_field gT := forall G : {group gT}, group_splitting_field G. Lemma quotient_splitting_field gT (G : {group gT}) (H : {set gT}) : G \subset 'N(H) -> group_splitting_field G -> group_splitting_field (G / H). Proof. move=> nHG splitG n rGH irrGH. by rewrite -(morphim_mx_abs_irr _ nHG) splitG //; exact/morphim_mx_irr. Qed. Lemma coset_splitting_field gT (H : {set gT}) : group_closure_field gT -> group_closure_field (coset_groupType H). Proof. move=> split_gT Gbar; have ->: Gbar = (coset H @*^-1 Gbar / H)%G. by apply: val_inj; rewrite /= /quotient morphpreK ?sub_im_coset. by apply: quotient_splitting_field; [exact: subsetIl | exact: split_gT]. Qed. End SplittingField. Section Abelian. Variables (gT : finGroupType) (G : {group gT}). Lemma mx_faithful_irr_center_cyclic n (rG : mx_representation F G n) : mx_faithful rG -> mx_irreducible rG -> cyclic 'Z(G). Proof. case: n rG => [|n] rG injG irrG; first by case/mx_irrP: irrG. move/trivgP: injG => KrG1; pose rZ := subg_repr rG (center_sub _). apply: (div_ring_mul_group_cyclic (repr_mx1 rZ)) (repr_mxM rZ) _ _; last first. exact: center_abelian. move=> x; rewrite -[[set _]]KrG1 !inE mul1mx -subr_eq0 andbC; set U := _ - _. do 2![case/andP]=> Gx cGx; rewrite Gx /=; apply: (mx_Schur irrG). apply/centgmxP=> y Gy; rewrite mulmxBl mulmxBr mulmx1 mul1mx. by rewrite -!repr_mxM // (centP cGx). Qed. Lemma mx_faithful_irr_abelian_cyclic n (rG : mx_representation F G n) : mx_faithful rG -> mx_irreducible rG -> abelian G -> cyclic G. Proof. move=> injG irrG cGG; rewrite -(setIidPl cGG). exact: mx_faithful_irr_center_cyclic injG irrG. Qed. Hypothesis splitG : group_splitting_field G. Lemma mx_irr_abelian_linear n (rG : mx_representation F G n) : mx_irreducible rG -> abelian G -> n = 1%N. Proof. by move=> irrG cGG; apply/eqP; rewrite -(abelian_abs_irr rG) ?splitG. Qed. Lemma mxsimple_abelian_linear n (rG : mx_representation F G n) M : abelian G -> mxsimple rG M -> \rank M = 1%N. Proof. move=> cGG simM; have [modM _ _] := simM. by move/(submod_mx_irr modM)/mx_irr_abelian_linear: simM => ->. Qed. Lemma linear_mxsimple n (rG : mx_representation F G n) (M : 'M_n) : mxmodule rG M -> \rank M = 1%N -> mxsimple rG M. Proof. move=> modM rM1; apply/(submod_mx_irr modM). by apply: mx_abs_irrW; rewrite linear_mx_abs_irr. Qed. End Abelian. Section AbelianQuotient. Variables (gT : finGroupType) (G : {group gT}). Variables (n : nat) (rG : mx_representation F G n). Lemma center_kquo_cyclic : mx_irreducible rG -> cyclic 'Z(G / rker rG)%g. Proof. move=> irrG; apply: mx_faithful_irr_center_cyclic (kquo_mx_faithful rG) _. exact/quo_mx_irr. Qed. Lemma der1_sub_rker : group_splitting_field G -> mx_irreducible rG -> (G^`(1) \subset rker rG)%g = (n == 1)%N. Proof. move=> splitG irrG; apply/idP/idP; last by move/eqP; exact: rker_linear. move/sub_der1_abelian; move/(abelian_abs_irr (kquo_repr rG))=> <-. by apply: (quotient_splitting_field (rker_norm _) splitG); exact/quo_mx_irr. Qed. End AbelianQuotient. Section Similarity. Variables (gT : finGroupType) (G : {group gT}). Local Notation reprG := (mx_representation F G). CoInductive mx_rsim n1 (rG1 : reprG n1) n2 (rG2 : reprG n2) : Prop := MxReprSim B of n1 = n2 & row_free B & forall x, x \in G -> rG1 x *m B = B *m rG2 x. Lemma mxrank_rsim n1 n2 (rG1 : reprG n1) (rG2 : reprG n2) : mx_rsim rG1 rG2 -> n1 = n2. Proof. by case. Qed. Lemma mx_rsim_refl n (rG : reprG n) : mx_rsim rG rG. Proof. exists 1%:M => // [|x _]; first by rewrite row_free_unit unitmx1. by rewrite mulmx1 mul1mx. Qed. Lemma mx_rsim_sym n1 n2 (rG1 : reprG n1) (rG2 : reprG n2) : mx_rsim rG1 rG2 -> mx_rsim rG2 rG1. Proof. case=> B def_n1; rewrite def_n1 in rG1 B *. rewrite row_free_unit => injB homB; exists (invmx B) => // [|x Gx]. by rewrite row_free_unit unitmx_inv. by apply: canRL (mulKmx injB) _; rewrite mulmxA -homB ?mulmxK. Qed. Lemma mx_rsim_trans n1 n2 n3 (rG1 : reprG n1) (rG2 : reprG n2) (rG3 : reprG n3) : mx_rsim rG1 rG2 -> mx_rsim rG2 rG3 -> mx_rsim rG1 rG3. Proof. case=> [B1 defn1 freeB1 homB1] [B2 defn2 freeB2 homB2]. exists (B1 *m B2); rewrite /row_free ?mxrankMfree 1?defn1 // => x Gx. by rewrite mulmxA homB1 // -!mulmxA homB2. Qed. Lemma mx_rsim_def n1 n2 (rG1 : reprG n1) (rG2 : reprG n2) : mx_rsim rG1 rG2 -> exists B, exists2 B', B' *m B = 1%:M & forall x, x \in G -> rG1 x = B *m rG2 x *m B'. Proof. case=> B def_n1; rewrite def_n1 in rG1 B *; rewrite row_free_unit => injB homB. by exists B, (invmx B) => [|x Gx]; rewrite ?mulVmx // -homB // mulmxK. Qed. Lemma mx_rsim_iso n (rG : reprG n) (U V : 'M_n) (modU : mxmodule rG U) (modV : mxmodule rG V) : mx_rsim (submod_repr modU) (submod_repr modV) <-> mx_iso rG U V. Proof. split=> [[B eqrUV injB homB] | [f injf homf defV]]. have: \rank (U *m val_submod (in_submod U 1%:M *m B)) = \rank U. do 2!rewrite mulmxA mxrankMfree ?row_base_free //. by rewrite -(eqmxMr _ (val_submod1 U)) -in_submodE val_submodK mxrank1. case/complete_unitmx => f injf defUf; exists f => //. apply/hom_mxP=> x Gx; rewrite -defUf -2!mulmxA -(val_submodJ modV) //. rewrite -(mulmxA _ B) -homB // val_submodE 3!(mulmxA U) (mulmxA _ _ B). rewrite -in_submodE -in_submodJ //. have [u ->] := submxP (mxmoduleP modU x Gx). by rewrite in_submodE -mulmxA -defUf !mulmxA mulmx1. apply/eqmxP; rewrite -mxrank_leqif_eq. by rewrite mxrankMfree ?eqrUV ?row_free_unit. by rewrite -defUf mulmxA val_submodP. have eqrUV: \rank U = \rank V by rewrite -defV mxrankMfree ?row_free_unit. exists (in_submod V (val_submod 1%:M *m f)) => // [|x Gx]. rewrite /row_free {6}eqrUV -[_ == _]sub1mx -val_submodS. rewrite in_submodK; last by rewrite -defV submxMr ?val_submodP. by rewrite val_submod1 -defV submxMr ?val_submod1. rewrite -in_submodJ; last by rewrite -defV submxMr ?val_submodP. rewrite -(hom_mxP (submx_trans (val_submodP _) homf)) //. by rewrite -(val_submodJ modU) // mul1mx 2!(mulmxA ((submod_repr _) x)) -val_submodE. Qed. Lemma mx_rsim_irr n1 n2 (rG1 : reprG n1) (rG2 : reprG n2) : mx_rsim rG1 rG2 -> mx_irreducible rG1 -> mx_irreducible rG2. Proof. case/mx_rsim_sym=> f def_n2; rewrite {n2}def_n2 in f rG2 * => injf homf. case/mx_irrP=> n1_gt0 minG; apply/mx_irrP; split=> // U modU nzU. rewrite /row_full -(mxrankMfree _ injf) -genmxE. apply: minG; last by rewrite -mxrank_eq0 genmxE mxrankMfree // mxrank_eq0. rewrite (eqmx_module _ (genmxE _)); apply/mxmoduleP=> x Gx. by rewrite -mulmxA -homf // mulmxA submxMr // (mxmoduleP modU). Qed. Lemma mx_rsim_abs_irr n1 n2 (rG1 : reprG n1) (rG2 : reprG n2) : mx_rsim rG1 rG2 -> mx_absolutely_irreducible rG1 = mx_absolutely_irreducible rG2. Proof. case=> f def_n2; rewrite -{n2}def_n2 in f rG2 *. rewrite row_free_unit => injf homf; congr (_ && (_ == _)). pose Eg (g : 'M[F]_n1) := lin_mx (mulmxr (invmx g) \o mulmx g). have free_Ef: row_free (Eg f). apply/row_freeP; exists (Eg (invmx f)); apply/row_matrixP=> i. rewrite rowE row1 mulmxA mul_rV_lin mx_rV_lin /=. by rewrite invmxK !{1}mulmxA mulmxKV // -mulmxA mulKmx // vec_mxK. symmetry; rewrite -(mxrankMfree _ free_Ef); congr (\rank _). apply/row_matrixP=> i; rewrite row_mul !rowK mul_vec_lin /=. by rewrite -homf ?enum_valP // mulmxK. Qed. Lemma rker_mx_rsim n1 n2 (rG1 : reprG n1) (rG2 : reprG n2) : mx_rsim rG1 rG2 -> rker rG1 = rker rG2. Proof. case=> f def_n2; rewrite -{n2}def_n2 in f rG2 *. rewrite row_free_unit => injf homf. apply/setP=> x; rewrite !inE !mul1mx; apply: andb_id2l => Gx. by rewrite -(can_eq (mulmxK injf)) homf // -scalar_mxC (can_eq (mulKmx injf)). Qed. Lemma mx_rsim_faithful n1 n2 (rG1 : reprG n1) (rG2 : reprG n2) : mx_rsim rG1 rG2 -> mx_faithful rG1 = mx_faithful rG2. Proof. by move=> simG12; rewrite /mx_faithful (rker_mx_rsim simG12). Qed. Lemma mx_rsim_factmod n (rG : reprG n) U V (modU : mxmodule rG U) (modV : mxmodule rG V) : (U + V :=: 1%:M)%MS -> mxdirect (U + V) -> mx_rsim (factmod_repr modV) (submod_repr modU). Proof. move=> addUV dxUV. have eqUV: \rank U = \rank (cokermx V). by rewrite mxrank_coker -{3}(mxrank1 F n) -addUV (mxdirectP dxUV) addnK. have{dxUV} dxUV: (U :&: V = 0)%MS by exact/mxdirect_addsP. exists (in_submod U (val_factmod 1%:M *m proj_mx U V)) => // [|x Gx]. rewrite /row_free -{6}eqUV -[_ == _]sub1mx -val_submodS val_submod1. rewrite in_submodK ?proj_mx_sub // -{1}[U](proj_mx_id dxUV) //. rewrite -{1}(add_sub_fact_mod V U) mulmxDl proj_mx_0 ?val_submodP // add0r. by rewrite submxMr // val_factmodS submx1. rewrite -in_submodJ ?proj_mx_sub // -(hom_mxP _) //; last first. by apply: submx_trans (submx1 _) _; rewrite -addUV proj_mx_hom. rewrite mulmxA; congr (_ *m _); rewrite mulmxA -val_factmodE; apply/eqP. rewrite eq_sym -subr_eq0 -mulmxBl proj_mx_0 //. by rewrite -[_ *m rG x](add_sub_fact_mod V) addrK val_submodP. Qed. Lemma mxtrace_rsim n1 n2 (rG1 : reprG n1) (rG2 : reprG n2) : mx_rsim rG1 rG2 -> {in G, forall x, \tr (rG1 x) = \tr (rG2 x)}. Proof. case/mx_rsim_def=> B [B' B'B def_rG1] x Gx. by rewrite def_rG1 // mxtrace_mulC mulmxA B'B mul1mx. Qed. Lemma mx_rsim_scalar n1 n2 (rG1 : reprG n1) (rG2 : reprG n2) x c : x \in G -> mx_rsim rG1 rG2 -> rG1 x = c%:M -> rG2 x = c%:M. Proof. move=> Gx /mx_rsim_sym[B _ Bfree rG2_B] rG1x. by apply: (row_free_inj Bfree); rewrite rG2_B // rG1x scalar_mxC. Qed. End Similarity. Section Socle. Variables (gT : finGroupType) (G : {group gT}). Variables (n : nat) (rG : mx_representation F G n) (sG : socleType rG). Lemma socle_irr (W : sG) : mx_irreducible (socle_repr W). Proof. by apply/submod_mx_irr; exact: socle_simple. Qed. Lemma socle_rsimP (W1 W2 : sG) : reflect (mx_rsim (socle_repr W1) (socle_repr W2)) (W1 == W2). Proof. have [simW1 simW2] := (socle_simple W1, socle_simple W2). by apply: (iffP (component_mx_isoP simW1 simW2)); move/mx_rsim_iso; exact. Qed. Local Notation mG U := (mxmodule rG U). Local Notation sr modV := (submod_repr modV). Lemma mx_rsim_in_submod U V (modU : mG U) (modV : mG V) : let U' := <>%MS in (U <= V)%MS -> exists modU' : mxmodule (sr modV) U', mx_rsim (sr modU) (sr modU'). Proof. move=> U' sUV; have modU': mxmodule (sr modV) U'. by rewrite (eqmx_module _ (genmxE _)) in_submod_module. have rankU': \rank U = \rank U' by rewrite genmxE mxrank_in_submod. pose v1 := val_submod 1%:M; pose U1 := v1 _ U. have sU1V: (U1 <= V)%MS by rewrite val_submod1. have sU1U': (in_submod V U1 <= U')%MS by rewrite genmxE submxMr ?val_submod1. exists modU', (in_submod U' (in_submod V U1)) => // [|x Gx]. apply/row_freeP; exists (v1 _ _ *m v1 _ _ *m in_submod U 1%:M). by rewrite 2!mulmxA -in_submodE -!val_submodE !in_submodK ?val_submodK. rewrite -!in_submodJ // -(val_submodJ modU) // mul1mx. by rewrite 2!{1}in_submodE mulmxA (mulmxA _ U1) -val_submodE -!in_submodE. Qed. Lemma rsim_submod1 U (modU : mG U) : (U :=: 1%:M)%MS -> mx_rsim (sr modU) rG. Proof. move=> U1; exists (val_submod 1%:M) => [||x Gx]; first by rewrite U1 mxrank1. by rewrite /row_free val_submod1. by rewrite -(val_submodJ modU) // mul1mx -val_submodE. Qed. Lemma mxtrace_submod1 U (modU : mG U) : (U :=: 1%:M)%MS -> {in G, forall x, \tr (sr modU x) = \tr (rG x)}. Proof. by move=> defU; exact: mxtrace_rsim (rsim_submod1 modU defU). Qed. Lemma mxtrace_dadd_mod U V W (modU : mG U) (modV : mG V) (modW : mG W) : (U + V :=: W)%MS -> mxdirect (U + V) -> {in G, forall x, \tr (sr modU x) + \tr (sr modV x) = \tr (sr modW x)}. Proof. move=> defW dxW x Gx; have [sUW sVW]: (U <= W)%MS /\ (V <= W)%MS. by apply/andP; rewrite -addsmx_sub defW. pose U' := <>%MS; pose V' := <>%MS. have addUV': (U' + V' :=: 1%:M)%MS. apply/eqmxP; rewrite submx1 /= (adds_eqmx (genmxE _) (genmxE _)). by rewrite -addsmxMr -val_submodS val_submod1 in_submodK ?defW. have dxUV': mxdirect (U' + V'). apply/eqnP; rewrite /= addUV' mxrank1 !genmxE !mxrank_in_submod //. by rewrite -(mxdirectP dxW) /= defW. have [modU' simU] := mx_rsim_in_submod modU modW sUW. have [modV' simV] := mx_rsim_in_submod modV modW sVW. rewrite (mxtrace_rsim simU) // (mxtrace_rsim simV) //. rewrite -(mxtrace_sub_fact_mod modV') addrC; congr (_ + _). by rewrite (mxtrace_rsim (mx_rsim_factmod modU' modV' addUV' dxUV')). Qed. Lemma mxtrace_dsum_mod (I : finType) (P : pred I) U W (modU : forall i, mG (U i)) (modW : mG W) : let S := (\sum_(i | P i) U i)%MS in (S :=: W)%MS -> mxdirect S -> {in G, forall x, \sum_(i | P i) \tr (sr (modU i) x) = \tr (sr modW x)}. Proof. move=> /= sumS dxS x Gx. elim: {P}_.+1 {-2}P (ltnSn #|P|) => // m IHm P lePm in W modW sumS dxS *. have [j /= Pj | P0] := pickP P; last first. case: sumS (_ x); rewrite !big_pred0 // mxrank0 => <- _ rWx. by rewrite [rWx]flatmx0 linear0. rewrite ltnS (cardD1x Pj) in lePm. rewrite mxdirectE /= !(bigD1 j Pj) -mxdirectE mxdirect_addsE /= in dxS sumS *. have [_ dxW' dxW] := and3P dxS; rewrite (sameP eqP mxdirect_addsP) in dxW. rewrite (IHm _ _ _ (sumsmx_module _ (fun i _ => modU i)) (eqmx_refl _)) //. exact: mxtrace_dadd_mod. Qed. Lemma mxtrace_component U (simU : mxsimple rG U) : let V := component_mx rG U in let modV := component_mx_module rG U in let modU := mxsimple_module simU in {in G, forall x, \tr (sr modV x) = \tr (sr modU x) *+ (\rank V %/ \rank U)}. Proof. move=> V modV modU x Gx. have [I W S simW defV dxV] := component_mx_semisimple simU. rewrite -(mxtrace_dsum_mod (fun i => mxsimple_module (simW i)) modV defV) //. have rankU_gt0: \rank U > 0 by rewrite lt0n mxrank_eq0; case simU. have isoW i: mx_iso rG U (W i). by apply: component_mx_iso; rewrite ?simU // -defV (sumsmx_sup i). have ->: (\rank V %/ \rank U)%N = #|I|. symmetry; rewrite -(mulnK #|I| rankU_gt0); congr (_ %/ _)%N. rewrite -defV (mxdirectP dxV) /= -sum_nat_const. by apply: eq_bigr => i _; exact: mxrank_iso. rewrite -sumr_const; apply: eq_bigr => i _; symmetry. by apply: mxtrace_rsim Gx; apply/mx_rsim_iso; exact: isoW. Qed. Lemma mxtrace_Socle : let modS := Socle_module sG in {in G, forall x, \tr (sr modS x) = \sum_(W : sG) \tr (socle_repr W x) *+ socle_mult W}. Proof. move=> /= x Gx /=; pose modW (W : sG) := component_mx_module rG (socle_base W). rewrite -(mxtrace_dsum_mod modW _ (eqmx_refl _) (Socle_direct sG)) //. by apply: eq_bigr => W _; rewrite (mxtrace_component (socle_simple W)). Qed. End Socle. Section Clifford. Variables (gT : finGroupType) (G H : {group gT}). Hypothesis nsHG : H <| G. Variables (n : nat) (rG : mx_representation F G n). Let sHG := normal_sub nsHG. Let nHG := normal_norm nsHG. Let rH := subg_repr rG sHG. Lemma Clifford_simple M x : mxsimple rH M -> x \in G -> mxsimple rH (M *m rG x). Proof. have modmG m U y: y \in G -> (mxmodule rH) m U -> mxmodule rH (U *m rG y). move=> Gy modU; apply/mxmoduleP=> h Hh; have Gh := subsetP sHG h Hh. rewrite -mulmxA -repr_mxM // conjgCV repr_mxM ?groupJ ?groupV // mulmxA. by rewrite submxMr ?(mxmoduleP modU) // -mem_conjg (normsP nHG). have nzmG m y (U : 'M_(m, n)): y \in G -> (U *m rG y == 0) = (U == 0). by move=> Gy; rewrite -{1}(mul0mx m (rG y)) (can_eq (repr_mxK rG Gy)). case=> [modM nzM simM] Gx; have Gx' := groupVr Gx. split=> [||U modU sUMx nzU]; rewrite ?modmG ?nzmG //. rewrite -(repr_mxKV rG Gx U) submxMr //. by rewrite (simM (U *m _)) ?modmG ?nzmG // -(repr_mxK rG Gx M) submxMr. Qed. Lemma Clifford_hom x m (U : 'M_(m, n)) : x \in 'C_G(H) -> (U <= dom_hom_mx rH (rG x))%MS. Proof. case/setIP=> Gx cHx; apply/rV_subP=> v _{U}. apply/hom_mxP=> h Hh; have Gh := subsetP sHG h Hh. by rewrite -!mulmxA /= -!repr_mxM // (centP cHx). Qed. Lemma Clifford_iso x U : x \in 'C_G(H) -> mx_iso rH U (U *m rG x). Proof. move=> cHx; have [Gx _] := setIP cHx. by exists (rG x); rewrite ?repr_mx_unit ?Clifford_hom. Qed. Lemma Clifford_iso2 x U V : mx_iso rH U V -> x \in G -> mx_iso rH (U *m rG x) (V *m rG x). Proof. case=> [f injf homUf defV] Gx; have Gx' := groupVr Gx. pose fx := rG (x^-1)%g *m f *m rG x; exists fx; last 1 first. - by rewrite !mulmxA repr_mxK //; exact: eqmxMr. - by rewrite !unitmx_mul andbC !repr_mx_unit. apply/hom_mxP=> h Hh; have Gh := subsetP sHG h Hh. rewrite -(mulmxA U) -repr_mxM // conjgCV repr_mxM ?groupJ // !mulmxA. rewrite !repr_mxK // (hom_mxP homUf) -?mem_conjg ?(normsP nHG) //=. by rewrite !repr_mxM ?invgK ?groupM // !mulmxA repr_mxKV. Qed. Lemma Clifford_componentJ M x : mxsimple rH M -> x \in G -> (component_mx rH (M *m rG x) :=: component_mx rH M *m rG x)%MS. Proof. set simH := mxsimple rH; set cH := component_mx rH. have actG: {in G, forall y M, simH M -> cH M *m rG y <= cH (M *m rG y)}%MS. move=> {M} y Gy /= M simM; have [I [U isoU def_cHM]] := component_mx_def simM. rewrite /cH def_cHM sumsmxMr; apply/sumsmx_subP=> i _. by apply: mx_iso_component; [exact: Clifford_simple | exact: Clifford_iso2]. move=> simM Gx; apply/eqmxP; rewrite actG // -/cH. rewrite -{1}[cH _](repr_mxKV rG Gx) submxMr // -{2}[M](repr_mxK rG Gx). by rewrite actG ?groupV //; exact: Clifford_simple. Qed. Hypothesis irrG : mx_irreducible rG. Lemma Clifford_basis M : mxsimple rH M -> {X : {set gT} | X \subset G & let S := \sum_(x in X) M *m rG x in S :=: 1%:M /\ mxdirect S}%MS. Proof. move=> simM. have simMG (g : [subg G]) : mxsimple rH (M *m rG (val g)). by case: g => x Gx; exact: Clifford_simple. have [|XG [defX1 dxX1]] := sum_mxsimple_direct_sub simMG (_ : _ :=: 1%:M)%MS. apply/eqmxP; case irrG => _ _ ->; rewrite ?submx1 //; last first. rewrite -submx0; apply/sumsmx_subP; move/(_ 1%g (erefl _)); apply: negP. by rewrite submx0 repr_mx1 mulmx1; case simM. apply/mxmoduleP=> x Gx; rewrite sumsmxMr; apply/sumsmx_subP=> [[y Gy]] /= _. by rewrite (sumsmx_sup (subg G (y * x))) // subgK ?groupM // -mulmxA repr_mxM. exists (val @: XG); first by apply/subsetP=> ?; case/imsetP=> [[x Gx]] _ ->. have bij_val: {on val @: XG, bijective (@sgval _ G)}. exists (subg G) => [g _ | x]; first exact: sgvalK. by case/imsetP=> [[x' Gx]] _ ->; rewrite subgK. have defXG g: (val g \in val @: XG) = (g \in XG). by apply/imsetP/idP=> [[h XGh] | XGg]; [move/val_inj-> | exists g]. by rewrite /= mxdirectE /= !(reindex _ bij_val) !(eq_bigl _ _ defXG). Qed. Variable sH : socleType rH. Definition Clifford_act (W : sH) x := let Gx := subgP (subg G x) in PackSocle (component_socle sH (Clifford_simple (socle_simple W) Gx)). Let valWact W x : (Clifford_act W x :=: W *m rG (sgval (subg G x)))%MS. Proof. rewrite PackSocleK; apply: Clifford_componentJ (subgP _). exact: socle_simple. Qed. Fact Clifford_is_action : is_action G Clifford_act. Proof. split=> [x W W' eqWW' | W x y Gx Gy]. pose Gx := subgP (subg G x); apply/socleP; apply/eqmxP. rewrite -(repr_mxK rG Gx W) -(repr_mxK rG Gx W'); apply: eqmxMr. apply: eqmx_trans (eqmx_sym _) (valWact _ _); rewrite -eqWW'; exact: valWact. apply/socleP; rewrite !{1}valWact 2!{1}(eqmxMr _ (valWact _ _)). by rewrite !subgK ?groupM ?repr_mxM ?mulmxA ?andbb. Qed. Definition Clifford_action := Action Clifford_is_action. Local Notation "'Cl" := Clifford_action (at level 8) : action_scope. Lemma val_Clifford_act W x : x \in G -> ('Cl%act W x :=: W *m rG x)%MS. Proof. by move=> Gx; apply: eqmx_trans (valWact _ _) _; rewrite subgK. Qed. Lemma Clifford_atrans : [transitive G, on [set: sH] | 'Cl]. Proof. have [_ nz1 _] := irrG. apply: mxsimple_exists (mxmodule1 rH) nz1 _ _ => [[M simM _]]. pose W1 := PackSocle (component_socle sH simM). have [X sXG [def1 _]] := Clifford_basis simM; move/subsetP: sXG => sXG. apply/imsetP; exists W1; first by rewrite inE. symmetry; apply/setP=> W; rewrite inE; have simW := socle_simple W. have:= submx1 (socle_base W); rewrite -def1 -[(\sum_(x in X) _)%MS]mulmx1. case/(hom_mxsemisimple_iso simW) => [x Xx _ | | x Xx isoMxW]. - by apply: Clifford_simple; rewrite ?sXG. - exact: scalar_mx_hom. have Gx := sXG x Xx; apply/imsetP; exists x => //; apply/socleP/eqmxP/eqmx_sym. apply: eqmx_trans (val_Clifford_act _ Gx) _; rewrite PackSocleK. apply: eqmx_trans (eqmx_sym (Clifford_componentJ simM Gx)) _. apply/eqmxP; rewrite (sameP genmxP eqP) !{1}genmx_component. by apply/component_mx_isoP=> //; exact: Clifford_simple. Qed. Lemma Clifford_Socle1 : Socle sH = 1%:M. Proof. case/imsetP: Clifford_atrans => W _ _; have simW := socle_simple W. have [X sXG [def1 _]] := Clifford_basis simW. rewrite reducible_Socle1 //; apply: mxsemisimple_reducible. apply: intro_mxsemisimple def1 _ => x /(subsetP sXG) Gx _. exact: Clifford_simple. Qed. Lemma Clifford_rank_components (W : sH) : (#|sH| * \rank W)%N = n. Proof. rewrite -{9}(mxrank1 F n) -Clifford_Socle1. rewrite (mxdirectP (Socle_direct sH)) /= -sum_nat_const. apply: eq_bigr => W1 _; have [W0 _ W0G] := imsetP Clifford_atrans. have{W0G} W0G W': W' \in orbit 'Cl G W0 by rewrite -W0G inE. have [/orbitP[x Gx <-] /orbitP[y Gy <-]] := (W0G W, W0G W1). by rewrite !{1}val_Clifford_act // !mxrankMfree // !repr_mx_free. Qed. Theorem Clifford_component_basis M : mxsimple rH M -> {t : nat & {x_ : sH -> 'I_t -> gT | forall W, let sW := (\sum_j M *m rG (x_ W j))%MS in [/\ forall j, x_ W j \in G, (sW :=: W)%MS & mxdirect sW]}}. Proof. move=> simM; pose t := (n %/ #|sH| %/ \rank M)%N; exists t. have [X /subsetP sXG [defX1 dxX1]] := Clifford_basis simM. pose sMv (W : sH) x := (M *m rG x <= W)%MS; pose Xv := [pred x in X | sMv _ x]. have sXvG W: {subset Xv W <= G} by move=> x /andP[/sXG]. have defW W: (\sum_(x in Xv W) M *m rG x :=: W)%MS. apply/eqmxP; rewrite -(geq_leqif (mxrank_leqif_eq _)); last first. by apply/sumsmx_subP=> x /andP[]. rewrite -(leq_add2r (\sum_(W' | W' != W) \rank W')) -((bigD1 W) predT) //=. rewrite -(mxdirectP (Socle_direct sH)) /= -/(Socle _) Clifford_Socle1 -defX1. apply: leq_trans (mxrankS _) (mxrank_sum_leqif _).1 => /=. rewrite (bigID (sMv W))%MS addsmxS //=. apply/sumsmx_subP=> x /andP[Xx notW_Mx]; have Gx := sXG x Xx. have simMx := Clifford_simple simM Gx. pose Wx := PackSocle (component_socle sH simMx). have sMxWx: (M *m rG x <= Wx)%MS by rewrite PackSocleK component_mx_id. by rewrite (sumsmx_sup Wx) //; apply: contra notW_Mx => /eqP <-. have dxXv W: mxdirect (\sum_(x in Xv W) M *m rG x). move: dxX1; rewrite !mxdirectE /= !(bigID (sMv W) (mem X)) /=. by rewrite -mxdirectE mxdirect_addsE /= => /andP[]. have def_t W: #|Xv W| = t. rewrite /t -{1}(Clifford_rank_components W) mulKn 1?(cardD1 W) //. rewrite -defW (mxdirectP (dxXv W)) /= (eq_bigr (fun _ => \rank M)) => [|x]. rewrite sum_nat_const mulnK //; last by rewrite lt0n mxrank_eq0; case simM. by move/sXvG=> Gx; rewrite mxrankMfree // row_free_unit repr_mx_unit. exists (fun W i => enum_val (cast_ord (esym (def_t W)) i)) => W. case: {def_t}t / (def_t W) => sW. case: (pickP (Xv W)) => [x0 XvWx0 | XvW0]; last first. by case/negP: (nz_socle W); rewrite -submx0 -defW big_pred0. have{x0 XvWx0} reXv := reindex _ (enum_val_bij_in XvWx0). have def_sW: (sW :=: W)%MS. apply: eqmx_trans (defW W); apply/eqmxP; apply/genmxP; congr <<_>>%MS. rewrite reXv /=; apply: eq_big => [j | j _]; first by have:= enum_valP j. by rewrite cast_ord_id. split=> // [j|]; first by rewrite (sXvG W) ?enum_valP. apply/mxdirectP; rewrite def_sW -(defW W) /= (mxdirectP (dxXv W)) /= reXv /=. by apply: eq_big => [j | j _]; [move: (enum_valP j) | rewrite cast_ord_id]. Qed. Lemma Clifford_astab : H <*> 'C_G(H) \subset 'C([set: sH] | 'Cl). Proof. rewrite join_subG !subsetI sHG subsetIl /=; apply/andP; split. apply/subsetP=> h Hh; have Gh := subsetP sHG h Hh; rewrite inE. apply/subsetP=> W _; have simW := socle_simple W; have [modW _ _] := simW. have simWh: mxsimple rH (socle_base W *m rG h) by exact: Clifford_simple. rewrite inE -val_eqE /= PackSocleK eq_sym. apply/component_mx_isoP; rewrite ?subgK //; apply: component_mx_iso => //. by apply: submx_trans (component_mx_id simW); move/mxmoduleP: modW => ->. apply/subsetP=> z cHz; have [Gz _] := setIP cHz; rewrite inE. apply/subsetP=> W _; have simW := socle_simple W; have [modW _ _] := simW. have simWz: mxsimple rH (socle_base W *m rG z) by exact: Clifford_simple. rewrite inE -val_eqE /= PackSocleK eq_sym. by apply/component_mx_isoP; rewrite ?subgK //; exact: Clifford_iso. Qed. Lemma Clifford_astab1 (W : sH) : 'C[W | 'Cl] = rstabs rG W. Proof. apply/setP=> x; rewrite !inE; apply: andb_id2l => Gx. rewrite sub1set inE (sameP eqP socleP) !val_Clifford_act //. rewrite andb_idr // => sWxW; rewrite -mxrank_leqif_sup //. by rewrite mxrankMfree ?repr_mx_free. Qed. Lemma Clifford_rstabs_simple (W : sH) : mxsimple (subg_repr rG (rstabs_sub rG W)) W. Proof. split => [||U modU sUW nzU]; last 2 [exact: nz_socle]. by rewrite /mxmodule rstabs_subg setIid. have modUH: mxmodule rH U. apply/mxmoduleP=> h Hh; rewrite (mxmoduleP modU) //. rewrite /= -Clifford_astab1 !(inE, sub1set) (subsetP sHG) //. rewrite (astab_act (subsetP Clifford_astab h _)) ?inE //=. by rewrite mem_gen // inE Hh. apply: (mxsimple_exists modUH nzU) => [[M simM sMU]]. have [t [x_ /(_ W)[Gx_ defW _]]] := Clifford_component_basis simM. rewrite -defW; apply/sumsmx_subP=> j _; set x := x_ W j. have{Gx_} Gx: x \in G by rewrite Gx_. apply: submx_trans (submxMr _ sMU) _; apply: (mxmoduleP modU). rewrite inE -val_Clifford_act Gx //; set Wx := 'Cl%act W x. have [-> //= | neWxW] := eqVneq Wx W. case: (simM) => _ /negP[]; rewrite -submx0. rewrite (canF_eq (actKin 'Cl Gx)) in neWxW. rewrite -(component_mx_disjoint _ _ neWxW); try exact: socle_simple. rewrite sub_capmx {1}(submx_trans sMU sUW) val_Clifford_act ?groupV //. by rewrite -(eqmxMr _ defW) sumsmxMr (sumsmx_sup j) ?repr_mxK. Qed. End Clifford. Section JordanHolder. Variables (gT : finGroupType) (G : {group gT}). Variables (n : nat) (rG : mx_representation F G n). Local Notation modG := ((mxmodule rG) n). Lemma section_module (U V : 'M_n) (modU : modG U) (modV : modG V) : mxmodule (factmod_repr modU) <>%MS. Proof. by rewrite (eqmx_module _ (genmxE _)) in_factmod_module addsmx_module. Qed. Definition section_repr U V (modU : modG U) (modV : modG V) := submod_repr (section_module modU modV). Lemma mx_factmod_sub U modU : mx_rsim (@section_repr U _ modU (mxmodule1 rG)) (factmod_repr modU). Proof. exists (val_submod 1%:M) => [||x Gx]. - apply: (@addIn (\rank U)); rewrite genmxE mxrank_in_factmod mxrank_coker. by rewrite (addsmx_idPr (submx1 U)) mxrank1 subnK ?rank_leq_row. - by rewrite /row_free val_submod1. by rewrite -[_ x]mul1mx -val_submodE val_submodJ. Qed. Definition max_submod (U V : 'M_n) := (U < V)%MS /\ (forall W, ~ [/\ modG W, U < W & W < V])%MS. Lemma max_submodP U V (modU : modG U) (modV : modG V) : (U <= V)%MS -> (max_submod U V <-> mx_irreducible (section_repr modU modV)). Proof. move=> sUV; split=> [[ltUV maxU] | ]. apply/mx_irrP; split=> [|WU modWU nzWU]. by rewrite genmxE lt0n mxrank_eq0 in_factmod_eq0; case/andP: ltUV. rewrite -sub1mx -val_submodS val_submod1 genmxE. pose W := (U + val_factmod (val_submod WU))%MS. suffices sVW: (V <= W)%MS. rewrite {2}in_factmodE (submx_trans (submxMr _ sVW)) //. rewrite addsmxMr -!in_factmodE val_factmodK. by rewrite ((in_factmod U U =P 0) _) ?adds0mx ?in_factmod_eq0. move/and3P: {maxU}(maxU W); apply: contraR; rewrite /ltmx addsmxSl => -> /=. move: modWU; rewrite /mxmodule rstabs_submod rstabs_factmod => -> /=. rewrite addsmx_sub submx_refl -in_factmod_eq0 val_factmodK. move: nzWU; rewrite -[_ == 0](inj_eq val_submod_inj) linear0 => ->. rewrite -(in_factmodsK sUV) addsmxS // val_factmodS. by rewrite -(genmxE (in_factmod U V)) val_submodP. case/mx_irrP; rewrite lt0n {1}genmxE mxrank_eq0 in_factmod_eq0 => ltUV maxV. split=> // [|W [modW /andP[sUW ltUW] /andP[sWV /negP[]]]]; first exact/andP. rewrite -(in_factmodsK sUV) -(in_factmodsK sUW) addsmxS // val_factmodS. rewrite -genmxE -val_submod1; set VU := <<_>>%MS. have sW_VU: (in_factmod U W <= VU)%MS. by rewrite genmxE -val_factmodS !submxMr. rewrite -(in_submodK sW_VU) val_submodS -(genmxE (in_submod _ _)). rewrite sub1mx maxV //. rewrite (eqmx_module _ (genmxE _)) in_submod_module ?genmxE ?submxMr //. by rewrite in_factmod_module addsmx_module. rewrite -submx0 [(_ <= 0)%MS]genmxE -val_submodS linear0 in_submodK //. by rewrite eqmx0 submx0 in_factmod_eq0. Qed. Lemma max_submod_eqmx U1 U2 V1 V2 : (U1 :=: U2)%MS -> (V1 :=: V2)%MS -> max_submod U1 V1 -> max_submod U2 V2. Proof. move=> eqU12 eqV12 [ltUV1 maxU1]. by split=> [|W]; rewrite -(lt_eqmx eqU12) -(lt_eqmx eqV12). Qed. Definition mx_subseries := all modG. Definition mx_composition_series V := mx_subseries V /\ (forall i, i < size V -> max_submod (0 :: V)`_i V`_i). Local Notation mx_series := mx_composition_series. Fact mx_subseries_module V i : mx_subseries V -> mxmodule rG V`_i. Proof. move=> modV; have [|leVi] := ltnP i (size V); first exact: all_nthP. by rewrite nth_default ?mxmodule0. Qed. Fact mx_subseries_module' V i : mx_subseries V -> mxmodule rG (0 :: V)`_i. Proof. by move=> modV; rewrite mx_subseries_module //= mxmodule0. Qed. Definition subseries_repr V i (modV : all modG V) := section_repr (mx_subseries_module' i modV) (mx_subseries_module i modV). Definition series_repr V i (compV : mx_composition_series V) := subseries_repr i (proj1 compV). Lemma mx_series_lt V : mx_composition_series V -> path ltmx 0 V. Proof. by case=> _ compV; apply/(pathP 0)=> i /compV[]. Qed. Lemma max_size_mx_series (V : seq 'M[F]_n) : path ltmx 0 V -> size V <= \rank (last 0 V). Proof. rewrite -[size V]addn0 -(mxrank0 F n n); elim: V 0 => //= V1 V IHV V0. rewrite ltmxErank -andbA => /and3P[_ ltV01 ltV]. by apply: leq_trans (IHV _ ltV); rewrite addSnnS leq_add2l. Qed. Lemma mx_series_repr_irr V i (compV : mx_composition_series V) : i < size V -> mx_irreducible (series_repr i compV). Proof. case: compV => modV compV /compV maxVi; apply/max_submodP => //. by apply: ltmxW; case: maxVi. Qed. Lemma mx_series_rcons U V : mx_series (rcons U V) <-> [/\ mx_series U, modG V & max_submod (last 0 U) V]. Proof. rewrite /mx_series /mx_subseries all_rcons size_rcons -rcons_cons. split=> [ [/andP[modU modV] maxU] | [[modU maxU] modV maxV]]. split=> //; last first. by have:= maxU _ (leqnn _); rewrite !nth_rcons leqnn ltnn eqxx -last_nth. by split=> // i ltiU; have:= maxU i (ltnW ltiU); rewrite !nth_rcons leqW ltiU. rewrite modV; split=> // i; rewrite !nth_rcons ltnS leq_eqVlt. case: eqP => [-> _ | /= _ ltiU]; first by rewrite ltnn ?eqxx -last_nth. by rewrite ltiU; exact: maxU. Qed. Theorem mx_Schreier U : mx_subseries U -> path ltmx 0 U -> classically (exists V, [/\ mx_series V, last 0 V :=: 1%:M & subseq U V])%MS. Proof. move: U => U0; set U := {1 2}U0; have: subseq U0 U := subseq_refl U. pose n' := n.+1; have: n < size U + n' by rewrite leq_addl. elim: n' U => [|n' IH_U] U ltUn' sU0U modU incU [] // noV. rewrite addn0 ltnNge in ltUn'; case/negP: ltUn'. by rewrite (leq_trans (max_size_mx_series incU)) ?rank_leq_row. apply: (noV); exists U; split => //; first split=> // i lt_iU; last first. apply/eqmxP; apply: contraT => neU1. apply: {IH_U}(IH_U (rcons U 1%:M)) noV. - by rewrite size_rcons addSnnS. - by rewrite (subseq_trans sU0U) ?subseq_rcons. - by rewrite /mx_subseries all_rcons mxmodule1. by rewrite rcons_path ltmxEneq neU1 submx1 !andbT. set U'i := _`_i; set Ui := _`_i; have defU := cat_take_drop i U. have defU'i: U'i = last 0 (take i U). rewrite (last_nth 0) /U'i -{1}defU -cat_cons nth_cat /=. by rewrite size_take lt_iU leqnn. move: incU; rewrite -defU cat_path (drop_nth 0) //= -/Ui -defU'i. set U' := take i U; set U'' := drop _ U; case/and3P=> incU' ltUi incU''. split=> // W [modW ltUW ltWV]; case: notF. apply: {IH_U}(IH_U (U' ++ W :: Ui :: U'')) noV; last 2 first. - by rewrite /mx_subseries -drop_nth // all_cat /= modW -all_cat defU. - by rewrite cat_path /= -defU'i; exact/and4P. - by rewrite -drop_nth // size_cat /= addnS -size_cat defU addSnnS. by rewrite (subseq_trans sU0U) // -defU cat_subseq // -drop_nth ?subseq_cons. Qed. Lemma mx_second_rsim U V (modU : modG U) (modV : modG V) : let modI := capmx_module modU modV in let modA := addsmx_module modU modV in mx_rsim (section_repr modI modU) (section_repr modV modA). Proof. move=> modI modA; set nI := {1}(\rank _). have sIU := capmxSl U V; have sVA := addsmxSr U V. pose valI := val_factmod (val_submod (1%:M : 'M_nI)). have UvalI: (valI <= U)%MS. rewrite -(addsmx_idPr sIU) (submx_trans _ (proj_factmodS _ _)) //. by rewrite submxMr // val_submod1 genmxE. exists (valI *m in_factmod _ 1%:M *m in_submod _ 1%:M) => [||x Gx]. - apply: (@addIn (\rank (U :&: V) + \rank V)%N); rewrite genmxE addnA addnCA. rewrite /nI genmxE !{1}mxrank_in_factmod 2?(addsmx_idPr _) //. by rewrite -mxrank_sum_cap addnC. - rewrite -kermx_eq0; apply/rowV0P=> u; rewrite (sameP sub_kermxP eqP). rewrite mulmxA -in_submodE mulmxA -in_factmodE -(inj_eq val_submod_inj). rewrite linear0 in_submodK ?in_factmod_eq0 => [Vvu|]; last first. by rewrite genmxE addsmxC in_factmod_addsK submxMr // mulmx_sub. apply: val_submod_inj; apply/eqP; rewrite linear0 -[val_submod u]val_factmodK. rewrite val_submodE val_factmodE -mulmxA -val_factmodE -/valI. by rewrite in_factmod_eq0 sub_capmx mulmx_sub. symmetry; rewrite -{1}in_submodE -{1}in_submodJ; last first. by rewrite genmxE addsmxC in_factmod_addsK -in_factmodE submxMr. rewrite -{1}in_factmodE -{1}in_factmodJ // mulmxA in_submodE; congr (_ *m _). apply/eqP; rewrite mulmxA -in_factmodE -subr_eq0 -linearB in_factmod_eq0. apply: submx_trans (capmxSr U V); rewrite -in_factmod_eq0 linearB /=. rewrite subr_eq0 {1}(in_factmodJ modI) // val_factmodK eq_sym. rewrite /valI val_factmodE mulmxA -val_factmodE val_factmodK. by rewrite -[submod_mx _ _]mul1mx -val_submodE val_submodJ. Qed. Lemma section_eqmx_add U1 U2 V1 V2 modU1 modU2 modV1 modV2 : (U1 :=: U2)%MS -> (U1 + V1 :=: U2 + V2)%MS -> mx_rsim (@section_repr U1 V1 modU1 modV1) (@section_repr U2 V2 modU2 modV2). Proof. move=> eqU12 eqV12; set n1 := {1}(\rank _). pose v1 := val_factmod (val_submod (1%:M : 'M_n1)). have sv12: (v1 <= U2 + V2)%MS. rewrite -eqV12 (submx_trans _ (proj_factmodS _ _)) //. by rewrite submxMr // val_submod1 genmxE. exists (v1 *m in_factmod _ 1%:M *m in_submod _ 1%:M) => [||x Gx]. - apply: (@addIn (\rank U1)); rewrite {2}eqU12 /n1 !{1}genmxE. by rewrite !{1}mxrank_in_factmod eqV12. - rewrite -kermx_eq0; apply/rowV0P=> u; rewrite (sameP sub_kermxP eqP) mulmxA. rewrite -in_submodE mulmxA -in_factmodE -(inj_eq val_submod_inj) linear0. rewrite in_submodK ?in_factmod_eq0 -?eqU12 => [U1uv1|]; last first. by rewrite genmxE -(in_factmod_addsK U2 V2) submxMr // mulmx_sub. apply: val_submod_inj; apply/eqP; rewrite linear0 -[val_submod _]val_factmodK. by rewrite in_factmod_eq0 val_factmodE val_submodE -mulmxA -val_factmodE. symmetry; rewrite -{1}in_submodE -{1}in_factmodE -{1}in_submodJ; last first. by rewrite genmxE -(in_factmod_addsK U2 V2) submxMr. rewrite -{1}in_factmodJ // mulmxA in_submodE; congr (_ *m _); apply/eqP. rewrite mulmxA -in_factmodE -subr_eq0 -linearB in_factmod_eq0 -eqU12. rewrite -in_factmod_eq0 linearB /= subr_eq0 {1}(in_factmodJ modU1) //. rewrite val_factmodK /v1 val_factmodE eq_sym mulmxA -val_factmodE val_factmodK. by rewrite -[_ *m _]mul1mx mulmxA -val_submodE val_submodJ. Qed. Lemma section_eqmx U1 U2 V1 V2 modU1 modU2 modV1 modV2 (eqU : (U1 :=: U2)%MS) (eqV : (V1 :=: V2)%MS) : mx_rsim (@section_repr U1 V1 modU1 modV1) (@section_repr U2 V2 modU2 modV2). Proof. by apply: section_eqmx_add => //; exact: adds_eqmx. Qed. Lemma mx_butterfly U V W modU modV modW : ~~ (U == V)%MS -> max_submod U W -> max_submod V W -> let modUV := capmx_module modU modV in max_submod (U :&: V)%MS U /\ mx_rsim (@section_repr V W modV modW) (@section_repr _ U modUV modU). Proof. move=> neUV maxU maxV modUV; have{neUV maxU} defW: (U + V :=: W)%MS. wlog{neUV modUV} ltUV: U V modU modV maxU maxV / ~~ (V <= U)%MS. by case/nandP: neUV => ?; first rewrite addsmxC; exact. apply/eqmxP/idPn=> neUVW; case: maxU => ltUW; case/(_ (U + V)%MS). rewrite addsmx_module // ltmxE ltmxEneq neUVW addsmxSl !addsmx_sub. by have [ltVW _] := maxV; rewrite submx_refl andbT ltUV !ltmxW. have sUV_U := capmxSl U V; have sVW: (V <= W)%MS by rewrite -defW addsmxSr. set goal := mx_rsim _ _; suffices{maxV} simUV: goal. split=> //; apply/(max_submodP modUV modU sUV_U). by apply: mx_rsim_irr simUV _; exact/max_submodP. apply: {goal}mx_rsim_sym. by apply: mx_rsim_trans (mx_second_rsim modU modV) _; exact: section_eqmx. Qed. Lemma mx_JordanHolder_exists U V : mx_composition_series U -> modG V -> max_submod V (last 0 U) -> {W : seq 'M_n | mx_composition_series W & last 0 W = V}. Proof. elim/last_ind: U V => [|U Um IHU] V compU modV; first by case; rewrite ltmx0. rewrite last_rcons => maxV; case/mx_series_rcons: compU => compU modUm maxUm. case eqUV: (last 0 U == V)%MS. case/lastP: U eqUV compU {maxUm IHU} => [|U' Um']. by rewrite andbC; move/eqmx0P->; exists [::]. rewrite last_rcons; move/eqmxP=> eqU'V; case/mx_series_rcons=> compU _ maxUm'. exists (rcons U' V); last by rewrite last_rcons. apply/mx_series_rcons; split => //; exact: max_submod_eqmx maxUm'. set Um' := last 0 U in maxUm eqUV; have [modU _] := compU. have modUm': modG Um' by rewrite /Um' (last_nth 0) mx_subseries_module'. have [|||W compW lastW] := IHU (V :&: Um')%MS; rewrite ?capmx_module //. by case: (mx_butterfly modUm' modV modUm); rewrite ?eqUV // {1}capmxC. exists (rcons W V); last by rewrite last_rcons. apply/mx_series_rcons; split; rewrite // lastW. by case: (mx_butterfly modV modUm' modUm); rewrite // andbC eqUV. Qed. Let rsim_rcons U V compU compUV i : i < size U -> mx_rsim (@series_repr U i compU) (@series_repr (rcons U V) i compUV). Proof. by move=> ltiU; apply: section_eqmx; rewrite -?rcons_cons nth_rcons ?leqW ?ltiU. Qed. Let last_mod U (compU : mx_series U) : modG (last 0 U). Proof. by case: compU => modU _; rewrite (last_nth 0) (mx_subseries_module' _ modU). Qed. Let rsim_last U V modUm modV compUV : mx_rsim (@section_repr (last 0 U) V modUm modV) (@series_repr (rcons U V) (size U) compUV). Proof. apply: section_eqmx; last by rewrite nth_rcons ltnn eqxx. by rewrite -rcons_cons nth_rcons leqnn -last_nth. Qed. Local Notation rsimT := mx_rsim_trans. Local Notation rsimC := mx_rsim_sym. Lemma mx_JordanHolder U V compU compV : let m := size U in (last 0 U :=: last 0 V)%MS -> m = size V /\ (exists p : 'S_m, forall i : 'I_m, mx_rsim (@series_repr U i compU) (@series_repr V (p i) compV)). Proof. elim: {U}(size U) {-2}U V (eqxx (size U)) compU compV => /= [|r IHr] U V. move/nilP->; case/lastP: V => [|V Vm] /= ? compVm; rewrite ?last_rcons => Vm0. by split=> //; exists 1%g; case. by case/mx_series_rcons: (compVm) => _ _ []; rewrite -(lt_eqmx Vm0) ltmx0. case/lastP: U => // [U Um]; rewrite size_rcons eqSS => szUr compUm. case/mx_series_rcons: (compUm); set Um' := last 0 U => compU modUm maxUm. case/lastP: V => [|V Vm] compVm; rewrite ?last_rcons ?size_rcons /= => eqUVm. by case/mx_series_rcons: (compUm) => _ _ []; rewrite (lt_eqmx eqUVm) ltmx0. case/mx_series_rcons: (compVm); set Vm' := last 0 V => compV modVm maxVm. have [modUm' modVm']: modG Um' * modG Vm' := (last_mod compU, last_mod compV). pose i_m := @ord_max (size U). have [eqUVm' | neqUVm'] := altP (@eqmxP _ _ _ _ Um' Vm'). have [szV [p sim_p]] := IHr U V szUr compU compV eqUVm'. split; first by rewrite szV. exists (lift_perm i_m i_m p) => i; case: (unliftP i_m i) => [j|] ->{i}. apply: rsimT (rsimC _) (rsimT (sim_p j) _). by rewrite lift_max; exact: rsim_rcons. by rewrite lift_perm_lift lift_max; apply: rsim_rcons; rewrite -szV. have simUVm := section_eqmx modUm' modVm' modUm modVm eqUVm' eqUVm. apply: rsimT (rsimC _) (rsimT simUVm _); first exact: rsim_last. by rewrite lift_perm_id /= szV; exact: rsim_last. have maxVUm: max_submod Vm' Um by exact: max_submod_eqmx (eqmx_sym _) maxVm. have:= mx_butterfly modUm' modVm' modUm neqUVm' maxUm maxVUm. move: (capmx_module _ _); set Wm := (Um' :&: Vm')%MS => modWm [maxWUm simWVm]. have:= mx_butterfly modVm' modUm' modUm _ maxVUm maxUm. move: (capmx_module _ _); rewrite andbC capmxC -/Wm => modWmV [// | maxWVm]. rewrite {modWmV}(bool_irrelevance modWmV modWm) => simWUm. have [W compW lastW] := mx_JordanHolder_exists compU modWm maxWUm. have compWU: mx_series (rcons W Um') by apply/mx_series_rcons; rewrite lastW. have compWV: mx_series (rcons W Vm') by apply/mx_series_rcons; rewrite lastW. have [|szW [pU pUW]] := IHr U _ szUr compU compWU; first by rewrite last_rcons. rewrite size_rcons in szW; have ltWU: size W < size U by rewrite -szW. have{IHr} := IHr _ V _ compWV compV; rewrite last_rcons size_rcons -szW. case=> {r szUr}// szV [pV pWV]; split; first by rewrite szV. pose j_m := Ordinal ltWU; pose i_m' := lift i_m j_m. exists (lift_perm i_m i_m pU * tperm i_m i_m' * lift_perm i_m i_m pV)%g => i. rewrite !permM; case: (unliftP i_m i) => [j {simWUm}|] ->{i}; last first. rewrite lift_perm_id tpermL lift_perm_lift lift_max {simWVm}. apply: rsimT (rsimT (pWV j_m) _); last by apply: rsim_rcons; rewrite -szV. apply: rsimT (rsimC _) {simWUm}(rsimT simWUm _); first exact: rsim_last. by rewrite -lastW in modWm *; exact: rsim_last. apply: rsimT (rsimC _) {pUW}(rsimT (pUW j) _). by rewrite lift_max; exact: rsim_rcons. rewrite lift_perm_lift; case: (unliftP j_m (pU j)) => [k|] ->{j pU}. rewrite tpermD ?(inj_eq (@lift_inj _ _)) ?neq_lift //. rewrite lift_perm_lift !lift_max; set j := lift j_m k. have ltjW: j < size W by have:= ltn_ord k; rewrite -(lift_max k) /= {1 3}szW. apply: rsimT (rsimT (pWV j) _); last by apply: rsim_rcons; rewrite -szV. by apply: rsimT (rsimC _) (rsim_rcons compW _ _); first exact: rsim_rcons. apply: rsimT {simWVm}(rsimC (rsimT simWVm _)) _. by rewrite -lastW in modWm *; exact: rsim_last. rewrite tpermR lift_perm_id /= szV. by apply: rsimT (rsim_last modVm' modVm _); exact: section_eqmx. Qed. Lemma mx_JordanHolder_max U (m := size U) V compU modV : (last 0 U :=: 1%:M)%MS -> mx_irreducible (@factmod_repr _ G n rG V modV) -> exists i : 'I_m, mx_rsim (factmod_repr modV) (@series_repr U i compU). Proof. rewrite {}/m; set Um := last 0 U => Um1 irrV. have modUm: modG Um := last_mod compU; have simV := rsimC (mx_factmod_sub modV). have maxV: max_submod V Um. move/max_submodP: (mx_rsim_irr simV irrV) => /(_ (submx1 _)). by apply: max_submod_eqmx; last exact: eqmx_sym. have [W compW lastW] := mx_JordanHolder_exists compU modV maxV. have compWU: mx_series (rcons W Um) by apply/mx_series_rcons; rewrite lastW. have:= mx_JordanHolder compU compWU; rewrite last_rcons size_rcons. case=> // szW [p pUW]; have ltWU: size W < size U by rewrite szW. pose i := Ordinal ltWU; exists ((p^-1)%g i). apply: rsimT simV (rsimT _ (rsimC (pUW _))); rewrite permKV. apply: rsimT (rsimC _) (rsim_last (last_mod compW) modUm _). by apply: section_eqmx; rewrite ?lastW. Qed. End JordanHolder. Bind Scope irrType_scope with socle_sort. Section Regular. Variables (gT : finGroupType) (G : {group gT}). Local Notation nG := #|pred_of_set (gval G)|. Local Notation rF := (GRing.Field.comUnitRingType F) (only parsing). Local Notation aG := (regular_repr rF G). Local Notation R_G := (group_ring rF G). Lemma gring_free : row_free R_G. Proof. apply/row_freeP; exists (lin1_mx (row (gring_index G 1) \o vec_mx)). apply/row_matrixP=> i; rewrite row_mul rowK mul_rV_lin1 /= mxvecK rowK row1. by rewrite gring_indexK // mul1g gring_valK. Qed. Lemma gring_op_id A : (A \in R_G)%MS -> gring_op aG A = A. Proof. case/envelop_mxP=> a ->{A}; rewrite linear_sum. by apply: eq_bigr => x Gx; rewrite linearZ /= gring_opG. Qed. Lemma gring_rowK A : (A \in R_G)%MS -> gring_mx aG (gring_row A) = A. Proof. exact: gring_op_id. Qed. Lemma mem_gring_mx m a (M : 'M_(m, nG)) : (gring_mx aG a \in M *m R_G)%MS = (a <= M)%MS. Proof. by rewrite vec_mxK submxMfree ?gring_free. Qed. Lemma mem_sub_gring m A (M : 'M_(m, nG)) : (A \in M *m R_G)%MS = (A \in R_G)%MS && (gring_row A <= M)%MS. Proof. rewrite -(andb_idl (memmx_subP (submxMl _ _) A)); apply: andb_id2l => R_A. by rewrite -mem_gring_mx gring_rowK. Qed. Section GringMx. Variables (n : nat) (rG : mx_representation F G n). Lemma gring_mxP a : (gring_mx rG a \in enveloping_algebra_mx rG)%MS. Proof. by rewrite vec_mxK submxMl. Qed. Lemma gring_opM A B : (B \in R_G)%MS -> gring_op rG (A *m B) = gring_op rG A *m gring_op rG B. Proof. by move=> R_B; rewrite -gring_opJ gring_rowK. Qed. Hypothesis irrG : mx_irreducible rG. Lemma rsim_regular_factmod : {U : 'M_nG & {modU : mxmodule aG U & mx_rsim rG (factmod_repr modU)}}. Proof. pose v : 'rV[F]_n := nz_row 1%:M. pose fU := lin1_mx (mulmx v \o gring_mx rG); pose U := kermx fU. have modU: mxmodule aG U. apply/mxmoduleP => x Gx; apply/sub_kermxP/row_matrixP=> i. rewrite 2!row_mul row0; move: (row i U) (sub_kermxP (row_sub i U)) => u. by rewrite !mul_rV_lin1 /= gring_mxJ // mulmxA => ->; rewrite mul0mx. have def_n: \rank (cokermx U) = n. apply/eqP; rewrite mxrank_coker mxrank_ker subKn ?rank_leq_row // -genmxE. rewrite -[_ == _]sub1mx; have [_ _ ->] := irrG; rewrite ?submx1 //. rewrite (eqmx_module _ (genmxE _)); apply/mxmoduleP=> x Gx. apply/row_subP=> i; apply: eq_row_sub (gring_index G (enum_val i * x)) _. rewrite !rowE mulmxA !mul_rV_lin1 /= -mulmxA -gring_mxJ //. by rewrite -rowE rowK. rewrite (eqmx_eq0 (genmxE _)); apply/rowV0Pn. exists v; last exact: (nz_row_mxsimple irrG). apply/submxP; exists (gring_row (aG 1%g)); rewrite mul_rV_lin1 /=. by rewrite -gring_opE gring_opG // repr_mx1 mulmx1. exists U; exists modU; apply: mx_rsim_sym. exists (val_factmod 1%:M *m fU) => // [|x Gx]. rewrite /row_free eqn_leq rank_leq_row /= -subn_eq0 -mxrank_ker mxrank_eq0. apply/rowV0P=> u /sub_kermxP; rewrite mulmxA => /sub_kermxP. by rewrite -/U -in_factmod_eq0 mulmxA mulmx1 val_factmodK => /eqP. rewrite mulmxA -val_factmodE (canRL (addKr _) (add_sub_fact_mod U _)). rewrite mulmxDl mulNmx (sub_kermxP (val_submodP _)) oppr0 add0r. apply/row_matrixP=> i; move: (val_factmod _) => zz. by rewrite !row_mul !mul_rV_lin1 /= gring_mxJ // mulmxA. Qed. Lemma rsim_regular_series U (compU : mx_composition_series aG U) : (last 0 U :=: 1%:M)%MS -> exists i : 'I_(size U), mx_rsim rG (series_repr i compU). Proof. move=> lastU; have [V [modV simGV]] := rsim_regular_factmod. have irrV := mx_rsim_irr simGV irrG. have [i simVU] := mx_JordanHolder_max compU lastU irrV. exists i; exact: mx_rsim_trans simGV simVU. Qed. Hypothesis F'G : [char F]^'.-group G. Lemma rsim_regular_submod : {U : 'M_nG & {modU : mxmodule aG U & mx_rsim rG (submod_repr modU)}}. Proof. have [V [modV eqG'V]] := rsim_regular_factmod. have [U modU defVU dxVU] := mx_Maschke F'G modV (submx1 V). exists U; exists modU; apply: mx_rsim_trans eqG'V _. by apply: mx_rsim_factmod; rewrite ?mxdirectE /= addsmxC // addnC. Qed. End GringMx. Definition gset_mx (A : {set gT}) := \sum_(x in A) aG x. Local Notation tG := #|pred_of_set (classes (gval G))|. Definition classg_base := \matrix_(k < tG) mxvec (gset_mx (enum_val k)). Let groupCl : {in G, forall x, {subset x ^: G <= G}}. Proof. by move=> x Gx; apply: subsetP; exact: class_subG. Qed. Lemma classg_base_free : row_free classg_base. Proof. rewrite -kermx_eq0; apply/rowV0P=> v /sub_kermxP; rewrite mulmx_sum_row => v0. apply/rowP=> k; rewrite mxE. have [x Gx def_k] := imsetP (enum_valP k). transitivity (@gring_proj F _ G x (vec_mx 0) 0 0); last first. by rewrite !linear0 !mxE. rewrite -{}v0 !linear_sum (bigD1 k) //= !linearZ /= rowK mxvecK def_k. rewrite linear_sum (bigD1 x) ?class_refl //= gring_projE // eqxx. rewrite !big1 ?addr0 ?mxE ?mulr1 // => [k' | y /andP[xGy ne_yx]]; first 1 last. by rewrite gring_projE ?(groupCl Gx xGy) // eq_sym (negPf ne_yx). rewrite rowK !linearZ /= mxvecK -(inj_eq enum_val_inj) def_k eq_sym. have [z Gz ->] := imsetP (enum_valP k'). move/eqP=> not_Gxz; rewrite linear_sum big1 ?scaler0 //= => y zGy. rewrite gring_projE ?(groupCl Gz zGy) //. by case: eqP zGy => // <- /class_transr. Qed. Lemma classg_base_center : (classg_base :=: 'Z(R_G))%MS. Proof. apply/eqmxP/andP; split. apply/row_subP=> k; rewrite rowK /gset_mx sub_capmx {1}linear_sum. have [x Gx ->{k}] := imsetP (enum_valP k); have sxGG := groupCl Gx. rewrite summx_sub => [|y xGy]; last by rewrite envelop_mx_id ?sxGG. rewrite memmx_cent_envelop; apply/centgmxP=> y Gy. rewrite {2}(reindex_acts 'J _ Gy) ?astabsJ ?class_norm //=. rewrite mulmx_suml mulmx_sumr; apply: eq_bigr => z; move/sxGG=> Gz. by rewrite -!repr_mxM ?groupJ -?conjgC. apply/memmx_subP=> A; rewrite sub_capmx memmx_cent_envelop. case/andP=> /envelop_mxP[a ->{A}] cGa. rewrite (partition_big_imset (class^~ G)) -/(classes G) /=. rewrite linear_sum summx_sub //= => xG GxG; have [x Gx def_xG] := imsetP GxG. apply: submx_trans (scalemx_sub (a x) (submx_refl _)). rewrite (eq_row_sub (enum_rank_in GxG xG)) // linearZ /= rowK enum_rankK_in //. rewrite !linear_sum {xG GxG}def_xG; apply: eq_big => [y | xy] /=. apply/idP/andP=> [| [_ xGy]]; last by rewrite -(eqP xGy) class_refl. by case/imsetP=> z Gz ->; rewrite groupJ // classGidl. case/imsetP=> y Gy ->{xy}; rewrite linearZ; congr (_ *: _). move/(canRL (repr_mxK aG Gy)): (centgmxP cGa y Gy); have Gy' := groupVr Gy. move/(congr1 (gring_proj x)); rewrite -mulmxA mulmx_suml !linear_sum. rewrite (bigD1 x Gx) big1 => [|z /andP[Gz]]; rewrite !linearZ /=; last first. by rewrite eq_sym gring_projE // => /negPf->; rewrite scaler0. rewrite gring_projE // eqxx scalemx1 (bigD1 (x ^ y)%g) ?groupJ //=. rewrite big1 => [|z /andP[Gz]]; rewrite -scalemxAl !linearZ /=. rewrite !addr0 -!repr_mxM ?groupM // mulgA mulKVg mulgK => /rowP/(_ 0). by rewrite gring_projE // eqxx scalemx1 !mxE. rewrite eq_sym -(can_eq (conjgKV y)) conjgK conjgE invgK. by rewrite -!repr_mxM ?gring_projE ?groupM // => /negPf->; rewrite scaler0. Qed. Lemma regular_module_ideal m (M : 'M_(m, nG)) : mxmodule aG M = right_mx_ideal R_G (M *m R_G). Proof. apply/idP/idP=> modM. apply/mulsmx_subP=> A B; rewrite !mem_sub_gring => /andP[R_A M_A] R_B. by rewrite envelop_mxM // gring_row_mul (mxmodule_envelop modM). apply/mxmoduleP=> x Gx; apply/row_subP=> i; rewrite row_mul -mem_gring_mx. rewrite gring_mxJ // (mulsmx_subP modM) ?envelop_mx_id //. by rewrite mem_gring_mx row_sub. Qed. Definition irrType := socleType aG. Identity Coercion type_of_irrType : irrType >-> socleType. Variable sG : irrType. Definition irr_degree (i : sG) := \rank (socle_base i). Local Notation "'n_ i" := (irr_degree i) : group_ring_scope. Local Open Scope group_ring_scope. Lemma irr_degreeE i : 'n_i = \rank (socle_base i). Proof. by []. Qed. Lemma irr_degree_gt0 i : 'n_i > 0. Proof. by rewrite lt0n mxrank_eq0; case: (socle_simple i). Qed. Definition irr_repr i : mx_representation F G 'n_i := socle_repr i. Lemma irr_reprE i x : irr_repr i x = submod_mx (socle_module i) x. Proof. by []. Qed. Lemma rfix_regular : (rfix_mx aG G :=: gring_row (gset_mx G))%MS. Proof. apply/eqmxP/andP; split; last first. apply/rfix_mxP => x Gx; rewrite -gring_row_mul; congr gring_row. rewrite {2}/gset_mx (reindex_astabs 'R x) ?astabsR //= mulmx_suml. by apply: eq_bigr => y Gy; rewrite repr_mxM. apply/rV_subP=> v /rfix_mxP cGv. have /envelop_mxP[a def_v]: (gring_mx aG v \in R_G)%MS. by rewrite vec_mxK submxMl. suffices ->: v = a 1%g *: gring_row (gset_mx G) by rewrite scalemx_sub. rewrite -linearZ scaler_sumr -[v]gring_mxK def_v; congr (gring_row _). apply: eq_bigr => x Gx; congr (_ *: _). move/rowP/(_ 0): (congr1 (gring_proj x \o gring_mx aG) (cGv x Gx)). rewrite /= gring_mxJ // def_v mulmx_suml !linear_sum (bigD1 1%g) //=. rewrite repr_mx1 -scalemxAl mul1mx linearZ /= gring_projE // eqxx scalemx1. rewrite big1 ?addr0 ?mxE /= => [ | y /andP[Gy nt_y]]; last first. rewrite -scalemxAl linearZ -repr_mxM //= gring_projE ?groupM //. by rewrite eq_sym eq_mulgV1 mulgK (negPf nt_y) scaler0. rewrite (bigD1 x) //= linearZ /= gring_projE // eqxx scalemx1. rewrite big1 ?addr0 ?mxE // => y /andP[Gy ne_yx]. by rewrite linearZ /= gring_projE // eq_sym (negPf ne_yx) scaler0. Qed. Lemma principal_comp_subproof : mxsimple aG (rfix_mx aG G). Proof. apply: linear_mxsimple; first exact: rfix_mx_module. apply/eqP; rewrite rfix_regular eqn_leq rank_leq_row lt0n mxrank_eq0. apply/eqP => /(congr1 (gring_proj 1 \o gring_mx aG)); apply/eqP. rewrite /= -[gring_mx _ _]/(gring_op _ _) !linear0 !linear_sum (bigD1 1%g) //=. rewrite gring_opG ?gring_projE // eqxx big1 ?addr0 ?oner_eq0 // => x. by case/andP=> Gx nt_x; rewrite gring_opG // gring_projE // eq_sym (negPf nt_x). Qed. Fact principal_comp_key : unit. Proof. by []. Qed. Definition principal_comp_def := PackSocle (component_socle sG principal_comp_subproof). Definition principal_comp := locked_with principal_comp_key principal_comp_def. Local Notation "1" := principal_comp : irrType_scope. Lemma irr1_rfix : (1%irr :=: rfix_mx aG G)%MS. Proof. rewrite [1%irr]unlock PackSocleK; apply/eqmxP. rewrite (component_mx_id principal_comp_subproof) andbT. have [I [W isoW ->]] := component_mx_def principal_comp_subproof. apply/sumsmx_subP=> i _; have [f _ hom_f <-]:= isoW i. by apply/rfix_mxP=> x Gx; rewrite -(hom_mxP hom_f) // (rfix_mxP G _). Qed. Lemma rank_irr1 : \rank 1%irr = 1%N. Proof. apply/eqP; rewrite eqn_leq lt0n mxrank_eq0 nz_socle andbT. by rewrite irr1_rfix rfix_regular rank_leq_row. Qed. Lemma degree_irr1 : 'n_1 = 1%N. Proof. apply/eqP; rewrite eqn_leq irr_degree_gt0 -rank_irr1. by rewrite mxrankS ?component_mx_id //; exact: socle_simple. Qed. Definition Wedderburn_subring (i : sG) := <>%MS. Local Notation "''R_' i" := (Wedderburn_subring i) : group_ring_scope. Let sums_R : (\sum_i 'R_i :=: Socle sG *m R_G)%MS. Proof. apply/eqmxP; set R_S := (_ <= _)%MS. have sRS: R_S by apply/sumsmx_subP=> i; rewrite genmxE submxMr ?(sumsmx_sup i). rewrite sRS -(mulmxKpV sRS) mulmxA submxMr //; apply/sumsmx_subP=> i _. rewrite -(submxMfree _ _ gring_free) -(mulmxA _ _ R_G) mulmxKpV //. by rewrite (sumsmx_sup i) ?genmxE. Qed. Lemma Wedderburn_ideal i : mx_ideal R_G 'R_i. Proof. apply/andP; split; last first. rewrite /right_mx_ideal genmxE (muls_eqmx (genmxE _) (eqmx_refl _)). by rewrite -[(_ <= _)%MS]regular_module_ideal component_mx_module. apply/mulsmx_subP=> A B R_A; rewrite !genmxE !mem_sub_gring => /andP[R_B SiB]. rewrite envelop_mxM {R_A}// gring_row_mul -{R_B}(gring_rowK R_B). pose f := mulmx (gring_row A) \o gring_mx aG. rewrite -[_ *m _](mul_rV_lin1 [linear of f]). suffices: (i *m lin1_mx f <= i)%MS by apply: submx_trans; rewrite submxMr. apply: hom_component_mx; first exact: socle_simple. apply/rV_subP=> v _; apply/hom_mxP=> x Gx. by rewrite !mul_rV_lin1 /f /= gring_mxJ ?mulmxA. Qed. Lemma Wedderburn_direct : mxdirect (\sum_i 'R_i)%MS. Proof. apply/mxdirectP; rewrite /= sums_R mxrankMfree ?gring_free //. rewrite (mxdirectP (Socle_direct sG)); apply: eq_bigr=> i _ /=. by rewrite genmxE mxrankMfree ?gring_free. Qed. Lemma Wedderburn_disjoint i j : i != j -> ('R_i :&: 'R_j)%MS = 0. Proof. move=> ne_ij; apply/eqP; rewrite -submx0 capmxC. by rewrite -(mxdirect_sumsP Wedderburn_direct j) // capmxS // (sumsmx_sup i). Qed. Lemma Wedderburn_annihilate i j : i != j -> ('R_i * 'R_j)%MS = 0. Proof. move=> ne_ij; apply/eqP; rewrite -submx0 -(Wedderburn_disjoint ne_ij). rewrite sub_capmx; apply/andP; split. case/andP: (Wedderburn_ideal i) => _; apply: submx_trans. by rewrite mulsmxS // genmxE submxMl. case/andP: (Wedderburn_ideal j) => idlRj _; apply: submx_trans idlRj. by rewrite mulsmxS // genmxE submxMl. Qed. Lemma Wedderburn_mulmx0 i j A B : i != j -> (A \in 'R_i)%MS -> (B \in 'R_j)%MS -> A *m B = 0. Proof. move=> ne_ij RiA RjB; apply: memmx0. by rewrite -(Wedderburn_annihilate ne_ij) mem_mulsmx. Qed. Hypothesis F'G : [char F]^'.-group G. Lemma irr_mx_sum : (\sum_(i : sG) i = 1%:M)%MS. Proof. by apply: reducible_Socle1; exact: mx_Maschke. Qed. Lemma Wedderburn_sum : (\sum_i 'R_i :=: R_G)%MS. Proof. by apply: eqmx_trans sums_R _; rewrite /Socle irr_mx_sum mul1mx. Qed. Definition Wedderburn_id i := vec_mx (mxvec 1%:M *m proj_mx 'R_i (\sum_(j | j != i) 'R_j)%MS). Local Notation "''e_' i" := (Wedderburn_id i) : group_ring_scope. Lemma Wedderburn_sum_id : \sum_i 'e_i = 1%:M. Proof. rewrite -linear_sum; apply: canLR mxvecK _. have: (1%:M \in R_G)%MS := envelop_mx1 aG. rewrite -Wedderburn_sum; case/(sub_dsumsmx Wedderburn_direct) => e Re -> _. apply: eq_bigr => i _; have dxR := mxdirect_sumsP Wedderburn_direct i (erefl _). rewrite (bigD1 i) // mulmxDl proj_mx_id ?Re // proj_mx_0 ?addr0 //=. by rewrite summx_sub // => j ne_ji; rewrite (sumsmx_sup j) ?Re. Qed. Lemma Wedderburn_id_mem i : ('e_i \in 'R_i)%MS. Proof. by rewrite vec_mxK proj_mx_sub. Qed. Lemma Wedderburn_is_id i : mxring_id 'R_i 'e_i. Proof. have ideRi A: (A \in 'R_i)%MS -> 'e_i *m A = A. move=> RiA; rewrite -{2}[A]mul1mx -Wedderburn_sum_id mulmx_suml. rewrite (bigD1 i) //= big1 ?addr0 // => j ne_ji. by rewrite (Wedderburn_mulmx0 ne_ji) ?Wedderburn_id_mem. split=> // [||A RiA]; first 2 [exact: Wedderburn_id_mem]. apply: contraNneq (nz_socle i) => e0. apply/rowV0P=> v; rewrite -mem_gring_mx -(genmxE (i *m _)) => /ideRi. by rewrite e0 mul0mx => /(canLR gring_mxK); rewrite linear0. rewrite -{2}[A]mulmx1 -Wedderburn_sum_id mulmx_sumr (bigD1 i) //=. rewrite big1 ?addr0 // => j; rewrite eq_sym => ne_ij. by rewrite (Wedderburn_mulmx0 ne_ij) ?Wedderburn_id_mem. Qed. Lemma Wedderburn_closed i : ('R_i * 'R_i = 'R_i)%MS. Proof. rewrite -{3}['R_i]genmx_id -/'R_i -genmx_muls; apply/genmxP. have [idlRi idrRi] := andP (Wedderburn_ideal i). apply/andP; split. by apply: submx_trans idrRi; rewrite mulsmxS // genmxE submxMl. have [_ Ri_e ideRi _] := Wedderburn_is_id i. by apply/memmx_subP=> A RiA; rewrite -[A]ideRi ?mem_mulsmx. Qed. Lemma Wedderburn_is_ring i : mxring 'R_i. Proof. rewrite /mxring /left_mx_ideal Wedderburn_closed submx_refl. by apply/mxring_idP; exists 'e_i; exact: Wedderburn_is_id. Qed. Lemma Wedderburn_min_ideal m i (E : 'A_(m, nG)) : E != 0 -> (E <= 'R_i)%MS -> mx_ideal R_G E -> (E :=: 'R_i)%MS. Proof. move=> nzE sE_Ri /andP[idlE idrE]; apply/eqmxP; rewrite sE_Ri. pose M := E *m pinvmx R_G; have defE: E = M *m R_G. by rewrite mulmxKpV // (submx_trans sE_Ri) // genmxE submxMl. have modM: mxmodule aG M by rewrite regular_module_ideal -defE. have simSi := socle_simple i; set Si := socle_base i in simSi. have [I [W isoW defW]]:= component_mx_def simSi. rewrite /'R_i /socle_val /= defW genmxE defE submxMr //. apply/sumsmx_subP=> j _. have simW := mx_iso_simple (isoW j) simSi; have [modW _ minW] := simW. have [{minW}dxWE | nzWE] := eqVneq (W j :&: M)%MS 0; last first. by rewrite (sameP capmx_idPl eqmxP) minW ?capmxSl ?capmx_module. have [_ Rei ideRi _] := Wedderburn_is_id i. have:= nzE; rewrite -submx0 => /memmx_subP[A E_A]. rewrite -(ideRi _ (memmx_subP sE_Ri _ E_A)). have:= E_A; rewrite defE mem_sub_gring => /andP[R_A M_A]. have:= Rei; rewrite genmxE mem_sub_gring => /andP[Re]. rewrite -{2}(gring_rowK Re) /socle_val defW => /sub_sumsmxP[e ->]. rewrite !(linear_sum, mulmx_suml) summx_sub //= => k _. rewrite -(gring_rowK R_A) -gring_mxA -mulmxA gring_rowK //. rewrite ((W k *m _ =P 0) _) ?linear0 ?sub0mx //. have [f _ homWf defWk] := mx_iso_trans (mx_iso_sym (isoW j)) (isoW k). rewrite -submx0 -{k defWk}(eqmxMr _ defWk) -(hom_envelop_mxC homWf) //. rewrite -(mul0mx _ f) submxMr {f homWf}// -dxWE sub_capmx. rewrite (mxmodule_envelop modW) //=; apply/row_subP=> k. rewrite row_mul -mem_gring_mx -(gring_rowK R_A) gring_mxA gring_rowK //. by rewrite -defE (memmx_subP idlE) // mem_mulsmx ?gring_mxP. Qed. Section IrrComponent. (* The component of the socle of the regular module that is associated to an *) (* irreducible representation. *) Variables (n : nat) (rG : mx_representation F G n). Local Notation E_G := (enveloping_algebra_mx rG). Let not_rsim_op0 (iG j : sG) A : mx_rsim rG (socle_repr iG) -> iG != j -> (A \in 'R_j)%MS -> gring_op rG A = 0. Proof. case/mx_rsim_def=> f [f' _ hom_f] ne_iG_j RjA. transitivity (f *m in_submod _ (val_submod 1%:M *m A) *m f'). have{RjA}: (A \in R_G)%MS by rewrite -Wedderburn_sum (sumsmx_sup j). case/envelop_mxP=> a ->{A}; rewrite !(linear_sum, mulmx_suml). by apply: eq_bigr => x Gx; rewrite !linearZ /= -scalemxAl -hom_f ?gring_opG. rewrite (_ : _ *m A = 0) ?(linear0, mul0mx) //. apply/row_matrixP=> i; rewrite row_mul row0 -[row _ _]gring_mxK -gring_row_mul. rewrite (Wedderburn_mulmx0 ne_iG_j) ?linear0 // genmxE mem_gring_mx. by rewrite (row_subP _) // val_submod1 component_mx_id //; exact: socle_simple. Qed. Definition irr_comp := odflt 1%irr [pick i | gring_op rG 'e_i != 0]. Local Notation iG := irr_comp. Hypothesis irrG : mx_irreducible rG. Lemma rsim_irr_comp : mx_rsim rG (irr_repr iG). Proof. have [M [modM rsimM]] := rsim_regular_submod irrG F'G. have simM: mxsimple aG M. case/mx_irrP: irrG => n_gt0 minG. have [f def_n injf homf] := mx_rsim_sym rsimM. apply/(submod_mx_irr modM)/mx_irrP. split=> [|U modU nzU]; first by rewrite def_n. rewrite /row_full -(mxrankMfree _ injf) -genmxE {4}def_n. apply: minG; last by rewrite -mxrank_eq0 genmxE mxrankMfree // mxrank_eq0. rewrite (eqmx_module _ (genmxE _)); apply/mxmoduleP=> x Gx. by rewrite -mulmxA -homf // mulmxA submxMr // (mxmoduleP modU). pose i := PackSocle (component_socle sG simM). have{modM rsimM} rsimM: mx_rsim rG (socle_repr i). apply: mx_rsim_trans rsimM (mx_rsim_sym _); apply/mx_rsim_iso. apply: (component_mx_iso (socle_simple _)) => //. by rewrite [component_mx _ _]PackSocleK component_mx_id. have [<- // | ne_i_iG] := eqVneq i iG. suffices {i M simM ne_i_iG rsimM}: gring_op rG 'e_iG != 0. by rewrite (not_rsim_op0 rsimM ne_i_iG) ?Wedderburn_id_mem ?eqxx. rewrite /iG; case: pickP => //= G0. suffices: rG 1%g == 0. by case/idPn; rewrite -mxrank_eq0 repr_mx1 mxrank1 -lt0n; case/mx_irrP: irrG. rewrite -gring_opG // repr_mx1 -Wedderburn_sum_id linear_sum big1 // => j _. by move/eqP: (G0 j). Qed. Lemma irr_comp'_op0 j A : j != iG -> (A \in 'R_j)%MS -> gring_op rG A = 0. Proof. by rewrite eq_sym; exact: not_rsim_op0 rsim_irr_comp. Qed. Lemma irr_comp_envelop : ('R_iG *m lin_mx (gring_op rG) :=: E_G)%MS. Proof. apply/eqmxP/andP; split; apply/row_subP=> i. by rewrite row_mul mul_rV_lin gring_mxP. rewrite rowK /= -gring_opG ?enum_valP // -mul_vec_lin -gring_opG ?enum_valP //. rewrite vec_mxK /= -mulmxA mulmx_sub {i}//= -(eqmxMr _ Wedderburn_sum). rewrite (bigD1 iG) //= addsmxMr addsmxC [_ *m _](sub_kermxP _) ?adds0mx //=. apply/sumsmx_subP => j ne_j_iG; apply/memmx_subP=> A RjA; apply/sub_kermxP. by rewrite mul_vec_lin /= (irr_comp'_op0 ne_j_iG RjA) linear0. Qed. Lemma ker_irr_comp_op : ('R_iG :&: kermx (lin_mx (gring_op rG)))%MS = 0. Proof. apply/eqP; rewrite -submx0; apply/memmx_subP=> A. rewrite sub_capmx /= submx0 mxvec_eq0 => /andP[R_A]. rewrite (sameP sub_kermxP eqP) mul_vec_lin mxvec_eq0 /= => opA0. have [_ Re ideR _] := Wedderburn_is_id iG; rewrite -[A]ideR {ideR}//. move: Re; rewrite genmxE mem_sub_gring /socle_val => /andP[Re]. rewrite -{2}(gring_rowK Re) -submx0. pose simMi := socle_simple iG; have [J [M isoM ->]] := component_mx_def simMi. case/sub_sumsmxP=> e ->; rewrite linear_sum mulmx_suml summx_sub // => j _. rewrite -(in_submodK (submxMl _ (M j))); move: (in_submod _ _) => v. have modMj: mxmodule aG (M j) by apply: mx_iso_module (isoM j) _; case: simMi. have rsimMj: mx_rsim rG (submod_repr modMj). by apply: mx_rsim_trans rsim_irr_comp _; exact/mx_rsim_iso. have [f [f' _ hom_f]] := mx_rsim_def (mx_rsim_sym rsimMj); rewrite submx0. have <-: (gring_mx aG (val_submod (v *m (f *m gring_op rG A *m f')))) = 0. by rewrite (eqP opA0) !(mul0mx, linear0). have: (A \in R_G)%MS by rewrite -Wedderburn_sum (sumsmx_sup iG). case/envelop_mxP=> a ->; rewrite !(linear_sum, mulmx_suml) /=; apply/eqP. apply: eq_bigr=> x Gx; rewrite !linearZ -scalemxAl !linearZ /=. by rewrite gring_opG // -hom_f // val_submodJ // gring_mxJ. Qed. Lemma regular_op_inj : {in [pred A | (A \in 'R_iG)%MS] &, injective (gring_op rG)}. Proof. move=> A B RnA RnB /= eqAB; apply/eqP; rewrite -subr_eq0 -mxvec_eq0 -submx0. rewrite -ker_irr_comp_op sub_capmx (sameP sub_kermxP eqP) mul_vec_lin. by rewrite 2!linearB /= eqAB subrr linear0 addmx_sub ?eqmx_opp /=. Qed. Lemma rank_irr_comp : \rank 'R_iG = \rank E_G. Proof. symmetry; rewrite -{1}irr_comp_envelop; apply/mxrank_injP. by rewrite ker_irr_comp_op. Qed. End IrrComponent. Lemma irr_comp_rsim n1 n2 rG1 rG2 : @mx_rsim _ G n1 rG1 n2 rG2 -> irr_comp rG1 = irr_comp rG2. Proof. case=> f eq_n12; rewrite -eq_n12 in rG2 f * => inj_f hom_f. congr (odflt _ _); apply: eq_pick => i; rewrite -!mxrank_eq0. rewrite -(mxrankMfree _ inj_f); symmetry; rewrite -(eqmxMfull _ inj_f). have /envelop_mxP[e ->{i}]: ('e_i \in R_G)%MS. by rewrite -Wedderburn_sum (sumsmx_sup i) ?Wedderburn_id_mem. congr (\rank _ != _); rewrite !(mulmx_suml, linear_sum); apply: eq_bigr => x Gx. by rewrite !linearZ -scalemxAl /= !gring_opG ?hom_f. Qed. Lemma irr_reprK i : irr_comp (irr_repr i) = i. Proof. apply/eqP; apply/component_mx_isoP; try exact: socle_simple. by move/mx_rsim_iso: (rsim_irr_comp (socle_irr i)); exact: mx_iso_sym. Qed. Lemma irr_repr'_op0 i j A : j != i -> (A \in 'R_j)%MS -> gring_op (irr_repr i) A = 0. Proof. by move=> neq_ij /irr_comp'_op0-> //; [exact: socle_irr | rewrite irr_reprK]. Qed. Lemma op_Wedderburn_id i : gring_op (irr_repr i) 'e_i = 1%:M. Proof. rewrite -(gring_op1 (irr_repr i)) -Wedderburn_sum_id. rewrite linear_sum (bigD1 i) //= addrC big1 ?add0r // => j neq_ji. exact: irr_repr'_op0 (Wedderburn_id_mem j). Qed. Lemma irr_comp_id (M : 'M_nG) (modM : mxmodule aG M) (iM : sG) : mxsimple aG M -> (M <= iM)%MS -> irr_comp (submod_repr modM) = iM. Proof. move=> simM sMiM; rewrite -[iM]irr_reprK. apply/esym/irr_comp_rsim/mx_rsim_iso/component_mx_iso => //. exact: socle_simple. Qed. Lemma irr1_repr x : x \in G -> irr_repr 1 x = 1%:M. Proof. move=> Gx; suffices: x \in rker (irr_repr 1) by case/rkerP. apply: subsetP x Gx; rewrite rker_submod rfix_mx_rstabC // -irr1_rfix. by apply: component_mx_id; exact: socle_simple. Qed. Hypothesis splitG : group_splitting_field G. Lemma rank_Wedderburn_subring i : \rank 'R_i = ('n_i ^ 2)%N. Proof. apply/eqP; rewrite -{1}[i]irr_reprK; have irrSi := socle_irr i. by case/andP: (splitG irrSi) => _; rewrite rank_irr_comp. Qed. Lemma sum_irr_degree : (\sum_i 'n_i ^ 2 = nG)%N. Proof. apply: etrans (eqnP gring_free). rewrite -Wedderburn_sum (mxdirectP Wedderburn_direct) /=. by apply: eq_bigr => i _; rewrite rank_Wedderburn_subring. Qed. Lemma irr_mx_mult i : socle_mult i = 'n_i. Proof. rewrite /socle_mult -(mxrankMfree _ gring_free) -genmxE. by rewrite rank_Wedderburn_subring mulKn ?irr_degree_gt0. Qed. Lemma mxtrace_regular : {in G, forall x, \tr (aG x) = \sum_i \tr (socle_repr i x) *+ 'n_i}. Proof. move=> x Gx; have soc1: (Socle sG :=: 1%:M)%MS by rewrite -irr_mx_sum. rewrite -(mxtrace_submod1 (Socle_module sG) soc1) // mxtrace_Socle //. by apply: eq_bigr => i _; rewrite irr_mx_mult. Qed. Definition linear_irr := [set i | 'n_i == 1%N]. Lemma irr_degree_abelian : abelian G -> forall i, 'n_i = 1%N. Proof. by move=> cGG i; exact: mxsimple_abelian_linear (socle_simple i). Qed. Lemma linear_irr_comp i : 'n_i = 1%N -> (i :=: socle_base i)%MS. Proof. move=> ni1; apply/eqmxP; rewrite andbC -mxrank_leqif_eq -/'n_i. by rewrite -(mxrankMfree _ gring_free) -genmxE rank_Wedderburn_subring ni1. exact: component_mx_id (socle_simple i). Qed. Lemma Wedderburn_subring_center i : ('Z('R_i) :=: mxvec 'e_i)%MS. Proof. have [nz_e Re ideR idRe] := Wedderburn_is_id i. have Ze: (mxvec 'e_i <= 'Z('R_i))%MS. rewrite sub_capmx [(_ <= _)%MS]Re. by apply/cent_mxP=> A R_A; rewrite ideR // idRe. pose irrG := socle_irr i; set rG := socle_repr i in irrG. pose E_G := enveloping_algebra_mx rG; have absG := splitG irrG. apply/eqmxP; rewrite andbC -(geq_leqif (mxrank_leqif_eq Ze)). have ->: \rank (mxvec 'e_i) = (0 + 1)%N. by apply/eqP; rewrite eqn_leq rank_leq_row lt0n mxrank_eq0 mxvec_eq0. rewrite -(mxrank_mul_ker _ (lin_mx (gring_op rG))) addnC leq_add //. rewrite leqn0 mxrank_eq0 -submx0 -(ker_irr_comp_op irrG) capmxS //. by rewrite irr_reprK capmxSl. apply: leq_trans (mxrankS _) (rank_leq_row (mxvec 1%:M)). apply/memmx_subP=> Ar; case/submxP=> a ->{Ar}. rewrite mulmxA mul_rV_lin /=; set A := vec_mx _. rewrite memmx1 (mx_abs_irr_cent_scalar absG) // -memmx_cent_envelop. apply/cent_mxP=> Br; rewrite -(irr_comp_envelop irrG) irr_reprK. case/submxP=> b /(canRL mxvecK) ->{Br}; rewrite mulmxA mx_rV_lin /=. set B := vec_mx _; have RiB: (B \in 'R_i)%MS by rewrite vec_mxK submxMl. have sRiR: ('R_i <= R_G)%MS by rewrite -Wedderburn_sum (sumsmx_sup i). have: (A \in 'Z('R_i))%MS by rewrite vec_mxK submxMl. rewrite sub_capmx => /andP[RiA /cent_mxP cRiA]. by rewrite -!gring_opM ?(memmx_subP sRiR) 1?cRiA. Qed. Lemma Wedderburn_center : ('Z(R_G) :=: \matrix_(i < #|sG|) mxvec 'e_(enum_val i))%MS. Proof. have:= mxdirect_sums_center Wedderburn_sum Wedderburn_direct Wedderburn_ideal. move/eqmx_trans; apply; apply/eqmxP/andP; split. apply/sumsmx_subP=> i _; rewrite Wedderburn_subring_center. by apply: (eq_row_sub (enum_rank i)); rewrite rowK enum_rankK. apply/row_subP=> i; rewrite rowK -Wedderburn_subring_center. by rewrite (sumsmx_sup (enum_val i)). Qed. Lemma card_irr : #|sG| = tG. Proof. rewrite -(eqnP classg_base_free) classg_base_center. have:= mxdirect_sums_center Wedderburn_sum Wedderburn_direct Wedderburn_ideal. move->; rewrite (mxdirectP _) /=; last first. apply/mxdirect_sumsP=> i _; apply/eqP; rewrite -submx0. rewrite -{2}(mxdirect_sumsP Wedderburn_direct i) // capmxS ?capmxSl //=. by apply/sumsmx_subP=> j neji; rewrite (sumsmx_sup j) ?capmxSl. rewrite -sum1_card; apply: eq_bigr => i _; apply/eqP. rewrite Wedderburn_subring_center eqn_leq rank_leq_row lt0n mxrank_eq0. by rewrite andbT mxvec_eq0; case: (Wedderburn_is_id i). Qed. Section CenterMode. Variable i : sG. Let i0 := Ordinal (irr_degree_gt0 i). Definition irr_mode x := irr_repr i x i0 i0. Lemma irr_mode1 : irr_mode 1 = 1. Proof. by rewrite /irr_mode repr_mx1 mxE eqxx. Qed. Lemma irr_center_scalar : {in 'Z(G), forall x, irr_repr i x = (irr_mode x)%:M}. Proof. rewrite /irr_mode => x /setIP[Gx cGx]. suffices [a ->]: exists a, irr_repr i x = a%:M by rewrite mxE eqxx. apply/is_scalar_mxP; apply: (mx_abs_irr_cent_scalar (splitG (socle_irr i))). by apply/centgmxP=> y Gy; rewrite -!{1}repr_mxM 1?(centP cGx). Qed. Lemma irr_modeM : {in 'Z(G) &, {morph irr_mode : x y / (x * y)%g >-> x * y}}. Proof. move=> x y Zx Zy; rewrite {1}/irr_mode repr_mxM ?(subsetP (center_sub G)) //. by rewrite !irr_center_scalar // -scalar_mxM mxE eqxx. Qed. Lemma irr_modeX n : {in 'Z(G), {morph irr_mode : x / (x ^+ n)%g >-> x ^+ n}}. Proof. elim: n => [|n IHn] x Zx; first exact: irr_mode1. by rewrite expgS irr_modeM ?groupX // exprS IHn. Qed. Lemma irr_mode_unit : {in 'Z(G), forall x, irr_mode x \is a GRing.unit}. Proof. move=> x Zx /=; have:= unitr1 F. by rewrite -irr_mode1 -(mulVg x) irr_modeM ?groupV // unitrM; case/andP=> _. Qed. Lemma irr_mode_neq0 : {in 'Z(G), forall x, irr_mode x != 0}. Proof. by move=> x /irr_mode_unit; rewrite unitfE. Qed. Lemma irr_modeV : {in 'Z(G), {morph irr_mode : x / (x^-1)%g >-> x^-1}}. Proof. move=> x Zx /=; rewrite -[_^-1]mul1r; apply: canRL (mulrK (irr_mode_unit Zx)) _. by rewrite -irr_modeM ?groupV // mulVg irr_mode1. Qed. End CenterMode. Lemma irr1_mode x : x \in G -> irr_mode 1 x = 1. Proof. by move=> Gx; rewrite /irr_mode irr1_repr ?mxE. Qed. End Regular. Local Notation "[ 1 sG ]" := (principal_comp sG) : irrType_scope. Section LinearIrr. Variables (gT : finGroupType) (G : {group gT}). Lemma card_linear_irr (sG : irrType G) : [char F]^'.-group G -> group_splitting_field G -> #|linear_irr sG| = #|G : G^`(1)|%g. Proof. move=> F'G splitG; apply/eqP. wlog sGq: / irrType (G / G^`(1))%G by exact: socle_exists. have [_ nG'G] := andP (der_normal 1 G); apply/eqP; rewrite -card_quotient //. have cGqGq: abelian (G / G^`(1))%g by exact: sub_der1_abelian. have F'Gq: [char F]^'.-group (G / G^`(1))%g by exact: morphim_pgroup. have splitGq: group_splitting_field (G / G^`(1))%G. exact: quotient_splitting_field. rewrite -(sum_irr_degree sGq) // -sum1_card. pose rG (j : sGq) := morphim_repr (socle_repr j) nG'G. have irrG j: mx_irreducible (rG j) by apply/morphim_mx_irr; exact: socle_irr. rewrite (reindex (fun j => irr_comp sG (rG j))) /=. apply: eq_big => [j | j _]; last by rewrite irr_degree_abelian. have [_ lin_j _ _] := rsim_irr_comp sG F'G (irrG j). by rewrite inE -lin_j -irr_degreeE irr_degree_abelian. pose sGlin := {i | i \in linear_irr sG}. have sG'k (i : sGlin) : G^`(1)%g \subset rker (irr_repr (val i)). by case: i => i /=; rewrite !inE => lin; rewrite rker_linear //=; exact/eqP. pose h' u := irr_comp sGq (quo_repr (sG'k u) nG'G). have irrGq u: mx_irreducible (quo_repr (sG'k u) nG'G). by apply/quo_mx_irr; exact: socle_irr. exists (fun i => oapp h' [1 sGq]%irr (insub i)) => [j | i] lin_i. rewrite (insubT (mem _) lin_i) /=; apply/esym/eqP/socle_rsimP. apply: mx_rsim_trans (rsim_irr_comp sGq F'Gq (irrGq _)). have [g lin_g inj_g hom_g] := rsim_irr_comp sG F'G (irrG j). exists g => [||G'x]; last 1 [case/morphimP=> x _ Gx ->] || by []. by rewrite quo_repr_coset ?hom_g. rewrite (insubT (mem _) lin_i) /=; apply/esym/eqP/socle_rsimP. set u := exist _ _ _; apply: mx_rsim_trans (rsim_irr_comp sG F'G (irrG _)). have [g lin_g inj_g hom_g] := rsim_irr_comp sGq F'Gq (irrGq u). exists g => [||x Gx]; last 1 [have:= hom_g (coset _ x)] || by []. by rewrite quo_repr_coset; first by apply; rewrite mem_quotient. Qed. Lemma primitive_root_splitting_abelian (z : F) : #|G|.-primitive_root z -> abelian G -> group_splitting_field G. Proof. move=> ozG cGG [|n] rG irrG; first by case/mx_irrP: irrG. case: (pickP [pred x in G | ~~ is_scalar_mx (rG x)]) => [x | scalG]. case/andP=> Gx nscal_rGx; have: horner_mx (rG x) ('X^#|G| - 1) == 0. rewrite rmorphB rmorphX /= horner_mx_C horner_mx_X. rewrite -repr_mxX ?inE // ((_ ^+ _ =P 1)%g _) ?repr_mx1 ?subrr //. by rewrite -order_dvdn order_dvdG. case/idPn; rewrite -mxrank_eq0 -(factor_Xn_sub_1 ozG). elim: #|G| => [|i IHi]; first by rewrite big_nil horner_mx_C mxrank1. rewrite big_nat_recr //= rmorphM mxrankMfree {IHi}//. rewrite row_free_unit rmorphB /= horner_mx_X horner_mx_C. rewrite (mx_Schur irrG) ?subr_eq0 //; last first. by apply: contraNneq nscal_rGx => ->; exact: scalar_mx_is_scalar. rewrite -memmx_cent_envelop linearB. rewrite addmx_sub ?eqmx_opp ?scalar_mx_cent //= memmx_cent_envelop. by apply/centgmxP=> j Zh_j; rewrite -!repr_mxM // (centsP cGG). pose M := <>%MS. have linM: \rank M = 1%N by rewrite genmxE mxrank_delta. have modM: mxmodule rG M. apply/mxmoduleP=> x Gx; move/idPn: (scalG x); rewrite /= Gx negbK. by case/is_scalar_mxP=> ? ->; rewrite scalar_mxC submxMl. apply: linear_mx_abs_irr; apply/eqP; rewrite eq_sym -linM. by case/mx_irrP: irrG => _; apply; rewrite // -mxrank_eq0 linM. Qed. Lemma cycle_repr_structure x (sG : irrType G) : G :=: <[x]> -> [char F]^'.-group G -> group_splitting_field G -> exists2 w : F, #|G|.-primitive_root w & exists iphi : 'I_#|G| -> sG, [/\ bijective iphi, #|sG| = #|G|, forall i, irr_mode (iphi i) x = w ^+ i & forall i, irr_repr (iphi i) x = (w ^+ i)%:M]. Proof. move=> defG; rewrite {defG}(group_inj defG) -/#[x] in sG * => F'X splitF. have Xx := cycle_id x; have cXX := cycle_abelian x. have card_sG: #|sG| = #[x]. by rewrite card_irr //; apply/eqP; rewrite -card_classes_abelian. have linX := irr_degree_abelian splitF cXX (_ : sG). pose r (W : sG) := irr_mode W x. have scalX W: irr_repr W x = (r W)%:M. by apply: irr_center_scalar; rewrite ?(center_idP _). have inj_r: injective r. move=> V W eqVW; rewrite -(irr_reprK F'X V) -(irr_reprK F'X W). move: (irr_repr V) (irr_repr W) (scalX V) (scalX W). rewrite !linX {}eqVW => rV rW <- rWx; apply: irr_comp_rsim => //. exists 1%:M; rewrite ?row_free_unit ?unitmx1 // => xk; case/cycleP=> k ->{xk}. by rewrite mulmx1 mul1mx !repr_mxX // rWx. have rx1 W: r W ^+ #[x] = 1. by rewrite -irr_modeX ?(center_idP _) // expg_order irr_mode1. have /hasP[w _ prim_w]: has #[x].-primitive_root (map r (enum sG)). rewrite has_prim_root 1?map_inj_uniq ?enum_uniq //; first 1 last. by rewrite size_map -cardE card_sG. by apply/allP=> _ /mapP[W _ ->]; rewrite unity_rootE rx1. have iphi'P := prim_rootP prim_w (rx1 _); pose iphi' := sval (iphi'P _). have def_r W: r W = w ^+ iphi' W by exact: svalP (iphi'P W). have inj_iphi': injective iphi'. by move=> i j eq_ij; apply: inj_r; rewrite !def_r eq_ij. have iphiP: codom iphi' =i 'I_#[x]. by apply/subset_cardP; rewrite ?subset_predT // card_ord card_image. pose iphi i := iinv (iphiP i); exists w => //; exists iphi. have iphiK: cancel iphi iphi' by move=> i; exact: f_iinv. have r_iphi i: r (iphi i) = w ^+ i by rewrite def_r iphiK. split=> // [|i]; last by rewrite scalX r_iphi. by exists iphi' => // W; rewrite /iphi iinv_f. Qed. Lemma splitting_cyclic_primitive_root : cyclic G -> [char F]^'.-group G -> group_splitting_field G -> classically {z : F | #|G|.-primitive_root z}. Proof. case/cyclicP=> x defG F'G splitF; case=> // IH. wlog sG: / irrType G by exact: socle_exists. have [w prim_w _] := cycle_repr_structure sG defG F'G splitF. by apply: IH; exists w. Qed. End LinearIrr. End FieldRepr. Arguments Scope rfix_mx [_ _ group_scope nat_scope _ group_scope]. Arguments Scope gset_mx [_ _ group_scope group_scope]. Arguments Scope classg_base [_ _ group_scope group_scope]. Arguments Scope irrType [_ _ group_scope group_scope]. Implicit Arguments mxmoduleP [F gT G n rG m U]. Implicit Arguments envelop_mxP [F gT G n rG A]. Implicit Arguments hom_mxP [F gT G n rG m f W]. Implicit Arguments mx_Maschke [F gT G n U]. Implicit Arguments rfix_mxP [F gT G n rG m W]. Implicit Arguments cyclic_mxP [F gT G n rG u v]. Implicit Arguments annihilator_mxP [F gT G n rG u A]. Implicit Arguments row_hom_mxP [F gT G n rG u v]. Implicit Arguments mxsimple_isoP [F gT G n rG U V]. Implicit Arguments socle_exists [F gT G n]. Implicit Arguments socleP [F gT G n rG sG0 W W']. Implicit Arguments mx_abs_irrP [F gT G n rG]. Implicit Arguments socle_rsimP [F gT G n rG sG W1 W2]. Implicit Arguments val_submod_inj [F n U m]. Implicit Arguments val_factmod_inj [F n U m]. Prenex Implicits val_submod_inj val_factmod_inj. Notation "'Cl" := (Clifford_action _) : action_scope. Bind Scope irrType_scope with socle_sort. Notation "[ 1 sG ]" := (principal_comp sG) : irrType_scope. Arguments Scope irr_degree [_ _ Group_scope _ irrType_scope]. Arguments Scope irr_repr [_ _ Group_scope _ irrType_scope group_scope]. Arguments Scope irr_mode [_ _ Group_scope _ irrType_scope group_scope]. Notation "''n_' i" := (irr_degree i) : group_ring_scope. Notation "''R_' i" := (Wedderburn_subring i) : group_ring_scope. Notation "''e_' i" := (Wedderburn_id i) : group_ring_scope. Section DecideRed. Import MatrixFormula. Local Notation term := GRing.term. Local Notation True := GRing.True. Local Notation And := GRing.And (only parsing). Local Notation morphAnd f := ((big_morph f) true andb). Local Notation eval := GRing.eval. Local Notation holds := GRing.holds. Local Notation qf_form := GRing.qf_form. Local Notation qf_eval := GRing.qf_eval. Section Definitions. Variables (F : fieldType) (gT : finGroupType) (G : {group gT}) (n : nat). Variable rG : mx_representation F G n. Definition mxmodule_form (U : 'M[term F]_n) := \big[And/True]_(x in G) submx_form (mulmx_term U (mx_term (rG x))) U. Lemma mxmodule_form_qf U : qf_form (mxmodule_form U). Proof. by rewrite (morphAnd (@qf_form _)) ?big1 //= => x _; rewrite submx_form_qf. Qed. Lemma eval_mxmodule U e : qf_eval e (mxmodule_form U) = mxmodule rG (eval_mx e U). Proof. rewrite (morphAnd (qf_eval e)) //= big_andE /=. apply/forallP/mxmoduleP=> Umod x; move/implyP: (Umod x); by rewrite eval_submx eval_mulmx eval_mx_term. Qed. Definition mxnonsimple_form (U : 'M[term F]_n) := let V := vec_mx (row_var F (n * n) 0) in let nzV := (~ mxrank_form 0 V)%T in let properVU := (submx_form V U /\ ~ submx_form U V)%T in (Exists_row_form (n * n) 0 (mxmodule_form V /\ nzV /\ properVU))%T. End Definitions. Variables (F : decFieldType) (gT : finGroupType) (G : {group gT}) (n : nat). Variable rG : mx_representation F G n. Definition mxnonsimple_sat U := GRing.sat (@row_env _ (n * n) [::]) (mxnonsimple_form rG (mx_term U)). Lemma mxnonsimpleP U : U != 0 -> reflect (mxnonsimple rG U) (mxnonsimple_sat U). Proof. rewrite /mxnonsimple_sat {1}/mxnonsimple_form; set Vt := vec_mx _ => /= nzU. pose nsim V := [&& mxmodule rG V, (V <= U)%MS, V != 0 & \rank V < \rank U]. set nsimUt := (_ /\ _)%T; have: qf_form nsimUt. by rewrite /= mxmodule_form_qf !mxrank_form_qf !submx_form_qf. move/GRing.qf_evalP; set qev := @GRing.qf_eval _ => qevP. have qev_nsim u: qev (row_env [:: u]) nsimUt = nsim n (vec_mx u). rewrite /nsim -mxrank_eq0 /qev /= eval_mxmodule eval_mxrank. rewrite !eval_submx eval_mx_term eval_vec_mx eval_row_var /=. do 2!bool_congr; apply: andb_id2l => sUV. by rewrite ltn_neqAle andbC !mxrank_leqif_sup. have n2gt0: n ^ 2 > 0. by move: nzU; rewrite muln_gt0 -mxrank_eq0; case: posnP (U) => // ->. apply: (iffP satP) => [|[V nsimV]]. by case/Exists_rowP=> // v; move/qevP; rewrite qev_nsim; exists (vec_mx v). apply/Exists_rowP=> //; exists (mxvec V); apply/qevP. by rewrite qev_nsim mxvecK. Qed. Lemma dec_mxsimple_exists (U : 'M_n) : mxmodule rG U -> U != 0 -> {V | mxsimple rG V & V <= U}%MS. Proof. elim: {U}_.+1 {-2}U (ltnSn (\rank U)) => // m IHm U leUm modU nzU. have [nsimU | simU] := mxnonsimpleP nzU; last first. by exists U; first exact/mxsimpleP. move: (xchooseP nsimU); move: (xchoose _) => W /and4P[modW sWU nzW ltWU]. case: (IHm W) => // [|V simV sVW]; first exact: leq_trans ltWU _. by exists V; last exact: submx_trans sVW sWU. Qed. Lemma dec_mx_reducible_semisimple U : mxmodule rG U -> mx_completely_reducible rG U -> mxsemisimple rG U. Proof. elim: {U}_.+1 {-2}U (ltnSn (\rank U)) => // m IHm U leUm modU redU. have [U0 | nzU] := eqVneq U 0. have{U0} U0: (\sum_(i < 0) 0 :=: U)%MS by rewrite big_ord0 U0. by apply: (intro_mxsemisimple U0); case. have [V simV sVU] := dec_mxsimple_exists modU nzU; have [modV nzV _] := simV. have [W modW defVW dxVW] := redU V modV sVU. have [||I W_ /= simW defW _] := IHm W _ modW. - rewrite ltnS in leUm; apply: leq_trans leUm. by rewrite -defVW (mxdirectP dxVW) /= -add1n leq_add2r lt0n mxrank_eq0. - by apply: mx_reducibleS redU; rewrite // -defVW addsmxSr. suffices defU: (\sum_i oapp W_ V i :=: U)%MS. by apply: (intro_mxsemisimple defU) => [] [|i] //=. apply: eqmx_trans defVW; rewrite (bigD1 None) //=; apply/eqmxP. have [i0 _ | I0] := pickP I. by rewrite (reindex some) ?addsmxS ?defW //; exists (odflt i0) => //; case. rewrite big_pred0 //; last by case => // /I0. by rewrite !addsmxS ?sub0mx // -defW big_pred0. Qed. Lemma DecSocleType : socleType rG. Proof. have [n0 | n_gt0] := posnP n. by exists [::] => // M [_]; rewrite -mxrank_eq0 -leqn0 -n0 rank_leq_row. have n2_gt0: n ^ 2 > 0 by rewrite muln_gt0 n_gt0. pose span Ms := (\sum_(M <- Ms) component_mx rG M)%MS. have: {in [::], forall M, mxsimple rG M} by []. elim: _.+1 {-2}nil (ltnSn (n - \rank (span nil))) => // m IHm Ms Ms_ge_n simMs. rewrite ltnS in Ms_ge_n; pose V := span Ms; pose Vt := mx_term V. pose Ut i := vec_mx (row_var F (n * n) i); pose Zt := mx_term (0 : 'M[F]_n). pose exU i f := Exists_row_form (n * n) i (~ submx_form (Ut i) Zt /\ f (Ut i)). pose meetUVf U := exU 1%N (fun W => submx_form W Vt /\ submx_form W U)%T. pose mx_sat := GRing.sat (@row_env F (n * n) [::]). have ev_sub0 := GRing.qf_evalP _ (submx_form_qf _ Zt). have ev_mod := GRing.qf_evalP _ (mxmodule_form_qf rG _). pose ev := (eval_mxmodule, eval_submx, eval_vec_mx, eval_row_var, eval_mx_term). case haveU: (mx_sat (exU 0%N (fun U => mxmodule_form rG U /\ ~ meetUVf _ U)%T)). have [U modU]: {U : 'M_n | mxmodule rG U & (U != 0) && ((U :&: V)%MS == 0)}. apply: sig2W; case/Exists_rowP: (satP haveU) => //= u [nzU [modU tiUV]]. exists (vec_mx u); first by move/ev_mod: modU; rewrite !ev. set W := (_ :&: V)%MS; move/ev_sub0: nzU; rewrite !ev -!submx0 => -> /=. apply/idPn=> nzW; case: tiUV; apply/Exists_rowP=> //; exists (mxvec W). apply/GRing.qf_evalP; rewrite /= ?submx_form_qf // !ev mxvecK nzW /=. by rewrite andbC -sub_capmx. case/andP=> nzU tiUV; have [M simM sMU] := dec_mxsimple_exists modU nzU. apply: (IHm (M :: Ms)) => [|M']; last first. by case/predU1P=> [-> //|]; exact: simMs. have [_ nzM _] := simM. suffices ltVMV: \rank V < \rank (span (M :: Ms)). rewrite (leq_trans _ Ms_ge_n) // ltn_sub2l ?(leq_trans ltVMV) //. exact: rank_leq_row. rewrite /span big_cons (ltn_leqif (mxrank_leqif_sup (addsmxSr _ _))). apply: contra nzM; rewrite addsmx_sub -submx0 -(eqP tiUV) sub_capmx sMU. by case/andP=> sMV _; rewrite (submx_trans _ sMV) ?component_mx_id. exists Ms => // M simM; have [modM nzM minM] := simM. have sMV: (M <= V)%MS. apply: contraFT haveU => not_sMV; apply/satP/Exists_rowP=> //. exists (mxvec M); split; first by apply/ev_sub0; rewrite !ev mxvecK submx0. split; first by apply/ev_mod; rewrite !ev mxvecK. apply/Exists_rowP=> // [[w]]. apply/GRing.qf_evalP; rewrite /= ?submx_form_qf // !ev /= mxvecK submx0. rewrite -nz_row_eq0 -(cyclic_mx_eq0 rG); set W := cyclic_mx _ _. apply: contra not_sMV => /and3P[nzW Vw Mw]. have{Vw Mw} [sWV sWM]: (W <= V /\ W <= M)%MS. rewrite !cyclic_mx_sub ?(submx_trans (nz_row_sub _)) //. by rewrite sumsmx_module // => M' _; exact: component_mx_module. by rewrite (submx_trans _ sWV) // minM ?cyclic_mx_module. wlog sG: / socleType rG by exact: socle_exists. have sVS: (V <= \sum_(W : sG | has (fun Mi => Mi <= W) Ms) W)%MS. rewrite [V](big_nth 0) big_mkord; apply/sumsmx_subP=> i _. set Mi := Ms`_i; have MsMi: Mi \in Ms by exact: mem_nth. have simMi := simMs _ MsMi; have S_Mi := component_socle sG simMi. rewrite (sumsmx_sup (PackSocle S_Mi)) ?PackSocleK //. by apply/hasP; exists Mi; rewrite ?component_mx_id. have [W MsW isoWM] := subSocle_iso simM (submx_trans sMV sVS). have [Mi MsMi sMiW] := hasP MsW; apply/hasP; exists Mi => //. have [simMi simW] := (simMs _ MsMi, socle_simple W); apply/mxsimple_isoP=> //. exact: mx_iso_trans (mx_iso_sym isoWM) (component_mx_iso simW simMi sMiW). Qed. End DecideRed. (* Change of representation field (by tensoring) *) Section ChangeOfField. Variables (aF rF : fieldType) (f : {rmorphism aF -> rF}). Local Notation "A ^f" := (map_mx (GRing.RMorphism.apply f) A) : ring_scope. Variables (gT : finGroupType) (G : {group gT}). Section OneRepresentation. Variables (n : nat) (rG : mx_representation aF G n). Local Notation rGf := (map_repr f rG). Lemma map_rfix_mx H : (rfix_mx rG H)^f = rfix_mx rGf H. Proof. rewrite map_kermx //; congr (kermx _); apply: map_lin1_mx => //= v. rewrite map_mxvec map_mxM; congr (mxvec (_ *m _)); last first. by apply: map_lin1_mx => //= u; rewrite map_mxM map_vec_mx. apply/row_matrixP=> i. by rewrite -map_row !rowK map_mxvec map_mx_sub map_mx1. Qed. Lemma rcent_map A : rcent rGf A^f = rcent rG A. Proof. by apply/setP=> x; rewrite !inE -!map_mxM inj_eq //; exact: map_mx_inj. Qed. Lemma rstab_map m (U : 'M_(m, n)) : rstab rGf U^f = rstab rG U. Proof. by apply/setP=> x; rewrite !inE -!map_mxM inj_eq //; exact: map_mx_inj. Qed. Lemma rstabs_map m (U : 'M_(m, n)) : rstabs rGf U^f = rstabs rG U. Proof. by apply/setP=> x; rewrite !inE -!map_mxM ?map_submx. Qed. Lemma centgmx_map A : centgmx rGf A^f = centgmx rG A. Proof. by rewrite /centgmx rcent_map. Qed. Lemma mxmodule_map m (U : 'M_(m, n)) : mxmodule rGf U^f = mxmodule rG U. Proof. by rewrite /mxmodule rstabs_map. Qed. Lemma mxsimple_map (U : 'M_n) : mxsimple rGf U^f -> mxsimple rG U. Proof. case; rewrite map_mx_eq0 // mxmodule_map // => modU nzU minU. split=> // V modV sVU nzV; rewrite -(map_submx f). by rewrite (minU V^f) //= ?mxmodule_map ?map_mx_eq0 // map_submx. Qed. Lemma mx_irr_map : mx_irreducible rGf -> mx_irreducible rG. Proof. by move=> irrGf; apply: mxsimple_map; rewrite map_mx1. Qed. Lemma rker_map : rker rGf = rker rG. Proof. by rewrite /rker -rstab_map map_mx1. Qed. Lemma map_mx_faithful : mx_faithful rGf = mx_faithful rG. Proof. by rewrite /mx_faithful rker_map. Qed. Lemma map_mx_abs_irr : mx_absolutely_irreducible rGf = mx_absolutely_irreducible rG. Proof. by rewrite /mx_absolutely_irreducible -map_enveloping_algebra_mx row_full_map. Qed. End OneRepresentation. Lemma mx_rsim_map n1 n2 rG1 rG2 : @mx_rsim _ _ G n1 rG1 n2 rG2 -> mx_rsim (map_repr f rG1) (map_repr f rG2). Proof. case=> g eqn12 inj_g hom_g. by exists g^f => // [|x Gx]; rewrite ?row_free_map // -!map_mxM ?hom_g. Qed. Lemma map_section_repr n (rG : mx_representation aF G n) rGf U V (modU : mxmodule rG U) (modV : mxmodule rG V) (modUf : mxmodule rGf U^f) (modVf : mxmodule rGf V^f) : map_repr f rG =1 rGf -> mx_rsim (map_repr f (section_repr modU modV)) (section_repr modUf modVf). Proof. move=> def_rGf; set VU := <<_>>%MS. pose valUV := val_factmod (val_submod (1%:M : 'M[aF]_(\rank VU))). have sUV_Uf: (valUV^f <= U^f + V^f)%MS. rewrite -map_addsmx map_submx; apply: submx_trans (proj_factmodS _ _). by rewrite val_factmodS val_submod1 genmxE. exists (in_submod _ (in_factmod U^f valUV^f)) => [||x Gx]. - rewrite !genmxE -(mxrank_map f) map_mxM map_col_base. by case: (\rank (cokermx U)) / (mxrank_map _ _); rewrite map_cokermx. - rewrite -kermx_eq0 -submx0; apply/rV_subP=> u. rewrite (sameP sub_kermxP eqP) submx0 -val_submod_eq0. rewrite val_submodE -mulmxA -val_submodE in_submodK; last first. by rewrite genmxE -(in_factmod_addsK _ V^f) submxMr. rewrite in_factmodE mulmxA -in_factmodE in_factmod_eq0. move/(submxMr (in_factmod U 1%:M *m in_submod VU 1%:M)^f). rewrite -mulmxA -!map_mxM //; do 2!rewrite mulmxA -in_factmodE -in_submodE. rewrite val_factmodK val_submodK map_mx1 mulmx1. have ->: in_factmod U U = 0 by apply/eqP; rewrite in_factmod_eq0. by rewrite linear0 map_mx0 eqmx0 submx0. rewrite {1}in_submodE mulmxA -in_submodE -in_submodJ; last first. by rewrite genmxE -(in_factmod_addsK _ V^f) submxMr. congr (in_submod _ _); rewrite -in_factmodJ // in_factmodE mulmxA -in_factmodE. apply/eqP; rewrite -subr_eq0 -def_rGf -!map_mxM -linearB in_factmod_eq0. rewrite -map_mx_sub map_submx -in_factmod_eq0 linearB. rewrite /= (in_factmodJ modU) // val_factmodK. rewrite [valUV]val_factmodE mulmxA -val_factmodE val_factmodK. rewrite -val_submodE in_submodK ?subrr //. by rewrite mxmodule_trans ?section_module // val_submod1. Qed. Lemma map_regular_subseries U i (modU : mx_subseries (regular_repr aF G) U) (modUf : mx_subseries (regular_repr rF G) [seq M^f | M <- U]) : mx_rsim (map_repr f (subseries_repr i modU)) (subseries_repr i modUf). Proof. set mf := map _ in modUf *; rewrite /subseries_repr. do 2!move: (mx_subseries_module' _ _) (mx_subseries_module _ _). have mf_i V: nth 0^f (mf V) i = (V`_i)^f. case: (ltnP i (size V)) => [ltiV | leVi]; first exact: nth_map. by rewrite !nth_default ?size_map. rewrite -(map_mx0 f) mf_i (mf_i (0 :: U)) => modUi'f modUif modUi' modUi. by apply: map_section_repr; exact: map_regular_repr. Qed. Lemma extend_group_splitting_field : group_splitting_field aF G -> group_splitting_field rF G. Proof. move=> splitG n rG irrG. have modU0: all ((mxmodule (regular_repr aF G)) #|G|) [::] by []. apply: (mx_Schreier modU0 _) => // [[U [compU lastU _]]]; have [modU _]:= compU. pose Uf := map ((map_mx f) _ _) U. have{lastU} lastUf: (last 0 Uf :=: 1%:M)%MS. by rewrite -(map_mx0 f) -(map_mx1 f) last_map; exact/map_eqmx. have modUf: mx_subseries (regular_repr rF G) Uf. rewrite /mx_subseries all_map; apply: etrans modU; apply: eq_all => Ui /=. rewrite -mxmodule_map; apply: eq_subset_r => x. by rewrite !inE map_regular_repr. have absUf i: i < size U -> mx_absolutely_irreducible (subseries_repr i modUf). move=> lt_i_U; rewrite -(mx_rsim_abs_irr (map_regular_subseries i modU _)). rewrite map_mx_abs_irr; apply: splitG. by apply: mx_rsim_irr (mx_series_repr_irr compU lt_i_U); exact: section_eqmx. have compUf: mx_composition_series (regular_repr rF G) Uf. split=> // i; rewrite size_map => ltiU. move/max_submodP: (mx_abs_irrW (absUf i ltiU)); apply. rewrite -{2}(map_mx0 f) -map_cons !(nth_map 0) ?leqW //. by rewrite map_submx // ltmxW // (pathP _ (mx_series_lt compU)). have [[i ltiU] simUi] := rsim_regular_series irrG compUf lastUf. have{simUi} simUi: mx_rsim rG (subseries_repr i modUf). by apply: mx_rsim_trans simUi _; exact: section_eqmx. by rewrite (mx_rsim_abs_irr simUi) absUf; rewrite size_map in ltiU. Qed. End ChangeOfField. (* Construction of a splitting field FA of an irreducible representation, for *) (* a matrix A in the centraliser of the representation. FA is the row-vector *) (* space of the matrix algebra generated by A with basis 1, A, ..., A ^+ d.-1 *) (* or, equivalently, the polynomials in {poly F} taken mod the (irreducible) *) (* minimal polynomial pA of A (of degree d). *) (* The details of the construction of FA are encapsulated in a submodule. *) Module Import MatrixGenField. Section GenField. Variables (F : fieldType) (gT : finGroupType) (G : {group gT}) (n' : nat). Local Notation n := n'.+1. Variables (rG : mx_representation F G n) (A : 'M[F]_n). Local Notation d := (degree_mxminpoly A). Local Notation Ad := (powers_mx A d). Local Notation pA := (mxminpoly A). Let d_gt0 := mxminpoly_nonconstant A. Local Notation irr := mx_irreducible. Record gen_of (irrG : irr rG) (cGA : centgmx rG A) := Gen {rVval : 'rV[F]_d}. Prenex Implicits rVval. Hypotheses (irrG : irr rG) (cGA : centgmx rG A). Notation FA := (gen_of irrG cGA). Let inFA := Gen irrG cGA. Canonical gen_subType := Eval hnf in [newType for @rVval irrG cGA]. Definition gen_eqMixin := Eval hnf in [eqMixin of FA by <:]. Canonical gen_eqType := Eval hnf in EqType FA gen_eqMixin. Definition gen_choiceMixin := [choiceMixin of FA by <:]. Canonical gen_choiceType := Eval hnf in ChoiceType FA gen_choiceMixin. Definition gen0 := inFA 0. Definition genN (x : FA) := inFA (- val x). Definition genD (x y : FA) := inFA (val x + val y). Lemma gen_addA : associative genD. Proof. by move=> x y z; apply: val_inj; rewrite /= addrA. Qed. Lemma gen_addC : commutative genD. Proof. by move=> x y; apply: val_inj; rewrite /= addrC. Qed. Lemma gen_add0r : left_id gen0 genD. Proof. by move=> x; apply: val_inj; rewrite /= add0r. Qed. Lemma gen_addNr : left_inverse gen0 genN genD. Proof. by move=> x; apply: val_inj; rewrite /= addNr. Qed. Definition gen_zmodMixin := ZmodMixin gen_addA gen_addC gen_add0r gen_addNr. Canonical gen_zmodType := Eval hnf in ZmodType FA gen_zmodMixin. Definition pval (x : FA) := rVpoly (val x). Definition mxval (x : FA) := horner_mx A (pval x). Definition gen (x : F) := inFA (poly_rV x%:P). Lemma genK x : mxval (gen x) = x%:M. Proof. by rewrite /mxval [pval _]poly_rV_K ?horner_mx_C // size_polyC; case: (x != 0). Qed. Lemma mxval_inj : injective mxval. Proof. exact: inj_comp (@horner_rVpoly_inj _ _ A) val_inj. Qed. Lemma mxval0 : mxval 0 = 0. Proof. by rewrite /mxval [pval _]raddf0 rmorph0. Qed. Lemma mxvalN : {morph mxval : x / - x}. Proof. by move=> x; rewrite /mxval [pval _]raddfN rmorphN. Qed. Lemma mxvalD : {morph mxval : x y / x + y}. Proof. by move=> x y; rewrite /mxval [pval _]raddfD rmorphD. Qed. Definition mxval_sum := big_morph mxval mxvalD mxval0. Definition gen1 := inFA (poly_rV 1). Definition genM x y := inFA (poly_rV (pval x * pval y %% pA)). Definition genV x := inFA (poly_rV (mx_inv_horner A (mxval x)^-1)). Lemma mxval_gen1 : mxval gen1 = 1%:M. Proof. by rewrite /mxval [pval _]poly_rV_K ?size_poly1 // horner_mx_C. Qed. Lemma mxval_genM : {morph mxval : x y / genM x y >-> x *m y}. Proof. move=> x y; rewrite /mxval [pval _]poly_rV_K ?size_mod_mxminpoly //. by rewrite -horner_mxK mx_inv_hornerK ?horner_mx_mem // rmorphM. Qed. Lemma mxval_genV : {morph mxval : x / genV x >-> invmx x}. Proof. move=> x; rewrite /mxval [pval _]poly_rV_K ?size_poly ?mx_inv_hornerK //. pose m B : 'M[F]_(n * n) := lin_mx (mulmxr B); set B := mxval x. case uB: (B \is a GRing.unit); last by rewrite invr_out ?uB ?horner_mx_mem. have defAd: Ad = Ad *m m B *m m B^-1. apply/row_matrixP=> i. by rewrite !row_mul mul_rV_lin /= mx_rV_lin /= mulmxK ?vec_mxK. rewrite -[B^-1]mul1mx -(mul_vec_lin (mulmxr_linear _ _)) defAd submxMr //. rewrite -mxval_gen1 (submx_trans (horner_mx_mem _ _)) // {1}defAd. rewrite -(geq_leqif (mxrank_leqif_sup _)) ?mxrankM_maxl // -{}defAd. apply/row_subP=> i; rewrite row_mul rowK mul_vec_lin /= -{2}[A]horner_mx_X. by rewrite -rmorphX mulmxE -rmorphM horner_mx_mem. Qed. Lemma gen_mulA : associative genM. Proof. by move=> x y z; apply: mxval_inj; rewrite !mxval_genM mulmxA. Qed. Lemma gen_mulC : commutative genM. Proof. by move=> x y; rewrite /genM mulrC. Qed. Lemma gen_mul1r : left_id gen1 genM. Proof. by move=> x; apply: mxval_inj; rewrite mxval_genM mxval_gen1 mul1mx. Qed. Lemma gen_mulDr : left_distributive genM +%R. Proof. by move=> x y z; apply: mxval_inj; rewrite !(mxvalD, mxval_genM) mulmxDl. Qed. Lemma gen_ntriv : gen1 != 0. Proof. by rewrite -(inj_eq mxval_inj) mxval_gen1 mxval0 oner_eq0. Qed. Definition gen_ringMixin := ComRingMixin gen_mulA gen_mulC gen_mul1r gen_mulDr gen_ntriv. Canonical gen_ringType := Eval hnf in RingType FA gen_ringMixin. Canonical gen_comRingType := Eval hnf in ComRingType FA gen_mulC. Lemma mxval1 : mxval 1 = 1%:M. Proof. exact: mxval_gen1. Qed. Lemma mxvalM : {morph mxval : x y / x * y >-> x *m y}. Proof. exact: mxval_genM. Qed. Lemma mxval_sub : additive mxval. Proof. by move=> x y; rewrite mxvalD mxvalN. Qed. Canonical mxval_additive := Additive mxval_sub. Lemma mxval_is_multiplicative : multiplicative mxval. Proof. by split; [exact: mxvalM | exact: mxval1]. Qed. Canonical mxval_rmorphism := AddRMorphism mxval_is_multiplicative. Lemma mxval_centg x : centgmx rG (mxval x). Proof. rewrite [mxval _]horner_rVpoly -memmx_cent_envelop vec_mxK {x}mulmx_sub //. apply/row_subP=> k; rewrite rowK memmx_cent_envelop; apply/centgmxP => g Gg /=. by rewrite !mulmxE commrX // /GRing.comm -mulmxE (centgmxP cGA). Qed. Lemma gen_mulVr : GRing.Field.axiom genV. Proof. move=> x; rewrite -(inj_eq mxval_inj) mxval0. move/(mx_Schur irrG (mxval_centg x)) => u_x. by apply: mxval_inj; rewrite mxvalM mxval_genV mxval1 mulVmx. Qed. Lemma gen_invr0 : genV 0 = 0. Proof. by apply: mxval_inj; rewrite mxval_genV !mxval0 -{2}invr0. Qed. Definition gen_unitRingMixin := FieldUnitMixin gen_mulVr gen_invr0. Canonical gen_unitRingType := Eval hnf in UnitRingType FA gen_unitRingMixin. Canonical gen_comUnitRingType := Eval hnf in [comUnitRingType of FA]. Definition gen_fieldMixin := @FieldMixin _ _ _ _ : GRing.Field.mixin_of gen_unitRingType. Definition gen_idomainMixin := FieldIdomainMixin gen_fieldMixin. Canonical gen_idomainType := Eval hnf in IdomainType FA gen_idomainMixin. Canonical gen_fieldType := Eval hnf in FieldType FA gen_fieldMixin. Lemma mxvalV : {morph mxval : x / x^-1 >-> invmx x}. Proof. exact: mxval_genV. Qed. Lemma gen_is_rmorphism : rmorphism gen. Proof. split=> [x y|]; first by apply: mxval_inj; rewrite genK !rmorphB /= !genK. by split=> // x y; apply: mxval_inj; rewrite genK !rmorphM /= !genK. Qed. Canonical gen_additive := Additive gen_is_rmorphism. Canonical gen_rmorphism := RMorphism gen_is_rmorphism. (* The generated field contains a root of the minimal polynomial (in some *) (* cases we want to use the construction solely for that purpose). *) Definition groot := inFA (poly_rV ('X %% pA)). Lemma mxval_groot : mxval groot = A. Proof. rewrite /mxval [pval _]poly_rV_K ?size_mod_mxminpoly // -horner_mxK. by rewrite mx_inv_hornerK ?horner_mx_mem // horner_mx_X. Qed. Lemma mxval_grootX k : mxval (groot ^+ k) = A ^+ k. Proof. by rewrite rmorphX /= mxval_groot. Qed. Lemma map_mxminpoly_groot : (map_poly gen pA).[groot] = 0. Proof. (* The [_ groot] prevents divergence of simpl. *) apply: mxval_inj; rewrite -horner_map [_ groot]/= mxval_groot mxval0. rewrite -(mx_root_minpoly A); congr ((_ : {poly _}).[A]). by apply/polyP=> i; rewrite 3!coef_map; exact: genK. Qed. (* Plugging the extension morphism gen into the ext_repr construction *) (* yields a (reducible) tensored representation. *) Lemma non_linear_gen_reducible : d > 1 -> mxnonsimple (map_repr gen_rmorphism rG) 1%:M. Proof. rewrite ltnNge mxminpoly_linear_is_scalar => Anscal. pose Af := map_mx gen A; exists (kermx (Af - groot%:M)). rewrite submx1 kermx_centg_module /=; last first. apply/centgmxP=> z Gz; rewrite mulmxBl mulmxBr scalar_mxC. by rewrite -!map_mxM 1?(centgmxP cGA). rewrite andbC mxrank_ker -subn_gt0 mxrank1 subKn ?rank_leq_row // lt0n. rewrite mxrank_eq0 subr_eq0; case: eqP => [defAf | _]. rewrite -(map_mx_is_scalar gen_rmorphism) -/Af in Anscal. by case/is_scalar_mxP: Anscal; exists groot. rewrite -mxrank_eq0 mxrank_ker subn_eq0 row_leq_rank. apply/row_freeP=> [[XA' XAK]]. have pAf0: (mxminpoly Af).[groot] == 0. by rewrite mxminpoly_map ?map_mxminpoly_groot. have{pAf0} [q def_pAf]:= factor_theorem _ _ pAf0. have q_nz: q != 0. case: eqP (congr1 (fun p : {poly _} => size p) def_pAf) => // ->. by rewrite size_mxminpoly mul0r size_poly0. have qAf0: horner_mx Af q = 0. rewrite -[_ q]mulr1 -[1]XAK mulrA -{2}(horner_mx_X Af) -(horner_mx_C Af). by rewrite -rmorphB -rmorphM -def_pAf /= mx_root_minpoly mul0r. have{qAf0} := dvdp_leq q_nz (mxminpoly_min qAf0); rewrite def_pAf. by rewrite size_Mmonic ?monicXsubC // polyseqXsubC addn2 ltnn. Qed. (* An alternative to the above, used in the proof of the p-stability of *) (* groups of odd order, is to reconsider the original vector space as a *) (* vector space of dimension n / e over FA. This is applicable only if G is *) (* the largest group represented on the original vector space (i.e., if we *) (* are not studying a representation of G induced by one of a larger group, *) (* as in B & G Theorem 2.6 for instance). We can't fully exploit one of the *) (* benefits of this approach -- that the type domain for the vector space can *) (* remain unchanged -- because we're restricting ourselves to row matrices; *) (* we have to use explicit bijections to convert between the two views. *) Definition subbase m (B : 'rV_m) : 'M_(m * d, n) := \matrix_ik mxvec (\matrix_(i, k) (row (B 0 i) (A ^+ k))) 0 ik. Lemma gen_dim_ex_proof : exists m, [exists B : 'rV_m, row_free (subbase B)]. Proof. by exists 0%N; apply/existsP; exists 0. Qed. Lemma gen_dim_ub_proof m : [exists B : 'rV_m, row_free (subbase B)] -> (m <= n)%N. Proof. case/existsP=> B /eqnP def_md. by rewrite (leq_trans _ (rank_leq_col (subbase B))) // def_md leq_pmulr. Qed. Definition gen_dim := ex_maxn gen_dim_ex_proof gen_dim_ub_proof. Notation m := gen_dim. Definition gen_base : 'rV_m := odflt 0 [pick B | row_free (subbase B)]. Definition base := subbase gen_base. Lemma base_free : row_free base. Proof. rewrite /base /gen_base /m; case: pickP => //; case: ex_maxnP => m_max. by case/existsP=> B Bfree _ no_free; rewrite no_free in Bfree. Qed. Lemma base_full : row_full base. Proof. rewrite /row_full (eqnP base_free) /m; case: ex_maxnP => m. case/existsP=> /= B /eqnP Bfree m_max; rewrite -Bfree eqn_leq rank_leq_col. rewrite -{1}(mxrank1 F n) mxrankS //; apply/row_subP=> j; set u := row _ _. move/implyP: {m_max}(m_max m.+1); rewrite ltnn implybF. apply: contraR => nBj; apply/existsP. exists (row_mx (const_mx j : 'M_1) B); rewrite -row_leq_rank. pose Bj := Ad *m lin1_mx (mulmx u \o vec_mx). have rBj: \rank Bj = d. apply/eqP; rewrite eqn_leq rank_leq_row -subn_eq0 -mxrank_ker mxrank_eq0 /=. apply/rowV0P=> v /sub_kermxP; rewrite mulmxA mul_rV_lin1 /=. rewrite -horner_rVpoly; pose x := inFA v; rewrite -/(mxval x). have [[] // | nzx /(congr1 (mulmx^~ (mxval x^-1)))] := eqVneq x 0. rewrite mul0mx /= -mulmxA -mxvalM divff // mxval1 mulmx1. by move/rowP/(_ j)/eqP; rewrite !mxE !eqxx oner_eq0. rewrite {1}mulSn -Bfree -{1}rBj {rBj} -mxrank_disjoint_sum. rewrite mxrankS // addsmx_sub -[m.+1]/(1 + m)%N; apply/andP; split. apply/row_subP=> k; rewrite row_mul mul_rV_lin1 /=. apply: eq_row_sub (mxvec_index (lshift _ 0) k) _. by rewrite !rowK mxvecK mxvecE mxE row_mxEl mxE -row_mul mul1mx. apply/row_subP; case/mxvec_indexP=> i k. apply: eq_row_sub (mxvec_index (rshift 1 i) k) _. by rewrite !rowK !mxvecE 2!mxE row_mxEr. apply/eqP/rowV0P=> v; rewrite sub_capmx => /andP[/submxP[w]]. set x := inFA w; rewrite {Bj}mulmxA mul_rV_lin1 /= -horner_rVpoly -/(mxval x). have [-> | nzx ->] := eqVneq x 0; first by rewrite mxval0 mulmx0. move/(submxMr (mxval x^-1)); rewrite -mulmxA -mxvalM divff {nzx}//. rewrite mxval1 mulmx1 => Bx'j; rewrite (submx_trans Bx'j) in nBj => {Bx'j} //. apply/row_subP; case/mxvec_indexP=> i k. rewrite row_mul rowK mxvecE mxE rowE -mulmxA. have ->: A ^+ k *m mxval x^-1 = mxval (groot ^+ k / x). by rewrite mxvalM rmorphX /= mxval_groot. rewrite [mxval _]horner_rVpoly; move: {k u x}(val _) => u. rewrite (mulmx_sum_row u) !linear_sum summx_sub //= => k _. rewrite !linearZ scalemx_sub //= rowK mxvecK -rowE. by apply: eq_row_sub (mxvec_index i k) _; rewrite rowK mxvecE mxE. Qed. Lemma gen_dim_factor : (m * d)%N = n. Proof. by rewrite -(eqnP base_free) (eqnP base_full). Qed. Lemma gen_dim_gt0 : m > 0. Proof. by case: posnP gen_dim_factor => // ->. Qed. Section Bijection. Variable m1 : nat. Definition in_gen (W : 'M[F]_(m1, n)) : 'M[FA]_(m1, m) := \matrix_(i, j) inFA (row j (vec_mx (row i W *m pinvmx base))). Definition val_gen (W : 'M[FA]_(m1, m)) : 'M[F]_(m1, n) := \matrix_i (mxvec (\matrix_j val (W i j)) *m base). Lemma in_genK : cancel in_gen val_gen. Proof. move=> W; apply/row_matrixP=> i; rewrite rowK; set w := row i W. have b_w: (w <= base)%MS by rewrite submx_full ?base_full. rewrite -{b_w}(mulmxKpV b_w); congr (_ *m _). by apply/rowP; case/mxvec_indexP=> j k; rewrite mxvecE !mxE. Qed. Lemma val_genK : cancel val_gen in_gen. Proof. move=> W; apply/matrixP=> i j; apply: val_inj; rewrite mxE /= rowK. case/row_freeP: base_free => B' BB'; rewrite -[_ *m _]mulmx1 -BB' mulmxA. by rewrite mulmxKpV ?submxMl // -mulmxA BB' mulmx1 mxvecK rowK. Qed. Lemma in_gen0 : in_gen 0 = 0. Proof. by apply/matrixP=> i j; rewrite !mxE !(mul0mx, linear0). Qed. Lemma val_gen0 : val_gen 0 = 0. Proof. by apply: (canLR in_genK); rewrite in_gen0. Qed. Lemma in_genN : {morph in_gen : W / - W}. Proof. move=> W; apply/matrixP=> i j; apply: val_inj. by rewrite !mxE !(mulNmx, linearN). Qed. Lemma val_genN : {morph val_gen : W / - W}. Proof. by move=> W; apply: (canLR in_genK); rewrite in_genN val_genK. Qed. Lemma in_genD : {morph in_gen : U V / U + V}. Proof. move=> U V; apply/matrixP=> i j; apply: val_inj. by rewrite !mxE !(mulmxDl, linearD). Qed. Lemma val_genD : {morph val_gen : U V / U + V}. Proof. by move=> U V; apply: (canLR in_genK); rewrite in_genD !val_genK. Qed. Definition in_gen_sum := big_morph in_gen in_genD in_gen0. Definition val_gen_sum := big_morph val_gen val_genD val_gen0. Lemma in_genZ a : {morph in_gen : W / a *: W >-> gen a *: W}. Proof. move=> W; apply/matrixP=> i j; apply: mxval_inj. rewrite !mxE mxvalM genK ![mxval _]horner_rVpoly /=. by rewrite mul_scalar_mx !(I, scalemxAl, linearZ). Qed. End Bijection. Prenex Implicits val_genK in_genK. Lemma val_gen_rV (w : 'rV_m) : val_gen w = mxvec (\matrix_j val (w 0 j)) *m base. Proof. by apply/rowP=> j; rewrite mxE. Qed. Section Bijection2. Variable m1 : nat. Lemma val_gen_row W (i : 'I_m1) : val_gen (row i W) = row i (val_gen W). Proof. rewrite val_gen_rV rowK; congr (mxvec _ *m _). by apply/matrixP=> j k; rewrite !mxE. Qed. Lemma in_gen_row W (i : 'I_m1) : in_gen (row i W) = row i (in_gen W). Proof. by apply: (canLR val_genK); rewrite val_gen_row in_genK. Qed. Lemma row_gen_sum_mxval W (i : 'I_m1) : row i (val_gen W) = \sum_j row (gen_base 0 j) (mxval (W i j)). Proof. rewrite -val_gen_row [row i W]row_sum_delta val_gen_sum. apply: eq_bigr => /= j _; rewrite mxE; move: {W i}(W i j) => x. have ->: x = \sum_k gen (val x 0 k) * inFA (delta_mx 0 k). case: x => u; apply: mxval_inj; rewrite {1}[u]row_sum_delta. rewrite mxval_sum [mxval _]horner_rVpoly mulmx_suml linear_sum /=. apply: eq_bigr => k _; rewrite mxvalM genK [mxval _]horner_rVpoly /=. by rewrite mul_scalar_mx -scalemxAl linearZ. rewrite scaler_suml val_gen_sum mxval_sum linear_sum; apply: eq_bigr => k _. rewrite mxvalM genK mul_scalar_mx linearZ [mxval _]horner_rVpoly /=. rewrite -scalerA; apply: (canLR in_genK); rewrite in_genZ; congr (_ *: _). apply: (canRL val_genK); transitivity (row (mxvec_index j k) base); last first. by rewrite -rowE rowK mxvecE mxE rowK mxvecK. rewrite rowE -mxvec_delta -[val_gen _](row_id 0) rowK /=; congr (mxvec _ *m _). apply/row_matrixP=> j'; rewrite rowK !mxE mulr_natr rowE mul_delta_mx_cond. by rewrite !mulrb (fun_if rVval). Qed. Lemma val_genZ x : {morph @val_gen m1 : W / x *: W >-> W *m mxval x}. Proof. move=> W; apply/row_matrixP=> i; rewrite row_mul !row_gen_sum_mxval. by rewrite mulmx_suml; apply: eq_bigr => j _; rewrite mxE mulrC mxvalM row_mul. Qed. End Bijection2. Lemma submx_in_gen m1 m2 (U : 'M_(m1, n)) (V : 'M_(m2, n)) : (U <= V -> in_gen U <= in_gen V)%MS. Proof. move=> sUV; apply/row_subP=> i; rewrite -in_gen_row. case/submxP: (row_subP sUV i) => u ->{i}. rewrite mulmx_sum_row in_gen_sum summx_sub // => j _. by rewrite in_genZ in_gen_row scalemx_sub ?row_sub. Qed. Lemma submx_in_gen_eq m1 m2 (U : 'M_(m1, n)) (V : 'M_(m2, n)) : (V *m A <= V -> (in_gen U <= in_gen V) = (U <= V))%MS. Proof. move=> sVA_V; apply/idP/idP=> siUV; last exact: submx_in_gen. apply/row_subP=> i; rewrite -[row i U]in_genK in_gen_row. case/submxP: (row_subP siUV i) => u ->{i U siUV}. rewrite mulmx_sum_row val_gen_sum summx_sub // => j _. rewrite val_genZ val_gen_row in_genK rowE -mulmxA mulmx_sub //. rewrite [mxval _]horner_poly mulmx_sumr summx_sub // => [[k _]] _ /=. rewrite mulmxA mul_mx_scalar -scalemxAl scalemx_sub {u j}//. elim: k => [|k IHk]; first by rewrite mulmx1. by rewrite exprSr mulmxA (submx_trans (submxMr A IHk)). Qed. Definition gen_mx g := \matrix_i in_gen (row (gen_base 0 i) (rG g)). Let val_genJmx m : {in G, forall g, {morph @val_gen m : W / W *m gen_mx g >-> W *m rG g}}. Proof. move=> g Gg /= W; apply/row_matrixP=> i; rewrite -val_gen_row !row_mul. rewrite mulmx_sum_row val_gen_sum row_gen_sum_mxval mulmx_suml. apply: eq_bigr => /= j _; rewrite val_genZ rowK in_genK mxE -!row_mul. by rewrite (centgmxP (mxval_centg _)). Qed. Lemma gen_mx_repr : mx_repr G gen_mx. Proof. split=> [|g h Gg Gh]; apply: (can_inj val_genK). by rewrite -[gen_mx 1]mul1mx val_genJmx // repr_mx1 mulmx1. rewrite {1}[val_gen]lock -[gen_mx g]mul1mx !val_genJmx // -mulmxA -repr_mxM //. by rewrite -val_genJmx ?groupM ?mul1mx -?lock. Qed. Canonical gen_repr := MxRepresentation gen_mx_repr. Local Notation rGA := gen_repr. Lemma val_genJ m : {in G, forall g, {morph @val_gen m : W / W *m rGA g >-> W *m rG g}}. Proof. exact: val_genJmx. Qed. Lemma in_genJ m : {in G, forall g, {morph @in_gen m : v / v *m rG g >-> v *m rGA g}}. Proof. by move=> g Gg /= v; apply: (canLR val_genK); rewrite val_genJ ?in_genK. Qed. Lemma rfix_gen (H : {set gT}) : H \subset G -> (rfix_mx rGA H :=: in_gen (rfix_mx rG H))%MS. Proof. move/subsetP=> sHG; apply/eqmxP/andP; split; last first. by apply/rfix_mxP=> g Hg; rewrite -in_genJ ?sHG ?rfix_mx_id. rewrite -[rfix_mx rGA H]val_genK; apply: submx_in_gen. by apply/rfix_mxP=> g Hg; rewrite -val_genJ ?rfix_mx_id ?sHG. Qed. Definition rowval_gen m1 U := <<\matrix_ik mxvec (\matrix_(i < m1, k < d) (row i (val_gen U) *m A ^+ k)) 0 ik>>%MS. Lemma submx_rowval_gen m1 m2 (U : 'M_(m1, n)) (V : 'M_(m2, m)) : (U <= rowval_gen V)%MS = (in_gen U <= V)%MS. Proof. rewrite genmxE; apply/idP/idP=> sUV. apply: submx_trans (submx_in_gen sUV) _. apply/row_subP; case/mxvec_indexP=> i k; rewrite -in_gen_row rowK mxvecE mxE. rewrite -mxval_grootX -val_gen_row -val_genZ val_genK scalemx_sub //. exact: row_sub. rewrite -[U]in_genK; case/submxP: sUV => u ->{U}. apply/row_subP=> i0; rewrite -val_gen_row row_mul; move: {i0 u}(row _ u) => u. rewrite mulmx_sum_row val_gen_sum summx_sub // => i _. rewrite val_genZ [mxval _]horner_rVpoly [_ *m Ad]mulmx_sum_row. rewrite !linear_sum summx_sub // => k _. rewrite !linearZ scalemx_sub {u}//= rowK mxvecK val_gen_row. by apply: (eq_row_sub (mxvec_index i k)); rewrite rowK mxvecE mxE. Qed. Lemma rowval_genK m1 (U : 'M_(m1, m)) : (in_gen (rowval_gen U) :=: U)%MS. Proof. apply/eqmxP; rewrite -submx_rowval_gen submx_refl /=. by rewrite -{1}[U]val_genK submx_in_gen // submx_rowval_gen val_genK. Qed. Lemma rowval_gen_stable m1 (U : 'M_(m1, m)) : (rowval_gen U *m A <= rowval_gen U)%MS. Proof. rewrite -[A]mxval_groot -{1}[_ U]in_genK -val_genZ. by rewrite submx_rowval_gen val_genK scalemx_sub // rowval_genK. Qed. Lemma rstab_in_gen m1 (U : 'M_(m1, n)) : rstab rGA (in_gen U) = rstab rG U. Proof. apply/setP=> x; rewrite !inE; case Gx: (x \in G) => //=. by rewrite -in_genJ // (inj_eq (can_inj in_genK)). Qed. Lemma rstabs_in_gen m1 (U : 'M_(m1, n)) : rstabs rG U \subset rstabs rGA (in_gen U). Proof. apply/subsetP=> x; rewrite !inE => /andP[Gx nUx]. by rewrite -in_genJ Gx // submx_in_gen. Qed. Lemma rstabs_rowval_gen m1 (U : 'M_(m1, m)) : rstabs rG (rowval_gen U) = rstabs rGA U. Proof. apply/setP=> x; rewrite !inE; case Gx: (x \in G) => //=. by rewrite submx_rowval_gen in_genJ // (eqmxMr _ (rowval_genK U)). Qed. Lemma mxmodule_rowval_gen m1 (U : 'M_(m1, m)) : mxmodule rG (rowval_gen U) = mxmodule rGA U. Proof. by rewrite /mxmodule rstabs_rowval_gen. Qed. Lemma gen_mx_irr : mx_irreducible rGA. Proof. apply/mx_irrP; split=> [|U Umod nzU]; first exact: gen_dim_gt0. rewrite -sub1mx -rowval_genK -submx_rowval_gen submx_full //. case/mx_irrP: irrG => _; apply; first by rewrite mxmodule_rowval_gen. rewrite -(inj_eq (can_inj in_genK)) in_gen0. by rewrite -mxrank_eq0 rowval_genK mxrank_eq0. Qed. Lemma rker_gen : rker rGA = rker rG. Proof. apply/setP=> g; rewrite !inE !mul1mx; case Gg: (g \in G) => //=. apply/eqP/eqP=> g1; apply/row_matrixP=> i. by apply: (can_inj in_genK); rewrite rowE in_genJ //= g1 mulmx1 row1. by apply: (can_inj val_genK); rewrite rowE val_genJ //= g1 mulmx1 row1. Qed. Lemma gen_mx_faithful : mx_faithful rGA = mx_faithful rG. Proof. by rewrite /mx_faithful rker_gen. Qed. End GenField. Section DecideGenField. Import MatrixFormula. Variable F : decFieldType. Local Notation False := GRing.False. Local Notation True := GRing.True. Local Notation Bool b := (GRing.Bool b%bool). Local Notation term := (GRing.term F). Local Notation form := (GRing.formula F). Local Notation morphAnd f := ((big_morph f) true andb). Variables (gT : finGroupType) (G : {group gT}) (n' : nat). Local Notation n := n'.+1. Variables (rG : mx_representation F G n) (A : 'M[F]_n). Hypotheses (irrG : mx_irreducible rG) (cGA : centgmx rG A). Local Notation FA := (gen_of irrG cGA). Local Notation inFA := (Gen irrG cGA). Local Notation d := (degree_mxminpoly A). Let d_gt0 : d > 0 := mxminpoly_nonconstant A. Local Notation Ad := (powers_mx A d). Let mxT (u : 'rV_d) := vec_mx (mulmx_term u (mx_term Ad)). Let eval_mxT e u : eval_mx e (mxT u) = mxval (inFA (eval_mx e u)). Proof. by rewrite eval_vec_mx eval_mulmx eval_mx_term [mxval _]horner_rVpoly. Qed. Let Ad'T := mx_term (pinvmx Ad). Let mulT (u v : 'rV_d) := mulmx_term (mxvec (mulmx_term (mxT u) (mxT v))) Ad'T. Lemma eval_mulT e u v : eval_mx e (mulT u v) = val (inFA (eval_mx e u) * inFA (eval_mx e v)). Proof. rewrite !(eval_mulmx, eval_mxvec) !eval_mxT eval_mx_term. by apply: (can_inj (@rVpolyK _ _)); rewrite -mxvalM [rVpoly _]horner_rVpolyK. Qed. Fixpoint gen_term t := match t with | 'X_k => row_var _ d k | x%:T => mx_term (val (x : FA)) | n1%:R => mx_term (val (n1%:R : FA))%R | t1 + t2 => \row_i (gen_term t1 0%R i + gen_term t2 0%R i) | - t1 => \row_i (- gen_term t1 0%R i) | t1 *+ n1 => mulmx_term (mx_term n1%:R%:M)%R (gen_term t1) | t1 * t2 => mulT (gen_term t1) (gen_term t2) | t1^-1 => gen_term t1 | t1 ^+ n1 => iter n1 (mulT (gen_term t1)) (mx_term (val (1%R : FA))) end%T. Definition gen_env (e : seq FA) := row_env (map val e). Lemma nth_map_rVval (e : seq FA) j : (map val e)`_j = val e`_j. Proof. case: (ltnP j (size e)) => [| leej]; first exact: (nth_map 0 0). by rewrite !nth_default ?size_map. Qed. Lemma set_nth_map_rVval (e : seq FA) j v : set_nth 0 (map val e) j v = map val (set_nth 0 e j (inFA v)). Proof. apply: (@eq_from_nth _ 0) => [|k _]; first by rewrite !(size_set_nth, size_map). by rewrite !(nth_map_rVval, nth_set_nth) /= nth_map_rVval [rVval _]fun_if. Qed. Lemma eval_gen_term e t : GRing.rterm t -> eval_mx (gen_env e) (gen_term t) = val (GRing.eval e t). Proof. elim: t => //=. - by move=> k _; apply/rowP=> i; rewrite !mxE /= nth_row_env nth_map_rVval. - by move=> x _; rewrite eval_mx_term. - by move=> x _; rewrite eval_mx_term. - move=> t1 IH1 t2 IH2 /andP[rt1 rt2]; rewrite -{}IH1 // -{}IH2 //. by apply/rowP=> k; rewrite !mxE. - by move=> t1 IH1 rt1; rewrite -{}IH1 //; apply/rowP=> k; rewrite !mxE. - move=> t1 IH1 n1 rt1; rewrite eval_mulmx eval_mx_term mul_scalar_mx. by rewrite scaler_nat {}IH1 //; elim: n1 => //= n1 IHn1; rewrite !mulrS IHn1. - by move=> t1 IH1 t2 IH2 /andP[rt1 rt2]; rewrite eval_mulT IH1 ?IH2. move=> t1 IH1 n1 /IH1 {IH1}IH1. elim: n1 => [|n1 IHn1] /=; first by rewrite eval_mx_term. by rewrite eval_mulT exprS IH1 IHn1. Qed. (* WARNING: Coq will core dump if the Notation Bool is used in the match *) (* pattern here. *) Fixpoint gen_form f := match f with | GRing.Bool b => Bool b | t1 == t2 => mxrank_form 0 (gen_term (t1 - t2)) | GRing.Unit t1 => mxrank_form 1 (gen_term t1) | f1 /\ f2 => gen_form f1 /\ gen_form f2 | f1 \/ f2 => gen_form f1 \/ gen_form f2 | f1 ==> f2 => gen_form f1 ==> gen_form f2 | ~ f1 => ~ gen_form f1 | ('exists 'X_k, f1) => Exists_row_form d k (gen_form f1) | ('forall 'X_k, f1) => ~ Exists_row_form d k (~ (gen_form f1)) end%T. Lemma sat_gen_form e f : GRing.rformula f -> reflect (GRing.holds e f) (GRing.sat (gen_env e) (gen_form f)). Proof. have ExP := Exists_rowP; have set_val := set_nth_map_rVval. elim: f e => //. - by move=> b e _; exact: (iffP satP). - rewrite /gen_form => t1 t2 e rt_t; set t := (_ - _)%T. have:= GRing.qf_evalP (gen_env e) (mxrank_form_qf 0 (gen_term t)). rewrite eval_mxrank mxrank_eq0 eval_gen_term // => tP. by rewrite (sameP satP tP) /= subr_eq0 val_eqE; exact: eqP. - move=> f1 IH1 f2 IH2 s /= /andP[/(IH1 s)f1P /(IH2 s)f2P]. by apply: (iffP satP) => [[/satP/f1P ? /satP/f2P] | [/f1P/satP ? /f2P/satP]]. - move=> f1 IH1 f2 IH2 s /= /andP[/(IH1 s)f1P /(IH2 s)f2P]. by apply: (iffP satP) => /= [] []; try move/satP; do [move/f1P | move/f2P]; try move/satP; auto. - move=> f1 IH1 f2 IH2 s /= /andP[/(IH1 s)f1P /(IH2 s)f2P]. by apply: (iffP satP) => /= implP; try move/satP; move/f1P; try move/satP; move/implP; try move/satP; move/f2P; try move/satP. - move=> f1 IH1 s /= /(IH1 s) f1P. by apply: (iffP satP) => /= notP; try move/satP; move/f1P; try move/satP. - move=> k f1 IHf1 s /IHf1 f1P; apply: (iffP satP) => /= [|[[v f1v]]]. by case/ExP=> // x /satP; rewrite set_val => /f1P; exists (inFA x). by apply/ExP=> //; exists v; rewrite set_val; apply/satP/f1P. move=> i f1 IHf1 s /IHf1 f1P; apply: (iffP satP) => /= allf1 => [[v]|]. apply/f1P; case: satP => // notf1x; case: allf1; apply/ExP=> //. by exists v; rewrite set_val. by case/ExP=> //= v []; apply/satP; rewrite set_val; apply/f1P. Qed. Definition gen_sat e f := GRing.sat (gen_env e) (gen_form (GRing.to_rform f)). Lemma gen_satP : GRing.DecidableField.axiom gen_sat. Proof. move=> e f; have [tor rto] := GRing.to_rformP e f. exact: (iffP (sat_gen_form e (GRing.to_rform_rformula f))). Qed. Definition gen_decFieldMixin := DecFieldMixin gen_satP. Canonical gen_decFieldType := Eval hnf in DecFieldType FA gen_decFieldMixin. End DecideGenField. Section FiniteGenField. Variables (F : finFieldType) (gT : finGroupType) (G : {group gT}) (n' : nat). Local Notation n := n'.+1. Variables (rG : mx_representation F G n) (A : 'M[F]_n). Hypotheses (irrG : mx_irreducible rG) (cGA : centgmx rG A). Notation FA := (gen_of irrG cGA). (* This should be [countMixin of FA by <:]*) Definition gen_countMixin := (sub_countMixin (gen_subType irrG cGA)). Canonical gen_countType := Eval hnf in CountType FA gen_countMixin. Canonical gen_subCountType := Eval hnf in [subCountType of FA]. Definition gen_finMixin := [finMixin of FA by <:]. Canonical gen_finType := Eval hnf in FinType FA gen_finMixin. Canonical gen_subFinType := Eval hnf in [subFinType of FA]. Canonical gen_finZmodType := Eval hnf in [finZmodType of FA]. Canonical gen_baseFinGroupType := Eval hnf in [baseFinGroupType of FA for +%R]. Canonical gen_finGroupType := Eval hnf in [finGroupType of FA for +%R]. Canonical gen_finRingType := Eval hnf in [finRingType of FA]. Canonical gen_finComRingType := Eval hnf in [finComRingType of FA]. Canonical gen_finUnitRingType := Eval hnf in [finUnitRingType of FA]. Canonical gen_finComUnitRingType := Eval hnf in [finComUnitRingType of FA]. Canonical gen_finIdomainType := Eval hnf in [finIdomainType of FA]. Canonical gen_finFieldType := Eval hnf in [finFieldType of FA]. Lemma card_gen : #|{:FA}| = (#|F| ^ degree_mxminpoly A)%N. Proof. by rewrite card_sub card_matrix mul1n. Qed. End FiniteGenField. End MatrixGenField. Canonical gen_subType. Canonical gen_eqType. Canonical gen_choiceType. Canonical gen_countType. Canonical gen_subCountType. Canonical gen_finType. Canonical gen_subFinType. Canonical gen_zmodType. Canonical gen_finZmodType. Canonical gen_baseFinGroupType. Canonical gen_finGroupType. Canonical gen_ringType. Canonical gen_finRingType. Canonical gen_comRingType. Canonical gen_finComRingType. Canonical gen_unitRingType. Canonical gen_finUnitRingType. Canonical gen_comUnitRingType. Canonical gen_finComUnitRingType. Canonical gen_idomainType. Canonical gen_finIdomainType. Canonical gen_fieldType. Canonical gen_finFieldType. Canonical gen_decFieldType. (* Classical splitting and closure field constructions provide convenient *) (* packaging for the pointwise construction. *) Section BuildSplittingField. Implicit Type gT : finGroupType. Implicit Type F : fieldType. Lemma group_splitting_field_exists gT (G : {group gT}) F : classically {Fs : fieldType & {rmorphism F -> Fs} & group_splitting_field Fs G}. Proof. move: F => F0 [] // nosplit; pose nG := #|G|; pose aG F := regular_repr F G. pose m := nG.+1; pose F := F0; pose U : seq 'M[F]_nG := [::]. suffices: size U + m <= nG by rewrite ltnn. have: mx_subseries (aG F) U /\ path ltmx 0 U by []. pose f : {rmorphism F0 -> F} := [rmorphism of idfun]. elim: m F U f => [|m IHm] F U f [modU ltU]. by rewrite addn0 (leq_trans (max_size_mx_series ltU)) ?rank_leq_row. rewrite addnS ltnNge -implybF; apply/implyP=> le_nG_Um; apply nosplit. exists F => //; case=> [|n] rG irrG; first by case/mx_irrP: irrG. apply/idPn=> nabsG; pose cG := ('C(enveloping_algebra_mx rG))%MS. have{nabsG} [A]: exists2 A, (A \in cG)%MS & ~~ is_scalar_mx A. apply/has_non_scalar_mxP; rewrite ?scalar_mx_cent // ltnNge. by apply: contra nabsG; exact: cent_mx_scalar_abs_irr. rewrite {cG}memmx_cent_envelop -mxminpoly_linear_is_scalar -ltnNge => cGA. move/(non_linear_gen_reducible irrG cGA). set F' := gen_fieldType _ _; set rG' := @map_repr _ F' _ _ _ _ rG. move: F' (gen_rmorphism _ _ : {rmorphism F -> F'}) => F' f' in rG' * => irrG'. pose U' := [seq map_mx f' Ui | Ui <- U]. have modU': mx_subseries (aG F') U'. apply: etrans modU; rewrite /mx_subseries all_map; apply: eq_all => Ui. rewrite -(mxmodule_map f'); apply: eq_subset_r => x. by rewrite !inE map_regular_repr. case: notF; apply: (mx_Schreier modU ltU) => [[V [compV lastV sUV]]]. have{lastV} [] := rsim_regular_series irrG compV lastV. have{sUV} defV: V = U. apply/eqP; rewrite eq_sym -(geq_leqif (size_subseq_leqif sUV)). rewrite -(leq_add2r m); apply: leq_trans le_nG_Um. by apply: IHm f _; rewrite (mx_series_lt compV); case: compV. rewrite {V}defV in compV * => i rsimVi. apply: (mx_Schreier modU') => [|[V' [compV' _ sUV']]]. rewrite {modU' compV modU i le_nG_Um rsimVi}/U' -(map_mx0 f'). by apply: etrans ltU; elim: U 0 => //= Ui U IHU Ui'; rewrite IHU map_ltmx. have{sUV'} defV': V' = U'; last rewrite {V'}defV' in compV'. apply/eqP; rewrite eq_sym -(geq_leqif (size_subseq_leqif sUV')) size_map. rewrite -(leq_add2r m); apply: leq_trans le_nG_Um. apply: IHm [rmorphism of f' \o f] _. by rewrite (mx_series_lt compV'); case: compV'. suffices{irrG'}: mx_irreducible rG' by case/mxsimpleP=> _ _ []. have ltiU': i < size U' by rewrite size_map. apply: mx_rsim_irr (mx_rsim_sym _ ) (mx_series_repr_irr compV' ltiU'). apply: mx_rsim_trans (mx_rsim_map f' rsimVi) _; exact: map_regular_subseries. Qed. Lemma group_closure_field_exists gT F : classically {Fs : fieldType & {rmorphism F -> Fs} & group_closure_field Fs gT}. Proof. set n := #|{group gT}|. suffices: classically {Fs : fieldType & {rmorphism F -> Fs} & forall G : {group gT}, enum_rank G < n -> group_splitting_field Fs G}. - apply: classic_bind => [[Fs f splitFs]] _ -> //. by exists Fs => // G; exact: splitFs. elim: (n) => [|i IHi]; first by move=> _ -> //; exists F => //; exists id. apply: classic_bind IHi => [[F' f splitF']]. have [le_n_i _ -> // | lt_i_n] := leqP n i. by exists F' => // G _; apply: splitF'; exact: leq_trans le_n_i. have:= @group_splitting_field_exists _ (enum_val (Ordinal lt_i_n)) F'. apply: classic_bind => [[Fs f' splitFs]] _ -> //. exists Fs => [|G]; first exact: [rmorphism of (f' \o f)]. rewrite ltnS leq_eqVlt -{1}[i]/(val (Ordinal lt_i_n)) val_eqE. case/predU1P=> [defG | ltGi]; first by rewrite -[G]enum_rankK defG. by apply: (extend_group_splitting_field f'); exact: splitF'. Qed. Lemma group_closure_closed_field (F : closedFieldType) gT : group_closure_field F gT. Proof. move=> G [|n] rG irrG; first by case/mx_irrP: irrG. apply: cent_mx_scalar_abs_irr => //; rewrite leqNgt. apply/(has_non_scalar_mxP (scalar_mx_cent _ _)) => [[A cGA nscalA]]. have [a]: exists a, eigenvalue A a. pose P := mxminpoly A; pose d := degree_mxminpoly A. have Pd1: P`_d = 1. by rewrite -(eqP (mxminpoly_monic A)) /lead_coef size_mxminpoly. have d_gt0: d > 0 := mxminpoly_nonconstant A. have [a def_ad] := solve_monicpoly (nth 0 (- P)) d_gt0. exists a; rewrite eigenvalue_root_min -/P /root -oppr_eq0 -hornerN. rewrite horner_coef size_opp size_mxminpoly -/d big_ord_recr -def_ad. by rewrite coefN Pd1 mulN1r /= subrr. case/negP; rewrite kermx_eq0 row_free_unit (mx_Schur irrG) ?subr_eq0 //. by rewrite -memmx_cent_envelop -raddfN linearD addmx_sub ?scalar_mx_cent. by apply: contraNneq nscalA => ->; exact: scalar_mx_is_scalar. Qed. End BuildSplittingField. mathcomp-1.5/theories/center.v0000644000175000017500000005770612307636117015471 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div fintype bigop. Require Import finset fingroup morphism perm automorphism quotient action. Require Import gproduct gfunctor cyclic. (******************************************************************************) (* Definition of the center of a group and of external central products: *) (* 'Z(G) == the center of the group G, i.e., 'C_G(G). *) (* cprod_by isoZ == the finGroupType for the central product of H and K *) (* with centers identified by the isomorphism gz on 'Z(H); *) (* here isoZ : isom 'Z(H) 'Z(K) gz. Note that the actual *) (* central product is [set: cprod_by isoZ]. *) (* cpairg1 isoZ == the isomorphism from H to cprod_by isoZ, isoZ as above. *) (* cpair1g isoZ == the isomorphism from K to cprod_by isoZ, isoZ as above. *) (* xcprod H K == the finGroupType for the external central product of H *) (* and K with identified centers, provided the dynamically *) (* tested condition 'Z(H) \isog 'Z(K) holds. *) (* ncprod H n == the finGroupType for the central product of n copies of *) (* H with their centers identified; [set: ncprod H 0] is *) (* isomorphic to 'Z(H). *) (* xcprodm cf eqf == the morphism induced on cprod_by isoZ, where as above *) (* isoZ : isom 'Z(H) 'Z(K) gz, by fH : {morphism H >-> rT} *) (* and fK : {morphism K >-> rT}, given both *) (* cf : fH @* H \subset 'C(fK @* K) and *) (* eqf : {in 'Z(H), fH =1 fK \o gz}. *) (* Following Aschbacher, we only provide external central products with *) (* identified centers, as these are well defined provided the local center *) (* isomorphism group of one of the subgroups is full. Nevertheless the *) (* entire construction could be carried out under the weaker assumption that *) (* gz is an isomorphism between subgroups of 'Z(H) and 'Z(K), and even the *) (* uniqueness theorem holds under the weaker assumption that gz map 'Z(H) to *) (* a characteristic subgroup of 'Z(K) not isomorphic to any other subgroup of *) (* 'Z(K), a condition that holds for example when K is cyclic, as in the *) (* structure theorem for p-groups of symplectic type. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section Defs. Variable gT : finGroupType. Definition center (A : {set gT}) := 'C_A(A). Canonical center_group (G : {group gT}) : {group gT} := Eval hnf in [group of center G]. End Defs. Arguments Scope center [_ group_scope]. Notation "''Z' ( A )" := (center A) : group_scope. Notation "''Z' ( H )" := (center_group H) : Group_scope. Lemma morphim_center : GFunctor.pcontinuous center. Proof. move=> gT rT G D f; exact: morphim_subcent. Qed. Canonical center_igFun := [igFun by fun _ _ => subsetIl _ _ & morphim_center]. Canonical center_gFun := [gFun by morphim_center]. Canonical center_pgFun := [pgFun by morphim_center]. Section Center. Variables gT : finGroupType. Implicit Type rT : finGroupType. Implicit Types (x y : gT) (A B : {set gT}) (G H K D : {group gT}). Lemma subcentP A B x : reflect (x \in A /\ centralises x B) (x \in 'C_A(B)). Proof. rewrite inE. case: (x \in A); last by right; case. by apply: (iffP centP) => [|[]]. Qed. Lemma subcent_sub A B : 'C_A(B) \subset 'N_A(B). Proof. by rewrite setIS ?cent_sub. Qed. Lemma subcent_norm G B : 'N_G(B) \subset 'N('C_G(B)). Proof. by rewrite normsI ?subIset ?normG // orbC cent_norm. Qed. Lemma subcent_normal G B : 'C_G(B) <| 'N_G(B). Proof. by rewrite /normal subcent_sub subcent_norm. Qed. Lemma subcent_char G H K : H \char G -> K \char G -> 'C_H(K) \char G. Proof. case/charP=> sHG chHG /charP[sKG chKG]; apply/charP. split=> [|f injf Gf]; first by rewrite subIset ?sHG. by rewrite injm_subcent ?chHG ?chKG. Qed. Lemma centerP A x : reflect (x \in A /\ centralises x A) (x \in 'Z(A)). Proof. exact: subcentP. Qed. Lemma center_sub A : 'Z(A) \subset A. Proof. exact: subsetIl. Qed. Lemma center1 : 'Z(1) = [1 gT]. Proof. by apply/eqP; rewrite eqEsubset center_sub sub1G. Qed. Lemma centerC A : {in A, centralised 'Z(A)}. Proof. by apply/centsP; rewrite centsC subsetIr. Qed. Lemma center_normal G : 'Z(G) <| G. Proof. exact: gFnormal. Qed. Lemma sub_center_normal H G : H \subset 'Z(G) -> H <| G. Proof. by rewrite subsetI centsC /normal => /andP[-> /cents_norm]. Qed. Lemma center_abelian G : abelian 'Z(G). Proof. by rewrite /abelian subIset // centsC subIset // subxx orbT. Qed. Lemma center_char G : 'Z(G) \char G. Proof. exact: gFchar. Qed. Lemma center_idP A : reflect ('Z(A) = A) (abelian A). Proof. exact: setIidPl. Qed. Lemma center_class_formula G : #|G| = #|'Z(G)| + \sum_(xG in [set x ^: G | x in G :\: 'C(G)]) #|xG|. Proof. by rewrite acts_sum_card_orbit ?cardsID // astabsJ normsD ?norms_cent ?normG. Qed. Lemma subcent1P A x y : reflect (y \in A /\ commute x y) (y \in 'C_A[x]). Proof. rewrite inE; case: (y \in A); last by right; case. by apply: (iffP cent1P) => [|[]]. Qed. Lemma subcent1_id x G : x \in G -> x \in 'C_G[x]. Proof. move=> Gx; rewrite inE Gx; exact/cent1P. Qed. Lemma subcent1_sub x G : 'C_G[x] \subset G. Proof. exact: subsetIl. Qed. Lemma subcent1C x y G : x \in G -> y \in 'C_G[x] -> x \in 'C_G[y]. Proof. by move=> Gx /subcent1P[_ cxy]; exact/subcent1P. Qed. Lemma subcent1_cycle_sub x G : x \in G -> <[x]> \subset 'C_G[x]. Proof. by move=> Gx; rewrite cycle_subG ?subcent1_id. Qed. Lemma subcent1_cycle_norm x G : 'C_G[x] \subset 'N(<[x]>). Proof. by rewrite cents_norm // cent_gen cent_set1 subsetIr. Qed. Lemma subcent1_cycle_normal x G : x \in G -> <[x]> <| 'C_G[x]. Proof. by move=> Gx; rewrite /normal subcent1_cycle_norm subcent1_cycle_sub. Qed. (* Gorenstein. 1.3.4 *) Lemma cyclic_center_factor_abelian G : cyclic (G / 'Z(G)) -> abelian G. Proof. case/cyclicP=> a Ga; case: (cosetP a) => /= z Nz def_a. have G_Zz: G :=: 'Z(G) * <[z]>. rewrite -quotientK ?cycle_subG ?quotient_cycle //=. by rewrite -def_a -Ga quotientGK // center_normal. rewrite G_Zz abelianM cycle_abelian center_abelian centsC /= G_Zz. by rewrite subIset ?centS ?orbT ?mulG_subr. Qed. Lemma cyclic_factor_abelian H G : H \subset 'Z(G) -> cyclic (G / H) -> abelian G. Proof. move=> sHZ cycGH; apply: cyclic_center_factor_abelian. have nG: G \subset 'N(_) := normal_norm (sub_center_normal _). have [f <-]:= homgP (homg_quotientS (nG _ sHZ) (nG _ (subxx _)) sHZ). exact: morphim_cyclic. Qed. Section Injm. Variables (rT : finGroupType) (D : {group gT}) (f : {morphism D >-> rT}). Hypothesis injf : 'injm f. Lemma injm_center G : G \subset D -> f @* 'Z(G) = 'Z(f @* G). Proof. exact: injm_subcent. Qed. End Injm. End Center. Implicit Arguments center_idP [gT A]. Lemma isog_center (aT rT : finGroupType) (G : {group aT}) (H : {group rT}) : G \isog H -> 'Z(G) \isog 'Z(H). Proof. exact: gFisog. Qed. Section Product. Variable gT : finGroupType. Implicit Types (A B C : {set gT}) (G H K : {group gT}). Lemma center_prod H K : K \subset 'C(H) -> 'Z(H) * 'Z(K) = 'Z(H * K). Proof. move=> cHK; apply/setP=> z; rewrite {3}/center centM !inE. have cKH: H \subset 'C(K) by rewrite centsC. apply/imset2P/and3P=> [[x y /setIP[Hx cHx] /setIP[Ky cKy] ->{z}]| []]. by rewrite mem_imset2 ?groupM // ?(subsetP cHK) ?(subsetP cKH). case/imset2P=> x y Hx Ky ->{z}. rewrite groupMr => [cHx|]; last exact: subsetP Ky. rewrite groupMl => [cKy|]; last exact: subsetP Hx. by exists x y; rewrite ?inE ?Hx ?Ky. Qed. Lemma center_cprod A B G : A \* B = G -> 'Z(A) \* 'Z(B) = 'Z(G). Proof. case/cprodP => [[H K -> ->] <- cHK]. rewrite cprodE ?center_prod //= subIset ?(subset_trans cHK) //. by rewrite centS ?center_sub. Qed. Lemma center_bigcprod I r P (F : I -> {set gT}) G : \big[cprod/1]_(i <- r | P i) F i = G -> \big[cprod/1]_(i <- r | P i) 'Z(F i) = 'Z(G). Proof. elim/big_ind2: _ G => [_ <-|A B C D IHA IHB G dG|_ _ G ->]; rewrite ?center1 //. case/cprodP: dG IHA IHB (dG) => [[H K -> ->] _ _] IHH IHK dG. by rewrite (IHH H) // (IHK K) // (center_cprod dG). Qed. Lemma cprod_center_id G : G \* 'Z(G) = G. Proof. by rewrite cprodE ?subsetIr // mulGSid ?center_sub. Qed. Lemma center_dprod A B G : A \x B = G -> 'Z(A) \x 'Z(B) = 'Z(G). Proof. case/dprodP=> [[H1 H2 -> ->] defG cH12 trH12]. move: defG; rewrite -cprodE // => /center_cprod/cprodP[_ /= <- cZ12]. by apply: dprodE; rewrite //= setIAC setIA -setIA trH12 (setIidPl _) ?sub1G. Qed. Lemma center_bigdprod I r P (F: I -> {set gT}) G : \big[dprod/1]_(i <- r | P i) F i = G -> \big[dprod/1]_(i <- r | P i) 'Z(F i) = 'Z(G). Proof. elim/big_ind2: _ G => [_ <-|A B C D IHA IHB G dG|_ _ G ->]; rewrite ?center1 //. case/dprodP: dG IHA IHB (dG) => [[H K -> ->] _ _ _] IHH IHK dG. by rewrite (IHH H) // (IHK K) // (center_dprod dG). Qed. Lemma Aut_cprod_full G H K : H \* K = G -> 'Z(H) = 'Z(K) -> Aut_in (Aut H) 'Z(H) \isog Aut 'Z(H) -> Aut_in (Aut K) 'Z(K) \isog Aut 'Z(K) -> Aut_in (Aut G) 'Z(G) \isog Aut 'Z(G). Proof. move=> defG eqZHK; have [_ defHK cHK] := cprodP defG. have defZ: 'Z(G) = 'Z(H) by rewrite -defHK -center_prod // eqZHK mulGid. have ziHK: H :&: K = 'Z(K). by apply/eqP; rewrite eqEsubset subsetI -{1 2}eqZHK !center_sub setIS. have AutZP := Aut_sub_fullP (@center_sub gT _). move/AutZP=> AutZHfull /AutZP AutZKfull; apply/AutZP=> g injg gZ. have [gH [def_gH ker_gH _ im_gH]] := domP g defZ. have [gK [def_gK ker_gK _ im_gK]] := domP g (etrans defZ eqZHK). have [injgH injgK]: 'injm gH /\ 'injm gK by rewrite ker_gH ker_gK. have [gHH gKK]: gH @* 'Z(H) = 'Z(H) /\ gK @* 'Z(K) = 'Z(K). by rewrite im_gH im_gK -eqZHK -defZ. have [|fH [injfH im_fH fHZ]] := AutZHfull gH injgH. by rewrite im_gH /= -defZ. have [|fK [injfK im_fK fKZ]] := AutZKfull gK injgK. by rewrite im_gK /= -eqZHK -defZ. have cfHK: fK @* K \subset 'C(fH @* H) by rewrite im_fH im_fK. have eq_fHK: {in H :&: K, fH =1 fK}. by move=> z; rewrite ziHK => Zz; rewrite fHZ ?fKZ /= ?eqZHK // def_gH def_gK. exists (cprodm_morphism defG cfHK eq_fHK). rewrite injm_cprodm injfH injfK im_cprodm im_fH im_fK defHK. rewrite -morphimIdom ziHK -eqZHK injm_center // im_fH eqxx. split=> //= z; rewrite {1}defZ => Zz; have [Hz _] := setIP Zz. by rewrite cprodmEl // fHZ // def_gH. Qed. End Product. Section CprodBy. Variables gTH gTK : finGroupType. Variables (H : {group gTH}) (K : {group gTK}) (gz : {morphism 'Z(H) >-> gTK}). Definition ker_cprod_by of isom 'Z(H) 'Z(K) gz := [set xy | let: (x, y) := xy in (x \in 'Z(H)) && (y == (gz x)^-1)]. Hypothesis isoZ : isom 'Z(H) 'Z(K) gz. Let kerHK := ker_cprod_by isoZ. Let injgz : 'injm gz. Proof. by case/isomP: isoZ. Qed. Let gzZ : gz @* 'Z(H) = 'Z(K). Proof. by case/isomP: isoZ. Qed. Let gzZchar : gz @* 'Z(H) \char 'Z(K). Proof. by rewrite gzZ char_refl. Qed. Let sgzZZ : gz @* 'Z(H) \subset 'Z(K) := char_sub gzZchar. Let sZH := center_sub H. Let sZK := center_sub K. Let sgzZG : gz @* 'Z(H) \subset K := subset_trans sgzZZ sZK. Lemma ker_cprod_by_is_group : group_set kerHK. Proof. apply/group_setP; rewrite inE /= group1 morph1 invg1 /=. split=> // [[x1 y1] [x2 y2]]. rewrite inE /= => /andP[Zx1 /eqP->]; have [_ cGx1] := setIP Zx1. rewrite inE /= => /andP[Zx2 /eqP->]; have [Gx2 _] := setIP Zx2. by rewrite inE /= groupM //= -invMg (centP cGx1) // morphM. Qed. Canonical ker_cprod_by_group := Group ker_cprod_by_is_group. Lemma ker_cprod_by_central : kerHK \subset 'Z(setX H K). Proof. rewrite -(center_dprod (setX_dprod H K)) -morphim_pairg1 -morphim_pair1g. rewrite -!injm_center ?subsetT ?injm_pair1g ?injm_pairg1 //=. rewrite morphim_pairg1 morphim_pair1g setX_dprod. apply/subsetP=> [[x y]]; rewrite inE => /andP[Zx /eqP->]. by rewrite inE /= Zx groupV (subsetP sgzZZ) ?mem_morphim. Qed. Fact cprod_by_key : unit. Proof. by []. Qed. Definition cprod_by_def := subFinGroupType [group of setX H K / kerHK]. Definition cprod_by := locked_with cprod_by_key cprod_by_def. Local Notation C := [set: FinGroup.arg_sort (FinGroup.base cprod_by)]. Definition in_cprod : gTH * gTK -> cprod_by := let: tt as k := cprod_by_key return _ -> locked_with k cprod_by_def in subg _ \o coset kerHK. Lemma in_cprodM : {in setX H K &, {morph in_cprod : u v / u * v}}. Proof. rewrite /in_cprod /cprod_by; case: cprod_by_key => /= u v Gu Gv. have nkerHKG := normal_norm (sub_center_normal ker_cprod_by_central). by rewrite -!morphM ?mem_quotient // (subsetP nkerHKG). Qed. Canonical in_cprod_morphism := Morphism in_cprodM. Lemma ker_in_cprod : 'ker in_cprod = kerHK. Proof. transitivity ('ker (subg [group of setX H K / kerHK] \o coset kerHK)). rewrite /ker /morphpre /= /in_cprod /cprod_by; case: cprod_by_key => /=. by rewrite ['N(_) :&: _]quotientGK ?sub_center_normal ?ker_cprod_by_central. by rewrite ker_comp ker_subg -kerE ker_coset. Qed. Lemma cpairg1_dom : H \subset 'dom (in_cprod \o @pairg1 gTH gTK). Proof. by rewrite -sub_morphim_pre ?subsetT // morphim_pairg1 setXS ?sub1G. Qed. Lemma cpair1g_dom : K \subset 'dom (in_cprod \o @pair1g gTH gTK). Proof. by rewrite -sub_morphim_pre ?subsetT // morphim_pair1g setXS ?sub1G. Qed. Definition cpairg1 := tag (restrmP _ cpairg1_dom). Definition cpair1g := tag (restrmP _ cpair1g_dom). Local Notation CH := (mfun cpairg1 @* gval H). Local Notation CK := (mfun cpair1g @* gval K). Lemma injm_cpairg1 : 'injm cpairg1. Proof. rewrite /cpairg1; case: restrmP => _ [_ -> _ _]. rewrite ker_comp ker_in_cprod; apply/subsetP=> x; rewrite 5!inE /=. by case/and3P=> _ Zx; rewrite inE eq_sym (inv_eq invgK) invg1 morph_injm_eq1. Qed. Let injH := injm_cpairg1. Lemma injm_cpair1g : 'injm cpair1g. Proof. rewrite /cpair1g; case: restrmP => _ [_ -> _ _]. rewrite ker_comp ker_in_cprod; apply/subsetP=> y; rewrite !inE /= morph1 invg1. by case/and3P. Qed. Let injK := injm_cpair1g. Lemma im_cpair_cent : CK \subset 'C(CH). Proof. rewrite /cpairg1 /cpair1g; do 2!case: restrmP => _ [_ _ _ -> //]. rewrite !morphim_comp morphim_cents // morphim_pair1g morphim_pairg1. by case/dprodP: (setX_dprod H K). Qed. Hint Resolve im_cpair_cent. Lemma im_cpair : CH * CK = C. Proof. rewrite /cpairg1 /cpair1g; do 2!case: restrmP => _ [_ _ _ -> //]. rewrite !morphim_comp -morphimMl morphim_pairg1 ?setXS ?sub1G //. rewrite morphim_pair1g setX_prod morphimEdom /= /in_cprod /cprod_by. by case: cprod_by_key; rewrite /= imset_comp imset_coset -morphimEdom im_subg. Qed. Lemma im_cpair_cprod : CH \* CK = C. Proof. by rewrite cprodE ?im_cpair. Qed. Lemma eq_cpairZ : {in 'Z(H), cpairg1 =1 cpair1g \o gz}. Proof. rewrite /cpairg1 /cpair1g => z1 Zz1; set z2 := gz z1. have Zz2: z2 \in 'Z(K) by rewrite (subsetP sgzZZ) ?mem_morphim. have [[Gz1 _] [/= Gz2 _]]:= (setIP Zz1, setIP Zz2). do 2![case: restrmP => f /= [df _ _ _]; rewrite {f}df]. apply/rcoset_kerP; rewrite ?inE ?group1 ?andbT //. by rewrite ker_in_cprod mem_rcoset inE /= invg1 mulg1 mul1g Zz1 /=. Qed. Lemma setI_im_cpair : CH :&: CK = 'Z(CH). Proof. apply/eqP; rewrite eqEsubset setIS //=. rewrite subsetI center_sub -injm_center //. rewrite (eq_in_morphim _ eq_cpairZ); first by rewrite morphim_comp morphimS. by rewrite !(setIidPr _) // -sub_morphim_pre. Qed. Lemma cpair1g_center : cpair1g @* 'Z(K) = 'Z(C). Proof. case/cprodP: (center_cprod im_cpair_cprod) => _ <- _. by rewrite injm_center // -setI_im_cpair mulSGid //= setIC setIS 1?centsC. Qed. (* Uses gzZ. *) Lemma cpair_center_id : 'Z(CH) = 'Z(CK). Proof. rewrite -!injm_center // -gzZ -morphim_comp; apply: eq_in_morphim eq_cpairZ. by rewrite !(setIidPr _) // -sub_morphim_pre. Qed. (* Uses gzZ. *) Lemma cpairg1_center : cpairg1 @* 'Z(H) = 'Z(C). Proof. by rewrite -cpair1g_center !injm_center // cpair_center_id. Qed. Section ExtCprodm. Variable rT : finGroupType. Variables (fH : {morphism H >-> rT}) (fK : {morphism K >-> rT}). Hypothesis cfHK : fK @* K \subset 'C(fH @* H). Hypothesis eq_fHK : {in 'Z(H), fH =1 fK \o gz}. Let gH := ifactm fH injm_cpairg1. Let gK := ifactm fK injm_cpair1g. Lemma xcprodm_cent : gK @* CK \subset 'C(gH @* CH). Proof. by rewrite !im_ifactm. Qed. Lemma xcprodmI : {in CH :&: CK, gH =1 gK}. Proof. rewrite setI_im_cpair -injm_center // => fHx; case/morphimP=> x Gx Zx ->{fHx}. by rewrite {2}eq_cpairZ //= ?ifactmE ?eq_fHK //= (subsetP sgzZG) ?mem_morphim. Qed. Definition xcprodm := cprodm im_cpair_cprod xcprodm_cent xcprodmI. Canonical xcprod_morphism := [morphism of xcprodm]. Lemma xcprodmEl : {in H, forall x, xcprodm (cpairg1 x) = fH x}. Proof. by move=> x Hx; rewrite /xcprodm cprodmEl ?mem_morphim ?ifactmE. Qed. Lemma xcprodmEr : {in K, forall y, xcprodm (cpair1g y) = fK y}. Proof. by move=> y Ky; rewrite /xcprodm cprodmEr ?mem_morphim ?ifactmE. Qed. Lemma xcprodmE : {in H & K, forall x y, xcprodm (cpairg1 x * cpair1g y) = fH x * fK y}. Proof. by move=> x y Hx Ky; rewrite /xcprodm cprodmE ?mem_morphim ?ifactmE. Qed. Lemma im_xcprodm : xcprodm @* C = fH @* H * fK @* K. Proof. by rewrite -im_cpair morphim_cprodm // !im_ifactm. Qed. Lemma im_xcprodml A : xcprodm @* (cpairg1 @* A) = fH @* A. Proof. rewrite -!(morphimIdom _ A) morphim_cprodml ?morphimS ?subsetIl //. by rewrite morphim_ifactm ?subsetIl. Qed. Lemma im_xcprodmr A : xcprodm @* (cpair1g @* A) = fK @* A. Proof. rewrite -!(morphimIdom _ A) morphim_cprodmr ?morphimS ?subsetIl //. by rewrite morphim_ifactm ?subsetIl. Qed. Lemma injm_xcprodm : 'injm xcprodm = 'injm fH && 'injm fK. Proof. rewrite injm_cprodm !ker_ifactm !subG1 !morphim_injm_eq1 ?subsetIl // -!subG1. apply: andb_id2l => /= injfH; apply: andb_idr => _. rewrite !im_ifactm // -(morphimIdom gH) setI_im_cpair -injm_center //. rewrite morphim_ifactm // eqEsubset subsetI morphimS //=. rewrite {1}injm_center // setIS //=. rewrite (eq_in_morphim _ eq_fHK); first by rewrite morphim_comp morphimS. by rewrite !(setIidPr _) // -sub_morphim_pre. Qed. End ExtCprodm. (* Uses gzZchar. *) Lemma Aut_cprod_by_full : Aut_in (Aut H) 'Z(H) \isog Aut 'Z(H) -> Aut_in (Aut K) 'Z(K) \isog Aut 'Z(K) -> Aut_in (Aut C) 'Z(C) \isog Aut 'Z(C). Proof. move=> AutZinH AutZinK. have Cfull:= Aut_cprod_full im_cpair_cprod cpair_center_id. by rewrite Cfull // -injm_center // injm_Aut_full ?center_sub. Qed. Section Isomorphism. Let gzZ_lone (Y : {group gTK}) : Y \subset 'Z(K) -> gz @* 'Z(H) \isog Y -> gz @* 'Z(H) = Y. Proof. move=> sYZ isoY; apply/eqP. by rewrite eq_sym eqEcard (card_isog isoY) gzZ sYZ /=. Qed. Variables (rT : finGroupType) (GH GK G : {group rT}). Hypotheses (defG : GH \* GK = G) (ziGHK : GH :&: GK = 'Z(GH)). Hypothesis AutZHfull : Aut_in (Aut H) 'Z(H) \isog Aut 'Z(H). Hypotheses (isoGH : GH \isog H) (isoGK : GK \isog K). (* Uses gzZ_lone *) Lemma cprod_by_uniq : exists f : {morphism G >-> cprod_by}, [/\ isom G C f, f @* GH = CH & f @* GK = CK]. Proof. have [_ defGHK cGKH] := cprodP defG. have AutZinH := Aut_sub_fullP sZH AutZHfull. have [fH injfH defGH]:= isogP (isog_symr isoGH). have [fK injfK defGK]:= isogP (isog_symr isoGK). have sfHZfK: fH @* 'Z(H) \subset fK @* K. by rewrite injm_center //= defGH defGK -ziGHK subsetIr. have gzZ_id: gz @* 'Z(H) = invm injfK @* (fH @* 'Z(H)). apply: gzZ_lone => /=. rewrite injm_center // defGH -ziGHK sub_morphim_pre /= ?defGK ?subsetIr //. by rewrite setIC morphpre_invm injm_center // defGK setIS 1?centsC. rewrite -morphim_comp. apply: isog_trans (sub_isog _ _); first by rewrite isog_sym sub_isog. by rewrite -sub_morphim_pre. by rewrite !injm_comp ?injm_invm. have: 'dom (invm injfH \o fK \o gz) = 'Z(H). rewrite /dom /= -(morphpreIdom gz); apply/setIidPl. by rewrite -2?sub_morphim_pre // gzZ_id morphim_invmE morphpreK ?morphimS. case/domP=> gzH [def_gzH ker_gzH _ im_gzH]. have{ker_gzH} injgzH: 'injm gzH by rewrite ker_gzH !injm_comp ?injm_invm. have{AutZinH} [|gH [injgH gH_H def_gH]] := AutZinH _ injgzH. by rewrite im_gzH !morphim_comp /= gzZ_id !morphim_invmE morphpreK ?injmK. have: 'dom (fH \o gH) = H by rewrite /dom /= -{3}gH_H injmK. case/domP=> gfH [def_gfH ker_gfH _ im_gfH]. have{im_gfH} gfH_H: gfH @* H = GH by rewrite im_gfH morphim_comp gH_H. have cgfHfK: fK @* K \subset 'C(gfH @* H) by rewrite gfH_H defGK. have eq_gfHK: {in 'Z(H), gfH =1 fK \o gz}. move=> z Zz; rewrite def_gfH /= def_gH //= def_gzH /= invmK //. have {Zz}: gz z \in gz @* 'Z(H) by rewrite mem_morphim. rewrite gzZ_id morphim_invmE; case/morphpreP=> _. exact: (subsetP (morphimS _ _)). pose f := xcprodm cgfHfK eq_gfHK. have injf: 'injm f by rewrite injm_xcprodm ker_gfH injm_comp. have fCH: f @* CH = GH by rewrite im_xcprodml gfH_H. have fCK: f @* CK = GK by rewrite im_xcprodmr defGK. have fC: f @* C = G by rewrite im_xcprodm gfH_H defGK defGHK. have [f' [_ ker_f' _ im_f']] := domP (invm_morphism injf) fC. exists f'; rewrite -fCH -fCK !{1}im_f' !{1}morphim_invm ?subsetT //. by split=> //; apply/isomP; rewrite ker_f' injm_invm im_f' -fC im_invm. Qed. Lemma isog_cprod_by : G \isog C. Proof. by have [f [isoG _ _]] := cprod_by_uniq; exact: isom_isog isoG. Qed. End Isomorphism. End CprodBy. Section ExtCprod. Import finfun. Variables gTH gTK : finGroupType. Variables (H : {group gTH}) (K : {group gTK}). Let gt_ b := if b then gTK else gTH. Local Notation isob := ('Z(H) \isog 'Z(K)) (only parsing). Let G_ b := if b as b' return {group gt_ b'} then K else H. Lemma xcprod_subproof : {gz : {morphism 'Z(H) >-> gt_ isob} | isom 'Z(H) 'Z(G_ isob) gz}. Proof. case: (pickP [pred f : {ffun _} | misom 'Z(H) 'Z(K) f]) => [f isoZ | no_f]. rewrite (misom_isog isoZ); case/andP: isoZ => fM isoZ. by exists [morphism of morphm fM]. move/pred0P: no_f => not_isoZ; rewrite [isob](congr1 negb not_isoZ). by exists (idm_morphism _); apply/isomP; rewrite injm_idm im_idm. Qed. Definition xcprod := cprod_by (svalP xcprod_subproof). Inductive xcprod_spec : finGroupType -> Prop := XcprodSpec gz isoZ : xcprod_spec (@cprod_by gTH gTK H K gz isoZ). Lemma xcprodP : 'Z(H) \isog 'Z(K) -> xcprod_spec xcprod. Proof. by rewrite /xcprod => isoZ; move: xcprod_subproof; rewrite isoZ. Qed. Lemma isog_xcprod (rT : finGroupType) (GH GK G : {group rT}) : Aut_in (Aut H) 'Z(H) \isog Aut 'Z(H) -> GH \isog H -> GK \isog K -> GH \* GK = G -> 'Z(GH) = 'Z(GK) -> G \isog [set: xcprod]. Proof. move=> AutZinH isoGH isoGK defG eqZGHK; have [_ _ cGHK] := cprodP defG. have [|gz isoZ] := xcprodP. have [[fH injfH <-] [fK injfK <-]] := (isogP isoGH, isogP isoGK). rewrite -!injm_center -?(isog_transl _ (sub_isog _ _)) ?center_sub //=. by rewrite eqZGHK sub_isog ?center_sub. rewrite (isog_cprod_by _ defG) //. by apply/eqP; rewrite eqEsubset setIS // subsetI {2}eqZGHK !center_sub. Qed. End ExtCprod. Section IterCprod. Variables (gT : finGroupType) (G : {group gT}). Fixpoint ncprod_def n : finGroupType := if n is n'.+1 then xcprod G [set: ncprod_def n'] else [finGroupType of subg_of 'Z(G)]. Fact ncprod_key : unit. Proof. by []. Qed. Definition ncprod := locked_with ncprod_key ncprod_def. Local Notation G_ n := [set: gsort (ncprod n)]. Lemma ncprod0 : G_ 0 \isog 'Z(G). Proof. by rewrite [ncprod]unlock isog_sym isog_subg. Qed. Lemma center_ncprod0 : 'Z(G_ 0) = G_ 0. Proof. by apply: center_idP; rewrite (isog_abelian ncprod0) center_abelian. Qed. Lemma center_ncprod n : 'Z(G_ n) \isog 'Z(G). Proof. elim: n => [|n]; first by rewrite center_ncprod0 ncprod0. rewrite [ncprod]unlock=> /isog_symr/xcprodP[gz isoZ] /=. by rewrite -cpairg1_center isog_sym sub_isog ?center_sub ?injm_cpairg1. Qed. Lemma ncprodS n : xcprod_spec G [set: ncprod n] (ncprod n.+1). Proof. by have:= xcprodP (isog_symr (center_ncprod n)); rewrite [ncprod]unlock. Qed. Lemma ncprod1 : G_ 1 \isog G. Proof. case: ncprodS => gz isoZ; rewrite isog_sym /= -im_cpair. rewrite mulGSid /=; first by rewrite sub_isog ?injm_cpairg1. rewrite -{3}center_ncprod0 injm_center ?injm_cpair1g //. by rewrite -cpair_center_id center_sub. Qed. Lemma Aut_ncprod_full n : Aut_in (Aut G) 'Z(G) \isog Aut 'Z(G) -> Aut_in (Aut (G_ n)) 'Z(G_ n) \isog Aut 'Z(G_ n). Proof. move=> AutZinG; elim: n => [|n IHn]. by rewrite center_ncprod0; apply/Aut_sub_fullP=> // g injg gG0; exists g. by case: ncprodS => gz isoZ; exact: Aut_cprod_by_full. Qed. End IterCprod. mathcomp-1.5/theories/div.v0000644000175000017500000010332312307636117014756 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq. (******************************************************************************) (* This file deals with divisibility for natural numbers. *) (* It contains the definitions of: *) (* edivn m d == the pair composed of the quotient and remainder *) (* of the Euclidean division of m by d. *) (* m %/ d == quotient of m by d. *) (* m %% d == remainder of m by d. *) (* m = n %[mod d] <-> m equals n modulo d. *) (* m == n %[mod d] <=> m equals n modulo d (boolean version). *) (* m <> n %[mod d] <-> m differs from n modulo d. *) (* m != n %[mod d] <=> m differs from n modulo d (boolean version). *) (* d %| m <=> d divides m. *) (* gcdn m n == the GCD of m and n. *) (* egcdn m n == the extended GCD of m and n. *) (* lcmn m n == the LCM of m and n. *) (* coprime m n <=> m and n are coprime (:= gcdn m n == 1). *) (* chinese m n r s == witness of the chinese remainder theorem. *) (* We adjoin an m to operator suffixes to indicate a nested %% (modn), as in *) (* modnDml : m %% d + n = m + n %[mod d]. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. (** Euclidean division *) Definition edivn_rec d := fix loop m q := if m - d is m'.+1 then loop m' q.+1 else (q, m). Definition edivn m d := if d > 0 then edivn_rec d.-1 m 0 else (0, m). CoInductive edivn_spec m d : nat * nat -> Type := EdivnSpec q r of m = q * d + r & (d > 0) ==> (r < d) : edivn_spec m d (q, r). Lemma edivnP m d : edivn_spec m d (edivn m d). Proof. rewrite -{1}[m]/(0 * d + m) /edivn; case: d => //= d. elim: m {-2}m 0 (leqnn m) => [|n IHn] [|m] q //= le_mn. have le_m'n: m - d <= n by rewrite (leq_trans (leq_subr d m)). rewrite subn_if_gt; case: ltnP => [// | le_dm]. by rewrite -{1}(subnKC le_dm) -addSn addnA -mulSnr; exact: IHn. Qed. Lemma edivn_eq d q r : r < d -> edivn (q * d + r) d = (q, r). Proof. move=> lt_rd; have d_gt0: 0 < d by exact: leq_trans lt_rd. case: edivnP lt_rd => q' r'; rewrite d_gt0 /=. wlog: q q' r r' / q <= q' by case/orP: (leq_total q q'); last symmetry; eauto. rewrite leq_eqVlt; case/predU1P => [-> /addnI-> |] //=. rewrite -(leq_pmul2r d_gt0) => /leq_add lt_qr eq_qr _ /lt_qr {lt_qr}. by rewrite addnS ltnNge mulSn -addnA eq_qr addnCA addnA leq_addr. Qed. Definition divn m d := (edivn m d).1. Notation "m %/ d" := (divn m d) : nat_scope. (* We redefine modn so that it is structurally decreasing. *) Definition modn_rec d := fix loop m := if m - d is m'.+1 then loop m' else m. Definition modn m d := if d > 0 then modn_rec d.-1 m else m. Notation "m %% d" := (modn m d) : nat_scope. Notation "m = n %[mod d ]" := (m %% d = n %% d) : nat_scope. Notation "m == n %[mod d ]" := (m %% d == n %% d) : nat_scope. Notation "m <> n %[mod d ]" := (m %% d <> n %% d) : nat_scope. Notation "m != n %[mod d ]" := (m %% d != n %% d) : nat_scope. Lemma modn_def m d : m %% d = (edivn m d).2. Proof. case: d => //= d; rewrite /modn /edivn /=. elim: m {-2}m 0 (leqnn m) => [|n IHn] [|m] q //=. rewrite ltnS !subn_if_gt; case: (d <= m) => // le_mn. by apply: IHn; apply: leq_trans le_mn; exact: leq_subr. Qed. Lemma edivn_def m d : edivn m d = (m %/ d, m %% d). Proof. by rewrite /divn modn_def; case: (edivn m d). Qed. Lemma divn_eq m d : m = m %/ d * d + m %% d. Proof. by rewrite /divn modn_def; case: edivnP. Qed. Lemma div0n d : 0 %/ d = 0. Proof. by case: d. Qed. Lemma divn0 m : m %/ 0 = 0. Proof. by []. Qed. Lemma mod0n d : 0 %% d = 0. Proof. by case: d. Qed. Lemma modn0 m : m %% 0 = m. Proof. by []. Qed. Lemma divn_small m d : m < d -> m %/ d = 0. Proof. by move=> lt_md; rewrite /divn (edivn_eq 0). Qed. Lemma divnMDl q m d : 0 < d -> (q * d + m) %/ d = q + m %/ d. Proof. move=> d_gt0; rewrite {1}(divn_eq m d) addnA -mulnDl. by rewrite /divn edivn_eq // modn_def; case: edivnP; rewrite d_gt0. Qed. Lemma mulnK m d : 0 < d -> m * d %/ d = m. Proof. by move=> d_gt0; rewrite -[m * d]addn0 divnMDl // div0n addn0. Qed. Lemma mulKn m d : 0 < d -> d * m %/ d = m. Proof. by move=> d_gt0; rewrite mulnC mulnK. Qed. Lemma expnB p m n : p > 0 -> m >= n -> p ^ (m - n) = p ^ m %/ p ^ n. Proof. by move=> p_gt0 /subnK{2}<-; rewrite expnD mulnK // expn_gt0 p_gt0. Qed. Lemma modn1 m : m %% 1 = 0. Proof. by rewrite modn_def; case: edivnP => ? []. Qed. Lemma divn1 m : m %/ 1 = m. Proof. by rewrite {2}(@divn_eq m 1) // modn1 addn0 muln1. Qed. Lemma divnn d : d %/ d = (0 < d). Proof. by case: d => // d; rewrite -{1}[d.+1]muln1 mulKn. Qed. Lemma divnMl p m d : p > 0 -> p * m %/ (p * d) = m %/ d. Proof. move=> p_gt0; case: (posnP d) => [-> | d_gt0]; first by rewrite muln0. rewrite {2}/divn; case: edivnP; rewrite d_gt0 /= => q r ->{m} lt_rd. rewrite mulnDr mulnCA divnMDl; last by rewrite muln_gt0 p_gt0. by rewrite addnC divn_small // ltn_pmul2l. Qed. Implicit Arguments divnMl [p m d]. Lemma divnMr p m d : p > 0 -> m * p %/ (d * p) = m %/ d. Proof. by move=> p_gt0; rewrite -!(mulnC p) divnMl. Qed. Implicit Arguments divnMr [p m d]. Lemma ltn_mod m d : (m %% d < d) = (0 < d). Proof. by case: d => // d; rewrite modn_def; case: edivnP. Qed. Lemma ltn_pmod m d : 0 < d -> m %% d < d. Proof. by rewrite ltn_mod. Qed. Lemma leq_trunc_div m d : m %/ d * d <= m. Proof. by rewrite {2}(divn_eq m d) leq_addr. Qed. Lemma leq_mod m d : m %% d <= m. Proof. by rewrite {2}(divn_eq m d) leq_addl. Qed. Lemma leq_div m d : m %/ d <= m. Proof. by case: d => // d; apply: leq_trans (leq_pmulr _ _) (leq_trunc_div _ _). Qed. Lemma ltn_ceil m d : 0 < d -> m < (m %/ d).+1 * d. Proof. by move=> d_gt0; rewrite {1}(divn_eq m d) -addnS mulSnr leq_add2l ltn_mod. Qed. Lemma ltn_divLR m n d : d > 0 -> (m %/ d < n) = (m < n * d). Proof. move=> d_gt0; apply/idP/idP. by rewrite -(leq_pmul2r d_gt0); apply: leq_trans (ltn_ceil _ _). rewrite !ltnNge -(@leq_pmul2r d n) //; apply: contra => le_nd_floor. exact: leq_trans le_nd_floor (leq_trunc_div _ _). Qed. Lemma leq_divRL m n d : d > 0 -> (m <= n %/ d) = (m * d <= n). Proof. by move=> d_gt0; rewrite leqNgt ltn_divLR // -leqNgt. Qed. Lemma ltn_Pdiv m d : 1 < d -> 0 < m -> m %/ d < m. Proof. by move=> d_gt1 m_gt0; rewrite ltn_divLR ?ltn_Pmulr // ltnW. Qed. Lemma divn_gt0 d m : 0 < d -> (0 < m %/ d) = (d <= m). Proof. by move=> d_gt0; rewrite leq_divRL ?mul1n. Qed. Lemma leq_div2r d m n : m <= n -> m %/ d <= n %/ d. Proof. have [-> //| d_gt0 le_mn] := posnP d. by rewrite leq_divRL // (leq_trans _ le_mn) -?leq_divRL. Qed. Lemma leq_div2l m d e : 0 < d -> d <= e -> m %/ e <= m %/ d. Proof. move/leq_divRL=> -> le_de. by apply: leq_trans (leq_trunc_div m e); apply: leq_mul. Qed. Lemma leq_divDl p m n : (m + n) %/ p <= m %/ p + n %/ p + 1. Proof. have [-> //| p_gt0] := posnP p; rewrite -ltnS -addnS ltn_divLR // ltnW //. rewrite {1}(divn_eq n p) {1}(divn_eq m p) addnACA !mulnDl -3!addnS leq_add2l. by rewrite mul2n -addnn -addSn leq_add // ltn_mod. Qed. Lemma geq_divBl k m p : k %/ p - m %/ p <= (k - m) %/ p + 1. Proof. rewrite leq_subLR addnA; apply: leq_trans (leq_divDl _ _ _). by rewrite -maxnE leq_div2r ?leq_maxr. Qed. Lemma divnMA m n p : m %/ (n * p) = m %/ n %/ p. Proof. case: n p => [|n] [|p]; rewrite ?muln0 ?div0n //. rewrite {2}(divn_eq m (n.+1 * p.+1)) mulnA mulnAC !divnMDl //. by rewrite [_ %/ p.+1]divn_small ?addn0 // ltn_divLR // mulnC ltn_mod. Qed. Lemma divnAC m n p : m %/ n %/ p = m %/ p %/ n. Proof. by rewrite -!divnMA mulnC. Qed. Lemma modn_small m d : m < d -> m %% d = m. Proof. by move=> lt_md; rewrite {2}(divn_eq m d) divn_small. Qed. Lemma modn_mod m d : m %% d = m %[mod d]. Proof. by case: d => // d; apply: modn_small; rewrite ltn_mod. Qed. Lemma modnMDl p m d : p * d + m = m %[mod d]. Proof. case: (posnP d) => [-> | d_gt0]; first by rewrite muln0. by rewrite {1}(divn_eq m d) addnA -mulnDl modn_def edivn_eq // ltn_mod. Qed. Lemma muln_modr {p m d} : 0 < p -> p * (m %% d) = (p * m) %% (p * d). Proof. move=> p_gt0; apply: (@addnI (p * (m %/ d * d))). by rewrite -mulnDr -divn_eq mulnCA -(divnMl p_gt0) -divn_eq. Qed. Lemma muln_modl {p m d} : 0 < p -> (m %% d) * p = (m * p) %% (d * p). Proof. by rewrite -!(mulnC p); apply: muln_modr. Qed. Lemma modnDl m d : d + m = m %[mod d]. Proof. by rewrite -{1}[d]mul1n modnMDl. Qed. Lemma modnDr m d : m + d = m %[mod d]. Proof. by rewrite addnC modnDl. Qed. Lemma modnn d : d %% d = 0. Proof. by rewrite -{1}[d]addn0 modnDl mod0n. Qed. Lemma modnMl p d : p * d %% d = 0. Proof. by rewrite -[p * d]addn0 modnMDl mod0n. Qed. Lemma modnMr p d : d * p %% d = 0. Proof. by rewrite mulnC modnMl. Qed. Lemma modnDml m n d : m %% d + n = m + n %[mod d]. Proof. by rewrite {2}(divn_eq m d) -addnA modnMDl. Qed. Lemma modnDmr m n d : m + n %% d = m + n %[mod d]. Proof. by rewrite !(addnC m) modnDml. Qed. Lemma modnDm m n d : m %% d + n %% d = m + n %[mod d]. Proof. by rewrite modnDml modnDmr. Qed. Lemma eqn_modDl p m n d : (p + m == p + n %[mod d]) = (m == n %[mod d]). Proof. case: d => [|d]; first by rewrite !modn0 eqn_add2l. apply/eqP/eqP=> eq_mn; last by rewrite -modnDmr eq_mn modnDmr. rewrite -(modnMDl p m) -(modnMDl p n) !mulnSr -!addnA. by rewrite -modnDmr eq_mn modnDmr. Qed. Lemma eqn_modDr p m n d : (m + p == n + p %[mod d]) = (m == n %[mod d]). Proof. by rewrite -!(addnC p) eqn_modDl. Qed. Lemma modnMml m n d : m %% d * n = m * n %[mod d]. Proof. by rewrite {2}(divn_eq m d) mulnDl mulnAC modnMDl. Qed. Lemma modnMmr m n d : m * (n %% d) = m * n %[mod d]. Proof. by rewrite !(mulnC m) modnMml. Qed. Lemma modnMm m n d : m %% d * (n %% d) = m * n %[mod d]. Proof. by rewrite modnMml modnMmr. Qed. Lemma modn2 m : m %% 2 = odd m. Proof. by elim: m => //= m IHm; rewrite -addn1 -modnDml IHm; case odd. Qed. Lemma divn2 m : m %/ 2 = m./2. Proof. by rewrite {2}(divn_eq m 2) modn2 muln2 addnC half_bit_double. Qed. Lemma odd_mod m d : odd d = false -> odd (m %% d) = odd m. Proof. by move=> d_even; rewrite {2}(divn_eq m d) odd_add odd_mul d_even andbF. Qed. Lemma modnXm m n a : (a %% n) ^ m = a ^ m %[mod n]. Proof. by elim: m => // m IHm; rewrite !expnS -modnMmr IHm modnMml modnMmr. Qed. (** Divisibility **) Definition dvdn d m := m %% d == 0. Notation "m %| d" := (dvdn m d) : nat_scope. Lemma dvdnP d m : reflect (exists k, m = k * d) (d %| m). Proof. apply: (iffP eqP) => [md0 | [k ->]]; last by rewrite modnMl. by exists (m %/ d); rewrite {1}(divn_eq m d) md0 addn0. Qed. Implicit Arguments dvdnP [d m]. Prenex Implicits dvdnP. Lemma dvdn0 d : d %| 0. Proof. by case: d. Qed. Lemma dvd0n n : (0 %| n) = (n == 0). Proof. by case: n. Qed. Lemma dvdn1 d : (d %| 1) = (d == 1). Proof. by case: d => [|[|d]] //; rewrite /dvdn modn_small. Qed. Lemma dvd1n m : 1 %| m. Proof. by rewrite /dvdn modn1. Qed. Lemma dvdn_gt0 d m : m > 0 -> d %| m -> d > 0. Proof. by case: d => // /prednK <-. Qed. Lemma dvdnn m : m %| m. Proof. by rewrite /dvdn modnn. Qed. Lemma dvdn_mull d m n : d %| n -> d %| m * n. Proof. by case/dvdnP=> n' ->; rewrite /dvdn mulnA modnMl. Qed. Lemma dvdn_mulr d m n : d %| m -> d %| m * n. Proof. by move=> d_m; rewrite mulnC dvdn_mull. Qed. Hint Resolve dvdn0 dvd1n dvdnn dvdn_mull dvdn_mulr. Lemma dvdn_mul d1 d2 m1 m2 : d1 %| m1 -> d2 %| m2 -> d1 * d2 %| m1 * m2. Proof. by move=> /dvdnP[q1 ->] /dvdnP[q2 ->]; rewrite mulnCA -mulnA 2?dvdn_mull. Qed. Lemma dvdn_trans n d m : d %| n -> n %| m -> d %| m. Proof. by move=> d_dv_n /dvdnP[n1 ->]; exact: dvdn_mull. Qed. Lemma dvdn_eq d m : (d %| m) = (m %/ d * d == m). Proof. apply/eqP/eqP=> [modm0 | <-]; last exact: modnMl. by rewrite {2}(divn_eq m d) modm0 addn0. Qed. Lemma dvdn2 n : (2 %| n) = ~~ odd n. Proof. by rewrite /dvdn modn2; case (odd n). Qed. Lemma dvdn_odd m n : m %| n -> odd n -> odd m. Proof. by move=> m_dv_n; apply: contraTT; rewrite -!dvdn2 => /dvdn_trans->. Qed. Lemma divnK d m : d %| m -> m %/ d * d = m. Proof. by rewrite dvdn_eq; move/eqP. Qed. Lemma leq_divLR d m n : d %| m -> (m %/ d <= n) = (m <= n * d). Proof. by case: d m => [|d] [|m] ///divnK=> {2}<-; rewrite leq_pmul2r. Qed. Lemma ltn_divRL d m n : d %| m -> (n < m %/ d) = (n * d < m). Proof. by move=> dv_d_m; rewrite !ltnNge leq_divLR. Qed. Lemma eqn_div d m n : d > 0 -> d %| m -> (n == m %/ d) = (n * d == m). Proof. by move=> d_gt0 dv_d_m; rewrite -(eqn_pmul2r d_gt0) divnK. Qed. Lemma eqn_mul d m n : d > 0 -> d %| m -> (m == n * d) = (m %/ d == n). Proof. by move=> d_gt0 dv_d_m; rewrite eq_sym -eqn_div // eq_sym. Qed. Lemma divn_mulAC d m n : d %| m -> m %/ d * n = m * n %/ d. Proof. case: d m => [[] //| d m] dv_d_m; apply/eqP. by rewrite eqn_div ?dvdn_mulr // mulnAC divnK. Qed. Lemma muln_divA d m n : d %| n -> m * (n %/ d) = m * n %/ d. Proof. by move=> dv_d_m; rewrite !(mulnC m) divn_mulAC. Qed. Lemma muln_divCA d m n : d %| m -> d %| n -> m * (n %/ d) = n * (m %/ d). Proof. by move=> dv_d_m dv_d_n; rewrite mulnC divn_mulAC ?muln_divA. Qed. Lemma divnA m n p : p %| n -> m %/ (n %/ p) = m * p %/ n. Proof. by case: p => [|p] dv_n; rewrite -{2}(divnK dv_n) // divnMr. Qed. Lemma modn_dvdm m n d : d %| m -> n %% m = n %[mod d]. Proof. by case/dvdnP=> q def_m; rewrite {2}(divn_eq n m) {3}def_m mulnA modnMDl. Qed. Lemma dvdn_leq d m : 0 < m -> d %| m -> d <= m. Proof. by move=> m_gt0 /dvdnP[[|k] Dm]; rewrite Dm // leq_addr in m_gt0 *. Qed. Lemma gtnNdvd n d : 0 < n -> n < d -> (d %| n) = false. Proof. by move=> n_gt0 lt_nd; rewrite /dvdn eqn0Ngt modn_small ?n_gt0. Qed. Lemma eqn_dvd m n : (m == n) = (m %| n) && (n %| m). Proof. case: m n => [|m] [|n] //; apply/idP/andP; first by move/eqP->; auto. rewrite eqn_leq => [[Hmn Hnm]]; apply/andP; have:= dvdn_leq; auto. Qed. Lemma dvdn_pmul2l p d m : 0 < p -> (p * d %| p * m) = (d %| m). Proof. by case: p => // p _; rewrite /dvdn -muln_modr // muln_eq0. Qed. Implicit Arguments dvdn_pmul2l [p m d]. Lemma dvdn_pmul2r p d m : 0 < p -> (d * p %| m * p) = (d %| m). Proof. by move=> p_gt0; rewrite -!(mulnC p) dvdn_pmul2l. Qed. Implicit Arguments dvdn_pmul2r [p m d]. Lemma dvdn_divLR p d m : 0 < p -> p %| d -> (d %/ p %| m) = (d %| m * p). Proof. by move=> /(@dvdn_pmul2r p _ m) <- /divnK->. Qed. Lemma dvdn_divRL p d m : p %| m -> (d %| m %/ p) = (d * p %| m). Proof. have [-> | /(@dvdn_pmul2r p d) <- /divnK-> //] := posnP p. by rewrite divn0 muln0 dvdn0. Qed. Lemma dvdn_div d m : d %| m -> m %/ d %| m. Proof. by move/divnK=> {2}<-; apply: dvdn_mulr. Qed. Lemma dvdn_exp2l p m n : m <= n -> p ^ m %| p ^ n. Proof. by move/subnK <-; rewrite expnD dvdn_mull. Qed. Lemma dvdn_Pexp2l p m n : p > 1 -> (p ^ m %| p ^ n) = (m <= n). Proof. move=> p_gt1; case: leqP => [|gt_n_m]; first exact: dvdn_exp2l. by rewrite gtnNdvd ?ltn_exp2l ?expn_gt0 // ltnW. Qed. Lemma dvdn_exp2r m n k : m %| n -> m ^ k %| n ^ k. Proof. by case/dvdnP=> q ->; rewrite expnMn dvdn_mull. Qed. Lemma dvdn_addr m d n : d %| m -> (d %| m + n) = (d %| n). Proof. by case/dvdnP=> q ->; rewrite /dvdn modnMDl. Qed. Lemma dvdn_addl n d m : d %| n -> (d %| m + n) = (d %| m). Proof. by rewrite addnC; exact: dvdn_addr. Qed. Lemma dvdn_add d m n : d %| m -> d %| n -> d %| m + n. Proof. by move/dvdn_addr->. Qed. Lemma dvdn_add_eq d m n : d %| m + n -> (d %| m) = (d %| n). Proof. by move=> dv_d_mn; apply/idP/idP => [/dvdn_addr | /dvdn_addl] <-. Qed. Lemma dvdn_subr d m n : n <= m -> d %| m -> (d %| m - n) = (d %| n). Proof. by move=> le_n_m dv_d_m; apply: dvdn_add_eq; rewrite subnK. Qed. Lemma dvdn_subl d m n : n <= m -> d %| n -> (d %| m - n) = (d %| m). Proof. by move=> le_n_m dv_d_m; rewrite -(dvdn_addl _ dv_d_m) subnK. Qed. Lemma dvdn_sub d m n : d %| m -> d %| n -> d %| m - n. Proof. by case: (leqP n m) => [le_nm /dvdn_subr <- // | /ltnW/eqnP ->]; rewrite dvdn0. Qed. Lemma dvdn_exp k d m : 0 < k -> d %| m -> d %| (m ^ k). Proof. by case: k => // k _ d_dv_m; rewrite expnS dvdn_mulr. Qed. Hint Resolve dvdn_add dvdn_sub dvdn_exp. Lemma eqn_mod_dvd d m n : n <= m -> (m == n %[mod d]) = (d %| m - n). Proof. by move=> le_mn; rewrite -{1}[n]add0n -{1}(subnK le_mn) eqn_modDr mod0n. Qed. Lemma divnDl m n d : d %| m -> (m + n) %/ d = m %/ d + n %/ d. Proof. by case: d => // d /divnK{1}<-; rewrite divnMDl. Qed. Lemma divnDr m n d : d %| n -> (m + n) %/ d = m %/ d + n %/ d. Proof. by move=> dv_n; rewrite addnC divnDl // addnC. Qed. (***********************************************************************) (* A function that computes the gcd of 2 numbers *) (***********************************************************************) Fixpoint gcdn_rec m n := let n' := n %% m in if n' is 0 then m else if m - n'.-1 is m'.+1 then gcdn_rec (m' %% n') n' else n'. Definition gcdn := nosimpl gcdn_rec. Lemma gcdnE m n : gcdn m n = if m == 0 then n else gcdn (n %% m) m. Proof. rewrite /gcdn; elim: m {-2}m (leqnn m) n => [|s IHs] [|m] le_ms [|n] //=. case def_n': (_ %% _) => // [n']. have{def_n'} lt_n'm: n' < m by rewrite -def_n' -ltnS ltn_pmod. rewrite {}IHs ?(leq_trans lt_n'm) // subn_if_gt ltnW //=; congr gcdn_rec. by rewrite -{2}(subnK (ltnW lt_n'm)) -addnS modnDr. Qed. Lemma gcdnn : idempotent gcdn. Proof. by case=> // n; rewrite gcdnE modnn. Qed. Lemma gcdnC : commutative gcdn. Proof. move=> m n; wlog lt_nm: m n / n < m. by case: (ltngtP n m) => [||-> //]; last symmetry; auto. by rewrite gcdnE -{1}(ltn_predK lt_nm) modn_small. Qed. Lemma gcd0n : left_id 0 gcdn. Proof. by case. Qed. Lemma gcdn0 : right_id 0 gcdn. Proof. by case. Qed. Lemma gcd1n : left_zero 1 gcdn. Proof. by move=> n; rewrite gcdnE modn1. Qed. Lemma gcdn1 : right_zero 1 gcdn. Proof. by move=> n; rewrite gcdnC gcd1n. Qed. Lemma dvdn_gcdr m n : gcdn m n %| n. Proof. elim: m {-2}m (leqnn m) n => [|s IHs] [|m] le_ms [|n] //. rewrite gcdnE; case def_n': (_ %% _) => [|n']; first by rewrite /dvdn def_n'. have lt_n's: n' < s by rewrite -ltnS (leq_trans _ le_ms) // -def_n' ltn_pmod. rewrite /= (divn_eq n.+1 m.+1) def_n' dvdn_addr ?dvdn_mull //; last exact: IHs. by rewrite gcdnE /= IHs // (leq_trans _ lt_n's) // ltnW // ltn_pmod. Qed. Lemma dvdn_gcdl m n : gcdn m n %| m. Proof. by rewrite gcdnC dvdn_gcdr. Qed. Lemma gcdn_gt0 m n : (0 < gcdn m n) = (0 < m) || (0 < n). Proof. by case: m n => [|m] [|n] //; apply: (@dvdn_gt0 _ m.+1) => //; exact: dvdn_gcdl. Qed. Lemma gcdnMDl k m n : gcdn m (k * m + n) = gcdn m n. Proof. by rewrite !(gcdnE m) modnMDl mulnC; case: m. Qed. Lemma gcdnDl m n : gcdn m (m + n) = gcdn m n. Proof. by rewrite -{2}(mul1n m) gcdnMDl. Qed. Lemma gcdnDr m n : gcdn m (n + m) = gcdn m n. Proof. by rewrite addnC gcdnDl. Qed. Lemma gcdnMl n m : gcdn n (m * n) = n. Proof. by case: n => [|n]; rewrite gcdnE modnMl gcd0n. Qed. Lemma gcdnMr n m : gcdn n (n * m) = n. Proof. by rewrite mulnC gcdnMl. Qed. Lemma gcdn_idPl {m n} : reflect (gcdn m n = m) (m %| n). Proof. by apply: (iffP idP) => [/dvdnP[q ->] | <-]; rewrite (gcdnMl, dvdn_gcdr). Qed. Lemma gcdn_idPr {m n} : reflect (gcdn m n = n) (n %| m). Proof. by rewrite gcdnC; apply: gcdn_idPl. Qed. Lemma expn_min e m n : e ^ minn m n = gcdn (e ^ m) (e ^ n). Proof. rewrite /minn; case: leqP; [rewrite gcdnC | move/ltnW]; by move/(dvdn_exp2l e)/gcdn_idPl. Qed. Lemma gcdn_modr m n : gcdn m (n %% m) = gcdn m n. Proof. by rewrite {2}(divn_eq n m) gcdnMDl. Qed. Lemma gcdn_modl m n : gcdn (m %% n) n = gcdn m n. Proof. by rewrite !(gcdnC _ n) gcdn_modr. Qed. (* Extended gcd, which computes Bezout coefficients. *) Fixpoint Bezout_rec km kn qs := if qs is q :: qs' then Bezout_rec kn (NatTrec.add_mul q kn km) qs' else (km, kn). Fixpoint egcdn_rec m n s qs := if s is s'.+1 then let: (q, r) := edivn m n in if r > 0 then egcdn_rec n r s' (q :: qs) else if odd (size qs) then qs else q.-1 :: qs else [::0]. Definition egcdn m n := Bezout_rec 0 1 (egcdn_rec m n n [::]). CoInductive egcdn_spec m n : nat * nat -> Type := EgcdnSpec km kn of km * m = kn * n + gcdn m n & kn * gcdn m n < m : egcdn_spec m n (km, kn). Lemma egcd0n n : egcdn 0 n = (1, 0). Proof. by case: n. Qed. Lemma egcdnP m n : m > 0 -> egcdn_spec m n (egcdn m n). Proof. rewrite /egcdn; have: (n, m) = Bezout_rec n m [::] by []. case: (posnP n) => [-> /=|]; first by split; rewrite // mul1n gcdn0. move: {2 6}n {4 6}n {1 4}m [::] (ltnSn n) => s n0 m0. elim: s n m => [[]//|s IHs] n m qs /= le_ns n_gt0 def_mn0 m_gt0. case: edivnP => q r def_m; rewrite n_gt0 /= => lt_rn. case: posnP => [r0 {s le_ns IHs lt_rn}|r_gt0]; last first. by apply: IHs => //=; [rewrite (leq_trans lt_rn) | rewrite natTrecE -def_m]. rewrite {r}r0 addn0 in def_m; set b := odd _; pose d := gcdn m n. pose km := ~~ b : nat; pose kn := if b then 1 else q.-1. rewrite (_ : Bezout_rec _ _ _ = Bezout_rec km kn qs); last first. by rewrite /kn /km; case: (b) => //=; rewrite natTrecE addn0 muln1. have def_d: d = n by rewrite /d def_m gcdnC gcdnE modnMl gcd0n -[n]prednK. have: km * m + 2 * b * d = kn * n + d. rewrite {}/kn {}/km def_m def_d -mulSnr; case: b; rewrite //= addn0 mul1n. by rewrite prednK //; apply: dvdn_gt0 m_gt0 _; rewrite def_m dvdn_mulr. have{def_m}: kn * d <= m. have q_gt0 : 0 < q by rewrite def_m muln_gt0 n_gt0 ?andbT in m_gt0. by rewrite /kn; case b; rewrite def_d def_m leq_pmul2r // leq_pred. have{def_d}: km * d <= n by rewrite -[n]mul1n def_d leq_pmul2r // leq_b1. move: km {q}kn m_gt0 n_gt0 def_mn0; rewrite {}/d {}/b. elim: qs m n => [|q qs IHq] n r kn kr n_gt0 r_gt0 /=. case=> -> -> {m0 n0}; rewrite !addn0 => le_kn_r _ def_d; split=> //. have d_gt0: 0 < gcdn n r by rewrite gcdn_gt0 n_gt0. have: 0 < kn * n by rewrite def_d addn_gt0 d_gt0 orbT. rewrite muln_gt0 n_gt0 andbT; move/ltn_pmul2l <-. by rewrite def_d -addn1 leq_add // mulnCA leq_mul2l le_kn_r orbT. rewrite !natTrecE; set m:= _ + r; set km := _ * _ + kn; pose d := gcdn m n. have ->: gcdn n r = d by rewrite [d]gcdnC gcdnMDl. have m_gt0: 0 < m by rewrite addn_gt0 r_gt0 orbT. have d_gt0: 0 < d by rewrite gcdn_gt0 m_gt0. move/IHq=> {IHq} IHq le_kn_r le_kr_n def_d; apply: IHq => //; rewrite -/d. by rewrite mulnDl leq_add // -mulnA leq_mul2l le_kr_n orbT. apply: (@addIn d); rewrite -!addnA addnn addnCA mulnDr -addnA addnCA. rewrite /km mulnDl mulnCA mulnA -addnA; congr (_ + _). by rewrite -def_d addnC -addnA -mulnDl -mulnDr addn_negb -mul2n. Qed. Lemma Bezoutl m n : m > 0 -> {a | a < m & m %| gcdn m n + a * n}. Proof. move=> m_gt0; case: (egcdnP n m_gt0) => km kn def_d lt_kn_m. exists kn; last by rewrite addnC -def_d dvdn_mull. apply: leq_ltn_trans lt_kn_m. by rewrite -{1}[kn]muln1 leq_mul2l gcdn_gt0 m_gt0 orbT. Qed. Lemma Bezoutr m n : n > 0 -> {a | a < n & n %| gcdn m n + a * m}. Proof. by rewrite gcdnC; exact: Bezoutl. Qed. (* Back to the gcd. *) Lemma dvdn_gcd p m n : p %| gcdn m n = (p %| m) && (p %| n). Proof. apply/idP/andP=> [dv_pmn | [dv_pm dv_pn]]. by rewrite !(dvdn_trans dv_pmn) ?dvdn_gcdl ?dvdn_gcdr. case (posnP n) => [->|n_gt0]; first by rewrite gcdn0. case: (Bezoutr m n_gt0) => // km _ /(dvdn_trans dv_pn). by rewrite dvdn_addl // dvdn_mull. Qed. Lemma gcdnAC : right_commutative gcdn. Proof. suffices dvd m n p: gcdn (gcdn m n) p %| gcdn (gcdn m p) n. by move=> m n p; apply/eqP; rewrite eqn_dvd !dvd. rewrite !dvdn_gcd dvdn_gcdr. by rewrite !(dvdn_trans (dvdn_gcdl _ p)) ?dvdn_gcdl ?dvdn_gcdr. Qed. Lemma gcdnA : associative gcdn. Proof. by move=> m n p; rewrite !(gcdnC m) gcdnAC. Qed. Lemma gcdnCA : left_commutative gcdn. Proof. by move=> m n p; rewrite !gcdnA (gcdnC m). Qed. Lemma gcdnACA : interchange gcdn gcdn. Proof. by move=> m n p q; rewrite -!gcdnA (gcdnCA n). Qed. Lemma muln_gcdr : right_distributive muln gcdn. Proof. move=> p m n; case: (posnP p) => [-> //| p_gt0]. elim: {m}m.+1 {-2}m n (ltnSn m) => // s IHs m n; rewrite ltnS => le_ms. rewrite gcdnE [rhs in _ = rhs]gcdnE muln_eq0 (gtn_eqF p_gt0) -muln_modr //=. by case: posnP => // m_gt0; apply: IHs; apply: leq_trans le_ms; apply: ltn_pmod. Qed. Lemma muln_gcdl : left_distributive muln gcdn. Proof. by move=> m n p; rewrite -!(mulnC p) muln_gcdr. Qed. Lemma gcdn_def d m n : d %| m -> d %| n -> (forall d', d' %| m -> d' %| n -> d' %| d) -> gcdn m n = d. Proof. move=> dv_dm dv_dn gdv_d; apply/eqP. by rewrite eqn_dvd dvdn_gcd dv_dm dv_dn gdv_d ?dvdn_gcdl ?dvdn_gcdr. Qed. Lemma muln_divCA_gcd n m : n * (m %/ gcdn n m) = m * (n %/ gcdn n m). Proof. by rewrite muln_divCA ?dvdn_gcdl ?dvdn_gcdr. Qed. (* We derive the lcm directly. *) Definition lcmn m n := m * n %/ gcdn m n. Lemma lcmnC : commutative lcmn. Proof. by move=> m n; rewrite /lcmn mulnC gcdnC. Qed. Lemma lcm0n : left_zero 0 lcmn. Proof. by move=> n; exact: div0n. Qed. Lemma lcmn0 : right_zero 0 lcmn. Proof. by move=> n; rewrite lcmnC lcm0n. Qed. Lemma lcm1n : left_id 1 lcmn. Proof. by move=> n; rewrite /lcmn gcd1n mul1n divn1. Qed. Lemma lcmn1 : right_id 1 lcmn. Proof. by move=> n; rewrite lcmnC lcm1n. Qed. Lemma muln_lcm_gcd m n : lcmn m n * gcdn m n = m * n. Proof. by apply/eqP; rewrite divnK ?dvdn_mull ?dvdn_gcdr. Qed. Lemma lcmn_gt0 m n : (0 < lcmn m n) = (0 < m) && (0 < n). Proof. by rewrite -muln_gt0 ltn_divRL ?dvdn_mull ?dvdn_gcdr. Qed. Lemma muln_lcmr : right_distributive muln lcmn. Proof. case=> // m n p; rewrite /lcmn -muln_gcdr -!mulnA divnMl // mulnCA. by rewrite muln_divA ?dvdn_mull ?dvdn_gcdr. Qed. Lemma muln_lcml : left_distributive muln lcmn. Proof. by move=> m n p; rewrite -!(mulnC p) muln_lcmr. Qed. Lemma lcmnA : associative lcmn. Proof. move=> m n p; rewrite {1 3}/lcmn mulnC !divn_mulAC ?dvdn_mull ?dvdn_gcdr //. rewrite -!divnMA ?dvdn_mulr ?dvdn_gcdl // mulnC mulnA !muln_gcdr. by rewrite ![_ * lcmn _ _]mulnC !muln_lcm_gcd !muln_gcdl -!(mulnC m) gcdnA. Qed. Lemma lcmnCA : left_commutative lcmn. Proof. by move=> m n p; rewrite !lcmnA (lcmnC m). Qed. Lemma lcmnAC : right_commutative lcmn. Proof. by move=> m n p; rewrite -!lcmnA (lcmnC n). Qed. Lemma lcmnACA : interchange lcmn lcmn. Proof. by move=> m n p q; rewrite -!lcmnA (lcmnCA n). Qed. Lemma dvdn_lcml d1 d2 : d1 %| lcmn d1 d2. Proof. by rewrite /lcmn -muln_divA ?dvdn_gcdr ?dvdn_mulr. Qed. Lemma dvdn_lcmr d1 d2 : d2 %| lcmn d1 d2. Proof. by rewrite lcmnC dvdn_lcml. Qed. Lemma dvdn_lcm d1 d2 m : lcmn d1 d2 %| m = (d1 %| m) && (d2 %| m). Proof. case: d1 d2 => [|d1] [|d2]; try by case: m => [|m]; rewrite ?lcmn0 ?andbF. rewrite -(@dvdn_pmul2r (gcdn d1.+1 d2.+1)) ?gcdn_gt0 // muln_lcm_gcd. by rewrite muln_gcdr dvdn_gcd {1}mulnC andbC !dvdn_pmul2r. Qed. Lemma lcmnMl m n : lcmn m (m * n) = m * n. Proof. by case: m => // m; rewrite /lcmn gcdnMr mulKn. Qed. Lemma lcmnMr m n : lcmn n (m * n) = m * n. Proof. by rewrite mulnC lcmnMl. Qed. Lemma lcmn_idPr {m n} : reflect (lcmn m n = n) (m %| n). Proof. by apply: (iffP idP) => [/dvdnP[q ->] | <-]; rewrite (lcmnMr, dvdn_lcml). Qed. Lemma lcmn_idPl {m n} : reflect (lcmn m n = m) (n %| m). Proof. by rewrite lcmnC; apply: lcmn_idPr. Qed. Lemma expn_max e m n : e ^ maxn m n = lcmn (e ^ m) (e ^ n). Proof. rewrite /maxn; case: leqP; [rewrite lcmnC | move/ltnW]; by move/(dvdn_exp2l e)/lcmn_idPr. Qed. (* Coprime factors *) Definition coprime m n := gcdn m n == 1. Lemma coprime1n n : coprime 1 n. Proof. by rewrite /coprime gcd1n. Qed. Lemma coprimen1 n : coprime n 1. Proof. by rewrite /coprime gcdn1. Qed. Lemma coprime_sym m n : coprime m n = coprime n m. Proof. by rewrite /coprime gcdnC. Qed. Lemma coprime_modl m n : coprime (m %% n) n = coprime m n. Proof. by rewrite /coprime gcdn_modl. Qed. Lemma coprime_modr m n : coprime m (n %% m) = coprime m n. Proof. by rewrite /coprime gcdn_modr. Qed. Lemma coprime2n n : coprime 2 n = odd n. Proof. by rewrite -coprime_modr modn2; case: (odd n). Qed. Lemma coprimen2 n : coprime n 2 = odd n. Proof. by rewrite coprime_sym coprime2n. Qed. Lemma coprimeSn n : coprime n.+1 n. Proof. by rewrite -coprime_modl (modnDr 1) coprime_modl coprime1n. Qed. Lemma coprimenS n : coprime n n.+1. Proof. by rewrite coprime_sym coprimeSn. Qed. Lemma coprimePn n : n > 0 -> coprime n.-1 n. Proof. by case: n => // n _; rewrite coprimenS. Qed. Lemma coprimenP n : n > 0 -> coprime n n.-1. Proof. by case: n => // n _; rewrite coprimeSn. Qed. Lemma coprimeP n m : n > 0 -> reflect (exists u, u.1 * n - u.2 * m = 1) (coprime n m). Proof. move=> n_gt0; apply: (iffP eqP) => [<-| [[kn km] /= kn_km_1]]. by have [kn km kg _] := egcdnP m n_gt0; exists (kn, km); rewrite kg addKn. apply gcdn_def; rewrite ?dvd1n // => d dv_d_n dv_d_m. by rewrite -kn_km_1 dvdn_subr ?dvdn_mull // ltnW // -subn_gt0 kn_km_1. Qed. Lemma modn_coprime k n : 0 < k -> (exists u, (k * u) %% n = 1) -> coprime k n. Proof. move=> k_gt0 [u Hu]; apply/coprimeP=> //. by exists (u, k * u %/ n); rewrite /= mulnC {1}(divn_eq (k * u) n) addKn. Qed. Lemma Gauss_dvd m n p : coprime m n -> (m * n %| p) = (m %| p) && (n %| p). Proof. by move=> co_mn; rewrite -muln_lcm_gcd (eqnP co_mn) muln1 dvdn_lcm. Qed. Lemma Gauss_dvdr m n p : coprime m n -> (m %| n * p) = (m %| p). Proof. case: n => [|n] co_mn; first by case: m co_mn => [|[]] // _; rewrite !dvd1n. by symmetry; rewrite mulnC -(@dvdn_pmul2r n.+1) ?Gauss_dvd // andbC dvdn_mull. Qed. Lemma Gauss_dvdl m n p : coprime m p -> (m %| n * p) = (m %| n). Proof. by rewrite mulnC; apply: Gauss_dvdr. Qed. Lemma dvdn_double_leq m n : m %| n -> odd m -> ~~ odd n -> 0 < n -> m.*2 <= n. Proof. move=> m_dv_n odd_m even_n n_gt0. by rewrite -muln2 dvdn_leq // Gauss_dvd ?coprimen2 ?m_dv_n ?dvdn2. Qed. Lemma dvdn_double_ltn m n : m %| n.-1 -> odd m -> odd n -> 1 < n -> m.*2 < n. Proof. by case: n => //; apply: dvdn_double_leq. Qed. Lemma Gauss_gcdr p m n : coprime p m -> gcdn p (m * n) = gcdn p n. Proof. move=> co_pm; apply/eqP; rewrite eqn_dvd !dvdn_gcd !dvdn_gcdl /=. rewrite andbC dvdn_mull ?dvdn_gcdr //= -(@Gauss_dvdr _ m) ?dvdn_gcdr //. by rewrite /coprime gcdnAC (eqnP co_pm) gcd1n. Qed. Lemma Gauss_gcdl p m n : coprime p n -> gcdn p (m * n) = gcdn p m. Proof. by move=> co_pn; rewrite mulnC Gauss_gcdr. Qed. Lemma coprime_mulr p m n : coprime p (m * n) = coprime p m && coprime p n. Proof. case co_pm: (coprime p m) => /=; first by rewrite /coprime Gauss_gcdr. apply/eqP=> co_p_mn; case/eqnP: co_pm; apply gcdn_def => // d dv_dp dv_dm. by rewrite -co_p_mn dvdn_gcd dv_dp dvdn_mulr. Qed. Lemma coprime_mull p m n : coprime (m * n) p = coprime m p && coprime n p. Proof. by rewrite -!(coprime_sym p) coprime_mulr. Qed. Lemma coprime_pexpl k m n : 0 < k -> coprime (m ^ k) n = coprime m n. Proof. case: k => // k _; elim: k => [|k IHk]; first by rewrite expn1. by rewrite expnS coprime_mull -IHk; case coprime. Qed. Lemma coprime_pexpr k m n : 0 < k -> coprime m (n ^ k) = coprime m n. Proof. by move=> k_gt0; rewrite !(coprime_sym m) coprime_pexpl. Qed. Lemma coprime_expl k m n : coprime m n -> coprime (m ^ k) n. Proof. by case: k => [|k] co_pm; rewrite ?coprime1n // coprime_pexpl. Qed. Lemma coprime_expr k m n : coprime m n -> coprime m (n ^ k). Proof. by rewrite !(coprime_sym m); exact: coprime_expl. Qed. Lemma coprime_dvdl m n p : m %| n -> coprime n p -> coprime m p. Proof. by case/dvdnP=> d ->; rewrite coprime_mull => /andP[]. Qed. Lemma coprime_dvdr m n p : m %| n -> coprime p n -> coprime p m. Proof. by rewrite !(coprime_sym p); exact: coprime_dvdl. Qed. Lemma coprime_egcdn n m : n > 0 -> coprime (egcdn n m).1 (egcdn n m).2. Proof. move=> n_gt0; case: (egcdnP m n_gt0) => kn km /= /eqP. have [/dvdnP[u defn] /dvdnP[v defm]] := (dvdn_gcdl n m, dvdn_gcdr n m). rewrite -[gcdn n m]mul1n {1}defm {1}defn !mulnA -mulnDl addnC. rewrite eqn_pmul2r ?gcdn_gt0 ?n_gt0 //; case: kn => // kn /eqP def_knu _. by apply/coprimeP=> //; exists (u, v); rewrite mulnC def_knu mulnC addnK. Qed. Lemma dvdn_pexp2r m n k : k > 0 -> (m ^ k %| n ^ k) = (m %| n). Proof. move=> k_gt0; apply/idP/idP=> [dv_mn_k|]; last exact: dvdn_exp2r. case: (posnP n) => [-> | n_gt0]; first by rewrite dvdn0. have [n' def_n] := dvdnP (dvdn_gcdr m n); set d := gcdn m n in def_n. have [m' def_m] := dvdnP (dvdn_gcdl m n); rewrite -/d in def_m. have d_gt0: d > 0 by rewrite gcdn_gt0 n_gt0 orbT. rewrite def_m def_n !expnMn dvdn_pmul2r ?expn_gt0 ?d_gt0 // in dv_mn_k. have: coprime (m' ^ k) (n' ^ k). rewrite coprime_pexpl // coprime_pexpr // /coprime -(eqn_pmul2r d_gt0) mul1n. by rewrite muln_gcdl -def_m -def_n. rewrite /coprime -gcdn_modr (eqnP dv_mn_k) gcdn0 -(exp1n k). by rewrite (inj_eq (expIn k_gt0)) def_m; move/eqP->; rewrite mul1n dvdn_gcdr. Qed. Section Chinese. (***********************************************************************) (* The chinese remainder theorem *) (***********************************************************************) Variables m1 m2 : nat. Hypothesis co_m12 : coprime m1 m2. Lemma chinese_remainder x y : (x == y %[mod m1 * m2]) = (x == y %[mod m1]) && (x == y %[mod m2]). Proof. wlog le_yx : x y / y <= x; last by rewrite !eqn_mod_dvd // Gauss_dvd. by case/orP: (leq_total y x); last rewrite !(eq_sym (x %% _)); auto. Qed. (***********************************************************************) (* A function that solves the chinese remainder problem *) (***********************************************************************) Definition chinese r1 r2 := r1 * m2 * (egcdn m2 m1).1 + r2 * m1 * (egcdn m1 m2).1. Lemma chinese_modl r1 r2 : chinese r1 r2 = r1 %[mod m1]. Proof. rewrite /chinese; case: (posnP m2) co_m12 => [-> /eqnP | m2_gt0 _]. by rewrite gcdn0 => ->; rewrite !modn1. case: egcdnP => // k2 k1 def_m1 _. rewrite mulnAC -mulnA def_m1 gcdnC (eqnP co_m12) mulnDr mulnA muln1. by rewrite addnAC (mulnAC _ m1) -mulnDl modnMDl. Qed. Lemma chinese_modr r1 r2 : chinese r1 r2 = r2 %[mod m2]. Proof. rewrite /chinese; case: (posnP m1) co_m12 => [-> /eqnP | m1_gt0 _]. by rewrite gcd0n => ->; rewrite !modn1. case: (egcdnP m2) => // k1 k2 def_m2 _. rewrite addnC mulnAC -mulnA def_m2 (eqnP co_m12) mulnDr mulnA muln1. by rewrite addnAC (mulnAC _ m2) -mulnDl modnMDl. Qed. Lemma chinese_mod x : x = chinese (x %% m1) (x %% m2) %[mod m1 * m2]. Proof. apply/eqP; rewrite chinese_remainder //. by rewrite chinese_modl chinese_modr !modn_mod !eqxx. Qed. End Chinese. mathcomp-1.5/theories/polydiv.v0000644000175000017500000037633712307636117015703 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq choice fintype. Require Import bigop ssralg poly. (******************************************************************************) (* This file provides a library for the basic theory of Euclidean and pseudo- *) (* Euclidean division for polynomials over ring structures. *) (* The library defines two versions of the pseudo-euclidean division: one for *) (* coefficients in a (not necessarily commutative) ring structure and one for *) (* coefficients equipped with a structure of integral domain. From the latter *) (* we derive the definition of the usual Euclidean division for coefficients *) (* in a field. Only the definition of the pseudo-division for coefficients in *) (* an integral domain is exported by default and benefits from notations. *) (* Also, the only theory exported by default is the one of division for *) (* polynomials with coefficients in a field. *) (* Other definitions and facts are qualified using name spaces indicating the *) (* hypotheses made on the structure of coefficients and the properties of the *) (* polynomial one divides with. *) (* *) (* Pdiv.Field (exported by the present library): *) (* edivp p q == pseudo-division of p by q with p q : {poly R} where *) (* R is an idomainType. *) (* Computes (k, quo, rem) : nat * {poly r} * {poly R}, *) (* such that size rem < size q and: *) (* + if lead_coef q is not a unit, then: *) (* (lead_coef q ^+ k) *: p = q * quo + rem *) (* + else if lead_coef q is a unit, then: *) (* p = q * quo + rem and k = 0 *) (* p %/ q == quotient (second component) computed by (edivp p q). *) (* p %% q == remainder (third component) computed by (edivp p q). *) (* scalp p q == exponent (first component) computed by (edivp p q). *) (* p %| q == tests the nullity of the remainder of the *) (* pseudo-division of p by q. *) (* rgcdp p q == Pseudo-greater common divisor obtained by performing *) (* the Euclidean algorithm on p and q using redivp as *) (* Euclidean division. *) (* p %= q == p and q are associate polynomials, i.e., p %| q and *) (* q %| p, or equivalently, p = c *: q for some nonzero *) (* constant c. *) (* gcdp p q == Pseudo-greater common divisor obtained by performing *) (* the Euclidean algorithm on p and q using edivp as *) (* Euclidean division. *) (* egcdp p q == The pair of Bezout coefficients: if e := egcdp p q, *) (* then size e.1 <= size q, size e.2 <= size p, and *) (* gcdp p q %= e.1 * p + e.2 * q *) (* coprimep p q == p and q are coprime, i.e., (gcdp p q) is a nonzero *) (* constant. *) (* gdcop q p == greatest divisor of p which is coprime to q. *) (* irreducible_poly p <-> p has only trivial (constant) divisors. *) (* *) (* Pdiv.Idomain: theory available for edivp and the related operation under *) (* the sole assumption that the ring of coefficients is canonically an *) (* integral domain (R : idomainType). *) (* *) (* Pdiv.IdomainMonic: theory available for edivp and the related operations *) (* under the assumption that the ring of coefficients is canonically *) (* and integral domain (R : idomainType) an the divisor is monic. *) (* *) (* Pdiv.IdomainUnit: theory available for edivp and the related operations *) (* under the assumption that the ring of coefficients is canonically an *) (* integral domain (R : idomainType) and the leading coefficient of the *) (* divisor is a unit. *) (* *) (* Pdiv.ClosedField: theory available for edivp and the related operation *) (* under the sole assumption that the ring of coefficients is canonically *) (* an algebraically closed field (R : closedField). *) (* *) (* Pdiv.Ring : *) (* redivp p q == pseudo-division of p by q with p q : {poly R} where R is *) (* a ringType. *) (* Computes (k, quo, rem) : nat * {poly r} * {poly R}, *) (* such that if rem = 0 then quo * q = p * (lead_coef q ^+ k) *) (* *) (* rdivp p q == quotient (second component) computed by (redivp p q). *) (* rmodp p q == remainder (third component) computed by (redivp p q). *) (* rscalp p q == exponent (first component) computed by (redivp p q). *) (* rdvdp p q == tests the nullity of the remainder of the pseudo-division *) (* of p by q. *) (* rgcdp p q == analogue of gcdp for coefficients in a ringType. *) (* rgdcop p q == analogue of gdcop for coefficients in a ringType. *) (*rcoprimep p q == analogue of coprimep p q for coefficients in a ringType. *) (* *) (* Pdiv.RingComRreg : theory of the operations defined in Pdiv.Ring, when the *) (* ring of coefficients is canonically commutative (R : comRingType) and *) (* the leading coefficient of the divisor is both right regular and *) (* commutes as a constant polynomial with the divisor itself *) (* *) (* Pdiv.RingMonic : theory of the operations defined in Pdiv.Ring, under the *) (* assumption that the divisor is monic. *) (* *) (* Pdiv.UnitRing: theory of the operations defined in Pdiv.Ring, when the *) (* ring R of coefficients is canonically with units (R : unitRingType). *) (* *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GRing.Theory. Local Open Scope ring_scope. Reserved Notation "p %= q" (at level 70, no associativity). Local Notation simp := Monoid.simpm. Module Pdiv. Module CommonRing. Section RingPseudoDivision. Variable R : ringType. Implicit Types d p q r : {poly R}. (* Pseudo division, defined on an arbitrary ring *) Definition redivp_rec (q : {poly R}) := let sq := size q in let cq := lead_coef q in fix loop (k : nat) (qq r : {poly R})(n : nat) {struct n} := if size r < sq then (k, qq, r) else let m := (lead_coef r) *: 'X^(size r - sq) in let qq1 := qq * cq%:P + m in let r1 := r * cq%:P - m * q in if n is n1.+1 then loop k.+1 qq1 r1 n1 else (k.+1, qq1, r1). Definition redivp_expanded_def p q := if q == 0 then (0%N, 0, p) else redivp_rec q 0 0 p (size p). Fact redivp_key : unit. Proof. by []. Qed. Definition redivp : {poly R} -> {poly R} -> nat * {poly R} * {poly R} := locked_with redivp_key redivp_expanded_def. Canonical redivp_unlockable := [unlockable fun redivp]. Definition rdivp p q := ((redivp p q).1).2. Definition rmodp p q := (redivp p q).2. Definition rscalp p q := ((redivp p q).1).1. Definition rdvdp p q := rmodp q p == 0. (*Definition rmultp := [rel m d | rdvdp d m].*) Lemma redivp_def p q : redivp p q = (rscalp p q, rdivp p q, rmodp p q). Proof. by rewrite /rscalp /rdivp /rmodp; case: (redivp p q) => [[]] /=. Qed. Lemma rdiv0p p : rdivp 0 p = 0. Proof. rewrite /rdivp unlock; case: ifP => // Hp; rewrite /redivp_rec !size_poly0. by rewrite polySpred ?Hp. Qed. Lemma rdivp0 p : rdivp p 0 = 0. Proof. by rewrite /rdivp unlock eqxx. Qed. Lemma rdivp_small p q : size p < size q -> rdivp p q = 0. Proof. rewrite /rdivp unlock; case: eqP => Eq; first by rewrite Eq size_poly0. by case sp: (size p) => [| s] hs /=; rewrite sp hs. Qed. Lemma leq_rdivp p q : (size (rdivp p q) <= size p). Proof. case: (ltnP (size p) (size q)); first by move/rdivp_small->; rewrite size_poly0. rewrite /rdivp /rmodp /rscalp unlock; case q0 : (q == 0) => /=. by rewrite size_poly0. have : (size (0 : {poly R})) <= size p by rewrite size_poly0. move: (leqnn (size p)); move: {2 3 4 6}(size p)=> A. elim: (size p) 0%N (0 : {poly R}) {1 3 4}p (leqnn (size p)) => [| n ihn] k q1 r. by move/size_poly_leq0P->; rewrite /= size_poly0 lt0n size_poly_eq0 q0. move=> /= hrn hr hq1 hq; case: ltnP=> //= hqr. have sr: 0 < size r by apply: leq_trans hqr; rewrite size_poly_gt0 q0. have sq: 0 < size q by rewrite size_poly_gt0 q0. apply: ihn => //. - apply/leq_sizeP => j hnj. rewrite coefB -scalerAl coefZ coefXnM ltn_subRL ltnNge. have hj : (size r).-1 <= j. by apply: leq_trans hnj; move: hrn; rewrite -{1}(prednK sr) ltnS. rewrite polySpred -?size_poly_gt0 // (leq_ltn_trans hj) /=; last first. by rewrite -{1}(add0n j) ltn_add2r. move: (hj); rewrite leq_eqVlt; case/orP. move/eqP<-; rewrite (@polySpred _ q) ?q0 // subSS coefMC. rewrite subKn; first by rewrite lead_coefE subrr. by rewrite -ltnS -!polySpred // ?q0 -?size_poly_gt0. move=> {hj} hj; move: (hj); rewrite prednK // coefMC; move/leq_sizeP=> -> //. suff: size q <= j - (size r - size q). by rewrite mul0r sub0r; move/leq_sizeP=> -> //; rewrite mulr0 oppr0. rewrite subnBA // addnC -(prednK sq) -(prednK sr) addSn subSS. by rewrite -addnBA ?(ltnW hj) // -{1}[_.-1]addn0 ltn_add2l subn_gt0. - apply: leq_trans (size_add _ _) _; rewrite geq_max; apply/andP; split. apply: leq_trans (size_mul_leq _ _) _. by rewrite size_polyC lead_coef_eq0 q0 /= addn1. rewrite size_opp; apply: leq_trans (size_mul_leq _ _) _. apply: leq_trans hr; rewrite -subn1 leq_subLR -{2}(subnK hqr) addnA leq_add2r. by rewrite add1n -(@size_polyXn R) size_scale_leq. apply: leq_trans (size_add _ _) _; rewrite geq_max; apply/andP; split. apply: leq_trans (size_mul_leq _ _) _. by rewrite size_polyC lead_coef_eq0 q0 /= addnS addn0. apply: leq_trans (size_scale_leq _ _) _; rewrite size_polyXn. by rewrite -subSn // leq_subLR -add1n leq_add. Qed. Lemma rmod0p p : rmodp 0 p = 0. Proof. rewrite /rmodp unlock; case: ifP => // Hp; rewrite /redivp_rec !size_poly0. by rewrite polySpred ?Hp. Qed. Lemma rmodp0 p : rmodp p 0 = p. Proof. by rewrite /rmodp unlock eqxx. Qed. Lemma rscalp_small p q : size p < size q -> rscalp p q = 0%N. Proof. rewrite /rscalp unlock; case: eqP => Eq // spq. by case sp: (size p) => [| s] /=; rewrite spq. Qed. Lemma ltn_rmodp p q : (size (rmodp p q) < size q) = (q != 0). Proof. rewrite /rdivp /rmodp /rscalp unlock; case q0 : (q == 0). by rewrite (eqP q0) /= size_poly0 ltn0. elim: (size p) 0%N 0 {1 3}p (leqnn (size p)) => [|n ihn] k q1 r. rewrite leqn0 size_poly_eq0; move/eqP->; rewrite /= size_poly0 /= lt0n. by rewrite size_poly_eq0 q0 /= size_poly0 lt0n size_poly_eq0 q0. move=> hr /=; case: (@ltnP (size r) _) => //= hsrq; rewrite ihn //. apply/leq_sizeP => j hnj; rewrite coefB. have sr: 0 < size r. by apply: leq_trans hsrq; apply: neq0_lt0n; rewrite size_poly_eq0. have sq: 0 < size q by rewrite size_poly_gt0 q0. have hj : (size r).-1 <= j. by apply: leq_trans hnj; move: hr; rewrite -{1}(prednK sr) ltnS. rewrite -scalerAl !coefZ coefXnM ltn_subRL ltnNge; move: (sr). move/prednK => {1}<-. have -> /= : (size r).-1 < size q + j. apply: (@leq_trans ((size q) + (size r).-1)); last by rewrite leq_add2l. by rewrite -{1}[_.-1]add0n ltn_add2r. move: (hj); rewrite leq_eqVlt; case/orP. move/eqP<-; rewrite -{1}(prednK sq) -{3}(prednK sr) subSS. rewrite subKn; first by rewrite coefMC !lead_coefE subrr. by move: hsrq; rewrite -{1}(prednK sq) -{1}(prednK sr) ltnS. move=> {hj} hj; move: (hj); rewrite prednK // coefMC; move/leq_sizeP=> -> //. suff: size q <= j - (size r - size q). by rewrite mul0r sub0r; move/leq_sizeP=> -> //; rewrite mulr0 oppr0. rewrite subnBA // addnC -(prednK sq) -(prednK sr) addSn subSS. by rewrite -addnBA ?(ltnW hj) // -{1}[_.-1]addn0 ltn_add2l subn_gt0. Qed. Lemma ltn_rmodpN0 p q : q != 0 -> size (rmodp p q) < size q. Proof. by rewrite ltn_rmodp. Qed. Lemma rmodp1 p : rmodp p 1 = 0. Proof. case p0: (p == 0); first by rewrite (eqP p0) rmod0p. apply/eqP; rewrite -size_poly_eq0. by have := (ltn_rmodp p 1); rewrite size_polyC !oner_neq0 ltnS leqn0. Qed. Lemma rmodp_small p q : size p < size q -> rmodp p q = p. Proof. rewrite /rmodp unlock; case: eqP => Eq; first by rewrite Eq size_poly0. by case sp: (size p) => [| s] Hs /=; rewrite sp Hs /=. Qed. Lemma leq_rmodp m d : size (rmodp m d) <= size m. Proof. case: (ltnP (size m) (size d)) => [|h]; first by move/rmodp_small->. case d0: (d == 0); first by rewrite (eqP d0) rmodp0. by apply: leq_trans h; apply: ltnW; rewrite ltn_rmodp d0. Qed. Lemma rmodpC p c : c != 0 -> rmodp p c%:P = 0. Proof. move=> Hc; apply/eqP; rewrite -size_poly_eq0 -leqn0 -ltnS. have -> : 1%N = nat_of_bool (c != 0) by rewrite Hc. by rewrite -size_polyC ltn_rmodp polyC_eq0. Qed. Lemma rdvdp0 d : rdvdp d 0. Proof. by rewrite /rdvdp rmod0p. Qed. Lemma rdvd0p n : (rdvdp 0 n) = (n == 0). Proof. by rewrite /rdvdp rmodp0. Qed. Lemma rdvd0pP n : reflect (n = 0) (rdvdp 0 n). Proof. by apply: (iffP idP); rewrite rdvd0p; move/eqP. Qed. Lemma rdvdpN0 p q : rdvdp p q -> q != 0 -> p != 0. Proof. by move=> pq hq; apply: contraL pq => /eqP ->; rewrite rdvd0p. Qed. Lemma rdvdp1 d : (rdvdp d 1) = ((size d) == 1%N). Proof. rewrite /rdvdp; case d0: (d == 0). by rewrite (eqP d0) rmodp0 size_poly0 (negPf (@oner_neq0 _)). have:= (size_poly_eq0 d); rewrite d0; move/negbT; rewrite -lt0n. rewrite leq_eqVlt; case/orP => hd; last first. by rewrite rmodp_small ?size_poly1 // oner_eq0 -(subnKC hd). rewrite eq_sym in hd; rewrite hd; have [c cn0 ->] := size_poly1P _ hd. rewrite /rmodp unlock -size_poly_eq0 size_poly1 /= size_poly1 size_polyC cn0 /=. by rewrite polyC_eq0 (negPf cn0) !lead_coefC !scale1r subrr !size_poly0. Qed. Lemma rdvd1p m : rdvdp 1 m. Proof. by rewrite /rdvdp rmodp1. Qed. Lemma Nrdvdp_small (n d : {poly R}) : n != 0 -> size n < size d -> (rdvdp d n) = false. Proof. by move=> nn0 hs; rewrite /rdvdp; rewrite (rmodp_small hs); apply: negPf. Qed. Lemma rmodp_eq0P p q : reflect (rmodp p q = 0) (rdvdp q p). Proof. exact: (iffP eqP). Qed. Lemma rmodp_eq0 p q : rdvdp q p -> rmodp p q = 0. Proof. by move/rmodp_eq0P. Qed. Lemma rdvdp_leq p q : rdvdp p q -> q != 0 -> size p <= size q. Proof. by move=> dvd_pq; rewrite leqNgt; apply: contra => /rmodp_small <-. Qed. Definition rgcdp p q := let: (p1, q1) := if size p < size q then (q, p) else (p, q) in if p1 == 0 then q1 else let fix loop (n : nat) (pp qq : {poly R}) {struct n} := let rr := rmodp pp qq in if rr == 0 then qq else if n is n1.+1 then loop n1 qq rr else rr in loop (size p1) p1 q1. Lemma rgcd0p : left_id 0 rgcdp. Proof. move=> p; rewrite /rgcdp size_poly0 size_poly_gt0 if_neg. case: ifP => /= [_ | nzp]; first by rewrite eqxx. by rewrite polySpred !(rmodp0, nzp) //; case: _.-1 => [|m]; rewrite rmod0p eqxx. Qed. Lemma rgcdp0 : right_id 0 rgcdp. Proof. move=> p; have:= rgcd0p p; rewrite /rgcdp size_poly0 size_poly_gt0 if_neg. by case: ifP => /= p0; rewrite ?(eqxx, p0) // (eqP p0). Qed. Lemma rgcdpE p q : rgcdp p q = if size p < size q then rgcdp (rmodp q p) p else rgcdp (rmodp p q) q. Proof. pose rgcdp_rec := fix rgcdp_rec (n : nat) (pp qq : {poly R}) {struct n} := let rr := rmodp pp qq in if rr == 0 then qq else if n is n1.+1 then rgcdp_rec n1 qq rr else rr. have Irec: forall m n p q, size q <= m -> size q <= n -> size q < size p -> rgcdp_rec m p q = rgcdp_rec n p q. + elim=> [|m Hrec] [|n] //= p1 q1. - rewrite leqn0 size_poly_eq0; move/eqP=> -> _. rewrite size_poly0 size_poly_gt0 rmodp0 => nzp. by rewrite (negPf nzp); case: n => [|n] /=; rewrite rmod0p eqxx. - rewrite leqn0 size_poly_eq0 => _; move/eqP=> ->. rewrite size_poly0 size_poly_gt0 rmodp0 => nzp. by rewrite (negPf nzp); case: m {Hrec} => [|m] /=; rewrite rmod0p eqxx. case: ifP => Epq Sm Sn Sq //; rewrite ?Epq //. case: (eqVneq q1 0) => [->|nzq]. by case: n m {Sm Sn Hrec} => [|m] [|n] //=; rewrite rmod0p eqxx. apply: Hrec; last by rewrite ltn_rmodp. by rewrite -ltnS (leq_trans _ Sm) // ltn_rmodp. by rewrite -ltnS (leq_trans _ Sn) // ltn_rmodp. case: (eqVneq p 0) => [-> | nzp]. by rewrite rmod0p rmodp0 rgcd0p rgcdp0 if_same. case: (eqVneq q 0) => [-> | nzq]. by rewrite rmod0p rmodp0 rgcd0p rgcdp0 if_same. rewrite /rgcdp -/rgcdp_rec. case: ltnP; rewrite (negPf nzp, negPf nzq) //=. move=> ltpq; rewrite ltn_rmodp (negPf nzp) //=. rewrite -(ltn_predK ltpq) /=; case: eqP => [->|]. by case: (size p) => [|[|s]]; rewrite /= rmodp0 (negPf nzp) // rmod0p eqxx. move/eqP=> nzqp; rewrite (negPf nzp). apply: Irec => //; last by rewrite ltn_rmodp. by rewrite -ltnS (ltn_predK ltpq) (leq_trans _ ltpq) ?leqW // ltn_rmodp. by rewrite ltnW // ltn_rmodp. move=> leqp; rewrite ltn_rmodp (negPf nzq) //=. have p_gt0: size p > 0 by rewrite size_poly_gt0. rewrite -(prednK p_gt0) /=; case: eqP => [->|]. by case: (size q) => [|[|s]]; rewrite /= rmodp0 (negPf nzq) // rmod0p eqxx. move/eqP=> nzpq; rewrite (negPf nzq). apply: Irec => //; last by rewrite ltn_rmodp. by rewrite -ltnS (prednK p_gt0) (leq_trans _ leqp) // ltn_rmodp. by rewrite ltnW // ltn_rmodp. Qed. CoInductive comm_redivp_spec m d : nat * {poly R} * {poly R} -> Type := ComEdivnSpec k (q r : {poly R}) of (GRing.comm d (lead_coef d)%:P -> m * (lead_coef d ^+ k)%:P = q * d + r) & (d != 0 -> size r < size d) : comm_redivp_spec m d (k, q, r). Lemma comm_redivpP m d : comm_redivp_spec m d (redivp m d). Proof. rewrite unlock; case: (altP (d =P 0))=> [->| Hd]. by constructor; rewrite !(simp, eqxx). have: GRing.comm d (lead_coef d)%:P -> m * (lead_coef d ^+ 0)%:P = 0 * d + m. by rewrite !simp. elim: (size m) 0%N 0 {1 4 6}m (leqnn (size m))=> [|n IHn] k q r Hr /=. have{Hr} ->: r = 0 by apply/eqP; rewrite -size_poly_eq0; move: Hr; case: size. suff hsd: size (0: {poly R}) < size d by rewrite hsd => /= ?; constructor. by rewrite size_polyC eqxx (polySpred Hd). case: ltP=> Hlt Heq; first by constructor=> // _; apply/ltP. apply: IHn=> [|Cda]; last first. rewrite mulrDl addrAC -addrA subrK exprSr polyC_mul mulrA Heq //. by rewrite mulrDl -mulrA Cda mulrA. apply/leq_sizeP => j Hj. rewrite coefD coefN coefMC -scalerAl coefZ coefXnM. move/ltP: Hlt; rewrite -leqNgt=> Hlt. move: Hj; rewrite leq_eqVlt; case/predU1P => [<-{j} | Hj]; last first. rewrite nth_default ?(leq_trans Hqq) // ?simp; last by apply: (leq_trans Hr). rewrite nth_default; first by rewrite if_same !simp oppr0. by rewrite -{1}(subKn Hlt) leq_sub2r // (leq_trans Hr). move: Hr; rewrite leq_eqVlt ltnS; case/predU1P=> Hqq; last first. rewrite !nth_default ?if_same ?simp ?oppr0 //. by rewrite -{1}(subKn Hlt) leq_sub2r // (leq_trans Hqq). rewrite {2}/lead_coef Hqq polySpred // subSS ltnNge leq_subr /=. by rewrite subKn ?addrN // -subn1 leq_subLR add1n -Hqq. Qed. Lemma rmodpp p : GRing.comm p (lead_coef p)%:P -> rmodp p p = 0. Proof. move=> hC; rewrite /rmodp unlock; case: ifP => hp /=; first by rewrite (eqP hp). move: (hp); rewrite -size_poly_eq0 /redivp_rec; case sp: (size p)=> [|n] // _. rewrite mul0r sp ltnn add0r subnn expr0 hC alg_polyC subrr. by case: n sp => [|n] sp; rewrite size_polyC /= eqxx. Qed. Definition rcoprimep (p q : {poly R}) := size (rgcdp p q) == 1%N. Fixpoint rgdcop_rec q p n := if n is m.+1 then if rcoprimep p q then p else rgdcop_rec q (rdivp p (rgcdp p q)) m else (q == 0)%:R. Definition rgdcop q p := rgdcop_rec q p (size p). Lemma rgdcop0 q : rgdcop q 0 = (q == 0)%:R. Proof. by rewrite /rgdcop size_poly0. Qed. End RingPseudoDivision. End CommonRing. Module RingComRreg. Import CommonRing. Section ComRegDivisor. Variable R : ringType. Variable d : {poly R}. Hypothesis Cdl : GRing.comm d (lead_coef d)%:P. Hypothesis Rreg : GRing.rreg (lead_coef d). Implicit Types p q r : {poly R}. Lemma redivp_eq q r : size r < size d -> let k := (redivp (q * d + r) d).1.1 in let c := (lead_coef d ^+ k)%:P in redivp (q * d + r) d = (k, q * c, r * c). Proof. move=> lt_rd; case: comm_redivpP=> k q1 r1; move/(_ Cdl)=> Heq. have: d != 0 by case: (size d) lt_rd (size_poly_eq0 d) => // n _ <-. move=> dn0; move/(_ dn0)=> Hs. have eC : q * d * (lead_coef d ^+ k)%:P = q * (lead_coef d ^+ k)%:P * d. by rewrite -mulrA polyC_exp (GRing.commrX k Cdl) mulrA. suff e1 : q1 = q * (lead_coef d ^+ k)%:P. congr (_, _, _) => //=; move/eqP: Heq; rewrite [_ + r1]addrC. rewrite -subr_eq; move/eqP<-; rewrite e1 mulrDl addrAC -{2}(add0r (r * _)). by rewrite eC subrr add0r. have : (q1 - q * (lead_coef d ^+ k)%:P) * d = r * (lead_coef d ^+ k)%:P - r1. apply: (@addIr _ r1); rewrite subrK. apply: (@addrI _ ((q * (lead_coef d ^+ k)%:P) * d)). by rewrite mulrDl mulNr !addrA [_ + (q1 * d)]addrC addrK -eC -mulrDl. move/eqP; rewrite -[_ == _ - _]subr_eq0 rreg_div0 //. by case/andP; rewrite subr_eq0; move/eqP. rewrite size_opp; apply: (leq_ltn_trans (size_add _ _)); rewrite size_opp. rewrite gtn_max Hs (leq_ltn_trans (size_mul_leq _ _)) //. rewrite size_polyC; case: (_ == _); last by rewrite addnS addn0. by rewrite addn0; apply: leq_ltn_trans lt_rd; case: size. Qed. (* this is a bad name *) Lemma rdivp_eq p : p * (lead_coef d ^+ (rscalp p d))%:P = (rdivp p d) * d + (rmodp p d). Proof. rewrite /rdivp /rmodp /rscalp; case: comm_redivpP=> k q1 r1 Hc _; exact: Hc. Qed. (* section variables impose an inconvenient order on parameters *) Lemma eq_rdvdp k q1 p: p * ((lead_coef d)^+ k)%:P = q1 * d -> rdvdp d p. Proof. move=> he. have Hnq0 := rreg_lead0 Rreg; set lq := lead_coef d. pose v := rscalp p d; pose m := maxn v k. rewrite /rdvdp -(rreg_polyMC_eq0 _ (@rregX _ _ (m - v) Rreg)). suff: ((rdivp p d) * (lq ^+ (m - v))%:P - q1 * (lq ^+ (m - k))%:P) * d + (rmodp p d) * (lq ^+ (m - v))%:P == 0. rewrite rreg_div0 //; first by case/andP. by rewrite rreg_size ?ltn_rmodp //; apply rregX. rewrite mulrDl addrAC mulNr -!mulrA polyC_exp -(GRing.commrX (m-v) Cdl). rewrite -polyC_exp mulrA -mulrDl -rdivp_eq // [(_ ^+ (m - k))%:P]polyC_exp. rewrite -(GRing.commrX (m-k) Cdl) -polyC_exp mulrA -he -!mulrA -!polyC_mul. rewrite -/v -!exprD addnC subnK ?leq_maxl //. by rewrite addnC subnK ?subrr ?leq_maxr. Qed. CoInductive rdvdp_spec p q : {poly R} -> bool -> Type := | Rdvdp k q1 & p * ((lead_coef q)^+ k)%:P = q1 * q : rdvdp_spec p q 0 true | RdvdpN & rmodp p q != 0 : rdvdp_spec p q (rmodp p q) false. (* Is that version useable ? *) Lemma rdvdp_eqP p : rdvdp_spec p d (rmodp p d) (rdvdp d p). Proof. case hdvd: (rdvdp d p); last by apply: RdvdpN; move/rmodp_eq0P/eqP: hdvd. move/rmodp_eq0P: (hdvd)->; apply: (@Rdvdp _ _ (rscalp p d) (rdivp p d)). by rewrite rdivp_eq //; move/rmodp_eq0P: (hdvd)->; rewrite addr0. Qed. Lemma rdvdp_mull p : rdvdp d (p * d). Proof. by apply: (@eq_rdvdp 0%N p); rewrite expr0 mulr1. Qed. Lemma rmodp_mull p : rmodp (p * d) d = 0. Proof. case: (d =P 0)=> Hd; first by rewrite Hd simp rmod0p. by apply/eqP; apply: rdvdp_mull. Qed. Lemma rmodpp : rmodp d d = 0. Proof. by rewrite -{1}(mul1r d) rmodp_mull. Qed. Lemma rdivpp : rdivp d d = (lead_coef d ^+ rscalp d d)%:P. have dn0 : d != 0 by rewrite -lead_coef_eq0 rreg_neq0. move: (rdivp_eq d); rewrite rmodpp addr0. suff ->: GRing.comm d (lead_coef d ^+ rscalp d d)%:P by move/(rreg_lead Rreg)->. by rewrite polyC_exp; apply: commrX. Qed. Lemma rdvdpp : rdvdp d d. Proof. apply/eqP; exact: rmodpp. Qed. Lemma rdivpK p : rdvdp d p -> (rdivp p d) * d = p * (lead_coef d ^+ rscalp p d)%:P. Proof. by rewrite rdivp_eq /rdvdp; move/eqP->; rewrite addr0. Qed. End ComRegDivisor. End RingComRreg. Module RingMonic. Import CommonRing. Import RingComRreg. Section MonicDivisor. Variable R : ringType. Implicit Types p q r : {poly R}. Variable d : {poly R}. Hypothesis mond : d \is monic. Lemma redivp_eq q r : size r < size d -> let k := (redivp (q * d + r) d).1.1 in redivp (q * d + r) d = (k, q, r). Proof. case: (monic_comreg mond)=> Hc Hr; move/(redivp_eq Hc Hr q). by rewrite (eqP mond); move=> -> /=; rewrite expr1n !mulr1. Qed. Lemma rdivp_eq p : p = (rdivp p d) * d + (rmodp p d). Proof. rewrite -rdivp_eq; rewrite (eqP mond); last exact: commr1. by rewrite expr1n mulr1. Qed. Lemma rdivpp : rdivp d d = 1. Proof. by case: (monic_comreg mond) => hc hr; rewrite rdivpp // (eqP mond) expr1n. Qed. Lemma rdivp_addl_mul_small q r : size r < size d -> rdivp (q * d + r) d = q. Proof. by move=> Hd; case: (monic_comreg mond)=> Hc Hr; rewrite /rdivp redivp_eq. Qed. Lemma rdivp_addl_mul q r : rdivp (q * d + r) d = q + rdivp r d. Proof. case: (monic_comreg mond)=> Hc Hr; rewrite {1}(rdivp_eq r) addrA. by rewrite -mulrDl rdivp_addl_mul_small // ltn_rmodp monic_neq0. Qed. Lemma rdivp_addl q r : rdvdp d q -> rdivp (q + r) d = rdivp q d + rdivp r d. Proof. case: (monic_comreg mond)=> Hc Hr; rewrite {1}(rdivp_eq r) addrA. rewrite {2}(rdivp_eq q); move/rmodp_eq0P->; rewrite addr0. by rewrite -mulrDl rdivp_addl_mul_small // ltn_rmodp monic_neq0. Qed. Lemma rdivp_addr q r : rdvdp d r -> rdivp (q + r) d = rdivp q d + rdivp r d. Proof. by rewrite addrC; move/rdivp_addl->; rewrite addrC. Qed. Lemma rdivp_mull p : rdivp (p * d) d = p. Proof. by rewrite -[p * d]addr0 rdivp_addl_mul rdiv0p addr0. Qed. Lemma rmodp_mull p : rmodp (p * d) d = 0. Proof. apply: rmodp_mull; rewrite (eqP mond); [exact: commr1 | exact: rreg1]. Qed. Lemma rmodpp : rmodp d d = 0. Proof. apply: rmodpp; rewrite (eqP mond); [exact: commr1 | exact: rreg1]. Qed. Lemma rmodp_addl_mul_small q r : size r < size d -> rmodp (q * d + r) d = r. Proof. by move=> Hd; case: (monic_comreg mond)=> Hc Hr; rewrite /rmodp redivp_eq. Qed. Lemma rmodp_add p q : rmodp (p + q) d = rmodp p d + rmodp q d. Proof. rewrite {1}(rdivp_eq p) {1}(rdivp_eq q). rewrite addrCA 2!addrA -mulrDl (addrC (rdivp q d)) -addrA. rewrite rmodp_addl_mul_small //; apply: (leq_ltn_trans (size_add _ _)). by rewrite gtn_max !ltn_rmodp // monic_neq0. Qed. Lemma rmodp_mulmr p q : rmodp (p * (rmodp q d)) d = rmodp (p * q) d. Proof. have -> : rmodp q d = q - (rdivp q d) * d. by rewrite {2}(rdivp_eq q) addrAC subrr add0r. rewrite mulrDr rmodp_add -mulNr mulrA. rewrite -{2}[rmodp _ _]addr0; congr (_ + _); exact: rmodp_mull. Qed. Lemma rdvdpp : rdvdp d d. Proof. apply: rdvdpp; rewrite (eqP mond); [exact: commr1 | exact: rreg1]. Qed. (* section variables impose an inconvenient order on parameters *) Lemma eq_rdvdp q1 p : p = q1 * d -> rdvdp d p. Proof. (* this probably means I need to specify impl args for comm_rref_rdvdp *) move=> h; apply: (@eq_rdvdp _ _ _ _ 1%N q1); rewrite (eqP mond). - exact: commr1. - exact: rreg1. by rewrite expr1n mulr1. Qed. Lemma rdvdp_mull p : rdvdp d (p * d). Proof. apply: rdvdp_mull; rewrite (eqP mond) //; [exact: commr1 | exact: rreg1]. Qed. Lemma rdvdpP p : reflect (exists qq, p = qq * d) (rdvdp d p). Proof. case: (monic_comreg mond)=> Hc Hr; apply: (iffP idP). case: rdvdp_eqP=> // k qq; rewrite (eqP mond) expr1n mulr1; move=> -> _. by exists qq. by case=> [qq]; move/eq_rdvdp. Qed. Lemma rdivpK p : rdvdp d p -> (rdivp p d) * d = p. Proof. by move=> dvddp; rewrite {2}[p]rdivp_eq rmodp_eq0 ?addr0. Qed. End MonicDivisor. End RingMonic. Module Ring. Include CommonRing. Import RingMonic. Section ExtraMonicDivisor. Variable R : ringType. Implicit Types d p q r : {poly R}. Lemma rdivp1 p : rdivp p 1 = p. Proof. by rewrite -{1}(mulr1 p) rdivp_mull // monic1. Qed. Lemma rdvdp_XsubCl p x : rdvdp ('X - x%:P) p = root p x. Proof. have [HcX Hr] := (monic_comreg (monicXsubC x)). apply/rmodp_eq0P/factor_theorem; last first. case=> p1 ->; apply: rmodp_mull; exact: monicXsubC. move=> e0; exists (rdivp p ('X - x%:P)). by rewrite {1}(rdivp_eq (monicXsubC x) p) e0 addr0. Qed. Lemma polyXsubCP p x : reflect (p.[x] = 0) (rdvdp ('X - x%:P) p). Proof. by apply: (iffP idP); rewrite rdvdp_XsubCl; move/rootP. Qed. Lemma root_factor_theorem p x : root p x = (rdvdp ('X - x%:P) p). Proof. by rewrite rdvdp_XsubCl. Qed. End ExtraMonicDivisor. End Ring. Module ComRing. Import Ring. Import RingComRreg. Section CommutativeRingPseudoDivision. Variable R : comRingType. Implicit Types d p q m n r : {poly R}. CoInductive redivp_spec (m d : {poly R}) : nat * {poly R} * {poly R} -> Type := EdivnSpec k (q r: {poly R}) of (lead_coef d ^+ k) *: m = q * d + r & (d != 0 -> size r < size d) : redivp_spec m d (k, q, r). Lemma redivpP m d : redivp_spec m d (redivp m d). Proof. rewrite redivp_def; constructor; last by move=> dn0; rewrite ltn_rmodp. by rewrite -mul_polyC mulrC rdivp_eq //= /GRing.comm mulrC. Qed. Lemma rdivp_eq d p : (lead_coef d ^+ (rscalp p d)) *: p = (rdivp p d) * d + (rmodp p d). Proof. rewrite /rdivp /rmodp /rscalp; case: redivpP=> k q1 r1 Hc _; exact: Hc. Qed. Lemma rdvdp_eqP d p : rdvdp_spec p d (rmodp p d) (rdvdp d p). Proof. case hdvd: (rdvdp d p); last by apply: RdvdpN; move/rmodp_eq0P/eqP: hdvd. move/rmodp_eq0P: (hdvd)->; apply: (@Rdvdp _ _ _ (rscalp p d) (rdivp p d)). by rewrite mulrC mul_polyC rdivp_eq; move/rmodp_eq0P: (hdvd)->; rewrite addr0. Qed. Lemma rdvdp_eq q p : (rdvdp q p) = ((lead_coef q) ^+ (rscalp p q) *: p == (rdivp p q) * q). apply/rmodp_eq0P/eqP; rewrite rdivp_eq; first by move->; rewrite addr0. by move/eqP; rewrite eq_sym addrC -subr_eq subrr; move/eqP->. Qed. End CommutativeRingPseudoDivision. End ComRing. Module UnitRing. Import Ring. Section UnitRingPseudoDivision. Variable R : unitRingType. Implicit Type p q r d : {poly R}. Lemma uniq_roots_rdvdp p rs : all (root p) rs -> uniq_roots rs -> rdvdp (\prod_(z <- rs) ('X - z%:P)) p. Proof. move=> rrs; case/(uniq_roots_prod_XsubC rrs)=> q ->; apply: RingMonic.rdvdp_mull. exact: monic_prod_XsubC. Qed. End UnitRingPseudoDivision. End UnitRing. Module IdomainDefs. Import Ring. Section IDomainPseudoDivisionDefs. Variable R : idomainType. Implicit Type p q r d : {poly R}. Definition edivp_expanded_def p q := let: (k, d, r) as edvpq := redivp p q in if lead_coef q \in GRing.unit then (0%N, (lead_coef q)^-k *: d, (lead_coef q)^-k *: r) else edvpq. Fact edivp_key : unit. Proof. by []. Qed. Definition edivp := locked_with edivp_key edivp_expanded_def. Canonical edivp_unlockable := [unlockable fun edivp]. Definition divp p q := ((edivp p q).1).2. Definition modp p q := (edivp p q).2. Definition scalp p q := ((edivp p q).1).1. Definition dvdp p q := modp q p == 0. Definition eqp p q := (dvdp p q) && (dvdp q p). End IDomainPseudoDivisionDefs. Notation "m %/ d" := (divp m d) : ring_scope. Notation "m %% d" := (modp m d) : ring_scope. Notation "p %| q" := (dvdp p q) : ring_scope. Notation "p %= q" := (eqp p q) : ring_scope. End IdomainDefs. Module WeakIdomain. Import Ring ComRing UnitRing IdomainDefs. Section WeakTheoryForIDomainPseudoDivision. Variable R : idomainType. Implicit Type p q r d : {poly R}. Lemma edivp_def p q : edivp p q = (scalp p q, divp p q, modp p q). Proof. by rewrite /scalp /divp /modp; case: (edivp p q) => [[]] /=. Qed. Lemma edivp_redivp p q : (lead_coef q \in GRing.unit) = false -> edivp p q = redivp p q. Proof. by move=> hu; rewrite unlock hu; case: (redivp p q) => [[? ?] ?]. Qed. Lemma divpE p q : p %/ q = if lead_coef q \in GRing.unit then (lead_coef q)^-(rscalp p q) *: (rdivp p q) else rdivp p q. Proof. by case ulcq: (lead_coef q \in GRing.unit); rewrite /divp unlock redivp_def ulcq. Qed. Lemma modpE p q : p %% q = if lead_coef q \in GRing.unit then (lead_coef q)^-(rscalp p q) *: (rmodp p q) else rmodp p q. Proof. by case ulcq: (lead_coef q \in GRing.unit); rewrite /modp unlock redivp_def ulcq. Qed. Lemma scalpE p q : scalp p q = if lead_coef q \in GRing.unit then 0%N else rscalp p q. Proof. by case h: (lead_coef q \in GRing.unit); rewrite /scalp unlock redivp_def h. Qed. Lemma dvdpE p q : p %| q = rdvdp p q. Proof. rewrite /dvdp modpE /rdvdp; case ulcq: (lead_coef p \in GRing.unit)=> //. rewrite -[_ *: _ == 0]size_poly_eq0 size_scale ?size_poly_eq0 //. by rewrite invr_eq0 expf_neq0 //; apply: contraTneq ulcq => ->; rewrite unitr0. Qed. Lemma lc_expn_scalp_neq0 p q : lead_coef q ^+ scalp p q != 0. Proof. case: (eqVneq q 0) => [->|nzq]; last by rewrite expf_neq0 ?lead_coef_eq0. by rewrite /scalp 2!unlock /= eqxx lead_coef0 unitr0 /= oner_neq0. Qed. Hint Resolve lc_expn_scalp_neq0. CoInductive edivp_spec (m d : {poly R}) : nat * {poly R} * {poly R} -> bool -> Type := |Redivp_spec k (q r: {poly R}) of (lead_coef d ^+ k) *: m = q * d + r & lead_coef d \notin GRing.unit & (d != 0 -> size r < size d) : edivp_spec m d (k, q, r) false |Fedivp_spec (q r: {poly R}) of m = q * d + r & (lead_coef d \in GRing.unit) & (d != 0 -> size r < size d) : edivp_spec m d (0%N, q, r) true. (* There are several ways to state this fact. The most appropriate statement*) (* might be polished in light of usage. *) Lemma edivpP m d : edivp_spec m d (edivp m d) (lead_coef d \in GRing.unit). Proof. have hC : GRing.comm d (lead_coef d)%:P by rewrite /GRing.comm mulrC. case ud: (lead_coef d \in GRing.unit); last first. rewrite edivp_redivp // redivp_def; constructor; rewrite ?ltn_rmodp // ?ud //. by rewrite rdivp_eq. have cdn0: lead_coef d != 0 by apply: contraTneq ud => ->; rewrite unitr0. rewrite unlock ud redivp_def; constructor => //. rewrite -scalerAl -scalerDr -mul_polyC. have hn0 : (lead_coef d ^+ rscalp m d)%:P != 0. by rewrite polyC_eq0; apply: expf_neq0. apply: (mulfI hn0); rewrite !mulrA -exprVn !polyC_exp -exprMn -polyC_mul. by rewrite divrr // expr1n mul1r -polyC_exp mul_polyC rdivp_eq. move=> dn0; rewrite size_scale ?ltn_rmodp // -exprVn expf_eq0 negb_and. by rewrite invr_eq0 cdn0 orbT. Qed. Lemma edivp_eq d q r : size r < size d -> lead_coef d \in GRing.unit -> edivp (q * d + r) d = (0%N, q, r). Proof. have hC : GRing.comm d (lead_coef d)%:P by exact: mulrC. move=> hsrd hu; rewrite unlock hu; case et: (redivp _ _) => [[s qq] rr]. have cdn0 : lead_coef d != 0. by move: hu; case d0: (lead_coef d == 0) => //; rewrite (eqP d0) unitr0. move: (et); rewrite RingComRreg.redivp_eq //; last by apply/rregP. rewrite et /=; case => e1 e2; rewrite -!mul_polyC -!exprVn !polyC_exp. suff h x y: x * (lead_coef d ^+ s)%:P = y -> ((lead_coef d)^-1)%:P ^+ s * y = x. by congr (_, _, _); apply: h. have hn0 : (lead_coef d)%:P ^+ s != 0 by apply: expf_neq0; rewrite polyC_eq0. move=> hh; apply: (mulfI hn0); rewrite mulrA -exprMn -polyC_mul divrr //. by rewrite expr1n mul1r -polyC_exp mulrC; apply: sym_eq. Qed. Lemma divp_eq p q : (lead_coef q ^+ (scalp p q)) *: p = (p %/ q) * q + (p %% q). Proof. rewrite divpE modpE scalpE. case uq: (lead_coef q \in GRing.unit); last by rewrite rdivp_eq. rewrite expr0 scale1r; case: (altP (q =P 0)) => [-> | qn0]. rewrite mulr0 add0r lead_coef0 rmodp0 /rscalp unlock eqxx expr0 invr1. by rewrite scale1r. have hn0 : (lead_coef q ^+ rscalp p q)%:P != 0. by rewrite polyC_eq0 expf_neq0 // lead_coef_eq0. apply: (mulfI hn0). rewrite -scalerAl -scalerDr !mul_polyC scalerA mulrV ?unitrX //. by rewrite scale1r rdivp_eq. Qed. Lemma dvdp_eq q p : (q %| p) = ((lead_coef q) ^+ (scalp p q) *: p == (p %/ q) * q). Proof. rewrite dvdpE rdvdp_eq scalpE divpE; case: ifP => ulcq //. rewrite expr0 scale1r; apply/eqP/eqP. by rewrite -scalerAl; move<-; rewrite scalerA mulVr ?scale1r // unitrX. by move=> {2}->; rewrite scalerAl scalerA mulrV ?scale1r // unitrX. Qed. Lemma divpK d p : d %| p -> p %/ d * d = ((lead_coef d) ^+ (scalp p d)) *: p. Proof. by rewrite dvdp_eq; move/eqP->. Qed. Lemma divpKC d p : d %| p -> d * (p %/ d) = ((lead_coef d) ^+ (scalp p d)) *: p. Proof. by move=> ?; rewrite mulrC divpK. Qed. Lemma dvdpP q p : reflect (exists2 cqq, cqq.1 != 0 & cqq.1 *: p = cqq.2 * q) (q %| p). Proof. rewrite dvdp_eq; apply: (iffP eqP) => [e | [[c qq] cn0 e]]. by exists (lead_coef q ^+ scalp p q, p %/ q) => //=. apply/eqP; rewrite -dvdp_eq dvdpE. have Ecc: c%:P != 0 by rewrite polyC_eq0. case: (eqVneq p 0) => [->|nz_p]; first by rewrite rdvdp0. pose p1 : {poly R} := lead_coef q ^+ rscalp p q *: qq - c *: (rdivp p q). have E1: c *: (rmodp p q) = p1 * q. rewrite mulrDl {1}mulNr -scalerAl -e scalerA mulrC -scalerA -scalerAl. by rewrite -scalerBr rdivp_eq addrC addKr. rewrite /dvdp; apply/idPn=> m_nz. have: p1 * q != 0 by rewrite -E1 -mul_polyC mulf_neq0 // -/(dvdp q p) dvdpE. rewrite mulf_eq0; case/norP=> p1_nz q_nz; have:= ltn_rmodp p q. rewrite q_nz -(size_scale _ cn0) E1 size_mul //. by rewrite polySpred // ltnNge leq_addl. Qed. Lemma mulpK p q : q != 0 -> p * q %/ q = lead_coef q ^+ scalp (p * q) q *: p. Proof. move=> qn0; move/rregP: (qn0); apply; rewrite -scalerAl divp_eq. suff -> : (p * q) %% q = 0 by rewrite addr0. rewrite modpE RingComRreg.rmodp_mull ?scaler0 ?if_same //. by red; rewrite mulrC. by apply/rregP; rewrite lead_coef_eq0. Qed. Lemma mulKp p q : q != 0 -> q * p %/ q = lead_coef q ^+ scalp (p * q) q *: p. Proof. move=> ?; rewrite mulrC; exact: mulpK. Qed. Lemma divpp p : p != 0 -> p %/ p = (lead_coef p ^+ scalp p p)%:P. Proof. move=> np0; have := (divp_eq p p). suff -> : p %% p = 0. by rewrite addr0; move/eqP; rewrite -mul_polyC (inj_eq (mulIf np0)); move/eqP. rewrite modpE Ring.rmodpp; last by red; rewrite mulrC. by rewrite scaler0 if_same. Qed. End WeakTheoryForIDomainPseudoDivision. Hint Resolve lc_expn_scalp_neq0. End WeakIdomain. Module CommonIdomain. Import Ring ComRing UnitRing IdomainDefs WeakIdomain. Section IDomainPseudoDivision. Variable R : idomainType. Implicit Type p q r d m n : {poly R}. Lemma scalp0 p : scalp p 0 = 0%N. Proof. by rewrite /scalp unlock lead_coef0 unitr0 unlock eqxx. Qed. Lemma divp_small p q : size p < size q -> p %/ q = 0. Proof. move=> spq; rewrite /divp unlock redivp_def /=. by case: ifP; rewrite rdivp_small // scaler0. Qed. Lemma leq_divp p q : (size (p %/ q) <= size p). Proof. rewrite /divp unlock redivp_def /=; case: ifP=> /=; rewrite ?leq_rdivp //. move=> ulcq; rewrite size_scale ?leq_rdivp //. rewrite -exprVn expf_neq0 // invr_eq0. by move: ulcq; case lcq0: (lead_coef q == 0) => //; rewrite (eqP lcq0) unitr0. Qed. Lemma div0p p : 0 %/ p = 0. Proof. by rewrite /divp unlock redivp_def /=; case: ifP; rewrite rdiv0p // scaler0. Qed. Lemma divp0 p : p %/ 0 = 0. Proof. by rewrite /divp unlock redivp_def /=; case: ifP; rewrite rdivp0 // scaler0. Qed. Lemma divp1 m : m %/ 1 = m. Proof. by rewrite divpE lead_coefC unitr1 Ring.rdivp1 expr1n invr1 scale1r. Qed. Lemma modp0 p : p %% 0 = p. Proof. rewrite /modp unlock redivp_def; case: ifP; rewrite rmodp0 //= lead_coef0. by rewrite unitr0. Qed. Lemma mod0p p : 0 %% p = 0. Proof. by rewrite /modp unlock redivp_def /=; case: ifP; rewrite rmod0p // scaler0. Qed. Lemma modp1 p : p %% 1 = 0. Proof. by rewrite /modp unlock redivp_def /=; case: ifP; rewrite rmodp1 // scaler0. Qed. Hint Resolve divp0 divp1 mod0p modp0 modp1. Lemma modp_small p q : size p < size q -> p %% q = p. Proof. move=> spq; rewrite /modp unlock redivp_def; case: ifP; rewrite rmodp_small //. by rewrite /= rscalp_small // expr0 /= invr1 scale1r. Qed. Lemma modpC p c : c != 0 -> p %% c%:P = 0. Proof. move=> cn0; rewrite /modp unlock redivp_def /=; case: ifP; rewrite ?rmodpC //. by rewrite scaler0. Qed. Lemma modp_mull p q : (p * q) %% q = 0. Proof. case: (altP (q =P 0)) => [-> | nq0]; first by rewrite modp0 mulr0. have rlcq : (GRing.rreg (lead_coef q)) by apply/rregP; rewrite lead_coef_eq0. have hC : GRing.comm q (lead_coef q)%:P by red; rewrite mulrC. by rewrite modpE; case: ifP => ulcq; rewrite RingComRreg.rmodp_mull // scaler0. Qed. Lemma modp_mulr d p : (d * p) %% d = 0. Proof. by rewrite mulrC modp_mull. Qed. Lemma modpp d : d %% d = 0. Proof. by rewrite -{1}(mul1r d) modp_mull. Qed. Lemma ltn_modp p q : (size (p %% q) < size q) = (q != 0). Proof. rewrite /modp unlock redivp_def /=; case: ifP=> /=; rewrite ?ltn_rmodp //. move=> ulcq; rewrite size_scale ?ltn_rmodp //. rewrite -exprVn expf_neq0 // invr_eq0. by move: ulcq; case lcq0: (lead_coef q == 0) => //; rewrite (eqP lcq0) unitr0. Qed. Lemma ltn_divpl d q p : d != 0 -> (size (q %/ d) < size p) = (size q < size (p * d)). Proof. move=> dn0; have sd : size d > 0 by rewrite size_poly_gt0 dn0. have: (lead_coef d) ^+ (scalp q d) != 0 by exact: lc_expn_scalp_neq0. move/size_scale; move/(_ q)<-; rewrite divp_eq; case quo0 : (q %/ d == 0). rewrite (eqP quo0) mul0r add0r size_poly0. case p0 : (p == 0); first by rewrite (eqP p0) mul0r size_poly0 ltnn ltn0. have sp : size p > 0 by rewrite size_poly_gt0 p0. rewrite /= size_mul ?p0 // sp; apply: sym_eq; move/prednK:(sp)<-. by rewrite addSn /= ltn_addl // ltn_modp. rewrite size_addl; last first. rewrite size_mul ?quo0 //; move/negbT: quo0; rewrite -size_poly_gt0. by move/prednK<-; rewrite addSn /= ltn_addl // ltn_modp. case: (altP (p =P 0)) => [-> | pn0]; first by rewrite mul0r size_poly0 !ltn0. by rewrite !size_mul ?quo0 //; move/prednK: sd<-; rewrite !addnS ltn_add2r. Qed. Lemma leq_divpr d p q : d != 0 -> (size p <= size (q %/ d)) = (size (p * d) <= size q). Proof. by move=> dn0; rewrite leqNgt ltn_divpl // -leqNgt. Qed. Lemma divpN0 d p : d != 0 -> (p %/ d != 0) = (size d <= size p). Proof. move=> dn0; rewrite -{2}(mul1r d) -leq_divpr // size_polyC oner_eq0 /=. by rewrite size_poly_gt0. Qed. Lemma size_divp p q : q != 0 -> size (p %/ q) = ((size p) - (size q).-1)%N. Proof. move=> nq0; case: (leqP (size q) (size p)) => sqp; last first. move: (sqp); rewrite -{1}(ltn_predK sqp) ltnS -subn_eq0 divp_small //. by move/eqP->; rewrite size_poly0. move: (nq0); rewrite -size_poly_gt0 => lt0sq. move: (sqp); move/(leq_trans lt0sq) => lt0sp. move: (lt0sp); rewrite size_poly_gt0=> p0. move: (divp_eq p q); move/(congr1 (size \o (@polyseq R)))=> /=. rewrite size_scale; last by rewrite expf_eq0 lead_coef_eq0 (negPf nq0) andbF. case: (eqVneq (p %/ q) 0) => [-> | qq0]. by rewrite mul0r add0r=> es; move: nq0; rewrite -(ltn_modp p) -es ltnNge sqp. move/negP:(qq0); move/negP; rewrite -size_poly_gt0 => lt0qq. rewrite size_addl. rewrite size_mul ?qq0 // => ->. apply/eqP; rewrite -(eqn_add2r ((size q).-1)). rewrite subnK; first by rewrite -subn1 addnBA // subn1. rewrite /leq -(subnDl 1%N) !add1n prednK // (@ltn_predK (size q)) //. by rewrite addnC subnDA subnn sub0n. by rewrite -[size q]add0n ltn_add2r. rewrite size_mul ?qq0 //. move: nq0; rewrite -(ltn_modp p); move/leq_trans; apply; move/prednK: lt0qq<-. by rewrite addSn /= leq_addl. Qed. Lemma ltn_modpN0 p q : q != 0 -> size (p %% q) < size q. Proof. by rewrite ltn_modp. Qed. Lemma modp_mod p q : (p %% q) %% q = p %% q. Proof. by case: (eqVneq q 0) => [-> | qn0]; rewrite ?modp0 // modp_small ?ltn_modp. Qed. Lemma leq_modp m d : size (m %% d) <= size m. Proof. rewrite /modp unlock redivp_def /=; case: ifP; rewrite ?leq_rmodp //. move=> ud; rewrite size_scale ?leq_rmodp // invr_eq0 expf_neq0 //. by apply: contraTneq ud => ->; rewrite unitr0. Qed. Lemma dvdp0 d : d %| 0. Proof. by rewrite /dvdp mod0p. Qed. Hint Resolve dvdp0. Lemma dvd0p p : (0 %| p) = (p == 0). Proof. by rewrite /dvdp modp0. Qed. Lemma dvd0pP p : reflect (p = 0) (0 %| p). Proof. by apply: (iffP idP); rewrite dvd0p; move/eqP. Qed. Lemma dvdpN0 p q : p %| q -> q != 0 -> p != 0. Proof. by move=> pq hq; apply: contraL pq=> /eqP ->; rewrite dvd0p. Qed. Lemma dvdp1 d : (d %| 1) = ((size d) == 1%N). Proof. rewrite /dvdp modpE; case ud: (lead_coef d \in GRing.unit); last exact: rdvdp1. rewrite -size_poly_eq0 size_scale; first by rewrite size_poly_eq0; exact: rdvdp1. by rewrite invr_eq0 expf_neq0 //; apply: contraTneq ud => ->; rewrite unitr0. Qed. Lemma dvd1p m : 1 %| m. Proof. by rewrite /dvdp modp1. Qed. Lemma gtNdvdp p q : p != 0 -> size p < size q -> (q %| p) = false. Proof. by move=> nn0 hs; rewrite /dvdp; rewrite (modp_small hs); apply: negPf. Qed. Lemma modp_eq0P p q : reflect (p %% q = 0) (q %| p). Proof. exact: (iffP eqP). Qed. Lemma modp_eq0 p q : (q %| p) -> p %% q = 0. Proof. by move/modp_eq0P. Qed. Lemma leq_divpl d p q : d %| p -> (size (p %/ d) <= size q) = (size p <= size (q * d)). Proof. case: (eqVneq d 0) => [-> | nd0]. by move/dvd0pP->; rewrite divp0 size_poly0 !leq0n. move=> hd; rewrite leq_eqVlt ltn_divpl // (leq_eqVlt (size p)). case lhs: (size p < size (q * d)); rewrite ?orbT ?orbF //. have: (lead_coef d) ^+ (scalp p d) != 0 by rewrite expf_neq0 // lead_coef_eq0. move/size_scale; move/(_ p)<-; rewrite divp_eq. move/modp_eq0P: hd->; rewrite addr0; case: (altP (p %/ d =P 0))=> [-> | quon0]. rewrite mul0r size_poly0 eq_sym (eq_sym 0%N) size_poly_eq0. case: (altP (q =P 0)) => [-> | nq0]; first by rewrite mul0r size_poly0 eqxx. by rewrite size_poly_eq0 mulf_eq0 (negPf nq0) (negPf nd0). case: (altP (q =P 0)) => [-> | nq0]. by rewrite mul0r size_poly0 !size_poly_eq0 mulf_eq0 (negPf nd0) orbF. rewrite !size_mul //; move: nd0; rewrite -size_poly_gt0; move/prednK<-. by rewrite !addnS /= eqn_add2r. Qed. Lemma dvdp_leq p q : q != 0 -> p %| q -> size p <= size q. move=> nq0 /modp_eq0P => rpq; case: (ltnP (size p) (size q)). by move/ltnW->. rewrite leq_eqVlt; case/orP; first by move/eqP->. by move/modp_small; rewrite rpq => h; move: nq0; rewrite h eqxx. Qed. Lemma eq_dvdp c quo q p : c != 0 -> c *: p = quo * q -> q %| p. Proof. move=> cn0; case: (eqVneq p 0) => [->|nz_quo def_quo] //. pose p1 : {poly R} := lead_coef q ^+ scalp p q *: quo - c *: (p %/ q). have E1: c *: (p %% q) = p1 * q. rewrite mulrDl {1}mulNr-scalerAl -def_quo scalerA mulrC -scalerA. by rewrite -scalerAl -scalerBr divp_eq addrAC subrr add0r. rewrite /dvdp; apply/idPn=> m_nz. have: p1 * q != 0 by rewrite -E1 -mul_polyC mulf_neq0 // polyC_eq0. rewrite mulf_eq0; case/norP=> p1_nz q_nz. have := (ltn_modp p q); rewrite q_nz -(size_scale (p %% q) cn0) E1. by rewrite size_mul // polySpred // ltnNge leq_addl. Qed. Lemma dvdpp d : d %| d. Proof. by rewrite /dvdp modpp. Qed. Hint Resolve dvdpp. Lemma divp_dvd p q : (p %| q) -> ((q %/ p) %| q). Proof. case: (eqVneq p 0) => [-> | np0]; first by rewrite divp0. rewrite dvdp_eq => /eqP h. apply: (@eq_dvdp ((lead_coef p)^+ (scalp q p)) p); last by rewrite mulrC. by rewrite expf_neq0 // lead_coef_eq0. Qed. Lemma dvdp_mull m d n : d %| n -> d %| m * n. Proof. case: (eqVneq d 0) => [-> |dn0]; first by move/dvd0pP->; rewrite mulr0 dvdpp. rewrite dvdp_eq => /eqP e. apply: (@eq_dvdp (lead_coef d ^+ scalp n d) (m * (n %/ d))). by rewrite expf_neq0 // lead_coef_eq0. by rewrite scalerAr e mulrA. Qed. Lemma dvdp_mulr n d m : d %| m -> d %| m * n. Proof. by move=> hdm; rewrite mulrC dvdp_mull. Qed. Hint Resolve dvdp_mull dvdp_mulr. Lemma dvdp_mul d1 d2 m1 m2 : d1 %| m1 -> d2 %| m2 -> d1 * d2 %| m1 * m2. Proof. case: (eqVneq d1 0) => [-> |d1n0]; first by move/dvd0pP->; rewrite !mul0r dvdpp. case: (eqVneq d2 0) => [-> |d2n0]; first by move => _ /dvd0pP ->; rewrite !mulr0. rewrite dvdp_eq; set c1 := _ ^+ _; set q1 := _ %/ _; move/eqP=> Hq1. rewrite dvdp_eq; set c2 := _ ^+ _; set q2 := _ %/ _; move/eqP=> Hq2. apply: (@eq_dvdp (c1 * c2) (q1 * q2)). by rewrite mulf_neq0 // expf_neq0 // lead_coef_eq0. rewrite -scalerA scalerAr scalerAl Hq1 Hq2 -!mulrA. by rewrite [d1 * (q2 * _)]mulrCA. Qed. Lemma dvdp_addr m d n : d %| m -> (d %| m + n) = (d %| n). Proof. case: (altP (d =P 0)) => [-> | dn0]; first by move/dvd0pP->; rewrite add0r. rewrite dvdp_eq; set c1 := _ ^+ _; set q1 := _ %/ _; move/eqP=> Eq1. apply/idP/idP; rewrite dvdp_eq; set c2 := _ ^+ _; set q2 := _ %/ _. have sn0 : c1 * c2 != 0. by rewrite !mulf_neq0 // expf_eq0 lead_coef_eq0 (negPf dn0) andbF. move/eqP=> Eq2; apply: (@eq_dvdp _ (c1 *: q2 - c2 *: q1) _ _ sn0). rewrite mulrDl -scaleNr -!scalerAl -Eq1 -Eq2 !scalerA. by rewrite mulNr mulrC scaleNr -scalerBr addrC addKr. have sn0 : c1 * c2 != 0. by rewrite !mulf_neq0 // expf_eq0 lead_coef_eq0 (negPf dn0) andbF. move/eqP=> Eq2; apply: (@eq_dvdp _ (c1 *: q2 + c2 *: q1) _ _ sn0). by rewrite mulrDl -!scalerAl -Eq1 -Eq2 !scalerA mulrC addrC scalerDr. Qed. Lemma dvdp_addl n d m : d %| n -> (d %| m + n) = (d %| m). Proof. by rewrite addrC; exact: dvdp_addr. Qed. Lemma dvdp_add d m n : d %| m -> d %| n -> d %| m + n. Proof. by move/dvdp_addr->. Qed. Lemma dvdp_add_eq d m n : d %| m + n -> (d %| m) = (d %| n). Proof. by move=> ?; apply/idP/idP; [move/dvdp_addr <-| move/dvdp_addl <-]. Qed. Lemma dvdp_subr d m n : d %| m -> (d %| m - n) = (d %| n). Proof. by move=> ?; apply dvdp_add_eq; rewrite -addrA addNr simp. Qed. Lemma dvdp_subl d m n : d %| n -> (d %| m - n) = (d %| m). Proof. by move/dvdp_addl<-; rewrite subrK. Qed. Lemma dvdp_sub d m n : d %| m -> d %| n -> d %| m - n. Proof. by move=> *; rewrite dvdp_subl. Qed. Lemma dvdp_mod d n m : d %| n -> (d %| m) = (d %| m %% n). Proof. case: (altP (n =P 0)) => [-> | nn0]; first by rewrite modp0. case: (altP (d =P 0)) => [-> | dn0]; first by move/dvd0pP->; rewrite modp0. rewrite dvdp_eq; set c1 := _ ^+ _; set q1 := _ %/ _; move/eqP=> Eq1. apply/idP/idP; rewrite dvdp_eq; set c2 := _ ^+ _; set q2 := _ %/ _. have sn0 : c1 * c2 != 0. by rewrite !mulf_neq0 // expf_eq0 lead_coef_eq0 (negPf dn0) andbF. pose quo := (c1 * lead_coef n ^+ scalp m n) *: q2 - c2 *: (m %/ n) * q1. move/eqP=> Eq2; apply: (@eq_dvdp _ quo _ _ sn0). rewrite mulrDl mulNr -!scalerAl -!mulrA -Eq1 -Eq2 -scalerAr !scalerA. rewrite mulrC [_ * c2]mulrC mulrA -[((_ * _) * _) *: _]scalerA -scalerBr. by rewrite divp_eq addrC addKr. have sn0 : c1 * c2 * lead_coef n ^+ scalp m n != 0. rewrite !mulf_neq0 // expf_eq0 lead_coef_eq0 ?(negPf dn0) ?andbF //. by rewrite (negPf nn0) andbF. move/eqP=> Eq2; apply: (@eq_dvdp _ (c2 *: (m %/ n) * q1 + c1 *: q2) _ _ sn0). rewrite -scalerA divp_eq scalerDr -!scalerA Eq2 scalerAl scalerAr Eq1. by rewrite scalerAl mulrDl mulrA. Qed. Lemma dvdp_trans : transitive (@dvdp R). Proof. move=> n d m. case: (altP (d =P 0)) => [-> | dn0]; first by move/dvd0pP->. case: (altP (n =P 0)) => [-> | nn0]; first by move=> _ /dvd0pP ->. rewrite dvdp_eq; set c1 := _ ^+ _; set q1 := _ %/ _; move/eqP=> Hq1. rewrite dvdp_eq; set c2 := _ ^+ _; set q2 := _ %/ _; move/eqP=> Hq2. have sn0 : c1 * c2 != 0 by rewrite mulf_neq0 // expf_neq0 // lead_coef_eq0. by apply: (@eq_dvdp _ (q2 * q1) _ _ sn0); rewrite -scalerA Hq2 scalerAr Hq1 mulrA. Qed. Lemma dvdp_mulIl p q : p %| p * q. Proof. by apply: dvdp_mulr; exact: dvdpp. Qed. Lemma dvdp_mulIr p q : q %| p * q. Proof. by apply: dvdp_mull; exact: dvdpp. Qed. Lemma dvdp_mul2r r p q : r != 0 -> (p * r %| q * r) = (p %| q). Proof. move => nzr. case: (eqVneq p 0) => [-> | pn0]. by rewrite mul0r !dvd0p mulf_eq0 (negPf nzr) orbF. case: (eqVneq q 0) => [-> | qn0]; first by rewrite mul0r !dvdp0. apply/idP/idP; last by move => ?; rewrite dvdp_mul ?dvdpp. rewrite dvdp_eq; set c := _ ^+ _; set x := _ %/ _; move/eqP=> Hx. apply: (@eq_dvdp c x). by rewrite expf_neq0 // lead_coef_eq0 mulf_neq0. by apply: (GRing.mulIf nzr); rewrite -GRing.mulrA -GRing.scalerAl. Qed. Lemma dvdp_mul2l r p q: r != 0 -> (r * p %| r * q) = (p %| q). Proof. by rewrite ![r * _]GRing.mulrC; apply: dvdp_mul2r. Qed. Lemma ltn_divpr d p q : d %| q -> (size p < size (q %/ d)) = (size (p * d) < size q). Proof. by move=> dv_d_q; rewrite !ltnNge leq_divpl. Qed. Lemma dvdp_exp d k p : 0 < k -> d %| p -> d %| (p ^+ k). Proof. by case: k => // k _ d_dv_m; rewrite exprS dvdp_mulr. Qed. Lemma dvdp_exp2l d k l : k <= l -> d ^+ k %| d ^+ l. Proof. by move/subnK <-; rewrite exprD dvdp_mull // ?lead_coef_exp ?unitrX. Qed. Lemma dvdp_Pexp2l d k l : 1 < size d -> (d ^+ k %| d ^+ l) = (k <= l). Proof. move=> sd; case: leqP => [|gt_n_m]; first exact: dvdp_exp2l. have dn0 : d != 0 by rewrite -size_poly_gt0; apply: ltn_trans sd. rewrite gtNdvdp ?expf_neq0 // polySpred ?expf_neq0 // size_exp /=. rewrite [size (d ^+ k)]polySpred ?expf_neq0 // size_exp ltnS ltn_mul2l. by move: sd; rewrite -subn_gt0 subn1; move->. Qed. Lemma dvdp_exp2r p q k : p %| q -> p ^+ k %| q ^+ k. Proof. case: (eqVneq p 0) => [-> | pn0]; first by move/dvd0pP->. rewrite dvdp_eq; set c := _ ^+ _; set t := _ %/ _; move/eqP=> e. apply: (@eq_dvdp (c ^+ k) (t ^+ k)); first by rewrite !expf_neq0 ?lead_coef_eq0. by rewrite -exprMn -exprZn; congr (_ ^+ k). Qed. Lemma dvdp_exp_sub p q k l: p != 0 -> (p ^+ k %| q * p ^+ l) = (p ^+ (k - l) %| q). Proof. move=> pn0; case: (leqP k l)=> hkl. move:(hkl); rewrite -subn_eq0; move/eqP->; rewrite expr0 dvd1p. apply: dvdp_mull; case: (ltnP 1%N (size p)) => sp. by rewrite dvdp_Pexp2l. move: sp; case esp: (size p) => [|sp]. by move/eqP: esp; rewrite size_poly_eq0 (negPf pn0). rewrite ltnS leqn0; move/eqP=> sp0; move/eqP: esp; rewrite sp0. by case/size_poly1P => c cn0 ->; move/subnK: hkl<-; rewrite exprD dvdp_mulIr. rewrite -{1}[k](@subnK l) 1?ltnW// exprD dvdp_mul2r//. elim: l {hkl}=> [|l ihl]; first by rewrite expr0 oner_eq0. by rewrite exprS mulf_neq0. Qed. Lemma dvdp_XsubCl p x : ('X - x%:P) %| p = root p x. Proof. rewrite dvdpE; exact: Ring.rdvdp_XsubCl. Qed. Lemma polyXsubCP p x : reflect (p.[x] = 0) (('X - x%:P) %| p). Proof. rewrite dvdpE; exact: Ring.polyXsubCP. Qed. Lemma eqp_div_XsubC p c : (p == (p %/ ('X - c%:P)) * ('X - c%:P)) = ('X - c%:P %| p). Proof. by rewrite dvdp_eq lead_coefXsubC expr1n scale1r. Qed. Lemma root_factor_theorem p x : root p x = (('X - x%:P) %| p). Proof. by rewrite dvdp_XsubCl. Qed. Lemma uniq_roots_dvdp p rs : all (root p) rs -> uniq_roots rs -> (\prod_(z <- rs) ('X - z%:P)) %| p. Proof. move=> rrs; case/(uniq_roots_prod_XsubC rrs)=> q ->. by apply: dvdp_mull; rewrite // (eqP (monic_prod_XsubC _)) unitr1. Qed. Lemma root_bigmul : forall x (ps : seq {poly R}), ~~root (\big[*%R/1]_(p <- ps) p) x = all (fun p => ~~ root p x) ps. Proof. move=> x; elim; first by rewrite big_nil root1. by move=> p ps ihp; rewrite big_cons /= rootM negb_or ihp. Qed. Lemma eqpP m n : reflect (exists2 c12, (c12.1 != 0) && (c12.2 != 0) & c12.1 *: m = c12.2 *: n) (m %= n). Proof. apply: (iffP idP) => [| [[c1 c2]/andP[nz_c1 nz_c2 eq_cmn]]]; last first. rewrite /eqp (@eq_dvdp c2 c1%:P) -?eq_cmn ?mul_polyC // (@eq_dvdp c1 c2%:P) //. by rewrite eq_cmn mul_polyC. case: (eqVneq m 0) => [-> | m_nz]. by case/andP => /dvd0pP -> _; exists (1, 1); rewrite ?scaler0 // oner_eq0. case: (eqVneq n 0) => [-> | n_nz]. by case/andP => _ /dvd0pP ->; exists (1, 1); rewrite ?scaler0 // oner_eq0. case/andP; rewrite !dvdp_eq; set c1 := _ ^+ _; set c2 := _ ^+ _. set q1 := _ %/ _; set q2 := _ %/ _; move/eqP => Hq1 /eqP Hq2; have Hc1 : c1 != 0 by rewrite expf_eq0 lead_coef_eq0 negb_and m_nz orbT. have Hc2 : c2 != 0 by rewrite expf_eq0 lead_coef_eq0 negb_and n_nz orbT. have def_q12: q1 * q2 = (c1 * c2)%:P. apply: (mulIf m_nz); rewrite mulrAC mulrC -Hq1 -scalerAr -Hq2 scalerA. by rewrite -mul_polyC. have: q1 * q2 != 0 by rewrite def_q12 -size_poly_eq0 size_polyC mulf_neq0. rewrite mulf_eq0; case/norP=> nz_q1 nz_q2. have: size q2 <= 1%N. have:= size_mul nz_q1 nz_q2; rewrite def_q12 size_polyC mulf_neq0 //=. by rewrite polySpred // => ->; rewrite leq_addl. rewrite leq_eqVlt ltnS leqn0 size_poly_eq0 (negPf nz_q2) orbF. case/size_poly1P=> c cn0 cqe; exists (c2, c); first by rewrite Hc2. by rewrite Hq2 -mul_polyC -cqe. Qed. Lemma eqp_eq p q: p %= q -> (lead_coef q) *: p = (lead_coef p) *: q. Proof. move=> /eqpP [[c1 c2] /= /andP [nz_c1 nz_c2]] eq. have/(congr1 lead_coef) := eq; rewrite !lead_coefZ. move=> eqC; apply/(@mulfI _ c2%:P); rewrite ?polyC_eq0 //. rewrite !mul_polyC scalerA -eqC mulrC -scalerA eq. by rewrite !scalerA mulrC. Qed. Lemma eqpxx : reflexive (@eqp R). Proof. by move=> p; rewrite /eqp dvdpp. Qed. Hint Resolve eqpxx. Lemma eqp_sym : symmetric (@eqp R). Proof. by move=> p q; rewrite /eqp andbC. Qed. Lemma eqp_trans : transitive (@eqp R). Proof. move=> p q r; case/andP=> Dp pD; case/andP=> Dq qD. by rewrite /eqp (dvdp_trans Dp) // (dvdp_trans qD). Qed. Lemma eqp_ltrans : left_transitive (@eqp R). Proof. move=> p q r pq. by apply/idP/idP=> e; apply: eqp_trans e; rewrite // eqp_sym. Qed. Lemma eqp_rtrans : right_transitive (@eqp R). Proof. by move=> x y xy z; rewrite eqp_sym (eqp_ltrans xy) eqp_sym. Qed. Lemma eqp0 : forall p, (p %= 0) = (p == 0). Proof. move=> p; case: eqP; move/eqP=> Ep; first by rewrite (eqP Ep) eqpxx. by apply/negP; case/andP=> _; rewrite /dvdp modp0 (negPf Ep). Qed. Lemma eqp01 : 0 %= (1 : {poly R}) = false. Proof. case abs : (0 %= 1) => //; case/eqpP: abs=> [[c1 c2]] /andP [c1n0 c2n0] /=. by rewrite scaler0 alg_polyC; move/eqP; rewrite eq_sym polyC_eq0 (negbTE c2n0). Qed. Lemma eqp_scale p c : c != 0 -> c *: p %= p. Proof. move=> c0; apply/eqpP; exists (1, c); first by rewrite c0 oner_eq0. by rewrite scale1r. Qed. Lemma eqp_size p q : p %= q -> size p = size q. Proof. case: (q =P 0); move/eqP => Eq; first by rewrite (eqP Eq) eqp0; move/eqP->. rewrite eqp_sym; case: (p =P 0); move/eqP => Ep. by rewrite (eqP Ep) eqp0; move/eqP->. by case/andP => Dp Dq; apply: anti_leq; rewrite !dvdp_leq. Qed. Lemma size_poly_eq1 p : (size p == 1%N) = (p %= 1). Proof. apply/size_poly1P/idP=> [[c cn0 ep] |]. by apply/eqpP; exists (1, c); rewrite ?oner_eq0 // alg_polyC scale1r. by move/eqp_size; rewrite size_poly1; move/eqP; move/size_poly1P. Qed. Lemma polyXsubC_eqp1 (x : R) : ('X - x%:P %= 1) = false. Proof. by rewrite -size_poly_eq1 size_XsubC. Qed. Lemma dvdp_eqp1 p q : p %| q -> q %= 1 -> p %= 1. Proof. move=> dpq hq. have sizeq : size q == 1%N by rewrite size_poly_eq1. have n0q : q != 0. by case abs: (q == 0) => //; move: hq; rewrite (eqP abs) eqp01. rewrite -size_poly_eq1 eqn_leq -{1}(eqP sizeq) dvdp_leq //=. case p0 : (size p == 0%N); last by rewrite neq0_lt0n. by move: dpq; rewrite size_poly_eq0 in p0; rewrite (eqP p0) dvd0p (negbTE n0q). Qed. Lemma eqp_dvdr q p d: p %= q -> d %| p = (d %| q). Proof. suff Hmn m n: m %= n -> (d %| m) -> (d %| n). by move=> mn; apply/idP/idP; apply: Hmn=> //; rewrite eqp_sym. by rewrite /eqp; case/andP=> pq qp dp; apply: (dvdp_trans dp). Qed. Lemma eqp_dvdl d2 d1 p : d1 %= d2 -> d1 %| p = (d2 %| p). suff Hmn m n: m %= n -> (m %| p) -> (n %| p). by move=> ?; apply/idP/idP; apply: Hmn; rewrite // eqp_sym. by rewrite /eqp; case/andP=> dd' d'd dp; apply: (dvdp_trans d'd). Qed. Lemma dvdp_scaler c m n : c != 0 -> m %| c *: n = (m %| n). Proof. move=> cn0; apply: eqp_dvdr; exact: eqp_scale. Qed. Lemma dvdp_scalel c m n : c != 0 -> (c *: m %| n) = (m %| n). Proof. move=> cn0; apply: eqp_dvdl; exact: eqp_scale. Qed. Lemma dvdp_opp d p : d %| (- p) = (d %| p). Proof. by apply: eqp_dvdr; rewrite -scaleN1r eqp_scale // oppr_eq0 oner_eq0. Qed. Lemma eqp_mul2r r p q : r != 0 -> (p * r %= q * r) = (p %= q). Proof. by move => nz_r; rewrite /eqp !dvdp_mul2r. Qed. Lemma eqp_mul2l r p q: r != 0 -> (r * p %= r * q) = (p %= q). Proof. by move => nz_r; rewrite /eqp !dvdp_mul2l. Qed. Lemma eqp_mull r p q: (q %= r) -> (p * q %= p * r). Proof. case/eqpP=> [[c d]] /andP [c0 d0 e]; apply/eqpP; exists (c, d); rewrite ?c0 //. by rewrite scalerAr e -scalerAr. Qed. Lemma eqp_mulr q p r : (p %= q) -> (p * r %= q * r). Proof. by move=> epq; rewrite ![_ * r]mulrC eqp_mull. Qed. Lemma eqp_exp p q k : p %= q -> p ^+ k %= q ^+ k. Proof. move=> pq; elim: k=> [|k ihk]; first by rewrite !expr0 eqpxx. by rewrite !exprS (@eqp_trans (q * p ^+ k)) // (eqp_mulr, eqp_mull). Qed. Lemma polyC_eqp1 (c : R) : (c%:P %= 1) = (c != 0). Proof. apply/eqpP/idP => [[[x y]] |nc0] /=. case c0: (c == 0); rewrite // alg_polyC (eqP c0) scaler0. by case/andP=> _ /=; move/negbTE<-; move/eqP; rewrite eq_sym polyC_eq0. exists (1, c); first by rewrite nc0 /= oner_neq0. by rewrite alg_polyC scale1r. Qed. Lemma dvdUp d p: d %= 1 -> d %| p. Proof. by move/eqp_dvdl->; rewrite dvd1p. Qed. Lemma dvdp_size_eqp p q : p %| q -> size p == size q = (p %= q). Proof. move=> pq; apply/idP/idP; last by move/eqp_size->. case (q =P 0)=> [->|]; [|move/eqP => Hq]. by rewrite size_poly0 size_poly_eq0; move/eqP->; rewrite eqpxx. case (p =P 0)=> [->|]; [|move/eqP => Hp]. by rewrite size_poly0 eq_sym size_poly_eq0; move/eqP->; rewrite eqpxx. move: pq; rewrite dvdp_eq; set c := _ ^+ _; set x := _ %/ _; move/eqP=> eqpq. move:(eqpq); move/(congr1 (size \o (@polyseq R)))=> /=. have cn0 : c != 0 by rewrite expf_neq0 // lead_coef_eq0. rewrite (@eqp_size _ q); last by exact: eqp_scale. rewrite size_mul ?p0 // => [-> HH|]; last first. apply/eqP=> HH; move: eqpq; rewrite HH mul0r. by move/eqP; rewrite scale_poly_eq0 (negPf Hq) (negPf cn0). suff: size x == 1%N. case/size_poly1P=> y H1y H2y. by apply/eqpP; exists (y, c); rewrite ?H1y // eqpq H2y mul_polyC. case: (size p) HH (size_poly_eq0 p)=> [|n]; first by case: eqP Hp. by rewrite addnS -add1n eqn_add2r;move/eqP->. Qed. Lemma eqp_root p q : p %= q -> root p =1 root q. Proof. move/eqpP=> [[c d]] /andP [c0 d0 e] x; move/negPf:c0=>c0; move/negPf:d0=>d0. rewrite rootE -[_==_]orFb -c0 -mulf_eq0 -hornerZ e hornerZ. by rewrite mulf_eq0 d0. Qed. Lemma eqp_rmod_mod p q : rmodp p q %= modp p q. Proof. rewrite modpE eqp_sym; case: ifP => ulcq //. apply: eqp_scale; rewrite invr_eq0 //. by apply: expf_neq0; apply: contraTneq ulcq => ->; rewrite unitr0. Qed. Lemma eqp_rdiv_div p q : rdivp p q %= divp p q. Proof. rewrite divpE eqp_sym; case: ifP=> ulcq //; apply: eqp_scale; rewrite invr_eq0 //. by apply: expf_neq0; apply: contraTneq ulcq => ->; rewrite unitr0. Qed. Lemma dvd_eqp_divl d p q (dvd_dp : d %| q) (eq_pq : p %= q) : p %/ d %= q %/ d. Proof. case: (eqVneq q 0) eq_pq=> [->|q_neq0]; first by rewrite eqp0=> /eqP->. have d_neq0: d != 0 by apply: contraL dvd_dp=> /eqP->; rewrite dvd0p. move=> eq_pq; rewrite -(@eqp_mul2r d) // !divpK // ?(eqp_dvdr _ eq_pq) //. rewrite (eqp_ltrans (eqp_scale _ _)) ?lc_expn_scalp_neq0 //. by rewrite (eqp_rtrans (eqp_scale _ _)) ?lc_expn_scalp_neq0. Qed. Definition gcdp_rec p q := let: (p1, q1) := if size p < size q then (q, p) else (p, q) in if p1 == 0 then q1 else let fix loop (n : nat) (pp qq : {poly R}) {struct n} := let rr := modp pp qq in if rr == 0 then qq else if n is n1.+1 then loop n1 qq rr else rr in loop (size p1) p1 q1. Definition gcdp := nosimpl gcdp_rec. Lemma gcd0p : left_id 0 gcdp. Proof. move=> p; rewrite /gcdp /gcdp_rec size_poly0 size_poly_gt0 if_neg. case: ifP => /= [_ | nzp]; first by rewrite eqxx. by rewrite polySpred !(modp0, nzp) //; case: _.-1 => [|m]; rewrite mod0p eqxx. Qed. Lemma gcdp0 : right_id 0 gcdp. Proof. move=> p; have:= gcd0p p; rewrite /gcdp /gcdp_rec size_poly0 size_poly_gt0. by rewrite if_neg; case: ifP => /= p0; rewrite ?(eqxx, p0) // (eqP p0). Qed. Lemma gcdpE p q : gcdp p q = if size p < size q then gcdp (modp q p) p else gcdp (modp p q) q. Proof. pose gcdpE_rec := fix gcdpE_rec (n : nat) (pp qq : {poly R}) {struct n} := let rr := modp pp qq in if rr == 0 then qq else if n is n1.+1 then gcdpE_rec n1 qq rr else rr. have Irec: forall k l p q, size q <= k -> size q <= l -> size q < size p -> gcdpE_rec k p q = gcdpE_rec l p q. + elim=> [|m Hrec] [|n] //= p1 q1. - rewrite leqn0 size_poly_eq0; move/eqP=> -> _. rewrite size_poly0 size_poly_gt0 modp0 => nzp. by rewrite (negPf nzp); case: n => [|n] /=; rewrite mod0p eqxx. - rewrite leqn0 size_poly_eq0 => _; move/eqP=> ->. rewrite size_poly0 size_poly_gt0 modp0 => nzp. by rewrite (negPf nzp); case: m {Hrec} => [|m] /=; rewrite mod0p eqxx. case: ifP => Epq Sm Sn Sq //; rewrite ?Epq //. case: (eqVneq q1 0) => [->|nzq]. by case: n m {Sm Sn Hrec} => [|m] [|n] //=; rewrite mod0p eqxx. apply: Hrec; last by rewrite ltn_modp. by rewrite -ltnS (leq_trans _ Sm) // ltn_modp. by rewrite -ltnS (leq_trans _ Sn) // ltn_modp. case: (eqVneq p 0) => [-> | nzp]. by rewrite mod0p modp0 gcd0p gcdp0 if_same. case: (eqVneq q 0) => [-> | nzq]. by rewrite mod0p modp0 gcd0p gcdp0 if_same. rewrite /gcdp /gcdp_rec. case: ltnP; rewrite (negPf nzp, negPf nzq) //=. move=> ltpq; rewrite ltn_modp (negPf nzp) //=. rewrite -(ltn_predK ltpq) /=; case: eqP => [->|]. by case: (size p) => [|[|s]]; rewrite /= modp0 (negPf nzp) // mod0p eqxx. move/eqP=> nzqp; rewrite (negPf nzp). apply: Irec => //; last by rewrite ltn_modp. by rewrite -ltnS (ltn_predK ltpq) (leq_trans _ ltpq) ?leqW // ltn_modp. by rewrite ltnW // ltn_modp. move=> leqp; rewrite ltn_modp (negPf nzq) //=. have p_gt0: size p > 0 by rewrite size_poly_gt0. rewrite -(prednK p_gt0) /=; case: eqP => [->|]. by case: (size q) => [|[|s]]; rewrite /= modp0 (negPf nzq) // mod0p eqxx. move/eqP=> nzpq; rewrite (negPf nzq); apply: Irec => //; rewrite ?ltn_modp //. by rewrite -ltnS (prednK p_gt0) (leq_trans _ leqp) // ltn_modp. by rewrite ltnW // ltn_modp. Qed. Lemma size_gcd1p p : size (gcdp 1 p) = 1%N. Proof. rewrite gcdpE size_polyC oner_eq0 /= modp1; case: ltnP. by rewrite gcd0p size_polyC oner_eq0. move/size1_polyC=> e; rewrite e. case p00: (p`_0 == 0); first by rewrite (eqP p00) modp0 gcdp0 size_poly1. by rewrite modpC ?p00 // gcd0p size_polyC p00. Qed. Lemma size_gcdp1 p : size (gcdp p 1) = 1%N. rewrite gcdpE size_polyC oner_eq0 /= modp1; case: ltnP; last first. by rewrite gcd0p size_polyC oner_eq0. rewrite ltnS leqn0 size_poly_eq0; move/eqP->; rewrite gcdp0 modp0 size_polyC. by rewrite oner_eq0. Qed. Lemma gcdpp : idempotent gcdp. Proof. by move=> p; rewrite gcdpE ltnn modpp gcd0p. Qed. Lemma dvdp_gcdlr p q : (gcdp p q %| p) && (gcdp p q %| q). Proof. elim: {p q}minn {-2}p {-2}q (leqnn (minn (size q) (size p))) => [|r Hrec] p q. rewrite geq_min !leqn0 !size_poly_eq0. by case/pred2P=> ->; rewrite (gcdp0, gcd0p) dvdpp ?andbT /=. case: (eqVneq p 0) => [-> _|nz_p]; first by rewrite gcd0p dvdpp andbT. case: (eqVneq q 0) => [->|nz_q]; first by rewrite gcdp0 dvdpp /=. rewrite gcdpE minnC /minn; case: ltnP => [lt_pq | le_pq] le_qr. suffices: minn (size p) (size (q %% p)) <= r. by move/Hrec; case/andP => E1 E2; rewrite E2 (dvdp_mod _ E2). by rewrite geq_min orbC -ltnS (leq_trans _ le_qr) ?ltn_modp. suffices: minn (size q) (size (p %% q)) <= r. by move/Hrec; case/andP => E1 E2; rewrite E2 andbT (dvdp_mod _ E2). by rewrite geq_min orbC -ltnS (leq_trans _ le_qr) ?ltn_modp. Qed. Lemma dvdp_gcdl p q : gcdp p q %| p. Proof. by case/andP: (dvdp_gcdlr p q). Qed. Lemma dvdp_gcdr p q :gcdp p q %| q. Proof. by case/andP: (dvdp_gcdlr p q). Qed. Lemma leq_gcdpl p q : p != 0 -> size (gcdp p q) <= size p. Proof. by move=> pn0; move: (dvdp_gcdl p q); apply: dvdp_leq. Qed. Lemma leq_gcdpr p q : q != 0 -> size (gcdp p q) <= size q. Proof. by move=> qn0; move: (dvdp_gcdr p q); apply: dvdp_leq. Qed. Lemma dvdp_gcd p m n : p %| gcdp m n = (p %| m) && (p %| n). Proof. apply/idP/andP=> [dv_pmn | [dv_pm dv_pn]]. by rewrite ?(dvdp_trans dv_pmn) ?dvdp_gcdl ?dvdp_gcdr. move: (leqnn (minn (size n) (size m))) dv_pm dv_pn. elim: {m n}minn {-2}m {-2}n => [|r Hrec] m n. rewrite geq_min !leqn0 !size_poly_eq0. by case/pred2P=> ->; rewrite (gcdp0, gcd0p). case: (eqVneq m 0) => [-> _|nz_m]; first by rewrite gcd0p /=. case: (eqVneq n 0) => [->|nz_n]; first by rewrite gcdp0 /=. rewrite gcdpE minnC /minn; case: ltnP => Cnm le_r dv_m dv_n. apply: Hrec => //; last by rewrite -(dvdp_mod _ dv_m). by rewrite geq_min orbC -ltnS (leq_trans _ le_r) ?ltn_modp. apply: Hrec => //; last by rewrite -(dvdp_mod _ dv_n). by rewrite geq_min orbC -ltnS (leq_trans _ le_r) ?ltn_modp. Qed. Lemma gcdpC : forall p q, gcdp p q %= gcdp q p. Proof. by move=> p q; rewrite /eqp !dvdp_gcd !dvdp_gcdl !dvdp_gcdr. Qed. Lemma gcd1p p : gcdp 1 p %= 1. Proof. rewrite -size_poly_eq1 gcdpE size_poly1; case: ltnP. by rewrite modp1 gcd0p size_poly1 eqxx. move/size1_polyC=> e; rewrite e. case p00: (p`_0 == 0); first by rewrite (eqP p00) modp0 gcdp0 size_poly1. by rewrite modpC ?p00 // gcd0p size_polyC p00. Qed. Lemma gcdp1 p : gcdp p 1 %= 1. Proof. by rewrite (eqp_ltrans (gcdpC _ _)) gcd1p. Qed. Lemma gcdp_addl_mul p q r: gcdp r (p * r + q) %= gcdp r q. Proof. suff h m n d : gcdp d n %| gcdp d (m * d + n). apply/andP; split => //; rewrite {2}(_: q = (-p) * r + (p * r + q)) ?H //. by rewrite GRing.mulNr GRing.addKr. by rewrite dvdp_gcd dvdp_gcdl /= dvdp_addr ?dvdp_gcdr ?dvdp_mull ?dvdp_gcdl. Qed. Lemma gcdp_addl m n : gcdp m (m + n) %= gcdp m n. Proof. by rewrite -{2}(mul1r m) gcdp_addl_mul. Qed. Lemma gcdp_addr m n : gcdp m (n + m) %= gcdp m n. Proof. by rewrite addrC gcdp_addl. Qed. Lemma gcdp_mull m n : gcdp n (m * n) %= n. Proof. case: (eqVneq n 0) => [-> | nn0]; first by rewrite gcd0p mulr0 eqpxx. case: (eqVneq m 0) => [-> | mn0]; first by rewrite mul0r gcdp0 eqpxx. rewrite gcdpE modp_mull gcd0p size_mul //; case: ifP; first by rewrite eqpxx. rewrite (polySpred mn0) addSn /= -{1}[size n]add0n ltn_add2r; move/negbT. rewrite -ltnNge prednK ?size_poly_gt0 // leq_eqVlt ltnS leqn0 size_poly_eq0. rewrite (negPf mn0) orbF; case/size_poly1P=> c cn0 -> {mn0 m}; rewrite mul_polyC. suff -> : n %% (c *: n) = 0 by rewrite gcd0p; exact: eqp_scale. by apply/modp_eq0P; rewrite dvdp_scalel. Qed. Lemma gcdp_mulr m n : gcdp n (n * m) %= n. Proof. by rewrite mulrC gcdp_mull. Qed. Lemma gcdp_scalel c m n : c != 0 -> gcdp (c *: m) n %= gcdp m n. Proof. move=> cn0; rewrite /eqp dvdp_gcd [gcdp m n %| _]dvdp_gcd !dvdp_gcdr !andbT. apply/andP; split; last first. by apply: dvdp_trans (dvdp_gcdl _ _) _; rewrite dvdp_scaler. by apply: dvdp_trans (dvdp_gcdl _ _) _; rewrite dvdp_scalel. Qed. Lemma gcdp_scaler c m n : c != 0 -> gcdp m (c *: n) %= gcdp m n. Proof. move=> cn0; apply: eqp_trans (gcdpC _ _) _. apply: eqp_trans (gcdp_scalel _ _ _) _ => //; exact: gcdpC. Qed. Lemma dvdp_gcd_idl m n : m %| n -> gcdp m n %= m. Proof. case: (eqVneq m 0) => [-> | mn0]. by rewrite dvd0p => /eqP ->; rewrite gcdp0 eqpxx. rewrite dvdp_eq; move/eqP; move/(f_equal (gcdp m)) => h. apply: eqp_trans (gcdp_mull (n %/ m) _); rewrite -h eqp_sym gcdp_scaler //. by rewrite expf_neq0 // lead_coef_eq0. Qed. Lemma dvdp_gcd_idr m n : n %| m -> gcdp m n %= n. Proof. move/dvdp_gcd_idl => h; apply: eqp_trans h; exact: gcdpC. Qed. Lemma gcdp_exp p k l : gcdp (p ^+ k) (p ^+ l) %= p ^+ minn k l. Proof. wlog leqmn: k l / k <= l. move=> hwlog; case: (leqP k l); first exact: hwlog. move/ltnW; rewrite minnC; move/hwlog=> h; apply: eqp_trans h; exact: gcdpC. rewrite (minn_idPl leqmn); move/subnK: leqmn<-; rewrite exprD. apply: eqp_trans (gcdp_mull _ _) _; exact: eqpxx. Qed. Lemma gcdp_eq0 p q : gcdp p q == 0 = (p == 0) && (q == 0). Proof. apply/idP/idP; last by case/andP => /eqP -> /eqP ->; rewrite gcdp0. have h m n: gcdp m n == 0 -> (m == 0). by rewrite -(dvd0p m); move/eqP<-; rewrite dvdp_gcdl. by move=> ?; rewrite (h _ q) // (h _ p) // -eqp0 (eqp_ltrans (gcdpC _ _)) eqp0. Qed. Lemma eqp_gcdr p q r : q %= r -> gcdp p q %= gcdp p r. Proof. move=> eqr; rewrite /eqp !(dvdp_gcd, dvdp_gcdl, andbT) /=. by rewrite -(eqp_dvdr _ eqr) dvdp_gcdr (eqp_dvdr _ eqr) dvdp_gcdr. Qed. Lemma eqp_gcdl r p q : p %= q -> gcdp p r %= gcdp q r. move=> eqr; rewrite /eqp !(dvdp_gcd, dvdp_gcdr, andbT) /=. by rewrite -(eqp_dvdr _ eqr) dvdp_gcdl (eqp_dvdr _ eqr) dvdp_gcdl. Qed. Lemma eqp_gcd p1 p2 q1 q2 : p1 %= p2 -> q1 %= q2 -> gcdp p1 q1 %= gcdp p2 q2. Proof. move=> e1 e2. by apply: eqp_trans (eqp_gcdr _ e2); apply: eqp_trans (eqp_gcdl _ e1). Qed. Lemma eqp_rgcd_gcd p q : rgcdp p q %= gcdp p q. Proof. move: (leqnn (minn (size p) (size q))); move: {2}(minn (size p) (size q)) => n. elim: n p q => [p q|n ihn p q hs]. rewrite leqn0 /minn; case: ltnP => _; rewrite size_poly_eq0; move/eqP->. by rewrite gcd0p rgcd0p eqpxx. by rewrite gcdp0 rgcdp0 eqpxx. case: (eqVneq p 0) => [-> | pn0]; first by rewrite gcd0p rgcd0p eqpxx. case: (eqVneq q 0) => [-> | qn0]; first by rewrite gcdp0 rgcdp0 eqpxx. rewrite gcdpE rgcdpE; case: ltnP => sp. have e := (eqp_rmod_mod q p); move: (e); move/(eqp_gcdl p) => h. apply: eqp_trans h; apply: ihn; rewrite (eqp_size e) geq_min. by rewrite -ltnS (leq_trans _ hs) // (minn_idPl (ltnW _)) ?ltn_modp. have e := (eqp_rmod_mod p q); move: (e); move/(eqp_gcdl q) => h. apply: eqp_trans h; apply: ihn; rewrite (eqp_size e) geq_min. by rewrite -ltnS (leq_trans _ hs) // (minn_idPr _) ?ltn_modp. Qed. Lemma gcdp_modr m n : gcdp m (n %% m) %= gcdp m n. Proof. case: (eqVneq m 0) => [-> | mn0]; first by rewrite modp0 eqpxx. have : (lead_coef m) ^+ (scalp n m) != 0 by rewrite expf_neq0 // lead_coef_eq0. move/gcdp_scaler; move/(_ m n) => h; apply: eqp_trans h; rewrite divp_eq. by rewrite eqp_sym gcdp_addl_mul. Qed. Lemma gcdp_modl m n : gcdp (m %% n) n %= gcdp m n. Proof. apply: eqp_trans (gcdpC _ _) _; apply: eqp_trans (gcdp_modr _ _) _. exact: gcdpC. Qed. Lemma gcdp_def d m n : d %| m -> d %| n -> (forall d', d' %| m -> d' %| n -> d' %| d) -> gcdp m n %= d. Proof. move=> dm dn h; rewrite /eqp dvdp_gcd dm dn !andbT. apply: h; [exact: dvdp_gcdl | exact: dvdp_gcdr]. Qed. Definition coprimep p q := size (gcdp p q) == 1%N. Lemma coprimep_size_gcd p q : coprimep p q -> size (gcdp p q) = 1%N. Proof. by rewrite /coprimep=> /eqP. Qed. Lemma coprimep_def p q : (coprimep p q) = (size (gcdp p q) == 1%N). Proof. done. Qed. Lemma coprimep_scalel c m n : c != 0 -> coprimep (c *: m) n = coprimep m n. Proof. by move=> ?; rewrite !coprimep_def (eqp_size (gcdp_scalel _ _ _)). Qed. Lemma coprimep_scaler c m n: c != 0 -> coprimep m (c *: n) = coprimep m n. Proof. by move=> ?; rewrite !coprimep_def (eqp_size (gcdp_scaler _ _ _)). Qed. Lemma coprimepp p : coprimep p p = (size p == 1%N). Proof. by rewrite coprimep_def gcdpp. Qed. Lemma gcdp_eqp1 p q : gcdp p q %= 1 = (coprimep p q). Proof. by rewrite coprimep_def size_poly_eq1. Qed. Lemma coprimep_sym p q : coprimep p q = coprimep q p. Proof. by rewrite -!gcdp_eqp1; apply: eqp_ltrans; rewrite gcdpC. Qed. Lemma coprime1p p : coprimep 1 p. Proof. rewrite /coprimep -[1%N](size_poly1 R); apply/eqP; apply: eqp_size. exact: gcd1p. Qed. Lemma coprimep1 p : coprimep p 1. Proof. by rewrite coprimep_sym; apply: coprime1p. Qed. Lemma coprimep0 p : coprimep p 0 = (p %= 1). Proof. by rewrite /coprimep gcdp0 size_poly_eq1. Qed. Lemma coprime0p p : coprimep 0 p = (p %= 1). Proof. by rewrite coprimep_sym coprimep0. Qed. (* This is different from coprimeP in div. shall we keep this? *) Lemma coprimepP p q : reflect (forall d, d %| p -> d %| q -> d %= 1) (coprimep p q). Proof. apply: (iffP idP)=> [|h]. rewrite /coprimep; move/eqP=> hs d dvddp dvddq. have dvddg: d %| gcdp p q by rewrite dvdp_gcd dvddp dvddq. by apply: (dvdp_eqp1 dvddg); rewrite -size_poly_eq1; apply/eqP. case/andP: (dvdp_gcdlr p q)=> h1 h2. by rewrite /coprimep size_poly_eq1; apply: h. Qed. Lemma coprimepPn p q : p != 0 -> reflect (exists d, (d %| gcdp p q) && ~~ (d %= 1)) (~~ coprimep p q). Proof. move=> p0; apply: (iffP idP). by rewrite -gcdp_eqp1=> ng1; exists (gcdp p q); rewrite dvdpp /=. case=> d; case/andP=> dg; apply: contra; rewrite -gcdp_eqp1=> g1. by move: dg; rewrite (eqp_dvdr _ g1) dvdp1 size_poly_eq1. Qed. Lemma coprimep_dvdl q p r : r %| q -> coprimep p q -> coprimep p r. Proof. move=> rq cpq; apply/coprimepP=> d dp dr; move/coprimepP:cpq=> cpq'. by apply: cpq'; rewrite // (dvdp_trans dr). Qed. Lemma coprimep_dvdr p q r : r %| p -> coprimep p q -> coprimep r q. Proof. move=> rp; rewrite ![coprimep _ q]coprimep_sym. by move/coprimep_dvdl; apply. Qed. Lemma coprimep_modl p q : coprimep (p %% q) q = coprimep p q. Proof. symmetry; rewrite !coprimep_def. case: (ltnP (size p) (size q))=> hpq; first by rewrite modp_small. by rewrite gcdpE ltnNge hpq. Qed. Lemma coprimep_modr q p : coprimep q (p %% q) = coprimep q p. Proof. by rewrite ![coprimep q _]coprimep_sym coprimep_modl. Qed. Lemma rcoprimep_coprimep q p : rcoprimep q p = coprimep q p. Proof. by rewrite /coprimep /rcoprimep; rewrite (eqp_size (eqp_rgcd_gcd _ _)). Qed. Lemma eqp_coprimepr p q r : q %= r -> coprimep p q = coprimep p r. Proof. by rewrite -!gcdp_eqp1; move/(eqp_gcdr p) => h1; apply: (eqp_ltrans h1). Qed. Lemma eqp_coprimepl p q r : q %= r -> coprimep q p = coprimep r p. Proof. rewrite !(coprimep_sym _ p); exact: eqp_coprimepr. Qed. (* This should be implemented with an extended remainder sequence *) Fixpoint egcdp_rec p q k {struct k} : {poly R} * {poly R} := if k is k'.+1 then if q == 0 then (1, 0) else let: (u, v) := egcdp_rec q (p %% q) k' in (lead_coef q ^+ scalp p q *: v, (u - v * (p %/ q))) else (1, 0). Definition egcdp p q := if size q <= size p then egcdp_rec p q (size q) else let e := egcdp_rec q p (size p) in (e.2, e.1). (* No provable egcd0p *) Lemma egcdp0 p : egcdp p 0 = (1, 0). Proof. by rewrite /egcdp size_poly0. Qed. Lemma egcdp_recP : forall k p q, q != 0 -> size q <= k -> size q <= size p -> let e := (egcdp_rec p q k) in [/\ size e.1 <= size q, size e.2 <= size p & gcdp p q %= e.1 * p + e.2 * q]. Proof. elim=> [|k ihk] p q /= qn0; first by rewrite leqn0 size_poly_eq0 (negPf qn0). move=> sqSn qsp; case: (eqVneq q 0)=> q0; first by rewrite q0 eqxx in qn0. rewrite (negPf qn0). have sp : size p > 0 by apply: leq_trans qsp; rewrite size_poly_gt0. case: (eqVneq (p %% q) 0) => [r0 | rn0] /=. rewrite r0 /egcdp_rec; case: k ihk sqSn => [|n] ihn sqSn /=. rewrite !scaler0 !mul0r subr0 add0r mul1r size_poly0 size_poly1. by rewrite dvdp_gcd_idr /dvdp ?r0. rewrite !eqxx mul0r scaler0 /= mul0r add0r subr0 mul1r size_poly0 size_poly1. by rewrite dvdp_gcd_idr /dvdp ?r0 //. have h1 : size (p %% q) <= k. by rewrite -ltnS; apply: leq_trans sqSn; rewrite ltn_modp. have h2 : size (p %% q) <= size q by rewrite ltnW // ltn_modp. have := (ihk q (p %% q) rn0 h1 h2). case: (egcdp_rec _ _)=> u v /= => [[ihn'1 ihn'2 ihn'3]]. rewrite gcdpE ltnNge qsp //= (eqp_ltrans (gcdpC _ _)); split; last first. - apply: (eqp_trans ihn'3). rewrite mulrBl addrCA -scalerAl scalerAr -mulrA -mulrBr. by rewrite divp_eq addrAC subrr add0r eqpxx. - apply: (leq_trans (size_add _ _)). case: (eqVneq v 0)=> [-> | vn0]. rewrite mul0r size_opp size_poly0 maxn0; apply: leq_trans ihn'1 _. exact: leq_modp. case: (eqVneq (p %/ q) 0)=> [-> | qqn0]. rewrite mulr0 size_opp size_poly0 maxn0; apply: leq_trans ihn'1 _. exact: leq_modp. rewrite geq_max (leq_trans ihn'1) ?leq_modp //= size_opp size_mul //. move: (ihn'2); rewrite -(leq_add2r (size (p %/ q))). have : size v + size (p %/ q) > 0 by rewrite addn_gt0 size_poly_gt0 vn0. have : size q + size (p %/ q) > 0 by rewrite addn_gt0 size_poly_gt0 qn0. do 2! move/prednK=> {1}<-; rewrite ltnS => h; apply: leq_trans h _. rewrite size_divp // addnBA; last by apply: leq_trans qsp; exact: leq_pred. rewrite addnC -addnBA ?leq_pred //; move: qn0; rewrite -size_poly_eq0 -lt0n. by move/prednK=> {1}<-; rewrite subSnn addn1. - by rewrite size_scale // lc_expn_scalp_neq0. Qed. Lemma egcdpP p q : p != 0 -> q != 0 -> forall (e := egcdp p q), [/\ size e.1 <= size q, size e.2 <= size p & gcdp p q %= e.1 * p + e.2 * q]. Proof. move=> pn0 qn0; rewrite /egcdp; case: (leqP (size q) (size p)) => /= hp. by apply: egcdp_recP. move/ltnW: hp => hp; case: (egcdp_recP pn0 (leqnn (size p)) hp) => h1 h2 h3. by split => //; rewrite (eqp_ltrans (gcdpC _ _)) addrC. Qed. Lemma egcdpE p q (e := egcdp p q) : gcdp p q %= e.1 * p + e.2 * q. Proof. rewrite {}/e; have [-> /= | qn0] := eqVneq q 0. by rewrite gcdp0 egcdp0 mul1r mulr0 addr0. have [p0 | pn0] := eqVneq p 0; last by case: (egcdpP pn0 qn0). rewrite p0 gcd0p mulr0 add0r /egcdp size_poly0 leqn0 size_poly_eq0 (negPf qn0). by rewrite /= mul1r. Qed. Lemma Bezoutp p q : exists u, u.1 * p + u.2 * q %= (gcdp p q). Proof. case: (eqVneq p 0) => [-> | pn0]. by rewrite gcd0p; exists (0, 1); rewrite mul0r mul1r add0r. case: (eqVneq q 0) => [-> | qn0]. by rewrite gcdp0; exists (1, 0); rewrite mul0r mul1r addr0. pose e := egcdp p q; exists e; rewrite eqp_sym. by case: (egcdpP pn0 qn0). Qed. Lemma Bezout_coprimepP : forall p q, reflect (exists u, u.1 * p + u.2 * q %= 1) (coprimep p q). Proof. move=> p q; rewrite -gcdp_eqp1; apply:(iffP idP)=> [g1|]. case: (Bezoutp p q) => [[u v] Puv]; exists (u, v); exact: eqp_trans g1. case=>[[u v]]; rewrite eqp_sym=> Puv; rewrite /eqp (eqp_dvdr _ Puv). by rewrite dvdp_addr dvdp_mull ?dvdp_gcdl ?dvdp_gcdr //= dvd1p. Qed. Lemma coprimep_root p q x : coprimep p q -> root p x -> q.[x] != 0. Proof. case/Bezout_coprimepP=> [[u v] euv] px0. move/eqpP: euv => [[c1 c2]] /andP /= [c1n0 c2n0 e]. suffices: c1 * (v.[x] * q.[x]) != 0. by rewrite !mulf_eq0 !negb_or c1n0 /=; case/andP. move/(f_equal (fun t => horner t x)): e; rewrite /= !hornerZ hornerD. by rewrite !hornerM (eqP px0) mulr0 add0r hornerC mulr1; move->. Qed. Lemma Gauss_dvdpl p q d: coprimep d q -> (d %| p * q) = (d %| p). Proof. move/Bezout_coprimepP=>[[u v] Puv]; apply/idP/idP; last exact: dvdp_mulr. move:Puv; move/(eqp_mull p); rewrite mulr1 mulrDr eqp_sym=> peq dpq. rewrite (eqp_dvdr _ peq) dvdp_addr; first by rewrite mulrA mulrAC dvdp_mulr. by rewrite mulrA dvdp_mull ?dvdpp. Qed. Lemma Gauss_dvdpr p q d: coprimep d q -> (d %| q * p) = (d %| p). Proof. rewrite mulrC; exact: Gauss_dvdpl. Qed. (* This could be simplified with the introduction of lcmp *) Lemma Gauss_dvdp m n p : coprimep m n -> (m * n %| p) = (m %| p) && (n %| p). Proof. case: (eqVneq m 0) => [-> | mn0]. by rewrite coprime0p; move/eqp_dvdl->; rewrite !mul0r dvd0p dvd1p andbT. case: (eqVneq n 0) => [-> | nn0]. by rewrite coprimep0; move/eqp_dvdl->; rewrite !mulr0 dvd1p. move=> hc; apply/idP/idP. move/Gauss_dvdpl: hc => <- h; move/(dvdp_mull m): (h); rewrite dvdp_mul2l //. move->; move/(dvdp_mulr n): (h); rewrite dvdp_mul2r // andbT. exact: dvdp_mulr. case/andP => dmp dnp; move: (dnp); rewrite dvdp_eq. set c2 := _ ^+ _; set q2 := _ %/ _; move/eqP=> e2. have := (sym_eq (Gauss_dvdpl q2 hc)); rewrite -e2. have -> : m %| c2 *: p by rewrite -mul_polyC dvdp_mull. rewrite dvdp_eq; set c3 := _ ^+ _; set q3 := _ %/ _; move/eqP=> e3. apply: (@eq_dvdp (c3 * c2) q3). by rewrite mulf_neq0 // expf_neq0 // lead_coef_eq0. by rewrite mulrA -e3 -scalerAl -e2 scalerA. Qed. Lemma Gauss_gcdpr p m n : coprimep p m -> gcdp p (m * n) %= gcdp p n. Proof. move=> co_pm; apply/eqP; rewrite /eqp !dvdp_gcd !dvdp_gcdl /= andbC. rewrite dvdp_mull ?dvdp_gcdr // -(@Gauss_dvdpl _ m). by rewrite mulrC dvdp_gcdr. apply/coprimepP=> d; rewrite dvdp_gcd; case/andP=> hdp _ hdm. by move/coprimepP: co_pm; apply. Qed. Lemma Gauss_gcdpl p m n : coprimep p n -> gcdp p (m * n) %= gcdp p m. Proof. by move=> co_pn; rewrite mulrC Gauss_gcdpr. Qed. Lemma coprimep_mulr p q r : coprimep p (q * r) = (coprimep p q && coprimep p r). Proof. apply/coprimepP/andP=> [hp|[/coprimepP hq hr]]. split; apply/coprimepP=> d dp dq; rewrite hp //; [exact: dvdp_mulr|exact: dvdp_mull]. move=> d dp dqr; move/(_ _ dp) in hq. rewrite Gauss_dvdpl in dqr; first exact: hq. by move/coprimep_dvdr:hr; apply. Qed. Lemma coprimep_mull p q r: coprimep (q * r) p = (coprimep q p && coprimep r p). Proof. by rewrite ![coprimep _ p]coprimep_sym coprimep_mulr. Qed. Lemma modp_coprime k u n : k != 0 -> (k * u) %% n %= 1 -> coprimep k n. Proof. move=> kn0 hmod; apply/Bezout_coprimepP. exists (((lead_coef n)^+(scalp (k * u) n) *: u), (- (k * u %/ n))). rewrite -scalerAl mulrC (divp_eq (u * k) n) mulNr -addrAC subrr add0r. by rewrite mulrC. Qed. Lemma coprimep_pexpl k m n : 0 < k -> coprimep (m ^+ k) n = coprimep m n. Proof. case: k => // k _; elim: k => [|k IHk]; first by rewrite expr1. by rewrite exprS coprimep_mull -IHk andbb. Qed. Lemma coprimep_pexpr k m n : 0 < k -> coprimep m (n ^+ k) = coprimep m n. Proof. by move=> k_gt0; rewrite !(coprimep_sym m) coprimep_pexpl. Qed. Lemma coprimep_expl k m n : coprimep m n -> coprimep (m ^+ k) n. Proof. by case: k => [|k] co_pm; rewrite ?coprime1p // coprimep_pexpl. Qed. Lemma coprimep_expr k m n : coprimep m n -> coprimep m (n ^+ k). Proof. by rewrite !(coprimep_sym m); exact: coprimep_expl. Qed. Lemma gcdp_mul2l p q r : gcdp (p * q) (p * r) %= (p * gcdp q r). Proof. case: (eqVneq p 0)=> [->|hp]; first by rewrite !mul0r gcdp0 eqpxx. rewrite /eqp !dvdp_gcd !dvdp_mul2l // dvdp_gcdr dvdp_gcdl !andbT. move: (Bezoutp q r) => [[u v]] huv. rewrite eqp_sym in huv; rewrite (eqp_dvdr _ (eqp_mull _ huv)). rewrite mulrDr ![p * (_ * _)]mulrCA. by apply: dvdp_add; rewrite dvdp_mull// (dvdp_gcdr, dvdp_gcdl). Qed. Lemma gcdp_mul2r q r p : gcdp (q * p) (r * p) %= (gcdp q r * p). Proof. by rewrite ![_ * p]GRing.mulrC gcdp_mul2l. Qed. Lemma mulp_gcdr p q r : r * (gcdp p q) %= gcdp (r * p) (r * q). Proof. by rewrite eqp_sym gcdp_mul2l. Qed. Lemma mulp_gcdl p q r : (gcdp p q) * r %= gcdp (p * r) (q * r). Proof. by rewrite eqp_sym gcdp_mul2r. Qed. Lemma coprimep_div_gcd p q : (p != 0) || (q != 0) -> coprimep (p %/ (gcdp p q)) (q %/ gcdp p q). Proof. move=> hpq. have gpq0: gcdp p q != 0 by rewrite gcdp_eq0 negb_and. rewrite -gcdp_eqp1 -(@eqp_mul2r (gcdp p q)) // mul1r. have: gcdp p q %| p by rewrite dvdp_gcdl. have: gcdp p q %| q by rewrite dvdp_gcdr. rewrite !dvdp_eq eq_sym; move/eqP=> hq; rewrite eq_sym; move/eqP=> hp. rewrite (eqp_ltrans (mulp_gcdl _ _ _)) hq hp. have lcn0 k : (lead_coef (gcdp p q)) ^+ k != 0. by rewrite expf_neq0 ?lead_coef_eq0. by apply: eqp_gcd; rewrite ?eqp_scale. Qed. Lemma divp_eq0 p q : (p %/ q == 0) = [|| p == 0, q ==0 | size p < size q]. Proof. apply/eqP/idP=> [d0|]; last first. case/or3P; [by move/eqP->; rewrite div0p| by move/eqP->; rewrite divp0|]. by move/divp_small. case: (eqVneq p 0) => [->|pn0]; first by rewrite eqxx. case: (eqVneq q 0) => [-> | qn0]; first by rewrite eqxx orbT. move: (divp_eq p q); rewrite d0 mul0r add0r. move/(f_equal (fun x : {poly R} => size x)). by rewrite size_scale ?lc_expn_scalp_neq0 // => ->; rewrite ltn_modp qn0 !orbT. Qed. Lemma dvdp_div_eq0 p q : q %| p -> (p %/ q == 0) = (p == 0). Proof. move=> dvdp_qp; have [->|p_neq0] := altP (p =P 0); first by rewrite div0p eqxx. rewrite divp_eq0 ltnNge dvdp_leq // (negPf p_neq0) orbF /=. by apply: contraTF dvdp_qp=> /eqP ->; rewrite dvd0p. Qed. Lemma Bezout_coprimepPn p q : p != 0 -> q != 0 -> reflect (exists2 uv : {poly R} * {poly R}, (0 < size uv.1 < size q) && (0 < size uv.2 < size p) & uv.1 * p = uv.2 * q) (~~ (coprimep p q)). move=> pn0 qn0; apply: (iffP idP); last first. case=> [[u v] /= /andP [/andP [ps1 s1] /andP [ps2 s2]] e]. have: ~~(size (q * p) <= size (u * p)). rewrite -ltnNge !size_mul // -?size_poly_gt0 // (polySpred pn0) !addnS. by rewrite ltn_add2r. apply: contra => ?; apply: dvdp_leq; rewrite ?mulf_neq0 // -?size_poly_gt0 //. by rewrite mulrC Gauss_dvdp // dvdp_mull // e dvdp_mull. rewrite coprimep_def neq_ltn. case/orP; first by rewrite ltnS leqn0 size_poly_eq0 gcdp_eq0 -[p == 0]negbK pn0. case sg: (size (gcdp p q)) => [|n] //; case: n sg=> [|n] // sg _. move: (dvdp_gcdl p q); rewrite dvdp_eq; set c1 := _ ^+ _; move/eqP=> hu1. move: (dvdp_gcdr p q); rewrite dvdp_eq; set c2 := _ ^+ _; move/eqP=> hv1. exists (c1 *: (q %/ gcdp p q), c2 *: (p %/ gcdp p q)); last first. by rewrite -!{1}scalerAl !scalerAr hu1 hv1 mulrCA. rewrite !{1}size_scale ?lc_expn_scalp_neq0 //= !size_poly_gt0 !divp_eq0. rewrite gcdp_eq0 !(negPf pn0) !(negPf qn0) /= -!leqNgt leq_gcdpl //. rewrite leq_gcdpr //= !ltn_divpl -?size_poly_eq0 ?sg //. rewrite !size_mul // -?size_poly_eq0 ?sg // ![(_ + n.+2)%N]addnS /=. by rewrite -{1}(addn0 (size p)) -{1}(addn0 (size q)) !ltn_add2l. Qed. Lemma dvdp_pexp2r m n k : k > 0 -> (m ^+ k %| n ^+ k) = (m %| n). Proof. move=> k_gt0; apply/idP/idP; last exact: dvdp_exp2r. case: (eqVneq n 0) => [-> | nn0] //; case: (eqVneq m 0) => [-> | mn0]. move/prednK: k_gt0=> {1}<-; rewrite exprS mul0r //= !dvd0p expf_eq0. by case/andP=> _ ->. set d := gcdp m n; have := (dvdp_gcdr m n); rewrite -/d dvdp_eq. set c1 := _ ^+ _; set n' := _ %/ _; move/eqP=> def_n. have := (dvdp_gcdl m n); rewrite -/d dvdp_eq. set c2 := _ ^+ _; set m' := _ %/ _; move/eqP=> def_m. have dn0 : d != 0 by rewrite gcdp_eq0 negb_and nn0 orbT. have c1n0 : c1 != 0 by rewrite !expf_neq0 // lead_coef_eq0. have c2n0 : c2 != 0 by rewrite !expf_neq0 // lead_coef_eq0. rewrite -(@dvdp_scaler (c1 ^+ k)) ?expf_neq0 ?lead_coef_eq0 //. have c2k_n0 : c2 ^+ k != 0 by rewrite !expf_neq0 // lead_coef_eq0. rewrite -(@dvdp_scalel (c2 ^+k)) // -!exprZn def_m def_n !exprMn. rewrite dvdp_mul2r ?expf_neq0 //. have: coprimep (m' ^+ k) (n' ^+ k). rewrite coprimep_pexpl // coprimep_pexpr //; apply: coprimep_div_gcd. by rewrite nn0 orbT. move/coprimepP=> hc hd. have /size_poly1P [c cn0 em'] : size m' == 1%N. case: (eqVneq m' 0) => [m'0 |m'_n0]. move/eqP: def_m; rewrite m'0 mul0r scale_poly_eq0. by rewrite (negPf mn0) (negPf c2n0). have := (hc _ (dvdpp _) hd); rewrite -size_poly_eq1. rewrite polySpred; last by rewrite expf_eq0 negb_and m'_n0 orbT. rewrite size_exp eqSS muln_eq0; move: k_gt0; rewrite lt0n; move/negPf->. by rewrite orbF -{2}(@prednK (size m')) ?lt0n // size_poly_eq0. rewrite -(@dvdp_scalel c2) // def_m em' mul_polyC dvdp_scalel //. by rewrite -(@dvdp_scaler c1) // def_n dvdp_mull. Qed. Lemma root_gcd p q x : root (gcdp p q) x = root p x && root q x. Proof. rewrite /= !root_factor_theorem; apply/idP/andP=> [dg| [dp dq]]. by split; apply: dvdp_trans dg _; rewrite ?(dvdp_gcdl, dvdp_gcdr). have:= (Bezoutp p q)=> [[[u v]]]; rewrite eqp_sym=> e. by rewrite (eqp_dvdr _ e) dvdp_addl dvdp_mull. Qed. Lemma root_biggcd : forall x (ps : seq {poly R}), root (\big[gcdp/0]_(p <- ps) p) x = all (fun p => root p x) ps. Proof. move=> x; elim; first by rewrite big_nil root0. by move=> p ps ihp; rewrite big_cons /= root_gcd ihp. Qed. (* "gdcop Q P" is the Greatest Divisor of P which is coprime to Q *) (* if P null, we pose that gdcop returns 1 if Q null, 0 otherwise*) Fixpoint gdcop_rec q p k := if k is m.+1 then if coprimep p q then p else gdcop_rec q (divp p (gcdp p q)) m else (q == 0)%:R. Definition gdcop q p := gdcop_rec q p (size p). CoInductive gdcop_spec q p : {poly R} -> Type := GdcopSpec r of (dvdp r p) & ((coprimep r q) || (p == 0)) & (forall d, dvdp d p -> coprimep d q -> dvdp d r) : gdcop_spec q p r. Lemma gdcop0 q : gdcop q 0 = (q == 0)%:R. Proof. by rewrite /gdcop size_poly0. Qed. Lemma gdcop_recP : forall q p k, size p <= k -> gdcop_spec q p (gdcop_rec q p k). Proof. move=> q p k; elim: k p => [p | k ihk p] /=. rewrite leqn0 size_poly_eq0; move/eqP->. case q0: (_ == _); split; rewrite ?coprime1p // ?eqxx ?orbT //. by move=> d _; rewrite (eqP q0) coprimep0 dvdp1 size_poly_eq1. move=> hs; case cop : (coprimep _ _); first by split; rewrite ?dvdpp ?cop. case (eqVneq p 0) => [-> | p0]. by rewrite div0p; apply: ihk; rewrite size_poly0 leq0n. case: (eqVneq q 0) => [-> | q0]. rewrite gcdp0 divpp ?p0 //= => {hs ihk}; case: k=> /=. rewrite eqxx; split; rewrite ?dvd1p ?coprimep0 ?eqpxx //=. by move=> d _; rewrite coprimep0 dvdp1 size_poly_eq1. move=> n; rewrite coprimep0 polyC_eqp1 //; rewrite lc_expn_scalp_neq0. split; first by rewrite (@eqp_dvdl 1) ?dvd1p // polyC_eqp1 lc_expn_scalp_neq0. by rewrite coprimep0 polyC_eqp1 // ?lc_expn_scalp_neq0. by move=> d _; rewrite coprimep0; move/eqp_dvdl->; rewrite dvd1p. move: (dvdp_gcdl p q); rewrite dvdp_eq; move/eqP=> e. have sgp : size (gcdp p q) <= size p. by apply: dvdp_leq; rewrite ?gcdp_eq0 ?p0 ?q0 // dvdp_gcdl. have : p %/ gcdp p q != 0; last move/negPf=>p'n0. move: (dvdp_mulIl (p %/ gcdp p q) (gcdp p q)); move/dvdpN0; apply; rewrite -e. by rewrite scale_poly_eq0 negb_or lc_expn_scalp_neq0. have gn0 : gcdp p q != 0. move: (dvdp_mulIr (p %/ gcdp p q) (gcdp p q)); move/dvdpN0; apply; rewrite -e. by rewrite scale_poly_eq0 negb_or lc_expn_scalp_neq0. have sp' : size (p %/ (gcdp p q)) <= k. rewrite size_divp ?sgp // leq_subLR (leq_trans hs)//. rewrite -subn_gt0 addnK -subn1 ltn_subRL addn0 ltnNge leq_eqVlt. by rewrite [_ == _]cop ltnS leqn0 size_poly_eq0 (negPf gn0). case (ihk _ sp')=> r' dr'p'; first rewrite p'n0 orbF=> cr'q maxr'. constructor=> //=; rewrite ?(negPf p0) ?orbF //. apply: (dvdp_trans dr'p'); apply: divp_dvd; exact: dvdp_gcdl. move=> d dp cdq; apply: maxr'; last by rewrite cdq. case dpq: (d %| gcdp p q). move: (dpq); rewrite dvdp_gcd dp /= => dq; apply: dvdUp; move: cdq. apply: contraLR=> nd1; apply/coprimepPn; last first. by exists d; rewrite dvdp_gcd dvdpp dq nd1. move/negP: p0; move/negP; apply: contra=> d0; move:dp; rewrite (eqP d0). by rewrite dvd0p. move: (dp); apply: contraLR=> ndp'. rewrite (@eqp_dvdr ((lead_coef (gcdp p q) ^+ scalp p (gcdp p q))*:p)). by rewrite e; rewrite Gauss_dvdpl //; apply: (coprimep_dvdl (dvdp_gcdr _ _)). by rewrite eqp_sym eqp_scale // lc_expn_scalp_neq0. Qed. Lemma gdcopP q p : gdcop_spec q p (gdcop q p). Proof. by rewrite /gdcop; apply: gdcop_recP. Qed. Lemma coprimep_gdco p q : (q != 0)%B -> coprimep (gdcop p q) p. Proof. by move=> q_neq0; case: gdcopP=> d; rewrite (negPf q_neq0) orbF. Qed. Lemma size2_dvdp_gdco p q d : p != 0 -> size d = 2%N -> (d %| (gdcop q p)) = (d %| p) && ~~(d %| q). Proof. case: (eqVneq d 0) => [-> | dn0]; first by rewrite size_poly0. move=> p0 sd; apply/idP/idP. case: gdcopP=> r rp crq maxr dr; move/negPf: (p0)=> p0f. rewrite (dvdp_trans dr) //=. move: crq; apply: contraL=> dq; rewrite p0f orbF; apply/coprimepPn. by move:p0; apply: contra=> r0; move: rp; rewrite (eqP r0) dvd0p. by exists d; rewrite dvdp_gcd dr dq -size_poly_eq1 sd. case/andP=> dp dq; case: gdcopP=> r rp crq maxr; apply: maxr=> //. apply/coprimepP=> x xd xq. move: (dvdp_leq dn0 xd); rewrite leq_eqVlt sd; case/orP; last first. rewrite ltnS leq_eqVlt; case/orP; first by rewrite -size_poly_eq1. rewrite ltnS leqn0 size_poly_eq0; move/eqP=> x0; move: xd; rewrite x0 dvd0p. by rewrite (negPf dn0). by rewrite -sd dvdp_size_eqp //; move/(eqp_dvdl q); rewrite xq (negPf dq). Qed. Lemma dvdp_gdco p q : (gdcop p q) %| q. Proof. by case: gdcopP. Qed. Lemma root_gdco p q x : p != 0 -> root (gdcop q p) x = root p x && ~~(root q x). Proof. move=> p0 /=; rewrite !root_factor_theorem. apply: size2_dvdp_gdco; rewrite ?p0 //. by rewrite size_addl size_polyX // size_opp size_polyC ltnS; case: (x != 0). Qed. Lemma dvdp_comp_poly r p q : (p %| q) -> (p \Po r) %| (q \Po r). Proof. case: (eqVneq p 0) => [-> | pn0]. by rewrite comp_poly0 !dvd0p; move/eqP->; rewrite comp_poly0. rewrite dvdp_eq; set c := _ ^+ _; set s := _ %/ _; move/eqP=> Hq. apply: (@eq_dvdp c (s \Po r)); first by rewrite expf_neq0 // lead_coef_eq0. by rewrite -comp_polyZ Hq comp_polyM. Qed. Lemma gcdp_comp_poly r p q : gcdp p q \Po r %= gcdp (p \Po r) (q \Po r). Proof. apply/andP; split. by rewrite dvdp_gcd !dvdp_comp_poly ?dvdp_gcdl ?dvdp_gcdr. case: (Bezoutp p q) => [[u v]] /andP []. move/(dvdp_comp_poly r) => Huv _. rewrite (dvdp_trans _ Huv) // comp_polyD !comp_polyM. by rewrite dvdp_add // dvdp_mull // (dvdp_gcdl,dvdp_gcdr). Qed. Lemma coprimep_comp_poly r p q : coprimep p q -> coprimep (p \Po r) (q \Po r). Proof. rewrite -!gcdp_eqp1 -!size_poly_eq1 -!dvdp1; move/(dvdp_comp_poly r). rewrite comp_polyC => Hgcd. by apply: dvdp_trans Hgcd; case/andP: (gcdp_comp_poly r p q). Qed. Lemma coprimep_addl_mul p q r : coprimep r (p * r + q) = coprimep r q. Proof. by rewrite !coprimep_def (eqp_size (gcdp_addl_mul _ _ _)). Qed. Definition irreducible_poly p := (size p > 1) * (forall q, size q != 1%N -> q %| p -> q %= p) : Prop. Lemma irredp_neq0 p : irreducible_poly p -> p != 0. Proof. by rewrite -size_poly_eq0 -lt0n => [[/ltnW]]. Qed. Definition apply_irredp p (irr_p : irreducible_poly p) := irr_p.2. Coercion apply_irredp : irreducible_poly >-> Funclass. Lemma modp_XsubC p c : p %% ('X - c%:P) = p.[c]%:P. Proof. have: root (p - p.[c]%:P) c by rewrite /root !hornerE subrr. case/factor_theorem=> q /(canRL (subrK _)) Dp; rewrite modpE /= lead_coefXsubC. rewrite GRing.unitr1 expr1n invr1 scale1r {1}Dp. rewrite RingMonic.rmodp_addl_mul_small // ?monicXsubC // size_XsubC size_polyC. by case: (p.[c] == 0). Qed. Lemma coprimep_XsubC p c : coprimep p ('X - c%:P) = ~~ root p c. Proof. rewrite -coprimep_modl modp_XsubC /root -alg_polyC. have [-> | /coprimep_scalel->] := altP eqP; last exact: coprime1p. by rewrite scale0r /coprimep gcd0p size_XsubC. Qed. Lemma coprimepX p : coprimep p 'X = ~~ root p 0. Proof. by rewrite -['X]subr0 coprimep_XsubC. Qed. Lemma eqp_monic : {in monic &, forall p q, (p %= q) = (p == q)}. Proof. move=> p q monic_p monic_q; apply/idP/eqP=> [|-> //]. case/eqpP=> [[a b] /= /andP[a_neq0 _] eq_pq]. apply: (@mulfI _ a%:P); first by rewrite polyC_eq0. rewrite !mul_polyC eq_pq; congr (_ *: q); apply: (mulIf (oner_neq0 _)). by rewrite -{1}(monicP monic_q) -(monicP monic_p) -!lead_coefZ eq_pq. Qed. Lemma dvdp_mul_XsubC p q c : (p %| ('X - c%:P) * q) = ((if root p c then p %/ ('X - c%:P) else p) %| q). Proof. case: ifPn => [| not_pc0]; last by rewrite Gauss_dvdpr ?coprimep_XsubC. rewrite root_factor_theorem -eqp_div_XsubC mulrC => /eqP{1}->. by rewrite dvdp_mul2l ?polyXsubC_eq0. Qed. Lemma dvdp_prod_XsubC (I : Type) (r : seq I) (F : I -> R) p : p %| \prod_(i <- r) ('X - (F i)%:P) -> {m | p %= \prod_(i <- mask m r) ('X - (F i)%:P)}. Proof. elim: r => [|i r IHr] in p *. by rewrite big_nil dvdp1; exists nil; rewrite // big_nil -size_poly_eq1. rewrite big_cons dvdp_mul_XsubC root_factor_theorem -eqp_div_XsubC. case: eqP => [{2}-> | _] /IHr[m Dp]; last by exists (false :: m). by exists (true :: m); rewrite /= mulrC big_cons eqp_mul2l ?polyXsubC_eq0. Qed. Lemma irredp_XsubC (x : R) : irreducible_poly ('X - x%:P). Proof. split=> [|d size_d d_dv_Xx]; first by rewrite size_XsubC. have: ~ d %= 1 by apply/negP; rewrite -size_poly_eq1. have [|m /=] := @dvdp_prod_XsubC _ [:: x] id d; first by rewrite big_seq1. by case: m => [|[] [|_ _] /=]; rewrite (big_nil, big_seq1). Qed. Lemma irredp_XsubCP d p : irreducible_poly p -> d %| p -> {d %= 1} + {d %= p}. Proof. move=> irred_p dvd_dp; have [] := boolP (_ %= 1); first by left. by rewrite -size_poly_eq1=> /irred_p /(_ dvd_dp); right. Qed. End IDomainPseudoDivision. Hint Resolve eqpxx divp0 divp1 mod0p modp0 modp1 dvdp_mull dvdp_mulr dvdpp. Hint Resolve dvdp0. End CommonIdomain. Module Idomain. Include IdomainDefs. Export IdomainDefs. Include WeakIdomain. Include CommonIdomain. End Idomain. Module IdomainMonic. Import Ring ComRing UnitRing IdomainDefs Idomain. Section MonicDivisor. Variable R : idomainType. Variable q : {poly R}. Hypothesis monq : q \is monic. Implicit Type p d r : {poly R}. Lemma divpE p : p %/ q = rdivp p q. Proof. by rewrite divpE (eqP monq) unitr1 expr1n invr1 scale1r. Qed. Lemma modpE p : p %% q = rmodp p q. Proof. by rewrite modpE (eqP monq) unitr1 expr1n invr1 scale1r. Qed. Lemma scalpE p : scalp p q = 0%N. Proof. by rewrite scalpE (eqP monq) unitr1. Qed. Lemma divp_eq p : p = (p %/ q) * q + (p %% q). Proof. by rewrite -divp_eq (eqP monq) expr1n scale1r. Qed. Lemma divpp p : q %/ q = 1. Proof. by rewrite divpp ?monic_neq0 // (eqP monq) expr1n. Qed. Lemma dvdp_eq p : (q %| p) = (p == (p %/ q) * q). Proof. by rewrite dvdp_eq (eqP monq) expr1n scale1r. Qed. Lemma dvdpP p : reflect (exists qq, p = qq * q) (q %| p). Proof. apply: (iffP idP); first by rewrite dvdp_eq; move/eqP=> e; exists (p %/ q). by case=> qq ->; rewrite dvdp_mull // dvdpp. Qed. Lemma mulpK p : p * q %/ q = p. Proof. by rewrite mulpK ?monic_neq0 // (eqP monq) expr1n scale1r. Qed. Lemma mulKp p : q * p %/ q = p. Proof. by rewrite mulrC; exact: mulpK. Qed. End MonicDivisor. End IdomainMonic. Module IdomainUnit. Import Ring ComRing UnitRing IdomainDefs Idomain. Section UnitDivisor. Variable R : idomainType. Variable d : {poly R}. Hypothesis ulcd : lead_coef d \in GRing.unit. Implicit Type p q r : {poly R}. Lemma divp_eq p : p = (p %/ d) * d + (p %% d). Proof. by have := (divp_eq p d); rewrite scalpE ulcd expr0 scale1r. Qed. Lemma edivpP p q r : p = q * d + r -> size r < size d -> q = (p %/ d) /\ r = p %% d. Proof. move=> ep srd; have := (divp_eq p); rewrite {1}ep. move/eqP; rewrite -subr_eq -addrA addrC eq_sym -subr_eq -mulrBl; move/eqP. have lcdn0 : lead_coef d != 0 by apply: contraTneq ulcd => ->; rewrite unitr0. case abs: (p %/ d - q == 0). move: abs; rewrite subr_eq0; move/eqP->; rewrite subrr mul0r; move/eqP. by rewrite eq_sym subr_eq0; move/eqP->. have hleq : size d <= size ((p %/ d - q) * d). rewrite size_proper_mul; last first. by rewrite mulf_eq0 (negPf lcdn0) orbF lead_coef_eq0 abs. move: abs; rewrite -size_poly_eq0; move/negbT; rewrite -lt0n; move/prednK<-. by rewrite addSn /= leq_addl. have hlt : size (r - p %% d) < size d. apply: leq_ltn_trans (size_add _ _) _; rewrite size_opp. by rewrite gtn_max srd ltn_modp /= -lead_coef_eq0. by move=> e; have:= (leq_trans hlt hleq); rewrite e ltnn. Qed. Lemma divpP p q r : p = q * d + r -> size r < size d -> q = (p %/ d). Proof. by move/edivpP=> h; case/h. Qed. Lemma modpP p q r : p = q * d + r -> size r < size d -> r = (p %% d). Proof. by move/edivpP=> h; case/h. Qed. Lemma ulc_eqpP p q : lead_coef q \is a GRing.unit -> reflect (exists2 c : R, c != 0 & p = c *: q) (p %= q). Proof. case: (altP (lead_coef q =P 0)) => [->|]; first by rewrite unitr0. rewrite lead_coef_eq0 => nz_q ulcq; apply: (iffP idP). case: (altP (p =P 0)) => [->|nz_p]. by rewrite eqp_sym eqp0 (negbTE nz_q). move/eqp_eq=> eq; exists (lead_coef p / lead_coef q). by rewrite mulf_neq0 // ?invr_eq0 lead_coef_eq0. by apply/(scaler_injl ulcq); rewrite scalerA mulrCA divrr // mulr1. by case=> c nz_c ->; apply/eqpP; exists (1, c); rewrite ?scale1r ?oner_eq0. Qed. Lemma dvdp_eq p : (d %| p) = (p == p %/ d * d). Proof. apply/eqP/eqP=> [modp0 | ->]; last exact: modp_mull. by rewrite {1}(divp_eq p) modp0 addr0. Qed. Lemma ucl_eqp_eq p q : lead_coef q \is a GRing.unit -> p %= q -> p = (lead_coef p / lead_coef q) *: q. Proof. move=> ulcq /eqp_eq; move/(congr1 ( *:%R (lead_coef q)^-1 )). by rewrite !scalerA mulrC divrr // scale1r mulrC. Qed. Lemma modp_scalel c p : (c *: p) %% d = c *: (p %% d). Proof. case: (altP (c =P 0)) => [-> | cn0]; first by rewrite !scale0r mod0p. have e : (c *: p) = (c *: (p %/ d)) * d + c *: (p %% d). by rewrite -scalerAl -scalerDr -divp_eq. have s: size (c *: (p %% d)) < size d. rewrite -mul_polyC; apply: leq_ltn_trans (size_mul_leq _ _) _. rewrite size_polyC cn0 addSn add0n /= ltn_modp. by rewrite -lead_coef_eq0; apply: contraTneq ulcd => ->; rewrite unitr0. by case: (edivpP e s) => _ ->. Qed. Lemma divp_scalel c p : (c *: p) %/ d = c *: (p %/ d). Proof. case: (altP (c =P 0)) => [-> | cn0]; first by rewrite !scale0r div0p. have e : (c *: p) = (c *: (p %/ d)) * d + c *: (p %% d). by rewrite -scalerAl -scalerDr -divp_eq. have s: size (c *: (p %% d)) < size d. rewrite -mul_polyC; apply: leq_ltn_trans (size_mul_leq _ _) _. rewrite size_polyC cn0 addSn add0n /= ltn_modp. by rewrite -lead_coef_eq0; apply: contraTneq ulcd => ->; rewrite unitr0. by case: (edivpP e s) => ->. Qed. Lemma eqp_modpl p q : p %= q -> (p %% d) %= (q %% d). Proof. case/eqpP=> [[c1 c2]] /andP /= [c1n0 c2n0 e]. by apply/eqpP; exists (c1, c2); rewrite ?c1n0 //= -!modp_scalel e. Qed. Lemma eqp_divl p q : p %= q -> (p %/ d) %= (q %/ d). Proof. case/eqpP=> [[c1 c2]] /andP /= [c1n0 c2n0 e]. by apply/eqpP; exists (c1, c2); rewrite ?c1n0 // -!divp_scalel e. Qed. Lemma modp_opp p : (- p) %% d = - (p %% d). Proof. by rewrite -mulN1r -[- (_ %% _)]mulN1r -polyC_opp !mul_polyC modp_scalel. Qed. Lemma divp_opp p : (- p) %/ d = - (p %/ d). Proof. by rewrite -mulN1r -[- (_ %/ _)]mulN1r -polyC_opp !mul_polyC divp_scalel. Qed. Lemma modp_add p q : (p + q) %% d = p %% d + q %% d. Proof. have hs : size (p %% d + q %% d) < size d. apply: leq_ltn_trans (size_add _ _) _. rewrite gtn_max !ltn_modp andbb -lead_coef_eq0. by apply: contraTneq ulcd => ->; rewrite unitr0. have he : (p + q) = (p %/ d + q %/ d) * d + (p %% d + q %% d). rewrite {1}(divp_eq p) {1}(divp_eq q) addrAC addrA -mulrDl. by rewrite [_ %% _ + _]addrC addrA. by case: (edivpP he hs). Qed. Lemma divp_add p q : (p + q) %/ d = p %/ d + q %/ d. Proof. have hs : size (p %% d + q %% d) < size d. apply: leq_ltn_trans (size_add _ _) _. rewrite gtn_max !ltn_modp andbb -lead_coef_eq0. by apply: contraTneq ulcd => ->; rewrite unitr0. have he : (p + q) = (p %/ d + q %/ d) * d + (p %% d + q %% d). rewrite {1}(divp_eq p) {1}(divp_eq q) addrAC addrA -mulrDl. by rewrite [_ %% _ + _]addrC addrA. by case: (edivpP he hs). Qed. Lemma mulpK q : (q * d) %/ d = q. Proof. case/edivpP: (sym_eq (addr0 (q * d))); rewrite // size_poly0 size_poly_gt0. by rewrite -lead_coef_eq0; apply: contraTneq ulcd => ->; rewrite unitr0. Qed. Lemma mulKp q : (d * q) %/ d = q. Proof. rewrite mulrC; exact: mulpK. Qed. Lemma divp_addl_mul_small q r : size r < size d -> (q * d + r) %/ d = q. Proof. by move=> srd; rewrite divp_add (divp_small srd) addr0 mulpK. Qed. Lemma modp_addl_mul_small q r : size r < size d -> (q * d + r) %% d = r. Proof. by move=> srd; rewrite modp_add modp_mull add0r modp_small. Qed. Lemma divp_addl_mul q r : (q * d + r) %/ d = q + r %/ d. Proof. by rewrite divp_add mulpK. Qed. Lemma divpp : d %/ d = 1. Proof. by rewrite -{1}(mul1r d) mulpK. Qed. Lemma leq_trunc_divp m : size (m %/ d * d) <= size m. Proof. have dn0 : d != 0. by rewrite -lead_coef_eq0; apply: contraTneq ulcd => ->; rewrite unitr0. case q0 : (m %/ d == 0); first by rewrite (eqP q0) mul0r size_poly0 leq0n. rewrite {2}(divp_eq m) size_addl // size_mul ?q0 //; move/negbT: q0. rewrite -size_poly_gt0; move/prednK<-; rewrite addSn /=. by move: dn0; rewrite -(ltn_modp m); move/ltn_addl->. Qed. Lemma dvdpP p : reflect (exists q, p = q * d) (d %| p). Proof. apply: (iffP idP) => [| [k ->]]; last by apply/eqP; rewrite modp_mull. by rewrite dvdp_eq; move/eqP->; exists (p %/ d). Qed. Lemma divpK p : d %| p -> p %/ d * d = p. Proof. by rewrite dvdp_eq; move/eqP. Qed. Lemma divpKC p : d %| p -> d * (p %/ d) = p. Proof. by move=> ?; rewrite mulrC divpK. Qed. Lemma dvdp_eq_div p q : d %| p -> (q == p %/ d) = (q * d == p). Proof. move/divpK=> {2}<-; apply/eqP/eqP; first by move->. suff dn0 : d != 0 by move/(mulIf dn0). by rewrite -lead_coef_eq0; apply: contraTneq ulcd => ->; rewrite unitr0. Qed. Lemma dvdp_eq_mul p q : d %| p -> (p == q * d) = (p %/ d == q). Proof. by move=>dv_d_p; rewrite eq_sym -dvdp_eq_div // eq_sym. Qed. Lemma divp_mulA p q : d %| q -> p * (q %/ d) = p * q %/ d. Proof. move=> hdm; apply/eqP; rewrite eq_sym -dvdp_eq_mul. by rewrite -mulrA divpK. by move/divpK: hdm<-; rewrite mulrA dvdp_mull // dvdpp. Qed. Lemma divp_mulAC m n : d %| m -> m %/ d * n = m * n %/ d. Proof. by move=> hdm; rewrite mulrC (mulrC m); exact: divp_mulA. Qed. Lemma divp_mulCA p q : d %| p -> d %| q -> p * (q %/ d) = q * (p %/ d). Proof. by move=> hdp hdq; rewrite mulrC divp_mulAC // divp_mulA. Qed. Lemma modp_mul p q : (p * (q %% d)) %% d = (p * q) %% d. Proof. have -> : q %% d = q - q %/ d * d by rewrite {2}(divp_eq q) -addrA addrC subrK. rewrite mulrDr modp_add // -mulNr mulrA -{2}[_ %% _]addr0; congr (_ + _). by apply/eqP; apply: dvdp_mull; exact: dvdpp. Qed. End UnitDivisor. Section MoreUnitDivisor. Variable R : idomainType. Variable d : {poly R}. Hypothesis ulcd : lead_coef d \in GRing.unit. Implicit Types p q : {poly R}. Lemma expp_sub m n : n <= m -> (d ^+ (m - n))%N = d ^+ m %/ d ^+ n. Proof. by move/subnK=> {2}<-; rewrite exprD mulpK // lead_coef_exp unitrX. Qed. Lemma divp_pmul2l p q : lead_coef q \in GRing.unit -> d * p %/ (d * q) = p %/ q. Proof. move=> uq. have udq: lead_coef (d * q) \in GRing.unit. by rewrite lead_coefM unitrM_comm ?ulcd //; red; rewrite mulrC. rewrite {1}(divp_eq uq p) mulrDr mulrCA divp_addl_mul //. have dn0 : d != 0. by rewrite -lead_coef_eq0; apply: contraTneq ulcd => ->; rewrite unitr0. have qn0 : q != 0. by rewrite -lead_coef_eq0; apply: contraTneq uq => ->; rewrite unitr0. have dqn0 : d * q != 0 by rewrite mulf_eq0 negb_or dn0. suff : size (d * (p %% q)) < size (d * q). by rewrite ltnNge -divpN0 // negbK => /eqP ->; rewrite addr0. case: (altP ( (p %% q) =P 0)) => [-> | rn0]. by rewrite mulr0 size_poly0 size_poly_gt0. rewrite !size_mul //; move: dn0; rewrite -size_poly_gt0. by move/prednK<-; rewrite !addSn /= ltn_add2l ltn_modp. Qed. Lemma divp_pmul2r p q : lead_coef p \in GRing.unit -> q * d %/ (p * d) = q %/ p. Proof. by move=> uq; rewrite -!(mulrC d) divp_pmul2l. Qed. Lemma divp_divl r p q : lead_coef r \in GRing.unit -> lead_coef p \in GRing.unit -> q %/ p %/ r = q %/ (p * r). Proof. move=> ulcr ulcp. have e : q = (q %/ p %/ r) * (p * r) + ((q %/ p) %% r * p + q %% p). rewrite addrA (mulrC p) mulrA -mulrDl; rewrite -divp_eq //; exact: divp_eq. have pn0 : p != 0. by rewrite -lead_coef_eq0; apply: contraTneq ulcp => ->; rewrite unitr0. have rn0 : r != 0. by rewrite -lead_coef_eq0; apply: contraTneq ulcr => ->; rewrite unitr0. have s : size ((q %/ p) %% r * p + q %% p) < size (p * r). case: (altP ((q %/ p) %% r =P 0)) => [-> | qn0]. rewrite mul0r add0r size_mul // (polySpred rn0) addnS /=. by apply: leq_trans (leq_addr _ _); rewrite ltn_modp. rewrite size_addl mulrC. by rewrite !size_mul // (polySpred pn0) !addSn /= ltn_add2l ltn_modp. rewrite size_mul // (polySpred qn0) addnS /=. by apply: leq_trans (leq_addr _ _); rewrite ltn_modp. case: (edivpP _ e s) => //; rewrite lead_coefM unitrM_comm ?ulcp //. by red; rewrite mulrC. Qed. Lemma divpAC p q : lead_coef p \in GRing.unit -> q %/ d %/ p = q %/ p %/ d. Proof. by move=> ulcp; rewrite !divp_divl // mulrC. Qed. Lemma modp_scaler c p : c \in GRing.unit -> p %% (c *: d) = (p %% d). Proof. move=> cn0; case: (eqVneq d 0) => [-> | dn0]; first by rewrite scaler0 !modp0. have e : p = (c^-1 *: (p %/ d)) * (c *: d) + (p %% d). by rewrite scalerCA scalerA mulVr // scale1r -(divp_eq ulcd). suff s : size (p %% d) < size (c *: d). by rewrite (modpP _ e s) // -mul_polyC lead_coefM lead_coefC unitrM cn0. by rewrite size_scale ?ltn_modp //; apply: contraTneq cn0 => ->; rewrite unitr0. Qed. Lemma divp_scaler c p : c \in GRing.unit -> p %/ (c *: d) = c^-1 *: (p %/ d). Proof. move=> cn0; case: (eqVneq d 0) => [-> | dn0]. by rewrite scaler0 !divp0 scaler0. have e : p = (c^-1 *: (p %/ d)) * (c *: d) + (p %% d). by rewrite scalerCA scalerA mulVr // scale1r -(divp_eq ulcd). suff s : size (p %% d) < size (c *: d). by rewrite (divpP _ e s) // -mul_polyC lead_coefM lead_coefC unitrM cn0. by rewrite size_scale ?ltn_modp //; apply: contraTneq cn0 => ->; rewrite unitr0. Qed. End MoreUnitDivisor. End IdomainUnit. Module Field. Import Ring ComRing UnitRing. Include IdomainDefs. Export IdomainDefs. Include CommonIdomain. Section FieldDivision. Variable F : fieldType. Implicit Type p q r d : {poly F}. Lemma divp_eq p q : p = (p %/ q) * q + (p %% q). Proof. case: (eqVneq q 0) => [-> | qn0]; first by rewrite modp0 mulr0 add0r. by apply: IdomainUnit.divp_eq; rewrite unitfE lead_coef_eq0. Qed. Lemma divp_modpP p q d r : p = q * d + r -> size r < size d -> q = (p %/ d) /\ r = p %% d. Proof. move=> he hs; apply: IdomainUnit.edivpP => //; rewrite unitfE lead_coef_eq0. by rewrite -size_poly_gt0; apply: leq_trans hs. Qed. Lemma divpP p q d r : p = q * d + r -> size r < size d -> q = (p %/ d). Proof. by move/divp_modpP=> h; case/h. Qed. Lemma modpP p q d r : p = q * d + r -> size r < size d -> r = (p %% d). Proof. by move/divp_modpP=> h; case/h. Qed. Lemma eqpfP p q : p %= q -> p = (lead_coef p / lead_coef q) *: q. Proof. have [->|nz_q] := altP (q =P 0). by rewrite eqp0 => /eqP ->; rewrite scaler0. move/IdomainUnit.ucl_eqp_eq; apply; rewrite unitfE. by move: nz_q; rewrite -lead_coef_eq0 => nz_qT. Qed. Lemma dvdp_eq q p : (q %| p) = (p == p %/ q * q). Proof. case: (eqVneq q 0) => [-> | qn0]; first by rewrite dvd0p mulr0 eq_sym. by apply: IdomainUnit.dvdp_eq; rewrite unitfE lead_coef_eq0. Qed. Lemma eqpf_eq p q : reflect (exists2 c, c != 0 & p = c *: q) (p %= q). Proof. apply: (iffP idP); last first. case=> c nz_c ->; apply/eqpP. by exists (1, c); rewrite ?scale1r ?oner_eq0. have [->|nz_q] := altP (q =P 0). by rewrite eqp0=> /eqP ->; exists 1; rewrite ?scale1r ?oner_eq0. case/IdomainUnit.ulc_eqpP; first by rewrite unitfE lead_coef_eq0. by move=> c nz_c ->; exists c. Qed. Lemma modp_scalel c p q : (c *: p) %% q = c *: (p %% q). Proof. case: (eqVneq q 0) => [-> | qn0]; first by rewrite !modp0. by apply: IdomainUnit.modp_scalel; rewrite unitfE lead_coef_eq0. Qed. Lemma mulpK p q : q != 0 -> p * q %/ q = p. Proof. by move=> qn0; rewrite IdomainUnit.mulpK // unitfE lead_coef_eq0. Qed. Lemma mulKp p q : q != 0 -> q * p %/ q = p. Proof. by rewrite mulrC; exact: mulpK. Qed. Lemma divp_scalel c p q : (c *: p) %/ q = c *: (p %/ q). Proof. case: (eqVneq q 0) => [-> | qn0]; first by rewrite !divp0 scaler0. by apply: IdomainUnit.divp_scalel; rewrite unitfE lead_coef_eq0. Qed. Lemma modp_scaler c p d : c != 0 -> p %% (c *: d) = (p %% d). Proof. move=> cn0; case: (eqVneq d 0) => [-> | dn0]; first by rewrite scaler0 !modp0. have e : p = (c^-1 *: (p %/ d)) * (c *: d) + (p %% d). by rewrite scalerCA scalerA mulVf // scale1r -divp_eq. suff s : size (p %% d) < size (c *: d) by rewrite (modpP e s). by rewrite size_scale ?ltn_modp. Qed. Lemma divp_scaler c p d : c != 0 -> p %/ (c *: d) = c^-1 *: (p %/ d). Proof. move=> cn0; case: (eqVneq d 0) => [-> | dn0]. by rewrite scaler0 !divp0 scaler0. have e : p = (c^-1 *: (p %/ d)) * (c *: d) + (p %% d). by rewrite scalerCA scalerA mulVf // scale1r -divp_eq. suff s : size (p %% d) < size (c *: d) by rewrite (divpP e s). by rewrite size_scale ?ltn_modp. Qed. Lemma eqp_modpl d p q : p %= q -> (p %% d) %= (q %% d). Proof. case/eqpP=> [[c1 c2]] /andP /= [c1n0 c2n0 e]. by apply/eqpP; exists (c1, c2); rewrite ?c1n0 // -!modp_scalel e. Qed. Lemma eqp_divl d p q : p %= q -> (p %/ d) %= (q %/ d). Proof. case/eqpP=> [[c1 c2]] /andP /= [c1n0 c2n0 e]. by apply/eqpP; exists (c1, c2); rewrite ?c1n0 // -!divp_scalel e. Qed. Lemma eqp_modpr d p q : p %= q -> (d %% p) %= (d %% q). Proof. case/eqpP=> [[c1 c2]] /andP [c1n0 c2n0 e]. have -> : p = (c1^-1 * c2) *: q by rewrite -scalerA -e scalerA mulVf // scale1r. by rewrite modp_scaler ?eqpxx // mulf_eq0 negb_or invr_eq0 c1n0. Qed. Lemma eqp_mod p1 p2 q1 q2 : p1 %= p2 -> q1 %= q2 -> p1 %% q1 %= p2 %% q2. Proof. move=> e1 e2; apply: eqp_trans (eqp_modpr _ e2). apply: eqp_trans (eqp_modpl _ e1); exact: eqpxx. Qed. Lemma eqp_divr (d m n : {poly F}) : m %= n -> (d %/ m) %= (d %/ n). Proof. case/eqpP=> [[c1 c2]] /andP [c1n0 c2n0 e]. have -> : m = (c1^-1 * c2) *: n by rewrite -scalerA -e scalerA mulVf // scale1r. by rewrite divp_scaler ?eqp_scale // ?invr_eq0 mulf_eq0 negb_or invr_eq0 c1n0. Qed. Lemma eqp_div p1 p2 q1 q2 : p1 %= p2 -> q1 %= q2 -> p1 %/ q1 %= p2 %/ q2. Proof. move=> e1 e2; apply: eqp_trans (eqp_divr _ e2). apply: eqp_trans (eqp_divl _ e1); exact: eqpxx. Qed. Lemma eqp_gdcor p q r : q %= r -> gdcop p q %= gdcop p r. Proof. move=> eqr; rewrite /gdcop (eqp_size eqr). move: (size r)=> n; elim: n p q r eqr => [|n ihn] p q r; first by rewrite eqpxx. move=> eqr /=; rewrite (eqp_coprimepl p eqr); case: ifP => _ //; apply: ihn. apply: eqp_div => //; exact: eqp_gcdl. Qed. Lemma eqp_gdcol p q r : q %= r -> gdcop q p %= gdcop r p. Proof. move=> eqr; rewrite /gdcop; move: (size p)=> n. elim: n p q r eqr {1 3}p (eqpxx p) => [|n ihn] p q r eqr s esp /=. move: eqr; case: (eqVneq q 0)=> [-> | nq0 eqr] /=. by rewrite eqp_sym eqp0; move->; rewrite eqxx eqpxx. suff rn0 : r != 0 by rewrite (negPf nq0) (negPf rn0) eqpxx. by apply: contraTneq eqr => ->; rewrite eqp0. rewrite (eqp_coprimepr _ eqr) (eqp_coprimepl _ esp); case: ifP=> _ //. apply: ihn => //; apply: eqp_div => //; exact: eqp_gcd. Qed. Lemma eqp_rgdco_gdco q p : rgdcop q p %= gdcop q p. Proof. rewrite /rgdcop /gdcop; move: (size p)=> n. elim: n p q {1 3}p {1 3}q (eqpxx p) (eqpxx q) => [|n ihn] p q s t /= sp tq. move: tq; case: (eqVneq t 0)=> [-> | nt0 etq]. by rewrite eqp_sym eqp0; move->; rewrite eqxx eqpxx. suff qn0 : q != 0 by rewrite (negPf nt0) (negPf qn0) eqpxx. by apply: contraTneq etq => ->; rewrite eqp0. rewrite rcoprimep_coprimep (eqp_coprimepl t sp) (eqp_coprimepr p tq). case: ifP=> // _; apply: ihn => //; apply: eqp_trans (eqp_rdiv_div _ _) _. by apply: eqp_div => //; apply: eqp_trans (eqp_rgcd_gcd _ _) _; apply: eqp_gcd. Qed. Lemma modp_opp p q : (- p) %% q = - (p %% q). Proof. case: (eqVneq q 0) => [-> | qn0]; first by rewrite !modp0. by apply: IdomainUnit.modp_opp; rewrite unitfE lead_coef_eq0. Qed. Lemma divp_opp p q : (- p) %/ q = - (p %/ q). Proof. case: (eqVneq q 0) => [-> | qn0]; first by rewrite !divp0 oppr0. by apply: IdomainUnit.divp_opp; rewrite unitfE lead_coef_eq0. Qed. Lemma modp_add d p q : (p + q) %% d = p %% d + q %% d. Proof. case: (eqVneq d 0) => [-> | dn0]; first by rewrite !modp0. by apply: IdomainUnit.modp_add; rewrite unitfE lead_coef_eq0. Qed. Lemma modNp p q : (- p) %% q = - (p %% q). Proof. by apply/eqP; rewrite -addr_eq0 -modp_add addNr mod0p. Qed. Lemma divp_add d p q : (p + q) %/ d = p %/ d + q %/ d. Proof. case: (eqVneq d 0) => [-> | dn0]; first by rewrite !divp0 addr0. by apply: IdomainUnit.divp_add; rewrite unitfE lead_coef_eq0. Qed. Lemma divp_addl_mul_small d q r : size r < size d -> (q * d + r) %/ d = q. Proof. move=> srd; rewrite divp_add (divp_small srd) addr0 mulpK //. by rewrite -size_poly_gt0; apply: leq_trans srd. Qed. Lemma modp_addl_mul_small d q r : size r < size d -> (q * d + r) %% d = r. Proof. by move=> srd; rewrite modp_add modp_mull add0r modp_small. Qed. Lemma divp_addl_mul d q r : d != 0 -> (q * d + r) %/ d = q + r %/ d. Proof. by move=> dn0; rewrite divp_add mulpK. Qed. Lemma divpp d : d != 0 -> d %/ d = 1. Proof. by move=> dn0; apply: IdomainUnit.divpp; rewrite unitfE lead_coef_eq0. Qed. Lemma leq_trunc_divp d m : size (m %/ d * d) <= size m. Proof. case: (eqVneq d 0) => [-> | dn0]; first by rewrite mulr0 size_poly0. by apply: IdomainUnit.leq_trunc_divp; rewrite unitfE lead_coef_eq0. Qed. Lemma divpK d p : d %| p -> p %/ d * d = p. Proof. case: (eqVneq d 0) => [-> | dn0]; first by move/dvd0pP->; rewrite mulr0. by apply: IdomainUnit.divpK; rewrite unitfE lead_coef_eq0. Qed. Lemma divpKC d p : d %| p -> d * (p %/ d) = p. Proof. by move=> ?; rewrite mulrC divpK. Qed. Lemma dvdp_eq_div d p q : d != 0 -> d %| p -> (q == p %/ d) = (q * d == p). Proof. by move=> dn0; apply: IdomainUnit.dvdp_eq_div; rewrite unitfE lead_coef_eq0. Qed. Lemma dvdp_eq_mul d p q : d != 0 -> d %| p -> (p == q * d) = (p %/ d == q). Proof. by move=> dn0 dv_d_p; rewrite eq_sym -dvdp_eq_div // eq_sym. Qed. Lemma divp_mulA d p q : d %| q -> p * (q %/ d) = p * q %/ d. Proof. case: (eqVneq d 0) => [-> | dn0]; first by move/dvd0pP->; rewrite !divp0 mulr0. by apply: IdomainUnit.divp_mulA; rewrite unitfE lead_coef_eq0. Qed. Lemma divp_mulAC d m n : d %| m -> m %/ d * n = m * n %/ d. Proof. by move=> hdm; rewrite mulrC (mulrC m); exact: divp_mulA. Qed. Lemma divp_mulCA d p q : d %| p -> d %| q -> p * (q %/ d) = q * (p %/ d). Proof. by move=> hdp hdq; rewrite mulrC divp_mulAC // divp_mulA. Qed. Lemma expp_sub d m n : d != 0 -> m >= n -> (d ^+ (m - n))%N = d ^+ m %/ d ^+ n. Proof. by move=> dn0 /subnK=> {2}<-; rewrite exprD mulpK // expf_neq0. Qed. Lemma divp_pmul2l d q p : d != 0 -> q != 0 -> d * p %/ (d * q) = p %/ q. Proof. by move=> dn0 qn0; apply: IdomainUnit.divp_pmul2l; rewrite unitfE lead_coef_eq0. Qed. Lemma divp_pmul2r d p q : d != 0 -> p != 0 -> q * d %/ (p * d) = q %/ p. Proof. by move=> dn0 qn0; rewrite -!(mulrC d) divp_pmul2l. Qed. Lemma divp_divl r p q : q %/ p %/ r = q %/ (p * r). Proof. case: (eqVneq r 0) => [-> | rn0]; first by rewrite mulr0 !divp0. case: (eqVneq p 0) => [-> | pn0]; first by rewrite mul0r !divp0 div0p. by apply: IdomainUnit.divp_divl; rewrite unitfE lead_coef_eq0. Qed. Lemma divpAC d p q : q %/ d %/ p = q %/ p %/ d. Proof. by rewrite !divp_divl // mulrC. Qed. Lemma edivp_def p q : edivp p q = (0%N, p %/ q, p %% q). Proof. rewrite Idomain.edivp_def; congr (_, _, _); rewrite /scalp 2!unlock /=. case (eqVneq q 0) => [-> | qn0]; first by rewrite eqxx lead_coef0 unitr0. rewrite (negPf qn0) /= unitfE lead_coef_eq0 qn0 /=. by case: (redivp_rec _ _ _ _) => [[]]. Qed. Lemma divpE p q : p %/ q = (lead_coef q)^-(rscalp p q) *: (rdivp p q). Proof. case: (eqVneq q 0) => [-> | qn0]; first by rewrite rdivp0 divp0 scaler0. by rewrite Idomain.divpE unitfE lead_coef_eq0 qn0. Qed. Lemma modpE p q : p %% q = (lead_coef q)^-(rscalp p q) *: (rmodp p q). Proof. case: (eqVneq q 0) => [-> | qn0]. by rewrite rmodp0 modp0 /rscalp unlock eqxx lead_coef0 expr0 invr1 scale1r. by rewrite Idomain.modpE unitfE lead_coef_eq0 qn0. Qed. Lemma scalpE p q : scalp p q = 0%N. Proof. case: (eqVneq q 0) => [-> | qn0]; first by rewrite scalp0. by rewrite Idomain.scalpE unitfE lead_coef_eq0 qn0. Qed. (* Just to have it without importing the weak theory *) Lemma dvdpE p q : p %| q = rdvdp p q. Proof. exact: Idomain.dvdpE. Qed. CoInductive edivp_spec m d : nat * {poly F} * {poly F} -> Type := EdivpSpec n q r of m = q * d + r & (d != 0) ==> (size r < size d) : edivp_spec m d (n, q, r). Lemma edivpP m d : edivp_spec m d (edivp m d). Proof. rewrite edivp_def; constructor; first exact: divp_eq. by apply/implyP=> dn0; rewrite ltn_modp. Qed. Lemma edivp_eq d q r : size r < size d -> edivp (q * d + r) d = (0%N, q, r). Proof. move=> srd; apply: Idomain.edivp_eq ; rewrite // unitfE lead_coef_eq0. rewrite -size_poly_gt0; exact: leq_trans srd. Qed. Lemma modp_mul p q m : (p * (q %% m)) %% m = (p * q) %% m. Proof. have ->: q %% m = q - q %/ m * m by rewrite {2}(divp_eq q m) -addrA addrC subrK. rewrite mulrDr modp_add // -mulNr mulrA -{2}[_ %% _]addr0; congr (_ + _). by apply/eqP; apply: dvdp_mull; exact: dvdpp. Qed. Lemma dvdpP p q : reflect (exists qq, p = qq * q) (q %| p). Proof. case: (eqVneq q 0)=> [-> | qn0]; last first. by apply: IdomainUnit.dvdpP; rewrite unitfE lead_coef_eq0. rewrite dvd0p. by apply: (iffP idP) => [/eqP->| [? ->]]; [exists 1|]; rewrite mulr0. Qed. Lemma Bezout_eq1_coprimepP : forall p q, reflect (exists u, u.1 * p + u.2 * q = 1) (coprimep p q). Proof. move=> p q; apply:(iffP idP)=> [hpq|]; last first. by case=>[[u v]] /= e; apply/Bezout_coprimepP; exists (u, v); rewrite e eqpxx. case/Bezout_coprimepP: hpq => [[u v]] /=. case/eqpP=> [[c1 c2]] /andP /= [c1n0 c2n0] e. exists (c2^-1 *: (c1 *: u), c2^-1 *: (c1 *: v)); rewrite /= -!scalerAl. by rewrite -!scalerDr e scalerA mulVf // scale1r. Qed. Lemma dvdp_gdcor p q : q != 0 -> p %| (gdcop q p) * (q ^+ size p). Proof. move=> q_neq0; rewrite /gdcop. elim: (size p) {-2 5}p (leqnn (size p))=> {p} [|n ihn] p. rewrite size_poly_leq0; move/eqP->. by rewrite size_poly0 /= dvd0p expr0 mulr1 (negPf q_neq0). move=> hsp /=; have [->|p_neq0] := altP (p =P 0). rewrite size_poly0 /= dvd0p expr0 mulr1 div0p /=. case: ifP=> // _; have := (ihn 0). by rewrite size_poly0 expr0 mulr1 dvd0p=> /(_ isT). have [|ncop_pq] := boolP (coprimep _ _); first by rewrite dvdp_mulr ?dvdpp. have g_gt1: (1 < size (gcdp p q))%N. have [|//|/eqP] := ltngtP; last by rewrite -coprimep_def (negPf ncop_pq). by rewrite ltnS leqn0 size_poly_eq0 gcdp_eq0 (negPf p_neq0). have sd : (size (p %/ gcdp p q) < size p)%N. rewrite size_divp -?size_poly_eq0 -(subnKC g_gt1) // add2n /=. by rewrite -[size _]prednK ?size_poly_gt0 // ltnS subSS leq_subr. rewrite -{1}[p](divpK (dvdp_gcdl _ q)) -(subnKC sd) addSnnS exprD mulrA. rewrite dvdp_mul ?ihn //; first by rewrite -ltnS (leq_trans sd). by rewrite exprS dvdp_mulr // dvdp_gcdr. Qed. Lemma reducible_cubic_root p q : size p <= 4 -> 1 < size q < size p -> q %| p -> {r | root p r}. Proof. move=> p_le4 /andP[]; rewrite leq_eqVlt eq_sym. have [/poly2_root[x qx0] _ _ | _ /= q_gt2 p_gt_q] := size q =P 2. by exists x; rewrite -!dvdp_XsubCl in qx0 *; apply: (dvdp_trans qx0). case/dvdpP/sig_eqW=> r def_p; rewrite def_p. suffices /poly2_root[x rx0]: size r = 2 by exists x; rewrite rootM rx0. have /norP[nz_r nz_q]: ~~ [|| r == 0 | q == 0]. by rewrite -mulf_eq0 -def_p -size_poly_gt0 (leq_ltn_trans _ p_gt_q). rewrite def_p size_mul // -subn1 leq_subLR ltn_subRL in p_gt_q p_le4. by apply/eqP; rewrite -(eqn_add2r (size q)) eqn_leq (leq_trans p_le4). Qed. Lemma cubic_irreducible p : 1 < size p <= 4 -> (forall x, ~~ root p x) -> irreducible_poly p. Proof. move=> /andP[p_gt1 p_le4] root'p; split=> // q sz_q_neq1 q_dv_p. have nz_p: p != 0 by rewrite -size_poly_gt0 ltnW. have nz_q: q != 0 by apply: contraTneq q_dv_p => ->; rewrite dvd0p. have q_gt1: size q > 1 by rewrite ltn_neqAle eq_sym sz_q_neq1 size_poly_gt0. rewrite -dvdp_size_eqp // eqn_leq dvdp_leq //= leqNgt; apply/negP=> p_gt_q. by have [|x /idPn//] := reducible_cubic_root p_le4 _ q_dv_p; rewrite q_gt1. Qed. Section FieldRingMap. Variable rR : ringType. Variable f : {rmorphism F -> rR}. Local Notation "p ^f" := (map_poly f p) : ring_scope. Implicit Type a b : {poly F}. Lemma redivp_map a b : redivp a^f b^f = (rscalp a b, (rdivp a b)^f, (rmodp a b)^f). Proof. rewrite /rdivp /rscalp /rmodp !unlock map_poly_eq0 size_map_poly. case: eqP; rewrite /= -(rmorph0 (map_poly_rmorphism f)) //; move/eqP=> q_nz. move: (size a) => m; elim: m 0%N 0 a => [|m IHm] qq r a /=. rewrite -!mul_polyC !size_map_poly !lead_coef_map // -(map_polyXn f). by rewrite -!(map_polyC f) -!rmorphM -rmorphB -rmorphD; case: (_ < _). rewrite -!mul_polyC !size_map_poly !lead_coef_map // -(map_polyXn f). by rewrite -!(map_polyC f) -!rmorphM -rmorphB -rmorphD /= IHm; case: (_ < _). Qed. End FieldRingMap. Section FieldMap. Variable rR : idomainType. Variable f : {rmorphism F -> rR}. Local Notation "p ^f" := (map_poly f p) : ring_scope. Implicit Type a b : {poly F}. Lemma edivp_map a b : edivp a^f b^f = (0%N, (a %/ b)^f, (a %% b)^f). Proof. case: (eqVneq b 0) => [-> | bn0]. rewrite (rmorph0 (map_poly_rmorphism f)) WeakIdomain.edivp_def !modp0 !divp0. by rewrite (rmorph0 (map_poly_rmorphism f)) scalp0. rewrite unlock redivp_map lead_coef_map rmorph_unit; last first. by rewrite unitfE lead_coef_eq0. rewrite modpE divpE !map_polyZ !rmorphV ?rmorphX // unitfE. by rewrite expf_neq0 // lead_coef_eq0. Qed. Lemma scalp_map p q : scalp p^f q^f = scalp p q. Proof. by rewrite /scalp edivp_map edivp_def. Qed. Lemma map_divp p q : (p %/ q)^f = p^f %/ q^f. Proof. by rewrite /divp edivp_map edivp_def. Qed. Lemma map_modp p q : (p %% q)^f = p^f %% q^f. Proof. by rewrite /modp edivp_map edivp_def. Qed. Lemma egcdp_map p q : egcdp (map_poly f p) (map_poly f q) = (map_poly f (egcdp p q).1, map_poly f (egcdp p q).2). Proof. wlog le_qp: p q / size q <= size p. move=> IH; have [/IH// | lt_qp] := leqP (size q) (size p). have /IH := ltnW lt_qp; rewrite /egcdp !size_map_poly ltnW // leqNgt lt_qp /=. by case: (egcdp_rec _ _ _) => u v [-> ->]. rewrite /egcdp !size_map_poly {}le_qp; move: (size q) => n. elim: n => /= [|n IHn] in p q *; first by rewrite rmorph1 rmorph0. rewrite map_poly_eq0; have [_ | nz_q] := ifPn; first by rewrite rmorph1 rmorph0. rewrite -map_modp (IHn q (p %% q)); case: (egcdp_rec _ _ n) => u v /=. by rewrite map_polyZ lead_coef_map -rmorphX scalp_map rmorphB rmorphM -map_divp. Qed. Lemma dvdp_map p q : (p^f %| q^f) = (p %| q). Proof. by rewrite /dvdp -map_modp map_poly_eq0. Qed. Lemma eqp_map p q : (p^f %= q^f) = (p %= q). Proof. by rewrite /eqp !dvdp_map. Qed. Lemma gcdp_map p q : (gcdp p q)^f = gcdp p^f q^f. Proof. wlog lt_p_q: p q / size p < size q. move=> IH; case: (ltnP (size p) (size q)) => [|le_q_p]; first exact: IH. rewrite gcdpE (gcdpE p^f) !size_map_poly ltnNge le_q_p /= -map_modp. case: (eqVneq q 0) => [-> | q_nz]; first by rewrite rmorph0 !gcdp0. by rewrite IH ?ltn_modp. elim: {q}_.+1 p {-2}q (ltnSn (size q)) lt_p_q => // m IHm p q le_q_m lt_p_q. rewrite gcdpE (gcdpE p^f) !size_map_poly lt_p_q -map_modp. case: (eqVneq p 0) => [-> | q_nz]; first by rewrite rmorph0 !gcdp0. by rewrite IHm ?(leq_trans lt_p_q) ?ltn_modp. Qed. Lemma coprimep_map p q : coprimep p^f q^f = coprimep p q. Proof. by rewrite -!gcdp_eqp1 -eqp_map rmorph1 gcdp_map. Qed. Lemma gdcop_rec_map p q n : (gdcop_rec p q n)^f = (gdcop_rec p^f q^f n). Proof. elim: n p q => [|n IH] => /= p q. by rewrite map_poly_eq0; case: eqP; rewrite ?rmorph1 ?rmorph0. rewrite /coprimep -gcdp_map size_map_poly. by case: eqP => Hq0 //; rewrite -map_divp -IH. Qed. Lemma gdcop_map p q : (gdcop p q)^f = (gdcop p^f q^f). Proof. by rewrite /gdcop gdcop_rec_map !size_map_poly. Qed. End FieldMap. End FieldDivision. End Field. Module ClosedField. Import Field. Section closed. Variable F : closedFieldType. Lemma root_coprimep (p q : {poly F}): (forall x, root p x -> q.[x] != 0) -> coprimep p q. Proof. move=> Ncmn; rewrite -gcdp_eqp1 -size_poly_eq1; apply/closed_rootP. by case=> r; rewrite root_gcd !rootE=> /andP [/Ncmn/negbTE->]. Qed. Lemma coprimepP (p q : {poly F}): reflect (forall x, root p x -> q.[x] != 0) (coprimep p q). Proof. by apply: (iffP idP)=> [/coprimep_root|/root_coprimep]. Qed. End closed. End ClosedField. End Pdiv. Export Pdiv.Field. mathcomp-1.5/theories/ring_quotient.v0000644000175000017500000006475012307636117017075 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import eqtype choice ssreflect ssrbool ssrnat ssrfun seq. Require Import ssralg generic_quotient. (******************************************************************************) (* This file describes quotients of algebraic structures. *) (* *) (* It defines a join hierarchy mxing the structures defined in file ssralg *) (* (up to unit ring type) and the quotType quotient structure defined in *) (* file generic_quotient. Every structure in that (join) hierarchy is *) (* parametrized by a base type T and the constants and operations on the *) (* base type that will be used to confer its algebraic structure to the *) (* quotient. Note that T itself is in general not an instance of an *) (* algebraic structure. The canonical surjection from T onto its quotient *) (* should be compatible with the parameter operations. *) (* *) (* The second part of the file provides a definition of (non trivial) *) (* decidable ideals (resp. prime ideals) of an arbitrary instance of ring *) (* structure and a construction of the quotient of a ring by such an ideal. *) (* These definitions extend the hierarchy of sub-structures defined in file *) (* ssralg (see Module Pred in ssralg), following a similar methodology. *) (* Although the definition of the (structure of) quotient of a ring by an *) (* ideal is a general one, we do not provide infrastructure for the case of *) (* non commutative ring and left or two-sided ideals. *) (* *) (* The file defines the following Structures: *) (* zmodQuotType T e z n a == Z-module obtained by quotienting type T *) (* with the relation e and whose neutral, *) (* opposite and addition are the images in the *) (* quotient of the parameters z, n and a, *) (* respectively. *) (* ringQuotType T e z n a o m == ring obtained by quotienting type T with *) (* the relation e and whose zero opposite, *) (* addition, one, and multiplication are the *) (* images in the quotient of the parameters *) (* z, n, a, o, m, respectively. *) (* unitRingQuotType ... u i == As in the previous cases, instance of unit *) (* ring whose unit predicate is obtained from *) (* u and the inverse from i. *) (* idealr R S == (S : pred R) is a non-trivial, decidable, *) (* right ideal of the ring R. *) (* prime_idealr R S == (S : pred R) is a non-trivial, decidable, *) (* right, prime ideal of the ring R. *) (* *) (* The formalization of ideals features the following constructions: *) (* nontrivial_ideal S == the collective predicate (S : pred R) on the *) (* ring R is stable by the ring product and does *) (* contain R's one. *) (* prime_idealr_closed S := u * v \in S -> (u \in S) || (v \in S) *) (* idealr_closed S == the collective predicate (S : pred R) on the *) (* ring R represents a (right) ideal. This *) (* implies its being a nontrivial_ideal. *) (* *) (* MkIdeal idealS == packs idealS : nontrivial_ideal S into an *) (* idealr S interface structure associating the *) (* idealr_closed property to the canonical *) (* pred_key S (see ssrbool), which must already *) (* be an zmodPred (see ssralg). *) (* MkPrimeIdeal pidealS == packs pidealS : prime_idealr_closed S into a *) (* prime_idealr S interface structure associating *) (* the prime_idealr_closed property to the *) (* canonical pred_key S (see ssrbool), which must *) (* already be an idealr (see above). *) (* {ideal_quot kI} == quotient by the keyed (right) ideal predicate *) (* kI of a commutative ring R. Note that we indeed*) (* only provide canonical structures of ring *) (* quotients for the case of commutative rings, *) (* for which a right ideal is obviously a *) (* two-sided ideal. *) (* *) (* Note : *) (* if (I : pred R) is a predicate over a ring R and (ideal : idealr I) is an *) (* instance of (right) ideal, in order to quantify over an arbitrary (keyed) *) (* predicate describing ideal, use type (keyed_pred ideal), as in: *) (* forall (kI : keyed_pred ideal),... *) (******************************************************************************) Import GRing.Theory. Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Local Open Scope ring_scope. Local Open Scope quotient_scope. Reserved Notation "{ideal_quot I }" (at level 0, format "{ideal_quot I }"). Reserved Notation "m = n %[mod_ideal I ]" (at level 70, n at next level, format "'[hv ' m '/' = n '/' %[mod_ideal I ] ']'"). Reserved Notation "m == n %[mod_ideal I ]" (at level 70, n at next level, format "'[hv ' m '/' == n '/' %[mod_ideal I ] ']'"). Reserved Notation "m <> n %[mod_ideal I ]" (at level 70, n at next level, format "'[hv ' m '/' <> n '/' %[mod_ideal I ] ']'"). Reserved Notation "m != n %[mod_ideal I ]" (at level 70, n at next level, format "'[hv ' m '/' != n '/' %[mod_ideal I ] ']'"). Section ZmodQuot. Variable (T : Type). Variable eqT : rel T. Variables (zeroT : T) (oppT : T -> T) (addT : T -> T -> T). Record zmod_quot_mixin_of (Q : Type) (qc : quot_class_of T Q) (zc : GRing.Zmodule.class_of Q) := ZmodQuotMixinPack { zmod_eq_quot_mixin :> eq_quot_mixin_of eqT qc zc; _ : \pi_(QuotTypePack qc Q) zeroT = 0 :> GRing.Zmodule.Pack zc Q; _ : {morph \pi_(QuotTypePack qc Q) : x / oppT x >-> @GRing.opp (GRing.Zmodule.Pack zc Q) x}; _ : {morph \pi_(QuotTypePack qc Q) : x y / addT x y >-> @GRing.add (GRing.Zmodule.Pack zc Q) x y} }. Record zmod_quot_class_of (Q : Type) : Type := ZmodQuotClass { zmod_quot_quot_class :> quot_class_of T Q; zmod_quot_zmod_class :> GRing.Zmodule.class_of Q; zmod_quot_mixin :> zmod_quot_mixin_of zmod_quot_quot_class zmod_quot_zmod_class }. Structure zmodQuotType : Type := ZmodQuotTypePack { zmod_quot_sort :> Type; _ : zmod_quot_class_of zmod_quot_sort; _ : Type }. Implicit Type zqT : zmodQuotType. Definition zmod_quot_class zqT : zmod_quot_class_of zqT := let: ZmodQuotTypePack _ cT _ as qT' := zqT return zmod_quot_class_of qT' in cT. Definition zmod_eq_quot_class zqT (zqc : zmod_quot_class_of zqT) : eq_quot_class_of eqT zqT := EqQuotClass zqc. Canonical zmodQuotType_eqType zqT := Equality.Pack (zmod_quot_class zqT) zqT. Canonical zmodQuotType_choiceType zqT := Choice.Pack (zmod_quot_class zqT) zqT. Canonical zmodQuotType_zmodType zqT := GRing.Zmodule.Pack (zmod_quot_class zqT) zqT. Canonical zmodQuotType_quotType zqT := QuotTypePack (zmod_quot_class zqT) zqT. Canonical zmodQuotType_eqQuotType zqT := EqQuotTypePack (zmod_eq_quot_class (zmod_quot_class zqT)) zqT. Coercion zmodQuotType_eqType : zmodQuotType >-> eqType. Coercion zmodQuotType_choiceType : zmodQuotType >-> choiceType. Coercion zmodQuotType_zmodType : zmodQuotType >-> zmodType. Coercion zmodQuotType_quotType : zmodQuotType >-> quotType. Coercion zmodQuotType_eqQuotType : zmodQuotType >-> eqQuotType. Definition ZmodQuotType_pack Q := fun (qT : quotType T) (zT : zmodType) qc zc of phant_id (quot_class qT) qc & phant_id (GRing.Zmodule.class zT) zc => fun m => ZmodQuotTypePack (@ZmodQuotClass Q qc zc m) Q. Definition ZmodQuotMixin_pack Q := fun (qT : eqQuotType eqT) (qc : eq_quot_class_of eqT Q) of phant_id (eq_quot_class qT) qc => fun (zT : zmodType) zc of phant_id (GRing.Zmodule.class zT) zc => fun e m0 mN mD => @ZmodQuotMixinPack Q qc zc e m0 mN mD. Definition ZmodQuotType_clone (Q : Type) qT cT of phant_id (zmod_quot_class qT) cT := @ZmodQuotTypePack Q cT Q. Lemma zmod_quot_mixinP zqT : zmod_quot_mixin_of (zmod_quot_class zqT) (zmod_quot_class zqT). Proof. by case: zqT => [] ? [] ? ? []. Qed. Lemma pi_zeror zqT : \pi_zqT zeroT = 0. Proof. by case: zqT => [] ? [] ? ? []. Qed. Lemma pi_oppr zqT : {morph \pi_zqT : x / oppT x >-> - x}. Proof. by case: zqT => [] ? [] ? ? []. Qed. Lemma pi_addr zqT : {morph \pi_zqT : x y / addT x y >-> x + y}. Proof. by case: zqT => [] ? [] ? ? []. Qed. Canonical pi_zero_quot_morph zqT := PiMorph (pi_zeror zqT). Canonical pi_opp_quot_morph zqT := PiMorph1 (pi_oppr zqT). Canonical pi_add_quot_morph zqT := PiMorph2 (pi_addr zqT). End ZmodQuot. Notation ZmodQuotType z o a Q m := (@ZmodQuotType_pack _ _ z o a Q _ _ _ _ id id m). Notation "[ 'zmodQuotType' z , o & a 'of' Q ]" := (@ZmodQuotType_clone _ _ z o a Q _ _ id) (at level 0, format "[ 'zmodQuotType' z , o & a 'of' Q ]") : form_scope. Notation ZmodQuotMixin Q m0 mN mD := (@ZmodQuotMixin_pack _ _ _ _ _ Q _ _ id _ _ id (pi_eq_quot _) m0 mN mD). Section PiAdditive. Variables (V : zmodType) (equivV : rel V) (zeroV : V). Variable Q : @zmodQuotType V equivV zeroV -%R +%R. Lemma pi_is_additive : additive \pi_Q. Proof. by move=> x y /=; rewrite !piE. Qed. Canonical pi_additive := Additive pi_is_additive. End PiAdditive. Section RingQuot. Variable (T : Type). Variable eqT : rel T. Variables (zeroT : T) (oppT : T -> T) (addT : T -> T -> T). Variables (oneT : T) (mulT : T -> T -> T). Record ring_quot_mixin_of (Q : Type) (qc : quot_class_of T Q) (rc : GRing.Ring.class_of Q) := RingQuotMixinPack { ring_zmod_quot_mixin :> zmod_quot_mixin_of eqT zeroT oppT addT qc rc; _ : \pi_(QuotTypePack qc Q) oneT = 1 :> GRing.Ring.Pack rc Q; _ : {morph \pi_(QuotTypePack qc Q) : x y / mulT x y >-> @GRing.mul (GRing.Ring.Pack rc Q) x y} }. Record ring_quot_class_of (Q : Type) : Type := RingQuotClass { ring_quot_quot_class :> quot_class_of T Q; ring_quot_ring_class :> GRing.Ring.class_of Q; ring_quot_mixin :> ring_quot_mixin_of ring_quot_quot_class ring_quot_ring_class }. Structure ringQuotType : Type := RingQuotTypePack { ring_quot_sort :> Type; _ : ring_quot_class_of ring_quot_sort; _ : Type }. Implicit Type rqT : ringQuotType. Definition ring_quot_class rqT : ring_quot_class_of rqT := let: RingQuotTypePack _ cT _ as qT' := rqT return ring_quot_class_of qT' in cT. Definition ring_zmod_quot_class rqT (rqc : ring_quot_class_of rqT) : zmod_quot_class_of eqT zeroT oppT addT rqT := ZmodQuotClass rqc. Definition ring_eq_quot_class rqT (rqc : ring_quot_class_of rqT) : eq_quot_class_of eqT rqT := EqQuotClass rqc. Canonical ringQuotType_eqType rqT := Equality.Pack (ring_quot_class rqT) rqT. Canonical ringQuotType_choiceType rqT := Choice.Pack (ring_quot_class rqT) rqT. Canonical ringQuotType_zmodType rqT := GRing.Zmodule.Pack (ring_quot_class rqT) rqT. Canonical ringQuotType_ringType rqT := GRing.Ring.Pack (ring_quot_class rqT) rqT. Canonical ringQuotType_quotType rqT := QuotTypePack (ring_quot_class rqT) rqT. Canonical ringQuotType_eqQuotType rqT := EqQuotTypePack (ring_eq_quot_class (ring_quot_class rqT)) rqT. Canonical ringQuotType_zmodQuotType rqT := ZmodQuotTypePack (ring_zmod_quot_class (ring_quot_class rqT)) rqT. Coercion ringQuotType_eqType : ringQuotType >-> eqType. Coercion ringQuotType_choiceType : ringQuotType >-> choiceType. Coercion ringQuotType_zmodType : ringQuotType >-> zmodType. Coercion ringQuotType_ringType : ringQuotType >-> ringType. Coercion ringQuotType_quotType : ringQuotType >-> quotType. Coercion ringQuotType_eqQuotType : ringQuotType >-> eqQuotType. Coercion ringQuotType_zmodQuotType : ringQuotType >-> zmodQuotType. Definition RingQuotType_pack Q := fun (qT : quotType T) (zT : ringType) qc rc of phant_id (quot_class qT) qc & phant_id (GRing.Ring.class zT) rc => fun m => RingQuotTypePack (@RingQuotClass Q qc rc m) Q. Definition RingQuotMixin_pack Q := fun (qT : zmodQuotType eqT zeroT oppT addT) => fun (qc : zmod_quot_class_of eqT zeroT oppT addT Q) of phant_id (zmod_quot_class qT) qc => fun (rT : ringType) rc of phant_id (GRing.Ring.class rT) rc => fun mZ m1 mM => @RingQuotMixinPack Q qc rc mZ m1 mM. Definition RingQuotType_clone (Q : Type) qT cT of phant_id (ring_quot_class qT) cT := @RingQuotTypePack Q cT Q. Lemma ring_quot_mixinP rqT : ring_quot_mixin_of (ring_quot_class rqT) (ring_quot_class rqT). Proof. by case: rqT => [] ? [] ? ? []. Qed. Lemma pi_oner rqT : \pi_rqT oneT = 1. Proof. by case: rqT => [] ? [] ? ? []. Qed. Lemma pi_mulr rqT : {morph \pi_rqT : x y / mulT x y >-> x * y}. Proof. by case: rqT => [] ? [] ? ? []. Qed. Canonical pi_one_quot_morph rqT := PiMorph (pi_oner rqT). Canonical pi_mul_quot_morph rqT := PiMorph2 (pi_mulr rqT). End RingQuot. Notation RingQuotType o mul Q mix := (@RingQuotType_pack _ _ _ _ _ o mul Q _ _ _ _ id id mix). Notation "[ 'ringQuotType' o & m 'of' Q ]" := (@RingQuotType_clone _ _ _ _ _ o m Q _ _ id) (at level 0, format "[ 'ringQuotType' o & m 'of' Q ]") : form_scope. Notation RingQuotMixin Q m1 mM := (@RingQuotMixin_pack _ _ _ _ _ _ _ Q _ _ id _ _ id (zmod_quot_mixinP _) m1 mM). Section PiRMorphism. Variables (R : ringType) (equivR : rel R) (zeroR : R). Variable Q : @ringQuotType R equivR zeroR -%R +%R 1 *%R. Lemma pi_is_multiplicative : multiplicative \pi_Q. Proof. by split; do ?move=> x y /=; rewrite !piE. Qed. Canonical pi_rmorphism := AddRMorphism pi_is_multiplicative. End PiRMorphism. Section UnitRingQuot. Variable (T : Type). Variable eqT : rel T. Variables (zeroT : T) (oppT : T -> T) (addT : T -> T -> T). Variables (oneT : T) (mulT : T -> T -> T). Variables (unitT : pred T) (invT : T -> T). Record unit_ring_quot_mixin_of (Q : Type) (qc : quot_class_of T Q) (rc : GRing.UnitRing.class_of Q) := UnitRingQuotMixinPack { unit_ring_zmod_quot_mixin :> ring_quot_mixin_of eqT zeroT oppT addT oneT mulT qc rc; _ : {mono \pi_(QuotTypePack qc Q) : x / unitT x >-> x \in @GRing.unit (GRing.UnitRing.Pack rc Q)}; _ : {morph \pi_(QuotTypePack qc Q) : x / invT x >-> @GRing.inv (GRing.UnitRing.Pack rc Q) x} }. Record unit_ring_quot_class_of (Q : Type) : Type := UnitRingQuotClass { unit_ring_quot_quot_class :> quot_class_of T Q; unit_ring_quot_ring_class :> GRing.UnitRing.class_of Q; unit_ring_quot_mixin :> unit_ring_quot_mixin_of unit_ring_quot_quot_class unit_ring_quot_ring_class }. Structure unitRingQuotType : Type := UnitRingQuotTypePack { unit_ring_quot_sort :> Type; _ : unit_ring_quot_class_of unit_ring_quot_sort; _ : Type }. Implicit Type rqT : unitRingQuotType. Definition unit_ring_quot_class rqT : unit_ring_quot_class_of rqT := let: UnitRingQuotTypePack _ cT _ as qT' := rqT return unit_ring_quot_class_of qT' in cT. Definition unit_ring_ring_quot_class rqT (rqc : unit_ring_quot_class_of rqT) : ring_quot_class_of eqT zeroT oppT addT oneT mulT rqT := RingQuotClass rqc. Definition unit_ring_zmod_quot_class rqT (rqc : unit_ring_quot_class_of rqT) : zmod_quot_class_of eqT zeroT oppT addT rqT := ZmodQuotClass rqc. Definition unit_ring_eq_quot_class rqT (rqc : unit_ring_quot_class_of rqT) : eq_quot_class_of eqT rqT := EqQuotClass rqc. Canonical unitRingQuotType_eqType rqT := Equality.Pack (unit_ring_quot_class rqT) rqT. Canonical unitRingQuotType_choiceType rqT := Choice.Pack (unit_ring_quot_class rqT) rqT. Canonical unitRingQuotType_zmodType rqT := GRing.Zmodule.Pack (unit_ring_quot_class rqT) rqT. Canonical unitRingQuotType_ringType rqT := GRing.Ring.Pack (unit_ring_quot_class rqT) rqT. Canonical unitRingQuotType_unitRingType rqT := GRing.UnitRing.Pack (unit_ring_quot_class rqT) rqT. Canonical unitRingQuotType_quotType rqT := QuotTypePack (unit_ring_quot_class rqT) rqT. Canonical unitRingQuotType_eqQuotType rqT := EqQuotTypePack (unit_ring_eq_quot_class (unit_ring_quot_class rqT)) rqT. Canonical unitRingQuotType_zmodQuotType rqT := ZmodQuotTypePack (unit_ring_zmod_quot_class (unit_ring_quot_class rqT)) rqT. Canonical unitRingQuotType_ringQuotType rqT := RingQuotTypePack (unit_ring_ring_quot_class (unit_ring_quot_class rqT)) rqT. Coercion unitRingQuotType_eqType : unitRingQuotType >-> eqType. Coercion unitRingQuotType_choiceType : unitRingQuotType >-> choiceType. Coercion unitRingQuotType_zmodType : unitRingQuotType >-> zmodType. Coercion unitRingQuotType_ringType : unitRingQuotType >-> ringType. Coercion unitRingQuotType_unitRingType : unitRingQuotType >-> unitRingType. Coercion unitRingQuotType_quotType : unitRingQuotType >-> quotType. Coercion unitRingQuotType_eqQuotType : unitRingQuotType >-> eqQuotType. Coercion unitRingQuotType_zmodQuotType : unitRingQuotType >-> zmodQuotType. Coercion unitRingQuotType_ringQuotType : unitRingQuotType >-> ringQuotType. Definition UnitRingQuotType_pack Q := fun (qT : quotType T) (rT : unitRingType) qc rc of phant_id (quot_class qT) qc & phant_id (GRing.UnitRing.class rT) rc => fun m => UnitRingQuotTypePack (@UnitRingQuotClass Q qc rc m) Q. Definition UnitRingQuotMixin_pack Q := fun (qT : ringQuotType eqT zeroT oppT addT oneT mulT) => fun (qc : ring_quot_class_of eqT zeroT oppT addT oneT mulT Q) of phant_id (zmod_quot_class qT) qc => fun (rT : unitRingType) rc of phant_id (GRing.UnitRing.class rT) rc => fun mR mU mV => @UnitRingQuotMixinPack Q qc rc mR mU mV. Definition UnitRingQuotType_clone (Q : Type) qT cT of phant_id (unit_ring_quot_class qT) cT := @UnitRingQuotTypePack Q cT Q. Lemma unit_ring_quot_mixinP rqT : unit_ring_quot_mixin_of (unit_ring_quot_class rqT) (unit_ring_quot_class rqT). Proof. by case: rqT => [] ? [] ? ? []. Qed. Lemma pi_unitr rqT : {mono \pi_rqT : x / unitT x >-> x \in GRing.unit}. Proof. by case: rqT => [] ? [] ? ? []. Qed. Lemma pi_invr rqT : {morph \pi_rqT : x / invT x >-> x^-1}. Proof. by case: rqT => [] ? [] ? ? []. Qed. Canonical pi_unit_quot_morph rqT := PiMono1 (pi_unitr rqT). Canonical pi_inv_quot_morph rqT := PiMorph1 (pi_invr rqT). End UnitRingQuot. Notation UnitRingQuotType u i Q mix := (@UnitRingQuotType_pack _ _ _ _ _ _ _ u i Q _ _ _ _ id id mix). Notation "[ 'unitRingQuotType' u & i 'of' Q ]" := (@UnitRingQuotType_clone _ _ _ _ _ _ _ u i Q _ _ id) (at level 0, format "[ 'unitRingQuotType' u & i 'of' Q ]") : form_scope. Notation UnitRingQuotMixin Q mU mV := (@UnitRingQuotMixin_pack _ _ _ _ _ _ _ _ _ Q _ _ id _ _ id (zmod_quot_mixinP _) mU mV). Section IdealDef. Definition nontrivial_ideal (R : ringType) (S : predPredType R) : Prop := 1 \notin S /\ forall a, {in S, forall u, a * u \in S}. Definition prime_idealr_closed (R : ringType) (S : predPredType R) : Prop := forall u v, u * v \in S -> (u \in S) || (v \in S). Definition idealr_closed (R : ringType) (S : predPredType R) := [/\ 0 \in S, 1 \notin S & forall a, {in S &, forall u v, a * u + v \in S}]. Lemma idealr_closed_nontrivial R S : @idealr_closed R S -> nontrivial_ideal S. Proof. by case=> S0 S1 hS; split => // a x xS; rewrite -[_ * _]addr0 hS. Qed. Lemma idealr_closedB R S : @idealr_closed R S -> zmod_closed S. Proof. by case=> S0 _ hS; split=> // x y xS yS; rewrite -mulN1r addrC hS. Qed. Coercion idealr_closedB : idealr_closed >-> zmod_closed. Coercion idealr_closed_nontrivial : idealr_closed >-> nontrivial_ideal. Structure idealr (R : ringType) (S : predPredType R) := MkIdeal { idealr_zmod :> zmodPred S; _ : nontrivial_ideal S }. Structure prime_idealr (R : ringType) (S : predPredType R) := MkPrimeIdeal { prime_idealr_zmod :> idealr S; _ : prime_idealr_closed S }. Definition Idealr (R : ringType) (I : predPredType R) (zmodI : zmodPred I) (kI : keyed_pred zmodI) : nontrivial_ideal I -> idealr I. Proof. by move=> kI1; split => //. Qed. Section IdealTheory. Variables (R : ringType) (I : predPredType R) (idealrI : idealr I) (kI : keyed_pred idealrI). Lemma idealr1 : 1 \in kI = false. Proof. by apply: negPf; case: idealrI kI => ? /= [? _] [] /= _ ->. Qed. Lemma idealMr a u : u \in kI -> a * u \in kI. Proof. by case: idealrI kI=> ? /= [? hI] [] /= ? hkI; rewrite !hkI; apply: hI. Qed. Lemma idealr0 : 0 \in kI. Proof. exact: rpred0. Qed. End IdealTheory. Section PrimeIdealTheory. Variables (R : comRingType) (I : predPredType R) (pidealrI : prime_idealr I) (kI : keyed_pred pidealrI). Lemma prime_idealrM u v : (u * v \in kI) = (u \in kI) || (v \in kI). Proof. apply/idP/idP; last by case/orP => /idealMr hI; rewrite // mulrC. by case: pidealrI kI=> ? /= hI [] /= ? hkI; rewrite !hkI; apply: hI. Qed. End PrimeIdealTheory. End IdealDef. Module Quotient. Section ZmodQuotient. Variables (R : zmodType) (I : predPredType R) (zmodI : zmodPred I) (kI : keyed_pred zmodI). Definition equiv (x y : R) := (x - y) \in kI. Lemma equivE x y : (equiv x y) = (x - y \in kI). Proof. by []. Qed. Lemma equiv_is_equiv : equiv_class_of equiv. Proof. split=> [x|x y|y x z]; rewrite !equivE ?subrr ?rpred0 //. by rewrite -opprB rpredN. by move=> *; rewrite -[x](addrNK y) -addrA rpredD. Qed. Canonical equiv_equiv := EquivRelPack equiv_is_equiv. Canonical equiv_encModRel := defaultEncModRel equiv. Definition type := {eq_quot equiv}. Definition type_of of phant R := type. Canonical rquot_quotType := [quotType of type]. Canonical rquot_eqType := [eqType of type]. Canonical rquot_choiceType := [choiceType of type]. Canonical rquot_eqQuotType := [eqQuotType equiv of type]. Lemma idealrBE x y : (x - y) \in kI = (x == y %[mod type]). Proof. by rewrite piE equivE. Qed. Lemma idealrDE x y : (x + y) \in kI = (x == - y %[mod type]). Proof. by rewrite -idealrBE opprK. Qed. Definition zero : type := lift_cst type 0. Definition add := lift_op2 type +%R. Definition opp := lift_op1 type -%R. Canonical pi_zero_morph := PiConst zero. Lemma pi_opp : {morph \pi : x / - x >-> opp x}. Proof. move=> x; unlock opp; apply/eqP; rewrite piE equivE. by rewrite -opprD rpredN idealrDE opprK reprK. Qed. Canonical pi_opp_morph := PiMorph1 pi_opp. Lemma pi_add : {morph \pi : x y / x + y >-> add x y}. Proof. move=> x y /=; unlock add; apply/eqP; rewrite piE equivE. rewrite opprD addrAC addrA -addrA. by rewrite rpredD // (idealrBE, idealrDE) ?pi_opp ?reprK. Qed. Canonical pi_add_morph := PiMorph2 pi_add. Lemma addqA: associative add. Proof. by move=> x y z; rewrite -[x]reprK -[y]reprK -[z]reprK !piE addrA. Qed. Lemma addqC: commutative add. Proof. by move=> x y; rewrite -[x]reprK -[y]reprK !piE addrC. Qed. Lemma add0q: left_id zero add. Proof. by move=> x; rewrite -[x]reprK !piE add0r. Qed. Lemma addNq: left_inverse zero opp add. Proof. by move=> x; rewrite -[x]reprK !piE addNr. Qed. Definition rquot_zmodMixin := ZmodMixin addqA addqC add0q addNq. Canonical rquot_zmodType := Eval hnf in ZmodType type rquot_zmodMixin. Definition rquot_zmodQuotMixin := ZmodQuotMixin type (lock _) pi_opp pi_add. Canonical rquot_zmodQuotType := ZmodQuotType 0 -%R +%R type rquot_zmodQuotMixin. End ZmodQuotient. Notation "{quot I }" := (@type_of _ _ _ I (Phant _)). Section RingQuotient. Variables (R : comRingType) (I : predPredType R) (idealI : idealr I) (kI : keyed_pred idealI). Local Notation type := {quot kI}. Definition one: type := lift_cst type 1. Definition mul := lift_op2 type *%R. Canonical pi_one_morph := PiConst one. Lemma pi_mul: {morph \pi : x y / x * y >-> mul x y}. Proof. move=> x y; unlock mul; apply/eqP; rewrite piE equivE. rewrite -[_ * _](addrNK (x * repr (\pi_type y))) -mulrBr. rewrite -addrA -mulrBl rpredD //. by rewrite idealMr // idealrDE opprK reprK. by rewrite mulrC idealMr // idealrDE opprK reprK. Qed. Canonical pi_mul_morph := PiMorph2 pi_mul. Lemma mulqA: associative mul. Proof. by move=> x y z; rewrite -[x]reprK -[y]reprK -[z]reprK !piE mulrA. Qed. Lemma mulqC: commutative mul. Proof. by move=> x y; rewrite -[x]reprK -[y]reprK !piE mulrC. Qed. Lemma mul1q: left_id one mul. Proof. by move=> x; rewrite -[x]reprK !piE mul1r. Qed. Lemma mulq_addl: left_distributive mul +%R. Proof. move=> x y z; rewrite -[x]reprK -[y]reprK -[z]reprK. by apply/eqP; rewrite piE /= mulrDl equiv_refl. Qed. Lemma nonzero1q: one != 0. Proof. by rewrite piE equivE subr0 idealr1. Qed. Definition rquot_comRingMixin := ComRingMixin mulqA mulqC mul1q mulq_addl nonzero1q. Canonical rquot_ringType := Eval hnf in RingType type rquot_comRingMixin. Canonical rquot_comRingType := Eval hnf in ComRingType type mulqC. Definition rquot_ringQuotMixin := RingQuotMixin type (lock _) pi_mul. Canonical rquot_ringQuotType := RingQuotType 1 *%R type rquot_ringQuotMixin. End RingQuotient. Section IDomainQuotient. Variables (R : comRingType) (I : predPredType R) (pidealI : prime_idealr I) (kI : keyed_pred pidealI). Lemma rquot_IdomainAxiom (x y : {quot kI}): x * y = 0 -> (x == 0) || (y == 0). Proof. by move=> /eqP; rewrite -[x]reprK -[y]reprK !piE !equivE !subr0 prime_idealrM. Qed. End IDomainQuotient. End Quotient. Notation "{ideal_quot I }" := (@Quotient.type_of _ _ _ I (Phant _)). Notation "x == y %[mod_ideal I ]" := (x == y %[mod {ideal_quot I}]) : quotient_scope. Notation "x = y %[mod_ideal I ]" := (x = y %[mod {ideal_quot I}]) : quotient_scope. Notation "x != y %[mod_ideal I ]" := (x != y %[mod {ideal_quot I}]) : quotient_scope. Notation "x <> y %[mod_ideal I ]" := (x <> y %[mod {ideal_quot I}]) : quotient_scope. Canonical Quotient.rquot_eqType. Canonical Quotient.rquot_choiceType. Canonical Quotient.rquot_zmodType. Canonical Quotient.rquot_ringType. Canonical Quotient.rquot_quotType. Canonical Quotient.rquot_eqQuotType. Canonical Quotient.rquot_zmodQuotType. Canonical Quotient.rquot_ringQuotType. mathcomp-1.5/theories/countalg.v0000644000175000017500000014014012307636117016006 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq choice fintype. Require Import bigop ssralg finalg zmodp matrix mxalgebra. Require Import poly polydiv mxpoly generic_quotient ring_quotient closed_field. Require Import ssrint rat. (*****************************************************************************) (* This file clones part of ssralg hierachy for countable types; it does not *) (* cover the left module / algebra interfaces, providing only *) (* countZmodType == countable zmodType interface. *) (* countRingType == countable ringType interface. *) (* countComRingType == countable comRingType interface. *) (* countUnitRingType == countable unitRingType interface. *) (* countComUnitRingType == countable comUnitRingType interface. *) (* countIdomainType == countable idomainType interface. *) (* countFieldType == countable fieldType interface. *) (* countDecFieldType == countable decFieldType interface. *) (* countClosedFieldType == countable closedFieldType interface. *) (* The interface cloning syntax is extended to these structures *) (* [countZmodType of M] == countZmodType structure for an M that has both *) (* zmodType and countType structures. *) (* ... etc *) (* This file provides constructions for both simple extension and algebraic *) (* closure of countable fields. *) (*****************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Local Open Scope ring_scope. Import GRing.Theory CodeSeq. Module CountRing. Local Notation mixin_of T := (Countable.mixin_of T). Section Generic. (* Implicits *) Variables (type base_type : Type) (class_of base_of : Type -> Type). Variable base_sort : base_type -> Type. (* Explicits *) Variable Pack : forall T, class_of T -> Type -> type. Variable Class : forall T, base_of T -> mixin_of T -> class_of T. Variable base_class : forall bT, base_of (base_sort bT). Definition gen_pack T := fun bT b & phant_id (base_class bT) b => fun fT c m & phant_id (Countable.class fT) (Countable.Class c m) => Pack (@Class T b m) T. End Generic. Implicit Arguments gen_pack [type base_type class_of base_of base_sort]. Local Notation cnt_ c := (@Countable.Class _ c c). Local Notation do_pack pack T := (pack T _ _ id _ _ _ id). Import GRing.Theory. Module Zmodule. Section ClassDef. Record class_of M := Class { base : GRing.Zmodule.class_of M; mixin : mixin_of M }. Local Coercion base : class_of >-> GRing.Zmodule.class_of. Local Coercion mixin : class_of >-> mixin_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.Zmodule.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (cnt_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition join_countType := @Countable.Pack zmodType (cnt_ xclass) xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.Zmodule.class_of. Coercion mixin : class_of >-> mixin_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Canonical join_countType. Notation countZmodType := type. Notation "[ 'countZmodType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'countZmodType' 'of' T ]") : form_scope. End Exports. End Zmodule. Import Zmodule.Exports. Module Ring. Section ClassDef. Record class_of R := Class { base : GRing.Ring.class_of R; mixin : mixin_of R }. Definition base2 R (c : class_of R) := Zmodule.Class (base c) (mixin c). Local Coercion base : class_of >-> GRing.Ring.class_of. Local Coercion base2 : class_of >-> Zmodule.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.Ring.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (cnt_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass cT. Definition countZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition join_countType := @Countable.Pack ringType (cnt_ xclass) xT. Definition join_countZmodType := @Zmodule.Pack ringType xclass xT. End ClassDef. Module Import Exports. Coercion base : class_of >-> GRing.Ring.class_of. Coercion base2 : class_of >-> Zmodule.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion countZmodType : type >-> Zmodule.type. Canonical countZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Canonical join_countType. Canonical join_countZmodType. Notation countRingType := type. Notation "[ 'countRingType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'countRingType' 'of' T ]") : form_scope. End Exports. End Ring. Import Ring.Exports. Module ComRing. Section ClassDef. Record class_of R := Class { base : GRing.ComRing.class_of R; mixin : mixin_of R }. Definition base2 R (c : class_of R) := Ring.Class (base c) (mixin c). Local Coercion base : class_of >-> GRing.ComRing.class_of. Local Coercion base2 : class_of >-> Ring.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.ComRing.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (cnt_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition countZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition countRingType := @Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition join_countType := @Countable.Pack comRingType (cnt_ xclass) xT. Definition join_countZmodType := @Zmodule.Pack comRingType xclass xT. Definition join_countRingType := @Ring.Pack comRingType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.ComRing.class_of. Coercion base2 : class_of >-> Ring.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion countZmodType : type >-> Zmodule.type. Canonical countZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion countRingType : type >-> Ring.type. Canonical countRingType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Canonical join_countType. Canonical join_countZmodType. Canonical join_countRingType. Notation countComRingType := CountRing.ComRing.type. Notation "[ 'countComRingType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'countComRingType' 'of' T ]") : form_scope. End Exports. End ComRing. Import ComRing.Exports. Module UnitRing. Section ClassDef. Record class_of R := Class { base : GRing.UnitRing.class_of R; mixin : mixin_of R }. Definition base2 R (c : class_of R) := Ring.Class (base c) (mixin c). Local Coercion base : class_of >-> GRing.UnitRing.class_of. Local Coercion base2 : class_of >-> Ring.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.UnitRing.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (cnt_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition countZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition countRingType := @Ring.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition join_countType := @Countable.Pack unitRingType (cnt_ xclass) xT. Definition join_countZmodType := @Zmodule.Pack unitRingType xclass xT. Definition join_countRingType := @Ring.Pack unitRingType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.UnitRing.class_of. Coercion base2 : class_of >-> Ring.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion countZmodType : type >-> Zmodule.type. Canonical countZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion countRingType : type >-> Ring.type. Canonical countRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Canonical join_countType. Canonical join_countZmodType. Canonical join_countRingType. Notation countUnitRingType := CountRing.UnitRing.type. Notation "[ 'countUnitRingType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'countUnitRingType' 'of' T ]") : form_scope. End Exports. End UnitRing. Import UnitRing.Exports. Module ComUnitRing. Section ClassDef. Record class_of R := Class { base : GRing.ComUnitRing.class_of R; mixin : mixin_of R }. Definition base2 R (c : class_of R) := ComRing.Class (base c) (mixin c). Definition base3 R (c : class_of R) := @UnitRing.Class R (base c) (mixin c). Local Coercion base : class_of >-> GRing.ComUnitRing.class_of. Local Coercion base2 : class_of >-> ComRing.class_of. Local Coercion base3 : class_of >-> UnitRing.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.ComUnitRing.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (cnt_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition countZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition countRingType := @Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition countComRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition countUnitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition join_countType := @Countable.Pack comUnitRingType (cnt_ xclass) xT. Definition join_countZmodType := @Zmodule.Pack comUnitRingType xclass xT. Definition join_countRingType := @Ring.Pack comUnitRingType xclass xT. Definition join_countComRingType := @ComRing.Pack comUnitRingType xclass xT. Definition join_countUnitRingType := @UnitRing.Pack comUnitRingType xclass xT. Definition ujoin_countComRingType := @ComRing.Pack unitRingType xclass xT. Definition cjoin_countUnitRingType := @UnitRing.Pack comRingType xclass xT. Definition ccjoin_countUnitRingType := @UnitRing.Pack countComRingType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.ComUnitRing.class_of. Coercion base2 : class_of >-> ComRing.class_of. Coercion base3 : class_of >-> UnitRing.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion countZmodType : type >-> Zmodule.type. Canonical countZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion countRingType : type >-> Ring.type. Canonical countRingType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion countComRingType : type >-> ComRing.type. Canonical countComRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion countUnitRingType : type >-> UnitRing.type. Canonical countUnitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Canonical join_countType. Canonical join_countZmodType. Canonical join_countRingType. Canonical join_countComRingType. Canonical join_countUnitRingType. Canonical ujoin_countComRingType. Canonical cjoin_countUnitRingType. Canonical ccjoin_countUnitRingType. Notation countComUnitRingType := CountRing.ComUnitRing.type. Notation "[ 'countComUnitRingType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'countComUnitRingType' 'of' T ]") : form_scope. End Exports. End ComUnitRing. Import ComUnitRing.Exports. Module IntegralDomain. Section ClassDef. Record class_of R := Class { base : GRing.IntegralDomain.class_of R; mixin : mixin_of R }. Definition base2 R (c : class_of R) := ComUnitRing.Class (base c) (mixin c). Local Coercion base : class_of >-> GRing.IntegralDomain.class_of. Local Coercion base2 : class_of >-> ComUnitRing.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.IntegralDomain.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (cnt_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition countZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition countRingType := @Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition countComRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition countUnitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition countComUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition join_countType := @Countable.Pack idomainType (cnt_ xclass) xT. Definition join_countZmodType := @Zmodule.Pack idomainType xclass xT. Definition join_countRingType := @Ring.Pack idomainType xclass xT. Definition join_countUnitRingType := @UnitRing.Pack idomainType xclass xT. Definition join_countComRingType := @ComRing.Pack idomainType xclass xT. Definition join_countComUnitRingType := @ComUnitRing.Pack idomainType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.IntegralDomain.class_of. Coercion base2 : class_of >-> ComUnitRing.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion countZmodType : type >-> Zmodule.type. Canonical countZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion countRingType : type >-> Ring.type. Canonical countRingType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion countComRingType : type >-> ComRing.type. Canonical countComRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion countUnitRingType : type >-> UnitRing.type. Canonical countUnitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion countComUnitRingType : type >-> ComUnitRing.type. Canonical countComUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Canonical join_countType. Canonical join_countZmodType. Canonical join_countRingType. Canonical join_countComRingType. Canonical join_countUnitRingType. Canonical join_countComUnitRingType. Notation countIdomainType := CountRing.IntegralDomain.type. Notation "[ 'countIdomainType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'countIdomainType' 'of' T ]") : form_scope. End Exports. End IntegralDomain. Import IntegralDomain.Exports. Module Field. Section ClassDef. Record class_of R := Class { base : GRing.Field.class_of R; mixin : mixin_of R }. Definition base2 R (c : class_of R) := IntegralDomain.Class (base c) (mixin c). Local Coercion base : class_of >-> GRing.Field.class_of. Local Coercion base2 : class_of >-> IntegralDomain.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.Field.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (cnt_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition countZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition countRingType := @Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition countComRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition countUnitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition countComUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition countIdomainType := @IntegralDomain.Pack cT xclass xT. Definition fieldType := @GRing.Field.Pack cT xclass xT. Definition join_countType := @Countable.Pack fieldType (cnt_ xclass) xT. Definition join_countZmodType := @Zmodule.Pack fieldType xclass xT. Definition join_countRingType := @Ring.Pack fieldType xclass xT. Definition join_countUnitRingType := @UnitRing.Pack fieldType xclass xT. Definition join_countComRingType := @ComRing.Pack fieldType xclass xT. Definition join_countComUnitRingType := @ComUnitRing.Pack fieldType xclass xT. Definition join_countIdomainType := @IntegralDomain.Pack fieldType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.Field.class_of. Coercion base2 : class_of >-> IntegralDomain.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion countZmodType : type >-> Zmodule.type. Canonical countZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion countRingType : type >-> Ring.type. Canonical countRingType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion countComRingType : type >-> ComRing.type. Canonical countComRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion countUnitRingType : type >-> UnitRing.type. Canonical countUnitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion countComUnitRingType : type >-> ComUnitRing.type. Canonical countComUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Coercion countIdomainType : type >-> IntegralDomain.type. Canonical countIdomainType. Coercion fieldType : type >-> GRing.Field.type. Canonical fieldType. Canonical join_countType. Canonical join_countZmodType. Canonical join_countRingType. Canonical join_countComRingType. Canonical join_countUnitRingType. Canonical join_countComUnitRingType. Canonical join_countIdomainType. Notation countFieldType := CountRing.Field.type. Notation "[ 'countFieldType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'countFieldType' 'of' T ]") : form_scope. End Exports. End Field. Import Field.Exports. Module DecidableField. Section ClassDef. Record class_of R := Class { base : GRing.DecidableField.class_of R; mixin : mixin_of R }. Definition base2 R (c : class_of R) := Field.Class (base c) (mixin c). Local Coercion base : class_of >-> GRing.DecidableField.class_of. Local Coercion base2 : class_of >-> Field.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.DecidableField.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (cnt_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition countZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition countRingType := @Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition countComRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition countUnitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition countComUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition countIdomainType := @IntegralDomain.Pack cT xclass xT. Definition fieldType := @GRing.Field.Pack cT xclass xT. Definition countFieldType := @Field.Pack cT xclass xT. Definition decFieldType := @GRing.DecidableField.Pack cT xclass xT. Definition join_countType := @Countable.Pack decFieldType (cnt_ xclass) xT. Definition join_countZmodType := @Zmodule.Pack decFieldType xclass xT. Definition join_countRingType := @Ring.Pack decFieldType xclass xT. Definition join_countUnitRingType := @UnitRing.Pack decFieldType xclass xT. Definition join_countComRingType := @ComRing.Pack decFieldType xclass xT. Definition join_countComUnitRingType := @ComUnitRing.Pack decFieldType xclass xT. Definition join_countIdomainType := @IntegralDomain.Pack decFieldType xclass xT. Definition join_countFieldType := @Field.Pack decFieldType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.DecidableField.class_of. Coercion base2 : class_of >-> Field.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion countZmodType : type >-> Zmodule.type. Canonical countZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion countRingType : type >-> Ring.type. Canonical countRingType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion countComRingType : type >-> ComRing.type. Canonical countComRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion countUnitRingType : type >-> UnitRing.type. Canonical countUnitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion countComUnitRingType : type >-> ComUnitRing.type. Canonical countComUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Coercion countIdomainType : type >-> IntegralDomain.type. Canonical countIdomainType. Coercion fieldType : type >-> GRing.Field.type. Canonical fieldType. Coercion countFieldType : type >-> Field.type. Canonical countFieldType. Coercion decFieldType : type >-> GRing.DecidableField.type. Canonical decFieldType. Canonical join_countType. Canonical join_countZmodType. Canonical join_countRingType. Canonical join_countComRingType. Canonical join_countUnitRingType. Canonical join_countComUnitRingType. Canonical join_countIdomainType. Canonical join_countFieldType. Notation countDecFieldType := CountRing.DecidableField.type. Notation "[ 'countDecFieldType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'countDecFieldType' 'of' T ]") : form_scope. End Exports. End DecidableField. Import DecidableField.Exports. Module ClosedField. Section ClassDef. Record class_of R := Class { base : GRing.ClosedField.class_of R; mixin : mixin_of R }. Definition base2 R (c : class_of R) := DecidableField.Class (base c) (mixin c). Local Coercion base : class_of >-> GRing.ClosedField.class_of. Local Coercion base2 : class_of >-> DecidableField.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Definition pack := gen_pack Pack Class GRing.ClosedField.class. Variable cT : type. Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition countType := @Countable.Pack cT (cnt_ xclass) xT. Definition zmodType := @GRing.Zmodule.Pack cT xclass xT. Definition countZmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @GRing.Ring.Pack cT xclass xT. Definition countRingType := @Ring.Pack cT xclass xT. Definition comRingType := @GRing.ComRing.Pack cT xclass xT. Definition countComRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @GRing.UnitRing.Pack cT xclass xT. Definition countUnitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @GRing.ComUnitRing.Pack cT xclass xT. Definition countComUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @GRing.IntegralDomain.Pack cT xclass xT. Definition countIdomainType := @IntegralDomain.Pack cT xclass xT. Definition fieldType := @GRing.Field.Pack cT xclass xT. Definition countFieldType := @Field.Pack cT xclass xT. Definition decFieldType := @GRing.DecidableField.Pack cT xclass xT. Definition countDecFieldType := @DecidableField.Pack cT xclass xT. Definition closedFieldType := @GRing.ClosedField.Pack cT xclass xT. Definition join_countType := @Countable.Pack closedFieldType (cnt_ xclass) xT. Definition join_countZmodType := @Zmodule.Pack closedFieldType xclass xT. Definition join_countRingType := @Ring.Pack closedFieldType xclass xT. Definition join_countUnitRingType := @UnitRing.Pack closedFieldType xclass xT. Definition join_countComRingType := @ComRing.Pack closedFieldType xclass xT. Definition join_countComUnitRingType := @ComUnitRing.Pack closedFieldType xclass xT. Definition join_countIdomainType := @IntegralDomain.Pack closedFieldType xclass xT. Definition join_countFieldType := @Field.Pack closedFieldType xclass xT. Definition join_countDecFieldType := @DecidableField.Pack closedFieldType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> GRing.ClosedField.class_of. Coercion base2 : class_of >-> DecidableField.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion countType : type >-> Countable.type. Canonical countType. Coercion zmodType : type >-> GRing.Zmodule.type. Canonical zmodType. Coercion countZmodType : type >-> Zmodule.type. Canonical countZmodType. Coercion ringType : type >-> GRing.Ring.type. Canonical ringType. Coercion countRingType : type >-> Ring.type. Canonical countRingType. Coercion comRingType : type >-> GRing.ComRing.type. Canonical comRingType. Coercion countComRingType : type >-> ComRing.type. Canonical countComRingType. Coercion unitRingType : type >-> GRing.UnitRing.type. Canonical unitRingType. Coercion countUnitRingType : type >-> UnitRing.type. Canonical countUnitRingType. Coercion comUnitRingType : type >-> GRing.ComUnitRing.type. Canonical comUnitRingType. Coercion countComUnitRingType : type >-> ComUnitRing.type. Canonical countComUnitRingType. Coercion idomainType : type >-> GRing.IntegralDomain.type. Canonical idomainType. Coercion fieldType : type >-> GRing.Field.type. Canonical fieldType. Coercion countFieldType : type >-> Field.type. Canonical countFieldType. Coercion decFieldType : type >-> GRing.DecidableField.type. Canonical decFieldType. Coercion countDecFieldType : type >-> DecidableField.type. Canonical countDecFieldType. Coercion closedFieldType : type >-> GRing.ClosedField.type. Canonical closedFieldType. Canonical join_countType. Canonical join_countZmodType. Canonical join_countRingType. Canonical join_countComRingType. Canonical join_countUnitRingType. Canonical join_countComUnitRingType. Canonical join_countIdomainType. Canonical join_countFieldType. Canonical join_countDecFieldType. Notation countClosedFieldType := CountRing.ClosedField.type. Notation "[ 'countClosedFieldType' 'of' T ]" := (do_pack pack T) (at level 0, format "[ 'countClosedFieldType' 'of' T ]") : form_scope. End Exports. End ClosedField. Import ClosedField.Exports. End CountRing. Import CountRing. Export Zmodule.Exports Ring.Exports ComRing.Exports UnitRing.Exports. Export ComUnitRing.Exports IntegralDomain.Exports. Export Field.Exports DecidableField.Exports ClosedField.Exports. Require Import poly polydiv generic_quotient ring_quotient. Require Import mxpoly polyXY. Import GRing.Theory. Require Import closed_field. Canonical Zp_countZmodType m := [countZmodType of 'I_m.+1]. Canonical Zp_countRingType m := [countRingType of 'I_m.+2]. Canonical Zp_countComRingType m := [countComRingType of 'I_m.+2]. Canonical Zp_countUnitRingType m := [countUnitRingType of 'I_m.+2]. Canonical Zp_countComUnitRingType m := [countComUnitRingType of 'I_m.+2]. Canonical Fp_countIdomainType p := [countIdomainType of 'F_p]. Canonical Fp_countFieldType p := [countFieldType of 'F_p]. Canonical Fp_countDecFieldType p := [countDecFieldType of 'F_p]. Canonical matrix_countZmodType (M : countZmodType) m n := [countZmodType of 'M[M]_(m, n)]. Canonical matrix_countRingType (R : countRingType) n := [countRingType of 'M[R]_n.+1]. Canonical matrix_countUnitRingType (R : countComUnitRingType) n := [countUnitRingType of 'M[R]_n.+1]. Definition poly_countMixin (R : countRingType) := [countMixin of polynomial R by <:]. Canonical polynomial_countType R := CountType _ (poly_countMixin R). Canonical poly_countType (R : countRingType) := [countType of {poly R}]. Canonical polynomial_countZmodType (R : countRingType) := [countZmodType of polynomial R]. Canonical poly_countZmodType (R : countRingType) := [countZmodType of {poly R}]. Canonical polynomial_countRingType (R : countRingType) := [countRingType of polynomial R]. Canonical poly_countRingType (R : countRingType) := [countRingType of {poly R}]. Canonical polynomial_countComRingType (R : countComRingType) := [countComRingType of polynomial R]. Canonical poly_countComRingType (R : countComRingType) := [countComRingType of {poly R}]. Canonical polynomial_countUnitRingType (R : countIdomainType) := [countUnitRingType of polynomial R]. Canonical poly_countUnitRingType (R : countIdomainType) := [countUnitRingType of {poly R}]. Canonical polynomial_countComUnitRingType (R : countIdomainType) := [countComUnitRingType of polynomial R]. Canonical poly_countComUnitRingType (R : countIdomainType) := [countComUnitRingType of {poly R}]. Canonical polynomial_countIdomainType (R : countIdomainType) := [countIdomainType of polynomial R]. Canonical poly_countIdomainType (R : countIdomainType) := [countIdomainType of {poly R}]. Canonical int_countZmodType := [countZmodType of int]. Canonical int_countRingType := [countRingType of int]. Canonical int_countComRingType := [countComRingType of int]. Canonical int_countUnitRingType := [countUnitRingType of int]. Canonical int_countComUnitRingType := [countComUnitRingType of int]. Canonical int_countIdomainType := [countIdomainType of int]. Canonical rat_countZmodType := [countZmodType of rat]. Canonical rat_countRingType := [countRingType of rat]. Canonical rat_countComRingType := [countComRingType of rat]. Canonical rat_countUnitRingType := [countUnitRingType of rat]. Canonical rat_countComUnitRingType := [countComUnitRingType of rat]. Canonical rat_countIdomainType := [countIdomainType of rat]. Canonical rat_countFieldType := [countFieldType of rat]. Lemma countable_field_extension (F : countFieldType) (p : {poly F}) : size p > 1 -> {E : countFieldType & {FtoE : {rmorphism F -> E} & {w : E | root (map_poly FtoE p) w & forall u : E, exists q, u = (map_poly FtoE q).[w]}}}. Proof. pose fix d i := if i is i1.+1 then let d1 := oapp (gcdp (d i1)) 0 (unpickle i1) in if size d1 > 1 then d1 else d i1 else p. move=> p_gt1; have sz_d i: size (d i) > 1 by elim: i => //= i IHi; case: ifP. have dv_d i j: i <= j -> d j %| d i. move/subnK <-; elim: {j}(j - i)%N => //= j IHj; case: ifP => //=. case: (unpickle _) => /= [q _|]; last by rewrite size_poly0. exact: dvdp_trans (dvdp_gcdl _ _) IHj. pose I : pred {poly F} := [pred q | d (pickle q).+1 %| q]. have I'co q i: q \notin I -> i > pickle q -> coprimep q (d i). rewrite inE => I'q /dv_d/coprimep_dvdl-> //; apply: contraR I'q. rewrite coprimep_sym /coprimep /= pickleK /= neq_ltn. case: ifP => [_ _| ->]; first exact: dvdp_gcdr. rewrite orbF ltnS leqn0 size_poly_eq0 gcdp_eq0 -size_poly_eq0. by rewrite -leqn0 leqNgt ltnW //. have memI q: reflect (exists i, d i %| q) (q \in I). apply: (iffP idP) => [|[i dv_di_q]]; first by exists (pickle q).+1. have [le_i_q | /I'co i_co_q] := leqP i (pickle q). rewrite inE /= pickleK /=; case: ifP => _; first exact: dvdp_gcdr. exact: dvdp_trans (dv_d _ _ le_i_q) dv_di_q. apply: contraR i_co_q _. by rewrite /coprimep (eqp_size (dvdp_gcd_idr dv_di_q)) neq_ltn sz_d orbT. have I_ideal : idealr_closed I. split=> [||a q1 q2 Iq1 Iq2]; first exact: dvdp0. by apply/memI=> [[i /idPn[]]]; rewrite dvdp1 neq_ltn sz_d orbT. apply/memI; exists (maxn (pickle q1).+1 (pickle q2).+1); apply: dvdp_add. by apply: dvdp_mull; apply: dvdp_trans Iq1; apply/dv_d/leq_maxl. by apply: dvdp_trans Iq2; apply/dv_d/leq_maxr. pose Iaddkey := GRing.Pred.Add (DefaultPredKey I) I_ideal. pose Iidkey := MkIdeal (GRing.Pred.Zmod Iaddkey I_ideal) I_ideal. pose E := ComRingType _ (@Quotient.mulqC _ _ _ (KeyedPred Iidkey)). pose PtoE : {rmorphism {poly F} -> E} := [rmorphism of \pi_E%qT : {poly F} -> E]. have PtoEd i: PtoE (d i) = 0. by apply/eqP; rewrite piE Quotient.equivE subr0; apply/memI; exists i. pose Einv (z : E) (q := repr z) (dq := d (pickle q).+1) := let q_unitP := Bezout_eq1_coprimepP q dq in if q_unitP is ReflectT ex_uv then PtoE (sval (sig_eqW ex_uv)).1 else 0. have Einv0: Einv 0 = 0. rewrite /Einv; case: Bezout_eq1_coprimepP => // ex_uv. case/negP: (oner_neq0 E); rewrite piE -[_ 1]/(PtoE 1); have [uv <-] := ex_uv. by rewrite rmorphD !rmorphM PtoEd /= reprK !mulr0 addr0. have EmulV: GRing.Field.axiom Einv. rewrite /Einv=> z nz_z; case: Bezout_eq1_coprimepP => [ex_uv |]; last first. move/Bezout_eq1_coprimepP; rewrite I'co //. by rewrite piE -{1}[z]reprK -Quotient.idealrBE subr0 in nz_z. apply/eqP; case: sig_eqW => {ex_uv} [uv uv1]; set i := _.+1 in uv1 *. rewrite piE /= -[z]reprK -(rmorphM PtoE) -Quotient.idealrBE. by rewrite -uv1 opprD addNKr -mulNr; apply/memI; exists i; exact: dvdp_mull. pose EringU := [comUnitRingType of UnitRingType _ (FieldUnitMixin EmulV Einv0)]. have Eunitf := @FieldMixin _ _ EmulV Einv0. pose Efield := FieldType (IdomainType EringU (FieldIdomainMixin Eunitf)) Eunitf. pose Ecount := CountType Efield (CanCountMixin (@reprK _ _)). pose FtoE := [rmorphism of PtoE \o polyC]; pose w : E := PtoE 'X. have defPtoE q: (map_poly FtoE q).[w] = PtoE q. by rewrite map_poly_comp horner_map [_.['X]]comp_polyXr. exists [countFieldType of Ecount], FtoE, w => [|u]. by rewrite /root defPtoE (PtoEd 0%N). by exists (repr u); rewrite defPtoE /= reprK. Qed. Lemma countable_algebraic_closure (F : countFieldType) : {K : countClosedFieldType & {FtoK : {rmorphism F -> K} | integralRange FtoK}}. Proof. pose minXp (R : ringType) (p : {poly R}) := if size p > 1 then p else 'X. have minXp_gt1 R p: size (minXp R p) > 1. by rewrite /minXp; case: ifP => // _; rewrite size_polyX. have minXpE (R : ringType) (p : {poly R}) : size p > 1 -> minXp R p = p. by rewrite /minXp => ->. have ext1 p := countable_field_extension (minXp_gt1 _ p). pose ext1fT E p := tag (ext1 E p). pose ext1to E p : {rmorphism _ -> ext1fT E p} := tag (tagged (ext1 E p)). pose ext1w E p : ext1fT E p := s2val (tagged (tagged (ext1 E p))). have ext1root E p: root (map_poly (ext1to E p) (minXp E p)) (ext1w E p). by rewrite /ext1w; case: (tagged (tagged (ext1 E p))). have ext1gen E p u: {q | u = (map_poly (ext1to E p) q).[ext1w E p]}. by apply: sig_eqW; rewrite /ext1w; case: (tagged (tagged (ext1 E p))) u. pose pExtEnum (E : countFieldType) := nat -> {poly E}. pose Ext := {E : countFieldType & pExtEnum E}; pose MkExt : Ext := Tagged _ _. pose EtoInc (E : Ext) i := ext1to (tag E) (tagged E i). pose incEp E i j := let v := map_poly (EtoInc E i) (tagged E j) in if decode j is [:: i1; k] then if i1 == i then odflt v (unpickle k) else v else v. pose fix E_ i := if i is i1.+1 then MkExt _ (incEp (E_ i1) i1) else MkExt F \0. pose E i := tag (E_ i); pose Krep := {i : nat & E i}. pose fix toEadd i k : {rmorphism E i -> E (k + i)%N} := if k is k1.+1 then [rmorphism of EtoInc _ (k1 + i)%N \o toEadd _ _] else [rmorphism of idfun]. pose toE i j (le_ij : i <= j) := ecast j {rmorphism E i -> E j} (subnK le_ij) (toEadd i (j - i)%N). have toEeq i le_ii: toE i i le_ii =1 id. by rewrite /toE; move: (subnK _); rewrite subnn => ?; rewrite eq_axiomK. have toEleS i j leij leiSj z: toE i j.+1 leiSj z = EtoInc _ _ (toE i j leij z). rewrite /toE; move: (j - i)%N {leij leiSj}(subnK _) (subnK _) => k. by case: j /; rewrite (addnK i k.+1) => eq_kk; rewrite [eq_kk]eq_axiomK. have toEirr := congr1 ((toE _ _)^~ _) (bool_irrelevance _ _). have toEtrans j i k leij lejk leik z: toE i k leik z = toE j k lejk (toE i j leij z). - elim: k leik lejk => [|k IHk] leiSk lejSk. by case: j => // in leij lejSk *; rewrite toEeq. have:= lejSk; rewrite {1}leq_eqVlt ltnS => /predU1P[Dk | lejk]. by rewrite -Dk in leiSk lejSk *; rewrite toEeq. by have leik := leq_trans leij lejk; rewrite !toEleS -IHk. have [leMl leMr] := (leq_maxl, leq_maxr); pose le_max := (leq_max, leqnn, orbT). pose pairK (x y : Krep) (m := maxn _ _) := (toE _ m (leMl _ _) (tagged x), toE _ m (leMr _ _) (tagged y)). pose eqKrep x y := prod_curry (@eq_op _) (pairK x y). have eqKrefl : reflexive eqKrep by move=> z; apply/eqP; apply: toEirr. have eqKsym : symmetric eqKrep. move=> z1 z2; rewrite {1}/eqKrep /= eq_sym; move: (leMl _ _) (leMr _ _). by rewrite maxnC => lez1m lez2m; congr (_ == _); apply: toEirr. have eqKtrans : transitive eqKrep. rewrite /eqKrep /= => z2 z1 z3 /eqP eq_z12 /eqP eq_z23. rewrite -(inj_eq (fmorph_inj (toE _ _ (leMr (tag z2) _)))). rewrite -!toEtrans ?le_max // maxnCA maxnA => lez3m lez1m. rewrite {lez1m}(toEtrans (maxn (tag z1) (tag z2))) // {}eq_z12. do [rewrite -toEtrans ?le_max // -maxnA => lez2m] in lez3m *. by rewrite (toEtrans (maxn (tag z2) (tag z3))) // eq_z23 -toEtrans. pose K := {eq_quot (EquivRel _ eqKrefl eqKsym eqKtrans)}%qT. have cntK : Countable.mixin_of K := CanCountMixin (@reprK _ _). pose EtoKrep i (x : E i) : K := \pi%qT (Tagged E x). have [EtoK piEtoK]: {EtoK | forall i, EtoKrep i =1 EtoK i} by exists EtoKrep. pose FtoK := EtoK 0%N; rewrite {}/EtoKrep in piEtoK. have eqEtoK i j x y: toE i _ (leMl i j) x = toE j _ (leMr i j) y -> EtoK i x = EtoK j y. - by move/eqP=> eq_xy; rewrite -!piEtoK; apply/eqmodP. have toEtoK j i leij x : EtoK j (toE i j leij x) = EtoK i x. by apply: eqEtoK; rewrite -toEtrans. have EtoK_0 i: EtoK i 0 = FtoK 0 by apply: eqEtoK; rewrite !rmorph0. have EtoK_1 i: EtoK i 1 = FtoK 1 by apply: eqEtoK; rewrite !rmorph1. have EtoKeq0 i x: (EtoK i x == FtoK 0) = (x == 0). by rewrite /FtoK -!piEtoK eqmodE /= /eqKrep /= rmorph0 fmorph_eq0. have toErepr m i leim x lerm: toE _ m lerm (tagged (repr (EtoK i x))) = toE i m leim x. - have: (Tagged E x == repr (EtoK i x) %[mod K])%qT by rewrite reprK piEtoK. rewrite eqmodE /= /eqKrep; case: (repr _) => j y /= in lerm * => /eqP /=. have leijm: maxn i j <= m by rewrite geq_max leim. by move/(congr1 (toE _ _ leijm)); rewrite -!toEtrans. pose Kadd (x y : K) := EtoK _ (prod_curry +%R (pairK (repr x) (repr y))). pose Kopp (x : K) := EtoK _ (- tagged (repr x)). pose Kmul (x y : K) := EtoK _ (prod_curry *%R (pairK (repr x) (repr y))). pose Kinv (x : K) := EtoK _ (tagged (repr x))^-1. have EtoK_D i: {morph EtoK i : x y / x + y >-> Kadd x y}. move=> x y; apply: eqEtoK; set j := maxn (tag _) _; rewrite !rmorphD. by rewrite -!toEtrans ?le_max // => lexm leym; rewrite !toErepr. have EtoK_N i: {morph EtoK i : x / - x >-> Kopp x}. by move=> x; apply: eqEtoK; set j := tag _; rewrite !rmorphN toErepr. have EtoK_M i: {morph EtoK i : x y / x * y >-> Kmul x y}. move=> x y; apply: eqEtoK; set j := maxn (tag _) _; rewrite !rmorphM. by rewrite -!toEtrans ?le_max // => lexm leym; rewrite !toErepr. have EtoK_V i: {morph EtoK i : x / x^-1 >-> Kinv x}. by move=> x; apply: eqEtoK; set j := tag _; rewrite !fmorphV toErepr. case: {toErepr}I in (Kadd) (Kopp) (Kmul) (Kinv) EtoK_D EtoK_N EtoK_M EtoK_V. pose inEi i z := {x : E i | z = EtoK i x}; have KtoE z: {i : nat & inEi i z}. by elim/quotW: z => [[i x] /=]; exists i, x; rewrite piEtoK. have inEle i j z: i <= j -> inEi i z -> inEi j z. by move=> leij [x ->]; exists (toE i j leij x); rewrite toEtoK. have KtoE2 z1 z2: {i : nat & inEi i z1 & inEi i z2}. have [[i1 Ez1] [i2 Ez2]] := (KtoE z1, KtoE z2). by exists (maxn i1 i2); [apply: inEle Ez1 | apply: inEle Ez2]. have KtoE3 z1 z2 z3: {i : nat & inEi i z1 & inEi i z2 * inEi i z3}%type. have [[i1 Ez1] [i2 Ez2 Ez3]] := (KtoE z1, KtoE2 z2 z3). by exists (maxn i1 i2); [apply: inEle Ez1 | split; apply: inEle (leMr _ _) _]. have KaddC: commutative Kadd. by move=> u v; have [i [x ->] [y ->]] := KtoE2 u v; rewrite -!EtoK_D addrC. have KaddA: associative Kadd. move=> u v w; have [i [x ->] [[y ->] [z ->]]] := KtoE3 u v w. by rewrite -!EtoK_D addrA. have Kadd0: left_id (FtoK 0) Kadd. by move=> u; have [i [x ->]] := KtoE u; rewrite -(EtoK_0 i) -EtoK_D add0r. have KaddN: left_inverse (FtoK 0) Kopp Kadd. by move=> u; have [i [x ->]] := KtoE u; rewrite -EtoK_N -EtoK_D addNr EtoK_0. pose Kzmod := ZmodType K (ZmodMixin KaddA KaddC Kadd0 KaddN). have KmulC: commutative Kmul. by move=> u v; have [i [x ->] [y ->]] := KtoE2 u v; rewrite -!EtoK_M mulrC. have KmulA: @associative Kzmod Kmul. move=> u v w; have [i [x ->] [[y ->] [z ->]]] := KtoE3 u v w. by rewrite -!EtoK_M mulrA. have Kmul1: left_id (FtoK 1) Kmul. by move=> u; have [i [x ->]] := KtoE u; rewrite -(EtoK_1 i) -EtoK_M mul1r. have KmulD: left_distributive Kmul Kadd. move=> u v w; have [i [x ->] [[y ->] [z ->]]] := KtoE3 u v w. by rewrite -!(EtoK_M, EtoK_D) mulrDl. have Kone_nz: FtoK 1 != FtoK 0 by rewrite EtoKeq0 oner_neq0. pose KringMixin := ComRingMixin KmulA KmulC Kmul1 KmulD Kone_nz. pose Kring := ComRingType (RingType Kzmod KringMixin) KmulC. have KmulV: @GRing.Field.axiom Kring Kinv. move=> u; have [i [x ->]] := KtoE u; rewrite EtoKeq0 => nz_x. by rewrite -EtoK_V -[_ * _]EtoK_M mulVf ?EtoK_1. have Kinv0: Kinv (FtoK 0) = FtoK 0 by rewrite -EtoK_V invr0. pose Kuring := [comUnitRingType of UnitRingType _ (FieldUnitMixin KmulV Kinv0)]. pose KfieldMixin := @FieldMixin _ _ KmulV Kinv0. pose Kidomain := IdomainType Kuring (FieldIdomainMixin KfieldMixin). pose Kfield := FieldType Kidomain KfieldMixin. have EtoKrmorphism i: rmorphism (EtoK i : E i -> Kfield). by do 2?split=> [x y|]; rewrite ?EtoK_D ?EtoK_N ?EtoK_M ?EtoK_1. pose EtoKM := RMorphism (EtoKrmorphism _); have EtoK_E: EtoK _ = EtoKM _ by []. have toEtoKp := @eq_map_poly _ Kring _ _(toEtoK _ _ _). have Kclosed: GRing.ClosedField.axiom Kfield. move=> n pK n_gt0; pose m0 := \max_(i < n) tag (KtoE (pK i)); pose m := m0.+1. have /fin_all_exists[pE DpE] (i : 'I_n): exists y, EtoK m y = pK i. pose u := KtoE (pK i); have leum0: tag u <= m0 by rewrite (bigmax_sup i). by have [y ->] := tagged u; exists (toE _ _ (leqW leum0) y); rewrite toEtoK. pose p := 'X^n - rVpoly (\row_i pE i); pose j := code [:: m0; pickle p]. pose pj := tagged (E_ j) j; pose w : E j.+1 := ext1w (E j) pj. have lemj: m <= j by rewrite (allP (ltn_code _)) ?mem_head. exists (EtoKM j.+1 w); apply/eqP; rewrite -subr_eq0; apply/eqP. transitivity (EtoKM j.+1 (map_poly (toE m j.+1 (leqW lemj)) p).[w]). rewrite -horner_map -map_poly_comp toEtoKp EtoK_E; move/EtoKM: w => w. rewrite rmorphB [_ 'X^n]map_polyXn !hornerE hornerXn; congr (_ - _ : Kring). rewrite (@horner_coef_wide _ n) ?size_map_poly ?size_poly //. by apply: eq_bigr => i _; rewrite coef_map coef_rVpoly valK mxE /= DpE. suffices Dpj: map_poly (toE m j lemj) p = pj. apply/eqP; rewrite EtoKeq0 (eq_map_poly (toEleS _ _ _ _)) map_poly_comp Dpj. rewrite -rootE -[pj]minXpE ?ext1root // -Dpj size_map_poly. by rewrite size_addl ?size_polyXn ltnS ?size_opp ?size_poly. rewrite {w}/pj; elim: {-9}j lemj => // k IHk lemSk. move: lemSk (lemSk); rewrite {1}leq_eqVlt ltnS => /predU1P[<- | lemk] lemSk. rewrite {k IHk lemSk}(eq_map_poly (toEeq m _)) map_poly_id //= /incEp. by rewrite codeK eqxx pickleK. rewrite (eq_map_poly (toEleS _ _ _ _)) map_poly_comp {}IHk //= /incEp codeK. by rewrite -if_neg neq_ltn lemk. suffices{Kclosed} algF_K: {FtoK : {rmorphism F -> Kfield} | integralRange FtoK}. pose Kdec := DecFieldType Kfield (closed_fields_QEMixin Kclosed). pose KclosedField := ClosedFieldType Kdec Kclosed. by exists [countClosedFieldType of CountType KclosedField cntK]. exists (EtoKM 0%N) => /= z; have [i [{z}z ->]] := KtoE z. suffices{z} /(_ z)[p mon_p]: integralRange (toE 0%N i isT). by rewrite -(fmorph_root (EtoKM i)) -map_poly_comp toEtoKp; exists p. rewrite /toE /E; clear - minXp_gt1 ext1root ext1gen. move: (i - 0)%N (subnK _) => n; case: i /. elim: n => [|n IHn] /= z; first exact: integral_id. have{z} [q ->] := ext1gen _ _ z; set pn := tagged (E_ _) _. apply: integral_horner. by apply/integral_poly=> i; rewrite coef_map; apply: integral_rmorph. apply: integral_root (ext1root _ _) _. by rewrite map_poly_eq0 -size_poly_gt0 ltnW. by apply/integral_poly=> i; rewrite coef_map; apply: integral_rmorph. Qed. mathcomp-1.5/theories/mxabelem.v0000644000175000017500000012602112307636117015766 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. Require Import fintype tuple finfun bigop prime ssralg poly finset. Require Import fingroup morphism perm automorphism quotient gproduct action. Require Import finalg zmodp commutator cyclic center pgroup gseries nilpotent. Require Import sylow maximal abelian matrix mxalgebra mxrepresentation. (******************************************************************************) (* This file completes the theory developed in mxrepresentation.v with the *) (* construction and properties of linear representations over finite fields, *) (* and in particular the correspondance between internal action on a (normal) *) (* elementary abelian p-subgroup and a linear representation on an Fp-module. *) (* We provide the following next constructions for a finite field F: *) (* 'Zm%act == the action of {unit F} on 'M[F]_(m, n). *) (* rowg A == the additive group of 'rV[F]_n spanned by the row space *) (* of the matrix A. *) (* rowg_mx L == the partial inverse to rowg; for any 'Zm-stable group L *) (* of 'rV[F]_n we have rowg (rowg_mx L) = L. *) (* GLrepr F n == the natural, faithful representation of 'GL_n[F]. *) (* reprGLm rG == the morphism G >-> 'GL_n[F] equivalent to the *) (* representation r of G (with rG : mx_repr r G). *) (* ('MR rG)%act == the action of G on 'rV[F]_n equivalent to the *) (* representation r of G (with rG : mx_repr r G). *) (* The second set of constructions defines the interpretation of a normal *) (* non-trivial elementary abelian p-subgroup as an 'F_p module. We assume *) (* abelE : p.-abelem E and ntE : E != 1, throughout, as these are needed to *) (* build the isomorphism between E and a nontrivial 'rV['F_p]_n. *) (* 'rV(E) == the type of row vectors of the 'F_p module equivalent *) (* to E when E is a non-trivial p.-abelem group. *) (* 'M(E) == the type of matrices corresponding to E. *) (* 'dim E == the width of vectors/matrices in 'rV(E) / 'M(E). *) (* abelem_rV abelE ntE == the one-to-one injection of E onto 'rV(E). *) (* rVabelem abelE ntE == the one-to-one projection of 'rV(E) onto E. *) (* abelem_repr abelE ntE nEG == the representation of G on 'rV(E) that is *) (* equivalent to conjugation by G in E; here abelE, ntE are *) (* as above, and G \subset 'N(E). *) (* This file end with basic results on p-modular representations of p-groups, *) (* and theorems giving the structure of the representation of extraspecial *) (* groups; these results use somewhat more advanced group theory than the *) (* rest of mxrepresentation, in particular, results of sylow.v and maximal.v. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope GRing.Theory FinRing.Theory. Local Open Scope ring_scope. (* Special results for representations on a finite field. In this case, the *) (* representation is equivalent to a morphism into the general linear group *) (* 'GL_n[F]. It is furthermore equivalent to a group action on the finite *) (* additive group of the corresponding row space 'rV_n. In addition, row *) (* spaces of matrices in 'M[F]_n correspond to subgroups of that vector group *) (* (this is only surjective when F is a prime field 'F_p), with moduleules *) (* corresponding to subgroups stabilized by the external action. *) Section FinRingRepr. Variable (R : finComUnitRingType) (gT : finGroupType). Variables (G : {group gT}) (n : nat) (rG : mx_representation R G n). Definition mx_repr_act (u : 'rV_n) x := u *m rG (val (subg G x)). Lemma mx_repr_actE u x : x \in G -> mx_repr_act u x = u *m rG x. Proof. by move=> Gx; rewrite /mx_repr_act /= subgK. Qed. Fact mx_repr_is_action : is_action G mx_repr_act. Proof. split=> [x | u x y Gx Gy]; first exact: can_inj (repr_mxK _ (subgP _)). by rewrite !mx_repr_actE ?groupM // -mulmxA repr_mxM. Qed. Canonical Structure mx_repr_action := Action mx_repr_is_action. Fact mx_repr_is_groupAction : is_groupAction [set: 'rV[R]_n] mx_repr_action. Proof. move=> x Gx /=; rewrite !inE. apply/andP; split; first by apply/subsetP=> u; rewrite !inE. by apply/morphicP=> /= u v _ _; rewrite !actpermE /= /mx_repr_act mulmxDl. Qed. Canonical Structure mx_repr_groupAction := GroupAction mx_repr_is_groupAction. End FinRingRepr. Notation "''MR' rG" := (mx_repr_action rG) (at level 10, rG at level 8) : action_scope. Notation "''MR' rG" := (mx_repr_groupAction rG) : groupAction_scope. Section FinFieldRepr. Variable F : finFieldType. (* The external group action (by scaling) of the multiplicative unit group *) (* of the finite field, and the correspondence between additive subgroups *) (* of row vectors that are stable by this action, and the matrix row spaces. *) Section ScaleAction. Variables m n : nat. Definition scale_act (A : 'M[F]_(m, n)) (a : {unit F}) := val a *: A. Lemma scale_actE A a : scale_act A a = val a *: A. Proof. by []. Qed. Fact scale_is_action : is_action setT scale_act. Proof. apply: is_total_action=> [A | A a b]; rewrite /scale_act ?scale1r //. by rewrite ?scalerA mulrC. Qed. Canonical scale_action := Action scale_is_action. Fact scale_is_groupAction : is_groupAction setT scale_action. Proof. move=> a _ /=; rewrite inE; apply/andP. split; first by apply/subsetP=> A; rewrite !inE. by apply/morphicP=> u A _ _ /=; rewrite !actpermE /= /scale_act scalerDr. Qed. Canonical scale_groupAction := GroupAction scale_is_groupAction. Lemma astab1_scale_act A : A != 0 -> 'C[A | scale_action] = 1%g. Proof. rewrite -mxrank_eq0=> nzA; apply/trivgP/subsetP=> a; apply: contraLR. rewrite !inE -val_eqE -subr_eq0 sub1set !inE => nz_a1. by rewrite -subr_eq0 -scaleN1r -scalerDl -mxrank_eq0 eqmx_scale. Qed. End ScaleAction. Local Notation "'Zm" := (scale_action _ _) (at level 8) : action_scope. Section RowGroup. Variable n : nat. Local Notation rVn := 'rV[F]_n. Definition rowg m (A : 'M[F]_(m, n)) : {set rVn} := [set u | u <= A]%MS. Lemma mem_rowg m A v : (v \in @rowg m A) = (v <= A)%MS. Proof. by rewrite inE. Qed. Fact rowg_group_set m A : group_set (@rowg m A). Proof. by apply/group_setP; split=> [|u v]; rewrite !inE ?sub0mx //; exact: addmx_sub. Qed. Canonical rowg_group m A := Group (@rowg_group_set m A). Lemma rowg_stable m (A : 'M_(m, n)) : [acts setT, on rowg A | 'Zm]. Proof. by apply/actsP=> a _ v; rewrite !inE eqmx_scale // -unitfE (valP a). Qed. Lemma rowgS m1 m2 (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (rowg A \subset rowg B) = (A <= B)%MS. Proof. apply/subsetP/idP=> sAB => [| u]. by apply/row_subP=> i; have:= sAB (row i A); rewrite !inE row_sub => ->. by rewrite !inE => suA; exact: submx_trans sAB. Qed. Lemma eq_rowg m1 m2 (A : 'M_(m1, n)) (B : 'M_(m2, n)) : (A :=: B)%MS -> rowg A = rowg B. Proof. by move=> eqAB; apply/eqP; rewrite eqEsubset !rowgS !eqAB andbb. Qed. Lemma rowg0 m : rowg (0 : 'M_(m, n)) = 1%g. Proof. by apply/trivgP/subsetP=> v; rewrite !inE eqmx0 submx0. Qed. Lemma rowg1 : rowg 1%:M = setT. Proof. by apply/setP=> x; rewrite !inE submx1. Qed. Lemma trivg_rowg m (A : 'M_(m, n)) : (rowg A == 1%g) = (A == 0). Proof. by rewrite -submx0 -rowgS rowg0 (sameP trivgP eqP). Qed. Definition rowg_mx (L : {set rVn}) := <<\matrix_(i < #|L|) enum_val i>>%MS. Lemma rowgK m (A : 'M_(m, n)) : (rowg_mx (rowg A) :=: A)%MS. Proof. apply/eqmxP; rewrite !genmxE; apply/andP; split. by apply/row_subP=> i; rewrite rowK; have:= enum_valP i; rewrite /= inE. apply/row_subP=> i; set v := row i A. have Av: v \in rowg A by rewrite inE row_sub. by rewrite (eq_row_sub (enum_rank_in Av v)) // rowK enum_rankK_in. Qed. Lemma rowg_mxS (L M : {set 'rV[F]_n}) : L \subset M -> (rowg_mx L <= rowg_mx M)%MS. Proof. move/subsetP=> sLM; rewrite !genmxE; apply/row_subP=> i. rewrite rowK; move: (enum_val i) (sLM _ (enum_valP i)) => v Mv. by rewrite (eq_row_sub (enum_rank_in Mv v)) // rowK enum_rankK_in. Qed. Lemma sub_rowg_mx (L : {set rVn}) : L \subset rowg (rowg_mx L). Proof. apply/subsetP=> v Lv; rewrite inE genmxE. by rewrite (eq_row_sub (enum_rank_in Lv v)) // rowK enum_rankK_in. Qed. Lemma stable_rowg_mxK (L : {group rVn}) : [acts setT, on L | 'Zm] -> rowg (rowg_mx L) = L. Proof. move=> linL; apply/eqP; rewrite eqEsubset sub_rowg_mx andbT. apply/subsetP=> v; rewrite inE genmxE => /submxP[u ->{v}]. rewrite mulmx_sum_row group_prod // => i _. rewrite rowK; move: (enum_val i) (enum_valP i) => v Lv. case: (eqVneq (u 0 i) 0) => [->|]; first by rewrite scale0r group1. by rewrite -unitfE => aP; rewrite ((actsP linL) (FinRing.Unit _ aP)) ?inE. Qed. Lemma rowg_mx1 : rowg_mx 1%g = 0. Proof. by apply/eqP; rewrite -submx0 -(rowg0 0) rowgK sub0mx. Qed. Lemma rowg_mx_eq0 (L : {group rVn}) : (rowg_mx L == 0) = (L :==: 1%g). Proof. rewrite -trivg_rowg; apply/idP/idP=> [|/eqP->]; last by rewrite rowg_mx1 rowg0. by rewrite !(sameP eqP trivgP); apply: subset_trans; exact: sub_rowg_mx. Qed. Lemma rowgI m1 m2 (A : 'M_(m1, n)) (B : 'M_(m2, n)) : rowg (A :&: B)%MS = rowg A :&: rowg B. Proof. by apply/setP=> u; rewrite !inE sub_capmx. Qed. Lemma card_rowg m (A : 'M_(m, n)) : #|rowg A| = (#|F| ^ \rank A)%N. Proof. rewrite -[\rank A]mul1n -card_matrix. have injA: injective (mulmxr (row_base A)). have /row_freeP[A' A'K] := row_base_free A. by move=> ?; apply: can_inj (mulmxr A') _ => u; rewrite /= -mulmxA A'K mulmx1. rewrite -(card_image (injA _)); apply: eq_card => v. by rewrite inE -(eq_row_base A) (sameP submxP codomP). Qed. Lemma rowgD m1 m2 (A : 'M_(m1, n)) (B : 'M_(m2, n)) : rowg (A + B)%MS = (rowg A * rowg B)%g. Proof. apply/eqP; rewrite eq_sym eqEcard mulG_subG /= !rowgS. rewrite addsmxSl addsmxSr -(@leq_pmul2r #|rowg A :&: rowg B|) ?cardG_gt0 //=. by rewrite -mul_cardG -rowgI !card_rowg -!expnD mxrank_sum_cap. Qed. Lemma cprod_rowg m1 m2 (A : 'M_(m1, n)) (B : 'M_(m2, n)) : rowg A \* rowg B = rowg (A + B)%MS. Proof. by rewrite rowgD cprodE // (sub_abelian_cent2 (zmod_abelian setT)). Qed. Lemma dprod_rowg m1 m2 (A : 'M[F]_(m1, n)) (B : 'M[F]_(m2, n)) : mxdirect (A + B) -> rowg A \x rowg B = rowg (A + B)%MS. Proof. rewrite (sameP mxdirect_addsP eqP) -trivg_rowg rowgI => /eqP tiAB. by rewrite -cprod_rowg dprodEcp. Qed. Lemma bigcprod_rowg m I r (P : pred I) (A : I -> 'M[F]_n) (B : 'M[F]_(m, n)) : (\sum_(i <- r | P i) A i :=: B)%MS -> \big[cprod/1%g]_(i <- r | P i) rowg (A i) = rowg B. Proof. by move/eq_rowg <-; apply/esym/big_morph=> [? ?|]; rewrite (rowg0, cprod_rowg). Qed. Lemma bigdprod_rowg m (I : finType) (P : pred I) A (B : 'M[F]_(m, n)) : let S := (\sum_(i | P i) A i)%MS in (S :=: B)%MS -> mxdirect S -> \big[dprod/1%g]_(i | P i) rowg (A i) = rowg B. Proof. move=> S defS; rewrite mxdirectE defS /= => /eqP rankB. apply: bigcprod_card_dprod (bigcprod_rowg defS) (eq_leq _). by rewrite card_rowg rankB expn_sum; apply: eq_bigr => i _; rewrite card_rowg. Qed. End RowGroup. Variables (gT : finGroupType) (G : {group gT}) (n' : nat). Local Notation n := n'.+1. Variable (rG : mx_representation F G n). Fact GL_mx_repr : mx_repr 'GL_n[F] GLval. Proof. by []. Qed. Canonical GLrepr := MxRepresentation GL_mx_repr. Lemma GLmx_faithful : mx_faithful GLrepr. Proof. by apply/subsetP=> A; rewrite !inE mul1mx. Qed. Definition reprGLm x : {'GL_n[F]} := insubd (1%g : {'GL_n[F]}) (rG x). Lemma val_reprGLm x : x \in G -> val (reprGLm x) = rG x. Proof. by move=> Gx; rewrite val_insubd (repr_mx_unitr rG). Qed. Lemma comp_reprGLm : {in G, GLval \o reprGLm =1 rG}. Proof. exact: val_reprGLm. Qed. Lemma reprGLmM : {in G &, {morph reprGLm : x y / x * y}}%g. Proof. by move=> x y Gx Gy; apply: val_inj; rewrite /= !val_reprGLm ?groupM ?repr_mxM. Qed. Canonical reprGL_morphism := Morphism reprGLmM. Lemma ker_reprGLm : 'ker reprGLm = rker rG. Proof. apply/setP=> x; rewrite !inE mul1mx; apply: andb_id2l => Gx. by rewrite -val_eqE val_reprGLm. Qed. Lemma astab_rowg_repr m (A : 'M_(m, n)) : 'C(rowg A | 'MR rG) = rstab rG A. Proof. apply/setP=> x; rewrite !inE /=; apply: andb_id2l => Gx. apply/subsetP/eqP=> cAx => [|u]; last first. by rewrite !inE mx_repr_actE // => /submxP[u' ->]; rewrite -mulmxA cAx. apply/row_matrixP=> i; apply/eqP; move/implyP: (cAx (row i A)). by rewrite !inE row_sub mx_repr_actE //= row_mul. Qed. Lemma astabs_rowg_repr m (A : 'M_(m, n)) : 'N(rowg A | 'MR rG) = rstabs rG A. Proof. apply/setP=> x; rewrite !inE /=; apply: andb_id2l => Gx. apply/subsetP/idP=> nAx => [|u]; last first. rewrite !inE mx_repr_actE // => Au; exact: (submx_trans (submxMr _ Au)). apply/row_subP=> i; move/implyP: (nAx (row i A)). by rewrite !inE row_sub mx_repr_actE //= row_mul. Qed. Lemma acts_rowg (A : 'M_n) : [acts G, on rowg A | 'MR rG] = mxmodule rG A. Proof. by rewrite astabs_rowg_repr. Qed. Lemma astab_setT_repr : 'C(setT | 'MR rG) = rker rG. Proof. by rewrite -rowg1 astab_rowg_repr. Qed. Lemma mx_repr_action_faithful : [faithful G, on setT | 'MR rG] = mx_faithful rG. Proof. by rewrite /faithful astab_setT_repr (setIidPr _) // [rker _]setIdE subsetIl. Qed. Lemma afix_repr (H : {set gT}) : H \subset G -> 'Fix_('MR rG)(H) = rowg (rfix_mx rG H). Proof. move/subsetP=> sHG; apply/setP=> /= u; rewrite !inE. apply/subsetP/rfix_mxP=> cHu x Hx; have:= cHu x Hx; by rewrite !inE /= => /eqP; rewrite mx_repr_actE ?sHG. Qed. Lemma gacent_repr (H : {set gT}) : H \subset G -> 'C_(| 'MR rG)(H) = rowg (rfix_mx rG H). Proof. by move=> sHG; rewrite gacentE // setTI afix_repr. Qed. End FinFieldRepr. Arguments Scope rowg_mx [_ _ group_scope]. Notation "''Zm'" := (scale_action _ _ _) (at level 8) : action_scope. Notation "''Zm'" := (scale_groupAction _ _ _) : groupAction_scope. Section MatrixGroups. Implicit Types m n p q : nat. Lemma exponent_mx_group m n q : m > 0 -> n > 0 -> q > 1 -> exponent [set: 'M['Z_q]_(m, n)] = q. Proof. move=> m_gt0 n_gt0 q_gt1; apply/eqP; rewrite eqn_dvd; apply/andP; split. apply/exponentP=> x _; apply/matrixP=> i j; rewrite mulmxnE !mxE. by rewrite -mulr_natr -Zp_nat_mod // modnn mulr0. pose cmx1 := const_mx 1%R : 'M['Z_q]_(m, n). apply: dvdn_trans (dvdn_exponent (in_setT cmx1)). have/matrixP/(_ (Ordinal m_gt0))/(_ (Ordinal n_gt0))/eqP := expg_order cmx1. by rewrite mulmxnE !mxE -order_dvdn order_Zp1 Zp_cast. Qed. Lemma rank_mx_group m n q : 'r([set: 'M['Z_q]_(m, n)]) = (m * n)%N. Proof. wlog q_gt1: q / q > 1 by case: q => [|[|q -> //]] /(_ 2)->. set G := setT; have cGG: abelian G := zmod_abelian _. have [mn0 | ] := posnP (m * n). by rewrite [G](card1_trivg _) ?rank1 // cardsT card_matrix mn0. rewrite muln_gt0 => /andP[m_gt0 n_gt0]. have expG: exponent G = q := exponent_mx_group m_gt0 n_gt0 q_gt1. apply/eqP; rewrite eqn_leq andbC -(leq_exp2l _ _ q_gt1) -{2}expG. have ->: (q ^ (m * n))%N = #|G| by rewrite cardsT card_matrix card_ord Zp_cast. rewrite max_card_abelian //= -grank_abelian //= -/G. pose B : {set 'M['Z_q]_(m, n)} := [set delta_mx ij.1 ij.2 | ij : 'I_m * 'I_n]. suffices ->: G = <>. have ->: (m * n)%N = #|{: 'I_m * 'I_n}| by rewrite card_prod !card_ord. exact: leq_trans (grank_min _) (leq_imset_card _ _). apply/setP=> v; rewrite inE (matrix_sum_delta v). rewrite group_prod // => i _; rewrite group_prod // => j _. rewrite -[v i j]natr_Zp scaler_nat groupX // mem_gen //. by apply/imsetP; exists (i, j). Qed. Lemma mx_group_homocyclic m n q : homocyclic [set: 'M['Z_q]_(m, n)]. Proof. wlog q_gt1: q / q > 1 by case: q => [|[|q -> //]] /(_ 2)->. set G := setT; have cGG: abelian G := zmod_abelian _. rewrite -max_card_abelian //= rank_mx_group cardsT card_matrix card_ord -/G. rewrite {1}Zp_cast //; have [-> // | ] := posnP (m * n). by rewrite muln_gt0 => /andP[m_gt0 n_gt0]; rewrite exponent_mx_group. Qed. Lemma abelian_type_mx_group m n q : q > 1 -> abelian_type [set: 'M['Z_q]_(m, n)] = nseq (m * n) q. Proof. rewrite (abelian_type_homocyclic (mx_group_homocyclic m n q)) rank_mx_group. have [-> // | ] := posnP (m * n); rewrite muln_gt0 => /andP[m_gt0 n_gt0] q_gt1. by rewrite exponent_mx_group. Qed. End MatrixGroups. Delimit Scope abelem_scope with Mg. Open Scope abelem_scope. Definition abelem_dim' (gT : finGroupType) (E : {set gT}) := (logn (pdiv #|E|) #|E|).-1. Arguments Scope abelem_dim' [_ group_scope]. Notation "''dim' E" := (abelem_dim' E).+1 (at level 10, E at level 8, format "''dim' E") : abelem_scope. Notation "''rV' ( E )" := 'rV_('dim E) (at level 8, format "''rV' ( E )") : abelem_scope. Notation "''M' ( E )" := 'M_('dim E) (at level 8, format "''M' ( E )") : abelem_scope. Notation "''rV[' F ] ( E )" := 'rV[F]_('dim E) (at level 8, only parsing) : abelem_scope. Notation "''M[' F ] ( E )" := 'M[F]_('dim E) (at level 8, only parsing) : abelem_scope. Section AbelemRepr. Section FpMatrix. Variables p m n : nat. Local Notation Mmn := 'M['F_p]_(m, n). Lemma mx_Fp_abelem : prime p -> p.-abelem [set: Mmn]. Proof. move=> p_pr; apply/abelemP=> //; rewrite zmod_abelian. split=> //= v _; rewrite zmodXgE -scaler_nat. by case/andP: (char_Fp p_pr) => _ /eqP->; rewrite scale0r. Qed. Lemma mx_Fp_stable (L : {group Mmn}) : [acts setT, on L | 'Zm]. Proof. apply/subsetP=> a _; rewrite !inE; apply/subsetP=> A L_A. by rewrite inE /= /scale_act -[val _]natr_Zp scaler_nat groupX. Qed. End FpMatrix. Section FpRow. Variables p n : nat. Local Notation rVn := 'rV['F_p]_n. Lemma rowg_mxK (L : {group rVn}) : rowg (rowg_mx L) = L. Proof. by apply: stable_rowg_mxK; exact: mx_Fp_stable. Qed. Lemma rowg_mxSK (L : {set rVn}) (M : {group rVn}) : (rowg_mx L <= rowg_mx M)%MS = (L \subset M). Proof. apply/idP/idP; last exact: rowg_mxS. by rewrite -rowgS rowg_mxK; apply: subset_trans; exact: sub_rowg_mx. Qed. Lemma mxrank_rowg (L : {group rVn}) : prime p -> \rank (rowg_mx L) = logn p #|L|. Proof. by move=> p_pr; rewrite -{2}(rowg_mxK L) card_rowg card_Fp ?pfactorK. Qed. End FpRow. Variables (p : nat) (gT : finGroupType) (E : {group gT}). Hypotheses (abelE : p.-abelem E) (ntE : E :!=: 1%g). Let pE : p.-group E := abelem_pgroup abelE. Let p_pr : prime p. Proof. by have [] := pgroup_pdiv pE ntE. Qed. Local Notation n' := (abelem_dim' (gval E)). Local Notation n := n'.+1. Local Notation rVn := 'rV['F_p](gval E). Lemma dim_abelemE : n = logn p #|E|. Proof. rewrite /n'; have [_ _ [k ->]] := pgroup_pdiv pE ntE. by rewrite /pdiv primes_exp ?primes_prime // pfactorK. Qed. Lemma card_abelem_rV : #|rVn| = #|E|. Proof. by rewrite dim_abelemE card_matrix mul1n card_Fp // -p_part part_pnat_id. Qed. Lemma isog_abelem_rV : E \isog [set: rVn]. Proof. by rewrite (isog_abelem_card _ abelE) cardsT card_abelem_rV mx_Fp_abelem /=. Qed. Local Notation ab_rV_P := (existsP isog_abelem_rV). Definition abelem_rV : gT -> rVn := xchoose ab_rV_P. Local Notation ErV := abelem_rV. Lemma abelem_rV_M : {in E &, {morph ErV : x y / (x * y)%g >-> x + y}}. Proof. by case/misomP: (xchooseP ab_rV_P) => fM _; move/morphicP: fM. Qed. Canonical abelem_rV_morphism := Morphism abelem_rV_M. Lemma abelem_rV_isom : isom E setT ErV. Proof. by case/misomP: (xchooseP ab_rV_P). Qed. Lemma abelem_rV_injm : 'injm ErV. Proof. by case/isomP: abelem_rV_isom. Qed. Lemma abelem_rV_inj : {in E &, injective ErV}. Proof. by apply/injmP; exact: abelem_rV_injm. Qed. Lemma im_abelem_rV : ErV @* E = setT. Proof. by case/isomP: abelem_rV_isom. Qed. Lemma mem_im_abelem_rV u : u \in ErV @* E. Proof. by rewrite im_abelem_rV inE. Qed. Lemma sub_im_abelem_rV mA : subset mA (mem (ErV @* E)). Proof. by rewrite unlock; apply/pred0P=> v /=; rewrite mem_im_abelem_rV. Qed. Hint Resolve mem_im_abelem_rV sub_im_abelem_rV. Lemma abelem_rV_1 : ErV 1 = 0%R. Proof. by rewrite morph1. Qed. Lemma abelem_rV_X x i : x \in E -> ErV (x ^+ i) = i%:R *: ErV x. Proof. by move=> Ex; rewrite morphX // scaler_nat. Qed. Lemma abelem_rV_V x : x \in E -> ErV x^-1 = - ErV x. Proof. by move=> Ex; rewrite morphV. Qed. Definition rVabelem : rVn -> gT := invm abelem_rV_injm. Canonical rVabelem_morphism := [morphism of rVabelem]. Local Notation rV_E := rVabelem. Lemma rVabelem0 : rV_E 0 = 1%g. Proof. exact: morph1. Qed. Lemma rVabelemD : {morph rV_E : u v / u + v >-> (u * v)%g}. Proof. by move=> u v /=; rewrite -morphM. Qed. Lemma rVabelemN : {morph rV_E: u / - u >-> (u^-1)%g}. Proof. by move=> u /=; rewrite -morphV. Qed. Lemma rVabelemZ (m : 'F_p) : {morph rV_E : u / m *: u >-> (u ^+ m)%g}. Proof. by move=> u; rewrite /= -morphX -?[(u ^+ m)%g]scaler_nat ?natr_Zp. Qed. Lemma abelem_rV_K : {in E, cancel ErV rV_E}. Proof. exact: invmE. Qed. Lemma rVabelemK : cancel rV_E ErV. Proof. by move=> u; rewrite invmK. Qed. Lemma rVabelem_inj : injective rV_E. Proof. exact: can_inj rVabelemK. Qed. Lemma rVabelem_injm : 'injm rV_E. Proof. exact: injm_invm abelem_rV_injm. Qed. Lemma im_rVabelem : rV_E @* setT = E. Proof. by rewrite -im_abelem_rV im_invm. Qed. Lemma mem_rVabelem u : rV_E u \in E. Proof. by rewrite -im_rVabelem mem_morphim. Qed. Lemma sub_rVabelem L : rV_E @* L \subset E. Proof. by rewrite -[_ @* L]morphimIim im_invm subsetIl. Qed. Hint Resolve mem_rVabelem sub_rVabelem. Lemma card_rVabelem L : #|rV_E @* L| = #|L|. Proof. by rewrite card_injm ?rVabelem_injm. Qed. Lemma abelem_rV_mK (H : {set gT}) : H \subset E -> rV_E @* (ErV @* H) = H. Proof. exact: morphim_invm abelem_rV_injm H. Qed. Lemma rVabelem_mK L : ErV @* (rV_E @* L) = L. Proof. by rewrite morphim_invmE morphpreK. Qed. Lemma rVabelem_minj : injective (morphim (MorPhantom rV_E)). Proof. exact: can_inj rVabelem_mK. Qed. Lemma rVabelemS L M : (rV_E @* L \subset rV_E @* M) = (L \subset M). Proof. by rewrite injmSK ?rVabelem_injm. Qed. Lemma abelem_rV_S (H K : {set gT}) : H \subset E -> (ErV @* H \subset ErV @* K) = (H \subset K). Proof. by move=> sHE; rewrite injmSK ?abelem_rV_injm. Qed. Lemma sub_rVabelem_im L (H : {set gT}) : (rV_E @* L \subset H) = (L \subset ErV @* H). Proof. by rewrite sub_morphim_pre ?morphpre_invm. Qed. Lemma sub_abelem_rV_im (H : {set gT}) (L : {set 'rV['F_p]_n}) : H \subset E -> (ErV @* H \subset L) = (H \subset rV_E @* L). Proof. by move=> sHE; rewrite sub_morphim_pre ?morphim_invmE. Qed. Section OneGroup. Variable G : {group gT}. Definition abelem_mx_fun (g : subg_of G) v := ErV ((rV_E v) ^ val g). Definition abelem_mx of G \subset 'N(E) := fun x => lin1_mx (abelem_mx_fun (subg G x)). Hypothesis nEG : G \subset 'N(E). Local Notation r := (abelem_mx nEG). Fact abelem_mx_linear_proof g : linear (abelem_mx_fun g). Proof. rewrite /abelem_mx_fun; case: g => x /= /(subsetP nEG) Nx /= m u v. rewrite rVabelemD rVabelemZ conjMg conjXg. by rewrite abelem_rV_M ?abelem_rV_X ?groupX ?memJ_norm // natr_Zp. Qed. Canonical abelem_mx_linear g := Linear (abelem_mx_linear_proof g). Let rVabelemJmx v x : x \in G -> rV_E (v *m r x) = (rV_E v) ^ x. Proof. move=> Gx; rewrite /= mul_rV_lin1 /= /abelem_mx_fun subgK //. by rewrite abelem_rV_K // memJ_norm // (subsetP nEG). Qed. Fact abelem_mx_repr : mx_repr G r. Proof. split=> [|x y Gx Gy]; apply/row_matrixP=> i; apply: rVabelem_inj. by rewrite rowE -row1 rVabelemJmx // conjg1. by rewrite !rowE mulmxA !rVabelemJmx ?groupM // conjgM. Qed. Canonical abelem_repr := MxRepresentation abelem_mx_repr. Let rG := abelem_repr. Lemma rVabelemJ v x : x \in G -> rV_E (v *m rG x) = (rV_E v) ^ x. Proof. exact: rVabelemJmx. Qed. Lemma abelem_rV_J : {in E & G, forall x y, ErV (x ^ y) = ErV x *m rG y}. Proof. by move=> x y Ex Gy; rewrite -{1}(abelem_rV_K Ex) -rVabelemJ ?rVabelemK. Qed. Lemma abelem_rowgJ m (A : 'M_(m, n)) x : x \in G -> rV_E @* rowg (A *m rG x) = (rV_E @* rowg A) :^ x. Proof. move=> Gx; apply: (canRL (conjsgKV _)); apply/setP=> y. rewrite mem_conjgV !morphim_invmE !inE memJ_norm ?(subsetP nEG) //=. apply: andb_id2l => Ey; rewrite abelem_rV_J //. by rewrite submxMfree // row_free_unit (repr_mx_unit rG). Qed. Lemma rV_abelem_sJ (L : {group gT}) x : x \in G -> L \subset E -> ErV @* (L :^ x) = rowg (rowg_mx (ErV @* L) *m rG x). Proof. move=> Gx sLE; apply: rVabelem_minj; rewrite abelem_rowgJ //. by rewrite rowg_mxK !morphim_invm // -(normsP nEG x Gx) conjSg. Qed. Lemma rstab_abelem m (A : 'M_(m, n)) : rstab rG A = 'C_G(rV_E @* rowg A). Proof. apply/setP=> x; rewrite !inE /=; apply: andb_id2l => Gx. apply/eqP/centP=> cAx => [_ /morphimP[u _ Au ->]|]. move: Au; rewrite inE => /submxP[u' ->] {u}. by apply/esym/commgP/conjg_fixP; rewrite -rVabelemJ -?mulmxA ?cAx. apply/row_matrixP=> i; apply: rVabelem_inj. by rewrite row_mul rVabelemJ // /conjg -cAx ?mulKg ?mem_morphim // inE row_sub. Qed. Lemma rstabs_abelem m (A : 'M_(m, n)) : rstabs rG A = 'N_G(rV_E @* rowg A). Proof. apply/setP=> x; rewrite !inE /=; apply: andb_id2l => Gx. by rewrite -rowgS -rVabelemS abelem_rowgJ. Qed. Lemma rstabs_abelemG (L : {group gT}) : L \subset E -> rstabs rG (rowg_mx (ErV @* L)) = 'N_G(L). Proof. by move=> sLE; rewrite rstabs_abelem rowg_mxK morphim_invm. Qed. Lemma mxmodule_abelem m (U : 'M['F_p]_(m, n)) : mxmodule rG U = (G \subset 'N(rV_E @* rowg U)). Proof. by rewrite -subsetIidl -rstabs_abelem. Qed. Lemma mxmodule_abelemG (L : {group gT}) : L \subset E -> mxmodule rG (rowg_mx (ErV @* L)) = (G \subset 'N(L)). Proof. by move=> sLE; rewrite -subsetIidl -rstabs_abelemG. Qed. Lemma mxsimple_abelemP (U : 'M['F_p]_n) : reflect (mxsimple rG U) (minnormal (rV_E @* rowg U) G). Proof. apply: (iffP mingroupP) => [[/andP[ntU modU] minU] | [modU ntU minU]]. split=> [||V modV sVU ntV]; first by rewrite mxmodule_abelem. by apply: contraNneq ntU => ->; rewrite /= rowg0 morphim1. rewrite -rowgS -rVabelemS [_ @* rowg V]minU //. rewrite -subG1 sub_rVabelem_im morphim1 subG1 trivg_rowg ntV /=. by rewrite -mxmodule_abelem. by rewrite rVabelemS rowgS. split=> [|D /andP[ntD nDG sDU]]. rewrite -subG1 sub_rVabelem_im morphim1 subG1 trivg_rowg ntU /=. by rewrite -mxmodule_abelem. apply/eqP; rewrite eqEsubset sDU sub_rVabelem_im /= -rowg_mxSK rowgK. have sDE: D \subset E := subset_trans sDU (sub_rVabelem _). rewrite minU ?mxmodule_abelemG //. by rewrite -rowgS rowg_mxK sub_abelem_rV_im. by rewrite rowg_mx_eq0 (morphim_injm_eq1 abelem_rV_injm). Qed. Lemma mxsimple_abelemGP (L : {group gT}) : L \subset E -> reflect (mxsimple rG (rowg_mx (ErV @* L))) (minnormal L G). Proof. move/abelem_rV_mK=> {2}<-; rewrite -{2}[_ @* L]rowg_mxK. exact: mxsimple_abelemP. Qed. Lemma abelem_mx_irrP : reflect (mx_irreducible rG) (minnormal E G). Proof. by rewrite -[E in minnormal E G]im_rVabelem -rowg1; exact: mxsimple_abelemP. Qed. Lemma rfix_abelem (H : {set gT}) : H \subset G -> (rfix_mx rG H :=: rowg_mx (ErV @* 'C_E(H)%g))%MS. Proof. move/subsetP=> sHG; apply/eqmxP/andP; split. rewrite -rowgS rowg_mxK -sub_rVabelem_im // subsetI sub_rVabelem /=. apply/centsP=> y /morphimP[v _]; rewrite inE => cGv ->{y} x Gx. by apply/commgP/conjg_fixP; rewrite /= -rVabelemJ ?sHG ?(rfix_mxP H _). rewrite genmxE; apply/rfix_mxP=> x Hx; apply/row_matrixP=> i. rewrite row_mul rowK; case/morphimP: (enum_valP i) => z Ez /setIP[_ cHz] ->. by rewrite -abelem_rV_J ?sHG // conjgE (centP cHz) ?mulKg. Qed. Lemma rker_abelem : rker rG = 'C_G(E). Proof. by rewrite /rker rstab_abelem rowg1 im_rVabelem. Qed. Lemma abelem_mx_faithful : 'C_G(E) = 1%g -> mx_faithful rG. Proof. by rewrite /mx_faithful rker_abelem => ->. Qed. End OneGroup. Section SubGroup. Variables G H : {group gT}. Hypotheses (nEG : G \subset 'N(E)) (sHG : H \subset G). Let nEH := subset_trans sHG nEG. Local Notation rG := (abelem_repr nEG). Local Notation rHG := (subg_repr rG sHG). Local Notation rH := (abelem_repr nEH). Lemma eq_abelem_subg_repr : {in H, rHG =1 rH}. Proof. move=> x Hx; apply/row_matrixP=> i; rewrite !rowE !mul_rV_lin1 /=. by rewrite /abelem_mx_fun !subgK ?(subsetP sHG). Qed. Lemma rsim_abelem_subg : mx_rsim rHG rH. Proof. exists 1%:M => // [|x Hx]; first by rewrite row_free_unit unitmx1. by rewrite mul1mx mulmx1 eq_abelem_subg_repr. Qed. Lemma mxmodule_abelem_subg m (U : 'M_(m, n)) : mxmodule rHG U = mxmodule rH U. Proof. apply: eq_subset_r => x; rewrite !inE; apply: andb_id2l => Hx. by rewrite eq_abelem_subg_repr. Qed. Lemma mxsimple_abelem_subg U : mxsimple rHG U <-> mxsimple rH U. Proof. have eq_modH := mxmodule_abelem_subg; rewrite /mxsimple eq_modH. by split=> [] [-> -> minU]; split=> // V; have:= minU V; rewrite eq_modH. Qed. End SubGroup. End AbelemRepr. Section ModularRepresentation. Variables (F : fieldType) (p : nat) (gT : finGroupType). Hypothesis charFp : p \in [char F]. Implicit Types G H : {group gT}. (* This is Gorenstein, Lemma 2.6.3. *) Lemma rfix_pgroup_char G H n (rG : mx_representation F G n) : n > 0 -> p.-group H -> H \subset G -> rfix_mx rG H != 0. Proof. move=> n_gt0 pH sHG; rewrite -(rfix_subg rG sHG). move: {2}_.+1 (ltnSn (n + #|H|)) {rG G sHG}(subg_repr _ _) => m. elim: m gT H pH => // m IHm gT' G pG in n n_gt0 *; rewrite ltnS => le_nG_m rG. apply/eqP=> Gregular; have irrG: mx_irreducible rG. apply/mx_irrP; split=> // U modU; rewrite -mxrank_eq0 -lt0n => Unz. rewrite /row_full eqn_leq rank_leq_col leqNgt; apply/negP=> ltUn. have: rfix_mx (submod_repr modU) G != 0. by apply: IHm => //; apply: leq_trans le_nG_m; rewrite ltn_add2r. by rewrite -mxrank_eq0 (rfix_submod modU) // Gregular capmx0 linear0 mxrank0. have{m le_nG_m IHm} faithfulG: mx_faithful rG. apply/trivgP/eqP/idPn; set C := _ rG => ntC. suffices: rfix_mx (kquo_repr rG) (G / _)%g != 0. by rewrite -mxrank_eq0 rfix_quo // Gregular mxrank0. apply: (IHm _ _ (morphim_pgroup _ _)) => //. by apply: leq_trans le_nG_m; rewrite ltn_add2l ltn_quotient // rstab_sub. have{Gregular} ntG: G :!=: 1%g. apply: contraL n_gt0; move/eqP=> G1; rewrite -leqNgt -(mxrank1 F n). rewrite -(mxrank0 F n n) -Gregular mxrankS //; apply/rfix_mxP=> x. by rewrite {1}G1 mul1mx => /set1P->; rewrite repr_mx1. have p_pr: prime p by case/andP: charFp. have{ntG pG} [z]: {z | z \in 'Z(G) & #[z] = p}; last case/setIP=> Gz cGz ozp. apply: Cauchy => //; apply: contraR ntG; rewrite -p'natE // => p'Z. have pZ: p.-group 'Z(G) by rewrite (pgroupS (center_sub G)). by rewrite (trivg_center_pgroup pG (card1_trivg (pnat_1 pZ p'Z))). have{cGz} cGz1: centgmx rG (rG z - 1%:M). apply/centgmxP=> x Gx; rewrite mulmxBl mulmxBr mulmx1 mul1mx. by rewrite -!repr_mxM // (centP cGz). have{irrG faithfulG cGz1} Urz1: rG z - 1%:M \in unitmx. apply: (mx_Schur irrG) cGz1 _; rewrite subr_eq0. move/implyP: (subsetP faithfulG z). by rewrite !inE Gz mul1mx -order_eq1 ozp -implybNN neq_ltn orbC prime_gt1. do [case: n n_gt0 => // n' _; set n := n'.+1] in rG Urz1 *. have charMp: p \in [char 'M[F]_n]. exact: (rmorph_char (scalar_mx_rmorphism _ _)). have{Urz1}: Frobenius_aut charMp (rG z - 1) \in GRing.unit by rewrite unitrX. rewrite (Frobenius_autB_comm _ (commr1 _)) Frobenius_aut1. by rewrite -[_ (rG z)](repr_mxX rG) // -ozp expg_order repr_mx1 subrr unitr0. Qed. Variables (G : {group gT}) (n : nat) (rG : mx_representation F G n). Lemma pcore_sub_rstab_mxsimple M : mxsimple rG M -> 'O_p(G) \subset rstab rG M. Proof. case=> modM nzM simM; have sGpG := pcore_sub p G. rewrite rfix_mx_rstabC //; set U := rfix_mx _ _. have:= simM (M :&: U)%MS; rewrite sub_capmx submx_refl. apply; rewrite ?capmxSl //. by rewrite capmx_module // normal_rfix_mx_module ?pcore_normal. rewrite -(in_submodK (capmxSl _ _)) val_submod_eq0 -submx0. rewrite -(rfix_submod modM) // submx0 rfix_pgroup_char ?pcore_pgroup //. by rewrite lt0n mxrank_eq0. Qed. Lemma pcore_sub_rker_mx_irr : mx_irreducible rG -> 'O_p(G) \subset rker rG. Proof. exact: pcore_sub_rstab_mxsimple. Qed. (* This is Gorenstein, Lemma 3.1.3. *) Lemma pcore_faithful_mx_irr : mx_irreducible rG -> mx_faithful rG -> 'O_p(G) = 1%g. Proof. move=> irrG ffulG; apply/trivgP; apply: subset_trans ffulG. exact: pcore_sub_rstab_mxsimple. Qed. End ModularRepresentation. Section Extraspecial. Variables (F : fieldType) (gT : finGroupType) (S : {group gT}) (p n : nat). Hypotheses (pS : p.-group S) (esS : extraspecial S). Hypothesis oSpn : #|S| = (p ^ n.*2.+1)%N. Hypotheses (splitF : group_splitting_field F S) (F'S : [char F]^'.-group S). Let p_pr := extraspecial_prime pS esS. Let p_gt0 := prime_gt0 p_pr. Let p_gt1 := prime_gt1 p_pr. Let oZp := card_center_extraspecial pS esS. Let modIp' (i : 'I_p.-1) : (i.+1 %% p = i.+1)%N. Proof. by case: i => i; rewrite /= -ltnS prednK //; exact: modn_small. Qed. (* This is Aschbacher (34.9), parts (1)-(4). *) Theorem extraspecial_repr_structure (sS : irrType F S) : [/\ #|linear_irr sS| = (p ^ n.*2)%N, exists iphi : 'I_p.-1 -> sS, let phi i := irr_repr (iphi i) in [/\ injective iphi, codom iphi =i ~: linear_irr sS, forall i, mx_faithful (phi i), forall z, z \in 'Z(S)^# -> exists2 w, primitive_root_of_unity p w & forall i, phi i z = (w ^+ i.+1)%:M & forall i, irr_degree (iphi i) = (p ^ n)%N] & #|sS| = (p ^ n.*2 + p.-1)%N]. Proof. have [[defPhiS defS'] prZ] := esS; set linS := linear_irr sS. have nb_lin: #|linS| = (p ^ n.*2)%N. rewrite card_linear_irr // -divgS ?der_sub //=. by rewrite oSpn defS' oZp expnS mulKn. have nb_irr: #|sS| = (p ^ n.*2 + p.-1)%N. pose Zcl := classes S ::&: 'Z(S). have cardZcl: #|Zcl| = p. transitivity #|[set [set z] | z in 'Z(S)]|; last first. by rewrite card_imset //; exact: set1_inj. apply: eq_card => zS; apply/setIdP/imsetP=> [[] | [z]]. case/imsetP=> z Sz ->{zS} szSZ. have Zz: z \in 'Z(S) by rewrite (subsetP szSZ) ?class_refl. exists z => //; rewrite inE Sz in Zz. apply/eqP; rewrite eq_sym eqEcard sub1set class_refl cards1. by rewrite -index_cent1 (setIidPl _) ?indexgg // sub_cent1. case/setIP=> Sz cSz ->{zS}; rewrite sub1set inE Sz; split=> //. apply/imsetP; exists z; rewrite //. apply/eqP; rewrite eqEcard sub1set class_refl cards1. by rewrite -index_cent1 (setIidPl _) ?indexgg // sub_cent1. move/eqP: (class_formula S); rewrite (bigID (mem Zcl)) /=. rewrite (eq_bigr (fun _ => 1%N)) => [|zS]; last first. case/andP=> _ /setIdP[/imsetP[z Sz ->{zS}] /subsetIP[_ cSzS]]. rewrite (setIidPl _) ?indexgg // sub_cent1 (subsetP cSzS) //. exact: mem_repr (class_refl S z). rewrite sum1dep_card setIdE (setIidPr _) 1?cardsE ?cardZcl; last first. by apply/subsetP=> zS; rewrite 2!inE => /andP[]. have pn_gt0: p ^ n.*2 > 0 by rewrite expn_gt0 p_gt0. rewrite card_irr // oSpn expnS -(prednK pn_gt0) mulnS eqn_add2l. rewrite (eq_bigr (fun _ => p)) => [|xS]; last first. case/andP=> SxS; rewrite inE SxS; case/imsetP: SxS => x Sx ->{xS} notZxS. have [y Sy ->] := repr_class S x; apply: p_maximal_index => //. apply: cent1_extraspecial_maximal => //; first exact: groupJ. apply: contra notZxS => Zxy; rewrite -{1}(lcoset_id Sy) class_lcoset. rewrite ((_ ^: _ =P [set x ^ y])%g _) ?sub1set // eq_sym eqEcard. rewrite sub1set class_refl cards1 -index_cent1 (setIidPl _) ?indexgg //. by rewrite sub_cent1; apply: subsetP Zxy; exact: subsetIr. rewrite sum_nat_dep_const mulnC eqn_pmul2l //; move/eqP <-. rewrite addSnnS prednK // -cardZcl -[card _](cardsID Zcl) /= addnC. by congr (_ + _)%N; apply: eq_card => t; rewrite !inE andbC // andbAC andbb. have fful_nlin i: i \in ~: linS -> mx_faithful (irr_repr i). rewrite !inE => nlin_phi. apply/trivgP; apply: (TI_center_nil (pgroup_nil pS) (rker_normal _)). rewrite setIC; apply: (prime_TIg prZ); rewrite /= -defS' der1_sub_rker //. exact: socle_irr. have [i0 nlin_i0]: exists i0, i0 \in ~: linS. by apply/card_gt0P; rewrite cardsCs setCK nb_irr nb_lin addKn -subn1 subn_gt0. have [z defZ]: exists z, 'Z(S) = <[z]> by apply/cyclicP; rewrite prime_cyclic. have Zz: z \in 'Z(S) by [rewrite defZ cycle_id]; have [Sz cSz] := setIP Zz. have ozp: #[z] = p by rewrite -oZp defZ. have ntz: z != 1%g by rewrite -order_gt1 ozp. pose phi := irr_repr i0; have irr_phi: mx_irreducible phi := socle_irr i0. pose w := irr_mode i0 z. have phi_z: phi z = w%:M by rewrite /phi irr_center_scalar. have phi_ze e: phi (z ^+ e)%g = (w ^+ e)%:M. by rewrite /phi irr_center_scalar ?groupX ?irr_modeX. have wp1: w ^+ p = 1 by rewrite -irr_modeX // -ozp expg_order irr_mode1. have injw: {in 'Z(S) &, injective (irr_mode i0)}. move=> x y Zx Zy /= eq_xy; have [[Sx _] [Sy _]] := (setIP Zx, setIP Zy). apply: mx_faithful_inj (fful_nlin _ nlin_i0) _ _ Sx Sy _. by rewrite !{1}irr_center_scalar ?eq_xy; first by split. have prim_w e: 0 < e < p -> p.-primitive_root (w ^+ e). case/andP=> e_gt0 lt_e_p; apply/andP; split=> //. apply/eqfunP=> -[d ltdp] /=; rewrite unity_rootE -exprM. rewrite -(irr_mode1 i0) -irr_modeX // (inj_in_eq injw) ?groupX ?group1 //. rewrite -order_dvdn ozp Euclid_dvdM // gtnNdvd //=. move: ltdp; rewrite leq_eqVlt. by case: eqP => [-> _ | _ ltd1p]; rewrite (dvdnn, gtnNdvd). have /cyclicP[a defAutZ]: cyclic (Aut 'Z(S)) by rewrite Aut_prime_cyclic ?ozp. have phi_unitP (i : 'I_p.-1): (i.+1%:R : 'Z_#[z]) \in GRing.unit. by rewrite unitZpE ?order_gt1 // ozp prime_coprime // -lt0n !modIp'. pose ephi i := invm (injm_Zpm a) (Zp_unitm (FinRing.Unit _ (phi_unitP i))). pose j : 'Z_#[z] := val (invm (injm_Zp_unitm z) a). have co_j_p: coprime j p. rewrite coprime_sym /j; case: (invm _ a) => /=. by rewrite ozp /GRing.unit /= Zp_cast. have [alpha Aut_alpha alphaZ] := center_aut_extraspecial pS esS co_j_p. have alpha_i_z i: ((alpha ^+ ephi i) z = z ^+ i.+1)%g. transitivity ((a ^+ ephi i) z)%g. elim: (ephi i : nat) => // e IHe; rewrite !expgS !permM alphaZ //. have Aut_a: a \in Aut 'Z(S) by rewrite defAutZ cycle_id. rewrite -{2}[a](invmK (injm_Zp_unitm z)); last by rewrite im_Zp_unitm -defZ. rewrite /= autE ?cycle_id // -/j /= /cyclem. rewrite -(autmE (groupX _ Aut_a)) -(autmE (groupX _ Aut_alpha)). by rewrite !morphX //= !autmE IHe. rewrite [(a ^+ _)%g](invmK (injm_Zpm a)) /=; last first. by rewrite im_Zpm -defAutZ defZ Aut_aut. by rewrite autE ?cycle_id //= val_Zp_nat ozp ?modIp'. have rphiP i: S :==: autm (groupX (ephi i) Aut_alpha) @* S by rewrite im_autm. pose rphi i := morphim_repr (eqg_repr phi (rphiP i)) (subxx S). have rphi_irr i: mx_irreducible (rphi i). by apply/morphim_mx_irr; exact/eqg_mx_irr. have rphi_fful i: mx_faithful (rphi i). rewrite /mx_faithful rker_morphim rker_eqg. by rewrite (trivgP (fful_nlin _ nlin_i0)) morphpreIdom; exact: injm_autm. have rphi_z i: rphi i z = (w ^+ i.+1)%:M. by rewrite /rphi [phi]lock /= /morphim_mx autmE alpha_i_z -lock phi_ze. pose iphi i := irr_comp sS (rphi i); pose phi_ i := irr_repr (iphi i). have{phi_ze} phi_ze i e: phi_ i (z ^+ e)%g = (w ^+ (e * i.+1)%N)%:M. rewrite /phi_ !{1}irr_center_scalar ?groupX ?irr_modeX //. suffices ->: irr_mode (iphi i) z = w ^+ i.+1 by rewrite mulnC exprM. have:= mx_rsim_sym (rsim_irr_comp sS F'S (rphi_irr i)). case/mx_rsim_def=> B [B' _ homB]; rewrite /irr_mode homB // rphi_z. rewrite -{1}scalemx1 -scalemxAr -scalemxAl -{1}(repr_mx1 (rphi i)). by rewrite -homB // repr_mx1 scalemx1 mxE. have inj_iphi: injective iphi. move=> i1 i2 eqi12; apply/eqP. move/eqP: (congr1 (fun i => irr_mode i (z ^+ 1)) eqi12). rewrite /irr_mode !{1}[irr_repr _ _]phi_ze !{1}mxE !mul1n. by rewrite (eq_prim_root_expr (prim_w 1%N p_gt1)) !modIp'. have deg_phi i: irr_degree (iphi i) = irr_degree i0. by case: (rsim_irr_comp sS F'S (rphi_irr i)). have im_iphi: codom iphi =i ~: linS. apply/subset_cardP; last apply/subsetP=> _ /codomP[i ->]. by rewrite card_image // card_ord cardsCs setCK nb_irr nb_lin addKn. by rewrite !inE /= (deg_phi i) in nlin_i0 *. split=> //; exists iphi; rewrite -/phi_. split=> // [i | ze | i]. - have sim_i := rsim_irr_comp sS F'S (rphi_irr i). by rewrite -(mx_rsim_faithful sim_i) rphi_fful. - rewrite {1}defZ 2!inE andbC; case/andP. case/cyclePmin=> e; rewrite ozp => lt_e_p ->{ze}. case: (posnP e) => [-> | e_gt0 _]; first by rewrite eqxx. exists (w ^+ e) => [|i]; first by rewrite prim_w ?e_gt0. by rewrite phi_ze exprM. rewrite deg_phi {i}; set d := irr_degree i0. apply/eqP; move/eqP: (sum_irr_degree sS F'S splitF). rewrite (bigID (mem linS)) /= -/irr_degree. rewrite (eq_bigr (fun _ => 1%N)) => [|i]; last by rewrite !inE; move/eqP->. rewrite sum1_card nb_lin. rewrite (eq_bigl (mem (codom iphi))) // => [|i]; last first. by rewrite -in_setC -im_iphi. rewrite (eq_bigr (fun _ => d ^ 2))%N => [|_ /codomP[i ->]]; last first. by rewrite deg_phi. rewrite sum_nat_const card_image // card_ord oSpn (expnS p) -{3}[p]prednK //. rewrite mulSn eqn_add2l eqn_pmul2l; last by rewrite -ltnS prednK. by rewrite -muln2 expnM eqn_sqr. Qed. (* This is the corolloray of the above that is actually used in the proof of *) (* B & G, Theorem 2.5. It encapsulates the dependency on a socle of the *) (* regular representation. *) Variables (m : nat) (rS : mx_representation F S m) (U : 'M[F]_m). Hypotheses (simU : mxsimple rS U) (ffulU : rstab rS U == 1%g). Let sZS := center_sub S. Let rZ := subg_repr rS sZS. Lemma faithful_repr_extraspecial : \rank U = (p ^ n)%N /\ (forall V, mxsimple rS V -> mx_iso rZ U V -> mx_iso rS U V). Proof. suffices IH V: mxsimple rS V -> mx_iso rZ U V -> [&& \rank U == (p ^ n)%N & mxsimple_iso rS U V]. - split=> [|/= V simV isoUV]. by case/andP: (IH U simU (mx_iso_refl _ _)) => /eqP. by case/andP: (IH V simV isoUV) => _ /(mxsimple_isoP simU). move=> simV isoUV; wlog sS: / irrType F S by exact: socle_exists. have [[_ defS'] prZ] := esS. have{prZ} ntZ: 'Z(S) :!=: 1%g by case: eqP prZ => // ->; rewrite cards1. have [_ [iphi]] := extraspecial_repr_structure sS. set phi := fun i => _ => [] [inj_phi im_phi _ phiZ dim_phi] _. have [modU nzU _]:= simU; pose rU := submod_repr modU. have nlinU: \rank U != 1%N. apply/eqP=> /(rker_linear rU); apply/negP; rewrite /rker rstab_submod. by rewrite (eqmx_rstab _ (val_submod1 _)) (eqP ffulU) defS' subG1. have irrU: mx_irreducible rU by exact/submod_mx_irr. have rsimU := rsim_irr_comp sS F'S irrU. set iU := irr_comp sS rU in rsimU; have [_ degU _ _]:= rsimU. have phiUP: iU \in codom iphi by rewrite im_phi !inE -degU. rewrite degU -(f_iinv phiUP) dim_phi eqxx /=; apply/(mxsimple_isoP simU). have [modV _ _]:= simV; pose rV := submod_repr modV. have irrV: mx_irreducible rV by exact/submod_mx_irr. have rsimV := rsim_irr_comp sS F'S irrV. set iV := irr_comp sS rV in rsimV; have [_ degV _ _]:= rsimV. have phiVP: iV \in codom iphi by rewrite im_phi !inE -degV -(mxrank_iso isoUV). pose jU := iinv phiUP; pose jV := iinv phiVP. have [z Zz ntz]:= trivgPn _ ntZ. have [|w prim_w phi_z] := phiZ z; first by rewrite 2!inE ntz. suffices eqjUV: jU == jV. apply/(mx_rsim_iso modU modV); apply: mx_rsim_trans rsimU _. by rewrite -(f_iinv phiUP) -/jU (eqP eqjUV) f_iinv; exact: mx_rsim_sym. have rsimUV: mx_rsim (subg_repr (phi jU) sZS) (subg_repr (phi jV) sZS). have [bU _ bUfree bUhom] := mx_rsim_sym rsimU. have [bV _ bVfree bVhom] := rsimV. have modUZ := mxmodule_subg sZS modU; have modVZ := mxmodule_subg sZS modV. case/(mx_rsim_iso modUZ modVZ): isoUV => [bZ degZ bZfree bZhom]. rewrite /phi !f_iinv; exists (bU *m bZ *m bV)=> [||x Zx]. - by rewrite -degU degZ degV. - by rewrite /row_free !mxrankMfree. have Sx := subsetP sZS x Zx. by rewrite 2!mulmxA bUhom // -(mulmxA _ _ bZ) bZhom // -4!mulmxA bVhom. have{rsimUV} [B [B' _ homB]] := mx_rsim_def rsimUV. have:= eqxx (irr_mode (iphi jU) z); rewrite /irr_mode; set i0 := Ordinal _. rewrite {2}[_ z]homB // ![_ z]phi_z mxE mulr1n -scalemx1 -scalemxAr -scalemxAl. rewrite -(repr_mx1 (subg_repr (phi jV) sZS)) -{B B'}homB // repr_mx1 scalemx1. by rewrite mxE (eq_prim_root_expr prim_w) !modIp'. Qed. End Extraspecial. mathcomp-1.5/theories/quotient.v0000644000175000017500000010351412307636117016046 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq div choice. Require Import fintype prime finset fingroup morphism automorphism. (******************************************************************************) (* This file contains the definitions of: *) (* coset_of H == the (sub)type of bilateral cosets of H (see below) *) (* coset H == the canonical projection into coset_of H *) (* A / H == the quotient of A by H, that is, the morphic image *) (* of A by coset H. We do not require H <| A, so in a *) (* textbook A / H would be written 'N_A(H) * H / H. *) (* quotm f (nHG : H <| G) == the quotient morphism induced by f, *) (* mapping G / H onto f @* G / f @* H *) (* qisom f (eqHG : H = G) == the identity isomorphism between *) (* [set: coset_of G] and [set: coset_of H]. *) (* We also prove the three isomorphism theorems, and counting lemmas for *) (* morphisms. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section Cosets. Variables (gT : finGroupType) (Q A : {set gT}). (******************************************************************************) (* Cosets are right cosets of elements in the normaliser *) (* We let cosets coerce to GroupSet.sort, so they inherit the group subset *) (* base group structure. Later we will define a proper group structure on *) (* cosets, which will then hide the inherited structure once coset_of unifies *) (* with FinGroup.sort; the coercion to GroupSet.sort will no longer be used. *) (* Note that for Hx Hy : coset_of H, Hx * Hy : {set gT} can mean either *) (* set_of_coset (mulg Hx Hy) OR mulg (set_of_coset Hx) (set_of_coset Hy) *) (* However, since the two terms are actually convertible, we can live with *) (* this ambiguity. *) (* We take great care that neither the type coset_of H, nor its Canonical *) (* finGroupType structure, nor the coset H morphism depend on the actual *) (* group structure of H. Otherwise, rewriting would be extremely awkward *) (* because all our equalities are stated at the set level. *) (* The trick we use is to interpret coset_of A, when A is any set, as the *) (* type of cosets of the group generated by A, in the group A <*> N(A) *) (* generated by A and its normaliser. This coincides with the type of *) (* bilateral cosets of A when A is a group. We restrict the domain of coset A *) (* to 'N(A), so that we get almost all the same conversion equalities as if *) (* we had forced A to be a group in the first place; the only exception, that *) (* 1 : coset_of A : set _ = <> rather than A, is covered by genGid. *) (******************************************************************************) Notation H := <>. Definition coset_range := [pred B in rcosets H 'N(A)]. Record coset_of : Type := Coset { set_of_coset :> GroupSet.sort gT; _ : coset_range set_of_coset }. Canonical coset_subType := Eval hnf in [subType for set_of_coset]. Definition coset_eqMixin := Eval hnf in [eqMixin of coset_of by <:]. Canonical coset_eqType := Eval hnf in EqType coset_of coset_eqMixin. Definition coset_choiceMixin := [choiceMixin of coset_of by <:]. Canonical coset_choiceType := Eval hnf in ChoiceType coset_of coset_choiceMixin. Definition coset_countMixin := [countMixin of coset_of by <:]. Canonical coset_countType := Eval hnf in CountType coset_of coset_countMixin. Canonical coset_subCountType := Eval hnf in [subCountType of coset_of]. Definition coset_finMixin := [finMixin of coset_of by <:]. Canonical coset_finType := Eval hnf in FinType coset_of coset_finMixin. Canonical coset_subFinType := Eval hnf in [subFinType of coset_of]. (* We build a new (canonical) structure of groupType for cosets. *) (* When A is a group, this is the largest possible quotient 'N(A) / A. *) Lemma coset_one_proof : coset_range H. Proof. by apply/rcosetsP; exists (1 : gT); rewrite (group1, mulg1). Qed. Definition coset_one := Coset coset_one_proof. Let nNH := subsetP (norm_gen A). Lemma coset_range_mul (B C : coset_of) : coset_range (B * C). Proof. case: B C => _ /= /rcosetsP[x Nx ->] [_ /= /rcosetsP[y Ny ->]]. by apply/rcosetsP; exists (x * y); rewrite !(groupM, rcoset_mul, nNH). Qed. Definition coset_mul B C := Coset (coset_range_mul B C). Lemma coset_range_inv (B : coset_of) : coset_range B^-1. Proof. case: B => _ /= /rcosetsP[x Nx ->]; rewrite norm_rlcoset ?nNH // invg_lcoset. by apply/rcosetsP; exists x^-1; rewrite ?groupV. Qed. Definition coset_inv B := Coset (coset_range_inv B). Lemma coset_mulP : associative coset_mul. Proof. by move=> B C D; apply: val_inj; rewrite /= mulgA. Qed. Lemma coset_oneP : left_id coset_one coset_mul. Proof. case=> B coB; apply: val_inj => /=; case/rcosetsP: coB => x Hx ->{B}. by rewrite mulgA mulGid. Qed. Lemma coset_invP : left_inverse coset_one coset_inv coset_mul. Proof. case=> B coB; apply: val_inj => /=; case/rcosetsP: coB => x Hx ->{B}. rewrite invg_rcoset -mulgA (mulgA H) mulGid. by rewrite norm_rlcoset ?nNH // -lcosetM mulVg mul1g. Qed. Definition coset_of_groupMixin := FinGroup.Mixin coset_mulP coset_oneP coset_invP. Canonical coset_baseGroupType := Eval hnf in BaseFinGroupType coset_of coset_of_groupMixin. Canonical coset_groupType := FinGroupType coset_invP. (* Projection of the initial group type over the cosets groupType *) Definition coset x : coset_of := insubd (1 : coset_of) (H :* x). (* This is a primitive lemma -- we'll need to restate it for *) (* the case where A is a group. *) Lemma val_coset_prim x : x \in 'N(A) -> coset x :=: H :* x. Proof. by move=> Nx; rewrite val_insubd /= mem_rcosets -{1}(mul1g x) mem_mulg. Qed. Lemma coset_morphM : {in 'N(A) &, {morph coset : x y / x * y}}. Proof. move=> x y Nx Ny; apply: val_inj. by rewrite /= !val_coset_prim ?groupM //= rcoset_mul ?nNH. Qed. Canonical coset_morphism := Morphism coset_morphM. Lemma ker_coset_prim : 'ker coset = 'N_H(A). Proof. apply/setP=> z; rewrite !in_setI andbC 2!inE -val_eqE /=. case Nz: (z \in 'N(A)); rewrite ?andbF ?val_coset_prim // !andbT. by apply/eqP/idP=> [<-| Az]; rewrite (rcoset_refl, rcoset_id). Qed. Implicit Type xbar : coset_of. Lemma coset_mem y xbar : y \in xbar -> coset y = xbar. Proof. case: xbar => /= Hx NHx Hxy; apply: val_inj=> /=. case/rcosetsP: NHx (NHx) Hxy => x Nx -> NHx Hxy. by rewrite val_insubd /= (rcoset_transl Hxy) NHx. Qed. (* coset is an inverse to repr *) Lemma mem_repr_coset xbar : repr xbar \in xbar. Proof. case: xbar => /= _ /rcosetsP[x _ ->]; exact: mem_repr_rcoset. Qed. Lemma repr_coset1 : repr (1 : coset_of) = 1. Proof. exact: repr_group. Qed. Lemma coset_reprK : cancel (fun xbar => repr xbar) coset. Proof. by move=> xbar; exact: coset_mem (mem_repr_coset xbar). Qed. (* cosetP is slightly stronger than using repr because we only *) (* guarantee repr xbar \in 'N(A) when A is a group. *) Lemma cosetP xbar : {x | x \in 'N(A) & xbar = coset x}. Proof. pose x := repr 'N_xbar(A). have [xbar_x Nx]: x \in xbar /\ x \in 'N(A). apply/setIP; rewrite {}/x; case: xbar => /= _ /rcosetsP[y Ny ->]. by apply: (mem_repr y); rewrite inE rcoset_refl. by exists x; last rewrite (coset_mem xbar_x). Qed. Lemma coset_id x : x \in A -> coset x = 1. Proof. by move=> Ax; apply: coset_mem; exact: mem_gen. Qed. Lemma im_coset : coset @* 'N(A) = setT. Proof. by apply/setP=> xbar; case: (cosetP xbar) => x Nx ->; rewrite inE mem_morphim. Qed. Lemma sub_im_coset (C : {set coset_of}) : C \subset coset @* 'N(A). Proof. by rewrite im_coset subsetT. Qed. Lemma cosetpre_proper C D : (coset @*^-1 C \proper coset @*^-1 D) = (C \proper D). Proof. by rewrite morphpre_proper ?sub_im_coset. Qed. Definition quotient : {set coset_of} := coset @* Q. Lemma quotientE : quotient = coset @* Q. Proof. by []. Qed. End Cosets. Arguments Scope coset_of [_ group_scope]. Arguments Scope coset [_ group_scope group_scope]. Arguments Scope quotient [_ group_scope group_scope]. Prenex Implicits coset_of coset. Bind Scope group_scope with coset_of. Notation "A / B" := (quotient A B) : group_scope. Section CosetOfGroupTheory. Variables (gT : finGroupType) (H : {group gT}). Implicit Types (A B : {set gT}) (G K : {group gT}) (xbar yb : coset_of H). Implicit Types (C D : {set coset_of H}) (L M : {group coset_of H}). Canonical quotient_group G A : {group coset_of A} := Eval hnf in [group of G / A]. Infix "/" := quotient_group : Group_scope. Lemma val_coset x : x \in 'N(H) -> coset H x :=: H :* x. Proof. by move=> Nx; rewrite val_coset_prim // genGid. Qed. Lemma coset_default x : (x \in 'N(H)) = false -> coset H x = 1. Proof. move=> Nx; apply: val_inj. by rewrite val_insubd /= mem_rcosets /= genGid mulSGid ?normG ?Nx. Qed. Lemma coset_norm xbar : xbar \subset 'N(H). Proof. case: xbar => /= _ /rcosetsP[x Nx ->]. by rewrite genGid mul_subG ?sub1set ?normG. Qed. Lemma ker_coset : 'ker (coset H) = H. Proof. by rewrite ker_coset_prim genGid (setIidPl _) ?normG. Qed. Lemma coset_idr x : x \in 'N(H) -> coset H x = 1 -> x \in H. Proof. by move=> Nx Hx1; rewrite -ker_coset mem_morphpre //= Hx1 set11. Qed. Lemma repr_coset_norm xbar : repr xbar \in 'N(H). Proof. exact: subsetP (coset_norm _) _ (mem_repr_coset _). Qed. Lemma imset_coset G : coset H @: G = G / H. Proof. apply/eqP; rewrite eqEsubset andbC imsetS ?subsetIr //=. apply/subsetP=> _ /imsetP[x Gx ->]. by case Nx: (x \in 'N(H)); rewrite ?(coset_default Nx) ?mem_morphim ?group1. Qed. Lemma val_quotient A : val @: (A / H) = rcosets H 'N_A(H). Proof. apply/setP=> B; apply/imsetP/rcosetsP=> [[xbar Axbar]|[x /setIP[Ax Nx]]] ->{B}. case/morphimP: Axbar => x Nx Ax ->{xbar}. by exists x; [rewrite inE Ax | rewrite /= val_coset]. by exists (coset H x); [apply/morphimP; exists x | rewrite /= val_coset]. Qed. Lemma card_quotient_subnorm A : #|A / H| = #|'N_A(H) : H|. Proof. by rewrite -(card_imset _ val_inj) val_quotient. Qed. Lemma leq_quotient A : #|A / H| <= #|A|. Proof. exact: leq_morphim. Qed. Lemma ltn_quotient A : H :!=: 1 -> H \subset A -> #|A / H| < #|A|. Proof. by move=> ntH sHA; rewrite ltn_morphim // ker_coset (setIidPr sHA) proper1G. Qed. Lemma card_quotient A : A \subset 'N(H) -> #|A / H| = #|A : H|. Proof. by move=> nHA; rewrite card_quotient_subnorm (setIidPl nHA). Qed. Lemma divg_normal G : H <| G -> #|G| %/ #|H| = #|G / H|. Proof. by case/andP=> sHG nHG; rewrite divgS ?card_quotient. Qed. (* Specializing all the morphisms lemmas that have different assumptions *) (* (e.g., because 'ker (coset H) = H), or conclusions (e.g., because we use *) (* A / H rather than coset H @* A). We may want to reevaluate later, and *) (* eliminate variants that aren't used . *) (* Variant of morph1; no specialization for other morph lemmas. *) Lemma coset1 : coset H 1 :=: H. Proof. by rewrite morph1 /= genGid. Qed. (* Variant of kerE. *) Lemma cosetpre1 : coset H @*^-1 1 = H. Proof. by rewrite -kerE ker_coset. Qed. (* Variant of morphimEdom; mophimE[sub] covered by imset_coset. *) (* morph[im|pre]Iim are also covered by im_quotient. *) Lemma im_quotient : 'N(H) / H = setT. Proof. exact: im_coset. Qed. Lemma quotientT : setT / H = setT. Proof. by rewrite -im_quotient; exact: morphimT. Qed. (* Variant of morphimIdom. *) Lemma quotientInorm A : 'N_A(H) / H = A / H. Proof. by rewrite /quotient setIC morphimIdom. Qed. Lemma quotient_setIpre A D : (A :&: coset H @*^-1 D) / H = A / H :&: D. Proof. exact: morphim_setIpre. Qed. Lemma mem_quotient x G : x \in G -> coset H x \in G / H. Proof. by move=> Gx; rewrite -imset_coset mem_imset. Qed. Lemma quotientS A B : A \subset B -> A / H \subset B / H. Proof. exact: morphimS. Qed. Lemma quotient0 : set0 / H = set0. Proof. exact: morphim0. Qed. Lemma quotient_set1 x : x \in 'N(H) -> [set x] / H = [set coset H x]. Proof. exact: morphim_set1. Qed. Lemma quotient1 : 1 / H = 1. Proof. exact: morphim1. Qed. Lemma quotientV A : A^-1 / H = (A / H)^-1. Proof. exact: morphimV. Qed. Lemma quotientMl A B : A \subset 'N(H) -> A * B / H = (A / H) * (B / H). Proof. exact: morphimMl. Qed. Lemma quotientMr A B : B \subset 'N(H) -> A * B / H = (A / H) * (B / H). Proof. exact: morphimMr. Qed. Lemma cosetpreM C D : coset H @*^-1 (C * D) = coset H @*^-1 C * coset H @*^-1 D. Proof. by rewrite morphpreMl ?sub_im_coset. Qed. Lemma quotientJ A x : x \in 'N(H) -> A :^ x / H = (A / H) :^ coset H x. Proof. exact: morphimJ. Qed. Lemma quotientU A B : (A :|: B) / H = A / H :|: B / H. Proof. exact: morphimU. Qed. Lemma quotientI A B : (A :&: B) / H \subset A / H :&: B / H. Proof. exact: morphimI. Qed. Lemma quotientY A B : A \subset 'N(H) -> B \subset 'N(H) -> (A <*> B) / H = (A / H) <*> (B / H). Proof. exact: morphimY. Qed. Lemma quotient_homg A : A \subset 'N(H) -> homg (A / H) A. Proof. exact: morphim_homg. Qed. Lemma coset_kerl x y : x \in H -> coset H (x * y) = coset H y. Proof. move=> Hx; case Ny: (y \in 'N(H)); first by rewrite mkerl ?ker_coset. by rewrite !coset_default ?groupMl // (subsetP (normG H)). Qed. Lemma coset_kerr x y : y \in H -> coset H (x * y) = coset H x. Proof. move=> Hy; case Nx: (x \in 'N(H)); first by rewrite mkerr ?ker_coset. by rewrite !coset_default ?groupMr // (subsetP (normG H)). Qed. Lemma rcoset_kercosetP x y : x \in 'N(H) -> y \in 'N(H) -> reflect (coset H x = coset H y) (x \in H :* y). Proof. rewrite -{6}ker_coset; exact: rcoset_kerP. Qed. Lemma kercoset_rcoset x y : x \in 'N(H) -> y \in 'N(H) -> coset H x = coset H y -> exists2 z, z \in H & x = z * y. Proof. by move=> Nx Ny eqfxy; rewrite -ker_coset; exact: ker_rcoset. Qed. Lemma quotientGI G A : H \subset G -> (G :&: A) / H = G / H :&: A / H. Proof. by rewrite -{1}ker_coset; exact: morphimGI. Qed. Lemma quotientIG A G : H \subset G -> (A :&: G) / H = A / H :&: G / H. Proof. by rewrite -{1}ker_coset; exact: morphimIG. Qed. Lemma quotientD A B : A / H :\: B / H \subset (A :\: B) / H. Proof. exact: morphimD. Qed. Lemma quotientD1 A : (A / H)^# \subset A^# / H. Proof. exact: morphimD1. Qed. Lemma quotientDG A G : H \subset G -> (A :\: G) / H = A / H :\: G / H. Proof. by rewrite -{1}ker_coset; exact: morphimDG. Qed. Lemma quotientK A : A \subset 'N(H) -> coset H @*^-1 (A / H) = H * A. Proof. by rewrite -{8}ker_coset; exact: morphimK. Qed. Lemma quotientYK G : G \subset 'N(H) -> coset H @*^-1 (G / H) = H <*> G. Proof. by move=> nHG; rewrite quotientK ?norm_joinEr. Qed. Lemma quotientGK G : H <| G -> coset H @*^-1 (G / H) = G. Proof. by case/andP; rewrite -{1}ker_coset; exact: morphimGK. Qed. Lemma quotient_class x A : x \in 'N(H) -> A \subset 'N(H) -> x ^: A / H = coset H x ^: (A / H). Proof. exact: morphim_class. Qed. Lemma classes_quotient A : A \subset 'N(H) -> classes (A / H) = [set xA / H | xA in classes A]. Proof. exact: classes_morphim. Qed. Lemma cosetpre_set1 x : x \in 'N(H) -> coset H @*^-1 [set coset H x] = H :* x. Proof. by rewrite -{9}ker_coset; exact: morphpre_set1. Qed. Lemma cosetpre_set1_coset xbar : coset H @*^-1 [set xbar] = xbar. Proof. by case: (cosetP xbar) => x Nx ->; rewrite cosetpre_set1 ?val_coset. Qed. Lemma cosetpreK C : coset H @*^-1 C / H = C. Proof. by rewrite /quotient morphpreK ?sub_im_coset. Qed. (* Variant of morhphim_ker *) Lemma trivg_quotient : H / H = 1. Proof. by rewrite -{3}ker_coset /quotient morphim_ker. Qed. Lemma quotientS1 G : G \subset H -> G / H = 1. Proof. by move=> sGH; apply/trivgP; rewrite -trivg_quotient quotientS. Qed. Lemma sub_cosetpre M : H \subset coset H @*^-1 M. Proof. by rewrite -{1}ker_coset; exact: ker_sub_pre. Qed. Lemma quotient_proper G K : H <| G -> H <| K -> (G / H \proper K / H) = (G \proper K). Proof. by move=> nHG nHK; rewrite -cosetpre_proper ?quotientGK. Qed. Lemma normal_cosetpre M : H <| coset H @*^-1 M. Proof. rewrite -{1}ker_coset; exact: ker_normal_pre. Qed. Lemma cosetpreSK C D : (coset H @*^-1 C \subset coset H @*^-1 D) = (C \subset D). Proof. by rewrite morphpreSK ?sub_im_coset. Qed. Lemma sub_quotient_pre A C : A \subset 'N(H) -> (A / H \subset C) = (A \subset coset H @*^-1 C). Proof. exact: sub_morphim_pre. Qed. Lemma sub_cosetpre_quo C G : H <| G -> (coset H @*^-1 C \subset G) = (C \subset G / H). Proof. by move=> nHG; rewrite -cosetpreSK quotientGK. Qed. (* Variant of ker_trivg_morphim. *) Lemma quotient_sub1 A : A \subset 'N(H) -> (A / H \subset [1]) = (A \subset H). Proof. by move=> nHA /=; rewrite -{10}ker_coset ker_trivg_morphim nHA. Qed. Lemma quotientSK A B : A \subset 'N(H) -> (A / H \subset B / H) = (A \subset H * B). Proof. by move=> nHA; rewrite morphimSK ?ker_coset. Qed. Lemma quotientSGK A G : A \subset 'N(H) -> H \subset G -> (A / H \subset G / H) = (A \subset G). Proof. by rewrite -{2}ker_coset; exact: morphimSGK. Qed. Lemma quotient_injG : {in [pred G : {group gT} | H <| G] &, injective (fun G => G / H)}. Proof. by rewrite /normal -{1}ker_coset; exact: morphim_injG. Qed. Lemma quotient_inj G1 G2 : H <| G1 -> H <| G2 -> G1 / H = G2 / H -> G1 :=: G2. Proof. by rewrite /normal -{1 3}ker_coset; exact: morphim_inj. Qed. Lemma quotient_neq1 A : H <| A -> (A / H != 1) = (H \proper A). Proof. case/andP=> sHA nHA; rewrite /proper sHA -trivg_quotient eqEsubset andbC. by rewrite quotientS //= quotientSGK. Qed. Lemma quotient_gen A : A \subset 'N(H) -> <> / H = <>. Proof. exact: morphim_gen. Qed. Lemma cosetpre_gen C : 1 \in C -> coset H @*^-1 <> = <>. Proof. by move=> C1; rewrite morphpre_gen ?sub_im_coset. Qed. Lemma quotientR A B : A \subset 'N(H) -> B \subset 'N(H) -> [~: A, B] / H = [~: A / H, B / H]. Proof. exact: morphimR. Qed. Lemma quotient_norm A : 'N(A) / H \subset 'N(A / H). Proof. exact: morphim_norm. Qed. Lemma quotient_norms A B : A \subset 'N(B) -> A / H \subset 'N(B / H). Proof. exact: morphim_norms. Qed. Lemma quotient_subnorm A B : 'N_A(B) / H \subset 'N_(A / H)(B / H). Proof. exact: morphim_subnorm. Qed. Lemma quotient_normal A B : A <| B -> A / H <| B / H. Proof. exact: morphim_normal. Qed. Lemma quotient_cent1 x : 'C[x] / H \subset 'C[coset H x]. Proof. case Nx: (x \in 'N(H)); first exact: morphim_cent1. by rewrite coset_default // cent11T subsetT. Qed. Lemma quotient_cent1s A x : A \subset 'C[x] -> A / H \subset 'C[coset H x]. Proof. by move=> sAC; exact: subset_trans (quotientS sAC) (quotient_cent1 x). Qed. Lemma quotient_subcent1 A x : 'C_A[x] / H \subset 'C_(A / H)[coset H x]. Proof. exact: subset_trans (quotientI _ _) (setIS _ (quotient_cent1 x)). Qed. Lemma quotient_cent A : 'C(A) / H \subset 'C(A / H). Proof. exact: morphim_cent. Qed. Lemma quotient_cents A B : A \subset 'C(B) -> A / H \subset 'C(B / H). Proof. exact: morphim_cents. Qed. Lemma quotient_abelian A : abelian A -> abelian (A / H). Proof. exact: morphim_abelian. Qed. Lemma quotient_subcent A B : 'C_A(B) / H \subset 'C_(A / H)(B / H). Proof. exact: morphim_subcent. Qed. Lemma norm_quotient_pre A C : A \subset 'N(H) -> A / H \subset 'N(C) -> A \subset 'N(coset H @*^-1 C). Proof. by move/sub_quotient_pre=> -> /subset_trans-> //; exact: morphpre_norm. Qed. Lemma cosetpre_normal C D : (coset H @*^-1 C <| coset H @*^-1 D) = (C <| D). Proof. by rewrite morphpre_normal ?sub_im_coset. Qed. Lemma quotient_normG G : H <| G -> 'N(G) / H = 'N(G / H). Proof. case/andP=> sHG nHG. by rewrite [_ / _]morphim_normG ?ker_coset // im_coset setTI. Qed. Lemma quotient_subnormG A G : H <| G -> 'N_A(G) / H = 'N_(A / H)(G / H). Proof. by case/andP=> sHG nHG; rewrite -morphim_subnormG ?ker_coset. Qed. Lemma cosetpre_cent1 x : 'C_('N(H))[x] \subset coset H @*^-1 'C[coset H x]. Proof. case Nx: (x \in 'N(H)); first by rewrite morphpre_cent1. by rewrite coset_default // cent11T morphpreT subsetIl. Qed. Lemma cosetpre_cent1s C x : coset H @*^-1 C \subset 'C[x] -> C \subset 'C[coset H x]. Proof. move=> sC; rewrite -cosetpreSK; apply: subset_trans (cosetpre_cent1 x). by rewrite subsetI subsetIl. Qed. Lemma cosetpre_subcent1 C x : 'C_(coset H @*^-1 C)[x] \subset coset H @*^-1 'C_C[coset H x]. Proof. by rewrite -morphpreIdom -setIA setICA morphpreI setIS // cosetpre_cent1. Qed. Lemma cosetpre_cent A : 'C_('N(H))(A) \subset coset H @*^-1 'C(A / H). Proof. exact: morphpre_cent. Qed. Lemma cosetpre_cents A C : coset H @*^-1 C \subset 'C(A) -> C \subset 'C(A / H). Proof. by apply: morphpre_cents; rewrite ?sub_im_coset. Qed. Lemma cosetpre_subcent C A : 'C_(coset H @*^-1 C)(A) \subset coset H @*^-1 'C_C(A / H). Proof. exact: morphpre_subcent. Qed. Lemma restrm_quotientE G A (nHG : G \subset 'N(H)) : A \subset G -> restrm nHG (coset H) @* A = A / H. Proof. exact: restrmEsub. Qed. Section InverseImage. Variables (G : {group gT}) (Kbar : {group coset_of H}). Hypothesis nHG : H <| G. CoInductive inv_quotient_spec (P : pred {group gT}) : Prop := InvQuotientSpec K of Kbar :=: K / H & H \subset K & P K. Lemma inv_quotientS : Kbar \subset G / H -> inv_quotient_spec (fun K => K \subset G). Proof. case/andP: nHG => sHG nHG' sKbarG. have sKdH: Kbar \subset 'N(H) / H by rewrite (subset_trans sKbarG) ?morphimS. exists (coset H @*^-1 Kbar)%G; first by rewrite cosetpreK. by rewrite -{1}ker_coset morphpreS ?sub1G. by rewrite sub_cosetpre_quo. Qed. Lemma inv_quotientN : Kbar <| G / H -> inv_quotient_spec (fun K => K <| G). Proof. move=> nKbar; case/inv_quotientS: (normal_sub nKbar) => K defKbar sHK sKG. exists K => //; rewrite defKbar -cosetpre_normal !quotientGK // in nKbar. exact: normalS nHG. Qed. End InverseImage. Lemma quotientMidr A : A * H / H = A / H. Proof. by rewrite [_ /_]morphimMr ?normG //= -!quotientE trivg_quotient mulg1. Qed. Lemma quotientMidl A : H * A / H = A / H. Proof. by rewrite [_ /_]morphimMl ?normG //= -!quotientE trivg_quotient mul1g. Qed. Lemma quotientYidr G : G \subset 'N(H) -> G <*> H / H = G / H. Proof. move=> nHG; rewrite -genM_join quotient_gen ?mul_subG ?normG //. by rewrite quotientMidr genGid. Qed. Lemma quotientYidl G : G \subset 'N(H) -> H <*> G / H = G / H. Proof. by move=> nHG; rewrite joingC quotientYidr. Qed. Section Injective. Variables (G : {group gT}). Hypotheses (nHG : G \subset 'N(H)) (tiHG : H :&: G = 1). Lemma quotient_isom : isom G (G / H) (restrm nHG (coset H)). Proof. by apply/isomP; rewrite ker_restrm setIC ker_coset tiHG im_restrm. Qed. Lemma quotient_isog : isog G (G / H). Proof. exact: isom_isog quotient_isom. Qed. End Injective. End CosetOfGroupTheory. Notation "A / H" := (quotient_group A H) : Group_scope. Section Quotient1. Variables (gT : finGroupType) (A : {set gT}). Lemma coset1_injm : 'injm (@coset gT 1). Proof. by rewrite ker_coset /=. Qed. Lemma quotient1_isom : isom A (A / 1) (coset 1). Proof. by apply: sub_isom coset1_injm; rewrite ?norms1. Qed. Lemma quotient1_isog : isog A (A / 1). Proof. apply: isom_isog quotient1_isom; exact: norms1. Qed. End Quotient1. Section QuotientMorphism. Variable (gT rT : finGroupType) (G H : {group gT}) (f : {morphism G >-> rT}). Implicit Types A : {set gT}. Implicit Types B : {set (coset_of H)}. Hypotheses (nsHG : H <| G). Let sHG : H \subset G := normal_sub nsHG. Let nHG : G \subset 'N(H) := normal_norm nsHG. Let nfHfG : f @* G \subset 'N(f @* H) := morphim_norms f nHG. Notation fH := (coset (f @* H) \o f). Lemma quotm_dom_proof : G \subset 'dom fH. Proof. by rewrite -sub_morphim_pre. Qed. Notation fH_G := (restrm quotm_dom_proof fH). Lemma quotm_ker_proof : 'ker (coset H) \subset 'ker fH_G. Proof. by rewrite ker_restrm ker_comp !ker_coset morphpreIdom morphimK ?mulG_subr. Qed. Definition quotm := factm quotm_ker_proof nHG. Canonical quotm_morphism := [morphism G / H of quotm]. Lemma quotmE x : x \in G -> quotm (coset H x) = coset (f @* H) (f x). Proof. exact: factmE. Qed. Lemma morphim_quotm A : quotm @* (A / H) = f @* A / f @* H. Proof. by rewrite morphim_factm morphim_restrm morphim_comp morphimIdom. Qed. Lemma morphpre_quotm Abar : quotm @*^-1 (Abar / f @* H) = f @*^-1 Abar / H. Proof. rewrite morphpre_factm morphpre_restrm morphpre_comp /=. rewrite morphpreIdom -[Abar / _]quotientInorm quotientK ?subsetIr //=. rewrite morphpreMl ?morphimS // morphimK // [_ * H]normC ?subIset ?nHG //. rewrite -quotientE -mulgA quotientMidl /= setIC -morphpreIim setIA. by rewrite (setIidPl nfHfG) morphpreIim -morphpreMl ?sub1G ?mul1g. Qed. Lemma ker_quotm : 'ker quotm = 'ker f / H. Proof. by rewrite -morphpre_quotm /quotient morphim1. Qed. Lemma injm_quotm : 'injm f -> 'injm quotm. Proof. by move/trivgP=> /= kf1; rewrite ker_quotm kf1 quotientE morphim1. Qed. End QuotientMorphism. Section EqIso. Variables (gT : finGroupType) (G H : {group gT}). Hypothesis (eqGH : G :=: H). Lemma im_qisom_proof : 'N(H) \subset 'N(G). Proof. by rewrite eqGH. Qed. Lemma qisom_ker_proof : 'ker (coset G) \subset 'ker (coset H). Proof. by rewrite eqGH. Qed. Lemma qisom_restr_proof : setT \subset 'N(H) / G. Proof. by rewrite eqGH im_quotient. Qed. Definition qisom := restrm qisom_restr_proof (factm qisom_ker_proof im_qisom_proof). Canonical qisom_morphism := Eval hnf in [morphism of qisom]. Lemma qisomE x : qisom (coset G x) = coset H x. Proof. case Nx: (x \in 'N(H)); first exact: factmE. by rewrite !coset_default ?eqGH ?morph1. Qed. Lemma val_qisom Gx : val (qisom Gx) = val Gx. Proof. by case: (cosetP Gx) => x Nx ->{Gx}; rewrite qisomE /= !val_coset -?eqGH. Qed. Lemma morphim_qisom A : qisom @* (A / G) = A / H. Proof. by rewrite morphim_restrm setTI morphim_factm. Qed. Lemma morphpre_qisom A : qisom @*^-1 (A / H) = A / G. Proof. rewrite morphpre_restrm setTI morphpre_factm eqGH. by rewrite morphpreK // im_coset subsetT. Qed. Lemma injm_qisom : 'injm qisom. Proof. by rewrite -quotient1 -morphpre_qisom morphpreS ?sub1G. Qed. Lemma im_qisom : qisom @* setT = setT. Proof. by rewrite -{2}im_quotient morphim_qisom eqGH im_quotient. Qed. Lemma qisom_isom : isom setT setT qisom. Proof. by apply/isomP; rewrite injm_qisom im_qisom. Qed. Lemma qisom_isog : [set: coset_of G] \isog [set: coset_of H]. Proof. exact: isom_isog qisom_isom. Qed. Lemma qisom_inj : injective qisom. Proof. by move=> x y; apply: (injmP injm_qisom); rewrite inE. Qed. Lemma morphim_qisom_inj : injective (fun Gx => qisom @* Gx). Proof. by move=> Gx Gy; apply: injm_morphim_inj; rewrite (injm_qisom, subsetT). Qed. End EqIso. Implicit Arguments qisom_inj [gT G H]. Implicit Arguments morphim_qisom_inj [gT G H]. Section FirstIsomorphism. Variables aT rT : finGroupType. Lemma first_isom (G : {group aT}) (f : {morphism G >-> rT}) : {g : {morphism G / 'ker f >-> rT} | 'injm g & forall A : {set aT}, g @* (A / 'ker f) = f @* A}. Proof. have nkG := ker_norm f. have skk: 'ker (coset ('ker f)) \subset 'ker f by rewrite ker_coset. exists (factm_morphism skk nkG) => /=; last exact: morphim_factm. by rewrite ker_factm -quotientE trivg_quotient. Qed. Variables (G H : {group aT}) (f : {morphism G >-> rT}). Hypothesis sHG : H \subset G. Lemma first_isog : (G / 'ker f) \isog (f @* G). Proof. by case: (first_isom f) => g injg im_g; apply/isogP; exists g; rewrite ?im_g. Qed. Lemma first_isom_loc : {g : {morphism H / 'ker_H f >-> rT} | 'injm g & forall A : {set aT}, A \subset H -> g @* (A / 'ker_H f) = f @* A}. Proof. case: (first_isom (restrm_morphism sHG f)). rewrite ker_restrm => g injg im_g; exists g => // A sAH. by rewrite im_g morphim_restrm (setIidPr sAH). Qed. Lemma first_isog_loc : (H / 'ker_H f) \isog (f @* H). Proof. by case: first_isom_loc => g injg im_g; apply/isogP; exists g; rewrite ?im_g. Qed. End FirstIsomorphism. Section SecondIsomorphism. Variables (gT : finGroupType) (H K : {group gT}). Hypothesis nKH : H \subset 'N(K). Lemma second_isom : {f : {morphism H / (K :&: H) >-> coset_of K} | 'injm f & forall A : {set gT}, A \subset H -> f @* (A / (K :&: H)) = A / K}. Proof. have ->: K :&: H = 'ker_H (coset K) by rewrite ker_coset setIC. exact: first_isom_loc. Qed. Lemma second_isog : H / (K :&: H) \isog H / K. Proof. by rewrite setIC -{1 3}(ker_coset K); exact: first_isog_loc. Qed. Lemma weak_second_isog : H / (K :&: H) \isog H * K / K. Proof. by rewrite quotientMidr; exact: second_isog. Qed. End SecondIsomorphism. Section ThirdIsomorphism. Variables (gT : finGroupType) (G H K : {group gT}). Lemma homg_quotientS (A : {set gT}) : A \subset 'N(H) -> A \subset 'N(K) -> H \subset K -> A / K \homg A / H. Proof. rewrite -!(gen_subG A) /=; set L := <> => nHL nKL sKH. have sub_ker: 'ker (restrm nHL (coset H)) \subset 'ker (restrm nKL (coset K)). by rewrite !ker_restrm !ker_coset setIS. have sAL: A \subset L := subset_gen A; rewrite -(setIidPr sAL). rewrite -[_ / H](morphim_restrm nHL) -[_ / K](morphim_restrm nKL) /=. by rewrite -(morphim_factm sub_ker (subxx L)) morphim_homg ?morphimS. Qed. Hypothesis sHK : H \subset K. Hypothesis snHG : H <| G. Hypothesis snKG : K <| G. Theorem third_isom : {f : {morphism (G / H) / (K / H) >-> coset_of K} | 'injm f & forall A : {set gT}, A \subset G -> f @* (A / H / (K / H)) = A / K}. Proof. have [[sKG nKG] [sHG nHG]] := (andP snKG, andP snHG). have sHker: 'ker (coset H) \subset 'ker (restrm nKG (coset K)). by rewrite ker_restrm !ker_coset subsetI sHG. have:= first_isom_loc (factm_morphism sHker nHG) (subxx _) => /=. rewrite ker_factm_loc ker_restrm ker_coset !(setIidPr sKG) /= -!quotientE. case=> f injf im_f; exists f => // A sAG; rewrite im_f ?morphimS //. by rewrite morphim_factm morphim_restrm (setIidPr sAG). Qed. Theorem third_isog : (G / H / (K / H)) \isog (G / K). Proof. by case: third_isom => f inj_f im_f; apply/isogP; exists f; rewrite ?im_f. Qed. End ThirdIsomorphism. Lemma char_from_quotient (gT : finGroupType) (G H K : {group gT}) : H <| K -> H \char G -> K / H \char G / H -> K \char G. Proof. case/andP=> sHK nHK chHG. have nsHG := char_normal chHG; have [sHG nHG] := andP nsHG. case/charP; rewrite quotientSGK // => sKG /= chKG. apply/charP; split=> // f injf Gf; apply/morphim_fixP => //. rewrite -(quotientSGK _ sHK); last by rewrite -morphimIim Gf subIset ?nHG. have{chHG} Hf: f @* H = H by case/charP: chHG => _; apply. set q := quotm_morphism f nsHG; have{injf}: 'injm q by exact: injm_quotm. have: q @* _ = _ := morphim_quotm _ _ _; move: q; rewrite Hf => q im_q injq. by rewrite -im_q chKG // im_q Gf. Qed. (* Counting lemmas for morphisms. *) Section CardMorphism. Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}). Implicit Types G H : {group aT}. Implicit Types L M : {group rT}. Lemma card_morphim G : #|f @* G| = #|D :&: G : 'ker f|. Proof. rewrite -morphimIdom -indexgI -card_quotient; last first. by rewrite normsI ?normG ?subIset ?ker_norm. by apply: esym (card_isog _); rewrite first_isog_loc ?subsetIl. Qed. Lemma dvdn_morphim G : #|f @* G| %| #|G|. Proof. rewrite card_morphim (dvdn_trans (dvdn_indexg _ _)) //. by rewrite cardSg ?subsetIr. Qed. Lemma logn_morphim p G : logn p #|f @* G| <= logn p #|G|. Proof. by rewrite dvdn_leq_log ?dvdn_morphim. Qed. Lemma coprime_morphl G p : coprime #|G| p -> coprime #|f @* G| p. Proof. exact: coprime_dvdl (dvdn_morphim G). Qed. Lemma coprime_morphr G p : coprime p #|G| -> coprime p #|f @* G|. Proof. exact: coprime_dvdr (dvdn_morphim G). Qed. Lemma coprime_morph G H : coprime #|G| #|H| -> coprime #|f @* G| #|f @* H|. Proof. by move=> coGH; rewrite coprime_morphl // coprime_morphr. Qed. Lemma index_morphim_ker G H : H \subset G -> G \subset D -> (#|f @* G : f @* H| * #|'ker_G f : H|)%N = #|G : H|. Proof. move=> sHG sGD; apply/eqP. rewrite -(eqn_pmul2l (cardG_gt0 (f @* H))) mulnA Lagrange ?morphimS //. rewrite !card_morphim (setIidPr sGD) (setIidPr (subset_trans sHG sGD)). rewrite -(eqn_pmul2l (cardG_gt0 ('ker_H f))) /=. by rewrite -{1}(setIidPr sHG) setIAC mulnCA mulnC mulnA !LagrangeI Lagrange. Qed. Lemma index_morphim G H : G :&: H \subset D -> #|f @* G : f @* H| %| #|G : H|. Proof. move=> dGH; rewrite -(indexgI G) -(setIidPr dGH) setIA. apply: dvdn_trans (indexSg (subsetIl _ H) (subsetIr D G)). rewrite -index_morphim_ker ?subsetIl ?subsetIr ?dvdn_mulr //= morphimIdom. by rewrite indexgS ?morphimS ?subsetIr. Qed. Lemma index_injm G H : 'injm f -> G \subset D -> #|f @* G : f @* H| = #|G : H|. Proof. move=> injf dG; rewrite -{2}(setIidPr dG) -(indexgI _ H) /=. rewrite -index_morphim_ker ?subsetIl ?subsetIr //= setIAC morphimIdom setIC. rewrite injmI ?subsetIr // indexgI /= morphimIdom setIC ker_injm //. by rewrite -(indexgI (1 :&: _)) /= -setIA !(setIidPl (sub1G _)) indexgg muln1. Qed. Lemma card_morphpre L : L \subset f @* D -> #|f @*^-1 L| = (#|'ker f| * #|L|)%N. Proof. move/morphpreK=> {2} <-; rewrite card_morphim morphpreIdom. by rewrite Lagrange // morphpreS ?sub1G. Qed. Lemma index_morphpre L M : L \subset f @* D -> #|f @*^-1 L : f @*^-1 M| = #|L : M|. Proof. move=> dL; rewrite -!divgI -morphpreI card_morphpre //. have: L :&: M \subset f @* D by rewrite subIset ?dL. by move/card_morphpre->; rewrite divnMl ?cardG_gt0. Qed. End CardMorphism. Lemma card_homg (aT rT : finGroupType) (G : {group aT}) (R : {group rT}) : G \homg R -> #|G| %| #|R|. Proof. by case/homgP=> f <-; rewrite card_morphim setIid dvdn_indexg. Qed. Section CardCosetpre. Variables (gT : finGroupType) (G H K : {group gT}) (L M : {group coset_of H}). Lemma dvdn_quotient : #|G / H| %| #|G|. Proof. exact: dvdn_morphim. Qed. Lemma index_quotient_ker : K \subset G -> G \subset 'N(H) -> (#|G / H : K / H| * #|G :&: H : K|)%N = #|G : K|. Proof. by rewrite -{5}(ker_coset H); exact: index_morphim_ker. Qed. Lemma index_quotient : G :&: K \subset 'N(H) -> #|G / H : K / H| %| #|G : K|. Proof. exact: index_morphim. Qed. Lemma index_quotient_eq : G :&: H \subset K -> K \subset G -> G \subset 'N(H) -> #|G / H : K / H| = #|G : K|. Proof. move=> sGH_K sKG sGN; rewrite -index_quotient_ker {sKG sGN}//. by rewrite -(indexgI _ K) (setIidPl sGH_K) indexgg muln1. Qed. Lemma card_cosetpre : #|coset H @*^-1 L| = (#|H| * #|L|)%N. Proof. by rewrite card_morphpre ?ker_coset ?sub_im_coset. Qed. Lemma index_cosetpre : #|coset H @*^-1 L : coset H @*^-1 M| = #|L : M|. Proof. by rewrite index_morphpre ?sub_im_coset. Qed. End CardCosetpre. mathcomp-1.5/theories/cyclotomic.v0000644000175000017500000003537712307636117016356 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. Require Import fintype tuple finfun bigop prime ssralg poly finset. Require Import fingroup finalg zmodp cyclic. Require Import ssrnum ssrint polydiv rat intdiv. Require Import mxpoly vector falgebra fieldext separable galois algC. (******************************************************************************) (* This file provides few basic properties of cyclotomic polynomials. *) (* We define: *) (* cyclotomic z n == the factorization of the nth cyclotomic polynomial in *) (* a ring R in which z is an nth primitive root of unity. *) (* 'Phi_n == the nth cyclotomic polynomial in int. *) (* This library is quite limited, and should be extended in the future. In *) (* particular the irreducibity of 'Phi_n is only stated indirectly, as the *) (* fact that its embedding in the algebraics (algC) is the minimal polynomial *) (* of an nth primitive root of unity. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GRing.Theory Num.Theory. Local Open Scope ring_scope. Section CyclotomicPoly. Section Ring. Variable R : ringType. Definition cyclotomic (z : R) n := \prod_(k < n | coprime k n) ('X - (z ^+ k)%:P). Lemma cyclotomic_monic z n : cyclotomic z n \is monic. Proof. exact: monic_prod_XsubC. Qed. Lemma size_cyclotomic z n : size (cyclotomic z n) = (totient n).+1. Proof. rewrite /cyclotomic -big_filter filter_index_enum size_prod_XsubC; congr _.+1. rewrite -cardE -sum1_card totient_count_coprime -big_mkcond big_mkord. by apply: eq_bigl => k; rewrite coprime_sym. Qed. End Ring. Lemma separable_Xn_sub_1 (R : idomainType) n : n%:R != 0 :> R -> @separable_poly R ('X^n - 1). Proof. case: n => [/eqP// | n nz_n]; rewrite /separable_poly linearB /=. rewrite derivC subr0 derivXn -scaler_nat coprimep_scaler //= exprS -scaleN1r. rewrite coprimep_sym coprimep_addl_mul coprimep_scaler ?coprimep1 //. by rewrite (signr_eq0 _ 1). Qed. Section Field. Variables (F : fieldType) (n : nat) (z : F). Hypothesis prim_z : n.-primitive_root z. Let n_gt0 := prim_order_gt0 prim_z. Lemma root_cyclotomic x : root (cyclotomic z n) x = n.-primitive_root x. Proof. rewrite /cyclotomic -big_filter filter_index_enum. rewrite -(big_map _ xpredT (fun y => 'X - y%:P)) root_prod_XsubC. apply/imageP/idP=> [[k co_k_n ->] | prim_x]. by rewrite prim_root_exp_coprime. have [k Dx] := prim_rootP prim_z (prim_expr_order prim_x). exists (Ordinal (ltn_pmod k n_gt0)) => /=. by rewrite unfold_in /= coprime_modl -(prim_root_exp_coprime k prim_z) -Dx. by rewrite prim_expr_mod. Qed. Lemma prod_cyclotomic : 'X^n - 1 = \prod_(d <- divisors n) cyclotomic (z ^+ (n %/ d)) d. Proof. have in_d d: (d %| n)%N -> val (@inord n d) = d by move/dvdn_leq/inordK=> /= ->. have dv_n k: (n %/ gcdn k n %| n)%N. by rewrite -{3}(divnK (dvdn_gcdr k n)) dvdn_mulr. have [uDn _ inDn] := divisors_correct n_gt0. have defDn: divisors n = map val (map (@inord n) (divisors n)). by rewrite -map_comp map_id_in // => d; rewrite inDn => /in_d. rewrite defDn big_map big_uniq /=; last first. by rewrite -(map_inj_uniq val_inj) -defDn. pose h (k : 'I_n) : 'I_n.+1 := inord (n %/ gcdn k n). rewrite -(factor_Xn_sub_1 prim_z) big_mkord. rewrite (partition_big h (dvdn^~ n)) /= => [|k _]; last by rewrite in_d ?dv_n. apply: eq_big => d; first by rewrite -(mem_map val_inj) -defDn inDn. set q := (n %/ d)%N => d_dv_n. have [q_gt0 d_gt0]: (0 < q /\ 0 < d)%N by apply/andP; rewrite -muln_gt0 divnK. have fP (k : 'I_d): (q * k < n)%N by rewrite divn_mulAC ?ltn_divLR ?ltn_pmul2l. rewrite (reindex (fun k => Ordinal (fP k))); last first. have f'P (k : 'I_n): (k %/ q < d)%N by rewrite ltn_divLR // mulnC divnK. exists (fun k => Ordinal (f'P k)) => [k _ | k /eqnP/=]. by apply: val_inj; rewrite /= mulKn. rewrite in_d // => Dd; apply: val_inj; rewrite /= mulnC divnK // /q -Dd. by rewrite divnA ?mulKn ?dvdn_gcdl ?dvdn_gcdr. apply: eq_big => k; rewrite ?exprM // -val_eqE in_d //=. rewrite -eqn_mul ?dvdn_gcdr ?gcdn_gt0 ?n_gt0 ?orbT //. rewrite -[n in gcdn _ n](divnK d_dv_n) -muln_gcdr mulnCA mulnA divnK //. by rewrite mulnC eqn_mul // divnn n_gt0 eq_sym. Qed. End Field. End CyclotomicPoly. Local Notation ZtoQ := (intr : int -> rat). Local Notation ZtoC := (intr : int -> algC). Local Notation QtoC := (ratr : rat -> algC). Local Notation intrp := (map_poly intr). Local Notation pZtoQ := (map_poly ZtoQ). Local Notation pZtoC := (map_poly ZtoC). Local Notation pQtoC := (map_poly ratr). Local Hint Resolve (@intr_inj [numDomainType of algC]). Local Notation QtoC_M := (ratr_rmorphism [numFieldType of algC]). Lemma C_prim_root_exists n : (n > 0)%N -> {z : algC | n.-primitive_root z}. Proof. pose p : {poly algC} := 'X^n - 1; have [r Dp] := closed_field_poly_normal p. move=> n_gt0; apply/sigW; rewrite (monicP _) ?monic_Xn_sub_1 // scale1r in Dp. have rn1: all n.-unity_root r by apply/allP=> z; rewrite -root_prod_XsubC -Dp. have sz_r: (n < (size r).+1)%N. by rewrite -(size_prod_XsubC r id) -Dp size_Xn_sub_1. have [|z] := hasP (has_prim_root n_gt0 rn1 _ sz_r); last by exists z. by rewrite -separable_prod_XsubC -Dp separable_Xn_sub_1 // pnatr_eq0 -lt0n. Qed. (* (Integral) Cyclotomic polynomials. *) Definition Cyclotomic n : {poly int} := let: exist z _ := C_prim_root_exists (ltn0Sn n.-1) in map_poly floorC (cyclotomic z n). Notation "''Phi_' n" := (Cyclotomic n) (at level 8, n at level 2, format "''Phi_' n"). Lemma Cyclotomic_monic n : 'Phi_n \is monic. Proof. rewrite /'Phi_n; case: (C_prim_root_exists _) => z /= _. rewrite monicE lead_coefE coef_map_id0 ?(int_algC_K 0) ?getCint0 //. by rewrite size_poly_eq -lead_coefE (monicP (cyclotomic_monic _ _)) (intCK 1). Qed. Lemma Cintr_Cyclotomic n z : n.-primitive_root z -> pZtoC 'Phi_n = cyclotomic z n. Proof. elim: {n}_.+1 {-2}n z (ltnSn n) => // m IHm n z0 le_mn prim_z0. rewrite /'Phi_n; case: (C_prim_root_exists _) => z /=. have n_gt0 := prim_order_gt0 prim_z0; rewrite prednK // => prim_z. have [uDn _ inDn] := divisors_correct n_gt0. pose q := \prod_(d <- rem n (divisors n)) 'Phi_d. have mon_q: q \is monic by apply: monic_prod => d _; exact: Cyclotomic_monic. have defXn1: cyclotomic z n * pZtoC q = 'X^n - 1. rewrite (prod_cyclotomic prim_z) (big_rem n) ?inDn //=. rewrite divnn n_gt0 rmorph_prod /=; congr (_ * _). apply: eq_big_seq => d; rewrite mem_rem_uniq ?inE //= inDn => /andP[n'd ddvn]. rewrite -IHm ?dvdn_prim_root // -ltnS (leq_ltn_trans _ le_mn) //. by rewrite ltn_neqAle n'd dvdn_leq. have mapXn1 (R1 R2 : ringType) (f : {rmorphism R1 -> R2}): map_poly f ('X^n - 1) = 'X^n - 1. - by rewrite rmorphB /= rmorph1 map_polyXn. have nz_q: pZtoC q != 0. by rewrite -size_poly_eq0 size_map_inj_poly // size_poly_eq0 monic_neq0. have [r def_zn]: exists r, cyclotomic z n = pZtoC r. have defZtoC: ZtoC =1 QtoC \o ZtoQ by move=> a; rewrite /= rmorph_int. have /dvdpP[r0 Dr0]: map_poly ZtoQ q %| 'X^n - 1. rewrite -(dvdp_map QtoC_M) mapXn1 -map_poly_comp. by rewrite -(eq_map_poly defZtoC) -defXn1 dvdp_mull. have [r [a nz_a Dr]] := rat_poly_scale r0. exists (zprimitive r); apply: (mulIf nz_q); rewrite defXn1. rewrite -rmorphM -(zprimitive_monic mon_q) -zprimitiveM /=. have ->: r * q = a *: ('X^n - 1). apply: (map_inj_poly (intr_inj : injective ZtoQ)) => //. rewrite map_polyZ mapXn1 Dr0 Dr -scalerAl scalerKV ?intr_eq0 //. by rewrite rmorphM. by rewrite zprimitiveZ // zprimitive_monic ?monic_Xn_sub_1 ?mapXn1. rewrite floorCpK; last by apply/polyOverP=> i; rewrite def_zn coef_map Cint_int. pose f e (k : 'I_n) := Ordinal (ltn_pmod (k * e) n_gt0). have [e Dz0] := prim_rootP prim_z (prim_expr_order prim_z0). have co_e_n: coprime e n by rewrite -(prim_root_exp_coprime e prim_z) -Dz0. have injf: injective (f e). apply: can_inj (f (egcdn e n).1) _ => k; apply: val_inj => /=. rewrite modnMml -mulnA -modnMmr -{1}(mul1n e). by rewrite (chinese_modr co_e_n 0) modnMmr muln1 modn_small. rewrite [_ n](reindex_inj injf); apply: eq_big => k /=. by rewrite coprime_modl coprime_mull co_e_n andbT. by rewrite prim_expr_mod // mulnC exprM -Dz0. Qed. Lemma prod_Cyclotomic n : (n > 0)%N -> \prod_(d <- divisors n) 'Phi_d = 'X^n - 1. Proof. move=> n_gt0; have [z prim_z] := C_prim_root_exists n_gt0. apply: (map_inj_poly (intr_inj : injective ZtoC)) => //. rewrite rmorphB rmorph1 rmorph_prod /= map_polyXn (prod_cyclotomic prim_z). apply: eq_big_seq => d; rewrite -dvdn_divisors // => d_dv_n. by rewrite -Cintr_Cyclotomic ?dvdn_prim_root. Qed. Lemma Cyclotomic0 : 'Phi_0 = 1. Proof. rewrite /'Phi_0; case: (C_prim_root_exists _) => z /= _. by rewrite -[1]polyseqK /cyclotomic big_ord0 map_polyE !polyseq1 /= (intCK 1). Qed. Lemma size_Cyclotomic n : size 'Phi_n = (totient n).+1. Proof. have [-> | n_gt0] := posnP n; first by rewrite Cyclotomic0 polyseq1. have [z prim_z] := C_prim_root_exists n_gt0. rewrite -(size_map_inj_poly (can_inj intCK)) //. rewrite (Cintr_Cyclotomic prim_z) -[_ n]big_filter filter_index_enum. rewrite size_prod_XsubC -cardE totient_count_coprime big_mkord -big_mkcond /=. by rewrite (eq_card (fun _ => coprime_sym _ _)) sum1_card. Qed. Lemma minCpoly_cyclotomic n z : n.-primitive_root z -> minCpoly z = cyclotomic z n. Proof. move=> prim_z; have n_gt0 := prim_order_gt0 prim_z. have Dpz := Cintr_Cyclotomic prim_z; set pz := cyclotomic z n in Dpz *. have mon_pz: pz \is monic by exact: cyclotomic_monic. have pz0: root pz z by rewrite root_cyclotomic. have [pf [Dpf mon_pf] dv_pf] := minCpolyP z. have /dvdpP_rat_int[f [af nz_af Df] [g /esym Dfg]]: pf %| pZtoQ 'Phi_n. rewrite -dv_pf; congr (root _ z): pz0; rewrite -Dpz -map_poly_comp. by apply: eq_map_poly => b; rewrite /= rmorph_int. without loss{nz_af} [mon_f mon_g]: af f g Df Dfg / f \is monic /\ g \is monic. move=> IH; pose cf := lead_coef f; pose cg := lead_coef g. have cfg1: cf * cg = 1. by rewrite -lead_coefM Dfg (monicP (Cyclotomic_monic n)). apply: (IH (af *~ cf) (f *~ cg) (g *~ cf)). - by rewrite rmorphMz -scalerMzr scalerMzl -mulrzA cfg1. - by rewrite mulrzAl mulrzAr -mulrzA cfg1. by rewrite !(intz, =^~ scaler_int) !monicE !lead_coefZ mulrC cfg1. have{af Df} Df: pQtoC pf = pZtoC f. have:= congr1 lead_coef Df. rewrite lead_coefZ lead_coef_map_inj //; last exact: intr_inj. rewrite !(monicP _) // mulr1 Df => <-; rewrite scale1r -map_poly_comp. by apply: eq_map_poly => b; rewrite /= rmorph_int. have [/size1_polyC Dg | g_gt1] := leqP (size g) 1. rewrite monicE Dg lead_coefC in mon_g. by rewrite -Dpz -Dfg Dg (eqP mon_g) mulr1 Dpf. have [zk gzk0]: exists zk, root (pZtoC g) zk. have [rg] := closed_field_poly_normal (pZtoC g). rewrite lead_coef_map_inj // (monicP mon_g) scale1r => Dg. rewrite -(size_map_inj_poly (can_inj intCK)) // Dg in g_gt1. rewrite size_prod_XsubC in g_gt1. by exists rg`_0; rewrite Dg root_prod_XsubC mem_nth. have [k cokn Dzk]: exists2 k, coprime k n & zk = z ^+ k. have: root pz zk by rewrite -Dpz -Dfg rmorphM rootM gzk0 orbT. rewrite -[pz]big_filter -(big_map _ xpredT (fun a => 'X - a%:P)). by rewrite root_prod_XsubC => /imageP[k]; exists k. have co_fg (R : idomainType): n%:R != 0 :> R -> @coprimep R (intrp f) (intrp g). move=> nz_n; have: separable_poly (intrp ('X^n - 1) : {poly R}). by rewrite rmorphB rmorph1 /= map_polyXn separable_Xn_sub_1. rewrite -prod_Cyclotomic // (big_rem n) -?dvdn_divisors //= -Dfg. by rewrite !rmorphM /= !separable_mul => /and3P[] /and3P[]. suffices fzk0: root (pZtoC f) zk. have [] // := negP (coprimep_root (co_fg _ _) fzk0). by rewrite pnatr_eq0 -lt0n. move: gzk0 cokn; rewrite {zk}Dzk; elim: {k}_.+1 {-2}k (ltnSn k) => // m IHm k. rewrite ltnS => lekm gzk0 cokn. have [|k_gt1] := leqP k 1; last have [p p_pr /dvdnP[k1 Dk]] := pdivP k_gt1. rewrite -[leq k 1](mem_iota 0 2) !inE => /pred2P[k0 | ->]; last first. by rewrite -Df dv_pf. have /eqP := size_Cyclotomic n; rewrite -Dfg size_Mmonic ?monic_neq0 //. rewrite k0 /coprime gcd0n in cokn; rewrite (eqP cokn). rewrite -(size_map_inj_poly (can_inj intCK)) // -Df -Dpf. by rewrite -(subnKC g_gt1) -(subnKC (size_minCpoly z)) !addnS. move: cokn; rewrite Dk coprime_mull => /andP[cok1n]. rewrite prime_coprime // (dvdn_charf (char_Fp p_pr)) => /co_fg {co_fg}. have charFpX: p \in [char {poly 'F_p}]. by rewrite (rmorph_char (polyC_rmorphism _)) ?char_Fp. rewrite -(coprimep_pexpr _ _ (prime_gt0 p_pr)) -(Frobenius_autE charFpX). rewrite -[g]comp_polyXr map_comp_poly -horner_map /= Frobenius_autE -rmorphX. rewrite -!map_poly_comp (@eq_map_poly _ _ _ (polyC \o *~%R 1)); last first. by move=> a; rewrite /= !rmorph_int. rewrite map_poly_comp -[_.[_]]map_comp_poly /= => co_fg. suffices: coprimep (pZtoC f) (pZtoC (g \Po 'X^p)). move/coprimep_root=> /=/(_ (z ^+ k1))/implyP. rewrite map_comp_poly map_polyXn horner_comp hornerXn. rewrite -exprM -Dk [_ == 0]gzk0 implybF => /negP[]. have: root pz (z ^+ k1). by rewrite root_cyclotomic // prim_root_exp_coprime. rewrite -Dpz -Dfg rmorphM rootM => /orP[] //= /IHm-> //. rewrite (leq_trans _ lekm) // -[k1]muln1 Dk ltn_pmul2l ?prime_gt1 //. by have:= ltnW k_gt1; rewrite Dk muln_gt0 => /andP[]. suffices: coprimep f (g \Po 'X^p). case/Bezout_coprimepP=> [[u v]]; rewrite -size_poly_eq1. rewrite -(size_map_inj_poly (can_inj intCK)) // rmorphD !rmorphM /=. rewrite size_poly_eq1 => {co_fg}co_fg; apply/Bezout_coprimepP. by exists (pZtoC u, pZtoC v). apply: contraLR co_fg => /coprimepPn[|d]; first exact: monic_neq0. rewrite andbC -size_poly_eq1 dvdp_gcd => /and3P[sz_d]. pose d1 := zprimitive d. have d_dv_mon h: d %| h -> h \is monic -> exists h1, h = d1 * h1. case/Pdiv.Idomain.dvdpP=> [[c h1] /= nz_c Dh] mon_h; exists (zprimitive h1). by rewrite -zprimitiveM mulrC -Dh zprimitiveZ ?zprimitive_monic. case/d_dv_mon=> // f1 Df1 /d_dv_mon[|f2 ->]. rewrite monicE lead_coefE size_comp_poly size_polyXn /=. rewrite comp_polyE coef_sum polySpred ?monic_neq0 //= mulnC. rewrite big_ord_recr /= -lead_coefE (monicP mon_g) scale1r. rewrite -exprM coefXn eqxx big1 ?add0r // => i _. rewrite coefZ -exprM coefXn eqn_pmul2l ?prime_gt0 //. by rewrite eqn_leq leqNgt ltn_ord mulr0. have monFp h: h \is monic -> size (map_poly intr h) = size h. by move=> mon_h; rewrite size_poly_eq // -lead_coefE (monicP mon_h) oner_eq0. apply/coprimepPn; last exists (map_poly intr d1). by rewrite -size_poly_eq0 monFp // size_poly_eq0 monic_neq0. rewrite Df1 !rmorphM dvdp_gcd !dvdp_mulr //= -size_poly_eq1. rewrite monFp ?size_zprimitive //. rewrite monicE [_ d1]intEsg sgz_lead_primitive -zprimitive_eq0 -/d1. rewrite -lead_coef_eq0 -absz_eq0. have/esym/eqP := congr1 (absz \o lead_coef) Df1. by rewrite /= (monicP mon_f) lead_coefM abszM muln_eq1 => /andP[/eqP-> _]. Qed. mathcomp-1.5/theories/generic_quotient.v0000644000175000017500000006601112307636117017542 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) (* -*- coding : utf-8 -*- *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat choice seq fintype. (*****************************************************************************) (* Provided a base type T, this files defines an interface for quotients Q *) (* of the type T with explicit functions for canonical surjection (\pi *) (* : T -> Q) and for choosing a representative (repr : Q -> T). It then *) (* provide a helper to quotient T by a decidable equivalence relation (e *) (* : rel T) if T is a choiceType (or encodable as a choiceType modulo e). *) (* *) (* See "Pragamatic Quotient Types in Coq", proceedings of ITP2013, *) (* by Cyril Cohen. *) (* *) (* *** Generic Quotienting *** *) (* QuotClass (reprK : cancel repr pi) == builds the quotient which *) (* canonical surjection function is pi and which *) (* representative selection function is repr. *) (* QuotType Q class == packs the quotClass class to build a quotType *) (* You may declare such elements as Canonical *) (* \pi_Q x == the class in Q of the element x of T *) (* \pi x == the class of x where Q is inferred from the context *) (* repr c == canonical representative in T of the class c *) (* [quotType of Q] == clone of the canonical quotType structure of Q on T *) (* x = y %[mod Q] := \pi_Q x = \pi_Q y *) (* <-> x and y are equal modulo Q *) (* x <> y %[mod Q] := \pi_Q x <> \pi_Q y *) (* x == y %[mod Q] := \pi_Q x == \pi_Q y *) (* x != y %[mod Q] := \pi_Q x != \pi_Q y *) (* *) (* The quotient_scope is delimited by %qT *) (* The most useful lemmas are piE and reprK *) (* *) (* *** Morphisms *** *) (* One may declare existing functions and predicates as liftings of some *) (* morphisms for a quotient. *) (* PiMorph1 pi_f == where pi_f : {morph \pi : x / f x >-> fq x} *) (* declares fq : Q -> Q as the lifting of f : T -> T *) (* PiMorph2 pi_g == idem with pi_g : {morph \pi : x y / g x y >-> gq x y} *) (* PiMono1 pi_p == idem with pi_p : {mono \pi : x / p x >-> pq x} *) (* PiMono2 pi_r == idem with pi_r : {morph \pi : x y / r x y >-> rq x y} *) (* PiMorph11 pi_f == idem with pi_f : {morph \pi : x / f x >-> fq x} *) (* where fq : Q -> Q' and f : T -> T'. *) (* PiMorph eq == Most general declaration of compatibility, *) (* /!\ use with caution /!\ *) (* One can use the following helpers to build the liftings which may or *) (* may not satisfy the above properties (but if they do not, it is *) (* probably not a good idea to define them): *) (* lift_op1 Q f := lifts f : T -> T *) (* lift_op2 Q g := lifts g : T -> T -> T *) (* lift_fun1 Q p := lifts p : T -> R *) (* lift_fun2 Q r := lifts r : T -> T -> R *) (* lift_op11 Q Q' f := lifts f : T -> T' *) (* There is also the special case of constants and embedding functions *) (* that one may define and declare as compatible with Q using: *) (* lift_cst Q x := lifts x : T to Q *) (* PiConst c := declare the result c of the previous construction as *) (* compatible with Q *) (* lift_embed Q e := lifts e : R -> T to R -> Q *) (* PiEmbed f := declare the result f of the previous construction as *) (* compatible with Q *) (* *) (* *** Quotients that have an eqType structure *** *) (* Having a canonical (eqQuotType e) structure enables piE to replace terms *) (* of the form (x == y) by terms of the form (e x' y') if x and y are *) (* canonical surjections of some x' and y'. *) (* EqQuotType e Q m == builds an (eqQuotType e) structure on Q from the *) (* morphism property m *) (* where m : {mono \pi : x y / e x y >-> x == y} *) (* [eqQuotType of Q] == clones the canonical eqQuotType structure of Q *) (* *) (* *** Equivalence and quotient by an equivalence *** *) (* EquivRel r er es et == builds an equiv_rel structure based on the *) (* reflexivity, symmetry and transitivity property *) (* of a boolean relation. *) (* {eq_quot e} == builds the quotType of T by equiv *) (* where e : rel T is an equiv_rel *) (* and T is a choiceType or a (choiceTypeMod e) *) (* it is canonically an eqType, a choiceType, *) (* a quotType and an eqQuotType. *) (* x = y %[mod_eq e] := x = y %[mod {eq_quot e}] *) (* <-> x and y are equal modulo e *) (* ... *) (*****************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Reserved Notation "\pi_ Q" (at level 0, format "\pi_ Q"). Reserved Notation "\pi" (at level 0, format "\pi"). Reserved Notation "{pi_ Q a }" (at level 0, Q at next level, format "{pi_ Q a }"). Reserved Notation "{pi a }" (at level 0, format "{pi a }"). Reserved Notation "x == y %[mod_eq e ]" (at level 70, y at next level, no associativity, format "'[hv ' x '/' == y '/' %[mod_eq e ] ']'"). Reserved Notation "x = y %[mod_eq e ]" (at level 70, y at next level, no associativity, format "'[hv ' x '/' = y '/' %[mod_eq e ] ']'"). Reserved Notation "x != y %[mod_eq e ]" (at level 70, y at next level, no associativity, format "'[hv ' x '/' != y '/' %[mod_eq e ] ']'"). Reserved Notation "x <> y %[mod_eq e ]" (at level 70, y at next level, no associativity, format "'[hv ' x '/' <> y '/' %[mod_eq e ] ']'"). Reserved Notation "{eq_quot e }" (at level 0, T at level 0, format "{eq_quot e }", only parsing). Delimit Scope quotient_scope with qT. Local Open Scope quotient_scope. (*****************************************) (* Definition of the quotient interface. *) (*****************************************) Section QuotientDef. Variable T : Type. Record quot_mixin_of qT := QuotClass { quot_repr : qT -> T; quot_pi : T -> qT; _ : cancel quot_repr quot_pi }. Notation quot_class_of := quot_mixin_of. Record quotType := QuotTypePack { quot_sort :> Type; quot_class : quot_class_of quot_sort; _ : Type }. Definition QuotType_pack qT m := @QuotTypePack qT m qT. Variable qT : quotType. Definition pi_phant of phant qT := quot_pi (quot_class qT). Local Notation "\pi" := (pi_phant (Phant qT)). Definition repr_of := quot_repr (quot_class qT). Lemma repr_ofK : cancel repr_of \pi. Proof. by rewrite /pi_phant /repr_of /=; case:qT=> [? []]. Qed. Definition QuotType_clone (Q : Type) qT cT of phant_id (quot_class qT) cT := @QuotTypePack Q cT Q. End QuotientDef. (****************************) (* Protecting some symbols. *) (****************************) Module Type PiSig. Parameter f : forall (T : Type) (qT : quotType T), phant qT -> T -> qT. Axiom E : f = pi_phant. End PiSig. Module Pi : PiSig. Definition f := pi_phant. Definition E := erefl f. End Pi. Module MPi : PiSig. Definition f := pi_phant. Definition E := erefl f. End MPi. Module Type ReprSig. Parameter f : forall (T : Type) (qT : quotType T), qT -> T. Axiom E : f = repr_of. End ReprSig. Module Repr : ReprSig. Definition f := repr_of. Definition E := erefl f. End Repr. (*******************) (* Fancy Notations *) (*******************) Notation repr := Repr.f. Notation "\pi_ Q" := (@Pi.f _ _ (Phant Q)) : quotient_scope. Notation "\pi" := (@Pi.f _ _ (Phant _)) (only parsing) : quotient_scope. Notation "x == y %[mod Q ]" := (\pi_Q x == \pi_Q y) : quotient_scope. Notation "x = y %[mod Q ]" := (\pi_Q x = \pi_Q y) : quotient_scope. Notation "x != y %[mod Q ]" := (\pi_Q x != \pi_Q y) : quotient_scope. Notation "x <> y %[mod Q ]" := (\pi_Q x <> \pi_Q y) : quotient_scope. Local Notation "\mpi" := (@MPi.f _ _ (Phant _)). Canonical mpi_unlock := Unlockable MPi.E. Canonical pi_unlock := Unlockable Pi.E. Canonical repr_unlock := Unlockable Repr.E. Notation quot_class_of := quot_mixin_of. Notation QuotType Q m := (@QuotType_pack _ Q m). Notation "[ 'quotType' 'of' Q ]" := (@QuotType_clone _ Q _ _ id) (at level 0, format "[ 'quotType' 'of' Q ]") : form_scope. Implicit Arguments repr [T qT]. Prenex Implicits repr. (************************) (* Exporting the theory *) (************************) Section QuotTypeTheory. Variable T : Type. Variable qT : quotType T. Lemma reprK : cancel repr \pi_qT. Proof. by move=> x; rewrite !unlock repr_ofK. Qed. CoInductive pi_spec (x : T) : T -> Type := PiSpec y of x = y %[mod qT] : pi_spec x y. Lemma piP (x : T) : pi_spec x (repr (\pi_qT x)). Proof. by constructor; rewrite reprK. Qed. Lemma mpiE : \mpi =1 \pi_qT. Proof. by move=> x; rewrite !unlock. Qed. Lemma quotW P : (forall y : T, P (\pi_qT y)) -> forall x : qT, P x. Proof. by move=> Py x; rewrite -[x]reprK; apply: Py. Qed. Lemma quotP P : (forall y : T, repr (\pi_qT y) = y -> P (\pi_qT y)) -> forall x : qT, P x. Proof. by move=> Py x; rewrite -[x]reprK; apply: Py; rewrite reprK. Qed. End QuotTypeTheory. (*******************) (* About morphisms *) (*******************) (* This was pi_morph T (x : T) := PiMorph { pi_op : T; _ : x = pi_op }. *) Structure equal_to T (x : T) := EqualTo { equal_val : T; _ : x = equal_val }. Lemma equal_toE (T : Type) (x : T) (m : equal_to x) : equal_val m = x. Proof. by case: m. Qed. Notation piE := (@equal_toE _ _). Canonical equal_to_pi T (qT : quotType T) (x : T) := @EqualTo _ (\pi_qT x) (\pi x) (erefl _). Implicit Arguments EqualTo [T x equal_val]. Prenex Implicits EqualTo. Section Morphism. Variables T U : Type. Variable (qT : quotType T). Variable (qU : quotType U). Variable (f : T -> T) (g : T -> T -> T) (p : T -> U) (r : T -> T -> U). Variable (fq : qT -> qT) (gq : qT -> qT -> qT) (pq : qT -> U) (rq : qT -> qT -> U). Variable (h : T -> U) (hq : qT -> qU). Hypothesis pi_f : {morph \pi : x / f x >-> fq x}. Hypothesis pi_g : {morph \pi : x y / g x y >-> gq x y}. Hypothesis pi_p : {mono \pi : x / p x >-> pq x}. Hypothesis pi_r : {mono \pi : x y / r x y >-> rq x y}. Hypothesis pi_h : forall (x : T), \pi_qU (h x) = hq (\pi_qT x). Variables (a b : T) (x : equal_to (\pi_qT a)) (y : equal_to (\pi_qT b)). (* Internal Lemmmas : do not use directly *) Lemma pi_morph1 : \pi (f a) = fq (equal_val x). Proof. by rewrite !piE. Qed. Lemma pi_morph2 : \pi (g a b) = gq (equal_val x) (equal_val y). Proof. by rewrite !piE. Qed. Lemma pi_mono1 : p a = pq (equal_val x). Proof. by rewrite !piE. Qed. Lemma pi_mono2 : r a b = rq (equal_val x) (equal_val y). Proof. by rewrite !piE. Qed. Lemma pi_morph11 : \pi (h a) = hq (equal_val x). Proof. by rewrite !piE. Qed. End Morphism. Implicit Arguments pi_morph1 [T qT f fq]. Implicit Arguments pi_morph2 [T qT g gq]. Implicit Arguments pi_mono1 [T U qT p pq]. Implicit Arguments pi_mono2 [T U qT r rq]. Implicit Arguments pi_morph11 [T U qT qU h hq]. Prenex Implicits pi_morph1 pi_morph2 pi_mono1 pi_mono2 pi_morph11. Notation "{pi_ Q a }" := (equal_to (\pi_Q a)) : quotient_scope. Notation "{pi a }" := (equal_to (\pi a)) : quotient_scope. (* Declaration of morphisms *) Notation PiMorph pi_x := (EqualTo pi_x). Notation PiMorph1 pi_f := (fun a (x : {pi a}) => EqualTo (pi_morph1 pi_f a x)). Notation PiMorph2 pi_g := (fun a b (x : {pi a}) (y : {pi b}) => EqualTo (pi_morph2 pi_g a b x y)). Notation PiMono1 pi_p := (fun a (x : {pi a}) => EqualTo (pi_mono1 pi_p a x)). Notation PiMono2 pi_r := (fun a b (x : {pi a}) (y : {pi b}) => EqualTo (pi_mono2 pi_r a b x y)). Notation PiMorph11 pi_f := (fun a (x : {pi a}) => EqualTo (pi_morph11 pi_f a x)). (* lifiting helpers *) Notation lift_op1 Q f := (locked (fun x : Q => \pi_Q (f (repr x)) : Q)). Notation lift_op2 Q g := (locked (fun x y : Q => \pi_Q (g (repr x) (repr y)) : Q)). Notation lift_fun1 Q f := (locked (fun x : Q => f (repr x))). Notation lift_fun2 Q g := (locked (fun x y : Q => g (repr x) (repr y))). Notation lift_op11 Q Q' f := (locked (fun x : Q => \pi_Q' (f (repr x)) : Q')). (* constant declaration *) Notation lift_cst Q x := (locked (\pi_Q x : Q)). Notation PiConst a := (@EqualTo _ _ a (lock _)). (* embedding declaration, please don't redefine \pi *) Notation lift_embed qT e := (locked (fun x => \pi_qT (e x) : qT)). Lemma eq_lock T T' e : e =1 (@locked (T -> T') (fun x : T => e x)). Proof. by rewrite -lock. Qed. Prenex Implicits eq_lock. Notation PiEmbed e := (fun x => @EqualTo _ _ (e x) (eq_lock (fun _ => \pi _) _)). (********************) (* About eqQuotType *) (********************) Section EqQuotTypeStructure. Variable T : Type. Variable eq_quot_op : rel T. Definition eq_quot_mixin_of (Q : Type) (qc : quot_class_of T Q) (ec : Equality.class_of Q) := {mono \pi_(QuotTypePack qc Q) : x y / eq_quot_op x y >-> @eq_op (Equality.Pack ec Q) x y}. Record eq_quot_class_of (Q : Type) : Type := EqQuotClass { eq_quot_quot_class :> quot_class_of T Q; eq_quot_eq_mixin :> Equality.class_of Q; pi_eq_quot_mixin :> eq_quot_mixin_of eq_quot_quot_class eq_quot_eq_mixin }. Record eqQuotType : Type := EqQuotTypePack { eq_quot_sort :> Type; _ : eq_quot_class_of eq_quot_sort; _ : Type }. Implicit Type eqT : eqQuotType. Definition eq_quot_class eqT : eq_quot_class_of eqT := let: EqQuotTypePack _ cT _ as qT' := eqT return eq_quot_class_of qT' in cT. Canonical eqQuotType_eqType eqT := EqType eqT (eq_quot_class eqT). Canonical eqQuotType_quotType eqT := QuotType eqT (eq_quot_class eqT). Coercion eqQuotType_eqType : eqQuotType >-> eqType. Coercion eqQuotType_quotType : eqQuotType >-> quotType. Definition EqQuotType_pack Q := fun (qT : quotType T) (eT : eqType) qc ec of phant_id (quot_class qT) qc & phant_id (Equality.class eT) ec => fun m => EqQuotTypePack (@EqQuotClass Q qc ec m) Q. Definition EqQuotType_clone (Q : Type) eqT cT of phant_id (eq_quot_class eqT) cT := @EqQuotTypePack Q cT Q. Lemma pi_eq_quot eqT : {mono \pi_eqT : x y / eq_quot_op x y >-> x == y}. Proof. by case: eqT => [] ? []. Qed. Canonical pi_eq_quot_mono eqT := PiMono2 (pi_eq_quot eqT). End EqQuotTypeStructure. Notation EqQuotType e Q m := (@EqQuotType_pack _ e Q _ _ _ _ id id m). Notation "[ 'eqQuotType' e 'of' Q ]" := (@EqQuotType_clone _ e Q _ _ id) (at level 0, format "[ 'eqQuotType' e 'of' Q ]") : form_scope. (**************************************************************************) (* Even if a quotType is a natural subType, we do not make this subType *) (* canonical, to allow the user to define the subtyping he wants. However *) (* one can: *) (* - get the eqMixin and the choiceMixin by subtyping *) (* - get the subType structure and maybe declare it Canonical. *) (**************************************************************************) Module QuotSubType. Section SubTypeMixin. Variable T : eqType. Variable qT : quotType T. Definition Sub x (px : repr (\pi_qT x) == x) := \pi_qT x. Lemma qreprK x Px : repr (@Sub x Px) = x. Proof. by rewrite /Sub (eqP Px). Qed. Lemma sortPx (x : qT) : repr (\pi_qT (repr x)) == repr x. Proof. by rewrite !reprK eqxx. Qed. Lemma sort_Sub (x : qT) : x = Sub (sortPx x). Proof. by rewrite /Sub reprK. Qed. Lemma reprP K (PK : forall x Px, K (@Sub x Px)) u : K u. Proof. by rewrite (sort_Sub u); apply: PK. Qed. Canonical subType := SubType _ _ _ reprP qreprK. Definition eqMixin := Eval hnf in [eqMixin of qT by <:]. Canonical eqType := EqType qT eqMixin. End SubTypeMixin. Definition choiceMixin (T : choiceType) (qT : quotType T) := Eval hnf in [choiceMixin of qT by <:]. Canonical choiceType (T : choiceType) (qT : quotType T) := ChoiceType qT (@choiceMixin T qT). Definition countMixin (T : countType) (qT : quotType T) := Eval hnf in [countMixin of qT by <:]. Canonical countType (T : countType) (qT : quotType T) := CountType qT (@countMixin T qT). Section finType. Variables (T : finType) (qT : quotType T). Canonical subCountType := [subCountType of qT]. Definition finMixin := Eval hnf in [finMixin of qT by <:]. End finType. End QuotSubType. Notation "[ 'subType' Q 'of' T 'by' %/ ]" := (@SubType T _ Q _ _ (@QuotSubType.reprP _ _) (@QuotSubType.qreprK _ _)) (at level 0, format "[ 'subType' Q 'of' T 'by' %/ ]") : form_scope. Notation "[ 'eqMixin' 'of' Q 'by' <:%/ ]" := (@QuotSubType.eqMixin _ _: Equality.class_of Q) (at level 0, format "[ 'eqMixin' 'of' Q 'by' <:%/ ]") : form_scope. Notation "[ 'choiceMixin' 'of' Q 'by' <:%/ ]" := (@QuotSubType.choiceMixin _ _: Choice.mixin_of Q) (at level 0, format "[ 'choiceMixin' 'of' Q 'by' <:%/ ]") : form_scope. Notation "[ 'countMixin' 'of' Q 'by' <:%/ ]" := (@QuotSubType.countMixin _ _: Countable.mixin_of Q) (at level 0, format "[ 'countMixin' 'of' Q 'by' <:%/ ]") : form_scope. Notation "[ 'finMixin' 'of' Q 'by' <:%/ ]" := (@QuotSubType.finMixin _ _: Finite.mixin_of Q) (at level 0, format "[ 'finMixin' 'of' Q 'by' <:%/ ]") : form_scope. (****************************************************) (* Definition of a (decidable) equivalence relation *) (****************************************************) Section EquivRel. Variable T : Type. Lemma left_trans (e : rel T) : symmetric e -> transitive e -> left_transitive e. Proof. by move=> s t ? * ?; apply/idP/idP; apply: t; rewrite // s. Qed. Lemma right_trans (e : rel T) : symmetric e -> transitive e -> right_transitive e. Proof. by move=> s t ? * x; rewrite ![e x _]s; apply: left_trans. Qed. Record equiv_class_of (equiv : rel T) := EquivClass of reflexive equiv & symmetric equiv & transitive equiv. Record equiv_rel := EquivRelPack { equiv :> rel T; _ : equiv_class_of equiv }. Variable e : equiv_rel. Definition equiv_class := let: EquivRelPack _ ce as e' := e return equiv_class_of e' in ce. Definition equiv_pack (r : rel T) ce of phant_id ce equiv_class := @EquivRelPack r ce. Lemma equiv_refl x : e x x. Proof. by case: e => [] ? []. Qed. Lemma equiv_sym : symmetric e. Proof. by case: e => [] ? []. Qed. Lemma equiv_trans : transitive e. Proof. by case: e => [] ? []. Qed. Lemma eq_op_trans (T' : eqType) : transitive (@eq_op T'). Proof. by move=> x y z; move/eqP->; move/eqP->. Qed. Lemma equiv_ltrans: left_transitive e. Proof. by apply: left_trans; [apply: equiv_sym|apply: equiv_trans]. Qed. Lemma equiv_rtrans: right_transitive e. Proof. by apply: right_trans; [apply: equiv_sym|apply: equiv_trans]. Qed. End EquivRel. Hint Resolve equiv_refl. Notation EquivRel r er es et := (@EquivRelPack _ r (EquivClass er es et)). Notation "[ 'equiv_rel' 'of' e ]" := (@equiv_pack _ _ e _ id) (at level 0, format "[ 'equiv_rel' 'of' e ]") : form_scope. (**************************************************) (* Encoding to another type modulo an equivalence *) (**************************************************) Section EncodingModuloRel. Variables (D E : Type) (ED : E -> D) (DE : D -> E) (e : rel D). Record encModRel_class_of (r : rel D) := EncModRelClassPack of (forall x, r x x -> r (ED (DE x)) x) & (r =2 e). Record encModRel := EncModRelPack { enc_mod_rel :> rel D; _ : encModRel_class_of enc_mod_rel }. Variable r : encModRel. Definition encModRelClass := let: EncModRelPack _ c as r' := r return encModRel_class_of r' in c. Definition encModRelP (x : D) : r x x -> r (ED (DE x)) x. Proof. by case: r => [] ? [] /= he _ /he. Qed. Definition encModRelE : r =2 e. Proof. by case: r => [] ? []. Qed. Definition encoded_equiv : rel E := [rel x y | r (ED x) (ED y)]. End EncodingModuloRel. Notation EncModRelClass m := (EncModRelClassPack (fun x _ => m x) (fun _ _ => erefl _)). Notation EncModRel r m := (@EncModRelPack _ _ _ _ _ r (EncModRelClass m)). Section EncodingModuloEquiv. Variables (D E : Type) (ED : E -> D) (DE : D -> E) (e : equiv_rel D). Variable (r : encModRel ED DE e). Lemma enc_mod_rel_is_equiv : equiv_class_of (enc_mod_rel r). Proof. split => [x|x y|y x z]; rewrite !encModRelE //; first by rewrite equiv_sym. by move=> exy /(equiv_trans exy). Qed. Definition enc_mod_rel_equiv_rel := EquivRelPack enc_mod_rel_is_equiv. Definition encModEquivP (x : D) : r (ED (DE x)) x. Proof. by rewrite encModRelP ?encModRelE. Qed. Local Notation e' := (encoded_equiv r). Lemma encoded_equivE : e' =2 [rel x y | e (ED x) (ED y)]. Proof. by move=> x y; rewrite /encoded_equiv /= encModRelE. Qed. Local Notation e'E := encoded_equivE. Lemma encoded_equiv_is_equiv : equiv_class_of e'. Proof. split => [x|x y|y x z]; rewrite !e'E //=; first by rewrite equiv_sym. by move=> exy /(equiv_trans exy). Qed. Canonical encoded_equiv_equiv_rel := EquivRelPack encoded_equiv_is_equiv. Lemma encoded_equivP x : e' (DE (ED x)) x. Proof. by rewrite /encoded_equiv /= encModEquivP. Qed. End EncodingModuloEquiv. (**************************************) (* Quotient by a equivalence relation *) (**************************************) Module EquivQuot. Section EquivQuot. Variables (D : Type) (C : choiceType) (CD : C -> D) (DC : D -> C). Variables (eD : equiv_rel D) (encD : encModRel CD DC eD). Notation eC := (encoded_equiv encD). Definition canon x := choose (eC x) (x). Record equivQuotient := EquivQuotient { erepr : C; _ : (frel canon) erepr erepr }. Definition type_of of (phantom (rel _) encD) := equivQuotient. Lemma canon_id : forall x, (invariant canon canon) x. Proof. move=> x /=; rewrite /canon (@eq_choose _ _ (eC x)). by rewrite (@choose_id _ (eC x) _ x) ?chooseP ?equiv_refl. by move=> y; apply: equiv_ltrans; rewrite equiv_sym /= chooseP. Qed. Definition pi := locked (fun x => EquivQuotient (canon_id x)). Lemma ereprK : cancel erepr pi. Proof. unlock pi; case=> x hx; move/eqP:(hx)=> hx'. exact: (@val_inj _ _ [subType for erepr]). Qed. Local Notation encDE := (encModRelE encD). Local Notation encDP := (encModEquivP encD). Canonical encD_equiv_rel := EquivRelPack (enc_mod_rel_is_equiv encD). Lemma pi_CD (x y : C) : reflect (pi x = pi y) (eC x y). Proof. apply: (iffP idP) => hxy. apply: (can_inj ereprK); unlock pi canon => /=. rewrite -(@eq_choose _ (eC x) (eC y)); last first. by move=> z; rewrite /eC /=; apply: equiv_ltrans. by apply: choose_id; rewrite ?equiv_refl //. rewrite (equiv_trans (chooseP (equiv_refl _ _))) //=. move: hxy => /(f_equal erepr) /=; unlock pi canon => /= ->. by rewrite equiv_sym /= chooseP. Qed. Lemma pi_DC (x y : D) : reflect (pi (DC x) = pi (DC y)) (eD x y). Proof. apply: (iffP idP)=> hxy. apply/pi_CD; rewrite /eC /=. by rewrite (equiv_ltrans (encDP _)) (equiv_rtrans (encDP _)) /= encDE. rewrite -encDE -(equiv_ltrans (encDP _)) -(equiv_rtrans (encDP _)) /=. exact/pi_CD. Qed. Lemma equivQTP : cancel (CD \o erepr) (pi \o DC). Proof. by move=> x; rewrite /= (pi_CD _ (erepr x) _) ?ereprK /eC /= ?encDP. Qed. Local Notation qT := (type_of (Phantom (rel D) encD)). Definition quotClass := QuotClass equivQTP. Canonical quotType := QuotType qT quotClass. Lemma eqmodP x y : reflect (x = y %[mod qT]) (eD x y). Proof. by apply: (iffP (pi_DC _ _)); rewrite !unlock. Qed. Fact eqMixin : Equality.mixin_of qT. Proof. exact: CanEqMixin ereprK. Qed. Canonical eqType := EqType qT eqMixin. Definition choiceMixin := CanChoiceMixin ereprK. Canonical choiceType := ChoiceType qT choiceMixin. Lemma eqmodE x y : x == y %[mod qT] = eD x y. Proof. exact: sameP eqP (@eqmodP _ _). Qed. Canonical eqQuotType := EqQuotType eD qT eqmodE. End EquivQuot. End EquivQuot. Canonical EquivQuot.quotType. Canonical EquivQuot.eqType. Canonical EquivQuot.choiceType. Canonical EquivQuot.eqQuotType. Notation "{eq_quot e }" := (@EquivQuot.type_of _ _ _ _ _ _ (Phantom (rel _) e)) : quotient_scope. Notation "x == y %[mod_eq r ]" := (x == y %[mod {eq_quot r}]) : quotient_scope. Notation "x = y %[mod_eq r ]" := (x = y %[mod {eq_quot r}]) : quotient_scope. Notation "x != y %[mod_eq r ]" := (x != y %[mod {eq_quot r}]) : quotient_scope. Notation "x <> y %[mod_eq r ]" := (x <> y %[mod {eq_quot r}]) : quotient_scope. (***********************************************************) (* If the type is directly a choiceType, no need to encode *) (***********************************************************) Section DefaultEncodingModuloRel. Variables (D : choiceType) (r : rel D). Definition defaultEncModRelClass := @EncModRelClassPack D D id id r r (fun _ rxx => rxx) (fun _ _ => erefl _). Canonical defaultEncModRel := EncModRelPack defaultEncModRelClass. End DefaultEncodingModuloRel. (***************************************************) (* Recovering a potential countable type structure *) (***************************************************) Section CountEncodingModuloRel. Variables (D : Type) (C : countType) (CD : C -> D) (DC : D -> C). Variables (eD : equiv_rel D) (encD : encModRel CD DC eD). Notation eC := (encoded_equiv encD). Fact eq_quot_countMixin : Countable.mixin_of {eq_quot encD}. Proof. exact: CanCountMixin (@EquivQuot.ereprK _ _ _ _ _ _). Qed. Canonical eq_quot_countType := CountType {eq_quot encD} eq_quot_countMixin. End CountEncodingModuloRel. Section EquivQuotTheory. Variables (T : choiceType) (e : equiv_rel T) (Q : eqQuotType e). Lemma eqmodE x y : x == y %[mod_eq e] = e x y. Proof. by rewrite pi_eq_quot. Qed. Lemma eqmodP x y : reflect (x = y %[mod_eq e]) (e x y). Proof. by rewrite -eqmodE; apply/eqP. Qed. End EquivQuotTheory. Prenex Implicits eqmodE eqmodP. Section EqQuotTheory. Variables (T : Type) (e : rel T) (Q : eqQuotType e). Lemma eqquotE x y : x == y %[mod Q] = e x y. Proof. by rewrite pi_eq_quot. Qed. Lemma eqquotP x y : reflect (x = y %[mod Q]) (e x y). Proof. by rewrite -eqquotE; apply/eqP. Qed. End EqQuotTheory. Prenex Implicits eqquotE eqquotP. mathcomp-1.5/theories/algnum.v0000644000175000017500000011471712307636117015470 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. Require Import fintype tuple finfun bigop prime ssralg finalg zmodp poly. Require Import ssrnum ssrint rat polydiv intdiv algC matrix mxalgebra mxpoly. Require Import vector falgebra fieldext separable galois cyclotomic. (******************************************************************************) (* This file provides a few basic results and constructions in algebraic *) (* number theory, that are used in the character theory library. Most of *) (* these could be generalized to a more abstract setting. Note that the type *) (* of abstract number fields is simply extFieldType rat. We define here: *) (* x \in Crat_span X <=> x is a Q-linear combination of elements of *) (* X : seq algC. *) (* x \in Cint_span X <=> x is a Z-linear combination of elements of *) (* X : seq algC. *) (* x \in Aint <=> x : algC is an algebraic integer, i.e., the (monic) *) (* polynomial of x over Q has integer coeficients. *) (* (e %| a)%A <=> e divides a with respect to algebraic integers, *) (* (e %| a)%Ax i.e., a is in the algebraic integer ideal generated *) (* by e. This is is notation for a \in dvdA e, where *) (* dvdv is the (collective) predicate for the Aint *) (* ideal generated by e. As in the (e %| a)%C notation *) (* e and a can be coerced to algC from nat or int. *) (* The (e %| a)%Ax display form is a workaround for *) (* design limitations of the Coq Notation facilities. *) (* (a == b %[mod e])%A, (a != b %[mod e])%A <=> *) (* a is equal (resp. not equal) to b mod e, i.e., a and *) (* b belong to the same e * Aint class. We do not *) (* force a, b and e to be algebraic integers. *) (* #[x]%C == the multiplicative order of x, i.e., the n such that *) (* x is an nth primitive root of unity, or 0 if x is not *) (* a root of unity. *) (* In addition several lemmas prove the (constructive) existence of number *) (* fields and of automorphisms of algC. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GRing.Theory Num.Theory. Local Open Scope ring_scope. Local Notation ZtoQ := (intr : int -> rat). Local Notation ZtoC := (intr : int -> algC). Local Notation QtoC := (ratr : rat -> algC). Local Notation intrp := (map_poly intr). Local Notation pZtoQ := (map_poly ZtoQ). Local Notation pZtoC := (map_poly ZtoC). Local Notation pQtoC := (map_poly ratr). Local Hint Resolve (@intr_inj _ : injective ZtoC). Local Notation QtoCm := [rmorphism of QtoC]. (* Number fields and rational spans. *) Lemma algC_PET (s : seq algC) : {z | exists a : nat ^ size s, z = \sum_(i < size s) s`_i *+ a i & exists ps, s = [seq (pQtoC p).[z] | p <- ps]}. Proof. elim: s => [|x s [z /sig_eqW[a Dz] /sig_eqW[ps Ds]]]. by exists 0; [exists [ffun _ => 2]; rewrite big_ord0 | exists nil]. have r_exists (y : algC): {r | r != 0 & root (pQtoC r) y}. have [r [_ mon_r] dv_r] := minCpolyP y. by exists r; rewrite ?monic_neq0 ?dv_r. suffices /sig_eqW[[n [|px [|pz []]]]// [Dpx Dpz]]: exists np, let zn := x *+ np.1 + z in [:: x; z] = [seq (pQtoC p).[zn] | p <- np.2]. - exists (x *+ n + z). exists [ffun i => oapp a n (unlift ord0 i)]. rewrite /= big_ord_recl ffunE unlift_none Dz; congr (_ + _). by apply: eq_bigr => i _; rewrite ffunE liftK. exists (px :: [seq p \Po pz | p <- ps]); rewrite /= -Dpx; congr (_ :: _). rewrite -map_comp Ds; apply: eq_map => p /=. by rewrite map_comp_poly horner_comp -Dpz. have [rx nz_rx rx0] := r_exists x. have [rz nz_rz rz0] := r_exists (- z). have char0_Q: [char rat] =i pred0 by exact: char_num. have [n [[pz Dpz] [px Dpx]]] := char0_PET nz_rz rz0 nz_rx rx0 char0_Q. by exists (n, [:: px; - pz]); rewrite /= !raddfN hornerN -[z]opprK Dpz Dpx. Qed. Canonical subfx_unitAlgType (F L : fieldType) iota (z : L) p := Eval hnf in [unitAlgType F of subFExtend iota z p]. Lemma num_field_exists (s : seq algC) : {Qs : fieldExtType rat & {QsC : {rmorphism Qs -> algC} & {s1 : seq Qs | map QsC s1 = s & <<1 & s1>>%VS = fullv}}}. Proof. have [z /sig_eqW[a Dz] /sig_eqW[ps Ds]] := algC_PET s. suffices [Qs [QsC [z1 z1C z1gen]]]: {Qs : fieldExtType rat & {QsC : {rmorphism Qs -> algC} & {z1 : Qs | QsC z1 = z & forall xx, exists p, fieldExt_horner z1 p = xx}}}. - set inQs := fieldExt_horner z1 in z1gen *; pose s1 := map inQs ps. have inQsK p: QsC (inQs p) = (pQtoC p).[z]. rewrite /= -horner_map z1C -map_poly_comp; congr _.[z]. apply: eq_map_poly => b /=; apply: canRL (mulfK _) _. by rewrite intr_eq0 denq_eq0. rewrite /= mulrzr -rmorphMz scalerMzl -{1}[b]divq_num_den -mulrzr. by rewrite divfK ?intr_eq0 ?denq_eq0 // scaler_int rmorph_int. exists Qs, QsC, s1; first by rewrite -map_comp Ds (eq_map inQsK). have sz_ps: size ps = size s by rewrite Ds size_map. apply/vspaceP=> x; rewrite memvf; have [p {x}<-] := z1gen x. elim/poly_ind: p => [|p b ApQs]; first by rewrite /inQs rmorph0 mem0v. rewrite /inQs rmorphD rmorphM /= fieldExt_hornerX fieldExt_hornerC -/inQs /=. suffices ->: z1 = \sum_(i < size s) s1`_i *+ a i. rewrite memvD ?memvZ ?mem1v ?memvM ?memv_suml // => i _. by rewrite rpredMn ?seqv_sub_adjoin ?mem_nth // size_map sz_ps. apply: (fmorph_inj QsC); rewrite z1C Dz rmorph_sum; apply: eq_bigr => i _. by rewrite rmorphMn {1}Ds !(nth_map 0) ?sz_ps //= inQsK. have [r [Dr /monic_neq0 nz_r] dv_r] := minCpolyP z. have rz0: root (pQtoC r) z by rewrite dv_r. have irr_r: irreducible_poly r. by apply/(subfx_irreducibleP rz0 nz_r)=> q qz0 nzq; rewrite dvdp_leq // -dv_r. exists (SubFieldExtType rz0 irr_r), (subfx_inj_rmorphism QtoCm z r). exists (subfx_root _ z r) => [|x]; first exact: subfx_inj_root. by have{x} [p ->] := subfxEroot rz0 nz_r x; exists p. Qed. Definition in_Crat_span s x := exists a : rat ^ size s, x = \sum_i QtoC (a i) * s`_i. Fact Crat_span_subproof s x : decidable (in_Crat_span s x). Proof. have [Qxs [QxsC [[|x1 s1] // [<- <-] {x s} _]]] := num_field_exists (x :: s). have QxsC_Z a zz: QxsC (a *: zz) = QtoC a * QxsC zz. rewrite mulrAC; apply: (canRL (mulfK _)); first by rewrite intr_eq0 denq_eq0. by rewrite mulrzr mulrzl -!rmorphMz scalerMzl -mulrzr -numqE scaler_int. apply: decP (x1 \in <>%VS) _; rewrite /in_Crat_span size_map. apply: (iffP idP) => [/coord_span-> | [a Dx]]. move: (coord _) => a; exists [ffun i => a i x1]; rewrite rmorph_sum. by apply: eq_bigr => i _; rewrite ffunE (nth_map 0). have{Dx} ->: x1 = \sum_i a i *: s1`_i. apply: (fmorph_inj QxsC); rewrite Dx rmorph_sum. by apply: eq_bigr => i _; rewrite QxsC_Z (nth_map 0). by apply: memv_suml => i _; rewrite memvZ ?memv_span ?mem_nth. Qed. Definition Crat_span s : pred algC := Crat_span_subproof s. Lemma Crat_spanP s x : reflect (in_Crat_span s x) (x \in Crat_span s). Proof. exact: sumboolP. Qed. Fact Crat_span_key s : pred_key (Crat_span s). Proof. by []. Qed. Canonical Crat_span_keyed s := KeyedPred (Crat_span_key s). Lemma mem_Crat_span s : {subset s <= Crat_span s}. Proof. move=> _ /(nthP 0)[ix ltxs <-]; pose i0 := Ordinal ltxs. apply/Crat_spanP; exists [ffun i => (i == i0)%:R]. rewrite (bigD1 i0) //= ffunE eqxx // rmorph1 mul1r. by rewrite big1 ?addr0 // => i; rewrite ffunE rmorph_nat mulr_natl => /negbTE->. Qed. Fact Crat_span_zmod_closed s : zmod_closed (Crat_span s). Proof. split=> [|_ _ /Crat_spanP[x ->] /Crat_spanP[y ->]]. apply/Crat_spanP; exists 0. by apply/esym/big1=> i _; rewrite ffunE rmorph0 mul0r. apply/Crat_spanP; exists (x - y); rewrite -sumrB; apply: eq_bigr => i _. by rewrite -mulrBl -rmorphB !ffunE. Qed. Canonical Crat_span_opprPred s := OpprPred (Crat_span_zmod_closed s). Canonical Crat_span_addrPred s := AddrPred (Crat_span_zmod_closed s). Canonical Crat_span_zmodPred s := ZmodPred (Crat_span_zmod_closed s). Section MoreAlgCaut. Implicit Type rR : unitRingType. Lemma alg_num_field (Qz : fieldExtType rat) a : a%:A = ratr a :> Qz. Proof. by rewrite -in_algE fmorph_eq_rat. Qed. Lemma rmorphZ_num (Qz : fieldExtType rat) rR (f : {rmorphism Qz -> rR}) a x : f (a *: x) = ratr a * f x. Proof. by rewrite -mulr_algl rmorphM alg_num_field fmorph_rat. Qed. Lemma fmorph_numZ (Qz1 Qz2 : fieldExtType rat) (f : {rmorphism Qz1 -> Qz2}) : scalable f. Proof. by move=> a x; rewrite rmorphZ_num -alg_num_field mulr_algl. Qed. Definition NumLRmorphism Qz1 Qz2 f := AddLRMorphism (@fmorph_numZ Qz1 Qz2 f). End MoreAlgCaut. Section NumFieldProj. Variables (Qn : fieldExtType rat) (QnC : {rmorphism Qn -> algC}). Lemma Crat_spanZ b a : {in Crat_span b, forall x, ratr a * x \in Crat_span b}. Proof. move=> _ /Crat_spanP[a1 ->]; apply/Crat_spanP; exists [ffun i => a * a1 i]. by rewrite mulr_sumr; apply: eq_bigr => i _; rewrite ffunE mulrA -rmorphM. Qed. Lemma Crat_spanM b : {in Crat & Crat_span b, forall a x, a * x \in Crat_span b}. Proof. by move=> _ x /CratP[a ->]; exact: Crat_spanZ. Qed. (* In principle CtoQn could be taken to be additive and Q-linear, but this *) (* would require a limit construction. *) Lemma num_field_proj : {CtoQn | CtoQn 0 = 0 & cancel QnC CtoQn}. Proof. pose b := vbasis {:Qn}. have Qn_bC (u : {x | x \in Crat_span (map QnC b)}): {y | QnC y = sval u}. case: u => _ /= /Crat_spanP/sig_eqW[a ->]. exists (\sum_i a i *: b`_i); rewrite rmorph_sum; apply: eq_bigr => i _. by rewrite rmorphZ_num (nth_map 0) // -(size_map QnC). pose CtoQn x := oapp (fun u => sval (Qn_bC u)) 0 (insub x). suffices QnCK: cancel QnC CtoQn by exists CtoQn; rewrite // -(rmorph0 QnC). move=> x; rewrite /CtoQn insubT => /= [|Qn_x]; last first. by case: (Qn_bC _) => x1 /= /fmorph_inj. rewrite (coord_vbasis (memvf x)) rmorph_sum rpred_sum // => i _. rewrite rmorphZ_num Crat_spanZ ?mem_Crat_span // -/b. by rewrite -tnth_nth -tnth_map mem_tnth. Qed. Lemma restrict_aut_to_num_field (nu : {rmorphism algC -> algC}) : (forall x, exists y, nu (QnC x) = QnC y) -> {nu0 : {lrmorphism Qn -> Qn} | {morph QnC : x / nu0 x >-> nu x}}. Proof. move=> Qn_nu; pose nu0 x := sval (sig_eqW (Qn_nu x)). have QnC_nu0: {morph QnC : x / nu0 x >-> nu x}. by rewrite /nu0 => x; case: (sig_eqW _). suffices nu0M: rmorphism nu0 by exists (NumLRmorphism (RMorphism nu0M)). do 2?split=> [x y|]; apply: (fmorph_inj QnC); rewrite ?QnC_nu0 ?rmorph1 //. by rewrite ?(rmorphB, QnC_nu0). by rewrite ?(rmorphM, QnC_nu0). Qed. Lemma map_Qnum_poly (nu : {rmorphism algC -> algC}) p : p \in polyOver 1%VS -> map_poly (nu \o QnC) p = (map_poly QnC p). Proof. move=> Qp; apply/polyP=> i; rewrite /= !coef_map /=. have /vlineP[a ->]: p`_i \in 1%VS by exact: polyOverP. by rewrite alg_num_field !fmorph_rat. Qed. End NumFieldProj. Lemma restrict_aut_to_normal_num_field (Qn : splittingFieldType rat) (QnC : {rmorphism Qn -> algC})(nu : {rmorphism algC -> algC}) : {nu0 : {lrmorphism Qn -> Qn} | {morph QnC : x / nu0 x >-> nu x}}. Proof. apply: restrict_aut_to_num_field => x. case: (splitting_field_normal 1%AS x) => rs /eqP Hrs. have: root (map_poly (nu \o QnC) (minPoly 1%AS x)) (nu (QnC x)). by rewrite fmorph_root root_minPoly. rewrite map_Qnum_poly ?minPolyOver // Hrs. rewrite [map_poly _ _](_:_ = \prod_(y <- map QnC rs) ('X - y%:P)); last first. rewrite big_map rmorph_prod; apply eq_bigr => i _. by rewrite rmorphB /= map_polyX map_polyC. rewrite root_prod_XsubC. by case/mapP => y _ ?; exists y. Qed. (* Integral spans. *) Lemma dec_Cint_span (V : vectType algC) m (s : m.-tuple V) v : decidable (inIntSpan s v). Proof. have s_s (i : 'I_m): s`_i \in <>%VS by rewrite memv_span ?memt_nth. have s_Zs a: \sum_(i < m) s`_i *~ a i \in <>%VS. by rewrite memv_suml // => i _; rewrite -scaler_int memvZ. case s_v: (v \in <>%VS); last by right=> [[a Dv]]; rewrite Dv s_Zs in s_v. pose IzT := {: 'I_m * 'I_(\dim <>)}; pose Iz := 'I_#|IzT|. pose b := vbasis <>. pose z_s := [seq coord b ij.2 (tnth s ij.1) | ij : IzT]. pose rank2 j i: Iz := enum_rank (i, j); pose val21 (p : Iz) := (enum_val p).1. pose inQzs w := [forall j, Crat_span z_s (coord b j w)]. have enum_pairK j: {in predT, cancel (rank2 j) val21}. by move=> i; rewrite /val21 enum_rankK. have Qz_Zs a: inQzs (\sum_(i < m) s`_i *~ a i). apply/forallP=> j; apply/Crat_spanP; rewrite /in_Crat_span size_map -cardE. exists [ffun ij => (a (val21 ij))%:Q *+ ((enum_val ij).2 == j)]. rewrite linear_sum {1}(reindex_onto _ _ (enum_pairK j)). rewrite big_mkcond; apply: eq_bigr => ij _ /=; rewrite nth_image (tnth_nth 0). rewrite (can2_eq (@enum_rankK _) (@enum_valK _)) ffunE -scaler_int /val21. case Dij: (enum_val ij) => [i j1]; rewrite xpair_eqE eqxx /= eq_sym -mulrb. by rewrite linearZ rmorphMn rmorph_int mulrnAl; case: eqP => // ->. case Qz_v: (inQzs v); last by right=> [[a Dv]]; rewrite Dv Qz_Zs in Qz_v. have [Qz [QzC [z1s Dz_s _]]] := num_field_exists z_s. have sz_z1s: size z1s = #|IzT| by rewrite -(size_map QzC) Dz_s size_map cardE. have xv j: {x | coord b j v = QzC x}. apply: sig_eqW; have /Crat_spanP[x ->] := forallP Qz_v j. exists (\sum_ij x ij *: z1s`_ij); rewrite rmorph_sum. apply: eq_bigr => ij _; rewrite mulrAC. apply: canLR (mulfK _) _; first by rewrite intr_eq0 denq_neq0. rewrite mulrzr -rmorphMz scalerMzl -(mulrzr (x _)) -numqE scaler_int. by rewrite rmorphMz mulrzl -(nth_map _ 0) ?Dz_s // -(size_map QzC) Dz_s. pose sz := [tuple [ffun j => z1s`_(rank2 j i)] | i < m]. have [Zsv | Zs'v] := dec_Qint_span sz [ffun j => sval (xv j)]. left; have{Zsv} [a Dv] := Zsv; exists a. transitivity (\sum_j \sum_(i < m) QzC ((sz`_i *~ a i) j) *: b`_j). rewrite {1}(coord_vbasis s_v) -/b; apply: eq_bigr => j _. rewrite -scaler_suml; congr (_ *: _). have{Dv} /ffunP/(_ j) := Dv; rewrite sum_ffunE !ffunE -rmorph_sum => <-. by case: (xv j). rewrite exchange_big; apply: eq_bigr => i _. rewrite (coord_vbasis (s_s i)) -/b mulrz_suml; apply: eq_bigr => j _. rewrite scalerMzl ffunMzE rmorphMz; congr ((_ *~ _) *: _). rewrite nth_mktuple ffunE -(nth_map _ 0) ?sz_z1s // Dz_s. by rewrite nth_image enum_rankK /= (tnth_nth 0). right=> [[a Dv]]; case: Zs'v; exists a. apply/ffunP=> j; rewrite sum_ffunE !ffunE; apply: (fmorph_inj QzC). case: (xv j) => /= _ <-; rewrite Dv linear_sum rmorph_sum. apply: eq_bigr => i _; rewrite nth_mktuple raddfMz !ffunMzE rmorphMz ffunE. by rewrite -(nth_map _ 0 QzC) ?sz_z1s // Dz_s nth_image enum_rankK -tnth_nth. Qed. Definition Cint_span (s : seq algC) : pred algC := fun x => dec_Cint_span (in_tuple [seq \row_(i < 1) y | y <- s]) (\row_i x). Fact Cint_span_key s : pred_key (Cint_span s). Proof. by []. Qed. Canonical Cint_span_keyed s := KeyedPred (Cint_span_key s). Lemma Cint_spanP n (s : n.-tuple algC) x : reflect (inIntSpan s x) (x \in Cint_span s). Proof. rewrite unfold_in; case: (dec_Cint_span _ _) => [Zs_x | Zs'x] /=. left; have{Zs_x} [] := Zs_x; rewrite /= size_map size_tuple => a /rowP/(_ 0). rewrite !mxE => ->; exists a; rewrite summxE; apply: eq_bigr => i _. by rewrite -scaler_int (nth_map 0) ?size_tuple // !mxE mulrzl. right=> [[a Dx]]; have{Zs'x} [] := Zs'x. rewrite /inIntSpan /= size_map size_tuple; exists a. apply/rowP=> i0; rewrite !mxE summxE Dx; apply: eq_bigr => i _. by rewrite -scaler_int mxE mulrzl (nth_map 0) ?size_tuple // !mxE. Qed. Lemma mem_Cint_span s : {subset s <= Cint_span s}. Proof. move=> _ /(nthP 0)[ix ltxs <-]; apply/(Cint_spanP (in_tuple s)). exists [ffun i => i == Ordinal ltxs : int]. rewrite (bigD1 (Ordinal ltxs)) //= ffunE eqxx. by rewrite big1 ?addr0 // => i; rewrite ffunE => /negbTE->. Qed. Lemma Cint_span_zmod_closed s : zmod_closed (Cint_span s). Proof. have sP := Cint_spanP (in_tuple s); split=> [|_ _ /sP[x ->] /sP[y ->]]. by apply/sP; exists 0; rewrite big1 // => i; rewrite ffunE. apply/sP; exists (x - y); rewrite -sumrB; apply: eq_bigr => i _. by rewrite !ffunE raddfB. Qed. Canonical Cint_span_opprPred s := OpprPred (Cint_span_zmod_closed s). Canonical Cint_span_addrPred s := AddrPred (Cint_span_zmod_closed s). Canonical Cint_span_zmodPred s := ZmodPred (Cint_span_zmod_closed s). (* Automorphism extensions. *) Lemma extend_algC_subfield_aut (Qs : fieldExtType rat) (QsC : {rmorphism Qs -> algC}) (phi : {rmorphism Qs -> Qs}) : {nu : {rmorphism algC -> algC} | {morph QsC : x / phi x >-> nu x}}. Proof. pose numF_inj (Qr : fieldExtType rat) := {rmorphism Qr -> algC}. pose subAut := {Qr : _ & numF_inj Qr * {lrmorphism Qr -> Qr}}%type. pose SubAut := existS _ _ (_, _) : subAut. pose Sdom (mu : subAut) := projS1 mu. pose Sinj (mu : subAut) : {rmorphism Sdom mu -> algC} := (projS2 mu).1. pose Saut (mu : subAut) : {rmorphism Sdom mu -> Sdom mu} := (projS2 mu).2. have SinjZ Qr (QrC : numF_inj Qr) a x: QrC (a *: x) = QtoC a * QrC x. rewrite mulrAC; apply: canRL (mulfK _) _. by rewrite intr_eq0 denq_neq0. by rewrite mulrzr mulrzl -!rmorphMz scalerMzl -scaler_int -mulrzr -numqE. have Sinj_poly Qr (QrC : numF_inj Qr) p: map_poly QrC (map_poly (in_alg Qr) p) = pQtoC p. - rewrite -map_poly_comp; apply: eq_map_poly => a. by rewrite /= SinjZ rmorph1 mulr1. have ext1 mu0 x: {mu1 | exists y, x = Sinj mu1 y & exists2 in01 : {lrmorphism _}, Sinj mu0 =1 Sinj mu1 \o in01 & {morph in01: y / Saut mu0 y >-> Saut mu1 y}}. - pose b0 := vbasis {:Sdom mu0}. have [z _ /sig_eqW[[|px ps] // [Dx Ds]]] := algC_PET (x :: map (Sinj mu0) b0). have [p [_ mon_p] /(_ p) pz0] := minCpolyP z; rewrite dvdpp in pz0. have [r Dr] := closed_field_poly_normal (pQtoC p : {poly algC}). rewrite lead_coef_map {mon_p}(monicP mon_p) rmorph1 scale1r in Dr. have{pz0} rz: z \in r by rewrite -root_prod_XsubC -Dr. have [Qr [QrC [rr Drr genQr]]] := num_field_exists r. have{rz} [zz Dz]: {zz | QrC zz = z}. by move: rz; rewrite -Drr => /mapP/sig2_eqW[zz]; exists zz. have{ps Ds} [in01 Din01]: {in01 : {lrmorphism _} | Sinj mu0 =1 QrC \o in01}. have in01P y: {yy | Sinj mu0 y = QrC yy}. exists (\sum_i coord b0 i y *: (map_poly (in_alg Qr) ps`_i).[zz]). rewrite {1}(coord_vbasis (memvf y)) !rmorph_sum; apply: eq_bigr => i _. rewrite !SinjZ; congr (_ * _); rewrite -(nth_map _ 0) ?size_tuple // Ds. rewrite -horner_map Dz Sinj_poly (nth_map 0) //. by have:= congr1 size Ds; rewrite !size_map size_tuple => <-. pose in01 y := sval (in01P y). have Din01 y: Sinj mu0 y = QrC (in01 y) by rewrite /in01; case: (in01P y). suffices in01M: lrmorphism in01 by exists (LRMorphism in01M). pose rwM := (=^~ Din01, SinjZ, rmorph1, rmorphB, rmorphM). by do 3?split; try move=> ? ?; apply: (fmorph_inj QrC); rewrite !rwM. have {z zz Dz px Dx} Dx: exists xx, x = QrC xx. exists (map_poly (in_alg Qr) px).[zz]. by rewrite -horner_map Dz Sinj_poly Dx. pose lin01 := linfun in01; pose K := (lin01 @: fullv)%VS. have memK y: reflect (exists yy, y = in01 yy) (y \in K). apply: (iffP memv_imgP) => [[yy _ ->] | [yy ->]]; by exists yy; rewrite ?lfunE ?memvf. have algK: is_aspace K. rewrite /is_aspace has_algid1; last first. by apply/memK; exists 1; rewrite rmorph1. apply/prodvP=> _ _ /memK[y1 ->] /memK[y2 ->]. by apply/memK; exists (y1 * y2); rewrite rmorphM. have ker_in01: lker lin01 == 0%VS. by apply/lker0P=> y1 y2; rewrite !lfunE; apply: fmorph_inj. pose f := (lin01 \o linfun (Saut mu0) \o lin01^-1)%VF. have Df y: f (in01 y) = in01 (Saut mu0 y). transitivity (f (lin01 y)); first by rewrite !lfunE. by do 4!rewrite lfunE /=; rewrite lker0_lfunK. have hom_f: kHom 1 (ASpace algK) f. apply/kHomP; split=> [_ _ /memK[y1 ->] /memK[y2 ->] |_ /vlineP[a ->]]. by rewrite -rmorphM !Df !rmorphM. by rewrite -(rmorph1 in01) -linearZ /= Df {1}linearZ /= rmorph1. pose pr := map_poly (in_alg Qr) p. have Qpr: pr \is a polyOver 1%VS. by apply/polyOverP=> i; rewrite coef_map memvZ ?memv_line. have splitQr: splittingFieldFor K pr fullv. apply: splittingFieldForS (sub1v (Sub K algK)) (subvf _) _; exists rr => //. congr (_ %= _): (eqpxx pr); apply: (@map_poly_inj _ _ QrC). rewrite Sinj_poly Dr -Drr big_map rmorph_prod; apply: eq_bigr => zz _. by rewrite rmorphB /= map_polyX map_polyC. have [f1 aut_f1 Df1]:= kHom_extends (sub1v (ASpace algK)) hom_f Qpr splitQr. pose nu := LRMorphism (kHom_lrmorphism aut_f1). exists (SubAut Qr QrC nu) => //; exists in01 => //= y. by rewrite -Df -Df1 //; apply/memK; exists y. have phiZ: scalable phi. move=> a y; do 2!rewrite -mulr_algl -in_algE. by rewrite -[a]divq_num_den !(fmorph_div, rmorphM, rmorph_int). pose fix ext n := if n is i.+1 then oapp (fun x => s2val (ext1 (ext i) x)) (ext i) (unpickle i) else SubAut Qs QsC (AddLRMorphism phiZ). have mem_ext x n: (pickle x < n)%N -> {xx | Sinj (ext n) xx = x}. move=> ltxn; apply: sig_eqW; elim: n ltxn => // n IHn. rewrite ltnS leq_eqVlt => /predU1P[<- | /IHn[xx <-]] /=. by rewrite pickleK /=; case: (ext1 _ x) => mu [xx]; exists xx. case: (unpickle n) => /= [y|]; last by exists xx. case: (ext1 _ y) => mu /= _ [in_mu inj_in_mu _]. by exists (in_mu xx); rewrite inj_in_mu. pose nu x := Sinj _ (Saut _ (sval (mem_ext x _ (ltnSn _)))). have nu_inj n y: nu (Sinj (ext n) y) = Sinj (ext n) (Saut (ext n) y). rewrite /nu; case: (mem_ext _ _ _); move: _.+1 => n1 y1 Dy /=. without loss /subnK Dn1: n n1 y y1 Dy / (n <= n1)%N. by move=> IH; case/orP: (leq_total n n1) => /IH => [/(_ y) | /(_ y1)]->. elim: {n}(_ - n)%N {-1}n => [|k IHk] n in Dn1 y Dy *. by move: y1 Dy; rewrite -Dn1 => y1 /fmorph_inj ->. rewrite addSnnS in Dn1; move/IHk: Dn1 => /=. case: (unpickle _) => [z|] /=; last exact. case: (ext1 _ _) => mu /= _ [in_mu Dinj Daut]. by rewrite Dy => /(_ _ (Dinj _))->; rewrite -Daut Dinj. suffices nuM: rmorphism nu. by exists (RMorphism nuM) => x; rewrite /= (nu_inj 0%N). pose le_nu (x : algC) n := (pickle x < n)%N. have max3 x1 x2 x3: exists n, [/\ le_nu x1 n, le_nu x2 n & le_nu x3 n]. exists (maxn (pickle x1) (maxn (pickle x2) (pickle x3))).+1. by apply/and3P; rewrite /le_nu !ltnS -!geq_max. do 2?split; try move=> x1 x2. - have [n] := max3 (x1 - x2) x1 x2. case=> /mem_ext[y Dx] /mem_ext[y1 Dx1] /mem_ext[y2 Dx2]. rewrite -Dx nu_inj; rewrite -Dx1 -Dx2 -rmorphB in Dx. by rewrite (fmorph_inj _ Dx) !rmorphB -!nu_inj Dx1 Dx2. - have [n] := max3 (x1 * x2) x1 x2. case=> /mem_ext[y Dx] /mem_ext[y1 Dx1] /mem_ext[y2 Dx2]. rewrite -Dx nu_inj; rewrite -Dx1 -Dx2 -rmorphM in Dx. by rewrite (fmorph_inj _ Dx) !rmorphM -!nu_inj Dx1 Dx2. by rewrite -(rmorph1 QsC) (nu_inj 0%N) !rmorph1. Qed. (* Extended automorphisms of Q_n. *) Lemma Qn_aut_exists k n : coprime k n -> {u : {rmorphism algC -> algC} | forall z, z ^+ n = 1 -> u z = z ^+ k}. Proof. have [-> /eqnP | n_gt0 co_k_n] := posnP n. by rewrite gcdn0 => ->; exists [rmorphism of idfun]. have [z prim_z] := C_prim_root_exists n_gt0. have [Qn [QnC [[|zn []] // [Dz]]] genQn] := num_field_exists [:: z]. pose phi := kHomExtend 1 \1 zn (zn ^+ k). have homQn1: kHom 1 1 (\1%VF : 'End(Qn)) by rewrite kHom1. have pzn_zk0: root (map_poly \1%VF (minPoly 1 zn)) (zn ^+ k). rewrite -(fmorph_root QnC) rmorphX Dz -map_poly_comp. rewrite (@eq_map_poly _ _ _ QnC) => [|a]; last by rewrite /= id_lfunE. set p1 := map_poly _ _. have [q1 Dp1]: exists q1, p1 = pQtoC q1. have aP i: (minPoly 1 zn)`_i \in 1%VS. by apply/polyOverP; exact: minPolyOver. have{aP} a_ i := sig_eqW (vlineP _ _ (aP i)). exists (\poly_(i < size (minPoly 1 zn)) sval (a_ i)). apply/polyP=> i; rewrite coef_poly coef_map coef_poly /=. case: ifP => _; rewrite ?rmorph0 //; case: (a_ i) => a /= ->. apply: canRL (mulfK _) _; first by rewrite intr_eq0 denq_eq0. by rewrite mulrzr -rmorphMz scalerMzl -mulrzr -numqE scaler_int rmorph_int. have: root p1 z by rewrite -Dz fmorph_root root_minPoly. rewrite Dp1; have [q2 [Dq2 _] ->] := minCpolyP z. case/dvdpP=> r1 ->; rewrite rmorphM rootM /= -Dq2; apply/orP; right. rewrite (minCpoly_cyclotomic prim_z) /cyclotomic. rewrite (bigD1 (Ordinal (ltn_pmod k n_gt0))) ?coprime_modl //=. by rewrite rootM root_XsubC prim_expr_mod ?eqxx. have phiM: lrmorphism phi. by apply/kHom_lrmorphism; rewrite -genQn span_seq1 /= kHomExtendP. have [nu Dnu] := extend_algC_subfield_aut QnC (RMorphism phiM). exists nu => _ /(prim_rootP prim_z)[i ->]. rewrite rmorphX exprAC -Dz -Dnu /= -{1}[zn]hornerX /phi. rewrite (kHomExtend_poly homQn1) ?polyOverX //. rewrite map_polyE map_id_in => [|?]; last by rewrite id_lfunE. by rewrite polyseqK hornerX rmorphX. Qed. (* Algebraic integers. *) Definition Aint : pred_class := fun x : algC => minCpoly x \is a polyOver Cint. Fact Aint_key : pred_key Aint. Proof. by []. Qed. Canonical Aint_keyed := KeyedPred Aint_key. Lemma root_monic_Aint p x : root p x -> p \is monic -> p \is a polyOver Cint -> x \in Aint. Proof. have pZtoQtoC pz: pQtoC (pZtoQ pz) = pZtoC pz. by rewrite -map_poly_comp; apply: eq_map_poly => b; rewrite /= rmorph_int. move=> px0 mon_p /floorCpP[pz Dp]; rewrite unfold_in. move: px0; rewrite Dp -pZtoQtoC; have [q [-> mon_q] ->] := minCpolyP x. case/dvdpP_rat_int=> qz [a nz_a Dq] [r]. move/(congr1 (fun q1 => lead_coef (a *: pZtoQ q1))). rewrite rmorphM scalerAl -Dq lead_coefZ lead_coefM /=. have /monicP->: pZtoQ pz \is monic by rewrite -(map_monic QtoCm) pZtoQtoC -Dp. rewrite (monicP mon_q) mul1r mulr1 lead_coef_map_inj //; last exact: intr_inj. rewrite Dq => ->; apply/polyOverP=> i; rewrite !(coefZ, coef_map). by rewrite -rmorphM /= rmorph_int Cint_int. Qed. Lemma Cint_rat_Aint z : z \in Crat -> z \in Aint -> z \in Cint. Proof. case/CratP=> a ->{z} /polyOverP/(_ 0%N). have [p [Dp mon_p] dv_p] := minCpolyP (ratr a); rewrite Dp coef_map. suffices /eqP->: p == 'X - a%:P by rewrite polyseqXsubC /= rmorphN rpredN. rewrite -eqp_monic ?monicXsubC // irredp_XsubC //. by rewrite -(size_map_poly QtoCm) -Dp neq_ltn size_minCpoly orbT. by rewrite -dv_p fmorph_root root_XsubC. Qed. Lemma Aint_Cint : {subset Cint <= Aint}. Proof. move=> x; rewrite -polyOverXsubC. by apply: root_monic_Aint; rewrite ?monicXsubC ?root_XsubC. Qed. Lemma Aint_int x : x%:~R \in Aint. Proof. by rewrite Aint_Cint ?Cint_int. Qed. Lemma Aint0 : 0 \in Aint. Proof. exact: (Aint_int 0). Qed. Lemma Aint1 : 1 \in Aint. Proof. exact: (Aint_int 1). Qed. Hint Resolve Aint0 Aint1. Lemma Aint_unity_root n x : (n > 0)%N -> n.-unity_root x -> x \in Aint. Proof. move=> n_gt0 xn1; apply: root_monic_Aint xn1 (monic_Xn_sub_1 _ n_gt0) _. by apply/polyOverP=> i; rewrite coefB coefC -mulrb coefXn /= rpredB ?rpred_nat. Qed. Lemma Aint_prim_root n z : n.-primitive_root z -> z \in Aint. Proof. move=> pr_z; apply/(Aint_unity_root (prim_order_gt0 pr_z))/unity_rootP. exact: prim_expr_order. Qed. Lemma Aint_Cnat : {subset Cnat <= Aint}. Proof. by move=> z /Cint_Cnat/Aint_Cint. Qed. (* This is Isaacs, Lemma (3.3) *) Lemma Aint_subring_exists (X : seq algC) : {subset X <= Aint} -> {S : pred algC & (*a*) subring_closed S /\ (*b*) {subset X <= S} & (*c*) {Y : {n : nat & n.-tuple algC} & {subset tagged Y <= S} & forall x, reflect (inIntSpan (tagged Y) x) (x \in S)}}. Proof. move=> AZ_X; pose m := (size X).+1. pose n (i : 'I_m) := (size (minCpoly X`_i)).-2; pose N := (\max_i n i).+1. pose IY := family (fun i => [pred e : 'I_N | e <= n i]%N). have IY_0: 0 \in IY by apply/familyP=> // i; rewrite ffunE. pose inIY := enum_rank_in IY_0. pose Y := [seq \prod_(i < m) X`_i ^+ (f : 'I_N ^ m) i | f in IY]. have S_P := Cint_spanP [tuple of Y]; set S := Cint_span _ in S_P. have sYS: {subset Y <= S} by exact: mem_Cint_span. have S_1: 1 \in S. by apply/sYS/imageP; exists 0 => //; rewrite big1 // => i; rewrite ffunE. have SmulX (i : 'I_m): {in S, forall x, x * X`_i \in S}. move=> _ /S_P[x ->]; rewrite mulr_suml rpred_sum // => j _. rewrite mulrzAl rpredMz {x}// nth_image mulrC (bigD1 i) //= mulrA -exprS. move: {j}(enum_val j) (familyP (enum_valP j)) => f fP. have:= fP i; rewrite inE /= leq_eqVlt => /predU1P[-> | fi_ltn]; last first. apply/sYS/imageP; have fiK: (inord (f i).+1 : 'I_N) = (f i).+1 :> nat. by rewrite inordK // ltnS (bigmax_sup i). exists (finfun [eta f with i |-> inord (f i).+1]). apply/familyP=> i1; rewrite inE ffunE /= fun_if fiK. by case: eqP => [-> // | _]; exact: fP. rewrite (bigD1 i isT) ffunE /= eqxx fiK; congr (_ * _). by apply: eq_bigr => i1; rewrite ffunE /= => /negPf->. have [/monicP ] := (minCpoly_monic X`_i, root_minCpoly X`_i). rewrite /root horner_coef lead_coefE -(subnKC (size_minCpoly _)) subn2. rewrite big_ord_recr /= addrC addr_eq0 => ->; rewrite mul1r => /eqP->. have /floorCpP[p Dp]: X`_i \in Aint. by have [/(nth_default 0)-> | /(mem_nth 0)/AZ_X] := leqP (size X) i. rewrite -/(n i) Dp mulNr rpredN // mulr_suml rpred_sum // => [[e le_e]] /= _. rewrite coef_map -mulrA mulrzl rpredMz ?sYS //; apply/imageP. have eK: (inord e : 'I_N) = e :> nat by rewrite inordK // ltnS (bigmax_sup i). exists (finfun [eta f with i |-> inord e]). apply/familyP=> i1; rewrite inE ffunE /= fun_if eK. by case: eqP => [-> // | _]; exact: fP. rewrite (bigD1 i isT) ffunE /= eqxx eK; congr (_ * _). by apply: eq_bigr => i1; rewrite ffunE /= => /negPf->. exists S; last by exists (Tagged (fun n => n.-tuple _) [tuple of Y]). split=> [|x Xx]; last first. by rewrite -[x]mul1r -(nth_index 0 Xx) (SmulX (Ordinal _)) // ltnS index_size. split=> // x y Sx Sy; first by rewrite rpredB. case/S_P: Sy => {y}[y ->]; rewrite mulr_sumr rpred_sum //= => j. rewrite mulrzAr rpredMz {y}// nth_image; move: {j}(enum_val j) => f. elim/big_rec: _ => [|i y _ IHy] in x Sx *; first by rewrite mulr1. rewrite mulrA {y}IHy //. elim: {f}(f i : nat) => [|e IHe] in x Sx *; first by rewrite mulr1. by rewrite exprS mulrA IHe // SmulX. Qed. Section AlgIntSubring. Import DefaultKeying GRing.DefaultPred perm. (* This is Isaacs, Theorem (3.4). *) Theorem fin_Csubring_Aint S n (Y : n.-tuple algC) : mulr_closed S -> (forall x, reflect (inIntSpan Y x) (x \in S)) -> {subset S <= Aint}. Proof. have ZP_C c: (ZtoC c)%:P \is a polyOver Cint by rewrite raddfMz rpred_int. move=> mulS S_P x Sx; pose v := \row_(i < n) Y`_i. have [v0 | nz_v] := eqVneq v 0. case/S_P: Sx => {x}x ->; rewrite big1 ?isAlgInt0 // => i _. by have /rowP/(_ i) := v0; rewrite !mxE => ->; rewrite mul0rz. have sYS (i : 'I_n): x * Y`_i \in S. by rewrite rpredM //; apply/S_P/Cint_spanP/mem_Cint_span/memt_nth. pose A := \matrix_(i, j < n) sval (sig_eqW (S_P _ (sYS j))) i. pose p := char_poly (map_mx ZtoC A). have: p \is a polyOver Cint. rewrite rpred_sum // => s _; rewrite rpredMsign rpred_prod // => j _. by rewrite !mxE /= rpredB ?rpredMn ?polyOverX. apply: root_monic_Aint (char_poly_monic _). rewrite -eigenvalue_root_char; apply/eigenvalueP; exists v => //. apply/rowP=> j; case dAj: (sig_eqW (S_P _ (sYS j))) => [a DxY]. by rewrite !mxE DxY; apply: eq_bigr => i _; rewrite !mxE dAj /= mulrzr. Qed. (* This is Isaacs, Corollary (3.5). *) Corollary Aint_subring : subring_closed Aint. Proof. suff rAZ: {in Aint &, forall x y, (x - y \in Aint) * (x * y \in Aint)}. by split=> // x y AZx AZy; rewrite rAZ. move=> x y AZx AZy. have [|S [ringS] ] := @Aint_subring_exists [:: x; y]; first exact/allP/and3P. move=> /allP/and3P[Sx Sy _] [Y _ genYS]. have AZ_S := fin_Csubring_Aint ringS genYS. by have [_ S_B S_M] := ringS; rewrite !AZ_S ?S_B ?S_M. Qed. Canonical Aint_opprPred := OpprPred Aint_subring. Canonical Aint_addrPred := AddrPred Aint_subring. Canonical Aint_mulrPred := MulrPred Aint_subring. Canonical Aint_zmodPred := ZmodPred Aint_subring. Canonical Aint_semiringPred := SemiringPred Aint_subring. Canonical Aint_smulrPred := SmulrPred Aint_subring. Canonical Aint_subringPred := SubringPred Aint_subring. End AlgIntSubring. Lemma Aint_aut (nu : {rmorphism algC -> algC}) x : (nu x \in Aint) = (x \in Aint). Proof. by rewrite !unfold_in minCpoly_aut. Qed. Definition dvdA (e : Algebraics.divisor) : pred_class := fun z : algC => if e == 0 then z == 0 else z / e \in Aint. Fact dvdA_key e : pred_key (dvdA e). Proof. by []. Qed. Canonical dvdA_keyed e := KeyedPred (dvdA_key e). Delimit Scope algC_scope with A. Delimit Scope algC_expanded_scope with Ax. Notation "e %| x" := (x \in dvdA e) : algC_expanded_scope. Notation "e %| x" := (@in_mem Algebraics.divisor x (mem (dvdA e))) : algC_scope. Fact dvdA_zmod_closed e : zmod_closed (dvdA e). Proof. split=> [|x y]; first by rewrite unfold_in mul0r eqxx rpred0 ?if_same. rewrite ![(e %| _)%A]unfold_in. case: ifP => [_ x0 /eqP-> | _]; first by rewrite subr0. by rewrite mulrBl; apply: rpredB. Qed. Canonical dvdA_opprPred e := OpprPred (dvdA_zmod_closed e). Canonical dvdA_addrPred e := AddrPred (dvdA_zmod_closed e). Canonical dvdA_zmodPred e := ZmodPred (dvdA_zmod_closed e). Definition eqAmod (e x y : Algebraics.divisor) := (e %| x - y)%A. Notation "x == y %[mod e ]" := (eqAmod e x y) : algC_scope. Notation "x != y %[mod e ]" := (~~ (eqAmod e x y)) : algC_scope. Lemma eqAmod_refl e x : (x == x %[mod e])%A. Proof. by rewrite /eqAmod subrr rpred0. Qed. Hint Resolve eqAmod_refl. Lemma eqAmod_sym e x y : ((x == y %[mod e]) = (y == x %[mod e]))%A. Proof. by rewrite /eqAmod -opprB rpredN. Qed. Lemma eqAmod_trans e y x z : (x == y %[mod e] -> y == z %[mod e] -> x == z %[mod e])%A. Proof. by move=> Exy Eyz; rewrite /eqAmod -[x](subrK y) -addrA rpredD. Qed. Lemma eqAmod_transl e x y z : (x == y %[mod e])%A -> (x == z %[mod e])%A = (y == z %[mod e])%A. Proof. by move/(sym_left_transitive (eqAmod_sym e) (@eqAmod_trans e)). Qed. Lemma eqAmod_transr e x y z : (x == y %[mod e])%A -> (z == x %[mod e])%A = (z == y %[mod e])%A. Proof. by move/(sym_right_transitive (eqAmod_sym e) (@eqAmod_trans e)). Qed. Lemma eqAmod0 e x : (x == 0 %[mod e])%A = (e %| x)%A. Proof. by rewrite /eqAmod subr0. Qed. Lemma eqAmodN e x y : (- x == y %[mod e])%A = (x == - y %[mod e])%A. Proof. by rewrite eqAmod_sym /eqAmod !opprK addrC. Qed. Lemma eqAmodDr e x y z : (y + x == z + x %[mod e])%A = (y == z %[mod e])%A. Proof. by rewrite /eqAmod addrAC opprD !addrA subrK. Qed. Lemma eqAmodDl e x y z : (x + y == x + z %[mod e])%A = (y == z %[mod e])%A. Proof. by rewrite !(addrC x) eqAmodDr. Qed. Lemma eqAmodD e x1 x2 y1 y2 : (x1 == x2 %[mod e] -> y1 == y2 %[mod e] -> x1 + y1 == x2 + y2 %[mod e])%A. Proof. rewrite -(eqAmodDl e x2 y1) -(eqAmodDr e y1); exact: eqAmod_trans. Qed. Lemma eqAmodm0 e : (e == 0 %[mod e])%A. Proof. by rewrite /eqAmod subr0 unfold_in; case: ifPn => // /divff->. Qed. Hint Resolve eqAmodm0. Lemma eqAmodMr e : {in Aint, forall z x y, x == y %[mod e] -> x * z == y * z %[mod e]}%A. Proof. move=> z Zz x y. rewrite /eqAmod -mulrBl ![(e %| _)%A]unfold_in mulf_eq0 mulrAC. by case: ifP => [_ -> // | _ Exy]; apply: rpredM. Qed. Lemma eqAmodMl e : {in Aint, forall z x y, x == y %[mod e] -> z * x == z * y %[mod e]}%A. Proof. by move=> z Zz x y Exy; rewrite !(mulrC z) eqAmodMr. Qed. Lemma eqAmodMl0 e : {in Aint, forall x, x * e == 0 %[mod e]}%A. Proof. by move=> x Zx; rewrite -(mulr0 x) eqAmodMl. Qed. Lemma eqAmodMr0 e : {in Aint, forall x, e * x == 0 %[mod e]}%A. Proof. by move=> x Zx; rewrite /= mulrC eqAmodMl0. Qed. Lemma eqAmod_addl_mul e : {in Aint, forall x y, x * e + y == y %[mod e]}%A. Proof. by move=> x Zx y; rewrite -{2}[y]add0r eqAmodDr eqAmodMl0. Qed. Lemma eqAmodM e : {in Aint &, forall x1 y2 x2 y1, x1 == x2 %[mod e] -> y1 == y2 %[mod e] -> x1 * y1 == x2 * y2 %[mod e]}%A. Proof. move=> x1 y2 Zx1 Zy2 x2 y1 eq_x /(eqAmodMl Zx1)/eqAmod_trans-> //. exact: eqAmodMr. Qed. Lemma eqAmod_rat : {in Crat & &, forall e m n, (m == n %[mod e])%A = (m == n %[mod e])%C}. Proof. move=> e m n Qe Qm Qn; rewrite /eqCmod unfold_in /eqAmod unfold_in. case: ifPn => // nz_e; apply/idP/idP=> [/Cint_rat_Aint | /Aint_Cint] -> //. by rewrite rpred_div ?rpredB. Qed. Lemma eqAmod0_rat : {in Crat &, forall e n, (n == 0 %[mod e])%A = (e %| n)%C}. Proof. by move=> e n Qe Qn; rewrite /= eqAmod_rat /eqCmod ?subr0 ?Crat0. Qed. Lemma eqAmod_nat (e m n : nat) : (m == n %[mod e])%A = (m == n %[mod e])%N. Proof. by rewrite eqAmod_rat ?rpred_nat // eqCmod_nat. Qed. Lemma eqAmod0_nat (e m : nat) : (m == 0 %[mod e])%A = (e %| m)%N. Proof. by rewrite eqAmod0_rat ?rpred_nat // dvdC_nat. Qed. (* Multiplicative order. *) Definition orderC x := let p := minCpoly x in oapp val 0%N [pick n : 'I_(2 * size p ^ 2) | p == intrp 'Phi_n]. Notation "#[ x ]" := (orderC x) : C_scope. Lemma exp_orderC x : x ^+ #[x]%C = 1. Proof. rewrite /orderC; case: pickP => //= [] [n _] /= /eqP Dp. have n_gt0: (0 < n)%N. rewrite lt0n; apply: contraTneq (size_minCpoly x) => n0. by rewrite Dp n0 Cyclotomic0 rmorph1 size_poly1. have [z prim_z] := C_prim_root_exists n_gt0. rewrite prim_expr_order // -(root_cyclotomic prim_z). by rewrite -Cintr_Cyclotomic // -Dp root_minCpoly. Qed. Lemma dvdn_orderC x n : (#[x]%C %| n)%N = (x ^+ n == 1). Proof. apply/idP/eqP=> [|x_n_1]; first by apply: expr_dvd; apply: exp_orderC. have [-> | n_gt0] := posnP n; first by rewrite dvdn0. have [m prim_x m_dv_n] := prim_order_exists n_gt0 x_n_1. have{n_gt0} m_gt0 := dvdn_gt0 n_gt0 m_dv_n; congr (_ %| n)%N: m_dv_n. pose p := minCpoly x; have Dp: p = cyclotomic x m := minCpoly_cyclotomic prim_x. rewrite /orderC; case: pickP => /= [k /eqP Dp_k | no_k]; last first. suffices lt_m_2p: (m < 2 * size p ^ 2)%N. have /eqP[] := no_k (Ordinal lt_m_2p). by rewrite /= -/p Dp -Cintr_Cyclotomic. rewrite Dp size_cyclotomic (sqrnD 1) addnAC mulnDr -add1n leq_add //. suffices: (m <= \prod_(q <- primes m | q == 2) q * totient m ^ 2)%N. have [m_even | m_odd] := boolP (2 \in primes m). by rewrite -big_filter filter_pred1_uniq ?primes_uniq // big_seq1. by rewrite big_hasC ?has_pred1 // => /leq_trans-> //; apply: leq_addl. rewrite big_mkcond totientE // -mulnn -!big_split /=. rewrite {1}[m]prod_prime_decomp // prime_decompE big_map /= !big_seq. elim/big_ind2: _ => // [n1 m1 n2 m2 | q]; first exact: leq_mul. rewrite mem_primes => /and3P[q_pr _ q_dv_m]. rewrite lognE q_pr m_gt0 q_dv_m /=; move: (logn q _) => k. rewrite !mulnA expnS leq_mul //. case: (ltngtP q) => // [|q_gt2 | ->]; first by rewrite ltnNge prime_gt1. rewrite mul1n mulnAC mulnn -{1}[q]muln1 leq_mul ?expn_gt0 ?prime_gt0 //. by rewrite -(subnKC q_gt2) (ltn_exp2l 1). by rewrite !muln1 -expnS (ltn_exp2l 0). have k_prim_x: k.-primitive_root x. have k_gt0: (0 < k)%N. rewrite lt0n; apply: contraTneq (size_minCpoly x) => k0. by rewrite Dp_k k0 Cyclotomic0 rmorph1 size_poly1. have [z prim_z] := C_prim_root_exists k_gt0. rewrite -(root_cyclotomic prim_z) -Cintr_Cyclotomic //. by rewrite -Dp_k root_minCpoly. apply/eqP; rewrite eqn_dvd !(@prim_order_dvd _ _ x) //. by rewrite !prim_expr_order ?eqxx. Qed. mathcomp-1.5/theories/fieldext.v0000644000175000017500000020525112307636117016003 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq div choice fintype. Require Import tuple finfun bigop ssralg finalg zmodp matrix vector falgebra. Require Import poly polydiv mxpoly generic_quotient. (******************************************************************************) (* * Finite dimensional field extentions *) (* fieldExtType F == the interface type for finite field extensions of F *) (* it simply combines the fieldType and FalgType F *) (* interfaces. *) (* [fieldExtType F of L] == a fieldExt F structure for a type L that has both *) (* fieldType and FalgType F canonical structures. *) (* [fieldExtType F of L for K] == a fieldExtType F structure for a type L *) (* that has an FalgType F canonical structure, given *) (* a K : fieldType whose unitRingType projection *) (* coincides with the canonical unitRingType for F. *) (* {subfield L} == the type of subfields of L that are also extensions *) (* of F; since we are in a finite dimensional setting *) (* these are exactly the F-subalgebras of L, and *) (* indeed {subfield L} is just display notation for *) (* {aspace L} when L is an extFieldType. *) (* --> All aspace operations apply to {subfield L}, but there are several *) (* additional lemmas and canonical instances specific to {subfield L} *) (* spaces, e.g., subvs_of E is an extFieldType F when E : {subfield L}. *) (* --> Also note that not all constructive subfields have type {subfield E} *) (* in the same way that not all constructive subspaces have type *) (* {vspace E}. These types only include the so called "detachable" *) (* subspaces (and subalgebras). *) (* *) (* (E :&: F)%AS, (E * F)%AS == the intersection and product (meet and join) *) (* of E and F as subfields. *) (* subFExtend iota z p == Given a field morphism iota : F -> L, this is a *) (* type for the field F^iota(z) obtained by *) (* adjoining z to the image of F in L under iota. *) (* The construction requires a non-zero polynomial *) (* p in F such that z is a root of p^iota; it *) (* returns the field F^iota if this is not so. *) (* However, p need not be irredicible. *) (* subfx_inj x == The injection of F^iota(z) into L. *) (* inj_subfx iota z p x == The injection of F into F^iota(z). *) (* subfx_eval iota z p q == Given q : {poly F} returns q.[z] as a value of *) (* type F^iota(z). *) (* subfx_root iota z p == The generator of F^iota(z) over F. *) (* SubFieldExtType pz0 irr_p == A fieldExtType F structure for F^iota(z) *) (* (more precisely, subFExtend iota z p), given *) (* proofs pz0: root (map_poly iota p) z and *) (* irr_p : irreducible_poly p. The corresponding *) (* vectType substructure (SubfxVectType pz0 irr_p) *) (* has dimension (size p).-1 over F. *) (* minPoly K x == the monic minimal polynomial of x over the *) (* subfield K. *) (* adjoin_degree K x == the degree of the minimial polynomial or the *) (* dimension of K(x)/K. *) (* Fadjoin_poly K x y == a polynomial p over K such that y = p.[x]. *) (* *) (* fieldOver F == L, but with an extFieldType (subvs_of F) *) (* structure, for F : {subfield L} *) (* vspaceOver F V == the smallest subspace of fieldOver F containing *) (* V; this coincides with V if V is an F-module. *) (* baseFieldType L == L, but with an extFieldType F0 structure, when L *) (* has a canonical extFieldType F structure and F *) (* in turn has an extFieldType F0 structure. *) (* baseVspace V == the subspace of baseFieldType L that coincides *) (* with V : {vspace L}. *) (* --> Some caution muse be exercised when using fieldOver and basFieldType, *) (* because these are convertible to L while carrying different Lmodule *) (* structures. This means that the safeguards engineered in the ssralg *) (* library that normally curb the Coq kernel's inclination to diverge are *) (* no longer effectcive, so additional precautions should be taken when *) (* matching or rewriting terms of the form a *: u, because Coq may take *) (* forever to realize it's dealing with a *: in the wrong structure. The *) (* baseField_scaleE and fieldOver_scaleE lemmas should be used to expand *) (* or fold such "trans-structure" operations explicitly beforehand. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Local Open Scope ring_scope. Import GRing.Theory. Module FieldExt. Import GRing. Section FieldExt. Variable R : ringType. Record class_of T := Class { base : Falgebra.class_of R T; comm_ext : commutative (Ring.mul base); idomain_ext : IntegralDomain.axiom (Ring.Pack base T); field_ext : Field.mixin_of (UnitRing.Pack base T) }. Local Coercion base : class_of >-> Falgebra.class_of. Section Bases. Variables (T : Type) (c : class_of T). Definition base1 := ComRing.Class (@comm_ext T c). Definition base2 := @ComUnitRing.Class T base1 c. Definition base3 := @IntegralDomain.Class T base2 (@idomain_ext T c). Definition base4 := @Field.Class T base3 (@field_ext T c). End Bases. Local Coercion base1 : class_of >-> ComRing.class_of. Local Coercion base2 : class_of >-> ComUnitRing.class_of. Local Coercion base3 : class_of >-> IntegralDomain.class_of. Local Coercion base4 : class_of >-> Field.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (phR : phant R) (T : Type) (cT : type phR). Definition class := let: Pack _ c _ := cT return class_of cT in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack := fun (bT : Falgebra.type phR) b & phant_id (Falgebra.class bT : Falgebra.class_of R bT) (b : Falgebra.class_of R T) => fun mT Cm IDm Fm & phant_id (Field.class mT) (@Field.Class T (@IntegralDomain.Class T (@ComUnitRing.Class T (@ComRing.Class T b Cm) b) IDm) Fm) => Pack phR (@Class T b Cm IDm Fm) T. Definition pack_eta K := let cK := Field.class K in let Cm := ComRing.mixin cK in let IDm := IntegralDomain.mixin cK in let Fm := Field.mixin cK in fun (bT : Falgebra.type phR) b & phant_id (Falgebra.class bT) b => fun cT_ & phant_id (@Class T b) cT_ => @Pack phR T (cT_ Cm IDm Fm) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. Definition unitRingType := @UnitRing.Pack cT xclass xT. Definition comRingType := @ComRing.Pack cT xclass xT. Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @IntegralDomain.Pack cT xclass xT. Definition fieldType := @Field.Pack cT xclass xT. Definition lmodType := @Lmodule.Pack R phR cT xclass xT. Definition lalgType := @Lalgebra.Pack R phR cT xclass xT. Definition algType := @Algebra.Pack R phR cT xclass xT. Definition unitAlgType := @UnitAlgebra.Pack R phR cT xclass xT. Definition vectType := @Vector.Pack R phR cT xclass xT. Definition FalgType := @Falgebra.Pack R phR cT xclass xT. Definition Falg_comRingType := @ComRing.Pack FalgType xclass xT. Definition Falg_comUnitRingType := @ComUnitRing.Pack FalgType xclass xT. Definition Falg_idomainType := @IntegralDomain.Pack FalgType xclass xT. Definition Falg_fieldType := @Field.Pack FalgType xclass xT. Definition vect_comRingType := @ComRing.Pack vectType xclass xT. Definition vect_comUnitRingType := @ComUnitRing.Pack vectType xclass xT. Definition vect_idomainType := @IntegralDomain.Pack vectType xclass xT. Definition vect_fieldType := @Field.Pack vectType xclass xT. Definition unitAlg_comRingType := @ComRing.Pack unitAlgType xclass xT. Definition unitAlg_comUnitRingType := @ComUnitRing.Pack unitAlgType xclass xT. Definition unitAlg_idomainType := @IntegralDomain.Pack unitAlgType xclass xT. Definition unitAlg_fieldType := @Field.Pack unitAlgType xclass xT. Definition alg_comRingType := @ComRing.Pack algType xclass xT. Definition alg_comUnitRingType := @ComUnitRing.Pack algType xclass xT. Definition alg_idomainType := @IntegralDomain.Pack algType xclass xT. Definition alg_fieldType := @Field.Pack algType xclass xT. Definition lalg_comRingType := @ComRing.Pack lalgType xclass xT. Definition lalg_comUnitRingType := @ComUnitRing.Pack lalgType xclass xT. Definition lalg_idomainType := @IntegralDomain.Pack lalgType xclass xT. Definition lalg_fieldType := @Field.Pack lalgType xclass xT. Definition lmod_comRingType := @ComRing.Pack lmodType xclass xT. Definition lmod_comUnitRingType := @ComUnitRing.Pack lmodType xclass xT. Definition lmod_idomainType := @IntegralDomain.Pack lmodType xclass xT. Definition lmod_fieldType := @Field.Pack lmodType xclass xT. End FieldExt. Module Exports. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion base : class_of >-> Falgebra.class_of. Coercion base4 : class_of >-> Field.class_of. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Coercion unitRingType : type >-> UnitRing.type. Canonical unitRingType. Coercion comRingType : type >-> ComRing.type. Canonical comRingType. Coercion comUnitRingType : type >-> ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> IntegralDomain.type. Canonical idomainType. Coercion fieldType : type >-> Field.type. Canonical fieldType. Coercion lmodType : type >-> Lmodule.type. Canonical lmodType. Coercion lalgType : type >-> Lalgebra.type. Canonical lalgType. Coercion algType : type >-> Algebra.type. Canonical algType. Coercion unitAlgType : type >-> UnitAlgebra.type. Canonical unitAlgType. Coercion vectType : type >-> Vector.type. Canonical vectType. Coercion FalgType : type >-> Falgebra.type. Canonical FalgType. Canonical Falg_comRingType. Canonical Falg_comUnitRingType. Canonical Falg_idomainType. Canonical Falg_fieldType. Canonical vect_comRingType. Canonical vect_comUnitRingType. Canonical vect_idomainType. Canonical vect_fieldType. Canonical unitAlg_comRingType. Canonical unitAlg_comUnitRingType. Canonical unitAlg_idomainType. Canonical unitAlg_fieldType. Canonical alg_comRingType. Canonical alg_comUnitRingType. Canonical alg_idomainType. Canonical alg_fieldType. Canonical lalg_comRingType. Canonical lalg_comUnitRingType. Canonical lalg_idomainType. Canonical lalg_fieldType. Canonical lmod_comRingType. Canonical lmod_comUnitRingType. Canonical lmod_idomainType. Canonical lmod_fieldType. Notation fieldExtType R := (type (Phant R)). Notation "[ 'fieldExtType' F 'of' L ]" := (@pack _ (Phant F) L _ _ id _ _ _ _ id) (at level 0, format "[ 'fieldExtType' F 'of' L ]") : form_scope. (*Notation "[ 'fieldExtType' F 'of' L 'for' K ]" := (@FieldExt.pack _ (Phant F) L _ _ id K _ _ _ idfun) (at level 0, format "[ 'fieldExtType' F 'of' L 'for' K ]") : form_scope. *) Notation "[ 'fieldExtType' F 'of' L 'for' K ]" := (@pack_eta _ (Phant F) L K _ _ id _ id) (at level 0, format "[ 'fieldExtType' F 'of' L 'for' K ]") : form_scope. Notation "{ 'subfield' L }" := (@aspace_of _ (FalgType _) (Phant L)) (at level 0, format "{ 'subfield' L }") : type_scope. End Exports. End FieldExt. Export FieldExt.Exports. Section FieldExtTheory. Variables (F0 : fieldType) (L : fieldExtType F0). Implicit Types (U V M : {vspace L}) (E F K : {subfield L}). Lemma dim_cosetv U x : x != 0 -> \dim (U * <[x]>) = \dim U. Proof. move=> nz_x; rewrite -limg_amulr limg_dim_eq //. apply/eqP; rewrite -subv0; apply/subvP=> y. by rewrite memv_cap memv0 memv_ker lfunE mulf_eq0 (negPf nz_x) orbF => /andP[]. Qed. Lemma prodvC : commutative (@prodv F0 L). Proof. move=> U V; without loss suffices subC: U V / (U * V <= V * U)%VS. by apply/eqP; rewrite eqEsubv !{1}subC. by apply/prodvP=> x y Ux Vy; rewrite mulrC memv_mul. Qed. Canonical prodv_comoid := Monoid.ComLaw prodvC. Lemma prodvCA : left_commutative (@prodv F0 L). Proof. exact: Monoid.mulmCA. Qed. Lemma prodvAC : right_commutative (@prodv F0 L). Proof. exact: Monoid.mulmAC. Qed. Lemma algid1 K : algid K = 1. Proof. exact/skew_field_algid1/fieldP. Qed. Lemma mem1v K : 1 \in K. Proof. by rewrite -algid_eq1 algid1. Qed. Lemma sub1v K : (1 <= K)%VS. Proof. exact: mem1v. Qed. Lemma subfield_closed K : agenv K = K. Proof. by apply/eqP; rewrite eqEsubv sub_agenv agenv_sub_modr ?sub1v ?asubv. Qed. Lemma AHom_lker0 (rT : FalgType F0) (f : 'AHom(L, rT)) : lker f == 0%VS. Proof. by apply/lker0P; apply: fmorph_inj. Qed. Lemma AEnd_lker0 (f : 'AEnd(L)) : lker f == 0%VS. Proof. exact: AHom_lker0. Qed. Fact aimg_is_aspace (rT : FalgType F0) (f : 'AHom(L, rT)) (E : {subfield L}) : is_aspace (f @: E). Proof. rewrite /is_aspace -aimgM limgS ?prodv_id // has_algid1 //. by apply/memv_imgP; exists 1; rewrite ?mem1v ?rmorph1. Qed. Canonical aimg_aspace rT f E := ASpace (@aimg_is_aspace rT f E). Lemma Fadjoin_idP {K x} : reflect (<>%VS = K) (x \in K). Proof. apply: (iffP idP) => [/addv_idPl-> | <-]; first exact: subfield_closed. exact: memv_adjoin. Qed. Lemma Fadjoin0 K : <>%VS = K. Proof. by rewrite addv0 subfield_closed. Qed. Lemma Fadjoin_nil K : <>%VS = K. Proof. by rewrite adjoin_nil subfield_closed. Qed. Lemma FadjoinP {K x E} : reflect (K <= E /\ x \in E)%VS (<>%AS <= E)%VS. Proof. apply: (iffP idP) => [sKxE | /andP]. by rewrite (subvP sKxE) ?memv_adjoin // (subv_trans _ sKxE) ?subv_adjoin. by rewrite -subv_add => /agenvS; rewrite subfield_closed. Qed. Lemma Fadjoin_seqP {K} {rs : seq L} {E} : reflect (K <= E /\ {subset rs <= E})%VS (<> <= E)%VS. Proof. apply: (iffP idP) => [sKrsE | [sKE /span_subvP/(conj sKE)/andP]]. split=> [|x rs_x]; first exact: subv_trans (subv_adjoin_seq _ _) sKrsE. by rewrite (subvP sKrsE) ?seqv_sub_adjoin. by rewrite -subv_add => /agenvS; rewrite subfield_closed. Qed. Lemma alg_polyOver E p : map_poly (in_alg L) p \is a polyOver E. Proof. by apply/(polyOverS (subvP (sub1v _)))/polyOver1P; exists p. Qed. Lemma sub_adjoin1v x E : (<<1; x>> <= E)%VS = (x \in E)%VS. Proof. by rewrite (sameP FadjoinP andP) sub1v. Qed. Fact vsval_multiplicative K : multiplicative (vsval : subvs_of K -> L). Proof. by split => //=; apply: algid1. Qed. Canonical vsval_rmorphism K := AddRMorphism (vsval_multiplicative K). Canonical vsval_lrmorphism K := [lrmorphism of (vsval : subvs_of K -> L)]. Lemma vsval_invf K (w : subvs_of K) : val w^-1 = (vsval w)^-1. Proof. have [-> | Uv] := eqVneq w 0; first by rewrite !invr0. by apply: vsval_invr; rewrite unitfE. Qed. Fact aspace_divr_closed K : divr_closed K. Proof. by split=> [|u v Ku Kv]; rewrite ?mem1v ?memvM ?memvV. Qed. Canonical aspace_mulrPred K := MulrPred (aspace_divr_closed K). Canonical aspace_divrPred K := DivrPred (aspace_divr_closed K). Canonical aspace_smulrPred K := SmulrPred (aspace_divr_closed K). Canonical aspace_sdivrPred K := SdivrPred (aspace_divr_closed K). Canonical aspace_semiringPred K := SemiringPred (aspace_divr_closed K). Canonical aspace_subringPred K := SubringPred (aspace_divr_closed K). Canonical aspace_subalgPred K := SubalgPred (memv_submod_closed K). Canonical aspace_divringPred K := DivringPred (aspace_divr_closed K). Canonical aspace_divalgPred K := DivalgPred (memv_submod_closed K). Definition subvs_mulC K := [comRingMixin of subvs_of K by <:]. Canonical subvs_comRingType K := Eval hnf in ComRingType (subvs_of K) (@subvs_mulC K). Canonical subvs_comUnitRingType K := Eval hnf in [comUnitRingType of subvs_of K]. Definition subvs_mul_eq0 K := [idomainMixin of subvs_of K by <:]. Canonical subvs_idomainType K := Eval hnf in IdomainType (subvs_of K) (@subvs_mul_eq0 K). Lemma subvs_fieldMixin K : GRing.Field.mixin_of (@subvs_idomainType K). Proof. by move=> w nz_w; rewrite unitrE -val_eqE /= vsval_invf algid1 divff. Qed. Canonical subvs_fieldType K := Eval hnf in FieldType (subvs_of K) (@subvs_fieldMixin K). Canonical subvs_fieldExtType K := Eval hnf in [fieldExtType F0 of subvs_of K]. Lemma polyOver_subvs {K} {p : {poly L}} : reflect (exists q : {poly subvs_of K}, p = map_poly vsval q) (p \is a polyOver K). Proof. apply: (iffP polyOverP) => [Hp | [q ->] i]; last by rewrite coef_map // subvsP. exists (\poly_(i < size p) (Subvs (Hp i))); rewrite -{1}[p]coefK. by apply/polyP=> i; rewrite coef_map !coef_poly; case: ifP. Qed. Lemma divp_polyOver K : {in polyOver K &, forall p q, p %/ q \is a polyOver K}. Proof. move=> _ _ /polyOver_subvs[p ->] /polyOver_subvs[q ->]. by apply/polyOver_subvs; exists (p %/ q); rewrite map_divp. Qed. Lemma modp_polyOver K : {in polyOver K &, forall p q, p %% q \is a polyOver K}. Proof. move=> _ _ /polyOver_subvs[p ->] /polyOver_subvs[q ->]. by apply/polyOver_subvs; exists (p %% q); rewrite map_modp. Qed. Lemma gcdp_polyOver K : {in polyOver K &, forall p q, gcdp p q \is a polyOver K}. Proof. move=> _ _ /polyOver_subvs[p ->] /polyOver_subvs[q ->]. by apply/polyOver_subvs; exists (gcdp p q); rewrite gcdp_map. Qed. Fact prodv_is_aspace E F : is_aspace (E * F). Proof. rewrite /is_aspace prodvCA -!prodvA prodvA !prodv_id has_algid1 //=. by rewrite -[1]mulr1 memv_mul ?mem1v. Qed. Canonical prodv_aspace E F : {subfield L} := ASpace (prodv_is_aspace E F). Fact field_mem_algid E F : algid E \in F. Proof. by rewrite algid1 mem1v. Qed. Canonical capv_aspace E F : {subfield L} := aspace_cap (field_mem_algid E F). Lemma polyOverSv U V : (U <= V)%VS -> {subset polyOver U <= polyOver V}. Proof. by move/subvP=> sUV; apply: polyOverS. Qed. Lemma field_subvMl F U : (U <= F * U)%VS. Proof. by rewrite -{1}[U]prod1v prodvSl ?sub1v. Qed. Lemma field_subvMr U F : (U <= U * F)%VS. Proof. by rewrite prodvC field_subvMl. Qed. Lemma field_module_eq F M : (F * M <= M)%VS -> (F * M)%VS = M. Proof. by move=> modM; apply/eqP; rewrite eqEsubv modM field_subvMl. Qed. Lemma sup_field_module F E : (F * E <= E)%VS = (F <= E)%VS. Proof. apply/idP/idP; first exact: subv_trans (field_subvMr F E). by move/(prodvSl E)/subv_trans->; rewrite ?asubv. Qed. Lemma field_module_dimS F M : (F * M <= M)%VS -> (\dim F %| \dim M)%N. Proof. exact/skew_field_module_dimS/fieldP. Qed. Lemma field_dimS F E : (F <= E)%VS -> (\dim F %| \dim E)%N. Proof. exact/skew_field_dimS/fieldP. Qed. Lemma dim_field_module F M : (F * M <= M)%VS -> \dim M = (\dim_F M * \dim F)%N. Proof. by move/field_module_dimS/divnK. Qed. Lemma dim_sup_field F E : (F <= E)%VS -> \dim E = (\dim_F E * \dim F)%N. Proof. by move/field_dimS/divnK. Qed. Lemma field_module_semisimple F M (m := \dim_F M) : (F * M <= M)%VS -> {X : m.-tuple L | {subset X <= M} /\ 0 \notin X & let FX := (\sum_(i < m) F * <[X`_i]>)%VS in FX = M /\ directv FX}. Proof. move=> modM; have dimM: (m * \dim F)%N = \dim M by rewrite -dim_field_module. have [X [defM dxFX nzX]] := skew_field_module_semisimple (@fieldP L) modM. have szX: size X == m. rewrite -(eqn_pmul2r (adim_gt0 F)) dimM -defM (directvP dxFX) /=. rewrite -sum1_size big_distrl; apply/eqP/eq_big_seq => x Xx /=. by rewrite mul1n dim_cosetv ?(memPn nzX). rewrite directvE /= !(big_nth 0) (eqP szX) !big_mkord -directvE /= in defM dxFX. exists (Tuple szX) => //; split=> // _ /tnthP[i ->]; rewrite (tnth_nth 0) /=. by rewrite -defM memvE (sumv_sup i) ?field_subvMl. Qed. Section FadjoinPolyDefinitions. Variables (U : {vspace L}) (x : L). Definition adjoin_degree := (\dim_U <>).-1.+1. Local Notation n := adjoin_degree. Definition Fadjoin_sum := (\sum_(i < n) U * <[x ^+ i]>)%VS. Definition Fadjoin_poly v : {poly L} := \poly_(i < n) (sumv_pi Fadjoin_sum (inord i) v / x ^+ i). Definition minPoly : {poly L} := 'X^n - Fadjoin_poly (x ^+ n). Lemma size_Fadjoin_poly v : size (Fadjoin_poly v) <= n. Proof. exact: size_poly. Qed. Lemma Fadjoin_polyOver v : Fadjoin_poly v \is a polyOver U. Proof. apply/(all_nthP 0) => i _; rewrite coef_poly /=. case: ifP => lti; last exact: mem0v. have /memv_cosetP[y Uy ->] := memv_sum_pi (erefl Fadjoin_sum) (inord i) v. rewrite inordK //; have [-> | /mulfK-> //] := eqVneq (x ^+ i) 0. by rewrite mulr0 mul0r mem0v. Qed. Fact Fadjoin_poly_is_linear : linear_for (in_alg L \; *:%R) Fadjoin_poly. Proof. move=> a u v; apply/polyP=> i; rewrite coefD coefZ !coef_poly. case: ifP => lti; last by rewrite mulr0 addr0. by rewrite linearP mulrA -mulrDl mulr_algl. Qed. Canonical Fadjoin_poly_additive := Additive Fadjoin_poly_is_linear. Canonical Fadjoin_poly_linear := AddLinear Fadjoin_poly_is_linear. Lemma size_minPoly : size minPoly = n.+1. Proof. by rewrite size_addl ?size_polyXn // size_opp ltnS size_poly. Qed. Lemma monic_minPoly : minPoly \is monic. Proof. rewrite monicE /lead_coef size_minPoly coefB coefXn eqxx. by rewrite nth_default ?subr0 ?size_poly. Qed. End FadjoinPolyDefinitions. Section FadjoinPoly. Variables (K : {subfield L}) (x : L). Local Notation n := (adjoin_degree (asval K) x). Local Notation sumKx := (Fadjoin_sum (asval K) x). Lemma adjoin_degreeE : n = \dim_K <>. Proof. by rewrite [n]prednK // divn_gt0 ?adim_gt0 // dimvS ?subv_adjoin. Qed. Lemma dim_Fadjoin : \dim <> = (n * \dim K)%N. Proof. by rewrite adjoin_degreeE -dim_sup_field ?subv_adjoin. Qed. Lemma adjoin0_deg : adjoin_degree K 0 = 1%N. Proof. by rewrite /adjoin_degree addv0 subfield_closed divnn adim_gt0. Qed. Lemma adjoin_deg_eq1 : (n == 1%N) = (x \in K). Proof. rewrite (sameP Fadjoin_idP eqP) adjoin_degreeE; have sK_Kx := subv_adjoin K x. apply/eqP/idP=> [dimKx1 | /eqP->]; last by rewrite divnn adim_gt0. by rewrite eq_sym eqEdim sK_Kx /= (dim_sup_field sK_Kx) dimKx1 mul1n. Qed. Lemma Fadjoin_sum_direct : directv sumKx. Proof. rewrite directvE /=; case Dn: {-2}n (leqnn n) => // [m] {Dn}. elim: m => [|m IHm] ltm1n; rewrite ?big_ord1 // !(big_ord_recr m.+1) /=. do [move/(_ (ltnW ltm1n))/eqP; set S := (\sum_i _)%VS] in IHm *. rewrite -IHm dimv_add_leqif; apply/subvP=> z; rewrite memv_cap => /andP[Sz]. case/memv_cosetP=> y Ky Dz; rewrite memv0 Dz mulf_eq0 expf_eq0 /=. apply: contraLR ltm1n => /norP[nz_y nz_x]. rewrite -leqNgt -(leq_pmul2r (adim_gt0 K)) -dim_Fadjoin. have{IHm} ->: (m.+1 * \dim K)%N = \dim S. rewrite -[m.+1]card_ord -sum_nat_const IHm. by apply: eq_bigr => i; rewrite dim_cosetv ?expf_neq0. apply/dimvS/agenv_sub_modl; first by rewrite (sumv_sup 0) //= prodv1 sub1v. rewrite prodvDl subv_add -[S]big_distrr prodvA prodv_id subvv !big_distrr /=. apply/subv_sumP=> i _; rewrite -expv_line prodvCA -expvSl expv_line. have [ltim | lemi] := ltnP i m; first by rewrite (sumv_sup (Sub i.+1 _)). have{lemi} /eqP->: i == m :> nat by rewrite eqn_leq leq_ord. rewrite -big_distrr -2!{2}(prodv_id K) /= -!prodvA big_distrr -/S prodvSr //=. by rewrite -(canLR (mulKf nz_y) Dz) -memvE memv_mul ?rpredV. Qed. Let nz_x_i (i : 'I_n) : x ^+ i != 0. Proof. by rewrite expf_eq0; case: eqP i => [->|_] [[]] //; rewrite adjoin0_deg. Qed. Lemma Fadjoin_eq_sum : <>%VS = sumKx. Proof. apply/esym/eqP; rewrite eqEdim eq_leq ?andbT. apply/subv_sumP=> i _; rewrite -agenvM prodvS ?subv_adjoin //. by rewrite -expv_line (subv_trans (subX_agenv _ _)) ?agenvS ?addvSr. rewrite dim_Fadjoin -[n]card_ord -sum_nat_const (directvP Fadjoin_sum_direct). by apply: eq_bigr => i _; rewrite /= dim_cosetv. Qed. Lemma Fadjoin_poly_eq v : v \in <>%VS -> (Fadjoin_poly K x v).[x] = v. Proof. move/(sumv_pi_sum Fadjoin_eq_sum)=> {2}<-; rewrite horner_poly. by apply: eq_bigr => i _; rewrite inord_val mulfVK. Qed. Lemma mempx_Fadjoin p : p \is a polyOver K -> p.[x] \in <>%VS. Proof. move=> Kp; rewrite rpred_horner ?memv_adjoin ?(polyOverS _ Kp) //. exact: subvP_adjoin. Qed. Lemma Fadjoin_polyP {v} : reflect (exists2 p, p \in polyOver K & v = p.[x]) (v \in <>%VS). Proof. apply: (iffP idP) => [Kx_v | [p Kp ->]]; last exact: mempx_Fadjoin. by exists (Fadjoin_poly K x v); rewrite ?Fadjoin_polyOver ?Fadjoin_poly_eq. Qed. Lemma Fadjoin_poly_unique p v : p \is a polyOver K -> size p <= n -> p.[x] = v -> Fadjoin_poly K x v = p. Proof. have polyKx q i: q \is a polyOver K -> q`_i * x ^+ i \in (K * <[x ^+ i]>)%VS. by move/polyOverP=> Kq; rewrite memv_mul ?Kq ?memv_line. move=> Kp szp Dv; have /Fadjoin_poly_eq/eqP := mempx_Fadjoin Kp. rewrite {1}Dv {Dv} !(@horner_coef_wide _ n) ?size_poly //. move/polyKx in Kp; have /polyKx K_pv := Fadjoin_polyOver K x v. rewrite (directv_sum_unique Fadjoin_sum_direct) // => /eqfunP eq_pq. apply/polyP=> i; have [leni|?] := leqP n i; last exact: mulIf (eq_pq (Sub i _)). by rewrite !nth_default ?(leq_trans _ leni) ?size_poly. Qed. Lemma Fadjoin_polyC v : v \in K -> Fadjoin_poly K x v = v%:P. Proof. move=> Kv; apply: Fadjoin_poly_unique; rewrite ?polyOverC ?hornerC //. by rewrite size_polyC (leq_trans (leq_b1 _)). Qed. Lemma Fadjoin_polyX : x \notin K -> Fadjoin_poly K x x = 'X. Proof. move=> K'x; apply: Fadjoin_poly_unique; rewrite ?polyOverX ?hornerX //. by rewrite size_polyX ltn_neqAle andbT eq_sym adjoin_deg_eq1. Qed. Lemma minPolyOver : minPoly K x \is a polyOver K. Proof. by rewrite /minPoly rpredB ?rpredX ?polyOverX ?Fadjoin_polyOver. Qed. Lemma minPolyxx : (minPoly K x).[x] = 0. Proof. by rewrite !hornerE hornerXn Fadjoin_poly_eq ?subrr ?rpredX ?memv_adjoin. Qed. Lemma root_minPoly : root (minPoly K x) x. Proof. exact/rootP/minPolyxx. Qed. Lemma Fadjoin_poly_mod p : p \is a polyOver K -> Fadjoin_poly K x p.[x] = p %% minPoly K x. Proof. move=> Kp; rewrite {1}(divp_eq p (minPoly K x)) 2!hornerE minPolyxx mulr0 add0r. apply: Fadjoin_poly_unique => //; first by rewrite modp_polyOver // minPolyOver. by rewrite -ltnS -size_minPoly ltn_modp // monic_neq0 ?monic_minPoly. Qed. Lemma minPoly_XsubC : reflect (minPoly K x = 'X - x%:P) (x \in K). Proof. set p := minPoly K x; apply: (iffP idP) => [Kx | Dp]; last first. suffices ->: x = - p`_0 by rewrite rpredN (polyOverP minPolyOver). by rewrite Dp coefB coefX coefC add0r opprK. rewrite (@all_roots_prod_XsubC _ p [:: x]) /= ?root_minPoly //. by rewrite big_seq1 (monicP (monic_minPoly K x)) scale1r. by apply/eqP; rewrite size_minPoly eqSS adjoin_deg_eq1. Qed. Lemma root_small_adjoin_poly p : p \is a polyOver K -> size p <= n -> root p x = (p == 0). Proof. move=> Kp szp; apply/rootP/eqP=> [px0 | ->]; last by rewrite horner0. rewrite -(Fadjoin_poly_unique Kp szp px0). by apply: Fadjoin_poly_unique; rewrite ?polyOver0 ?size_poly0 ?horner0. Qed. Lemma minPoly_irr p : p \is a polyOver K -> p %| minPoly K x -> (p %= minPoly K x) || (p %= 1). Proof. rewrite dvdp_eq; set q := _ %/ _ => Kp def_pq. have Kq: q \is a polyOver K by rewrite divp_polyOver // minPolyOver. move: q Kq def_pq root_minPoly (size_minPoly K x) => q Kq /eqP->. rewrite rootM => pqx0 szpq. have [nzq nzp]: q != 0 /\ p != 0. by apply/norP; rewrite -mulf_eq0 -size_poly_eq0 szpq. without loss{pqx0} qx0: q p Kp Kq nzp nzq szpq / root q x. move=> IH; case/orP: pqx0 => /IH{IH}IH; first exact: IH. have{IH} /orP[]: (q %= p * q) || (q %= 1) by apply: IH => //; rewrite mulrC. by rewrite orbC -{1}[q]mul1r eqp_mul2r // eqp_sym => ->. by rewrite -{1}[p]mul1r eqp_sym eqp_mul2r // => ->. apply/orP; right; rewrite -size_poly_eq1 eqn_leq lt0n size_poly_eq0 nzp andbT. rewrite -(leq_add2r (size q)) -leq_subLR subn1 -size_mul // mulrC szpq. by rewrite ltnNge; apply: contra nzq => /(root_small_adjoin_poly Kq) <-. Qed. Lemma minPoly_dvdp p : p \is a polyOver K -> root p x -> (minPoly K x) %| p. Proof. move=> Kp rootp. have gcdK : gcdp (minPoly K x) p \is a polyOver K. by rewrite gcdp_polyOver ?minPolyOver. have /orP[gcd_eqK|gcd_eq1] := minPoly_irr gcdK (dvdp_gcdl (minPoly K x) p). by rewrite -(eqp_dvdl _ gcd_eqK) dvdp_gcdr. case/negP: (root1 x). by rewrite -(eqp_root gcd_eq1) root_gcd rootp root_minPoly. Qed. End FadjoinPoly. Lemma minPolyS K E a : (K <= E)%VS -> minPoly E a %| minPoly K a. Proof. move=> sKE; apply: minPoly_dvdp; last exact: root_minPoly. by apply: (polyOverSv sKE); rewrite minPolyOver. Qed. Implicit Arguments Fadjoin_polyP [K x v]. Lemma Fadjoin1_polyP x v : reflect (exists p, v = (map_poly (in_alg L) p).[x]) (v \in <<1; x>>%VS). Proof. apply: (iffP Fadjoin_polyP) => [[_ /polyOver1P]|] [p ->]; first by exists p. by exists (map_poly (in_alg L) p) => //; apply: alg_polyOver. Qed. Section Horner. Variables z : L. Definition fieldExt_horner := horner_morph (fun x => mulrC z (in_alg L x)). Canonical fieldExtHorner_additive := [additive of fieldExt_horner]. Canonical fieldExtHorner_rmorphism := [rmorphism of fieldExt_horner]. Lemma fieldExt_hornerC b : fieldExt_horner b%:P = b%:A. Proof. exact: horner_morphC. Qed. Lemma fieldExt_hornerX : fieldExt_horner 'X = z. Proof. exact: horner_morphX. Qed. Fact fieldExt_hornerZ : scalable fieldExt_horner. Proof. move=> a p; rewrite -mul_polyC rmorphM /= fieldExt_hornerC. by rewrite -scalerAl mul1r. Qed. Canonical fieldExt_horner_linear := AddLinear fieldExt_hornerZ. Canonical fieldExt_horner_lrmorhism := [lrmorphism of fieldExt_horner]. End Horner. End FieldExtTheory. Notation "E :&: F" := (capv_aspace E F) : aspace_scope. Notation "'C_ E [ x ]" := (capv_aspace E 'C[x]) : aspace_scope. Notation "'C_ ( E ) [ x ]" := (capv_aspace E 'C[x]) (only parsing) : aspace_scope. Notation "'C_ E ( V )" := (capv_aspace E 'C(V)) : aspace_scope. Notation "'C_ ( E ) ( V )" := (capv_aspace E 'C(V)) (only parsing) : aspace_scope. Notation "E * F" := (prodv_aspace E F) : aspace_scope. Notation "f @: E" := (aimg_aspace f E) : aspace_scope. Implicit Arguments Fadjoin_idP [F0 L K x]. Implicit Arguments FadjoinP [F0 L K x E]. Implicit Arguments Fadjoin_seqP [F0 L K rs E]. Implicit Arguments polyOver_subvs [F0 L K p]. Implicit Arguments Fadjoin_polyP [F0 L K x v]. Implicit Arguments Fadjoin1_polyP [F0 L x v]. Implicit Arguments minPoly_XsubC [F0 L K x]. Section MapMinPoly. Variables (F0 : fieldType) (L rL : fieldExtType F0) (f : 'AHom(L, rL)). Variables (K : {subfield L}) (x : L). Lemma adjoin_degree_aimg : adjoin_degree (f @: K) (f x) = adjoin_degree K x. Proof. rewrite !adjoin_degreeE -aimg_adjoin. by rewrite !limg_dim_eq ?(eqP (AHom_lker0 f)) ?capv0. Qed. Lemma map_minPoly : map_poly f (minPoly K x) = minPoly (f @: K) (f x). Proof. set fp := minPoly (f @: K) (f x); pose fM := [rmorphism of f]. have [p Kp Dp]: exists2 p, p \is a polyOver K & map_poly f p = fp. have Kfp: fp \is a polyOver (f @: K)%VS by apply: minPolyOver. exists (map_poly f^-1%VF fp). apply/polyOver_poly=> j _; have /memv_imgP[y Ky ->] := polyOverP Kfp j. by rewrite lker0_lfunK ?AHom_lker0. rewrite -map_poly_comp map_poly_id // => _ /(allP Kfp)/memv_imgP[y _ ->]. by rewrite /= limg_lfunVK ?memv_img ?memvf. apply/eqP; rewrite -eqp_monic ?monic_map ?monic_minPoly // -Dp eqp_map. have: ~~ (p %= 1) by rewrite -size_poly_eq1 -(size_map_poly fM) Dp size_minPoly. apply: implyP; rewrite implyNb orbC eqp_sym minPoly_irr //. rewrite -(dvdp_map fM) Dp minPoly_dvdp ?fmorph_root ?root_minPoly //. by apply/polyOver_poly=> j _; apply/memv_img/polyOverP/minPolyOver. Qed. End MapMinPoly. (* Changing up the reference field of a fieldExtType. *) Section FieldOver. Variables (F0 : fieldType) (L : fieldExtType F0) (F : {subfield L}). Definition fieldOver of {vspace L} : Type := L. Local Notation K_F := (subvs_of F). Local Notation L_F := (fieldOver F). Canonical fieldOver_eqType := [eqType of L_F]. Canonical fieldOver_choiceType := [choiceType of L_F]. Canonical fieldOver_zmodType := [zmodType of L_F]. Canonical fieldOver_ringType := [ringType of L_F]. Canonical fieldOver_unitRingType := [unitRingType of L_F]. Canonical fieldOver_comRingType := [comRingType of L_F]. Canonical fieldOver_comUnitRingType := [comUnitRingType of L_F]. Canonical fieldOver_idomainType := [idomainType of L_F]. Canonical fieldOver_fieldType := [fieldType of L_F]. Definition fieldOver_scale (a : K_F) (u : L_F) : L_F := vsval a * u. Local Infix "*F:" := fieldOver_scale (at level 40). Fact fieldOver_scaleA a b u : a *F: (b *F: u) = (a * b) *F: u. Proof. exact: mulrA. Qed. Fact fieldOver_scale1 u : 1 *F: u = u. Proof. by rewrite /(1 *F: u) /= algid1 mul1r. Qed. Fact fieldOver_scaleDr a u v : a *F: (u + v) = a *F: u + a *F: v. Proof. exact: mulrDr. Qed. Fact fieldOver_scaleDl v a b : (a + b) *F: v = a *F: v + b *F: v. Proof. exact: mulrDl. Qed. Definition fieldOver_lmodMixin := LmodMixin fieldOver_scaleA fieldOver_scale1 fieldOver_scaleDr fieldOver_scaleDl. Canonical fieldOver_lmodType := LmodType K_F L_F fieldOver_lmodMixin. Lemma fieldOver_scaleE a (u : L) : a *: (u : L_F) = vsval a * u. Proof. by []. Qed. Fact fieldOver_scaleAl a u v : a *F: (u * v) = (a *F: u) * v. Proof. exact: mulrA. Qed. Canonical fieldOver_lalgType := LalgType K_F L_F fieldOver_scaleAl. Fact fieldOver_scaleAr a u v : a *F: (u * v) = u * (a *F: v). Proof. exact: mulrCA. Qed. Canonical fieldOver_algType := AlgType K_F L_F fieldOver_scaleAr. Canonical fieldOver_unitAlgType := [unitAlgType K_F of L_F]. Fact fieldOver_vectMixin : Vector.mixin_of fieldOver_lmodType. Proof. have [bL [_ nz_bL] [defL dxSbL]] := field_module_semisimple (subvf (F * _)). do [set n := \dim_F {:L} in bL nz_bL *; set SbL := (\sum_i _)%VS] in defL dxSbL. have in_bL i (a : K_F) : val a * (bL`_i : L_F) \in (F * <[bL`_i]>)%VS. by rewrite memv_mul ?(valP a) ?memv_line. have nz_bLi (i : 'I_n): bL`_i != 0 by rewrite (memPn nz_bL) ?memt_nth. pose r2v (v : 'rV[K_F]_n) : L_F := \sum_i v 0 i *: (bL`_i : L_F). have r2v_lin: linear r2v. move=> a u v; rewrite /r2v scaler_sumr -big_split /=; apply: eq_bigr => i _. by rewrite scalerA -scalerDl !mxE. have v2rP x: {r : 'rV[K_F]_n | x = r2v r}. apply: sig_eqW; have /memv_sumP[y Fy ->]: x \in SbL by rewrite defL memvf. have /fin_all_exists[r Dr] i: exists r, y i = r *: (bL`_i : L_F). by have /memv_cosetP[a Fa ->] := Fy i isT; exists (Subvs Fa). by exists (\row_i r i); apply: eq_bigr => i _; rewrite mxE. pose v2r x := sval (v2rP x). have v2rK: cancel v2r (Linear r2v_lin) by rewrite /v2r => x; case: (v2rP x). suffices r2vK: cancel r2v v2r. by exists n, v2r; [exact: can2_linear v2rK | exists r2v]. move=> r; apply/rowP=> i; apply/val_inj/(mulIf (nz_bLi i))/eqP; move: i isT. by apply/forall_inP; move/directv_sum_unique: dxSbL => <- //; exact/eqP/v2rK. Qed. Canonical fieldOver_vectType := VectType K_F L_F fieldOver_vectMixin. Canonical fieldOver_FalgType := [FalgType K_F of L_F]. Canonical fieldOver_fieldExtType := [fieldExtType K_F of L_F]. Implicit Types (V : {vspace L}) (E : {subfield L}). Lemma trivial_fieldOver : (1%VS : {vspace L_F}) =i F. Proof. move=> x; apply/vlineP/idP=> [[{x}x ->] | Fx]. by rewrite fieldOver_scaleE mulr1 (valP x). by exists (vsproj F x); rewrite fieldOver_scaleE mulr1 vsprojK. Qed. Definition vspaceOver V := <>%VS. Lemma mem_vspaceOver V : vspaceOver V =i (F * V)%VS. Proof. move=> y; apply/idP/idP; last rewrite unlock; move=> /coord_span->. rewrite (@memv_suml F0 L) // => i _. by rewrite memv_mul ?subvsP // vbasis_mem ?memt_nth. rewrite memv_suml // => ij _; rewrite -tnth_nth; set x := tnth _ ij. have/allpairsP[[u z] /= [Fu Vz {x}->]]: x \in _ := mem_tnth ij _. by rewrite scalerAl (memvZ (Subvs _)) ?memvZ ?memv_span //= vbasis_mem. Qed. Lemma mem_aspaceOver E : (F <= E)%VS -> vspaceOver E =i E. Proof. by move=> sFE y; rewrite mem_vspaceOver field_module_eq ?sup_field_module. Qed. Fact aspaceOver_suproof E : is_aspace (vspaceOver E). Proof. rewrite /is_aspace has_algid1; last by rewrite mem_vspaceOver (@mem1v _ L). by apply/prodvP=> u v; rewrite !mem_vspaceOver; exact: memvM. Qed. Canonical aspaceOver E := ASpace (aspaceOver_suproof E). Lemma dim_vspaceOver M : (F * M <= M)%VS -> \dim (vspaceOver M) = \dim_F M. Proof. move=> modM; have [] := field_module_semisimple modM. set n := \dim_F M => b [Mb nz_b] [defM dx_b]. suff: basis_of (vspaceOver M) b by apply: size_basis. apply/andP; split. rewrite eqEsubv; apply/andP; split; apply/span_subvP=> u. by rewrite mem_vspaceOver field_module_eq // => /Mb. move/(@vbasis_mem _ _ _ M); rewrite -defM => /memv_sumP[{u}u Fu ->]. apply: memv_suml => i _; have /memv_cosetP[a Fa ->] := Fu i isT. by apply: (memvZ (Subvs Fa)); rewrite memv_span ?memt_nth. apply/freeP=> a /(directv_sum_independent dx_b) a_0 i. have{a_0}: a i *: (b`_i : L_F) == 0. by rewrite a_0 {i}// => i _; rewrite memv_mul ?memv_line ?subvsP. by rewrite scaler_eq0=> /predU1P[] // /idPn[]; rewrite (memPn nz_b) ?memt_nth. Qed. Lemma dim_aspaceOver E : (F <= E)%VS -> \dim (vspaceOver E) = \dim_F E. Proof. by rewrite -sup_field_module; exact: dim_vspaceOver. Qed. Lemma vspaceOverP V_F : {V | [/\ V_F = vspaceOver V, (F * V <= V)%VS & V_F =i V]}. Proof. pose V := (F * <>)%VS. have idV: (F * V)%VS = V by rewrite prodvA prodv_id. suffices defVF: V_F = vspaceOver V. by exists V; split=> [||u]; rewrite ?defVF ?mem_vspaceOver ?idV. apply/vspaceP=> v; rewrite mem_vspaceOver idV. do [apply/idP/idP; last rewrite /V unlock] => [/coord_vbasis|/coord_span] ->. by apply: memv_suml => i _; rewrite memv_mul ?subvsP ?memv_span ?memt_nth. apply: memv_suml => i _; rewrite -tnth_nth; set xu := tnth _ i. have /allpairsP[[x u] /=]: xu \in _ := mem_tnth i _. case=> /vbasis_mem Fx /vbasis_mem Vu ->. rewrite scalerAl (coord_span Vu) mulr_sumr memv_suml // => j_. by rewrite -scalerCA (memvZ (Subvs _)) ?memvZ // vbasis_mem ?memt_nth. Qed. Lemma aspaceOverP (E_F : {subfield L_F}) : {E | [/\ E_F = aspaceOver E, (F <= E)%VS & E_F =i E]}. Proof. have [V [defEF modV memV]] := vspaceOverP E_F. have algE: has_algid V && (V * V <= V)%VS. rewrite has_algid1; last by rewrite -memV mem1v. by apply/prodvP=> u v; rewrite -!memV; exact: memvM. by exists (ASpace algE); rewrite -sup_field_module; split; first exact: val_inj. Qed. End FieldOver. (* Changing the reference field to a smaller field. *) Section BaseField. Variables (F0 : fieldType) (F : fieldExtType F0) (L : fieldExtType F). Definition baseField_type of phant L : Type := L. Notation L0 := (baseField_type (Phant (FieldExt.sort L))). Canonical baseField_eqType := [eqType of L0]. Canonical baseField_choiceType := [choiceType of L0]. Canonical baseField_zmodType := [zmodType of L0]. Canonical baseField_ringType := [ringType of L0]. Canonical baseField_unitRingType := [unitRingType of L0]. Canonical baseField_comRingType := [comRingType of L0]. Canonical baseField_comUnitRingType := [comUnitRingType of L0]. Canonical baseField_idomainType := [idomainType of L0]. Canonical baseField_fieldType := [fieldType of L0]. Definition baseField_scale (a : F0) (u : L0) : L0 := in_alg F a *: u. Local Infix "*F0:" := baseField_scale (at level 40). Fact baseField_scaleA a b u : a *F0: (b *F0: u) = (a * b) *F0: u. Proof. by rewrite [_ *F0: _]scalerA -rmorphM. Qed. Fact baseField_scale1 u : 1 *F0: u = u. Proof. by rewrite /(1 *F0: u) rmorph1 scale1r. Qed. Fact baseField_scaleDr a u v : a *F0: (u + v) = a *F0: u + a *F0: v. Proof. exact: scalerDr. Qed. Fact baseField_scaleDl v a b : (a + b) *F0: v = a *F0: v + b *F0: v. Proof. by rewrite -scalerDl -rmorphD. Qed. Definition baseField_lmodMixin := LmodMixin baseField_scaleA baseField_scale1 baseField_scaleDr baseField_scaleDl. Canonical baseField_lmodType := LmodType F0 L0 baseField_lmodMixin. Lemma baseField_scaleE a (u : L) : a *: (u : L0) = a%:A *: u. Proof. by []. Qed. Fact baseField_scaleAl a (u v : L0) : a *F0: (u * v) = (a *F0: u) * v. Proof. exact: scalerAl. Qed. Canonical baseField_lalgType := LalgType F0 L0 baseField_scaleAl. Fact baseField_scaleAr a u v : a *F0: (u * v) = u * (a *F0: v). Proof. exact: scalerAr. Qed. Canonical baseField_algType := AlgType F0 L0 baseField_scaleAr. Canonical baseField_unitAlgType := [unitAlgType F0 of L0]. Let n := \dim {:F}. Let bF : n.-tuple F := vbasis {:F}. Let coordF (x : F) := (coord_vbasis (memvf x)). Fact baseField_vectMixin : Vector.mixin_of baseField_lmodType. Proof. pose bL := vbasis {:L}; set m := \dim {:L} in bL. pose v2r (x : L0) := mxvec (\matrix_(i, j) coord bF j (coord bL i x)). have v2r_lin: linear v2r. move=> a x y; rewrite -linearP; congr (mxvec _); apply/matrixP=> i j. by rewrite !mxE linearP mulr_algl linearP. pose r2v r := \sum_(i < m) (\sum_(j < n) vec_mx r i j *: bF`_j) *: bL`_i. have v2rK: cancel v2r r2v. move=> x; transitivity (\sum_(i < m) coord bL i x *: bL`_i); last first. by rewrite -coord_vbasis ?memvf. (* GG: rewrite {2}(coord_vbasis (memvf x)) -/m would take 8s; *) (* The -/m takes 8s, and without it then apply: eq_bigr takes 12s. *) (* The time drops to 2s with a -[GRing.Field.ringType F]/(F : fieldType) *) apply: eq_bigr => i _; rewrite mxvecK; congr (_ *: _ : L). by rewrite (coordF (coord bL i x)); apply: eq_bigr => j _; rewrite mxE. exists (m * n)%N, v2r => //; exists r2v => // r. apply: (canLR vec_mxK); apply/matrixP=> i j; rewrite mxE. by rewrite !coord_sum_free ?(basis_free (vbasisP _)). Qed. Canonical baseField_vectType := VectType F0 L0 baseField_vectMixin. Canonical baseField_FalgType := [FalgType F0 of L0]. Canonical baseField_extFieldType := [fieldExtType F0 of L0]. Let F0ZEZ a x v : a *: ((x *: v : L) : L0) = (a *: x) *: v. Proof. by rewrite [a *: _]scalerA -scalerAl mul1r. Qed. Let baseVspace_basis V : seq L0 := [seq tnth bF ij.2 *: tnth (vbasis V) ij.1 | ij : 'I_(\dim V) * 'I_n]. Definition baseVspace V := <>%VS. Lemma mem_baseVspace V : baseVspace V =i V. Proof. move=> y; apply/idP/idP=> [/coord_span->|/coord_vbasis->]; last first. apply: memv_suml => i _; rewrite (coordF (coord _ i (y : L))) scaler_suml -/n. apply: memv_suml => j _; rewrite -/bF -F0ZEZ memvZ ?memv_span // -!tnth_nth. by apply/imageP; exists (i, j). (* GG: the F0ZEZ lemma avoids serious performance issues here. *) apply: memv_suml => k _; rewrite nth_image; case: (enum_val k) => i j /=. by rewrite F0ZEZ memvZ ?vbasis_mem ?mem_tnth. Qed. Lemma dim_baseVspace V : \dim (baseVspace V) = (\dim V * n)%N. Proof. pose bV0 := baseVspace_basis V; set m := \dim V in bV0 *. suffices /size_basis->: basis_of (baseVspace V) bV0. by rewrite card_prod !card_ord. rewrite /basis_of eqxx. apply/freeP=> s sb0 k; rewrite -(enum_valK k); case/enum_val: k => i j. have free_baseP := freeP (basis_free (vbasisP _)). move: j; apply: (free_baseP _ _ fullv); move: i; apply: (free_baseP _ _ V). transitivity (\sum_i \sum_j s (enum_rank (i, j)) *: bV0`_(enum_rank (i, j))). apply: eq_bigr => i _; rewrite scaler_suml; apply: eq_bigr => j _. by rewrite -F0ZEZ nth_image enum_rankK -!tnth_nth. rewrite pair_bigA (reindex _ (onW_bij _ (enum_val_bij _))); apply: etrans sb0. by apply: eq_bigr => k _; rewrite -{5 6}[k](enum_valK k); case/enum_val: k. Qed. Fact baseAspace_suproof (E : {subfield L}) : is_aspace (baseVspace E). Proof. rewrite /is_aspace has_algid1; last by rewrite mem_baseVspace (mem1v E). by apply/prodvP=> u v; rewrite !mem_baseVspace; exact: memvM. Qed. Canonical baseAspace E := ASpace (baseAspace_suproof E). Fact refBaseField_key : unit. Proof. by []. Qed. Definition refBaseField := locked_with refBaseField_key (baseAspace 1). Canonical refBaseField_unlockable := [unlockable of refBaseField]. Notation F1 := refBaseField. Lemma dim_refBaseField : \dim F1 = n. Proof. by rewrite [F1]unlock dim_baseVspace dimv1 mul1n. Qed. Lemma baseVspace_module V (V0 := baseVspace V) : (F1 * V0 <= V0)%VS. Proof. apply/prodvP=> u v; rewrite [F1]unlock !mem_baseVspace => /vlineP[x ->] Vv. by rewrite -(@scalerAl F L) mul1r; exact: memvZ. Qed. Lemma sub_baseField (E : {subfield L}) : (F1 <= baseVspace E)%VS. Proof. by rewrite -sup_field_module baseVspace_module. Qed. Lemma vspaceOver_refBase V : vspaceOver F1 (baseVspace V) =i V. Proof. move=> v; rewrite mem_vspaceOver field_module_eq ?baseVspace_module //. by rewrite mem_baseVspace. Qed. Lemma module_baseVspace M0 : (F1 * M0 <= M0)%VS -> {V | M0 = baseVspace V & M0 =i V}. Proof. move=> modM0; pose V := <>%VS. suffices memM0: M0 =i V. by exists V => //; apply/vspaceP=> v; rewrite mem_baseVspace memM0. move=> v; rewrite -{1}(field_module_eq modM0) -(mem_vspaceOver M0) {}/V. move: (vspaceOver F1 M0) => M. apply/idP/idP=> [/coord_vbasis|/coord_span]->; apply/memv_suml=> i _. rewrite /(_ *: _) /= /fieldOver_scale; case: (coord _ i _) => /= x. rewrite {1}[F1]unlock mem_baseVspace => /vlineP[{x}x ->]. by rewrite -(@scalerAl F L) mul1r memvZ ?memv_span ?memt_nth. move: (coord _ i _) => x; rewrite -[_`_i]mul1r scalerAl -tnth_nth. have F1x: x%:A \in F1. by rewrite [F1]unlock mem_baseVspace (@memvZ F L) // mem1v. by congr (_ \in M): (memvZ (Subvs F1x) (vbasis_mem (mem_tnth i _))). Qed. Lemma module_baseAspace (E0 : {subfield L0}) : (F1 <= E0)%VS -> {E | E0 = baseAspace E & E0 =i E}. Proof. rewrite -sup_field_module => /module_baseVspace[E defE0 memE0]. suffices algE: is_aspace E by exists (ASpace algE); first exact: val_inj. rewrite /is_aspace has_algid1 -?memE0 ?mem1v //. by apply/prodvP=> u v; rewrite -!memE0; apply: memvM. Qed. End BaseField. Notation baseFieldType L := (baseField_type (Phant L)). (* Base of fieldOver, finally. *) Section MoreFieldOver. Variables (F0 : fieldType) (L : fieldExtType F0) (F : {subfield L}). Lemma base_vspaceOver V : baseVspace (vspaceOver F V) =i (F * V)%VS. Proof. by move=> v; rewrite mem_baseVspace mem_vspaceOver. Qed. Lemma base_moduleOver V : (F * V <= V)%VS -> baseVspace (vspaceOver F V) =i V. Proof. by move=> /field_module_eq defV v; rewrite base_vspaceOver defV. Qed. Lemma base_aspaceOver (E : {subfield L}) : (F <= E)%VS -> baseVspace (vspaceOver F E) =i E. Proof. by rewrite -sup_field_module; apply: base_moduleOver. Qed. End MoreFieldOver. Section SubFieldExtension. Local Open Scope quotient_scope. Variables (F L : fieldType) (iota : {rmorphism F -> L}). Variables (z : L) (p : {poly F}). Local Notation "p ^iota" := (map_poly (GRing.RMorphism.apply iota) p) (at level 2, format "p ^iota") : ring_scope. Let wf_p := (p != 0) && root p^iota z. Let p0 : {poly F} := if wf_p then (lead_coef p)^-1 *: p else 'X. Let z0 := if wf_p then z else 0. Let n := (size p0).-1. Let p0_mon : p0 \is monic. Proof. rewrite /p0; case: ifP => [/andP[nz_p _] | _]; last exact: monicX. by rewrite monicE lead_coefZ mulVf ?lead_coef_eq0. Qed. Let nz_p0 : p0 != 0. Proof. by rewrite monic_neq0 // p0_mon. Qed. Let p0z0 : root p0^iota z0. Proof. rewrite /p0 /z0; case: ifP => [/andP[_ pz0]|]; last by rewrite map_polyX rootX. by rewrite map_polyZ rootE hornerZ (rootP pz0) mulr0. Qed. Let n_gt0: 0 < n. Proof. rewrite /n -subn1 subn_gt0 -(size_map_poly iota). by rewrite (root_size_gt1 _ p0z0) ?map_poly_eq0. Qed. Let z0Ciota : commr_rmorph iota z0. Proof. by move=> x; apply: mulrC. Qed. Local Notation iotaPz := (horner_morph z0Ciota). Let iotaFz (x : 'rV[F]_n) := iotaPz (rVpoly x). Definition equiv_subfext x y := (iotaFz x == iotaFz y). Fact equiv_subfext_is_equiv : equiv_class_of equiv_subfext. Proof. by rewrite /equiv_subfext; split=> x // y w /eqP->. Qed. Canonical equiv_subfext_equiv := EquivRelPack equiv_subfext_is_equiv. Canonical equiv_subfext_encModRel := defaultEncModRel equiv_subfext. Definition subFExtend := {eq_quot equiv_subfext}. Canonical subFExtend_eqType := [eqType of subFExtend]. Canonical subFExtend_choiceType := [choiceType of subFExtend]. Canonical subFExtend_quotType := [quotType of subFExtend]. Canonical subFExtend_eqQuotType := [eqQuotType equiv_subfext of subFExtend]. Definition subfx_inj := lift_fun1 subFExtend iotaFz. Fact pi_subfx_inj : {mono \pi : x / iotaFz x >-> subfx_inj x}. Proof. unlock subfx_inj => x; apply/eqP; rewrite -/(equiv_subfext _ x). by rewrite -eqmodE reprK. Qed. Canonical pi_subfx_inj_morph := PiMono1 pi_subfx_inj. Let iotaPz_repr x : iotaPz (rVpoly (repr (\pi_(subFExtend) x))) = iotaFz x. Proof. by rewrite -/(iotaFz _) -!pi_subfx_inj reprK. Qed. Definition subfext0 := lift_cst subFExtend 0. Canonical subfext0_morph := PiConst subfext0. Definition subfext_add := lift_op2 subFExtend +%R. Fact pi_subfext_add : {morph \pi : x y / x + y >-> subfext_add x y}. Proof. unlock subfext_add => x y /=; apply/eqmodP/eqP. by rewrite /iotaFz !linearD /= !iotaPz_repr. Qed. Canonical pi_subfx_add_morph := PiMorph2 pi_subfext_add. Definition subfext_opp := lift_op1 subFExtend -%R. Fact pi_subfext_opp : {morph \pi : x / - x >-> subfext_opp x}. Proof. unlock subfext_opp => y /=; apply/eqmodP/eqP. by rewrite /iotaFz !linearN /= !iotaPz_repr. Qed. Canonical pi_subfext_opp_morph := PiMorph1 pi_subfext_opp. Fact addfxA : associative subfext_add. Proof. by move=> x y t; rewrite -[x]reprK -[y]reprK -[t]reprK !piE addrA. Qed. Fact addfxC : commutative subfext_add. Proof. by move=> x y; rewrite -[x]reprK -[y]reprK !piE addrC. Qed. Fact add0fx : left_id subfext0 subfext_add. Proof. by move=> x; rewrite -[x]reprK !piE add0r. Qed. Fact addfxN : left_inverse subfext0 subfext_opp subfext_add. Proof. by move=> x; rewrite -[x]reprK !piE addNr. Qed. Definition subfext_zmodMixin := ZmodMixin addfxA addfxC add0fx addfxN. Canonical subfext_zmodType := Eval hnf in ZmodType subFExtend subfext_zmodMixin. Let poly_rV_modp_K q : rVpoly (poly_rV (q %% p0) : 'rV[F]_n) = q %% p0. Proof. by apply: poly_rV_K; rewrite -ltnS -polySpred // ltn_modp. Qed. Let iotaPz_modp q : iotaPz (q %% p0) = iotaPz q. Proof. rewrite {2}(divp_eq q p0) rmorphD rmorphM /=. by rewrite [iotaPz p0](rootP p0z0) mulr0 add0r. Qed. Definition subfx_mul_rep (x y : 'rV[F]_n) : 'rV[F]_n := poly_rV ((rVpoly x) * (rVpoly y) %% p0). Definition subfext_mul := lift_op2 subFExtend subfx_mul_rep. Fact pi_subfext_mul : {morph \pi : x y / subfx_mul_rep x y >-> subfext_mul x y}. Proof. unlock subfext_mul => x y /=; apply/eqmodP/eqP. by rewrite /iotaFz !poly_rV_modp_K !iotaPz_modp !rmorphM /= !iotaPz_repr. Qed. Canonical pi_subfext_mul_morph := PiMorph2 pi_subfext_mul. Definition subfext1 := lift_cst subFExtend (poly_rV 1). Canonical subfext1_morph := PiConst subfext1. Fact mulfxA : associative (subfext_mul). Proof. elim/quotW=> x; elim/quotW=> y; elim/quotW=> w; rewrite !piE /subfx_mul_rep. by rewrite !poly_rV_modp_K [_ %% p0 * _]mulrC !modp_mul // mulrA mulrC. Qed. Fact mulfxC : commutative subfext_mul. Proof. by elim/quotW=> x; elim/quotW=> y; rewrite !piE /subfx_mul_rep /= mulrC. Qed. Fact mul1fx : left_id subfext1 subfext_mul. Proof. elim/quotW=> x; rewrite !piE /subfx_mul_rep poly_rV_K ?size_poly1 // mul1r. by rewrite modp_small ?rVpolyK // (polySpred nz_p0) ltnS size_poly. Qed. Fact mulfx_addl : left_distributive subfext_mul subfext_add. Proof. elim/quotW=> x; elim/quotW=> y; elim/quotW=> w; rewrite !piE /subfx_mul_rep. by rewrite linearD /= mulrDl modp_add linearD. Qed. Fact nonzero1fx : subfext1 != subfext0. Proof. rewrite !piE /equiv_subfext /iotaFz !linear0. by rewrite poly_rV_K ?rmorph1 ?oner_eq0 // size_poly1. Qed. Definition subfext_comRingMixin := ComRingMixin mulfxA mulfxC mul1fx mulfx_addl nonzero1fx. Canonical subfext_Ring := Eval hnf in RingType subFExtend subfext_comRingMixin. Canonical subfext_comRing := Eval hnf in ComRingType subFExtend mulfxC. Definition subfx_poly_inv (q : {poly F}) : {poly F} := if iotaPz q == 0 then 0 else let r := gdcop q p0 in let: (u, v) := egcdp q r in ((u * q + v * r)`_0)^-1 *: u. Let subfx_poly_invE q : iotaPz (subfx_poly_inv q) = (iotaPz q)^-1. Proof. rewrite /subfx_poly_inv. have [-> | nzq] := altP eqP; first by rewrite rmorph0 invr0. rewrite [nth]lock -[_^-1]mul1r; apply: canRL (mulfK nzq) _; rewrite -rmorphM /=. have rz0: iotaPz (gdcop q p0) = 0. by apply/rootP; rewrite gdcop_map root_gdco ?map_poly_eq0 // p0z0 nzq. do [case: gdcopP => r _; rewrite (negPf nz_p0) orbF => co_r_q _] in rz0 *. case: (egcdp q r) (egcdpE q r) => u v /=/eqp_size/esym/eqP. rewrite coprimep_size_gcd 1?coprimep_sym // => /size_poly1P[a nz_a Da]. rewrite Da -scalerAl (canRL (addrK _) Da) -lock coefC linearZ linearB /=. by rewrite rmorphM /= rz0 mulr0 subr0 horner_morphC -rmorphM mulVf ?rmorph1. Qed. Definition subfx_inv_rep (x : 'rV[F]_n) : 'rV[F]_n := poly_rV (subfx_poly_inv (rVpoly x) %% p0). Definition subfext_inv := lift_op1 subFExtend subfx_inv_rep. Fact pi_subfext_inv : {morph \pi : x / subfx_inv_rep x >-> subfext_inv x}. Proof. unlock subfext_inv => x /=; apply/eqmodP/eqP; rewrite /iotaFz. by rewrite 2!{1}poly_rV_modp_K 2!{1}iotaPz_modp !subfx_poly_invE iotaPz_repr. Qed. Canonical pi_subfext_inv_morph := PiMorph1 pi_subfext_inv. Fact subfx_fieldAxiom : GRing.Field.axiom (subfext_inv : subFExtend -> subFExtend). Proof. elim/quotW=> x; apply: contraNeq; rewrite !piE /equiv_subfext /iotaFz !linear0. apply: contraR => nz_x; rewrite poly_rV_K ?size_poly1 // !poly_rV_modp_K. by rewrite iotaPz_modp rmorph1 rmorphM /= iotaPz_modp subfx_poly_invE mulVf. Qed. Fact subfx_inv0 : subfext_inv (0 : subFExtend) = (0 : subFExtend). Proof. apply/eqP; rewrite !piE /equiv_subfext /iotaFz /subfx_inv_rep !linear0. by rewrite /subfx_poly_inv rmorph0 eqxx mod0p !linear0. Qed. Definition subfext_unitRingMixin := FieldUnitMixin subfx_fieldAxiom subfx_inv0. Canonical subfext_unitRingType := Eval hnf in UnitRingType subFExtend subfext_unitRingMixin. Canonical subfext_comUnitRing := Eval hnf in [comUnitRingType of subFExtend]. Definition subfext_fieldMixin := @FieldMixin _ _ subfx_fieldAxiom subfx_inv0. Definition subfext_idomainMixin := FieldIdomainMixin subfext_fieldMixin. Canonical subfext_idomainType := Eval hnf in IdomainType subFExtend subfext_idomainMixin. Canonical subfext_fieldType := Eval hnf in FieldType subFExtend subfext_fieldMixin. Fact subfx_inj_is_rmorphism : rmorphism subfx_inj. Proof. do 2?split; last by rewrite piE /iotaFz poly_rV_K ?rmorph1 ?size_poly1. by elim/quotW=> x; elim/quotW=> y; rewrite !piE /iotaFz linearB rmorphB. elim/quotW=> x; elim/quotW=> y; rewrite !piE /subfx_mul_rep /iotaFz. by rewrite poly_rV_modp_K iotaPz_modp rmorphM. Qed. Canonical subfx_inj_additive := Additive subfx_inj_is_rmorphism. Canonical subfx_inj_rmorphism := RMorphism subfx_inj_is_rmorphism. Definition subfx_eval := lift_embed subFExtend (fun q => poly_rV (q %% p0)). Canonical subfx_eval_morph := PiEmbed subfx_eval. Definition subfx_root := subfx_eval 'X. Lemma subfx_eval_is_rmorphism : rmorphism subfx_eval. Proof. do 2?split=> [x y|] /=; apply/eqP; rewrite piE. - by rewrite -linearB modp_add modNp. - by rewrite /subfx_mul_rep !poly_rV_modp_K !(modp_mul, mulrC _ y). by rewrite modp_small // size_poly1 -subn_gt0 subn1. Qed. Canonical subfx_eval_additive := Additive subfx_eval_is_rmorphism. Canonical subfx_eval_rmorphism := AddRMorphism subfx_eval_is_rmorphism. Definition inj_subfx := (subfx_eval \o polyC). Canonical inj_subfx_addidive := [additive of inj_subfx]. Canonical inj_subfx_rmorphism := [rmorphism of inj_subfx]. Lemma subfxE x: exists p, x = subfx_eval p. Proof. elim/quotW: x => x; exists (rVpoly x); apply/eqP; rewrite piE /equiv_subfext. by rewrite /iotaFz poly_rV_modp_K iotaPz_modp. Qed. Definition subfx_scale a x := inj_subfx a * x. Fact subfx_scalerA a b x : subfx_scale a (subfx_scale b x) = subfx_scale (a * b) x. Proof. by rewrite /subfx_scale rmorphM mulrA. Qed. Fact subfx_scaler1r : left_id 1 subfx_scale. Proof. by move=> x; rewrite /subfx_scale rmorph1 mul1r. Qed. Fact subfx_scalerDr : right_distributive subfx_scale +%R. Proof. by move=> a; exact: mulrDr. Qed. Fact subfx_scalerDl x : {morph subfx_scale^~ x : a b / a + b}. Proof. by move=> a b; rewrite /subfx_scale rmorphD mulrDl. Qed. Definition subfx_lmodMixin := LmodMixin subfx_scalerA subfx_scaler1r subfx_scalerDr subfx_scalerDl. Canonical subfx_lmodType := LmodType F subFExtend subfx_lmodMixin. Fact subfx_scaleAl : GRing.Lalgebra.axiom ( *%R : subFExtend -> _). Proof. by move=> a; apply: mulrA. Qed. Canonical subfx_lalgType := LalgType F subFExtend subfx_scaleAl. Fact subfx_scaleAr : GRing.Algebra.axiom subfx_lalgType. Proof. by move=> a; apply: mulrCA. Qed. Canonical subfx_algType := AlgType F subFExtend subfx_scaleAr. Canonical subfext_unitAlgType := [unitAlgType F of subFExtend]. Fact subfx_evalZ : scalable subfx_eval. Proof. by move=> a q; rewrite -mul_polyC rmorphM. Qed. Canonical subfx_eval_linear := AddLinear subfx_evalZ. Canonical subfx_eval_lrmorphism := [lrmorphism of subfx_eval]. Hypothesis (pz0 : root p^iota z). Section NonZero. Hypothesis nz_p : p != 0. Lemma subfx_inj_eval q : subfx_inj (subfx_eval q) = q^iota.[z]. Proof. by rewrite piE /iotaFz poly_rV_modp_K iotaPz_modp /iotaPz /z0 /wf_p nz_p pz0. Qed. Lemma subfx_inj_root : subfx_inj subfx_root = z. Proof. by rewrite subfx_inj_eval // map_polyX hornerX. Qed. Lemma subfx_injZ b x : subfx_inj (b *: x) = iota b * subfx_inj x. Proof. by rewrite rmorphM /= subfx_inj_eval // map_polyC hornerC. Qed. Lemma subfx_inj_base b : subfx_inj b%:A = iota b. Proof. by rewrite subfx_injZ rmorph1 mulr1. Qed. Lemma subfxEroot x : {q | x = (map_poly (in_alg subFExtend) q).[subfx_root]}. Proof. have /sig_eqW[q ->] := subfxE x; exists q. apply: (fmorph_inj subfx_inj_rmorphism). rewrite -horner_map /= subfx_inj_root subfx_inj_eval //. by rewrite -map_poly_comp (eq_map_poly subfx_inj_base). Qed. Lemma subfx_irreducibleP : (forall q, root q^iota z -> q != 0 -> size p <= size q) <-> irreducible_poly p. Proof. split=> [min_p | irr_p q qz0 nz_q]. split=> [|q nonC_q q_dv_p]. by rewrite -(size_map_poly iota) (root_size_gt1 _ pz0) ?map_poly_eq0. have /dvdpP[r Dp] := q_dv_p; rewrite -dvdp_size_eqp // eqn_leq dvdp_leq //=. have [nz_r nz_q]: r != 0 /\ q != 0 by apply/norP; rewrite -mulf_eq0 -Dp. have: root r^iota z || root q^iota z by rewrite -rootM -rmorphM -Dp. case/orP=> /min_p; [case/(_ _)/idPn=> // | exact]. rewrite polySpred // -leqNgt Dp size_mul //= polySpred // -subn2 ltn_subRL. by rewrite addSnnS addnC ltn_add2l ltn_neqAle eq_sym nonC_q size_poly_gt0. pose r := gcdp p q; have nz_r: r != 0 by rewrite gcdp_eq0 (negPf nz_p). suffices /eqp_size <-: r %= p by rewrite dvdp_leq ?dvdp_gcdr. rewrite (irr_p _) ?dvdp_gcdl // -(size_map_poly iota) gtn_eqF //. by rewrite (@root_size_gt1 _ z) ?map_poly_eq0 // gcdp_map root_gcd pz0. Qed. End NonZero. Section Irreducible. Hypothesis irr_p : irreducible_poly p. Let nz_p : p != 0. Proof. exact: irredp_neq0. Qed. (* The Vector axiom requires irreducibility. *) Lemma min_subfx_vectAxiom : Vector.axiom (size p).-1 subfx_lmodType. Proof. move/subfx_irreducibleP: irr_p => /=/(_ nz_p) min_p; set d := (size p).-1. have Dd: d.+1 = size p by rewrite polySpred. pose Fz2v x : 'rV_d := poly_rV (sval (sig_eqW (subfxE x)) %% p). pose vFz : 'rV_d -> subFExtend := subfx_eval \o @rVpoly F d. have FLinj: injective subfx_inj by apply: fmorph_inj. have Fz2vK: cancel Fz2v vFz. move=> x; rewrite /vFz /Fz2v; case: (sig_eqW _) => /= q ->. apply: FLinj; rewrite !subfx_inj_eval // {2}(divp_eq q p) rmorphD rmorphM /=. by rewrite !hornerE (eqP pz0) mulr0 add0r poly_rV_K // -ltnS Dd ltn_modpN0. suffices vFzK: cancel vFz Fz2v. by exists Fz2v; [apply: can2_linear Fz2vK | exists vFz]. apply: inj_can_sym Fz2vK _ => v1 v2 /(congr1 subfx_inj)/eqP. rewrite -subr_eq0 -!raddfB /= subfx_inj_eval // => /min_p/implyP. rewrite leqNgt implybNN -Dd ltnS size_poly linearB subr_eq0 /=. by move/eqP/(can_inj (@rVpolyK _ _)). Qed. Definition SubfxVectMixin := VectMixin min_subfx_vectAxiom. Definition SubfxVectType := VectType F subFExtend SubfxVectMixin. Definition SubfxFalgType := Eval simpl in [FalgType F of SubfxVectType]. Definition SubFieldExtType := Eval simpl in [fieldExtType F of SubfxFalgType]. End Irreducible. End SubFieldExtension. Prenex Implicits subfx_inj. Lemma irredp_FAdjoin (F : fieldType) (p : {poly F}) : irreducible_poly p -> {L : fieldExtType F & \dim {:L} = (size p).-1 & {z | root (map_poly (in_alg L) p) z & <<1; z>>%VS = fullv}}. Proof. case=> p_gt1 irr_p; set n := (size p).-1; pose vL := [vectType F of 'rV_n]. have Dn: n.+1 = size p := ltn_predK p_gt1. have nz_p: p != 0 by rewrite -size_poly_eq0 -Dn. suffices [L dimL [toPF [toL toPF_K toL_K]]]: {L : fieldExtType F & \dim {:L} = (size p).-1 & {toPF : {linear L -> {poly F}} & {toL : {lrmorphism {poly F} -> L} | cancel toPF toL & forall q, toPF (toL q) = q %% p}}}. - exists L => //; pose z := toL 'X; set iota := in_alg _. suffices q_z q: toPF (map_poly iota q).[z] = q %% p. exists z; first by rewrite /root -(can_eq toPF_K) q_z modpp linear0. apply/vspaceP=> x; rewrite memvf; apply/Fadjoin_polyP. exists (map_poly iota (toPF x)). by apply/polyOverP=> i; rewrite coef_map memvZ ?mem1v. by apply: (can_inj toPF_K); rewrite q_z -toL_K toPF_K. elim/poly_ind: q => [|a q IHq]. by rewrite map_poly0 horner0 linear0 mod0p. rewrite rmorphD rmorphM /= map_polyX map_polyC hornerMXaddC linearD /=. rewrite linearZ /= -(rmorph1 toL) toL_K -modp_scalel alg_polyC modp_add. congr (_ + _); rewrite -toL_K rmorphM /= -/z; congr (toPF (_ * z)). by apply: (can_inj toPF_K); rewrite toL_K. pose toL q : vL := poly_rV (q %% p); pose toPF (x : vL) := rVpoly x. have toL_K q : toPF (toL q) = q %% p. by rewrite /toPF poly_rV_K // -ltnS Dn ?ltn_modp -?Dn. have toPF_K: cancel toPF toL. by move=> x; rewrite /toL modp_small ?rVpolyK // -Dn ltnS size_poly. have toPinj := can_inj toPF_K. pose mul x y := toL (toPF x * toPF y); pose L1 := toL 1. have L1K: toPF L1 = 1 by rewrite toL_K modp_small ?size_poly1. have mulC: commutative mul by rewrite /mul => x y; rewrite mulrC. have mulA: associative mul. by move=> x y z; apply: toPinj; rewrite -!(mulC z) !toL_K !modp_mul mulrCA. have mul1: left_id L1 mul. by move=> x; apply: toPinj; rewrite mulC !toL_K modp_mul mulr1 -toL_K toPF_K. have mulD: left_distributive mul +%R. move=> x y z; apply: toPinj; rewrite /toPF raddfD /= -!/(toPF _). by rewrite !toL_K /toPF raddfD mulrDl modp_add. have nzL1: L1 != 0 by rewrite -(inj_eq toPinj) L1K /toPF raddf0 oner_eq0. pose mulM := ComRingMixin mulA mulC mul1 mulD nzL1. pose rL := ComRingType (RingType vL mulM) mulC. have mulZl: GRing.Lalgebra.axiom mul. move=> a x y; apply: toPinj; rewrite toL_K /toPF !linearZ /= -!/(toPF _). by rewrite toL_K -scalerAl modp_scalel. have mulZr: GRing.Algebra.axiom (LalgType F rL mulZl). by move=> a x y; rewrite !(mulrC x) scalerAl. pose aL := AlgType F _ mulZr; pose urL := FalgUnitRingType aL. pose uaL := [unitAlgType F of AlgType F urL mulZr]. pose faL := [FalgType F of uaL]. have unitE: GRing.Field.mixin_of urL. move=> x nz_x; apply/unitrP; set q := toPF x. have nz_q: q != 0 by rewrite -(inj_eq toPinj) /toPF raddf0 in nz_x. have /Bezout_eq1_coprimepP[u upq1]: coprimep p q. apply: contraLR (leq_gcdpr p nz_q) => /irr_p/implyP. rewrite dvdp_gcdl -ltnNge /= => /eqp_size->. by rewrite (polySpred nz_p) ltnS size_poly. suffices: x * toL u.2 = 1 by exists (toL u.2); rewrite mulrC. apply: toPinj; rewrite !toL_K -upq1 modp_mul modp_add mulrC. by rewrite modp_mull add0r. pose ucrL := [comUnitRingType of ComRingType urL mulC]. have mul0 := GRing.Field.IdomainMixin unitE. pose fL := FieldType (IdomainType ucrL mul0) unitE. exists [fieldExtType F of faL for fL]; first by rewrite dimvf; apply: mul1n. exists [linear of toPF as @rVpoly _ _]. suffices toLM: lrmorphism (toL : {poly F} -> aL) by exists (LRMorphism toLM). have toLlin: linear toL. by move=> a q1 q2; rewrite -linearP -modp_scalel -modp_add. do ?split; try exact: toLlin; move=> q r /=. by apply: toPinj; rewrite !toL_K modp_mul -!(mulrC r) modp_mul. Qed. (*Coq 8.3 processes this shorter proof correctly, but then crashes on Qed. Lemma Xirredp_FAdjoin' (F : fieldType) (p : {poly F}) : irreducible_poly p -> {L : fieldExtType F & Vector.dim L = (size p).-1 & {z | root (map_poly (in_alg L) p) z & <<1; z>>%VS = fullv}}. Proof. case=> p_gt1 irr_p; set n := (size p).-1; pose vL := [vectType F of 'rV_n]. have Dn: n.+1 = size p := ltn_predK p_gt1. have nz_p: p != 0 by rewrite -size_poly_eq0 -Dn. pose toL q : vL := poly_rV (q %% p). have toL_K q : rVpoly (toL q) = q %% p. by rewrite poly_rV_K // -ltnS Dn ?ltn_modp -?Dn. pose mul (x y : vL) : vL := toL (rVpoly x * rVpoly y). pose L1 : vL := poly_rV 1. have L1K: rVpoly L1 = 1 by rewrite poly_rV_K // size_poly1 -ltnS Dn. have mulC: commutative mul by rewrite /mul => x y; rewrite mulrC. have mulA: associative mul. by move=> x y z; rewrite -!(mulC z) /mul !toL_K /toL !modp_mul mulrCA. have mul1: left_id L1 mul. move=> x; rewrite /mul L1K mul1r /toL modp_small ?rVpolyK // -Dn ltnS. by rewrite size_poly. have mulD: left_distributive mul +%R. move=> x y z; apply: canLR (@rVpolyK _ _) _. by rewrite !raddfD mulrDl /= !toL_K /toL modp_add. have nzL1: L1 != 0 by rewrite -(can_eq (@rVpolyK _ _)) L1K raddf0 oner_eq0. pose mulM := ComRingMixin mulA mulC mul1 mulD nzL1. pose rL := ComRingType (RingType vL mulM) mulC. have mulZl: GRing.Lalgebra.axiom mul. move=> a x y; apply: canRL (@rVpolyK _ _) _; rewrite !linearZ /= toL_K. by rewrite -scalerAl modp_scalel. have mulZr: @GRing.Algebra.axiom _ (LalgType F rL mulZl). by move=> a x y; rewrite !(mulrC x) scalerAl. pose aL := AlgType F _ mulZr; pose urL := FalgUnitRingType aL. pose uaL := [unitAlgType F of AlgType F urL mulZr]. pose faL := [FalgType F of uaL]. have unitE: GRing.Field.mixin_of urL. move=> x nz_x; apply/unitrP; set q := rVpoly x. have nz_q: q != 0 by rewrite -(can_eq (@rVpolyK _ _)) raddf0 in nz_x. have /Bezout_eq1_coprimepP[u upq1]: coprimep p q. have /contraR := irr_p _ _ (dvdp_gcdl p q); apply. have: size (gcdp p q) <= size q by exact: leq_gcdpr. rewrite leqNgt;apply:contra;move/eqp_size ->. by rewrite (polySpred nz_p) ltnS size_poly. suffices: x * toL u.2 = 1 by exists (toL u.2); rewrite mulrC. congr (poly_rV _); rewrite toL_K modp_mul mulrC (canRL (addKr _) upq1). by rewrite -mulNr modp_addl_mul_small ?size_poly1. pose ucrL := [comUnitRingType of ComRingType urL mulC]. pose fL := FieldType (IdomainType ucrL (GRing.Field.IdomainMixin unitE)) unitE. exists [fieldExtType F of faL for fL]; first exact: mul1n. pose z : vL := toL 'X; set iota := in_alg _. have q_z q: rVpoly (map_poly iota q).[z] = q %% p. elim/poly_ind: q => [|a q IHq]. by rewrite map_poly0 horner0 linear0 mod0p. rewrite rmorphD rmorphM /= map_polyX map_polyC hornerMXaddC linearD /=. rewrite linearZ /= L1K alg_polyC modp_add; congr (_ + _); last first. by rewrite modp_small // size_polyC; case: (~~ _) => //; apply: ltnW. by rewrite !toL_K IHq mulrC modp_mul mulrC modp_mul. exists z; first by rewrite /root -(can_eq (@rVpolyK _ _)) q_z modpp linear0. apply/vspaceP=> x; rewrite memvf; apply/Fadjoin_polyP. exists (map_poly iota (rVpoly x)). by apply/polyOverP=> i; rewrite coef_map memvZ ?mem1v. apply: (can_inj (@rVpolyK _ _)). by rewrite q_z modp_small // -Dn ltnS size_poly. Qed. *) mathcomp-1.5/theories/classfun.v0000644000175000017500000027547612307636117016035 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. Require Import fintype tuple finfun bigop prime ssralg poly finset. Require Import fingroup morphism perm automorphism quotient finalg action. Require Import gproduct zmodp commutator cyclic center pgroup sylow. Require Import matrix vector falgebra ssrnum algC algnum. (******************************************************************************) (* This file contains the basic theory of class functions: *) (* 'CF(G) == the type of class functions on G : {group gT}, i.e., *) (* which map gT to the type algC of complex algebraics, *) (* have support in G, and are constant on each conjugacy *) (* class of G. 'CF(G) implements the algebraType interface *) (* of finite-dimensional F-algebras. *) (* The identity 1 : 'CF(G) is the indicator function of G, *) (* and (later) the principal character. *) (* --> The %CF scope (cfun_scope) is bound to the 'CF(_) types. *) (* 'CF(G)%VS == the (total) vector space of 'CF(G). *) (* 'CF(G, A) == the subspace of functions in 'CF(G) with support in A. *) (* phi x == the image of x : gT under phi : 'CF(G). *) (* #[phi]%CF == the multiplicative order of phi : 'CF(G). *) (* cfker phi == the kernel of phi : 'CF(G); note that cfker phi <| G. *) (* cfaithful phi <=> phi : 'CF(G) is faithful (has a trivial kernel). *) (* '1_A == the indicator function of A as a function of 'CF(G). *) (* (Provided A <| G; G is determined by the context.) *) (* phi^*%CF == the function conjugate to phi : 'CF(G). *) (* cfAut u phi == the function conjugate to phi by an algC-automorphism u *) (* phi^u The notation "_ ^u" is only reserved; it is up to *) (* clients to set Notation "phi ^u" := (cfAut u phi). *) (* '[phi, psi] == the convolution of phi, psi : 'CF(G) over G, normalised *) (* '[phi, psi]_G by #|G| so that '[1, 1]_G = 1 (G is usually inferred). *) (* cfdotr psi phi == '[phi, psi] (self-expanding). *) (* '[phi], '[phi]_G == the squared norm '[phi, phi] of phi : 'CF(G). *) (* orthogonal R S <=> each phi in R : seq 'CF(G) is orthogonal to each psi in *) (* S, i.e., '[phi, psi] = 0. As 'CF(G) coerces to seq, one *) (* can write orthogonal phi S and orthogonal phi psi. *) (* pairwise_orthogonal S <=> the class functions in S are pairwise orthogonal *) (* AND non-zero. *) (* orthonormal S <=> S is pairwise orthogonal and all class functions in S *) (* have norm 1. *) (* isometry tau <-> tau : 'CF(D) -> 'CF(R) is an isometry, mapping *) (* '[_, _]_D to '[_, _]_R. *) (* {in CD, isometry tau, to CR} <-> in the domain CD, tau is an isometry *) (* whose range is contained in CR. *) (* cfReal phi <=> phi is real, i.e., phi^* == phi. *) (* cfAut_closed u S <-> S : seq 'CF(G) is closed under conjugation by u. *) (* conjC_closed S <-> S : seq 'CF(G) is closed under complex conjugation. *) (* conjC_subset S1 S2 <-> S1 : seq 'CF(G) represents a subset of S2 closed *) (* under complex conjugation. *) (* := [/\ uniq S1, {subset S1 <= S2} & conjC_closed S1]. *) (* 'Res[H] phi == the restriction of phi : 'CF(G) to a function of 'CF(H) *) (* 'Res[H, G] phi 'Res[H] phi x = phi x if x \in H (when H \subset G), *) (* 'Res phi 'Res[H] phi x = 0 if x \notin H. The syntax variants *) (* allow H and G to be inferred; the default is to specify *) (* H explicitly, and infer G from the type of phi. *) (* 'Ind[G] phi == the class function of 'CF(G) induced by phi : 'CF(H), *) (* 'Ind[G, H] phi when H \subset G. As with 'Res phi, both G and H can *) (* 'Ind phi be inferred, though usually G isn't. *) (* cfMorph phi == the class function in 'CF(G) that maps x to phi (f x), *) (* where phi : 'CF(f @* G), provided G \subset 'dom f. *) (* cfIsom isoGR phi == the class function in 'CF(R) that maps f x to phi x, *) (* given isoGR : isom G R f, f : {morphism G >-> rT} and *) (* phi : 'CF(G). *) (* (phi %% H)%CF == special case of cfMorph phi, when phi : 'CF(G / H). *) (* (phi / H)%CF == the class function in 'CF(G / H) that coincides with *) (* phi : 'CF(G) on cosets of H \subset cfker phi. *) (* For a group G that is a semidirect product (defG : K ><| H = G), we have *) (* cfSdprod KxH phi == for phi : 'CF(H), the class function of 'CF(G) that *) (* maps k * h to psi h when k \in K and h \in H. *) (* For a group G that is a direct product (with KxH : K \x H = G), we have *) (* cfDprodl KxH phi == for phi : 'CF(K), the class function of 'CF(G) that *) (* maps k * h to phi k when k \in K and h \in H. *) (* cfDprodr KxH psi == for psi : 'CF(H), the class function of 'CF(G) that *) (* maps k * h to psi h when k \in K and h \in H. *) (* cfDprod KxH phi psi == for phi : 'CF(K), psi : 'CF(H), the class function *) (* of 'CF(G) that maps k * h to phi k * psi h (this is *) (* the product of the two functions above). *) (* Finally, given defG : \big[dprod/1]_(i | P i) A i = G, with G and A i *) (* groups and i ranges over a finType, we have *) (* cfBigdprodi defG phi == for phi : 'CF(A i) s.t. P i, the class function *) (* of 'CF(G) that maps x to phi x_i, where x_i is the *) (* (A i)-component of x : G. *) (* cfBigdprodi defG phi == for phi : forall i, 'CF(A i), the class function *) (* of 'CF(G) that maps x to \prod_(i | P i) phi i x_i, *) (* where x_i is the (A i)-component of x : G. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope GRing.Theory Num.Theory. Local Open Scope ring_scope. Delimit Scope cfun_scope with CF. Reserved Notation "''CF' ( G , A )" (at level 8, format "''CF' ( G , A )"). Reserved Notation "''CF' ( G )" (at level 8, format "''CF' ( G )"). Reserved Notation "''1_' G" (at level 8, G at level 2, format "''1_' G"). Reserved Notation "''Res[' H , G ]" (at level 8, only parsing). Reserved Notation "''Res[' H ]" (at level 8, format "''Res[' H ]"). Reserved Notation "''Res'" (at level 8, only parsing). Reserved Notation "''Ind[' G , H ]" (at level 8, only parsing). Reserved Notation "''Ind[' G ]" (at level 8, format "''Ind[' G ]"). Reserved Notation "''Ind'" (at level 8, only parsing). Reserved Notation "'[ phi , psi ]_ G" (at level 2, only parsing). Reserved Notation "'[ phi , psi ]" (at level 2, format "'[hv' ''[' phi , '/ ' psi ] ']'"). Reserved Notation "'[ phi ]_ G" (at level 2, only parsing). Reserved Notation "'[ phi ]" (at level 2, format "''[' phi ]"). Reserved Notation "phi ^u" (at level 3, format "phi ^u"). Section AlgC. (* Arithmetic properties of group orders in the characteristic 0 field algC. *) Variable (gT : finGroupType). Implicit Types (G : {group gT}) (B : {set gT}). Lemma neq0CG G : (#|G|)%:R != 0 :> algC. Proof. exact: natrG_neq0. Qed. Lemma neq0CiG G B : (#|G : B|)%:R != 0 :> algC. Proof. exact: natr_indexg_neq0. Qed. Lemma gt0CG G : 0 < #|G|%:R :> algC. Proof. exact: natrG_gt0. Qed. Lemma gt0CiG G B : 0 < #|G : B|%:R :> algC. Proof. exact: natr_indexg_gt0. Qed. Lemma algC'G G : [char algC]^'.-group G. Proof. by apply/pgroupP=> p _; rewrite inE /= char_num. Qed. End AlgC. Section Defs. Variable gT : finGroupType. Definition is_class_fun (B : {set gT}) (f : {ffun gT -> algC}) := [forall x, forall y in B, f (x ^ y) == f x] && (support f \subset B). Lemma intro_class_fun (G : {group gT}) f : {in G &, forall x y, f (x ^ y) = f x} -> (forall x, x \notin G -> f x = 0) -> is_class_fun G (finfun f). Proof. move=> fJ Gf; apply/andP; split; last first. by apply/supportP=> x notAf; rewrite ffunE Gf. apply/'forall_eqfun_inP=> x y Gy; rewrite !ffunE. by have [/fJ-> // | notGx] := boolP (x \in G); rewrite !Gf ?groupJr. Qed. Variable B : {set gT}. Local Notation G := <>. Record classfun : predArgType := Classfun {cfun_val; _ : is_class_fun G cfun_val}. Implicit Types phi psi xi : classfun. (* The default expansion lemma cfunE requires key = 0. *) Fact classfun_key : unit. Proof. by []. Qed. Definition Cfun := locked_with classfun_key (fun flag : nat => Classfun). Canonical cfun_subType := Eval hnf in [subType for cfun_val]. Definition cfun_eqMixin := Eval hnf in [eqMixin of classfun by <:]. Canonical cfun_eqType := Eval hnf in EqType classfun cfun_eqMixin. Definition cfun_choiceMixin := Eval hnf in [choiceMixin of classfun by <:]. Canonical cfun_choiceType := Eval hnf in ChoiceType classfun cfun_choiceMixin. Definition fun_of_cfun phi := cfun_val phi : gT -> algC. Coercion fun_of_cfun : classfun >-> Funclass. Lemma cfunElock k f fP : @Cfun k (finfun f) fP =1 f. Proof. by rewrite locked_withE; apply: ffunE. Qed. Lemma cfunE f fP : @Cfun 0 (finfun f) fP =1 f. Proof. exact: cfunElock. Qed. Lemma cfunP phi psi : phi =1 psi <-> phi = psi. Proof. by split=> [/ffunP/val_inj | ->]. Qed. Lemma cfun0gen phi x : x \notin G -> phi x = 0. Proof. by case: phi => f fP; case: (andP fP) => _ /supportP; exact. Qed. Lemma cfun_in_genP phi psi : {in G, phi =1 psi} -> phi = psi. Proof. move=> eq_phi; apply/cfunP=> x. by have [/eq_phi-> // | notAx] := boolP (x \in G); rewrite !cfun0gen. Qed. Lemma cfunJgen phi x y : y \in G -> phi (x ^ y) = phi x. Proof. case: phi => f fP Gy; apply/eqP. by case: (andP fP) => /'forall_forall_inP->. Qed. Fact cfun_zero_subproof : is_class_fun G (0 : {ffun _}). Proof. exact: intro_class_fun. Qed. Definition cfun_zero := Cfun 0 cfun_zero_subproof. Fact cfun_comp_subproof f phi : f 0 = 0 -> is_class_fun G [ffun x => f (phi x)]. Proof. by move=> f0; apply: intro_class_fun => [x y _ /cfunJgen | x /cfun0gen] ->. Qed. Definition cfun_comp f f0 phi := Cfun 0 (@cfun_comp_subproof f phi f0). Definition cfun_opp := cfun_comp (oppr0 _). Fact cfun_add_subproof phi psi : is_class_fun G [ffun x => phi x + psi x]. Proof. apply: intro_class_fun => [x y Gx Gy | x notGx]; rewrite ?cfunJgen //. by rewrite !cfun0gen ?add0r. Qed. Definition cfun_add phi psi := Cfun 0 (cfun_add_subproof phi psi). Fact cfun_indicator_subproof (A : {set gT}) : is_class_fun G [ffun x => ((x \in G) && (x ^: G \subset A))%:R]. Proof. apply: intro_class_fun => [x y Gx Gy | x /negbTE/= -> //]. by rewrite groupJr ?classGidl. Qed. Definition cfun_indicator A := Cfun 1 (cfun_indicator_subproof A). Local Notation "''1_' A" := (cfun_indicator A) : ring_scope. Lemma cfun1Egen x : '1_G x = (x \in G)%:R. Proof. by rewrite cfunElock andb_idr // => /class_subG->. Qed. Fact cfun_mul_subproof phi psi : is_class_fun G [ffun x => phi x * psi x]. Proof. apply: intro_class_fun => [x y Gx Gy | x notGx]; rewrite ?cfunJgen //. by rewrite cfun0gen ?mul0r. Qed. Definition cfun_mul phi psi := Cfun 0 (cfun_mul_subproof phi psi). Definition cfun_unit := [pred phi : classfun | [forall x in G, phi x != 0]]. Definition cfun_inv phi := if phi \in cfun_unit then cfun_comp (invr0 _) phi else phi. Definition cfun_scale a := cfun_comp (mulr0 a). Fact cfun_addA : associative cfun_add. Proof. by move=> phi psi xi; apply/cfunP=> x; rewrite !cfunE addrA. Qed. Fact cfun_addC : commutative cfun_add. Proof. by move=> phi psi; apply/cfunP=> x; rewrite !cfunE addrC. Qed. Fact cfun_add0 : left_id cfun_zero cfun_add. Proof. by move=> phi; apply/cfunP=> x; rewrite !cfunE add0r. Qed. Fact cfun_addN : left_inverse cfun_zero cfun_opp cfun_add. Proof. by move=> phi; apply/cfunP=> x; rewrite !cfunE addNr. Qed. Definition cfun_zmodMixin := ZmodMixin cfun_addA cfun_addC cfun_add0 cfun_addN. Canonical cfun_zmodType := ZmodType classfun cfun_zmodMixin. Lemma muln_cfunE phi n x : (phi *+ n) x = phi x *+ n. Proof. by elim: n => [|n IHn]; rewrite ?mulrS !cfunE ?IHn. Qed. Lemma sum_cfunE I r (P : pred I) (phi : I -> classfun) x : (\sum_(i <- r | P i) phi i) x = \sum_(i <- r | P i) (phi i) x. Proof. by elim/big_rec2: _ => [|i _ psi _ <-]; rewrite cfunE. Qed. Fact cfun_mulA : associative cfun_mul. Proof. by move=> phi psi xi; apply/cfunP=> x; rewrite !cfunE mulrA. Qed. Fact cfun_mulC : commutative cfun_mul. Proof. by move=> phi psi; apply/cfunP=> x; rewrite !cfunE mulrC. Qed. Fact cfun_mul1 : left_id '1_G cfun_mul. Proof. by move=> phi; apply: cfun_in_genP => x Gx; rewrite !cfunE cfun1Egen Gx mul1r. Qed. Fact cfun_mulD : left_distributive cfun_mul cfun_add. Proof. by move=> phi psi xi; apply/cfunP=> x; rewrite !cfunE mulrDl. Qed. Fact cfun_nz1 : '1_G != 0. Proof. by apply/eqP=> /cfunP/(_ 1%g)/eqP; rewrite cfun1Egen cfunE group1 oner_eq0. Qed. Definition cfun_ringMixin := ComRingMixin cfun_mulA cfun_mulC cfun_mul1 cfun_mulD cfun_nz1. Canonical cfun_ringType := RingType classfun cfun_ringMixin. Canonical cfun_comRingType := ComRingType classfun cfun_mulC. Lemma expS_cfunE phi n x : (phi ^+ n.+1) x = phi x ^+ n.+1. Proof. by elim: n => //= n IHn; rewrite !cfunE IHn. Qed. Fact cfun_mulV : {in cfun_unit, left_inverse 1 cfun_inv *%R}. Proof. move=> phi Uphi; rewrite /cfun_inv Uphi; apply/cfun_in_genP=> x Gx. by rewrite !cfunE cfun1Egen Gx mulVf ?(forall_inP Uphi). Qed. Fact cfun_unitP phi psi : psi * phi = 1 -> phi \in cfun_unit. Proof. move/cfunP=> phiK; apply/forall_inP=> x Gx; rewrite -unitfE; apply/unitrP. by exists (psi x); have:= phiK x; rewrite !cfunE cfun1Egen Gx mulrC. Qed. Fact cfun_inv0id : {in [predC cfun_unit], cfun_inv =1 id}. Proof. by rewrite /cfun_inv => phi /negbTE/= ->. Qed. Definition cfun_unitMixin := ComUnitRingMixin cfun_mulV cfun_unitP cfun_inv0id. Canonical cfun_unitRingType := UnitRingType classfun cfun_unitMixin. Canonical cfun_comUnitRingType := [comUnitRingType of classfun]. Fact cfun_scaleA a b phi : cfun_scale a (cfun_scale b phi) = cfun_scale (a * b) phi. Proof. by apply/cfunP=> x; rewrite !cfunE mulrA. Qed. Fact cfun_scale1 : left_id 1 cfun_scale. Proof. by move=> phi; apply/cfunP=> x; rewrite !cfunE mul1r. Qed. Fact cfun_scaleDr : right_distributive cfun_scale +%R. Proof. by move=> a phi psi; apply/cfunP=> x; rewrite !cfunE mulrDr. Qed. Fact cfun_scaleDl phi : {morph cfun_scale^~ phi : a b / a + b}. Proof. by move=> a b; apply/cfunP=> x; rewrite !cfunE mulrDl. Qed. Definition cfun_lmodMixin := LmodMixin cfun_scaleA cfun_scale1 cfun_scaleDr cfun_scaleDl. Canonical cfun_lmodType := LmodType algC classfun cfun_lmodMixin. Fact cfun_scaleAl a phi psi : a *: (phi * psi) = (a *: phi) * psi. Proof. by apply/cfunP=> x; rewrite !cfunE mulrA. Qed. Fact cfun_scaleAr a phi psi : a *: (phi * psi) = phi * (a *: psi). Proof. by rewrite !(mulrC phi) cfun_scaleAl. Qed. Canonical cfun_lalgType := LalgType algC classfun cfun_scaleAl. Canonical cfun_algType := AlgType algC classfun cfun_scaleAr. Canonical cfun_unitAlgType := [unitAlgType algC of classfun]. Section Automorphism. Variable u : {rmorphism algC -> algC}. Definition cfAut := cfun_comp (rmorph0 u). Lemma cfAut_cfun1i A : cfAut '1_A = '1_A. Proof. by apply/cfunP=> x; rewrite !cfunElock rmorph_nat. Qed. Lemma cfAutZ a phi : cfAut (a *: phi) = u a *: cfAut phi. Proof. by apply/cfunP=> x; rewrite !cfunE rmorphM. Qed. Lemma cfAut_is_rmorphism : rmorphism cfAut. Proof. by do 2?split=> [phi psi|]; last exact: cfAut_cfun1i; apply/cfunP=> x; rewrite !cfunE (rmorphB, rmorphM). Qed. Canonical cfAut_additive := Additive cfAut_is_rmorphism. Canonical cfAut_rmorphism := RMorphism cfAut_is_rmorphism. Lemma cfAut_cfun1 : cfAut 1 = 1. Proof. exact: rmorph1. Qed. Lemma cfAut_scalable : scalable_for (u \; *:%R) cfAut. Proof. by move=> a phi; apply/cfunP=> x; rewrite !cfunE rmorphM. Qed. Canonical cfAut_linear := AddLinear cfAut_scalable. Canonical cfAut_lrmorphism := [lrmorphism of cfAut]. Definition cfAut_closed (S : seq classfun) := {in S, forall phi, cfAut phi \in S}. End Automorphism. Definition cfReal phi := cfAut conjC phi == phi. Definition cfConjC_subset (S1 S2 : seq classfun) := [/\ uniq S1, {subset S1 <= S2} & cfAut_closed conjC S1]. Fact cfun_vect_iso : Vector.axiom #|classes G| classfun. Proof. exists (fun phi => \row_i phi (repr (enum_val i))) => [a phi psi|]. by apply/rowP=> i; rewrite !(mxE, cfunE). set n := #|_|; pose eK x : 'I_n := enum_rank_in (classes1 _) (x ^: G). have rV2vP v : is_class_fun G [ffun x => v (eK x) *+ (x \in G)]. apply: intro_class_fun => [x y Gx Gy | x /negbTE/=-> //]. by rewrite groupJr // /eK classGidl. exists (fun v : 'rV_n => Cfun 0 (rV2vP (v 0))) => [phi | v]. apply/cfun_in_genP=> x Gx; rewrite cfunE Gx mxE enum_rankK_in ?mem_classes //. by have [y Gy ->] := repr_class <> x; rewrite cfunJgen. apply/rowP=> i; rewrite mxE cfunE; have /imsetP[x Gx def_i] := enum_valP i. rewrite def_i; have [y Gy ->] := repr_class <> x. by rewrite groupJ // /eK classGidl // -def_i enum_valK_in. Qed. Definition cfun_vectMixin := VectMixin cfun_vect_iso. Canonical cfun_vectType := VectType algC classfun cfun_vectMixin. Canonical cfun_FalgType := [FalgType algC of classfun]. Definition cfun_base A : #|classes B ::&: A|.-tuple classfun := [tuple of [seq '1_xB | xB in classes B ::&: A]]. Definition classfun_on A := <>%VS. Definition cfdot phi psi := #|B|%:R^-1 * \sum_(x in B) phi x * (psi x)^*. Definition cfdotr_head k psi phi := let: tt := k in cfdot phi psi. Definition cfnorm_head k phi := let: tt := k in cfdot phi phi. Coercion seq_of_cfun phi := [:: phi]. Definition cforder phi := \big[lcmn/1%N]_(x in <>) #[phi x]%C. End Defs. Bind Scope cfun_scope with classfun. Arguments Scope classfun [_ group_scope]. Arguments Scope classfun_on [_ group_scope group_scope]. Arguments Scope cfun_indicator [_ group_scope]. Arguments Scope cfAut [_ group_scope _ cfun_scope]. Arguments Scope cfReal [_ group_scope cfun_scope]. Arguments Scope cfdot [_ group_scope cfun_scope cfun_scope]. Arguments Scope cfdotr_head [_ group_scope _ cfun_scope cfun_scope]. Arguments Scope cfdotr_head [_ group_scope _ cfun_scope]. Notation "''CF' ( G )" := (classfun G) : type_scope. Notation "''CF' ( G )" := (@fullv _ (cfun_vectType G)) : vspace_scope. Notation "''1_' A" := (cfun_indicator _ A) : ring_scope. Notation "''CF' ( G , A )" := (classfun_on G A) : ring_scope. Notation "1" := (@GRing.one (cfun_ringType _)) (only parsing) : cfun_scope. Notation "phi ^*" := (cfAut conjC phi) : cfun_scope. Notation conjC_closed := (cfAut_closed conjC). Prenex Implicits cfReal. (* Workaround for overeager projection reduction. *) Notation eqcfP := (@eqP (cfun_eqType _) _ _) (only parsing). Notation "#[ phi ]" := (cforder phi) : cfun_scope. Notation "''[' u , v ]_ G":= (@cfdot _ G u v) (only parsing) : ring_scope. Notation "''[' u , v ]" := (cfdot u v) : ring_scope. Notation "''[' u ]_ G" := '[u, u]_G (only parsing) : ring_scope. Notation "''[' u ]" := '[u, u] : ring_scope. Notation cfdotr := (cfdotr_head tt). Notation cfnorm := (cfnorm_head tt). Section Predicates. Variables (gT rT : finGroupType) (D : {set gT}) (R : {set rT}). Implicit Types (phi psi : 'CF(D)) (S : seq 'CF(D)) (tau : 'CF(D) -> 'CF(R)). Definition cfker phi := [set x in D | [forall y, phi (x * y)%g == phi y]]. Definition cfaithful phi := cfker phi \subset [1]. Definition ortho_rec S1 S2 := all [pred phi | all [pred psi | '[phi, psi] == 0] S2] S1. Fixpoint pair_ortho_rec S := if S is psi :: S' then ortho_rec psi S' && pair_ortho_rec S' else true. (* We exclude 0 from pairwise orthogonal sets. *) Definition pairwise_orthogonal S := (0 \notin S) && pair_ortho_rec S. Definition orthonormal S := all [pred psi | '[psi] == 1] S && pair_ortho_rec S. Definition isometry tau := forall phi psi, '[tau phi, tau psi] = '[phi, psi]. Definition isometry_from_to mCFD tau mCFR := prop_in2 mCFD (inPhantom (isometry tau)) /\ prop_in1 mCFD (inPhantom (forall phi, in_mem (tau phi) mCFR)). End Predicates. (* Outside section so the nosimpl does not get "cooked" out. *) Definition orthogonal gT D S1 S2 := nosimpl (@ortho_rec gT D S1 S2). Arguments Scope cfker [_ group_scope cfun_scope]. Arguments Scope cfaithful [_ group_scope cfun_scope]. Arguments Scope orthogonal [_ group_scope cfun_scope cfun_scope]. Arguments Scope pairwise_orthogonal [_ group_scope cfun_scope]. Arguments Scope orthonormal [_ group_scope cfun_scope]. Arguments Scope isometry [_ _ group_scope group_scope cfun_scope]. Notation "{ 'in' CFD , 'isometry' tau , 'to' CFR }" := (isometry_from_to (mem CFD) tau (mem CFR)) (at level 0, format "{ 'in' CFD , 'isometry' tau , 'to' CFR }") : type_scope. Section ClassFun. Variables (gT : finGroupType) (G : {group gT}). Implicit Types (A B : {set gT}) (H K : {group gT}) (phi psi xi : 'CF(G)). Local Notation "''1_' A" := (cfun_indicator G A). Lemma cfun0 phi x : x \notin G -> phi x = 0. Proof. by rewrite -{1}(genGid G) => /(cfun0gen phi). Qed. Lemma support_cfun phi : support phi \subset G. Proof. by apply/subsetP=> g; apply: contraR => /cfun0->. Qed. Lemma cfunJ phi x y : y \in G -> phi (x ^ y) = phi x. Proof. by rewrite -{1}(genGid G) => /(cfunJgen phi)->. Qed. Lemma cfun_repr phi x : phi (repr (x ^: G)) = phi x. Proof. by have [y Gy ->] := repr_class G x; exact: cfunJ. Qed. Lemma cfun_inP phi psi : {in G, phi =1 psi} -> phi = psi. Proof. by rewrite -{1}genGid => /cfun_in_genP. Qed. Lemma cfuniE A x : A <| G -> '1_A x = (x \in A)%:R. Proof. case/andP=> sAG nAG; rewrite cfunElock genGid. by rewrite class_sub_norm // andb_idl // => /(subsetP sAG). Qed. Lemma support_cfuni A : A <| G -> support '1_A =i A. Proof. by move=> nsAG x; rewrite !inE cfuniE // pnatr_eq0 -lt0n lt0b. Qed. Lemma eq_mul_cfuni A phi : A <| G -> {in A, phi * '1_A =1 phi}. Proof. by move=> nsAG x Ax; rewrite cfunE cfuniE // Ax mulr1. Qed. Lemma eq_cfuni A : A <| G -> {in A, '1_A =1 (1 : 'CF(G))}. Proof. by rewrite -['1_A]mul1r; exact: eq_mul_cfuni. Qed. Lemma cfuniG : '1_G = 1. Proof. by rewrite -[G in '1_G]genGid. Qed. Lemma cfun1E g : (1 : 'CF(G)) g = (g \in G)%:R. Proof. by rewrite -cfuniG cfuniE. Qed. Lemma cfun11 : (1 : 'CF(G)) 1%g = 1. Proof. by rewrite cfun1E group1. Qed. Lemma prod_cfunE I r (P : pred I) (phi : I -> 'CF(G)) x : x \in G -> (\prod_(i <- r | P i) phi i) x = \prod_(i <- r | P i) (phi i) x. Proof. by move=> Gx; elim/big_rec2: _ => [|i _ psi _ <-]; rewrite ?cfunE ?cfun1E ?Gx. Qed. Lemma exp_cfunE phi n x : x \in G -> (phi ^+ n) x = phi x ^+ n. Proof. by rewrite -[n]card_ord -!prodr_const; apply: prod_cfunE. Qed. Lemma mul_cfuni A B : '1_A * '1_B = '1_(A :&: B) :> 'CF(G). Proof. apply/cfunP=> g; rewrite !cfunElock -natrM mulnb subsetI. by rewrite andbCA !andbA andbb. Qed. Lemma cfun_classE x y : '1_(x ^: G) y = ((x \in G) && (y \in x ^: G))%:R. Proof. rewrite cfunElock genGid class_sub_norm ?class_norm //; congr (_ : bool)%:R. by apply: andb_id2r => /imsetP[z Gz ->]; rewrite groupJr. Qed. Lemma cfun_on_sum A : 'CF(G, A) = (\sum_(xG in classes G | xG \subset A) <['1_xG]>)%VS. Proof. rewrite ['CF(G, A)]span_def big_map big_filter. by apply: eq_bigl => xG; rewrite !inE. Qed. Lemma cfun_onP A phi : reflect (forall x, x \notin A -> phi x = 0) (phi \in 'CF(G, A)). Proof. apply: (iffP idP) => [/coord_span-> x notAx | Aphi]. set b := cfun_base G A; rewrite sum_cfunE big1 // => i _; rewrite cfunE. have /mapP[xG]: b`_i \in b by rewrite -tnth_nth mem_tnth. rewrite mem_enum => /setIdP[/imsetP[y Gy ->] Ay] ->. by rewrite cfun_classE Gy (contraNF (subsetP Ay x)) ?mulr0. suffices <-: \sum_(xG in classes G) phi (repr xG) *: '1_xG = phi. apply: memv_suml => _ /imsetP[x Gx ->]; rewrite rpredZeq cfun_repr. have [s_xG_A | /subsetPn[_ /imsetP[y Gy ->]]] := boolP (x ^: G \subset A). by rewrite cfun_on_sum [_ \in _](sumv_sup (x ^: G)) ?mem_classes ?orbT. by move/Aphi; rewrite cfunJ // => ->; rewrite eqxx. apply/cfun_inP=> x Gx; rewrite sum_cfunE (bigD1 (x ^: G)) ?mem_classes //=. rewrite cfunE cfun_repr cfun_classE Gx class_refl mulr1. rewrite big1 ?addr0 // => _ /andP[/imsetP[y Gy ->]]; apply: contraNeq. rewrite cfunE cfun_repr cfun_classE Gy mulf_eq0 => /norP[_]. by rewrite pnatr_eq0 -lt0n lt0b => /class_transr->. Qed. Implicit Arguments cfun_onP [A phi]. Lemma cfun_on0 A phi x : phi \in 'CF(G, A) -> x \notin A -> phi x = 0. Proof. by move/cfun_onP; exact. Qed. Lemma sum_by_classes (R : ringType) (F : gT -> R) : {in G &, forall g h, F (g ^ h) = F g} -> \sum_(g in G) F g = \sum_(xG in classes G) #|xG|%:R * F (repr xG). Proof. move=> FJ; rewrite {1}(partition_big _ _ ((@mem_classes gT)^~ G)) /=. apply: eq_bigr => _ /imsetP[x Gx ->]; have [y Gy ->] := repr_class G x. rewrite mulr_natl -sumr_const FJ {y Gy}//; apply/esym/eq_big=> y /=. apply/idP/andP=> [xGy | [Gy /eqP<-]]; last exact: class_refl. by rewrite (class_transr xGy) (subsetP (class_subG Gx (subxx _))). by case/imsetP=> z Gz ->; rewrite FJ. Qed. Lemma cfun_base_free A : free (cfun_base G A). Proof. have b_i (i : 'I_#|classes G ::&: A|) : (cfun_base G A)`_i = '1_(enum_val i). by rewrite /enum_val -!tnth_nth tnth_map. apply/freeP => s S0 i; move/cfunP/(_ (repr (enum_val i))): S0. rewrite sum_cfunE (bigD1 i) //= big1 ?addr0 => [|j]. rewrite b_i !cfunE; have /setIdP[/imsetP[x Gx ->] _] := enum_valP i. by rewrite cfun_repr cfun_classE Gx class_refl mulr1. apply: contraNeq; rewrite b_i !cfunE mulf_eq0 => /norP[_]. rewrite -(inj_eq enum_val_inj). have /setIdP[/imsetP[x _ ->] _] := enum_valP i; rewrite cfun_repr. have /setIdP[/imsetP[y Gy ->] _] := enum_valP j; rewrite cfun_classE Gy. by rewrite pnatr_eq0 -lt0n lt0b => /class_transr->. Qed. Lemma dim_cfun : \dim 'CF(G) = #|classes G|. Proof. by rewrite dimvf /Vector.dim /= genGid. Qed. Lemma dim_cfun_on A : \dim 'CF(G, A) = #|classes G ::&: A|. Proof. by rewrite (eqnP (cfun_base_free A)) size_tuple. Qed. Lemma dim_cfun_on_abelian A : abelian G -> A \subset G -> \dim 'CF(G, A) = #|A|. Proof. move/abelian_classP=> cGG sAG; rewrite -(card_imset _ set1_inj) dim_cfun_on. apply/eq_card=> xG; rewrite !inE. apply/andP/imsetP=> [[/imsetP[x Gx ->] Ax] | [x Ax ->]] {xG}. by rewrite cGG ?sub1set // in Ax *; exists x. by rewrite -{1}(cGG x) ?mem_classes ?(subsetP sAG) ?sub1set. Qed. Lemma cfuni_on A : '1_A \in 'CF(G, A). Proof. apply/cfun_onP=> x notAx; rewrite cfunElock genGid. by case: andP => // [[_ s_xG_A]]; rewrite (subsetP s_xG_A) ?class_refl in notAx. Qed. Lemma mul_cfuni_on A phi : phi * '1_A \in 'CF(G, A). Proof. by apply/cfun_onP=> x /(cfun_onP (cfuni_on A)) Ax0; rewrite cfunE Ax0 mulr0. Qed. Lemma cfun_onE phi A : (phi \in 'CF(G, A)) = (support phi \subset A). Proof. exact: (sameP cfun_onP supportP). Qed. Lemma cfun_onT phi : phi \in 'CF(G, [set: gT]). Proof. by rewrite cfun_onE. Qed. Lemma cfun_onD1 phi A : (phi \in 'CF(G, A^#)) = (phi \in 'CF(G, A)) && (phi 1%g == 0). Proof. by rewrite !cfun_onE -!(eq_subset (in_set (support _))) subsetD1 !inE negbK. Qed. Lemma cfun_onG phi : phi \in 'CF(G, G). Proof. by rewrite cfun_onE support_cfun. Qed. Lemma cfunD1E phi : (phi \in 'CF(G, G^#)) = (phi 1%g == 0). Proof. by rewrite cfun_onD1 cfun_onG. Qed. Lemma cfunGid : 'CF(G, G) = 'CF(G)%VS. Proof. by apply/vspaceP=> phi; rewrite cfun_onG memvf. Qed. Lemma cfun_onS A B phi : B \subset A -> phi \in 'CF(G, B) -> phi \in 'CF(G, A). Proof. by rewrite !cfun_onE => sBA /subset_trans->. Qed. Lemma cfun_complement A : A <| G -> ('CF(G, A) + 'CF(G, G :\: A)%SET = 'CF(G))%VS. Proof. case/andP=> sAG nAG; rewrite -cfunGid [rhs in _ = rhs]cfun_on_sum. rewrite (bigID (fun B => B \subset A)) /=. congr (_ + _)%VS; rewrite cfun_on_sum; apply: eq_bigl => /= xG. rewrite andbAC; apply/esym/andb_idr=> /andP[/imsetP[x Gx ->] _]. by rewrite class_subG. rewrite -andbA; apply: andb_id2l => /imsetP[x Gx ->]. by rewrite !class_sub_norm ?normsD ?normG // inE andbC. Qed. Lemma cfConjCE phi x : (phi^*)%CF x = (phi x)^*. Proof. by rewrite cfunE. Qed. Lemma cfConjCK : involutive (fun phi => phi^*)%CF. Proof. by move=> phi; apply/cfunP=> x; rewrite !cfunE conjCK. Qed. Lemma cfConjC_cfun1 : (1^*)%CF = 1 :> 'CF(G). Proof. exact: rmorph1. Qed. (* Class function kernel and faithful class functions *) Fact cfker_is_group phi : group_set (cfker phi). Proof. apply/group_setP; split=> [|x y]; rewrite !inE ?group1. by apply/forallP=> y; rewrite mul1g. case/andP=> Gx /forallP-Kx /andP[Gy /forallP-Ky]; rewrite groupM //. by apply/forallP=> z; rewrite -mulgA (eqP (Kx _)) Ky. Qed. Canonical cfker_group phi := Group (cfker_is_group phi). Lemma cfker_sub phi : cfker phi \subset G. Proof. by rewrite /cfker setIdE subsetIl. Qed. Lemma cfker_norm phi : G \subset 'N(cfker phi). Proof. apply/subsetP=> z Gz; have phiJz := cfunJ phi _ (groupVr Gz). rewrite inE; apply/subsetP=> _ /imsetP[x /setIdP[Gx /forallP-Kx] ->]. rewrite inE groupJ //; apply/forallP=> y. by rewrite -(phiJz y) -phiJz conjMg conjgK Kx. Qed. Lemma cfker_normal phi : cfker phi <| G. Proof. by rewrite /normal cfker_sub cfker_norm. Qed. Lemma cfkerMl phi x y : x \in cfker phi -> phi (x * y)%g = phi y. Proof. by case/setIdP=> _ /eqfunP->. Qed. Lemma cfkerMr phi x y : x \in cfker phi -> phi (y * x)%g = phi y. Proof. by move=> Kx; rewrite conjgC cfkerMl ?cfunJ ?(subsetP (cfker_sub phi)). Qed. Lemma cfker1 phi x : x \in cfker phi -> phi x = phi 1%g. Proof. by move=> Kx; rewrite -[x]mulg1 cfkerMl. Qed. Lemma cfker_cfun0 : @cfker _ G 0 = G. Proof. apply/setP=> x; rewrite !inE andb_idr // => Gx; apply/forallP=> y. by rewrite !cfunE. Qed. Lemma cfker_add phi psi : cfker phi :&: cfker psi \subset cfker (phi + psi). Proof. apply/subsetP=> x /setIP[Kphi_x Kpsi_x]; have [Gx _] := setIdP Kphi_x. by rewrite inE Gx; apply/forallP=> y; rewrite !cfunE !cfkerMl. Qed. Lemma cfker_sum I r (P : pred I) (Phi : I -> 'CF(G)) : G :&: \bigcap_(i <- r | P i) cfker (Phi i) \subset cfker (\sum_(i <- r | P i) Phi i). Proof. elim/big_rec2: _ => [|i K psi Pi sK_psi]; first by rewrite setIT cfker_cfun0. by rewrite setICA; apply: subset_trans (setIS _ sK_psi) (cfker_add _ _). Qed. Lemma cfker_scale a phi : cfker phi \subset cfker (a *: phi). Proof. apply/subsetP=> x Kphi_x; have [Gx _] := setIdP Kphi_x. by rewrite inE Gx; apply/forallP=> y; rewrite !cfunE cfkerMl. Qed. Lemma cfker_scale_nz a phi : a != 0 -> cfker (a *: phi) = cfker phi. Proof. move=> nz_a; apply/eqP. by rewrite eqEsubset -{2}(scalerK nz_a phi) !cfker_scale. Qed. Lemma cfker_opp phi : cfker (- phi) = cfker phi. Proof. by rewrite -scaleN1r cfker_scale_nz // oppr_eq0 oner_eq0. Qed. Lemma cfker_cfun1 : @cfker _ G 1 = G. Proof. apply/setP=> x; rewrite !inE andb_idr // => Gx; apply/forallP=> y. by rewrite !cfun1E groupMl. Qed. Lemma cfker_mul phi psi : cfker phi :&: cfker psi \subset cfker (phi * psi). Proof. apply/subsetP=> x /setIP[Kphi_x Kpsi_x]; have [Gx _] := setIdP Kphi_x. by rewrite inE Gx; apply/forallP=> y; rewrite !cfunE !cfkerMl. Qed. Lemma cfker_prod I r (P : pred I) (Phi : I -> 'CF(G)) : G :&: \bigcap_(i <- r | P i) cfker (Phi i) \subset cfker (\prod_(i <- r | P i) Phi i). Proof. elim/big_rec2: _ => [|i K psi Pi sK_psi]; first by rewrite setIT cfker_cfun1. by rewrite setICA; apply: subset_trans (setIS _ sK_psi) (cfker_mul _ _). Qed. Lemma cfaithfulE phi : cfaithful phi = (cfker phi \subset [1]). Proof. by []. Qed. End ClassFun. Arguments Scope classfun_on [_ group_scope group_scope]. Notation "''CF' ( G , A )" := (classfun_on G A) : ring_scope. Implicit Arguments cfun_onP [gT G A phi]. Hint Resolve cfun_onT. Section DotProduct. Variable (gT : finGroupType) (G : {group gT}). Implicit Types (M : {group gT}) (phi psi xi : 'CF(G)) (R S : seq 'CF(G)). Lemma cfdotE phi psi : '[phi, psi] = #|G|%:R^-1 * \sum_(x in G) phi x * (psi x)^*. Proof. by []. Qed. Lemma cfdotElr A B phi psi : phi \in 'CF(G, A) -> psi \in 'CF(G, B) -> '[phi, psi] = #|G|%:R^-1 * \sum_(x in A :&: B) phi x * (psi x)^*. Proof. move=> Aphi Bpsi; rewrite (big_setID G) cfdotE (big_setID (A :&: B)) setIC /=. congr (_ * (_ + _)); rewrite !big1 // => x /setDP[_]. by move/cfun0->; rewrite mul0r. rewrite inE; case/nandP=> notABx; first by rewrite (cfun_on0 Aphi) ?mul0r. by rewrite (cfun_on0 Bpsi) // rmorph0 mulr0. Qed. Lemma cfdotEl A phi psi : phi \in 'CF(G, A) -> '[phi, psi] = #|G|%:R^-1 * \sum_(x in A) phi x * (psi x)^*. Proof. by move=> Aphi; rewrite (cfdotElr Aphi (cfun_onT psi)) setIT. Qed. Lemma cfdotEr A phi psi : psi \in 'CF(G, A) -> '[phi, psi] = #|G|%:R^-1 * \sum_(x in A) phi x * (psi x)^*. Proof. by move=> Apsi; rewrite (cfdotElr (cfun_onT phi) Apsi) setTI. Qed. Lemma cfdot_complement A phi psi : phi \in 'CF(G, A) -> psi \in 'CF(G, G :\: A) -> '[phi, psi] = 0. Proof. move=> Aphi A'psi; rewrite (cfdotElr Aphi A'psi). by rewrite setDE setICA setICr setI0 big_set0 mulr0. Qed. Lemma cfnormE A phi : phi \in 'CF(G, A) -> '[phi] = #|G|%:R^-1 * (\sum_(x in A) `|phi x| ^+ 2). Proof. by move/cfdotEl->; rewrite (eq_bigr _ (fun _ _ => normCK _)). Qed. Lemma eq_cfdotl A phi1 phi2 psi : psi \in 'CF(G, A) -> {in A, phi1 =1 phi2} -> '[phi1, psi] = '[phi2, psi]. Proof. move/cfdotEr=> eq_dot eq_phi; rewrite !eq_dot; congr (_ * _). by apply: eq_bigr => x Ax; rewrite eq_phi. Qed. Lemma cfdot_cfuni A B : A <| G -> B <| G -> '['1_A, '1_B]_G = #|A :&: B|%:R / #|G|%:R. Proof. move=> nsAG nsBG; rewrite (cfdotElr (cfuni_on G A) (cfuni_on G B)) mulrC. congr (_ / _); rewrite -sumr_const; apply: eq_bigr => x /setIP[Ax Bx]. by rewrite !cfuniE // Ax Bx rmorph1 mulr1. Qed. Lemma cfnorm1 : '[1]_G = 1. Proof. by rewrite cfdot_cfuni ?genGid // setIid divff ?neq0CG. Qed. Lemma cfdotrE psi phi : cfdotr psi phi = '[phi, psi]. Proof. by []. Qed. Lemma cfdotr_is_linear xi : linear (cfdotr xi : 'CF(G) -> algC^o). Proof. move=> a phi psi; rewrite scalerAr -mulrDr; congr (_ * _). rewrite linear_sum -big_split; apply: eq_bigr => x _ /=. by rewrite !cfunE mulrDl -mulrA. Qed. Canonical cfdotr_additive xi := Additive (cfdotr_is_linear xi). Canonical cfdotr_linear xi := Linear (cfdotr_is_linear xi). Lemma cfdot0l xi : '[0, xi] = 0. Proof. by rewrite -cfdotrE linear0. Qed. Lemma cfdotNl xi phi : '[- phi, xi] = - '[phi, xi]. Proof. by rewrite -!cfdotrE linearN. Qed. Lemma cfdotDl xi phi psi : '[phi + psi, xi] = '[phi, xi] + '[psi, xi]. Proof. by rewrite -!cfdotrE linearD. Qed. Lemma cfdotBl xi phi psi : '[phi - psi, xi] = '[phi, xi] - '[psi, xi]. Proof. by rewrite -!cfdotrE linearB. Qed. Lemma cfdotMnl xi phi n : '[phi *+ n, xi] = '[phi, xi] *+ n. Proof. by rewrite -!cfdotrE linearMn. Qed. Lemma cfdot_suml xi I r (P : pred I) (phi : I -> 'CF(G)) : '[\sum_(i <- r | P i) phi i, xi] = \sum_(i <- r | P i) '[phi i, xi]. Proof. by rewrite -!cfdotrE linear_sum. Qed. Lemma cfdotZl xi a phi : '[a *: phi, xi] = a * '[phi, xi]. Proof. by rewrite -!cfdotrE linearZ. Qed. Lemma cfdotC phi psi : '[phi, psi] = ('[psi, phi])^*. Proof. rewrite /cfdot rmorphM fmorphV rmorph_nat rmorph_sum; congr (_ * _). by apply: eq_bigr=> x _; rewrite rmorphM conjCK mulrC. Qed. Lemma eq_cfdotr A phi psi1 psi2 : phi \in 'CF(G, A) -> {in A, psi1 =1 psi2} -> '[phi, psi1] = '[phi, psi2]. Proof. by move=> Aphi /eq_cfdotl eq_dot; rewrite cfdotC eq_dot // -cfdotC. Qed. Lemma cfdotBr xi phi psi : '[xi, phi - psi] = '[xi, phi] - '[xi, psi]. Proof. by rewrite !(cfdotC xi) -rmorphB cfdotBl. Qed. Canonical cfun_dot_additive xi := Additive (cfdotBr xi). Lemma cfdot0r xi : '[xi, 0] = 0. Proof. exact: raddf0. Qed. Lemma cfdotNr xi phi : '[xi, - phi] = - '[xi, phi]. Proof. exact: raddfN. Qed. Lemma cfdotDr xi phi psi : '[xi, phi + psi] = '[xi, phi] + '[xi, psi]. Proof. exact: raddfD. Qed. Lemma cfdotMnr xi phi n : '[xi, phi *+ n] = '[xi, phi] *+ n. Proof. exact: raddfMn. Qed. Lemma cfdot_sumr xi I r (P : pred I) (phi : I -> 'CF(G)) : '[xi, \sum_(i <- r | P i) phi i] = \sum_(i <- r | P i) '[xi, phi i]. Proof. exact: raddf_sum. Qed. Lemma cfdotZr a xi phi : '[xi, a *: phi] = a^* * '[xi, phi]. Proof. by rewrite !(cfdotC xi) cfdotZl rmorphM. Qed. Lemma cfdot_cfAut (u : {rmorphism algC -> algC}) phi psi : {in image psi G, {morph u : x / x^*}} -> '[cfAut u phi, cfAut u psi] = u '[phi, psi]. Proof. move=> uC; rewrite rmorphM fmorphV rmorph_nat rmorph_sum; congr (_ * _). by apply: eq_bigr => x Gx; rewrite !cfunE rmorphM uC ?map_f ?mem_enum. Qed. Lemma cfdot_conjC phi psi : '[phi^*, psi^*] = '[phi, psi]^*. Proof. by rewrite cfdot_cfAut. Qed. Lemma cfdot_conjCl phi psi : '[phi^*, psi] = '[phi, psi^*]^*. Proof. by rewrite -cfdot_conjC cfConjCK. Qed. Lemma cfdot_conjCr phi psi : '[phi, psi^*] = '[phi^*, psi]^*. Proof. by rewrite -cfdot_conjC cfConjCK. Qed. Lemma cfnorm_ge0 phi : 0 <= '[phi]. Proof. by rewrite mulr_ge0 ?invr_ge0 ?ler0n ?sumr_ge0 // => x _; exact: mul_conjC_ge0. Qed. Lemma cfnorm_eq0 phi : ('[phi] == 0) = (phi == 0). Proof. apply/idP/eqP=> [|->]; last by rewrite cfdot0r. rewrite mulf_eq0 invr_eq0 (negbTE (neq0CG G)) /= => /eqP/psumr_eq0P phi0. apply/cfun_inP=> x Gx; apply/eqP; rewrite cfunE -mul_conjC_eq0. by rewrite phi0 // => y _; exact: mul_conjC_ge0. Qed. Lemma cfnorm_gt0 phi : ('[phi] > 0) = (phi != 0). Proof. by rewrite ltr_def cfnorm_ge0 cfnorm_eq0 andbT. Qed. Lemma sqrt_cfnorm_ge0 phi : 0 <= sqrtC '[phi]. Proof. by rewrite sqrtC_ge0 cfnorm_ge0. Qed. Lemma sqrt_cfnorm_eq0 phi : (sqrtC '[phi] == 0) = (phi == 0). Proof. by rewrite sqrtC_eq0 cfnorm_eq0. Qed. Lemma sqrt_cfnorm_gt0 phi : (sqrtC '[phi] > 0) = (phi != 0). Proof. by rewrite sqrtC_gt0 cfnorm_gt0. Qed. Lemma cfnormZ a phi : '[a *: phi]= `|a| ^+ 2 * '[phi]_G. Proof. by rewrite cfdotZl cfdotZr mulrA normCK. Qed. Lemma cfnormN phi : '[- phi] = '[phi]. Proof. by rewrite cfdotNl raddfN opprK. Qed. Lemma cfnorm_sign n phi : '[(-1) ^+ n *: phi] = '[phi]. Proof. by rewrite -signr_odd scaler_sign; case: (odd n); rewrite ?cfnormN. Qed. Lemma cfnormD phi psi : let d := '[phi, psi] in '[phi + psi] = '[phi] + '[psi] + (d + d^*). Proof. by rewrite /= addrAC -cfdotC cfdotDl !cfdotDr !addrA. Qed. Lemma cfnormB phi psi : let d := '[phi, psi] in '[phi - psi] = '[phi] + '[psi] - (d + d^*). Proof. by rewrite /= cfnormD cfnormN cfdotNr rmorphN -opprD. Qed. Lemma cfnormDd phi psi : '[phi, psi] = 0 -> '[phi + psi] = '[phi] + '[psi]. Proof. by move=> ophipsi; rewrite cfnormD ophipsi rmorph0 !addr0. Qed. Lemma cfnormBd phi psi : '[phi, psi] = 0 -> '[phi - psi] = '[phi] + '[psi]. Proof. by move=> ophipsi; rewrite cfnormDd ?cfnormN // cfdotNr ophipsi oppr0. Qed. Lemma cfnorm_conjC phi : '[phi^*] = '[phi]. Proof. by rewrite cfdot_conjC geC0_conj // cfnorm_ge0. Qed. Lemma cfCauchySchwarz phi psi : `|'[phi, psi]| ^+ 2 <= '[phi] * '[psi] ?= iff ~~ free (phi :: psi). Proof. rewrite free_cons span_seq1 seq1_free -negb_or negbK orbC. have [-> | nz_psi] /= := altP (psi =P 0). by apply/lerifP; rewrite !cfdot0r normCK mul0r mulr0. without loss ophi: phi / '[phi, psi] = 0. move=> IHo; pose a := '[phi, psi] / '[psi]; pose phi1 := phi - a *: psi. have ophi: '[phi1, psi] = 0. by rewrite cfdotBl cfdotZl divfK ?cfnorm_eq0 ?subrr. rewrite (canRL (subrK _) (erefl phi1)) rpredDr ?rpredZ ?memv_line //. rewrite cfdotDl ophi add0r cfdotZl normrM (ger0_norm (cfnorm_ge0 _)). rewrite exprMn mulrA -cfnormZ cfnormDd; last by rewrite cfdotZr ophi mulr0. by have:= IHo _ ophi; rewrite mulrDl -lerif_subLR subrr ophi normCK mul0r. rewrite ophi normCK mul0r; split; first by rewrite mulr_ge0 ?cfnorm_ge0. rewrite eq_sym mulf_eq0 orbC cfnorm_eq0 (negPf nz_psi) /=. apply/idP/idP=> [|/vlineP[a {2}->]]; last by rewrite cfdotZr ophi mulr0. by rewrite cfnorm_eq0 => /eqP->; apply: rpred0. Qed. Lemma cfCauchySchwarz_sqrt phi psi : `|'[phi, psi]| <= sqrtC '[phi] * sqrtC '[psi] ?= iff ~~ free (phi :: psi). Proof. rewrite -(sqrCK (normr_ge0 _)) -sqrtCM ?qualifE ?cfnorm_ge0 //. rewrite (mono_in_lerif ler_sqrtC) 1?rpredM ?qualifE ?normr_ge0 ?cfnorm_ge0 //. exact: cfCauchySchwarz. Qed. Lemma cf_triangle_lerif phi psi : sqrtC '[phi + psi] <= sqrtC '[phi] + sqrtC '[psi] ?= iff ~~ free (phi :: psi) && (0 <= coord [tuple psi] 0 phi). Proof. rewrite -(mono_in_lerif ler_sqr) ?rpredD ?qualifE ?sqrtC_ge0 ?cfnorm_ge0 //. rewrite andbC sqrrD !sqrtCK addrAC cfnormD (mono_lerif (ler_add2l _)). rewrite -mulr_natr -[_ + _](divfK (negbT (eqC_nat 2 0))) -/('Re _). rewrite (mono_lerif (ler_pmul2r _)) ?ltr0n //. have:= lerif_trans (lerif_Re_Creal '[phi, psi]) (cfCauchySchwarz_sqrt phi psi). congr (_ <= _ ?= iff _); apply: andb_id2r. rewrite free_cons span_seq1 seq1_free -negb_or negbK orbC. have [-> | nz_psi] := altP (psi =P 0); first by rewrite cfdot0r coord0. case/vlineP=> [x ->]; rewrite cfdotZl linearZ pmulr_lge0 ?cfnorm_gt0 //=. by rewrite (coord_free 0) ?seq1_free // eqxx mulr1. Qed. Lemma orthogonal_cons phi R S : orthogonal (phi :: R) S = orthogonal phi S && orthogonal R S. Proof. by rewrite /orthogonal /= andbT. Qed. Lemma orthoP phi psi : reflect ('[phi, psi] = 0) (orthogonal phi psi). Proof. by rewrite /orthogonal /= !andbT; exact: eqP. Qed. Lemma orthogonalP S R : reflect {in S & R, forall phi psi, '[phi, psi] = 0} (orthogonal S R). Proof. apply: (iffP allP) => oSR phi => [psi /oSR/allP opS /opS/eqP // | /oSR opS]. by apply/allP=> psi /= /opS->. Qed. Lemma orthoPl phi S : reflect {in S, forall psi, '[phi, psi] = 0} (orthogonal phi S). Proof. by rewrite [orthogonal _ S]andbT /=; apply: (iffP allP) => ophiS ? /ophiS/eqP. Qed. Implicit Arguments orthoPl [phi S]. Lemma orthogonal_sym : symmetric (@orthogonal _ G). Proof. apply: symmetric_from_pre => R S /orthogonalP oRS. by apply/orthogonalP=> phi psi Rpsi Sphi; rewrite cfdotC oRS ?rmorph0. Qed. Lemma orthoPr S psi : reflect {in S, forall phi, '[phi, psi] = 0} (orthogonal S psi). Proof. rewrite orthogonal_sym. by apply: (iffP orthoPl) => oSpsi phi Sphi; rewrite cfdotC oSpsi ?conjC0. Qed. Lemma eq_orthogonal R1 R2 S1 S2 : R1 =i R2 -> S1 =i S2 -> orthogonal R1 S1 = orthogonal R2 S2. Proof. move=> eqR eqS; rewrite [orthogonal _ _](eq_all_r eqR). by apply: eq_all => psi /=; exact: eq_all_r. Qed. Lemma orthogonal_catl R1 R2 S : orthogonal (R1 ++ R2) S = orthogonal R1 S && orthogonal R2 S. Proof. exact: all_cat. Qed. Lemma orthogonal_catr R S1 S2 : orthogonal R (S1 ++ S2) = orthogonal R S1 && orthogonal R S2. Proof. by rewrite !(orthogonal_sym R) orthogonal_catl. Qed. Lemma span_orthogonal S1 S2 phi1 phi2 : orthogonal S1 S2 -> phi1 \in <>%VS -> phi2 \in <>%VS -> '[phi1, phi2] = 0. Proof. move/orthogonalP=> oS12; do 2!move/(@coord_span _ _ _ (in_tuple _))->. rewrite cfdot_suml big1 // => i _; rewrite cfdot_sumr big1 // => j _. by rewrite cfdotZl cfdotZr oS12 ?mem_nth ?mulr0. Qed. Lemma orthogonal_split S beta : {X : 'CF(G) & X \in <>%VS & {Y | [/\ beta = X + Y, '[X, Y] = 0 & orthogonal Y S]}}. Proof. suffices [X S_X [Y -> oYS]]: {X : _ & X \in <>%VS & {Y | beta = X + Y & orthogonal Y S}}. - exists X => //; exists Y. by rewrite cfdotC (span_orthogonal oYS) ?memv_span1 ?conjC0. elim: S beta => [|phi S IHS] beta. by exists 0; last exists beta; rewrite ?mem0v ?add0r. have [[U S_U [V -> oVS]] [X S_X [Y -> oYS]]] := (IHS phi, IHS beta). pose Z := '[Y, V] / '[V] *: V; exists (X + Z). rewrite /Z -{4}(addKr U V) scalerDr scalerN addrA addrC span_cons. by rewrite memv_add ?memvB ?memvZ ?memv_line. exists (Y - Z); first by rewrite addrCA !addrA addrK addrC. apply/orthoPl=> psi; rewrite !inE => /predU1P[-> | Spsi]; last first. by rewrite cfdotBl cfdotZl (orthoPl oVS _ Spsi) mulr0 subr0 (orthoPl oYS). rewrite cfdotBl !cfdotDr (span_orthogonal oYS) // ?memv_span ?mem_head //. rewrite !cfdotZl (span_orthogonal oVS _ S_U) ?mulr0 ?memv_span ?mem_head //. have [-> | nzV] := eqVneq V 0; first by rewrite cfdot0r !mul0r subrr. by rewrite divfK ?cfnorm_eq0 ?subrr. Qed. Lemma map_orthogonal M (nu : 'CF(G) -> 'CF(M)) S R (A : pred 'CF(G)) : {in A &, isometry nu} -> {subset S <= A} -> {subset R <= A} -> orthogonal (map nu S) (map nu R) = orthogonal S R. Proof. move=> Inu sSA sRA; rewrite [orthogonal _ _]all_map. apply: eq_in_all => phi Sphi; rewrite /= all_map. by apply: eq_in_all => psi Rpsi; rewrite /= Inu ?(sSA phi) ?(sRA psi). Qed. Lemma orthogonal_oppr S R : orthogonal S (map -%R R) = orthogonal S R. Proof. wlog suffices IH: S R / orthogonal S R -> orthogonal S (map -%R R). apply/idP/idP=> /IH; rewrite ?mapK //; exact: opprK. move/orthogonalP=> oSR; apply/orthogonalP=> xi1 _ Sxi1 /mapP[xi2 Rxi2 ->]. by rewrite cfdotNr oSR ?oppr0. Qed. Lemma orthogonal_oppl S R : orthogonal (map -%R S) R = orthogonal S R. Proof. by rewrite -!(orthogonal_sym R) orthogonal_oppr. Qed. Lemma pairwise_orthogonalP S : reflect (uniq (0 :: S) /\ {in S &, forall phi psi, phi != psi -> '[phi, psi] = 0}) (pairwise_orthogonal S). Proof. rewrite /pairwise_orthogonal /=; case notS0: (~~ _); last by right; case. elim: S notS0 => [|phi S IH] /=; first by left. rewrite inE eq_sym andbT => /norP[nz_phi /IH{IH}IH]. have [opS | not_opS] := allP; last first. right=> [[/andP[notSp _] opS]]; case: not_opS => psi Spsi /=. by rewrite opS ?mem_head 1?mem_behead // (memPnC notSp). rewrite (contra (opS _)) /= ?cfnorm_eq0 //. apply: (iffP IH) => [] [uniqS oSS]; last first. by split=> //; apply: sub_in2 oSS => psi Spsi; exact: mem_behead. split=> // psi xi; rewrite !inE => /predU1P[-> // | Spsi]. by case/predU1P=> [-> | /opS] /eqP. case/predU1P=> [-> _ | Sxi /oSS-> //]. by apply/eqP; rewrite cfdotC conjC_eq0 [_ == 0]opS. Qed. Lemma pairwise_orthogonal_cat R S : pairwise_orthogonal (R ++ S) = [&& pairwise_orthogonal R, pairwise_orthogonal S & orthogonal R S]. Proof. rewrite /pairwise_orthogonal mem_cat negb_or -!andbA; do !bool_congr. elim: R => [|phi R /= ->]; rewrite ?andbT // orthogonal_cons all_cat -!andbA /=. by do !bool_congr. Qed. Lemma eq_pairwise_orthogonal R S : perm_eq R S -> pairwise_orthogonal R = pairwise_orthogonal S. Proof. apply: catCA_perm_subst R S => R S S'. rewrite !pairwise_orthogonal_cat !orthogonal_catr (orthogonal_sym R S) -!andbA. by do !bool_congr. Qed. Lemma sub_pairwise_orthogonal S1 S2 : {subset S1 <= S2} -> uniq S1 -> pairwise_orthogonal S2 -> pairwise_orthogonal S1. Proof. move=> sS12 uniqS1 /pairwise_orthogonalP[/andP[notS2_0 _] oS2]. apply/pairwise_orthogonalP; rewrite /= (contra (sS12 0)) //. by split=> //; exact: sub_in2 oS2. Qed. Lemma orthogonal_free S : pairwise_orthogonal S -> free S. Proof. case/pairwise_orthogonalP=> [/=/andP[notS0 uniqS] oSS]. rewrite -(in_tupleE S); apply/freeP => a aS0 i. have S_i: S`_i \in S by exact: mem_nth. have /eqP: '[S`_i, 0]_G = 0 := cfdot0r _. rewrite -{2}aS0 raddf_sum /= (bigD1 i) //= big1 => [|j neq_ji]; last 1 first. by rewrite cfdotZr oSS ?mulr0 ?mem_nth // eq_sym nth_uniq. rewrite addr0 cfdotZr mulf_eq0 conjC_eq0 cfnorm_eq0. by case/pred2P=> // Si0; rewrite -Si0 S_i in notS0. Qed. Lemma filter_pairwise_orthogonal S p : pairwise_orthogonal S -> pairwise_orthogonal (filter p S). Proof. move=> orthoS; apply: sub_pairwise_orthogonal (orthoS). exact: mem_subseq (filter_subseq p S). exact/filter_uniq/free_uniq/orthogonal_free. Qed. Lemma orthonormal_not0 S : orthonormal S -> 0 \notin S. Proof. by case/andP=> /allP S1 _; rewrite (contra (S1 _)) //= cfdot0r eq_sym oner_eq0. Qed. Lemma orthonormalE S : orthonormal S = all [pred phi | '[phi] == 1] S && pairwise_orthogonal S. Proof. by rewrite -(andb_idl (@orthonormal_not0 S)) andbCA. Qed. Lemma orthonormal_orthogonal S : orthonormal S -> pairwise_orthogonal S. Proof. by rewrite orthonormalE => /andP[_]. Qed. Lemma orthonormal_cat R S : orthonormal (R ++ S) = [&& orthonormal R, orthonormal S & orthogonal R S]. Proof. rewrite !orthonormalE pairwise_orthogonal_cat all_cat -!andbA. by do !bool_congr. Qed. Lemma eq_orthonormal R S : perm_eq R S -> orthonormal R = orthonormal S. Proof. move=> eqRS; rewrite !orthonormalE (eq_all_r (perm_eq_mem eqRS)). by rewrite (eq_pairwise_orthogonal eqRS). Qed. Lemma orthonormal_free S : orthonormal S -> free S. Proof. by move/orthonormal_orthogonal/orthogonal_free. Qed. Lemma orthonormalP S : reflect (uniq S /\ {in S &, forall phi psi, '[phi, psi]_G = (phi == psi)%:R}) (orthonormal S). Proof. rewrite orthonormalE; have [/= normS | not_normS] := allP; last first. by right=> [[_ o1S]]; case: not_normS => phi Sphi; rewrite /= o1S ?eqxx. apply: (iffP (pairwise_orthogonalP S)) => [] [uniqS oSS]. split=> // [|phi psi]; first by case/andP: uniqS. by have [-> _ /normS/eqP | /oSS] := altP eqP. split=> // [|phi psi Sphi Spsi /negbTE]; last by rewrite oSS // => ->. by rewrite /= (contra (normS _)) // cfdot0r eq_sym oner_eq0. Qed. Lemma sub_orthonormal S1 S2 : {subset S1 <= S2} -> uniq S1 -> orthonormal S2 -> orthonormal S1. Proof. move=> sS12 uniqS1 /orthonormalP[_ oS1]. by apply/orthonormalP; split; last exact: sub_in2 sS12 _ _. Qed. Lemma orthonormal2P phi psi : reflect [/\ '[phi, psi] = 0, '[phi] = 1 & '[psi] = 1] (orthonormal [:: phi; psi]). Proof. rewrite /orthonormal /= !andbT andbC. by apply: (iffP and3P) => [] []; do 3!move/eqP->. Qed. Lemma conjC_pair_orthogonal S chi : conjC_closed S -> ~~ has cfReal S -> pairwise_orthogonal S -> chi \in S -> pairwise_orthogonal (chi :: chi^*%CF). Proof. move=> ccS /hasPn nrS oSS Schi; apply: sub_pairwise_orthogonal oSS. by apply/allP; rewrite /= Schi ccS. by rewrite /= inE eq_sym nrS. Qed. Lemma cfdot_real_conjC phi psi : cfReal phi -> '[phi, psi^*]_G = '[phi, psi]^*. Proof. by rewrite -cfdot_conjC => /eqcfP->. Qed. (* Note: other isometry lemmas, and the dot product lemmas for orthogonal *) (* and orthonormal sequences are in vcharacter, because we need the 'Z[S] *) (* notation for the isometry domains. Alternatively, this could be moved to *) (* cfun. *) End DotProduct. Implicit Arguments orthoP [gT G phi psi]. Implicit Arguments orthoPl [gT G phi S]. Implicit Arguments orthoPr [gT G S psi]. Implicit Arguments orthogonalP [gT G R S]. Implicit Arguments pairwise_orthogonalP [gT G S]. Implicit Arguments orthonormalP [gT G S]. Section CfunOrder. Variables (gT : finGroupType) (G : {group gT}) (phi : 'CF(G)). Lemma dvdn_cforderP n : reflect {in G, forall x, phi x ^+ n = 1} (#[phi]%CF %| n)%N. Proof. apply: (iffP (dvdn_biglcmP _ _ _)); rewrite genGid => phiG1 x Gx. by apply/eqP; rewrite -dvdn_orderC phiG1. by rewrite dvdn_orderC phiG1. Qed. Lemma dvdn_cforder n : (#[phi]%CF %| n) = (phi ^+ n == 1). Proof. apply/dvdn_cforderP/eqP=> phi_n_1 => [|x Gx]. by apply/cfun_inP=> x Gx; rewrite exp_cfunE // cfun1E Gx phi_n_1. by rewrite -exp_cfunE // phi_n_1 // cfun1E Gx. Qed. Lemma exp_cforder : phi ^+ #[phi]%CF = 1. Proof. by apply/eqP; rewrite -dvdn_cforder. Qed. End CfunOrder. Implicit Arguments dvdn_cforderP [gT G phi n]. Section MorphOrder. Variables (aT rT : finGroupType) (G : {group aT}) (R : {group rT}). Variable f : {rmorphism 'CF(G) -> 'CF(R)}. Lemma cforder_rmorph phi : #[f phi]%CF %| #[phi]%CF. Proof. by rewrite dvdn_cforder -rmorphX exp_cforder rmorph1. Qed. Lemma cforder_inj_rmorph phi : injective f -> #[f phi]%CF = #[phi]%CF. Proof. move=> inj_f; apply/eqP; rewrite eqn_dvd cforder_rmorph dvdn_cforder /=. by rewrite -(rmorph_eq1 _ inj_f) rmorphX exp_cforder. Qed. End MorphOrder. Section BuildIsometries. Variable (gT : finGroupType) (L G : {group gT}). Implicit Types (phi psi xi : 'CF(L)) (R S : seq 'CF(L)). Implicit Types (U : pred 'CF(L)) (W : pred 'CF(G)). Lemma sub_iso_to U1 U2 W1 W2 tau : {subset U2 <= U1} -> {subset W1 <= W2} -> {in U1, isometry tau, to W1} -> {in U2, isometry tau, to W2}. Proof. by move=> sU sW [Itau Wtau]; split=> [|u /sU/Wtau/sW //]; exact: sub_in2 Itau. Qed. Lemma isometry_of_cfnorm S tauS : pairwise_orthogonal S -> pairwise_orthogonal tauS -> map cfnorm tauS = map cfnorm S -> {tau : {linear 'CF(L) -> 'CF(G)} | map tau S = tauS & {in <>%VS &, isometry tau}}. Proof. move=> oS oT eq_nST; have freeS := orthogonal_free oS. have eq_sz: size tauS = size S by have:= congr1 size eq_nST; rewrite !size_map. have [tau /(_ freeS eq_sz) defT] := linear_of_free S tauS. rewrite -[S]/(tval (in_tuple S)). exists tau => // u v /coord_span-> /coord_span->; rewrite !raddf_sum /=. apply: eq_bigr => i _ /=; rewrite linearZ !cfdotZr !cfdot_suml; congr (_ * _). apply: eq_bigr => j _ /=; rewrite linearZ !cfdotZl; congr (_ * _). rewrite -!((nth_map _ 0) tau) // defT; have [-> | neq_ji] := eqVneq j i. by rewrite -!['[_]]((nth_map _ 0) cfnorm) ?eq_sz // eq_nST. have{oS} [/=/andP[_ uS] oS] := pairwise_orthogonalP oS. have{oT} [/=/andP[_ uT] oT] := pairwise_orthogonalP oT. by rewrite oS ?oT ?mem_nth ? nth_uniq ?eq_sz. Qed. Lemma isometry_raddf_inj U (tau : {additive 'CF(L) -> 'CF(G)}) : {in U &, isometry tau} -> {in U &, forall u v, u - v \in U} -> {in U &, injective tau}. Proof. move=> Itau linU phi psi Uphi Upsi /eqP; rewrite -subr_eq0 -raddfB. by rewrite -cfnorm_eq0 Itau ?linU // cfnorm_eq0 subr_eq0 => /eqP. Qed. Lemma opp_isometry : @isometry _ _ G G -%R. Proof. by move=> x y; rewrite cfdotNl cfdotNr opprK. Qed. End BuildIsometries. Section Restrict. Variables (gT : finGroupType) (A B : {set gT}). Local Notation H := <>. Local Notation G := <>. Fact cfRes_subproof (phi : 'CF(B)) : is_class_fun H [ffun x => phi (if H \subset G then x else 1%g) *+ (x \in H)]. Proof. apply: intro_class_fun => /= [x y Hx Hy | x /negbTE/=-> //]. by rewrite Hx (groupJ Hx) //; case: subsetP => // sHG; rewrite cfunJgen ?sHG. Qed. Definition cfRes phi := Cfun 1 (cfRes_subproof phi). Lemma cfResE phi : A \subset B -> {in A, cfRes phi =1 phi}. Proof. by move=> sAB x Ax; rewrite cfunElock mem_gen ?genS. Qed. Lemma cfRes1 phi : cfRes phi 1%g = phi 1%g. Proof. by rewrite cfunElock if_same group1. Qed. Lemma cfRes_is_linear : linear cfRes. Proof. by move=> a phi psi; apply/cfunP=> x; rewrite !cfunElock mulrnAr mulrnDl. Qed. Canonical cfRes_additive := Additive cfRes_is_linear. Canonical cfRes_linear := Linear cfRes_is_linear. Lemma cfRes_cfun1 : cfRes 1 = 1. Proof. apply: cfun_in_genP => x Hx; rewrite cfunElock Hx !cfun1Egen Hx. by case: subsetP => [-> // | _]; rewrite group1. Qed. Lemma cfRes_is_multiplicative : multiplicative cfRes. Proof. split=> [phi psi|]; [apply/cfunP=> x | exact: cfRes_cfun1]. by rewrite !cfunElock mulrnAr mulrnAl -mulrnA mulnb andbb. Qed. Canonical cfRes_rmorphism := AddRMorphism cfRes_is_multiplicative. Canonical cfRes_lrmorphism := [lrmorphism of cfRes]. End Restrict. Arguments Scope cfRes [_ group_scope group_scope cfun_scope]. Notation "''Res[' H , G ]" := (@cfRes _ H G) (only parsing) : ring_scope. Notation "''Res[' H ]" := 'Res[H, _] : ring_scope. Notation "''Res'" := 'Res[_] (only parsing) : ring_scope. Section MoreRestrict. Variables (gT : finGroupType) (G H : {group gT}). Implicit Types (A : {set gT}) (phi : 'CF(G)). Lemma cfResEout phi : ~~ (H \subset G) -> 'Res[H] phi = (phi 1%g)%:A. Proof. move/negPf=> not_sHG; apply/cfunP=> x. by rewrite cfunE cfun1E mulr_natr cfunElock !genGid not_sHG. Qed. Lemma cfResRes A phi : A \subset H -> H \subset G -> 'Res[A] ('Res[H] phi) = 'Res[A] phi. Proof. move=> sAH sHG; apply/cfunP=> x; rewrite !cfunElock !genGid !gen_subG sAH sHG. by rewrite (subset_trans sAH) // -mulrnA mulnb -in_setI (setIidPr _) ?gen_subG. Qed. Lemma cfRes_id A psi : 'Res[A] psi = psi. Proof. by apply/cfun_in_genP=> x Ax; rewrite cfunElock Ax subxx. Qed. Lemma sub_cfker_Res A phi : A \subset H -> A \subset cfker phi -> A \subset cfker ('Res[H, G] phi). Proof. move=> sAH kerA; apply/subsetP=> x Ax; have Hx := subsetP sAH x Ax. rewrite inE Hx; apply/forallP=> y; rewrite !cfunElock !genGid groupMl //. by rewrite !(fun_if phi) cfkerMl // (subsetP kerA). Qed. Lemma eq_cfker_Res phi : H \subset cfker phi -> cfker ('Res[H, G] phi) = H. Proof. by move=> kH; apply/eqP; rewrite eqEsubset cfker_sub sub_cfker_Res. Qed. Lemma cfRes_sub_ker phi : H \subset cfker phi -> 'Res[H, G] phi = (phi 1%g)%:A. Proof. move=> kerHphi; have sHG := subset_trans kerHphi (cfker_sub phi). apply/cfun_inP=> x Hx; have ker_x := subsetP kerHphi x Hx. by rewrite cfResE // cfunE cfun1E Hx mulr1 cfker1. Qed. Lemma cforder_Res phi : #['Res[H] phi]%CF %| #[phi]%CF. Proof. exact: cforder_rmorph. Qed. End MoreRestrict. Section Morphim. Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}). Section Main. Variable G : {group aT}. Implicit Type phi : 'CF(f @* G). Fact cfMorph_subproof phi : is_class_fun <> [ffun x => phi (if G \subset D then f x else 1%g) *+ (x \in G)]. Proof. rewrite genGid; apply: intro_class_fun => [x y Gx Gy | x /negPf-> //]. rewrite Gx groupJ //; case subsetP => // sGD. by rewrite morphJ ?cfunJ ?mem_morphim ?sGD. Qed. Definition cfMorph phi := Cfun 1 (cfMorph_subproof phi). Lemma cfMorphE phi x : G \subset D -> x \in G -> cfMorph phi x = phi (f x). Proof. by rewrite cfunElock => -> ->. Qed. Lemma cfMorph1 phi : cfMorph phi 1%g = phi 1%g. Proof. by rewrite cfunElock morph1 if_same group1. Qed. Lemma cfMorphEout phi : ~~ (G \subset D) -> cfMorph phi = (phi 1%g)%:A. Proof. move/negPf=> not_sGD; apply/cfunP=> x; rewrite cfunE cfun1E mulr_natr. by rewrite cfunElock not_sGD. Qed. Lemma cfMorph_cfun1 : cfMorph 1 = 1. Proof. apply/cfun_inP=> x Gx; rewrite cfunElock !cfun1E Gx. by case: subsetP => [sGD | _]; rewrite ?group1 // mem_morphim ?sGD. Qed. Fact cfMorph_is_linear : linear cfMorph. Proof. by move=> a phi psi; apply/cfunP=> x; rewrite !cfunElock mulrnAr -mulrnDl. Qed. Canonical cfMorph_additive := Additive cfMorph_is_linear. Canonical cfMorph_linear := Linear cfMorph_is_linear. Fact cfMorph_is_multiplicative : multiplicative cfMorph. Proof. split=> [phi psi|]; [apply/cfunP=> x | exact: cfMorph_cfun1]. by rewrite !cfunElock mulrnAr mulrnAl -mulrnA mulnb andbb. Qed. Canonical cfMorph_rmorphism := AddRMorphism cfMorph_is_multiplicative. Canonical cfMorph_lrmorphism := [lrmorphism of cfMorph]. Hypothesis sGD : G \subset D. Lemma cfMorph_inj : injective cfMorph. Proof. move=> phi1 phi2 eq_phi; apply/cfun_inP=> _ /morphimP[x Dx Gx ->]. by rewrite -!cfMorphE // eq_phi. Qed. Lemma cfMorph_eq1 phi : (cfMorph phi == 1) = (phi == 1). Proof. by apply: rmorph_eq1; apply: cfMorph_inj. Qed. Lemma cfker_morph phi : cfker (cfMorph phi) = G :&: f @*^-1 (cfker phi). Proof. apply/setP=> x; rewrite !inE; apply: andb_id2l => Gx. have Dx := subsetP sGD x Gx; rewrite Dx mem_morphim //=. apply/forallP/forallP=> Kx y. have [{y} /morphimP[y Dy Gy ->] | fG'y] := boolP (y \in f @* G). by rewrite -morphM // -!(cfMorphE phi) ?groupM. by rewrite !cfun0 ?groupMl // mem_morphim. have [Gy | G'y] := boolP (y \in G); last by rewrite !cfun0 ?groupMl. by rewrite !cfMorphE ?groupM ?morphM // (subsetP sGD). Qed. Lemma cfker_morph_im phi : f @* cfker (cfMorph phi) = cfker phi. Proof. by rewrite cfker_morph // morphim_setIpre (setIidPr (cfker_sub _)). Qed. Lemma sub_cfker_morph phi (A : {set aT}) : (A \subset cfker (cfMorph phi)) = (A \subset G) && (f @* A \subset cfker phi). Proof. rewrite cfker_morph // subsetI; apply: andb_id2l => sAG. by rewrite sub_morphim_pre // (subset_trans sAG). Qed. Lemma sub_morphim_cfker phi (A : {set aT}) : A \subset G -> (f @* A \subset cfker phi) = (A \subset cfker (cfMorph phi)). Proof. by move=> sAG; rewrite sub_cfker_morph ?sAG. Qed. Lemma cforder_morph phi : #[cfMorph phi]%CF = #[phi]%CF. Proof. by apply: cforder_inj_rmorph; apply: cfMorph_inj. Qed. End Main. Lemma cfResMorph (G H : {group aT}) (phi : 'CF(f @* G)) : H \subset G -> G \subset D -> 'Res (cfMorph phi) = cfMorph ('Res[f @* H] phi). Proof. move=> sHG sGD; have sHD := subset_trans sHG sGD. apply/cfun_inP=> x Hx; have [Gx Dx] := (subsetP sHG x Hx, subsetP sHD x Hx). by rewrite !(cfMorphE, cfResE) ?morphimS ?mem_morphim //. Qed. End Morphim. Prenex Implicits cfMorph. Section Isomorphism. Variables (aT rT : finGroupType) (G : {group aT}) (f : {morphism G >-> rT}). Variable R : {group rT}. Hypothesis isoGR : isom G R f. Let defR := isom_im isoGR. Local Notation G1 := (isom_inv isoGR @* R). Let defG : G1 = G := isom_im (isom_sym isoGR). Fact cfIsom_key : unit. Proof. by []. Qed. Definition cfIsom := locked_with cfIsom_key (cfMorph \o 'Res[G1] : 'CF(G) -> 'CF(R)). Canonical cfIsom_unlockable := [unlockable of cfIsom]. Lemma cfIsomE phi x : x \in G -> cfIsom phi (f x) = phi x. Proof. move=> Gx; rewrite unlock cfMorphE //= /restrm ?defG ?cfRes_id ?invmE //. by rewrite -defR mem_morphim. Qed. Lemma cfIsom1 phi : cfIsom phi 1%g = phi 1%g. Proof. by rewrite -(morph1 f) cfIsomE. Qed. Canonical cfIsom_additive := [additive of cfIsom]. Canonical cfIsom_linear := [linear of cfIsom]. Canonical cfIsom_rmorphism := [rmorphism of cfIsom]. Canonical cfIsom_lrmorphism := [lrmorphism of cfIsom]. Lemma cfIsom_cfun1 : cfIsom 1 = 1. Proof. exact: rmorph1. Qed. Lemma cfker_isom phi : cfker (cfIsom phi) = f @* cfker phi. Proof. rewrite unlock cfker_morph // defG cfRes_id morphpre_restrm morphpre_invm. by rewrite -defR !morphimIim. Qed. End Isomorphism. Prenex Implicits cfIsom. Section InvMorphism. Variables (aT rT : finGroupType) (G : {group aT}) (f : {morphism G >-> rT}). Variable R : {group rT}. Hypothesis isoGR : isom G R f. Lemma cfIsomK : cancel (cfIsom isoGR) (cfIsom (isom_sym isoGR)). Proof. move=> phi; apply/cfun_inP=> x Gx; rewrite -{1}(invmE (isom_inj isoGR) Gx). by rewrite !cfIsomE // -(isom_im isoGR) mem_morphim. Qed. Lemma cfIsomKV : cancel (cfIsom (isom_sym isoGR)) (cfIsom isoGR). Proof. move=> phi; apply/cfun_inP=> y Ry; pose injGR := isom_inj isoGR. rewrite -{1}[y](invmK injGR) ?(isom_im isoGR) //. suffices /morphpreP[fGy Gf'y]: y \in invm injGR @*^-1 G by rewrite !cfIsomE. by rewrite morphpre_invm (isom_im isoGR). Qed. Lemma cfIsom_inj : injective (cfIsom isoGR). Proof. exact: can_inj cfIsomK. Qed. Lemma cfIsom_eq1 phi : (cfIsom isoGR phi == 1) = (phi == 1). Proof. by apply: rmorph_eq1; apply: cfIsom_inj. Qed. Lemma cforder_isom phi : #[cfIsom isoGR phi]%CF = #[phi]%CF. Proof. exact: cforder_inj_rmorph cfIsom_inj. Qed. End InvMorphism. Implicit Arguments cfIsom_inj [aT rT G R f x1 x2]. Section Coset. Variables (gT : finGroupType) (G : {group gT}) (B : {set gT}). Implicit Type rT : finGroupType. Local Notation H := <>%g. Definition cfMod : 'CF(G / B) -> 'CF(G) := cfMorph. Definition ffun_Quo (phi : 'CF(G)) := [ffun Hx : coset_of B => phi (if B \subset cfker phi then repr Hx else 1%g) *+ (Hx \in G / B)%g]. Fact cfQuo_subproof phi : is_class_fun <> (ffun_Quo phi). Proof. rewrite genGid; apply: intro_class_fun => [|Hx /negPf-> //]. move=> _ _ /morphimP[x Nx Gx ->] /morphimP[z Nz Gz ->]. rewrite -morphJ ?mem_morphim ?val_coset_prim ?groupJ //= -gen_subG. case: subsetP => // KphiH; do 2!case: repr_rcosetP => _ /KphiH/cfkerMl->. by rewrite cfunJ. Qed. Definition cfQuo phi := Cfun 1 (cfQuo_subproof phi). Local Notation "phi / 'B'" := (cfQuo phi) (at level 40) : cfun_scope. Local Notation "phi %% 'B'" := (cfMod phi) (at level 40) : cfun_scope. (* We specialize the cfMorph lemmas to cfMod by strengthening the domain *) (* condition G \subset 'N(H) to H <| G; the cfMorph lemmas can be used if the *) (* stronger results are needed. *) Lemma cfModE phi x : B <| G -> x \in G -> (phi %% B)%CF x = phi (coset B x). Proof. by move/normal_norm=> nBG; exact: cfMorphE. Qed. Lemma cfMod1 phi : (phi %% B)%CF 1%g = phi 1%g. Proof. exact: cfMorph1. Qed. Canonical cfMod_additive := [additive of cfMod]. Canonical cfMod_rmorphism := [rmorphism of cfMod]. Canonical cfMod_linear := [linear of cfMod]. Canonical cfMod_lrmorphism := [lrmorphism of cfMod]. Lemma cfMod_cfun1 : (1 %% B)%CF = 1. Proof. exact: rmorph1. Qed. Lemma cfker_mod phi : B <| G -> B \subset cfker (phi %% B). Proof. case/andP=> sBG nBG; rewrite cfker_morph // subsetI sBG. apply: subset_trans _ (ker_sub_pre _ _); rewrite ker_coset_prim subsetI. by rewrite (subset_trans sBG nBG) sub_gen. Qed. (* Note that cfQuo is nondegenerate even when G does not normalize B. *) Lemma cfQuoEnorm (phi : 'CF(G)) x : B \subset cfker phi -> x \in 'N_G(B) -> (phi / B)%CF (coset B x) = phi x. Proof. rewrite cfunElock -gen_subG => sHK /setIP[Gx nHx]; rewrite sHK /=. rewrite mem_morphim // val_coset_prim //. by case: repr_rcosetP => _ /(subsetP sHK)/cfkerMl->. Qed. Lemma cfQuoE (phi : 'CF(G)) x : B <| G -> B \subset cfker phi -> x \in G -> (phi / B)%CF (coset B x) = phi x. Proof. by case/andP=> _ nBG sBK Gx; rewrite cfQuoEnorm // (setIidPl _). Qed. Lemma cfQuo1 (phi : 'CF(G)) : (phi / B)%CF 1%g = phi 1%g. Proof. by rewrite cfunElock repr_coset1 group1 if_same. Qed. Lemma cfQuoEout (phi : 'CF(G)) : ~~ (B \subset cfker phi) -> (phi / B)%CF = (phi 1%g)%:A. Proof. move/negPf=> not_kerB; apply/cfunP=> x; rewrite cfunE cfun1E mulr_natr. by rewrite cfunElock not_kerB. Qed. (* cfQuo is only linear on the class functions that have H in their kernel. *) Lemma cfQuo_cfun1 : (1 / B)%CF = 1. Proof. apply/cfun_inP=> Hx G_Hx; rewrite cfunElock !cfun1E G_Hx cfker_cfun1 -gen_subG. have [x nHx Gx ->] := morphimP G_Hx. case: subsetP=> [sHG | _]; last by rewrite group1. by rewrite val_coset_prim //; case: repr_rcosetP => y /sHG/groupM->. Qed. (* Cancellation properties *) Lemma cfModK : B <| G -> cancel cfMod cfQuo. Proof. move=> nsBG phi; apply/cfun_inP=> _ /morphimP[x Nx Gx ->] //. by rewrite cfQuoE ?cfker_mod ?cfModE. Qed. Lemma cfQuoK : B <| G -> forall phi, B \subset cfker phi -> (phi / B %% B)%CF = phi. Proof. by move=> nsHG phi sHK; apply/cfun_inP=> x Gx; rewrite cfModE ?cfQuoE. Qed. Lemma cfMod_eq1 psi : B <| G -> (psi %% B == 1)%CF = (psi == 1). Proof. by move/cfModK/can_eq <-; rewrite rmorph1. Qed. Lemma cfQuo_eq1 phi : B <| G -> B \subset cfker phi -> (phi / B == 1)%CF = (phi == 1). Proof. by move=> nsBG kerH; rewrite -cfMod_eq1 // cfQuoK. Qed. End Coset. Arguments Scope cfQuo [_ Group_scope group_scope cfun_scope]. Arguments Scope cfMod [_ Group_scope group_scope cfun_scope]. Prenex Implicits cfMod. Notation "phi / H" := (cfQuo H phi) : cfun_scope. Notation "phi %% H" := (@cfMod _ _ H phi) : cfun_scope. Section MoreCoset. Variables (gT : finGroupType) (G : {group gT}). Implicit Types (H K : {group gT}) (phi : 'CF(G)). Lemma cfResMod H K (psi : 'CF(G / K)) : H \subset G -> K <| G -> ('Res (psi %% K) = 'Res[H / K] psi %% K)%CF. Proof. by move=> sHG /andP[_]; apply: cfResMorph. Qed. Lemma quotient_cfker_mod (A : {set gT}) K (psi : 'CF(G / K)) : K <| G -> (cfker (psi %% K) / K)%g = cfker psi. Proof. by case/andP=> _ /cfker_morph_im <-. Qed. Lemma sub_cfker_mod (A : {set gT}) K (psi : 'CF(G / K)) : K <| G -> A \subset 'N(K) -> (A \subset cfker (psi %% K)) = (A / K \subset cfker psi)%g. Proof. by move=> nsKG nKA; rewrite -(quotientSGK nKA) ?quotient_cfker_mod ?cfker_mod. Qed. Lemma cfker_quo H phi : H <| G -> H \subset cfker (phi) -> cfker (phi / H) = (cfker phi / H)%g. Proof. move=> nsHG /cfQuoK {2}<- //; have [sHG nHG] := andP nsHG. by rewrite cfker_morph 1?quotientGI // cosetpreK (setIidPr _) ?cfker_sub. Qed. Lemma cfQuoEker phi x : x \in G -> (phi / cfker phi)%CF (coset (cfker phi) x) = phi x. Proof. by move/cfQuoE->; rewrite ?cfker_normal. Qed. Lemma cfaithful_quo phi : cfaithful (phi / cfker phi). Proof. by rewrite cfaithfulE cfker_quo ?cfker_normal ?trivg_quotient. Qed. (* Note that there is no requirement that K be normal in H or G. *) Lemma cfResQuo H K phi : K \subset cfker phi -> K \subset H -> H \subset G -> ('Res[H / K] (phi / K) = 'Res[H] phi / K)%CF. Proof. move=> kerK sKH sHG; apply/cfun_inP=> xb Hxb; rewrite cfResE ?quotientS //. have{xb Hxb} [x nKx Hx ->] := morphimP Hxb. by rewrite !cfQuoEnorm ?cfResE ?sub_cfker_Res // inE ?Hx ?(subsetP sHG). Qed. Lemma cfQuoInorm K phi : K \subset cfker phi -> (phi / K)%CF = 'Res ('Res['N_G(K)] phi / K)%CF. Proof. move=> kerK; rewrite -cfResQuo ?subsetIl ?quotientInorm ?cfRes_id //. by rewrite subsetI normG (subset_trans kerK) ?cfker_sub. Qed. Lemma cforder_mod H (psi : 'CF(G / H)) : H <| G -> #[psi %% H]%CF = #[psi]%CF. Proof. by move/cfModK/can_inj/cforder_inj_rmorph->. Qed. Lemma cforder_quo H phi : H <| G -> H \subset cfker phi -> #[phi / H]%CF = #[phi]%CF. Proof. by move=> nsHG kerHphi; rewrite -cforder_mod ?cfQuoK. Qed. End MoreCoset. Section Product. Variable (gT : finGroupType) (G : {group gT}). Lemma cfunM_onI A B phi psi : phi \in 'CF(G, A) -> psi \in 'CF(G, B) -> phi * psi \in 'CF(G, A :&: B). Proof. rewrite !cfun_onE => Aphi Bpsi; apply/subsetP=> x; rewrite !inE cfunE mulf_eq0. by case/norP=> /(subsetP Aphi)-> /(subsetP Bpsi). Qed. Lemma cfunM_on A phi psi : phi \in 'CF(G, A) -> psi \in 'CF(G, A) -> phi * psi \in 'CF(G, A). Proof. by move=> Aphi Bpsi; rewrite -[A]setIid cfunM_onI. Qed. End Product. Section SDproduct. Variables (gT : finGroupType) (G K H : {group gT}). Hypothesis defG : K ><| H = G. Fact cfSdprodKey : unit. Proof. by []. Qed. Definition cfSdprod := locked_with cfSdprodKey (cfMorph \o cfIsom (tagged (sdprod_isom defG)) : 'CF(H) -> 'CF(G)). Canonical cfSdprod_unlockable := [unlockable of cfSdprod]. Canonical cfSdprod_additive := [additive of cfSdprod]. Canonical cfSdprod_linear := [linear of cfSdprod]. Canonical cfSdprod_rmorphism := [rmorphism of cfSdprod]. Canonical cfSdprod_lrmorphism := [lrmorphism of cfSdprod]. Lemma cfSdprod1 phi : cfSdprod phi 1%g = phi 1%g. Proof. by rewrite unlock /= cfMorph1 cfIsom1. Qed. Let nsKG : K <| G. Proof. by have [] := sdprod_context defG. Qed. Let sHG : H \subset G. Proof. by have [] := sdprod_context defG. Qed. Let sKG : K \subset G. Proof. by have [] := andP nsKG. Qed. Lemma cfker_sdprod phi : K \subset cfker (cfSdprod phi). Proof. by rewrite unlock_with cfker_mod. Qed. Lemma cfSdprodEr phi : {in H, cfSdprod phi =1 phi}. Proof. by move=> y Hy; rewrite unlock cfModE ?cfIsomE ?(subsetP sHG). Qed. Lemma cfSdprodE phi : {in K & H, forall x y, cfSdprod phi (x * y)%g = phi y}. Proof. by move=> x y Kx Hy; rewrite /= cfkerMl ?(subsetP (cfker_sdprod _)) ?cfSdprodEr. Qed. Lemma cfSdprodK : cancel cfSdprod 'Res[H]. Proof. by move=> phi; apply/cfun_inP=> x Hx; rewrite cfResE ?cfSdprodEr. Qed. Lemma cfSdprod_inj : injective cfSdprod. Proof. exact: can_inj cfSdprodK. Qed. Lemma cfSdprod_eq1 phi : (cfSdprod phi == 1) = (phi == 1). Proof. exact: rmorph_eq1 cfSdprod_inj. Qed. Lemma cfRes_sdprodK phi : K \subset cfker phi -> cfSdprod ('Res[H] phi) = phi. Proof. move=> kerK; apply/cfun_inP=> _ /(mem_sdprod defG)[x [y [Kx Hy -> _]]]. by rewrite cfSdprodE // cfResE // cfkerMl ?(subsetP kerK). Qed. Lemma sdprod_cfker phi : K ><| cfker phi = cfker (cfSdprod phi). Proof. have [skerH [_ _ nKH tiKH]] := (cfker_sub phi, sdprodP defG). rewrite unlock cfker_morph ?normal_norm // cfker_isom restrmEsub //=. rewrite -(sdprod_modl defG) ?sub_cosetpre //=; congr (_ ><| _). by rewrite quotientK ?(subset_trans skerH) // -group_modr //= setIC tiKH mul1g. Qed. Lemma cforder_sdprod phi : #[cfSdprod phi]%CF = #[phi]%CF. Proof. by apply: cforder_inj_rmorph cfSdprod_inj. Qed. End SDproduct. Section DProduct. Variables (gT : finGroupType) (G K H : {group gT}). Hypothesis KxH : K \x H = G. Lemma reindex_dprod R idx (op : Monoid.com_law idx) (F : gT -> R) : \big[op/idx]_(g in G) F g = \big[op/idx]_(k in K) \big[op/idx]_(h in H) F (k * h)%g. Proof. have /mulgmP/misomP[fM /isomP[injf im_f]] := KxH. rewrite pair_big_dep -im_f morphimEdom big_imset; last exact/injmP. by apply: eq_big => [][x y]; rewrite ?inE. Qed. Definition cfDprodr := cfSdprod (dprodWsd KxH). Definition cfDprodl := cfSdprod (dprodWsdC KxH). Definition cfDprod phi psi := cfDprodl phi * cfDprodr psi. Canonical cfDprodl_additive := [additive of cfDprodl]. Canonical cfDprodl_linear := [linear of cfDprodl]. Canonical cfDprodl_rmorphism := [rmorphism of cfDprodl]. Canonical cfDprodl_lrmorphism := [lrmorphism of cfDprodl]. Canonical cfDprodr_additive := [additive of cfDprodr]. Canonical cfDprodr_linear := [linear of cfDprodr]. Canonical cfDprodr_rmorphism := [rmorphism of cfDprodr]. Canonical cfDprodr_lrmorphism := [lrmorphism of cfDprodr]. Lemma cfDprodl1 phi : cfDprodl phi 1%g = phi 1%g. Proof. exact: cfSdprod1. Qed. Lemma cfDprodr1 psi : cfDprodr psi 1%g = psi 1%g. Proof. exact: cfSdprod1. Qed. Lemma cfDprod1 phi psi : cfDprod phi psi 1%g = phi 1%g * psi 1%g. Proof. by rewrite cfunE /= !cfSdprod1. Qed. Lemma cfDprodl_eq1 phi : (cfDprodl phi == 1) = (phi == 1). Proof. exact: cfSdprod_eq1. Qed. Lemma cfDprodr_eq1 psi : (cfDprodr psi == 1) = (psi == 1). Proof. exact: cfSdprod_eq1. Qed. Lemma cfDprod_cfun1r phi : cfDprod phi 1 = cfDprodl phi. Proof. by rewrite /cfDprod rmorph1 mulr1. Qed. Lemma cfDprod_cfun1l psi : cfDprod 1 psi = cfDprodr psi. Proof. by rewrite /cfDprod rmorph1 mul1r. Qed. Lemma cfDprod_cfun1 : cfDprod 1 1 = 1. Proof. by rewrite cfDprod_cfun1l rmorph1. Qed. Lemma cfDprod_split phi psi : cfDprod phi psi = cfDprod phi 1 * cfDprod 1 psi. Proof. by rewrite cfDprod_cfun1l cfDprod_cfun1r. Qed. Let nsKG : K <| G. Proof. by have [] := dprod_normal2 KxH. Qed. Let nsHG : H <| G. Proof. by have [] := dprod_normal2 KxH. Qed. Let cKH : H \subset 'C(K). Proof. by have [] := dprodP KxH. Qed. Let sKG := normal_sub nsKG. Let sHG := normal_sub nsHG. Lemma cfDprodlK : cancel cfDprodl 'Res[K]. Proof. exact: cfSdprodK. Qed. Lemma cfDprodrK : cancel cfDprodr 'Res[H]. Proof. exact: cfSdprodK. Qed. Lemma cfker_dprodl phi : cfker phi \x H = cfker (cfDprodl phi). Proof. by rewrite dprodC -sdprod_cfker dprodEsd // centsC (centsS (cfker_sub _)). Qed. Lemma cfker_dprodr psi : K \x cfker psi = cfker (cfDprodr psi). Proof. by rewrite -sdprod_cfker dprodEsd // (subset_trans (cfker_sub _)). Qed. Lemma cfDprodEl phi : {in K & H, forall k h, cfDprodl phi (k * h)%g = phi k}. Proof. by move=> k h Kk Hh /=; rewrite -(centsP cKH) // cfSdprodE. Qed. Lemma cfDprodEr psi : {in K & H, forall k h, cfDprodr psi (k * h)%g = psi h}. Proof. exact: cfSdprodE. Qed. Lemma cfDprodE phi psi : {in K & H, forall h k, cfDprod phi psi (h * k)%g = phi h * psi k}. Proof. by move=> k h Kk Hh /=; rewrite cfunE cfDprodEl ?cfDprodEr. Qed. Lemma cfDprod_Resl phi psi : 'Res[K] (cfDprod phi psi) = psi 1%g *: phi. Proof. by apply/cfun_inP=> x Kx; rewrite cfunE cfResE // -{1}[x]mulg1 mulrC cfDprodE. Qed. Lemma cfDprod_Resr phi psi : 'Res[H] (cfDprod phi psi) = phi 1%g *: psi. Proof. by apply/cfun_inP=> y Hy; rewrite cfunE cfResE // -{1}[y]mul1g cfDprodE. Qed. Lemma cfDprodKl (psi : 'CF(H)) : psi 1%g = 1 -> cancel (cfDprod^~ psi) 'Res. Proof. by move=> psi1 phi; rewrite cfDprod_Resl psi1 scale1r. Qed. Lemma cfDprodKr (phi : 'CF(K)) : phi 1%g = 1 -> cancel (cfDprod phi) 'Res. Proof. by move=> phi1 psi; rewrite cfDprod_Resr phi1 scale1r. Qed. (* Note that equality holds here iff either cfker phi = K and cfker psi = H, *) (* or else phi != 0, psi != 0 and coprime #|K : cfker phi| #|H : cfker phi|. *) Lemma cfker_dprod phi psi : cfker phi <*> cfker psi \subset cfker (cfDprod phi psi). Proof. rewrite -genM_join gen_subG; apply/subsetP=> _ /mulsgP[x y kKx kHy ->] /=. have [[Kx _] [Hy _]] := (setIdP kKx, setIdP kHy). have Gxy: (x * y)%g \in G by rewrite -(dprodW KxH) mem_mulg. rewrite inE Gxy; apply/forallP=> g. have [Gg | G'g] := boolP (g \in G); last by rewrite !cfun0 1?groupMl. have{g Gg} [k [h [Kk Hh -> _]]] := mem_dprod KxH Gg. rewrite mulgA -(mulgA x) (centsP cKH y) // mulgA -mulgA !cfDprodE ?groupM //. by rewrite !cfkerMl. Qed. Lemma cfdot_dprod phi1 phi2 psi1 psi2 : '[cfDprod phi1 psi1, cfDprod phi2 psi2] = '[phi1, phi2] * '[psi1, psi2]. Proof. rewrite !cfdotE mulrCA -mulrA mulrCA mulrA -invfM -natrM (dprod_card KxH). congr (_ * _); rewrite big_distrl reindex_dprod /=; apply: eq_bigr => k Kk. rewrite big_distrr; apply: eq_bigr => h Hh /=. by rewrite mulrCA -mulrA -rmorphM mulrCA mulrA !cfDprodE. Qed. Lemma cfDprodl_iso : isometry cfDprodl. Proof. by move=> phi1 phi2; rewrite -!cfDprod_cfun1r cfdot_dprod cfnorm1 mulr1. Qed. Lemma cfDprodr_iso : isometry cfDprodr. Proof. by move=> psi1 psi2; rewrite -!cfDprod_cfun1l cfdot_dprod cfnorm1 mul1r. Qed. Lemma cforder_dprodl phi : #[cfDprodl phi]%CF = #[phi]%CF. Proof. exact: cforder_sdprod. Qed. Lemma cforder_dprodr psi : #[cfDprodr psi]%CF = #[psi]%CF. Proof. exact: cforder_sdprod. Qed. End DProduct. Lemma cfDprodC (gT : finGroupType) (G K H : {group gT}) (KxH : K \x H = G) (HxK : H \x K = G) chi psi : cfDprod KxH chi psi = cfDprod HxK psi chi. Proof. rewrite /cfDprod mulrC. by congr (_ * _); congr (cfSdprod _ _); apply: eq_irrelevance. Qed. Section Bigdproduct. Variables (gT : finGroupType) (I : finType) (P : pred I). Variables (A : I -> {group gT}) (G : {group gT}). Hypothesis defG : \big[dprod/1%g]_(i | P i) A i = G. Let sAG i : P i -> A i \subset G. Proof. by move=> Pi; rewrite -(bigdprodWY defG) (bigD1 i) ?joing_subl. Qed. Fact cfBigdprodi_subproof i : gval (if P i then A i else 1%G) \x <<\bigcup_(j | P j && (j != i)) A j>> = G. Proof. have:= defG; rewrite fun_if big_mkcond (bigD1 i) // -big_mkcondl /= => defGi. by have [[_ Gi' _ defGi']] := dprodP defGi; rewrite (bigdprodWY defGi') -defGi'. Qed. Definition cfBigdprodi i := cfDprodl (cfBigdprodi_subproof i) \o 'Res[_, A i]. Canonical cfBigdprodi_additive i := [additive of @cfBigdprodi i]. Canonical cfBigdprodi_linear i := [linear of @cfBigdprodi i]. Canonical cfBigdprodi_rmorphism i := [rmorphism of @cfBigdprodi i]. Canonical cfBigdprodi_lrmorphism i := [lrmorphism of @cfBigdprodi i]. Lemma cfBigdprodi1 i (phi : 'CF(A i)) : cfBigdprodi phi 1%g = phi 1%g. Proof. by rewrite cfDprodl1 cfRes1. Qed. Lemma cfBigdprodi_eq1 i (phi : 'CF(A i)) : P i -> (cfBigdprodi phi == 1) = (phi == 1). Proof. by move=> Pi; rewrite cfSdprod_eq1 Pi cfRes_id. Qed. Lemma cfBigdprodiK i : P i -> cancel (@cfBigdprodi i) 'Res[A i]. Proof. move=> Pi phi; have:= cfDprodlK (cfBigdprodi_subproof i) ('Res phi). by rewrite -[cfDprodl _ _]/(cfBigdprodi phi) Pi cfRes_id. Qed. Lemma cfBigdprodi_inj i : P i -> injective (@cfBigdprodi i). Proof. by move/cfBigdprodiK; apply: can_inj. Qed. Lemma cfBigdprodEi i (phi : 'CF(A i)) x : P i -> (forall j, P j -> x j \in A j) -> cfBigdprodi phi (\prod_(j | P j) x j)%g = phi (x i). Proof. set r := enum P => Pi /forall_inP; have r_i: i \in r by rewrite mem_enum. have:= bigdprodWcp defG; rewrite -big_andE -!(big_filter _ P) filter_index_enum. rewrite -/r big_all => defGr /allP Ax. rewrite (perm_bigcprod defGr Ax (perm_to_rem r_i)) big_cons cfDprodEl ?Pi //. - by rewrite cfRes_id. - by rewrite Ax. rewrite big_seq group_prod // => j; rewrite mem_rem_uniq ?enum_uniq //. case/andP=> i'j /= r_j; apply/mem_gen/bigcupP; exists j; last exact: Ax. by rewrite -[P j](mem_enum P) r_j. Qed. Lemma cfBigdprodi_iso i : P i -> isometry (@cfBigdprodi i). Proof. by move=> Pi phi psi; rewrite cfDprodl_iso Pi !cfRes_id. Qed. Definition cfBigdprod (phi : forall i, 'CF(A i)) := \prod_(i | P i) cfBigdprodi (phi i). Lemma cfBigdprodE phi x : (forall i, P i -> x i \in A i) -> cfBigdprod phi (\prod_(i | P i) x i)%g = \prod_(i | P i) phi i (x i). Proof. move=> Ax; rewrite prod_cfunE; last by rewrite -(bigdprodW defG) mem_prodg. by apply: eq_bigr => i Pi; rewrite cfBigdprodEi. Qed. Lemma cfBigdprod1 phi : cfBigdprod phi 1%g = \prod_(i | P i) phi i 1%g. Proof. by rewrite prod_cfunE //; apply/eq_bigr=> i _; apply: cfBigdprodi1. Qed. Lemma cfBigdprodK phi (Phi := cfBigdprod phi) i (a := phi i 1%g / Phi 1%g) : Phi 1%g != 0 -> P i -> a != 0 /\ a *: 'Res[A i] Phi = phi i. Proof. move=> nzPhi Pi; split. rewrite mulf_neq0 ?invr_eq0 // (contraNneq _ nzPhi) // => phi_i0. by rewrite cfBigdprod1 (bigD1 i) //= phi_i0 mul0r. apply/cfun_inP=> x Aix; rewrite cfunE cfResE ?sAG // mulrAC. have {1}->: x = (\prod_(j | P j) (if j == i then x else 1))%g. rewrite -big_mkcondr (big_pred1 i) ?eqxx // => j /=. by apply: andb_idl => /eqP->. rewrite cfBigdprodE => [|j _]; last by case: eqP => // ->. apply: canLR (mulfK nzPhi) _; rewrite cfBigdprod1 !(bigD1 i Pi) /= eqxx. by rewrite mulrCA !mulrA; congr (_ * _); apply: eq_bigr => j /andP[_ /negPf->]. Qed. Lemma cfdot_bigdprod phi psi : '[cfBigdprod phi, cfBigdprod psi] = \prod_(i | P i) '[phi i, psi i]. Proof. apply: canLR (mulKf (neq0CG G)) _; rewrite -(bigdprod_card defG). rewrite (big_morph _ (@natrM _) (erefl _)) -big_split /=. rewrite (eq_bigr _ (fun i _ => mulVKf (neq0CG _) _)) (big_distr_big_dep 1%g) /=. set F := pfamily _ _ _; pose h (f : {ffun I -> gT}) := (\prod_(i | P i) f i)%g. pose is_hK x f := forall f1, (f1 \in F) && (h f1 == x) = (f == f1). have /fin_all_exists[h1 Dh1] x: exists f, x \in G -> is_hK x f. case Gx: (x \in G); last by exists [ffun _ => x]. have [f [Af fK Uf]] := mem_bigdprod defG Gx. exists [ffun i => if P i then f i else 1%g] => _ f1. apply/andP/eqP=> [[/pfamilyP[Pf1 Af1] /eqP Dx] | <-]. by apply/ffunP=> i; rewrite ffunE; case: ifPn => [/Uf-> | /(supportP Pf1)]. split; last by rewrite fK; apply/eqP/eq_bigr=> i Pi; rewrite ffunE Pi. by apply/familyP=> i; rewrite ffunE !unfold_in; case: ifP => //= /Af. rewrite (reindex_onto h h1) /= => [|x /Dh1/(_ (h1 x))]; last first. by rewrite eqxx => /andP[_ /eqP]. apply/eq_big => [f | f /andP[/Dh1<- /andP[/pfamilyP[_ Af] _]]]; last first. by rewrite !cfBigdprodE // rmorph_prod -big_split /=. apply/idP/idP=> [/andP[/Dh1<-] | Ff]; first by rewrite eqxx andbT. have /pfamilyP[_ Af] := Ff; suffices Ghf: h f \in G by rewrite -Dh1 ?Ghf ?Ff /=. by apply/group_prod=> i Pi; rewrite (subsetP (sAG Pi)) ?Af. Qed. End Bigdproduct. Section MorphIsometry. Variable gT : finGroupType. Implicit Types (D G H K : {group gT}) (aT rT : finGroupType). Lemma cfMorph_iso aT rT (G D : {group aT}) (f : {morphism D >-> rT}) : G \subset D -> isometry (cfMorph : 'CF(f @* G) -> 'CF(G)). Proof. move=> sGD phi psi; rewrite !cfdotE card_morphim (setIidPr sGD). rewrite -(LagrangeI G ('ker f)) /= mulnC natrM invfM -mulrA. congr (_ * _); apply: (canLR (mulKf (neq0CG _))). rewrite mulr_sumr (partition_big_imset f) /= -morphimEsub //. apply: eq_bigr => _ /morphimP[x Dx Gx ->]. rewrite -(card_rcoset _ x) mulr_natl -sumr_const. apply/eq_big => [y | y /andP[Gy /eqP <-]]; last by rewrite !cfMorphE. rewrite mem_rcoset inE groupMr ?groupV // -mem_rcoset. by apply: andb_id2l => /(subsetP sGD) Dy; exact: sameP eqP (rcoset_kerP f _ _). Qed. Lemma cfIsom_iso rT G (R : {group rT}) (f : {morphism G >-> rT}) : forall isoG : isom G R f, isometry (cfIsom isoG). Proof. move=> isoG phi psi; rewrite unlock cfMorph_iso //; set G1 := _ @* R. by rewrite -(isom_im (isom_sym isoG)) -/G1 in phi psi *; rewrite !cfRes_id. Qed. Lemma cfMod_iso H G : H <| G -> isometry (@cfMod _ G H). Proof. by case/andP=> _; apply: cfMorph_iso. Qed. Lemma cfQuo_iso H G : H <| G -> {in [pred phi | H \subset cfker phi] &, isometry (@cfQuo _ G H)}. Proof. by move=> nsHG phi psi sHkphi sHkpsi; rewrite -(cfMod_iso nsHG) !cfQuoK. Qed. Lemma cfnorm_quo H G phi : H <| G -> H \subset cfker phi -> '[phi / H] = '[phi]_G. Proof. by move=> nsHG sHker; apply: cfQuo_iso. Qed. Lemma cfSdprod_iso K H G (defG : K ><| H = G) : isometry (cfSdprod defG). Proof. move=> phi psi; have [/andP[_ nKG] _ _ _ _] := sdprod_context defG. by rewrite [cfSdprod _]locked_withE cfMorph_iso ?cfIsom_iso. Qed. End MorphIsometry. Section Induced. Variable gT : finGroupType. Section Def. Variables B A : {set gT}. Local Notation G := <>. Local Notation H := <>. (* The defalut value for the ~~ (H \subset G) case matches the one for cfRes *) (* so that Frobenius reciprocity holds even in this degenerate case. *) Definition ffun_cfInd (phi : 'CF(A)) := [ffun x => if H \subset G then #|A|%:R^-1 * (\sum_(y in G) phi (x ^ y)) else #|G|%:R * '[phi, 1] *+ (x == 1%g)]. Fact cfInd_subproof phi : is_class_fun G (ffun_cfInd phi). Proof. apply: intro_class_fun => [x y Gx Gy | x H'x]; last first. case: subsetP => [sHG | _]; last by rewrite (negPf (group1_contra H'x)). rewrite big1 ?mulr0 // => y Gy; rewrite cfun0gen ?(contra _ H'x) //= => /sHG. by rewrite memJ_norm ?(subsetP (normG _)). rewrite conjg_eq1 (reindex_inj (mulgI y^-1)%g); congr (if _ then _ * _ else _). by apply: eq_big => [z | z Gz]; rewrite ?groupMl ?groupV // -conjgM mulKVg. Qed. Definition cfInd phi := Cfun 1 (cfInd_subproof phi). Lemma cfInd_is_linear : linear cfInd. Proof. move=> c phi psi; apply/cfunP=> x; rewrite !cfunElock; case: ifP => _. rewrite mulrCA -mulrDr [c * _]mulr_sumr -big_split /=. by congr (_ * _); apply: eq_bigr => y _; rewrite !cfunE. rewrite mulrnAr -mulrnDl !(mulrCA c) -!mulrDr [c * _]mulr_sumr -big_split /=. by congr (_ * (_ * _) *+ _); apply: eq_bigr => y; rewrite !cfunE mulrA mulrDl. Qed. Canonical cfInd_additive := Additive cfInd_is_linear. Canonical cfInd_linear := Linear cfInd_is_linear. End Def. Local Notation "''Ind[' B , A ]" := (@cfInd B A) : ring_scope. Local Notation "''Ind[' B ]" := 'Ind[B, _] : ring_scope. Lemma cfIndE (G H : {group gT}) phi x : H \subset G -> 'Ind[G, H] phi x = #|H|%:R^-1 * (\sum_(y in G) phi (x ^ y)). Proof. by rewrite cfunElock !genGid => ->. Qed. Variables G K H : {group gT}. Implicit Types (phi : 'CF(H)) (psi : 'CF(G)). Lemma cfIndEout phi : ~~ (H \subset G) -> 'Ind[G] phi = (#|G|%:R * '[phi, 1]) *: '1_1%G. Proof. move/negPf=> not_sHG; apply/cfunP=> x; rewrite cfunE cfuniE ?normal1 // inE. by rewrite mulr_natr cfunElock !genGid not_sHG. Qed. Lemma cfIndEsdprod (phi : 'CF(K)) x : K ><| H = G -> 'Ind[G] phi x = \sum_(w in H) phi (x ^ w)%g. Proof. move=> defG; have [/andP[sKG _] _ mulKH nKH _] := sdprod_context defG. rewrite cfIndE //; apply: canLR (mulKf (neq0CG _)) _; rewrite -mulKH mulr_sumr. rewrite (set_partition_big _ (rcosets_partition_mul H K)) ?big_imset /=. apply: eq_bigr => y Hy; rewrite rcosetE norm_rlcoset ?(subsetP nKH) //. rewrite -lcosetE mulr_natl big_imset /=; last exact: in2W (mulgI _). by rewrite -sumr_const; apply: eq_bigr => z Kz; rewrite conjgM cfunJ. have [{nKH}nKH /isomP[injf _]] := sdprod_isom defG. apply: can_in_inj (fun Ky => invm injf (coset K (repr Ky))) _ => y Hy. by rewrite rcosetE -val_coset ?(subsetP nKH) // coset_reprK invmE. Qed. Lemma cfInd_on A phi : H \subset G -> phi \in 'CF(H, A) -> 'Ind[G] phi \in 'CF(G, class_support A G). Proof. move=> sHG Af; apply/cfun_onP=> g AG'g; rewrite cfIndE ?big1 ?mulr0 // => h Gh. apply: (cfun_on0 Af); apply: contra AG'g => Agh. by rewrite -[g](conjgK h) memJ_class_support // groupV. Qed. Lemma cfInd_id phi : 'Ind[H] phi = phi. Proof. apply/cfun_inP=> x Hx; rewrite cfIndE // (eq_bigr _ (cfunJ phi x)) sumr_const. by rewrite -[phi x *+ _]mulr_natl mulKf ?neq0CG. Qed. Lemma cfInd_normal phi : H <| G -> 'Ind[G] phi \in 'CF(G, H). Proof. case/andP=> sHG nHG; apply: (cfun_onS (class_support_sub_norm (subxx _) nHG)). by rewrite cfInd_on ?cfun_onG. Qed. Lemma cfInd1 phi : H \subset G -> 'Ind[G] phi 1%g = #|G : H|%:R * phi 1%g. Proof. move=> sHG; rewrite cfIndE // natf_indexg // -mulrA mulrCA; congr (_ * _). by rewrite mulr_natl -sumr_const; apply: eq_bigr => x; rewrite conj1g. Qed. Lemma cfInd_cfun1 : H <| G -> 'Ind[G, H] 1 = #|G : H|%:R *: '1_H. Proof. move=> nsHG; have [sHG nHG] := andP nsHG; rewrite natf_indexg // mulrC. apply/cfunP=> x; rewrite cfIndE ?cfunE ?cfuniE // -mulrA; congr (_ * _). rewrite mulr_natl -sumr_const; apply: eq_bigr => y Gy. by rewrite cfun1E -{1}(normsP nHG y Gy) memJ_conjg. Qed. Lemma cfnorm_Ind_cfun1 : H <| G -> '['Ind[G, H] 1] = #|G : H|%:R. Proof. move=> nsHG; rewrite cfInd_cfun1 // cfnormZ normr_nat cfdot_cfuni // setIid. by rewrite expr2 {2}natf_indexg ?normal_sub // !mulrA divfK ?mulfK ?neq0CG. Qed. Lemma cfIndInd phi : K \subset G -> H \subset K -> 'Ind[G] ('Ind[K] phi) = 'Ind[G] phi. Proof. move=> sKG sHK; apply/cfun_inP=> x Gx; rewrite !cfIndE ?(subset_trans sHK) //. apply: canLR (mulKf (neq0CG K)) _; rewrite mulr_sumr mulr_natl. transitivity (\sum_(y in G) \sum_(z in K) #|H|%:R^-1 * phi ((x ^ y) ^ z)). by apply: eq_bigr => y Gy; rewrite cfIndE // -mulr_sumr. symmetry; rewrite exchange_big /= -sumr_const; apply: eq_bigr => z Kz. rewrite (reindex_inj (mulIg z)). by apply: eq_big => [y | y _]; rewrite ?conjgM // groupMr // (subsetP sKG). Qed. (* This is Isaacs, Lemma (5.2). *) Lemma Frobenius_reciprocity phi psi : '[phi, 'Res[H] psi] = '['Ind[G] phi, psi]. Proof. have [sHG | not_sHG] := boolP (H \subset G); last first. rewrite cfResEout // cfIndEout // cfdotZr cfdotZl mulrAC; congr (_ * _). rewrite (cfdotEl _ (cfuni_on _ _)) mulVKf ?neq0CG // big_set1. by rewrite cfuniE ?normal1 ?set11 ?mul1r. transitivity (#|H|%:R^-1 * \sum_(x in G) phi x * (psi x)^*). rewrite (big_setID H) /= (setIidPr sHG) addrC big1 ?add0r; last first. by move=> x /setDP[_ /cfun0->]; rewrite mul0r. by congr (_ * _); apply: eq_bigr => x Hx; rewrite cfResE. set h' := _^-1; apply: canRL (mulKf (neq0CG G)) _. transitivity (h' * \sum_(y in G) \sum_(x in G) phi (x ^ y) * (psi (x ^ y))^*). rewrite mulrCA mulr_natl -sumr_const; congr (_ * _); apply: eq_bigr => y Gy. by rewrite (reindex_acts 'J _ Gy) ?astabsJ ?normG. rewrite exchange_big mulr_sumr; apply: eq_bigr => x _; rewrite cfIndE //=. by rewrite -mulrA mulr_suml; congr (_ * _); apply: eq_bigr => y /(cfunJ psi)->. Qed. Definition cfdot_Res_r := Frobenius_reciprocity. Lemma cfdot_Res_l psi phi : '['Res[H] psi, phi] = '[psi, 'Ind[G] phi]. Proof. by rewrite cfdotC cfdot_Res_r -cfdotC. Qed. Lemma cfIndM phi psi: H \subset G -> 'Ind[G] (phi * ('Res[H] psi)) = 'Ind[G] phi * psi. Proof. move=> HsG; apply/cfun_inP=> x Gx; rewrite !cfIndE // !cfunE !cfIndE // -mulrA. congr (_ * _); rewrite mulr_suml; apply: eq_bigr=> i iG; rewrite !cfunE. case:(boolP (x^i \in H))=> xJi; last by rewrite cfun0gen ?mul0r ?genGid. by rewrite !cfResE //; congr (_*_); rewrite cfunJgen ?genGid. Qed. End Induced. Arguments Scope cfInd [_ group_scope group_scope cfun_scope]. Notation "''Ind[' G , H ]" := (@cfInd _ G H) (only parsing) : ring_scope. Notation "''Ind[' G ]" := 'Ind[G, _] : ring_scope. Notation "''Ind'" := 'Ind[_] (only parsing) : ring_scope. Section MorphInduced. Variables (aT rT : finGroupType) (D G H : {group aT}) (R S : {group rT}). Lemma cfIndMorph (f : {morphism D >-> rT}) (phi : 'CF(f @* H)) : 'ker f \subset H -> H \subset G -> G \subset D -> 'Ind[G] (cfMorph phi) = cfMorph ('Ind[f @* G] phi). Proof. move=> sKH sHG sGD; have [sHD inD] := (subset_trans sHG sGD, subsetP sGD). apply/cfun_inP=> /= x Gx; have [Dx sKG] := (inD x Gx, subset_trans sKH sHG). rewrite cfMorphE ?cfIndE ?morphimS // (partition_big_imset f) -morphimEsub //=. rewrite card_morphim (setIidPr sHD) natf_indexg // invfM invrK -mulrA. congr (_ * _); rewrite mulr_sumr; apply: eq_bigr => _ /morphimP[y Dy Gy ->]. rewrite -(card_rcoset _ y) mulr_natl -sumr_const. apply: eq_big => [z | z /andP[Gz /eqP <-]]. have [Gz | G'z] := boolP (z \in G). by rewrite (sameP eqP (rcoset_kerP _ _ _)) ?inD. by case: rcosetP G'z => // [[t Kt ->]]; rewrite groupM // (subsetP sKG). have [Dz Dxz] := (inD z Gz, inD (x ^ z) (groupJ Gx Gz)); rewrite -morphJ //. have [Hxz | notHxz] := boolP (x ^ z \in H); first by rewrite cfMorphE. by rewrite !cfun0 // -sub1set -morphim_set1 // morphimSGK ?sub1set. Qed. Variables (g : {morphism G >-> rT}) (h : {morphism H >-> rT}). Hypotheses (isoG : isom G R g) (isoH : isom H S h) (eq_hg : {in H, h =1 g}). Hypothesis sHG : H \subset G. Lemma cfResIsom phi : 'Res[S] (cfIsom isoG phi) = cfIsom isoH ('Res[H] phi). Proof. have [[injg defR] [injh defS]] := (isomP isoG, isomP isoH). rewrite !morphimEdom in defS defR; apply/cfun_inP=> s. rewrite -{1}defS => /imsetP[x Hx ->] {s}; have Gx := subsetP sHG x Hx. rewrite {1}eq_hg ?(cfResE, cfIsomE) // -defS -?eq_hg ?mem_imset // -defR. by rewrite (eq_in_imset eq_hg) imsetS. Qed. Lemma cfIndIsom phi : 'Ind[R] (cfIsom isoH phi) = cfIsom isoG ('Ind[G] phi). Proof. have [[injg defR] [_ defS]] := (isomP isoG, isomP isoH). rewrite morphimEdom (eq_in_imset eq_hg) -morphimEsub // in defS. apply/cfun_inP=> s; rewrite -{1}defR => /morphimP[x _ Gx ->]{s}. rewrite cfIsomE ?cfIndE // -defR -{1}defS ?morphimS ?card_injm // morphimEdom. congr (_ * _); rewrite big_imset //=; last exact/injmP. apply: eq_bigr => y Gy; rewrite -morphJ //. have [Hxy | H'xy] := boolP (x ^ y \in H); first by rewrite -eq_hg ?cfIsomE. by rewrite !cfun0 -?defS // -sub1set -morphim_set1 ?injmSK ?sub1set // groupJ. Qed. End MorphInduced. Section FieldAutomorphism. Variables (u : {rmorphism algC -> algC}) (gT rT : finGroupType). Variables (G K H : {group gT}) (f : {morphism G >-> rT}) (R : {group rT}). Implicit Types (phi : 'CF(G)) (S : seq 'CF(G)). Local Notation "phi ^u" := (cfAut u phi) (at level 3, format "phi ^u"). Lemma cfAutZ_nat n phi : (n%:R *: phi)^u = n%:R *: phi^u. Proof. exact: raddfZnat. Qed. Lemma cfAutZ_Cnat z phi : z \in Cnat -> (z *: phi)^u = z *: phi^u. Proof. exact: raddfZ_Cnat. Qed. Lemma cfAutZ_Cint z phi : z \in Cint -> (z *: phi)^u = z *: phi^u. Proof. exact: raddfZ_Cint. Qed. Lemma cfAut_inj : injective (@cfAut gT G u). Proof. move=> phi psi /cfunP eqfg; apply/cfunP=> x. by have := eqfg x; rewrite !cfunE => /fmorph_inj. Qed. Lemma cfAut_eq1 phi : (cfAut u phi == 1) = (phi == 1). Proof. by rewrite rmorph_eq1 //; apply: cfAut_inj. Qed. Lemma support_cfAut phi : support phi^u =i support phi. Proof. by move=> x; rewrite !inE cfunE fmorph_eq0. Qed. Lemma map_cfAut_free S : cfAut_closed u S -> free S -> free (map (cfAut u) S). Proof. set Su := map _ S => sSuS freeS; have uniqS := free_uniq freeS. have uniqSu: uniq Su by rewrite (map_inj_uniq cfAut_inj). have{sSuS} sSuS: {subset Su <= S} by move=> _ /mapP[phi Sphi ->]; apply: sSuS. have [|eqSuS _] := leq_size_perm uniqSu sSuS; first by rewrite size_map. by rewrite (perm_free (uniq_perm_eq uniqSu uniqS eqSuS)). Qed. Lemma cfAut_on A phi : (phi^u \in 'CF(G, A)) = (phi \in 'CF(G, A)). Proof. by rewrite !cfun_onE (eq_subset (support_cfAut phi)). Qed. Lemma cfker_aut phi : cfker phi^u = cfker phi. Proof. apply/setP=> x; rewrite !inE; apply: andb_id2l => Gx. by apply/forallP/forallP=> Kx y; have:= Kx y; rewrite !cfunE (inj_eq (fmorph_inj u)). Qed. Lemma cfAut_cfuni A : ('1_A)^u = '1_A :> 'CF(G). Proof. by apply/cfunP=> x; rewrite !cfunElock rmorph_nat. Qed. Lemma cforder_aut phi : #[phi^u]%CF = #[phi]%CF. Proof. exact: cforder_inj_rmorph cfAut_inj. Qed. Lemma cfAutRes phi : ('Res[H] phi)^u = 'Res phi^u. Proof. by apply/cfunP=> x; rewrite !cfunElock rmorphMn. Qed. Lemma cfAutMorph (psi : 'CF(f @* H)) : (cfMorph psi)^u = cfMorph psi^u. Proof. by apply/cfun_inP=> x Hx; rewrite !cfunElock Hx. Qed. Lemma cfAutIsom (isoGR : isom G R f) phi : (cfIsom isoGR phi)^u = cfIsom isoGR phi^u. Proof. apply/cfun_inP=> y; have [_ {1}<-] := isomP isoGR => /morphimP[x _ Gx ->{y}]. by rewrite !(cfunE, cfIsomE). Qed. Lemma cfAutQuo phi : (phi / H)^u = (phi^u / H)%CF. Proof. by apply/cfunP=> Hx; rewrite !cfunElock cfker_aut rmorphMn. Qed. Lemma cfAutMod (psi : 'CF(G / H)) : (psi %% H)^u = (psi^u %% H)%CF. Proof. by apply/cfunP=> x; rewrite !cfunElock rmorphMn. Qed. Lemma cfAutInd (psi : 'CF(H)) : ('Ind[G] psi)^u = 'Ind psi^u. Proof. have [sHG | not_sHG] := boolP (H \subset G). apply/cfunP=> x; rewrite !(cfunE, cfIndE) // rmorphM fmorphV rmorph_nat. by congr (_ * _); rewrite rmorph_sum; apply: eq_bigr => y; rewrite !cfunE. rewrite !cfIndEout // linearZ /= cfAut_cfuni rmorphM rmorph_nat. rewrite -cfdot_cfAut ?rmorph1 // => _ /imageP[x Hx ->]. by rewrite cfun1E Hx !rmorph1. Qed. Hypothesis KxH : K \x H = G. Lemma cfAutDprodl (phi : 'CF(K)) : (cfDprodl KxH phi)^u = cfDprodl KxH phi^u. Proof. apply/cfun_inP=> _ /(mem_dprod KxH)[x [y [Kx Hy -> _]]]. by rewrite !(cfunE, cfDprodEl). Qed. Lemma cfAutDprodr (psi : 'CF(H)) : (cfDprodr KxH psi)^u = cfDprodr KxH psi^u. Proof. apply/cfun_inP=> _ /(mem_dprod KxH)[x [y [Kx Hy -> _]]]. by rewrite !(cfunE, cfDprodEr). Qed. Lemma cfAutDprod (phi : 'CF(K)) (psi : 'CF(H)) : (cfDprod KxH phi psi)^u = cfDprod KxH phi^u psi^u. Proof. by rewrite rmorphM /= cfAutDprodl cfAutDprodr. Qed. End FieldAutomorphism. Implicit Arguments cfAut_inj [gT G x1 x2]. Definition conj_cfRes := cfAutRes conjC. Definition cfker_conjC := cfker_aut conjC. Definition conj_cfQuo := cfAutQuo conjC. Definition conj_cfMod := cfAutMod conjC. Definition conj_cfInd := cfAutInd conjC. Definition cfconjC_eq1 := cfAut_eq1 conjC. mathcomp-1.5/theories/fingroup.v0000644000175000017500000034034512307636117016034 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq choice fintype. Require Import div path bigop prime finset. (******************************************************************************) (* This file defines the main interface for finite groups : *) (* finGroupType == the structure for finite types with a group law. *) (* {group gT} == type of groups with elements of type gT. *) (* baseFinGroupType == the structure for finite types with a monoid law *) (* and an involutive antimorphism; finGroupType is *) (* derived from baseFinGroupType (via a telescope). *) (* FinGroupType mulVg == the finGroupType structure for an existing *) (* baseFinGroupType structure, built from a proof of *) (* the left inverse group axiom for that structure's *) (* operations. *) (* BaseFinGroupType bgm == the baseFingroupType structure built by packaging *) (* bgm : FinGroup.mixin_of T for a type T with an *) (* existing finType structure. *) (* FinGroup.BaseMixin mulA mul1x invK invM == *) (* the mixin for a baseFinGroupType structure, built *) (* from proofs of the baseFinGroupType axioms. *) (* FinGroup.Mixin mulA mul1x mulVg == *) (* the mixin for a baseFinGroupType structure, built *) (* from proofs of the group axioms. *) (* [baseFinGroupType of T] == a clone of an existing baseFinGroupType *) (* structure on T, for T (the existing structure *) (* might be for som delta-expansion of T). *) (* [finGroupType of T] == a clone of an existing finGroupType structure on *) (* T, for the canonical baseFinGroupType structure *) (* of T (the existing structure might be for the *) (* baseFinGroupType of some delta-expansion of T). *) (* [group of G] == a clone for an existing {group gT} structure on *) (* G : {set gT} (the existing structure might be for *) (* some delta-expansion of G). *) (* If gT implements finGroupType, then we can form {set gT}, the type of *) (* finite sets with elements of type gT (as finGroupType extends finType). *) (* The group law extends pointwise to {set gT}, which thus implements a sub- *) (* interface baseFinGroupType of finGroupType. To be consistent with the *) (* predType interface, this is done by coercion to FinGroup.arg_sort, an *) (* alias for FinGroup.sort. Accordingly, all pointwise group operations below *) (* have arguments of type (FinGroup.arg_sort) gT and return results of type *) (* FinGroup.sort gT. *) (* The notations below are declared in two scopes: *) (* group_scope (delimiter %g) for point operations and set constructs. *) (* Group_scope (delimiter %G) for explicit {group gT} structures. *) (* These scopes should not be opened globally, although group_scope is often *) (* opened locally in group-theory files (via Import GroupScope). *) (* As {group gT} is both a subtype and an interface structure for {set gT}, *) (* the fact that a given G : {set gT} is a group can (and usually should) be *) (* inferred by type inference with canonical structures. This means that all *) (* `group' constructions (e.g., the normaliser 'N_G(H)) actually define sets *) (* with a canonical {group gT} structure; the %G delimiter can be used to *) (* specify the actual {group gT} structure (e.g., 'N_G(H)%G). *) (* Operations on elements of a group: *) (* x * y == the group product of x and y. *) (* x ^+ n == the nth power of x, i.e., x * ... * x (n times). *) (* x^-1 == the group inverse of x. *) (* x ^- n == the inverse of x ^+ n (notation for (x ^+ n)^-1). *) (* 1 == the unit element. *) (* x ^ y == the conjugate of x by y. *) (* \prod_(i ...) x i == the product of the x i (order-sensitive). *) (* commute x y <-> x and y commute. *) (* centralises x A <-> x centralises A. *) (* 'C[x] == the set of elements that commute with x. *) (* 'C_G[x] == the set of elements of G that commute with x. *) (* <[x]> == the cyclic subgroup generated by the element x. *) (* #[x] == the order of the element x, i.e., #|<[x]>|. *) (* [~ x1, ..., xn] == the commutator of x1, ..., xn. *) (* Operations on subsets/subgroups of a finite group: *) (* H * G == {xy | x \in H, y \in G}. *) (* 1 or [1] or [1 gT] == the unit group. *) (* [set: gT]%G == the group of all x : gT (in Group_scope). *) (* [subg G] == the subtype, set, or group of all x \in G: this *) (* notation is defined simultaneously in %type, %g *) (* and %G scopes, and G must denote a {group gT} *) (* structure (G is in the %G scope). *) (* subg, sgval == the projection into and injection from [subg G]. *) (* H^# == the set H minus the unit element *) (* repr H == some element of H if 1 \notin H != set0, else 1. *) (* (repr is defined over sets of a baseFinGroupType, *) (* so it can be used, e.g., to pick right cosets.) *) (* x *: H == left coset of H by x. *) (* lcosets H G == the set of the left cosets of H by elements of G. *) (* H :* x == right coset of H by x. *) (* rcosets H G == the set of the right cosets of H by elements of G. *) (* #|G : H| == the index of H in G, i.e., #|rcosets G H|. *) (* H :^ x == the conjugate of H by x. *) (* x ^: H == the conjugate class of x in H. *) (* classes G == the set of all conjugate classes of G. *) (* G :^: H == {G :^ x | x \in H}. *) (* class_support G H == {x ^ y | x \in G, y \in H}. *) (* [~: H1, ..., Hn] == commutator subgroup of H1, ..., Hn. *) (*{in G, centralised H} <-> G centralises H. *) (* {in G, normalised H} <-> G normalises H. *) (* <-> forall x, x \in G -> H :^ x = H. *) (* 'N(H) == the normaliser of H. *) (* 'N_G(H) == the normaliser of H in G. *) (* H <| G <=> H is normal in G. *) (* 'C(H) == the centraliser of H. *) (* 'C_G(H) == the centraliser of H in G. *) (* <> == the subgroup generated by the set H. *) (* H <*> G == the subgroup generated by sets H and G (H join G). *) (* (H * G)%G == the join of G H : {group gT} (convertible, but not *) (* identical to (G <*> H)%G). *) (* (\prod_(i ...) H i)%G == the group generated by the H i. *) (* gcore H G == the largest subgroup of H normalised by G. *) (* If H is a subgroup of G, this is the largest *) (* normal subgroup of G contained in H). *) (* abelian H <=> H is abelian. *) (* subgroups G == the set of subgroups of G, i.e., the set of all *) (* H : {group gT} such that H \subset G. *) (* In the notation below G is a variable that is bound in P. *) (* [max G | P] <=> G is the largest group such that P holds. *) (* [max H of G | P] <=> H is the largest group G such that P holds. *) (* [max G | P & Q] := [max G | P && Q], likewise [max H of G | P & Q]. *) (* [min G | P] <=> G is the smallest group such that P holds. *) (* [min G | P & Q] := [min G | P && Q], likewise [min H of G | P & Q]. *) (* [min H of G | P] <=> H is the smallest group G such that P holds. *) (* In addition to the generic suffixes described in ssrbool.v and finset.v, *) (* we associate the following suffixes to group operations: *) (* 1 - identity element, as in group1 : 1 \in G. *) (* M - multiplication, as is invMg : (x * y)^-1 = x^-1 * y^-1. *) (* Also nat multiplication, for expgM : x ^+ (m * n) = x ^+ m ^+ n. *) (* D - (nat) addition, for expgD : x ^+ (m + n) = x ^+ m * x ^+ n. *) (* V - inverse, as in mulgV : x * x^-1 = 1. *) (* X - exponentiation, as in conjXg : (x ^+ n) ^ y = (x ^ y) ^+ n. *) (* J - conjugation, as in orderJ : #[x ^ y] = #[x]. *) (* R - commutator, as in conjRg : [~ x, y] ^ z = [~ x ^ z, y ^ z]. *) (* Y - join, as in centY : 'C(G <*> H) = 'C(G) :&: 'C(H). *) (* We sometimes prefix these with an `s' to indicate a set-lifted operation, *) (* e.g., conjsMg : (A * B) :^ x = A :^ x * B :^ x. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Delimit Scope group_scope with g. Delimit Scope Group_scope with G. (* This module can be imported to open the scope for group element *) (* operations locally to a file, without exporing the Open to *) (* clients of that file (as Open would do). *) Module GroupScope. Open Scope group_scope. End GroupScope. Import GroupScope. (* These are the operation notations introduced by this file. *) Reserved Notation "[ ~ x1 , x2 , .. , xn ]" (at level 0, format "'[ ' [ ~ x1 , '/' x2 , '/' .. , '/' xn ] ']'"). Reserved Notation "[ 1 gT ]" (at level 0, format "[ 1 gT ]"). Reserved Notation "[ 1 ]" (at level 0, format "[ 1 ]"). Reserved Notation "[ 'subg' G ]" (at level 0, format "[ 'subg' G ]"). Reserved Notation "A ^#" (at level 2, format "A ^#"). Reserved Notation "A :^ x" (at level 35, right associativity). Reserved Notation "x ^: B" (at level 35, right associativity). Reserved Notation "A :^: B" (at level 35, right associativity). Reserved Notation "#| B : A |" (at level 0, B, A at level 99, format "#| B : A |"). Reserved Notation "''N' ( A )" (at level 8, format "''N' ( A )"). Reserved Notation "''N_' G ( A )" (at level 8, G at level 2, format "''N_' G ( A )"). Reserved Notation "A <| B" (at level 70, no associativity). Reserved Notation "#[ x ]" (at level 0, format "#[ x ]"). Reserved Notation "A <*> B" (at level 40, left associativity). Reserved Notation "[ ~: A1 , A2 , .. , An ]" (at level 0, format "[ ~: '[' A1 , '/' A2 , '/' .. , '/' An ']' ]"). Reserved Notation "[ 'max' A 'of' G | gP ]" (at level 0, format "[ '[hv' 'max' A 'of' G '/ ' | gP ']' ]"). Reserved Notation "[ 'max' G | gP ]" (at level 0, format "[ '[hv' 'max' G '/ ' | gP ']' ]"). Reserved Notation "[ 'max' A 'of' G | gP & gQ ]" (at level 0, format "[ '[hv' 'max' A 'of' G '/ ' | gP '/ ' & gQ ']' ]"). Reserved Notation "[ 'max' G | gP & gQ ]" (at level 0, format "[ '[hv' 'max' G '/ ' | gP '/ ' & gQ ']' ]"). Reserved Notation "[ 'min' A 'of' G | gP ]" (at level 0, format "[ '[hv' 'min' A 'of' G '/ ' | gP ']' ]"). Reserved Notation "[ 'min' G | gP ]" (at level 0, format "[ '[hv' 'min' G '/ ' | gP ']' ]"). Reserved Notation "[ 'min' A 'of' G | gP & gQ ]" (at level 0, format "[ '[hv' 'min' A 'of' G '/ ' | gP '/ ' & gQ ']' ]"). Reserved Notation "[ 'min' G | gP & gQ ]" (at level 0, format "[ '[hv' 'min' G '/ ' | gP '/ ' & gQ ']' ]"). Module FinGroup. (* We split the group axiomatisation in two. We define a *) (* class of "base groups", which are basically monoids *) (* with an involutive antimorphism, from which we derive *) (* the class of groups proper. This allows use to reuse *) (* much of the group notation and algebraic axioms for *) (* group subsets, by defining a base group class on them. *) (* We use class/mixins here rather than telescopes to *) (* be able to interoperate with the type coercions. *) (* Another potential benefit (not exploited here) would *) (* be to define a class for infinite groups, which could *) (* share all of the algebraic laws. *) Record mixin_of (T : Type) : Type := BaseMixin { mul : T -> T -> T; one : T; inv : T -> T; _ : associative mul; _ : left_id one mul; _ : involutive inv; _ : {morph inv : x y / mul x y >-> mul y x} }. Structure base_type : Type := PackBase { sort : Type; _ : mixin_of sort; _ : Finite.class_of sort }. (* We want to use sort as a coercion class, both to infer *) (* argument scopes properly, and to allow groups and cosets to *) (* coerce to the base group of group subsets. *) (* However, the return type of group operations should NOT be a *) (* coercion class, since this would trump the real (head-normal) *) (* coercion class for concrete group types, thus spoiling the *) (* coercion of A * B to pred_sort in x \in A * B, or rho * tau to *) (* ffun and Funclass in (rho * tau) x, when rho tau : perm T. *) (* Therefore we define an alias of sort for argument types, and *) (* make it the default coercion FinGroup.base_class >-> Sortclass *) (* so that arguments of a functions whose parameters are of type, *) (* say, gT : finGroupType, can be coerced to the coercion class *) (* of arg_sort. Care should be taken, however, to declare the *) (* return type of functions and operators as FinGroup.sort gT *) (* rather than gT, e.g., mulg : gT -> gT -> FinGroup.sort gT. *) (* Note that since we do this here and in quotient.v for all the *) (* basic functions, the inferred return type should generally be *) (* correct. *) Definition arg_sort := sort. Definition mixin T := let: PackBase _ m _ := T return mixin_of (sort T) in m. Definition finClass T := let: PackBase _ _ m := T return Finite.class_of (sort T) in m. Structure type : Type := Pack { base : base_type; _ : left_inverse (one (mixin base)) (inv (mixin base)) (mul (mixin base)) }. (* We only need three axioms to make a true group. *) Section Mixin. Variables (T : Type) (one : T) (mul : T -> T -> T) (inv : T -> T). Hypothesis mulA : associative mul. Hypothesis mul1 : left_id one mul. Hypothesis mulV : left_inverse one inv mul. Notation "1" := one. Infix "*" := mul. Notation "x ^-1" := (inv x). Lemma mk_invgK : involutive inv. Proof. have mulV21 x: x^-1^-1 * 1 = x by rewrite -(mulV x) mulA mulV mul1. by move=> x; rewrite -[_ ^-1]mulV21 -(mul1 1) mulA !mulV21. Qed. Lemma mk_invMg : {morph inv : x y / x * y >-> y * x}. Proof. have mulxV x: x * x^-1 = 1 by rewrite -{1}[x]mk_invgK mulV. move=> x y /=; rewrite -[y^-1 * _]mul1 -(mulV (x * y)) -2!mulA (mulA y). by rewrite mulxV mul1 mulxV -(mulxV (x * y)) mulA mulV mul1. Qed. Definition Mixin := BaseMixin mulA mul1 mk_invgK mk_invMg. End Mixin. Definition pack_base T m := fun c cT & phant_id (Finite.class cT) c => @PackBase T m c. Definition clone_base T := fun bT & sort bT -> T => fun m c (bT' := @PackBase T m c) & phant_id bT' bT => bT'. Definition clone T := fun bT gT & sort bT * sort (base gT) -> T * T => fun m (gT' := @Pack bT m) & phant_id gT' gT => gT'. Section InheritedClasses. Variable bT : base_type. Local Notation T := (arg_sort bT). Local Notation rT := (sort bT). Local Notation class := (finClass bT). Canonical eqType := Equality.Pack class rT. Canonical choiceType := Choice.Pack class rT. Canonical countType := Countable.Pack class rT. Canonical finType := Finite.Pack class rT. Definition arg_eqType := Eval hnf in [eqType of T]. Definition arg_choiceType := Eval hnf in [choiceType of T]. Definition arg_countType := Eval hnf in [countType of T]. Definition arg_finType := Eval hnf in [finType of T]. End InheritedClasses. Module Import Exports. (* Declaring sort as a Coercion is clearly redundant; it only *) (* serves the purpose of eliding FinGroup.sort in the display of *) (* return types. The warning could be eliminated by using the *) (* functor trick to replace Sortclass by a dummy target. *) Coercion arg_sort : base_type >-> Sortclass. Coercion sort : base_type >-> Sortclass. Coercion mixin : base_type >-> mixin_of. Coercion base : type >-> base_type. Canonical eqType. Canonical choiceType. Canonical countType. Canonical finType. Coercion arg_eqType : base_type >-> Equality.type. Canonical arg_eqType. Coercion arg_choiceType : base_type >-> Choice.type. Canonical arg_choiceType. Coercion arg_countType : base_type >-> Countable.type. Canonical arg_countType. Coercion arg_finType : base_type >-> Finite.type. Canonical arg_finType. Bind Scope group_scope with sort. Bind Scope group_scope with arg_sort. Notation baseFinGroupType := base_type. Notation finGroupType := type. Notation BaseFinGroupType T m := (@pack_base T m _ _ id). Notation FinGroupType := Pack. Notation "[ 'baseFinGroupType' 'of' T ]" := (@clone_base T _ id _ _ id) (at level 0, format "[ 'baseFinGroupType' 'of' T ]") : form_scope. Notation "[ 'finGroupType' 'of' T ]" := (@clone T _ _ id _ id) (at level 0, format "[ 'finGroupType' 'of' T ]") : form_scope. End Exports. End FinGroup. Export FinGroup.Exports. Section ElementOps. Variable T : baseFinGroupType. Notation rT := (FinGroup.sort T). Definition oneg : rT := FinGroup.one T. Definition mulg : T -> T -> rT := FinGroup.mul T. Definition invg : T -> rT := FinGroup.inv T. Definition expgn_rec (x : T) n : rT := iterop n mulg x oneg. End ElementOps. Definition expgn := nosimpl expgn_rec. Notation "1" := (oneg _) : group_scope. Notation "x1 * x2" := (mulg x1 x2) : group_scope. Notation "x ^-1" := (invg x) : group_scope. Notation "x ^+ n" := (expgn x n) : group_scope. Notation "x ^- n" := (x ^+ n)^-1 : group_scope. (* Arguments of conjg are restricted to true groups to avoid an *) (* improper interpretation of A ^ B with A and B sets, namely: *) (* {x^-1 * (y * z) | y \in A, x, z \in B} *) Definition conjg (T : finGroupType) (x y : T) := y^-1 * (x * y). Notation "x1 ^ x2" := (conjg x1 x2) : group_scope. Definition commg (T : finGroupType) (x y : T) := x^-1 * x ^ y. Notation "[ ~ x1 , x2 , .. , xn ]" := (commg .. (commg x1 x2) .. xn) : group_scope. Prenex Implicits mulg invg expgn conjg commg. Notation "\prod_ ( i <- r | P ) F" := (\big[mulg/1]_(i <- r | P%B) F%g) : group_scope. Notation "\prod_ ( i <- r ) F" := (\big[mulg/1]_(i <- r) F%g) : group_scope. Notation "\prod_ ( m <= i < n | P ) F" := (\big[mulg/1]_(m <= i < n | P%B) F%g) : group_scope. Notation "\prod_ ( m <= i < n ) F" := (\big[mulg/1]_(m <= i < n) F%g) : group_scope. Notation "\prod_ ( i | P ) F" := (\big[mulg/1]_(i | P%B) F%g) : group_scope. Notation "\prod_ i F" := (\big[mulg/1]_i F%g) : group_scope. Notation "\prod_ ( i : t | P ) F" := (\big[mulg/1]_(i : t | P%B) F%g) (only parsing) : group_scope. Notation "\prod_ ( i : t ) F" := (\big[mulg/1]_(i : t) F%g) (only parsing) : group_scope. Notation "\prod_ ( i < n | P ) F" := (\big[mulg/1]_(i < n | P%B) F%g) : group_scope. Notation "\prod_ ( i < n ) F" := (\big[mulg/1]_(i < n) F%g) : group_scope. Notation "\prod_ ( i 'in' A | P ) F" := (\big[mulg/1]_(i in A | P%B) F%g) : group_scope. Notation "\prod_ ( i 'in' A ) F" := (\big[mulg/1]_(i in A) F%g) : group_scope. Section PreGroupIdentities. Variable T : baseFinGroupType. Implicit Types x y z : T. Local Notation mulgT := (@mulg T). Lemma mulgA : associative mulgT. Proof. by case: T => ? []. Qed. Lemma mul1g : left_id 1 mulgT. Proof. by case: T => ? []. Qed. Lemma invgK : @involutive T invg. Proof. by case: T => ? []. Qed. Lemma invMg x y : (x * y)^-1 = y^-1 * x^-1. Proof. by case: T x y => ? []. Qed. Lemma invg_inj : @injective T T invg. Proof. exact: can_inj invgK. Qed. Lemma eq_invg_sym x y : (x^-1 == y) = (x == y^-1). Proof. by exact: (inv_eq invgK). Qed. Lemma invg1 : 1^-1 = 1 :> T. Proof. by apply: invg_inj; rewrite -{1}[1^-1]mul1g invMg invgK mul1g. Qed. Lemma eq_invg1 x : (x^-1 == 1) = (x == 1). Proof. by rewrite eq_invg_sym invg1. Qed. Lemma mulg1 : right_id 1 mulgT. Proof. by move=> x; apply: invg_inj; rewrite invMg invg1 mul1g. Qed. Canonical finGroup_law := Monoid.Law mulgA mul1g mulg1. Lemma expgnE x n : x ^+ n = expgn_rec x n. Proof. by []. Qed. Lemma expg0 x : x ^+ 0 = 1. Proof. by []. Qed. Lemma expg1 x : x ^+ 1 = x. Proof. by []. Qed. Lemma expgS x n : x ^+ n.+1 = x * x ^+ n. Proof. by case: n => //; rewrite mulg1. Qed. Lemma expg1n n : 1 ^+ n = 1 :> T. Proof. by elim: n => // n IHn; rewrite expgS mul1g. Qed. Lemma expgD x n m : x ^+ (n + m) = x ^+ n * x ^+ m. Proof. by elim: n => [|n IHn]; rewrite ?mul1g // !expgS IHn mulgA. Qed. Lemma expgSr x n : x ^+ n.+1 = x ^+ n * x. Proof. by rewrite -addn1 expgD expg1. Qed. Lemma expgM x n m : x ^+ (n * m) = x ^+ n ^+ m. Proof. elim: m => [|m IHm]; first by rewrite muln0 expg0. by rewrite mulnS expgD IHm expgS. Qed. Lemma expgAC x m n : x ^+ m ^+ n = x ^+ n ^+ m. Proof. by rewrite -!expgM mulnC. Qed. Definition commute x y := x * y = y * x. Lemma commute_refl x : commute x x. Proof. by []. Qed. Lemma commute_sym x y : commute x y -> commute y x. Proof. by []. Qed. Lemma commute1 x : commute x 1. Proof. by rewrite /commute mulg1 mul1g. Qed. Lemma commuteM x y z : commute x y -> commute x z -> commute x (y * z). Proof. by move=> cxy cxz; rewrite /commute -mulgA -cxz !mulgA cxy. Qed. Lemma commuteX x y n : commute x y -> commute x (y ^+ n). Proof. move=> cxy; elim: n => [|n]; [exact: commute1 | rewrite expgS; exact: commuteM]. Qed. Lemma commuteX2 x y m n : commute x y -> commute (x ^+ m) (y ^+ n). Proof. by move=> cxy; exact/commuteX/commute_sym/commuteX. Qed. Lemma expgVn x n : x^-1 ^+ n = x ^- n. Proof. by elim: n => [|n IHn]; rewrite ?invg1 // expgSr expgS invMg IHn. Qed. Lemma expgMn x y n : commute x y -> (x * y) ^+ n = x ^+ n * y ^+ n. Proof. move=> cxy; elim: n => [|n IHn]; first by rewrite mulg1. by rewrite !expgS IHn -mulgA (mulgA y) (commuteX _ (commute_sym cxy)) !mulgA. Qed. End PreGroupIdentities. Hint Resolve commute1. Implicit Arguments invg_inj [T]. Prenex Implicits commute invgK invg_inj. Section GroupIdentities. Variable T : finGroupType. Implicit Types x y z : T. Local Notation mulgT := (@mulg T). Lemma mulVg : left_inverse 1 invg mulgT. Proof. by case T. Qed. Lemma mulgV : right_inverse 1 invg mulgT. Proof. by move=> x; rewrite -{1}(invgK x) mulVg. Qed. Lemma mulKg : left_loop invg mulgT. Proof. by move=> x y; rewrite mulgA mulVg mul1g. Qed. Lemma mulKVg : rev_left_loop invg mulgT. Proof. by move=> x y; rewrite mulgA mulgV mul1g. Qed. Lemma mulgI : right_injective mulgT. Proof. move=> x; exact: can_inj (mulKg x). Qed. Lemma mulgK : right_loop invg mulgT. Proof. by move=> x y; rewrite -mulgA mulgV mulg1. Qed. Lemma mulgKV : rev_right_loop invg mulgT. Proof. by move=> x y; rewrite -mulgA mulVg mulg1. Qed. Lemma mulIg : left_injective mulgT. Proof. move=> x; exact: can_inj (mulgK x). Qed. Lemma eq_invg_mul x y : (x^-1 == y :> T) = (x * y == 1 :> T). Proof. by rewrite -(inj_eq (@mulgI x)) mulgV eq_sym. Qed. Lemma eq_mulgV1 x y : (x == y) = (x * y^-1 == 1 :> T). Proof. by rewrite -(inj_eq invg_inj) eq_invg_mul. Qed. Lemma eq_mulVg1 x y : (x == y) = (x^-1 * y == 1 :> T). Proof. by rewrite -eq_invg_mul invgK. Qed. Lemma commuteV x y : commute x y -> commute x y^-1. Proof. by move=> cxy; apply: (@mulIg y); rewrite mulgKV -mulgA cxy mulKg. Qed. Lemma conjgE x y : x ^ y = y^-1 * (x * y). Proof. by []. Qed. Lemma conjgC x y : x * y = y * x ^ y. Proof. by rewrite mulKVg. Qed. Lemma conjgCV x y : x * y = y ^ x^-1 * x. Proof. by rewrite -mulgA mulgKV invgK. Qed. Lemma conjg1 x : x ^ 1 = x. Proof. by rewrite conjgE commute1 mulKg. Qed. Lemma conj1g x : 1 ^ x = 1. Proof. by rewrite conjgE mul1g mulVg. Qed. Lemma conjMg x y z : (x * y) ^ z = x ^ z * y ^ z. Proof. by rewrite !conjgE !mulgA mulgK. Qed. Lemma conjgM x y z : x ^ (y * z) = (x ^ y) ^ z. Proof. by rewrite !conjgE invMg !mulgA. Qed. Lemma conjVg x y : x^-1 ^ y = (x ^ y)^-1. Proof. by rewrite !conjgE !invMg invgK mulgA. Qed. Lemma conjJg x y z : (x ^ y) ^ z = (x ^ z) ^ y ^ z. Proof. by rewrite 2!conjMg conjVg. Qed. Lemma conjXg x y n : (x ^+ n) ^ y = (x ^ y) ^+ n. Proof. by elim: n => [|n IHn]; rewrite ?conj1g // !expgS conjMg IHn. Qed. Lemma conjgK : @right_loop T T invg conjg. Proof. by move=> y x; rewrite -conjgM mulgV conjg1. Qed. Lemma conjgKV : @rev_right_loop T T invg conjg. Proof. by move=> y x; rewrite -conjgM mulVg conjg1. Qed. Lemma conjg_inj : @left_injective T T T conjg. Proof. move=> y; exact: can_inj (conjgK y). Qed. Lemma conjg_eq1 x y : (x ^ y == 1) = (x == 1). Proof. by rewrite -(inj_eq (@conjg_inj y) x) conj1g. Qed. Lemma conjg_prod I r (P : pred I) F z : (\prod_(i <- r | P i) F i) ^ z = \prod_(i <- r | P i) (F i ^ z). Proof. by apply: (big_morph (conjg^~ z)) => [x y|]; rewrite ?conj1g ?conjMg. Qed. Lemma commgEl x y : [~ x, y] = x^-1 * x ^ y. Proof. by []. Qed. Lemma commgEr x y : [~ x, y] = y^-1 ^ x * y. Proof. by rewrite -!mulgA. Qed. Lemma commgC x y : x * y = y * x * [~ x, y]. Proof. by rewrite -mulgA !mulKVg. Qed. Lemma commgCV x y : x * y = [~ x^-1, y^-1] * (y * x). Proof. by rewrite commgEl !mulgA !invgK !mulgKV. Qed. Lemma conjRg x y z : [~ x, y] ^ z = [~ x ^ z, y ^ z]. Proof. by rewrite !conjMg !conjVg. Qed. Lemma invg_comm x y : [~ x, y]^-1 = [~ y, x]. Proof. by rewrite commgEr conjVg invMg invgK. Qed. Lemma commgP x y : reflect (commute x y) ([~ x, y] == 1 :> T). Proof. by rewrite [[~ x, y]]mulgA -invMg -eq_mulVg1 eq_sym; exact: eqP. Qed. Lemma conjg_fixP x y : reflect (x ^ y = x) ([~ x, y] == 1 :> T). Proof. by rewrite -eq_mulVg1 eq_sym; exact: eqP. Qed. Lemma commg1_sym x y : ([~ x, y] == 1 :> T) = ([~ y, x] == 1 :> T). Proof. by rewrite -invg_comm (inv_eq invgK) invg1. Qed. Lemma commg1 x : [~ x, 1] = 1. Proof. exact/eqP/commgP. Qed. Lemma comm1g x : [~ 1, x] = 1. Proof. by rewrite -invg_comm commg1 invg1. Qed. Lemma commgg x : [~ x, x] = 1. Proof. by exact/eqP/commgP. Qed. Lemma commgXg x n : [~ x, x ^+ n] = 1. Proof. exact/eqP/commgP/commuteX. Qed. Lemma commgVg x : [~ x, x^-1] = 1. Proof. by exact/eqP/commgP/commuteV. Qed. Lemma commgXVg x n : [~ x, x ^- n] = 1. Proof. exact/eqP/commgP/commuteV/commuteX. Qed. (* Other commg identities should slot in here. *) End GroupIdentities. Hint Rewrite mulg1 mul1g invg1 mulVg mulgV (@invgK) mulgK mulgKV invMg mulgA : gsimpl. Ltac gsimpl := autorewrite with gsimpl; try done. Definition gsimp := (mulg1 , mul1g, (invg1, @invgK), (mulgV, mulVg)). Definition gnorm := (gsimp, (mulgK, mulgKV, (mulgA, invMg))). Implicit Arguments mulgI [T]. Implicit Arguments mulIg [T]. Implicit Arguments conjg_inj [T]. Implicit Arguments commgP [T x y]. Implicit Arguments conjg_fixP [T x y]. Prenex Implicits conjg_fixP commgP. Section Repr. (* Plucking a set representative. *) Variable gT : baseFinGroupType. Implicit Type A : {set gT}. Definition repr A := if 1 \in A then 1 else odflt 1 [pick x in A]. Lemma mem_repr A x : x \in A -> repr A \in A. Proof. by rewrite /repr; case: ifP => // _; case: pickP => // A0; rewrite [x \in A]A0. Qed. Lemma card_mem_repr A : #|A| > 0 -> repr A \in A. Proof. by rewrite lt0n => /existsP[x]; exact: mem_repr. Qed. Lemma repr_set1 x : repr [set x] = x. Proof. by apply/set1P/card_mem_repr; rewrite cards1. Qed. Lemma repr_set0 : repr set0 = 1. Proof. by rewrite /repr; case: pickP => [x|_]; rewrite !inE. Qed. End Repr. Implicit Arguments mem_repr [gT A]. Section BaseSetMulDef. (* We only assume a baseFinGroupType to allow this construct to be iterated. *) Variable gT : baseFinGroupType. Implicit Types A B : {set gT}. (* Set-lifted group operations. *) Definition set_mulg A B := mulg @2: (A, B). Definition set_invg A := invg @^-1: A. (* The pre-group structure of group subsets. *) Lemma set_mul1g : left_id [set 1] set_mulg. Proof. move=> A; apply/setP=> y; apply/imset2P/idP=> [[_ x /set1P-> Ax ->] | Ay]. by rewrite mul1g. by exists (1 : gT) y; rewrite ?(set11, mul1g). Qed. Lemma set_mulgA : associative set_mulg. Proof. move=> A B C; apply/setP=> y. apply/imset2P/imset2P=> [[x1 z Ax1 /imset2P[x2 x3 Bx2 Cx3 ->] ->]| [z x3]]. by exists (x1 * x2) x3; rewrite ?mulgA //; apply/imset2P; exists x1 x2. case/imset2P=> x1 x2 Ax1 Bx2 -> Cx3 ->. by exists x1 (x2 * x3); rewrite ?mulgA //; apply/imset2P; exists x2 x3. Qed. Lemma set_invgK : involutive set_invg. Proof. by move=> A; apply/setP=> x; rewrite !inE invgK. Qed. Lemma set_invgM : {morph set_invg : A B / set_mulg A B >-> set_mulg B A}. Proof. move=> A B; apply/setP=> z; rewrite inE. apply/imset2P/imset2P=> [[x y Ax By /(canRL invgK)->] | [y x]]. by exists y^-1 x^-1; rewrite ?invMg // inE invgK. by rewrite !inE => By1 Ax1 ->; exists x^-1 y^-1; rewrite ?invMg. Qed. Definition group_set_baseGroupMixin : FinGroup.mixin_of (set_type gT) := FinGroup.BaseMixin set_mulgA set_mul1g set_invgK set_invgM. Canonical group_set_baseGroupType := Eval hnf in BaseFinGroupType (set_type gT) group_set_baseGroupMixin. Canonical group_set_of_baseGroupType := Eval hnf in [baseFinGroupType of {set gT}]. End BaseSetMulDef. (* Time to open the bag of dirty tricks. When we define groups down below *) (* as a subtype of {set gT}, we need them to be able to coerce to sets in *) (* both set-style contexts (x \in G) and monoid-style contexts (G * H), *) (* and we need the coercion function to be EXACTLY the structure *) (* projection in BOTH cases -- otherwise the canonical unification breaks.*) (* Alas, Coq doesn't let us use the same coercion function twice, even *) (* when the targets are convertible. Our workaround (ab)uses the module *) (* system to declare two different identity coercions on an alias class. *) Module GroupSet. Definition sort (gT : baseFinGroupType) := {set gT}. End GroupSet. Identity Coercion GroupSet_of_sort : GroupSet.sort >-> set_of. Module Type GroupSetBaseGroupSig. Definition sort gT := group_set_of_baseGroupType gT : Type. End GroupSetBaseGroupSig. Module MakeGroupSetBaseGroup (Gset_base : GroupSetBaseGroupSig). Identity Coercion of_sort : Gset_base.sort >-> FinGroup.arg_sort. End MakeGroupSetBaseGroup. Module Export GroupSetBaseGroup := MakeGroupSetBaseGroup GroupSet. Canonical group_set_eqType gT := Eval hnf in [eqType of GroupSet.sort gT]. Canonical group_set_choiceType gT := Eval hnf in [choiceType of GroupSet.sort gT]. Canonical group_set_countType gT := Eval hnf in [countType of GroupSet.sort gT]. Canonical group_set_finType gT := Eval hnf in [finType of GroupSet.sort gT]. Section GroupSetMulDef. (* Some of these constructs could be defined on a baseFinGroupType. *) (* We restrict them to proper finGroupType because we only develop *) (* the theory for that case. *) Variable gT : finGroupType. Implicit Types A B : {set gT}. Implicit Type x y : gT. Definition lcoset A x := mulg x @: A. Definition rcoset A x := mulg^~ x @: A. Definition lcosets A B := lcoset A @: B. Definition rcosets A B := rcoset A @: B. Definition indexg B A := #|rcosets A B|. Definition conjugate A x := conjg^~ x @: A. Definition conjugates A B := conjugate A @: B. Definition class x B := conjg x @: B. Definition classes A := class^~ A @: A. Definition class_support A B := conjg @2: (A, B). Definition commg_set A B := commg @2: (A, B). (* These will only be used later, but are defined here so that we can *) (* keep all the Notation together. *) Definition normaliser A := [set x | conjugate A x \subset A]. Definition centraliser A := \bigcap_(x in A) normaliser [set x]. Definition abelian A := A \subset centraliser A. Definition normal A B := (A \subset B) && (B \subset normaliser A). (* "normalised" and "centralise[s|d]" are intended to be used with *) (* the {in ...} form, as in abelian below. *) Definition normalised A := forall x, conjugate A x = A. Definition centralises x A := forall y, y \in A -> commute x y. Definition centralised A := forall x, centralises x A. End GroupSetMulDef. Arguments Scope lcoset [_ group_scope group_scope]. Arguments Scope rcoset [_ group_scope group_scope]. Arguments Scope rcosets [_ group_scope group_scope]. Arguments Scope lcosets [_ group_scope group_scope]. Arguments Scope indexg [_ group_scope group_scope]. Arguments Scope conjugate [_ group_scope group_scope]. Arguments Scope conjugates [_ group_scope group_scope]. Arguments Scope class [_ group_scope group_scope]. Arguments Scope classes [_ group_scope]. Arguments Scope class_support [_ group_scope group_scope]. Arguments Scope commg_set [_ group_scope group_scope]. Arguments Scope normaliser [_ group_scope]. Arguments Scope centraliser [_ group_scope]. Arguments Scope abelian [_ group_scope]. Arguments Scope normal [_ group_scope group_scope]. Arguments Scope centralised [_ group_scope]. Arguments Scope normalised [_ group_scope]. Arguments Scope centralises [_ group_scope group_scope]. Arguments Scope centralised [_ group_scope]. Notation "[ 1 gT ]" := (1 : {set gT}) : group_scope. Notation "[ 1 ]" := [1 FinGroup.sort _] : group_scope. Notation "A ^#" := (A :\ 1) : group_scope. Notation "x *: A" := ([set x%g] * A) : group_scope. Notation "A :* x" := (A * [set x%g]) : group_scope. Notation "A :^ x" := (conjugate A x) : group_scope. Notation "x ^: B" := (class x B) : group_scope. Notation "A :^: B" := (conjugates A B) : group_scope. Notation "#| B : A |" := (indexg B A) : group_scope. (* No notation for lcoset and rcoset, which are to be used mostly *) (* in curried form; x *: B and A :* 1 denote singleton products, *) (* so thus we can use mulgA, mulg1, etc, on, say, A :* 1 * B :* x. *) (* No notation for the set commutator generator set set_commg. *) Notation "''N' ( A )" := (normaliser A) : group_scope. Notation "''N_' G ( A )" := (G%g :&: 'N(A)) : group_scope. Notation "A <| B" := (normal A B) : group_scope. Notation "''C' ( A )" := (centraliser A) : group_scope. Notation "''C_' G ( A )" := (G%g :&: 'C(A)) : group_scope. Notation "''C_' ( G ) ( A )" := 'C_G(A) (only parsing) : group_scope. Notation "''C' [ x ]" := 'N([set x%g]) : group_scope. Notation "''C_' G [ x ]" := 'N_G([set x%g]) : group_scope. Notation "''C_' ( G ) [ x ]" := 'C_G[x] (only parsing) : group_scope. Prenex Implicits repr lcoset rcoset lcosets rcosets normal. Prenex Implicits conjugate conjugates class classes class_support. Prenex Implicits commg_set normalised centralised abelian. Section BaseSetMulProp. (* Properties of the purely multiplicative structure. *) Variable gT : baseFinGroupType. Implicit Types A B C D : {set gT}. Implicit Type x y z : gT. (* Set product. We already have all the pregroup identities, so we *) (* only need to add the monotonicity rules. *) Lemma mulsgP A B x : reflect (imset2_spec mulg (mem A) (fun _ => mem B) x) (x \in A * B). Proof. exact: imset2P. Qed. Lemma mem_mulg A B x y : x \in A -> y \in B -> x * y \in A * B. Proof. by move=> Ax By; apply/mulsgP; exists x y. Qed. Lemma prodsgP (I : finType) (P : pred I) (A : I -> {set gT}) x : reflect (exists2 c, forall i, P i -> c i \in A i & x = \prod_(i | P i) c i) (x \in \prod_(i | P i) A i). Proof. rewrite -big_filter filter_index_enum; set r := enum P. pose inA c i := c i \in A i; set RHS := x \in _. suffices IHr: reflect (exists2 c, all (inA c) r & x = \prod_(i <- r) c i) RHS. apply: (iffP IHr) => [][c inAc ->]. rewrite -[r]filter_index_enum big_filter; exists c => // i Pi. by apply: (allP inAc); rewrite mem_enum. rewrite -big_filter filter_index_enum; exists c => //; apply/allP=> i. rewrite mem_enum; exact: inAc. have: uniq r by [rewrite enum_uniq]; rewrite {}/RHS. elim: {P}r x => /= [x _|i r IHr x /andP[r'i Ur]]. by rewrite unlock; apply: (iffP set1P) => [-> | [] //]; exists (fun _ => 1). rewrite big_cons; apply: (iffP idP) => [|[c /andP[Aci Ac] ->]]; last first. by rewrite big_cons mem_mulg //; apply/IHr=> //; exists c. case/mulsgP=> y _ Ai_y /IHr[//| c Ac ->] ->{x}. exists [eta c with i |-> y] => /=. rewrite /inA /= eqxx Ai_y; apply/allP=> j rj. by case: eqP rj r'i => [-> -> // | _ rj _]; exact: (allP Ac). rewrite big_cons eqxx !big_seq; congr (_ * _). by apply: eq_bigr => j rj; case: eqP rj r'i => // -> ->. Qed. Lemma mem_prodg (I : finType) (P : pred I) (A : I -> {set gT}) c : (forall i, P i -> c i \in A i) -> \prod_(i | P i) c i \in \prod_(i | P i) A i. Proof. by move=> Ac; apply/prodsgP; exists c. Qed. Lemma mulSg A B C : A \subset B -> A * C \subset B * C. Proof. exact: imset2Sl. Qed. Lemma mulgS A B C : B \subset C -> A * B \subset A * C. Proof. exact: imset2Sr. Qed. Lemma mulgSS A B C D : A \subset B -> C \subset D -> A * C \subset B * D. Proof. exact: imset2S. Qed. Lemma mulg_subl A B : 1 \in B -> A \subset A * B. Proof. by move=> B1; rewrite -{1}(mulg1 A) mulgS ?sub1set. Qed. Lemma mulg_subr A B : 1 \in A -> B \subset A * B. Proof. by move=> A1; rewrite -{1}(mul1g B) mulSg ?sub1set. Qed. Lemma mulUg A B C : (A :|: B) * C = (A * C) :|: (B * C). Proof. exact: imset2Ul. Qed. Lemma mulgU A B C : A * (B :|: C) = (A * B) :|: (A * C). Proof. exact: imset2Ur. Qed. (* Set (pointwise) inverse. *) Lemma invUg A B : (A :|: B)^-1 = A^-1 :|: B^-1. Proof. exact: preimsetU. Qed. Lemma invIg A B : (A :&: B)^-1 = A^-1 :&: B^-1. Proof. exact: preimsetI. Qed. Lemma invDg A B : (A :\: B)^-1 = A^-1 :\: B^-1. Proof. exact: preimsetD. Qed. Lemma invCg A : (~: A)^-1 = ~: A^-1. Proof. exact: preimsetC. Qed. Lemma invSg A B : (A^-1 \subset B^-1) = (A \subset B). Proof. by rewrite !(sameP setIidPl eqP) -invIg (inj_eq invg_inj). Qed. Lemma mem_invg x A : (x \in A^-1) = (x^-1 \in A). Proof. by rewrite inE. Qed. Lemma memV_invg x A : (x^-1 \in A^-1) = (x \in A). Proof. by rewrite inE invgK. Qed. Lemma card_invg A : #|A^-1| = #|A|. Proof. by apply: card_preimset; exact: invg_inj. Qed. (* Product with singletons. *) Lemma set1gE : 1 = [set 1] :> {set gT}. Proof. by []. Qed. Lemma set1gP x : reflect (x = 1) (x \in [1]). Proof. exact: set1P. Qed. Lemma mulg_set1 x y : [set x] :* y = [set x * y]. Proof. by rewrite [_ * _]imset2_set1l imset_set1. Qed. Lemma invg_set1 x : [set x]^-1 = [set x^-1]. Proof. by apply/setP=> y; rewrite !inE inv_eq //; exact: invgK. Qed. End BaseSetMulProp. Implicit Arguments set1gP [gT x]. Implicit Arguments mulsgP [gT A B x]. Implicit Arguments prodsgP [gT I P A x]. Section GroupSetMulProp. (* Constructs that need a finGroupType *) Variable gT : finGroupType. Implicit Types A B C D : {set gT}. Implicit Type x y z : gT. (* Left cosets. *) Lemma lcosetE A x : lcoset A x = x *: A. Proof. by rewrite [_ * _]imset2_set1l. Qed. Lemma card_lcoset A x : #|x *: A| = #|A|. Proof. by rewrite -lcosetE (card_imset _ (mulgI _)). Qed. Lemma mem_lcoset A x y : (y \in x *: A) = (x^-1 * y \in A). Proof. by rewrite -lcosetE [_ x](can_imset_pre _ (mulKg _)) inE. Qed. Lemma lcosetP A x y : reflect (exists2 a, a \in A & y = x * a) (y \in x *: A). Proof. rewrite -lcosetE; exact: imsetP. Qed. Lemma lcosetsP A B C : reflect (exists2 x, x \in B & C = x *: A) (C \in lcosets A B). Proof. by apply: (iffP imsetP) => [] [x Bx ->]; exists x; rewrite ?lcosetE. Qed. Lemma lcosetM A x y : (x * y) *: A = x *: (y *: A). Proof. by rewrite -mulg_set1 mulgA. Qed. Lemma lcoset1 A : 1 *: A = A. Proof. exact: mul1g. Qed. Lemma lcosetK : left_loop invg (fun x A => x *: A). Proof. by move=> x A; rewrite -lcosetM mulVg mul1g. Qed. Lemma lcosetKV : rev_left_loop invg (fun x A => x *: A). Proof. by move=> x A; rewrite -lcosetM mulgV mul1g. Qed. Lemma lcoset_inj : right_injective (fun x A => x *: A). Proof. by move=> x; exact: can_inj (lcosetK x). Qed. Lemma lcosetS x A B : (x *: A \subset x *: B) = (A \subset B). Proof. apply/idP/idP=> sAB; last exact: mulgS. by rewrite -(lcosetK x A) -(lcosetK x B) mulgS. Qed. Lemma sub_lcoset x A B : (A \subset x *: B) = (x^-1 *: A \subset B). Proof. by rewrite -(lcosetS x^-1) lcosetK. Qed. Lemma sub_lcosetV x A B : (A \subset x^-1 *: B) = (x *: A \subset B). Proof. by rewrite sub_lcoset invgK. Qed. (* Right cosets. *) Lemma rcosetE A x : rcoset A x = A :* x. Proof. by rewrite [_ * _]imset2_set1r. Qed. Lemma card_rcoset A x : #|A :* x| = #|A|. Proof. by rewrite -rcosetE (card_imset _ (mulIg _)). Qed. Lemma mem_rcoset A x y : (y \in A :* x) = (y * x^-1 \in A). Proof. by rewrite -rcosetE [_ x](can_imset_pre A (mulgK _)) inE. Qed. Lemma rcosetP A x y : reflect (exists2 a, a \in A & y = a * x) (y \in A :* x). Proof. by rewrite -rcosetE; exact: imsetP. Qed. Lemma rcosetsP A B C : reflect (exists2 x, x \in B & C = A :* x) (C \in rcosets A B). Proof. by apply: (iffP imsetP) => [] [x Bx ->]; exists x; rewrite ?rcosetE. Qed. Lemma rcosetM A x y : A :* (x * y) = A :* x :* y. Proof. by rewrite -mulg_set1 mulgA. Qed. Lemma rcoset1 A : A :* 1 = A. Proof. exact: mulg1. Qed. Lemma rcosetK : right_loop invg (fun A x => A :* x). Proof. by move=> x A; rewrite -rcosetM mulgV mulg1. Qed. Lemma rcosetKV : rev_right_loop invg (fun A x => A :* x). Proof. by move=> x A; rewrite -rcosetM mulVg mulg1. Qed. Lemma rcoset_inj : left_injective (fun A x => A :* x). Proof. by move=> x; exact: can_inj (rcosetK x). Qed. Lemma rcosetS x A B : (A :* x \subset B :* x) = (A \subset B). Proof. apply/idP/idP=> sAB; last exact: mulSg. by rewrite -(rcosetK x A) -(rcosetK x B) mulSg. Qed. Lemma sub_rcoset x A B : (A \subset B :* x) = (A :* x ^-1 \subset B). Proof. by rewrite -(rcosetS x^-1) rcosetK. Qed. Lemma sub_rcosetV x A B : (A \subset B :* x^-1) = (A :* x \subset B). Proof. by rewrite sub_rcoset invgK. Qed. (* Inverse map lcosets to rcosets *) Lemma lcosets_invg A B : lcosets A^-1 B^-1 = invg @^-1: rcosets A B. Proof. apply/setP=> C; rewrite inE. apply/imsetP/imsetP=> [] [a]; rewrite -memV_invg ?invgK => Aa; try move/(canRL invgK); move->; exists a^-1; by rewrite // lcosetE rcosetE invMg invg_set1 ?invgK. Qed. (* Conjugates. *) Lemma conjg_preim A x : A :^ x = (conjg^~ x^-1) @^-1: A. Proof. exact: can_imset_pre (conjgK _). Qed. Lemma mem_conjg A x y : (y \in A :^ x) = (y ^ x^-1 \in A). Proof. by rewrite conjg_preim inE. Qed. Lemma mem_conjgV A x y : (y \in A :^ x^-1) = (y ^ x \in A). Proof. by rewrite mem_conjg invgK. Qed. Lemma memJ_conjg A x y : (y ^ x \in A :^ x) = (y \in A). Proof. by rewrite mem_conjg conjgK. Qed. Lemma conjsgE A x : A :^ x = x^-1 *: (A :* x). Proof. by apply/setP=> y; rewrite mem_lcoset mem_rcoset -mulgA mem_conjg. Qed. Lemma conjsg1 A : A :^ 1 = A. Proof. by rewrite conjsgE invg1 mul1g mulg1. Qed. Lemma conjsgM A x y : A :^ (x * y) = (A :^ x) :^ y. Proof. by rewrite !conjsgE invMg -!mulg_set1 !mulgA. Qed. Lemma conjsgK : @right_loop _ gT invg conjugate. Proof. by move=> x A; rewrite -conjsgM mulgV conjsg1. Qed. Lemma conjsgKV : @rev_right_loop _ gT invg conjugate. Proof. by move=> x A; rewrite -conjsgM mulVg conjsg1. Qed. Lemma conjsg_inj : @left_injective _ gT _ conjugate. Proof. by move=> x; exact: can_inj (conjsgK x). Qed. Lemma cardJg A x : #|A :^ x| = #|A|. Proof. by rewrite (card_imset _ (conjg_inj x)). Qed. Lemma conjSg A B x : (A :^ x \subset B :^ x) = (A \subset B). Proof. by rewrite !conjsgE lcosetS rcosetS. Qed. Lemma properJ A B x : (A :^ x \proper B :^ x) = (A \proper B). Proof. by rewrite /proper !conjSg. Qed. Lemma sub_conjg A B x : (A :^ x \subset B) = (A \subset B :^ x^-1). Proof. by rewrite -(conjSg A _ x) conjsgKV. Qed. Lemma sub_conjgV A B x : (A :^ x^-1 \subset B) = (A \subset B :^ x). Proof. by rewrite -(conjSg _ B x) conjsgKV. Qed. Lemma conjg_set1 x y : [set x] :^ y = [set x ^ y]. Proof. by rewrite [_ :^ _]imset_set1. Qed. Lemma conjs1g x : 1 :^ x = 1. Proof. by rewrite conjg_set1 conj1g. Qed. Lemma conjsg_eq1 A x : (A :^ x == 1%g) = (A == 1%g). Proof. by rewrite (canF_eq (conjsgK x)) conjs1g. Qed. Lemma conjsMg A B x : (A * B) :^ x = A :^ x * B :^ x. Proof. by rewrite !conjsgE !mulgA rcosetK. Qed. Lemma conjIg A B x : (A :&: B) :^ x = A :^ x :&: B :^ x. Proof. by rewrite !conjg_preim preimsetI. Qed. Lemma conj0g x : set0 :^ x = set0. Proof. exact: imset0. Qed. Lemma conjTg x : [set: gT] :^ x = [set: gT]. Proof. by rewrite conjg_preim preimsetT. Qed. Lemma bigcapJ I r (P : pred I) (B : I -> {set gT}) x : \bigcap_(i <- r | P i) (B i :^ x) = (\bigcap_(i <- r | P i) B i) :^ x. Proof. by rewrite (big_endo (conjugate^~ x)) => // [B1 B2|]; rewrite (conjTg, conjIg). Qed. Lemma conjUg A B x : (A :|: B) :^ x = A :^ x :|: B :^ x. Proof. by rewrite !conjg_preim preimsetU. Qed. Lemma bigcupJ I r (P : pred I) (B : I -> {set gT}) x : \bigcup_(i <- r | P i) (B i :^ x) = (\bigcup_(i <- r | P i) B i) :^ x. Proof. rewrite (big_endo (conjugate^~ x)) => // [B1 B2|]; first by rewrite conjUg. exact: imset0. Qed. Lemma conjCg A x : (~: A) :^ x = ~: A :^ x. Proof. by rewrite !conjg_preim preimsetC. Qed. Lemma conjDg A B x : (A :\: B) :^ x = A :^ x :\: B :^ x. Proof. by rewrite !setDE !(conjCg, conjIg). Qed. Lemma conjD1g A x : A^# :^ x = (A :^ x)^#. Proof. by rewrite conjDg conjs1g. Qed. (* Classes; not much for now. *) Lemma memJ_class x y A : y \in A -> x ^ y \in x ^: A. Proof. exact: mem_imset. Qed. Lemma classS x A B : A \subset B -> x ^: A \subset x ^: B. Proof. exact: imsetS. Qed. Lemma class_set1 x y : x ^: [set y] = [set x ^ y]. Proof. exact: imset_set1. Qed. Lemma class1g x A : x \in A -> 1 ^: A = 1. Proof. move=> Ax; apply/setP=> y. by apply/imsetP/set1P=> [[a Aa]|] ->; last exists x; rewrite ?conj1g. Qed. Lemma classVg x A : x^-1 ^: A = (x ^: A)^-1. Proof. apply/setP=> xy; rewrite inE; apply/imsetP/imsetP=> [] [y Ay def_xy]. by rewrite def_xy conjVg invgK; exists y. by rewrite -[xy]invgK def_xy -conjVg; exists y. Qed. Lemma mem_classes x A : x \in A -> x ^: A \in classes A. Proof. exact: mem_imset. Qed. Lemma memJ_class_support A B x y : x \in A -> y \in B -> x ^ y \in class_support A B. Proof. by move=> Ax By; apply: mem_imset2. Qed. Lemma class_supportM A B C : class_support A (B * C) = class_support (class_support A B) C. Proof. apply/setP=> x; apply/imset2P/imset2P=> [[a y Aa] | [y c]]. case/mulsgP=> b c Bb Cc -> ->{x y}. by exists (a ^ b) c; rewrite ?(mem_imset2, conjgM). case/imset2P=> a b Aa Bb -> Cc ->{x y}. by exists a (b * c); rewrite ?(mem_mulg, conjgM). Qed. Lemma class_support_set1l A x : class_support [set x] A = x ^: A. Proof. exact: imset2_set1l. Qed. Lemma class_support_set1r A x : class_support A [set x] = A :^ x. Proof. exact: imset2_set1r. Qed. Lemma classM x A B : x ^: (A * B) = class_support (x ^: A) B. Proof. by rewrite -!class_support_set1l class_supportM. Qed. Lemma class_lcoset x y A : x ^: (y *: A) = (x ^ y) ^: A. Proof. by rewrite classM class_set1 class_support_set1l. Qed. Lemma class_rcoset x A y : x ^: (A :* y) = (x ^: A) :^ y. Proof. by rewrite -class_support_set1r classM. Qed. (* Conjugate set. *) Lemma conjugatesS A B C : B \subset C -> A :^: B \subset A :^: C. Proof. exact: imsetS. Qed. Lemma conjugates_set1 A x : A :^: [set x] = [set A :^ x]. Proof. exact: imset_set1. Qed. Lemma conjugates_conj A x B : (A :^ x) :^: B = A :^: (x *: B). Proof. rewrite /conjugates [x *: B]imset2_set1l -imset_comp. by apply: eq_imset => y /=; rewrite conjsgM. Qed. (* Class support. *) Lemma class_supportEl A B : class_support A B = \bigcup_(x in A) x ^: B. Proof. exact: curry_imset2l. Qed. Lemma class_supportEr A B : class_support A B = \bigcup_(x in B) A :^ x. Proof. exact: curry_imset2r. Qed. (* Groups (at last!) *) Definition group_set A := (1 \in A) && (A * A \subset A). Lemma group_setP A : reflect (1 \in A /\ {in A & A, forall x y, x * y \in A}) (group_set A). Proof. apply: (iffP andP) => [] [A1 AM]; split=> {A1}//. by move=> x y Ax Ay; apply: (subsetP AM); rewrite mem_mulg. apply/subsetP=> _ /mulsgP[x y Ax Ay ->]; exact: AM. Qed. Structure group_type : Type := Group { gval :> GroupSet.sort gT; _ : group_set gval }. Definition group_of of phant gT : predArgType := group_type. Notation Local groupT := (group_of (Phant gT)). Identity Coercion type_of_group : group_of >-> group_type. Canonical group_subType := Eval hnf in [subType for gval]. Definition group_eqMixin := Eval hnf in [eqMixin of group_type by <:]. Canonical group_eqType := Eval hnf in EqType group_type group_eqMixin. Definition group_choiceMixin := [choiceMixin of group_type by <:]. Canonical group_choiceType := Eval hnf in ChoiceType group_type group_choiceMixin. Definition group_countMixin := [countMixin of group_type by <:]. Canonical group_countType := Eval hnf in CountType group_type group_countMixin. Canonical group_subCountType := Eval hnf in [subCountType of group_type]. Definition group_finMixin := [finMixin of group_type by <:]. Canonical group_finType := Eval hnf in FinType group_type group_finMixin. Canonical group_subFinType := Eval hnf in [subFinType of group_type]. (* No predType or baseFinGroupType structures, as these would hide the *) (* group-to-set coercion and thus spoil unification. *) Canonical group_of_subType := Eval hnf in [subType of groupT]. Canonical group_of_eqType := Eval hnf in [eqType of groupT]. Canonical group_of_choiceType := Eval hnf in [choiceType of groupT]. Canonical group_of_countType := Eval hnf in [countType of groupT]. Canonical group_of_subCountType := Eval hnf in [subCountType of groupT]. Canonical group_of_finType := Eval hnf in [finType of groupT]. Canonical group_of_subFinType := Eval hnf in [subFinType of groupT]. Definition group (A : {set gT}) gA : groupT := @Group A gA. Definition clone_group G := let: Group _ gP := G return {type of Group for G} -> groupT in fun k => k gP. Lemma group_inj : injective gval. Proof. exact: val_inj. Qed. Lemma groupP (G : groupT) : group_set G. Proof. by case: G. Qed. Lemma congr_group (H K : groupT) : H = K -> H :=: K. Proof. exact: congr1. Qed. Lemma isgroupP A : reflect (exists G : groupT, A = G) (group_set A). Proof. by apply: (iffP idP) => [gA | [[B gB] -> //]]; exists (Group gA). Qed. Lemma group_set_one : group_set 1. Proof. by rewrite /group_set set11 mulg1 subxx. Qed. Canonical one_group := group group_set_one. Canonical set1_group := @group [set 1] group_set_one. Lemma group_setT (phT : phant gT) : group_set (setTfor phT). Proof. by apply/group_setP; split=> [|x y _ _]; rewrite inE. Qed. Canonical setT_group phT := group (group_setT phT). (* These definitions come early so we can establish the Notation. *) Definition generated A := \bigcap_(G : groupT | A \subset G) G. Definition gcore A B := \bigcap_(x in B) A :^ x. Definition joing A B := generated (A :|: B). Definition commutator A B := generated (commg_set A B). Definition cycle x := generated [set x]. Definition order x := #|cycle x|. End GroupSetMulProp. Implicit Arguments lcosetP [gT A x y]. Implicit Arguments lcosetsP [gT A B C]. Implicit Arguments rcosetP [gT A x y]. Implicit Arguments rcosetsP [gT A B C]. Implicit Arguments group_setP [gT A]. Prenex Implicits group_set mulsgP set1gP. Prenex Implicits lcosetP lcosetsP rcosetP rcosetsP group_setP. Arguments Scope commutator [_ group_scope group_scope]. Arguments Scope joing [_ group_scope group_scope]. Arguments Scope generated [_ group_scope]. Notation "{ 'group' gT }" := (group_of (Phant gT)) (at level 0, format "{ 'group' gT }") : type_scope. Notation "[ 'group' 'of' G ]" := (clone_group (@group _ G)) (at level 0, format "[ 'group' 'of' G ]") : form_scope. Bind Scope Group_scope with group_type. Bind Scope Group_scope with group_of. Notation "1" := (one_group _) : Group_scope. Notation "[ 1 gT ]" := (1%G : {group gT}) : Group_scope. Notation "[ 'set' : gT ]" := (setT_group (Phant gT)) : Group_scope. (* Helper notation for defining new groups that need a bespoke finGroupType. *) (* The actual group for such a type (say, my_gT) will be the full group, *) (* i.e., [set: my_gT] or [set: my_gT]%G, but Coq will not recognize *) (* specific notation for these because of the coercions inserted during type *) (* inference, unless they are defined as [set: gsort my_gT] using the *) (* Notation below. *) Notation gsort gT := (FinGroup.arg_sort (FinGroup.base gT%type)) (only parsing). Notation "<< A >>" := (generated A) : group_scope. Notation "<[ x ] >" := (cycle x) : group_scope. Notation "#[ x ]" := (order x) : group_scope. Notation "A <*> B" := (joing A B) : group_scope. Notation "[ ~: A1 , A2 , .. , An ]" := (commutator .. (commutator A1 A2) .. An) : group_scope. Prenex Implicits order cycle gcore. Section GroupProp. Variable gT : finGroupType. Notation sT := {set gT}. Implicit Types A B C D : sT. Implicit Types x y z : gT. Implicit Types G H K : {group gT}. Section OneGroup. Variable G : {group gT}. Lemma valG : val G = G. Proof. by []. Qed. (* Non-triviality. *) Lemma group1 : 1 \in G. Proof. by case/group_setP: (valP G). Qed. Hint Resolve group1. (* Loads of silly variants to placate the incompleteness of trivial. *) (* An alternative would be to upgrade done, pending better support *) (* in the ssreflect ML code. *) Notation gTr := (FinGroup.sort gT). Notation Gcl := (pred_of_set G : pred gTr). Lemma group1_class1 : (1 : gTr) \in G. Proof. by []. Qed. Lemma group1_class2 : 1 \in Gcl. Proof. by []. Qed. Lemma group1_class12 : (1 : gTr) \in Gcl. Proof. by []. Qed. Lemma group1_eqType : (1 : gT : eqType) \in G. Proof. by []. Qed. Lemma group1_finType : (1 : gT : finType) \in G. Proof. by []. Qed. Lemma group1_contra x : x \notin G -> x != 1. Proof. by apply: contraNneq => ->. Qed. Lemma sub1G : [1 gT] \subset G. Proof. by rewrite sub1set. Qed. Lemma subG1 : (G \subset [1]) = (G :==: 1). Proof. by rewrite eqEsubset sub1G andbT. Qed. Lemma setI1g : 1 :&: G = 1. Proof. exact: (setIidPl sub1G). Qed. Lemma setIg1 : G :&: 1 = 1. Proof. exact: (setIidPr sub1G). Qed. Lemma subG1_contra H : G \subset H -> G :!=: 1 -> H :!=: 1. Proof. by move=> sGH; rewrite -subG1; apply: contraNneq => <-. Qed. Lemma repr_group : repr G = 1. Proof. by rewrite /repr group1. Qed. Lemma cardG_gt0 : 0 < #|G|. Proof. by rewrite lt0n; apply/existsP; exists (1 : gT). Qed. (* Workaround for the fact that the simple matching used by Trivial does not *) (* always allow conversion. In particular cardG_gt0 always fails to apply to *) (* subgoals that have been simplified (by /=) because type inference in the *) (* notation #|G| introduces redexes of the form *) (* Finite.sort (arg_finGroupType (FinGroup.base gT)) *) (* which get collapsed to Fingroup.arg_sort (FinGroup.base gT). *) Definition cardG_gt0_reduced : 0 < card (@mem gT (predPredType gT) G) := cardG_gt0. Lemma indexg_gt0 A : 0 < #|G : A|. Proof. rewrite lt0n; apply/existsP; exists A. rewrite -{2}[A]mulg1 -rcosetE; exact: mem_imset. Qed. Lemma trivgP : reflect (G :=: 1) (G \subset [1]). Proof. by rewrite subG1; exact: eqP. Qed. Lemma trivGP : reflect (G = 1%G) (G \subset [1]). Proof. by rewrite subG1; exact: eqP. Qed. Lemma proper1G : ([1] \proper G) = (G :!=: 1). Proof. by rewrite properEneq sub1G andbT eq_sym. Qed. Lemma trivgPn : reflect (exists2 x, x \in G & x != 1) (G :!=: 1). Proof. rewrite -subG1. by apply: (iffP subsetPn) => [] [x Gx x1]; exists x; rewrite ?inE in x1 *. Qed. Lemma trivg_card_le1 : (G :==: 1) = (#|G| <= 1). Proof. by rewrite eq_sym eqEcard cards1 sub1G. Qed. Lemma trivg_card1 : (G :==: 1) = (#|G| == 1%N). Proof. by rewrite trivg_card_le1 eqn_leq cardG_gt0 andbT. Qed. Lemma cardG_gt1 : (#|G| > 1) = (G :!=: 1). Proof. by rewrite trivg_card_le1 ltnNge. Qed. Lemma card_le1_trivg : #|G| <= 1 -> G :=: 1. Proof. by rewrite -trivg_card_le1; move/eqP. Qed. Lemma card1_trivg : #|G| = 1%N -> G :=: 1. Proof. by move=> G1; rewrite card_le1_trivg ?G1. Qed. (* Inclusion and product. *) Lemma mulG_subl A : A \subset A * G. Proof. exact: mulg_subl group1. Qed. Lemma mulG_subr A : A \subset G * A. Proof. exact: mulg_subr group1. Qed. Lemma mulGid : G * G = G. Proof. by apply/eqP; rewrite eqEsubset mulG_subr andbT; case/andP: (valP G). Qed. Lemma mulGS A B : (G * A \subset G * B) = (A \subset G * B). Proof. apply/idP/idP; first exact: subset_trans (mulG_subr A). by move/(mulgS G); rewrite mulgA mulGid. Qed. Lemma mulSG A B : (A * G \subset B * G) = (A \subset B * G). Proof. apply/idP/idP; first exact: subset_trans (mulG_subl A). by move/(mulSg G); rewrite -mulgA mulGid. Qed. Lemma mul_subG A B : A \subset G -> B \subset G -> A * B \subset G. Proof. by move=> sAG sBG; rewrite -mulGid mulgSS. Qed. (* Membership lemmas *) Lemma groupM x y : x \in G -> y \in G -> x * y \in G. Proof. by case/group_setP: (valP G) x y. Qed. Lemma groupX x n : x \in G -> x ^+ n \in G. Proof. by move=> Gx; elim: n => [|n IHn]; rewrite ?group1 // expgS groupM. Qed. Lemma groupVr x : x \in G -> x^-1 \in G. Proof. move=> Gx; rewrite -(mul1g x^-1) -mem_rcoset ((G :* x =P G) _) //. by rewrite eqEcard card_rcoset leqnn mul_subG ?sub1set. Qed. Lemma groupVl x : x^-1 \in G -> x \in G. Proof. by move/groupVr; rewrite invgK. Qed. Lemma groupV x : (x^-1 \in G) = (x \in G). Proof. by apply/idP/idP; [exact: groupVl | exact: groupVr]. Qed. Lemma groupMl x y : x \in G -> (x * y \in G) = (y \in G). Proof. move=> Gx; apply/idP/idP=> Gy; last exact: groupM. rewrite -(mulKg x y); exact: groupM (groupVr _) _. Qed. Lemma groupMr x y : x \in G -> (y * x \in G) = (y \in G). Proof. by move=> Gx; rewrite -[_ \in G]groupV invMg groupMl groupV. Qed. Definition in_group := (group1, groupV, (groupMl, groupX)). Lemma groupJ x y : x \in G -> y \in G -> x ^ y \in G. Proof. by move=> Gx Gy; rewrite !in_group. Qed. Lemma groupJr x y : y \in G -> (x ^ y \in G) = (x \in G). Proof. by move=> Gy; rewrite groupMl (groupMr, groupV). Qed. Lemma groupR x y : x \in G -> y \in G -> [~ x, y] \in G. Proof. by move=> Gx Gy; rewrite !in_group. Qed. Lemma group_prod I r (P : pred I) F : (forall i, P i -> F i \in G) -> \prod_(i <- r | P i) F i \in G. Proof. by move=> G_P; elim/big_ind: _ => //; exact: groupM. Qed. (* Inverse is an anti-morphism. *) Lemma invGid : G^-1 = G. Proof. by apply/setP=> x; rewrite inE groupV. Qed. Lemma inv_subG A : (A^-1 \subset G) = (A \subset G). Proof. by rewrite -{1}invGid invSg. Qed. Lemma invg_lcoset x : (x *: G)^-1 = G :* x^-1. Proof. by rewrite invMg invGid invg_set1. Qed. Lemma invg_rcoset x : (G :* x)^-1 = x^-1 *: G. Proof. by rewrite invMg invGid invg_set1. Qed. Lemma memV_lcosetV x y : (y^-1 \in x^-1 *: G) = (y \in G :* x). Proof. by rewrite -invg_rcoset memV_invg. Qed. Lemma memV_rcosetV x y : (y^-1 \in G :* x^-1) = (y \in x *: G). Proof. by rewrite -invg_lcoset memV_invg. Qed. (* Product idempotence *) Lemma mulSgGid A x : x \in A -> A \subset G -> A * G = G. Proof. move=> Ax sAG; apply/eqP; rewrite eqEsubset -{2}mulGid mulSg //=. apply/subsetP=> y Gy; rewrite -(mulKVg x y) mem_mulg // groupMr // groupV. exact: (subsetP sAG). Qed. Lemma mulGSgid A x : x \in A -> A \subset G -> G * A = G. Proof. rewrite -memV_invg -invSg invGid => Ax sAG. by apply: invg_inj; rewrite invMg invGid (mulSgGid Ax). Qed. (* Left cosets *) Lemma lcoset_refl x : x \in x *: G. Proof. by rewrite mem_lcoset mulVg group1. Qed. Lemma lcoset_sym x y : (x \in y *: G) = (y \in x *: G). Proof. by rewrite !mem_lcoset -groupV invMg invgK. Qed. Lemma lcoset_transl x y : x \in y *: G -> x *: G = y *: G. Proof. move=> Gyx; apply/setP=> u; rewrite !mem_lcoset in Gyx *. by rewrite -{2}(mulKVg x u) mulgA (groupMl _ Gyx). Qed. Lemma lcoset_transr x y z : x \in y *: G -> (x \in z *: G) = (y \in z *: G). Proof. by move=> Gyx; rewrite -2!(lcoset_sym z) (lcoset_transl Gyx). Qed. Lemma lcoset_trans x y z : x \in y *: G -> y \in z *: G -> x \in z *: G. Proof. by move/lcoset_transr->. Qed. Lemma lcoset_id x : x \in G -> x *: G = G. Proof. rewrite -{-2}(mul1g G); exact: lcoset_transl. Qed. (* Right cosets, with an elimination form for repr. *) Lemma rcoset_refl x : x \in G :* x. Proof. by rewrite mem_rcoset mulgV group1. Qed. Lemma rcoset_sym x y : (x \in G :* y) = (y \in G :* x). Proof. by rewrite -!memV_lcosetV lcoset_sym. Qed. Lemma rcoset_transl x y : x \in G :* y -> G :* x = G :* y. Proof. move=> Gyx; apply: invg_inj; rewrite !invg_rcoset. by apply: lcoset_transl; rewrite memV_lcosetV. Qed. Lemma rcoset_transr x y z : x \in G :* y -> (x \in G :* z) = (y \in G :* z). Proof. by move=> Gyx; rewrite -2!(rcoset_sym z) (rcoset_transl Gyx). Qed. Lemma rcoset_trans x y z : y \in G :* x -> z \in G :* y -> z \in G :* x. Proof. by move/rcoset_transl->. Qed. Lemma rcoset_id x : x \in G -> G :* x = G. Proof. by rewrite -{-2}(mulg1 G); exact: rcoset_transl. Qed. (* Elimination form. *) CoInductive rcoset_repr_spec x : gT -> Type := RcosetReprSpec g : g \in G -> rcoset_repr_spec x (g * x). Lemma mem_repr_rcoset x : repr (G :* x) \in G :* x. Proof. exact: mem_repr (rcoset_refl x). Qed. (* This form sometimes fails because ssreflect 1.1 delegates matching to the *) (* (weaker) primitive Coq algorithm for general (co)inductive type families. *) Lemma repr_rcosetP x : rcoset_repr_spec x (repr (G :* x)). Proof. by rewrite -[repr _](mulgKV x); split; rewrite -mem_rcoset mem_repr_rcoset. Qed. Lemma rcoset_repr x : G :* (repr (G :* x)) = G :* x. Proof. by apply: rcoset_transl; exact: mem_repr (rcoset_refl x). Qed. (* Coset spaces. *) Lemma mem_lcosets A x : (x *: G \in lcosets G A) = (x \in A * G). Proof. apply/imsetP/mulsgP=> [[a Aa eqxaG] | [a g Aa Gg ->{x}]]. exists a (a^-1 * x); rewrite ?mulKVg //. by rewrite -mem_lcoset -lcosetE -eqxaG lcoset_refl. by exists a; rewrite // lcosetM lcosetE lcoset_id. Qed. Lemma mem_rcosets A x : (G :* x \in rcosets G A) = (x \in G * A). Proof. rewrite -memV_invg invMg invGid -mem_lcosets. by rewrite -{4}invGid lcosets_invg inE invg_lcoset invgK. Qed. (* Conjugates. *) Lemma group_setJ A x : group_set (A :^ x) = group_set A. Proof. by rewrite /group_set mem_conjg conj1g -conjsMg conjSg. Qed. Lemma group_set_conjG x : group_set (G :^ x). Proof. by rewrite group_setJ groupP. Qed. Canonical conjG_group x := group (group_set_conjG x). Lemma conjGid : {in G, normalised G}. Proof. by move=> x Gx; apply/setP=> y; rewrite mem_conjg groupJr ?groupV. Qed. Lemma conj_subG x A : x \in G -> A \subset G -> A :^ x \subset G. Proof. by move=> Gx sAG; rewrite -(conjGid Gx) conjSg. Qed. (* Classes *) Lemma class1G : 1 ^: G = 1. Proof. exact: class1g group1. Qed. Lemma classes1 : [1] \in classes G. Proof. by rewrite -class1G mem_classes. Qed. Lemma classGidl x y : y \in G -> (x ^ y) ^: G = x ^: G. Proof. by move=> Gy; rewrite -class_lcoset lcoset_id. Qed. Lemma classGidr x : {in G, normalised (x ^: G)}. Proof. by move=> y Gy /=; rewrite -class_rcoset rcoset_id. Qed. Lemma class_refl x : x \in x ^: G. Proof. by apply/imsetP; exists (1 : gT); rewrite ?conjg1. Qed. Hint Resolve class_refl. Lemma class_transr x y : x \in y ^: G -> x ^: G = y ^: G. Proof. by case/imsetP=> z Gz ->; rewrite classGidl. Qed. Lemma class_sym x y : (x \in y ^: G) = (y \in x ^: G). Proof. by apply/idP/idP=> /class_transr->. Qed. Lemma class_transl x y z : x \in y ^: G -> (x \in z ^: G) = (y \in z ^: G). Proof. by rewrite -!(class_sym z) => /class_transr->. Qed. Lemma class_trans x y z : x \in y ^: G -> y \in z ^: G -> x \in z ^: G. Proof. by move/class_transl->. Qed. Lemma repr_class x : {y | y \in G & repr (x ^: G) = x ^ y}. Proof. set z := repr _; have: #|[set y in G | z == x ^ y]| > 0. have: z \in x ^: G by exact: (mem_repr x). by case/imsetP=> y Gy ->; rewrite (cardD1 y) inE Gy eqxx. by move/card_mem_repr; move: (repr _) => y /setIdP[Gy /eqP]; exists y. Qed. Lemma classG_eq1 x : (x ^: G == 1) = (x == 1). Proof. apply/eqP/eqP=> [xG1 | ->]; last exact: class1G. by have:= class_refl x; rewrite xG1 => /set1P. Qed. Lemma class_subG x A : x \in G -> A \subset G -> x ^: A \subset G. Proof. move=> Gx sAG; apply/subsetP=> _ /imsetP[y Ay ->]. by rewrite groupJ // (subsetP sAG). Qed. Lemma repr_classesP xG : reflect (repr xG \in G /\ xG = repr xG ^: G) (xG \in classes G). Proof. apply: (iffP imsetP) => [[x Gx ->] | []]; last by exists (repr xG). by have [y Gy ->] := repr_class x; rewrite classGidl ?groupJ. Qed. Lemma mem_repr_classes xG : xG \in classes G -> repr xG \in xG. Proof. by case/repr_classesP=> _ {2}->; exact: class_refl. Qed. Lemma classes_gt0 : 0 < #|classes G|. Proof. by rewrite (cardsD1 1) classes1. Qed. Lemma classes_gt1 : (#|classes G| > 1) = (G :!=: 1). Proof. rewrite (cardsD1 1) classes1 ltnS lt0n cards_eq0. apply/set0Pn/trivgPn=> [[xG /setD1P[nt_xG]] | [x Gx ntx]]. by case/imsetP=> x Gx def_xG; rewrite def_xG classG_eq1 in nt_xG; exists x. by exists (x ^: G); rewrite !inE classG_eq1 ntx; exact: mem_imset. Qed. Lemma mem_class_support A x : x \in A -> x \in class_support A G. Proof. by move=> Ax; rewrite -[x]conjg1 memJ_class_support. Qed. Lemma class_supportGidl A x : x \in G -> class_support (A :^ x) G = class_support A G. Proof. by move=> Gx; rewrite -class_support_set1r -class_supportM lcoset_id. Qed. Lemma class_supportGidr A : {in G, normalised (class_support A G)}. Proof. by move=> x Gx /=; rewrite -class_support_set1r -class_supportM rcoset_id. Qed. Lemma class_support_subG A : A \subset G -> class_support A G \subset G. Proof. by move=> sAG; rewrite class_supportEr; apply/bigcupsP=> x Gx; exact: conj_subG. Qed. Lemma sub_class_support A : A \subset class_support A G. Proof. by rewrite class_supportEr (bigcup_max 1) ?conjsg1. Qed. Lemma class_support_id : class_support G G = G. Proof. by apply/eqP; rewrite eqEsubset sub_class_support class_support_subG. Qed. Lemma class_supportD1 A : (class_support A G)^# = cover (A^# :^: G). Proof. rewrite cover_imset class_supportEr setDE big_distrl /=. by apply: eq_bigr => x _; rewrite -setDE conjD1g. Qed. (* Subgroup Type construction. *) (* We only expect to use this for abstract groups, so we don't project *) (* the argument to a set. *) Inductive subg_of : predArgType := Subg x & x \in G. Definition sgval u := let: Subg x _ := u in x. Canonical subg_subType := Eval hnf in [subType for sgval]. Definition subg_eqMixin := Eval hnf in [eqMixin of subg_of by <:]. Canonical subg_eqType := Eval hnf in EqType subg_of subg_eqMixin. Definition subg_choiceMixin := [choiceMixin of subg_of by <:]. Canonical subg_choiceType := Eval hnf in ChoiceType subg_of subg_choiceMixin. Definition subg_countMixin := [countMixin of subg_of by <:]. Canonical subg_countType := Eval hnf in CountType subg_of subg_countMixin. Canonical subg_subCountType := Eval hnf in [subCountType of subg_of]. Definition subg_finMixin := [finMixin of subg_of by <:]. Canonical subg_finType := Eval hnf in FinType subg_of subg_finMixin. Canonical subg_subFinType := Eval hnf in [subFinType of subg_of]. Lemma subgP u : sgval u \in G. Proof. exact: valP. Qed. Lemma subg_inj : injective sgval. Proof. exact: val_inj. Qed. Lemma congr_subg u v : u = v -> sgval u = sgval v. Proof. exact: congr1. Qed. Definition subg_one := Subg group1. Definition subg_inv u := Subg (groupVr (subgP u)). Definition subg_mul u v := Subg (groupM (subgP u) (subgP v)). Lemma subg_oneP : left_id subg_one subg_mul. Proof. move=> u; apply: val_inj; exact: mul1g. Qed. Lemma subg_invP : left_inverse subg_one subg_inv subg_mul. Proof. move=> u; apply: val_inj; exact: mulVg. Qed. Lemma subg_mulP : associative subg_mul. Proof. move=> u v w; apply: val_inj; exact: mulgA. Qed. Definition subFinGroupMixin := FinGroup.Mixin subg_mulP subg_oneP subg_invP. Canonical subBaseFinGroupType := Eval hnf in BaseFinGroupType subg_of subFinGroupMixin. Canonical subFinGroupType := FinGroupType subg_invP. Lemma sgvalM : {in setT &, {morph sgval : x y / x * y}}. Proof. by []. Qed. Lemma valgM : {in setT &, {morph val : x y / (x : subg_of) * y >-> x * y}}. Proof. by []. Qed. Definition subg : gT -> subg_of := insubd (1 : subg_of). Lemma subgK x : x \in G -> val (subg x) = x. Proof. by move=> Gx; rewrite insubdK. Qed. Lemma sgvalK : cancel sgval subg. Proof. case=> x Gx; apply: val_inj; exact: subgK. Qed. Lemma subg_default x : (x \in G) = false -> val (subg x) = 1. Proof. by move=> Gx; rewrite val_insubd Gx. Qed. Lemma subgM : {in G &, {morph subg : x y / x * y}}. Proof. by move=> x y Gx Gy; apply: val_inj; rewrite /= !subgK ?groupM. Qed. End OneGroup. Hint Resolve group1. Lemma groupD1_inj G H : G^# = H^# -> G :=: H. Proof. by move/(congr1 (setU 1)); rewrite !setD1K. Qed. Lemma invMG G H : (G * H)^-1 = H * G. Proof. by rewrite invMg !invGid. Qed. Lemma mulSGid G H : H \subset G -> H * G = G. Proof. exact: mulSgGid (group1 H). Qed. Lemma mulGSid G H : H \subset G -> G * H = G. Proof. exact: mulGSgid (group1 H). Qed. Lemma mulGidPl G H : reflect (G * H = G) (H \subset G). Proof. by apply: (iffP idP) => [|<-]; [exact: mulGSid | exact: mulG_subr]. Qed. Lemma mulGidPr G H : reflect (G * H = H) (G \subset H). Proof. by apply: (iffP idP) => [|<-]; [exact: mulSGid | exact: mulG_subl]. Qed. Lemma comm_group_setP G H : reflect (commute G H) (group_set (G * H)). Proof. rewrite /group_set (subsetP (mulG_subl _ _)) ?group1 // andbC. have <-: #|G * H| <= #|H * G| by rewrite -invMG card_invg. rewrite -mulgA mulGS mulgA mulSG -eqEcard eq_sym; exact: eqP. Qed. Lemma card_lcosets G H : #|lcosets H G| = #|G : H|. Proof. by rewrite -[#|G : H|](card_preimset _ invg_inj) -lcosets_invg !invGid. Qed. (* Group Modularity equations *) Lemma group_modl A B G : A \subset G -> A * (B :&: G) = A * B :&: G. Proof. move=> sAG; apply/eqP; rewrite eqEsubset subsetI mulgS ?subsetIl //. rewrite -{2}mulGid mulgSS ?subsetIr //. apply/subsetP => _ /setIP[/mulsgP[a b Aa Bb ->] Gab]. by rewrite mem_mulg // inE Bb -(groupMl _ (subsetP sAG _ Aa)). Qed. Lemma group_modr A B G : B \subset G -> (G :&: A) * B = G :&: A * B. Proof. move=> sBG; apply: invg_inj; rewrite !(invMg, invIg) invGid !(setIC G). by rewrite group_modl // -invGid invSg. Qed. End GroupProp. Hint Resolve group1 group1_class1 group1_class12 group1_class12. Hint Resolve group1_eqType group1_finType. Hint Resolve cardG_gt0 cardG_gt0_reduced indexg_gt0. Notation "G :^ x" := (conjG_group G x) : Group_scope. Notation "[ 'subg' G ]" := (subg_of G) : type_scope. Notation "[ 'subg' G ]" := [set: subg_of G] : group_scope. Notation "[ 'subg' G ]" := [set: subg_of G]%G : Group_scope. Prenex Implicits subg sgval subg_of. Bind Scope group_scope with subg_of. Implicit Arguments trivgP [gT G]. Implicit Arguments trivGP [gT G]. Implicit Arguments mulGidPl [gT G H]. Implicit Arguments mulGidPr [gT G H]. Implicit Arguments comm_group_setP [gT G H]. Implicit Arguments repr_classesP [gT G xG]. Prenex Implicits trivgP trivGP comm_group_setP. Section GroupInter. Variable gT : finGroupType. Implicit Types A B : {set gT}. Implicit Types G H : {group gT}. Lemma group_setI G H : group_set (G :&: H). Proof. apply/group_setP; split=> [|x y]; rewrite !inE ?group1 //. by case/andP=> Gx Hx; rewrite !groupMl. Qed. Canonical setI_group G H := group (group_setI G H). Section Nary. Variables (I : finType) (P : pred I) (F : I -> {group gT}). Lemma group_set_bigcap : group_set (\bigcap_(i | P i) F i). Proof. elim/big_rec: _ => [|i G _ gG]; first exact: groupP. exact: group_setI (Group gG). Qed. Canonical bigcap_group := group group_set_bigcap. End Nary. Canonical generated_group A : {group _} := Eval hnf in [group of <>]. Canonical gcore_group G A : {group _} := Eval hnf in [group of gcore G A]. Canonical commutator_group A B : {group _} := Eval hnf in [group of [~: A, B]]. Canonical joing_group A B : {group _} := Eval hnf in [group of A <*> B]. Canonical cycle_group x : {group _} := Eval hnf in [group of <[x]>]. Lemma order_gt0 (x : gT) : 0 < #[x]. Proof. exact: cardG_gt0. Qed. End GroupInter. Hint Resolve order_gt0. Definition joinG (gT : finGroupType) (G H : {group gT}) := joing_group G H. Definition subgroups (gT : finGroupType) (G : {set gT}) := [set H : {group gT} | H \subset G]. Arguments Scope generated_group [_ group_scope]. Arguments Scope joing_group [_ group_scope group_scope]. Notation "G :&: H" := (setI_group G H) : Group_scope. Notation "<< A >>" := (generated_group A) : Group_scope. Notation "<[ x ] >" := (cycle_group x) : Group_scope. Notation "[ ~: A1 , A2 , .. , An ]" := (commutator_group .. (commutator_group A1 A2) .. An) : Group_scope. Notation "A <*> B" := (joing_group A B) : Group_scope. Notation "G * H" := (joinG G H) : Group_scope. Prenex Implicits joinG. Notation "\prod_ ( i <- r | P ) F" := (\big[joinG/1%G]_(i <- r | P%B) F%G) : Group_scope. Notation "\prod_ ( i <- r ) F" := (\big[joinG/1%G]_(i <- r) F%G) : Group_scope. Notation "\prod_ ( m <= i < n | P ) F" := (\big[joinG/1%G]_(m <= i < n | P%B) F%G) : Group_scope. Notation "\prod_ ( m <= i < n ) F" := (\big[joinG/1%G]_(m <= i < n) F%G) : Group_scope. Notation "\prod_ ( i | P ) F" := (\big[joinG/1%G]_(i | P%B) F%G) : Group_scope. Notation "\prod_ i F" := (\big[joinG/1%G]_i F%G) : Group_scope. Notation "\prod_ ( i : t | P ) F" := (\big[joinG/1%G]_(i : t | P%B) F%G) (only parsing) : Group_scope. Notation "\prod_ ( i : t ) F" := (\big[joinG/1%G]_(i : t) F%G) (only parsing) : Group_scope. Notation "\prod_ ( i < n | P ) F" := (\big[joinG/1%G]_(i < n | P%B) F%G) : Group_scope. Notation "\prod_ ( i < n ) F" := (\big[joinG/1%G]_(i < n) F%G) : Group_scope. Notation "\prod_ ( i 'in' A | P ) F" := (\big[joinG/1%G]_(i in A | P%B) F%G) : Group_scope. Notation "\prod_ ( i 'in' A ) F" := (\big[joinG/1%G]_(i in A) F%G) : Group_scope. Section Lagrange. Variable gT : finGroupType. Implicit Types G H K : {group gT}. Lemma LagrangeI G H : (#|G :&: H| * #|G : H|)%N = #|G|. Proof. rewrite -[#|G|]sum1_card (partition_big_imset (rcoset H)) /=. rewrite mulnC -sum_nat_const; apply: eq_bigr => _ /rcosetsP[x Gx ->]. rewrite -(card_rcoset _ x) -sum1_card; apply: eq_bigl => y. rewrite rcosetE eqEcard mulGS !card_rcoset leqnn andbT. by rewrite group_modr sub1set // inE. Qed. Lemma divgI G H : #|G| %/ #|G :&: H| = #|G : H|. Proof. by rewrite -(LagrangeI G H) mulKn ?cardG_gt0. Qed. Lemma divg_index G H : #|G| %/ #|G : H| = #|G :&: H|. Proof. by rewrite -(LagrangeI G H) mulnK. Qed. Lemma dvdn_indexg G H : #|G : H| %| #|G|. Proof. by rewrite -(LagrangeI G H) dvdn_mull. Qed. Theorem Lagrange G H : H \subset G -> (#|H| * #|G : H|)%N = #|G|. Proof. by move/setIidPr=> sHG; rewrite -{1}sHG LagrangeI. Qed. Lemma cardSg G H : H \subset G -> #|H| %| #|G|. Proof. by move/Lagrange <-; rewrite dvdn_mulr. Qed. Lemma lognSg p G H : G \subset H -> logn p #|G| <= logn p #|H|. Proof. by move=> sGH; rewrite dvdn_leq_log ?cardSg. Qed. Lemma piSg G H : G \subset H -> {subset \pi(gval G) <= \pi(gval H)}. Proof. move=> sGH p; rewrite !mem_primes !cardG_gt0 => /and3P[-> _ pG]. exact: dvdn_trans (cardSg sGH). Qed. Lemma divgS G H : H \subset G -> #|G| %/ #|H| = #|G : H|. Proof. by move/Lagrange <-; rewrite mulKn. Qed. Lemma divg_indexS G H : H \subset G -> #|G| %/ #|G : H| = #|H|. Proof. by move/Lagrange <-; rewrite mulnK. Qed. Lemma coprimeSg G H p : H \subset G -> coprime #|G| p -> coprime #|H| p. Proof. by move=> sHG; exact: coprime_dvdl (cardSg sHG). Qed. Lemma coprimegS G H p : H \subset G -> coprime p #|G| -> coprime p #|H|. Proof. by move=> sHG; exact: coprime_dvdr (cardSg sHG). Qed. Lemma indexJg G H x : #|G :^ x : H :^ x| = #|G : H|. Proof. by rewrite -!divgI -conjIg !cardJg. Qed. Lemma indexgg G : #|G : G| = 1%N. Proof. by rewrite -divgS // divnn cardG_gt0. Qed. Lemma rcosets_id G : rcosets G G = [set G : {set gT}]. Proof. apply/esym/eqP; rewrite eqEcard sub1set [#|_|]indexgg cards1 andbT. by apply/rcosetsP; exists 1; rewrite ?mulg1. Qed. Lemma Lagrange_index G H K : H \subset G -> K \subset H -> (#|G : H| * #|H : K|)%N = #|G : K|. Proof. move=> sHG sKH; apply/eqP; rewrite mulnC -(eqn_pmul2l (cardG_gt0 K)). by rewrite mulnA !Lagrange // (subset_trans sKH). Qed. Lemma indexgI G H : #|G : G :&: H| = #|G : H|. Proof. by rewrite -divgI divgS ?subsetIl. Qed. Lemma indexgS G H K : H \subset K -> #|G : K| %| #|G : H|. Proof. move=> sHK; rewrite -(@dvdn_pmul2l #|G :&: K|) ?cardG_gt0 // LagrangeI. by rewrite -(Lagrange (setIS G sHK)) mulnAC LagrangeI dvdn_mulr. Qed. Lemma indexSg G H K : H \subset K -> K \subset G -> #|K : H| %| #|G : H|. Proof. move=> sHK sKG; rewrite -(@dvdn_pmul2l #|H|) ?cardG_gt0 //. by rewrite !Lagrange ?(cardSg, subset_trans sHK). Qed. Lemma indexg_eq1 G H : (#|G : H| == 1%N) = (G \subset H). Proof. rewrite eqn_leq -(leq_pmul2l (cardG_gt0 (G :&: H))) LagrangeI muln1. by rewrite indexg_gt0 andbT (sameP setIidPl eqP) eqEcard subsetIl. Qed. Lemma indexg_gt1 G H : (#|G : H| > 1) = ~~ (G \subset H). Proof. by rewrite -indexg_eq1 eqn_leq indexg_gt0 andbT -ltnNge. Qed. Lemma index1g G H : H \subset G -> #|G : H| = 1%N -> H :=: G. Proof. by move=> sHG iHG; apply/eqP; rewrite eqEsubset sHG -indexg_eq1 iHG. Qed. Lemma indexg1 G : #|G : 1| = #|G|. Proof. by rewrite -divgS ?sub1G // cards1 divn1. Qed. Lemma indexMg G A : #|G * A : G| = #|A : G|. Proof. congr #|(_ : {set _})|; apply/eqP; rewrite eqEsubset andbC imsetS ?mulG_subr //. by apply/subsetP=> _ /imsetP[x GAx ->]; rewrite rcosetE mem_rcosets. Qed. Lemma rcosets_partition_mul G H : partition (rcosets H G) (H * G). Proof. have eqiR: {in H * G & &, equivalence_rel [rel x y | y \in rcoset H x]}. by move=> *; rewrite /= !rcosetE rcoset_refl; split=> // /rcoset_transl->. congr (partition _ _): (equivalence_partitionP eqiR); apply/setP=> Hx. apply/imsetP/idP=> [[x HGx defHx] | /rcosetsP[x Gx ->]]. suffices ->: Hx = H :* x by rewrite mem_rcosets. apply/setP=> y; rewrite defHx inE /= rcosetE andb_idl //. by apply: subsetP y; rewrite mulGS sub1set. exists (1 * x); rewrite ?mem_mulg // mul1g. apply/setP=> y; rewrite inE /= rcosetE andb_idl //. by apply: subsetP y; rewrite mulgS ?sub1set. Qed. Lemma rcosets_partition G H : H \subset G -> partition (rcosets H G) G. Proof. by move/mulSGid=> {2}<-; exact: rcosets_partition_mul. Qed. Lemma LagrangeMl G H : (#|G| * #|H : G|)%N = #|G * H|. Proof. rewrite mulnC -(card_uniform_partition _ (rcosets_partition_mul H G)) //. by move=> _ /rcosetsP[x Hx ->]; rewrite card_rcoset. Qed. Lemma LagrangeMr G H : (#|G : H| * #|H|)%N = #|G * H|. Proof. by rewrite mulnC LagrangeMl -card_invg invMg !invGid. Qed. Lemma mul_cardG G H : (#|G| * #|H| = #|G * H|%g * #|G :&: H|)%N. Proof. by rewrite -LagrangeMr -(LagrangeI G H) -mulnA mulnC. Qed. Lemma dvdn_cardMg G H : #|G * H| %| #|G| * #|H|. Proof. by rewrite mul_cardG dvdn_mulr. Qed. Lemma cardMg_divn G H : #|G * H| = (#|G| * #|H|) %/ #|G :&: H|. Proof. by rewrite mul_cardG mulnK ?cardG_gt0. Qed. Lemma cardIg_divn G H : #|G :&: H| = (#|G| * #|H|) %/ #|G * H|. Proof. by rewrite mul_cardG mulKn // (cardD1 (1 * 1)) mem_mulg. Qed. Lemma TI_cardMg G H : G :&: H = 1 -> #|G * H| = (#|G| * #|H|)%N. Proof. by move=> tiGH; rewrite mul_cardG tiGH cards1 muln1. Qed. Lemma cardMg_TI G H : #|G| * #|H| <= #|G * H| -> G :&: H = 1. Proof. move=> leGH; apply: card_le1_trivg. rewrite -(@leq_pmul2l #|G * H|); first by rewrite -mul_cardG muln1. by apply: leq_trans leGH; rewrite muln_gt0 !cardG_gt0. Qed. Lemma coprime_TIg G H : coprime #|G| #|H| -> G :&: H = 1. Proof. move=> coGH; apply/eqP; rewrite trivg_card1 -dvdn1 -{}(eqnP coGH). by rewrite dvdn_gcd /= {2}setIC !cardSg ?subsetIl. Qed. Lemma prime_TIg G H : prime #|G| -> ~~ (G \subset H) -> G :&: H = 1. Proof. case/primeP=> _; move/(_ _ (cardSg (subsetIl G H))). rewrite (sameP setIidPl eqP) eqEcard subsetIl -ltnNge ltn_neqAle -trivg_card1. by case/predU1P=> ->. Qed. Lemma prime_meetG G H : prime #|G| -> G :&: H != 1 -> G \subset H. Proof. by move=> prG; apply: contraR; move/prime_TIg->. Qed. Lemma coprime_cardMg G H : coprime #|G| #|H| -> #|G * H| = (#|G| * #|H|)%N. Proof. by move=> coGH; rewrite TI_cardMg ?coprime_TIg. Qed. Lemma coprime_index_mulG G H K : H \subset G -> K \subset G -> coprime #|G : H| #|G : K| -> H * K = G. Proof. move=> sHG sKG co_iG_HK; apply/eqP; rewrite eqEcard mul_subG //=. rewrite -(@leq_pmul2r #|H :&: K|) ?cardG_gt0 // -mul_cardG. rewrite -(Lagrange sHG) -(LagrangeI K H) mulnAC setIC -mulnA. rewrite !leq_pmul2l ?cardG_gt0 // dvdn_leq // -(Gauss_dvdr _ co_iG_HK). by rewrite -(indexgI K) Lagrange_index ?indexgS ?subsetIl ?subsetIr. Qed. End Lagrange. Section GeneratedGroup. Variable gT : finGroupType. Implicit Types x y z : gT. Implicit Types A B C D : {set gT}. Implicit Types G H K : {group gT}. Lemma subset_gen A : A \subset <>. Proof. exact/bigcapsP. Qed. Lemma sub_gen A B : A \subset B -> A \subset <>. Proof. by move/subset_trans=> -> //; exact: subset_gen. Qed. Lemma mem_gen x A : x \in A -> x \in <>. Proof. exact: subsetP (subset_gen A) x. Qed. Lemma generatedP x A : reflect (forall G, A \subset G -> x \in G) (x \in <>). Proof. exact: bigcapP. Qed. Lemma gen_subG A G : (<> \subset G) = (A \subset G). Proof. apply/idP/idP=> [|sAG]; first exact: subset_trans (subset_gen A). by apply/subsetP=> x /generatedP; apply. Qed. Lemma genGid G : <> = G. Proof. by apply/eqP; rewrite eqEsubset gen_subG subset_gen andbT. Qed. Lemma genGidG G : <>%G = G. Proof. by apply: val_inj; exact: genGid. Qed. Lemma gen_set_id A : group_set A -> <> = A. Proof. by move=> gA; exact: (genGid (group gA)). Qed. Lemma genS A B : A \subset B -> <> \subset <>. Proof. by move=> sAB; rewrite gen_subG sub_gen. Qed. Lemma gen0 : <> = 1 :> {set gT}. Proof. by apply/eqP; rewrite eqEsubset sub1G gen_subG sub0set. Qed. Lemma gen_expgs A : {n | <> = (1 |: A) ^+ n}. Proof. set B := (1 |: A); pose N := #|gT|. have BsubG n : B ^+ n \subset <>. by elim: n => [|n IHn]; rewrite ?expgS ?mul_subG ?subUset ?sub1G ?subset_gen. have B_1 n : 1 \in B ^+ n. by elim: n => [|n IHn]; rewrite ?set11 // expgS mulUg mul1g inE IHn. case: (pickP (fun i : 'I_N => B ^+ i.+1 \subset B ^+ i)) => [n fixBn | no_fix]. exists n; apply/eqP; rewrite eqEsubset BsubG andbT. rewrite -[B ^+ n]gen_set_id ?genS ?subsetUr //. by apply: subset_trans fixBn; rewrite expgS mulUg subsetU ?mulg_subl ?orbT. rewrite /group_set B_1 /=. elim: {2}(n : nat) => [|m IHm]; first by rewrite mulg1. by apply: subset_trans fixBn; rewrite !expgSr mulgA mulSg. suffices: N < #|B ^+ N| by rewrite ltnNge max_card. elim: {-2}N (leqnn N) => [|n IHn] lt_nN; first by rewrite cards1. apply: leq_ltn_trans (IHn (ltnW lt_nN)) (proper_card _). by rewrite /proper (no_fix (Ordinal lt_nN)) expgS mulUg mul1g subsetUl. Qed. Lemma gen_prodgP A x : reflect (exists n, exists2 c, forall i : 'I_n, c i \in A & x = \prod_i c i) (x \in <>). Proof. apply: (iffP idP) => [|[n [c Ac ->]]]; last first. by apply: group_prod => i _; rewrite mem_gen ?Ac. have [n ->] := gen_expgs A; rewrite /expgn /expgn_rec Monoid.iteropE. have ->: n = count 'I_n (index_enum _). by rewrite -size_filter filter_index_enum -cardT card_ord. rewrite -big_const_seq; case/prodsgP=> /= c Ac def_x. have{Ac def_x} ->: x = \prod_(i | c i \in A) c i. rewrite big_mkcond {x}def_x; apply: eq_bigr => i _. by case/setU1P: (Ac i isT) => -> //; rewrite if_same. rewrite -big_filter; set e := filter _ _; case def_e: e => [|i e']. by exists 0; exists (fun _ => 1) => [[] // |]; rewrite big_nil big_ord0. rewrite -{e'}def_e (big_nth i) big_mkord. exists (size e); exists (c \o nth i e \o val) => // j /=. have: nth i e j \in e by rewrite mem_nth. by rewrite mem_filter; case/andP. Qed. Lemma genD A B : A \subset <> -> <> = <>. Proof. by move=> sAB; apply/eqP; rewrite eqEsubset genS (subsetDl, gen_subG). Qed. Lemma genV A : <> = <>. Proof. apply/eqP; rewrite eqEsubset !gen_subG -!(invSg _ <<_>>) invgK. by rewrite !invGid !subset_gen. Qed. Lemma genJ A z : <> = <> :^ z. Proof. by apply/eqP; rewrite eqEsubset sub_conjg !gen_subG conjSg -?sub_conjg !sub_gen. Qed. Lemma conjYg A B z : (A <*> B) :^z = A :^ z <*> B :^ z. Proof. by rewrite -genJ conjUg. Qed. Lemma genD1 A x : x \in <> -> <> = <>. Proof. move=> gA'x; apply/eqP; rewrite eqEsubset genS; last by rewrite subsetDl. rewrite gen_subG; apply/subsetP=> y Ay. by case: (y =P x) => [-> //|]; move/eqP=> nyx; rewrite mem_gen // !inE nyx. Qed. Lemma genD1id A : <> = <>. Proof. by rewrite genD1 ?group1. Qed. Notation joingT := (@joing gT) (only parsing). Notation joinGT := (@joinG gT) (only parsing). Lemma joingE A B : A <*> B = <>. Proof. by []. Qed. Lemma joinGE G H : (G * H)%G = (G <*> H)%G. Proof. by []. Qed. Lemma joingC : commutative joingT. Proof. by move=> A B; rewrite /joing setUC. Qed. Lemma joing_idr A B : A <*> <> = A <*> B. Proof. apply/eqP; rewrite eqEsubset gen_subG subUset gen_subG /=. by rewrite -subUset subset_gen genS // setUS // subset_gen. Qed. Lemma joing_idl A B : <> <*> B = A <*> B. Proof. by rewrite -!(joingC B) joing_idr. Qed. Lemma joing_subl A B : A \subset A <*> B. Proof. by rewrite sub_gen ?subsetUl. Qed. Lemma joing_subr A B : B \subset A <*> B. Proof. by rewrite sub_gen ?subsetUr. Qed. Lemma join_subG A B G : (A <*> B \subset G) = (A \subset G) && (B \subset G). Proof. by rewrite gen_subG subUset. Qed. Lemma joing_idPl G A : reflect (G <*> A = G) (A \subset G). Proof. apply: (iffP idP) => [sHG | <-]; last by rewrite joing_subr. by rewrite joingE (setUidPl sHG) genGid. Qed. Lemma joing_idPr A G : reflect (A <*> G = G) (A \subset G). Proof. by rewrite joingC; exact: joing_idPl. Qed. Lemma joing_subP A B G : reflect (A \subset G /\ B \subset G) (A <*> B \subset G). Proof. by rewrite join_subG; exact: andP. Qed. Lemma joing_sub A B C : A <*> B = C -> A \subset C /\ B \subset C. Proof. by move <-; exact/joing_subP. Qed. Lemma genDU A B C : A \subset C -> <> = <> -> <> = <>. Proof. move=> sAC; rewrite -joingE -joing_idr => <- {B}; rewrite joing_idr. by congr <<_>>; rewrite setDE setUIr setUCr setIT; exact/setUidPr. Qed. Lemma joingA : associative joingT. Proof. by move=> A B C; rewrite joing_idl joing_idr /joing setUA. Qed. Lemma joing1G G : 1 <*> G = G. Proof. by rewrite -gen0 joing_idl /joing set0U genGid. Qed. Lemma joingG1 G : G <*> 1 = G. Proof. by rewrite joingC joing1G. Qed. Lemma genM_join G H : <> = G <*> H. Proof. apply/eqP; rewrite eqEsubset gen_subG /= -{1}[G <*> H]mulGid. rewrite genS; last by rewrite subUset mulG_subl mulG_subr. by rewrite mulgSS ?(sub_gen, subsetUl, subsetUr). Qed. Lemma mulG_subG G H K : (G * H \subset K) = (G \subset K) && (H \subset K). Proof. by rewrite -gen_subG genM_join join_subG. Qed. Lemma mulGsubP K H G : reflect (K \subset G /\ H \subset G) (K * H \subset G). Proof. by rewrite mulG_subG; exact: andP. Qed. Lemma mulG_sub K H A : K * H = A -> K \subset A /\ H \subset A. Proof. by move <-; rewrite mulG_subl mulG_subr. Qed. Lemma trivMg G H : (G * H == 1) = (G :==: 1) && (H :==: 1). Proof. by rewrite !eqEsubset -{2}[1]mulGid mulgSS ?sub1G // !andbT mulG_subG. Qed. Lemma comm_joingE G H : commute G H -> G <*> H = G * H. Proof. by move/comm_group_setP=> gGH; rewrite -genM_join; exact: (genGid (group gGH)). Qed. Lemma joinGC : commutative joinGT. Proof. by move=> G H; apply: val_inj; exact: joingC. Qed. Lemma joinGA : associative joinGT. Proof. by move=> G H K; apply: val_inj; exact: joingA. Qed. Lemma join1G : left_id 1%G joinGT. Proof. by move=> G; apply: val_inj; exact: joing1G. Qed. Lemma joinG1 : right_id 1%G joinGT. Proof. by move=> G; apply: val_inj; exact: joingG1. Qed. Canonical joinG_law := Monoid.Law joinGA join1G joinG1. Canonical joinG_abelaw := Monoid.ComLaw joinGC. Lemma bigprodGEgen I r (P : pred I) (F : I -> {set gT}) : (\prod_(i <- r | P i) <>)%G :=: << \bigcup_(i <- r | P i) F i >>. Proof. elim/big_rec2: _ => /= [|i A _ _ ->]; first by rewrite gen0. by rewrite joing_idl joing_idr. Qed. Lemma bigprodGE I r (P : pred I) (F : I -> {group gT}) : (\prod_(i <- r | P i) F i)%G :=: << \bigcup_(i <- r | P i) F i >>. Proof. rewrite -bigprodGEgen /=; apply: congr_group. by apply: eq_bigr => i _; rewrite genGidG. Qed. Lemma mem_commg A B x y : x \in A -> y \in B -> [~ x, y] \in [~: A, B]. Proof. by move=> Ax By; rewrite mem_gen ?mem_imset2. Qed. Lemma commSg A B C : A \subset B -> [~: A, C] \subset [~: B, C]. Proof. by move=> sAC; rewrite genS ?imset2S. Qed. Lemma commgS A B C : B \subset C -> [~: A, B] \subset [~: A, C]. Proof. by move=> sBC; rewrite genS ?imset2S. Qed. Lemma commgSS A B C D : A \subset B -> C \subset D -> [~: A, C] \subset [~: B, D]. Proof. by move=> sAB sCD; rewrite genS ?imset2S. Qed. Lemma der1_subG G : [~: G, G] \subset G. Proof. by rewrite gen_subG; apply/subsetP=> _ /imset2P[x y Gx Gy ->]; exact: groupR. Qed. Lemma comm_subG A B G : A \subset G -> B \subset G -> [~: A, B] \subset G. Proof. by move=> sAG sBG; apply: subset_trans (der1_subG G); exact: commgSS. Qed. Lemma commGC A B : [~: A, B] = [~: B, A]. Proof. rewrite -[[~: A, B]]genV; congr <<_>>; apply/setP=> z; rewrite inE. by apply/imset2P/imset2P=> [] [x y Ax Ay]; last rewrite -{1}(invgK z); rewrite -invg_comm => /invg_inj->; exists y x. Qed. Lemma conjsRg A B x : [~: A, B] :^ x = [~: A :^ x, B :^ x]. Proof. wlog suffices: A B x / [~: A, B] :^ x \subset [~: A :^ x, B :^ x]. move=> subJ; apply/eqP; rewrite eqEsubset subJ /= -sub_conjgV. by rewrite -{2}(conjsgK x A) -{2}(conjsgK x B). rewrite -genJ gen_subG; apply/subsetP=> _ /imsetP[_ /imset2P[y z Ay Bz ->] ->]. by rewrite conjRg mem_commg ?memJ_conjg. Qed. End GeneratedGroup. Implicit Arguments gen_prodgP [gT A x]. Implicit Arguments joing_idPl [gT G A]. Implicit Arguments joing_idPr [gT A G]. Implicit Arguments mulGsubP [gT K H G]. Implicit Arguments joing_subP [gT A B G]. Section Cycles. (* Elementary properties of cycles and order, needed in perm.v. *) (* More advanced results on the structure of cyclic groups will *) (* be given in cyclic.v. *) Variable gT : finGroupType. Implicit Types x y : gT. Implicit Types G : {group gT}. Import Monoid.Theory. Lemma cycle1 : <[1]> = [1 gT]. Proof. exact: genGid. Qed. Lemma order1 : #[1 : gT] = 1%N. Proof. by rewrite /order cycle1 cards1. Qed. Lemma cycle_id x : x \in <[x]>. Proof. by rewrite mem_gen // set11. Qed. Lemma mem_cycle x i : x ^+ i \in <[x]>. Proof. by rewrite groupX // cycle_id. Qed. Lemma cycle_subG x G : (<[x]> \subset G) = (x \in G). Proof. by rewrite gen_subG sub1set. Qed. Lemma cycle_eq1 x : (<[x]> == 1) = (x == 1). Proof. by rewrite eqEsubset sub1G andbT cycle_subG inE. Qed. Lemma orderE x : #[x] = #|<[x]>|. Proof. by []. Qed. Lemma order_eq1 x : (#[x] == 1%N) = (x == 1). Proof. by rewrite -trivg_card1 cycle_eq1. Qed. Lemma order_gt1 x : (#[x] > 1) = (x != 1). Proof. by rewrite ltnNge -trivg_card_le1 cycle_eq1. Qed. Lemma cycle_traject x : <[x]> =i traject (mulg x) 1 #[x]. Proof. set t := _ 1; apply: fsym; apply/subset_cardP; last first. by apply/subsetP=> _ /trajectP[i _ ->]; rewrite -iteropE mem_cycle. rewrite (card_uniqP _) ?size_traject //; case def_n: #[_] => // [n]. rewrite looping_uniq; apply: contraL (card_size (t n)) => /loopingP t_xi. rewrite -ltnNge size_traject -def_n ?subset_leq_card //. rewrite -(eq_subset_r (in_set _)) {}/t; set G := finset _. rewrite -[x]mulg1 -[G]gen_set_id ?genS ?sub1set ?inE ?(t_xi 1%N)//. apply/group_setP; split=> [|y z]; rewrite !inE ?(t_xi 0) //. by do 2!case/trajectP=> ? _ ->; rewrite -!iteropE -expgD [x ^+ _]iteropE. Qed. Lemma cycle2g x : #[x] = 2 -> <[x]> = [set 1; x]. Proof. by move=> ox; apply/setP=> y; rewrite cycle_traject ox !inE mulg1. Qed. Lemma cyclePmin x y : y \in <[x]> -> {i | i < #[x] & y = x ^+ i}. Proof. rewrite cycle_traject; set tx := traject _ _ #[x] => tx_y; pose i := index y tx. have lt_i_x : i < #[x] by rewrite -index_mem size_traject in tx_y. by exists i; rewrite // [x ^+ i]iteropE /= -(nth_traject _ lt_i_x) nth_index. Qed. Lemma cycleP x y : reflect (exists i, y = x ^+ i) (y \in <[x]>). Proof. by apply: (iffP idP) => [/cyclePmin[i _]|[i ->]]; [exists i | exact: mem_cycle]. Qed. Lemma expg_order x : x ^+ #[x] = 1. Proof. have: uniq (traject (mulg x) 1 #[x]). by apply/card_uniqP; rewrite size_traject -(eq_card (cycle_traject x)). case/cyclePmin: (mem_cycle x #[x]) => [] [//|i] ltix. rewrite -(subnKC ltix) addSnnS /= expgD; move: (_ - _) => j x_j1. case/andP=> /trajectP[]; exists j; first exact: leq_addl. by apply: (mulgI (x ^+ i.+1)); rewrite -iterSr iterS -iteropE -expgS mulg1. Qed. Lemma expg_mod p k x : x ^+ p = 1 -> x ^+ (k %% p) = x ^+ k. Proof. move=> xp. by rewrite {2}(divn_eq k p) expgD mulnC expgM xp expg1n mul1g. Qed. Lemma expg_mod_order x i : x ^+ (i %% #[x]) = x ^+ i. Proof. by rewrite expg_mod // expg_order. Qed. Lemma invg_expg x : x^-1 = x ^+ #[x].-1. Proof. by apply/eqP; rewrite eq_invg_mul -expgS prednK ?expg_order. Qed. Lemma invg2id x : #[x] = 2 -> x^-1 = x. Proof. by move=> ox; rewrite invg_expg ox. Qed. Lemma cycleX x i : <[x ^+ i]> \subset <[x]>. Proof. rewrite cycle_subG; exact: mem_cycle. Qed. Lemma cycleV x : <[x^-1]> = <[x]>. Proof. by apply/eqP; rewrite eq_sym eqEsubset !cycle_subG groupV -groupV !cycle_id. Qed. Lemma orderV x : #[x^-1] = #[x]. Proof. by rewrite /order cycleV. Qed. Lemma cycleJ x y : <[x ^ y]> = <[x]> :^ y. Proof. by rewrite -genJ conjg_set1. Qed. Lemma orderJ x y : #[x ^ y] = #[x]. Proof. by rewrite /order cycleJ cardJg. Qed. End Cycles. Section Normaliser. Variable gT : finGroupType. Implicit Types x y z : gT. Implicit Types A B C D : {set gT}. Implicit Type G H K : {group gT}. Lemma normP x A : reflect (A :^ x = A) (x \in 'N(A)). Proof. suffices ->: (x \in 'N(A)) = (A :^ x == A) by exact: eqP. by rewrite eqEcard cardJg leqnn andbT inE. Qed. Implicit Arguments normP [x A]. Lemma group_set_normaliser A : group_set 'N(A). Proof. apply/group_setP; split=> [|x y Nx Ny]; rewrite inE ?conjsg1 //. by rewrite conjsgM !(normP _). Qed. Canonical normaliser_group A := group (group_set_normaliser A). Lemma normsP A B : reflect {in A, normalised B} (A \subset 'N(B)). Proof. apply: (iffP subsetP) => nBA x Ax; last by rewrite inE nBA //. by apply/normP; exact: nBA. Qed. Implicit Arguments normsP [A B]. Lemma memJ_norm x y A : x \in 'N(A) -> (y ^ x \in A) = (y \in A). Proof. by move=> Nx; rewrite -{1}(normP Nx) memJ_conjg. Qed. Lemma norms_cycle x y : (<[y]> \subset 'N(<[x]>)) = (x ^ y \in <[x]>). Proof. by rewrite cycle_subG inE -cycleJ cycle_subG. Qed. Lemma norm1 : 'N(1) = setT :> {set gT}. Proof. by apply/setP=> x; rewrite !inE conjs1g subxx. Qed. Lemma norms1 A : A \subset 'N(1). Proof. by rewrite norm1 subsetT. Qed. Lemma normCs A : 'N(~: A) = 'N(A). Proof. by apply/setP=> x; rewrite -groupV !inE conjCg setCS sub_conjg. Qed. Lemma normG G : G \subset 'N(G). Proof. by apply/normsP; exact: conjGid. Qed. Lemma normT : 'N([set: gT]) = [set: gT]. Proof. by apply/eqP; rewrite -subTset normG. Qed. Lemma normsG A G : A \subset G -> A \subset 'N(G). Proof. move=> sAG; exact: subset_trans (normG G). Qed. Lemma normC A B : A \subset 'N(B) -> commute A B. Proof. move/subsetP=> nBA; apply/setP=> u. apply/mulsgP/mulsgP=> [[x y Ax By] | [y x By Ax]] -> {u}. by exists (y ^ x^-1) x; rewrite -?conjgCV // memJ_norm // groupV nBA. by exists x (y ^ x); rewrite -?conjgC // memJ_norm // nBA. Qed. Lemma norm_joinEl G H : G \subset 'N(H) -> G <*> H = G * H. Proof. by move/normC/comm_joingE. Qed. Lemma norm_joinEr G H : H \subset 'N(G) -> G <*> H = G * H. Proof. by move/normC=> cHG; exact: comm_joingE. Qed. Lemma norm_rlcoset G x : x \in 'N(G) -> G :* x = x *: G. Proof. by rewrite -sub1set => /normC. Qed. Lemma rcoset_mul G x y : x \in 'N(G) -> (G :* x) * (G :* y) = G :* (x * y). Proof. move/norm_rlcoset=> GxxG. by rewrite mulgA -(mulgA _ _ G) -GxxG mulgA mulGid -mulgA mulg_set1. Qed. Lemma normJ A x : 'N(A :^ x) = 'N(A) :^ x. Proof. by apply/setP=> y; rewrite mem_conjg !inE -conjsgM conjgCV conjsgM conjSg. Qed. Lemma norm_conj_norm x A B : x \in 'N(A) -> (A \subset 'N(B :^ x)) = (A \subset 'N(B)). Proof. by move=> Nx; rewrite normJ -sub_conjgV (normP _) ?groupV. Qed. Lemma norm_gen A : 'N(A) \subset 'N(<>). Proof. by apply/normsP=> x Nx; rewrite -genJ (normP Nx). Qed. Lemma class_norm x G : G \subset 'N(x ^: G). Proof. by apply/normsP=> y; exact: classGidr. Qed. Lemma class_normal x G : x \in G -> x ^: G <| G. Proof. by move=> Gx; rewrite /normal class_norm class_subG. Qed. Lemma class_sub_norm G A x : G \subset 'N(A) -> (x ^: G \subset A) = (x \in A). Proof. move=> nAG; apply/subsetP/idP=> [-> // | Ax xy]; first exact: class_refl. by case/imsetP=> y Gy ->; rewrite memJ_norm ?(subsetP nAG). Qed. Lemma class_support_norm A G : G \subset 'N(class_support A G). Proof. by apply/normsP; exact: class_supportGidr. Qed. Lemma class_support_sub_norm A B G : A \subset G -> B \subset 'N(G) -> class_support A B \subset G. Proof. move=> sAG nGB; rewrite class_supportEr. by apply/bigcupsP=> x Bx; rewrite -(normsP nGB x Bx) conjSg. Qed. Section norm_trans. Variables (A B C D : {set gT}). Hypotheses (nBA : A \subset 'N(B)) (nCA : A \subset 'N(C)). Lemma norms_gen : A \subset 'N(<>). Proof. exact: subset_trans nBA (norm_gen B). Qed. Lemma norms_norm : A \subset 'N('N(B)). Proof. by apply/normsP=> x Ax; rewrite -normJ (normsP nBA). Qed. Lemma normsI : A \subset 'N(B :&: C). Proof. by apply/normsP=> x Ax; rewrite conjIg !(normsP _ x Ax). Qed. Lemma normsU : A \subset 'N(B :|: C). Proof. by apply/normsP=> x Ax; rewrite conjUg !(normsP _ x Ax). Qed. Lemma normsIs : B \subset 'N(D) -> A :&: B \subset 'N(C :&: D). Proof. move/normsP=> nDB; apply/normsP=> x; case/setIP=> Ax Bx. by rewrite conjIg (normsP nCA) ?nDB. Qed. Lemma normsD : A \subset 'N(B :\: C). Proof. by apply/normsP=> x Ax; rewrite conjDg !(normsP _ x Ax). Qed. Lemma normsM : A \subset 'N(B * C). Proof. by apply/normsP=> x Ax; rewrite conjsMg !(normsP _ x Ax). Qed. Lemma normsY : A \subset 'N(B <*> C). Proof. by apply/normsP=> x Ax; rewrite -genJ conjUg !(normsP _ x Ax). Qed. Lemma normsR : A \subset 'N([~: B, C]). Proof. by apply/normsP=> x Ax; rewrite conjsRg !(normsP _ x Ax). Qed. Lemma norms_class_support : A \subset 'N(class_support B C). Proof. apply/subsetP=> x Ax; rewrite inE sub_conjg class_supportEr. apply/bigcupsP=> y Cy; rewrite -sub_conjg -conjsgM conjgC conjsgM. by rewrite (normsP nBA) // bigcup_sup ?memJ_norm ?(subsetP nCA). Qed. End norm_trans. Lemma normsIG A B G : A \subset 'N(B) -> A :&: G \subset 'N(B :&: G). Proof. by move/normsIs->; rewrite ?normG. Qed. Lemma normsGI A B G : A \subset 'N(B) -> G :&: A \subset 'N(G :&: B). Proof. by move=> nBA; rewrite !(setIC G) normsIG. Qed. Lemma norms_bigcap I r (P : pred I) A (B_ : I -> {set gT}) : A \subset \bigcap_(i <- r | P i) 'N(B_ i) -> A \subset 'N(\bigcap_(i <- r | P i) B_ i). Proof. elim/big_rec2: _ => [|i B N _ IH /subsetIP[nBiA /IH]]; last exact: normsI. by rewrite normT. Qed. Lemma norms_bigcup I r (P : pred I) A (B_ : I -> {set gT}) : A \subset \bigcap_(i <- r | P i) 'N(B_ i) -> A \subset 'N(\bigcup_(i <- r | P i) B_ i). Proof. move=> nBA; rewrite -normCs setC_bigcup norms_bigcap //. by rewrite (eq_bigr _ (fun _ _ => normCs _)). Qed. Lemma normsD1 A B : A \subset 'N(B) -> A \subset 'N(B^#). Proof. by move/normsD->; rewrite ?norms1. Qed. Lemma normD1 A : 'N(A^#) = 'N(A). Proof. apply/eqP; rewrite eqEsubset normsD1 //. rewrite -{2}(setID A 1) setIC normsU //; apply/normsP=> x _; apply/setP=> y. by rewrite conjIg conjs1g !inE mem_conjg; case: eqP => // ->; rewrite conj1g. Qed. Lemma normalP A B : reflect (A \subset B /\ {in B, normalised A}) (A <| B). Proof. by apply: (iffP andP)=> [] [sAB]; move/normsP. Qed. Lemma normal_sub A B : A <| B -> A \subset B. Proof. by case/andP. Qed. Lemma normal_norm A B : A <| B -> B \subset 'N(A). Proof. by case/andP. Qed. Lemma normalS G H K : K \subset H -> H \subset G -> K <| G -> K <| H. Proof. by move=> sKH sHG /andP[_ nKG]; rewrite /(K <| _) sKH (subset_trans sHG). Qed. Lemma normal1 G : 1 <| G. Proof. by rewrite /normal sub1set group1 norms1. Qed. Lemma normal_refl G : G <| G. Proof. by rewrite /(G <| _) normG subxx. Qed. Lemma normalG G : G <| 'N(G). Proof. by rewrite /(G <| _) normG subxx. Qed. Lemma normalSG G H : H \subset G -> H <| 'N_G(H). Proof. by move=> sHG; rewrite /normal subsetI sHG normG subsetIr. Qed. Lemma normalJ A B x : (A :^ x <| B :^ x) = (A <| B). Proof. by rewrite /normal normJ !conjSg. Qed. Lemma normalM G A B : A <| G -> B <| G -> A * B <| G. Proof. by case/andP=> sAG nAG /andP[sBG nBG]; rewrite /normal mul_subG ?normsM. Qed. Lemma normalY G A B : A <| G -> B <| G -> A <*> B <| G. Proof. by case/andP=> sAG ? /andP[sBG ?]; rewrite /normal join_subG sAG sBG ?normsY. Qed. Lemma normalYl G H : (H <| H <*> G) = (G \subset 'N(H)). Proof. by rewrite /normal joing_subl join_subG normG. Qed. Lemma normalYr G H : (H <| G <*> H) = (G \subset 'N(H)). Proof. by rewrite joingC normalYl. Qed. Lemma normalI G A B : A <| G -> B <| G -> A :&: B <| G. Proof. by case/andP=> sAG nAG /andP[_ nBG]; rewrite /normal subIset ?sAG // normsI. Qed. Lemma norm_normalI G A : G \subset 'N(A) -> G :&: A <| G. Proof. by move=> nAG; rewrite /normal subsetIl normsI ?normG. Qed. Lemma normalGI G H A : H \subset G -> A <| G -> H :&: A <| H. Proof. by move=> sHG /andP[_ nAG]; exact: norm_normalI (subset_trans sHG nAG). Qed. Lemma normal_subnorm G H : (H <| 'N_G(H)) = (H \subset G). Proof. by rewrite /normal subsetIr subsetI normG !andbT. Qed. Lemma normalD1 A G : (A^# <| G) = (A <| G). Proof. by rewrite /normal normD1 subDset (setUidPr (sub1G G)). Qed. Lemma gcore_sub A G : gcore A G \subset A. Proof. by rewrite (bigcap_min 1) ?conjsg1. Qed. Lemma gcore_norm A G : G \subset 'N(gcore A G). Proof. apply/subsetP=> x Gx; rewrite inE; apply/bigcapsP=> y Gy. by rewrite sub_conjg -conjsgM bigcap_inf ?groupM ?groupV. Qed. Lemma gcore_normal A G : A \subset G -> gcore A G <| G. Proof. by move=> sAG; rewrite /normal gcore_norm (subset_trans (gcore_sub A G)). Qed. Lemma gcore_max A B G : B \subset A -> G \subset 'N(B) -> B \subset gcore A G. Proof. move=> sBA nBG; apply/bigcapsP=> y Gy. by rewrite -sub_conjgV (normsP nBG) ?groupV. Qed. Lemma sub_gcore A B G : G \subset 'N(B) -> (B \subset gcore A G) = (B \subset A). Proof. move=> nBG; apply/idP/idP=> [sBAG | sBA]; last exact: gcore_max. exact: subset_trans (gcore_sub A G). Qed. (* An elementary proof that subgroups of index 2 are normal; it is almost as *) (* short as the "advanced" proof using group actions; besides, the fact that *) (* the coset is equal to the complement is used in extremal.v. *) Lemma rcoset_index2 G H x : H \subset G -> #|G : H| = 2 -> x \in G :\: H -> H :* x = G :\: H. Proof. move=> sHG indexHG => /setDP[Gx notHx]; apply/eqP. rewrite eqEcard -(leq_add2l #|G :&: H|) cardsID -(LagrangeI G H) indexHG muln2. rewrite (setIidPr sHG) card_rcoset addnn leqnn andbT. apply/subsetP=> _ /rcosetP[y Hy ->]; apply/setDP. by rewrite !groupMl // (subsetP sHG). Qed. Lemma index2_normal G H : H \subset G -> #|G : H| = 2 -> H <| G. Proof. move=> sHG indexHG; rewrite /normal sHG; apply/subsetP=> x Gx. case Hx: (x \in H); first by rewrite inE conjGid. rewrite inE conjsgE mulgA -sub_rcosetV -invg_rcoset. by rewrite !(rcoset_index2 sHG) ?inE ?groupV ?Hx // invDg !invGid. Qed. Lemma cent1P x y : reflect (commute x y) (x \in 'C[y]). Proof. rewrite inE conjg_set1 sub1set inE (sameP eqP conjg_fixP)commg1_sym. exact: commgP. Qed. Lemma cent1id x : x \in 'C[x]. Proof. exact/cent1P. Qed. Lemma cent1E x y : (x \in 'C[y]) = (x * y == y * x). Proof. by rewrite (sameP (cent1P x y) eqP). Qed. Lemma cent1C x y : (x \in 'C[y]) = (y \in 'C[x]). Proof. by rewrite !cent1E eq_sym. Qed. Canonical centraliser_group A : {group _} := Eval hnf in [group of 'C(A)]. Lemma cent_set1 x : 'C([set x]) = 'C[x]. Proof. by apply: big_pred1 => y /=; rewrite inE. Qed. Lemma cent1J x y : 'C[x ^ y] = 'C[x] :^ y. Proof. by rewrite -conjg_set1 normJ. Qed. Lemma centP A x : reflect (centralises x A) (x \in 'C(A)). Proof. by apply: (iffP bigcapP) => cxA y /cxA/cent1P. Qed. Lemma centsP A B : reflect {in A, centralised B} (A \subset 'C(B)). Proof. by apply: (iffP subsetP) => cAB x /cAB/centP. Qed. Lemma centsC A B : (A \subset 'C(B)) = (B \subset 'C(A)). Proof. by apply/centsP/centsP=> cAB x ? y ?; rewrite /commute -cAB. Qed. Lemma cents1 A : A \subset 'C(1). Proof. by rewrite centsC sub1G. Qed. Lemma cent1T : 'C(1) = setT :> {set gT}. Proof. by apply/eqP; rewrite -subTset cents1. Qed. Lemma cent11T : 'C[1] = setT :> {set gT}. Proof. by rewrite -cent_set1 cent1T. Qed. Lemma cent_sub A : 'C(A) \subset 'N(A). Proof. apply/subsetP=> x /centP cAx; rewrite inE. by apply/subsetP=> _ /imsetP[y Ay ->]; rewrite /conjg -cAx ?mulKg. Qed. Lemma cents_norm A B : A \subset 'C(B) -> A \subset 'N(B). Proof. by move=> cAB; exact: subset_trans (cent_sub B). Qed. Lemma centC A B : A \subset 'C(B) -> commute A B. Proof. by move=> cAB; exact: normC (cents_norm cAB). Qed. Lemma cent_joinEl G H : G \subset 'C(H) -> G <*> H = G * H. Proof. by move=> cGH; exact: norm_joinEl (cents_norm cGH). Qed. Lemma cent_joinEr G H : H \subset 'C(G) -> G <*> H = G * H. Proof. by move=> cGH; exact: norm_joinEr (cents_norm cGH). Qed. Lemma centJ A x : 'C(A :^ x) = 'C(A) :^ x. Proof. apply/setP=> y; rewrite mem_conjg; apply/centP/centP=> cAy z Az. by apply: (conjg_inj x); rewrite 2!conjMg conjgKV cAy ?memJ_conjg. by apply: (conjg_inj x^-1); rewrite 2!conjMg cAy -?mem_conjg. Qed. Lemma cent_norm A : 'N(A) \subset 'N('C(A)). Proof. by apply/normsP=> x nCx; rewrite -centJ (normP nCx). Qed. Lemma norms_cent A B : A \subset 'N(B) -> A \subset 'N('C(B)). Proof. move=> nBA; exact: subset_trans nBA (cent_norm B). Qed. Lemma cent_normal A : 'C(A) <| 'N(A). Proof. by rewrite /(_ <| _) cent_sub cent_norm. Qed. Lemma centS A B : B \subset A -> 'C(A) \subset 'C(B). Proof. by move=> sAB; rewrite centsC (subset_trans sAB) 1?centsC. Qed. Lemma centsS A B C : A \subset B -> C \subset 'C(B) -> C \subset 'C(A). Proof. by move=> sAB cCB; exact: subset_trans cCB (centS sAB). Qed. Lemma centSS A B C D : A \subset C -> B \subset D -> C \subset 'C(D) -> A \subset 'C(B). Proof. move=> sAC sBD cCD; exact: subset_trans (centsS sBD cCD). Qed. Lemma centI A B : 'C(A) <*> 'C(B) \subset 'C(A :&: B). Proof. by rewrite gen_subG subUset !centS ?(subsetIl, subsetIr). Qed. Lemma centU A B : 'C(A :|: B) = 'C(A) :&: 'C(B). Proof. apply/eqP; rewrite eqEsubset subsetI 2?centS ?(subsetUl, subsetUr) //=. by rewrite centsC subUset -centsC subsetIl -centsC subsetIr. Qed. Lemma cent_gen A : 'C(<>) = 'C(A). Proof. by apply/setP=> x; rewrite -!sub1set centsC gen_subG centsC. Qed. Lemma cent_cycle x : 'C(<[x]>) = 'C[x]. Proof. by rewrite cent_gen cent_set1. Qed. Lemma sub_cent1 A x : (A \subset 'C[x]) = (x \in 'C(A)). Proof. by rewrite -cent_cycle centsC cycle_subG. Qed. Lemma cents_cycle x y : commute x y -> <[x]> \subset 'C(<[y]>). Proof. move=> cxy; rewrite cent_cycle cycle_subG; exact/cent1P. Qed. Lemma cycle_abelian x : abelian <[x]>. Proof. exact: cents_cycle. Qed. Lemma centY A B : 'C(A <*> B) = 'C(A) :&: 'C(B). Proof. by rewrite cent_gen centU. Qed. Lemma centM G H : 'C(G * H) = 'C(G) :&: 'C(H). Proof. by rewrite -cent_gen genM_join centY. Qed. Lemma cent_classP x G : reflect (x ^: G = [set x]) (x \in 'C(G)). Proof. apply: (iffP (centP _ _)) => [Cx | Cx1 y Gy]. apply/eqP; rewrite eqEsubset sub1set class_refl andbT. by apply/subsetP=> _ /imsetP[y Gy ->]; rewrite inE conjgE Cx ?mulKg. by apply/commgP/conjg_fixP/set1P; rewrite -Cx1; apply/imsetP; exists y. Qed. Lemma commG1P A B : reflect ([~: A, B] = 1) (A \subset 'C(B)). Proof. apply: (iffP (centsP A B)) => [cAB | cAB1 x Ax y By]. apply/trivgP; rewrite gen_subG; apply/subsetP=> _ /imset2P[x y Ax Ay ->]. by rewrite inE; apply/commgP; exact: cAB. by apply/commgP; rewrite -in_set1 -[[set 1]]cAB1 mem_commg. Qed. Lemma abelianE A : abelian A = (A \subset 'C(A)). Proof. by []. Qed. Lemma abelian1 : abelian [1 gT]. Proof. exact: sub1G. Qed. Lemma abelianS A B : A \subset B -> abelian B -> abelian A. Proof. by move=> sAB; exact: centSS. Qed. Lemma abelianJ A x : abelian (A :^ x) = abelian A. Proof. by rewrite /abelian centJ conjSg. Qed. Lemma abelian_gen A : abelian <> = abelian A. Proof. by rewrite /abelian cent_gen gen_subG. Qed. Lemma abelianY A B : abelian (A <*> B) = [&& abelian A, abelian B & B \subset 'C(A)]. Proof. rewrite /abelian join_subG /= centY !subsetI -!andbA; congr (_ && _). by rewrite centsC andbA andbb andbC. Qed. Lemma abelianM G H : abelian (G * H) = [&& abelian G, abelian H & H \subset 'C(G)]. Proof. by rewrite -abelian_gen genM_join abelianY. Qed. Section SubAbelian. Variable A B C : {set gT}. Hypothesis cAA : abelian A. Lemma sub_abelian_cent : C \subset A -> A \subset 'C(C). Proof. by move=> sCA; rewrite centsC (subset_trans sCA). Qed. Lemma sub_abelian_cent2 : B \subset A -> C \subset A -> B \subset 'C(C). Proof. by move=> sBA; move/sub_abelian_cent; exact: subset_trans. Qed. Lemma sub_abelian_norm : C \subset A -> A \subset 'N(C). Proof. by move=> sCA; rewrite cents_norm ?sub_abelian_cent. Qed. Lemma sub_abelian_normal : (C \subset A) = (C <| A). Proof. by rewrite /normal; case sHG: (C \subset A); rewrite // sub_abelian_norm. Qed. End SubAbelian. End Normaliser. Implicit Arguments normP [gT x A]. Implicit Arguments centP [gT x A]. Implicit Arguments normsP [gT A B]. Implicit Arguments cent1P [gT x y]. Implicit Arguments normalP [gT A B]. Implicit Arguments centsP [gT A B]. Implicit Arguments commG1P [gT A B]. Prenex Implicits normP normsP cent1P normalP centP centsP commG1P. Arguments Scope normaliser_group [_ group_scope]. Arguments Scope centraliser_group [_ group_scope]. Notation "''N' ( A )" := (normaliser_group A) : Group_scope. Notation "''C' ( A )" := (centraliser_group A) : Group_scope. Notation "''C' [ x ]" := (normaliser_group [set x%g]) : Group_scope. Notation "''N_' G ( A )" := (setI_group G 'N(A)) : Group_scope. Notation "''C_' G ( A )" := (setI_group G 'C(A)) : Group_scope. Notation "''C_' ( G ) ( A )" := (setI_group G 'C(A)) (only parsing) : Group_scope. Notation "''C_' G [ x ]" := (setI_group G 'C[x]) : Group_scope. Notation "''C_' ( G ) [ x ]" := (setI_group G 'C[x]) (only parsing) : Group_scope. Hint Resolve normG normal_refl. Section MinMaxGroup. Variable gT : finGroupType. Variable gP : pred {group gT}. Arguments Scope gP [Group_scope]. Definition maxgroup := maxset (fun A => group_set A && gP <>). Definition mingroup := minset (fun A => group_set A && gP <>). Lemma ex_maxgroup : (exists G, gP G) -> {G : {group gT} | maxgroup G}. Proof. move=> exP; have [A maxA]: {A | maxgroup A}. apply: ex_maxset; case: exP => G gPG. by exists (G : {set gT}); rewrite groupP genGidG. by exists <>%G; rewrite /= gen_set_id; case/andP: (maxsetp maxA). Qed. Lemma ex_mingroup : (exists G, gP G) -> {G : {group gT} | mingroup G}. Proof. move=> exP; have [A minA]: {A | mingroup A}. apply: ex_minset; case: exP => G gPG. by exists (G : {set gT}); rewrite groupP genGidG. by exists <>%G; rewrite /= gen_set_id; case/andP: (minsetp minA). Qed. Variable G : {group gT}. Lemma mingroupP : reflect (gP G /\ forall H, gP H -> H \subset G -> H :=: G) (mingroup G). Proof. apply: (iffP minsetP); rewrite /= groupP genGidG /= => [] [-> minG]. by split=> // H gPH sGH; apply: minG; rewrite // groupP genGidG. split=> // A; case/andP=> gA gPA; rewrite -(gen_set_id gA); exact: minG. Qed. Lemma maxgroupP : reflect (gP G /\ forall H, gP H -> G \subset H -> H :=: G) (maxgroup G). Proof. apply: (iffP maxsetP); rewrite /= groupP genGidG /= => [] [-> maxG]. by split=> // H gPH sGH; apply: maxG; rewrite // groupP genGidG. split=> // A; case/andP=> gA gPA; rewrite -(gen_set_id gA); exact: maxG. Qed. Lemma maxgroupp : maxgroup G -> gP G. Proof. by case/maxgroupP. Qed. Lemma mingroupp : mingroup G -> gP G. Proof. by case/mingroupP. Qed. Hypothesis gPG : gP G. Lemma maxgroup_exists : {H : {group gT} | maxgroup H & G \subset H}. Proof. have [A maxA sGA]: {A | maxgroup A & G \subset A}. by apply: maxset_exists; rewrite groupP genGidG. by exists <>%G; rewrite /= gen_set_id; case/andP: (maxsetp maxA). Qed. Lemma mingroup_exists : {H : {group gT} | mingroup H & H \subset G}. Proof. have [A maxA sGA]: {A | mingroup A & A \subset G}. by apply: minset_exists; rewrite groupP genGidG. by exists <>%G; rewrite /= gen_set_id; case/andP: (minsetp maxA). Qed. End MinMaxGroup. Notation "[ 'max' A 'of' G | gP ]" := (maxgroup (fun G : {group _} => gP) A) : group_scope. Notation "[ 'max' G | gP ]" := [max gval G of G | gP] : group_scope. Notation "[ 'max' A 'of' G | gP & gQ ]" := [max A of G | gP && gQ] : group_scope. Notation "[ 'max' G | gP & gQ ]" := [max G | gP && gQ] : group_scope. Notation "[ 'min' A 'of' G | gP ]" := (mingroup (fun G : {group _} => gP) A) : group_scope. Notation "[ 'min' G | gP ]" := [min gval G of G | gP] : group_scope. Notation "[ 'min' A 'of' G | gP & gQ ]" := [min A of G | gP && gQ] : group_scope. Notation "[ 'min' G | gP & gQ ]" := [min G | gP && gQ] : group_scope. Implicit Arguments mingroupP [gT gP G]. Implicit Arguments maxgroupP [gT gP G]. Prenex Implicits mingroupP maxgroupP. mathcomp-1.5/theories/frobenius.v0000644000175000017500000010547512307636117016202 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat div fintype bigop prime. Require Import finset fingroup morphism perm action quotient gproduct. Require Import cyclic center pgroup nilpotent sylow hall abelian. (******************************************************************************) (* Definition of Frobenius groups, some basic results, and the Frobenius *) (* theorem on the number of solutions of x ^+ n = 1. *) (* semiregular K H <-> *) (* the internal action of H on K is semiregular, i.e., no nontrivial *) (* elements of H and K commute; note that this is actually a symmetric *) (* condition. *) (* semiprime K H <-> *) (* the internal action of H on K is "prime", i.e., an element of K that *) (* centralises a nontrivial element of H must actually centralise all *) (* of H. *) (* normedTI A G L <=> *) (* A is nonempty, strictly disjoint from its conjugates in G, and has *) (* normaliser L in G. *) (* [Frobenius G = K ><| H] <=> *) (* G is (isomorphic to) a Frobenius group with kernel K and complement *) (* H. This is an effective predicate (in bool), which tests the *) (* equality with the semidirect product, and then the fact that H is a *) (* proper self-normalizing TI-subgroup of G. *) (* [Frobenius G with kernel H] <=> *) (* G is (isomorphic to) a Frobenius group with kernel K; same as above, *) (* but without the semi-direct product. *) (* [Frobenius G with complement H] <=> *) (* G is (isomorphic to) a Frobenius group with complement H; same as *) (* above, but without the semi-direct product. The proof that this form *) (* is equivalent to the above (i.e., the existence of Frobenius *) (* kernels) requires chareacter theory and will only be proved in the *) (* vcharacter module. *) (* [Frobenius G] <=> G is a Frobenius group. *) (* Frobenius_action G H S to <-> *) (* The action to of G on S defines an isomorphism of G with a *) (* (permutation) Frobenius group, i.e., to is faithful and transitive *) (* on S, no nontrivial element of G fixes more than one point in S, and *) (* H is the stabilizer of some element of S, and non-trivial. Thus, *) (* Frobenius_action G H S 'P *) (* asserts that G is a Frobenius group in the classic sense. *) (* has_Frobenius_action G H <-> *) (* Frobenius_action G H S to holds for some sT : finType, S : {set st} *) (* and to : {action gT &-> sT}. This is a predicate in Prop, but is *) (* exactly reflected by [Frobenius G with complement H] : bool. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section Definitions. Variable gT : finGroupType. Implicit Types A G K H L : {set gT}. (* Corresponds to "H acts on K in a regular manner" in B & G. *) Definition semiregular K H := {in H^#, forall x, 'C_K[x] = 1}. (* Corresponds to "H acts on K in a prime manner" in B & G. *) Definition semiprime K H := {in H^#, forall x, 'C_K[x] = 'C_K(H)}. Definition normedTI A G L := [&& A != set0, trivIset (A :^: G) & 'N_G(A) == L]. Definition Frobenius_group_with_complement G H := (H != G) && normedTI H^# G H. Definition Frobenius_group G := [exists H : {group gT}, Frobenius_group_with_complement G H]. Definition Frobenius_group_with_kernel_and_complement G K H := (K ><| H == G) && Frobenius_group_with_complement G H. Definition Frobenius_group_with_kernel G K := [exists H : {group gT}, Frobenius_group_with_kernel_and_complement G K H]. Section FrobeniusAction. Variables G H : {set gT}. Variables (sT : finType) (S : {set sT}) (to : {action gT &-> sT}). Definition Frobenius_action := [/\ [faithful G, on S | to], [transitive G, on S | to], {in G^#, forall x, #|'Fix_(S | to)[x]| <= 1}, H != 1 & exists2 u, u \in S & H = 'C_G[u | to]]. End FrobeniusAction. CoInductive has_Frobenius_action G H : Prop := HasFrobeniusAction sT S to of @Frobenius_action G H sT S to. End Definitions. Arguments Scope semiregular [_ group_scope group_scope]. Arguments Scope semiprime [_ group_scope group_scope]. Arguments Scope normedTI [_ group_scope group_scope group_scope]. Arguments Scope Frobenius_group_with_complement [_ group_scope group_scope]. Arguments Scope Frobenius_group [_ group_scope]. Arguments Scope Frobenius_group_with_kernel [_ group_scope group_scope]. Arguments Scope Frobenius_group_with_kernel_and_complement [_ group_scope group_scope group_scope]. Arguments Scope Frobenius_action [_ group_scope group_scope _ group_scope action_scope]. Arguments Scope has_Frobenius_action [_ group_scope group_scope]. Notation "[ 'Frobenius' G 'with' 'complement' H ]" := (Frobenius_group_with_complement G H) (at level 0, G at level 50, H at level 35, format "[ 'Frobenius' G 'with' 'complement' H ]") : group_scope. Notation "[ 'Frobenius' G 'with' 'kernel' K ]" := (Frobenius_group_with_kernel G K) (at level 0, G at level 50, K at level 35, format "[ 'Frobenius' G 'with' 'kernel' K ]") : group_scope. Notation "[ 'Frobenius' G ]" := (Frobenius_group G) (at level 0, G at level 50, format "[ 'Frobenius' G ]") : group_scope. Notation "[ 'Frobenius' G = K ><| H ]" := (Frobenius_group_with_kernel_and_complement G K H) (at level 0, G at level 50, K, H at level 35, format "[ 'Frobenius' G = K ><| H ]") : group_scope. Section FrobeniusBasics. Variable gT : finGroupType. Implicit Types (A B : {set gT}) (G H K L R X : {group gT}). Lemma semiregular1l H : semiregular 1 H. Proof. by move=> x _ /=; rewrite setI1g. Qed. Lemma semiregular1r K : semiregular K 1. Proof. by move=> x; rewrite setDv inE. Qed. Lemma semiregular_sym H K : semiregular K H -> semiregular H K. Proof. move=> regH x /setD1P[ntx Kx]; apply: contraNeq ntx. rewrite -subG1 -setD_eq0 -setIDAC => /set0Pn[y /setIP[Hy cxy]]. by rewrite (sameP eqP set1gP) -(regH y Hy) inE Kx cent1C. Qed. Lemma semiregularS K1 K2 A1 A2 : K1 \subset K2 -> A1 \subset A2 -> semiregular K2 A2 -> semiregular K1 A1. Proof. move=> sK12 sA12 regKA2 x /setD1P[ntx /(subsetP sA12)A2x]. by apply/trivgP; rewrite -(regKA2 x) ?inE ?ntx ?setSI. Qed. Lemma semiregular_prime H K : semiregular K H -> semiprime K H. Proof. move=> regH x Hx; apply/eqP; rewrite eqEsubset {1}regH // sub1G. by rewrite -cent_set1 setIS ?centS // sub1set; case/setD1P: Hx. Qed. Lemma semiprime_regular H K : semiprime K H -> 'C_K(H) = 1 -> semiregular K H. Proof. by move=> prKH tiKcH x Hx; rewrite prKH. Qed. Lemma semiprimeS K1 K2 A1 A2 : K1 \subset K2 -> A1 \subset A2 -> semiprime K2 A2 -> semiprime K1 A1. Proof. move=> sK12 sA12 prKA2 x /setD1P[ntx A1x]. apply/eqP; rewrite eqEsubset andbC -{1}cent_set1 setIS ?centS ?sub1set //=. rewrite -(setIidPl sK12) -!setIA prKA2 ?setIS ?centS //. by rewrite !inE ntx (subsetP sA12). Qed. Lemma cent_semiprime H K X : semiprime K H -> X \subset H -> X :!=: 1 -> 'C_K(X) = 'C_K(H). Proof. move=> prKH sXH /trivgPn[x Xx ntx]; apply/eqP. rewrite eqEsubset -{1}(prKH x) ?inE ?(subsetP sXH) ?ntx //=. by rewrite -cent_cycle !setIS ?centS ?cycle_subG. Qed. Lemma stab_semiprime H K X : semiprime K H -> X \subset K -> 'C_H(X) != 1 -> 'C_H(X) = H. Proof. move=> prKH sXK ntCHX; apply/setIidPl; rewrite centsC -subsetIidl. rewrite -{2}(setIidPl sXK) -setIA -(cent_semiprime prKH _ ntCHX) ?subsetIl //. by rewrite !subsetI subxx sXK centsC subsetIr. Qed. Lemma cent_semiregular H K X : semiregular K H -> X \subset H -> X :!=: 1 -> 'C_K(X) = 1. Proof. move=> regKH sXH /trivgPn[x Xx ntx]; apply/trivgP. rewrite -(regKH x) ?inE ?(subsetP sXH) ?ntx ?setIS //=. by rewrite -cent_cycle centS ?cycle_subG. Qed. Lemma regular_norm_dvd_pred K H : H \subset 'N(K) -> semiregular K H -> #|H| %| #|K|.-1. Proof. move=> nKH regH; have actsH: [acts H, on K^# | 'J] by rewrite astabsJ normD1. rewrite (cardsD1 1 K) group1 -(acts_sum_card_orbit actsH) /=. rewrite (eq_bigr (fun _ => #|H|)) ?sum_nat_const ?dvdn_mull //. move=> _ /imsetP[x /setIdP[ntx Kx] ->]; rewrite card_orbit astab1J. rewrite ['C_H[x]](trivgP _) ?indexg1 //=. apply/subsetP=> y /setIP[Hy cxy]; apply: contraR ntx => nty. by rewrite -[[set 1]](regH y) inE ?nty // Kx cent1C. Qed. Lemma regular_norm_coprime K H : H \subset 'N(K) -> semiregular K H -> coprime #|K| #|H|. Proof. move=> nKH regH. by rewrite (coprime_dvdr (regular_norm_dvd_pred nKH regH)) ?coprimenP. Qed. Lemma semiregularJ K H x : semiregular K H -> semiregular (K :^ x) (H :^ x). Proof. move=> regH yx; rewrite -conjD1g => /imsetP[y Hy ->]. by rewrite cent1J -conjIg regH ?conjs1g. Qed. Lemma semiprimeJ K H x : semiprime K H -> semiprime (K :^ x) (H :^ x). Proof. move=> prH yx; rewrite -conjD1g => /imsetP[y Hy ->]. by rewrite cent1J centJ -!conjIg prH. Qed. Lemma normedTI_P A G L : reflect [/\ A != set0, L \subset 'N_G(A) & {in G, forall g, ~~ [disjoint A & A :^ g] -> g \in L}] (normedTI A G L). Proof. apply: (iffP and3P) => [[nzA /trivIsetP tiAG /eqP <-] | [nzA sLN tiAG]]. split=> // g Gg; rewrite inE Gg (sameP normP eqP) /= eq_sym; apply: contraR. by apply: tiAG; rewrite ?mem_orbit ?orbit_refl. have [/set0Pn[a Aa] /subsetIP[_ nAL]] := (nzA, sLN); split=> //; last first. rewrite eqEsubset sLN andbT; apply/subsetP=> x /setIP[Gx nAx]. by apply/tiAG/pred0Pn=> //; exists a; rewrite /= (normP nAx) Aa. apply/trivIsetP=> _ _ /imsetP[x Gx ->] /imsetP[y Gy ->]; apply: contraR. rewrite -setI_eq0 -(mulgKV x y) conjsgM; set g := (y * x^-1)%g. have Gg: g \in G by rewrite groupMl ?groupV. rewrite -conjIg (inj_eq (act_inj 'Js x)) (eq_sym A) (sameP eqP normP). by rewrite -cards_eq0 cardJg cards_eq0 setI_eq0 => /tiAG/(subsetP nAL)->. Qed. Implicit Arguments normedTI_P [A G L]. Lemma normedTI_memJ_P A G L : reflect [/\ A != set0, L \subset G & {in A & G, forall a g, (a ^ g \in A) = (g \in L)}] (normedTI A G L). Proof. apply: (iffP normedTI_P) => [[-> /subsetIP[sLG nAL] tiAG] | [-> sLG tiAG]]. split=> // a g Aa Gg; apply/idP/idP=> [Aag | Lg]; last first. by rewrite memJ_norm ?(subsetP nAL). by apply/tiAG/pred0Pn=> //; exists (a ^ g)%g; rewrite /= Aag memJ_conjg. split=> // [ | g Gg /pred0Pn[ag /=]]; last first. by rewrite andbC => /andP[/imsetP[a Aa ->]]; rewrite tiAG. apply/subsetP=> g Lg; have Gg := subsetP sLG g Lg. by rewrite !inE Gg; apply/subsetP=> _ /imsetP[a Aa ->]; rewrite tiAG. Qed. Lemma partition_class_support A G : A != set0 -> trivIset (A :^: G) -> partition (A :^: G) (class_support A G). Proof. rewrite /partition cover_imset -class_supportEr eqxx => nzA ->. by apply: contra nzA => /imsetP[x _ /eqP]; rewrite eq_sym -!cards_eq0 cardJg. Qed. Lemma partition_normedTI A G L : normedTI A G L -> partition (A :^: G) (class_support A G). Proof. by case/and3P=> ntA tiAG _; apply: partition_class_support. Qed. Lemma card_support_normedTI A G L : normedTI A G L -> #|class_support A G| = (#|A| * #|G : L|)%N. Proof. case/and3P=> ntA tiAG /eqP <-; rewrite -card_conjugates mulnC. apply: card_uniform_partition (partition_class_support ntA tiAG). by move=> _ /imsetP[y _ ->]; rewrite cardJg. Qed. Lemma normedTI_S A B G L : A != set0 -> L \subset 'N(A) -> A \subset B -> normedTI B G L -> normedTI A G L. Proof. move=> nzA /subsetP nAL /subsetP sAB /normedTI_memJ_P[nzB sLG tiB]. apply/normedTI_memJ_P; split=> // a x Aa Gx. by apply/idP/idP => [Aax | /nAL/memJ_norm-> //]; rewrite -(tiB a) ?sAB. Qed. Lemma cent1_normedTI A G L : normedTI A G L -> {in A, forall x, 'C_G[x] \subset L}. Proof. case/normedTI_memJ_P=> [_ _ tiAG] x Ax; apply/subsetP=> y /setIP[Gy cxy]. by rewrite -(tiAG x) // /(x ^ y) -(cent1P cxy) mulKg. Qed. Lemma Frobenius_actionP G H : reflect (has_Frobenius_action G H) [Frobenius G with complement H]. Proof. apply: (iffP andP) => [[neqHG] | [sT S to [ffulG transG regG ntH [u Su defH]]]]. case/normedTI_P=> nzH /subsetIP[sHG _] tiHG. suffices: Frobenius_action G H (rcosets H G) 'Rs by exact: HasFrobeniusAction. pose Hfix x := 'Fix_(rcosets H G | 'Rs)[x]. have regG: {in G^#, forall x, #|Hfix x| <= 1}. move=> x /setD1P[ntx Gx]. apply: wlog_neg; rewrite -ltnNge => /ltnW/card_gt0P/=[Hy]. rewrite -(cards1 Hy) => /setIP[/imsetP[y Gy ->{Hy}] cHyx]. apply/subset_leq_card/subsetP=> _ /setIP[/imsetP[z Gz ->] cHzx]. rewrite -!sub_astab1 !astab1_act !sub1set astab1Rs in cHyx cHzx *. rewrite !rcosetE; apply/set1P/rcoset_transl; rewrite mem_rcoset. apply: tiHG; [by rewrite !in_group | apply/pred0Pn; exists (x ^ y^-1)]. by rewrite conjD1g !inE conjg_eq1 ntx -mem_conjg cHyx conjsgM memJ_conjg. have ntH: H :!=: 1 by rewrite -subG1 -setD_eq0. split=> //; first 1 last; first exact: transRs_rcosets. by exists (H : {set gT}); rewrite ?orbit_refl // astab1Rs (setIidPr sHG). apply/subsetP=> y /setIP[Gy cHy]; apply: contraR neqHG => nt_y. rewrite (index1g sHG) //; apply/eqP; rewrite eqn_leq indexg_gt0 andbT. apply: leq_trans (regG y _); last by rewrite setDE 2!inE Gy nt_y /=. by rewrite /Hfix (setIidPl _) -1?astabC ?sub1set. have sHG: H \subset G by rewrite defH subsetIl. split. apply: contraNneq ntH => /= defG. suffices defS: S = [set u] by rewrite -(trivgP ffulG) /= defS defH. apply/eqP; rewrite eq_sym eqEcard sub1set Su. by rewrite -(atransP transG u Su) card_orbit -defH defG indexgg cards1. apply/normedTI_P; rewrite setD_eq0 subG1 normD1 subsetI sHG normG. split=> // x Gx; rewrite -setI_eq0 conjD1g defH inE Gx conjIg conjGid //. rewrite -setDIl -setIIr -astab1_act setDIl => /set0Pn[y /setIP[Gy /setD1P[_]]]. case/setIP; rewrite 2!(sameP astab1P afix1P) => cuy cuxy; apply/astab1P. apply: contraTeq (regG y Gy) => cu'x. rewrite (cardD1 u) (cardD1 (to u x)) inE Su cuy inE /= inE cu'x cuxy. by rewrite (actsP (atrans_acts transG)) ?Su. Qed. Section FrobeniusProperties. Variables G H K : {group gT}. Hypothesis frobG : [Frobenius G = K ><| H]. Lemma FrobeniusWker : [Frobenius G with kernel K]. Proof. by apply/existsP; exists H. Qed. Lemma FrobeniusWcompl : [Frobenius G with complement H]. Proof. by case/andP: frobG. Qed. Lemma FrobeniusW : [Frobenius G]. Proof. by apply/existsP; exists H; exact: FrobeniusWcompl. Qed. Lemma Frobenius_context : [/\ K ><| H = G, K :!=: 1, H :!=: 1, K \proper G & H \proper G]. Proof. have [/eqP defG neqHG ntH _] := and4P frobG; rewrite setD_eq0 subG1 in ntH. have ntK: K :!=: 1 by apply: contraNneq neqHG => K1; rewrite -defG K1 sdprod1g. rewrite properEcard properEneq neqHG; have /mulG_sub[-> ->] := sdprodW defG. by rewrite -(sdprod_card defG) ltn_Pmulr ?cardG_gt1. Qed. Lemma Frobenius_partition : partition (gval K |: (H^# :^: K)) G. Proof. have [/eqP defG _ tiHG] := and3P frobG; have [_ tiH1G /eqP defN] := and3P tiHG. have [[_ /mulG_sub[sKG sHG] nKH tiKH] mulHK] := (sdprodP defG, sdprodWC defG). set HG := H^# :^: K; set KHG := _ |: _. have defHG: HG = H^# :^: G. have: 'C_G[H^# | 'Js] * K = G by rewrite astab1Js defN mulHK. move/subgroup_transitiveP/atransP. by apply; rewrite ?atrans_orbit ?orbit_refl. have /and3P[defHK _ nzHG] := partition_normedTI tiHG. rewrite -defHG in defHK nzHG tiH1G. have [tiKHG HG'K]: trivIset KHG /\ gval K \notin HG. apply: trivIsetU1 => // _ /imsetP[x Kx ->]; rewrite -setI_eq0. by rewrite -(conjGid Kx) -conjIg setIDA tiKH setDv conj0g. rewrite /partition andbC tiKHG !inE negb_or nzHG eq_sym -card_gt0 cardG_gt0 /=. rewrite eqEcard; apply/andP; split. rewrite /cover big_setU1 //= subUset sKG -/(cover HG) (eqP defHK). by rewrite class_support_subG // (subset_trans _ sHG) ?subD1set. rewrite -(eqnP tiKHG) big_setU1 //= (eqnP tiH1G) (eqP defHK). rewrite (card_support_normedTI tiHG) -(Lagrange sHG) (cardsD1 1) group1 mulSn. by rewrite leq_add2r -mulHK indexMg -indexgI tiKH indexg1. Qed. Lemma Frobenius_cent1_ker : {in K^#, forall x, 'C_G[x] \subset K}. Proof. have [/eqP defG _ /normedTI_memJ_P[_ _ tiHG]] := and3P frobG. move=> x /setD1P[ntx Kx]; have [_ /mulG_sub[sKG _] _ tiKH] := sdprodP defG. have [/eqP <- _ _] := and3P Frobenius_partition; rewrite big_distrl /=. apply/bigcupsP=> _ /setU1P[|/imsetP[y Ky]] ->; first exact: subsetIl. apply: contraR ntx => /subsetPn[z]; rewrite inE mem_conjg => /andP[Hzy cxz] _. rewrite -(conjg_eq1 x y^-1) -in_set1 -set1gE -tiKH inE andbC. rewrite -(tiHG _ _ Hzy) ?(subsetP sKG) ?in_group // Ky andbT -conjJg. by rewrite /(z ^ x) (cent1P cxz) mulKg. Qed. Lemma Frobenius_reg_ker : semiregular K H. Proof. move=> x /setD1P[ntx Hx]. apply/trivgP/subsetP=> y /setIP[Ky cxy]; apply: contraR ntx => nty. have K1y: y \in K^# by rewrite inE nty. have [/eqP/sdprod_context[_ sHG _ _ tiKH] _] := andP frobG. suffices: x \in K :&: H by rewrite tiKH inE. by rewrite inE (subsetP (Frobenius_cent1_ker K1y)) // inE cent1C (subsetP sHG). Qed. Lemma Frobenius_reg_compl : semiregular H K. Proof. by apply: semiregular_sym; exact: Frobenius_reg_ker. Qed. Lemma Frobenius_dvd_ker1 : #|H| %| #|K|.-1. Proof. apply: regular_norm_dvd_pred Frobenius_reg_ker. by have[/sdprodP[]] := Frobenius_context. Qed. Lemma ltn_odd_Frobenius_ker : odd #|G| -> #|H|.*2 < #|K|. Proof. move/oddSg=> oddG. have [/sdprodW/mulG_sub[sKG sHG] ntK _ _ _] := Frobenius_context. by rewrite dvdn_double_ltn ?oddG ?cardG_gt1 ?Frobenius_dvd_ker1. Qed. Lemma Frobenius_index_dvd_ker1 : #|G : K| %| #|K|.-1. Proof. have[defG _ _ /andP[sKG _] _] := Frobenius_context. by rewrite -divgS // -(sdprod_card defG) mulKn ?Frobenius_dvd_ker1. Qed. Lemma Frobenius_coprime : coprime #|K| #|H|. Proof. by rewrite (coprime_dvdr Frobenius_dvd_ker1) ?coprimenP. Qed. Lemma Frobenius_trivg_cent : 'C_K(H) = 1. Proof. by apply: (cent_semiregular Frobenius_reg_ker); case: Frobenius_context. Qed. Lemma Frobenius_index_coprime : coprime #|K| #|G : K|. Proof. by rewrite (coprime_dvdr Frobenius_index_dvd_ker1) ?coprimenP. Qed. Lemma Frobenius_ker_Hall : Hall G K. Proof. have [_ _ _ /andP[sKG _] _] := Frobenius_context. by rewrite /Hall sKG Frobenius_index_coprime. Qed. Lemma Frobenius_compl_Hall : Hall G H. Proof. have [defG _ _ _ _] := Frobenius_context. by rewrite -(sdprod_Hall defG) Frobenius_ker_Hall. Qed. End FrobeniusProperties. Lemma normedTI_J x A G L : normedTI (A :^ x) (G :^ x) (L :^ x) = normedTI A G L. Proof. rewrite {1}/normedTI normJ -conjIg -(conj0g x) !(can_eq (conjsgK x)). congr [&& _, _ == _ & _]; rewrite /cover (reindex_inj (@conjsg_inj _ x)). by apply: eq_big => Hy; rewrite ?orbit_conjsg ?cardJg. by rewrite bigcupJ cardJg (eq_bigl _ _ (orbit_conjsg _ _ _ _)). Qed. Lemma FrobeniusJcompl x G H : [Frobenius G :^ x with complement H :^ x] = [Frobenius G with complement H]. Proof. by congr (_ && _); rewrite ?(can_eq (conjsgK x)) // -conjD1g normedTI_J. Qed. Lemma FrobeniusJ x G K H : [Frobenius G :^ x = K :^ x ><| H :^ x] = [Frobenius G = K ><| H]. Proof. by congr (_ && _); rewrite ?FrobeniusJcompl // -sdprodJ (can_eq (conjsgK x)). Qed. Lemma FrobeniusJker x G K : [Frobenius G :^ x with kernel K :^ x] = [Frobenius G with kernel K]. Proof. apply/existsP/existsP=> [] [H]; last by exists (H :^ x)%G; rewrite FrobeniusJ. by rewrite -(conjsgKV x H) FrobeniusJ; exists (H :^ x^-1)%G. Qed. Lemma FrobeniusJgroup x G : [Frobenius G :^ x] = [Frobenius G]. Proof. apply/existsP/existsP=> [] [H]. by rewrite -(conjsgKV x H) FrobeniusJcompl; exists (H :^ x^-1)%G. by exists (H :^ x)%G; rewrite FrobeniusJcompl. Qed. Lemma Frobenius_ker_dvd_ker1 G K : [Frobenius G with kernel K] -> #|G : K| %| #|K|.-1. Proof. case/existsP=> H; exact: Frobenius_index_dvd_ker1. Qed. Lemma Frobenius_ker_coprime G K : [Frobenius G with kernel K] -> coprime #|K| #|G : K|. Proof. case/existsP=> H; exact: Frobenius_index_coprime. Qed. Lemma Frobenius_semiregularP G K H : K ><| H = G -> K :!=: 1 -> H :!=: 1 -> reflect (semiregular K H) [Frobenius G = K ><| H]. Proof. move=> defG ntK ntH. apply: (iffP idP) => [|regG]; first exact: Frobenius_reg_ker. have [nsKG sHG defKH nKH tiKH]:= sdprod_context defG; have [sKG _]:= andP nsKG. apply/and3P; split; first by rewrite defG. by rewrite eqEcard sHG -(sdprod_card defG) -ltnNge ltn_Pmull ?cardG_gt1. apply/normedTI_memJ_P; rewrite setD_eq0 subG1 sHG -defKH -(normC nKH). split=> // z _ /setD1P[ntz Hz] /mulsgP[y x Hy Kx ->]; rewrite groupMl // !inE. rewrite conjg_eq1 ntz; apply/idP/idP=> [Hzxy | Hx]; last by rewrite !in_group. apply: (subsetP (sub1G H)); have Hzy: z ^ y \in H by apply: groupJ. rewrite -(regG (z ^ y)); last by apply/setD1P; rewrite conjg_eq1. rewrite inE Kx cent1C (sameP cent1P commgP) -in_set1 -[[set 1]]tiKH inE /=. rewrite andbC groupM ?groupV -?conjgM //= commgEr groupMr //. by rewrite memJ_norm ?(subsetP nKH) ?groupV. Qed. Lemma prime_FrobeniusP G K H : K :!=: 1 -> prime #|H| -> reflect (K ><| H = G /\ 'C_K(H) = 1) [Frobenius G = K ><| H]. Proof. move=> ntK H_pr; have ntH: H :!=: 1 by rewrite -cardG_gt1 prime_gt1. have [defG | not_sdG] := eqVneq (K ><| H) G; last first. by apply: (iffP andP) => [] [defG]; rewrite defG ?eqxx in not_sdG. apply: (iffP (Frobenius_semiregularP defG ntK ntH)) => [regH | [_ regH x]]. split=> //; have [x defH] := cyclicP (prime_cyclic H_pr). by rewrite defH cent_cycle regH // !inE defH cycle_id andbT -cycle_eq1 -defH. case/setD1P=> nt_x Hx; apply/trivgP; rewrite -regH setIS //= -cent_cycle. by rewrite centS // prime_meetG // (setIidPr _) ?cycle_eq1 ?cycle_subG. Qed. Lemma Frobenius_subl G K K1 H : K1 :!=: 1 -> K1 \subset K -> H \subset 'N(K1) -> [Frobenius G = K ><| H] -> [Frobenius K1 <*> H = K1 ><| H]. Proof. move=> ntK1 sK1K nK1H frobG; have [_ _ ntH _ _] := Frobenius_context frobG. apply/Frobenius_semiregularP=> //. by rewrite sdprodEY ?coprime_TIg ?(coprimeSg sK1K) ?(Frobenius_coprime frobG). by move=> x /(Frobenius_reg_ker frobG) cKx1; apply/trivgP; rewrite -cKx1 setSI. Qed. Lemma Frobenius_subr G K H H1 : H1 :!=: 1 -> H1 \subset H -> [Frobenius G = K ><| H] -> [Frobenius K <*> H1 = K ><| H1]. Proof. move=> ntH1 sH1H frobG; have [defG ntK _ _ _] := Frobenius_context frobG. apply/Frobenius_semiregularP=> //. have [_ _ /(subset_trans sH1H) nH1K tiHK] := sdprodP defG. by rewrite sdprodEY //; apply/trivgP; rewrite -tiHK setIS. by apply: sub_in1 (Frobenius_reg_ker frobG); exact/subsetP/setSD. Qed. Lemma Frobenius_kerP G K : reflect [/\ K :!=: 1, K \proper G, K <| G & {in K^#, forall x, 'C_G[x] \subset K}] [Frobenius G with kernel K]. Proof. apply: (iffP existsP) => [[H frobG] | [ntK ltKG nsKG regK]]. have [/sdprod_context[nsKG _ _ _ _] ntK _ ltKG _] := Frobenius_context frobG. by split=> //; exact: Frobenius_cent1_ker frobG. have /andP[sKG nKG] := nsKG. have hallK: Hall G K. rewrite /Hall sKG //= coprime_sym coprime_pi' //. apply: sub_pgroup (pgroup_pi K) => p; have [P sylP] := Sylow_exists p G. have [[sPG pP p'GiP] sylPK] := (and3P sylP, Hall_setI_normal nsKG sylP). rewrite -p_rank_gt0 -(rank_Sylow sylPK) rank_gt0 => ntPK. rewrite inE /= -p'natEpi // (pnat_dvd _ p'GiP) ?indexgS //. have /trivgPn[z]: P :&: K :&: 'Z(P) != 1. by rewrite meet_center_nil ?(pgroup_nil pP) ?(normalGI sPG nsKG). rewrite !inE -andbA -sub_cent1=> /and4P[_ Kz _ cPz] ntz. by apply: subset_trans (regK z _); [exact/subsetIP | exact/setD1P]. have /splitsP[H /complP[tiKH defG]] := SchurZassenhaus_split hallK nsKG. have [_ sHG] := mulG_sub defG; have nKH := subset_trans sHG nKG. exists H; apply/Frobenius_semiregularP; rewrite ?sdprodE //. by apply: contraNneq (proper_subn ltKG) => H1; rewrite -defG H1 mulg1. apply: semiregular_sym => x Kx; apply/trivgP; rewrite -tiKH. by rewrite subsetI subsetIl (subset_trans _ (regK x _)) ?setSI. Qed. Lemma set_Frobenius_compl G K H : K ><| H = G -> [Frobenius G with kernel K] -> [Frobenius G = K ><| H]. Proof. move=> defG /Frobenius_kerP[ntK ltKG _ regKG]. apply/Frobenius_semiregularP=> //. by apply: contraTneq ltKG => H_1; rewrite -defG H_1 sdprodg1 properxx. apply: semiregular_sym => y /regKG sCyK. have [_ sHG _ _ tiKH] := sdprod_context defG. by apply/trivgP; rewrite /= -(setIidPr sHG) setIAC -tiKH setSI. Qed. Lemma Frobenius_kerS G K G1 : G1 \subset G -> K \proper G1 -> [Frobenius G with kernel K] -> [Frobenius G1 with kernel K]. Proof. move=> sG1G ltKG1 /Frobenius_kerP[ntK _ /andP[_ nKG] regKG]. apply/Frobenius_kerP; rewrite /normal proper_sub // (subset_trans sG1G) //. by split=> // x /regKG; apply: subset_trans; rewrite setSI. Qed. Lemma Frobenius_action_kernel_def G H K sT S to : K ><| H = G -> @Frobenius_action _ G H sT S to -> K :=: 1 :|: [set x in G | 'Fix_(S | to)[x] == set0]. Proof. move=> defG FrobG. have partG: partition (gval K |: (H^# :^: K)) G. apply: Frobenius_partition; apply/andP; rewrite defG; split=> //. by apply/Frobenius_actionP; exact: HasFrobeniusAction FrobG. have{FrobG} [ffulG transG regG ntH [u Su defH]]:= FrobG. apply/setP=> x; rewrite !inE; have [-> | ntx] := altP eqP; first exact: group1. rewrite /= -(cover_partition partG) /cover. have neKHy y: gval K <> H^# :^ y. by move/setP/(_ 1); rewrite group1 conjD1g setD11. rewrite big_setU1 /= ?inE; last by apply/imsetP=> [[y _ /neKHy]]. have [nsKG sHG _ _ tiKH] := sdprod_context defG; have [sKG nKG]:= andP nsKG. symmetry; case Kx: (x \in K) => /=. apply/set0Pn=> [[v /setIP[Sv]]]; have [y Gy ->] := atransP2 transG Su Sv. rewrite -sub1set -astabC sub1set astab1_act mem_conjg => Hxy. case/negP: ntx; rewrite -in_set1 -(conjgKV y x) -mem_conjgV conjs1g -tiKH. by rewrite defH setIA inE -mem_conjg (setIidPl sKG) (normsP nKG) ?Kx. apply/andP=> [[/bigcupP[_ /imsetP[y Ky ->] Hyx] /set0Pn[]]]; exists (to u y). rewrite inE (actsP (atrans_acts transG)) ?(subsetP sKG) // Su. rewrite -sub1set -astabC sub1set astab1_act. by rewrite conjD1g defH conjIg !inE in Hyx; case/and3P: Hyx. Qed. End FrobeniusBasics. Implicit Arguments normedTI_P [gT A G L]. Implicit Arguments normedTI_memJ_P [gT A G L]. Implicit Arguments Frobenius_kerP [gT G K]. Lemma Frobenius_coprime_quotient (gT : finGroupType) (G K H N : {group gT}) : K ><| H = G -> N <| G -> coprime #|K| #|H| /\ H :!=: 1%g -> N \proper K /\ {in H^#, forall x, 'C_K[x] \subset N} -> [Frobenius G / N = (K / N) ><| (H / N)]%g. Proof. move=> defG nsNG [coKH ntH] [ltNK regH]. have [[sNK _] [_ /mulG_sub[sKG sHG] _ _]] := (andP ltNK, sdprodP defG). have [_ nNG] := andP nsNG; have nNH := subset_trans sHG nNG. apply/Frobenius_semiregularP; first exact: quotient_coprime_sdprod. - by rewrite quotient_neq1 ?(normalS _ sKG). - by rewrite -(isog_eq1 (quotient_isog _ _)) ?coprime_TIg ?(coprimeSg sNK). move=> _ /(subsetP (quotientD1 _ _))/morphimP[x nNx H1x ->]. rewrite -cent_cycle -quotient_cycle //=. rewrite -strongest_coprime_quotient_cent ?cycle_subG //. - by rewrite cent_cycle quotientS1 ?regH. - by rewrite subIset ?sNK. - rewrite (coprimeSg (subsetIl N _)) ?(coprimeSg sNK) ?(coprimegS _ coKH) //. by rewrite cycle_subG; case/setD1P: H1x. by rewrite orbC abelian_sol ?cycle_abelian. Qed. Section InjmFrobenius. Variables (gT rT : finGroupType) (D G : {group gT}) (f : {morphism D >-> rT}). Implicit Types (H K : {group gT}) (sGD : G \subset D) (injf : 'injm f). Lemma injm_Frobenius_compl H sGD injf : [Frobenius G with complement H] -> [Frobenius f @* G with complement f @* H]. Proof. case/andP=> neqGH /normedTI_P[nzH /subsetIP[sHG _] tiHG]. have sHD := subset_trans sHG sGD; have sH1D := subset_trans (subD1set H 1) sHD. apply/andP; rewrite (can_in_eq (injmK injf)) //; split=> //. apply/normedTI_P; rewrite normD1 -injmD1 // -!cards_eq0 card_injm // in nzH *. rewrite subsetI normG morphimS //; split=> // _ /morphimP[x Dx Gx ->] ti'fHx. rewrite mem_morphim ?tiHG //; apply: contra ti'fHx; rewrite -!setI_eq0 => tiHx. by rewrite -morphimJ // -injmI ?conj_subG // (eqP tiHx) morphim0. Qed. Lemma injm_Frobenius H K sGD injf : [Frobenius G = K ><| H] -> [Frobenius f @* G = f @* K ><| f @* H]. Proof. case/andP=> /eqP defG frobG. by apply/andP; rewrite (injm_sdprod _ injf defG) // eqxx injm_Frobenius_compl. Qed. Lemma injm_Frobenius_ker K sGD injf : [Frobenius G with kernel K] -> [Frobenius f @* G with kernel f @* K]. Proof. case/existsP=> H frobG; apply/existsP; exists (f @* H)%G; exact: injm_Frobenius. Qed. Lemma injm_Frobenius_group sGD injf : [Frobenius G] -> [Frobenius f @* G]. Proof. case/existsP=> H frobG; apply/existsP; exists (f @* H)%G. exact: injm_Frobenius_compl. Qed. End InjmFrobenius. Theorem Frobenius_Ldiv (gT : finGroupType) (G : {group gT}) n : n %| #|G| -> n %| #|'Ldiv_n(G)|. Proof. move=> nG; move: {2}_.+1 (ltnSn (#|G| %/ n)) => mq. elim: mq => // mq IHm in gT G n nG *; case/dvdnP: nG => q oG. have [q_gt0 n_gt0] : 0 < q /\ 0 < n by apply/andP; rewrite -muln_gt0 -oG. rewrite ltnS oG mulnK // => leqm. have:= q_gt0; rewrite leq_eqVlt => /predU1P[q1 | lt1q]. rewrite -(mul1n n) q1 -oG (setIidPl _) //. by apply/subsetP=> x Gx; rewrite inE -order_dvdn order_dvdG. pose p := pdiv q; have pr_p: prime p by exact: pdiv_prime. have lt1p: 1 < p := prime_gt1 pr_p; have p_gt0 := ltnW lt1p. have{leqm} lt_qp_mq: q %/ p < mq by apply: leq_trans leqm; rewrite ltn_Pdiv. have: n %| #|'Ldiv_(p * n)(G)|. have: p * n %| #|G| by rewrite oG dvdn_pmul2r ?pdiv_dvd. move/IHm=> IH; apply: dvdn_trans (IH _); first exact: dvdn_mull. by rewrite oG divnMr. rewrite -(cardsID 'Ldiv_n()) dvdn_addl. rewrite -setIA ['Ldiv_n(_)](setIidPr _) //. by apply/subsetP=> x; rewrite !inE -!order_dvdn; apply: dvdn_mull. rewrite -setIDA; set A := _ :\: _. have pA x: x \in A -> #[x]`_p = (n`_p * p)%N. rewrite !inE -!order_dvdn => /andP[xn xnp]. rewrite !p_part // -expnSr; congr (p ^ _)%N; apply/eqP. rewrite eqn_leq -{1}addn1 -(pfactorK 1 pr_p) -lognM ?expn1 // mulnC. rewrite dvdn_leq_log ?muln_gt0 ?p_gt0 //= ltnNge; apply: contra xn => xn. move: xnp; rewrite -[#[x]](partnC p) //. rewrite !Gauss_dvd ?coprime_partC //; case/andP=> _. rewrite p_part ?pfactor_dvdn // xn Gauss_dvdr // coprime_sym. exact: pnat_coprime (pnat_id _) (part_pnat _ _). rewrite -(partnC p n_gt0) Gauss_dvd ?coprime_partC //; apply/andP; split. rewrite -sum1_card (partition_big_imset (@cycle _)) /=. apply: dvdn_sum => _ /imsetP[x /setIP[Gx Ax] ->]. rewrite (eq_bigl (generator <[x]>)) => [|y]. rewrite sum1dep_card -totient_gen -[#[x]](partnC p) //. rewrite totient_coprime ?coprime_partC // dvdn_mulr // . by rewrite (pA x Ax) p_part // -expnSr totient_pfactor // dvdn_mull. rewrite /generator eq_sym andbC; case xy: {+}(_ == _) => //. rewrite !inE -!order_dvdn in Ax *. by rewrite -cycle_subG /order -(eqP xy) cycle_subG Gx. rewrite -sum1_card (partition_big_imset (fun x => x.`_p ^: G)) /=. apply: dvdn_sum => _ /imsetP[x /setIP[Gx Ax] ->]. set y := x.`_p; have oy: #[y] = (n`_p * p)%N by rewrite order_constt pA. rewrite (partition_big (fun x => x.`_p) (mem (y ^: G))) /= => [|z]; last first. by case/andP=> _ /eqP <-; rewrite /= class_refl. pose G' := ('C_G[y] / <[y]>)%G; pose n' := gcdn #|G'| n`_p^'. have n'_gt0: 0 < n' by rewrite gcdn_gt0 cardG_gt0. rewrite (eq_bigr (fun _ => #|'Ldiv_n'(G')|)) => [|_ /imsetP[a Ga ->]]. rewrite sum_nat_const -index_cent1 indexgI. rewrite -(dvdn_pmul2l (cardG_gt0 'C_G[y])) mulnA LagrangeI. have oCy: #|'C_G[y]| = (#[y] * #|G'|)%N. rewrite card_quotient ?subcent1_cycle_norm // Lagrange //. by rewrite subcent1_cycle_sub ?groupX. rewrite oCy -mulnA -(muln_lcm_gcd #|G'|) -/n' mulnA dvdn_mul //. rewrite muln_lcmr -oCy order_constt pA // mulnAC partnC // dvdn_lcm. by rewrite cardSg ?subsetIl // mulnC oG dvdn_pmul2r ?pdiv_dvd. apply: IHm; [exact: dvdn_gcdl | apply: leq_ltn_trans lt_qp_mq]. rewrite -(@divnMr n`_p^') // -muln_lcm_gcd mulnC divnMl //. rewrite leq_divRL // divn_mulAC ?leq_divLR ?dvdn_mulr ?dvdn_lcmr //. rewrite dvdn_leq ?muln_gt0 ?q_gt0 //= mulnC muln_lcmr dvdn_lcm. rewrite -(@dvdn_pmul2l n`_p) // mulnA -oy -oCy mulnCA partnC // -oG. by rewrite cardSg ?subsetIl // dvdn_mul ?pdiv_dvd. pose h := [fun z => coset <[y]> (z ^ a^-1)]. pose h' := [fun Z : coset_of <[y]> => (y * (repr Z).`_p^') ^ a]. rewrite -sum1_card (reindex_onto h h') /= => [|Z]; last first. rewrite conjgK coset_kerl ?cycle_id ?morph_constt ?repr_coset_norm //. rewrite /= coset_reprK 2!inE -order_dvdn dvdn_gcd => /and3P[_ _ p'Z]. by apply: constt_p_elt (pnat_dvd p'Z _); apply: part_pnat. apply: eq_bigl => z; apply/andP/andP=> [[]|[]]. rewrite inE -andbA => /and3P[Gz Az _] /eqP zp_ya. have czy: z ^ a^-1 \in 'C[y]. rewrite -mem_conjg -normJ conjg_set1 -zp_ya. by apply/cent1P; apply: commuteX. have Nz: z ^ a^-1 \in 'N(<[y]>) by apply: subsetP czy; apply: norm_gen. have G'z: h z \in G' by rewrite mem_morphim //= inE groupJ // groupV. rewrite inE G'z inE -order_dvdn dvdn_gcd order_dvdG //=. rewrite /order -morphim_cycle // -quotientE card_quotient ?cycle_subG //. rewrite -(@dvdn_pmul2l #[y]) // Lagrange; last first. by rewrite /= cycleJ cycle_subG mem_conjgV -zp_ya mem_cycle. rewrite oy mulnAC partnC // [#|_|]orderJ; split. by rewrite !inE -!order_dvdn mulnC in Az; case/andP: Az. set Z := coset _ _; have NZ := repr_coset_norm Z; have:= coset_reprK Z. case/kercoset_rcoset=> {NZ}// _ /cycleP[i ->] ->{Z}. rewrite consttM; last exact/commute_sym/commuteX/cent1P. rewrite (constt1P _) ?p_eltNK 1?p_eltX ?p_elt_constt // mul1g. by rewrite conjMg consttJ conjgKV -zp_ya consttC. rewrite 2!inE -order_dvdn; set Z := coset _ _ => /andP[Cz n'Z] /eqP def_z. have Nz: z ^ a^-1 \in 'N(<[y]>). rewrite -def_z conjgK groupMr; first by rewrite -(cycle_subG y) normG. by rewrite groupX ?repr_coset_norm. have{Cz} /setIP[Gz Cz]: z ^ a^-1 \in 'C_G[y]. case/morphimP: Cz => u Nu Cu /kercoset_rcoset[] // _ /cycleP[i ->] ->. by rewrite groupMr // groupX // inE groupX //; apply/cent1P. have{def_z} zp_ya: z.`_p = y ^ a. rewrite -def_z consttJ consttM. rewrite constt_p_elt ?p_elt_constt //. by rewrite (constt1P _) ?p_eltNK ?p_elt_constt ?mulg1. apply: commute_sym; apply/cent1P. by rewrite -def_z conjgK groupMl // in Cz; apply/cent1P. have ozp: #[z ^ a^-1]`_p = #[y] by rewrite -order_constt consttJ zp_ya conjgK. split; rewrite zp_ya // -class_lcoset lcoset_id // eqxx andbT. rewrite -(conjgKV a z) !inE groupJ //= -!order_dvdn orderJ; apply/andP; split. apply: contra (partn_dvd p n_gt0) _. by rewrite ozp -(muln1 n`_p) oy dvdn_pmul2l // dvdn1 neq_ltn lt1p orbT. rewrite -(partnC p n_gt0) mulnCA mulnA -oy -(@partnC p #[_]) // ozp. apply dvdn_mul => //; apply: dvdn_trans (dvdn_trans n'Z (dvdn_gcdr _ _)). rewrite {2}/order -morphim_cycle // -quotientE card_quotient ?cycle_subG //. rewrite -(@dvdn_pmul2l #|<[z ^ a^-1]> :&: <[y]>|) ?cardG_gt0 // LagrangeI. rewrite -[#|<[_]>|](partnC p) ?order_gt0 // dvdn_pmul2r // ozp. by rewrite cardSg ?subsetIr. Qed. mathcomp-1.5/theories/jordanholder.v0000644000175000017500000007174212307636117016660 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq path choice fintype. Require Import bigop finset fingroup morphism automorphism quotient action. Require Import gseries. (******************************************************************************) (* This files establishes Jordan-Holder theorems for finite groups. These *) (* theorems state the uniqueness up to permutation and isomorphism for the *) (* series of quotient built from the successive elements of any composition *) (* series of the same group. These quotients are also called factors of the *) (* composition series. To avoid the heavy use of highly polymorphic lists *) (* describing these quotient series, we introduce sections. *) (* This library defines: *) (* (G1 / G2)%sec == alias for the pair (G1, G2) of groups in the same *) (* finGroupType, coerced to the actual quotient group*) (* group G1 / G2. We call this pseudo-quotient a *) (* section of G1 and G2. *) (* section_isog s1 s2 == s1 and s2 respectively coerce to isomorphic *) (* quotient groups. *) (* section_repr s == canonical representative of the isomorphism class *) (* of the section s. *) (* mksrepr G1 G2 == canonical representative of the isomorphism class *) (* of (G1 / G2)%sec. *) (* mkfactors G s == if s is [:: s1, s2, ..., sn], constructs the list *) (* [:: mksrepr G s1, mksrepr s1 s2, ..., mksrepr sn-1 sn] *) (* comps G s == s is a composition series for G i.e. s is a *) (* decreasing sequence of subgroups of G *) (* in which two adjacent elements are maxnormal one *) (* in the other and the last element of s is 1. *) (* Given aT and rT two finGroupTypes, (D : {group rT}), (A : {group aT}) and *) (* (to : groupAction A D) an external action. *) (* maxainv to B C == C is a maximal proper normal subgroup of B *) (* invariant by (the external action of A via) to. *) (* asimple to B == the maximal proper normal subgroup of B invariant *) (* by the external action to is trivial. *) (* acomps to G s == s is a composition series for G invariant by to, *) (* i.e. s is a decreasing sequence of subgroups of G *) (* in which two adjacent elements are maximally *) (* invariant by to one in the other and the *) (* last element of s is 1. *) (* We prove two versions of the result: *) (* - JordanHolderUniqueness establishes the uniqueness up to permutation *) (* and isomorphism of the lists of factors in composition series of a *) (* given group. *) (* - StrongJordanHolderUniqueness extends the result to composition series *) (* invariant by an external group action. *) (* See also "The Rooster and the Butterflies", proceedings of Calculemus 2013,*) (* by Assia Mahboubi. *) (******************************************************************************) Import GroupScope. Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Inductive section (gT : finGroupType) := GSection of {group gT} * {group gT}. Delimit Scope section_scope with sec. Bind Scope section_scope with section. Definition mkSec (gT : finGroupType) (G1 G2 : {group gT}) := GSection (G1, G2). Infix "/" := mkSec : section_scope. Coercion pair_of_section gT (s : section gT) := let: GSection u := s in u. Coercion quotient_of_section gT (s : section gT) : GroupSet.sort _ := s.1 / s.2. Coercion section_group gT (s : section gT) : {group (coset_of s.2)} := Eval hnf in [group of s]. Section Sections. Variables (gT : finGroupType). Implicit Types (G : {group gT}) (s : section gT). Canonical section_subType := Eval hnf in [newType for @pair_of_section gT]. Definition section_eqMixin := Eval hnf in [eqMixin of section gT by <:]. Canonical section_eqType := Eval hnf in EqType (section gT) section_eqMixin. Definition section_choiceMixin := [choiceMixin of section gT by <:]. Canonical section_choiceType := Eval hnf in ChoiceType (section gT) section_choiceMixin. Definition section_countMixin := [countMixin of section gT by <:]. Canonical section_countType := Eval hnf in CountType (section gT) section_countMixin. Canonical section_subCountType := Eval hnf in [subCountType of section gT]. Definition section_finMixin := [finMixin of section gT by <:]. Canonical section_finType := Eval hnf in FinType (section gT) section_finMixin. Canonical section_subFinType := Eval hnf in [subFinType of section gT]. Canonical section_group. (* Isomorphic sections *) Definition section_isog := [rel x y : section gT | x \isog y]. (* A witness of the isomorphism class of a section *) Definition section_repr s := odflt (1 / 1)%sec (pick (section_isog ^~ s)). Definition mksrepr G1 G2 := section_repr (mkSec G1 G2). Lemma section_reprP s : section_repr s \isog s. Proof. by rewrite /section_repr; case: pickP => //= /(_ s); rewrite isog_refl. Qed. Lemma section_repr_isog s1 s2 : s1 \isog s2 -> section_repr s1 = section_repr s2. Proof. by move=> iso12; congr (odflt _ _); apply: eq_pick => s; exact: isog_transr. Qed. Definition mkfactors (G : {group gT}) (s : seq {group gT}) := map section_repr (pairmap (@mkSec _) G s). End Sections. Section CompositionSeries. Variable gT : finGroupType. Local Notation gTg := {group gT}. Implicit Types (G : gTg) (s : seq gTg). Local Notation compo := [rel x y : {set gT} | maxnormal y x x]. Definition comps G s := ((last G s) == 1%G) && compo.-series G s. Lemma compsP G s : reflect (last G s = 1%G /\ path [rel x y : gTg | maxnormal y x x] G s) (comps G s). Proof. by apply: (iffP andP) => [] [/eqP]. Qed. Lemma trivg_comps G s : comps G s -> (G :==: 1) = (s == [::]). Proof. case/andP=> ls cs; apply/eqP/eqP=> [G1 | s1]; last first. by rewrite s1 /= in ls; apply/eqP. by case: s {ls} cs => //= H s /andP[/maxgroupp]; rewrite G1 /proper sub1G andbF. Qed. Lemma comps_cons G H s : comps G (H :: s) -> comps H s. Proof. by case/andP => /= ls /andP[_]; rewrite /comps ls. Qed. Lemma simple_compsP G s : comps G s -> reflect (s = [:: 1%G]) (simple G). Proof. move=> cs; apply: (iffP idP) => [|s1]; last first. by rewrite s1 /comps eqxx /= andbT -simple_maxnormal in cs. case: s cs => [/trivg_comps/eqP-> | H s]; first by case/simpleP; rewrite eqxx. rewrite [comps _ _]andbCA /= => /andP[/maxgroupp maxH /trivg_comps/esym nil_s]. rewrite simple_maxnormal => /maxgroupP[_ simG]. have H1: H = 1%G by apply/val_inj/simG; rewrite // sub1G. by move: nil_s; rewrite H1 eqxx => /eqP->. Qed. Lemma exists_comps (G : gTg) : exists s, comps G s. Proof. elim: {G} #|G| {1 3}G (leqnn #|G|) => [G | n IHn G cG]. by rewrite leqNgt cardG_gt0. have [sG | nsG] := boolP (simple G). by exists [:: 1%G]; rewrite /comps eqxx /= -simple_maxnormal andbT. have [-> | ntG] := eqVneq G 1%G; first by exists [::]; rewrite /comps eqxx. have [N maxN] := ex_maxnormal_ntrivg ntG. have [|s /andP[ls cs]] := IHn N. by rewrite -ltnS (leq_trans _ cG) // proper_card // (maxnormal_proper maxN). by exists (N :: s); exact/and3P. Qed. (******************************************************************************) (* The factors associated to two composition series of the same group are *) (* the same up to isomorphism and permutation *) (******************************************************************************) Lemma JordanHolderUniqueness (G : gTg) (s1 s2 : seq gTg) : comps G s1 -> comps G s2 -> perm_eq (mkfactors G s1) (mkfactors G s2). Proof. elim: {G}#|G| {-2}G (leqnn #|G|) => [|n Hi] G cG in s1 s2 * => cs1 cs2. by rewrite leqNgt cardG_gt0 in cG. have [G1 | ntG] := boolP (G :==: 1). have -> : s1 = [::] by apply/eqP; rewrite -(trivg_comps cs1). have -> : s2 = [::] by apply/eqP; rewrite -(trivg_comps cs2). by rewrite /= perm_eq_refl. have [sG | nsG] := boolP (simple G). by rewrite (simple_compsP cs1 sG) (simple_compsP cs2 sG) perm_eq_refl. case es1: s1 cs1 => [|N1 st1] cs1. by move: (trivg_comps cs1); rewrite eqxx; move/negP:ntG. case es2: s2 cs2 => [|N2 st2] cs2 {s1 es1}. by move: (trivg_comps cs2); rewrite eqxx; move/negP:ntG. case/andP: cs1 => /= lst1; case/andP=> maxN_1 pst1. case/andP: cs2 => /= lst2; case/andP=> maxN_2 pst2. have cN1 : #|N1| <= n. by rewrite -ltnS (leq_trans _ cG) ?proper_card ?(maxnormal_proper maxN_1). have cN2 : #|N2| <= n. by rewrite -ltnS (leq_trans _ cG) ?proper_card ?(maxnormal_proper maxN_2). case: (N1 =P N2) {s2 es2} => [eN12 |]. by rewrite eN12 /= perm_cons Hi // /comps ?lst2 //= -eN12 lst1. move/eqP; rewrite -val_eqE /=; move/eqP=> neN12. have nN1G : N1 <| G by apply: maxnormal_normal. have nN2G : N2 <| G by apply: maxnormal_normal. pose N := (N1 :&: N2)%G. have nNG : N <| G. by rewrite /normal subIset ?(normal_sub nN1G) //= normsI ?normal_norm. have iso1 : (G / N1)%G \isog (N2 / N)%G. rewrite isog_sym /= -(maxnormalM maxN_1 maxN_2) //. rewrite (@normC _ N1 N2) ?(subset_trans (normal_sub nN1G)) ?normal_norm //. by rewrite weak_second_isog ?(subset_trans (normal_sub nN2G)) ?normal_norm. have iso2 : (G / N2)%G \isog (N1 / N)%G. rewrite isog_sym /= -(maxnormalM maxN_1 maxN_2) // setIC. by rewrite weak_second_isog ?(subset_trans (normal_sub nN1G)) ?normal_norm. have [sN /andP[lsN csN]] := exists_comps N. have i1 : perm_eq (mksrepr G N1 :: mkfactors N1 st1) [:: mksrepr G N1, mksrepr N1 N & mkfactors N sN]. rewrite perm_cons -[mksrepr _ _ :: _]/(mkfactors N1 [:: N & sN]). apply: Hi=> //; rewrite /comps ?lst1 //= lsN csN andbT /=. rewrite -quotient_simple. by rewrite -(isog_simple iso2) quotient_simple. by rewrite (normalS (subsetIl N1 N2) (normal_sub nN1G)). have i2 : perm_eq (mksrepr G N2 :: mkfactors N2 st2) [:: mksrepr G N2, mksrepr N2 N & mkfactors N sN]. rewrite perm_cons -[mksrepr _ _ :: _]/(mkfactors N2 [:: N & sN]). apply: Hi=> //; rewrite /comps ?lst2 //= lsN csN andbT /=. rewrite -quotient_simple. by rewrite -(isog_simple iso1) quotient_simple. by rewrite (normalS (subsetIr N1 N2) (normal_sub nN2G)). pose fG1 := [:: mksrepr G N1, mksrepr N1 N & mkfactors N sN]. pose fG2 := [:: mksrepr G N2, mksrepr N2 N & mkfactors N sN]. have i3 : perm_eq fG1 fG2. rewrite (@perm_catCA _ [::_] [::_]) /mksrepr. rewrite (@section_repr_isog _ (mkSec _ _) (mkSec _ _) iso1). rewrite -(@section_repr_isog _ (mkSec _ _) (mkSec _ _) iso2). exact: perm_eq_refl. apply: (perm_eq_trans i1); apply: (perm_eq_trans i3); rewrite perm_eq_sym. apply: perm_eq_trans i2; exact: perm_eq_refl. Qed. End CompositionSeries. (******************************************************************************) (* Helper lemmas for group actions. *) (******************************************************************************) Section MoreGroupAction. Variables (aT rT : finGroupType). Variables (A : {group aT}) (D : {group rT}). Variable to : groupAction A D. Lemma gactsP (G : {set rT}) : reflect {acts A, on G | to} [acts A, on G | to]. Proof. apply: (iffP idP) => [nGA x|nGA]; first exact: acts_act. apply/subsetP=> a Aa; rewrite !inE; rewrite Aa. by apply/subsetP=> x; rewrite inE nGA. Qed. Lemma gactsM (N1 N2 : {set rT}) : N1 \subset D -> N2 \subset D -> [acts A, on N1 | to] -> [acts A, on N2 | to] -> [acts A, on N1 * N2 | to]. Proof. move=> sN1D sN2D aAN1 aAN2; apply/gactsP=> x Ax y. apply/idP/idP; case/mulsgP=> y1 y2 N1y1 N2y2 e. move: (actKin to Ax y); rewrite e; move<-. rewrite gactM ?groupV ?(subsetP sN1D y1) ?(subsetP sN2D) //. by apply: mem_mulg; rewrite ?(gactsP _ aAN1) ?(gactsP _ aAN2) // groupV. rewrite e gactM // ?(subsetP sN1D y1) ?(subsetP sN2D) //. by apply: mem_mulg; rewrite ?(gactsP _ aAN1) // ?(gactsP _ aAN2). Qed. Lemma gactsI (N1 N2 : {set rT}) : [acts A, on N1 | to] -> [acts A, on N2 | to] -> [acts A, on N1 :&: N2 | to]. Proof. move=> aAN1 aAN2. apply/subsetP=> x Ax; rewrite !inE Ax /=; apply/subsetP=> y Ny; rewrite inE. case/setIP: Ny=> N1y N2y; rewrite inE ?astabs_act ?N1y ?N2y //. - by move/subsetP: aAN2; move/(_ x Ax). - by move/subsetP: aAN1; move/(_ x Ax). Qed. Lemma gastabsP (S : {set rT}) (a : aT) : a \in A -> reflect (forall x, (to x a \in S) = (x \in S)) (a \in 'N(S | to)). Proof. move=> Aa; apply: (iffP idP) => [nSa x|nSa]; first exact: astabs_act. by rewrite !inE Aa; apply/subsetP=> x; rewrite inE nSa. Qed. End MoreGroupAction. (******************************************************************************) (* Helper lemmas for quotient actions. *) (******************************************************************************) Section MoreQuotientAction. Variables (aT rT : finGroupType). Variables (A : {group aT})(D : {group rT}). Variable to : groupAction A D. Lemma qact_dom_doms (H : {group rT}) : H \subset D -> qact_dom to H \subset A. Proof. by move=> sHD; apply/subsetP=> x; rewrite qact_domE // inE; case/andP. Qed. Lemma acts_qact_doms (H : {group rT}) : H \subset D -> [acts A, on H | to] -> qact_dom to H :=: A. Proof. move=> sHD aH; apply/eqP; rewrite eqEsubset; apply/andP. split; first exact: qact_dom_doms. apply/subsetP=> x Ax; rewrite qact_domE //; apply/gastabsP=> //. by move/gactsP: aH; move/(_ x Ax). Qed. Lemma qacts_cosetpre (H : {group rT}) (K' : {group coset_of H}) : H \subset D -> [acts A, on H | to] -> [acts qact_dom to H, on K' | to / H] -> [acts A, on coset H @*^-1 K' | to]. Proof. move=> sHD aH aK'; apply/subsetP=> x Ax; move: (Ax) (subsetP aK'). rewrite -{1}(acts_qact_doms sHD aH) => qdx; move/(_ x qdx) => nx. rewrite !inE Ax; apply/subsetP=> y; case/morphpreP=> Ny /= K'Hy; rewrite inE. apply/morphpreP; split; first by rewrite acts_qact_dom_norm. by move/gastabsP: nx; move/(_ qdx (coset H y)); rewrite K'Hy qactE. Qed. Lemma qacts_coset (H K : {group rT}) : H \subset D -> [acts A, on K | to] -> [acts qact_dom to H, on (coset H) @* K | to / H]. Proof. move=> sHD aK. apply/subsetP=> x qdx; rewrite inE qdx inE; apply/subsetP=> y. case/morphimP=> z Nz Kz /= e; rewrite e inE qactE // mem_imset // inE. move/gactsP: aK; move/(_ x (subsetP (qact_dom_doms sHD) _ qdx) z); rewrite Kz. move->; move/acts_act: (acts_qact_dom to H); move/(_ x qdx z). by rewrite Nz andbT. Qed. End MoreQuotientAction. Section StableCompositionSeries. Variables (aT rT : finGroupType). Variables (D : {group rT})(A : {group aT}). Variable to : groupAction A D. Definition maxainv (B C : {set rT}) := [max C of H | [&& (H <| B), ~~ (B \subset H) & [acts A, on H | to]]]. Section MaxAinvProps. Variables K N : {group rT}. Lemma maxainv_norm : maxainv K N -> N <| K. Proof. by move/maxgroupp; case/andP. Qed. Lemma maxainv_proper : maxainv K N -> N \proper K. Proof. by move/maxgroupp; case/andP; rewrite properE; move/normal_sub->; case/andP. Qed. Lemma maxainv_sub : maxainv K N -> N \subset K. Proof. move=> h; apply: proper_sub; exact: maxainv_proper. Qed. Lemma maxainv_ainvar : maxainv K N -> A \subset 'N(N | to). Proof. by move/maxgroupp; case/and3P. Qed. Lemma maxainvS : maxainv K N -> N \subset K. Proof. by move=> pNN; rewrite proper_sub // maxainv_proper. Qed. Lemma maxainv_exists : K :!=: 1 -> {N : {group rT} | maxainv K N}. Proof. move=> nt; apply: ex_maxgroup. exists [1 rT]%G. rewrite /= normal1 subG1 nt /=. apply/subsetP=> a Da; rewrite !inE Da /= sub1set !inE. by rewrite /= -actmE // morph1 eqxx. Qed. End MaxAinvProps. Lemma maxainvM (G H K : {group rT}) : H \subset D -> K \subset D -> maxainv G H -> maxainv G K -> H :<>: K -> H * K = G. Proof. move: H K => N1 N2 sN1D sN2D pmN1 pmN2 neN12. have cN12 : commute N1 N2. apply: normC; apply: (subset_trans (maxainv_sub pmN1)). by rewrite normal_norm ?maxainv_norm. wlog nsN21 : G N1 N2 sN1D sN2D pmN1 pmN2 neN12 cN12/ ~~(N1 \subset N2). move/eqP: (neN12); rewrite eqEsubset negb_and; case/orP=> ns; first by apply. by rewrite cN12; apply=> //; apply: sym_not_eq. have nP : N1 * N2 <| G by rewrite normalM ?maxainv_norm. have sN2P : N2 \subset N1 * N2 by rewrite mulg_subr ?group1. case/maxgroupP: (pmN1); case/andP=> nN1G pN1G mN1. case/maxgroupP: (pmN2); case/andP=> nN2G pN2G mN2. case/andP: pN1G=> nsGN1 ha1; case/andP: pN2G=> nsGN2 ha2. case e : (G \subset N1 * N2). by apply/eqP; rewrite eqEsubset e mulG_subG !normal_sub. have: N1 <*> N2 = N2 by apply: mN2; rewrite /= ?comm_joingE // nP e /= gactsM. by rewrite comm_joingE // => h; move: nsN21; rewrite -h mulg_subl. Qed. Definition asimple (K : {set rT}) := maxainv K 1. Implicit Types (H K : {group rT}) (s : seq {group rT}). Lemma asimpleP K : reflect [/\ K :!=: 1 & forall H, H <| K -> [acts A, on H | to] -> H :=: 1 \/ H :=: K] (asimple K). Proof. apply: (iffP idP). case/maxgroupP; rewrite normal1 /=; case/andP=> nsK1 aK H1. rewrite eqEsubset negb_and nsK1 /=; split => // H nHK ha. case eHK : (H :==: K); first by right; apply/eqP. left; apply: H1; rewrite ?sub1G // nHK; move/negbT: eHK. by rewrite eqEsubset negb_and normal_sub //=; move->. case=> ntK h; apply/maxgroupP; split. move: ntK; rewrite eqEsubset sub1G andbT normal1; move->. apply/subsetP=> a Da; rewrite !inE Da /= sub1set !inE. by rewrite /= -actmE // morph1 eqxx. move=> H /andP[nHK /andP[nsKH ha]] _. case: (h _ nHK ha)=> // /eqP; rewrite eqEsubset. by rewrite (negbTE nsKH) andbF. Qed. Definition acomps K s := ((last K s) == 1%G) && path [rel x y : {group rT} | maxainv x y] K s. Lemma acompsP K s : reflect (last K s = 1%G /\ path [rel x y : {group rT} | maxainv x y] K s) (acomps K s). Proof. by apply: (iffP andP); case; move/eqP. Qed. Lemma trivg_acomps K s : acomps K s -> (K :==: 1) = (s == [::]). Proof. case/andP=> ls cs; apply/eqP/eqP; last first. by move=> se; rewrite se /= in ls; apply/eqP. move=> G1; case: s ls cs => // H s _ /=; case/andP; case/maxgroupP. by rewrite G1 sub1G andbF. Qed. Lemma acomps_cons K H s : acomps K (H :: s) -> acomps H s. Proof. by case/andP => /= ls; case/andP=> _ p; rewrite /acomps ls. Qed. Lemma asimple_acompsP K s : acomps K s -> reflect (s = [:: 1%G]) (asimple K). Proof. move=> cs; apply: (iffP idP); last first. by move=> se; move: cs; rewrite se /=; case/andP=> /=; rewrite andbT. case: s cs. by rewrite /acomps /= andbT; move/eqP->; case/asimpleP; rewrite eqxx. move=> H s cs sG; apply/eqP. rewrite eqseq_cons -(trivg_acomps (acomps_cons cs)) andbC andbb. case/acompsP: cs => /= ls; case/andP=> mH ps. case/maxgroupP: sG; case/and3P => _ ntG _ ->; rewrite ?sub1G //. rewrite (maxainv_norm mH); case/andP: (maxainv_proper mH)=> _ ->. exact: (maxainv_ainvar mH). Qed. Lemma exists_acomps K : exists s, acomps K s. Proof. elim: {K} #|K| {1 3}K (leqnn #|K|) => [K | n Hi K cK]. by rewrite leqNgt cardG_gt0. case/orP: (orbN (asimple K)) => [sK | nsK]. by exists [:: (1%G : {group rT})]; rewrite /acomps eqxx /= andbT. case/orP: (orbN (K :==: 1))=> [tK | ntK]. by exists (Nil _); rewrite /acomps /= andbT. case: (maxainv_exists ntK)=> N pmN. have cN: #|N| <= n. by rewrite -ltnS (leq_trans _ cK) // proper_card // (maxainv_proper pmN). case: (Hi _ cN)=> s; case/andP=> lasts ps; exists [:: N & s]; rewrite /acomps. by rewrite last_cons lasts /= pmN. Qed. End StableCompositionSeries. Arguments Scope maxainv [_ _ Group_scope Group_scope groupAction_scope group_scope group_scope]. Arguments Scope asimple [_ _ Group_scope Group_scope groupAction_scope group_scope]. Section StrongJordanHolder. Section AuxiliaryLemmas. Variables aT rT : finGroupType. Variables (A : {group aT}) (D : {group rT}) (to : groupAction A D). Lemma maxainv_asimple_quo (G H : {group rT}) : H \subset D -> maxainv to G H -> asimple (to / H) (G / H). Proof. move=> sHD /maxgroupP[/and3P[nHG pHG aH] Hmax]. apply/asimpleP; split; first by rewrite -subG1 quotient_sub1 ?normal_norm. move=> K' nK'Q aK'. have: (K' \proper (G / H)) || (G / H == K'). by rewrite properE eqEsubset andbC (normal_sub nK'Q) !andbT orbC orbN. case/orP=> [ pHQ | eQH]; last by right; apply sym_eq; apply/eqP. left; pose K := ((coset H) @*^-1 K')%G. have eK'I : K' \subset (coset H) @* 'N(H). by rewrite (subset_trans (normal_sub nK'Q)) ?morphimS ?normal_norm. have eKK' : K' :=: K / H by rewrite /(K / H) morphpreK //=. suff eKH : K :=: H by rewrite -trivg_quotient eKK' eKH. have sHK : H \subset K by rewrite -ker_coset kerE morphpreS // sub1set group1. apply: Hmax => //; apply/and3P; split; last exact: qacts_cosetpre. by rewrite -(quotientGK nHG) cosetpre_normal. by move: (proper_subn pHQ); rewrite sub_morphim_pre ?normal_norm. Qed. Lemma asimple_quo_maxainv (G H : {group rT}) : H \subset D -> G \subset D -> [acts A, on G | to] -> [acts A, on H | to] -> H <| G -> asimple (to / H) (G / H) -> maxainv to G H. Proof. move=> sHD sGD aG aH nHG /asimpleP[ntQ maxQ]; apply/maxgroupP; split. by rewrite nHG -quotient_sub1 ?normal_norm // subG1 ntQ. move=> K /and3P[nKG nsGK aK] sHK. pose K' := (K / H)%G. have K'dQ : K' <| (G / H)%G by apply: morphim_normal. have nKH : H <| K by rewrite (normalS _ _ nHG) // normal_sub. have: K' :=: 1%G \/ K' :=: (G / H). apply: (maxQ K' K'dQ) => /=. apply/subsetP=> x Adx. rewrite inE Adx /= inE. apply/subsetP=> y. rewrite quotientE; case/morphimP=> z Nz Kz ->; rewrite /= !inE qactE //. have ntoyx : to z x \in 'N(H) by rewrite (acts_qact_dom_norm Adx). apply/morphimP; exists (to z x) => //. suff h: qact_dom to H \subset A. by rewrite astabs_act // (subsetP aK) //; apply: (subsetP h). by apply/subsetP=> t; rewrite qact_domE // inE; case/ andP. case; last first. move/quotient_injG; rewrite !inE /=; move/(_ nKH nHG)=> c; move: nsGK. by rewrite c subxx. rewrite /= -trivg_quotient; move=> tK'; apply:(congr1 (@gval _)); move: tK'. by apply: (@quotient_injG _ H); rewrite ?inE /= ?normal_refl. Qed. Lemma asimpleI (N1 N2 : {group rT}) : N2 \subset 'N(N1) -> N1 \subset D -> [acts A, on N1 | to] -> [acts A, on N2 | to] -> asimple (to / N1) (N2 / N1) -> asimple (to / (N2 :&: N1)) (N2 / (N2 :&: N1)). Proof. move=> nN21 sN1D aN1 aN2 /asimpleP[ntQ1 max1]. have [f1 [f1e f1ker f1pre f1im]] := restrmP (coset_morphism N1) nN21. have hf2' : N2 \subset 'N(N2 :&: N1) by apply: normsI => //; rewrite normG. have hf2'' : 'ker (coset (N2 :&: N1)) \subset 'ker f1. by rewrite f1ker !ker_coset. pose f2 := factm_morphism hf2'' hf2'. apply/asimpleP; split. rewrite /= setIC; apply/negP; move: (second_isog nN21); move/isog_eq1->. by apply/negP. move=> H nHQ2 aH; pose K := f2 @* H. have nKQ1 : K <| N2 / N1. rewrite (_ : N2 / N1 = f2 @* (N2 / (N2 :&: N1))) ?morphim_normal //. by rewrite morphim_factm f1im. have sqA : qact_dom to N1 \subset A. by apply/subsetP=> t; rewrite qact_domE // inE; case/andP. have nNN2 : (N2 :&: N1) <| N2. rewrite /normal subsetIl; apply: normsI => //; exact: normG. have aKQ1 : [acts qact_dom to N1, on K | to / N1]. pose H':= coset (N2 :&: N1)@*^-1 H. have eHH' : H :=: H' / (N2 :&: N1) by rewrite cosetpreK. have -> : K :=: f1 @* H' by rewrite /K eHH' morphim_factm. have sH'N2 : H' \subset N2. rewrite /H' eHH' quotientGK ?normal_cosetpre //=. by rewrite sub_cosetpre_quo ?normal_sub. have -> : f1 @* H' = coset N1 @* H' by rewrite f1im //=. apply: qacts_coset => //; apply: qacts_cosetpre => //; last exact: gactsI. by apply: (subset_trans (subsetIr _ _)). have injf2 : 'injm f2. by rewrite ker_factm f1ker /= ker_coset /= subG1 /= -quotientE trivg_quotient. have iHK : H \isog K. apply/isogP; pose f3 := restrm_morphism (normal_sub nHQ2) f2. by exists f3; rewrite 1?injm_restrm // morphim_restrm setIid. case: (max1 _ nKQ1 aKQ1). by move/eqP; rewrite -(isog_eq1 iHK); move/eqP->; left. move=> he /=; right; apply/eqP; rewrite eqEcard normal_sub //=. move: (second_isog nN21); rewrite setIC; move/card_isog->; rewrite -he. by move/card_isog: iHK=> <-; rewrite leqnn. Qed. End AuxiliaryLemmas. Variables (aT rT : finGroupType). Variables (A : {group aT}) (D : {group rT}) (to : groupAction A D). (******************************************************************************) (* The factors associated to two A-stable composition series of the same *) (* group are the same up to isomorphism and permutation *) (******************************************************************************) Lemma StrongJordanHolderUniqueness (G : {group rT}) (s1 s2 : seq {group rT}) : G \subset D -> acomps to G s1 -> acomps to G s2 -> perm_eq (mkfactors G s1) (mkfactors G s2). Proof. elim: {G} #|G| {-2}G (leqnn #|G|) => [|n Hi] G cG in s1 s2 * => hsD cs1 cs2. by rewrite leqNgt cardG_gt0 in cG. case/orP: (orbN (G :==: 1)) => [tG | ntG]. have -> : s1 = [::] by apply/eqP; rewrite -(trivg_acomps cs1). have -> : s2 = [::] by apply/eqP; rewrite -(trivg_acomps cs2). by rewrite /= perm_eq_refl. case/orP: (orbN (asimple to G))=> [sG | nsG]. have -> : s1 = [:: 1%G ] by apply/(asimple_acompsP cs1). have -> : s2 = [:: 1%G ] by apply/(asimple_acompsP cs2). by rewrite /= perm_eq_refl. case es1: s1 cs1 => [|N1 st1] cs1. by move: (trivg_comps cs1); rewrite eqxx; move/negP:ntG. case es2: s2 cs2 => [|N2 st2] cs2 {s1 es1}. by move: (trivg_comps cs2); rewrite eqxx; move/negP:ntG. case/andP: cs1 => /= lst1; case/andP=> maxN_1 pst1. case/andP: cs2 => /= lst2; case/andP=> maxN_2 pst2. have sN1D : N1 \subset D. by apply: subset_trans hsD; apply: maxainv_sub maxN_1. have sN2D : N2 \subset D. by apply: subset_trans hsD; apply: maxainv_sub maxN_2. have cN1 : #|N1| <= n. by rewrite -ltnS (leq_trans _ cG) ?proper_card ?(maxainv_proper maxN_1). have cN2 : #|N2| <= n. by rewrite -ltnS (leq_trans _ cG) ?proper_card ?(maxainv_proper maxN_2). case: (N1 =P N2) {s2 es2} => [eN12 |]. by rewrite eN12 /= perm_cons Hi // /acomps ?lst2 //= -eN12 lst1. move/eqP; rewrite -val_eqE /=; move/eqP=> neN12. have nN1G : N1 <| G by apply: (maxainv_norm maxN_1). have nN2G : N2 <| G by apply: (maxainv_norm maxN_2). pose N := (N1 :&: N2)%G. have nNG : N <| G. by rewrite /normal subIset ?(normal_sub nN1G) //= normsI ?normal_norm. have iso1 : (G / N1)%G \isog (N2 / N)%G. rewrite isog_sym /= -(maxainvM _ _ maxN_1 maxN_2) //. rewrite (@normC _ N1 N2) ?(subset_trans (normal_sub nN1G)) ?normal_norm //. by rewrite weak_second_isog ?(subset_trans (normal_sub nN2G)) ?normal_norm. have iso2 : (G / N2)%G \isog (N1 / N)%G. rewrite isog_sym /= -(maxainvM _ _ maxN_1 maxN_2) // setIC. by rewrite weak_second_isog ?(subset_trans (normal_sub nN1G)) ?normal_norm. case: (exists_acomps to N)=> sN; case/andP=> lsN csN. have aN1 : [acts A, on N1 | to]. by case/maxgroupP: maxN_1; case/and3P. have aN2 : [acts A, on N2 | to]. by case/maxgroupP: maxN_2; case/and3P. have nNN1 : N <| N1. by apply: (normalS _ _ nNG); rewrite ?subsetIl ?normal_sub. have nNN2 : N <| N2. by apply: (normalS _ _ nNG); rewrite ?subsetIr ?normal_sub. have aN : [ acts A, on N1 :&: N2 | to]. apply/subsetP=> x Ax; rewrite !inE Ax /=; apply/subsetP=> y Ny; rewrite inE. case/setIP: Ny=> N1y N2y. rewrite inE ?astabs_act ?N1y ?N2y //. by move/subsetP: aN2; move/(_ x Ax). by move/subsetP: aN1; move/(_ x Ax). have i1 : perm_eq (mksrepr G N1 :: mkfactors N1 st1) [:: mksrepr G N1, mksrepr N1 N & mkfactors N sN]. rewrite perm_cons -[mksrepr _ _ :: _]/(mkfactors N1 [:: N & sN]). apply: Hi=> //; rewrite /acomps ?lst1 //= lsN csN andbT /=. apply: asimple_quo_maxainv=> //; first by apply: subIset; rewrite sN1D. apply: asimpleI => //. apply: subset_trans (normal_norm nN2G); exact: normal_sub. rewrite -quotientMidl (maxainvM _ _ maxN_2) //. by apply: maxainv_asimple_quo. by move=> e; apply: neN12. have i2 : perm_eq (mksrepr G N2 :: mkfactors N2 st2) [:: mksrepr G N2, mksrepr N2 N & mkfactors N sN]. rewrite perm_cons -[mksrepr _ _ :: _]/(mkfactors N2 [:: N & sN]). apply: Hi=> //; rewrite /acomps ?lst2 //= lsN csN andbT /=. apply: asimple_quo_maxainv=> //; first by apply: subIset; rewrite sN1D. have e : N1 :&: N2 :=: N2 :&: N1 by rewrite setIC. rewrite (group_inj (setIC N1 N2)); apply: asimpleI => //. apply: subset_trans (normal_norm nN1G); exact: normal_sub. rewrite -quotientMidl (maxainvM _ _ maxN_1) //. exact: maxainv_asimple_quo. pose fG1 := [:: mksrepr G N1, mksrepr N1 N & mkfactors N sN]. pose fG2 := [:: mksrepr G N2, mksrepr N2 N & mkfactors N sN]. have i3 : perm_eq fG1 fG2. rewrite (@perm_catCA _ [::_] [::_]) /mksrepr. rewrite (@section_repr_isog _ (mkSec _ _) (mkSec _ _) iso1). rewrite -(@section_repr_isog _ (mkSec _ _) (mkSec _ _) iso2). exact: perm_eq_refl. apply: (perm_eq_trans i1); apply: (perm_eq_trans i3); rewrite perm_eq_sym. apply: perm_eq_trans i2; exact: perm_eq_refl. Qed. End StrongJordanHolder. mathcomp-1.5/theories/hall.v0000644000175000017500000012273112307636117015120 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div fintype finset. Require Import prime fingroup morphism automorphism quotient action gproduct. Require Import commutator center pgroup finmodule nilpotent sylow. Require Import abelian maximal. (*****************************************************************************) (* In this files we prove the Schur-Zassenhaus splitting and transitivity *) (* theorems (under solvability assumptions), then derive P. Hall's *) (* generalization of Sylow's theorem to solvable groups and its corollaries, *) (* in particular the theory of coprime action. We develop both the theory of *) (* coprime action of a solvable group on Sylow subgroups (as in Aschbacher *) (* 18.7), and that of coprime action on Hall subgroups of a solvable group *) (* as per B & G, Proposition 1.5; however we only support external group *) (* action (as opposed to internal action by conjugation) for the latter case *) (* because it is much harder to apply in practice. *) (*****************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section Hall. Implicit Type gT : finGroupType. Theorem SchurZassenhaus_split gT (G H : {group gT}) : Hall G H -> H <| G -> [splits G, over H]. Proof. move: {2}_.+1 (ltnSn #|G|) => n; elim: n => // n IHn in gT G H *. rewrite ltnS => Gn hallH nsHG; have [sHG nHG] := andP nsHG. have [-> | [p pr_p pH]] := trivgVpdiv H. by apply/splitsP; exists G; rewrite inE -subG1 subsetIl mul1g eqxx. have [P sylP] := Sylow_exists p H. case nPG: (P <| G); last first. pose N := ('N_G(P))%G; have sNG: N \subset G by rewrite subsetIl. have eqHN_G: H * N = G by exact: Frattini_arg sylP. pose H' := (H :&: N)%G. have nsH'N: H' <| N. by rewrite /normal subsetIr normsI ?normG ?(subset_trans sNG). have eq_iH: #|G : H| = #|N| %/ #|H'|. rewrite -divgS // -(divnMl (cardG_gt0 H')) mulnC -eqHN_G. by rewrite -mul_cardG (mulnC #|H'|) divnMl // cardG_gt0. have hallH': Hall N H'. rewrite /Hall -divgS subsetIr //= -eq_iH. by case/andP: hallH => _; apply: coprimeSg; exact: subsetIl. have: [splits N, over H']. apply: IHn hallH' nsH'N; apply: {n}leq_trans Gn. rewrite proper_card // properEneq sNG andbT; apply/eqP=> eqNG. by rewrite -eqNG normal_subnorm (subset_trans (pHall_sub sylP)) in nPG. case/splitsP=> K /complP[tiKN eqH'K]. have sKN: K \subset N by rewrite -(mul1g K) -eqH'K mulSg ?sub1set. apply/splitsP; exists K; rewrite inE -subG1; apply/andP; split. by rewrite /= -(setIidPr sKN) setIA tiKN. by rewrite eqEsubset -eqHN_G mulgS // -eqH'K mulGS mulSg ?subsetIl. pose Z := 'Z(P); pose Gbar := G / Z; pose Hbar := H / Z. have sZP: Z \subset P by exact: center_sub. have sZH: Z \subset H by exact: subset_trans (pHall_sub sylP). have sZG: Z \subset G by exact: subset_trans sHG. have nZG: Z <| G by apply: char_normal_trans nPG; exact: center_char. have nZH: Z <| H by exact: normalS nZG. have nHGbar: Hbar <| Gbar by exact: morphim_normal. have hallHbar: Hall Gbar Hbar by apply: morphim_Hall (normal_norm _) _. have: [splits Gbar, over Hbar]. apply: IHn => //; apply: {n}leq_trans Gn; rewrite ltn_quotient //. apply/eqP=> /(trivg_center_pgroup (pHall_pgroup sylP))/eqP. rewrite trivg_card1 (card_Hall sylP) p_part -(expn0 p). by rewrite eqn_exp2l ?prime_gt1 // lognE pH pr_p cardG_gt0. case/splitsP=> Kbar /complP[tiHKbar eqHKbar]. have: Kbar \subset Gbar by rewrite -eqHKbar mulG_subr. case/inv_quotientS=> //= ZK quoZK sZZK sZKG. have nZZK: Z <| ZK by exact: normalS nZG. have cardZK: #|ZK| = (#|Z| * #|G : H|)%N. rewrite -(Lagrange sZZK); congr (_ * _)%N. rewrite -card_quotient -?quoZK; last by case/andP: nZZK. rewrite -(divgS sHG) -(Lagrange sZG) -(Lagrange sZH) divnMl //. rewrite -!card_quotient ?normal_norm //= -/Gbar -/Hbar. by rewrite -eqHKbar (TI_cardMg tiHKbar) mulKn. have: [splits ZK, over Z]. rewrite (Gaschutz_split nZZK _ sZZK) ?center_abelian //; last first. rewrite -divgS // cardZK mulKn ?cardG_gt0 //. by case/andP: hallH => _; exact: coprimeSg. by apply/splitsP; exists 1%G; rewrite inE -subG1 subsetIr mulg1 eqxx. case/splitsP=> K /complP[tiZK eqZK]. have sKZK: K \subset ZK by rewrite -(mul1g K) -eqZK mulSg ?sub1G. have tiHK: H :&: K = 1. apply/trivgP; rewrite /= -(setIidPr sKZK) setIA -tiZK setSI //. rewrite -quotient_sub1; last by rewrite subIset 1?normal_norm. by rewrite /= quotientGI //= -quoZK tiHKbar. apply/splitsP; exists K; rewrite inE tiHK ?eqEcard subxx leqnn /=. rewrite mul_subG ?(subset_trans sKZK) //= TI_cardMg //. rewrite -(@mulKn #|K| #|Z|) ?cardG_gt0 // -TI_cardMg // eqZK. by rewrite cardZK mulKn ?cardG_gt0 // Lagrange. Qed. Theorem SchurZassenhaus_trans_sol gT (H K K1 : {group gT}) : solvable H -> K \subset 'N(H) -> K1 \subset H * K -> coprime #|H| #|K| -> #|K1| = #|K| -> exists2 x, x \in H & K1 :=: K :^ x. Proof. move: {2}_.+1 (ltnSn #|H|) => n; elim: n => // n IHn in gT H K K1 *. rewrite ltnS => leHn solH nHK; have [-> | ] := eqsVneq H 1. rewrite mul1g => sK1K _ eqK1K; exists 1; first exact: set11. by apply/eqP; rewrite conjsg1 eqEcard sK1K eqK1K /=. pose G := (H <*> K)%G. have defG: G :=: H * K by rewrite -normC // -norm_joinEl // joingC. have sHG: H \subset G by exact: joing_subl. have sKG: K \subset G by exact: joing_subr. have nsHG: H <| G by rewrite /(H <| G) sHG join_subG normG. case/(solvable_norm_abelem solH nsHG)=> M [sMH nsMG ntM] /and3P[_ abelM _]. have [sMG nMG] := andP nsMG; rewrite -defG => sK1G coHK oK1K. have nMsG (L : {set gT}): L \subset G -> L \subset 'N(M). by move/subset_trans->. have [coKM coHMK]: coprime #|M| #|K| /\ coprime #|H / M| #|K|. by apply/andP; rewrite -coprime_mull card_quotient ?nMsG ?Lagrange. have oKM (K' : {group gT}): K' \subset G -> #|K'| = #|K| -> #|K' / M| = #|K|. move=> sK'G oK'. rewrite -quotientMidr -?norm_joinEl ?card_quotient ?nMsG //; last first. by rewrite gen_subG subUset sK'G. rewrite -divgS /=; last by rewrite -gen_subG genS ?subsetUr. by rewrite norm_joinEl ?nMsG // coprime_cardMg ?mulnK // oK' coprime_sym. have [xb]: exists2 xb, xb \in H / M & K1 / M = (K / M) :^ xb. apply: IHn; try by rewrite (quotient_sol, morphim_norms, oKM K) ?(oKM K1). by apply: leq_trans leHn; rewrite ltn_quotient. by rewrite -morphimMl ?nMsG // -defG morphimS. case/morphimP=> x nMx Hx ->{xb} eqK1Kx; pose K2 := (K :^ x)%G. have{eqK1Kx} eqK12: K1 / M = K2 / M by rewrite quotientJ. suff [y My ->]: exists2 y, y \in M & K1 :=: K2 :^ y. by exists (x * y); [rewrite groupMl // (subsetP sMH) | rewrite conjsgM]. have nMK1: K1 \subset 'N(M) by exact: nMsG. have defMK: M * K1 = M <*> K1 by rewrite -normC // -norm_joinEl // joingC. have sMKM: M \subset M <*> K1 by rewrite joing_subl. have nMKM: M <| M <*> K1 by rewrite normalYl. have trMK1: M :&: K1 = 1 by rewrite coprime_TIg ?oK1K. have trMK2: M :&: K2 = 1 by rewrite coprime_TIg ?cardJg ?oK1K. apply: (Gaschutz_transitive nMKM _ sMKM) => //=; last 2 first. - by rewrite inE trMK1 defMK !eqxx. - by rewrite -!(setIC M) trMK1. - by rewrite -divgS //= -defMK coprime_cardMg oK1K // mulKn. rewrite inE trMK2 eqxx eq_sym eqEcard /= -defMK andbC. by rewrite !coprime_cardMg ?cardJg ?oK1K ?leqnn //= mulGS -quotientSK -?eqK12. Qed. Lemma SchurZassenhaus_trans_actsol gT (G A B : {group gT}) : solvable A -> A \subset 'N(G) -> B \subset A <*> G -> coprime #|G| #|A| -> #|A| = #|B| -> exists2 x, x \in G & B :=: A :^ x. Proof. set AG := A <*> G; move: {2}_.+1 (ltnSn #|AG|) => n. elim: n => // n IHn in gT A B G AG *. rewrite ltnS => leAn solA nGA sB_AG coGA oAB. have [A1 | ntA] := eqsVneq A 1. by exists 1; rewrite // conjsg1 A1 (@card1_trivg _ B) // -oAB A1 cards1. have [M [sMA nsMA ntM]] := solvable_norm_abelem solA (normal_refl A) ntA. case/is_abelemP=> q q_pr /abelem_pgroup qM; have nMA := normal_norm nsMA. have defAG: AG = A * G := norm_joinEl nGA. have sA_AG: A \subset AG := joing_subl _ _. have sG_AG: G \subset AG := joing_subr _ _. have sM_AG := subset_trans sMA sA_AG. have oAG: #|AG| = (#|A| * #|G|)%N by rewrite defAG coprime_cardMg 1?coprime_sym. have q'G: #|G|`_q = 1%N. rewrite part_p'nat ?p'natE -?prime_coprime // coprime_sym. have [_ _ [k oM]] := pgroup_pdiv qM ntM. by rewrite -(@coprime_pexpr k.+1) // -oM (coprimegS sMA). have coBG: coprime #|B| #|G| by rewrite -oAB coprime_sym. have defBG: B * G = AG. by apply/eqP; rewrite eqEcard mul_subG ?sG_AG //= oAG oAB coprime_cardMg. case nMG: (G \subset 'N(M)). have nsM_AG: M <| AG by rewrite /normal sM_AG join_subG nMA. have nMB: B \subset 'N(M) := subset_trans sB_AG (normal_norm nsM_AG). have sMB: M \subset B. have [Q sylQ]:= Sylow_exists q B; have sQB := pHall_sub sylQ. apply: subset_trans (normal_sub_max_pgroup (Hall_max _) qM nsM_AG) (sQB). rewrite pHallE (subset_trans sQB) //= oAG partnM // q'G muln1 oAB. by rewrite (card_Hall sylQ). have defAGq: AG / M = (A / M) <*> (G / M). by rewrite quotient_gen ?quotientU ?subUset ?nMA. have: B / M \subset (A / M) <*> (G / M) by rewrite -defAGq quotientS. case/IHn; rewrite ?morphim_sol ?quotient_norms ?coprime_morph //. - by rewrite -defAGq (leq_trans _ leAn) ?ltn_quotient. - by rewrite !card_quotient // -!divgS // oAB. move=> Mx; case/morphimP=> x Nx Gx ->{Mx} //; rewrite -quotientJ //= => defBq. exists x => //; apply: quotient_inj defBq; first by rewrite /normal sMB. by rewrite -(normsP nMG x Gx) /normal normJ !conjSg. pose K := M <*> G; pose R := K :&: B; pose N := 'N_G(M). have defK: K = M * G by rewrite -norm_joinEl ?(subset_trans sMA). have oK: #|K| = (#|M| * #|G|)%N. by rewrite defK coprime_cardMg // coprime_sym (coprimegS sMA). have sylM: q.-Sylow(K) M. by rewrite pHallE joing_subl /= oK partnM // q'G muln1 part_pnat_id. have sylR: q.-Sylow(K) R. rewrite pHallE subsetIl /= -(card_Hall sylM) -(@eqn_pmul2r #|G|) // -oK. rewrite -coprime_cardMg ?(coprimeSg _ coBG) ?subsetIr //=. by rewrite group_modr ?joing_subr ?(setIidPl _) // defBG join_subG sM_AG. have [mx] := Sylow_trans sylM sylR. rewrite /= -/K defK; case/imset2P=> m x Mm Gx ->{mx}. rewrite conjsgM conjGid {m Mm}// => defR. have sNG: N \subset G := subsetIl _ _. have pNG: N \proper G by rewrite /proper sNG subsetI subxx nMG. have nNA: A \subset 'N(N) by rewrite normsI ?norms_norm. have: B :^ x^-1 \subset A <*> N. rewrite norm_joinEl ?group_modl // -defAG subsetI !sub_conjgV -normJ -defR. rewrite conjGid ?(subsetP sG_AG) // normsI ?normsG // (subset_trans sB_AG) //. by rewrite join_subG normsM // -defK normsG ?joing_subr. do [case/IHn; rewrite ?cardJg ?(coprimeSg _ coGA) //= -/N] => [|y Ny defB]. rewrite joingC norm_joinEr // coprime_cardMg ?(coprimeSg sNG) //. by rewrite (leq_trans _ leAn) // oAG mulnC ltn_pmul2l // proper_card. exists (y * x); first by rewrite groupM // (subsetP sNG). by rewrite conjsgM -defB conjsgKV. Qed. Lemma Hall_exists_subJ pi gT (G : {group gT}) : solvable G -> exists2 H : {group gT}, pi.-Hall(G) H & forall K : {group gT}, K \subset G -> pi.-group K -> exists2 x, x \in G & K \subset H :^ x. Proof. move: {2}_.+1 (ltnSn #|G|) => n. elim: n gT G => // n IHn gT G; rewrite ltnS => leGn solG. have [-> | ntG] := eqsVneq G 1. exists 1%G => [|_ /trivGP-> _]; last by exists 1; rewrite ?set11 ?sub1G. by rewrite pHallE sub1G cards1 part_p'nat. case: (solvable_norm_abelem solG (normal_refl _)) => // M [sMG nsMG ntM]. case/is_abelemP=> p pr_p /and3P[pM cMM _]. pose Gb := (G / M)%G; case: (IHn _ Gb) => [||Hb]; try exact: quotient_sol. by rewrite (leq_trans (ltn_quotient _ _)). case/and3P=> [sHbGb piHb pi'Hb'] transHb. case: (inv_quotientS nsMG sHbGb) => H def_H sMH sHG. have nMG := normal_norm nsMG; have nMH := subset_trans sHG nMG. have{transHb} transH (K : {group gT}): K \subset G -> pi.-group K -> exists2 x, x \in G & K \subset H :^ x. - move=> sKG piK; have nMK := subset_trans sKG nMG. case: (transHb (K / M)%G) => [||xb Gxb sKHxb]; first exact: morphimS. exact: morphim_pgroup. case/morphimP: Gxb => x Nx Gx /= def_x; exists x => //. apply/subsetP=> y Ky. have: y \in coset M y by rewrite val_coset (subsetP nMK, rcoset_refl). have: coset M y \in (H :^ x) / M. rewrite /quotient morphimJ //=. rewrite def_x def_H in sKHxb; apply: (subsetP sKHxb); exact: mem_quotient. case/morphimP=> z Nz Hxz ->. rewrite val_coset //; case/rcosetP=> t Mt ->; rewrite groupMl //. by rewrite mem_conjg (subsetP sMH) // -mem_conjg (normP Nx). have{pi'Hb'} pi'H': pi^'.-nat #|G : H|. move: pi'Hb'; rewrite -!divgS // def_H !card_quotient //. by rewrite -(divnMl (cardG_gt0 M)) !Lagrange. have [pi_p | pi'p] := boolP (p \in pi). exists H => //; apply/and3P; split=> //; rewrite /pgroup. by rewrite -(Lagrange sMH) -card_quotient // pnat_mul -def_H (pi_pnat pM). have [ltHG | leGH {n IHn leGn transH}] := ltnP #|H| #|G|. case: (IHn _ H (leq_trans ltHG leGn)) => [|H1]; first exact: solvableS solG. case/and3P=> sH1H piH1 pi'H1' transH1. have sH1G: H1 \subset G by exact: subset_trans sHG. exists H1 => [|K sKG piK]. apply/and3P; split => //. rewrite -divgS // -(Lagrange sHG) -(Lagrange sH1H) -mulnA. by rewrite mulKn // pnat_mul pi'H1'. case: (transH K sKG piK) => x Gx def_K. case: (transH1 (K :^ x^-1)%G) => [||y Hy def_K1]. - by rewrite sub_conjgV. - by rewrite /pgroup cardJg. exists (y * x); first by rewrite groupMr // (subsetP sHG). by rewrite -(conjsgKV x K) conjsgM conjSg. have{leGH Gb sHbGb sHG sMH pi'H'} eqHG: H = G. by apply/eqP; rewrite -val_eqE eqEcard sHG. have{H Hb def_H eqHG piHb nMH} hallM: pi^'.-Hall(G) M. rewrite /pHall /pgroup sMG pnatNK -card_quotient //=. by rewrite -eqHG -def_H (pi_pnat pM). case/splitsP: (SchurZassenhaus_split (pHall_Hall hallM) nsMG) => H. case/complP=> trMH defG. have sHG: H \subset G by rewrite -defG mulG_subr. exists H => [|K sKG piK]. apply: etrans hallM; rewrite /pHall sMG sHG /= -!divgS // -defG andbC. by rewrite (TI_cardMg trMH) mulKn ?mulnK // pnatNK. pose G1 := (K <*> M)%G; pose K1 := (H :&: G1)%G. have nMK: K \subset 'N(M) by apply: subset_trans sKG nMG. have defG1: M * K = G1 by rewrite -normC -?norm_joinEl. have sK1G1: K1 \subset M * K by rewrite defG1 subsetIr. have coMK: coprime #|M| #|K|. by rewrite coprime_sym (pnat_coprime piK) //; exact: (pHall_pgroup hallM). case: (SchurZassenhaus_trans_sol _ nMK sK1G1 coMK) => [||x Mx defK1]. - exact: solvableS solG. - apply/eqP; rewrite -(eqn_pmul2l (cardG_gt0 M)) -TI_cardMg //; last first. by apply/trivgP; rewrite -trMH /= setIA subsetIl. rewrite -coprime_cardMg // defG1; apply/eqP; congr #|(_ : {set _})|. rewrite group_modl; last by rewrite -defG1 mulG_subl. by apply/setIidPr; rewrite defG gen_subG subUset sKG. exists x^-1; first by rewrite groupV (subsetP sMG). by rewrite -(_ : K1 :^ x^-1 = K) ?(conjSg, subsetIl) // defK1 conjsgK. Qed. End Hall. Section HallCorollaries. Variable gT : finGroupType. Corollary Hall_exists pi (G : {group gT}) : solvable G -> exists H : {group gT}, pi.-Hall(G) H. Proof. by case/(Hall_exists_subJ pi) => H; exists H. Qed. Corollary Hall_trans pi (G H1 H2 : {group gT}) : solvable G -> pi.-Hall(G) H1 -> pi.-Hall(G) H2 -> exists2 x, x \in G & H1 :=: H2 :^ x. Proof. move=> solG; have [H hallH transH] := Hall_exists_subJ pi solG. have conjH (K : {group gT}): pi.-Hall(G) K -> exists2 x, x \in G & K = (H :^ x)%G. - move=> hallK; have [sKG piK _] := and3P hallK. case: (transH K sKG piK) => x Gx sKH; exists x => //. apply/eqP; rewrite -val_eqE eqEcard sKH cardJg. by rewrite (card_Hall hallH) (card_Hall hallK) /=. case/conjH=> x1 Gx1 ->{H1}; case/conjH=> x2 Gx2 ->{H2}. exists (x2^-1 * x1); first by rewrite groupMl ?groupV. by apply: val_inj; rewrite /= conjsgM conjsgK. Qed. Corollary Hall_superset pi (G K : {group gT}) : solvable G -> K \subset G -> pi.-group K -> exists2 H : {group gT}, pi.-Hall(G) H & K \subset H. Proof. move=> solG sKG; have [H hallH transH] := Hall_exists_subJ pi solG. by case/transH=> // x Gx sKHx; exists (H :^ x)%G; rewrite ?pHallJ. Qed. Corollary Hall_subJ pi (G H K : {group gT}) : solvable G -> pi.-Hall(G) H -> K \subset G -> pi.-group K -> exists2 x, x \in G & K \subset H :^ x. Proof. move=> solG HallH sKG piK; have [M HallM sKM]:= Hall_superset solG sKG piK. have [x Gx defM] := Hall_trans solG HallM HallH. by exists x; rewrite // -defM. Qed. Corollary Hall_Jsub pi (G H K : {group gT}) : solvable G -> pi.-Hall(G) H -> K \subset G -> pi.-group K -> exists2 x, x \in G & K :^ x \subset H. Proof. move=> solG HallH sKG piK; have [x Gx sKHx] := Hall_subJ solG HallH sKG piK. by exists x^-1; rewrite ?groupV // sub_conjgV. Qed. Lemma Hall_Frattini_arg pi (G K H : {group gT}) : solvable K -> K <| G -> pi.-Hall(K) H -> K * 'N_G(H) = G. Proof. move=> solK /andP[sKG nKG] hallH. have sHG: H \subset G by apply: subset_trans sKG; case/andP: hallH. rewrite setIC group_modl //; apply/setIidPr/subsetP=> x Gx. pose H1 := (H :^ x^-1)%G. have hallH1: pi.-Hall(K) H1 by rewrite pHallJnorm // groupV (subsetP nKG). case: (Hall_trans solK hallH hallH1) => y Ky defH. rewrite -(mulKVg y x) mem_mulg //; apply/normP. by rewrite conjsgM {1}defH conjsgK conjsgKV. Qed. End HallCorollaries. Section InternalAction. Variables (pi : nat_pred) (gT : finGroupType). Implicit Types G H K A X : {group gT}. (* Part of Aschbacher (18.7.4). *) Lemma coprime_norm_cent A G : A \subset 'N(G) -> coprime #|G| #|A| -> 'N_G(A) = 'C_G(A). Proof. move=> nGA coGA; apply/eqP; rewrite eqEsubset andbC setIS ?cent_sub //=. rewrite subsetI subsetIl /= (sameP commG1P trivgP) -(coprime_TIg coGA). rewrite subsetI commg_subr subsetIr andbT. move: nGA; rewrite -commg_subl; apply: subset_trans. by rewrite commSg ?subsetIl. Qed. (* This is B & G, Proposition 1.5(a) *) Proposition coprime_Hall_exists A G : A \subset 'N(G) -> coprime #|G| #|A| -> solvable G -> exists2 H : {group gT}, pi.-Hall(G) H & A \subset 'N(H). Proof. move=> nGA coGA solG; have [H hallH] := Hall_exists pi solG. have sG_AG: G \subset A <*> G by rewrite joing_subr. have nG_AG: A <*> G \subset 'N(G) by rewrite join_subG nGA normG. pose N := 'N_(A <*> G)(H)%G. have nGN: N \subset 'N(G) by rewrite subIset ?nG_AG. have nGN_N: G :&: N <| N by rewrite /(_ <| N) subsetIr normsI ?normG. have NG_AG: G * N = A <*> G. by apply: Hall_Frattini_arg hallH => //; exact/andP. have iGN_A: #|N| %/ #|G :&: N| = #|A|. rewrite setIC divgI -card_quotient // -quotientMidl NG_AG. rewrite card_quotient -?divgS //= norm_joinEl //. by rewrite coprime_cardMg 1?coprime_sym // mulnK. have hallGN: Hall N (G :&: N). by rewrite /Hall -divgS subsetIr //= iGN_A (coprimeSg _ coGA) ?subsetIl. case/splitsP: {hallGN nGN_N}(SchurZassenhaus_split hallGN nGN_N) => B. case/complP=> trBGN defN. have{trBGN iGN_A} oBA: #|B| = #|A|. by rewrite -iGN_A -{1}defN (TI_cardMg trBGN) mulKn. have sBN: B \subset N by rewrite -defN mulG_subr. case: (SchurZassenhaus_trans_sol solG nGA _ coGA oBA) => [|x Gx defB]. by rewrite -(normC nGA) -norm_joinEl // -NG_AG -(mul1g B) mulgSS ?sub1G. exists (H :^ x^-1)%G; first by rewrite pHallJ ?groupV. apply/subsetP=> y Ay; have: y ^ x \in B by rewrite defB memJ_conjg. move/(subsetP sBN)=> /setIP[_ /normP nHyx]. by apply/normP; rewrite -conjsgM conjgCV invgK conjsgM nHyx. Qed. (* This is B & G, Proposition 1.5(c) *) Proposition coprime_Hall_trans A G H1 H2 : A \subset 'N(G) -> coprime #|G| #|A| -> solvable G -> pi.-Hall(G) H1 -> A \subset 'N(H1) -> pi.-Hall(G) H2 -> A \subset 'N(H2) -> exists2 x, x \in 'C_G(A) & H1 :=: H2 :^ x. Proof. move: H1 => H nGA coGA solG hallH nHA hallH2. have{H2 hallH2} [x Gx -> nH1xA] := Hall_trans solG hallH2 hallH. have sG_AG: G \subset A <*> G by rewrite -{1}genGid genS ?subsetUr. have nG_AG: A <*> G \subset 'N(G) by rewrite gen_subG subUset nGA normG. pose N := 'N_(A <*> G)(H)%G. have nGN: N \subset 'N(G) by rewrite subIset ?nG_AG. have nGN_N: G :&: N <| N. apply/normalP; rewrite subsetIr; split=> // y Ny. by rewrite conjIg (normP _) // (subsetP nGN, conjGid). have NG_AG : G * N = A <*> G. by apply: Hall_Frattini_arg hallH => //; exact/andP. have iGN_A: #|N : G :&: N| = #|A|. rewrite -card_quotient //; last by case/andP: nGN_N. rewrite (card_isog (second_isog nGN)) /= -quotientMidr (normC nGN) NG_AG. rewrite card_quotient // -divgS //= joingC norm_joinEr //. by rewrite coprime_cardMg // mulnC mulnK. have solGN: solvable (G :&: N) by apply: solvableS solG; exact: subsetIl. have oAxA: #|A :^ x^-1| = #|A| by exact: cardJg. have sAN: A \subset N by rewrite subsetI -{1}genGid genS // subsetUl. have nGNA: A \subset 'N(G :&: N). by apply/normsP=> y ?; rewrite conjIg (normsP nGA) ?(conjGid, subsetP sAN). have coGNA: coprime #|G :&: N| #|A| := coprimeSg (subsetIl _ _) coGA. case: (SchurZassenhaus_trans_sol solGN nGNA _ coGNA oAxA) => [|y GNy defAx]. have ->: (G :&: N) * A = N. apply/eqP; rewrite eqEcard -{2}(mulGid N) mulgSS ?subsetIr //=. by rewrite coprime_cardMg // -iGN_A Lagrange ?subsetIr. rewrite sub_conjgV conjIg -normJ subsetI conjGid ?joing_subl //. by rewrite mem_gen // inE Gx orbT. case/setIP: GNy => Gy; case/setIP=> _; move/normP=> nHy. exists (y * x)^-1. rewrite -coprime_norm_cent // groupV inE groupM //=; apply/normP. by rewrite conjsgM -defAx conjsgKV. by apply: val_inj; rewrite /= -{2}nHy -(conjsgM _ y) conjsgK. Qed. (* A complement to the above: 'C(A) acts on 'Nby(A) *) Lemma norm_conj_cent A G x : x \in 'C(A) -> (A \subset 'N(G :^ x)) = (A \subset 'N(G)). Proof. by move=> cAx; rewrite norm_conj_norm ?(subsetP (cent_sub A)). Qed. (* Strongest version of the centraliser lemma -- not found in textbooks! *) (* Obviously, the solvability condition could be removed once we have the *) (* Odd Order Theorem. *) Lemma strongest_coprime_quotient_cent A G H : let R := H :&: [~: G, A] in A \subset 'N(H) -> R \subset G -> coprime #|R| #|A| -> solvable R || solvable A -> 'C_G(A) / H = 'C_(G / H)(A / H). Proof. move=> R nHA sRG coRA solRA. have nRA: A \subset 'N(R) by rewrite normsI ?commg_normr. apply/eqP; rewrite eqEsubset subsetI morphimS ?subsetIl //=. rewrite (subset_trans _ (morphim_cent _ _)) ?morphimS ?subsetIr //=. apply/subsetP=> _ /setIP[/morphimP[x Nx Gx ->] cAHx]. have{cAHx} cAxR y: y \in A -> [~ x, y] \in R. move=> Ay; have Ny: y \in 'N(H) by exact: subsetP Ay. rewrite inE mem_commg // andbT coset_idr ?groupR // morphR //=. by apply/eqP; apply/commgP; apply: (centP cAHx); rewrite mem_quotient. have AxRA: A :^ x \subset R * A. apply/subsetP=> _ /imsetP[y Ay ->]. rewrite -normC // -(mulKVg y (y ^ x)) -commgEl mem_mulg //. by rewrite -groupV invg_comm cAxR. have [y Ry def_Ax]: exists2 y, y \in R & A :^ x = A :^ y. have oAx: #|A :^ x| = #|A| by rewrite cardJg. have [solR | solA] := orP solRA; first exact: SchurZassenhaus_trans_sol. by apply: SchurZassenhaus_trans_actsol; rewrite // joingC norm_joinEr. rewrite -imset_coset; apply/imsetP; exists (x * y^-1); last first. by rewrite conjgCV mkerl // ker_coset memJ_norm groupV; case/setIP: Ry. rewrite /= inE groupMl // ?(groupV, subsetP sRG) //=. apply/centP=> z Az; apply/commgP/eqP/set1P. rewrite -[[set 1]](coprime_TIg coRA) inE {1}commgEl commgEr /= -/R. rewrite invMg -mulgA invgK groupMl // conjMg mulgA -commgEl. rewrite groupMl ?cAxR // memJ_norm ?(groupV, subsetP nRA) // Ry /=. by rewrite groupMr // conjVg groupV conjgM -mem_conjg -def_Ax memJ_conjg. Qed. (* A weaker but more practical version, still stronger than the usual form *) (* (viz. Aschbacher 18.7.4), similar to the one needed in Aschbacher's *) (* proof of Thompson factorization. Note that the coprime and solvability *) (* assumptions could be further weakened to H :&: G (and hence become *) (* trivial if H and G are TI). However, the assumption that A act on G is *) (* needed in this case. *) Lemma coprime_norm_quotient_cent A G H : A \subset 'N(G) -> A \subset 'N(H) -> coprime #|H| #|A| -> solvable H -> 'C_G(A) / H = 'C_(G / H)(A / H). Proof. move=> nGA nHA coHA solH; have sRH := subsetIl H [~: G, A]. rewrite strongest_coprime_quotient_cent ?(coprimeSg sRH) 1?(solvableS sRH) //. by rewrite subIset // commg_subl nGA orbT. Qed. (* A useful consequence (similar to Ex. 6.1 in Aschbacher) of the stronger *) (* theorem. *) Lemma coprime_cent_mulG A G H : A \subset 'N(G) -> A \subset 'N(H) -> G \subset 'N(H) -> coprime #|H| #|A| -> solvable H -> 'C_(H * G)(A) = 'C_H(A) * 'C_G(A). Proof. move=> nHA nGA nHG coHA solH; rewrite -norm_joinEr //. have nsHG: H <| H <*> G by rewrite /normal joing_subl join_subG normG. rewrite -{2}(setIidPr (normal_sub nsHG)) setIAC. rewrite group_modr ?setSI ?joing_subr //=; symmetry; apply/setIidPl. rewrite -quotientSK ?subIset 1?normal_norm //. by rewrite !coprime_norm_quotient_cent ?normsY //= norm_joinEr ?quotientMidl. Qed. (* Another special case of the strong coprime quotient lemma; not found in *) (* textbooks, but nevertheless used implicitly throughout B & G, sometimes *) (* justified by switching to external action. *) Lemma quotient_TI_subcent K G H : G \subset 'N(K) -> G \subset 'N(H) -> K :&: H = 1 -> 'C_K(G) / H = 'C_(K / H)(G / H). Proof. move=> nGK nGH tiKH. have tiHR: H :&: [~: K, G] = 1. by apply/trivgP; rewrite /= setIC -tiKH setSI ?commg_subl. apply: strongest_coprime_quotient_cent; rewrite ?tiHR ?sub1G ?solvable1 //. by rewrite cards1 coprime1n. Qed. (* This is B & G, Proposition 1.5(d): the more traditional form of the lemma *) (* above, with the assumption H <| G weakened to H \subset G. The stronger *) (* coprime and solvability assumptions are easier to satisfy in practice. *) Proposition coprime_quotient_cent A G H : H \subset G -> A \subset 'N(H) -> coprime #|G| #|A| -> solvable G -> 'C_G(A) / H = 'C_(G / H)(A / H). Proof. move=> sHG nHA coGA solG. have sRG: H :&: [~: G, A] \subset G by rewrite subIset ?sHG. by rewrite strongest_coprime_quotient_cent ?(coprimeSg sRG) 1?(solvableS sRG). Qed. (* This is B & G, Proposition 1.5(e). *) Proposition coprime_comm_pcore A G K : A \subset 'N(G) -> coprime #|G| #|A| -> solvable G -> pi^'.-Hall(G) K -> K \subset 'C_G(A) -> [~: G, A] \subset 'O_pi(G). Proof. move=> nGA coGA solG hallK cKA. case: (coprime_Hall_exists nGA) => // H hallH nHA. have sHG: H \subset G by case/andP: hallH. have sKG: K \subset G by case/andP: hallK. have coKH: coprime #|K| #|H|. case/and3P: hallH=> _ piH _; case/and3P: hallK => _ pi'K _. by rewrite coprime_sym (pnat_coprime piH pi'K). have defG: G :=: K * H. apply/eqP; rewrite eq_sym eqEcard coprime_cardMg //. rewrite -{1}(mulGid G) mulgSS //= (card_Hall hallH) (card_Hall hallK). by rewrite mulnC partnC. have sGA_H: [~: G, A] \subset H. rewrite gen_subG defG; apply/subsetP=> xya; case/imset2P=> xy a. case/imset2P=> x y Kx Hy -> Aa -> {xya xy}. rewrite commMgJ (([~ x, a] =P 1) _) ?(conj1g, mul1g). by rewrite groupMl ?groupV // memJ_norm ?(subsetP nHA). rewrite subsetI sKG in cKA; apply/commgP; exact: (centsP cKA). apply: pcore_max; last first. by rewrite /(_ <| G) /= commg_norml commGC commg_subr nGA. by case/and3P: hallH => _ piH _; apply: pgroupS piH. Qed. End InternalAction. (* This is B & G, Proposition 1.5(b). *) Proposition coprime_Hall_subset pi (gT : finGroupType) (A G X : {group gT}) : A \subset 'N(G) -> coprime #|G| #|A| -> solvable G -> X \subset G -> pi.-group X -> A \subset 'N(X) -> exists H : {group gT}, [/\ pi.-Hall(G) H, A \subset 'N(H) & X \subset H]. Proof. move: {2}_.+1 (ltnSn #|G|) => n. elim: n => // n IHn in gT A G X * => leGn nGA coGA solG sXG piX nXA. have [G1 | ntG] := eqsVneq G 1. case: (coprime_Hall_exists pi nGA) => // H hallH nHA. by exists H; split; rewrite // (subset_trans sXG) // G1 sub1G. have sG_AG: G \subset A <*> G by rewrite joing_subr. have sA_AG: A \subset A <*> G by rewrite joing_subl. have nG_AG: A <*> G \subset 'N(G) by rewrite join_subG nGA normG. have nsG_AG: G <| A <*> G by exact/andP. case: (solvable_norm_abelem solG nsG_AG) => // M [sMG nsMAG ntM]. have{nsMAG} [nMA nMG]: A \subset 'N(M) /\ G \subset 'N(M). by apply/andP; rewrite -join_subG normal_norm. have nMX: X \subset 'N(M) by exact: subset_trans nMG. case/is_abelemP=> p pr_p; case/and3P=> pM cMM _. have: #|G / M| < n by rewrite (leq_trans (ltn_quotient _ _)). move/(IHn _ (A / M)%G _ (X / M)%G); rewrite !(quotient_norms, quotientS) //. rewrite !(coprime_morph, quotient_sol, morphim_pgroup) //. case=> //= Hq []; case/and3P=> sHGq piHq pi'Hq' nHAq sXHq. case/inv_quotientS: (sHGq) => [|HM defHM sMHM sHMG]; first exact/andP. have nMHM := subset_trans sHMG nMG. have{sXHq} sXHM: X \subset HM by rewrite -(quotientSGK nMX) -?defHM. have{pi'Hq' sHGq} pi'HM': pi^'.-nat #|G : HM|. move: pi'Hq'; rewrite -!divgS // defHM !card_quotient //. by rewrite -(divnMl (cardG_gt0 M)) !Lagrange. have{nHAq} nHMA: A \subset 'N(HM). by rewrite -(quotientSGK nMA) ?normsG ?quotient_normG -?defHM //; exact/andP. case/orP: (orbN (p \in pi)) => pi_p. exists HM; split=> //; apply/and3P; split; rewrite /pgroup //. by rewrite -(Lagrange sMHM) pnat_mul -card_quotient // -defHM (pi_pnat pM). case: (ltnP #|HM| #|G|) => [ltHG | leGHM {n IHn leGn}]. case: (IHn _ A HM X (leq_trans ltHG leGn)) => // [||H [hallH nHA sXH]]. - exact: coprimeSg coGA. - exact: solvableS solG. case/and3P: hallH => sHHM piH pi'H'. have sHG: H \subset G by exact: subset_trans sHMG. exists H; split=> //; apply/and3P; split=> //. rewrite -divgS // -(Lagrange sHMG) -(Lagrange sHHM) -mulnA mulKn //. by rewrite pnat_mul pi'H'. have{leGHM nHMA sHMG sMHM sXHM pi'HM'} eqHMG: HM = G. by apply/eqP; rewrite -val_eqE eqEcard sHMG. have pi'M: pi^'.-group M by rewrite /pgroup (pi_pnat pM). have{HM Hq nMHM defHM eqHMG piHq} hallM: pi^'.-Hall(G) M. apply/and3P; split; rewrite // /pgroup pnatNK. by rewrite -card_quotient // -eqHMG -defHM. case: (coprime_Hall_exists pi nGA) => // H hallH nHA. pose XM := (X <*> M)%G; pose Y := (H :&: XM)%G. case/and3P: (hallH) => sHG piH _. have sXXM: X \subset XM by rewrite joing_subl. have co_pi_M (B : {group gT}): pi.-group B -> coprime #|B| #|M|. by move=> piB; rewrite (pnat_coprime piB). have hallX: pi.-Hall(XM) X. rewrite /pHall piX sXXM -divgS //= norm_joinEl //. by rewrite coprime_cardMg ?co_pi_M // mulKn. have sXMG: XM \subset G by rewrite join_subG sXG. have hallY: pi.-Hall(XM) Y. have sYXM: Y \subset XM by rewrite subsetIr. have piY: pi.-group Y by apply: pgroupS piH; exact: subsetIl. rewrite /pHall sYXM piY -divgS // -(_ : Y * M = XM). by rewrite coprime_cardMg ?co_pi_M // mulKn //. rewrite /= setIC group_modr ?joing_subr //=; apply/setIidPl. rewrite ((H * M =P G) _) // eqEcard mul_subG //= coprime_cardMg ?co_pi_M //. by rewrite (card_Hall hallM) (card_Hall hallH) partnC. have nXMA: A \subset 'N(XM) by rewrite normsY. have:= coprime_Hall_trans nXMA _ _ hallX nXA hallY. rewrite !(coprimeSg sXMG, solvableS sXMG, normsI) //. case=> // x /setIP[XMx cAx] ->. exists (H :^ x)%G; split; first by rewrite pHallJ ?(subsetP sXMG). by rewrite norm_conj_cent. by rewrite conjSg subsetIl. Qed. Section ExternalAction. Variables (pi : nat_pred) (aT gT : finGroupType). Variables (A : {group aT}) (G : {group gT}) (to : groupAction A G). Section FullExtension. Local Notation inA := (sdpair2 to). Local Notation inG := (sdpair1 to). Local Notation A' := (inA @* gval A). Local Notation G' := (inG @* gval G). Let injG : 'injm inG := injm_sdpair1 _. Let injA : 'injm inA := injm_sdpair2 _. Hypotheses (coGA : coprime #|G| #|A|) (solG : solvable G). Lemma external_action_im_coprime : coprime #|G'| #|A'|. Proof. by rewrite !card_injm. Qed. Let coGA' := external_action_im_coprime. Let solG' : solvable G' := morphim_sol _ solG. Let nGA' := im_sdpair_norm to. Lemma ext_coprime_Hall_exists : exists2 H : {group gT}, pi.-Hall(G) H & [acts A, on H | to]. Proof. have [H' hallH' nHA'] := coprime_Hall_exists pi nGA' coGA' solG'. have sHG' := pHall_sub hallH'. exists (inG @*^-1 H')%G => /=. by rewrite -(morphim_invmE injG) -{1}(im_invm injG) morphim_pHall. by rewrite actsEsd ?morphpreK // subsetIl. Qed. Lemma ext_coprime_Hall_trans (H1 H2 : {group gT}) : pi.-Hall(G) H1 -> [acts A, on H1 | to] -> pi.-Hall(G) H2 -> [acts A, on H2 | to] -> exists2 x, x \in 'C_(G | to)(A) & H1 :=: H2 :^ x. Proof. move=> hallH1 nH1A hallH2 nH2A. have sH1G := pHall_sub hallH1; have sH2G := pHall_sub hallH2. rewrite !actsEsd // in nH1A nH2A. have hallH1': pi.-Hall(G') (inG @* H1) by rewrite morphim_pHall. have hallH2': pi.-Hall(G') (inG @* H2) by rewrite morphim_pHall. have [x'] := coprime_Hall_trans nGA' coGA' solG' hallH1' nH1A hallH2' nH2A. case/setIP=> /= Gx' cAx' /eqP defH1; pose x := invm injG x'. have Gx: x \in G by rewrite -(im_invm injG) mem_morphim. have def_x': x' = inG x by rewrite invmK. exists x; first by rewrite inE Gx gacentEsd mem_morphpre /= -?def_x'. apply/eqP; move: defH1; rewrite def_x' /= -morphimJ //=. by rewrite !eqEsubset !injmSK // conj_subG. Qed. Lemma ext_norm_conj_cent (H : {group gT}) x : H \subset G -> x \in 'C_(G | to)(A) -> [acts A, on H :^ x | to] = [acts A, on H | to]. Proof. move=> sHG /setIP[Gx]. rewrite gacentEsd !actsEsd ?conj_subG ?morphimJ // 2!inE Gx /=. exact: norm_conj_cent. Qed. Lemma ext_coprime_Hall_subset (X : {group gT}) : X \subset G -> pi.-group X -> [acts A, on X | to] -> exists H : {group gT}, [/\ pi.-Hall(G) H, [acts A, on H | to] & X \subset H]. Proof. move=> sXG piX; rewrite actsEsd // => nXA'. case: (coprime_Hall_subset nGA' coGA' solG' _ (morphim_pgroup _ piX) nXA'). exact: morphimS. move=> H' /= [piH' nHA' sXH']; have sHG' := pHall_sub piH'. exists (inG @*^-1 H')%G; rewrite actsEsd ?subsetIl ?morphpreK // nHA'. rewrite -sub_morphim_pre //= sXH'; split=> //. by rewrite -(morphim_invmE injG) -{1}(im_invm injG) morphim_pHall. Qed. End FullExtension. (* We only prove a weaker form of the coprime group action centraliser *) (* lemma, because it is more convenient in practice to make G the range *) (* of the action, whence G both contains H and is stable under A. *) (* However we do restrict the coprime/solvable assumptions to H, and *) (* we do not require that G normalize H. *) Lemma ext_coprime_quotient_cent (H : {group gT}) : H \subset G -> [acts A, on H | to] -> coprime #|H| #|A| -> solvable H -> 'C_(|to)(A) / H = 'C_(|to / H)(A). Proof. move=> sHG nHA coHA solH; pose N := 'N_G(H). have nsHN: H <| N by rewrite normal_subnorm. have [sHN nHn] := andP nsHN. have sNG: N \subset G by exact: subsetIl. have nNA: {acts A, on group N | to}. split; rewrite // actsEsd // injm_subnorm ?injm_sdpair1 //=. by rewrite normsI ?norms_norm ?im_sdpair_norm -?actsEsd. rewrite -!(gacentIdom _ A) -quotientInorm -gacentIim setIAC. rewrite -(gacent_actby nNA) gacentEsd -morphpreIim /= -/N. have:= (injm_sdpair1 <[nNA]>, injm_sdpair2 <[nNA]>). set inG := sdpair1 _; set inA := sdpair2 _ => [[injG injA]]. set G' := inG @* N; set A' := inA @* A; pose H' := inG @* H. have defN: 'N(H | to) = A by apply/eqP; rewrite eqEsubset subsetIl. have def_Dq: qact_dom to H = A by rewrite qact_domE. have sAq: A \subset qact_dom to H by rewrite def_Dq. rewrite {2}def_Dq -(gacent_ract _ sAq); set to_q := (_ \ _)%gact. have:= And3 (sdprod_sdpair to_q) (injm_sdpair1 to_q) (injm_sdpair2 to_q). rewrite gacentEsd; set inAq := sdpair2 _; set inGq := sdpair1 _ => /=. set Gq := inGq @* _; set Aq := inAq @* _ => [[q_d iGq iAq]]. have nH': 'N(H') = setT. apply/eqP; rewrite -subTset -im_sdpair mulG_subG morphim_norms //=. by rewrite -actsEsd // acts_actby subxx /= (setIidPr sHN). have: 'dom (coset H' \o inA \o invm iAq) = Aq. by rewrite ['dom _]morphpre_invm /= nH' morphpreT. case/domP=> qA [def_qA ker_qA _ im_qA]. have{coHA} coHA': coprime #|H'| #|A'| by rewrite !card_injm. have{ker_qA} injAq: 'injm qA. rewrite {}ker_qA !ker_comp ker_coset morphpre_invm -morphpreIim /= setIC. by rewrite coprime_TIg // -kerE (trivgP injA) morphim1. have{im_qA} im_Aq : qA @* Aq = A' / H'. by rewrite {}im_qA !morphim_comp im_invm. have: 'dom (quotm (sdpair1_morphism <[nNA]>) nsHN \o invm iGq) = Gq. by rewrite ['dom _]morphpre_invm /= quotientInorm. case/domP=> qG [def_qG ker_qG _ im_qG]. have{ker_qG} injGq: 'injm qG. rewrite {}ker_qG ker_comp ker_quotm morphpre_invm (trivgP injG). by rewrite quotient1 morphim1. have im_Gq: qG @* Gq = G' / H'. rewrite {}im_qG morphim_comp im_invm morphim_quotm //= -/inG -/H'. by rewrite -morphimIdom setIAC setIid. have{def_qA def_qG} q_J : {in Gq & Aq, morph_act 'J 'J qG qA}. move=> x' a'; case/morphimP=> Hx; case/morphimP=> x nHx Gx -> GHx ->{Hx x'}. case/morphimP=> a _ Aa ->{a'} /=; rewrite -/inAq -/inGq. rewrite !{}def_qG {}def_qA /= !invmE // -sdpair_act //= -/inG -/inA. have Nx: x \in N by rewrite inE Gx. have Nxa: to x a \in N by case: (nNA); move/acts_act->. have [Gxa nHxa] := setIP Nxa. rewrite invmE qactE ?quotmE ?mem_morphim ?def_Dq //=. by rewrite -morphJ /= ?nH' ?inE // -sdpair_act //= actbyE. pose q := sdprodm q_d q_J. have{injAq injGq} injq: 'injm q. rewrite injm_sdprodm injAq injGq /= {}im_Aq {}im_Gq -/Aq . by rewrite -quotientGI ?im_sdpair_TI ?morphimS //= quotient1. rewrite -[inGq @*^-1 _]morphpreIim -/Gq. have sC'G: inG @*^-1 'C_G'(A') \subset G by rewrite !subIset ?subxx. rewrite -[_ / _](injmK iGq) ?quotientS //= -/inGq; congr (_ @*^-1 _). apply: (injm_morphim_inj injq); rewrite 1?injm_subcent ?subsetT //= -/q. rewrite 2?morphim_sdprodml ?morphimS //= im_Gq. rewrite morphim_sdprodmr ?morphimS //= im_Aq. rewrite {}im_qG morphim_comp morphim_invm ?morphimS //. rewrite morphim_quotm morphpreK ?subsetIl //= -/H'. rewrite coprime_norm_quotient_cent ?im_sdpair_norm ?nH' ?subsetT //=. exact: morphim_sol. Qed. End ExternalAction. Section SylowSolvableAct. Variables (gT : finGroupType) (p : nat). Implicit Types A B G X : {group gT}. Lemma sol_coprime_Sylow_exists A G : solvable A -> A \subset 'N(G) -> coprime #|G| #|A| -> exists2 P : {group gT}, p.-Sylow(G) P & A \subset 'N(P). Proof. move=> solA nGA coGA; pose AG := A <*> G. have nsG_AG: G <| AG by rewrite /normal joing_subr join_subG nGA normG. have [sG_AG nG_AG]:= andP nsG_AG. have [P sylP] := Sylow_exists p G; pose N := 'N_AG(P); pose NG := G :&: N. have nGN: N \subset 'N(G) by rewrite subIset ?nG_AG. have sNG_G: NG \subset G := subsetIl G N. have nsNG_N: NG <| N by rewrite /normal subsetIr normsI ?normG. have defAG: G * N = AG := Frattini_arg nsG_AG sylP. have oA : #|A| = #|N| %/ #|NG|. rewrite /NG setIC divgI -card_quotient // -quotientMidl defAG. rewrite card_quotient -?divgS //= norm_joinEl //. by rewrite coprime_cardMg 1?coprime_sym // mulnK. have: [splits N, over NG]. rewrite SchurZassenhaus_split // /Hall -divgS subsetIr //. by rewrite -oA (coprimeSg sNG_G). case/splitsP=> B; case/complP=> tNG_B defN. have [nPB]: B \subset 'N(P) /\ B \subset AG. by apply/andP; rewrite andbC -subsetI -/N -defN mulG_subr. case/SchurZassenhaus_trans_actsol => // [|x Gx defB]. by rewrite oA -defN TI_cardMg // mulKn. exists (P :^ x^-1)%G; first by rewrite pHallJ ?groupV. by rewrite normJ -sub_conjg -defB. Qed. Lemma sol_coprime_Sylow_trans A G : solvable A -> A \subset 'N(G) -> coprime #|G| #|A| -> [transitive 'C_G(A), on [set P in 'Syl_p(G) | A \subset 'N(P)] | 'JG]. Proof. move=> solA nGA coGA; pose AG := A <*> G; set FpA := finset _. have nG_AG: AG \subset 'N(G) by rewrite join_subG nGA normG. have [P sylP nPA] := sol_coprime_Sylow_exists solA nGA coGA. pose N := 'N_AG(P); have sAN: A \subset N by rewrite subsetI joing_subl. have trNPA: A :^: AG ::&: N = A :^: N. pose NG := 'N_G(P); have sNG_G : NG \subset G := subsetIl _ _. have nNGA: A \subset 'N(NG) by rewrite normsI ?norms_norm. apply/setP=> Ax; apply/setIdP/imsetP=> [[]|[x Nx ->{Ax}]]; last first. by rewrite conj_subG //; case/setIP: Nx => AGx; rewrite mem_imset. have ->: N = A <*> NG by rewrite /N /AG !norm_joinEl // -group_modl. have coNG_A := coprimeSg sNG_G coGA; case/imsetP=> x AGx ->{Ax}. case/SchurZassenhaus_trans_actsol; rewrite ?cardJg // => y Ny /= ->. by exists y; rewrite // mem_gen 1?inE ?Ny ?orbT. have{trNPA}: [transitive 'N_AG(A), on FpA | 'JG]. have ->: FpA = 'Fix_('Syl_p(G) | 'JG)(A). by apply/setP=> Q; rewrite 4!inE afixJG. have SylP : P \in 'Syl_p(G) by rewrite inE. apply/(trans_subnorm_fixP _ SylP); rewrite ?astab1JG //. rewrite (atrans_supgroup _ (Syl_trans _ _)) ?joing_subr //= -/AG. by apply/actsP=> x /= AGx Q /=; rewrite !inE -{1}(normsP nG_AG x) ?pHallJ2. rewrite {1}/AG norm_joinEl // -group_modl ?normG ?coprime_norm_cent //=. rewrite -cent_joinEr ?subsetIr // => trC_FpA. have FpA_P: P \in FpA by rewrite !inE sylP. apply/(subgroup_transitiveP FpA_P _ trC_FpA); rewrite ?joing_subr //=. rewrite astab1JG cent_joinEr ?subsetIr // -group_modl // -mulgA. by congr (_ * _); rewrite mulSGid ?subsetIl. Qed. Lemma sol_coprime_Sylow_subset A G X : A \subset 'N(G) -> coprime #|G| #|A| -> solvable A -> X \subset G -> p.-group X -> A \subset 'N(X) -> exists P : {group gT}, [/\ p.-Sylow(G) P, A \subset 'N(P) & X \subset P]. Proof. move=> nGA coGA solA sXG pX nXA. pose nAp (Q : {group gT}) := [&& p.-group Q, Q \subset G & A \subset 'N(Q)]. have: nAp X by exact/and3P. case/maxgroup_exists=> R; case/maxgroupP; case/and3P=> pR sRG nRA maxR sXR. have [P sylP sRP]:= Sylow_superset sRG pR. suffices defP: P :=: R by exists P; rewrite sylP defP. case/and3P: sylP => sPG pP _; apply: (nilpotent_sub_norm (pgroup_nil pP)) => //. pose N := 'N_G(R); have{sPG} sPN_N: 'N_P(R) \subset N by exact: setSI. apply: norm_sub_max_pgroup (pgroupS (subsetIl _ _) pP) sPN_N (subsetIr _ _). have nNA: A \subset 'N(N) by rewrite normsI ?norms_norm. have coNA: coprime #|N| #|A| by apply: coprimeSg coGA; rewrite subsetIl. have{solA coNA} [Q sylQ nQA] := sol_coprime_Sylow_exists solA nNA coNA. suffices defQ: Q :=: R by rewrite max_pgroup_Sylow -{2}defQ. apply: maxR; first by apply/and3P; case/and3P: sylQ; rewrite subsetI; case/andP. by apply: normal_sub_max_pgroup (Hall_max sylQ) pR _; rewrite normal_subnorm. Qed. End SylowSolvableAct. mathcomp-1.5/theories/gseries.v0000644000175000017500000005077712307636117015653 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path fintype bigop. Require Import finset fingroup morphism automorphism quotient action. Require Import commutator center. (******************************************************************************) (* H <|<| G <=> H is subnormal in G, i.e., H <| ... <| G. *) (* invariant_factor A H G <=> A normalises both H and G, and H <| G. *) (* A.-invariant <=> the (invariant_factor A) relation, in the context *) (* of the g_rel.-series notation. *) (* g_rel.-series H s <=> H :: s is a sequence of groups whose projection *) (* to sets satisfies relation g_rel pairwise; for *) (* example H <|<| G iff G = last H s for some s such *) (* that normal.-series H s. *) (* stable_factor A H G == H <| G and A centralises G / H. *) (* A.-stable == the stable_factor relation, in the scope of the *) (* r.-series notation. *) (* G.-central == the central_factor relation, in the scope of the *) (* r.-series notation. *) (* maximal M G == M is a maximal proper subgroup of G. *) (* maximal_eq M G == (M == G) or (maximal M G). *) (* maxnormal M G N == M is a maximal subgroup of G normalized by N. *) (* minnormal M N == M is a minimal nontrivial group normalized by N. *) (* simple G == G is a (nontrivial) simple group. *) (* := minnormal G G *) (* G.-chief == the chief_factor relation, in the scope of the *) (* r.-series notation. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section GroupDefs. Variable gT : finGroupType. Implicit Types A B U V : {set gT}. Notation Local groupT := (group_of (Phant gT)). Definition subnormal A B := (A \subset B) && (iter #|B| (fun N => generated (class_support A N)) B == A). Definition invariant_factor A B C := [&& A \subset 'N(B), A \subset 'N(C) & B <| C]. Definition group_rel_of (r : rel {set gT}) := [rel H G : groupT | r H G]. Definition stable_factor A V U := ([~: U, A] \subset V) && (V <| U). (* this orders allows and3P to be used *) Definition central_factor A V U := [&& [~: U, A] \subset V, V \subset U & U \subset A]. Definition maximal A B := [max A of G | G \proper B]. Definition maximal_eq A B := (A == B) || maximal A B. Definition maxnormal A B U := [max A of G | G \proper B & U \subset 'N(G)]. Definition minnormal A B := [min A of G | G :!=: 1 & B \subset 'N(G)]. Definition simple A := minnormal A A. Definition chief_factor A V U := maxnormal V U A && (U <| A). End GroupDefs. Arguments Scope subnormal [_ group_scope group_scope]. Arguments Scope invariant_factor [_ group_scope group_scope group_scope]. Arguments Scope stable_factor [_ group_scope group_scope group_scope]. Arguments Scope central_factor [_ group_scope group_scope group_scope]. Arguments Scope maximal [_ group_scope group_scope]. Arguments Scope maximal_eq [_ group_scope group_scope]. Arguments Scope maxnormal [_ group_scope group_scope group_scope]. Arguments Scope minnormal [_ group_scope group_scope]. Arguments Scope simple [_ group_scope]. Arguments Scope chief_factor [_ group_scope group_scope group_scope]. Prenex Implicits subnormal maximal simple. Notation "H <|<| G" := (subnormal H G) (at level 70, no associativity) : group_scope. Notation "A .-invariant" := (invariant_factor A) (at level 2, format "A .-invariant") : group_rel_scope. Notation "A .-stable" := (stable_factor A) (at level 2, format "A .-stable") : group_rel_scope. Notation "A .-central" := (central_factor A) (at level 2, format "A .-central") : group_rel_scope. Notation "G .-chief" := (chief_factor G) (at level 2, format "G .-chief") : group_rel_scope. Arguments Scope group_rel_of [_ group_rel_scope Group_scope Group_scope]. Notation "r .-series" := (path (rel_of_simpl_rel (group_rel_of r))) (at level 2, format "r .-series") : group_scope. Section Subnormal. Variable gT : finGroupType. Implicit Types (A B C D : {set gT}) (G H K : {group gT}). Let setIgr H G := (G :&: H)%G. Let sub_setIgr G H : G \subset H -> G = setIgr H G. Proof. by move/setIidPl/group_inj. Qed. Let path_setIgr H G s : normal.-series H s -> normal.-series (setIgr G H) (map (setIgr G) s). Proof. elim: s H => //= K s IHs H /andP[/andP[sHK nHK] Ksn]. by rewrite /normal setSI ?normsIG ?IHs. Qed. Lemma subnormalP H G : reflect (exists2 s, normal.-series H s & last H s = G) (H <|<| G). Proof. apply: (iffP andP) => [[sHG snHG] | [s Hsn <-{G}]]. elim: {G}#|G| {-2}G sHG snHG => [|m IHm] G sHG. by exists [::]; last by apply/eqP; rewrite eq_sym. rewrite iterSr => /IHm[|s Hsn defG]. by rewrite sub_gen // class_supportEr (bigD1 1) //= conjsg1 subsetUl. exists (rcons s G); rewrite ?last_rcons // -cats1 cat_path Hsn defG /=. rewrite /normal gen_subG class_support_subG //=. by rewrite norms_gen ?class_support_norm. set f := fun _ => <<_>>; have idf: iter _ f H == H. by elim=> //= m IHm; rewrite (eqP IHm) /f class_support_id genGid. elim: {s}(size s) {-2}s (eqxx (size s)) Hsn => [[] //= | m IHm s]. case/lastP: s => // s G; rewrite size_rcons last_rcons -cats1 cat_path /=. set K := last H s => def_m /and3P[Hsn /andP[sKG nKG] _]. have:= sKG; rewrite subEproper; case/predU1P=> [<-|prKG]; first exact: IHm. pose L := [group of f G]. have sHK: H \subset K by case/IHm: Hsn. have sLK: L \subset K by rewrite gen_subG class_support_sub_norm. rewrite -(subnK (proper_card (sub_proper_trans sLK prKG))) iter_add iterSr. have defH: H = setIgr L H by rewrite -sub_setIgr ?sub_gen ?sub_class_support. have: normal.-series H (map (setIgr L) s) by rewrite defH path_setIgr. case/IHm=> [|_]; first by rewrite size_map. by rewrite {1 2}defH last_map (subset_trans sHK) //= (setIidPr sLK) => /eqP->. Qed. Lemma subnormal_refl G : G <|<| G. Proof. by apply/subnormalP; exists [::]. Qed. Lemma subnormal_trans K H G : H <|<| K -> K <|<| G -> H <|<| G. Proof. case/subnormalP=> [s1 Hs1 <-] /subnormalP[s2 Hs12 <-]. by apply/subnormalP; exists (s1 ++ s2); rewrite ?last_cat // cat_path Hs1. Qed. Lemma normal_subnormal H G : H <| G -> H <|<| G. Proof. by move=> nsHG; apply/subnormalP; exists [:: G]; rewrite //= nsHG. Qed. Lemma setI_subnormal G H K : K \subset G -> H <|<| G -> H :&: K <|<| K. Proof. move=> sKG /subnormalP[s Hs defG]; apply/subnormalP. exists (map (setIgr K) s); first exact: path_setIgr. rewrite (last_map (setIgr K)) defG. by apply: val_inj; rewrite /= (setIidPr sKG). Qed. Lemma subnormal_sub G H : H <|<| G -> H \subset G. Proof. by case/andP. Qed. Lemma invariant_subnormal A G H : A \subset 'N(G) -> A \subset 'N(H) -> H <|<| G -> exists2 s, (A.-invariant).-series H s & last H s = G. Proof. move=> nGA nHA /andP[]; move: #|G| => m. elim: m => [|m IHm] in G nGA * => sHG. by rewrite eq_sym; exists [::]; last exact/eqP. rewrite iterSr; set K := <<_>>. have nKA: A \subset 'N(K) by rewrite norms_gen ?norms_class_support. have sHK: H \subset K by rewrite sub_gen ?sub_class_support. case/IHm=> // s Hsn defK; exists (rcons s G); last by rewrite last_rcons. rewrite rcons_path Hsn !andbA defK nGA nKA /= -/K. by rewrite gen_subG class_support_subG ?norms_gen ?class_support_norm. Qed. Lemma subnormalEsupport G H : H <|<| G -> H :=: G \/ <> \proper G. Proof. case/andP=> sHG; set K := <<_>> => /eqP <-. have: K \subset G by rewrite gen_subG class_support_subG. rewrite subEproper; case/predU1P=> [defK|]; [left | by right]. by elim: #|G| => //= _ ->. Qed. Lemma subnormalEr G H : H <|<| G -> H :=: G \/ (exists K : {group gT}, [/\ H <|<| K, K <| G & K \proper G]). Proof. case/subnormalP=> s Hs <-{G}. elim/last_ind: s Hs => [|s G IHs]; first by left. rewrite last_rcons -cats1 cat_path /= andbT; set K := last H s. case/andP=> Hs nsKG; have:= normal_sub nsKG; rewrite subEproper. case/predU1P=> [<- | prKG]; [exact: IHs | right; exists K; split=> //]. by apply/subnormalP; exists s. Qed. Lemma subnormalEl G H : H <|<| G -> H :=: G \/ (exists K : {group gT}, [/\ H <| K, K <|<| G & H \proper K]). Proof. case/subnormalP=> s Hs <-{G}; elim: s H Hs => /= [|K s IHs] H; first by left. case/andP=> nsHK Ks; have:= normal_sub nsHK; rewrite subEproper. case/predU1P=> [-> | prHK]; [exact: IHs | right; exists K; split=> //]. by apply/subnormalP; exists s. Qed. End Subnormal. Implicit Arguments subnormalP [gT G H]. Prenex Implicits subnormalP. Section MorphSubNormal. Variable gT : finGroupType. Implicit Type G H K : {group gT}. Lemma morphim_subnormal (rT : finGroupType) G (f : {morphism G >-> rT}) H K : H <|<| K -> f @* H <|<| f @* K. Proof. case/subnormalP => s Hs <-{K}; apply/subnormalP. elim: s H Hs => [|K s IHs] H /=; first by exists [::]. case/andP=> nsHK /IHs[fs Hfs <-]. by exists ([group of f @* K] :: fs); rewrite /= ?morphim_normal. Qed. Lemma quotient_subnormal H G K : G <|<| K -> G / H <|<| K / H. Proof. exact: morphim_subnormal. Qed. End MorphSubNormal. Section MaxProps. Variable gT : finGroupType. Implicit Types G H M : {group gT}. Lemma maximal_eqP M G : reflect (M \subset G /\ forall H, M \subset H -> H \subset G -> H :=: M \/ H :=: G) (maximal_eq M G). Proof. rewrite subEproper /maximal_eq; case: eqP => [->|_]; first left. by split=> // H sGH sHG; right; apply/eqP; rewrite eqEsubset sHG. apply: (iffP maxgroupP) => [] [sMG maxM]; split=> // H. by move/maxM=> maxMH; rewrite subEproper; case/predU1P; auto. by rewrite properEneq => /andP[/eqP neHG sHG] /maxM[]. Qed. Lemma maximal_exists H G : H \subset G -> H :=: G \/ (exists2 M : {group gT}, maximal M G & H \subset M). Proof. rewrite subEproper; case/predU1P=> sHG; first by left. suff [M *]: {M : {group gT} | maximal M G & H \subset M} by right; exists M. exact: maxgroup_exists. Qed. Lemma mulg_normal_maximal G M H : M <| G -> maximal M G -> H \subset G -> ~~ (H \subset M) -> (M * H = G)%g. Proof. case/andP=> sMG nMG /maxgroupP[_ maxM] sHG not_sHM. apply/eqP; rewrite eqEproper mul_subG // -norm_joinEr ?(subset_trans sHG) //. by apply: contra not_sHM => /maxM <-; rewrite ?joing_subl ?joing_subr. Qed. End MaxProps. Section MinProps. Variable gT : finGroupType. Implicit Types G H M : {group gT}. Lemma minnormal_exists G H : H :!=: 1 -> G \subset 'N(H) -> {M : {group gT} | minnormal M G & M \subset H}. Proof. by move=> ntH nHG; apply: mingroup_exists (H) _; rewrite ntH. Qed. End MinProps. Section MorphPreMax. Variables (gT rT : finGroupType) (D : {group gT}) (f : {morphism D >-> rT}). Variables (M G : {group rT}). Hypotheses (dM : M \subset f @* D) (dG : G \subset f @* D). Lemma morphpre_maximal : maximal (f @*^-1 M) (f @*^-1 G) = maximal M G. Proof. apply/maxgroupP/maxgroupP; rewrite morphpre_proper //= => [] [ltMG maxM]. split=> // H ltHG sMH; have dH := subset_trans (proper_sub ltHG) dG. rewrite -(morphpreK dH) [f @*^-1 H]maxM ?morphpreK ?morphpreSK //. by rewrite morphpre_proper. split=> // H ltHG sMH. have dH: H \subset D := subset_trans (proper_sub ltHG) (subsetIl D _). have defH: f @*^-1 (f @* H) = H. by apply: morphimGK dH; apply: subset_trans sMH; exact: ker_sub_pre. rewrite -defH morphpre_proper ?morphimS // in ltHG. by rewrite -defH [f @* H]maxM // -(morphpreK dM) morphimS. Qed. Lemma morphpre_maximal_eq : maximal_eq (f @*^-1 M) (f @*^-1 G) = maximal_eq M G. Proof. by rewrite /maximal_eq morphpre_maximal !eqEsubset !morphpreSK. Qed. End MorphPreMax. Section InjmMax. Variables (gT rT : finGroupType) (D : {group gT}) (f : {morphism D >-> rT}). Variables M G L : {group gT}. Hypothesis injf : 'injm f. Hypotheses (dM : M \subset D) (dG : G \subset D) (dL : L \subset D). Lemma injm_maximal : maximal (f @* M) (f @* G) = maximal M G. Proof. rewrite -(morphpre_invm injf) -(morphpre_invm injf G). by rewrite morphpre_maximal ?morphim_invm. Qed. Lemma injm_maximal_eq : maximal_eq (f @* M) (f @* G) = maximal_eq M G. Proof. by rewrite /maximal_eq injm_maximal // injm_eq. Qed. Lemma injm_maxnormal : maxnormal (f @* M) (f @* G) (f @* L) = maxnormal M G L. Proof. pose injfm := (injm_proper injf, injm_norms, injmSK injf, subsetIl). apply/maxgroupP/maxgroupP; rewrite !injfm // => [[nML maxM]]. split=> // H nHL sMH; have [/proper_sub sHG _] := andP nHL. have dH := subset_trans sHG dG; apply: (injm_morphim_inj injf) => //. by apply: maxM; rewrite !injfm. split=> // fH nHL sMH; have [/proper_sub sfHG _] := andP nHL. have{sfHG} dfH: fH \subset f @* D := subset_trans sfHG (morphim_sub f G). by rewrite -(morphpreK dfH) !injfm // in nHL sMH *; rewrite (maxM _ nHL). Qed. Lemma injm_minnormal : minnormal (f @* M) (f @* G) = minnormal M G. Proof. pose injfm := (morphim_injm_eq1 injf, injm_norms, injmSK injf, subsetIl). apply/mingroupP/mingroupP; rewrite !injfm // => [[nML minM]]. split=> // H nHG sHM; have dH := subset_trans sHM dM. by apply: (injm_morphim_inj injf) => //; apply: minM; rewrite !injfm. split=> // fH nHG sHM; have dfH := subset_trans sHM (morphim_sub f M). by rewrite -(morphpreK dfH) !injfm // in nHG sHM *; rewrite (minM _ nHG). Qed. End InjmMax. Section QuoMax. Variables (gT : finGroupType) (K G H : {group gT}). Lemma cosetpre_maximal (Q R : {group coset_of K}) : maximal (coset K @*^-1 Q) (coset K @*^-1 R) = maximal Q R. Proof. by rewrite morphpre_maximal ?sub_im_coset. Qed. Lemma cosetpre_maximal_eq (Q R : {group coset_of K}) : maximal_eq (coset K @*^-1 Q) (coset K @*^-1 R) = maximal_eq Q R. Proof. by rewrite /maximal_eq !eqEsubset !cosetpreSK cosetpre_maximal. Qed. Lemma quotient_maximal : K <| G -> K <| H -> maximal (G / K) (H / K) = maximal G H. Proof. by move=> nKG nKH; rewrite -cosetpre_maximal ?quotientGK. Qed. Lemma quotient_maximal_eq : K <| G -> K <| H -> maximal_eq (G / K) (H / K) = maximal_eq G H. Proof. by move=> nKG nKH; rewrite -cosetpre_maximal_eq ?quotientGK. Qed. Lemma maximalJ x : maximal (G :^ x) (H :^ x) = maximal G H. Proof. rewrite -{1}(setTI G) -{1}(setTI H) -!morphim_conj. by rewrite injm_maximal ?subsetT ?injm_conj. Qed. Lemma maximal_eqJ x : maximal_eq (G :^ x) (H :^ x) = maximal_eq G H. Proof. by rewrite /maximal_eq !eqEsubset !conjSg maximalJ. Qed. End QuoMax. Section MaxNormalProps. Variables (gT : finGroupType). Implicit Types (A B C : {set gT}) (G H K L M : {group gT}). Lemma maxnormal_normal A B : maxnormal A B B -> A <| B. Proof. by case/maxsetP=> /and3P[/gen_set_id /= -> pAB nAB]; rewrite /normal proper_sub. Qed. Lemma maxnormal_proper A B C : maxnormal A B C -> A \proper B. Proof. by case/maxsetP=> /and3P[gA pAB _] _; exact: (sub_proper_trans (subset_gen A)). Qed. Lemma maxnormal_sub A B C : maxnormal A B C -> A \subset B. Proof. by move=> maxA; rewrite proper_sub //; exact: (maxnormal_proper maxA). Qed. Lemma ex_maxnormal_ntrivg G : G :!=: 1-> {N : {group gT} | maxnormal N G G}. Proof. move=> ntG; apply: ex_maxgroup; exists [1 gT]%G; rewrite norm1 proper1G. by rewrite subsetT ntG. Qed. Lemma maxnormalM G H K : maxnormal H G G -> maxnormal K G G -> H :<>: K -> H * K = G. Proof. move=> maxH maxK /eqP; apply: contraNeq => ltHK_G. have [nsHG nsKG] := (maxnormal_normal maxH, maxnormal_normal maxK). have cHK: commute H K. exact: normC (subset_trans (normal_sub nsHG) (normal_norm nsKG)). wlog suffices: H K {maxH} maxK nsHG nsKG cHK ltHK_G / H \subset K. by move=> IH; rewrite eqEsubset !IH // -cHK. have{maxK} /maxgroupP[_ maxK] := maxK. apply/joing_idPr/maxK; rewrite ?joing_subr //= comm_joingE //. by rewrite properEneq ltHK_G; exact: normalM. Qed. Lemma maxnormal_minnormal G L M : G \subset 'N(M) -> L \subset 'N(G) -> maxnormal M G L -> minnormal (G / M) (L / M). Proof. move=> nMG nGL /maxgroupP[/andP[/andP[sMG ltMG] nML] maxM]; apply/mingroupP. rewrite -subG1 quotient_sub1 ?ltMG ?quotient_norms //. split=> // Hb /andP[ntHb nHbL]; have nsMG: M <| G by exact/andP. case/inv_quotientS=> // H defHb sMH sHG; rewrite defHb; congr (_ / M). apply/eqP; rewrite eqEproper sHG /=; apply: contra ntHb => ltHG. have nsMH: M <| H := normalS sMH sHG nsMG. rewrite defHb quotientS1 // (maxM H) // ltHG /= -(quotientGK nsMH) -defHb. exact: norm_quotient_pre. Qed. Lemma minnormal_maxnormal G L M : M <| G -> L \subset 'N(M) -> minnormal (G / M) (L / M) -> maxnormal M G L. Proof. case/andP=> sMG nMG nML /mingroupP[/andP[/= ntGM _] minGM]; apply/maxgroupP. split=> [|H /andP[/andP[sHG ltHG] nHL] sMH]. by rewrite /proper sMG nML andbT; apply: contra ntGM => /quotientS1 ->. apply/eqP; rewrite eqEsubset sMH andbT -quotient_sub1 ?(subset_trans sHG) //. rewrite subG1; apply: contraR ltHG => ntHM; rewrite -(quotientSGK nMG) //. by rewrite (minGM (H / M)%G) ?quotientS // ntHM quotient_norms. Qed. End MaxNormalProps. Section Simple. Implicit Types gT rT : finGroupType. Lemma simpleP gT (G : {group gT}) : reflect (G :!=: 1 /\ forall H : {group gT}, H <| G -> H :=: 1 \/ H :=: G) (simple G). Proof. apply: (iffP mingroupP); rewrite normG andbT => [[ntG simG]]. split=> // N /andP[sNG nNG]. by case: (eqsVneq N 1) => [|ntN]; [left | right; apply: simG; rewrite ?ntN]. split=> // N /andP[ntN nNG] sNG. by case: (simG N) ntN => // [|->]; [exact/andP | case/eqP]. Qed. Lemma quotient_simple gT (G H : {group gT}) : H <| G -> simple (G / H) = maxnormal H G G. Proof. move=> nsHG; have nGH := normal_norm nsHG. by apply/idP/idP; [exact: minnormal_maxnormal | exact: maxnormal_minnormal]. Qed. Lemma isog_simple gT rT (G : {group gT}) (M : {group rT}) : G \isog M -> simple G = simple M. Proof. move=> eqGM; wlog suffices: gT rT G M eqGM / simple M -> simple G. by move=> IH; apply/idP/idP; apply: IH; rewrite // isog_sym. case/isogP: eqGM => f injf <- /simpleP[ntGf simGf]. apply/simpleP; split=> [|N nsNG]; first by rewrite -(morphim_injm_eq1 injf). rewrite -(morphim_invm injf (normal_sub nsNG)). have: f @* N <| f @* G by rewrite morphim_normal. by case/simGf=> /= ->; [left | right]; rewrite (morphim1, morphim_invm). Qed. Lemma simple_maxnormal gT (G : {group gT}) : simple G = maxnormal 1 G G. Proof. by rewrite -quotient_simple ?normal1 // -(isog_simple (quotient1_isog G)). Qed. End Simple. Section Chiefs. Variable gT : finGroupType. Implicit Types G H U V : {group gT}. Lemma chief_factor_minnormal G V U : chief_factor G V U -> minnormal (U / V) (G / V). Proof. case/andP=> maxV /andP[sUG nUG]; apply: maxnormal_minnormal => //. by have /andP[_ nVG] := maxgroupp maxV; exact: subset_trans sUG nVG. Qed. Lemma acts_irrQ G U V : G \subset 'N(V) -> V <| U -> acts_irreducibly G (U / V) 'Q = minnormal (U / V) (G / V). Proof. move=> nVG nsVU; apply/mingroupP/mingroupP; case=> /andP[->] /=. rewrite astabsQ // subsetI nVG /= => nUG minUV. rewrite quotient_norms //; split=> // H /andP[ntH nHG] sHU. by apply: minUV (sHU); rewrite ntH -(cosetpreK H) actsQ // norm_quotient_pre. rewrite sub_quotient_pre // => nUG minU; rewrite astabsQ //. rewrite (subset_trans nUG); last first. by rewrite subsetI subsetIl /= -{2}(quotientGK nsVU) morphpre_norm. split=> // H /andP[ntH nHG] sHU. rewrite -{1}(cosetpreK H) astabsQ ?normal_cosetpre ?subsetI ?nVG //= in nHG. apply: minU sHU; rewrite ntH; apply: subset_trans (quotientS _ nHG) _. by rewrite -{2}(cosetpreK H) quotient_norm. Qed. Lemma chief_series_exists H G : H <| G -> {s | (G.-chief).-series 1%G s & last 1%G s = H}. Proof. elim: {H}_.+1 {-2}H (ltnSn #|H|) => // m IHm U leUm nsUG. have [-> | ntU] := eqVneq U 1%G; first by exists [::]. have [V maxV]: {V : {group gT} | maxnormal V U G}. by apply: ex_maxgroup; exists 1%G; rewrite proper1G ntU norms1. have /andP[ltVU nVG] := maxgroupp maxV. have [||s ch_s defV] := IHm V; first exact: leq_trans (proper_card ltVU) _. by rewrite /normal (subset_trans (proper_sub ltVU) (normal_sub nsUG)). exists (rcons s U); last by rewrite last_rcons. by rewrite rcons_path defV /= ch_s /chief_factor; exact/and3P. Qed. End Chiefs. Section Central. Variables (gT : finGroupType) (G : {group gT}). Implicit Types H K : {group gT}. Lemma central_factor_central H K : central_factor G H K -> (K / H) \subset 'Z(G / H). Proof. by case/and3P=> /quotient_cents2r *; rewrite subsetI quotientS. Qed. Lemma central_central_factor H K : (K / H) \subset 'Z(G / H) -> H <| K -> H <| G -> central_factor G H K. Proof. case/subsetIP=> sKGb cGKb /andP[sHK nHK] /andP[sHG nHG]. by rewrite /central_factor -quotient_cents2 // cGKb sHK -(quotientSGK nHK). Qed. End Central. mathcomp-1.5/theories/bigop.v0000644000175000017500000021741312307636117015302 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div fintype. Require Import tuple finfun. (******************************************************************************) (* This file provides a generic definition for iterating an operator over a *) (* set of indices (reducebig); this big operator is parametrized by the *) (* return type (R), the type of indices (I), the operator (op), the default *) (* value on empty lists (idx), the range of indices (r), the filter applied *) (* on this range (P) and the expression we are iterating (F). The definition *) (* is not to be used directly, but via the wide range of notations provided *) (* and which allows a natural use of big operators. *) (* The lemmas can be classified according to the operator being iterated: *) (* 1. results independent of the operator: extensionality with respect to *) (* the range of indices, to the filtering predicate or to the expression *) (* being iterated; reindexing, widening or narrowing of the range of *) (* indices; we provide lemmas for the special cases where indices are *) (* natural numbers or bounded natural numbers ("ordinals"). We supply *) (* several "functional" induction principles that can be used with the *) (* ssreflect 1.3 "elim" tactic to do induction over the index range for *) (* up to 3 bigops simultaneously. *) (* 2. results depending on the properties of the operator: *) (* We distinguish: monoid laws (op is associative, idx is an identity *) (* element), abelian monoid laws (op is also commutative), and laws with *) (* a distributive operation (semi-rings). Examples of such results are *) (* splitting, permuting, and exchanging bigops. *) (* A special section is dedicated to big operators on natural numbers. *) (******************************************************************************) (* Notations: *) (* The general form for iterated operators is *) (* _ *) (* - is one of \big[op/idx], \sum, \prod, or \max (see below). *) (* - can be any expression. *) (* - binds an index variable in ; is one of *) (* (i <- s) i ranges over the sequence s *) (* (m <= i < n) i ranges over the nat interval m, m.+1, ..., n.-1 *) (* (i < n) i ranges over the (finite) type 'I_n (i.e., ordinal n) *) (* (i : T) i ranges over the finite type T *) (* i or (i) i ranges over its (inferred) finite type *) (* (i in A) i ranges over the elements that satisfy the collective *) (* predicate A (the domain of A must be a finite type) *) (* (i <- s | ) limits the range to the i for which *) (* holds. can be any expression that coerces to *) (* bool, and may mention the bound index i. All six kinds of *) (* ranges above can have a part. *) (* - One can use the "\big[op/idx]" notations for any operator. *) (* - BIG_F and BIG_P are pattern abbreviations for the and *) (* part of a \big ... expression; for (i in A) and (i in A | C) *) (* ranges the term matched by BIG_P will include the i \in A condition. *) (* - The (locked) head constant of a \big notation is bigop. *) (* - The "\sum", "\prod" and "\max" notations in the %N scope are used for *) (* natural numbers with addition, multiplication and maximum (and their *) (* corresponding neutral elements), respectively. *) (* - The "\sum" and "\prod" reserved notations are overloaded in ssralg in *) (* the %R scope, in mxalgebra, vector & falgebra in the %MS and %VS scopes; *) (* "\prod" is also overloaded in fingroup, the %g and %G scopes. *) (* - We reserve "\bigcup" and "\bigcap" notations for iterated union and *) (* intersection (of sets, groups, vector spaces, etc). *) (******************************************************************************) (* Tips for using lemmas in this file: *) (* to apply a lemma for a specific operator: if no special property is *) (* required for the operator, simply apply the lemma; if the lemma needs *) (* certain properties for the operator, make sure the appropriate Canonical *) (* instances are declared. *) (******************************************************************************) (* Interfaces for operator properties are packaged in the Monoid submodule: *) (* Monoid.law idx == interface (keyed on the operator) for associative *) (* operators with identity element idx. *) (* Monoid.com_law idx == extension (telescope) of Monoid.law for operators *) (* that are also commutative. *) (* Monoid.mul_law abz == interface for operators with absorbing (zero) *) (* element abz. *) (* Monoid.add_law idx mop == extension of Monoid.com_law for operators over *) (* which operation mop distributes (mop will often also *) (* have a Monoid.mul_law idx structure). *) (* [law of op], [com_law of op], [mul_law of op], [add_law mop of op] == *) (* syntax for cloning Monoid structures. *) (* Monoid.Theory == submodule containing basic generic algebra lemmas *) (* for operators satisfying the Monoid interfaces. *) (* Monoid.simpm == generic monoid simplification rewrite multirule. *) (* Monoid structures are predeclared for many basic operators: (_ && _)%B, *) (* (_ || _)%B, (_ (+) _)%B (exclusive or) , (_ + _)%N, (_ * _)%N, maxn, *) (* gcdn, lcmn and (_ ++ _)%SEQ (list concatenation). *) (******************************************************************************) (* Additional documentation for this file: *) (* Y. Bertot, G. Gonthier, S. Ould Biha and I. Pasca. *) (* Canonical Big Operators. In TPHOLs 2008, LNCS vol. 5170, Springer. *) (* Article available at: *) (* http://hal.inria.fr/docs/00/33/11/93/PDF/main.pdf *) (******************************************************************************) (* Examples of use in: poly.v, matrix.v *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Reserved Notation "\big [ op / idx ]_ i F" (at level 36, F at level 36, op, idx at level 10, i at level 0, right associativity, format "'[' \big [ op / idx ]_ i '/ ' F ']'"). Reserved Notation "\big [ op / idx ]_ ( i <- r | P ) F" (at level 36, F at level 36, op, idx at level 10, i, r at level 50, format "'[' \big [ op / idx ]_ ( i <- r | P ) '/ ' F ']'"). Reserved Notation "\big [ op / idx ]_ ( i <- r ) F" (at level 36, F at level 36, op, idx at level 10, i, r at level 50, format "'[' \big [ op / idx ]_ ( i <- r ) '/ ' F ']'"). Reserved Notation "\big [ op / idx ]_ ( m <= i < n | P ) F" (at level 36, F at level 36, op, idx at level 10, m, i, n at level 50, format "'[' \big [ op / idx ]_ ( m <= i < n | P ) F ']'"). Reserved Notation "\big [ op / idx ]_ ( m <= i < n ) F" (at level 36, F at level 36, op, idx at level 10, i, m, n at level 50, format "'[' \big [ op / idx ]_ ( m <= i < n ) '/ ' F ']'"). Reserved Notation "\big [ op / idx ]_ ( i | P ) F" (at level 36, F at level 36, op, idx at level 10, i at level 50, format "'[' \big [ op / idx ]_ ( i | P ) '/ ' F ']'"). Reserved Notation "\big [ op / idx ]_ ( i : t | P ) F" (at level 36, F at level 36, op, idx at level 10, i at level 50, format "'[' \big [ op / idx ]_ ( i : t | P ) '/ ' F ']'"). Reserved Notation "\big [ op / idx ]_ ( i : t ) F" (at level 36, F at level 36, op, idx at level 10, i at level 50, format "'[' \big [ op / idx ]_ ( i : t ) '/ ' F ']'"). Reserved Notation "\big [ op / idx ]_ ( i < n | P ) F" (at level 36, F at level 36, op, idx at level 10, i, n at level 50, format "'[' \big [ op / idx ]_ ( i < n | P ) '/ ' F ']'"). Reserved Notation "\big [ op / idx ]_ ( i < n ) F" (at level 36, F at level 36, op, idx at level 10, i, n at level 50, format "'[' \big [ op / idx ]_ ( i < n ) F ']'"). Reserved Notation "\big [ op / idx ]_ ( i 'in' A | P ) F" (at level 36, F at level 36, op, idx at level 10, i, A at level 50, format "'[' \big [ op / idx ]_ ( i 'in' A | P ) '/ ' F ']'"). Reserved Notation "\big [ op / idx ]_ ( i 'in' A ) F" (at level 36, F at level 36, op, idx at level 10, i, A at level 50, format "'[' \big [ op / idx ]_ ( i 'in' A ) '/ ' F ']'"). Reserved Notation "\sum_ i F" (at level 41, F at level 41, i at level 0, right associativity, format "'[' \sum_ i '/ ' F ']'"). Reserved Notation "\sum_ ( i <- r | P ) F" (at level 41, F at level 41, i, r at level 50, format "'[' \sum_ ( i <- r | P ) '/ ' F ']'"). Reserved Notation "\sum_ ( i <- r ) F" (at level 41, F at level 41, i, r at level 50, format "'[' \sum_ ( i <- r ) '/ ' F ']'"). Reserved Notation "\sum_ ( m <= i < n | P ) F" (at level 41, F at level 41, i, m, n at level 50, format "'[' \sum_ ( m <= i < n | P ) '/ ' F ']'"). Reserved Notation "\sum_ ( m <= i < n ) F" (at level 41, F at level 41, i, m, n at level 50, format "'[' \sum_ ( m <= i < n ) '/ ' F ']'"). Reserved Notation "\sum_ ( i | P ) F" (at level 41, F at level 41, i at level 50, format "'[' \sum_ ( i | P ) '/ ' F ']'"). Reserved Notation "\sum_ ( i : t | P ) F" (at level 41, F at level 41, i at level 50, only parsing). Reserved Notation "\sum_ ( i : t ) F" (at level 41, F at level 41, i at level 50, only parsing). Reserved Notation "\sum_ ( i < n | P ) F" (at level 41, F at level 41, i, n at level 50, format "'[' \sum_ ( i < n | P ) '/ ' F ']'"). Reserved Notation "\sum_ ( i < n ) F" (at level 41, F at level 41, i, n at level 50, format "'[' \sum_ ( i < n ) '/ ' F ']'"). Reserved Notation "\sum_ ( i 'in' A | P ) F" (at level 41, F at level 41, i, A at level 50, format "'[' \sum_ ( i 'in' A | P ) '/ ' F ']'"). Reserved Notation "\sum_ ( i 'in' A ) F" (at level 41, F at level 41, i, A at level 50, format "'[' \sum_ ( i 'in' A ) '/ ' F ']'"). Reserved Notation "\max_ i F" (at level 41, F at level 41, i at level 0, format "'[' \max_ i '/ ' F ']'"). Reserved Notation "\max_ ( i <- r | P ) F" (at level 41, F at level 41, i, r at level 50, format "'[' \max_ ( i <- r | P ) '/ ' F ']'"). Reserved Notation "\max_ ( i <- r ) F" (at level 41, F at level 41, i, r at level 50, format "'[' \max_ ( i <- r ) '/ ' F ']'"). Reserved Notation "\max_ ( m <= i < n | P ) F" (at level 41, F at level 41, i, m, n at level 50, format "'[' \max_ ( m <= i < n | P ) '/ ' F ']'"). Reserved Notation "\max_ ( m <= i < n ) F" (at level 41, F at level 41, i, m, n at level 50, format "'[' \max_ ( m <= i < n ) '/ ' F ']'"). Reserved Notation "\max_ ( i | P ) F" (at level 41, F at level 41, i at level 50, format "'[' \max_ ( i | P ) '/ ' F ']'"). Reserved Notation "\max_ ( i : t | P ) F" (at level 41, F at level 41, i at level 50, only parsing). Reserved Notation "\max_ ( i : t ) F" (at level 41, F at level 41, i at level 50, only parsing). Reserved Notation "\max_ ( i < n | P ) F" (at level 41, F at level 41, i, n at level 50, format "'[' \max_ ( i < n | P ) '/ ' F ']'"). Reserved Notation "\max_ ( i < n ) F" (at level 41, F at level 41, i, n at level 50, format "'[' \max_ ( i < n ) F ']'"). Reserved Notation "\max_ ( i 'in' A | P ) F" (at level 41, F at level 41, i, A at level 50, format "'[' \max_ ( i 'in' A | P ) '/ ' F ']'"). Reserved Notation "\max_ ( i 'in' A ) F" (at level 41, F at level 41, i, A at level 50, format "'[' \max_ ( i 'in' A ) '/ ' F ']'"). Reserved Notation "\prod_ i F" (at level 36, F at level 36, i at level 0, format "'[' \prod_ i '/ ' F ']'"). Reserved Notation "\prod_ ( i <- r | P ) F" (at level 36, F at level 36, i, r at level 50, format "'[' \prod_ ( i <- r | P ) '/ ' F ']'"). Reserved Notation "\prod_ ( i <- r ) F" (at level 36, F at level 36, i, r at level 50, format "'[' \prod_ ( i <- r ) '/ ' F ']'"). Reserved Notation "\prod_ ( m <= i < n | P ) F" (at level 36, F at level 36, i, m, n at level 50, format "'[' \prod_ ( m <= i < n | P ) '/ ' F ']'"). Reserved Notation "\prod_ ( m <= i < n ) F" (at level 36, F at level 36, i, m, n at level 50, format "'[' \prod_ ( m <= i < n ) '/ ' F ']'"). Reserved Notation "\prod_ ( i | P ) F" (at level 36, F at level 36, i at level 50, format "'[' \prod_ ( i | P ) '/ ' F ']'"). Reserved Notation "\prod_ ( i : t | P ) F" (at level 36, F at level 36, i at level 50, only parsing). Reserved Notation "\prod_ ( i : t ) F" (at level 36, F at level 36, i at level 50, only parsing). Reserved Notation "\prod_ ( i < n | P ) F" (at level 36, F at level 36, i, n at level 50, format "'[' \prod_ ( i < n | P ) '/ ' F ']'"). Reserved Notation "\prod_ ( i < n ) F" (at level 36, F at level 36, i, n at level 50, format "'[' \prod_ ( i < n ) '/ ' F ']'"). Reserved Notation "\prod_ ( i 'in' A | P ) F" (at level 36, F at level 36, i, A at level 50, format "'[' \prod_ ( i 'in' A | P ) F ']'"). Reserved Notation "\prod_ ( i 'in' A ) F" (at level 36, F at level 36, i, A at level 50, format "'[' \prod_ ( i 'in' A ) '/ ' F ']'"). Reserved Notation "\bigcup_ i F" (at level 41, F at level 41, i at level 0, format "'[' \bigcup_ i '/ ' F ']'"). Reserved Notation "\bigcup_ ( i <- r | P ) F" (at level 41, F at level 41, i, r at level 50, format "'[' \bigcup_ ( i <- r | P ) '/ ' F ']'"). Reserved Notation "\bigcup_ ( i <- r ) F" (at level 41, F at level 41, i, r at level 50, format "'[' \bigcup_ ( i <- r ) '/ ' F ']'"). Reserved Notation "\bigcup_ ( m <= i < n | P ) F" (at level 41, F at level 41, m, i, n at level 50, format "'[' \bigcup_ ( m <= i < n | P ) '/ ' F ']'"). Reserved Notation "\bigcup_ ( m <= i < n ) F" (at level 41, F at level 41, i, m, n at level 50, format "'[' \bigcup_ ( m <= i < n ) '/ ' F ']'"). Reserved Notation "\bigcup_ ( i | P ) F" (at level 41, F at level 41, i at level 50, format "'[' \bigcup_ ( i | P ) '/ ' F ']'"). Reserved Notation "\bigcup_ ( i : t | P ) F" (at level 41, F at level 41, i at level 50, format "'[' \bigcup_ ( i : t | P ) '/ ' F ']'"). Reserved Notation "\bigcup_ ( i : t ) F" (at level 41, F at level 41, i at level 50, format "'[' \bigcup_ ( i : t ) '/ ' F ']'"). Reserved Notation "\bigcup_ ( i < n | P ) F" (at level 41, F at level 41, i, n at level 50, format "'[' \bigcup_ ( i < n | P ) '/ ' F ']'"). Reserved Notation "\bigcup_ ( i < n ) F" (at level 41, F at level 41, i, n at level 50, format "'[' \bigcup_ ( i < n ) '/ ' F ']'"). Reserved Notation "\bigcup_ ( i 'in' A | P ) F" (at level 41, F at level 41, i, A at level 50, format "'[' \bigcup_ ( i 'in' A | P ) '/ ' F ']'"). Reserved Notation "\bigcup_ ( i 'in' A ) F" (at level 41, F at level 41, i, A at level 50, format "'[' \bigcup_ ( i 'in' A ) '/ ' F ']'"). Reserved Notation "\bigcap_ i F" (at level 41, F at level 41, i at level 0, format "'[' \bigcap_ i '/ ' F ']'"). Reserved Notation "\bigcap_ ( i <- r | P ) F" (at level 41, F at level 41, i, r at level 50, format "'[' \bigcap_ ( i <- r | P ) F ']'"). Reserved Notation "\bigcap_ ( i <- r ) F" (at level 41, F at level 41, i, r at level 50, format "'[' \bigcap_ ( i <- r ) '/ ' F ']'"). Reserved Notation "\bigcap_ ( m <= i < n | P ) F" (at level 41, F at level 41, m, i, n at level 50, format "'[' \bigcap_ ( m <= i < n | P ) '/ ' F ']'"). Reserved Notation "\bigcap_ ( m <= i < n ) F" (at level 41, F at level 41, i, m, n at level 50, format "'[' \bigcap_ ( m <= i < n ) '/ ' F ']'"). Reserved Notation "\bigcap_ ( i | P ) F" (at level 41, F at level 41, i at level 50, format "'[' \bigcap_ ( i | P ) '/ ' F ']'"). Reserved Notation "\bigcap_ ( i : t | P ) F" (at level 41, F at level 41, i at level 50, format "'[' \bigcap_ ( i : t | P ) '/ ' F ']'"). Reserved Notation "\bigcap_ ( i : t ) F" (at level 41, F at level 41, i at level 50, format "'[' \bigcap_ ( i : t ) '/ ' F ']'"). Reserved Notation "\bigcap_ ( i < n | P ) F" (at level 41, F at level 41, i, n at level 50, format "'[' \bigcap_ ( i < n | P ) '/ ' F ']'"). Reserved Notation "\bigcap_ ( i < n ) F" (at level 41, F at level 41, i, n at level 50, format "'[' \bigcap_ ( i < n ) '/ ' F ']'"). Reserved Notation "\bigcap_ ( i 'in' A | P ) F" (at level 41, F at level 41, i, A at level 50, format "'[' \bigcap_ ( i 'in' A | P ) '/ ' F ']'"). Reserved Notation "\bigcap_ ( i 'in' A ) F" (at level 41, F at level 41, i, A at level 50, format "'[' \bigcap_ ( i 'in' A ) '/ ' F ']'"). Module Monoid. Section Definitions. Variables (T : Type) (idm : T). Structure law := Law { operator : T -> T -> T; _ : associative operator; _ : left_id idm operator; _ : right_id idm operator }. Local Coercion operator : law >-> Funclass. Structure com_law := ComLaw { com_operator : law; _ : commutative com_operator }. Local Coercion com_operator : com_law >-> law. Structure mul_law := MulLaw { mul_operator : T -> T -> T; _ : left_zero idm mul_operator; _ : right_zero idm mul_operator }. Local Coercion mul_operator : mul_law >-> Funclass. Structure add_law (mul : T -> T -> T) := AddLaw { add_operator : com_law; _ : left_distributive mul add_operator; _ : right_distributive mul add_operator }. Local Coercion add_operator : add_law >-> com_law. Let op_id (op1 op2 : T -> T -> T) := phant_id op1 op2. Definition clone_law op := fun (opL : law) & op_id opL op => fun opmA op1m opm1 (opL' := @Law op opmA op1m opm1) & phant_id opL' opL => opL'. Definition clone_com_law op := fun (opL : law) (opC : com_law) & op_id opL op & op_id opC op => fun opmC (opC' := @ComLaw opL opmC) & phant_id opC' opC => opC'. Definition clone_mul_law op := fun (opM : mul_law) & op_id opM op => fun op0m opm0 (opM' := @MulLaw op op0m opm0) & phant_id opM' opM => opM'. Definition clone_add_law mop aop := fun (opC : com_law) (opA : add_law mop) & op_id opC aop & op_id opA aop => fun mopDm mopmD (opA' := @AddLaw mop opC mopDm mopmD) & phant_id opA' opA => opA'. End Definitions. Module Import Exports. Coercion operator : law >-> Funclass. Coercion com_operator : com_law >-> law. Coercion mul_operator : mul_law >-> Funclass. Coercion add_operator : add_law >-> com_law. Notation "[ 'law' 'of' f ]" := (@clone_law _ _ f _ id _ _ _ id) (at level 0, format"[ 'law' 'of' f ]") : form_scope. Notation "[ 'com_law' 'of' f ]" := (@clone_com_law _ _ f _ _ id id _ id) (at level 0, format "[ 'com_law' 'of' f ]") : form_scope. Notation "[ 'mul_law' 'of' f ]" := (@clone_mul_law _ _ f _ id _ _ id) (at level 0, format"[ 'mul_law' 'of' f ]") : form_scope. Notation "[ 'add_law' m 'of' a ]" := (@clone_add_law _ _ m a _ _ id id _ _ id) (at level 0, format "[ 'add_law' m 'of' a ]") : form_scope. End Exports. Section CommutativeAxioms. Variable (T : Type) (zero one : T) (mul add : T -> T -> T) (inv : T -> T). Hypothesis mulC : commutative mul. Lemma mulC_id : left_id one mul -> right_id one mul. Proof. by move=> mul1x x; rewrite mulC. Qed. Lemma mulC_zero : left_zero zero mul -> right_zero zero mul. Proof. by move=> mul0x x; rewrite mulC. Qed. Lemma mulC_dist : left_distributive mul add -> right_distributive mul add. Proof. by move=> mul_addl x y z; rewrite !(mulC x). Qed. End CommutativeAxioms. Module Theory. Section Theory. Variables (T : Type) (idm : T). Section Plain. Variable mul : law idm. Lemma mul1m : left_id idm mul. Proof. by case mul. Qed. Lemma mulm1 : right_id idm mul. Proof. by case mul. Qed. Lemma mulmA : associative mul. Proof. by case mul. Qed. Lemma iteropE n x : iterop n mul x idm = iter n (mul x) idm. Proof. by case: n => // n; rewrite iterSr mulm1 iteropS. Qed. End Plain. Section Commutative. Variable mul : com_law idm. Lemma mulmC : commutative mul. Proof. by case mul. Qed. Lemma mulmCA : left_commutative mul. Proof. by move=> x y z; rewrite !mulmA (mulmC x). Qed. Lemma mulmAC : right_commutative mul. Proof. by move=> x y z; rewrite -!mulmA (mulmC y). Qed. Lemma mulmACA : interchange mul mul. Proof. by move=> x y z t; rewrite -!mulmA (mulmCA y). Qed. End Commutative. Section Mul. Variable mul : mul_law idm. Lemma mul0m : left_zero idm mul. Proof. by case mul. Qed. Lemma mulm0 : right_zero idm mul. Proof. by case mul. Qed. End Mul. Section Add. Variables (mul : T -> T -> T) (add : add_law idm mul). Lemma addmA : associative add. Proof. exact: mulmA. Qed. Lemma addmC : commutative add. Proof. exact: mulmC. Qed. Lemma addmCA : left_commutative add. Proof. exact: mulmCA. Qed. Lemma addmAC : right_commutative add. Proof. exact: mulmAC. Qed. Lemma add0m : left_id idm add. Proof. exact: mul1m. Qed. Lemma addm0 : right_id idm add. Proof. exact: mulm1. Qed. Lemma mulm_addl : left_distributive mul add. Proof. by case add. Qed. Lemma mulm_addr : right_distributive mul add. Proof. by case add. Qed. End Add. Definition simpm := (mulm1, mulm0, mul1m, mul0m, mulmA). End Theory. End Theory. Include Theory. End Monoid. Export Monoid.Exports. Section PervasiveMonoids. Import Monoid. Canonical andb_monoid := Law andbA andTb andbT. Canonical andb_comoid := ComLaw andbC. Canonical andb_muloid := MulLaw andFb andbF. Canonical orb_monoid := Law orbA orFb orbF. Canonical orb_comoid := ComLaw orbC. Canonical orb_muloid := MulLaw orTb orbT. Canonical addb_monoid := Law addbA addFb addbF. Canonical addb_comoid := ComLaw addbC. Canonical orb_addoid := AddLaw andb_orl andb_orr. Canonical andb_addoid := AddLaw orb_andl orb_andr. Canonical addb_addoid := AddLaw andb_addl andb_addr. Canonical addn_monoid := Law addnA add0n addn0. Canonical addn_comoid := ComLaw addnC. Canonical muln_monoid := Law mulnA mul1n muln1. Canonical muln_comoid := ComLaw mulnC. Canonical muln_muloid := MulLaw mul0n muln0. Canonical addn_addoid := AddLaw mulnDl mulnDr. Canonical maxn_monoid := Law maxnA max0n maxn0. Canonical maxn_comoid := ComLaw maxnC. Canonical maxn_addoid := AddLaw maxn_mull maxn_mulr. Canonical gcdn_monoid := Law gcdnA gcd0n gcdn0. Canonical gcdn_comoid := ComLaw gcdnC. Canonical gcdnDoid := AddLaw muln_gcdl muln_gcdr. Canonical lcmn_monoid := Law lcmnA lcm1n lcmn1. Canonical lcmn_comoid := ComLaw lcmnC. Canonical lcmn_addoid := AddLaw muln_lcml muln_lcmr. Canonical cat_monoid T := Law (@catA T) (@cat0s T) (@cats0 T). End PervasiveMonoids. (* Unit test for the [...law of ...] Notations Definition myp := addn. Definition mym := muln. Canonical myp_mon := [law of myp]. Canonical myp_cmon := [com_law of myp]. Canonical mym_mul := [mul_law of mym]. Canonical myp_add := [add_law _ of myp]. Print myp_add. Print Canonical Projections. *) Delimit Scope big_scope with BIG. Open Scope big_scope. (* The bigbody wrapper is a workaround for a quirk of the Coq pretty-printer, *) (* which would fail to redisplay the \big notation when the or *) (* do not depend on the bound index. The BigBody constructor *) (* packages both in in a term in which i occurs; it also depends on the *) (* iterated , as this can give more information on the expected type of *) (* the , thus allowing for the insertion of coercions. *) CoInductive bigbody R I := BigBody of I & (R -> R -> R) & bool & R. Definition applybig {R I} (body : bigbody R I) x := let: BigBody _ op b v := body in if b then op v x else x. Definition reducebig R I idx r (body : I -> bigbody R I) := foldr (applybig \o body) idx r. Module Type BigOpSig. Parameter bigop : forall R I, R -> seq I -> (I -> bigbody R I) -> R. Axiom bigopE : bigop = reducebig. End BigOpSig. Module BigOp : BigOpSig. Definition bigop := reducebig. Lemma bigopE : bigop = reducebig. Proof. by []. Qed. End BigOp. Notation bigop := BigOp.bigop (only parsing). Canonical bigop_unlock := Unlockable BigOp.bigopE. Definition index_iota m n := iota m (n - m). Definition index_enum (T : finType) := Finite.enum T. Lemma mem_index_iota m n i : i \in index_iota m n = (m <= i < n). Proof. rewrite mem_iota; case le_m_i: (m <= i) => //=. by rewrite -leq_subLR subSn // -subn_gt0 -subnDA subnKC // subn_gt0. Qed. Lemma mem_index_enum T i : i \in index_enum T. Proof. by rewrite -[index_enum T]enumT mem_enum. Qed. Hint Resolve mem_index_enum. Lemma filter_index_enum T P : filter P (index_enum T) = enum P. Proof. by []. Qed. Notation "\big [ op / idx ]_ ( i <- r | P ) F" := (bigop idx r (fun i => BigBody i op P%B F)) : big_scope. Notation "\big [ op / idx ]_ ( i <- r ) F" := (bigop idx r (fun i => BigBody i op true F)) : big_scope. Notation "\big [ op / idx ]_ ( m <= i < n | P ) F" := (bigop idx (index_iota m n) (fun i : nat => BigBody i op P%B F)) : big_scope. Notation "\big [ op / idx ]_ ( m <= i < n ) F" := (bigop idx (index_iota m n) (fun i : nat => BigBody i op true F)) : big_scope. Notation "\big [ op / idx ]_ ( i | P ) F" := (bigop idx (index_enum _) (fun i => BigBody i op P%B F)) : big_scope. Notation "\big [ op / idx ]_ i F" := (bigop idx (index_enum _) (fun i => BigBody i op true F)) : big_scope. Notation "\big [ op / idx ]_ ( i : t | P ) F" := (bigop idx (index_enum _) (fun i : t => BigBody i op P%B F)) (only parsing) : big_scope. Notation "\big [ op / idx ]_ ( i : t ) F" := (bigop idx (index_enum _) (fun i : t => BigBody i op true F)) (only parsing) : big_scope. Notation "\big [ op / idx ]_ ( i < n | P ) F" := (\big[op/idx]_(i : ordinal n | P%B) F) : big_scope. Notation "\big [ op / idx ]_ ( i < n ) F" := (\big[op/idx]_(i : ordinal n) F) : big_scope. Notation "\big [ op / idx ]_ ( i 'in' A | P ) F" := (\big[op/idx]_(i | (i \in A) && P) F) : big_scope. Notation "\big [ op / idx ]_ ( i 'in' A ) F" := (\big[op/idx]_(i | i \in A) F) : big_scope. Notation BIG_F := (F in \big[_/_]_(i <- _ | _) F i)%pattern. Notation BIG_P := (P in \big[_/_]_(i <- _ | P i) _)%pattern. Local Notation "+%N" := addn (at level 0, only parsing). Notation "\sum_ ( i <- r | P ) F" := (\big[+%N/0%N]_(i <- r | P%B) F%N) : nat_scope. Notation "\sum_ ( i <- r ) F" := (\big[+%N/0%N]_(i <- r) F%N) : nat_scope. Notation "\sum_ ( m <= i < n | P ) F" := (\big[+%N/0%N]_(m <= i < n | P%B) F%N) : nat_scope. Notation "\sum_ ( m <= i < n ) F" := (\big[+%N/0%N]_(m <= i < n) F%N) : nat_scope. Notation "\sum_ ( i | P ) F" := (\big[+%N/0%N]_(i | P%B) F%N) : nat_scope. Notation "\sum_ i F" := (\big[+%N/0%N]_i F%N) : nat_scope. Notation "\sum_ ( i : t | P ) F" := (\big[+%N/0%N]_(i : t | P%B) F%N) (only parsing) : nat_scope. Notation "\sum_ ( i : t ) F" := (\big[+%N/0%N]_(i : t) F%N) (only parsing) : nat_scope. Notation "\sum_ ( i < n | P ) F" := (\big[+%N/0%N]_(i < n | P%B) F%N) : nat_scope. Notation "\sum_ ( i < n ) F" := (\big[+%N/0%N]_(i < n) F%N) : nat_scope. Notation "\sum_ ( i 'in' A | P ) F" := (\big[+%N/0%N]_(i in A | P%B) F%N) : nat_scope. Notation "\sum_ ( i 'in' A ) F" := (\big[+%N/0%N]_(i in A) F%N) : nat_scope. Local Notation "*%N" := muln (at level 0, only parsing). Notation "\prod_ ( i <- r | P ) F" := (\big[*%N/1%N]_(i <- r | P%B) F%N) : nat_scope. Notation "\prod_ ( i <- r ) F" := (\big[*%N/1%N]_(i <- r) F%N) : nat_scope. Notation "\prod_ ( m <= i < n | P ) F" := (\big[*%N/1%N]_(m <= i < n | P%B) F%N) : nat_scope. Notation "\prod_ ( m <= i < n ) F" := (\big[*%N/1%N]_(m <= i < n) F%N) : nat_scope. Notation "\prod_ ( i | P ) F" := (\big[*%N/1%N]_(i | P%B) F%N) : nat_scope. Notation "\prod_ i F" := (\big[*%N/1%N]_i F%N) : nat_scope. Notation "\prod_ ( i : t | P ) F" := (\big[*%N/1%N]_(i : t | P%B) F%N) (only parsing) : nat_scope. Notation "\prod_ ( i : t ) F" := (\big[*%N/1%N]_(i : t) F%N) (only parsing) : nat_scope. Notation "\prod_ ( i < n | P ) F" := (\big[*%N/1%N]_(i < n | P%B) F%N) : nat_scope. Notation "\prod_ ( i < n ) F" := (\big[*%N/1%N]_(i < n) F%N) : nat_scope. Notation "\prod_ ( i 'in' A | P ) F" := (\big[*%N/1%N]_(i in A | P%B) F%N) : nat_scope. Notation "\prod_ ( i 'in' A ) F" := (\big[*%N/1%N]_(i in A) F%N) : nat_scope. Notation "\max_ ( i <- r | P ) F" := (\big[maxn/0%N]_(i <- r | P%B) F%N) : nat_scope. Notation "\max_ ( i <- r ) F" := (\big[maxn/0%N]_(i <- r) F%N) : nat_scope. Notation "\max_ ( i | P ) F" := (\big[maxn/0%N]_(i | P%B) F%N) : nat_scope. Notation "\max_ i F" := (\big[maxn/0%N]_i F%N) : nat_scope. Notation "\max_ ( i : I | P ) F" := (\big[maxn/0%N]_(i : I | P%B) F%N) (only parsing) : nat_scope. Notation "\max_ ( i : I ) F" := (\big[maxn/0%N]_(i : I) F%N) (only parsing) : nat_scope. Notation "\max_ ( m <= i < n | P ) F" := (\big[maxn/0%N]_(m <= i < n | P%B) F%N) : nat_scope. Notation "\max_ ( m <= i < n ) F" := (\big[maxn/0%N]_(m <= i < n) F%N) : nat_scope. Notation "\max_ ( i < n | P ) F" := (\big[maxn/0%N]_(i < n | P%B) F%N) : nat_scope. Notation "\max_ ( i < n ) F" := (\big[maxn/0%N]_(i < n) F%N) : nat_scope. Notation "\max_ ( i 'in' A | P ) F" := (\big[maxn/0%N]_(i in A | P%B) F%N) : nat_scope. Notation "\max_ ( i 'in' A ) F" := (\big[maxn/0%N]_(i in A) F%N) : nat_scope. (* Induction loading *) Lemma big_load R (K K' : R -> Type) idx op I r (P : pred I) F : K (\big[op/idx]_(i <- r | P i) F i) * K' (\big[op/idx]_(i <- r | P i) F i) -> K' (\big[op/idx]_(i <- r | P i) F i). Proof. by case. Qed. Implicit Arguments big_load [R K' I]. Section Elim3. Variables (R1 R2 R3 : Type) (K : R1 -> R2 -> R3 -> Type). Variables (id1 : R1) (op1 : R1 -> R1 -> R1). Variables (id2 : R2) (op2 : R2 -> R2 -> R2). Variables (id3 : R3) (op3 : R3 -> R3 -> R3). Hypothesis Kid : K id1 id2 id3. Lemma big_rec3 I r (P : pred I) F1 F2 F3 (K_F : forall i y1 y2 y3, P i -> K y1 y2 y3 -> K (op1 (F1 i) y1) (op2 (F2 i) y2) (op3 (F3 i) y3)) : K (\big[op1/id1]_(i <- r | P i) F1 i) (\big[op2/id2]_(i <- r | P i) F2 i) (\big[op3/id3]_(i <- r | P i) F3 i). Proof. by rewrite unlock; elim: r => //= i r; case: ifP => //; exact: K_F. Qed. Hypothesis Kop : forall x1 x2 x3 y1 y2 y3, K x1 x2 x3 -> K y1 y2 y3-> K (op1 x1 y1) (op2 x2 y2) (op3 x3 y3). Lemma big_ind3 I r (P : pred I) F1 F2 F3 (K_F : forall i, P i -> K (F1 i) (F2 i) (F3 i)) : K (\big[op1/id1]_(i <- r | P i) F1 i) (\big[op2/id2]_(i <- r | P i) F2 i) (\big[op3/id3]_(i <- r | P i) F3 i). Proof. by apply: big_rec3 => i x1 x2 x3 /K_F; exact: Kop. Qed. End Elim3. Implicit Arguments big_rec3 [R1 R2 R3 id1 op1 id2 op2 id3 op3 I r P F1 F2 F3]. Implicit Arguments big_ind3 [R1 R2 R3 id1 op1 id2 op2 id3 op3 I r P F1 F2 F3]. Section Elim2. Variables (R1 R2 : Type) (K : R1 -> R2 -> Type) (f : R2 -> R1). Variables (id1 : R1) (op1 : R1 -> R1 -> R1). Variables (id2 : R2) (op2 : R2 -> R2 -> R2). Hypothesis Kid : K id1 id2. Lemma big_rec2 I r (P : pred I) F1 F2 (K_F : forall i y1 y2, P i -> K y1 y2 -> K (op1 (F1 i) y1) (op2 (F2 i) y2)) : K (\big[op1/id1]_(i <- r | P i) F1 i) (\big[op2/id2]_(i <- r | P i) F2 i). Proof. by rewrite unlock; elim: r => //= i r; case: ifP => //; exact: K_F. Qed. Hypothesis Kop : forall x1 x2 y1 y2, K x1 x2 -> K y1 y2 -> K (op1 x1 y1) (op2 x2 y2). Lemma big_ind2 I r (P : pred I) F1 F2 (K_F : forall i, P i -> K (F1 i) (F2 i)) : K (\big[op1/id1]_(i <- r | P i) F1 i) (\big[op2/id2]_(i <- r | P i) F2 i). Proof. by apply: big_rec2 => i x1 x2 /K_F; exact: Kop. Qed. Hypotheses (f_op : {morph f : x y / op2 x y >-> op1 x y}) (f_id : f id2 = id1). Lemma big_morph I r (P : pred I) F : f (\big[op2/id2]_(i <- r | P i) F i) = \big[op1/id1]_(i <- r | P i) f (F i). Proof. by rewrite unlock; elim: r => //= i r <-; rewrite -f_op -fun_if. Qed. End Elim2. Implicit Arguments big_rec2 [R1 R2 id1 op1 id2 op2 I r P F1 F2]. Implicit Arguments big_ind2 [R1 R2 id1 op1 id2 op2 I r P F1 F2]. Implicit Arguments big_morph [R1 R2 id1 op1 id2 op2 I]. Section Elim1. Variables (R : Type) (K : R -> Type) (f : R -> R). Variables (idx : R) (op op' : R -> R -> R). Hypothesis Kid : K idx. Lemma big_rec I r (P : pred I) F (Kop : forall i x, P i -> K x -> K (op (F i) x)) : K (\big[op/idx]_(i <- r | P i) F i). Proof. by rewrite unlock; elim: r => //= i r; case: ifP => //; exact: Kop. Qed. Hypothesis Kop : forall x y, K x -> K y -> K (op x y). Lemma big_ind I r (P : pred I) F (K_F : forall i, P i -> K (F i)) : K (\big[op/idx]_(i <- r | P i) F i). Proof. by apply: big_rec => // i x /K_F /Kop; exact. Qed. Hypothesis Kop' : forall x y, K x -> K y -> op x y = op' x y. Lemma eq_big_op I r (P : pred I) F (K_F : forall i, P i -> K (F i)) : \big[op/idx]_(i <- r | P i) F i = \big[op'/idx]_(i <- r | P i) F i. Proof. by elim/(big_load K): _; elim/big_rec2: _ => // i _ y Pi [Ky <-]; auto. Qed. Hypotheses (fM : {morph f : x y / op x y}) (f_id : f idx = idx). Lemma big_endo I r (P : pred I) F : f (\big[op/idx]_(i <- r | P i) F i) = \big[op/idx]_(i <- r | P i) f (F i). Proof. exact: big_morph. Qed. End Elim1. Implicit Arguments big_rec [R idx op I r P F]. Implicit Arguments big_ind [R idx op I r P F]. Implicit Arguments eq_big_op [R idx op I]. Implicit Arguments big_endo [R idx op I]. Section Extensionality. Variables (R : Type) (idx : R) (op : R -> R -> R). Section SeqExtension. Variable I : Type. Lemma big_filter r (P : pred I) F : \big[op/idx]_(i <- filter P r) F i = \big[op/idx]_(i <- r | P i) F i. Proof. by rewrite unlock; elim: r => //= i r <-; case (P i). Qed. Lemma big_filter_cond r (P1 P2 : pred I) F : \big[op/idx]_(i <- filter P1 r | P2 i) F i = \big[op/idx]_(i <- r | P1 i && P2 i) F i. Proof. rewrite -big_filter -(big_filter r); congr bigop. rewrite -filter_predI; apply: eq_filter => i; exact: andbC. Qed. Lemma eq_bigl r (P1 P2 : pred I) F : P1 =1 P2 -> \big[op/idx]_(i <- r | P1 i) F i = \big[op/idx]_(i <- r | P2 i) F i. Proof. by move=> eqP12; rewrite -!(big_filter r) (eq_filter eqP12). Qed. (* A lemma to permute aggregate conditions. *) Lemma big_andbC r (P Q : pred I) F : \big[op/idx]_(i <- r | P i && Q i) F i = \big[op/idx]_(i <- r | Q i && P i) F i. Proof. by apply: eq_bigl => i; exact: andbC. Qed. Lemma eq_bigr r (P : pred I) F1 F2 : (forall i, P i -> F1 i = F2 i) -> \big[op/idx]_(i <- r | P i) F1 i = \big[op/idx]_(i <- r | P i) F2 i. Proof. by move=> eqF12; elim/big_rec2: _ => // i x _ /eqF12-> ->. Qed. Lemma eq_big r (P1 P2 : pred I) F1 F2 : P1 =1 P2 -> (forall i, P1 i -> F1 i = F2 i) -> \big[op/idx]_(i <- r | P1 i) F1 i = \big[op/idx]_(i <- r | P2 i) F2 i. Proof. by move/eq_bigl <-; move/eq_bigr->. Qed. Lemma congr_big r1 r2 (P1 P2 : pred I) F1 F2 : r1 = r2 -> P1 =1 P2 -> (forall i, P1 i -> F1 i = F2 i) -> \big[op/idx]_(i <- r1 | P1 i) F1 i = \big[op/idx]_(i <- r2 | P2 i) F2 i. Proof. by move=> <-{r2}; exact: eq_big. Qed. Lemma big_nil (P : pred I) F : \big[op/idx]_(i <- [::] | P i) F i = idx. Proof. by rewrite unlock. Qed. Lemma big_cons i r (P : pred I) F : let x := \big[op/idx]_(j <- r | P j) F j in \big[op/idx]_(j <- i :: r | P j) F j = if P i then op (F i) x else x. Proof. by rewrite unlock. Qed. Lemma big_map J (h : J -> I) r (P : pred I) F : \big[op/idx]_(i <- map h r | P i) F i = \big[op/idx]_(j <- r | P (h j)) F (h j). Proof. by rewrite unlock; elim: r => //= j r ->. Qed. Lemma big_nth x0 r (P : pred I) F : \big[op/idx]_(i <- r | P i) F i = \big[op/idx]_(0 <= i < size r | P (nth x0 r i)) (F (nth x0 r i)). Proof. by rewrite -{1}(mkseq_nth x0 r) big_map /index_iota subn0. Qed. Lemma big_hasC r (P : pred I) F : ~~ has P r -> \big[op/idx]_(i <- r | P i) F i = idx. Proof. by rewrite -big_filter has_count -size_filter -eqn0Ngt unlock => /nilP->. Qed. Lemma big_pred0_eq (r : seq I) F : \big[op/idx]_(i <- r | false) F i = idx. Proof. by rewrite big_hasC // has_pred0. Qed. Lemma big_pred0 r (P : pred I) F : P =1 xpred0 -> \big[op/idx]_(i <- r | P i) F i = idx. Proof. by move/eq_bigl->; exact: big_pred0_eq. Qed. Lemma big_cat_nested r1 r2 (P : pred I) F : let x := \big[op/idx]_(i <- r2 | P i) F i in \big[op/idx]_(i <- r1 ++ r2 | P i) F i = \big[op/x]_(i <- r1 | P i) F i. Proof. by rewrite unlock /reducebig foldr_cat. Qed. Lemma big_catl r1 r2 (P : pred I) F : ~~ has P r2 -> \big[op/idx]_(i <- r1 ++ r2 | P i) F i = \big[op/idx]_(i <- r1 | P i) F i. Proof. by rewrite big_cat_nested => /big_hasC->. Qed. Lemma big_catr r1 r2 (P : pred I) F : ~~ has P r1 -> \big[op/idx]_(i <- r1 ++ r2 | P i) F i = \big[op/idx]_(i <- r2 | P i) F i. Proof. rewrite -big_filter -(big_filter r2) filter_cat. by rewrite has_count -size_filter; case: filter. Qed. Lemma big_const_seq r (P : pred I) x : \big[op/idx]_(i <- r | P i) x = iter (count P r) (op x) idx. Proof. by rewrite unlock; elim: r => //= i r ->; case: (P i). Qed. End SeqExtension. (* The following lemmas can be used to localise extensionality to a specific *) (* index sequence. This is done by ssreflect rewriting, before applying *) (* congruence or induction lemmas. *) Lemma big_seq_cond (I : eqType) r (P : pred I) F : \big[op/idx]_(i <- r | P i) F i = \big[op/idx]_(i <- r | (i \in r) && P i) F i. Proof. by rewrite -!(big_filter r); congr bigop; apply: eq_in_filter => i ->. Qed. Lemma big_seq (I : eqType) (r : seq I) F : \big[op/idx]_(i <- r) F i = \big[op/idx]_(i <- r | i \in r) F i. Proof. by rewrite big_seq_cond big_andbC. Qed. Lemma eq_big_seq (I : eqType) (r : seq I) F1 F2 : {in r, F1 =1 F2} -> \big[op/idx]_(i <- r) F1 i = \big[op/idx]_(i <- r) F2 i. Proof. by move=> eqF; rewrite !big_seq (eq_bigr _ eqF). Qed. (* Similar lemmas for exposing integer indexing in the predicate. *) Lemma big_nat_cond m n (P : pred nat) F : \big[op/idx]_(m <= i < n | P i) F i = \big[op/idx]_(m <= i < n | (m <= i < n) && P i) F i. Proof. by rewrite big_seq_cond; apply: eq_bigl => i; rewrite mem_index_iota. Qed. Lemma big_nat m n F : \big[op/idx]_(m <= i < n) F i = \big[op/idx]_(m <= i < n | m <= i < n) F i. Proof. by rewrite big_nat_cond big_andbC. Qed. Lemma congr_big_nat m1 n1 m2 n2 P1 P2 F1 F2 : m1 = m2 -> n1 = n2 -> (forall i, m1 <= i < n2 -> P1 i = P2 i) -> (forall i, P1 i && (m1 <= i < n2) -> F1 i = F2 i) -> \big[op/idx]_(m1 <= i < n1 | P1 i) F1 i = \big[op/idx]_(m2 <= i < n2 | P2 i) F2 i. Proof. move=> <- <- eqP12 eqF12; rewrite big_seq_cond (big_seq_cond _ P2). apply: eq_big => i; rewrite ?inE /= !mem_index_iota. by apply: andb_id2l; exact: eqP12. by rewrite andbC; exact: eqF12. Qed. Lemma eq_big_nat m n F1 F2 : (forall i, m <= i < n -> F1 i = F2 i) -> \big[op/idx]_(m <= i < n) F1 i = \big[op/idx]_(m <= i < n) F2 i. Proof. by move=> eqF; apply: congr_big_nat. Qed. Lemma big_geq m n (P : pred nat) F : m >= n -> \big[op/idx]_(m <= i < n | P i) F i = idx. Proof. by move=> ge_m_n; rewrite /index_iota (eqnP ge_m_n) big_nil. Qed. Lemma big_ltn_cond m n (P : pred nat) F : m < n -> let x := \big[op/idx]_(m.+1 <= i < n | P i) F i in \big[op/idx]_(m <= i < n | P i) F i = if P m then op (F m) x else x. Proof. by case: n => [//|n] le_m_n; rewrite /index_iota subSn // big_cons. Qed. Lemma big_ltn m n F : m < n -> \big[op/idx]_(m <= i < n) F i = op (F m) (\big[op/idx]_(m.+1 <= i < n) F i). Proof. move=> lt_mn; exact: big_ltn_cond. Qed. Lemma big_addn m n a (P : pred nat) F : \big[op/idx]_(m + a <= i < n | P i) F i = \big[op/idx]_(m <= i < n - a | P (i + a)) F (i + a). Proof. rewrite /index_iota -subnDA addnC iota_addl big_map. by apply: eq_big => ? *; rewrite addnC. Qed. Lemma big_add1 m n (P : pred nat) F : \big[op/idx]_(m.+1 <= i < n | P i) F i = \big[op/idx]_(m <= i < n.-1 | P (i.+1)) F (i.+1). Proof. by rewrite -addn1 big_addn subn1; apply: eq_big => ? *; rewrite addn1. Qed. Lemma big_nat_recl n m F : m <= n -> \big[op/idx]_(m <= i < n.+1) F i = op (F m) (\big[op/idx]_(m <= i < n) F i.+1). Proof. by move=> lemn; rewrite big_ltn // big_add1. Qed. Lemma big_mkord n (P : pred nat) F : \big[op/idx]_(0 <= i < n | P i) F i = \big[op/idx]_(i < n | P i) F i. Proof. rewrite /index_iota subn0 -(big_map (@nat_of_ord n)). by congr bigop; rewrite /index_enum unlock val_ord_enum. Qed. Lemma big_nat_widen m n1 n2 (P : pred nat) F : n1 <= n2 -> \big[op/idx]_(m <= i < n1 | P i) F i = \big[op/idx]_(m <= i < n2 | P i && (i < n1)) F i. Proof. move=> len12; symmetry; rewrite -big_filter filter_predI big_filter. have [ltn_trans eq_by_mem] := (ltn_trans, eq_sorted_irr ltn_trans ltnn). congr bigop; apply: eq_by_mem; rewrite ?sorted_filter ?iota_ltn_sorted // => i. rewrite mem_filter !mem_index_iota andbCA andbA andb_idr => // /andP[_]. by move/leq_trans->. Qed. Lemma big_ord_widen_cond n1 n2 (P : pred nat) (F : nat -> R) : n1 <= n2 -> \big[op/idx]_(i < n1 | P i) F i = \big[op/idx]_(i < n2 | P i && (i < n1)) F i. Proof. by move/big_nat_widen=> len12; rewrite -big_mkord len12 big_mkord. Qed. Lemma big_ord_widen n1 n2 (F : nat -> R) : n1 <= n2 -> \big[op/idx]_(i < n1) F i = \big[op/idx]_(i < n2 | i < n1) F i. Proof. by move=> le_n12; exact: (big_ord_widen_cond (predT)). Qed. Lemma big_ord_widen_leq n1 n2 (P : pred 'I_(n1.+1)) F : n1 < n2 -> \big[op/idx]_(i < n1.+1 | P i) F i = \big[op/idx]_(i < n2 | P (inord i) && (i <= n1)) F (inord i). Proof. move=> len12; pose g G i := G (inord i : 'I_(n1.+1)). rewrite -(big_ord_widen_cond (g _ P) (g _ F) len12) {}/g. by apply: eq_big => i *; rewrite inord_val. Qed. Lemma big_ord0 P F : \big[op/idx]_(i < 0 | P i) F i = idx. Proof. by rewrite big_pred0 => [|[]]. Qed. Lemma big_tnth I r (P : pred I) F : let r_ := tnth (in_tuple r) in \big[op/idx]_(i <- r | P i) F i = \big[op/idx]_(i < size r | P (r_ i)) (F (r_ i)). Proof. case: r => /= [|x0 r]; first by rewrite big_nil big_ord0. by rewrite (big_nth x0) big_mkord; apply: eq_big => i; rewrite (tnth_nth x0). Qed. Lemma big_index_uniq (I : eqType) (r : seq I) (E : 'I_(size r) -> R) : uniq r -> \big[op/idx]_i E i = \big[op/idx]_(x <- r) oapp E idx (insub (index x r)). Proof. move=> Ur; apply/esym; rewrite big_tnth; apply: eq_bigr => i _. by rewrite index_uniq // valK. Qed. Lemma big_tuple I n (t : n.-tuple I) (P : pred I) F : \big[op/idx]_(i <- t | P i) F i = \big[op/idx]_(i < n | P (tnth t i)) F (tnth t i). Proof. by rewrite big_tnth tvalK; case: _ / (esym _). Qed. Lemma big_ord_narrow_cond n1 n2 (P : pred 'I_n2) F (le_n12 : n1 <= n2) : let w := widen_ord le_n12 in \big[op/idx]_(i < n2 | P i && (i < n1)) F i = \big[op/idx]_(i < n1 | P (w i)) F (w i). Proof. case: n1 => [|n1] /= in le_n12 *. by rewrite big_ord0 big_pred0 // => i; rewrite andbF. rewrite (big_ord_widen_leq _ _ le_n12); apply: eq_big => i. by apply: andb_id2r => le_i_n1; congr P; apply: val_inj; rewrite /= inordK. by case/andP=> _ le_i_n1; congr F; apply: val_inj; rewrite /= inordK. Qed. Lemma big_ord_narrow_cond_leq n1 n2 (P : pred _) F (le_n12 : n1 <= n2) : let w := @widen_ord n1.+1 n2.+1 le_n12 in \big[op/idx]_(i < n2.+1 | P i && (i <= n1)) F i = \big[op/idx]_(i < n1.+1 | P (w i)) F (w i). Proof. exact: (@big_ord_narrow_cond n1.+1 n2.+1). Qed. Lemma big_ord_narrow n1 n2 F (le_n12 : n1 <= n2) : let w := widen_ord le_n12 in \big[op/idx]_(i < n2 | i < n1) F i = \big[op/idx]_(i < n1) F (w i). Proof. exact: (big_ord_narrow_cond (predT)). Qed. Lemma big_ord_narrow_leq n1 n2 F (le_n12 : n1 <= n2) : let w := @widen_ord n1.+1 n2.+1 le_n12 in \big[op/idx]_(i < n2.+1 | i <= n1) F i = \big[op/idx]_(i < n1.+1) F (w i). Proof. exact: (big_ord_narrow_cond_leq (predT)). Qed. Lemma big_ord_recl n F : \big[op/idx]_(i < n.+1) F i = op (F ord0) (\big[op/idx]_(i < n) F (@lift n.+1 ord0 i)). Proof. pose G i := F (inord i); have eqFG i: F i = G i by rewrite /G inord_val. rewrite (eq_bigr _ (fun i _ => eqFG i)) -(big_mkord _ (fun _ => _) G) eqFG. rewrite big_ltn // big_add1 /= big_mkord; congr op. by apply: eq_bigr => i _; rewrite eqFG. Qed. Lemma big_const (I : finType) (A : pred I) x : \big[op/idx]_(i in A) x = iter #|A| (op x) idx. Proof. by rewrite big_const_seq -size_filter cardE. Qed. Lemma big_const_nat m n x : \big[op/idx]_(m <= i < n) x = iter (n - m) (op x) idx. Proof. by rewrite big_const_seq count_predT size_iota. Qed. Lemma big_const_ord n x : \big[op/idx]_(i < n) x = iter n (op x) idx. Proof. by rewrite big_const card_ord. Qed. Lemma big_nseq_cond I n a (P : pred I) F : \big[op/idx]_(i <- nseq n a | P i) F i = if P a then iter n (op (F a)) idx else idx. Proof. by rewrite unlock; elim: n => /= [|n ->]; case: (P a). Qed. Lemma big_nseq I n a (F : I -> R): \big[op/idx]_(i <- nseq n a) F i = iter n (op (F a)) idx. Proof. exact: big_nseq_cond. Qed. End Extensionality. Section MonoidProperties. Import Monoid.Theory. Variable R : Type. Variable idx : R. Notation Local "1" := idx. Section Plain. Variable op : Monoid.law 1. Notation Local "*%M" := op (at level 0). Notation Local "x * y" := (op x y). Lemma eq_big_idx_seq idx' I r (P : pred I) F : right_id idx' *%M -> has P r -> \big[*%M/idx']_(i <- r | P i) F i =\big[*%M/1]_(i <- r | P i) F i. Proof. move=> op_idx'; rewrite -!(big_filter _ _ r) has_count -size_filter. case/lastP: (filter P r) => {r}// r i _. by rewrite -cats1 !(big_cat_nested, big_cons, big_nil) op_idx' mulm1. Qed. Lemma eq_big_idx idx' (I : finType) i0 (P : pred I) F : P i0 -> right_id idx' *%M -> \big[*%M/idx']_(i | P i) F i =\big[*%M/1]_(i | P i) F i. Proof. by move=> Pi0 op_idx'; apply: eq_big_idx_seq => //; apply/hasP; exists i0. Qed. Lemma big1_eq I r (P : pred I) : \big[*%M/1]_(i <- r | P i) 1 = 1. Proof. by rewrite big_const_seq; elim: (count _ _) => //= n ->; exact: mul1m. Qed. Lemma big1 I r (P : pred I) F : (forall i, P i -> F i = 1) -> \big[*%M/1]_(i <- r | P i) F i = 1. Proof. by move/(eq_bigr _)->; exact: big1_eq. Qed. Lemma big1_seq (I : eqType) r (P : pred I) F : (forall i, P i && (i \in r) -> F i = 1) -> \big[*%M/1]_(i <- r | P i) F i = 1. Proof. by move=> eqF1; rewrite big_seq_cond big_andbC big1. Qed. Lemma big_seq1 I (i : I) F : \big[*%M/1]_(j <- [:: i]) F j = F i. Proof. by rewrite unlock /= mulm1. Qed. Lemma big_mkcond I r (P : pred I) F : \big[*%M/1]_(i <- r | P i) F i = \big[*%M/1]_(i <- r) (if P i then F i else 1). Proof. by rewrite unlock; elim: r => //= i r ->; case P; rewrite ?mul1m. Qed. Lemma big_mkcondr I r (P Q : pred I) F : \big[*%M/1]_(i <- r | P i && Q i) F i = \big[*%M/1]_(i <- r | P i) (if Q i then F i else 1). Proof. by rewrite -big_filter_cond big_mkcond big_filter. Qed. Lemma big_mkcondl I r (P Q : pred I) F : \big[*%M/1]_(i <- r | P i && Q i) F i = \big[*%M/1]_(i <- r | Q i) (if P i then F i else 1). Proof. by rewrite big_andbC big_mkcondr. Qed. Lemma big_cat I r1 r2 (P : pred I) F : \big[*%M/1]_(i <- r1 ++ r2 | P i) F i = \big[*%M/1]_(i <- r1 | P i) F i * \big[*%M/1]_(i <- r2 | P i) F i. Proof. rewrite !(big_mkcond _ P) unlock. by elim: r1 => /= [|i r1 ->]; rewrite (mul1m, mulmA). Qed. Lemma big_pred1_eq (I : finType) (i : I) F : \big[*%M/1]_(j | j == i) F j = F i. Proof. by rewrite -big_filter filter_index_enum enum1 big_seq1. Qed. Lemma big_pred1 (I : finType) i (P : pred I) F : P =1 pred1 i -> \big[*%M/1]_(j | P j) F j = F i. Proof. by move/(eq_bigl _ _)->; exact: big_pred1_eq. Qed. Lemma big_cat_nat n m p (P : pred nat) F : m <= n -> n <= p -> \big[*%M/1]_(m <= i < p | P i) F i = (\big[*%M/1]_(m <= i < n | P i) F i) * (\big[*%M/1]_(n <= i < p | P i) F i). Proof. move=> le_mn le_np; rewrite -big_cat -{2}(subnKC le_mn) -iota_add subnDA. by rewrite subnKC // leq_sub. Qed. Lemma big_nat1 n F : \big[*%M/1]_(n <= i < n.+1) F i = F n. Proof. by rewrite big_ltn // big_geq // mulm1. Qed. Lemma big_nat_recr n m F : m <= n -> \big[*%M/1]_(m <= i < n.+1) F i = (\big[*%M/1]_(m <= i < n) F i) * F n. Proof. by move=> lemn; rewrite (@big_cat_nat n) ?leqnSn // big_nat1. Qed. Lemma big_ord_recr n F : \big[*%M/1]_(i < n.+1) F i = (\big[*%M/1]_(i < n) F (widen_ord (leqnSn n) i)) * F ord_max. Proof. transitivity (\big[*%M/1]_(0 <= i < n.+1) F (inord i)). by rewrite big_mkord; apply: eq_bigr=> i _; rewrite inord_val. rewrite big_nat_recr // big_mkord; congr (_ * F _); last first. by apply: val_inj; rewrite /= inordK. by apply: eq_bigr => [] i _; congr F; apply: ord_inj; rewrite inordK //= leqW. Qed. Lemma big_sumType (I1 I2 : finType) (P : pred (I1 + I2)) F : \big[*%M/1]_(i | P i) F i = (\big[*%M/1]_(i | P (inl _ i)) F (inl _ i)) * (\big[*%M/1]_(i | P (inr _ i)) F (inr _ i)). Proof. by rewrite /index_enum {1}[@Finite.enum]unlock /= big_cat !big_map. Qed. Lemma big_split_ord m n (P : pred 'I_(m + n)) F : \big[*%M/1]_(i | P i) F i = (\big[*%M/1]_(i | P (lshift n i)) F (lshift n i)) * (\big[*%M/1]_(i | P (rshift m i)) F (rshift m i)). Proof. rewrite -(big_map _ _ (lshift n) _ P F) -(big_map _ _ (@rshift m _) _ P F). rewrite -big_cat; congr bigop; apply: (inj_map val_inj). rewrite /index_enum -!enumT val_enum_ord map_cat -map_comp val_enum_ord. rewrite -map_comp (map_comp (addn m)) val_enum_ord. by rewrite -iota_addl addn0 iota_add. Qed. Lemma big_flatten I rr (P : pred I) F : \big[*%M/1]_(i <- flatten rr | P i) F i = \big[*%M/1]_(r <- rr) \big[*%M/1]_(i <- r | P i) F i. Proof. by elim: rr => [|r rr IHrr]; rewrite ?big_nil //= big_cat big_cons -IHrr. Qed. End Plain. Section Abelian. Variable op : Monoid.com_law 1. Notation Local "'*%M'" := op (at level 0). Notation Local "x * y" := (op x y). Lemma eq_big_perm (I : eqType) r1 r2 (P : pred I) F : perm_eq r1 r2 -> \big[*%M/1]_(i <- r1 | P i) F i = \big[*%M/1]_(i <- r2 | P i) F i. Proof. move/perm_eqP; rewrite !(big_mkcond _ _ P). elim: r1 r2 => [|i r1 IHr1] r2 eq_r12. by case: r2 eq_r12 => // i r2; move/(_ (pred1 i)); rewrite /= eqxx. have r2i: i \in r2 by rewrite -has_pred1 has_count -eq_r12 /= eqxx. case/splitPr: r2 / r2i => [r3 r4] in eq_r12 *; rewrite big_cat /= !big_cons. rewrite mulmCA; congr (_ * _); rewrite -big_cat; apply: IHr1 => a. move/(_ a): eq_r12; rewrite !count_cat /= addnCA; exact: addnI. Qed. Lemma big_uniq (I : finType) (r : seq I) F : uniq r -> \big[*%M/1]_(i <- r) F i = \big[*%M/1]_(i in r) F i. Proof. move=> uniq_r; rewrite -(big_filter _ _ _ (mem r)); apply: eq_big_perm. by rewrite filter_index_enum uniq_perm_eq ?enum_uniq // => i; rewrite mem_enum. Qed. Lemma big_rem (I : eqType) r x (P : pred I) F : x \in r -> \big[*%M/1]_(y <- r | P y) F y = (if P x then F x else 1) * \big[*%M/1]_(y <- rem x r | P y) F y. Proof. by move/perm_to_rem/(eq_big_perm _)->; rewrite !(big_mkcond _ _ P) big_cons. Qed. Lemma big_undup (I : eqType) (r : seq I) (P : pred I) F : idempotent *%M -> \big[*%M/1]_(i <- undup r | P i) F i = \big[*%M/1]_(i <- r | P i) F i. Proof. move=> idM; rewrite -!(big_filter _ _ _ P) filter_undup. elim: {P r}(filter P r) => //= i r IHr. case: ifP => [r_i | _]; rewrite !big_cons {}IHr //. by rewrite (big_rem _ _ r_i) mulmA idM. Qed. Lemma eq_big_idem (I : eqType) (r1 r2 : seq I) (P : pred I) F : idempotent *%M -> r1 =i r2 -> \big[*%M/1]_(i <- r1 | P i) F i = \big[*%M/1]_(i <- r2 | P i) F i. Proof. move=> idM eq_r; rewrite -big_undup // -(big_undup r2) //; apply/eq_big_perm. by rewrite uniq_perm_eq ?undup_uniq // => i; rewrite !mem_undup eq_r. Qed. Lemma big_undup_iterop_count (I : eqType) (r : seq I) (P : pred I) F : \big[*%M/1]_(i <- undup r | P i) iterop (count_mem i r) *%M (F i) 1 = \big[*%M/1]_(i <- r | P i) F i. Proof. rewrite -[RHS](eq_big_perm _ F (perm_undup_count _)) big_flatten big_map. by rewrite big_mkcond; apply: eq_bigr => i _; rewrite big_nseq_cond iteropE. Qed. Lemma big_split I r (P : pred I) F1 F2 : \big[*%M/1]_(i <- r | P i) (F1 i * F2 i) = \big[*%M/1]_(i <- r | P i) F1 i * \big[*%M/1]_(i <- r | P i) F2 i. Proof. by elim/big_rec3: _ => [|i x y _ _ ->]; rewrite ?mulm1 // mulmCA -!mulmA mulmCA. Qed. Lemma bigID I r (a P : pred I) F : \big[*%M/1]_(i <- r | P i) F i = \big[*%M/1]_(i <- r | P i && a i) F i * \big[*%M/1]_(i <- r | P i && ~~ a i) F i. Proof. rewrite !(big_mkcond _ _ _ F) -big_split. by apply: eq_bigr => i; case: (a i); rewrite !simpm. Qed. Implicit Arguments bigID [I r]. Lemma bigU (I : finType) (A B : pred I) F : [disjoint A & B] -> \big[*%M/1]_(i in [predU A & B]) F i = (\big[*%M/1]_(i in A) F i) * (\big[*%M/1]_(i in B) F i). Proof. move=> dAB; rewrite (bigID (mem A)). congr (_ * _); apply: eq_bigl => i; first by rewrite orbK. by have:= pred0P dAB i; rewrite andbC /= !inE; case: (i \in A). Qed. Lemma bigD1 (I : finType) j (P : pred I) F : P j -> \big[*%M/1]_(i | P i) F i = F j * \big[*%M/1]_(i | P i && (i != j)) F i. Proof. move=> Pj; rewrite (bigID (pred1 j)); congr (_ * _). by apply: big_pred1 => i; rewrite /= andbC; case: eqP => // ->. Qed. Implicit Arguments bigD1 [I P F]. Lemma bigD1_seq (I : eqType) (r : seq I) j F : j \in r -> uniq r -> \big[*%M/1]_(i <- r) F i = F j * \big[*%M/1]_(i <- r | i != j) F i. Proof. by move=> /big_rem-> /rem_filter->; rewrite big_filter. Qed. Lemma cardD1x (I : finType) (A : pred I) j : A j -> #|SimplPred A| = 1 + #|[pred i | A i & i != j]|. Proof. move=> Aj; rewrite (cardD1 j) [j \in A]Aj; congr (_ + _). by apply: eq_card => i; rewrite inE /= andbC. Qed. Implicit Arguments cardD1x [I A]. Lemma partition_big (I J : finType) (P : pred I) p (Q : pred J) F : (forall i, P i -> Q (p i)) -> \big[*%M/1]_(i | P i) F i = \big[*%M/1]_(j | Q j) \big[*%M/1]_(i | P i && (p i == j)) F i. Proof. move=> Qp; transitivity (\big[*%M/1]_(i | P i && Q (p i)) F i). by apply: eq_bigl => i; case Pi: (P i); rewrite // Qp. elim: {Q Qp}_.+1 {-2}Q (ltnSn #|Q|) => // n IHn Q. case: (pickP Q) => [j Qj | Q0 _]; last first. by rewrite !big_pred0 // => i; rewrite Q0 andbF. rewrite ltnS (cardD1x j Qj) (bigD1 j) //; move/IHn=> {n IHn} <-. rewrite (bigID (fun i => p i == j)); congr (_ * _); apply: eq_bigl => i. by case: eqP => [-> | _]; rewrite !(Qj, simpm). by rewrite andbA. Qed. Implicit Arguments partition_big [I J P F]. Lemma reindex_onto (I J : finType) (h : J -> I) h' (P : pred I) F : (forall i, P i -> h (h' i) = i) -> \big[*%M/1]_(i | P i) F i = \big[*%M/1]_(j | P (h j) && (h' (h j) == j)) F (h j). Proof. move=> h'K; elim: {P}_.+1 {-3}P h'K (ltnSn #|P|) => //= n IHn P h'K. case: (pickP P) => [i Pi | P0 _]; last first. by rewrite !big_pred0 // => j; rewrite P0. rewrite ltnS (cardD1x i Pi); move/IHn {n IHn} => IH. rewrite (bigD1 i Pi) (bigD1 (h' i)) h'K ?Pi ?eq_refl //=; congr (_ * _). rewrite {}IH => [|j]; [apply: eq_bigl => j | by case/andP; auto]. rewrite andbC -andbA (andbCA (P _)); case: eqP => //= hK; congr (_ && ~~ _). by apply/eqP/eqP=> [<-|->] //; rewrite h'K. Qed. Implicit Arguments reindex_onto [I J P F]. Lemma reindex (I J : finType) (h : J -> I) (P : pred I) F : {on [pred i | P i], bijective h} -> \big[*%M/1]_(i | P i) F i = \big[*%M/1]_(j | P (h j)) F (h j). Proof. case=> h' hK h'K; rewrite (reindex_onto h h' h'K). by apply: eq_bigl => j; rewrite !inE; case Pi: (P _); rewrite //= hK ?eqxx. Qed. Implicit Arguments reindex [I J P F]. Lemma reindex_inj (I : finType) (h : I -> I) (P : pred I) F : injective h -> \big[*%M/1]_(i | P i) F i = \big[*%M/1]_(j | P (h j)) F (h j). Proof. move=> injh; exact: reindex (onW_bij _ (injF_bij injh)). Qed. Implicit Arguments reindex_inj [I h P F]. Lemma big_nat_rev m n P F : \big[*%M/1]_(m <= i < n | P i) F i = \big[*%M/1]_(m <= i < n | P (m + n - i.+1)) F (m + n - i.+1). Proof. case: (ltnP m n) => ltmn; last by rewrite !big_geq. rewrite -{3 4}(subnK (ltnW ltmn)) addnA. do 2!rewrite (big_addn _ _ 0) big_mkord; rewrite (reindex_inj rev_ord_inj) /=. by apply: eq_big => [i | i _]; rewrite /= -addSn subnDr addnC addnBA. Qed. Lemma pair_big_dep (I J : finType) (P : pred I) (Q : I -> pred J) F : \big[*%M/1]_(i | P i) \big[*%M/1]_(j | Q i j) F i j = \big[*%M/1]_(p | P p.1 && Q p.1 p.2) F p.1 p.2. Proof. rewrite (partition_big (fun p => p.1) P) => [|j]; last by case/andP. apply: eq_bigr => i /= Pi; rewrite (reindex_onto (pair i) (fun p => p.2)). by apply: eq_bigl => j; rewrite !eqxx [P i]Pi !andbT. by case=> i' j /=; case/andP=> _ /=; move/eqP->. Qed. Lemma pair_big (I J : finType) (P : pred I) (Q : pred J) F : \big[*%M/1]_(i | P i) \big[*%M/1]_(j | Q j) F i j = \big[*%M/1]_(p | P p.1 && Q p.2) F p.1 p.2. Proof. exact: pair_big_dep. Qed. Lemma pair_bigA (I J : finType) (F : I -> J -> R) : \big[*%M/1]_i \big[*%M/1]_j F i j = \big[*%M/1]_p F p.1 p.2. Proof. exact: pair_big_dep. Qed. Lemma exchange_big_dep I J rI rJ (P : pred I) (Q : I -> pred J) (xQ : pred J) F : (forall i j, P i -> Q i j -> xQ j) -> \big[*%M/1]_(i <- rI | P i) \big[*%M/1]_(j <- rJ | Q i j) F i j = \big[*%M/1]_(j <- rJ | xQ j) \big[*%M/1]_(i <- rI | P i && Q i j) F i j. Proof. move=> PQxQ; pose p u := (u.2, u.1). rewrite (eq_bigr _ _ _ (fun _ _ => big_tnth _ _ rI _ _)) (big_tnth _ _ rJ). rewrite (eq_bigr _ _ _ (fun _ _ => (big_tnth _ _ rJ _ _))) big_tnth. rewrite !pair_big_dep (reindex_onto (p _ _) (p _ _)) => [|[]] //=. apply: eq_big => [] [j i] //=; symmetry; rewrite eqxx andbT andb_idl //. by case/andP; exact: PQxQ. Qed. Implicit Arguments exchange_big_dep [I J rI rJ P Q F]. Lemma exchange_big I J rI rJ (P : pred I) (Q : pred J) F : \big[*%M/1]_(i <- rI | P i) \big[*%M/1]_(j <- rJ | Q j) F i j = \big[*%M/1]_(j <- rJ | Q j) \big[*%M/1]_(i <- rI | P i) F i j. Proof. rewrite (exchange_big_dep Q) //; apply: eq_bigr => i /= Qi. by apply: eq_bigl => j; rewrite Qi andbT. Qed. Lemma exchange_big_dep_nat m1 n1 m2 n2 (P : pred nat) (Q : rel nat) (xQ : pred nat) F : (forall i j, m1 <= i < n1 -> m2 <= j < n2 -> P i -> Q i j -> xQ j) -> \big[*%M/1]_(m1 <= i < n1 | P i) \big[*%M/1]_(m2 <= j < n2 | Q i j) F i j = \big[*%M/1]_(m2 <= j < n2 | xQ j) \big[*%M/1]_(m1 <= i < n1 | P i && Q i j) F i j. Proof. move=> PQxQ; rewrite (eq_bigr _ _ _ (fun _ _ => big_seq_cond _ _ _ _ _)). rewrite big_seq_cond /= (exchange_big_dep xQ) => [|i j]; last first. by rewrite !mem_index_iota => /andP[mn_i Pi] /andP[mn_j /PQxQ->]. rewrite 2!(big_seq_cond _ _ _ xQ); apply: eq_bigr => j /andP[-> _] /=. by rewrite [rhs in _ = rhs]big_seq_cond; apply: eq_bigl => i; rewrite -andbA. Qed. Implicit Arguments exchange_big_dep_nat [m1 n1 m2 n2 P Q F]. Lemma exchange_big_nat m1 n1 m2 n2 (P Q : pred nat) F : \big[*%M/1]_(m1 <= i < n1 | P i) \big[*%M/1]_(m2 <= j < n2 | Q j) F i j = \big[*%M/1]_(m2 <= j < n2 | Q j) \big[*%M/1]_(m1 <= i < n1 | P i) F i j. Proof. rewrite (exchange_big_dep_nat Q) //. by apply: eq_bigr => i /= Qi; apply: eq_bigl => j; rewrite Qi andbT. Qed. End Abelian. End MonoidProperties. Implicit Arguments big_filter [R op idx I]. Implicit Arguments big_filter_cond [R op idx I]. Implicit Arguments congr_big [R op idx I r1 P1 F1]. Implicit Arguments eq_big [R op idx I r P1 F1]. Implicit Arguments eq_bigl [R op idx I r P1]. Implicit Arguments eq_bigr [R op idx I r P F1]. Implicit Arguments eq_big_idx [R op idx idx' I P F]. Implicit Arguments big_seq_cond [R op idx I r]. Implicit Arguments eq_big_seq [R op idx I r F1]. Implicit Arguments congr_big_nat [R op idx m1 n1 P1 F1]. Implicit Arguments big_map [R op idx I J r]. Implicit Arguments big_nth [R op idx I r]. Implicit Arguments big_catl [R op idx I r1 r2 P F]. Implicit Arguments big_catr [R op idx I r1 r2 P F]. Implicit Arguments big_geq [R op idx m n P F]. Implicit Arguments big_ltn_cond [R op idx m n P F]. Implicit Arguments big_ltn [R op idx m n F]. Implicit Arguments big_addn [R op idx]. Implicit Arguments big_mkord [R op idx n]. Implicit Arguments big_nat_widen [R op idx] . Implicit Arguments big_ord_widen_cond [R op idx n1]. Implicit Arguments big_ord_widen [R op idx n1]. Implicit Arguments big_ord_widen_leq [R op idx n1]. Implicit Arguments big_ord_narrow_cond [R op idx n1 n2 P F]. Implicit Arguments big_ord_narrow_cond_leq [R op idx n1 n2 P F]. Implicit Arguments big_ord_narrow [R op idx n1 n2 F]. Implicit Arguments big_ord_narrow_leq [R op idx n1 n2 F]. Implicit Arguments big_mkcond [R op idx I r]. Implicit Arguments big1_eq [R op idx I]. Implicit Arguments big1_seq [R op idx I]. Implicit Arguments big1 [R op idx I]. Implicit Arguments big_pred1 [R op idx I P F]. Implicit Arguments eq_big_perm [R op idx I r1 P F]. Implicit Arguments big_uniq [R op idx I F]. Implicit Arguments big_rem [R op idx I r P F]. Implicit Arguments bigID [R op idx I r]. Implicit Arguments bigU [R op idx I]. Implicit Arguments bigD1 [R op idx I P F]. Implicit Arguments bigD1_seq [R op idx I r F]. Implicit Arguments partition_big [R op idx I J P F]. Implicit Arguments reindex_onto [R op idx I J P F]. Implicit Arguments reindex [R op idx I J P F]. Implicit Arguments reindex_inj [R op idx I h P F]. Implicit Arguments pair_big_dep [R op idx I J]. Implicit Arguments pair_big [R op idx I J]. Implicit Arguments exchange_big_dep [R op idx I J rI rJ P Q F]. Implicit Arguments exchange_big_dep_nat [R op idx m1 n1 m2 n2 P Q F]. Implicit Arguments big_ord_recl [R op idx]. Implicit Arguments big_ord_recr [R op idx]. Implicit Arguments big_nat_recl [R op idx]. Implicit Arguments big_nat_recr [R op idx]. Section Distributivity. Import Monoid.Theory. Variable R : Type. Variables zero one : R. Notation Local "0" := zero. Notation Local "1" := one. Variable times : Monoid.mul_law 0. Notation Local "*%M" := times (at level 0). Notation Local "x * y" := (times x y). Variable plus : Monoid.add_law 0 *%M. Notation Local "+%M" := plus (at level 0). Notation Local "x + y" := (plus x y). Lemma big_distrl I r a (P : pred I) F : \big[+%M/0]_(i <- r | P i) F i * a = \big[+%M/0]_(i <- r | P i) (F i * a). Proof. by rewrite (big_endo ( *%M^~ a)) ?mul0m // => x y; exact: mulm_addl. Qed. Lemma big_distrr I r a (P : pred I) F : a * \big[+%M/0]_(i <- r | P i) F i = \big[+%M/0]_(i <- r | P i) (a * F i). Proof. by rewrite big_endo ?mulm0 // => x y; exact: mulm_addr. Qed. Lemma big_distrlr I J rI rJ (pI : pred I) (pJ : pred J) F G : (\big[+%M/0]_(i <- rI | pI i) F i) * (\big[+%M/0]_(j <- rJ | pJ j) G j) = \big[+%M/0]_(i <- rI | pI i) \big[+%M/0]_(j <- rJ | pJ j) (F i * G j). Proof. by rewrite big_distrl; apply: eq_bigr => i _; rewrite big_distrr. Qed. Lemma big_distr_big_dep (I J : finType) j0 (P : pred I) (Q : I -> pred J) F : \big[*%M/1]_(i | P i) \big[+%M/0]_(j | Q i j) F i j = \big[+%M/0]_(f in pfamily j0 P Q) \big[*%M/1]_(i | P i) F i (f i). Proof. pose fIJ := {ffun I -> J}; pose Pf := pfamily j0 (_ : seq I) Q. rewrite -big_filter filter_index_enum; set r := enum P; symmetry. transitivity (\big[+%M/0]_(f in Pf r) \big[*%M/1]_(i <- r) F i (f i)). apply: eq_big => f; last by rewrite -big_filter filter_index_enum. by apply: eq_forallb => i; rewrite /= mem_enum. have: uniq r by exact: enum_uniq. elim: {P}r => /= [_ | i r IHr]. rewrite (big_pred1 [ffun => j0]) ?big_nil //= => f. apply/familyP/eqP=> /= [Df |->{f} i]; last by rewrite ffunE !inE. by apply/ffunP=> i; rewrite ffunE; exact/eqP/Df. case/andP=> /negbTE nri; rewrite big_cons big_distrl => {IHr}/IHr <-. rewrite (partition_big (fun f : fIJ => f i) (Q i)) => [|f]; last first. by move/familyP/(_ i); rewrite /= inE /= eqxx. pose seti j (f : fIJ) := [ffun k => if k == i then j else f k]. apply: eq_bigr => j Qij. rewrite (reindex_onto (seti j) (seti j0)) => [|f /andP[_ /eqP fi]]; last first. by apply/ffunP=> k; rewrite !ffunE; case: eqP => // ->. rewrite big_distrr; apply: eq_big => [f | f eq_f]; last first. rewrite big_cons ffunE eqxx !big_seq; congr (_ * _). by apply: eq_bigr => k; rewrite ffunE; case: eqP nri => // -> ->. rewrite !ffunE !eqxx andbT; apply/andP/familyP=> /= [[Pjf fij0] k | Pff]. have:= familyP Pjf k; rewrite /= ffunE inE; case: eqP => // -> _. by rewrite nri -(eqP fij0) !ffunE !inE !eqxx. split; [apply/familyP | apply/eqP/ffunP] => k; have:= Pff k; rewrite !ffunE. by rewrite inE; case: eqP => // ->. by case: eqP => // ->; rewrite nri /= => /eqP. Qed. Lemma big_distr_big (I J : finType) j0 (P : pred I) (Q : pred J) F : \big[*%M/1]_(i | P i) \big[+%M/0]_(j | Q j) F i j = \big[+%M/0]_(f in pffun_on j0 P Q) \big[*%M/1]_(i | P i) F i (f i). Proof. rewrite (big_distr_big_dep j0); apply: eq_bigl => f. by apply/familyP/familyP=> Pf i; case: ifP (Pf i). Qed. Lemma bigA_distr_big_dep (I J : finType) (Q : I -> pred J) F : \big[*%M/1]_i \big[+%M/0]_(j | Q i j) F i j = \big[+%M/0]_(f in family Q) \big[*%M/1]_i F i (f i). Proof. case: (pickP J) => [j0 _ | J0]; first exact: (big_distr_big_dep j0). rewrite {1 4}/index_enum -enumT; case: (enum I) (mem_enum I) => [I0 | i r _]. have f0: I -> J by move=> i; have:= I0 i. rewrite (big_pred1 (finfun f0)) ?big_nil // => g. by apply/familyP/eqP=> _; first apply/ffunP; move=> i; have:= I0 i. have Q0 i': Q i' =1 pred0 by move=> j; have:= J0 j. rewrite big_cons /= big_pred0 // mul0m big_pred0 // => f. by apply/familyP=> /(_ i); rewrite [_ \in _]Q0. Qed. Lemma bigA_distr_big (I J : finType) (Q : pred J) (F : I -> J -> R) : \big[*%M/1]_i \big[+%M/0]_(j | Q j) F i j = \big[+%M/0]_(f in ffun_on Q) \big[*%M/1]_i F i (f i). Proof. exact: bigA_distr_big_dep. Qed. Lemma bigA_distr_bigA (I J : finType) F : \big[*%M/1]_(i : I) \big[+%M/0]_(j : J) F i j = \big[+%M/0]_(f : {ffun I -> J}) \big[*%M/1]_i F i (f i). Proof. by rewrite bigA_distr_big; apply: eq_bigl => ?; exact/familyP. Qed. End Distributivity. Implicit Arguments big_distrl [R zero times plus I r]. Implicit Arguments big_distrr [R zero times plus I r]. Implicit Arguments big_distr_big_dep [R zero one times plus I J]. Implicit Arguments big_distr_big [R zero one times plus I J]. Implicit Arguments bigA_distr_big_dep [R zero one times plus I J]. Implicit Arguments bigA_distr_big [R zero one times plus I J]. Implicit Arguments bigA_distr_bigA [R zero one times plus I J]. Section BigBool. Section Seq. Variables (I : Type) (r : seq I) (P B : pred I). Lemma big_has : \big[orb/false]_(i <- r) B i = has B r. Proof. by rewrite unlock. Qed. Lemma big_all : \big[andb/true]_(i <- r) B i = all B r. Proof. by rewrite unlock. Qed. Lemma big_has_cond : \big[orb/false]_(i <- r | P i) B i = has (predI P B) r. Proof. by rewrite big_mkcond unlock. Qed. Lemma big_all_cond : \big[andb/true]_(i <- r | P i) B i = all [pred i | P i ==> B i] r. Proof. by rewrite big_mkcond unlock. Qed. End Seq. Section FinType. Variables (I : finType) (P B : pred I). Lemma big_orE : \big[orb/false]_(i | P i) B i = [exists (i | P i), B i]. Proof. by rewrite big_has_cond; apply/hasP/existsP=> [] [i]; exists i. Qed. Lemma big_andE : \big[andb/true]_(i | P i) B i = [forall (i | P i), B i]. Proof. rewrite big_all_cond; apply/allP/forallP=> /= allB i; rewrite allB //. exact: mem_index_enum. Qed. End FinType. End BigBool. Section NatConst. Variables (I : finType) (A : pred I). Lemma sum_nat_const n : \sum_(i in A) n = #|A| * n. Proof. by rewrite big_const iter_addn_0 mulnC. Qed. Lemma sum1_card : \sum_(i in A) 1 = #|A|. Proof. by rewrite sum_nat_const muln1. Qed. Lemma sum1_count J (r : seq J) (a : pred J) : \sum_(j <- r | a j) 1 = count a r. Proof. by rewrite big_const_seq iter_addn_0 mul1n. Qed. Lemma sum1_size J (r : seq J) : \sum_(j <- r) 1 = size r. Proof. by rewrite sum1_count count_predT. Qed. Lemma prod_nat_const n : \prod_(i in A) n = n ^ #|A|. Proof. by rewrite big_const -Monoid.iteropE. Qed. Lemma sum_nat_const_nat n1 n2 n : \sum_(n1 <= i < n2) n = (n2 - n1) * n. Proof. by rewrite big_const_nat; elim: (_ - _) => //= ? ->. Qed. Lemma prod_nat_const_nat n1 n2 n : \prod_(n1 <= i < n2) n = n ^ (n2 - n1). Proof. by rewrite big_const_nat -Monoid.iteropE. Qed. End NatConst. Lemma leqif_sum (I : finType) (P C : pred I) (E1 E2 : I -> nat) : (forall i, P i -> E1 i <= E2 i ?= iff C i) -> \sum_(i | P i) E1 i <= \sum_(i | P i) E2 i ?= iff [forall (i | P i), C i]. Proof. move=> leE12; rewrite -big_andE. by elim/big_rec3: _ => // i Ci m1 m2 /leE12; exact: leqif_add. Qed. Lemma leq_sum I r (P : pred I) (E1 E2 : I -> nat) : (forall i, P i -> E1 i <= E2 i) -> \sum_(i <- r | P i) E1 i <= \sum_(i <- r | P i) E2 i. Proof. by move=> leE12; elim/big_ind2: _ => // m1 m2 n1 n2; exact: leq_add. Qed. Lemma sum_nat_eq0 (I : finType) (P : pred I) (E : I -> nat) : (\sum_(i | P i) E i == 0)%N = [forall (i | P i), E i == 0%N]. Proof. by rewrite eq_sym -(@leqif_sum I P _ (fun _ => 0%N) E) ?big1_eq. Qed. Lemma prodn_cond_gt0 I r (P : pred I) F : (forall i, P i -> 0 < F i) -> 0 < \prod_(i <- r | P i) F i. Proof. by move=> Fpos; elim/big_ind: _ => // n1 n2; rewrite muln_gt0 => ->. Qed. Lemma prodn_gt0 I r (P : pred I) F : (forall i, 0 < F i) -> 0 < \prod_(i <- r | P i) F i. Proof. move=> Fpos; exact: prodn_cond_gt0. Qed. Lemma leq_bigmax_cond (I : finType) (P : pred I) F i0 : P i0 -> F i0 <= \max_(i | P i) F i. Proof. by move=> Pi0; rewrite (bigD1 i0) ?leq_maxl. Qed. Implicit Arguments leq_bigmax_cond [I P F]. Lemma leq_bigmax (I : finType) F (i0 : I) : F i0 <= \max_i F i. Proof. exact: leq_bigmax_cond. Qed. Implicit Arguments leq_bigmax [I F]. Lemma bigmax_leqP (I : finType) (P : pred I) m F : reflect (forall i, P i -> F i <= m) (\max_(i | P i) F i <= m). Proof. apply: (iffP idP) => leFm => [i Pi|]. by apply: leq_trans leFm; exact: leq_bigmax_cond. by elim/big_ind: _ => // m1 m2; rewrite geq_max => ->. Qed. Lemma bigmax_sup (I : finType) i0 (P : pred I) m F : P i0 -> m <= F i0 -> m <= \max_(i | P i) F i. Proof. by move=> Pi0 le_m_Fi0; exact: leq_trans (leq_bigmax_cond i0 Pi0). Qed. Implicit Arguments bigmax_sup [I P m F]. Lemma bigmax_eq_arg (I : finType) i0 (P : pred I) F : P i0 -> \max_(i | P i) F i = F [arg max_(i > i0 | P i) F i]. Proof. move=> Pi0; case: arg_maxP => //= i Pi maxFi. by apply/eqP; rewrite eqn_leq leq_bigmax_cond // andbT; exact/bigmax_leqP. Qed. Implicit Arguments bigmax_eq_arg [I P F]. Lemma eq_bigmax_cond (I : finType) (A : pred I) F : #|A| > 0 -> {i0 | i0 \in A & \max_(i in A) F i = F i0}. Proof. case: (pickP A) => [i0 Ai0 _ | ]; last by move/eq_card0->. by exists [arg max_(i > i0 in A) F i]; [case: arg_maxP | exact: bigmax_eq_arg]. Qed. Lemma eq_bigmax (I : finType) F : #|I| > 0 -> {i0 : I | \max_i F i = F i0}. Proof. by case/(eq_bigmax_cond F) => x _ ->; exists x. Qed. Lemma expn_sum m I r (P : pred I) F : (m ^ (\sum_(i <- r | P i) F i) = \prod_(i <- r | P i) m ^ F i)%N. Proof. exact: (big_morph _ (expnD m)). Qed. Lemma dvdn_biglcmP (I : finType) (P : pred I) F m : reflect (forall i, P i -> F i %| m) (\big[lcmn/1%N]_(i | P i) F i %| m). Proof. apply: (iffP idP) => [dvFm i Pi | dvFm]. by rewrite (bigD1 i) // dvdn_lcm in dvFm; case/andP: dvFm. by elim/big_ind: _ => // p q p_m; rewrite dvdn_lcm p_m. Qed. Lemma biglcmn_sup (I : finType) i0 (P : pred I) F m : P i0 -> m %| F i0 -> m %| \big[lcmn/1%N]_(i | P i) F i. Proof. by move=> Pi0 m_Fi0; rewrite (dvdn_trans m_Fi0) // (bigD1 i0) ?dvdn_lcml. Qed. Implicit Arguments biglcmn_sup [I P F m]. Lemma dvdn_biggcdP (I : finType) (P : pred I) F m : reflect (forall i, P i -> m %| F i) (m %| \big[gcdn/0]_(i | P i) F i). Proof. apply: (iffP idP) => [dvmF i Pi | dvmF]. by rewrite (bigD1 i) // dvdn_gcd in dvmF; case/andP: dvmF. by elim/big_ind: _ => // p q m_p; rewrite dvdn_gcd m_p. Qed. Lemma biggcdn_inf (I : finType) i0 (P : pred I) F m : P i0 -> F i0 %| m -> \big[gcdn/0]_(i | P i) F i %| m. Proof. by move=> Pi0; apply: dvdn_trans; rewrite (bigD1 i0) ?dvdn_gcdl. Qed. Implicit Arguments biggcdn_inf [I P F m]. Unset Implicit Arguments. mathcomp-1.5/theories/nilpotent.v0000644000175000017500000006764512307636117016230 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path fintype div. Require Import bigop prime finset fingroup morphism automorphism quotient. Require Import commutator gproduct gfunctor center gseries cyclic. (******************************************************************************) (* This file defines nilpotent and solvable groups, and give some of their *) (* elementary properties; more will be added later (e.g., the nilpotence of *) (* p-groups in sylow.v, or the fact that minimal normal subgroups of solvable *) (* groups are elementary abelian in maximal.v). This file defines: *) (* nilpotent G == G is nilpotent, i.e., [~: H, G] is a proper subgroup of H *) (* for all nontrivial H <| G. *) (* solvable G == G is solvable, i.e., H^`(1) is a proper subgroup of H for *) (* all nontrivial subgroups H of G. *) (* 'L_n(G) == the nth term of the lower central series, namely *) (* [~: G, ..., G] (n Gs) if n > 0, with 'L_0(G) = G. *) (* G is nilpotent iff 'L_n(G) = 1 for some n. *) (* 'Z_n(G) == the nth term of the upper central series, i.e., *) (* with 'Z_0(G) = 1, 'Z_n.+1(G) / 'Z_n(G) = 'Z(G / 'Z_n(G)). *) (* nil_class G == the nilpotence class of G, i.e., the least n such that *) (* 'L_n.+1(G) = 1 (or, equivalently, 'Z_n(G) = G), if G is *) (* nilpotent; we take nil_class G = #|G| when G is not *) (* nilpotent, so nil_class G < #|G| iff G is nilpotent. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section SeriesDefs. Variables (n : nat) (gT : finGroupType) (A : {set gT}). Definition lower_central_at_rec := iter n (fun B => [~: B, A]) A. Definition upper_central_at_rec := iter n (fun B => coset B @*^-1 'Z(A / B)) 1. End SeriesDefs. (* By convention, the lower central series starts at 1 while the upper series *) (* starts at 0 (sic). *) Definition lower_central_at n := lower_central_at_rec n.-1. (* Note: 'nosimpl' MUST be used outside of a section -- the end of section *) (* "cooking" destroys it. *) Definition upper_central_at := nosimpl upper_central_at_rec. Arguments Scope lower_central_at [nat_scope _ group_scope]. Arguments Scope upper_central_at [nat_scope _ group_scope]. Notation "''L_' n ( G )" := (lower_central_at n G) (at level 8, n at level 2, format "''L_' n ( G )") : group_scope. Notation "''Z_' n ( G )" := (upper_central_at n G) (at level 8, n at level 2, format "''Z_' n ( G )") : group_scope. Section PropertiesDefs. Variables (gT : finGroupType) (A : {set gT}). Definition nilpotent := [forall (G : {group gT} | G \subset A :&: [~: G, A]), G :==: 1]. Definition nil_class := index 1 (mkseq (fun n => 'L_n.+1(A)) #|A|). Definition solvable := [forall (G : {group gT} | G \subset A :&: [~: G, G]), G :==: 1]. End PropertiesDefs. Arguments Scope nilpotent [_ group_scope]. Arguments Scope nil_class [_ group_scope]. Arguments Scope solvable [_ group_scope]. Prenex Implicits nil_class nilpotent solvable. Section NilpotentProps. Variable gT: finGroupType. Implicit Types (A B : {set gT}) (G H : {group gT}). Lemma nilpotent1 : nilpotent [1 gT]. Proof. by apply/forall_inP=> H; rewrite commG1 setIid -subG1. Qed. Lemma nilpotentS A B : B \subset A -> nilpotent A -> nilpotent B. Proof. move=> sBA nilA; apply/forall_inP=> H sHR. have:= forallP nilA H; rewrite (subset_trans sHR) //. by apply: subset_trans (setIS _ _) (setSI _ _); rewrite ?commgS. Qed. Lemma nil_comm_properl G H A : nilpotent G -> H \subset G -> H :!=: 1 -> A \subset 'N_G(H) -> [~: H, A] \proper H. Proof. move=> nilG sHG ntH; rewrite subsetI properE; case/andP=> sAG nHA. rewrite (subset_trans (commgS H (subset_gen A))) ?commg_subl ?gen_subG //. apply: contra ntH => sHR; have:= forallP nilG H; rewrite subsetI sHG. by rewrite (subset_trans sHR) ?commgS. Qed. Lemma nil_comm_properr G A H : nilpotent G -> H \subset G -> H :!=: 1 -> A \subset 'N_G(H) -> [~: A, H] \proper H. Proof. by rewrite commGC; apply: nil_comm_properl. Qed. Lemma centrals_nil (s : seq {group gT}) G : G.-central.-series 1%G s -> last 1%G s = G -> nilpotent G. Proof. move=> cGs defG; apply/forall_inP=> H /subsetIP[sHG sHR]. move: sHG; rewrite -{}defG -subG1 -[1]/(gval 1%G). elim: s 1%G cGs => //= L s IHs K /andP[/and3P[sRK sKL sLG] /IHs sHL] sHs. exact: subset_trans sHR (subset_trans (commSg _ (sHL sHs)) sRK). Qed. End NilpotentProps. Section LowerCentral. Variable gT : finGroupType. Implicit Types (A B : {set gT}) (G H : {group gT}). Lemma lcn0 A : 'L_0(A) = A. Proof. by []. Qed. Lemma lcn1 A : 'L_1(A) = A. Proof. by []. Qed. Lemma lcnSn n A : 'L_n.+2(A) = [~: 'L_n.+1(A), A]. Proof. by []. Qed. Lemma lcnSnS n G : [~: 'L_n(G), G] \subset 'L_n.+1(G). Proof. by case: n => //; exact: der1_subG. Qed. Lemma lcnE n A : 'L_n.+1(A) = lower_central_at_rec n A. Proof. by []. Qed. Lemma lcn2 A : 'L_2(A) = A^`(1). Proof. by []. Qed. Lemma lcn_group_set n G : group_set 'L_n(G). Proof. by case: n => [|[|n]]; exact: groupP. Qed. Canonical lower_central_at_group n G := Group (lcn_group_set n G). Lemma lcn_char n G : 'L_n(G) \char G. Proof. by case: n => [|n]; last elim: n => [|n IHn]; rewrite ?lcnSn ?charR ?char_refl. Qed. Lemma lcn_normal n G : 'L_n(G) <| G. Proof. by apply: char_normal; exact: lcn_char. Qed. Lemma lcn_sub n G : 'L_n(G) \subset G. Proof. by case/andP: (lcn_normal n G). Qed. Lemma lcn_norm n G : G \subset 'N('L_n(G)). Proof. by case/andP: (lcn_normal n G). Qed. Lemma lcn_subS n G : 'L_n.+1(G) \subset 'L_n(G). Proof. case: n => // n; rewrite lcnSn commGC commg_subr. by case/andP: (lcn_normal n.+1 G). Qed. Lemma lcn_normalS n G : 'L_n.+1(G) <| 'L_n(G). Proof. by apply: normalS (lcn_normal _ _); rewrite (lcn_subS, lcn_sub). Qed. Lemma lcn_central n G : 'L_n(G) / 'L_n.+1(G) \subset 'Z(G / 'L_n.+1(G)). Proof. case: n => [|n]; first by rewrite trivg_quotient sub1G. by rewrite subsetI quotientS ?lcn_sub ?quotient_cents2r. Qed. Lemma lcn_sub_leq m n G : n <= m -> 'L_m(G) \subset 'L_n(G). Proof. by move/subnK <-; elim: {m}(m - n) => // m; exact: subset_trans (lcn_subS _ _). Qed. Lemma lcnS n A B : A \subset B -> 'L_n(A) \subset 'L_n(B). Proof. by case: n => // n sAB; elim: n => // n IHn; rewrite !lcnSn genS ?imset2S. Qed. Lemma lcn_cprod n A B G : A \* B = G -> 'L_n(A) \* 'L_n(B) = 'L_n(G). Proof. case: n => // n /cprodP[[H K -> ->{A B}] defG cHK]. have sL := subset_trans (lcn_sub _ _); rewrite cprodE ?(centSS _ _ cHK) ?sL //. symmetry; elim: n => // n; rewrite lcnSn => ->; rewrite commMG /=; last first. by apply: subset_trans (commg_normr _ _); rewrite sL // -defG mulG_subr. rewrite -!(commGC G) -defG -{1}(centC cHK). rewrite !commMG ?normsR ?lcn_norm ?cents_norm // 1?centsC //. by rewrite -!(commGC 'L__(_)) -!lcnSn !(commG1P _) ?mul1g ?sL // centsC. Qed. Lemma lcn_dprod n A B G : A \x B = G -> 'L_n(A) \x 'L_n(B) = 'L_n(G). Proof. move=> defG; have [[K H defA defB] _ _ tiAB] := dprodP defG. rewrite !dprodEcp // in defG *; first exact: lcn_cprod. by rewrite defA defB; apply/trivgP; rewrite -tiAB defA defB setISS ?lcn_sub. Qed. Lemma der_cprod n A B G : A \* B = G -> A^`(n) \* B^`(n) = G^`(n). Proof. by move=> defG; elim: n => {defG}// n; apply: (lcn_cprod 2). Qed. Lemma der_dprod n A B G : A \x B = G -> A^`(n) \x B^`(n) = G^`(n). Proof. by move=> defG; elim: n => {defG}// n; apply: (lcn_dprod 2). Qed. Lemma lcn_bigcprod n I r P (F : I -> {set gT}) G : \big[cprod/1]_(i <- r | P i) F i = G -> \big[cprod/1]_(i <- r | P i) 'L_n(F i) = 'L_n(G). Proof. elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first exact/esym/trivgP/lcn_sub. by rewrite -(lcn_cprod n dG); have [[_ H _ dH]] := cprodP dG; rewrite dH (IH H). Qed. Lemma lcn_bigdprod n I r P (F : I -> {set gT}) G : \big[dprod/1]_(i <- r | P i) F i = G -> \big[dprod/1]_(i <- r | P i) 'L_n(F i) = 'L_n(G). Proof. elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first exact/esym/trivgP/lcn_sub. by rewrite -(lcn_dprod n dG); have [[_ H _ dH]] := dprodP dG; rewrite dH (IH H). Qed. Lemma der_bigcprod n I r P (F : I -> {set gT}) G : \big[cprod/1]_(i <- r | P i) F i = G -> \big[cprod/1]_(i <- r | P i) (F i)^`(n) = G^`(n). Proof. elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first by rewrite gF1. by rewrite -(der_cprod n dG); have [[_ H _ dH]] := cprodP dG; rewrite dH (IH H). Qed. Lemma der_bigdprod n I r P (F : I -> {set gT}) G : \big[dprod/1]_(i <- r | P i) F i = G -> \big[dprod/1]_(i <- r | P i) (F i)^`(n) = G^`(n). Proof. elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first by rewrite gF1. by rewrite -(der_dprod n dG); have [[_ H _ dH]] := dprodP dG; rewrite dH (IH H). Qed. Lemma nilpotent_class G : nilpotent G = (nil_class G < #|G|). Proof. rewrite /nil_class; set s := mkseq _ _. transitivity (1 \in s); last by rewrite -index_mem size_mkseq. apply/idP/mapP=> {s}/= [nilG | [n _ Ln1]]; last first. apply/forall_inP=> H /subsetIP[sHG sHR]. rewrite -subG1 {}Ln1; elim: n => // n IHn. by rewrite (subset_trans sHR) ?commSg. pose m := #|G|.-1; exists m; first by rewrite mem_iota /= prednK. rewrite ['L__(G)]card_le1_trivg //= -(subnn m). elim: {-2}m => [|n]; [by rewrite subn0 prednK | rewrite lcnSn subnS]. case: (eqsVneq 'L_n.+1(G) 1) => [-> | ntLn]; first by rewrite comm1G cards1. case: (m - n) => [|m' /= IHn]; first by rewrite leqNgt cardG_gt1 ntLn. rewrite -ltnS (leq_trans (proper_card _) IHn) //. by rewrite (nil_comm_properl nilG) ?lcn_sub // subsetI subxx lcn_norm. Qed. Lemma lcn_nil_classP n G : nilpotent G -> reflect ('L_n.+1(G) = 1) (nil_class G <= n). Proof. rewrite nilpotent_class /nil_class; set s := mkseq _ _. set c := index 1 s => lt_c_G; case: leqP => [le_c_n | lt_n_c]. have Lc1: nth 1 s c = 1 by rewrite nth_index // -index_mem size_mkseq. by left; apply/trivgP; rewrite -Lc1 nth_mkseq ?lcn_sub_leq. right; apply/eqP/negPf; rewrite -(before_find 1 lt_n_c) nth_mkseq //. exact: ltn_trans lt_n_c lt_c_G. Qed. Lemma lcnP G : reflect (exists n, 'L_n.+1(G) = 1) (nilpotent G). Proof. apply: (iffP idP) => [nilG | [n Ln1]]. by exists (nil_class G); exact/lcn_nil_classP. apply/forall_inP=> H /subsetIP[sHG sHR]; rewrite -subG1 -{}Ln1. by elim: n => // n IHn; rewrite (subset_trans sHR) ?commSg. Qed. Lemma abelian_nil G : abelian G -> nilpotent G. Proof. by move=> abG; apply/lcnP; exists 1%N; exact/commG1P. Qed. Lemma nil_class0 G : (nil_class G == 0) = (G :==: 1). Proof. apply/idP/eqP=> [nilG | ->]. by apply/(lcn_nil_classP 0); rewrite ?nilpotent_class (eqP nilG) ?cardG_gt0. by rewrite -leqn0; apply/(lcn_nil_classP 0); rewrite ?nilpotent1. Qed. Lemma nil_class1 G : (nil_class G <= 1) = abelian G. Proof. have [-> | ntG] := eqsVneq G 1. by rewrite abelian1 leq_eqVlt ltnS leqn0 nil_class0 eqxx orbT. apply/idP/idP=> cGG. apply/commG1P; apply/(lcn_nil_classP 1); rewrite // nilpotent_class. by rewrite (leq_ltn_trans cGG) // cardG_gt1. by apply/(lcn_nil_classP 1); rewrite ?abelian_nil //; apply/commG1P. Qed. Lemma cprod_nil A B G : A \* B = G -> nilpotent G = nilpotent A && nilpotent B. Proof. move=> defG; case/cprodP: defG (defG) => [[H K -> ->{A B}] defG _] defGc. apply/idP/andP=> [nilG | [/lcnP[m LmH1] /lcnP[n LnK1]]]. by rewrite !(nilpotentS _ nilG) // -defG (mulG_subr, mulG_subl). apply/lcnP; exists (m + n.+1); apply/trivgP. case/cprodP: (lcn_cprod (m.+1 + n.+1) defGc) => _ <- _. by rewrite mulG_subG /= -{1}LmH1 -LnK1 !lcn_sub_leq ?leq_addl ?leq_addr. Qed. Lemma mulg_nil G H : H \subset 'C(G) -> nilpotent (G * H) = nilpotent G && nilpotent H. Proof. by move=> cGH; rewrite -(cprod_nil (cprodEY cGH)) /= cent_joinEr. Qed. Lemma dprod_nil A B G : A \x B = G -> nilpotent G = nilpotent A && nilpotent B. Proof. by case/dprodP=> [[H K -> ->] <- cHK _]; rewrite mulg_nil. Qed. Lemma bigdprod_nil I r (P : pred I) (A_ : I -> {set gT}) G : \big[dprod/1]_(i <- r | P i) A_ i = G -> (forall i, P i -> nilpotent (A_ i)) -> nilpotent G. Proof. move=> defG nilA; elim/big_rec: _ => [|i B Pi nilB] in G defG *. by rewrite -defG nilpotent1. have [[_ H _ defB] _ _ _] := dprodP defG. by rewrite (dprod_nil defG) nilA //= defB nilB. Qed. End LowerCentral. Notation "''L_' n ( G )" := (lower_central_at_group n G) : Group_scope. Lemma lcn_cont n : GFunctor.continuous (lower_central_at n). Proof. case: n => //; elim=> // n IHn g0T h0T H phi. by rewrite !lcnSn morphimR ?lcn_sub // commSg ?IHn. Qed. Canonical lcn_igFun n := [igFun by lcn_sub^~ n & lcn_cont n]. Canonical lcn_gFun n := [gFun by lcn_cont n]. Canonical lcn_mgFun n := [mgFun by fun _ G H => @lcnS _ n G H]. Section UpperCentralFunctor. Variable n : nat. Implicit Type gT : finGroupType. Lemma ucn_pmap : exists hZ : GFunctor.pmap, @upper_central_at n = hZ. Proof. elim: n => [|n' [hZ defZ]]; first by exists trivGfun_pgFun. by exists [pgFun of center %% hZ]; rewrite /= -defZ. Qed. (* Now extract all the intermediate facts of the last proof. *) Lemma ucn_group_set gT (G : {group gT}) : group_set 'Z_n(G). Proof. by have [hZ ->] := ucn_pmap; exact: groupP. Qed. Canonical upper_central_at_group gT G := Group (@ucn_group_set gT G). Lemma ucn_sub gT (G : {group gT}) : 'Z_n(G) \subset G. Proof. by have [hZ ->] := ucn_pmap; exact: gFsub. Qed. Lemma morphim_ucn : GFunctor.pcontinuous (upper_central_at n). Proof. by have [hZ ->] := ucn_pmap; exact: pmorphimF. Qed. Canonical ucn_igFun := [igFun by ucn_sub & morphim_ucn]. Canonical ucn_gFun := [gFun by morphim_ucn]. Canonical ucn_pgFun := [pgFun by morphim_ucn]. Variable (gT : finGroupType) (G : {group gT}). Lemma ucn_char : 'Z_n(G) \char G. Proof. exact: gFchar. Qed. Lemma ucn_norm : G \subset 'N('Z_n(G)). Proof. exact: gFnorm. Qed. Lemma ucn_normal : 'Z_n(G) <| G. Proof. exact: gFnormal. Qed. End UpperCentralFunctor. Notation "''Z_' n ( G )" := (upper_central_at_group n G) : Group_scope. Section UpperCentral. Variable gT : finGroupType. Implicit Types (A B : {set gT}) (G H : {group gT}). Lemma ucn0 A : 'Z_0(A) = 1. Proof. by []. Qed. Lemma ucnSn n A : 'Z_n.+1(A) = coset 'Z_n(A) @*^-1 'Z(A / 'Z_n(A)). Proof. by []. Qed. Lemma ucnE n A : 'Z_n(A) = upper_central_at_rec n A. Proof. by []. Qed. Lemma ucn_subS n G : 'Z_n(G) \subset 'Z_n.+1(G). Proof. by rewrite -{1}['Z_n(G)]ker_coset morphpreS ?sub1G. Qed. Lemma ucn_sub_geq m n G : n >= m -> 'Z_m(G) \subset 'Z_n(G). Proof. move/subnK <-; elim: {n}(n - m) => // n IHn. exact: subset_trans (ucn_subS _ _). Qed. Lemma ucn_central n G : 'Z_n.+1(G) / 'Z_n(G) = 'Z(G / 'Z_n(G)). Proof. by rewrite ucnSn cosetpreK. Qed. Lemma ucn_normalS n G : 'Z_n(G) <| 'Z_n.+1(G). Proof. by rewrite (normalS _ _ (ucn_normal n G)) ?ucn_subS ?ucn_sub. Qed. Lemma ucn_comm n G : [~: 'Z_n.+1(G), G] \subset 'Z_n(G). Proof. rewrite -quotient_cents2 ?normal_norm ?ucn_normal ?ucn_normalS //. by rewrite ucn_central subsetIr. Qed. Lemma ucn1 G : 'Z_1(G) = 'Z(G). Proof. apply: (quotient_inj (normal1 _) (normal1 _)). by rewrite /= (ucn_central 0) -injmF ?norms1 ?coset1_injm. Qed. Lemma ucnSnR n G : 'Z_n.+1(G) = [set x in G | [~: [set x], G] \subset 'Z_n(G)]. Proof. apply/setP=> x; rewrite inE -(setIidPr (ucn_sub n.+1 G)) inE ucnSn. case Gx: (x \in G) => //=; have nZG := ucn_norm n G. rewrite -sub1set -sub_quotient_pre -?quotient_cents2 ?sub1set ?(subsetP nZG) //. by rewrite subsetI quotientS ?sub1set. Qed. Lemma ucn_cprod n A B G : A \* B = G -> 'Z_n(A) \* 'Z_n(B) = 'Z_n(G). Proof. case/cprodP=> [[H K -> ->{A B}] mulHK cHK]. elim: n => [|n /cprodP[_ /= defZ cZn]]; first exact: cprod1g. set Z := 'Z_n(G) in defZ cZn; rewrite (ucnSn n G) /= -/Z. have /mulGsubP[nZH nZK]: H * K \subset 'N(Z) by rewrite mulHK gFnorm. have <-: 'Z(H / Z) * 'Z(K / Z) = 'Z(G / Z). by rewrite -mulHK quotientMl // center_prod ?quotient_cents. have ZquoZ (B A : {group gT}): B \subset 'C(A) -> 'Z_n(A) * 'Z_n(B) = Z -> 'Z(A / Z) = 'Z_n.+1(A) / Z. - move=> cAB {defZ}defZ; have cAZnB := subset_trans (ucn_sub n B) cAB. have /second_isom[/=]: A \subset 'N(Z). by rewrite -defZ normsM ?gFnorm ?cents_norm // centsC. suffices ->: Z :&: A = 'Z_n(A). by move=> f inj_f im_f; rewrite -!im_f ?gFsub // ucn_central injm_center. rewrite -defZ -group_modl ?gFsub //; apply/mulGidPl. have [-> | n_gt0] := posnP n; first exact: subsetIl. by apply: subset_trans (ucn_sub_geq A n_gt0); rewrite /= setIC ucn1 setIS. rewrite (ZquoZ H K) 1?centsC 1?(centC cZn) // {ZquoZ}(ZquoZ K H) //. have cZn1: 'Z_n.+1(K) \subset 'C('Z_n.+1(H)) by apply: centSS cHK; apply: gFsub. rewrite -quotientMl ?quotientK ?mul_subG ?(subset_trans (gFsub _ _)) //=. rewrite cprodE // -cent_joinEr ?mulSGid //= cent_joinEr //= -/Z. by rewrite -defZ mulgSS ?ucn_subS. Qed. Lemma ucn_dprod n A B G : A \x B = G -> 'Z_n(A) \x 'Z_n(B) = 'Z_n(G). Proof. move=> defG; have [[K H defA defB] _ _ tiAB] := dprodP defG. rewrite !dprodEcp // in defG *; first exact: ucn_cprod. by rewrite defA defB; apply/trivgP; rewrite -tiAB defA defB setISS ?ucn_sub. Qed. Lemma ucn_bigcprod n I r P (F : I -> {set gT}) G : \big[cprod/1]_(i <- r | P i) F i = G -> \big[cprod/1]_(i <- r | P i) 'Z_n(F i) = 'Z_n(G). Proof. elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first by rewrite gF1. by rewrite -(ucn_cprod n dG); have [[_ H _ dH]] := cprodP dG; rewrite dH (IH H). Qed. Lemma ucn_bigdprod n I r P (F : I -> {set gT}) G : \big[dprod/1]_(i <- r | P i) F i = G -> \big[dprod/1]_(i <- r | P i) 'Z_n(F i) = 'Z_n(G). Proof. elim/big_rec2: _ G => [_ <- | i A Z _ IH G dG]; first by rewrite gF1. by rewrite -(ucn_dprod n dG); have [[_ H _ dH]] := dprodP dG; rewrite dH (IH H). Qed. Lemma ucn_lcnP n G : ('L_n.+1(G) == 1) = ('Z_n(G) == G). Proof. rewrite !eqEsubset sub1G ucn_sub /= andbT -(ucn0 G). elim: {1 3}n 0 (addn0 n) => [j <- //|i IHi j]. rewrite addSnnS => /IHi <- {IHi}; rewrite ucnSn lcnSn. have nZG := normal_norm (ucn_normal j G). have nZL := subset_trans (lcn_sub _ _) nZG. by rewrite -sub_morphim_pre // subsetI morphimS ?lcn_sub // quotient_cents2. Qed. Lemma ucnP G : reflect (exists n, 'Z_n(G) = G) (nilpotent G). Proof. apply: (iffP (lcnP G)) => [] [n /eqP clGn]; by exists n; apply/eqP; rewrite ucn_lcnP in clGn *. Qed. Lemma ucn_nil_classP n G : nilpotent G -> reflect ('Z_n(G) = G) (nil_class G <= n). Proof. move=> nilG; rewrite (sameP (lcn_nil_classP n nilG) eqP) ucn_lcnP; exact: eqP. Qed. Lemma ucn_id n G : 'Z_n('Z_n(G)) = 'Z_n(G). Proof. by rewrite -{2}['Z_n(G)]gFid. Qed. Lemma ucn_nilpotent n G : nilpotent 'Z_n(G). Proof. by apply/ucnP; exists n; rewrite ucn_id. Qed. Lemma nil_class_ucn n G : nil_class 'Z_n(G) <= n. Proof. by apply/ucn_nil_classP; rewrite ?ucn_nilpotent ?ucn_id. Qed. End UpperCentral. Section MorphNil. Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}). Implicit Type G : {group aT}. Lemma morphim_lcn n G : G \subset D -> f @* 'L_n(G) = 'L_n(f @* G). Proof. move=> sHG; case: n => //; elim=> // n IHn. by rewrite !lcnSn -IHn morphimR // (subset_trans _ sHG) // lcn_sub. Qed. Lemma injm_ucn n G : 'injm f -> G \subset D -> f @* 'Z_n(G) = 'Z_n(f @* G). Proof. exact: injmF. Qed. Lemma morphim_nil G : nilpotent G -> nilpotent (f @* G). Proof. case/ucnP=> n ZnG; apply/ucnP; exists n; apply/eqP. by rewrite eqEsubset ucn_sub /= -{1}ZnG morphim_ucn. Qed. Lemma injm_nil G : 'injm f -> G \subset D -> nilpotent (f @* G) = nilpotent G. Proof. move=> injf sGD; apply/idP/idP; last exact: morphim_nil. case/ucnP=> n; rewrite -injm_ucn // => /injm_morphim_inj defZ. by apply/ucnP; exists n; rewrite defZ ?(subset_trans (ucn_sub n G)). Qed. Lemma nil_class_morphim G : nilpotent G -> nil_class (f @* G) <= nil_class G. Proof. move=> nilG; rewrite (sameP (ucn_nil_classP _ (morphim_nil nilG)) eqP) /=. by rewrite eqEsubset ucn_sub -{1}(ucn_nil_classP _ nilG (leqnn _)) morphim_ucn. Qed. Lemma nil_class_injm G : 'injm f -> G \subset D -> nil_class (f @* G) = nil_class G. Proof. move=> injf sGD; case nilG: (nilpotent G). apply/eqP; rewrite eqn_leq nil_class_morphim //. rewrite (sameP (lcn_nil_classP _ nilG) eqP) -subG1. rewrite -(injmSK injf) ?(subset_trans (lcn_sub _ _)) // morphim1. by rewrite morphim_lcn // (lcn_nil_classP _ _ (leqnn _)) //= injm_nil. transitivity #|G|; apply/eqP; rewrite eqn_leq. rewrite -(card_injm injf sGD) (leq_trans (index_size _ _)) ?size_mkseq //. by rewrite leqNgt -nilpotent_class injm_nil ?nilG. rewrite (leq_trans (index_size _ _)) ?size_mkseq // leqNgt -nilpotent_class. by rewrite nilG. Qed. End MorphNil. Section QuotientNil. Variables gT : finGroupType. Implicit Types (rT : finGroupType) (G H : {group gT}). Lemma quotient_ucn_add m n G : 'Z_(m + n)(G) / 'Z_n(G) = 'Z_m(G / 'Z_n(G)). Proof. elim: m => [|m IHm]; first exact: trivg_quotient. apply/setP=> Zx; have [x Nx ->{Zx}] := cosetP Zx. have [sZG nZG] := andP (ucn_normal n G). rewrite (ucnSnR m) inE -!sub1set -morphim_set1 //= -quotientR ?sub1set // -IHm. rewrite !quotientSGK ?(ucn_sub_geq, leq_addl, comm_subG _ nZG, sub1set) //=. by rewrite addSn /= ucnSnR inE. Qed. Lemma isog_nil rT G (L : {group rT}) : G \isog L -> nilpotent G = nilpotent L. Proof. by case/isogP=> f injf <-; rewrite injm_nil. Qed. Lemma isog_nil_class rT G (L : {group rT}) : G \isog L -> nil_class G = nil_class L. Proof. by case/isogP=> f injf <-; rewrite nil_class_injm. Qed. Lemma quotient_nil G H : nilpotent G -> nilpotent (G / H). Proof. exact: morphim_nil. Qed. Lemma quotient_center_nil G : nilpotent (G / 'Z(G)) = nilpotent G. Proof. rewrite -ucn1; apply/idP/idP; last exact: quotient_nil. case/ucnP=> c nilGq; apply/ucnP; exists c.+1; have nsZ1G := ucn_normal 1 G. apply: (quotient_inj _ nsZ1G); last by rewrite /= -(addn1 c) quotient_ucn_add. by rewrite (normalS _ _ nsZ1G) ?ucn_sub ?ucn_sub_geq. Qed. Lemma nil_class_quotient_center G : nilpotent (G) -> nil_class (G / 'Z(G)) = (nil_class G).-1. Proof. move=> nilG; have nsZ1G := ucn_normal 1 G. apply/eqP; rewrite -ucn1 eqn_leq; apply/andP; split. apply/ucn_nil_classP; rewrite ?quotient_nil //= -quotient_ucn_add ucn1. by rewrite (ucn_nil_classP _ _ _) ?addn1 ?leqSpred. rewrite -subn1 leq_subLR addnC; apply/ucn_nil_classP => //=. apply: (quotient_inj _ nsZ1G) => /=. by apply: normalS (ucn_sub _ _) nsZ1G; rewrite /= addnS ucn_sub_geq. by rewrite quotient_ucn_add; apply/ucn_nil_classP; rewrite //= quotient_nil. Qed. Lemma nilpotent_sub_norm G H : nilpotent G -> H \subset G -> 'N_G(H) \subset H -> G :=: H. Proof. move=> nilG sHG sNH; apply/eqP; rewrite eqEsubset sHG andbT; apply/negP=> nsGH. have{nsGH} [i sZH []]: exists2 i, 'Z_i(G) \subset H & ~ 'Z_i.+1(G) \subset H. case/ucnP: nilG => n ZnG; rewrite -{}ZnG in nsGH. elim: n => [|i IHi] in nsGH *; first by rewrite sub1G in nsGH. by case sZH: ('Z_i(G) \subset H); [exists i | apply: IHi; rewrite sZH]. apply: subset_trans sNH; rewrite subsetI ucn_sub -commg_subr. by apply: subset_trans sZH; apply: subset_trans (ucn_comm i G); exact: commgS. Qed. Lemma nilpotent_proper_norm G H : nilpotent G -> H \proper G -> H \proper 'N_G(H). Proof. move=> nilG; rewrite properEneq properE subsetI normG => /andP[neHG sHG]. by rewrite sHG; apply: contra neHG; move/(nilpotent_sub_norm nilG)->. Qed. Lemma nilpotent_subnormal G H : nilpotent G -> H \subset G -> H <|<| G. Proof. move=> nilG; elim: {H}_.+1 {-2}H (ltnSn (#|G| - #|H|)) => // m IHm H. rewrite ltnS => leGHm sHG; have:= sHG; rewrite subEproper. case/predU1P=> [->|]; first exact: subnormal_refl. move/(nilpotent_proper_norm nilG); set K := 'N_G(H) => prHK. have snHK: H <|<| K by rewrite normal_subnormal ?normalSG. have sKG: K \subset G by rewrite subsetIl. apply: subnormal_trans snHK (IHm _ (leq_trans _ leGHm) sKG). by rewrite ltn_sub2l ?proper_card ?(proper_sub_trans prHK). Qed. Lemma TI_center_nil G H : nilpotent G -> H <| G -> H :&: 'Z(G) = 1 -> H :=: 1. Proof. move=> nilG /andP[sHG nHG] tiHZ. rewrite -{1}(setIidPl sHG); have{nilG} /ucnP[n <-] := nilG. elim: n => [|n IHn]; apply/trivgP; rewrite ?subsetIr // -tiHZ. rewrite [H :&: 'Z(G)]setIA subsetI setIS ?ucn_sub //= (sameP commG1P trivgP). rewrite -commg_subr commGC in nHG. rewrite -IHn subsetI (subset_trans _ nHG) ?commSg ?subsetIl //=. by rewrite (subset_trans _ (ucn_comm n G)) ?commSg ?subsetIr. Qed. Lemma meet_center_nil G H : nilpotent G -> H <| G -> H :!=: 1 -> H :&: 'Z(G) != 1. Proof. by move=> nilG nsHG; apply: contraNneq => /TI_center_nil->. Qed. Lemma center_nil_eq1 G : nilpotent G -> ('Z(G) == 1) = (G :==: 1). Proof. move=> nilG; apply/eqP/eqP=> [Z1 | ->]; last exact: center1. by rewrite (TI_center_nil nilG) // (setIidPr (center_sub G)). Qed. Lemma cyclic_nilpotent_quo_der1_cyclic G : nilpotent G -> cyclic (G / G^`(1)) -> cyclic G. Proof. move=> nG; rewrite (isog_cyclic (quotient1_isog G)). have [-> // | ntG' cGG'] := (eqVneq G^`(1) 1)%g. suffices: 'L_2(G) \subset G :&: 'L_3(G) by move/(eqfun_inP nG)=> <-. rewrite subsetI lcn_sub /= -quotient_cents2 ?lcn_norm //. apply: cyclic_factor_abelian (lcn_central 2 G) _. by rewrite (isog_cyclic (third_isog _ _ _)) ?lcn_normal // lcn_subS. Qed. End QuotientNil. Section Solvable. Variable gT : finGroupType. Implicit Types G H : {group gT}. Lemma nilpotent_sol G : nilpotent G -> solvable G. Proof. move=> nilG; apply/forall_inP=> H /subsetIP[sHG sHH']. by rewrite (forall_inP nilG) // subsetI sHG (subset_trans sHH') ?commgS. Qed. Lemma abelian_sol G : abelian G -> solvable G. Proof. by move/abelian_nil; exact: nilpotent_sol. Qed. Lemma solvable1 : solvable [1 gT]. Proof. exact: abelian_sol (abelian1 gT). Qed. Lemma solvableS G H : H \subset G -> solvable G -> solvable H. Proof. move=> sHG solG; apply/forall_inP=> K /subsetIP[sKH sKK']. by rewrite (forall_inP solG) // subsetI (subset_trans sKH). Qed. Lemma sol_der1_proper G H : solvable G -> H \subset G -> H :!=: 1 -> H^`(1) \proper H. Proof. move=> solG sHG ntH; rewrite properE comm_subG //; apply: implyP ntH. by have:= forallP solG H; rewrite subsetI sHG implybNN. Qed. Lemma derivedP G : reflect (exists n, G^`(n) = 1) (solvable G). Proof. apply: (iffP idP) => [solG | [n solGn]]; last first. apply/forall_inP=> H /subsetIP[sHG sHH']. rewrite -subG1 -{}solGn; elim: n => // n IHn. exact: subset_trans sHH' (commgSS _ _). suffices IHn n: #|G^`(n)| <= (#|G|.-1 - n).+1. by exists #|G|.-1; rewrite [G^`(_)]card_le1_trivg ?(leq_trans (IHn _)) ?subnn. elim: n => [|n IHn]; first by rewrite subn0 prednK. rewrite dergSn subnS -ltnS. have [-> | ntGn] := eqVneq G^`(n) 1; first by rewrite commG1 cards1. case: (_ - _) IHn => [|n']; first by rewrite leqNgt cardG_gt1 ntGn. by apply: leq_trans (proper_card _); exact: sol_der1_proper (der_sub _ _) _. Qed. End Solvable. Section MorphSol. Variables (gT rT : finGroupType) (D : {group gT}) (f : {morphism D >-> rT}). Variable G : {group gT}. Lemma morphim_sol : solvable G -> solvable (f @* G). Proof. move/(solvableS (subsetIr D G)); case/derivedP=> n Gn1; apply/derivedP. by exists n; rewrite /= -morphimIdom -morphim_der ?subsetIl // Gn1 morphim1. Qed. Lemma injm_sol : 'injm f -> G \subset D -> solvable (f @* G) = solvable G. Proof. move=> injf sGD; apply/idP/idP; last exact: morphim_sol. case/derivedP=> n Gn1; apply/derivedP; exists n; apply/trivgP. rewrite -(injmSK injf) ?(subset_trans (der_sub _ _)) ?morphim_der //. by rewrite Gn1 morphim1. Qed. End MorphSol. Section QuotientSol. Variables gT rT : finGroupType. Implicit Types G H K : {group gT}. Lemma isog_sol G (L : {group rT}) : G \isog L -> solvable G = solvable L. Proof. by case/isogP=> f injf <-; rewrite injm_sol. Qed. Lemma quotient_sol G H : solvable G -> solvable (G / H). Proof. exact: morphim_sol. Qed. Lemma series_sol G H : H <| G -> solvable G = solvable H && solvable (G / H). Proof. case/andP=> sHG nHG; apply/idP/andP=> [solG | [solH solGH]]. by rewrite quotient_sol // (solvableS sHG). apply/forall_inP=> K /subsetIP[sKG sK'K]. suffices sKH: K \subset H by rewrite (forall_inP solH) // subsetI sKH. have nHK := subset_trans sKG nHG. rewrite -quotient_sub1 // subG1 (forall_inP solGH) //. by rewrite subsetI -morphimR ?morphimS. Qed. Lemma metacyclic_sol G : metacyclic G -> solvable G. Proof. case/metacyclicP=> K [cycK nsKG cycGq]. by rewrite (series_sol nsKG) !abelian_sol ?cyclic_abelian. Qed. End QuotientSol. mathcomp-1.5/theories/commutator.v0000644000175000017500000003202312307636117016364 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat fintype bigop finset. Require Import binomial fingroup morphism automorphism quotient gfunctor. (******************************************************************************) (* This files contains the proofs of several key properties of commutators, *) (* including the Hall-Witt identity and the Three Subgroup Lemma. *) (* The definition and notation for both pointwise and set wise commutators *) (* ([~x, y, ...] and [~: A, B ,...], respectively) are given in fingroup.v *) (* This file defines the derived group series: *) (* G^`(0) == G *) (* G^`(n.+1) == [~: G^`(n), G^`(n)] *) (* as several classical results involve the (first) derived group G^`(1), *) (* such as the equivalence H <| G /\ G / H abelian <-> G^`(1) \subset H. The *) (* connection between the derived series and solvable groups will only be *) (* established in nilpotent.v, however. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Definition derived_at_rec n (gT : finGroupType) (A : {set gT}) := iter n (fun B => [~: B, B]) A. (* Note: 'nosimpl' MUST be used outside of a section -- the end of section *) (* "cooking" destroys it. *) Definition derived_at := nosimpl derived_at_rec. Arguments Scope derived_at [nat_scope _ group_scope]. Notation "G ^` ( n )" := (derived_at n G) : group_scope. Section DerivedBasics. Variables gT : finGroupType. Implicit Type A : {set gT}. Implicit Types G : {group gT}. Lemma derg0 A : A^`(0) = A. Proof. by []. Qed. Lemma derg1 A : A^`(1) = [~: A, A]. Proof. by []. Qed. Lemma dergSn n A : A^`(n.+1) = [~: A^`(n), A^`(n)]. Proof. by []. Qed. Lemma der_group_set G n : group_set G^`(n). Proof. by case: n => [|n]; exact: groupP. Qed. Canonical derived_at_group G n := Group (der_group_set G n). End DerivedBasics. Notation "G ^` ( n )" := (derived_at_group G n) : Group_scope. Section Basic_commutator_properties. Variable gT : finGroupType. Implicit Types x y z : gT. Lemma conjg_mulR x y : x ^ y = x * [~ x, y]. Proof. by rewrite mulKVg. Qed. Lemma conjg_Rmul x y : x ^ y = [~ y, x^-1] * x. Proof. by rewrite commgEr invgK mulgKV. Qed. Lemma commMgJ x y z : [~ x * y, z] = [~ x, z] ^ y * [~ y, z]. Proof. by rewrite !commgEr conjgM mulgA -conjMg mulgK. Qed. Lemma commgMJ x y z : [~ x, y * z] = [~ x, z] * [~ x, y] ^ z. Proof. by rewrite !commgEl conjgM -mulgA -conjMg mulKVg. Qed. Lemma commMgR x y z : [~ x * y, z] = [~ x, z] * [~ x, z, y] * [~ y, z]. Proof. by rewrite commMgJ conjg_mulR. Qed. Lemma commgMR x y z : [~ x, y * z] = [~ x, z] * [~ x, y] * [~ x, y, z]. Proof. by rewrite commgMJ conjg_mulR mulgA. Qed. Lemma Hall_Witt_identity x y z : [~ x, y^-1, z] ^ y * [~ y, z^-1, x] ^ z * [~ z, x^-1, y] ^ x = 1. Proof. (* gsimpl *) pose a x y z : gT := x * z * y ^ x. suffices{x y z} hw_aux x y z: [~ x, y^-1, z] ^ y = (a x y z)^-1 * (a y z x). by rewrite !hw_aux 2!mulgA !mulgK mulVg. by rewrite commgEr conjMg -conjgM -conjg_Rmul 2!invMg conjgE !mulgA. Qed. (* the following properties are useful for studying p-groups of class 2 *) Section LeftComm. Variables (i : nat) (x y : gT). Hypothesis cxz : commute x [~ x, y]. Lemma commVg : [~ x^-1, y] = [~ x, y]^-1. Proof. apply/eqP; rewrite commgEl eq_sym eq_invg_mul invgK mulgA -cxz. by rewrite -conjg_mulR -conjMg mulgV conj1g. Qed. Lemma commXg : [~ x ^+ i, y] = [~ x, y] ^+ i. Proof. elim: i => [|i' IHi]; first exact: comm1g. by rewrite !expgS commMgJ /conjg commuteX // mulKg IHi. Qed. End LeftComm. Section RightComm. Variables (i : nat) (x y : gT). Hypothesis cyz : commute y [~ x, y]. Let cyz' := commuteV cyz. Lemma commgV : [~ x, y^-1] = [~ x, y]^-1. Proof. by rewrite -invg_comm commVg -(invg_comm x y) ?invgK. Qed. Lemma commgX : [~ x, y ^+ i] = [~ x, y] ^+ i. Proof. by rewrite -invg_comm commXg -(invg_comm x y) ?expgVn ?invgK. Qed. End RightComm. Section LeftRightComm. Variables (i j : nat) (x y : gT). Hypotheses (cxz : commute x [~ x, y]) (cyz : commute y [~ x, y]). Lemma commXXg : [~ x ^+ i, y ^+ j] = [~ x, y] ^+ (i * j). Proof. rewrite expgM commgX commXg //; exact: commuteX. Qed. Lemma expMg_Rmul : (y * x) ^+ i = y ^+ i * x ^+ i * [~ x, y] ^+ 'C(i, 2). Proof. rewrite -triangular_sum; symmetry. elim: i => [|k IHk] /=; first by rewrite big_geq ?mulg1. rewrite big_nat_recr //= addnC expgD !expgS -{}IHk !mulgA; congr (_ * _). by rewrite -!mulgA commuteX2 // -commgX // [mulg y]lock 3!mulgA -commgC. Qed. End LeftRightComm. End Basic_commutator_properties. (***** Set theoretic commutators *****) Section Commutator_properties. Variable gT : finGroupType. Implicit Type (rT : finGroupType) (A B C : {set gT}) (D G H K : {group gT}). Lemma commG1 A : [~: A, 1] = 1. Proof. by apply/commG1P; rewrite centsC sub1G. Qed. Lemma comm1G A : [~: 1, A] = 1. Proof. by rewrite commGC commG1. Qed. Lemma commg_sub A B : [~: A, B] \subset A <*> B. Proof. by rewrite comm_subG // (joing_subl, joing_subr). Qed. Lemma commg_norml G A : G \subset 'N([~: G, A]). Proof. apply/subsetP=> x Gx; rewrite inE -genJ gen_subG. apply/subsetP=> _ /imsetP[_ /imset2P[y z Gy Az ->] ->]. by rewrite -(mulgK [~ x, z] (_ ^ x)) -commMgJ !(mem_commg, groupMl, groupV). Qed. Lemma commg_normr G A : G \subset 'N([~: A, G]). Proof. by rewrite commGC commg_norml. Qed. Lemma commg_norm G H : G <*> H \subset 'N([~: G, H]). Proof. by rewrite join_subG ?commg_norml ?commg_normr. Qed. Lemma commg_normal G H : [~: G, H] <| G <*> H. Proof. by rewrite /(_ <| _) commg_sub commg_norm. Qed. Lemma normsRl A G B : A \subset G -> A \subset 'N([~: G, B]). Proof. by move=> sAG; exact: subset_trans (commg_norml G B). Qed. Lemma normsRr A G B : A \subset G -> A \subset 'N([~: B, G]). Proof. by move=> sAG; exact: subset_trans (commg_normr G B). Qed. Lemma commg_subr G H : ([~: G, H] \subset H) = (G \subset 'N(H)). Proof. rewrite gen_subG; apply/subsetP/subsetP=> [sRH x Gx | nGH xy]. rewrite inE; apply/subsetP=> _ /imsetP[y Ky ->]. by rewrite conjg_Rmul groupMr // sRH // mem_imset2 ?groupV. case/imset2P=> x y Gx Hy ->{xy}. by rewrite commgEr groupMr // memJ_norm (groupV, nGH). Qed. Lemma commg_subl G H : ([~: G, H] \subset G) = (H \subset 'N(G)). Proof. by rewrite commGC commg_subr. Qed. Lemma commg_subI A B G H : A \subset 'N_G(H) -> B \subset 'N_H(G) -> [~: A, B] \subset G :&: H. Proof. rewrite !subsetI -(gen_subG _ 'N(G)) -(gen_subG _ 'N(H)). rewrite -commg_subr -commg_subl; case/andP=> sAG sRH; case/andP=> sBH sRG. by rewrite (subset_trans _ sRG) ?(subset_trans _ sRH) ?commgSS ?subset_gen. Qed. Lemma quotient_cents2 A B K : A \subset 'N(K) -> B \subset 'N(K) -> (A / K \subset 'C(B / K)) = ([~: A, B] \subset K). Proof. move=> nKA nKB. by rewrite (sameP commG1P trivgP) /= -quotientR // quotient_sub1 // comm_subG. Qed. Lemma quotient_cents2r A B K : [~: A, B] \subset K -> (A / K) \subset 'C(B / K). Proof. move=> sABK; rewrite -2![_ / _]morphimIdom -!quotientE. by rewrite quotient_cents2 ?subsetIl ?(subset_trans _ sABK) ?commgSS ?subsetIr. Qed. Lemma sub_der1_norm G H : G^`(1) \subset H -> H \subset G -> G \subset 'N(H). Proof. by move=> sG'H sHG; rewrite -commg_subr (subset_trans _ sG'H) ?commgS. Qed. Lemma sub_der1_normal G H : G^`(1) \subset H -> H \subset G -> H <| G. Proof. by move=> sG'H sHG; rewrite /(H <| G) sHG sub_der1_norm. Qed. Lemma sub_der1_abelian G H : G^`(1) \subset H -> abelian (G / H). Proof. by move=> sG'H; exact: quotient_cents2r. Qed. Lemma der1_min G H : G \subset 'N(H) -> abelian (G / H) -> G^`(1) \subset H. Proof. by move=> nHG abGH; rewrite -quotient_cents2. Qed. Lemma der_abelian n G : abelian (G^`(n) / G^`(n.+1)). Proof. by rewrite sub_der1_abelian // der_subS. Qed. Lemma commg_normSl G H K : G \subset 'N(H) -> [~: G, H] \subset 'N([~: K, H]). Proof. by move=> nHG; rewrite normsRr // commg_subr. Qed. Lemma commg_normSr G H K : G \subset 'N(H) -> [~: H, G] \subset 'N([~: H, K]). Proof. by move=> nHG; rewrite !(commGC H) commg_normSl. Qed. Lemma commMGr G H K : [~: G, K] * [~: H, K] \subset [~: G * H , K]. Proof. by rewrite mul_subG ?commSg ?(mulG_subl, mulG_subr). Qed. Lemma commMG G H K : H \subset 'N([~: G, K]) -> [~: G * H , K] = [~: G, K] * [~: H, K]. Proof. move=> nRH; apply/eqP; rewrite eqEsubset commMGr andbT. have nRHK: [~: H, K] \subset 'N([~: G, K]) by rewrite comm_subG ?commg_normr. have defM := norm_joinEr nRHK; rewrite -defM gen_subG /=. apply/subsetP=> _ /imset2P[_ z /imset2P[x y Gx Hy ->] Kz ->]. by rewrite commMgJ {}defM mem_mulg ?memJ_norm ?mem_commg // (subsetP nRH). Qed. Lemma comm3G1P A B C : reflect {in A & B & C, forall h k l, [~ h, k, l] = 1} ([~: A, B, C] :==: 1). Proof. have R_C := sameP trivgP commG1P. rewrite -subG1 R_C gen_subG -{}R_C gen_subG. apply: (iffP subsetP) => [cABC x y z Ax By Cz | cABC xyz]. by apply/set1P; rewrite cABC // !mem_imset2. by case/imset2P=> _ z /imset2P[x y Ax By ->] Cz ->; rewrite cABC. Qed. Lemma three_subgroup G H K : [~: G, H, K] :=: 1 -> [~: H, K, G] :=: 1-> [~: K, G, H] :=: 1. Proof. move/eqP/comm3G1P=> cGHK /eqP/comm3G1P cHKG. apply/eqP/comm3G1P=> x y z Kx Gy Hz; symmetry. rewrite -(conj1g y) -(Hall_Witt_identity y^-1 z x) invgK. by rewrite cGHK ?groupV // cHKG ?groupV // !conj1g !mul1g conjgKV. Qed. Lemma der1_joing_cycles (x y : gT) : let XY := <[x]> <*> <[y]> in let xy := [~ x, y] in xy \in 'C(XY) -> XY^`(1) = <[xy]>. Proof. rewrite joing_idl joing_idr /= -sub_cent1 => /norms_gen nRxy. apply/eqP; rewrite eqEsubset cycle_subG mem_commg ?mem_gen ?set21 ?set22 //. rewrite der1_min // quotient_gen -1?gen_subG // quotientU abelian_gen. rewrite /abelian subUset centU !subsetI andbC centsC -andbA -!abelianE. rewrite !quotient_abelian ?(abelianS (subset_gen _) (cycle_abelian _)) //=. by rewrite andbb quotient_cents2r ?genS // /commg_set imset2_set1l imset_set1. Qed. Lemma commgAC G x y z : x \in G -> y \in G -> z \in G -> commute y z -> abelian [~: [set x], G] -> [~ x, y, z] = [~ x, z, y]. Proof. move=> Gx Gy Gz cyz /centsP cRxG; pose cx' u := [~ x^-1, u]. have xR3 u v: [~ x, u, v] = x^-1 * (cx' u * cx' v) * x ^ (u * v). rewrite mulgA -conjg_mulR conjVg [cx' v]commgEl mulgA -invMg. by rewrite -mulgA conjgM -conjMg -!commgEl. suffices RxGcx' u: u \in G -> cx' u \in [~: [set x], G]. by rewrite !xR3 {}cyz; congr (_ * _ * _); rewrite cRxG ?RxGcx'. move=> Gu; suffices/groupMl <-: [~ x, u] ^ x^-1 \in [~: [set x], G]. by rewrite -commMgJ mulgV comm1g group1. by rewrite memJ_norm ?mem_commg ?set11 // groupV (subsetP (commg_normr _ _)). Qed. (* Aschbacher, exercise 3.6 (used in proofs of Aschbacher 24.7 and B & G 1.10 *) Lemma comm_norm_cent_cent H G K : H \subset 'N(G) -> H \subset 'C(K) -> G \subset 'N(K) -> [~: G, H] \subset 'C(K). Proof. move=> nGH /centsP cKH nKG; rewrite commGC gen_subG centsC. apply/centsP=> x Kx _ /imset2P[y z Hy Gz ->]; red. rewrite mulgA -[x * _]cKH ?groupV // -!mulgA; congr (_ * _). rewrite (mulgA x) (conjgC x) (conjgCV z) 3!mulgA; congr (_ * _). by rewrite -2!mulgA (cKH y) // -mem_conjg (normsP nKG). Qed. Lemma charR H K G : H \char G -> K \char G -> [~: H, K] \char G. Proof. case/charP=> sHG chH /charP[sKG chK]; apply/charP. by split=> [|f infj Gf]; [rewrite comm_subG | rewrite morphimR // chH // chK]. Qed. Lemma der_char n G : G^`(n) \char G. Proof. by elim: n => [|n IHn]; rewrite ?char_refl // dergSn charR. Qed. Lemma der_sub n G : G^`(n) \subset G. Proof. by rewrite char_sub ?der_char. Qed. Lemma der_norm n G : G \subset 'N(G^`(n)). Proof. by rewrite char_norm ?der_char. Qed. Lemma der_normal n G : G^`(n) <| G. Proof. by rewrite char_normal ?der_char. Qed. Lemma der_subS n G : G^`(n.+1) \subset G^`(n). Proof. by rewrite comm_subG. Qed. Lemma der_normalS n G : G^`(n.+1) <| G^`(n). Proof. by rewrite sub_der1_normal // der_subS. Qed. Lemma morphim_der rT D (f : {morphism D >-> rT}) n G : G \subset D -> f @* G^`(n) = (f @* G)^`(n). Proof. move=> sGD; elim: n => // n IHn. by rewrite !dergSn -IHn morphimR ?(subset_trans (der_sub n G)). Qed. Lemma dergS n G H : G \subset H -> G^`(n) \subset H^`(n). Proof. by move=> sGH; elim: n => // n IHn; exact: commgSS. Qed. Lemma quotient_der n G H : G \subset 'N(H) -> G^`(n) / H = (G / H)^`(n). Proof. exact: morphim_der. Qed. Lemma derJ G n x : (G :^ x)^`(n) = G^`(n) :^ x. Proof. by elim: n => //= n IHn; rewrite !dergSn IHn -conjsRg. Qed. Lemma derG1P G : reflect (G^`(1) = 1) (abelian G). Proof. exact: commG1P. Qed. End Commutator_properties. Implicit Arguments derG1P [gT G]. Lemma der_cont n : GFunctor.continuous (derived_at n). Proof. by move=> aT rT G f; rewrite morphim_der. Qed. Canonical der_igFun n := [igFun by der_sub^~ n & der_cont n]. Canonical der_gFun n := [gFun by der_cont n]. Canonical der_mgFun n := [mgFun by dergS^~ n]. Lemma isog_der (aT rT : finGroupType) n (G : {group aT}) (H : {group rT}) : G \isog H -> G^`(n) \isog H^`(n). Proof. exact: gFisog. Qed. mathcomp-1.5/theories/ssralg.v0000644000175000017500000073143012307636117015475 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat div seq choice fintype. Require Import finfun bigop prime binomial. (******************************************************************************) (* The algebraic part of the Algebraic Hierarchy, as described in *) (* ``Packaging mathematical structures'', TPHOLs09, by *) (* Francois Garillot, Georges Gonthier, Assia Mahboubi, Laurence Rideau *) (* *) (* This file defines for each Structure (Zmodule, Ring, etc ...) its type, *) (* its packers and its canonical properties : *) (* *) (* * Zmodule (additive abelian groups): *) (* zmodType == interface type for Zmodule structure. *) (* ZmodMixin addA addC add0x addNx == builds the mixin for a Zmodule from the *) (* algebraic properties of its operations. *) (* ZmodType V m == packs the mixin m to build a Zmodule of type *) (* zmodType. The carrier type V must have a *) (* choiceType canonical structure. *) (* [zmodType of V for S] == V-clone of the zmodType structure S: a copy of S *) (* where the sort carrier has been replaced by V, *) (* and which is therefore a zmodType structure on V. *) (* The sort carrier for S must be convertible to V. *) (* [zmodType of V] == clone of a canonical zmodType structure on V. *) (* Similar to the above, except S is inferred, but *) (* possibly with a syntactically different carrier. *) (* 0 == the zero (additive identity) of a Zmodule. *) (* x + y == the sum of x and y (in a Zmodule). *) (* - x == the opposite (additive inverse) of x. *) (* x - y == the difference of x and y; this is only notation *) (* for x + (- y). *) (* x *+ n == n times x, with n in nat (non-negative), i.e., *) (* x + (x + .. (x + x)..) (n terms); x *+ 1 is thus *) (* convertible to x, and x *+ 2 to x + x. *) (* x *- n == notation for - (x *+ n), the opposite of x *+ n. *) (* \sum_ e == iterated sum for a Zmodule (cf bigop.v). *) (* e`_i == nth 0 e i, when e : seq M and M has a zmodType *) (* structure. *) (* support f == 0.-support f, i.e., [pred x | f x != 0]. *) (* oppr_closed S <-> collective predicate S is closed under opposite. *) (* addr_closed S <-> collective predicate S is closed under finite *) (* sums (0 and x + y in S, for x, y in S). *) (* zmod_closed S <-> collective predicate S is closed under zmodType *) (* operations (0 and x - y in S, for x, y in S). *) (* This property coerces to oppr_pred and addr_pred. *) (* OpprPred oppS == packs oppS : oppr_closed S into an opprPred S *) (* interface structure associating this property to *) (* the canonical pred_key S, i.e. the k for which S *) (* has a Canonical keyed_pred k structure (see file *) (* ssrbool.v). *) (* AddrPred addS == packs addS : addr_closed S into an addrPred S *) (* interface structure associating this property to *) (* the canonical pred_key S (see above). *) (* ZmodPred oppS == packs oppS : oppr_closed S into an zmodPred S *) (* interface structure associating the zmod_closed *) (* property to the canonical pred_key S (see above), *) (* which must already be an addrPred. *) (* [zmodMixin of M by <:] == zmodType mixin for a subType whose base type is *) (* a zmodType and whose predicate's canonical *) (* pred_key is a zmodPred. *) (* --> Coq can be made to behave as if all predicates had canonical zmodPred *) (* keys by executing Import DefaultKeying GRing.DefaultPred. The required *) (* oppr_closed and addr_closed assumptions will be either abstracted, *) (* resolved or issued as separate proof obligations by the ssreflect *) (* plugin abstraction and Prop-irrelevance functions. *) (* * Ring (non-commutative rings): *) (* ringType == interface type for a Ring structure. *) (* RingMixin mulA mul1x mulx1 mulDx mulxD == builds the mixin for a Ring from *) (* the algebraic properties of its multiplicative *) (* operators; the carrier type must have a zmodType *) (* structure. *) (* RingType R m == packs the ring mixin m into a ringType. *) (* R^c == the converse Ring for R: R^c is convertible to R *) (* but when R has a canonical ringType structure *) (* R^c has the converse one: if x y : R^c, then *) (* x * y = (y : R) * (x : R). *) (* [ringType of R for S] == R-clone of the ringType structure S. *) (* [ringType of R] == clone of a canonical ringType structure on R. *) (* 1 == the multiplicative identity element of a Ring. *) (* n%:R == the ring image of an n in nat; this is just *) (* notation for 1 *+ n, so 1%:R is convertible to 1 *) (* and 2%:R to 1 + 1. *) (* x * y == the ring product of x and y. *) (* \prod_ e == iterated product for a ring (cf bigop.v). *) (* x ^+ n == x to the nth power with n in nat (non-negative), *) (* i.e., x * (x * .. (x * x)..) (n factors); x ^+ 1 *) (* is thus convertible to x, and x ^+ 2 to x * x. *) (* GRing.sign R b := (-1) ^+ b in R : ringType, with b : bool. *) (* This is a parsing-only helper notation, to be *) (* used for defining more specific instances. *) (* GRing.comm x y <-> x and y commute, i.e., x * y = y * x. *) (* GRing.lreg x <-> x if left-regular, i.e., *%R x is injective. *) (* GRing.rreg x <-> x if right-regular, i.e., *%R x is injective. *) (* [char R] == the characteristic of R, defined as the set of *) (* prime numbers p such that p%:R = 0 in R. The set *) (* [char p] has a most one element, and is *) (* implemented as a pred_nat collective predicate *) (* (see prime.v); thus the statement p \in [char R] *) (* can be read as `R has characteristic p', while *) (* [char R] =i pred0 means `R has characteristic 0' *) (* when R is a field. *) (* Frobenius_aut chRp == the Frobenius automorphism mapping x in R to *) (* x ^+ p, where chRp : p \in [char R] is a proof *) (* that R has (non-zero) characteristic p. *) (* mulr_closed S <-> collective predicate S is closed under finite *) (* products (1 and x * y in S for x, y in S). *) (* smulr_closed S <-> collective predicate S is closed under products *) (* and opposite (-1 and x * y in S for x, y in S). *) (* semiring_closed S <-> collective predicate S is closed under semiring *) (* operations (0, 1, x + y and x * y in S). *) (* subring_closed S <-> collective predicate S is closed under ring *) (* operations (1, x - y and x * y in S). *) (* MulrPred mulS == packs mulS : mulr_closed S into a mulrPred S, *) (* SmulrPred mulS smulrPred S, semiringPred S, or subringPred S *) (* SemiringPred mulS interface structure, corresponding to the above *) (* SubRingPred mulS properties, respectively, provided S already has *) (* the supplementary zmodType closure properties. *) (* The properties above coerce to subproperties so, *) (* e.g., ringS : subring_closed S can be used for *) (* the proof obligations of all prerequisites. *) (* [ringMixin of R by <:] == ringType mixin for a subType whose base type is *) (* a ringType and whose predicate's canonical key *) (* is a SubringPred. *) (* --> As for zmodType predicates, Import DefaultKeying GRing.DefaultPred *) (* turns unresolved GRing.Pred unification constraints into proof *) (* obligations for basic closure assumptions. *) (* *) (* * ComRing (commutative Rings): *) (* comRingType == interface type for commutative ring structure. *) (* ComRingType R mulC == packs mulC into a comRingType; the carrier type *) (* R must have a ringType canonical structure. *) (* ComRingMixin mulA mulC mul1x mulDx == builds the mixin for a Ring (i.e., a *) (* *non commutative* ring), using the commutativity *) (* to reduce the number of proof obligagtions. *) (* [comRingType of R for S] == R-clone of the comRingType structure S. *) (* [comRingType of R] == clone of a canonical comRingType structure on R. *) (* [comRingMixin of R by <:] == comutativity mixin axiom for R when it is a *) (* subType of a commutative ring. *) (* *) (* * UnitRing (Rings whose units have computable inverses): *) (* unitRingType == interface type for the UnitRing structure. *) (* UnitRingMixin mulVr mulrV unitP inv0id == builds the mixin for a UnitRing *) (* from the properties of the inverse operation and *) (* the boolean test for being a unit (invertible). *) (* The inverse of a non-unit x is constrained to be *) (* x itself (property inv0id). The carrier type *) (* must have a ringType canonical structure. *) (* UnitRingType R m == packs the unit ring mixin m into a unitRingType. *) (* WARNING: while it is possible to omit R for most of the *) (* XxxType functions, R MUST be explicitly given *) (* when UnitRingType is used with a mixin produced *) (* by ComUnitRingMixin, otherwise the resulting *) (* structure will have the WRONG sort key and will *) (* NOT BE USED during type inference. *) (* [unitRingType of R for S] == R-clone of the unitRingType structure S. *) (* [unitRingType of R] == clones a canonical unitRingType structure on R. *) (* x \is a GRing.unit <=> x is a unit (i.e., has an inverse). *) (* x^-1 == the ring inverse of x, if x is a unit, else x. *) (* x / y == x divided by y (notation for x * y^-1). *) (* x ^- n := notation for (x ^+ n)^-1, the inverse of x ^+ n. *) (* invr_closed S <-> collective predicate S is closed under inverse. *) (* divr_closed S <-> collective predicate S is closed under division *) (* (1 and x / y in S). *) (* sdivr_closed S <-> collective predicate S is closed under division *) (* and opposite (-1 and x / y in S, for x, y in S). *) (* divring_closed S <-> collective predicate S is closed under unitRing *) (* operations (1, x - y and x / y in S). *) (* DivrPred invS == packs invS : mulr_closed S into a divrPred S, *) (* SdivrPred invS sdivrPred S or divringPred S interface structure, *) (* DivringPred invS corresponding to the above properties, resp., *) (* provided S already has the supplementary ringType *) (* closure properties. The properties above coerce *) (* to subproperties, as explained above. *) (* [unitRingMixin of R by <:] == unitRingType mixin for a subType whose base *) (* type is a unitRingType and whose predicate's *) (* canonical key is a divringPred and whose ring *) (* structure is compatible with the base type's. *) (* *) (* * ComUnitRing (commutative rings with computable inverses): *) (* comUnitRingType == interface type for ComUnitRing structure. *) (* ComUnitRingMixin mulVr unitP inv0id == builds the mixin for a UnitRing (a *) (* *non commutative* unit ring, using commutativity *) (* to simplify the proof obligations; the carrier *) (* type must have a comRingType structure. *) (* WARNING: ALWAYS give an explicit type argument *) (* to UnitRingType along with a mixin produced by *) (* ComUnitRingMixin (see above). *) (* [comUnitRingType of R] == a comUnitRingType structure for R created by *) (* merging canonical comRingType and unitRingType *) (* structures on R. *) (* *) (* * IntegralDomain (integral, commutative, ring with partial inverses): *) (* idomainType == interface type for the IntegralDomain structure. *) (* IdomainType R mulf_eq0 == packs the integrality property into an *) (* idomainType integral domain structure; R must *) (* have a comUnitRingType canonical structure. *) (* [idomainType of R for S] == R-clone of the idomainType structure S. *) (* [idomainType of R] == clone of a canonical idomainType structure on R. *) (* [idomainMixin of R by <:] == mixin axiom for a idomain subType. *) (* *) (* * Field (commutative fields): *) (* fieldType == interface type for fields. *) (* GRing.Field.axiom inv == the field axiom (x != 0 -> inv x * x = 1). *) (* FieldUnitMixin mulVx unitP inv0id == builds a *non commutative unit ring* *) (* mixin, using the field axiom to simplify proof *) (* obligations. The carrier type must have a *) (* comRingType canonical structure. *) (* FieldMixin mulVx == builds the field mixin from the field axiom. The *) (* carrier type must have a comRingType structure. *) (* FieldIdomainMixin m == builds an *idomain* mixin from a field mixin m. *) (* FieldType R m == packs the field mixin M into a fieldType. The *) (* carrier type R must be an idomainType. *) (* [fieldType of F for S] == F-clone of the fieldType structure S. *) (* [fieldType of F] == clone of a canonical fieldType structure on F. *) (* [fieldMixin of R by <:] == mixin axiom for a field subType. *) (* *) (* * DecidableField (fields with a decidable first order theory): *) (* decFieldType == interface type for DecidableField structure. *) (* DecFieldMixin satP == builds the mixin for a DecidableField from the *) (* correctness of its satisfiability predicate. The *) (* carrier type must have a unitRingType structure. *) (* DecFieldType F m == packs the decidable field mixin m into a *) (* decFieldType; the carrier type F must have a *) (* fieldType structure. *) (* [decFieldType of F for S] == F-clone of the decFieldType structure S. *) (* [decFieldType of F] == clone of a canonical decFieldType structure on F *) (* GRing.term R == the type of formal expressions in a unit ring R *) (* with formal variables 'X_k, k : nat, and *) (* manifest constants x%:T, x : R. The notation of *) (* all the ring operations is redefined for terms, *) (* in scope %T. *) (* GRing.formula R == the type of first order formulas over R; the %T *) (* scope binds the logical connectives /\, \/, ~, *) (* ==>, ==, and != to formulae; GRing.True/False *) (* and GRing.Bool b denote constant formulae, and *) (* quantifiers are written 'forall/'exists 'X_k, f. *) (* GRing.Unit x tests for ring units *) (* GRing.If p_f t_f e_f emulates if-then-else *) (* GRing.Pick p_f t_f e_f emulates fintype.pick *) (* foldr GRing.Exists/Forall q_f xs can be used *) (* to write iterated quantifiers. *) (* GRing.eval e t == the value of term t with valuation e : seq R *) (* (e maps 'X_i to e`_i). *) (* GRing.same_env e1 e2 <-> environments e1 and e2 are extensionally equal. *) (* GRing.qf_form f == f is quantifier-free. *) (* GRing.holds e f == the intuitionistic CiC interpretation of the *) (* formula f holds with valuation e. *) (* GRing.qf_eval e f == the value (in bool) of a quantifier-free f. *) (* GRing.sat e f == valuation e satisfies f (only in a decField). *) (* GRing.sol n f == a sequence e of size n such that e satisfies f, *) (* if one exists, or [::] if there is no such e. *) (* QEdecFieldMixin wfP okP == a decidable field Mixin built from a quantifier *) (* eliminator p and proofs wfP : GRing.wf_QE_proj p *) (* and okP : GRing.valid_QE_proj p that p returns *) (* well-formed and valid formulae, i.e., p i (u, v) *) (* is a quantifier-free formula equivalent to *) (* 'exists 'X_i, u1 == 0 /\ ... /\ u_m == 0 /\ v1 != 0 ... /\ v_n != 0 *) (* *) (* * ClosedField (algebraically closed fields): *) (* closedFieldType == interface type for the ClosedField structure. *) (* ClosedFieldType F m == packs the closed field mixin m into a *) (* closedFieldType. The carrier F must have a *) (* decFieldType structure. *) (* [closedFieldType of F on S] == F-clone of a closedFieldType structure S. *) (* [closedFieldType of F] == clone of a canonicalclosedFieldType structure *) (* on F. *) (* *) (* * Lmodule (module with left multiplication by external scalars). *) (* lmodType R == interface type for an Lmodule structure with *) (* scalars of type R; R must have a ringType *) (* structure. *) (* LmodMixin scalA scal1v scalxD scalDv == builds an Lmodule mixin from the *) (* algebraic properties of the scaling operation; *) (* the module carrier type must have a zmodType *) (* structure, and the scalar carrier must have a *) (* ringType structure. *) (* LmodType R V m == packs the mixin v to build an Lmodule of type *) (* lmodType R. The carrier type V must have a *) (* zmodType structure. *) (* [lmodType R of V for S] == V-clone of an lmodType R structure S. *) (* [lmodType R of V] == clone of a canonical lmodType R structure on V. *) (* a *: v == v scaled by a, when v is in an Lmodule V and a *) (* is in the scalar Ring of V. *) (* scaler_closed S <-> collective predicate S is closed under scaling. *) (* linear_closed S <-> collective predicate S is closed under linear *) (* combinations (a *: u + v in S when u, v in S). *) (* submod_closed S <-> collective predicate S is closed under lmodType *) (* operations (0 and a *: u + v in S). *) (* SubmodPred scaleS == packs scaleS : scaler_closed S in a submodPred S *) (* interface structure corresponding to the above *) (* property, provided S's key is a zmodPred; *) (* submod_closed coerces to all the prerequisites. *) (* [lmodMixin of V by <:] == mixin for a subType of an lmodType, whose *) (* predicate's key is a submodPred. *) (* *) (* * Lalgebra (left algebra, ring with scaling that associates on the left): *) (* lalgType R == interface type for Lalgebra structures with *) (* scalars in R; R must have ringType structure. *) (* LalgType R V scalAl == packs scalAl : k (x y) = (k x) y into an *) (* Lalgebra of type lalgType R. The carrier type V *) (* must have both lmodType R and ringType canonical *) (* structures. *) (* R^o == the regular algebra of R: R^o is convertible to *) (* R, but when R has a ringType structure then R^o *) (* extends it to an lalgType structure by letting R *) (* act on itself: if x : R and y : R^o then *) (* x *: y = x * (y : R). *) (* k%:A == the image of the scalar k in an L-algebra; this *) (* is simply notation for k *: 1. *) (* [lalgType R of V for S] == V-clone the lalgType R structure S. *) (* [lalgType R of V] == clone of a canonical lalgType R structure on V. *) (* subalg_closed S <-> collective predicate S is closed under lalgType *) (* operations (1, a *: u + v and u * v in S). *) (* SubalgPred scaleS == packs scaleS : scaler_closed S in a subalgPred S *) (* interface structure corresponding to the above *) (* property, provided S's key is a subringPred; *) (* subalg_closed coerces to all the prerequisites. *) (* [lalgMixin of V by <:] == mixin axiom for a subType of an lalgType. *) (* *) (* * Algebra (ring with scaling that associates both left and right): *) (* algType R == type for Algebra structure with scalars in R. *) (* R should be a commutative ring. *) (* AlgType R A scalAr == packs scalAr : k (x y) = x (k y) into an Algebra *) (* Structure of type algType R. The carrier type A *) (* must have an lalgType R structure. *) (* CommAlgType R A == creates an Algebra structure for an A that has *) (* both lalgType R and comRingType structures. *) (* [algType R of V for S] == V-clone of an algType R structure on S. *) (* [algType R of V] == clone of a canonical algType R structure on V. *) (* [algMixin of V by <:] == mixin axiom for a subType of an algType. *) (* *) (* * UnitAlgebra (algebra with computable inverses): *) (* unitAlgType R == interface type for UnitAlgebra structure with *) (* scalars in R; R should have a unitRingType *) (* structure. *) (* [unitAlgType R of V] == a unitAlgType R structure for V created by *) (* merging canonical algType and unitRingType on V. *) (* divalg_closed S <-> collective predicate S is closed under all *) (* unitAlgType operations (1, a *: u + v and u / v *) (* are in S fo u, v in S). *) (* DivalgPred scaleS == packs scaleS : scaler_closed S in a divalgPred S *) (* interface structure corresponding to the above *) (* property, provided S's key is a divringPred; *) (* divalg_closed coerces to all the prerequisites. *) (* *) (* In addition to this structure hierarchy, we also develop a separate, *) (* parallel hierarchy for morphisms linking these structures: *) (* *) (* * Additive (additive functions): *) (* additive f <-> f of type U -> V is additive, i.e., f maps the *) (* Zmodule structure of U to that of V, 0 to 0, *) (* - to - and + to + (equivalently, binary - to -). *) (* := {morph f : u v / u + v}. *) (* {additive U -> V} == the interface type for a Structure (keyed on *) (* a function f : U -> V) that encapsulates the *) (* additive property; both U and V must have *) (* zmodType canonical structures. *) (* Additive add_f == packs add_f : additive f into an additive *) (* function structure of type {additive U -> V}. *) (* [additive of f as g] == an f-clone of the additive structure on the *) (* function g -- f and g must be convertible. *) (* [additive of f] == a clone of an existing additive structure on f. *) (* *) (* * RMorphism (ring morphisms): *) (* multiplicative f <-> f of type R -> S is multiplicative, i.e., f *) (* maps 1 and * in R to 1 and * in S, respectively, *) (* R ans S must have canonical ringType structures. *) (* rmorphism f <-> f is a ring morphism, i.e., f is both additive *) (* and multiplicative. *) (* {rmorphism R -> S} == the interface type for ring morphisms, i.e., *) (* a Structure that encapsulates the rmorphism *) (* property for functions f : R -> S; both R and S *) (* must have ringType structures. *) (* RMorphism morph_f == packs morph_f : rmorphism f into a Ring morphism *) (* structure of type {rmorphism R -> S}. *) (* AddRMorphism mul_f == packs mul_f : multiplicative f into an rmorphism *) (* structure of type {rmorphism R -> S}; f must *) (* already have an {additive R -> S} structure. *) (* [rmorphism of f as g] == an f-clone of the rmorphism structure of g. *) (* [rmorphism of f] == a clone of an existing additive structure on f. *) (* -> If R and S are UnitRings the f also maps units to units and inverses *) (* of units to inverses; if R is a field then f if a field isomorphism *) (* between R and its image. *) (* -> As rmorphism coerces to both additive and multiplicative, all *) (* structures for f can be built from a single proof of rmorphism f. *) (* -> Additive properties (raddf_suffix, see below) are duplicated and *) (* specialised for RMorphism (as rmorph_suffix). This allows more *) (* precise rewriting and cleaner chaining: although raddf lemmas will *) (* recognize RMorphism functions, the converse will not hold (we cannot *) (* add reverse inheritance rules because of incomplete backtracking in *) (* the Canonical Projection unification), so one would have to insert a *) (* /= every time one switched from additive to multiplicative rules. *) (* -> The property duplication also means that it is not strictly necessary *) (* to declare all Additive instances. *) (* *) (* * Linear (linear functions): *) (* scalable f <-> f of type U -> V is scalable, i.e., f morphs *) (* scaling on U to scaling on V, a *: _ to a *: _. *) (* U and V must both have lmodType R structures, *) (* for the same ringType R. *) (* scalable_for s f <-> f is scalable for scaling operator s, i.e., *) (* f morphs a *: _ to s a _; the range of f only *) (* need to be a zmodType. The scaling operator s *) (* should be one of *:%R (see scalable, above), *%R *) (* or a combination nu \; *%R or nu \; *:%R with *) (* nu : {rmorphism _}; otherwise some of the theory *) (* (e.g., the linearZ rule) will not apply. *) (* linear f <-> f of type U -> V is linear, i.e., f morphs *) (* linear combinations a *: u + v in U to similar *) (* linear combinations in V; U and V must both have *) (* lmodType R structures, for the same ringType R. *) (* := forall a, {morph f: u v / a *: u + v}. *) (* scalar f <-> f of type U -> R is a scalar function, i.e., *) (* f (a *: u + v) = a * f u + f v. *) (* linear_for s f <-> f is linear for the scaling operator s, i.e., *) (* f (a *: u + v) = s a (f u) + f v. The range of f *) (* only needs to be a zmodType, but s MUST be of *) (* the form described in in scalable_for paragraph *) (* for this predicate to type check. *) (* lmorphism f <-> f is both additive and scalable. This is in *) (* fact equivalent to linear f, although somewhat *) (* less convenient to prove. *) (* lmorphism_for s f <-> f is both additive and scalable for s. *) (* {linear U -> V} == the interface type for linear functions, i.e., a *) (* Structure that encapsulates the linear property *) (* for functions f : U -> V; both U and V must have *) (* lmodType R structures, for the same R. *) (* {scalar U} == the interface type for scalar functions, of type *) (* U -> R where U has an lmodType R structure. *) (* {linear U -> V | s} == the interface type for functions linear for s. *) (* Linear lin_f == packs lin_f : lmorphism_for s f into a linear *) (* function structure of type {linear U -> V | s}. *) (* As linear_for s f coerces to lmorphism_for s f, *) (* Linear can be used with lin_f : linear_for s f *) (* (indeed, that is the recommended usage). Note *) (* that as linear f, scalar f, {linear U -> V} and *) (* {scalar U} are simply notation for corresponding *) (* generic "_for" forms, Linear can be used for any *) (* of these special cases, transparantly. *) (* AddLinear scal_f == packs scal_f : scalable_for s f into a *) (* {linear U -> V | s} structure; f must already *) (* have an additive structure; as with Linear, *) (* AddLinear can be used with lin_f : linear f, etc *) (* [linear of f as g] == an f-clone of the linear structure of g. *) (* [linear of f] == a clone of an existing linear structure on f. *) (* (a *: u)%Rlin == transient forms that simplifiy to a *: u, a * u, *) (* (a * u)%Rlin nu a *: u, and nu a * u, respectively, and are *) (* (a *:^nu u)%Rlin created by rewriting with the linearZ lemma. The *) (* (a *^nu u)%Rlin forms allows the RHS of linearZ to be matched *) (* reliably, using the GRing.Scale.law structure. *) (* -> Similarly to Ring morphisms, additive properties are specialized for *) (* linear functions. *) (* -> Although {scalar U} is convertible to {linear U -> R^o}, it does not *) (* actually use R^o, so that rewriting preserves the canonical structure *) (* of the range of scalar functions. *) (* -> The generic linearZ lemma uses a set of bespoke interface structures to *) (* ensure that both left-to-right and right-to-left rewriting work even in *) (* the presence of scaling functions that simplify non-trivially (e.g., *) (* idfun \; *%R). Because most of the canonical instances and projections *) (* are coercions the machinery will be mostly invisible (with only the *) (* {linear ...} structure and %Rlin notations showing), but users should *) (* beware that in (a *: f u)%Rlin, a actually occurs in the f u subterm. *) (* -> The simpler linear_LR, or more specialized linearZZ and scalarZ rules *) (* should be used instead of linearZ if there are complexity issues, as *) (* well as for explicit forward and backward application, as the main *) (* parameter of linearZ is a proper sub-interface of {linear fUV | s}. *) (* *) (* * LRMorphism (linear ring morphisms, i.e., algebra morphisms): *) (* lrmorphism f <-> f of type A -> B is a linear Ring (Algebra) *) (* morphism: f is both additive, multiplicative and *) (* scalable. A and B must both have lalgType R *) (* canonical structures, for the same ringType R. *) (* lrmorphism_for s f <-> f a linear Ring morphism for the scaling *) (* operator s: f is additive, multiplicative and *) (* scalable for s. A must be an lalgType R, but B *) (* only needs to have a ringType structure. *) (* {lrmorphism A -> B} == the interface type for linear morphisms, i.e., a *) (* Structure that encapsulates the lrmorphism *) (* property for functions f : A -> B; both A and B *) (* must have lalgType R structures, for the same R. *) (* {lrmorphism A -> B | s} == the interface type for morphisms linear for s. *) (* LRmorphism lrmorph_f == packs lrmorph_f : lrmorphism_for s f into a *) (* linear morphism structure of type *) (* {lrmorphism A -> B | s}. Like Linear, LRmorphism *) (* can be used transparently for lrmorphism f. *) (* AddLRmorphism scal_f == packs scal_f : scalable_for s f into a linear *) (* morphism structure of type *) (* {lrmorphism A -> B | s}; f must already have an *) (* {rmorphism A -> B} structure, and AddLRmorphism *) (* can be applied to a linear_for s f, linear f, *) (* scalar f, etc argument, like AddLinear. *) (* [lrmorphism of f] == creates an lrmorphism structure from existing *) (* rmorphism and linear structures on f; this is *) (* the preferred way of creating lrmorphism *) (* structures. *) (* -> Linear and rmorphism properties do not need to be specialized for *) (* as we supply inheritance join instances in both directions. *) (* Finally we supply some helper notation for morphisms: *) (* x^f == the image of x under some morphism. This *) (* notation is only reserved (not defined) here; *) (* it is bound locally in sections where some *) (* morphism is used heavily (e.g., the container *) (* morphism in the parametricity sections of poly *) (* and matrix, or the Frobenius section here). *) (* \0 == the constant null function, which has a *) (* canonical linear structure, and simplifies on *) (* application (see ssrfun.v). *) (* f \+ g == the additive composition of f and g, i.e., the *) (* function x |-> f x + g x; f \+ g is canonically *) (* linear when f and g are, and simplifies on *) (* application (see ssrfun.v). *) (* f \- g == the function x |-> f x - g x, canonically *) (* linear when f and g are, and simplifies on *) (* application. *) (* k \*: f == the function x |-> k *: f x, which is *) (* canonically linear when f is and simplifies on *) (* application (this is a shorter alternative to *) (* *:%R k \o f). *) (* GRing.in_alg A == the ring morphism that injects R into A, where A *) (* has an lalgType R structure; GRing.in_alg A k *) (* simplifies to k%:A. *) (* a \*o f == the function x |-> a * f x, canonically linear *) (* linear when f is and its codomain is an algType *) (* and which simplifies on application. *) (* a \o* f == the function x |-> f x * a, canonically linear *) (* linear when f is and its codomain is an lalgType *) (* and which simplifies on application. *) (* The Lemmas about these structures are contained in both the GRing module *) (* and in the submodule GRing.Theory, which can be imported when unqualified *) (* access to the theory is needed (GRing.Theory also allows the unqualified *) (* use of additive, linear, Linear, etc). The main GRing module should NOT be *) (* imported. *) (* Notations are defined in scope ring_scope (delimiter %R), except term *) (* and formula notations, which are in term_scope (delimiter %T). *) (* This library also extends the conventional suffixes described in library *) (* ssrbool.v with the following: *) (* 0 -- ring 0, as in addr0 : x + 0 = x. *) (* 1 -- ring 1, as in mulr1 : x * 1 = x. *) (* D -- ring addition, as in linearD : f (u + v) = f u + f v. *) (* B -- ring substraction, as in opprB : - (x - y) = y - x. *) (* M -- ring multiplication, as in invfM : (x * y)^-1 = x^-1 * y^-1. *) (* Mn -- ring by nat multiplication, as in raddfMn : f (x *+ n) = f x *+ n. *) (* N -- ring opposite, as in mulNr : (- x) * y = - (x * y). *) (* V -- ring inverse, as in mulVr : x^-1 * x = 1. *) (* X -- ring exponentiation, as in rmorphX : f (x ^+ n) = f x ^+ n. *) (* Z -- (left) module scaling, as in linearZ : f (a *: v) = s *: f v. *) (* The operator suffixes D, B, M and X are also used for the corresponding *) (* operations on nat, as in natrX : (m ^ n)%:R = m%:R ^+ n. For the binary *) (* power operator, a trailing "n" suffix is used to indicate the operator *) (* suffix applies to the left-hand ring argument, as in *) (* expr1n : 1 ^+ n = 1 vs. expr1 : x ^+ 1 = x. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Reserved Notation "+%R" (at level 0). Reserved Notation "-%R" (at level 0). Reserved Notation "*%R" (at level 0, format " *%R"). Reserved Notation "*:%R" (at level 0, format " *:%R"). Reserved Notation "n %:R" (at level 2, left associativity, format "n %:R"). Reserved Notation "k %:A" (at level 2, left associativity, format "k %:A"). Reserved Notation "[ 'char' F ]" (at level 0, format "[ 'char' F ]"). Reserved Notation "x %:T" (at level 2, left associativity, format "x %:T"). Reserved Notation "''X_' i" (at level 8, i at level 2, format "''X_' i"). (* Patch for recurring Coq parser bug: Coq seg faults when a level 200 *) (* notation is used as a pattern. *) Reserved Notation "''exists' ''X_' i , f" (at level 199, i at level 2, right associativity, format "'[hv' ''exists' ''X_' i , '/ ' f ']'"). Reserved Notation "''forall' ''X_' i , f" (at level 199, i at level 2, right associativity, format "'[hv' ''forall' ''X_' i , '/ ' f ']'"). Reserved Notation "x ^f" (at level 2, left associativity, format "x ^f"). Reserved Notation "\0" (at level 0). Reserved Notation "f \+ g" (at level 50, left associativity). Reserved Notation "f \- g" (at level 50, left associativity). Reserved Notation "a \*o f" (at level 40). Reserved Notation "a \o* f" (at level 40). Reserved Notation "a \*: f" (at level 40). Delimit Scope ring_scope with R. Delimit Scope term_scope with T. Local Open Scope ring_scope. Module Import GRing. Import Monoid.Theory. Module Zmodule. Record mixin_of (V : Type) : Type := Mixin { zero : V; opp : V -> V; add : V -> V -> V; _ : associative add; _ : commutative add; _ : left_id zero add; _ : left_inverse zero opp add }. Section ClassDef. Record class_of T := Class { base : Choice.class_of T; mixin : mixin_of T }. Local Coercion base : class_of >-> Choice.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack m := fun bT b & phant_id (Choice.class bT) b => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> Choice.class_of. Coercion mixin : class_of >-> mixin_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Notation zmodType := type. Notation ZmodType T m := (@pack T m _ _ id). Notation ZmodMixin := Mixin. Notation "[ 'zmodType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'zmodType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'zmodType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'zmodType' 'of' T ]") : form_scope. End Exports. End Zmodule. Import Zmodule.Exports. Definition zero V := Zmodule.zero (Zmodule.class V). Definition opp V := Zmodule.opp (Zmodule.class V). Definition add V := Zmodule.add (Zmodule.class V). Local Notation "0" := (zero _) : ring_scope. Local Notation "-%R" := (@opp _) : ring_scope. Local Notation "- x" := (opp x) : ring_scope. Local Notation "+%R" := (@add _) : ring_scope. Local Notation "x + y" := (add x y) : ring_scope. Local Notation "x - y" := (x + - y) : ring_scope. Definition natmul V x n := nosimpl iterop _ n +%R x (zero V). Local Notation "x *+ n" := (natmul x n) : ring_scope. Local Notation "x *- n" := (- (x *+ n)) : ring_scope. Local Notation "\sum_ ( i <- r | P ) F" := (\big[+%R/0]_(i <- r | P) F). Local Notation "\sum_ ( m <= i < n ) F" := (\big[+%R/0]_(m <= i < n) F). Local Notation "\sum_ ( i < n ) F" := (\big[+%R/0]_(i < n) F). Local Notation "\sum_ ( i 'in' A ) F" := (\big[+%R/0]_(i in A) F). Local Notation "s `_ i" := (nth 0 s i) : ring_scope. Section ZmoduleTheory. Variable V : zmodType. Implicit Types x y : V. Lemma addrA : @associative V +%R. Proof. by case V => T [? []]. Qed. Lemma addrC : @commutative V V +%R. Proof. by case V => T [? []]. Qed. Lemma add0r : @left_id V V 0 +%R. Proof. by case V => T [? []]. Qed. Lemma addNr : @left_inverse V V V 0 -%R +%R. Proof. by case V => T [? []]. Qed. Lemma addr0 : @right_id V V 0 +%R. Proof. by move=> x; rewrite addrC add0r. Qed. Lemma addrN : @right_inverse V V V 0 -%R +%R. Proof. by move=> x; rewrite addrC addNr. Qed. Definition subrr := addrN. Canonical add_monoid := Monoid.Law addrA add0r addr0. Canonical add_comoid := Monoid.ComLaw addrC. Lemma addrCA : @left_commutative V V +%R. Proof. exact: mulmCA. Qed. Lemma addrAC : @right_commutative V V +%R. Proof. exact: mulmAC. Qed. Lemma addrACA : @interchange V +%R +%R. Proof. exact: mulmACA. Qed. Lemma addKr : @left_loop V V -%R +%R. Proof. by move=> x y; rewrite addrA addNr add0r. Qed. Lemma addNKr : @rev_left_loop V V -%R +%R. Proof. by move=> x y; rewrite addrA addrN add0r. Qed. Lemma addrK : @right_loop V V -%R +%R. Proof. by move=> x y; rewrite -addrA addrN addr0. Qed. Lemma addrNK : @rev_right_loop V V -%R +%R. Proof. by move=> x y; rewrite -addrA addNr addr0. Qed. Definition subrK := addrNK. Lemma addrI : @right_injective V V V +%R. Proof. move=> x; exact: can_inj (addKr x). Qed. Lemma addIr : @left_injective V V V +%R. Proof. move=> y; exact: can_inj (addrK y). Qed. Lemma opprK : @involutive V -%R. Proof. by move=> x; apply: (@addIr (- x)); rewrite addNr addrN. Qed. Lemma oppr_inj : @injective V V -%R. Proof. exact: inv_inj opprK. Qed. Lemma oppr0 : -0 = 0 :> V. Proof. by rewrite -[-0]add0r subrr. Qed. Lemma oppr_eq0 x : (- x == 0) = (x == 0). Proof. by rewrite (inv_eq opprK) oppr0. Qed. Lemma subr0 x : x - 0 = x. Proof. by rewrite oppr0 addr0. Qed. Lemma sub0r x : 0 - x = - x. Proof. by rewrite add0r. Qed. Lemma opprD : {morph -%R: x y / x + y : V}. Proof. by move=> x y; apply: (@addrI (x + y)); rewrite addrA subrr addrAC addrK subrr. Qed. Lemma opprB x y : - (x - y) = y - x. Proof. by rewrite opprD addrC opprK. Qed. Lemma subr_eq x y z : (x - z == y) = (x == y + z). Proof. exact: can2_eq (subrK z) (addrK z) x y. Qed. Lemma subr_eq0 x y : (x - y == 0) = (x == y). Proof. by rewrite subr_eq add0r. Qed. Lemma addr_eq0 x y : (x + y == 0) = (x == - y). Proof. by rewrite -[x == _]subr_eq0 opprK. Qed. Lemma eqr_opp x y : (- x == - y) = (x == y). Proof. exact: can_eq opprK x y. Qed. Lemma eqr_oppLR x y : (- x == y) = (x == - y). Proof. exact: inv_eq opprK x y. Qed. Lemma mulr0n x : x *+ 0 = 0. Proof. by []. Qed. Lemma mulr1n x : x *+ 1 = x. Proof. by []. Qed. Lemma mulr2n x : x *+ 2 = x + x. Proof. by []. Qed. Lemma mulrS x n : x *+ n.+1 = x + x *+ n. Proof. by case: n => //=; rewrite addr0. Qed. Lemma mulrSr x n : x *+ n.+1 = x *+ n + x. Proof. by rewrite addrC mulrS. Qed. Lemma mulrb x (b : bool) : x *+ b = (if b then x else 0). Proof. by case: b. Qed. Lemma mul0rn n : 0 *+ n = 0 :> V. Proof. by elim: n => // n IHn; rewrite mulrS add0r. Qed. Lemma mulNrn x n : (- x) *+ n = x *- n. Proof. by elim: n => [|n IHn]; rewrite ?oppr0 // !mulrS opprD IHn. Qed. Lemma mulrnDl n : {morph (fun x => x *+ n) : x y / x + y}. Proof. move=> x y; elim: n => [|n IHn]; rewrite ?addr0 // !mulrS. by rewrite addrCA -!addrA -IHn -addrCA. Qed. Lemma mulrnDr x m n : x *+ (m + n) = x *+ m + x *+ n. Proof. elim: m => [|m IHm]; first by rewrite add0r. by rewrite !mulrS IHm addrA. Qed. Lemma mulrnBl n : {morph (fun x => x *+ n) : x y / x - y}. Proof. move=> x y; elim: n => [|n IHn]; rewrite ?subr0 // !mulrS -!addrA; congr(_ + _). by rewrite addrC IHn -!addrA opprD [_ - y]addrC. Qed. Lemma mulrnBr x m n : n <= m -> x *+ (m - n) = x *+ m - x *+ n. Proof. elim: m n => [|m IHm] [|n le_n_m]; rewrite ?subr0 // {}IHm //. by rewrite mulrSr mulrS opprD addrA addrK. Qed. Lemma mulrnA x m n : x *+ (m * n) = x *+ m *+ n. Proof. by rewrite mulnC; elim: n => //= n IHn; rewrite mulrS mulrnDr IHn. Qed. Lemma mulrnAC x m n : x *+ m *+ n = x *+ n *+ m. Proof. by rewrite -!mulrnA mulnC. Qed. Lemma sumrN I r P (F : I -> V) : (\sum_(i <- r | P i) - F i = - (\sum_(i <- r | P i) F i)). Proof. by rewrite (big_morph _ opprD oppr0). Qed. Lemma sumrB I r (P : pred I) (F1 F2 : I -> V) : \sum_(i <- r | P i) (F1 i - F2 i) = \sum_(i <- r | P i) F1 i - \sum_(i <- r | P i) F2 i. Proof. by rewrite -sumrN -big_split /=. Qed. Lemma sumrMnl I r P (F : I -> V) n : \sum_(i <- r | P i) F i *+ n = (\sum_(i <- r | P i) F i) *+ n. Proof. by rewrite (big_morph _ (mulrnDl n) (mul0rn _)). Qed. Lemma sumrMnr x I r P (F : I -> nat) : \sum_(i <- r | P i) x *+ F i = x *+ (\sum_(i <- r | P i) F i). Proof. by rewrite (big_morph _ (mulrnDr x) (erefl _)). Qed. Lemma sumr_const (I : finType) (A : pred I) (x : V) : \sum_(i in A) x = x *+ #|A|. Proof. by rewrite big_const -iteropE. Qed. Lemma telescope_sumr n m (f : nat -> V) : n <= m -> \sum_(n <= k < m) (f k.+1 - f k) = f m - f n. Proof. rewrite leq_eqVlt => /predU1P[-> | ]; first by rewrite subrr big_geq. case: m => // m lenm; rewrite sumrB big_nat_recr // big_nat_recl //=. by rewrite addrC opprD addrA subrK addrC. Qed. Section ClosedPredicates. Variable S : predPredType V. Definition addr_closed := 0 \in S /\ {in S &, forall u v, u + v \in S}. Definition oppr_closed := {in S, forall u, - u \in S}. Definition subr_2closed := {in S &, forall u v, u - v \in S}. Definition zmod_closed := 0 \in S /\ subr_2closed. Lemma zmod_closedN : zmod_closed -> oppr_closed. Proof. by case=> S0 SB y Sy; rewrite -sub0r !SB. Qed. Lemma zmod_closedD : zmod_closed -> addr_closed. Proof. by case=> S0 SB; split=> // y z Sy Sz; rewrite -[z]opprK -[- z]sub0r !SB. Qed. End ClosedPredicates. End ZmoduleTheory. Implicit Arguments addrI [[V] x1 x2]. Implicit Arguments addIr [[V] x1 x2]. Implicit Arguments oppr_inj [[V] x1 x2]. Module Ring. Record mixin_of (R : zmodType) : Type := Mixin { one : R; mul : R -> R -> R; _ : associative mul; _ : left_id one mul; _ : right_id one mul; _ : left_distributive mul +%R; _ : right_distributive mul +%R; _ : one != 0 }. Definition EtaMixin R one mul mulA mul1x mulx1 mul_addl mul_addr nz1 := let _ := @Mixin R one mul mulA mul1x mulx1 mul_addl mul_addr nz1 in @Mixin (Zmodule.Pack (Zmodule.class R) R) _ _ mulA mul1x mulx1 mul_addl mul_addr nz1. Section ClassDef. Record class_of (R : Type) : Type := Class { base : Zmodule.class_of R; mixin : mixin_of (Zmodule.Pack base R) }. Local Coercion base : class_of >-> Zmodule.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack b0 (m0 : mixin_of (@Zmodule.Pack T b0 T)) := fun bT b & phant_id (Zmodule.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> Zmodule.class_of. Coercion mixin : class_of >-> mixin_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Notation ringType := type. Notation RingType T m := (@pack T _ m _ _ id _ id). Notation RingMixin := Mixin. Notation "[ 'ringType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'ringType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'ringType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'ringType' 'of' T ]") : form_scope. End Exports. End Ring. Import Ring.Exports. Definition one (R : ringType) : R := Ring.one (Ring.class R). Definition mul (R : ringType) : R -> R -> R := Ring.mul (Ring.class R). Definition exp R x n := nosimpl iterop _ n (@mul R) x (one R). Notation sign R b := (exp (- one R) (nat_of_bool b)) (only parsing). Definition comm R x y := @mul R x y = mul y x. Definition lreg R x := injective (@mul R x). Definition rreg R x := injective ((@mul R)^~ x). Local Notation "1" := (one _) : ring_scope. Local Notation "- 1" := (- (1)) : ring_scope. Local Notation "n %:R" := (1 *+ n) : ring_scope. Local Notation "*%R" := (@mul _). Local Notation "x * y" := (mul x y) : ring_scope. Local Notation "x ^+ n" := (exp x n) : ring_scope. Local Notation "\prod_ ( i <- r | P ) F" := (\big[*%R/1]_(i <- r | P) F). Local Notation "\prod_ ( i | P ) F" := (\big[*%R/1]_(i | P) F). Local Notation "\prod_ ( i 'in' A ) F" := (\big[*%R/1]_(i in A) F). Local Notation "\prod_ ( m <= i < n ) F" := (\big[*%R/1%R]_(m <= i < n) F%R). (* The ``field'' characteristic; the definition, and many of the theorems, *) (* has to apply to rings as well; indeed, we need the Frobenius automorphism *) (* results for a non commutative ring in the proof of Gorenstein 2.6.3. *) Definition char (R : Ring.type) of phant R : nat_pred := [pred p | prime p & p%:R == 0 :> R]. Local Notation "[ 'char' R ]" := (char (Phant R)) : ring_scope. (* Converse ring tag. *) Definition converse R : Type := R. Local Notation "R ^c" := (converse R) (at level 2, format "R ^c") : type_scope. Section RingTheory. Variable R : ringType. Implicit Types x y : R. Lemma mulrA : @associative R *%R. Proof. by case R => T [? []]. Qed. Lemma mul1r : @left_id R R 1 *%R. Proof. by case R => T [? []]. Qed. Lemma mulr1 : @right_id R R 1 *%R. Proof. by case R => T [? []]. Qed. Lemma mulrDl : @left_distributive R R *%R +%R. Proof. by case R => T [? []]. Qed. Lemma mulrDr : @right_distributive R R *%R +%R. Proof. by case R => T [? []]. Qed. Lemma oner_neq0 : 1 != 0 :> R. Proof. by case R => T [? []]. Qed. Lemma oner_eq0 : (1 == 0 :> R) = false. Proof. exact: negbTE oner_neq0. Qed. Lemma mul0r : @left_zero R R 0 *%R. Proof. by move=> x; apply: (addIr (1 * x)); rewrite -mulrDl !add0r mul1r. Qed. Lemma mulr0 : @right_zero R R 0 *%R. Proof. by move=> x; apply: (addIr (x * 1)); rewrite -mulrDr !add0r mulr1. Qed. Lemma mulrN x y : x * (- y) = - (x * y). Proof. by apply: (addrI (x * y)); rewrite -mulrDr !subrr mulr0. Qed. Lemma mulNr x y : (- x) * y = - (x * y). Proof. by apply: (addrI (x * y)); rewrite -mulrDl !subrr mul0r. Qed. Lemma mulrNN x y : (- x) * (- y) = x * y. Proof. by rewrite mulrN mulNr opprK. Qed. Lemma mulN1r x : -1 * x = - x. Proof. by rewrite mulNr mul1r. Qed. Lemma mulrN1 x : x * -1 = - x. Proof. by rewrite mulrN mulr1. Qed. Canonical mul_monoid := Monoid.Law mulrA mul1r mulr1. Canonical muloid := Monoid.MulLaw mul0r mulr0. Canonical addoid := Monoid.AddLaw mulrDl mulrDr. Lemma mulr_suml I r P (F : I -> R) x : (\sum_(i <- r | P i) F i) * x = \sum_(i <- r | P i) F i * x. Proof. exact: big_distrl. Qed. Lemma mulr_sumr I r P (F : I -> R) x : x * (\sum_(i <- r | P i) F i) = \sum_(i <- r | P i) x * F i. Proof. exact: big_distrr. Qed. Lemma mulrBl x y z : (y - z) * x = y * x - z * x. Proof. by rewrite mulrDl mulNr. Qed. Lemma mulrBr x y z : x * (y - z) = x * y - x * z. Proof. by rewrite mulrDr mulrN. Qed. Lemma mulrnAl x y n : (x *+ n) * y = (x * y) *+ n. Proof. by elim: n => [|n IHn]; rewrite ?mul0r // !mulrS mulrDl IHn. Qed. Lemma mulrnAr x y n : x * (y *+ n) = (x * y) *+ n. Proof. by elim: n => [|n IHn]; rewrite ?mulr0 // !mulrS mulrDr IHn. Qed. Lemma mulr_natl x n : n%:R * x = x *+ n. Proof. by rewrite mulrnAl mul1r. Qed. Lemma mulr_natr x n : x * n%:R = x *+ n. Proof. by rewrite mulrnAr mulr1. Qed. Lemma natrD m n : (m + n)%:R = m%:R + n%:R :> R. Proof. exact: mulrnDr. Qed. Lemma natrB m n : n <= m -> (m - n)%:R = m%:R - n%:R :> R. Proof. exact: mulrnBr. Qed. Definition natr_sum := big_morph (natmul 1) natrD (mulr0n 1). Lemma natrM m n : (m * n)%:R = m%:R * n%:R :> R. Proof. by rewrite mulrnA -mulr_natr. Qed. Lemma expr0 x : x ^+ 0 = 1. Proof. by []. Qed. Lemma expr1 x : x ^+ 1 = x. Proof. by []. Qed. Lemma expr2 x : x ^+ 2 = x * x. Proof. by []. Qed. Lemma exprS x n : x ^+ n.+1 = x * x ^+ n. Proof. by case: n => //; rewrite mulr1. Qed. Lemma expr0n n : 0 ^+ n = (n == 0%N)%:R :> R. Proof. by case: n => // n; rewrite exprS mul0r. Qed. Lemma expr1n n : 1 ^+ n = 1 :> R. Proof. by elim: n => // n IHn; rewrite exprS mul1r. Qed. Lemma exprD x m n : x ^+ (m + n) = x ^+ m * x ^+ n. Proof. by elim: m => [|m IHm]; rewrite ?mul1r // !exprS -mulrA -IHm. Qed. Lemma exprSr x n : x ^+ n.+1 = x ^+ n * x. Proof. by rewrite -addn1 exprD expr1. Qed. Lemma commr_sym x y : comm x y -> comm y x. Proof. by []. Qed. Lemma commr_refl x : comm x x. Proof. by []. Qed. Lemma commr0 x : comm x 0. Proof. by rewrite /comm mulr0 mul0r. Qed. Lemma commr1 x : comm x 1. Proof. by rewrite /comm mulr1 mul1r. Qed. Lemma commrN x y : comm x y -> comm x (- y). Proof. by move=> com_xy; rewrite /comm mulrN com_xy mulNr. Qed. Lemma commrN1 x : comm x (-1). Proof. apply: commrN; exact: commr1. Qed. Lemma commrD x y z : comm x y -> comm x z -> comm x (y + z). Proof. by rewrite /comm mulrDl mulrDr => -> ->. Qed. Lemma commrMn x y n : comm x y -> comm x (y *+ n). Proof. rewrite /comm => com_xy. by elim: n => [|n IHn]; rewrite ?commr0 // mulrS commrD. Qed. Lemma commrM x y z : comm x y -> comm x z -> comm x (y * z). Proof. by move=> com_xy; rewrite /comm mulrA com_xy -!mulrA => ->. Qed. Lemma commr_nat x n : comm x n%:R. Proof. by apply: commrMn; exact: commr1. Qed. Lemma commrX x y n : comm x y -> comm x (y ^+ n). Proof. rewrite /comm => com_xy. by elim: n => [|n IHn]; rewrite ?commr1 // exprS commrM. Qed. Lemma exprMn_comm x y n : comm x y -> (x * y) ^+ n = x ^+ n * y ^+ n. Proof. move=> com_xy; elim: n => /= [|n IHn]; first by rewrite mulr1. by rewrite !exprS IHn !mulrA; congr (_ * _); rewrite -!mulrA -commrX. Qed. Lemma commr_sign x n : comm x ((-1) ^+ n). Proof. exact: (commrX n (commrN1 x)). Qed. Lemma exprMn_n x m n : (x *+ m) ^+ n = x ^+ n *+ (m ^ n) :> R. Proof. elim: n => [|n IHn]; first by rewrite mulr1n. rewrite exprS IHn -mulr_natr -mulrA -commr_nat mulr_natr -mulrnA -expnSr. by rewrite -mulr_natr mulrA -exprS mulr_natr. Qed. Lemma exprM x m n : x ^+ (m * n) = x ^+ m ^+ n. Proof. elim: m => [|m IHm]; first by rewrite expr1n. by rewrite mulSn exprD IHm exprS exprMn_comm //; exact: commrX. Qed. Lemma exprAC x m n : (x ^+ m) ^+ n = (x ^+ n) ^+ m. Proof. by rewrite -!exprM mulnC. Qed. Lemma expr_mod n x i : x ^+ n = 1 -> x ^+ (i %% n) = x ^+ i. Proof. move=> xn1; rewrite {2}(divn_eq i n) exprD mulnC exprM xn1. by rewrite expr1n mul1r. Qed. Lemma expr_dvd n x i : x ^+ n = 1 -> n %| i -> x ^+ i = 1. Proof. by move=> xn1 dvd_n_i; rewrite -(expr_mod i xn1) (eqnP dvd_n_i). Qed. Lemma natrX n k : (n ^ k)%:R = n%:R ^+ k :> R. Proof. by rewrite exprMn_n expr1n. Qed. Lemma signr_odd n : (-1) ^+ (odd n) = (-1) ^+ n :> R. Proof. elim: n => //= n IHn; rewrite exprS -{}IHn. by case/odd: n; rewrite !mulN1r ?opprK. Qed. Lemma signr_eq0 n : ((-1) ^+ n == 0 :> R) = false. Proof. by rewrite -signr_odd; case: odd; rewrite ?oppr_eq0 oner_eq0. Qed. Lemma mulr_sign (b : bool) x : (-1) ^+ b * x = (if b then - x else x). Proof. by case: b; rewrite ?mulNr mul1r. Qed. Lemma signr_addb b1 b2 : (-1) ^+ (b1 (+) b2) = (-1) ^+ b1 * (-1) ^+ b2 :> R. Proof. by rewrite mulr_sign; case: b1 b2 => [] []; rewrite ?opprK. Qed. Lemma signrE (b : bool) : (-1) ^+ b = 1 - b.*2%:R :> R. Proof. by case: b; rewrite ?subr0 // opprD addNKr. Qed. Lemma signrN b : (-1) ^+ (~~ b) = - (-1) ^+ b :> R. Proof. by case: b; rewrite ?opprK. Qed. Lemma mulr_signM (b1 b2 : bool) x1 x2 : ((-1) ^+ b1 * x1) * ((-1) ^+ b2 * x2) = (-1) ^+ (b1 (+) b2) * (x1 * x2). Proof. by rewrite signr_addb -!mulrA; congr (_ * _); rewrite !mulrA commr_sign. Qed. Lemma exprNn x n : (- x) ^+ n = (-1) ^+ n * x ^+ n :> R. Proof. by rewrite -mulN1r exprMn_comm // /comm mulN1r mulrN mulr1. Qed. Lemma sqrrN x : (- x) ^+ 2 = x ^+ 2. Proof. exact: mulrNN. Qed. Lemma sqrr_sign n : ((-1) ^+ n) ^+ 2 = 1 :> R. Proof. by rewrite exprAC sqrrN !expr1n. Qed. Lemma signrMK n : @involutive R ( *%R ((-1) ^+ n)). Proof. by move=> x; rewrite mulrA -expr2 sqrr_sign mul1r. Qed. Lemma mulrI_eq0 x y : lreg x -> (x * y == 0) = (y == 0). Proof. by move=> reg_x; rewrite -{1}(mulr0 x) (inj_eq reg_x). Qed. Lemma lreg_neq0 x : lreg x -> x != 0. Proof. by move=> reg_x; rewrite -[x]mulr1 mulrI_eq0 ?oner_eq0. Qed. Lemma mulrI0_lreg x : (forall y, x * y = 0 -> y = 0) -> lreg x. Proof. move=> reg_x y z eq_xy_xz; apply/eqP; rewrite -subr_eq0 [y - z]reg_x //. by rewrite mulrBr eq_xy_xz subrr. Qed. Lemma lregN x : lreg x -> lreg (- x). Proof. by move=> reg_x y z; rewrite !mulNr => /oppr_inj/reg_x. Qed. Lemma lreg1 : lreg (1 : R). Proof. by move=> x y; rewrite !mul1r. Qed. Lemma lregM x y : lreg x -> lreg y -> lreg (x * y). Proof. by move=> reg_x reg_y z t; rewrite -!mulrA => /reg_x/reg_y. Qed. Lemma lregX x n : lreg x -> lreg (x ^+ n). Proof. by move=> reg_x; elim: n => [|n]; [exact: lreg1 | rewrite exprS; exact: lregM]. Qed. Lemma lreg_sign n : lreg ((-1) ^+ n : R). Proof. by apply: lregX; apply: lregN; apply: lreg1. Qed. Lemma prodr_const (I : finType) (A : pred I) (x : R) : \prod_(i in A) x = x ^+ #|A|. Proof. by rewrite big_const -iteropE. Qed. Lemma prodrXr x I r P (F : I -> nat) : \prod_(i <- r | P i) x ^+ F i = x ^+ (\sum_(i <- r | P i) F i). Proof. by rewrite (big_morph _ (exprD _) (erefl _)). Qed. Lemma prodrN (I : finType) (A : pred I) (F : I -> R) : \prod_(i in A) - F i = (- 1) ^+ #|A| * \prod_(i in A) F i. Proof. rewrite -sum1_card; elim/big_rec3: _ => [|i x n _ _ ->]; first by rewrite mulr1. by rewrite exprS !mulrA mulN1r !mulNr commrX //; apply: commrN1. Qed. Lemma prodrMn n (I : finType) (A : pred I) (F : I -> R) : \prod_(i in A) (F i *+ n) = \prod_(i in A) F i *+ n ^ #|A|. Proof. rewrite -sum1_card; elim/big_rec3: _ => // i x m _ _ ->. by rewrite mulrnAr mulrnAl expnS mulrnA. Qed. Lemma natr_prod I r P (F : I -> nat) : (\prod_(i <- r | P i) F i)%:R = \prod_(i <- r | P i) (F i)%:R :> R. Proof. exact: (big_morph _ natrM). Qed. Lemma exprDn_comm x y n (cxy : comm x y) : (x + y) ^+ n = \sum_(i < n.+1) (x ^+ (n - i) * y ^+ i) *+ 'C(n, i). Proof. elim: n => [|n IHn]; rewrite big_ord_recl mulr1 ?big_ord0 ?addr0 //=. rewrite exprS {}IHn /= mulrDl !big_distrr /= big_ord_recl mulr1 subn0. rewrite !big_ord_recr /= !binn !subnn !mul1r !subn0 bin0 !exprS -addrA. congr (_ + _); rewrite addrA -big_split /=; congr (_ + _). apply: eq_bigr => i _; rewrite !mulrnAr !mulrA -exprS -subSn ?(valP i) //. by rewrite subSS (commrX _ (commr_sym cxy)) -mulrA -exprS -mulrnDr. Qed. Lemma exprBn_comm x y n (cxy : comm x y) : (x - y) ^+ n = \sum_(i < n.+1) ((-1) ^+ i * x ^+ (n - i) * y ^+ i) *+ 'C(n, i). Proof. rewrite exprDn_comm; last exact: commrN. by apply: eq_bigr => i _; congr (_ *+ _); rewrite -commr_sign -mulrA -exprNn. Qed. Lemma subrXX_comm x y n (cxy : comm x y) : x ^+ n - y ^+ n = (x - y) * (\sum_(i < n) x ^+ (n.-1 - i) * y ^+ i). Proof. case: n => [|n]; first by rewrite big_ord0 mulr0 subrr. rewrite mulrBl !big_distrr big_ord_recl big_ord_recr /= subnn mulr1 mul1r. rewrite subn0 -!exprS opprD -!addrA; congr (_ + _); rewrite addrA -sumrB. rewrite big1 ?add0r // => i _; rewrite !mulrA -exprS -subSn ?(valP i) //. by rewrite subSS (commrX _ (commr_sym cxy)) -mulrA -exprS subrr. Qed. Lemma exprD1n x n : (x + 1) ^+ n = \sum_(i < n.+1) x ^+ i *+ 'C(n, i). Proof. rewrite addrC (exprDn_comm n (commr_sym (commr1 x))). by apply: eq_bigr => i _; rewrite expr1n mul1r. Qed. Lemma subrX1 x n : x ^+ n - 1 = (x - 1) * (\sum_(i < n) x ^+ i). Proof. rewrite -!(opprB 1) mulNr -{1}(expr1n n). rewrite (subrXX_comm _ (commr_sym (commr1 x))); congr (- (_ * _)). by apply: eq_bigr => i _; rewrite expr1n mul1r. Qed. Lemma sqrrD1 x : (x + 1) ^+ 2 = x ^+ 2 + x *+ 2 + 1. Proof. rewrite exprD1n !big_ord_recr big_ord0 /= add0r. by rewrite addrC addrA addrAC. Qed. Lemma sqrrB1 x : (x - 1) ^+ 2 = x ^+ 2 - x *+ 2 + 1. Proof. by rewrite -sqrrN opprB addrC sqrrD1 sqrrN mulNrn. Qed. Lemma subr_sqr_1 x : x ^+ 2 - 1 = (x - 1) * (x + 1). Proof. by rewrite subrX1 !big_ord_recr big_ord0 /= addrAC add0r. Qed. Definition Frobenius_aut p of p \in [char R] := fun x => x ^+ p. Section FrobeniusAutomorphism. Variable p : nat. Hypothesis charFp : p \in [char R]. Lemma charf0 : p%:R = 0 :> R. Proof. by apply/eqP; case/andP: charFp. Qed. Lemma charf_prime : prime p. Proof. by case/andP: charFp. Qed. Hint Resolve charf_prime. Lemma mulrn_char x : x *+ p = 0. Proof. by rewrite -mulr_natl charf0 mul0r. Qed. Lemma natr_mod_char n : (n %% p)%:R = n%:R :> R. Proof. by rewrite {2}(divn_eq n p) natrD mulrnA mulrn_char add0r. Qed. Lemma dvdn_charf n : (p %| n)%N = (n%:R == 0 :> R). Proof. apply/idP/eqP=> [/dvdnP[n' ->]|n0]; first by rewrite natrM charf0 mulr0. apply/idPn; rewrite -prime_coprime // => /eqnP pn1. have [a _ /dvdnP[b]] := Bezoutl n (prime_gt0 charf_prime). move/(congr1 (fun m => m%:R : R))/eqP. by rewrite natrD !natrM charf0 n0 !mulr0 pn1 addr0 oner_eq0. Qed. Lemma charf_eq : [char R] =i (p : nat_pred). Proof. move=> q; apply/andP/eqP=> [[q_pr q0] | ->]; last by rewrite charf0. by apply/eqP; rewrite eq_sym -dvdn_prime2 // dvdn_charf. Qed. Lemma bin_lt_charf_0 k : 0 < k < p -> 'C(p, k)%:R = 0 :> R. Proof. by move=> lt0kp; apply/eqP; rewrite -dvdn_charf prime_dvd_bin. Qed. Local Notation "x ^f" := (Frobenius_aut charFp x). Lemma Frobenius_autE x : x^f = x ^+ p. Proof. by []. Qed. Local Notation fE := Frobenius_autE. Lemma Frobenius_aut0 : 0^f = 0. Proof. by rewrite fE -(prednK (prime_gt0 charf_prime)) exprS mul0r. Qed. Lemma Frobenius_aut1 : 1^f = 1. Proof. by rewrite fE expr1n. Qed. Lemma Frobenius_autD_comm x y (cxy : comm x y) : (x + y)^f = x^f + y^f. Proof. have defp := prednK (prime_gt0 charf_prime). rewrite !fE exprDn_comm // big_ord_recr subnn -defp big_ord_recl /= defp. rewrite subn0 mulr1 mul1r bin0 binn big1 ?addr0 // => i _. by rewrite -mulr_natl bin_lt_charf_0 ?mul0r //= -{2}defp ltnS (valP i). Qed. Lemma Frobenius_autMn x n : (x *+ n)^f = x^f *+ n. Proof. elim: n => [|n IHn]; first exact: Frobenius_aut0. rewrite !mulrS Frobenius_autD_comm ?IHn //; exact: commrMn. Qed. Lemma Frobenius_aut_nat n : (n%:R)^f = n%:R. Proof. by rewrite Frobenius_autMn Frobenius_aut1. Qed. Lemma Frobenius_autM_comm x y : comm x y -> (x * y)^f = x^f * y^f. Proof. by exact: exprMn_comm. Qed. Lemma Frobenius_autX x n : (x ^+ n)^f = x^f ^+ n. Proof. by rewrite !fE -!exprM mulnC. Qed. Lemma Frobenius_autN x : (- x)^f = - x^f. Proof. apply/eqP; rewrite -subr_eq0 opprK addrC. by rewrite -(Frobenius_autD_comm (commrN _)) // subrr Frobenius_aut0. Qed. Lemma Frobenius_autB_comm x y : comm x y -> (x - y)^f = x^f - y^f. Proof. by move/commrN/Frobenius_autD_comm->; rewrite Frobenius_autN. Qed. End FrobeniusAutomorphism. Lemma exprNn_char x n : [char R].-nat n -> (- x) ^+ n = - (x ^+ n). Proof. pose p := pdiv n; have [|n_gt1 charRn] := leqP n 1; first by case: (n) => [|[]]. have charRp: p \in [char R] by rewrite (pnatPpi charRn) // pi_pdiv. have /p_natP[e ->]: p.-nat n by rewrite -(eq_pnat _ (charf_eq charRp)). elim: e => // e IHe; rewrite expnSr !exprM {}IHe. by rewrite -Frobenius_autE Frobenius_autN. Qed. Section Char2. Hypothesis charR2 : 2 \in [char R]. Lemma addrr_char2 x : x + x = 0. Proof. by rewrite -mulr2n mulrn_char. Qed. Lemma oppr_char2 x : - x = x. Proof. by apply/esym/eqP; rewrite -addr_eq0 addrr_char2. Qed. Lemma subr_char2 x y : x - y = x + y. Proof. by rewrite oppr_char2. Qed. Lemma addrK_char2 x : involutive (+%R^~ x). Proof. by move=> y; rewrite /= -subr_char2 addrK. Qed. Lemma addKr_char2 x : involutive (+%R x). Proof. by move=> y; rewrite -{1}[x]oppr_char2 addKr. Qed. End Char2. Canonical converse_eqType := [eqType of R^c]. Canonical converse_choiceType := [choiceType of R^c]. Canonical converse_zmodType := [zmodType of R^c]. Definition converse_ringMixin := let mul' x y := y * x in let mulrA' x y z := esym (mulrA z y x) in let mulrDl' x y z := mulrDr z x y in let mulrDr' x y z := mulrDl y z x in @Ring.Mixin converse_zmodType 1 mul' mulrA' mulr1 mul1r mulrDl' mulrDr' oner_neq0. Canonical converse_ringType := RingType R^c converse_ringMixin. Section ClosedPredicates. Variable S : predPredType R. Definition mulr_2closed := {in S &, forall u v, u * v \in S}. Definition mulr_closed := 1 \in S /\ mulr_2closed. Definition smulr_closed := -1 \in S /\ mulr_2closed. Definition semiring_closed := addr_closed S /\ mulr_closed. Definition subring_closed := [/\ 1 \in S, subr_2closed S & mulr_2closed]. Lemma smulr_closedM : smulr_closed -> mulr_closed. Proof. by case=> SN1 SM; split=> //; rewrite -[1]mulr1 -mulrNN SM. Qed. Lemma smulr_closedN : smulr_closed -> oppr_closed S. Proof. by case=> SN1 SM x Sx; rewrite -mulN1r SM. Qed. Lemma semiring_closedD : semiring_closed -> addr_closed S. Proof. by case. Qed. Lemma semiring_closedM : semiring_closed -> mulr_closed. Proof. by case. Qed. Lemma subring_closedB : subring_closed -> zmod_closed S. Proof. by case=> S1 SB _; split; rewrite // -(subrr 1) SB. Qed. Lemma subring_closedM : subring_closed -> smulr_closed. Proof. by case=> S1 SB SM; split; rewrite ?(zmod_closedN (subring_closedB _)). Qed. Lemma subring_closed_semi : subring_closed -> semiring_closed. Proof. by move=> ringS; split; [apply/zmod_closedD/subring_closedB | case: ringS]. Qed. End ClosedPredicates. End RingTheory. Section RightRegular. Variable R : ringType. Implicit Types x y : R. Let Rc := converse_ringType R. Lemma mulIr_eq0 x y : rreg x -> (y * x == 0) = (y == 0). Proof. exact: (@mulrI_eq0 Rc). Qed. Lemma mulIr0_rreg x : (forall y, y * x = 0 -> y = 0) -> rreg x. Proof. exact: (@mulrI0_lreg Rc). Qed. Lemma rreg_neq0 x : rreg x -> x != 0. Proof. exact: (@lreg_neq0 Rc). Qed. Lemma rregN x : rreg x -> rreg (- x). Proof. exact: (@lregN Rc). Qed. Lemma rreg1 : rreg (1 : R). Proof. exact: (@lreg1 Rc). Qed. Lemma rregM x y : rreg x -> rreg y -> rreg (x * y). Proof. by move=> reg_x reg_y; exact: (@lregM Rc). Qed. Lemma revrX x n : (x : Rc) ^+ n = (x : R) ^+ n. Proof. by elim: n => // n IHn; rewrite exprS exprSr IHn. Qed. Lemma rregX x n : rreg x -> rreg (x ^+ n). Proof. by move/(@lregX Rc x n); rewrite revrX. Qed. End RightRegular. Module Lmodule. Structure mixin_of (R : ringType) (V : zmodType) : Type := Mixin { scale : R -> V -> V; _ : forall a b v, scale a (scale b v) = scale (a * b) v; _ : left_id 1 scale; _ : right_distributive scale +%R; _ : forall v, {morph scale^~ v: a b / a + b} }. Section ClassDef. Variable R : ringType. Structure class_of V := Class { base : Zmodule.class_of V; mixin : mixin_of R (Zmodule.Pack base V) }. Local Coercion base : class_of >-> Zmodule.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variable (phR : phant R) (T : Type) (cT : type phR). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack phR T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack b0 (m0 : mixin_of R (@Zmodule.Pack T b0 T)) := fun bT b & phant_id (Zmodule.class bT) b => fun m & phant_id m0 m => Pack phR (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. End ClassDef. Module Import Exports. Coercion base : class_of >-> Zmodule.class_of. Coercion mixin : class_of >-> mixin_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Notation lmodType R := (type (Phant R)). Notation LmodType R T m := (@pack _ (Phant R) T _ m _ _ id _ id). Notation LmodMixin := Mixin. Notation "[ 'lmodType' R 'of' T 'for' cT ]" := (@clone _ (Phant R) T cT _ idfun) (at level 0, format "[ 'lmodType' R 'of' T 'for' cT ]") : form_scope. Notation "[ 'lmodType' R 'of' T ]" := (@clone _ (Phant R) T _ _ id) (at level 0, format "[ 'lmodType' R 'of' T ]") : form_scope. End Exports. End Lmodule. Import Lmodule.Exports. Definition scale (R : ringType) (V : lmodType R) := Lmodule.scale (Lmodule.class V). Local Notation "*:%R" := (@scale _ _). Local Notation "a *: v" := (scale a v) : ring_scope. Section LmoduleTheory. Variables (R : ringType) (V : lmodType R). Implicit Types (a b c : R) (u v : V). Local Notation "*:%R" := (@scale R V). Lemma scalerA a b v : a *: (b *: v) = a * b *: v. Proof. by case: V v => ? [] ? []. Qed. Lemma scale1r : @left_id R V 1 *:%R. Proof. by case: V => ? [] ? []. Qed. Lemma scalerDr a : {morph *:%R a : u v / u + v}. Proof. by case: V a => ? [] ? []. Qed. Lemma scalerDl v : {morph *:%R^~ v : a b / a + b}. Proof. by case: V v => ? [] ? []. Qed. Lemma scale0r v : 0 *: v = 0. Proof. by apply: (addIr (1 *: v)); rewrite -scalerDl !add0r. Qed. Lemma scaler0 a : a *: 0 = 0 :> V. Proof. by rewrite -{1}(scale0r 0) scalerA mulr0 scale0r. Qed. Lemma scaleNr a v : - a *: v = - (a *: v). Proof. by apply: (addIr (a *: v)); rewrite -scalerDl !addNr scale0r. Qed. Lemma scaleN1r v : (- 1) *: v = - v. Proof. by rewrite scaleNr scale1r. Qed. Lemma scalerN a v : a *: (- v) = - (a *: v). Proof. by apply: (addIr (a *: v)); rewrite -scalerDr !addNr scaler0. Qed. Lemma scalerBl a b v : (a - b) *: v = a *: v - b *: v. Proof. by rewrite scalerDl scaleNr. Qed. Lemma scalerBr a u v : a *: (u - v) = a *: u - a *: v. Proof. by rewrite scalerDr scalerN. Qed. Lemma scaler_nat n v : n%:R *: v = v *+ n. Proof. elim: n => /= [|n ]; first by rewrite scale0r. by rewrite !mulrS scalerDl ?scale1r => ->. Qed. Lemma scaler_sign (b : bool) v: (-1) ^+ b *: v = (if b then - v else v). Proof. by case: b; rewrite ?scaleNr scale1r. Qed. Lemma signrZK n : @involutive V ( *:%R ((-1) ^+ n)). Proof. by move=> u; rewrite scalerA -expr2 sqrr_sign scale1r. Qed. Lemma scalerMnl a v n : a *: v *+ n = (a *+ n) *: v. Proof. elim: n => [|n IHn]; first by rewrite !mulr0n scale0r. by rewrite !mulrSr IHn scalerDl. Qed. Lemma scalerMnr a v n : a *: v *+ n = a *: (v *+ n). Proof. elim: n => [|n IHn]; first by rewrite !mulr0n scaler0. by rewrite !mulrSr IHn scalerDr. Qed. Lemma scaler_suml v I r (P : pred I) F : (\sum_(i <- r | P i) F i) *: v = \sum_(i <- r | P i) F i *: v. Proof. exact: (big_morph _ (scalerDl v) (scale0r v)). Qed. Lemma scaler_sumr a I r (P : pred I) (F : I -> V) : a *: (\sum_(i <- r | P i) F i) = \sum_(i <- r | P i) a *: F i. Proof. exact: big_endo (scalerDr a) (scaler0 a) I r P F. Qed. Section ClosedPredicates. Variable S : predPredType V. Definition scaler_closed := forall a, {in S, forall v, a *: v \in S}. Definition linear_closed := forall a, {in S &, forall u v, a *: u + v \in S}. Definition submod_closed := 0 \in S /\ linear_closed. Lemma linear_closedB : linear_closed -> subr_2closed S. Proof. by move=> Slin u v Su Sv; rewrite addrC -scaleN1r Slin. Qed. Lemma submod_closedB : submod_closed -> zmod_closed S. Proof. by case=> S0 /linear_closedB. Qed. Lemma submod_closedZ : submod_closed -> scaler_closed. Proof. by case=> S0 Slin a v Sv; rewrite -[a *: v]addr0 Slin. Qed. End ClosedPredicates. End LmoduleTheory. Module Lalgebra. Definition axiom (R : ringType) (V : lmodType R) (mul : V -> V -> V) := forall a u v, a *: mul u v = mul (a *: u) v. Section ClassDef. Variable R : ringType. Record class_of (T : Type) : Type := Class { base : Ring.class_of T; mixin : Lmodule.mixin_of R (Zmodule.Pack base T); ext : @axiom R (Lmodule.Pack _ (Lmodule.Class mixin) T) (Ring.mul base) }. Definition base2 R m := Lmodule.Class (@mixin R m). Local Coercion base : class_of >-> Ring.class_of. Local Coercion base2 : class_of >-> Lmodule.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variable (phR : phant R) (T : Type) (cT : type phR). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack phR T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack T b0 mul0 (axT : @axiom R (@Lmodule.Pack R _ T b0 T) mul0) := fun bT b & phant_id (Ring.class bT) (b : Ring.class_of T) => fun mT m & phant_id (@Lmodule.class R phR mT) (@Lmodule.Class R T b m) => fun ax & phant_id axT ax => Pack (Phant R) (@Class T b m ax) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. Definition lmodType := @Lmodule.Pack R phR cT xclass xT. Definition lmod_ringType := @Lmodule.Pack R phR ringType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> Ring.class_of. Coercion base2 : class_of >-> Lmodule.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Coercion lmodType : type >-> Lmodule.type. Canonical lmodType. Canonical lmod_ringType. Notation lalgType R := (type (Phant R)). Notation LalgType R T a := (@pack _ (Phant R) T _ _ a _ _ id _ _ id _ id). Notation "[ 'lalgType' R 'of' T 'for' cT ]" := (@clone _ (Phant R) T cT _ idfun) (at level 0, format "[ 'lalgType' R 'of' T 'for' cT ]") : form_scope. Notation "[ 'lalgType' R 'of' T ]" := (@clone _ (Phant R) T _ _ id) (at level 0, format "[ 'lalgType' R 'of' T ]") : form_scope. End Exports. End Lalgebra. Import Lalgebra.Exports. (* Scalar injection (see the definition of in_alg A below). *) Local Notation "k %:A" := (k *: 1) : ring_scope. (* Regular ring algebra tag. *) Definition regular R : Type := R. Local Notation "R ^o" := (regular R) (at level 2, format "R ^o") : type_scope. Section LalgebraTheory. Variables (R : ringType) (A : lalgType R). Implicit Types x y : A. Lemma scalerAl k (x y : A) : k *: (x * y) = k *: x * y. Proof. by case: A k x y => ? []. Qed. Lemma mulr_algl a x : a%:A * x = a *: x. Proof. by rewrite -scalerAl mul1r. Qed. Canonical regular_eqType := [eqType of R^o]. Canonical regular_choiceType := [choiceType of R^o]. Canonical regular_zmodType := [zmodType of R^o]. Canonical regular_ringType := [ringType of R^o]. Definition regular_lmodMixin := let mkMixin := @Lmodule.Mixin R regular_zmodType (@mul R) in mkMixin (@mulrA R) (@mul1r R) (@mulrDr R) (fun v a b => mulrDl a b v). Canonical regular_lmodType := LmodType R R^o regular_lmodMixin. Canonical regular_lalgType := LalgType R R^o (@mulrA regular_ringType). Section ClosedPredicates. Variable S : predPredType A. Definition subalg_closed := [/\ 1 \in S, linear_closed S & mulr_2closed S]. Lemma subalg_closedZ : subalg_closed -> submod_closed S. Proof. by case=> S1 Slin _; split; rewrite // -(subrr 1) linear_closedB. Qed. Lemma subalg_closedBM : subalg_closed -> subring_closed S. Proof. by case=> S1 Slin SM; split=> //; apply: linear_closedB. Qed. End ClosedPredicates. End LalgebraTheory. (* Morphism hierarchy. *) Module Additive. Section ClassDef. Variables U V : zmodType. Definition axiom (f : U -> V) := {morph f : x y / x - y}. Structure map (phUV : phant (U -> V)) := Pack {apply; _ : axiom apply}. Local Coercion apply : map >-> Funclass. Variables (phUV : phant (U -> V)) (f g : U -> V) (cF : map phUV). Definition class := let: Pack _ c as cF' := cF return axiom cF' in c. Definition clone fA of phant_id g (apply cF) & phant_id fA class := @Pack phUV f fA. End ClassDef. Module Exports. Notation additive f := (axiom f). Coercion apply : map >-> Funclass. Notation Additive fA := (Pack (Phant _) fA). Notation "{ 'additive' fUV }" := (map (Phant fUV)) (at level 0, format "{ 'additive' fUV }") : ring_scope. Notation "[ 'additive' 'of' f 'as' g ]" := (@clone _ _ _ f g _ _ idfun id) (at level 0, format "[ 'additive' 'of' f 'as' g ]") : form_scope. Notation "[ 'additive' 'of' f ]" := (@clone _ _ _ f f _ _ id id) (at level 0, format "[ 'additive' 'of' f ]") : form_scope. End Exports. End Additive. Include Additive.Exports. (* Allows GRing.additive to resolve conflicts. *) (* Lifted additive operations. *) Section LiftedZmod. Variables (U : Type) (V : zmodType). Definition null_fun_head (phV : phant V) of U : V := let: Phant := phV in 0. Definition add_fun_head t (f g : U -> V) x := let: tt := t in f x + g x. Definition sub_fun_head t (f g : U -> V) x := let: tt := t in f x - g x. End LiftedZmod. (* Lifted multiplication. *) Section LiftedRing. Variables (R : ringType) (T : Type). Implicit Type f : T -> R. Definition mull_fun_head t a f x := let: tt := t in a * f x. Definition mulr_fun_head t a f x := let: tt := t in f x * a. End LiftedRing. (* Lifted linear operations. *) Section LiftedScale. Variables (R : ringType) (U : Type) (V : lmodType R) (A : lalgType R). Definition scale_fun_head t a (f : U -> V) x := let: tt := t in a *: f x. Definition in_alg_head (phA : phant A) k : A := let: Phant := phA in k%:A. End LiftedScale. Notation null_fun V := (null_fun_head (Phant V)) (only parsing). (* The real in_alg notation is declared after GRing.Theory so that at least *) (* in Coq 8.2 it gets precedence when GRing.Theory is not imported. *) Local Notation in_alg_loc A := (in_alg_head (Phant A)) (only parsing). Local Notation "\0" := (null_fun _) : ring_scope. Local Notation "f \+ g" := (add_fun_head tt f g) : ring_scope. Local Notation "f \- g" := (sub_fun_head tt f g) : ring_scope. Local Notation "a \*: f" := (scale_fun_head tt a f) : ring_scope. Local Notation "x \*o f" := (mull_fun_head tt x f) : ring_scope. Local Notation "x \o* f" := (mulr_fun_head tt x f) : ring_scope. Section AdditiveTheory. Section Properties. Variables (U V : zmodType) (k : unit) (f : {additive U -> V}). Lemma raddfB : {morph f : x y / x - y}. Proof. exact: Additive.class. Qed. Lemma raddf0 : f 0 = 0. Proof. by rewrite -[0]subr0 raddfB subrr. Qed. Lemma raddf_eq0 x : injective f -> (f x == 0) = (x == 0). Proof. by move=> /inj_eq <-; rewrite raddf0. Qed. Lemma raddfN : {morph f : x / - x}. Proof. by move=> x /=; rewrite -sub0r raddfB raddf0 sub0r. Qed. Lemma raddfD : {morph f : x y / x + y}. Proof. by move=> x y; rewrite -[y]opprK raddfB -raddfN. Qed. Lemma raddfMn n : {morph f : x / x *+ n}. Proof. by elim: n => [|n IHn] x /=; rewrite ?raddf0 // !mulrS raddfD IHn. Qed. Lemma raddfMNn n : {morph f : x / x *- n}. Proof. by move=> x /=; rewrite raddfN raddfMn. Qed. Lemma raddf_sum I r (P : pred I) E : f (\sum_(i <- r | P i) E i) = \sum_(i <- r | P i) f (E i). Proof. exact: (big_morph f raddfD raddf0). Qed. Lemma can2_additive f' : cancel f f' -> cancel f' f -> additive f'. Proof. by move=> fK f'K x y /=; apply: (canLR fK); rewrite raddfB !f'K. Qed. Lemma bij_additive : bijective f -> exists2 f' : {additive V -> U}, cancel f f' & cancel f' f. Proof. by case=> f' fK f'K; exists (Additive (can2_additive fK f'K)). Qed. Fact locked_is_additive : additive (locked_with k (f : U -> V)). Proof. by case: k f => [] []. Qed. Canonical locked_additive := Additive locked_is_additive. End Properties. Section RingProperties. Variables (R S : ringType) (f : {additive R -> S}). Lemma raddfMnat n x : f (n%:R * x) = n%:R * f x. Proof. by rewrite !mulr_natl raddfMn. Qed. Lemma raddfMsign n x : f ((-1) ^+ n * x) = (-1) ^+ n * f x. Proof. by rewrite !(mulr_sign, =^~ signr_odd) (fun_if f) raddfN. Qed. Variables (U : lmodType R) (V : lmodType S) (h : {additive U -> V}). Lemma raddfZnat n u : h (n%:R *: u) = n%:R *: h u. Proof. by rewrite !scaler_nat raddfMn. Qed. Lemma raddfZsign n u : h ((-1) ^+ n *: u) = (-1) ^+ n *: h u. Proof. by rewrite !(scaler_sign, =^~ signr_odd) (fun_if h) raddfN. Qed. End RingProperties. Section AddFun. Variables (U V W : zmodType) (f g : {additive V -> W}) (h : {additive U -> V}). Fact idfun_is_additive : additive (@idfun U). Proof. by []. Qed. Canonical idfun_additive := Additive idfun_is_additive. Fact comp_is_additive : additive (f \o h). Proof. by move=> x y /=; rewrite !raddfB. Qed. Canonical comp_additive := Additive comp_is_additive. Fact opp_is_additive : additive (-%R : U -> U). Proof. by move=> x y; rewrite /= opprD. Qed. Canonical opp_additive := Additive opp_is_additive. Fact null_fun_is_additive : additive (\0 : U -> V). Proof. by move=> /=; rewrite subr0. Qed. Canonical null_fun_additive := Additive null_fun_is_additive. Fact add_fun_is_additive : additive (f \+ g). Proof. by move=> x y /=; rewrite !raddfB addrCA -!addrA addrCA -opprD. Qed. Canonical add_fun_additive := Additive add_fun_is_additive. Fact sub_fun_is_additive : additive (f \- g). Proof. by move=> x y /=; rewrite !raddfB addrAC -!addrA -!opprD addrAC addrA. Qed. Canonical sub_fun_additive := Additive sub_fun_is_additive. End AddFun. Section MulFun. Variables (R : ringType) (U : zmodType). Variables (a : R) (f : {additive U -> R}). Fact mull_fun_is_additive : additive (a \*o f). Proof. by move=> x y /=; rewrite raddfB mulrBr. Qed. Canonical mull_fun_additive := Additive mull_fun_is_additive. Fact mulr_fun_is_additive : additive (a \o* f). Proof. by move=> x y /=; rewrite raddfB mulrBl. Qed. Canonical mulr_fun_additive := Additive mulr_fun_is_additive. End MulFun. Section ScaleFun. Variables (R : ringType) (U : zmodType) (V : lmodType R). Variables (a : R) (f : {additive U -> V}). Canonical scale_additive := Additive (@scalerBr R V a). Canonical scale_fun_additive := [additive of a \*: f as f \; *:%R a]. End ScaleFun. End AdditiveTheory. Module RMorphism. Section ClassDef. Variables R S : ringType. Definition mixin_of (f : R -> S) := {morph f : x y / x * y}%R * (f 1 = 1) : Prop. Record class_of f : Prop := Class {base : additive f; mixin : mixin_of f}. Local Coercion base : class_of >-> additive. Structure map (phRS : phant (R -> S)) := Pack {apply; _ : class_of apply}. Local Coercion apply : map >-> Funclass. Variables (phRS : phant (R -> S)) (f g : R -> S) (cF : map phRS). Definition class := let: Pack _ c as cF' := cF return class_of cF' in c. Definition clone fM of phant_id g (apply cF) & phant_id fM class := @Pack phRS f fM. Definition pack (fM : mixin_of f) := fun (bF : Additive.map phRS) fA & phant_id (Additive.class bF) fA => Pack phRS (Class fA fM). Canonical additive := Additive.Pack phRS class. End ClassDef. Module Exports. Notation multiplicative f := (mixin_of f). Notation rmorphism f := (class_of f). Coercion base : rmorphism >-> Additive.axiom. Coercion mixin : rmorphism >-> multiplicative. Coercion apply : map >-> Funclass. Notation RMorphism fM := (Pack (Phant _) fM). Notation AddRMorphism fM := (pack fM id). Notation "{ 'rmorphism' fRS }" := (map (Phant fRS)) (at level 0, format "{ 'rmorphism' fRS }") : ring_scope. Notation "[ 'rmorphism' 'of' f 'as' g ]" := (@clone _ _ _ f g _ _ idfun id) (at level 0, format "[ 'rmorphism' 'of' f 'as' g ]") : form_scope. Notation "[ 'rmorphism' 'of' f ]" := (@clone _ _ _ f f _ _ id id) (at level 0, format "[ 'rmorphism' 'of' f ]") : form_scope. Coercion additive : map >-> Additive.map. Canonical additive. End Exports. End RMorphism. Include RMorphism.Exports. Section RmorphismTheory. Section Properties. Variables (R S : ringType) (k : unit) (f : {rmorphism R -> S}). Lemma rmorph0 : f 0 = 0. Proof. exact: raddf0. Qed. Lemma rmorphN : {morph f : x / - x}. Proof. exact: raddfN. Qed. Lemma rmorphD : {morph f : x y / x + y}. Proof. exact: raddfD. Qed. Lemma rmorphB : {morph f: x y / x - y}. Proof. exact: raddfB. Qed. Lemma rmorphMn n : {morph f : x / x *+ n}. Proof. exact: raddfMn. Qed. Lemma rmorphMNn n : {morph f : x / x *- n}. Proof. exact: raddfMNn. Qed. Lemma rmorph_sum I r (P : pred I) E : f (\sum_(i <- r | P i) E i) = \sum_(i <- r | P i) f (E i). Proof. exact: raddf_sum. Qed. Lemma rmorphMsign n : {morph f : x / (- 1) ^+ n * x}. Proof. exact: raddfMsign. Qed. Lemma rmorphismP : rmorphism f. Proof. exact: RMorphism.class. Qed. Lemma rmorphismMP : multiplicative f. Proof. exact: rmorphismP. Qed. Lemma rmorph1 : f 1 = 1. Proof. by case: rmorphismMP. Qed. Lemma rmorphM : {morph f: x y / x * y}. Proof. by case: rmorphismMP. Qed. Lemma rmorph_prod I r (P : pred I) E : f (\prod_(i <- r | P i) E i) = \prod_(i <- r | P i) f (E i). Proof. exact: (big_morph f rmorphM rmorph1). Qed. Lemma rmorphX n : {morph f: x / x ^+ n}. Proof. by elim: n => [|n IHn] x; rewrite ?rmorph1 // !exprS rmorphM IHn. Qed. Lemma rmorph_nat n : f n%:R = n%:R. Proof. by rewrite rmorphMn rmorph1. Qed. Lemma rmorphN1 : f (- 1) = (- 1). Proof. by rewrite rmorphN rmorph1. Qed. Lemma rmorph_sign n : f ((- 1) ^+ n) = (- 1) ^+ n. Proof. by rewrite rmorphX rmorphN1. Qed. Lemma rmorph_char p : p \in [char R] -> p \in [char S]. Proof. by rewrite !inE -rmorph_nat => /andP[-> /= /eqP->]; rewrite rmorph0. Qed. Lemma rmorph_eq_nat x n : injective f -> (f x == n%:R) = (x == n%:R). Proof. by move/inj_eq <-; rewrite rmorph_nat. Qed. Lemma rmorph_eq1 x : injective f -> (f x == 1) = (x == 1). Proof. exact: rmorph_eq_nat 1%N. Qed. Lemma can2_rmorphism f' : cancel f f' -> cancel f' f -> rmorphism f'. Proof. move=> fK f'K; split; first exact: can2_additive fK f'K. by split=> [x y|]; apply: (canLR fK); rewrite /= (rmorphM, rmorph1) ?f'K. Qed. Lemma bij_rmorphism : bijective f -> exists2 f' : {rmorphism S -> R}, cancel f f' & cancel f' f. Proof. by case=> f' fK f'K; exists (RMorphism (can2_rmorphism fK f'K)). Qed. Fact locked_is_multiplicative : multiplicative (locked_with k (f : R -> S)). Proof. by case: k f => [] [? []]. Qed. Canonical locked_rmorphism := AddRMorphism locked_is_multiplicative. End Properties. Section Projections. Variables (R S T : ringType) (f : {rmorphism S -> T}) (g : {rmorphism R -> S}). Fact idfun_is_multiplicative : multiplicative (@idfun R). Proof. by []. Qed. Canonical idfun_rmorphism := AddRMorphism idfun_is_multiplicative. Fact comp_is_multiplicative : multiplicative (f \o g). Proof. by split=> [x y|] /=; rewrite ?rmorph1 ?rmorphM. Qed. Canonical comp_rmorphism := AddRMorphism comp_is_multiplicative. End Projections. Section InAlgebra. Variables (R : ringType) (A : lalgType R). Fact in_alg_is_rmorphism : rmorphism (in_alg_loc A). Proof. split=> [x y|]; first exact: scalerBl. by split=> [x y|] /=; rewrite ?scale1r // -scalerAl mul1r scalerA. Qed. Canonical in_alg_additive := Additive in_alg_is_rmorphism. Canonical in_alg_rmorphism := RMorphism in_alg_is_rmorphism. Lemma in_algE a : in_alg_loc A a = a%:A. Proof. by []. Qed. End InAlgebra. End RmorphismTheory. Module Scale. Section ScaleLaw. Structure law (R : ringType) (V : zmodType) (s : R -> V -> V) := Law { op : R -> V -> V; _ : op = s; _ : op (-1) =1 -%R; _ : forall a, additive (op a) }. Definition mul_law R := Law (erefl *%R) (@mulN1r R) (@mulrBr R). Definition scale_law R U := Law (erefl *:%R) (@scaleN1r R U) (@scalerBr R U). Variables (R : ringType) (V : zmodType) (s : R -> V -> V) (s_law : law s). Local Notation s_op := (op s_law). Lemma opE : s_op = s. Proof. by case: s_law. Qed. Lemma N1op : s_op (-1) =1 -%R. Proof. by case: s_law. Qed. Fact opB a : additive (s_op a). Proof. by case: s_law. Qed. Definition op_additive a := Additive (opB a). Variables (aR : ringType) (nu : {rmorphism aR -> R}). Fact comp_opE : nu \; s_op = nu \; s. Proof. exact: congr1 opE. Qed. Fact compN1op : (nu \; s_op) (-1) =1 -%R. Proof. by move=> v; rewrite /= rmorphN1 N1op. Qed. Definition comp_law : law (nu \; s) := Law comp_opE compN1op (fun a => opB _). End ScaleLaw. End Scale. Module Linear. Section ClassDef. Variables (R : ringType) (U : lmodType R) (V : zmodType) (s : R -> V -> V). Implicit Type phUV : phant (U -> V). Local Coercion Scale.op : Scale.law >-> Funclass. Definition axiom (f : U -> V) (s_law : Scale.law s) of s = s_law := forall a, {morph f : u v / a *: u + v >-> s a u + v}. Definition mixin_of (f : U -> V) := forall a, {morph f : v / a *: v >-> s a v}. Record class_of f : Prop := Class {base : additive f; mixin : mixin_of f}. Local Coercion base : class_of >-> additive. Lemma class_of_axiom f s_law Ds : @axiom f s_law Ds -> class_of f. Proof. move=> fL; have fB: additive f. by move=> x y /=; rewrite -scaleN1r addrC fL Ds Scale.N1op addrC. by split=> // a v /=; rewrite -[a *: v](addrK v) fB fL addrK Ds. Qed. Structure map (phUV : phant (U -> V)) := Pack {apply; _ : class_of apply}. Local Coercion apply : map >-> Funclass. Variables (phUV : phant (U -> V)) (f g : U -> V) (cF : map phUV). Definition class := let: Pack _ c as cF' := cF return class_of cF' in c. Definition clone fL of phant_id g (apply cF) & phant_id fL class := @Pack phUV f fL. Definition pack (fZ : mixin_of f) := fun (bF : Additive.map phUV) fA & phant_id (Additive.class bF) fA => Pack phUV (Class fA fZ). Canonical additive := Additive.Pack phUV class. (* Support for right-to-left rewriting with the generic linearZ rule. *) Notation mapUV := (map (Phant (U -> V))). Definition map_class := mapUV. Definition map_at (a : R) := mapUV. Structure map_for a s_a := MapFor {map_for_map : mapUV; _ : s a = s_a}. Definition unify_map_at a (f : map_at a) := MapFor f (erefl (s a)). Structure wrapped := Wrap {unwrap : mapUV}. Definition wrap (f : map_class) := Wrap f. End ClassDef. Module Exports. Canonical Scale.mul_law. Canonical Scale.scale_law. Canonical Scale.comp_law. Canonical Scale.op_additive. Delimit Scope linear_ring_scope with linR. Notation "a *: u" := (@Scale.op _ _ *:%R _ a u) : linear_ring_scope. Notation "a * u" := (@Scale.op _ _ *%R _ a u) : linear_ring_scope. Notation "a *:^ nu u" := (@Scale.op _ _ (nu \; *:%R) _ a u) (at level 40, nu at level 1, format "a *:^ nu u") : linear_ring_scope. Notation "a *^ nu u" := (@Scale.op _ _ (nu \; *%R) _ a u) (at level 40, nu at level 1, format "a *^ nu u") : linear_ring_scope. Notation scalable_for s f := (mixin_of s f). Notation scalable f := (scalable_for *:%R f). Notation linear_for s f := (axiom f (erefl s)). Notation linear f := (linear_for *:%R f). Notation scalar f := (linear_for *%R f). Notation lmorphism_for s f := (class_of s f). Notation lmorphism f := (lmorphism_for *:%R f). Coercion class_of_axiom : axiom >-> lmorphism_for. Coercion base : lmorphism_for >-> Additive.axiom. Coercion mixin : lmorphism_for >-> scalable. Coercion apply : map >-> Funclass. Notation Linear fL := (Pack (Phant _) fL). Notation AddLinear fZ := (pack fZ id). Notation "{ 'linear' fUV | s }" := (map s (Phant fUV)) (at level 0, format "{ 'linear' fUV | s }") : ring_scope. Notation "{ 'linear' fUV }" := {linear fUV | *:%R} (at level 0, format "{ 'linear' fUV }") : ring_scope. Notation "{ 'scalar' U }" := {linear U -> _ | *%R} (at level 0, format "{ 'scalar' U }") : ring_scope. Notation "[ 'linear' 'of' f 'as' g ]" := (@clone _ _ _ _ _ f g _ _ idfun id) (at level 0, format "[ 'linear' 'of' f 'as' g ]") : form_scope. Notation "[ 'linear' 'of' f ]" := (@clone _ _ _ _ _ f f _ _ id id) (at level 0, format "[ 'linear' 'of' f ]") : form_scope. Coercion additive : map >-> Additive.map. Canonical additive. (* Support for right-to-left rewriting with the generic linearZ rule. *) Coercion map_for_map : map_for >-> map. Coercion unify_map_at : map_at >-> map_for. Canonical unify_map_at. Coercion unwrap : wrapped >-> map. Coercion wrap : map_class >-> wrapped. Canonical wrap. End Exports. End Linear. Include Linear.Exports. Section LinearTheory. Variable R : ringType. Section GenericProperties. Variables (U : lmodType R) (V : zmodType) (s : R -> V -> V) (k : unit). Variable f : {linear U -> V | s}. Lemma linear0 : f 0 = 0. Proof. exact: raddf0. Qed. Lemma linearN : {morph f : x / - x}. Proof. exact: raddfN. Qed. Lemma linearD : {morph f : x y / x + y}. Proof. exact: raddfD. Qed. Lemma linearB : {morph f : x y / x - y}. Proof. exact: raddfB. Qed. Lemma linearMn n : {morph f : x / x *+ n}. Proof. exact: raddfMn. Qed. Lemma linearMNn n : {morph f : x / x *- n}. Proof. exact: raddfMNn. Qed. Lemma linear_sum I r (P : pred I) E : f (\sum_(i <- r | P i) E i) = \sum_(i <- r | P i) f (E i). Proof. exact: raddf_sum. Qed. Lemma linearZ_LR : scalable_for s f. Proof. by case: f => ? []. Qed. Lemma linearP a : {morph f : u v / a *: u + v >-> s a u + v}. Proof. by move=> u v /=; rewrite linearD linearZ_LR. Qed. Fact locked_is_scalable : scalable_for s (locked_with k (f : U -> V)). Proof. by case: k f => [] [? []]. Qed. Canonical locked_linear := AddLinear locked_is_scalable. End GenericProperties. Section BidirectionalLinearZ. Variables (U : lmodType R) (V : zmodType) (s : R -> V -> V). (* The general form of the linearZ lemma uses some bespoke interfaces to *) (* allow right-to-left rewriting when a composite scaling operation such as *) (* conjC \; *%R has been expanded, say in a^* * f u. This redex is matched *) (* by using the Scale.law interface to recognize a "head" scaling operation *) (* h (here *%R), stow away its "scalar" c, then reconcile h c and s a, once *) (* s is known, that is, once the Linear.map structure for f has been found. *) (* In general, s and a need not be equal to h and c; indeed they need not *) (* have the same type! The unification is performed by the unify_map_at *) (* default instance for the Linear.map_for U s a h_c sub-interface of *) (* Linear.map; the h_c pattern uses the Scale.law structure to insure it is *) (* inferred when rewriting right-to-left. *) (* The wrap on the rhs allows rewriting f (a *: b *: u) into a *: b *: f u *) (* with rewrite !linearZ /= instead of rewrite linearZ /= linearZ /=. *) (* Without it, the first rewrite linearZ would produce *) (* (a *: apply (map_for_map (@check_map_at .. a f)) (b *: u)%R)%Rlin *) (* and matching the second rewrite LHS would bypass the unify_map_at default *) (* instance for b, reuse the one for a, and subsequently fail to match the *) (* b *: u argument. The extra wrap / unwrap ensures that this can't happen. *) (* In the RL direction, the wrap / unwrap will be inserted on the redex side *) (* as needed, without causing unnecessary delta-expansion: using an explicit *) (* identity function would have Coq normalize the redex to head normal, then *) (* reduce the identity to expose the map_for_map projection, and the *) (* expanded Linear.map structure would then be exposed in the result. *) (* Most of this machinery will be invisible to a casual user, because all *) (* the projections and default instances involved are declared as coercions. *) Variables (S : ringType) (h : S -> V -> V) (h_law : Scale.law h). Lemma linearZ c a (h_c := Scale.op h_law c) (f : Linear.map_for U s a h_c) u : f (a *: u) = h_c (Linear.wrap f u). Proof. by rewrite linearZ_LR; case: f => f /= ->. Qed. End BidirectionalLinearZ. Section LmodProperties. Variables (U V : lmodType R) (f : {linear U -> V}). Lemma linearZZ : scalable f. Proof. exact: linearZ_LR. Qed. Lemma linearPZ : linear f. Proof. exact: linearP. Qed. Lemma can2_linear f' : cancel f f' -> cancel f' f -> linear f'. Proof. by move=> fK f'K a x y /=; apply: (canLR fK); rewrite linearP !f'K. Qed. Lemma bij_linear : bijective f -> exists2 f' : {linear V -> U}, cancel f f' & cancel f' f. Proof. by case=> f' fK f'K; exists (Linear (can2_linear fK f'K)). Qed. End LmodProperties. Section ScalarProperties. Variable (U : lmodType R) (f : {scalar U}). Lemma scalarZ : scalable_for *%R f. Proof. exact: linearZ_LR. Qed. Lemma scalarP : scalar f. Proof. exact: linearP. Qed. End ScalarProperties. Section LinearLmod. Variables (W U : lmodType R) (V : zmodType) (s : R -> V -> V). Variables (f : {linear U -> V | s}) (h : {linear W -> U}). Lemma idfun_is_scalable : scalable (@idfun U). Proof. by []. Qed. Canonical idfun_linear := AddLinear idfun_is_scalable. Lemma opp_is_scalable : scalable (-%R : U -> U). Proof. by move=> a v /=; rewrite scalerN. Qed. Canonical opp_linear := AddLinear opp_is_scalable. Lemma comp_is_scalable : scalable_for s (f \o h). Proof. by move=> a v /=; rewrite !linearZ_LR. Qed. Canonical comp_linear := AddLinear comp_is_scalable. Variables (s_law : Scale.law s) (g : {linear U -> V | Scale.op s_law}). Let Ds : s =1 Scale.op s_law. Proof. by rewrite Scale.opE. Qed. Lemma null_fun_is_scalable : scalable_for (Scale.op s_law) (\0 : U -> V). Proof. by move=> a v /=; rewrite raddf0. Qed. Canonical null_fun_linear := AddLinear null_fun_is_scalable. Lemma add_fun_is_scalable : scalable_for s (f \+ g). Proof. by move=> a u; rewrite /= !linearZ_LR !Ds raddfD. Qed. Canonical add_fun_linear := AddLinear add_fun_is_scalable. Lemma sub_fun_is_scalable : scalable_for s (f \- g). Proof. by move=> a u; rewrite /= !linearZ_LR !Ds raddfB. Qed. Canonical sub_fun_linear := AddLinear sub_fun_is_scalable. End LinearLmod. Section LinearLalg. Variables (A : lalgType R) (U : lmodType R). Variables (a : A) (f : {linear U -> A}). Fact mulr_fun_is_scalable : scalable (a \o* f). Proof. by move=> k x /=; rewrite linearZ scalerAl. Qed. Canonical mulr_fun_linear := AddLinear mulr_fun_is_scalable. End LinearLalg. End LinearTheory. Module LRMorphism. Section ClassDef. Variables (R : ringType) (A : lalgType R) (B : ringType) (s : R -> B -> B). Record class_of (f : A -> B) : Prop := Class {base : rmorphism f; mixin : scalable_for s f}. Local Coercion base : class_of >-> rmorphism. Definition base2 f (fLM : class_of f) := Linear.Class fLM (mixin fLM). Local Coercion base2 : class_of >-> lmorphism. Structure map (phAB : phant (A -> B)) := Pack {apply; _ : class_of apply}. Local Coercion apply : map >-> Funclass. Variables (phAB : phant (A -> B)) (f : A -> B) (cF : map phAB). Definition class := let: Pack _ c as cF' := cF return class_of cF' in c. Definition clone := fun (g : RMorphism.map phAB) fM & phant_id (RMorphism.class g) fM => fun (h : Linear.map s phAB) fZ & phant_id (Linear.mixin (Linear.class h)) fZ => Pack phAB (@Class f fM fZ). Definition pack (fZ : scalable_for s f) := fun (g : RMorphism.map phAB) fM & phant_id (RMorphism.class g) fM => Pack phAB (Class fM fZ). Canonical additive := Additive.Pack phAB class. Canonical rmorphism := RMorphism.Pack phAB class. Canonical linear := Linear.Pack phAB class. Canonical join_rmorphism := @RMorphism.Pack _ _ phAB linear class. Canonical join_linear := @Linear.Pack R A B s phAB rmorphism class. End ClassDef. Module Exports. Notation lrmorphism_for s f := (class_of s f). Notation lrmorphism f := (lrmorphism_for *:%R f). Coercion base : lrmorphism_for >-> RMorphism.class_of. Coercion base2 : lrmorphism_for >-> lmorphism_for. Coercion apply : map >-> Funclass. Notation LRMorphism f_lrM := (Pack (Phant _) (Class f_lrM f_lrM)). Notation AddLRMorphism fZ := (pack fZ id). Notation "{ 'lrmorphism' fAB | s }" := (map s (Phant fAB)) (at level 0, format "{ 'lrmorphism' fAB | s }") : ring_scope. Notation "{ 'lrmorphism' fAB }" := {lrmorphism fAB | *:%R} (at level 0, format "{ 'lrmorphism' fAB }") : ring_scope. Notation "[ 'lrmorphism' 'of' f ]" := (@clone _ _ _ _ _ f _ _ id _ _ id) (at level 0, format "[ 'lrmorphism' 'of' f ]") : form_scope. Coercion additive : map >-> Additive.map. Canonical additive. Coercion rmorphism : map >-> RMorphism.map. Canonical rmorphism. Coercion linear : map >-> Linear.map. Canonical linear. Canonical join_rmorphism. Canonical join_linear. End Exports. End LRMorphism. Include LRMorphism.Exports. Section LRMorphismTheory. Variables (R : ringType) (A B : lalgType R) (C : ringType) (s : R -> C -> C). Variables (k : unit) (f : {lrmorphism A -> B}) (g : {lrmorphism B -> C | s}). Definition idfun_lrmorphism := [lrmorphism of @idfun A]. Definition comp_lrmorphism := [lrmorphism of g \o f]. Definition locked_lrmorphism := [lrmorphism of locked_with k (f : A -> B)]. Lemma rmorph_alg a : f a%:A = a%:A. Proof. by rewrite linearZ rmorph1. Qed. Lemma lrmorphismP : lrmorphism f. Proof. exact: LRMorphism.class. Qed. Lemma can2_lrmorphism f' : cancel f f' -> cancel f' f -> lrmorphism f'. Proof. move=> fK f'K; split; [exact: (can2_rmorphism fK) | exact: (can2_linear fK)]. Qed. Lemma bij_lrmorphism : bijective f -> exists2 f' : {lrmorphism B -> A}, cancel f f' & cancel f' f. Proof. by case/bij_rmorphism=> f' fK f'K; exists (AddLRMorphism (can2_linear fK f'K)). Qed. End LRMorphismTheory. Module ComRing. Definition RingMixin R one mul mulA mulC mul1x mul_addl := let mulx1 := Monoid.mulC_id mulC mul1x in let mul_addr := Monoid.mulC_dist mulC mul_addl in @Ring.EtaMixin R one mul mulA mul1x mulx1 mul_addl mul_addr. Section ClassDef. Record class_of R := Class {base : Ring.class_of R; mixin : commutative (Ring.mul base)}. Local Coercion base : class_of >-> Ring.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variable (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack mul0 (m0 : @commutative T T mul0) := fun bT b & phant_id (Ring.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> Ring.class_of. Implicit Arguments mixin [R]. Coercion mixin : class_of >-> commutative. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Notation comRingType := type. Notation ComRingType T m := (@pack T _ m _ _ id _ id). Notation ComRingMixin := RingMixin. Notation "[ 'comRingType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'comRingType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'comRingType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'comRingType' 'of' T ]") : form_scope. End Exports. End ComRing. Import ComRing.Exports. Section ComRingTheory. Variable R : comRingType. Implicit Types x y : R. Lemma mulrC : @commutative R R *%R. Proof. by case: R => T []. Qed. Canonical mul_comoid := Monoid.ComLaw mulrC. Lemma mulrCA : @left_commutative R R *%R. Proof. exact: mulmCA. Qed. Lemma mulrAC : @right_commutative R R *%R. Proof. exact: mulmAC. Qed. Lemma mulrACA : @interchange R *%R *%R. Proof. exact: mulmACA. Qed. Lemma exprMn n : {morph (fun x => x ^+ n) : x y / x * y}. Proof. move=> x y; apply: exprMn_comm; exact: mulrC. Qed. Lemma prodrXl n I r (P : pred I) (F : I -> R) : \prod_(i <- r | P i) F i ^+ n = (\prod_(i <- r | P i) F i) ^+ n. Proof. by rewrite (big_morph _ (exprMn n) (expr1n _ n)). Qed. Lemma prodr_undup_exp_count (I : eqType) r (P : pred I) (F : I -> R) : \prod_(i <- undup r | P i) F i ^+ count_mem i r = \prod_(i <- r | P i) F i. Proof. exact: big_undup_iterop_count. Qed. Lemma exprDn x y n : (x + y) ^+ n = \sum_(i < n.+1) (x ^+ (n - i) * y ^+ i) *+ 'C(n, i). Proof. by rewrite exprDn_comm //; exact: mulrC. Qed. Lemma exprBn x y n : (x - y) ^+ n = \sum_(i < n.+1) ((-1) ^+ i * x ^+ (n - i) * y ^+ i) *+ 'C(n, i). Proof. by rewrite exprBn_comm //; exact: mulrC. Qed. Lemma subrXX x y n : x ^+ n - y ^+ n = (x - y) * (\sum_(i < n) x ^+ (n.-1 - i) * y ^+ i). Proof. by rewrite -subrXX_comm //; exact: mulrC. Qed. Lemma sqrrD x y : (x + y) ^+ 2 = x ^+ 2 + x * y *+ 2 + y ^+ 2. Proof. by rewrite exprDn !big_ord_recr big_ord0 /= add0r mulr1 mul1r. Qed. Lemma sqrrB x y : (x - y) ^+ 2 = x ^+ 2 - x * y *+ 2 + y ^+ 2. Proof. by rewrite sqrrD mulrN mulNrn sqrrN. Qed. Lemma subr_sqr x y : x ^+ 2 - y ^+ 2 = (x - y) * (x + y). Proof. by rewrite subrXX !big_ord_recr big_ord0 /= add0r mulr1 mul1r. Qed. Lemma subr_sqrDB x y : (x + y) ^+ 2 - (x - y) ^+ 2 = x * y *+ 4. Proof. rewrite sqrrD sqrrB -!(addrAC _ (y ^+ 2)) opprB. by rewrite addrC addrA subrK -mulrnDr. Qed. Section FrobeniusAutomorphism. Variables (p : nat) (charRp : p \in [char R]). Lemma Frobenius_aut_is_rmorphism : rmorphism (Frobenius_aut charRp). Proof. split=> [x y|]; first exact: Frobenius_autB_comm (mulrC _ _). split=> [x y|]; first exact: Frobenius_autM_comm (mulrC _ _). exact: Frobenius_aut1. Qed. Canonical Frobenius_aut_additive := Additive Frobenius_aut_is_rmorphism. Canonical Frobenius_aut_rmorphism := RMorphism Frobenius_aut_is_rmorphism. End FrobeniusAutomorphism. Lemma exprDn_char x y n : [char R].-nat n -> (x + y) ^+ n = x ^+ n + y ^+ n. Proof. pose p := pdiv n; have [|n_gt1 charRn] := leqP n 1; first by case: (n) => [|[]]. have charRp: p \in [char R] by rewrite (pnatPpi charRn) ?pi_pdiv. have{charRn} /p_natP[e ->]: p.-nat n by rewrite -(eq_pnat _ (charf_eq charRp)). by elim: e => // e IHe; rewrite !expnSr !exprM IHe -Frobenius_autE rmorphD. Qed. Lemma rmorph_comm (S : ringType) (f : {rmorphism R -> S}) x y : comm (f x) (f y). Proof. by red; rewrite -!rmorphM mulrC. Qed. Section ScaleLinear. Variables (U V : lmodType R) (b : R) (f : {linear U -> V}). Lemma scale_is_scalable : scalable ( *:%R b : V -> V). Proof. by move=> a v /=; rewrite !scalerA mulrC. Qed. Canonical scale_linear := AddLinear scale_is_scalable. Lemma scale_fun_is_scalable : scalable (b \*: f). Proof. by move=> a v /=; rewrite !linearZ. Qed. Canonical scale_fun_linear := AddLinear scale_fun_is_scalable. End ScaleLinear. End ComRingTheory. Module Algebra. Section Mixin. Variables (R : ringType) (A : lalgType R). Definition axiom := forall k (x y : A), k *: (x * y) = x * (k *: y). Lemma comm_axiom : phant A -> commutative (@mul A) -> axiom. Proof. by move=> _ commA k x y; rewrite commA scalerAl commA. Qed. End Mixin. Section ClassDef. Variable R : ringType. Record class_of (T : Type) : Type := Class { base : Lalgebra.class_of R T; mixin : axiom (Lalgebra.Pack _ base T) }. Local Coercion base : class_of >-> Lalgebra.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variable (phR : phant R) (T : Type) (cT : type phR). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack phR T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack b0 (ax0 : @axiom R b0) := fun bT b & phant_id (@Lalgebra.class R phR bT) b => fun ax & phant_id ax0 ax => Pack phR (@Class T b ax) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. Definition lmodType := @Lmodule.Pack R phR cT xclass xT. Definition lalgType := @Lalgebra.Pack R phR cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> Lalgebra.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Coercion lmodType : type >-> Lmodule.type. Canonical lmodType. Coercion lalgType : type >-> Lalgebra.type. Canonical lalgType. Notation algType R := (type (Phant R)). Notation AlgType R A ax := (@pack _ (Phant R) A _ ax _ _ id _ id). Notation CommAlgType R A := (AlgType R A (comm_axiom (Phant A) (@mulrC _))). Notation "[ 'algType' R 'of' T 'for' cT ]" := (@clone _ (Phant R) T cT _ idfun) (at level 0, format "[ 'algType' R 'of' T 'for' cT ]") : form_scope. Notation "[ 'algType' R 'of' T ]" := (@clone _ (Phant R) T _ _ id) (at level 0, format "[ 'algType' R 'of' T ]") : form_scope. End Exports. End Algebra. Import Algebra.Exports. Section AlgebraTheory. Variables (R : comRingType) (A : algType R). Implicit Types (k : R) (x y : A). Lemma scalerAr k x y : k *: (x * y) = x * (k *: y). Proof. by case: A k x y => T []. Qed. Lemma scalerCA k x y : k *: x * y = x * (k *: y). Proof. by rewrite -scalerAl scalerAr. Qed. Lemma mulr_algr a x : x * a%:A = a *: x. Proof. by rewrite -scalerAr mulr1. Qed. Lemma exprZn k x n : (k *: x) ^+ n = k ^+ n *: x ^+ n. Proof. elim: n => [|n IHn]; first by rewrite !expr0 scale1r. by rewrite !exprS IHn -scalerA scalerAr scalerAl. Qed. Lemma scaler_prod I r (P : pred I) (F : I -> R) (G : I -> A) : \prod_(i <- r | P i) (F i *: G i) = \prod_(i <- r | P i) F i *: \prod_(i <- r | P i) G i. Proof. elim/big_rec3: _ => [|i x a _ _ ->]; first by rewrite scale1r. by rewrite -scalerAl -scalerAr scalerA. Qed. Lemma scaler_prodl (I : finType) (S : pred I) (F : I -> A) k : \prod_(i in S) (k *: F i) = k ^+ #|S| *: \prod_(i in S) F i. Proof. by rewrite scaler_prod prodr_const. Qed. Lemma scaler_prodr (I : finType) (S : pred I) (F : I -> R) x : \prod_(i in S) (F i *: x) = \prod_(i in S) F i *: x ^+ #|S|. Proof. by rewrite scaler_prod prodr_const. Qed. Canonical regular_comRingType := [comRingType of R^o]. Canonical regular_algType := CommAlgType R R^o. Variables (U : lmodType R) (a : A) (f : {linear U -> A}). Lemma mull_fun_is_scalable : scalable (a \*o f). Proof. by move=> k x /=; rewrite linearZ scalerAr. Qed. Canonical mull_fun_linear := AddLinear mull_fun_is_scalable. End AlgebraTheory. Module UnitRing. Record mixin_of (R : ringType) : Type := Mixin { unit : pred R; inv : R -> R; _ : {in unit, left_inverse 1 inv *%R}; _ : {in unit, right_inverse 1 inv *%R}; _ : forall x y, y * x = 1 /\ x * y = 1 -> unit x; _ : {in [predC unit], inv =1 id} }. Definition EtaMixin R unit inv mulVr mulrV unitP inv_out := let _ := @Mixin R unit inv mulVr mulrV unitP inv_out in @Mixin (Ring.Pack (Ring.class R) R) unit inv mulVr mulrV unitP inv_out. Section ClassDef. Record class_of (R : Type) : Type := Class { base : Ring.class_of R; mixin : mixin_of (Ring.Pack base R) }. Local Coercion base : class_of >-> Ring.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack b0 (m0 : mixin_of (@Ring.Pack T b0 T)) := fun bT b & phant_id (Ring.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> Ring.class_of. Coercion mixin : class_of >-> mixin_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Notation unitRingType := type. Notation UnitRingType T m := (@pack T _ m _ _ id _ id). Notation UnitRingMixin := EtaMixin. Notation "[ 'unitRingType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'unitRingType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'unitRingType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'unitRingType' 'of' T ]") : form_scope. End Exports. End UnitRing. Import UnitRing.Exports. Definition unit {R : unitRingType} := [qualify a u : R | UnitRing.unit (UnitRing.class R) u]. Fact unit_key R : pred_key (@unit R). Proof. by []. Qed. Canonical unit_keyed R := KeyedQualifier (@unit_key R). Definition inv {R : unitRingType} : R -> R := UnitRing.inv (UnitRing.class R). Local Notation "x ^-1" := (inv x). Local Notation "x / y" := (x * y^-1). Local Notation "x ^- n" := ((x ^+ n)^-1). Section UnitRingTheory. Variable R : unitRingType. Implicit Types x y : R. Lemma divrr : {in unit, right_inverse 1 (@inv R) *%R}. Proof. by case: R => T [? []]. Qed. Definition mulrV := divrr. Lemma mulVr : {in unit, left_inverse 1 (@inv R) *%R}. Proof. by case: R => T [? []]. Qed. Lemma invr_out x : x \isn't a unit -> x^-1 = x. Proof. by case: R x => T [? []]. Qed. Lemma unitrP x : reflect (exists y, y * x = 1 /\ x * y = 1) (x \is a unit). Proof. apply: (iffP idP) => [Ux | []]; last by case: R x => T [? []]. by exists x^-1; rewrite divrr ?mulVr. Qed. Lemma mulKr : {in unit, left_loop (@inv R) *%R}. Proof. by move=> x Ux y; rewrite mulrA mulVr ?mul1r. Qed. Lemma mulVKr : {in unit, rev_left_loop (@inv R) *%R}. Proof. by move=> x Ux y; rewrite mulrA mulrV ?mul1r. Qed. Lemma mulrK : {in unit, right_loop (@inv R) *%R}. Proof. by move=> x Ux y; rewrite -mulrA divrr ?mulr1. Qed. Lemma mulrVK : {in unit, rev_right_loop (@inv R) *%R}. Proof. by move=> x Ux y; rewrite -mulrA mulVr ?mulr1. Qed. Definition divrK := mulrVK. Lemma mulrI : {in @unit R, right_injective *%R}. Proof. by move=> x Ux; exact: can_inj (mulKr Ux). Qed. Lemma mulIr : {in @unit R, left_injective *%R}. Proof. by move=> x Ux; exact: can_inj (mulrK Ux). Qed. (* Due to noncommutativity, fractions are inverted. *) Lemma telescope_prodr n m (f : nat -> R) : (forall k, n < k < m -> f k \is a unit) -> n < m -> \prod_(n <= k < m) (f k / f k.+1) = f n / f m. Proof. move=> Uf /subnK-Dm; do [rewrite -{}Dm; move: {m}(m - _)%N => m] in Uf *. rewrite unlock /index_iota -addSnnS addnK /= -mulrA; congr (_ * _). have{Uf}: all [preim f of unit] (iota n.+1 m). by apply/allP=> k; rewrite mem_iota addnC => /Uf. elim: m n => [|m IHm] n /=; first by rewrite mulr1. by rewrite -mulrA addSnnS => /andP[/mulKr-> /IHm]. Qed. Lemma commrV x y : comm x y -> comm x y^-1. Proof. have [Uy cxy | /invr_out-> //] := boolP (y \in unit). by apply: (canLR (mulrK Uy)); rewrite -mulrA cxy mulKr. Qed. Lemma unitrE x : (x \is a unit) = (x / x == 1). Proof. apply/idP/eqP=> [Ux | xx1]; first exact: divrr. by apply/unitrP; exists x^-1; rewrite -commrV. Qed. Lemma invrK : involutive (@inv R). Proof. move=> x; case Ux: (x \in unit); last by rewrite !invr_out ?Ux. rewrite -(mulrK Ux _^-1) -mulrA commrV ?mulKr //. by apply/unitrP; exists x; rewrite divrr ?mulVr. Qed. Lemma invr_inj : injective (@inv R). Proof. exact: inv_inj invrK. Qed. Lemma unitrV x : (x^-1 \in unit) = (x \in unit). Proof. by rewrite !unitrE invrK commrV. Qed. Lemma unitr1 : 1 \in @unit R. Proof. by apply/unitrP; exists 1; rewrite mulr1. Qed. Lemma invr1 : 1^-1 = 1 :> R. Proof. by rewrite -{2}(mulVr unitr1) mulr1. Qed. Lemma div1r x : 1 / x = x^-1. Proof. by rewrite mul1r. Qed. Lemma divr1 x : x / 1 = x. Proof. by rewrite invr1 mulr1. Qed. Lemma natr_div m d : d %| m -> d%:R \is a @unit R -> (m %/ d)%:R = m%:R / d%:R :> R. Proof. by rewrite dvdn_eq => /eqP def_m unit_d; rewrite -{2}def_m natrM mulrK. Qed. Lemma unitr0 : (0 \is a @unit R) = false. Proof. by apply/unitrP=> [[x [_]]]; apply/eqP; rewrite mul0r eq_sym oner_neq0. Qed. Lemma invr0 : 0^-1 = 0 :> R. Proof. by rewrite invr_out ?unitr0. Qed. Lemma unitrN1 : -1 \is a @unit R. Proof. by apply/unitrP; exists (-1); rewrite mulrNN mulr1. Qed. Lemma invrN1 : (-1)^-1 = -1 :> R. Proof. by rewrite -{2}(divrr unitrN1) mulN1r opprK. Qed. Lemma invr_sign n : ((-1) ^- n) = (-1) ^+ n :> R. Proof. by rewrite -signr_odd; case: (odd n); rewrite (invr1, invrN1). Qed. Lemma unitrMl x y : y \is a unit -> (x * y \is a unit) = (x \is a unit). Proof. move=> Uy; wlog Ux: x y Uy / x \is a unit => [WHxy|]. by apply/idP/idP=> Ux; first rewrite -(mulrK Uy x); rewrite WHxy ?unitrV. rewrite Ux; apply/unitrP; exists (y^-1 * x^-1). by rewrite -!mulrA mulKr ?mulrA ?mulrK ?divrr ?mulVr. Qed. Lemma unitrMr x y : x \is a unit -> (x * y \is a unit) = (y \is a unit). Proof. move=> Ux; apply/idP/idP=> [Uxy | Uy]; last by rewrite unitrMl. by rewrite -(mulKr Ux y) unitrMl ?unitrV. Qed. Lemma invrM : {in unit &, forall x y, (x * y)^-1 = y^-1 * x^-1}. Proof. move=> x y Ux Uy; have Uxy: (x * y \in unit) by rewrite unitrMl. by apply: (mulrI Uxy); rewrite divrr ?mulrA ?mulrK ?divrr. Qed. Lemma unitrM_comm x y : comm x y -> (x * y \is a unit) = (x \is a unit) && (y \is a unit). Proof. move=> cxy; apply/idP/andP=> [Uxy | [Ux Uy]]; last by rewrite unitrMl. suffices Ux: x \in unit by rewrite unitrMr in Uxy. apply/unitrP; case/unitrP: Uxy => z [zxy xyz]; exists (y * z). rewrite mulrA xyz -{1}[y]mul1r -{1}zxy cxy -!mulrA (mulrA x) (mulrA _ z) xyz. by rewrite mul1r -cxy. Qed. Lemma unitrX x n : x \is a unit -> x ^+ n \is a unit. Proof. by move=> Ux; elim: n => [|n IHn]; rewrite ?unitr1 // exprS unitrMl. Qed. Lemma unitrX_pos x n : n > 0 -> (x ^+ n \in unit) = (x \in unit). Proof. case: n => // n _; rewrite exprS unitrM_comm; last exact: commrX. by case Ux: (x \is a unit); rewrite // unitrX. Qed. Lemma exprVn x n : x^-1 ^+ n = x ^- n. Proof. elim: n => [|n IHn]; first by rewrite !expr0 ?invr1. case Ux: (x \is a unit); first by rewrite exprSr exprS IHn -invrM // unitrX. by rewrite !invr_out ?unitrX_pos ?Ux. Qed. Lemma exprB m n x : n <= m -> x \is a unit -> x ^+ (m - n) = x ^+ m / x ^+ n. Proof. by move/subnK=> {2}<- Ux; rewrite exprD mulrK ?unitrX. Qed. Lemma invr_neq0 x : x != 0 -> x^-1 != 0. Proof. move=> nx0; case Ux: (x \is a unit); last by rewrite invr_out ?Ux. by apply/eqP=> x'0; rewrite -unitrV x'0 unitr0 in Ux. Qed. Lemma invr_eq0 x : (x^-1 == 0) = (x == 0). Proof. by apply: negb_inj; apply/idP/idP; move/invr_neq0; rewrite ?invrK. Qed. Lemma invr_eq1 x : (x^-1 == 1) = (x == 1). Proof. by rewrite (inv_eq invrK) invr1. Qed. Lemma rev_unitrP (x y : R^c) : y * x = 1 /\ x * y = 1 -> x \is a unit. Proof. by case=> [yx1 xy1]; apply/unitrP; exists y. Qed. Definition converse_unitRingMixin := @UnitRing.Mixin _ ((unit : pred_class) : pred R^c) _ mulrV mulVr rev_unitrP invr_out. Canonical converse_unitRingType := UnitRingType R^c converse_unitRingMixin. Canonical regular_unitRingType := [unitRingType of R^o]. Section ClosedPredicates. Variables S : predPredType R. Definition invr_closed := {in S, forall x, x^-1 \in S}. Definition divr_2closed := {in S &, forall x y, x / y \in S}. Definition divr_closed := 1 \in S /\ divr_2closed. Definition sdivr_closed := -1 \in S /\ divr_2closed. Definition divring_closed := [/\ 1 \in S, subr_2closed S & divr_2closed]. Lemma divr_closedV : divr_closed -> invr_closed. Proof. by case=> S1 Sdiv x Sx; rewrite -[x^-1]mul1r Sdiv. Qed. Lemma divr_closedM : divr_closed -> mulr_closed S. Proof. by case=> S1 Sdiv; split=> // x y Sx Sy; rewrite -[y]invrK -[y^-1]mul1r !Sdiv. Qed. Lemma sdivr_closed_div : sdivr_closed -> divr_closed. Proof. by case=> SN1 Sdiv; split; rewrite // -(divrr unitrN1) Sdiv. Qed. Lemma sdivr_closedM : sdivr_closed -> smulr_closed S. Proof. by move=> Sdiv; have [_ SM] := divr_closedM (sdivr_closed_div Sdiv); case: Sdiv. Qed. Lemma divring_closedBM : divring_closed -> subring_closed S. Proof. by case=> S1 SB Sdiv; split=> //; case: divr_closedM. Qed. Lemma divring_closed_div : divring_closed -> sdivr_closed. Proof. case=> S1 SB Sdiv; split; rewrite ?zmod_closedN //. exact/subring_closedB/divring_closedBM. Qed. End ClosedPredicates. End UnitRingTheory. Implicit Arguments invr_inj [[R] x1 x2]. Section UnitRingMorphism. Variables (R S : unitRingType) (f : {rmorphism R -> S}). Lemma rmorph_unit x : x \in unit -> f x \in unit. Proof. case/unitrP=> y [yx1 xy1]; apply/unitrP. by exists (f y); rewrite -!rmorphM // yx1 xy1 rmorph1. Qed. Lemma rmorphV : {in unit, {morph f: x / x^-1}}. Proof. move=> x Ux; rewrite /= -[(f x)^-1]mul1r. by apply: (canRL (mulrK (rmorph_unit Ux))); rewrite -rmorphM mulVr ?rmorph1. Qed. Lemma rmorph_div x y : y \in unit -> f (x / y) = f x / f y. Proof. by move=> Uy; rewrite rmorphM rmorphV. Qed. End UnitRingMorphism. Module ComUnitRing. Section Mixin. Variables (R : comRingType) (unit : pred R) (inv : R -> R). Hypothesis mulVx : {in unit, left_inverse 1 inv *%R}. Hypothesis unitPl : forall x y, y * x = 1 -> unit x. Fact mulC_mulrV : {in unit, right_inverse 1 inv *%R}. Proof. by move=> x Ux /=; rewrite mulrC mulVx. Qed. Fact mulC_unitP x y : y * x = 1 /\ x * y = 1 -> unit x. Proof. case=> yx _; exact: unitPl yx. Qed. Definition Mixin := UnitRingMixin mulVx mulC_mulrV mulC_unitP. End Mixin. Section ClassDef. Record class_of (R : Type) : Type := Class { base : ComRing.class_of R; mixin : UnitRing.mixin_of (Ring.Pack base R) }. Local Coercion base : class_of >-> ComRing.class_of. Definition base2 R m := UnitRing.Class (@mixin R m). Local Coercion base2 : class_of >-> UnitRing.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variables (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack := fun bT b & phant_id (ComRing.class bT) (b : ComRing.class_of T) => fun mT m & phant_id (UnitRing.class mT) (@UnitRing.Class T b m) => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. Definition comRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @UnitRing.Pack cT xclass xT. Definition com_unitRingType := @UnitRing.Pack comRingType xclass xT. End ClassDef. Module Import Exports. Coercion base : class_of >-> ComRing.class_of. Coercion mixin : class_of >-> UnitRing.mixin_of. Coercion base2 : class_of >-> UnitRing.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Coercion comRingType : type >-> ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> UnitRing.type. Canonical unitRingType. Canonical com_unitRingType. Notation comUnitRingType := type. Notation ComUnitRingMixin := Mixin. Notation "[ 'comUnitRingType' 'of' T ]" := (@pack T _ _ id _ _ id) (at level 0, format "[ 'comUnitRingType' 'of' T ]") : form_scope. End Exports. End ComUnitRing. Import ComUnitRing.Exports. Module UnitAlgebra. Section ClassDef. Variable R : ringType. Record class_of (T : Type) : Type := Class { base : Algebra.class_of R T; mixin : GRing.UnitRing.mixin_of (Ring.Pack base T) }. Definition base2 R m := UnitRing.Class (@mixin R m). Local Coercion base : class_of >-> Algebra.class_of. Local Coercion base2 : class_of >-> UnitRing.class_of. Structure type (phR : phant R) := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variable (phR : phant R) (T : Type) (cT : type phR). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack := fun bT b & phant_id (@Algebra.class R phR bT) (b : Algebra.class_of R T) => fun mT m & phant_id (UnitRing.mixin (UnitRing.class mT)) m => Pack (Phant R) (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. Definition unitRingType := @UnitRing.Pack cT xclass xT. Definition lmodType := @Lmodule.Pack R phR cT xclass xT. Definition lalgType := @Lalgebra.Pack R phR cT xclass xT. Definition algType := @Algebra.Pack R phR cT xclass xT. Definition lmod_unitRingType := @Lmodule.Pack R phR unitRingType xclass xT. Definition lalg_unitRingType := @Lalgebra.Pack R phR unitRingType xclass xT. Definition alg_unitRingType := @Algebra.Pack R phR unitRingType xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> Algebra.class_of. Coercion base2 : class_of >-> UnitRing.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Coercion unitRingType : type >-> UnitRing.type. Canonical unitRingType. Coercion lmodType : type >-> Lmodule.type. Canonical lmodType. Coercion lalgType : type >-> Lalgebra.type. Canonical lalgType. Coercion algType : type >-> Algebra.type. Canonical algType. Canonical lmod_unitRingType. Canonical lalg_unitRingType. Canonical alg_unitRingType. Notation unitAlgType R := (type (Phant R)). Notation "[ 'unitAlgType' R 'of' T ]" := (@pack _ (Phant R) T _ _ id _ _ id) (at level 0, format "[ 'unitAlgType' R 'of' T ]") : form_scope. End Exports. End UnitAlgebra. Import UnitAlgebra.Exports. Section ComUnitRingTheory. Variable R : comUnitRingType. Implicit Types x y : R. Lemma unitrM x y : (x * y \in unit) = (x \in unit) && (y \in unit). Proof. by apply: unitrM_comm; exact: mulrC. Qed. Lemma unitrPr x : reflect (exists y, x * y = 1) (x \in unit). Proof. by apply: (iffP (unitrP x)) => [[y []] | [y]]; exists y; rewrite // mulrC. Qed. Lemma expr_div_n x y n : (x / y) ^+ n = x ^+ n / y ^+ n. Proof. by rewrite exprMn exprVn. Qed. Canonical regular_comUnitRingType := [comUnitRingType of R^o]. Canonical regular_unitAlgType := [unitAlgType R of R^o]. End ComUnitRingTheory. Section UnitAlgebraTheory. Variable (R : comUnitRingType) (A : unitAlgType R). Implicit Types (k : R) (x y : A). Lemma scaler_injl : {in unit, @right_injective R A A *:%R}. Proof. move=> k Uk x1 x2 Hx1x2. by rewrite -[x1]scale1r -(mulVr Uk) -scalerA Hx1x2 scalerA mulVr // scale1r. Qed. Lemma scaler_unit k x : k \in unit -> (k *: x \in unit) = (x \in unit). Proof. move=> Uk; apply/idP/idP=> [Ukx | Ux]; apply/unitrP; last first. exists (k^-1 *: x^-1). by rewrite -!scalerAl -!scalerAr !scalerA !mulVr // !mulrV // scale1r. exists (k *: (k *: x)^-1); split. apply: (mulrI Ukx). by rewrite mulr1 mulrA -scalerAr mulrV // -scalerAl mul1r. apply: (mulIr Ukx). by rewrite mul1r -mulrA -scalerAl mulVr // -scalerAr mulr1. Qed. Lemma invrZ k x : k \in unit -> x \in unit -> (k *: x)^-1 = k^-1 *: x^-1. Proof. move=> Uk Ux; have Ukx: (k *: x \in unit) by rewrite scaler_unit. apply: (mulIr Ukx). by rewrite mulVr // -scalerAl -scalerAr scalerA !mulVr // scale1r. Qed. Section ClosedPredicates. Variables S : predPredType A. Definition divalg_closed := [/\ 1 \in S, linear_closed S & divr_2closed S]. Lemma divalg_closedBdiv : divalg_closed -> divring_closed S. Proof. by case=> S1 /linear_closedB. Qed. Lemma divalg_closedZ : divalg_closed -> subalg_closed S. Proof. by case=> S1 Slin Sdiv; split=> //; have [] := @divr_closedM A S. Qed. End ClosedPredicates. End UnitAlgebraTheory. (* Interface structures for algebraically closed predicates. *) Module Pred. Structure opp V S := Opp {opp_key : pred_key S; _ : @oppr_closed V S}. Structure add V S := Add {add_key : pred_key S; _ : @addr_closed V S}. Structure mul R S := Mul {mul_key : pred_key S; _ : @mulr_closed R S}. Structure zmod V S := Zmod {zmod_add : add S; _ : @oppr_closed V S}. Structure semiring R S := Semiring {semiring_add : add S; _ : @mulr_closed R S}. Structure smul R S := Smul {smul_opp : opp S; _ : @mulr_closed R S}. Structure div R S := Div {div_mul : mul S; _ : @invr_closed R S}. Structure submod R V S := Submod {submod_zmod : zmod S; _ : @scaler_closed R V S}. Structure subring R S := Subring {subring_zmod : zmod S; _ : @mulr_closed R S}. Structure sdiv R S := Sdiv {sdiv_smul : smul S; _ : @invr_closed R S}. Structure subalg (R : ringType) (A : lalgType R) S := Subalg {subalg_ring : subring S; _ : @scaler_closed R A S}. Structure divring R S := Divring {divring_ring : subring S; _ : @invr_closed R S}. Structure divalg (R : ringType) (A : unitAlgType R) S := Divalg {divalg_ring : divring S; _ : @scaler_closed R A S}. Section Subtyping. Ltac done := case=> *; assumption. Fact zmod_oppr R S : @zmod R S -> oppr_closed S. Proof. by []. Qed. Fact semiring_mulr R S : @semiring R S -> mulr_closed S. Proof. by []. Qed. Fact smul_mulr R S : @smul R S -> mulr_closed S. Proof. by []. Qed. Fact submod_scaler R V S : @submod R V S -> scaler_closed S. Proof. by []. Qed. Fact subring_mulr R S : @subring R S -> mulr_closed S. Proof. by []. Qed. Fact sdiv_invr R S : @sdiv R S -> invr_closed S. Proof. by []. Qed. Fact subalg_scaler R A S : @subalg R A S -> scaler_closed S. Proof. by []. Qed. Fact divring_invr R S : @divring R S -> invr_closed S. Proof. by []. Qed. Fact divalg_scaler R A S : @divalg R A S -> scaler_closed S. Proof. by []. Qed. Definition zmod_opp R S (addS : @zmod R S) := Opp (add_key (zmod_add addS)) (zmod_oppr addS). Definition semiring_mul R S (ringS : @semiring R S) := Mul (add_key (semiring_add ringS)) (semiring_mulr ringS). Definition smul_mul R S (mulS : @smul R S) := Mul (opp_key (smul_opp mulS)) (smul_mulr mulS). Definition subring_semi R S (ringS : @subring R S) := Semiring (zmod_add (subring_zmod ringS)) (subring_mulr ringS). Definition subring_smul R S (ringS : @subring R S) := Smul (zmod_opp (subring_zmod ringS)) (subring_mulr ringS). Definition sdiv_div R S (divS : @sdiv R S) := Div (smul_mul (sdiv_smul divS)) (sdiv_invr divS). Definition subalg_submod R A S (algS : @subalg R A S) := Submod (subring_zmod (subalg_ring algS)) (subalg_scaler algS). Definition divring_sdiv R S (ringS : @divring R S) := Sdiv (subring_smul (divring_ring ringS)) (divring_invr ringS). Definition divalg_alg R A S (algS : @divalg R A S) := Subalg (divring_ring (divalg_ring algS)) (divalg_scaler algS). End Subtyping. Section Extensionality. (* This could be avoided by exploiting the Coq 8.4 eta-convertibility. *) Lemma opp_ext (U : zmodType) S k (kS : @keyed_pred U S k) : oppr_closed kS -> oppr_closed S. Proof. by move=> oppS x; rewrite -!(keyed_predE kS); apply: oppS. Qed. Lemma add_ext (U : zmodType) S k (kS : @keyed_pred U S k) : addr_closed kS -> addr_closed S. Proof. by case=> S0 addS; split=> [|x y]; rewrite -!(keyed_predE kS) //; apply: addS. Qed. Lemma mul_ext (R : ringType) S k (kS : @keyed_pred R S k) : mulr_closed kS -> mulr_closed S. Proof. by case=> S1 mulS; split=> [|x y]; rewrite -!(keyed_predE kS) //; apply: mulS. Qed. Lemma scale_ext (R : ringType) (U : lmodType R) S k (kS : @keyed_pred U S k) : scaler_closed kS -> scaler_closed S. Proof. by move=> linS a x; rewrite -!(keyed_predE kS); apply: linS. Qed. Lemma inv_ext (R : unitRingType) S k (kS : @keyed_pred R S k) : invr_closed kS -> invr_closed S. Proof. by move=> invS x; rewrite -!(keyed_predE kS); apply: invS. Qed. End Extensionality. Module Default. Definition opp V S oppS := @Opp V S (DefaultPredKey S) oppS. Definition add V S addS := @Add V S (DefaultPredKey S) addS. Definition mul R S mulS := @Mul R S (DefaultPredKey S) mulS. Definition zmod V S addS oppS := @Zmod V S (add addS) oppS. Definition semiring R S addS mulS := @Semiring R S (add addS) mulS. Definition smul R S oppS mulS := @Smul R S (opp oppS) mulS. Definition div R S mulS invS := @Div R S (mul mulS) invS. Definition submod R V S addS oppS linS := @Submod R V S (zmod addS oppS) linS. Definition subring R S addS oppS mulS := @Subring R S (zmod addS oppS) mulS. Definition sdiv R S oppS mulS invS := @Sdiv R S (smul oppS mulS) invS. Definition subalg R A S addS oppS mulS linS := @Subalg R A S (subring addS oppS mulS) linS. Definition divring R S addS oppS mulS invS := @Divring R S (subring addS oppS mulS) invS. Definition divalg R A S addS oppS mulS invS linS := @Divalg R A S (divring addS oppS mulS invS) linS. End Default. Module Exports. Notation oppr_closed := oppr_closed. Notation addr_closed := addr_closed. Notation mulr_closed := mulr_closed. Notation zmod_closed := zmod_closed. Notation smulr_closed := smulr_closed. Notation invr_closed := invr_closed. Notation divr_closed := divr_closed. Notation linear_closed := linear_closed. Notation submod_closed := submod_closed. Notation semiring_closed := semiring_closed. Notation subring_closed := subring_closed. Notation sdivr_closed := sdivr_closed. Notation subalg_closed := subalg_closed. Notation divring_closed := divring_closed. Notation divalg_closed := divalg_closed. Coercion zmod_closedD : zmod_closed >-> addr_closed. Coercion zmod_closedN : zmod_closed >-> oppr_closed. Coercion smulr_closedN : smulr_closed >-> oppr_closed. Coercion smulr_closedM : smulr_closed >-> mulr_closed. Coercion divr_closedV : divr_closed >-> invr_closed. Coercion divr_closedM : divr_closed >-> mulr_closed. Coercion submod_closedZ : submod_closed >-> scaler_closed. Coercion submod_closedB : submod_closed >-> zmod_closed. Coercion semiring_closedD : semiring_closed >-> addr_closed. Coercion semiring_closedM : semiring_closed >-> mulr_closed. Coercion subring_closedB : subring_closed >-> zmod_closed. Coercion subring_closedM : subring_closed >-> smulr_closed. Coercion subring_closed_semi : subring_closed >-> semiring_closed. Coercion sdivr_closedM : sdivr_closed >-> smulr_closed. Coercion sdivr_closed_div : sdivr_closed >-> divr_closed. Coercion subalg_closedZ : subalg_closed >-> submod_closed. Coercion subalg_closedBM : subalg_closed >-> subring_closed. Coercion divring_closedBM : divring_closed >-> subring_closed. Coercion divring_closed_div : divring_closed >-> sdivr_closed. Coercion divalg_closedZ : divalg_closed >-> subalg_closed. Coercion divalg_closedBdiv : divalg_closed >-> divring_closed. Coercion opp_key : opp >-> pred_key. Coercion add_key : add >-> pred_key. Coercion mul_key : mul >-> pred_key. Coercion zmod_opp : zmod >-> opp. Canonical zmod_opp. Coercion zmod_add : zmod >-> add. Coercion semiring_add : semiring >-> add. Coercion semiring_mul : semiring >-> mul. Canonical semiring_mul. Coercion smul_opp : smul >-> opp. Coercion smul_mul : smul >-> mul. Canonical smul_mul. Coercion div_mul : div >-> mul. Coercion submod_zmod : submod >-> zmod. Coercion subring_zmod : subring >-> zmod. Coercion subring_semi : subring >-> semiring. Canonical subring_semi. Coercion subring_smul : subring >-> smul. Canonical subring_smul. Coercion sdiv_smul : sdiv >-> smul. Coercion sdiv_div : sdiv >-> div. Canonical sdiv_div. Coercion subalg_submod : subalg >-> submod. Canonical subalg_submod. Coercion subalg_ring : subalg >-> subring. Coercion divring_ring : divring >-> subring. Coercion divring_sdiv : divring >-> sdiv. Canonical divring_sdiv. Coercion divalg_alg : divalg >-> subalg. Canonical divalg_alg. Coercion divalg_ring : divalg >-> divring. Notation opprPred := opp. Notation addrPred := add. Notation mulrPred := mul. Notation zmodPred := zmod. Notation semiringPred := semiring. Notation smulrPred := smul. Notation divrPred := div. Notation submodPred := submod. Notation subringPred := subring. Notation sdivrPred := sdiv. Notation subalgPred := subalg. Notation divringPred := divring. Notation divalgPred := divalg. Definition OpprPred U S k kS NkS := Opp k (@opp_ext U S k kS NkS). Definition AddrPred U S k kS DkS := Add k (@add_ext U S k kS DkS). Definition MulrPred R S k kS MkS := Mul k (@mul_ext R S k kS MkS). Definition ZmodPred U S k kS NkS := Zmod k (@opp_ext U S k kS NkS). Definition SemiringPred R S k kS MkS := Semiring k (@mul_ext R S k kS MkS). Definition SmulrPred R S k kS MkS := Smul k (@mul_ext R S k kS MkS). Definition DivrPred R S k kS VkS := Div k (@inv_ext R S k kS VkS). Definition SubmodPred R U S k kS ZkS := Submod k (@scale_ext R U S k kS ZkS). Definition SubringPred R S k kS MkS := Subring k (@mul_ext R S k kS MkS). Definition SdivrPred R S k kS VkS := Sdiv k (@inv_ext R S k kS VkS). Definition SubalgPred (R : ringType) (A : lalgType R) S k kS ZkS := Subalg k (@scale_ext R A S k kS ZkS). Definition DivringPred R S k kS VkS := Divring k (@inv_ext R S k kS VkS). Definition DivalgPred (R : ringType) (A : unitAlgType R) S k kS ZkS := Divalg k (@scale_ext R A S k kS ZkS). End Exports. End Pred. Import Pred.Exports. Module DefaultPred. Canonical Pred.Default.opp. Canonical Pred.Default.add. Canonical Pred.Default.mul. Canonical Pred.Default.zmod. Canonical Pred.Default.semiring. Canonical Pred.Default.smul. Canonical Pred.Default.div. Canonical Pred.Default.submod. Canonical Pred.Default.subring. Canonical Pred.Default.sdiv. Canonical Pred.Default.subalg. Canonical Pred.Default.divring. Canonical Pred.Default.divalg. End DefaultPred. Section ZmodulePred. Variables (V : zmodType) (S : predPredType V). Section Add. Variables (addS : addrPred S) (kS : keyed_pred addS). Lemma rpred0D : addr_closed kS. Proof. by split=> [|x y]; rewrite !keyed_predE; case: addS => _ [_]//; apply. Qed. Lemma rpred0 : 0 \in kS. Proof. by case: rpred0D. Qed. Lemma rpredD : {in kS &, forall u v, u + v \in kS}. Proof. by case: rpred0D. Qed. Lemma rpred_sum I r (P : pred I) F : (forall i, P i -> F i \in kS) -> \sum_(i <- r | P i) F i \in kS. Proof. by move=> IH; elim/big_ind: _; [exact: rpred0 | exact: rpredD |]. Qed. Lemma rpredMn n : {in kS, forall u, u *+ n \in kS}. Proof. by move=> u Su; rewrite -(card_ord n) -sumr_const rpred_sum. Qed. End Add. Section Opp. Variables (oppS : opprPred S) (kS : keyed_pred oppS). Lemma rpredNr : oppr_closed kS. Proof. by move=> x; rewrite !keyed_predE; case: oppS => _; apply. Qed. Lemma rpredN : {mono -%R: u / u \in kS}. Proof. by move=> u; apply/idP/idP=> /rpredNr; rewrite ?opprK; apply. Qed. End Opp. Section Sub. Variables (subS : zmodPred S) (kS : keyed_pred subS). Lemma rpredB : {in kS &, forall u v, u - v \in kS}. Proof. by move=> u v Su Sv; rewrite /= rpredD ?rpredN. Qed. Lemma rpredMNn n : {in kS, forall u, u *- n \in kS}. Proof. by move=> u Su; rewrite /= rpredN rpredMn. Qed. Lemma rpredDr x y : x \in kS -> (y + x \in kS) = (y \in kS). Proof. move=> Sx; apply/idP/idP=> [Sxy | /rpredD-> //]. by rewrite -(addrK x y) rpredB. Qed. Lemma rpredDl x y : x \in kS -> (x + y \in kS) = (y \in kS). Proof. by rewrite addrC; apply: rpredDr. Qed. Lemma rpredBr x y : x \in kS -> (y - x \in kS) = (y \in kS). Proof. by rewrite -rpredN; apply: rpredDr. Qed. Lemma rpredBl x y : x \in kS -> (x - y \in kS) = (y \in kS). Proof. by rewrite -(rpredN _ y); apply: rpredDl. Qed. End Sub. End ZmodulePred. Section RingPred. Variables (R : ringType) (S : predPredType R). Lemma rpredMsign (oppS : opprPred S) (kS : keyed_pred oppS) n x : ((-1) ^+ n * x \in kS) = (x \in kS). Proof. by rewrite -signr_odd mulr_sign; case: ifP => // _; rewrite rpredN. Qed. Section Mul. Variables (mulS : mulrPred S) (kS : keyed_pred mulS). Lemma rpred1M : mulr_closed kS. Proof. by split=> [|x y]; rewrite !keyed_predE; case: mulS => _ [_] //; apply. Qed. Lemma rpred1 : 1 \in kS. Proof. by case: rpred1M. Qed. Lemma rpredM : {in kS &, forall u v, u * v \in kS}. Proof. by case: rpred1M. Qed. Lemma rpred_prod I r (P : pred I) F : (forall i, P i -> F i \in kS) -> \prod_(i <- r | P i) F i \in kS. Proof. by move=> IH; elim/big_ind: _; [exact: rpred1 | exact: rpredM |]. Qed. Lemma rpredX n : {in kS, forall u, u ^+ n \in kS}. Proof. by move=> u Su; rewrite -(card_ord n) -prodr_const rpred_prod. Qed. End Mul. Lemma rpred_nat (rngS : semiringPred S) (kS : keyed_pred rngS) n : n%:R \in kS. Proof. by rewrite rpredMn ?rpred1. Qed. Lemma rpredN1 (mulS : smulrPred S) (kS : keyed_pred mulS) : -1 \in kS. Proof. by rewrite rpredN rpred1. Qed. Lemma rpred_sign (mulS : smulrPred S) (kS : keyed_pred mulS) n : (-1) ^+ n \in kS. Proof. by rewrite rpredX ?rpredN1. Qed. End RingPred. Section LmodPred. Variables (R : ringType) (V : lmodType R) (S : predPredType V). Lemma rpredZsign (oppS : opprPred S) (kS : keyed_pred oppS) n u : ((-1) ^+ n *: u \in kS) = (u \in kS). Proof. by rewrite -signr_odd scaler_sign fun_if if_arg rpredN if_same. Qed. Lemma rpredZnat (addS : addrPred S) (kS : keyed_pred addS) n : {in kS, forall u, n%:R *: u \in kS}. Proof. by move=> u Su; rewrite /= scaler_nat rpredMn. Qed. Lemma rpredZ (linS : submodPred S) (kS : keyed_pred linS) : scaler_closed kS. Proof. by move=> a u; rewrite !keyed_predE; case: {kS}linS => _; apply. Qed. End LmodPred. Section UnitRingPred. Variable R : unitRingType. Section Div. Variables (S : predPredType R) (divS : divrPred S) (kS : keyed_pred divS). Lemma rpredVr x : x \in kS -> x^-1 \in kS. Proof. by rewrite !keyed_predE; case: divS x. Qed. Lemma rpredV x : (x^-1 \in kS) = (x \in kS). Proof. by apply/idP/idP=> /rpredVr; rewrite ?invrK. Qed. Lemma rpred_div : {in kS &, forall x y, x / y \in kS}. Proof. by move=> x y Sx Sy; rewrite /= rpredM ?rpredV. Qed. Lemma rpredXN n : {in kS, forall x, x ^- n \in kS}. Proof. by move=> x Sx; rewrite /= rpredV rpredX. Qed. Lemma rpredMl x y : x \in kS -> x \is a unit-> (x * y \in kS) = (y \in kS). Proof. move=> Sx Ux; apply/idP/idP=> [Sxy | /(rpredM Sx)-> //]. by rewrite -(mulKr Ux y); rewrite rpredM ?rpredV. Qed. Lemma rpredMr x y : x \in kS -> x \is a unit -> (y * x \in kS) = (y \in kS). Proof. move=> Sx Ux; apply/idP/idP=> [Sxy | /rpredM-> //]. by rewrite -(mulrK Ux y); rewrite rpred_div. Qed. Lemma rpred_divr x y : x \in kS -> x \is a unit -> (y / x \in kS) = (y \in kS). Proof. by rewrite -rpredV -unitrV; apply: rpredMr. Qed. Lemma rpred_divl x y : x \in kS -> x \is a unit -> (x / y \in kS) = (y \in kS). Proof. by rewrite -(rpredV y); apply: rpredMl. Qed. End Div. Fact unitr_sdivr_closed : @sdivr_closed R unit. Proof. by split=> [|x y Ux Uy]; rewrite ?unitrN1 // unitrMl ?unitrV. Qed. Canonical unit_opprPred := OpprPred unitr_sdivr_closed. Canonical unit_mulrPred := MulrPred unitr_sdivr_closed. Canonical unit_divrPred := DivrPred unitr_sdivr_closed. Canonical unit_smulrPred := SmulrPred unitr_sdivr_closed. Canonical unit_sdivrPred := SdivrPred unitr_sdivr_closed. Implicit Type x : R. Lemma unitrN x : (- x \is a unit) = (x \is a unit). Proof. exact: rpredN. Qed. Lemma invrN x : (- x)^-1 = - x^-1. Proof. have [Ux | U'x] := boolP (x \is a unit); last by rewrite !invr_out ?unitrN. by rewrite -mulN1r invrM ?unitrN1 // invrN1 mulrN1. Qed. Lemma invr_signM n x : ((-1) ^+ n * x)^-1 = (-1) ^+ n * x^-1. Proof. by rewrite -signr_odd !mulr_sign; case: ifP => // _; rewrite invrN. Qed. Lemma divr_signM (b1 b2 : bool) x1 x2: ((-1) ^+ b1 * x1) / ((-1) ^+ b2 * x2) = (-1) ^+ (b1 (+) b2) * (x1 / x2). Proof. by rewrite invr_signM mulr_signM. Qed. End UnitRingPred. (* Reification of the theory of rings with units, in named style *) Section TermDef. Variable R : Type. Inductive term : Type := | Var of nat | Const of R | NatConst of nat | Add of term & term | Opp of term | NatMul of term & nat | Mul of term & term | Inv of term | Exp of term & nat. Inductive formula : Type := | Bool of bool | Equal of term & term | Unit of term | And of formula & formula | Or of formula & formula | Implies of formula & formula | Not of formula | Exists of nat & formula | Forall of nat & formula. End TermDef. Bind Scope term_scope with term. Bind Scope term_scope with formula. Arguments Scope Add [_ term_scope term_scope]. Arguments Scope Opp [_ term_scope]. Arguments Scope NatMul [_ term_scope nat_scope]. Arguments Scope Mul [_ term_scope term_scope]. Arguments Scope Mul [_ term_scope term_scope]. Arguments Scope Inv [_ term_scope]. Arguments Scope Exp [_ term_scope nat_scope]. Arguments Scope Equal [_ term_scope term_scope]. Arguments Scope Unit [_ term_scope]. Arguments Scope And [_ term_scope term_scope]. Arguments Scope Or [_ term_scope term_scope]. Arguments Scope Implies [_ term_scope term_scope]. Arguments Scope Not [_ term_scope]. Arguments Scope Exists [_ nat_scope term_scope]. Arguments Scope Forall [_ nat_scope term_scope]. Implicit Arguments Bool [R]. Prenex Implicits Const Add Opp NatMul Mul Exp Bool Unit And Or Implies Not. Prenex Implicits Exists Forall. Notation True := (Bool true). Notation False := (Bool false). Local Notation "''X_' i" := (Var _ i) : term_scope. Local Notation "n %:R" := (NatConst _ n) : term_scope. Local Notation "x %:T" := (Const x) : term_scope. Local Notation "0" := 0%:R%T : term_scope. Local Notation "1" := 1%:R%T : term_scope. Local Infix "+" := Add : term_scope. Local Notation "- t" := (Opp t) : term_scope. Local Notation "t - u" := (Add t (- u)) : term_scope. Local Infix "*" := Mul : term_scope. Local Infix "*+" := NatMul : term_scope. Local Notation "t ^-1" := (Inv t) : term_scope. Local Notation "t / u" := (Mul t u^-1) : term_scope. Local Infix "^+" := Exp : term_scope. Local Infix "==" := Equal : term_scope. Local Infix "/\" := And : term_scope. Local Infix "\/" := Or : term_scope. Local Infix "==>" := Implies : term_scope. Local Notation "~ f" := (Not f) : term_scope. Local Notation "x != y" := (Not (x == y)) : term_scope. Local Notation "''exists' ''X_' i , f" := (Exists i f) : term_scope. Local Notation "''forall' ''X_' i , f" := (Forall i f) : term_scope. Section Substitution. Variable R : Type. Fixpoint tsubst (t : term R) (s : nat * term R) := match t with | 'X_i => if i == s.1 then s.2 else t | _%:T | _%:R => t | t1 + t2 => tsubst t1 s + tsubst t2 s | - t1 => - tsubst t1 s | t1 *+ n => tsubst t1 s *+ n | t1 * t2 => tsubst t1 s * tsubst t2 s | t1^-1 => (tsubst t1 s)^-1 | t1 ^+ n => tsubst t1 s ^+ n end%T. Fixpoint fsubst (f : formula R) (s : nat * term R) := match f with | Bool _ => f | t1 == t2 => tsubst t1 s == tsubst t2 s | Unit t1 => Unit (tsubst t1 s) | f1 /\ f2 => fsubst f1 s /\ fsubst f2 s | f1 \/ f2 => fsubst f1 s \/ fsubst f2 s | f1 ==> f2 => fsubst f1 s ==> fsubst f2 s | ~ f1 => ~ fsubst f1 s | ('exists 'X_i, f1) => 'exists 'X_i, if i == s.1 then f1 else fsubst f1 s | ('forall 'X_i, f1) => 'forall 'X_i, if i == s.1 then f1 else fsubst f1 s end%T. End Substitution. Section EvalTerm. Variable R : unitRingType. (* Evaluation of a reified term into R a ring with units *) Fixpoint eval (e : seq R) (t : term R) {struct t} : R := match t with | ('X_i)%T => e`_i | (x%:T)%T => x | (n%:R)%T => n%:R | (t1 + t2)%T => eval e t1 + eval e t2 | (- t1)%T => - eval e t1 | (t1 *+ n)%T => eval e t1 *+ n | (t1 * t2)%T => eval e t1 * eval e t2 | t1^-1%T => (eval e t1)^-1 | (t1 ^+ n)%T => eval e t1 ^+ n end. Definition same_env (e e' : seq R) := nth 0 e =1 nth 0 e'. Lemma eq_eval e e' t : same_env e e' -> eval e t = eval e' t. Proof. by move=> eq_e; elim: t => //= t1 -> // t2 ->. Qed. Lemma eval_tsubst e t s : eval e (tsubst t s) = eval (set_nth 0 e s.1 (eval e s.2)) t. Proof. case: s => i u; elim: t => //=; do 2?[move=> ? -> //] => j. by rewrite nth_set_nth /=; case: (_ == _). Qed. (* Evaluation of a reified formula *) Fixpoint holds (e : seq R) (f : formula R) {struct f} : Prop := match f with | Bool b => b | (t1 == t2)%T => eval e t1 = eval e t2 | Unit t1 => eval e t1 \in unit | (f1 /\ f2)%T => holds e f1 /\ holds e f2 | (f1 \/ f2)%T => holds e f1 \/ holds e f2 | (f1 ==> f2)%T => holds e f1 -> holds e f2 | (~ f1)%T => ~ holds e f1 | ('exists 'X_i, f1)%T => exists x, holds (set_nth 0 e i x) f1 | ('forall 'X_i, f1)%T => forall x, holds (set_nth 0 e i x) f1 end. Lemma same_env_sym e e' : same_env e e' -> same_env e' e. Proof. exact: fsym. Qed. (* Extensionality of formula evaluation *) Lemma eq_holds e e' f : same_env e e' -> holds e f -> holds e' f. Proof. pose sv := set_nth (0 : R). have eq_i i v e1 e2: same_env e1 e2 -> same_env (sv e1 i v) (sv e2 i v). by move=> eq_e j; rewrite !nth_set_nth /= eq_e. elim: f e e' => //=. - by move=> t1 t2 e e' eq_e; rewrite !(eq_eval _ eq_e). - by move=> t e e' eq_e; rewrite (eq_eval _ eq_e). - by move=> f1 IH1 f2 IH2 e e' eq_e; move/IH2: (eq_e); move/IH1: eq_e; tauto. - by move=> f1 IH1 f2 IH2 e e' eq_e; move/IH2: (eq_e); move/IH1: eq_e; tauto. - by move=> f1 IH1 f2 IH2 e e' eq_e f12; move/IH1: (same_env_sym eq_e); eauto. - by move=> f1 IH1 e e'; move/same_env_sym; move/IH1; tauto. - by move=> i f1 IH1 e e'; move/(eq_i i)=> eq_e [x f_ex]; exists x; eauto. by move=> i f1 IH1 e e'; move/(eq_i i); eauto. Qed. (* Evaluation and substitution by a constant *) Lemma holds_fsubst e f i v : holds e (fsubst f (i, v%:T)%T) <-> holds (set_nth 0 e i v) f. Proof. elim: f e => //=; do [ by move=> *; rewrite !eval_tsubst | move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto | move=> f IHf e; move: (IHf e); tauto | move=> j f IHf e]. - case eq_ji: (j == i); first rewrite (eqP eq_ji). by split=> [] [x f_x]; exists x; rewrite set_set_nth eqxx in f_x *. split=> [] [x f_x]; exists x; move: f_x; rewrite set_set_nth eq_sym eq_ji; have:= IHf (set_nth 0 e j x); tauto. case eq_ji: (j == i); first rewrite (eqP eq_ji). by split=> [] f_ x; move: (f_ x); rewrite set_set_nth eqxx. split=> [] f_ x; move: (IHf (set_nth 0 e j x)) (f_ x); by rewrite set_set_nth eq_sym eq_ji; tauto. Qed. (* Boolean test selecting terms in the language of rings *) Fixpoint rterm (t : term R) := match t with | _^-1 => false | t1 + t2 | t1 * t2 => rterm t1 && rterm t2 | - t1 | t1 *+ _ | t1 ^+ _ => rterm t1 | _ => true end%T. (* Boolean test selecting formulas in the theory of rings *) Fixpoint rformula (f : formula R) := match f with | Bool _ => true | t1 == t2 => rterm t1 && rterm t2 | Unit t1 => false | f1 /\ f2 | f1 \/ f2 | f1 ==> f2 => rformula f1 && rformula f2 | ~ f1 | ('exists 'X__, f1) | ('forall 'X__, f1) => rformula f1 end%T. (* Upper bound of the names used in a term *) Fixpoint ub_var (t : term R) := match t with | 'X_i => i.+1 | t1 + t2 | t1 * t2 => maxn (ub_var t1) (ub_var t2) | - t1 | t1 *+ _ | t1 ^+ _ | t1^-1 => ub_var t1 | _ => 0%N end%T. (* Replaces inverses in the term t by fresh variables, accumulating the *) (* substitution. *) Fixpoint to_rterm (t : term R) (r : seq (term R)) (n : nat) {struct t} := match t with | t1^-1 => let: (t1', r1) := to_rterm t1 r n in ('X_(n + size r1), rcons r1 t1') | t1 + t2 => let: (t1', r1) := to_rterm t1 r n in let: (t2', r2) := to_rterm t2 r1 n in (t1' + t2', r2) | - t1 => let: (t1', r1) := to_rterm t1 r n in (- t1', r1) | t1 *+ m => let: (t1', r1) := to_rterm t1 r n in (t1' *+ m, r1) | t1 * t2 => let: (t1', r1) := to_rterm t1 r n in let: (t2', r2) := to_rterm t2 r1 n in (Mul t1' t2', r2) | t1 ^+ m => let: (t1', r1) := to_rterm t1 r n in (t1' ^+ m, r1) | _ => (t, r) end%T. Lemma to_rterm_id t r n : rterm t -> to_rterm t r n = (t, r). Proof. elim: t r n => //. - by move=> t1 IHt1 t2 IHt2 r n /= /andP[rt1 rt2]; rewrite {}IHt1 // IHt2. - by move=> t IHt r n /= rt; rewrite {}IHt. - by move=> t IHt r n m /= rt; rewrite {}IHt. - by move=> t1 IHt1 t2 IHt2 r n /= /andP[rt1 rt2]; rewrite {}IHt1 // IHt2. - by move=> t IHt r n m /= rt; rewrite {}IHt. Qed. (* A ring formula stating that t1 is equal to 0 in the ring theory. *) (* Also applies to non commutative rings. *) Definition eq0_rform t1 := let m := ub_var t1 in let: (t1', r1) := to_rterm t1 [::] m in let fix loop r i := match r with | [::] => t1' == 0 | t :: r' => let f := 'X_i * t == 1 /\ t * 'X_i == 1 in 'forall 'X_i, (f \/ 'X_i == t /\ ~ ('exists 'X_i, f)) ==> loop r' i.+1 end%T in loop r1 m. (* Transformation of a formula in the theory of rings with units into an *) (* equivalent formula in the sub-theory of rings. *) Fixpoint to_rform f := match f with | Bool b => f | t1 == t2 => eq0_rform (t1 - t2) | Unit t1 => eq0_rform (t1 * t1^-1 - 1) | f1 /\ f2 => to_rform f1 /\ to_rform f2 | f1 \/ f2 => to_rform f1 \/ to_rform f2 | f1 ==> f2 => to_rform f1 ==> to_rform f2 | ~ f1 => ~ to_rform f1 | ('exists 'X_i, f1) => 'exists 'X_i, to_rform f1 | ('forall 'X_i, f1) => 'forall 'X_i, to_rform f1 end%T. (* The transformation gives a ring formula. *) Lemma to_rform_rformula f : rformula (to_rform f). Proof. suffices eq0_ring t1: rformula (eq0_rform t1) by elim: f => //= => f1 ->. rewrite /eq0_rform; move: (ub_var t1) => m; set tr := _ m. suffices: all rterm (tr.1 :: tr.2). case: tr => {t1} t1 r /= /andP[t1_r]. by elim: r m => [|t r IHr] m; rewrite /= ?andbT // => /andP[->]; exact: IHr. have: all rterm [::] by []. rewrite {}/tr; elim: t1 [::] => //=. - move=> t1 IHt1 t2 IHt2 r. move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /= /andP[t1_r]. move/IHt2; case: to_rterm => {t2 r IHt2} t2 r /= /andP[t2_r]. by rewrite t1_r t2_r. - by move=> t1 IHt1 r /IHt1; case: to_rterm. - by move=> t1 IHt1 n r /IHt1; case: to_rterm. - move=> t1 IHt1 t2 IHt2 r. move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /= /andP[t1_r]. move/IHt2; case: to_rterm => {t2 r IHt2} t2 r /= /andP[t2_r]. by rewrite t1_r t2_r. - move=> t1 IHt1 r. by move/IHt1; case: to_rterm => {t1 r IHt1} t1 r /=; rewrite all_rcons. - by move=> t1 IHt1 n r /IHt1; case: to_rterm. Qed. (* Correctness of the transformation. *) Lemma to_rformP e f : holds e (to_rform f) <-> holds e f. Proof. suffices{e f} equal0_equiv e t1 t2: holds e (eq0_rform (t1 - t2)) <-> (eval e t1 == eval e t2). - elim: f e => /=; try tauto. + move=> t1 t2 e. by split; [move/equal0_equiv/eqP | move/eqP/equal0_equiv]. + move=> t1 e; rewrite unitrE; exact: equal0_equiv. + move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto. + move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto. + move=> f1 IHf1 f2 IHf2 e; move: (IHf1 e) (IHf2 e); tauto. + move=> f1 IHf1 e; move: (IHf1 e); tauto. + by move=> n f1 IHf1 e; split=> [] [x] /IHf1; exists x. + by move=> n f1 IHf1 e; split=> Hx x; apply/IHf1. rewrite -(add0r (eval e t2)) -(can2_eq (subrK _) (addrK _)). rewrite -/(eval e (t1 - t2)); move: (t1 - t2)%T => {t1 t2} t. have sub_var_tsubst s t0: s.1 >= ub_var t0 -> tsubst t0 s = t0. elim: t0 {t} => //=. - by move=> n; case: ltngtP. - by move=> t1 IHt1 t2 IHt2; rewrite geq_max => /andP[/IHt1-> /IHt2->]. - by move=> t1 IHt1 /IHt1->. - by move=> t1 IHt1 n /IHt1->. - by move=> t1 IHt1 t2 IHt2; rewrite geq_max => /andP[/IHt1-> /IHt2->]. - by move=> t1 IHt1 /IHt1->. - by move=> t1 IHt1 n /IHt1->. pose fix rsub t' m r : term R := if r is u :: r' then tsubst (rsub t' m.+1 r') (m, u^-1)%T else t'. pose fix ub_sub m r : Prop := if r is u :: r' then ub_var u <= m /\ ub_sub m.+1 r' else true. suffices{t} rsub_to_r t r0 m: m >= ub_var t -> ub_sub m r0 -> let: (t', r) := to_rterm t r0 m in [/\ take (size r0) r = r0, ub_var t' <= m + size r, ub_sub m r & rsub t' m r = t]. - have:= rsub_to_r t [::] _ (leqnn _); rewrite /eq0_rform. case: (to_rterm _ _ _) => [t1' r1] [//|_ _ ub_r1 def_t]. rewrite -{2}def_t {def_t}. elim: r1 (ub_var t) e ub_r1 => [|u r1 IHr1] m e /= => [_|[ub_u ub_r1]]. by split=> /eqP. rewrite eval_tsubst /=; set y := eval e u; split=> t_eq0. apply/IHr1=> //; apply: t_eq0. rewrite nth_set_nth /= eqxx -(eval_tsubst e u (m, Const _)). rewrite sub_var_tsubst //= -/y. case Uy: (y \in unit); [left | right]; first by rewrite mulVr ?divrr. split=> [|[z]]; first by rewrite invr_out ?Uy. rewrite nth_set_nth /= eqxx. rewrite -!(eval_tsubst _ _ (m, Const _)) !sub_var_tsubst // -/y => yz1. by case/unitrP: Uy; exists z. move=> x def_x; apply/IHr1=> //; suff ->: x = y^-1 by []; move: def_x. rewrite nth_set_nth /= eqxx -(eval_tsubst e u (m, Const _)). rewrite sub_var_tsubst //= -/y; case=> [[xy1 yx1] | [xy nUy]]. by rewrite -[y^-1]mul1r -[1]xy1 mulrK //; apply/unitrP; exists x. rewrite invr_out //; apply/unitrP=> [[z yz1]]; case: nUy; exists z. rewrite nth_set_nth /= eqxx -!(eval_tsubst _ _ (m, _%:T)%T). by rewrite !sub_var_tsubst. have rsub_id r t0 n: ub_var t0 <= n -> rsub t0 n r = t0. by elim: r n => //= t1 r IHr n let0n; rewrite IHr ?sub_var_tsubst ?leqW. have rsub_acc r s t1 m1: ub_var t1 <= m1 + size r -> rsub t1 m1 (r ++ s) = rsub t1 m1 r. elim: r t1 m1 => [|t1 r IHr] t2 m1 /=; first by rewrite addn0; apply: rsub_id. by move=> letmr; rewrite IHr ?addSnnS. elim: t r0 m => /=; try do [ by move=> n r m hlt hub; rewrite take_size (ltn_addr _ hlt) rsub_id | by move=> n r m hlt hub; rewrite leq0n take_size rsub_id | move=> t1 IHt1 t2 IHt2 r m; rewrite geq_max; case/andP=> hub1 hub2 hmr; case: to_rterm {IHt1 hub1 hmr}(IHt1 r m hub1 hmr) => t1' r1; case=> htake1 hub1' hsub1 <-; case: to_rterm {IHt2 hub2 hsub1}(IHt2 r1 m hub2 hsub1) => t2' r2 /=; rewrite geq_max; case=> htake2 -> hsub2 /= <-; rewrite -{1 2}(cat_take_drop (size r1) r2) htake2; set r3 := drop _ _; rewrite size_cat addnA (leq_trans _ (leq_addr _ _)) //; split=> {hsub2}//; first by [rewrite takel_cat // -htake1 size_take geq_min leqnn orbT]; rewrite -(rsub_acc r1 r3 t1') {hub1'}// -{htake1}htake2 {r3}cat_take_drop; by elim: r2 m => //= u r2 IHr2 m; rewrite IHr2 | do [ move=> t1 IHt1 r m; do 2!move/IHt1=> {IHt1}IHt1 | move=> t1 IHt1 n r m; do 2!move/IHt1=> {IHt1}IHt1]; case: to_rterm IHt1 => t1' r1 [-> -> hsub1 <-]; split=> {hsub1}//; by elim: r1 m => //= u r1 IHr1 m; rewrite IHr1]. move=> t1 IH r m letm /IH {IH} /(_ letm) {letm}. case: to_rterm => t1' r1 /= [def_r ub_t1' ub_r1 <-]. rewrite size_rcons addnS leqnn -{1}cats1 takel_cat ?def_r; last first. by rewrite -def_r size_take geq_min leqnn orbT. elim: r1 m ub_r1 ub_t1' {def_r} => /= [|u r1 IHr1] m => [_|[->]]. by rewrite addn0 eqxx. by rewrite -addSnnS => /IHr1 IH /IH[_ _ ub_r1 ->]. Qed. (* Boolean test selecting formulas which describe a constructible set, *) (* i.e. formulas without quantifiers. *) (* The quantifier elimination check. *) Fixpoint qf_form (f : formula R) := match f with | Bool _ | _ == _ | Unit _ => true | f1 /\ f2 | f1 \/ f2 | f1 ==> f2 => qf_form f1 && qf_form f2 | ~ f1 => qf_form f1 | _ => false end%T. (* Boolean holds predicate for quantifier free formulas *) Definition qf_eval e := fix loop (f : formula R) : bool := match f with | Bool b => b | t1 == t2 => (eval e t1 == eval e t2)%bool | Unit t1 => eval e t1 \in unit | f1 /\ f2 => loop f1 && loop f2 | f1 \/ f2 => loop f1 || loop f2 | f1 ==> f2 => (loop f1 ==> loop f2)%bool | ~ f1 => ~~ loop f1 |_ => false end%T. (* qf_eval is equivalent to holds *) Lemma qf_evalP e f : qf_form f -> reflect (holds e f) (qf_eval e f). Proof. elim: f => //=; try by move=> *; exact: idP. - move=> t1 t2 _; exact: eqP. - move=> f1 IHf1 f2 IHf2 /= /andP[/IHf1[] f1T]; last by right; case. by case/IHf2; [left | right; case]. - move=> f1 IHf1 f2 IHf2 /= /andP[/IHf1[] f1F]; first by do 2 left. by case/IHf2; [left; right | right; case]. - move=> f1 IHf1 f2 IHf2 /= /andP[/IHf1[] f1T]; last by left. by case/IHf2; [left | right; move/(_ f1T)]. by move=> f1 IHf1 /IHf1[]; [right | left]. Qed. Implicit Type bc : seq (term R) * seq (term R). (* Quantifier-free formula are normalized into DNF. A DNF is *) (* represented by the type seq (seq (term R) * seq (term R)), where we *) (* separate positive and negative literals *) (* DNF preserving conjunction *) Definition and_dnf bcs1 bcs2 := \big[cat/nil]_(bc1 <- bcs1) map (fun bc2 => (bc1.1 ++ bc2.1, bc1.2 ++ bc2.2)) bcs2. (* Computes a DNF from a qf ring formula *) Fixpoint qf_to_dnf (f : formula R) (neg : bool) {struct f} := match f with | Bool b => if b (+) neg then [:: ([::], [::])] else [::] | t1 == t2 => [:: if neg then ([::], [:: t1 - t2]) else ([:: t1 - t2], [::])] | f1 /\ f2 => (if neg then cat else and_dnf) [rec f1, neg] [rec f2, neg] | f1 \/ f2 => (if neg then and_dnf else cat) [rec f1, neg] [rec f2, neg] | f1 ==> f2 => (if neg then and_dnf else cat) [rec f1, ~~ neg] [rec f2, neg] | ~ f1 => [rec f1, ~~ neg] | _ => if neg then [:: ([::], [::])] else [::] end%T where "[ 'rec' f , neg ]" := (qf_to_dnf f neg). (* Conversely, transforms a DNF into a formula *) Definition dnf_to_form := let pos_lit t := And (t == 0) in let neg_lit t := And (t != 0) in let cls bc := Or (foldr pos_lit True bc.1 /\ foldr neg_lit True bc.2) in foldr cls False. (* Catenation of dnf is the Or of formulas *) Lemma cat_dnfP e bcs1 bcs2 : qf_eval e (dnf_to_form (bcs1 ++ bcs2)) = qf_eval e (dnf_to_form bcs1 \/ dnf_to_form bcs2). Proof. by elim: bcs1 => //= bc1 bcs1 IH1; rewrite -orbA; congr orb; rewrite IH1. Qed. (* and_dnf is the And of formulas *) Lemma and_dnfP e bcs1 bcs2 : qf_eval e (dnf_to_form (and_dnf bcs1 bcs2)) = qf_eval e (dnf_to_form bcs1 /\ dnf_to_form bcs2). Proof. elim: bcs1 => [|bc1 bcs1 IH1] /=; first by rewrite /and_dnf big_nil. rewrite /and_dnf big_cons -/(and_dnf bcs1 bcs2) cat_dnfP /=. rewrite {}IH1 /= andb_orl; congr orb. elim: bcs2 bc1 {bcs1} => [|bc2 bcs2 IH] bc1 /=; first by rewrite andbF. rewrite {}IH /= andb_orr; congr orb => {bcs2}. suffices aux (l1 l2 : seq (term R)) g : let redg := foldr (And \o g) True in qf_eval e (redg (l1 ++ l2)) = qf_eval e (redg l1 /\ redg l2)%T. + by rewrite 2!aux /= 2!andbA -andbA -andbCA andbA andbCA andbA. by elim: l1 => [| t1 l1 IHl1] //=; rewrite -andbA IHl1. Qed. Lemma qf_to_dnfP e : let qev f b := qf_eval e (dnf_to_form (qf_to_dnf f b)) in forall f, qf_form f && rformula f -> qev f false = qf_eval e f. Proof. move=> qev; have qevT f: qev f true = ~~ qev f false. rewrite {}/qev; elim: f => //=; do [by case | move=> f1 IH1 f2 IH2 | ]. - by move=> t1 t2; rewrite !andbT !orbF. - by rewrite and_dnfP cat_dnfP negb_and -IH1 -IH2. - by rewrite and_dnfP cat_dnfP negb_or -IH1 -IH2. - by rewrite and_dnfP cat_dnfP /= negb_or IH1 -IH2 negbK. by move=> t1 ->; rewrite negbK. rewrite /qev; elim=> //=; first by case. - by move=> t1 t2 _; rewrite subr_eq0 !andbT orbF. - move=> f1 IH1 f2 IH2; rewrite andbCA -andbA andbCA andbA; case/andP. by rewrite and_dnfP /= => /IH1-> /IH2->. - move=> f1 IH1 f2 IH2; rewrite andbCA -andbA andbCA andbA; case/andP. by rewrite cat_dnfP /= => /IH1-> => /IH2->. - move=> f1 IH1 f2 IH2; rewrite andbCA -andbA andbCA andbA; case/andP. by rewrite cat_dnfP /= [qf_eval _ _]qevT -implybE => /IH1 <- /IH2->. by move=> f1 IH1 /IH1 <-; rewrite -qevT. Qed. Lemma dnf_to_form_qf bcs : qf_form (dnf_to_form bcs). Proof. by elim: bcs => //= [[clT clF] _ ->] /=; elim: clT => //=; elim: clF. Qed. Definition dnf_rterm cl := all rterm cl.1 && all rterm cl.2. Lemma qf_to_dnf_rterm f b : rformula f -> all dnf_rterm (qf_to_dnf f b). Proof. set ok := all dnf_rterm. have cat_ok bcs1 bcs2: ok bcs1 -> ok bcs2 -> ok (bcs1 ++ bcs2). by move=> ok1 ok2; rewrite [ok _]all_cat; exact/andP. have and_ok bcs1 bcs2: ok bcs1 -> ok bcs2 -> ok (and_dnf bcs1 bcs2). rewrite /and_dnf unlock; elim: bcs1 => //= cl1 bcs1 IH1; rewrite -andbA. case/and3P=> ok11 ok12 ok1 ok2; rewrite cat_ok ?{}IH1 {bcs1 ok1}//. elim: bcs2 ok2 => //= cl2 bcs2 IH2 /andP[ok2 /IH2->]. by rewrite /dnf_rterm !all_cat ok11 ok12 /= !andbT. elim: f b => //=; [ by do 2!case | | | | | by auto | | ]; try by repeat case/andP || intro; case: ifP; auto. by rewrite /dnf_rterm => ?? [] /= ->. Qed. Lemma dnf_to_rform bcs : rformula (dnf_to_form bcs) = all dnf_rterm bcs. Proof. elim: bcs => //= [[cl1 cl2] bcs ->]; rewrite {2}/dnf_rterm /=; congr (_ && _). by congr andb; [elim: cl1 | elim: cl2] => //= t cl ->; rewrite andbT. Qed. Section If. Variables (pred_f then_f else_f : formula R). Definition If := (pred_f /\ then_f \/ ~ pred_f /\ else_f)%T. Lemma If_form_qf : qf_form pred_f -> qf_form then_f -> qf_form else_f -> qf_form If. Proof. by move=> /= -> -> ->. Qed. Lemma If_form_rf : rformula pred_f -> rformula then_f -> rformula else_f -> rformula If. Proof. by move=> /= -> -> ->. Qed. Lemma eval_If e : let ev := qf_eval e in ev If = (if ev pred_f then ev then_f else ev else_f). Proof. by rewrite /=; case: ifP => _; rewrite ?orbF. Qed. End If. Section Pick. Variables (I : finType) (pred_f then_f : I -> formula R) (else_f : formula R). Definition Pick := \big[Or/False]_(p : {ffun pred I}) ((\big[And/True]_i (if p i then pred_f i else ~ pred_f i)) /\ (if pick p is Some i then then_f i else else_f))%T. Lemma Pick_form_qf : (forall i, qf_form (pred_f i)) -> (forall i, qf_form (then_f i)) -> qf_form else_f -> qf_form Pick. Proof. move=> qfp qft qfe; have mA := (big_morph qf_form) true andb. rewrite mA // big1 //= => p _. rewrite mA // big1 => [|i _]; first by case: pick. by rewrite fun_if if_same /= qfp. Qed. Lemma eval_Pick e (qev := qf_eval e) : let P i := qev (pred_f i) in qev Pick = (if pick P is Some i then qev (then_f i) else qev else_f). Proof. move=> P; rewrite ((big_morph qev) false orb) //= big_orE /=. apply/existsP/idP=> [[p] | true_at_P]. rewrite ((big_morph qev) true andb) //= big_andE /=. case/andP=> /forallP-eq_p_P. rewrite (@eq_pick _ _ P) => [|i]; first by case: pick. by move/(_ i): eq_p_P => /=; case: (p i) => //=; move/negbTE. exists [ffun i => P i] => /=; apply/andP; split. rewrite ((big_morph qev) true andb) //= big_andE /=. by apply/forallP=> i; rewrite /= ffunE; case Pi: (P i) => //=; apply: negbT. rewrite (@eq_pick _ _ P) => [|i]; first by case: pick true_at_P. by rewrite ffunE. Qed. End Pick. Section MultiQuant. Variable f : formula R. Implicit Types (I : seq nat) (e : seq R). Lemma foldExistsP I e : (exists2 e', {in [predC I], same_env e e'} & holds e' f) <-> holds e (foldr Exists f I). Proof. elim: I e => /= [|i I IHi] e. by split=> [[e' eq_e] |]; [apply: eq_holds => i; rewrite eq_e | exists e]. split=> [[e' eq_e f_e'] | [x]]; last set e_x := set_nth 0 e i x. exists e'`_i; apply/IHi; exists e' => // j. by have:= eq_e j; rewrite nth_set_nth /= !inE; case: eqP => // ->. case/IHi=> e' eq_e f_e'; exists e' => // j. by have:= eq_e j; rewrite nth_set_nth /= !inE; case: eqP. Qed. Lemma foldForallP I e : (forall e', {in [predC I], same_env e e'} -> holds e' f) <-> holds e (foldr Forall f I). Proof. elim: I e => /= [|i I IHi] e. by split=> [|f_e e' eq_e]; [exact | apply: eq_holds f_e => i; rewrite eq_e]. split=> [f_e' x | f_e e' eq_e]; first set e_x := set_nth 0 e i x. apply/IHi=> e' eq_e; apply: f_e' => j. by have:= eq_e j; rewrite nth_set_nth /= !inE; case: eqP. move/IHi: (f_e e'`_i); apply=> j. by have:= eq_e j; rewrite nth_set_nth /= !inE; case: eqP => // ->. Qed. End MultiQuant. End EvalTerm. Prenex Implicits dnf_rterm. Module IntegralDomain. Definition axiom (R : ringType) := forall x y : R, x * y = 0 -> (x == 0) || (y == 0). Section ClassDef. Record class_of (R : Type) : Type := Class {base : ComUnitRing.class_of R; mixin : axiom (Ring.Pack base R)}. Local Coercion base : class_of >-> ComUnitRing.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variable (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack b0 (m0 : axiom (@Ring.Pack T b0 T)) := fun bT b & phant_id (ComUnitRing.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. Definition comRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> ComUnitRing.class_of. Implicit Arguments mixin [R x y]. Coercion mixin : class_of >-> axiom. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Coercion comRingType : type >-> ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> ComUnitRing.type. Canonical comUnitRingType. Notation idomainType := type. Notation IdomainType T m := (@pack T _ m _ _ id _ id). Notation "[ 'idomainType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'idomainType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'idomainType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'idomainType' 'of' T ]") : form_scope. End Exports. End IntegralDomain. Import IntegralDomain.Exports. Section IntegralDomainTheory. Variable R : idomainType. Implicit Types x y : R. Lemma mulf_eq0 x y : (x * y == 0) = (x == 0) || (y == 0). Proof. apply/eqP/idP; first by case: R x y => T []. by case/pred2P=> ->; rewrite (mulr0, mul0r). Qed. Lemma prodf_eq0 (I : finType) (P : pred I) (F : I -> R) : reflect (exists2 i, P i & (F i == 0)) (\prod_(i | P i) F i == 0). Proof. apply: (iffP idP) => [|[i Pi /eqP Fi0]]; last first. by rewrite (bigD1 i) //= Fi0 mul0r. elim: (index_enum _) => [|i r IHr]; first by rewrite big_nil oner_eq0. rewrite big_cons /=; have [Pi | _] := ifP; last exact: IHr. by rewrite mulf_eq0; case/orP=> // Fi0; exists i. Qed. Lemma prodf_seq_eq0 I r (P : pred I) (F : I -> R) : (\prod_(i <- r | P i) F i == 0) = has (fun i => P i && (F i == 0)) r. Proof. by rewrite (big_morph _ mulf_eq0 (oner_eq0 _)) big_has_cond. Qed. Lemma mulf_neq0 x y : x != 0 -> y != 0 -> x * y != 0. Proof. move=> x0 y0; rewrite mulf_eq0; exact/norP. Qed. Lemma prodf_neq0 (I : finType) (P : pred I) (F : I -> R) : reflect (forall i, P i -> (F i != 0)) (\prod_(i | P i) F i != 0). Proof. by rewrite (sameP (prodf_eq0 _ _) exists_inP) negb_exists_in; exact: forall_inP. Qed. Lemma prodf_seq_neq0 I r (P : pred I) (F : I -> R) : (\prod_(i <- r | P i) F i != 0) = all (fun i => P i ==> (F i != 0)) r. Proof. rewrite prodf_seq_eq0 -all_predC; apply: eq_all => i /=. by rewrite implybE negb_and. Qed. Lemma expf_eq0 x n : (x ^+ n == 0) = (n > 0) && (x == 0). Proof. elim: n => [|n IHn]; first by rewrite oner_eq0. by rewrite exprS mulf_eq0 IHn andKb. Qed. Lemma sqrf_eq0 x : (x ^+ 2 == 0) = (x == 0). Proof. exact: expf_eq0. Qed. Lemma expf_neq0 x m : x != 0 -> x ^+ m != 0. Proof. by move=> x_nz; rewrite expf_eq0; apply/nandP; right. Qed. Lemma natf_neq0 n : (n%:R != 0 :> R) = [char R]^'.-nat n. Proof. have [-> | /prod_prime_decomp->] := posnP n; first by rewrite eqxx. rewrite !big_seq; elim/big_rec: _ => [|[p e] s /=]; first by rewrite oner_eq0. case/mem_prime_decomp=> p_pr _ _; rewrite pnat_mul pnat_exp eqn0Ngt orbC => <-. by rewrite natrM natrX mulf_eq0 expf_eq0 negb_or negb_and pnatE ?inE p_pr. Qed. Lemma natf0_char n : n > 0 -> n%:R == 0 :> R -> exists p, p \in [char R]. Proof. move=> n_gt0 nR_0; exists (pdiv n`_[char R]). apply: pnatP (pdiv_dvd _); rewrite ?part_pnat // ?pdiv_prime //. by rewrite ltn_neqAle eq_sym partn_eq1 // -natf_neq0 nR_0 /=. Qed. Lemma charf'_nat n : [char R]^'.-nat n = (n%:R != 0 :> R). Proof. have [-> | n_gt0] := posnP n; first by rewrite eqxx. apply/idP/idP => [|nz_n]; last first. by apply/pnatP=> // p p_pr p_dvd_n; apply: contra nz_n => /dvdn_charf <-. apply: contraL => n0; have [// | p charRp] := natf0_char _ n0. have [p_pr _] := andP charRp; rewrite (eq_pnat _ (eq_negn (charf_eq charRp))). by rewrite p'natE // (dvdn_charf charRp) n0. Qed. Lemma charf0P : [char R] =i pred0 <-> (forall n, (n%:R == 0 :> R) = (n == 0)%N). Proof. split=> charF0 n; last by rewrite !inE charF0 andbC; case: eqP => // ->. have [-> | n_gt0] := posnP; first exact: eqxx. by apply/negP; case/natf0_char=> // p; rewrite charF0. Qed. Lemma eqf_sqr x y : (x ^+ 2 == y ^+ 2) = (x == y) || (x == - y). Proof. by rewrite -subr_eq0 subr_sqr mulf_eq0 subr_eq0 addr_eq0. Qed. Lemma mulfI x : x != 0 -> injective ( *%R x). Proof. move=> nz_x y z; rewrite -[x * z]add0r; move/(canLR (addrK _))/eqP. rewrite -mulrN -mulrDr mulf_eq0 (negbTE nz_x) /=. by move/eqP/(canRL (subrK _)); rewrite add0r. Qed. Lemma mulIf x : x != 0 -> injective ( *%R^~ x). Proof. by move=> nz_x y z; rewrite -!(mulrC x); exact: mulfI. Qed. Lemma sqrf_eq1 x : (x ^+ 2 == 1) = (x == 1) || (x == -1). Proof. by rewrite -subr_eq0 subr_sqr_1 mulf_eq0 subr_eq0 addr_eq0. Qed. Lemma expfS_eq1 x n : (x ^+ n.+1 == 1) = (x == 1) || (\sum_(i < n.+1) x ^+ i == 0). Proof. by rewrite -![_ == 1]subr_eq0 subrX1 mulf_eq0. Qed. Lemma lregP x : reflect (lreg x) (x != 0). Proof. by apply: (iffP idP) => [/mulfI | /lreg_neq0]. Qed. Lemma rregP x : reflect (rreg x) (x != 0). Proof. by apply: (iffP idP) => [/mulIf | /rreg_neq0]. Qed. Canonical regular_idomainType := [idomainType of R^o]. End IntegralDomainTheory. Implicit Arguments lregP [[R] [x]]. Implicit Arguments rregP [[R] [x]]. Module Field. Definition mixin_of (F : unitRingType) := forall x : F, x != 0 -> x \in unit. Lemma IdomainMixin R : mixin_of R -> IntegralDomain.axiom R. Proof. move=> m x y xy0; apply/norP=> [[]] /m Ux /m. by rewrite -(unitrMr _ Ux) xy0 unitr0. Qed. Section Mixins. Variables (R : comRingType) (inv : R -> R). Definition axiom := forall x, x != 0 -> inv x * x = 1. Hypothesis mulVx : axiom. Hypothesis inv0 : inv 0 = 0. Fact intro_unit (x y : R) : y * x = 1 -> x != 0. Proof. by move=> yx1; apply: contraNneq (oner_neq0 R) => x0; rewrite -yx1 x0 mulr0. Qed. Fact inv_out : {in predC (predC1 0), inv =1 id}. Proof. by move=> x /negbNE/eqP->. Qed. Definition UnitMixin := ComUnitRing.Mixin mulVx intro_unit inv_out. Lemma Mixin : mixin_of (UnitRing.Pack (UnitRing.Class UnitMixin) R). Proof. by []. Qed. End Mixins. Section ClassDef. Record class_of (F : Type) : Type := Class { base : IntegralDomain.class_of F; mixin : mixin_of (UnitRing.Pack base F) }. Local Coercion base : class_of >-> IntegralDomain.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variable (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack b0 (m0 : mixin_of (@UnitRing.Pack T b0 T)) := fun bT b & phant_id (IntegralDomain.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. Definition comRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @IntegralDomain.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> IntegralDomain.class_of. Implicit Arguments mixin [F x]. Coercion mixin : class_of >-> mixin_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Coercion comRingType : type >-> ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> IntegralDomain.type. Canonical idomainType. Notation fieldType := type. Notation FieldType T m := (@pack T _ m _ _ id _ id). Notation FieldUnitMixin := UnitMixin. Notation FieldIdomainMixin := IdomainMixin. Notation FieldMixin := Mixin. Notation "[ 'fieldType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'fieldType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'fieldType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'fieldType' 'of' T ]") : form_scope. End Exports. End Field. Import Field.Exports. Section FieldTheory. Variable F : fieldType. Implicit Types x y : F. Lemma fieldP : Field.mixin_of F. Proof. by case: F => T []. Qed. Lemma unitfE x : (x \in unit) = (x != 0). Proof. by apply/idP/idP=> [/(memPn _)-> | /fieldP]; rewrite ?unitr0. Qed. Lemma mulVf x : x != 0 -> x^-1 * x = 1. Proof. by rewrite -unitfE; exact: mulVr. Qed. Lemma divff x : x != 0 -> x / x = 1. Proof. by rewrite -unitfE; exact: divrr. Qed. Definition mulfV := divff. Lemma mulKf x : x != 0 -> cancel ( *%R x) ( *%R x^-1). Proof. by rewrite -unitfE; exact: mulKr. Qed. Lemma mulVKf x : x != 0 -> cancel ( *%R x^-1) ( *%R x). Proof. by rewrite -unitfE; exact: mulVKr. Qed. Lemma mulfK x : x != 0 -> cancel ( *%R^~ x) ( *%R^~ x^-1). Proof. by rewrite -unitfE; exact: mulrK. Qed. Lemma mulfVK x : x != 0 -> cancel ( *%R^~ x^-1) ( *%R^~ x). Proof. by rewrite -unitfE; exact: divrK. Qed. Definition divfK := mulfVK. Lemma invfM : {morph @inv F : x y / x * y}. Proof. move=> x y; case: (eqVneq x 0) => [-> |nzx]; first by rewrite !(mul0r, invr0). case: (eqVneq y 0) => [-> |nzy]; first by rewrite !(mulr0, invr0). by rewrite mulrC invrM ?unitfE. Qed. Lemma invf_div x y : (x / y)^-1 = y / x. Proof. by rewrite invfM invrK mulrC. Qed. Lemma expfB_cond m n x : (x == 0) + n <= m -> x ^+ (m - n) = x ^+ m / x ^+ n. Proof. move/subnK=> <-; rewrite addnA addnK !exprD. have [-> | nz_x] := altP eqP; first by rewrite !mulr0 !mul0r. by rewrite mulfK ?expf_neq0. Qed. Lemma expfB m n x : n < m -> x ^+ (m - n) = x ^+ m / x ^+ n. Proof. by move=> lt_n_m; apply: expfB_cond; case: eqP => // _; apply: ltnW. Qed. Lemma prodfV I r (P : pred I) (E : I -> F) : \prod_(i <- r | P i) (E i)^-1 = (\prod_(i <- r | P i) E i)^-1. Proof. by rewrite (big_morph _ invfM (invr1 F)). Qed. Lemma prodf_div I r (P : pred I) (E D : I -> F) : \prod_(i <- r | P i) (E i / D i) = \prod_(i <- r | P i) E i / \prod_(i <- r | P i) D i. Proof. by rewrite big_split prodfV. Qed. Lemma telescope_prodf n m (f : nat -> F) : (forall k, n < k < m -> f k != 0) -> n < m -> \prod_(n <= k < m) (f k.+1 / f k) = f m / f n. Proof. move=> nz_f ltnm; apply: invr_inj; rewrite prodf_div !invf_div -prodf_div. by apply: telescope_prodr => // k /nz_f; rewrite unitfE. Qed. Lemma addf_div x1 y1 x2 y2 : y1 != 0 -> y2 != 0 -> x1 / y1 + x2 / y2 = (x1 * y2 + x2 * y1) / (y1 * y2). Proof. by move=> nzy1 nzy2; rewrite invfM mulrDl !mulrA mulrAC !mulfK. Qed. Lemma mulf_div x1 y1 x2 y2 : (x1 / y1) * (x2 / y2) = (x1 * x2) / (y1 * y2). Proof. by rewrite mulrACA -invfM. Qed. Lemma char0_natf_div : [char F] =i pred0 -> forall m d, d %| m -> (m %/ d)%:R = m%:R / d%:R :> F. Proof. move/charf0P=> char0F m [|d] d_dv_m; first by rewrite divn0 invr0 mulr0. by rewrite natr_div // unitfE char0F. Qed. Section FieldMorphismInj. Variables (R : ringType) (f : {rmorphism F -> R}). Lemma fmorph_eq0 x : (f x == 0) = (x == 0). Proof. have [-> | nz_x] := altP (x =P _); first by rewrite rmorph0 eqxx. apply/eqP; move/(congr1 ( *%R (f x^-1)))/eqP. by rewrite -rmorphM mulVf // mulr0 rmorph1 ?oner_eq0. Qed. Lemma fmorph_inj : injective f. Proof. move=> x y eqfxy; apply/eqP; rewrite -subr_eq0 -fmorph_eq0 rmorphB //. by rewrite eqfxy subrr. Qed. Lemma fmorph_eq1 x : (f x == 1) = (x == 1). Proof. by rewrite -(inj_eq fmorph_inj) rmorph1. Qed. Lemma fmorph_char : [char R] =i [char F]. Proof. by move=> p; rewrite !inE -fmorph_eq0 rmorph_nat. Qed. End FieldMorphismInj. Section FieldMorphismInv. Variables (R : unitRingType) (f : {rmorphism F -> R}). Lemma fmorph_unit x : (f x \in unit) = (x != 0). Proof. have [-> |] := altP (x =P _); first by rewrite rmorph0 unitr0. by rewrite -unitfE; exact: rmorph_unit. Qed. Lemma fmorphV : {morph f: x / x^-1}. Proof. move=> x; have [-> | nz_x] := eqVneq x 0; first by rewrite !(invr0, rmorph0). by rewrite rmorphV ?unitfE. Qed. Lemma fmorph_div : {morph f : x y / x / y}. Proof. by move=> x y; rewrite rmorphM fmorphV. Qed. End FieldMorphismInv. Canonical regular_fieldType := [fieldType of F^o]. Section ModuleTheory. Variable V : lmodType F. Implicit Types (a : F) (v : V). Lemma scalerK a : a != 0 -> cancel ( *:%R a : V -> V) ( *:%R a^-1). Proof. by move=> nz_a v; rewrite scalerA mulVf // scale1r. Qed. Lemma scalerKV a : a != 0 -> cancel ( *:%R a^-1 : V -> V) ( *:%R a). Proof. by rewrite -invr_eq0 -{3}[a]invrK; exact: scalerK. Qed. Lemma scalerI a : a != 0 -> injective ( *:%R a : V -> V). Proof. move=> nz_a; exact: can_inj (scalerK nz_a). Qed. Lemma scaler_eq0 a v : (a *: v == 0) = (a == 0) || (v == 0). Proof. have [-> | nz_a] := altP (a =P _); first by rewrite scale0r eqxx. by rewrite (can2_eq (scalerK nz_a) (scalerKV nz_a)) scaler0. Qed. Lemma rpredZeq S (modS : submodPred S) (kS : keyed_pred modS) a v : (a *: v \in kS) = (a == 0) || (v \in kS). Proof. have [-> | nz_a] := altP eqP; first by rewrite scale0r rpred0. by apply/idP/idP; first rewrite -{2}(scalerK nz_a v); apply: rpredZ. Qed. End ModuleTheory. Lemma char_lalg (A : lalgType F) : [char A] =i [char F]. Proof. by move=> p; rewrite inE -scaler_nat scaler_eq0 oner_eq0 orbF. Qed. Section Predicates. Context (S : pred_class) (divS : @divrPred F S) (kS : keyed_pred divS). Lemma fpredMl x y : x \in kS -> x != 0 -> (x * y \in kS) = (y \in kS). Proof. by rewrite -!unitfE; exact: rpredMl. Qed. Lemma fpredMr x y : x \in kS -> x != 0 -> (y * x \in kS) = (y \in kS). Proof. by rewrite -!unitfE; exact: rpredMr. Qed. Lemma fpred_divl x y : x \in kS -> x != 0 -> (x / y \in kS) = (y \in kS). Proof. by rewrite -!unitfE; exact: rpred_divl. Qed. Lemma fpred_divr x y : x \in kS -> x != 0 -> (y / x \in kS) = (y \in kS). Proof. by rewrite -!unitfE; exact: rpred_divr. Qed. End Predicates. End FieldTheory. Implicit Arguments fmorph_inj [[F] [R] x1 x2]. Module DecidableField. Definition axiom (R : unitRingType) (s : seq R -> pred (formula R)) := forall e f, reflect (holds e f) (s e f). Record mixin_of (R : unitRingType) : Type := Mixin { sat : seq R -> pred (formula R); satP : axiom sat}. Section ClassDef. Record class_of (F : Type) : Type := Class {base : Field.class_of F; mixin : mixin_of (UnitRing.Pack base F)}. Local Coercion base : class_of >-> Field.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variable (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack b0 (m0 : mixin_of (@UnitRing.Pack T b0 T)) := fun bT b & phant_id (Field.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. Definition comRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @IntegralDomain.Pack cT xclass xT. Definition fieldType := @Field.Pack cT xclass xT. End ClassDef. Module Exports. Coercion base : class_of >-> Field.class_of. Coercion mixin : class_of >-> mixin_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Coercion comRingType : type >-> ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> IntegralDomain.type. Canonical idomainType. Coercion fieldType : type >-> Field.type. Canonical fieldType. Notation decFieldType := type. Notation DecFieldType T m := (@pack T _ m _ _ id _ id). Notation DecFieldMixin := Mixin. Notation "[ 'decFieldType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'decFieldType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'decFieldType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'decFieldType' 'of' T ]") : form_scope. End Exports. End DecidableField. Import DecidableField.Exports. Section DecidableFieldTheory. Variable F : decFieldType. Definition sat := DecidableField.sat (DecidableField.class F). Lemma satP : DecidableField.axiom sat. Proof. exact: DecidableField.satP. Qed. Fact sol_subproof n f : reflect (exists s, (size s == n) && sat s f) (sat [::] (foldr Exists f (iota 0 n))). Proof. apply: (iffP (satP _ _)) => [|[s]]; last first. case/andP=> /eqP sz_s /satP f_s; apply/foldExistsP. exists s => // i; rewrite !inE mem_iota -leqNgt add0n => le_n_i. by rewrite !nth_default ?sz_s. case/foldExistsP=> e e0 f_e; set s := take n (set_nth 0 e n 0). have sz_s: size s = n by rewrite size_take size_set_nth leq_max leqnn. exists s; rewrite sz_s eqxx; apply/satP; apply: eq_holds f_e => i. case: (leqP n i) => [le_n_i | lt_i_n]. by rewrite -e0 ?nth_default ?sz_s // !inE mem_iota -leqNgt. by rewrite nth_take // nth_set_nth /= eq_sym eqn_leq leqNgt lt_i_n. Qed. Definition sol n f := if sol_subproof n f is ReflectT sP then xchoose sP else nseq n 0. Lemma size_sol n f : size (sol n f) = n. Proof. rewrite /sol; case: sol_subproof => [sP | _]; last exact: size_nseq. by case/andP: (xchooseP sP) => /eqP. Qed. Lemma solP n f : reflect (exists2 s, size s = n & holds s f) (sat (sol n f) f). Proof. rewrite /sol; case: sol_subproof => [sP | sPn]. case/andP: (xchooseP sP) => _ ->; left. by case: sP => s; case/andP; move/eqP=> <-; move/satP; exists s. apply: (iffP (satP _ _)); first by exists (nseq n 0); rewrite ?size_nseq. by case=> s sz_s; move/satP=> f_s; case: sPn; exists s; rewrite sz_s eqxx. Qed. Lemma eq_sat f1 f2 : (forall e, holds e f1 <-> holds e f2) -> sat^~ f1 =1 sat^~ f2. Proof. by move=> eqf12 e; apply/satP/satP; case: (eqf12 e). Qed. Lemma eq_sol f1 f2 : (forall e, holds e f1 <-> holds e f2) -> sol^~ f1 =1 sol^~ f2. Proof. rewrite /sol => /eq_sat eqf12 n. do 2![case: sol_subproof] => //= [f1s f2s | ns1 [s f2s] | [s f1s] []]. - by apply: eq_xchoose => s; rewrite eqf12. - by case: ns1; exists s; rewrite -eqf12. by exists s; rewrite eqf12. Qed. End DecidableFieldTheory. Implicit Arguments satP [[F] [e] [f]]. Implicit Arguments solP [[F] [n] [f]]. Section QE_Mixin. Variable F : Field.type. Implicit Type f : formula F. Variable proj : nat -> seq (term F) * seq (term F) -> formula F. (* proj is the elimination of a single existential quantifier *) (* The elimination projector is well_formed. *) Definition wf_QE_proj := forall i bc (bc_i := proj i bc), dnf_rterm bc -> qf_form bc_i && rformula bc_i. (* The elimination projector is valid *) Definition valid_QE_proj := forall i bc (ex_i_bc := ('exists 'X_i, dnf_to_form [:: bc])%T) e, dnf_rterm bc -> reflect (holds e ex_i_bc) (qf_eval e (proj i bc)). Hypotheses (wf_proj : wf_QE_proj) (ok_proj : valid_QE_proj). Let elim_aux f n := foldr Or False (map (proj n) (qf_to_dnf f false)). Fixpoint quantifier_elim f := match f with | f1 /\ f2 => (quantifier_elim f1) /\ (quantifier_elim f2) | f1 \/ f2 => (quantifier_elim f1) \/ (quantifier_elim f2) | f1 ==> f2 => (~ quantifier_elim f1) \/ (quantifier_elim f2) | ~ f => ~ quantifier_elim f | ('exists 'X_n, f) => elim_aux (quantifier_elim f) n | ('forall 'X_n, f) => ~ elim_aux (~ quantifier_elim f) n | _ => f end%T. Lemma quantifier_elim_wf f : let qf := quantifier_elim f in rformula f -> qf_form qf && rformula qf. Proof. suffices aux_wf f0 n : let qf := elim_aux f0 n in rformula f0 -> qf_form qf && rformula qf. - by elim: f => //=; do ?[ move=> f1 IH1 f2 IH2; case/andP=> rf1 rf2; case/andP:(IH1 rf1)=> -> ->; case/andP:(IH2 rf2)=> -> -> // | move=> n f1 IH rf1; case/andP: (IH rf1)=> qff rf; rewrite aux_wf ]. rewrite /elim_aux => rf. suffices or_wf fs : let ofs := foldr Or False fs in all (@qf_form F) fs && all (@rformula F) fs -> qf_form ofs && rformula ofs. - apply: or_wf. suffices map_proj_wf bcs: let mbcs := map (proj n) bcs in all dnf_rterm bcs -> all (@qf_form _) mbcs && all (@rformula _) mbcs. by apply: map_proj_wf; exact: qf_to_dnf_rterm. elim: bcs => [|bc bcs ihb] bcsr //= /andP[rbc rbcs]. by rewrite andbAC andbA wf_proj //= andbC ihb. elim: fs => //= g gs ihg; rewrite -andbA => /and4P[-> qgs -> rgs] /=. by apply: ihg; rewrite qgs rgs. Qed. Lemma quantifier_elim_rformP e f : rformula f -> reflect (holds e f) (qf_eval e (quantifier_elim f)). Proof. pose rc e n f := exists x, qf_eval (set_nth 0 e n x) f. have auxP f0 e0 n0: qf_form f0 && rformula f0 -> reflect (rc e0 n0 f0) (qf_eval e0 (elim_aux f0 n0)). + rewrite /elim_aux => cf; set bcs := qf_to_dnf f0 false. apply: (@iffP (rc e0 n0 (dnf_to_form bcs))); last first. - by case=> x; rewrite -qf_to_dnfP //; exists x. - by case=> x; rewrite qf_to_dnfP //; exists x. have: all dnf_rterm bcs by case/andP: cf => _; exact: qf_to_dnf_rterm. elim: {f0 cf}bcs => [|bc bcs IHbcs] /=; first by right; case. case/andP=> r_bc /IHbcs {IHbcs}bcsP. have f_qf := dnf_to_form_qf [:: bc]. case: ok_proj => //= [ex_x|no_x]. left; case: ex_x => x /(qf_evalP _ f_qf); rewrite /= orbF => bc_x. by exists x; rewrite /= bc_x. apply: (iffP bcsP) => [[x bcs_x] | [x]] /=. by exists x; rewrite /= bcs_x orbT. case/orP => [bc_x|]; last by exists x. by case: no_x; exists x; apply/(qf_evalP _ f_qf); rewrite /= bc_x. elim: f e => //. - move=> b e _; exact: idP. - move=> t1 t2 e _; exact: eqP. - move=> f1 IH1 f2 IH2 e /= /andP[/IH1[] f1e]; last by right; case. by case/IH2; [left | right; case]. - move=> f1 IH1 f2 IH2 e /= /andP[/IH1[] f1e]; first by do 2!left. by case/IH2; [left; right | right; case]. - move=> f1 IH1 f2 IH2 e /= /andP[/IH1[] f1e]; last by left. by case/IH2; [left | right; move/(_ f1e)]. - by move=> f IHf e /= /IHf[]; [right | left]. - move=> n f IHf e /= rf; have rqf := quantifier_elim_wf rf. by apply: (iffP (auxP _ _ _ rqf)) => [] [x]; exists x; exact/IHf. move=> n f IHf e /= rf; have rqf := quantifier_elim_wf rf. case: auxP => // [f_x|no_x]; first by right=> no_x; case: f_x => x /IHf[]. by left=> x; apply/IHf=> //; apply/idPn=> f_x; case: no_x; exists x. Qed. Definition proj_sat e f := qf_eval e (quantifier_elim (to_rform f)). Lemma proj_satP : DecidableField.axiom proj_sat. Proof. move=> e f; have fP := quantifier_elim_rformP e (to_rform_rformula f). by apply: (iffP fP); move/to_rformP. Qed. Definition QEdecFieldMixin := DecidableField.Mixin proj_satP. End QE_Mixin. Module ClosedField. (* Axiom == all non-constant monic polynomials have a root *) Definition axiom (R : ringType) := forall n (P : nat -> R), n > 0 -> exists x : R, x ^+ n = \sum_(i < n) P i * (x ^+ i). Section ClassDef. Record class_of (F : Type) : Type := Class {base : DecidableField.class_of F; _ : axiom (Ring.Pack base F)}. Local Coercion base : class_of >-> DecidableField.class_of. Structure type := Pack {sort; _ : class_of sort; _ : Type}. Local Coercion sort : type >-> Sortclass. Variable (T : Type) (cT : type). Definition class := let: Pack _ c _ as cT' := cT return class_of cT' in c. Definition clone c of phant_id class c := @Pack T c T. Let xT := let: Pack T _ _ := cT in T. Notation xclass := (class : class_of xT). Definition pack b0 (m0 : axiom (@Ring.Pack T b0 T)) := fun bT b & phant_id (DecidableField.class bT) b => fun m & phant_id m0 m => Pack (@Class T b m) T. (* There should eventually be a constructor from polynomial resolution *) (* that builds the DecidableField mixin using QE. *) Definition eqType := @Equality.Pack cT xclass xT. Definition choiceType := @Choice.Pack cT xclass xT. Definition zmodType := @Zmodule.Pack cT xclass xT. Definition ringType := @Ring.Pack cT xclass xT. Definition comRingType := @ComRing.Pack cT xclass xT. Definition unitRingType := @UnitRing.Pack cT xclass xT. Definition comUnitRingType := @ComUnitRing.Pack cT xclass xT. Definition idomainType := @IntegralDomain.Pack cT xclass xT. Definition fieldType := @Field.Pack cT xclass xT. Definition decFieldType := @DecidableField.Pack cT class xT. End ClassDef. Module Exports. Coercion base : class_of >-> DecidableField.class_of. Coercion sort : type >-> Sortclass. Bind Scope ring_scope with sort. Coercion eqType : type >-> Equality.type. Canonical eqType. Coercion choiceType : type >-> Choice.type. Canonical choiceType. Coercion zmodType : type >-> Zmodule.type. Canonical zmodType. Coercion ringType : type >-> Ring.type. Canonical ringType. Coercion comRingType : type >-> ComRing.type. Canonical comRingType. Coercion unitRingType : type >-> UnitRing.type. Canonical unitRingType. Coercion comUnitRingType : type >-> ComUnitRing.type. Canonical comUnitRingType. Coercion idomainType : type >-> IntegralDomain.type. Canonical idomainType. Coercion fieldType : type >-> Field.type. Canonical fieldType. Coercion decFieldType : type >-> DecidableField.type. Canonical decFieldType. Notation closedFieldType := type. Notation ClosedFieldType T m := (@pack T _ m _ _ id _ id). Notation "[ 'closedFieldType' 'of' T 'for' cT ]" := (@clone T cT _ idfun) (at level 0, format "[ 'closedFieldType' 'of' T 'for' cT ]") : form_scope. Notation "[ 'closedFieldType' 'of' T ]" := (@clone T _ _ id) (at level 0, format "[ 'closedFieldType' 'of' T ]") : form_scope. End Exports. End ClosedField. Import ClosedField.Exports. Section ClosedFieldTheory. Variable F : closedFieldType. Lemma solve_monicpoly : ClosedField.axiom F. Proof. by case: F => ? []. Qed. End ClosedFieldTheory. Module SubType. Section Zmodule. Variables (V : zmodType) (S : predPredType V). Variables (subS : zmodPred S) (kS : keyed_pred subS). Variable U : subType (mem kS). Let inU v Sv : U := Sub v Sv. Let zeroU := inU (rpred0 kS). Let oppU (u : U) := inU (rpredNr (valP u)). Let addU (u1 u2 : U) := inU (rpredD (valP u1) (valP u2)). Fact addA : associative addU. Proof. by move=> u1 u2 u3; apply: val_inj; rewrite !SubK addrA. Qed. Fact addC : commutative addU. Proof. by move=> u1 u2; apply: val_inj; rewrite !SubK addrC. Qed. Fact add0 : left_id zeroU addU. Proof. by move=> u; apply: val_inj; rewrite !SubK add0r. Qed. Fact addN : left_inverse zeroU oppU addU. Proof. by move=> u; apply: val_inj; rewrite !SubK addNr. Qed. Definition zmodMixin of phant U := ZmodMixin addA addC add0 addN. End Zmodule. Section Ring. Variables (R : ringType) (S : predPredType R). Variables (ringS : subringPred S) (kS : keyed_pred ringS). Definition cast_zmodType (V : zmodType) T (VeqT : V = T :> Type) := let cast mV := let: erefl in _ = T := VeqT return Zmodule.class_of T in mV in Zmodule.Pack (cast (Zmodule.class V)) T. Variable (T : subType (mem kS)) (V : zmodType) (VeqT: V = T :> Type). Let inT x Sx : T := Sub x Sx. Let oneT := inT (rpred1 kS). Let mulT (u1 u2 : T) := inT (rpredM (valP u1) (valP u2)). Let T' := cast_zmodType VeqT. Hypothesis valM : {morph (val : T' -> R) : x y / x - y}. Let val0 : val (0 : T') = 0. Proof. by rewrite -(subrr (0 : T')) valM subrr. Qed. Let valD : {morph (val : T' -> R): x y / x + y}. Proof. by move=> u v; rewrite -{1}[v]opprK -[- v]sub0r !valM val0 sub0r opprK. Qed. Fact mulA : @associative T' mulT. Proof. by move=> u1 u2 u3; apply: val_inj; rewrite !SubK mulrA. Qed. Fact mul1l : left_id oneT mulT. Proof. by move=> u; apply: val_inj; rewrite !SubK mul1r. Qed. Fact mul1r : right_id oneT mulT. Proof. by move=> u; apply: val_inj; rewrite !SubK mulr1. Qed. Fact mulDl : @left_distributive T' T' mulT +%R. Proof. by move=> u1 u2 u3; apply: val_inj; rewrite !(SubK, valD) mulrDl. Qed. Fact mulDr : @right_distributive T' T' mulT +%R. Proof. by move=> u1 u2 u3; apply: val_inj; rewrite !(SubK, valD) mulrDr. Qed. Fact nz1 : oneT != 0 :> T'. Proof. by apply: contraNneq (oner_neq0 R) => eq10; rewrite -val0 -eq10 SubK. Qed. Definition ringMixin := RingMixin mulA mul1l mul1r mulDl mulDr nz1. End Ring. Section Lmodule. Variables (R : ringType) (V : lmodType R) (S : predPredType V). Variables (linS : submodPred S) (kS : keyed_pred linS). Variables (W : subType (mem kS)) (Z : zmodType) (ZeqW : Z = W :> Type). Let scaleW a (w : W) := (Sub _ : _ -> W) (rpredZ a (valP w)). Let W' := cast_zmodType ZeqW. Hypothesis valD : {morph (val : W' -> V) : x y / x + y}. Fact scaleA a b (w : W') : scaleW a (scaleW b w) = scaleW (a * b) w. Proof. by apply: val_inj; rewrite !SubK scalerA. Qed. Fact scale1 : left_id 1 scaleW. Proof. by move=> w; apply: val_inj; rewrite !SubK scale1r. Qed. Fact scaleDr : @right_distributive R W' scaleW +%R. Proof. by move=> a w w2; apply: val_inj; rewrite !(SubK, valD) scalerDr. Qed. Fact scaleDl w : {morph (scaleW^~ w : R -> W') : a b / a + b}. Proof. by move=> a b; apply: val_inj; rewrite !(SubK, valD) scalerDl. Qed. Definition lmodMixin := LmodMixin scaleA scale1 scaleDr scaleDl. End Lmodule. Lemma lalgMixin (R : ringType) (A : lalgType R) (B : lmodType R) (f : B -> A) : phant B -> injective f -> scalable f -> forall mulB, {morph f : x y / mulB x y >-> x * y} -> Lalgebra.axiom mulB. Proof. by move=> _ injf fZ mulB fM a x y; apply: injf; rewrite !(fZ, fM) scalerAl. Qed. Lemma comRingMixin (R : comRingType) (T : ringType) (f : T -> R) : phant T -> injective f -> {morph f : x y / x * y} -> commutative (@mul T). Proof. by move=> _ inj_f fM x y; apply: inj_f; rewrite !fM mulrC. Qed. Lemma algMixin (R : comRingType) (A : algType R) (B : lalgType R) (f : B -> A) : phant B -> injective f -> {morph f : x y / x * y} -> scalable f -> @Algebra.axiom R B. Proof. by move=> _ inj_f fM fZ a x y; apply: inj_f; rewrite !(fM, fZ) scalerAr. Qed. Section UnitRing. Definition cast_ringType (Q : ringType) T (QeqT : Q = T :> Type) := let cast rQ := let: erefl in _ = T := QeqT return Ring.class_of T in rQ in Ring.Pack (cast (Ring.class Q)) T. Variables (R : unitRingType) (S : predPredType R). Variables (ringS : divringPred S) (kS : keyed_pred ringS). Variables (T : subType (mem kS)) (Q : ringType) (QeqT : Q = T :> Type). Let inT x Sx : T := Sub x Sx. Let invT (u : T) := inT (rpredVr (valP u)). Let unitT := [qualify a u : T | val u \is a unit]. Let T' := cast_ringType QeqT. Hypothesis val1 : val (1 : T') = 1. Hypothesis valM : {morph (val : T' -> R) : x y / x * y}. Fact mulVr : {in (unitT : predPredType T'), left_inverse (1 : T') invT (@mul T')}. Proof. by move=> u Uu; apply: val_inj; rewrite val1 valM SubK mulVr. Qed. Fact mulrV : {in unitT, right_inverse (1 : T') invT (@mul T')}. Proof. by move=> u Uu; apply: val_inj; rewrite val1 valM SubK mulrV. Qed. Fact unitP (u v : T') : v * u = 1 /\ u * v = 1 -> u \in unitT. Proof. by case=> vu1 uv1; apply/unitrP; exists (val v); rewrite -!valM vu1 uv1. Qed. Fact unit_id : {in [predC unitT], invT =1 id}. Proof. by move=> u /invr_out def_u1; apply: val_inj; rewrite SubK. Qed. Definition unitRingMixin := UnitRingMixin mulVr mulrV unitP unit_id. End UnitRing. Lemma idomainMixin (R : idomainType) (T : ringType) (f : T -> R) : phant T -> injective f -> f 0 = 0 -> {morph f : u v / u * v} -> @IntegralDomain.axiom T. Proof. move=> _ injf f0 fM u v uv0. by rewrite -!(inj_eq injf) !f0 -mulf_eq0 -fM uv0 f0. Qed. Lemma fieldMixin (F : fieldType) (K : unitRingType) (f : K -> F) : phant K -> injective f -> f 0 = 0 -> {mono f : u / u \in unit} -> @Field.mixin_of K. Proof. by move=> _ injf f0 fU u; rewrite -fU unitfE -f0 inj_eq. Qed. Module Exports. Notation "[ 'zmodMixin' 'of' U 'by' <: ]" := (zmodMixin (Phant U)) (at level 0, format "[ 'zmodMixin' 'of' U 'by' <: ]") : form_scope. Notation "[ 'ringMixin' 'of' R 'by' <: ]" := (@ringMixin _ _ _ _ _ _ (@erefl Type R%type) (rrefl _)) (at level 0, format "[ 'ringMixin' 'of' R 'by' <: ]") : form_scope. Notation "[ 'lmodMixin' 'of' U 'by' <: ]" := (@lmodMixin _ _ _ _ _ _ _ (@erefl Type U%type) (rrefl _)) (at level 0, format "[ 'lmodMixin' 'of' U 'by' <: ]") : form_scope. Notation "[ 'lalgMixin' 'of' A 'by' <: ]" := ((lalgMixin (Phant A) val_inj (rrefl _)) *%R (rrefl _)) (at level 0, format "[ 'lalgMixin' 'of' A 'by' <: ]") : form_scope. Notation "[ 'comRingMixin' 'of' R 'by' <: ]" := (comRingMixin (Phant R) val_inj (rrefl _)) (at level 0, format "[ 'comRingMixin' 'of' R 'by' <: ]") : form_scope. Notation "[ 'algMixin' 'of' A 'by' <: ]" := (algMixin (Phant A) val_inj (rrefl _) (rrefl _)) (at level 0, format "[ 'algMixin' 'of' A 'by' <: ]") : form_scope. Notation "[ 'unitRingMixin' 'of' R 'by' <: ]" := (@unitRingMixin _ _ _ _ _ _ (@erefl Type R%type) (erefl _) (rrefl _)) (at level 0, format "[ 'unitRingMixin' 'of' R 'by' <: ]") : form_scope. Notation "[ 'idomainMixin' 'of' R 'by' <: ]" := (idomainMixin (Phant R) val_inj (erefl _) (rrefl _)) (at level 0, format "[ 'idomainMixin' 'of' R 'by' <: ]") : form_scope. Notation "[ 'fieldMixin' 'of' F 'by' <: ]" := (fieldMixin (Phant F) val_inj (erefl _) (frefl _)) (at level 0, format "[ 'fieldMixin' 'of' F 'by' <: ]") : form_scope. End Exports. End SubType. Module Theory. Definition addrA := addrA. Definition addrC := addrC. Definition add0r := add0r. Definition addNr := addNr. Definition addr0 := addr0. Definition addrN := addrN. Definition subrr := subrr. Definition addrCA := addrCA. Definition addrAC := addrAC. Definition addrACA := addrACA. Definition addKr := addKr. Definition addNKr := addNKr. Definition addrK := addrK. Definition addrNK := addrNK. Definition subrK := subrK. Definition addrI := @addrI. Definition addIr := @addIr. Implicit Arguments addrI [[V] x1 x2]. Implicit Arguments addIr [[V] x1 x2]. Definition opprK := opprK. Definition oppr_inj := @oppr_inj. Implicit Arguments oppr_inj [[V] x1 x2]. Definition oppr0 := oppr0. Definition oppr_eq0 := oppr_eq0. Definition opprD := opprD. Definition opprB := opprB. Definition subr0 := subr0. Definition sub0r := sub0r. Definition subr_eq := subr_eq. Definition subr_eq0 := subr_eq0. Definition addr_eq0 := addr_eq0. Definition eqr_opp := eqr_opp. Definition eqr_oppLR := eqr_oppLR. Definition sumrN := sumrN. Definition sumrB := sumrB. Definition sumrMnl := sumrMnl. Definition sumrMnr := sumrMnr. Definition sumr_const := sumr_const. Definition telescope_sumr := telescope_sumr. Definition mulr0n := mulr0n. Definition mulr1n := mulr1n. Definition mulr2n := mulr2n. Definition mulrS := mulrS. Definition mulrSr := mulrSr. Definition mulrb := mulrb. Definition mul0rn := mul0rn. Definition mulNrn := mulNrn. Definition mulrnDl := mulrnDl. Definition mulrnDr := mulrnDr. Definition mulrnBl := mulrnBl. Definition mulrnBr := mulrnBr. Definition mulrnA := mulrnA. Definition mulrnAC := mulrnAC. Definition mulrA := mulrA. Definition mul1r := mul1r. Definition mulr1 := mulr1. Definition mulrDl := mulrDl. Definition mulrDr := mulrDr. Definition oner_neq0 := oner_neq0. Definition oner_eq0 := oner_eq0. Definition mul0r := mul0r. Definition mulr0 := mulr0. Definition mulrN := mulrN. Definition mulNr := mulNr. Definition mulrNN := mulrNN. Definition mulN1r := mulN1r. Definition mulrN1 := mulrN1. Definition mulr_suml := mulr_suml. Definition mulr_sumr := mulr_sumr. Definition mulrBl := mulrBl. Definition mulrBr := mulrBr. Definition mulrnAl := mulrnAl. Definition mulrnAr := mulrnAr. Definition mulr_natl := mulr_natl. Definition mulr_natr := mulr_natr. Definition natrD := natrD. Definition natrB := natrB. Definition natr_sum := natr_sum. Definition natrM := natrM. Definition natrX := natrX. Definition expr0 := expr0. Definition exprS := exprS. Definition expr1 := expr1. Definition expr2 := expr2. Definition expr0n := expr0n. Definition expr1n := expr1n. Definition exprD := exprD. Definition exprSr := exprSr. Definition commr_sym := commr_sym. Definition commr_refl := commr_refl. Definition commr0 := commr0. Definition commr1 := commr1. Definition commrN := commrN. Definition commrN1 := commrN1. Definition commrD := commrD. Definition commrMn := commrMn. Definition commrM := commrM. Definition commr_nat := commr_nat. Definition commrX := commrX. Definition exprMn_comm := exprMn_comm. Definition commr_sign := commr_sign. Definition exprMn_n := exprMn_n. Definition exprM := exprM. Definition exprAC := exprAC. Definition expr_mod := expr_mod. Definition expr_dvd := expr_dvd. Definition signr_odd := signr_odd. Definition signr_eq0 := signr_eq0. Definition mulr_sign := mulr_sign. Definition signr_addb := signr_addb. Definition signrN := signrN. Definition signrE := signrE. Definition mulr_signM := mulr_signM. Definition exprNn := exprNn. Definition sqrrN := sqrrN. Definition sqrr_sign := sqrr_sign. Definition signrMK := signrMK. Definition mulrI_eq0 := mulrI_eq0. Definition lreg_neq0 := lreg_neq0. Definition mulrI0_lreg := mulrI0_lreg. Definition lregN := lregN. Definition lreg1 := lreg1. Definition lregM := lregM. Definition lregX := lregX. Definition lreg_sign := lreg_sign. Definition lregP {R x} := @lregP R x. Definition mulIr_eq0 := mulIr_eq0. Definition mulIr0_rreg := mulIr0_rreg. Definition rreg_neq0 := rreg_neq0. Definition rregN := rregN. Definition rreg1 := rreg1. Definition rregM := rregM. Definition revrX := revrX. Definition rregX := rregX. Definition rregP {R x} := @rregP R x. Definition exprDn_comm := exprDn_comm. Definition exprBn_comm := exprBn_comm. Definition subrXX_comm := subrXX_comm. Definition exprD1n := exprD1n. Definition subrX1 := subrX1. Definition sqrrD1 := sqrrD1. Definition sqrrB1 := sqrrB1. Definition subr_sqr_1 := subr_sqr_1. Definition charf0 := charf0. Definition charf_prime := charf_prime. Definition mulrn_char := mulrn_char. Definition dvdn_charf := dvdn_charf. Definition charf_eq := charf_eq. Definition bin_lt_charf_0 := bin_lt_charf_0. Definition Frobenius_autE := Frobenius_autE. Definition Frobenius_aut0 := Frobenius_aut0. Definition Frobenius_aut1 := Frobenius_aut1. Definition Frobenius_autD_comm := Frobenius_autD_comm. Definition Frobenius_autMn := Frobenius_autMn. Definition Frobenius_aut_nat := Frobenius_aut_nat. Definition Frobenius_autM_comm := Frobenius_autM_comm. Definition Frobenius_autX := Frobenius_autX. Definition Frobenius_autN := Frobenius_autN. Definition Frobenius_autB_comm := Frobenius_autB_comm. Definition exprNn_char := exprNn_char. Definition addrr_char2 := addrr_char2. Definition oppr_char2 := oppr_char2. Definition addrK_char2 := addrK_char2. Definition addKr_char2 := addKr_char2. Definition prodr_const := prodr_const. Definition mulrC := mulrC. Definition mulrCA := mulrCA. Definition mulrAC := mulrAC. Definition mulrACA := mulrACA. Definition exprMn := exprMn. Definition prodrXl := prodrXl. Definition prodrXr := prodrXr. Definition prodrN := prodrN. Definition prodrMn := prodrMn. Definition natr_prod := natr_prod. Definition prodr_undup_exp_count := prodr_undup_exp_count. Definition exprDn := exprDn. Definition exprBn := exprBn. Definition subrXX := subrXX. Definition sqrrD := sqrrD. Definition sqrrB := sqrrB. Definition subr_sqr := subr_sqr. Definition subr_sqrDB := subr_sqrDB. Definition exprDn_char := exprDn_char. Definition mulrV := mulrV. Definition divrr := divrr. Definition mulVr := mulVr. Definition invr_out := invr_out. Definition unitrP {R x} := @unitrP R x. Definition mulKr := mulKr. Definition mulVKr := mulVKr. Definition mulrK := mulrK. Definition mulrVK := mulrVK. Definition divrK := divrK. Definition mulrI := mulrI. Definition mulIr := mulIr. Definition telescope_prodr := telescope_prodr. Definition commrV := commrV. Definition unitrE := unitrE. Definition invrK := invrK. Definition invr_inj := @invr_inj. Implicit Arguments invr_inj [[R] x1 x2]. Definition unitrV := unitrV. Definition unitr1 := unitr1. Definition invr1 := invr1. Definition divr1 := divr1. Definition div1r := div1r. Definition natr_div := natr_div. Definition unitr0 := unitr0. Definition invr0 := invr0. Definition unitrN1 := unitrN1. Definition unitrN := unitrN. Definition invrN1 := invrN1. Definition invrN := invrN. Definition invr_sign := invr_sign. Definition unitrMl := unitrMl. Definition unitrMr := unitrMr. Definition invrM := invrM. Definition invr_eq0 := invr_eq0. Definition invr_eq1 := invr_eq1. Definition invr_neq0 := invr_neq0. Definition unitrM_comm := unitrM_comm. Definition unitrX := unitrX. Definition unitrX_pos := unitrX_pos. Definition exprVn := exprVn. Definition exprB := exprB. Definition invr_signM := invr_signM. Definition divr_signM := divr_signM. Definition rpred0D := rpred0D. Definition rpred0 := rpred0. Definition rpredD := rpredD. Definition rpredNr := rpredNr. Definition rpred_sum := rpred_sum. Definition rpredMn := rpredMn. Definition rpredN := rpredN. Definition rpredB := rpredB. Definition rpredMNn := rpredMNn. Definition rpredDr := rpredDr. Definition rpredDl := rpredDl. Definition rpredBr := rpredBr. Definition rpredBl := rpredBl. Definition rpredMsign := rpredMsign. Definition rpred1M := rpred1M. Definition rpred1 := rpred1. Definition rpredM := rpredM. Definition rpred_prod := rpred_prod. Definition rpredX := rpredX. Definition rpred_nat := rpred_nat. Definition rpredN1 := rpredN1. Definition rpred_sign := rpred_sign. Definition rpredZsign := rpredZsign. Definition rpredZnat := rpredZnat. Definition rpredZ := rpredZ. Definition rpredVr := rpredVr. Definition rpredV := rpredV. Definition rpred_div := rpred_div. Definition rpredXN := rpredXN. Definition rpredZeq := rpredZeq. Definition char_lalg := char_lalg. Definition rpredMr := rpredMr. Definition rpredMl := rpredMl. Definition rpred_divr := rpred_divr. Definition rpred_divl := rpred_divl. Definition eq_eval := eq_eval. Definition eval_tsubst := eval_tsubst. Definition eq_holds := eq_holds. Definition holds_fsubst := holds_fsubst. Definition unitrM := unitrM. Definition unitrPr {R x} := @unitrPr R x. Definition expr_div_n := expr_div_n. Definition mulf_eq0 := mulf_eq0. Definition prodf_eq0 := prodf_eq0. Definition prodf_seq_eq0 := prodf_seq_eq0. Definition mulf_neq0 := mulf_neq0. Definition prodf_neq0 := prodf_neq0. Definition prodf_seq_neq0 := prodf_seq_neq0. Definition expf_eq0 := expf_eq0. Definition sqrf_eq0 := sqrf_eq0. Definition expf_neq0 := expf_neq0. Definition natf_neq0 := natf_neq0. Definition natf0_char := natf0_char. Definition charf'_nat := charf'_nat. Definition charf0P := charf0P. Definition eqf_sqr := eqf_sqr. Definition mulfI := mulfI. Definition mulIf := mulIf. Definition sqrf_eq1 := sqrf_eq1. Definition expfS_eq1 := expfS_eq1. Definition fieldP := fieldP. Definition unitfE := unitfE. Definition mulVf := mulVf. Definition mulfV := mulfV. Definition divff := divff. Definition mulKf := mulKf. Definition mulVKf := mulVKf. Definition mulfK := mulfK. Definition mulfVK := mulfVK. Definition divfK := divfK. Definition invfM := invfM. Definition invf_div := invf_div. Definition expfB_cond := expfB_cond. Definition expfB := expfB. Definition prodfV := prodfV. Definition prodf_div := prodf_div. Definition telescope_prodf := telescope_prodf. Definition addf_div := addf_div. Definition mulf_div := mulf_div. Definition char0_natf_div := char0_natf_div. Definition fpredMr := fpredMr. Definition fpredMl := fpredMl. Definition fpred_divr := fpred_divr. Definition fpred_divl := fpred_divl. Definition satP {F e f} := @satP F e f. Definition eq_sat := eq_sat. Definition solP {F n f} := @solP F n f. Definition eq_sol := eq_sol. Definition size_sol := size_sol. Definition solve_monicpoly := solve_monicpoly. Definition raddf0 := raddf0. Definition raddf_eq0 := raddf_eq0. Definition raddfN := raddfN. Definition raddfD := raddfD. Definition raddfB := raddfB. Definition raddf_sum := raddf_sum. Definition raddfMn := raddfMn. Definition raddfMNn := raddfMNn. Definition raddfMnat := raddfMnat. Definition raddfMsign := raddfMsign. Definition can2_additive := can2_additive. Definition bij_additive := bij_additive. Definition rmorph0 := rmorph0. Definition rmorphN := rmorphN. Definition rmorphD := rmorphD. Definition rmorphB := rmorphB. Definition rmorph_sum := rmorph_sum. Definition rmorphMn := rmorphMn. Definition rmorphMNn := rmorphMNn. Definition rmorphismP := rmorphismP. Definition rmorphismMP := rmorphismMP. Definition rmorph1 := rmorph1. Definition rmorph_eq1 := rmorph_eq1. Definition rmorphM := rmorphM. Definition rmorphMsign := rmorphMsign. Definition rmorph_nat := rmorph_nat. Definition rmorph_eq_nat := rmorph_eq_nat. Definition rmorph_prod := rmorph_prod. Definition rmorphX := rmorphX. Definition rmorphN1 := rmorphN1. Definition rmorph_sign := rmorph_sign. Definition rmorph_char := rmorph_char. Definition can2_rmorphism := can2_rmorphism. Definition bij_rmorphism := bij_rmorphism. Definition rmorph_comm := rmorph_comm. Definition rmorph_unit := rmorph_unit. Definition rmorphV := rmorphV. Definition rmorph_div := rmorph_div. Definition fmorph_eq0 := fmorph_eq0. Definition fmorph_inj := @fmorph_inj. Implicit Arguments fmorph_inj [[F] [R] x1 x2]. Definition fmorph_eq1 := fmorph_eq1. Definition fmorph_char := fmorph_char. Definition fmorph_unit := fmorph_unit. Definition fmorphV := fmorphV. Definition fmorph_div := fmorph_div. Definition scalerA := scalerA. Definition scale1r := scale1r. Definition scalerDr := scalerDr. Definition scalerDl := scalerDl. Definition scaler0 := scaler0. Definition scale0r := scale0r. Definition scaleNr := scaleNr. Definition scaleN1r := scaleN1r. Definition scalerN := scalerN. Definition scalerBl := scalerBl. Definition scalerBr := scalerBr. Definition scaler_nat := scaler_nat. Definition scalerMnl := scalerMnl. Definition scalerMnr := scalerMnr. Definition scaler_suml := scaler_suml. Definition scaler_sumr := scaler_sumr. Definition scaler_eq0 := scaler_eq0. Definition scalerK := scalerK. Definition scalerKV := scalerKV. Definition scalerI := scalerI. Definition scalerAl := scalerAl. Definition mulr_algl := mulr_algl. Definition scaler_sign := scaler_sign. Definition signrZK := signrZK. Definition scalerCA := scalerCA. Definition scalerAr := scalerAr. Definition mulr_algr := mulr_algr. Definition exprZn := exprZn. Definition scaler_prodl := scaler_prodl. Definition scaler_prodr := scaler_prodr. Definition scaler_prod := scaler_prod. Definition scaler_injl := scaler_injl. Definition scaler_unit := scaler_unit. Definition invrZ := invrZ. Definition raddfZnat := raddfZnat. Definition raddfZsign := raddfZsign. Definition in_algE := in_algE. Definition linear0 := linear0. Definition linearN := linearN. Definition linearD := linearD. Definition linearB := linearB. Definition linear_sum := linear_sum. Definition linearMn := linearMn. Definition linearMNn := linearMNn. Definition linearP := linearP. Definition linearZ_LR := linearZ_LR. Definition linearZ := linearZ. Definition linearPZ := linearPZ. Definition linearZZ := linearZZ. Definition scalarP := scalarP. Definition scalarZ := scalarZ. Definition can2_linear := can2_linear. Definition bij_linear := bij_linear. Definition rmorph_alg := rmorph_alg. Definition lrmorphismP := lrmorphismP. Definition can2_lrmorphism := can2_lrmorphism. Definition bij_lrmorphism := bij_lrmorphism. Notation null_fun V := (null_fun V) (only parsing). Notation in_alg A := (in_alg_loc A). End Theory. Notation in_alg A := (in_alg_loc A). End GRing. Export Zmodule.Exports Ring.Exports Lmodule.Exports Lalgebra.Exports. Export Additive.Exports RMorphism.Exports Linear.Exports LRMorphism.Exports. Export ComRing.Exports Algebra.Exports UnitRing.Exports UnitAlgebra.Exports. Export ComUnitRing.Exports IntegralDomain.Exports Field.Exports. Export DecidableField.Exports ClosedField.Exports. Export Pred.Exports SubType.Exports. Notation QEdecFieldMixin := QEdecFieldMixin. Notation "0" := (zero _) : ring_scope. Notation "-%R" := (@opp _) : ring_scope. Notation "- x" := (opp x) : ring_scope. Notation "+%R" := (@add _). Notation "x + y" := (add x y) : ring_scope. Notation "x - y" := (add x (- y)) : ring_scope. Notation "x *+ n" := (natmul x n) : ring_scope. Notation "x *- n" := (opp (x *+ n)) : ring_scope. Notation "s `_ i" := (seq.nth 0%R s%R i) : ring_scope. Notation support := 0.-support. Notation "1" := (one _) : ring_scope. Notation "- 1" := (opp 1) : ring_scope. Notation "n %:R" := (natmul 1 n) : ring_scope. Notation "[ 'char' R ]" := (char (Phant R)) : ring_scope. Notation Frobenius_aut chRp := (Frobenius_aut chRp). Notation "*%R" := (@mul _). Notation "x * y" := (mul x y) : ring_scope. Notation "x ^+ n" := (exp x n) : ring_scope. Notation "x ^-1" := (inv x) : ring_scope. Notation "x ^- n" := (inv (x ^+ n)) : ring_scope. Notation "x / y" := (mul x y^-1) : ring_scope. Notation "*:%R" := (@scale _ _). Notation "a *: m" := (scale a m) : ring_scope. Notation "k %:A" := (scale k 1) : ring_scope. Notation "\0" := (null_fun _) : ring_scope. Notation "f \+ g" := (add_fun_head tt f g) : ring_scope. Notation "f \- g" := (sub_fun_head tt f g) : ring_scope. Notation "a \*: f" := (scale_fun_head tt a f) : ring_scope. Notation "x \*o f" := (mull_fun_head tt x f) : ring_scope. Notation "x \o* f" := (mulr_fun_head tt x f) : ring_scope. Notation "\sum_ ( i <- r | P ) F" := (\big[+%R/0%R]_(i <- r | P%B) F%R) : ring_scope. Notation "\sum_ ( i <- r ) F" := (\big[+%R/0%R]_(i <- r) F%R) : ring_scope. Notation "\sum_ ( m <= i < n | P ) F" := (\big[+%R/0%R]_(m <= i < n | P%B) F%R) : ring_scope. Notation "\sum_ ( m <= i < n ) F" := (\big[+%R/0%R]_(m <= i < n) F%R) : ring_scope. Notation "\sum_ ( i | P ) F" := (\big[+%R/0%R]_(i | P%B) F%R) : ring_scope. Notation "\sum_ i F" := (\big[+%R/0%R]_i F%R) : ring_scope. Notation "\sum_ ( i : t | P ) F" := (\big[+%R/0%R]_(i : t | P%B) F%R) (only parsing) : ring_scope. Notation "\sum_ ( i : t ) F" := (\big[+%R/0%R]_(i : t) F%R) (only parsing) : ring_scope. Notation "\sum_ ( i < n | P ) F" := (\big[+%R/0%R]_(i < n | P%B) F%R) : ring_scope. Notation "\sum_ ( i < n ) F" := (\big[+%R/0%R]_(i < n) F%R) : ring_scope. Notation "\sum_ ( i 'in' A | P ) F" := (\big[+%R/0%R]_(i in A | P%B) F%R) : ring_scope. Notation "\sum_ ( i 'in' A ) F" := (\big[+%R/0%R]_(i in A) F%R) : ring_scope. Notation "\prod_ ( i <- r | P ) F" := (\big[*%R/1%R]_(i <- r | P%B) F%R) : ring_scope. Notation "\prod_ ( i <- r ) F" := (\big[*%R/1%R]_(i <- r) F%R) : ring_scope. Notation "\prod_ ( m <= i < n | P ) F" := (\big[*%R/1%R]_(m <= i < n | P%B) F%R) : ring_scope. Notation "\prod_ ( m <= i < n ) F" := (\big[*%R/1%R]_(m <= i < n) F%R) : ring_scope. Notation "\prod_ ( i | P ) F" := (\big[*%R/1%R]_(i | P%B) F%R) : ring_scope. Notation "\prod_ i F" := (\big[*%R/1%R]_i F%R) : ring_scope. Notation "\prod_ ( i : t | P ) F" := (\big[*%R/1%R]_(i : t | P%B) F%R) (only parsing) : ring_scope. Notation "\prod_ ( i : t ) F" := (\big[*%R/1%R]_(i : t) F%R) (only parsing) : ring_scope. Notation "\prod_ ( i < n | P ) F" := (\big[*%R/1%R]_(i < n | P%B) F%R) : ring_scope. Notation "\prod_ ( i < n ) F" := (\big[*%R/1%R]_(i < n) F%R) : ring_scope. Notation "\prod_ ( i 'in' A | P ) F" := (\big[*%R/1%R]_(i in A | P%B) F%R) : ring_scope. Notation "\prod_ ( i 'in' A ) F" := (\big[*%R/1%R]_(i in A) F%R) : ring_scope. Canonical add_monoid. Canonical add_comoid. Canonical mul_monoid. Canonical mul_comoid. Canonical muloid. Canonical addoid. Canonical locked_additive. Canonical locked_rmorphism. Canonical locked_linear. Canonical locked_lrmorphism. Canonical idfun_additive. Canonical idfun_rmorphism. Canonical idfun_linear. Canonical idfun_lrmorphism. Canonical comp_additive. Canonical comp_rmorphism. Canonical comp_linear. Canonical comp_lrmorphism. Canonical opp_additive. Canonical opp_linear. Canonical scale_additive. Canonical scale_linear. Canonical null_fun_additive. Canonical null_fun_linear. Canonical scale_fun_additive. Canonical scale_fun_linear. Canonical add_fun_additive. Canonical add_fun_linear. Canonical sub_fun_additive. Canonical sub_fun_linear. Canonical mull_fun_additive. Canonical mull_fun_linear. Canonical mulr_fun_additive. Canonical mulr_fun_linear. Canonical Frobenius_aut_additive. Canonical Frobenius_aut_rmorphism. Canonical in_alg_additive. Canonical in_alg_rmorphism. Notation "R ^c" := (converse R) (at level 2, format "R ^c") : type_scope. Canonical converse_eqType. Canonical converse_choiceType. Canonical converse_zmodType. Canonical converse_ringType. Canonical converse_unitRingType. Notation "R ^o" := (regular R) (at level 2, format "R ^o") : type_scope. Canonical regular_eqType. Canonical regular_choiceType. Canonical regular_zmodType. Canonical regular_ringType. Canonical regular_lmodType. Canonical regular_lalgType. Canonical regular_comRingType. Canonical regular_algType. Canonical regular_unitRingType. Canonical regular_comUnitRingType. Canonical regular_unitAlgType. Canonical regular_idomainType. Canonical regular_fieldType. Canonical unit_keyed. Canonical unit_opprPred. Canonical unit_mulrPred. Canonical unit_smulrPred. Canonical unit_divrPred. Canonical unit_sdivrPred. Bind Scope term_scope with term. Bind Scope term_scope with formula. Notation "''X_' i" := (Var _ i) : term_scope. Notation "n %:R" := (NatConst _ n) : term_scope. Notation "0" := 0%:R%T : term_scope. Notation "1" := 1%:R%T : term_scope. Notation "x %:T" := (Const x) : term_scope. Infix "+" := Add : term_scope. Notation "- t" := (Opp t) : term_scope. Notation "t - u" := (Add t (- u)) : term_scope. Infix "*" := Mul : term_scope. Infix "*+" := NatMul : term_scope. Notation "t ^-1" := (Inv t) : term_scope. Notation "t / u" := (Mul t u^-1) : term_scope. Infix "^+" := Exp : term_scope. Infix "==" := Equal : term_scope. Notation "x != y" := (GRing.Not (x == y)) : term_scope. Infix "/\" := And : term_scope. Infix "\/" := Or : term_scope. Infix "==>" := Implies : term_scope. Notation "~ f" := (Not f) : term_scope. Notation "''exists' ''X_' i , f" := (Exists i f) : term_scope. Notation "''forall' ''X_' i , f" := (Forall i f) : term_scope. (* Lifting Structure from the codomain of finfuns. *) Section FinFunZmod. Variable (aT : finType) (rT : zmodType). Implicit Types f g : {ffun aT -> rT}. Definition ffun_zero := [ffun a : aT => (0 : rT)]. Definition ffun_opp f := [ffun a => - f a]. Definition ffun_add f g := [ffun a => f a + g a]. Fact ffun_addA : associative ffun_add. Proof. by move=> f1 f2 f3; apply/ffunP=> a; rewrite !ffunE addrA. Qed. Fact ffun_addC : commutative ffun_add. Proof. by move=> f1 f2; apply/ffunP=> a; rewrite !ffunE addrC. Qed. Fact ffun_add0 : left_id ffun_zero ffun_add. Proof. by move=> f; apply/ffunP=> a; rewrite !ffunE add0r. Qed. Fact ffun_addN : left_inverse ffun_zero ffun_opp ffun_add. Proof. by move=> f; apply/ffunP=> a; rewrite !ffunE addNr. Qed. Definition ffun_zmodMixin := Zmodule.Mixin ffun_addA ffun_addC ffun_add0 ffun_addN. Canonical ffun_zmodType := Eval hnf in ZmodType _ ffun_zmodMixin. Section Sum. Variables (I : Type) (r : seq I) (P : pred I) (F : I -> {ffun aT -> rT}). Lemma sum_ffunE x : (\sum_(i <- r | P i) F i) x = \sum_(i <- r | P i) F i x. Proof. by elim/big_rec2: _ => // [|i _ y _ <-]; rewrite !ffunE. Qed. Lemma sum_ffun : \sum_(i <- r | P i) F i = [ffun x => \sum_(i <- r | P i) F i x]. Proof. by apply/ffunP=> i; rewrite sum_ffunE ffunE. Qed. End Sum. Lemma ffunMnE f n x : (f *+ n) x = f x *+ n. Proof. by rewrite -[n]card_ord -!sumr_const sum_ffunE. Qed. End FinFunZmod. Canonical exp_zmodType (M : zmodType) n := [zmodType of M ^ n]. Section FinFunRing. (* As rings require 1 != 0 in order to lift a ring structure over finfuns *) (* we need evidence that the domain is non-empty. *) Variable (aT : finType) (R : ringType) (a : aT). Definition ffun_one : {ffun aT -> R} := [ffun => 1]. Definition ffun_mul (f g : {ffun aT -> R}) := [ffun x => f x * g x]. Fact ffun_mulA : associative ffun_mul. Proof. by move=> f1 f2 f3; apply/ffunP=> i; rewrite !ffunE mulrA. Qed. Fact ffun_mul_1l : left_id ffun_one ffun_mul. Proof. by move=> f; apply/ffunP=> i; rewrite !ffunE mul1r. Qed. Fact ffun_mul_1r : right_id ffun_one ffun_mul. Proof. by move=> f; apply/ffunP=> i; rewrite !ffunE mulr1. Qed. Fact ffun_mul_addl : left_distributive ffun_mul (@ffun_add _ _). Proof. by move=> f1 f2 f3; apply/ffunP=> i; rewrite !ffunE mulrDl. Qed. Fact ffun_mul_addr : right_distributive ffun_mul (@ffun_add _ _). Proof. by move=> f1 f2 f3; apply/ffunP=> i; rewrite !ffunE mulrDr. Qed. Fact ffun1_nonzero : ffun_one != 0. Proof. by apply/eqP => /ffunP/(_ a)/eqP; rewrite !ffunE oner_eq0. Qed. Definition ffun_ringMixin := RingMixin ffun_mulA ffun_mul_1l ffun_mul_1r ffun_mul_addl ffun_mul_addr ffun1_nonzero. Definition ffun_ringType := Eval hnf in RingType {ffun aT -> R} ffun_ringMixin. End FinFunRing. Section FinFunComRing. Variable (aT : finType) (R : comRingType) (a : aT). Fact ffun_mulC : commutative (@ffun_mul aT R). Proof. by move=> f1 f2; apply/ffunP=> i; rewrite !ffunE mulrC. Qed. Definition ffun_comRingType := Eval hnf in ComRingType (ffun_ringType R a) ffun_mulC. End FinFunComRing. Section FinFunLmod. Variable (R : ringType) (aT : finType) (rT : lmodType R). Implicit Types f g : {ffun aT -> rT}. Definition ffun_scale k f := [ffun a => k *: f a]. Fact ffun_scaleA k1 k2 f : ffun_scale k1 (ffun_scale k2 f) = ffun_scale (k1 * k2) f. Proof. by apply/ffunP=> a; rewrite !ffunE scalerA. Qed. Fact ffun_scale1 : left_id 1 ffun_scale. Proof. by move=> f; apply/ffunP=> a; rewrite !ffunE scale1r. Qed. Fact ffun_scale_addr k : {morph (ffun_scale k) : x y / x + y}. Proof. by move=> f g; apply/ffunP=> a; rewrite !ffunE scalerDr. Qed. Fact ffun_scale_addl u : {morph (ffun_scale)^~ u : k1 k2 / k1 + k2}. Proof. by move=> k1 k2; apply/ffunP=> a; rewrite !ffunE scalerDl. Qed. Definition ffun_lmodMixin := LmodMixin ffun_scaleA ffun_scale1 ffun_scale_addr ffun_scale_addl. Canonical ffun_lmodType := Eval hnf in LmodType R {ffun aT -> rT} ffun_lmodMixin. End FinFunLmod. Canonical exp_lmodType (R : ringType) (M : lmodType R) n := [lmodType R of M ^ n]. (* External direct product. *) Section PairZmod. Variables M1 M2 : zmodType. Definition opp_pair (x : M1 * M2) := (- x.1, - x.2). Definition add_pair (x y : M1 * M2) := (x.1 + y.1, x.2 + y.2). Fact pair_addA : associative add_pair. Proof. by move=> x y z; congr (_, _); apply: addrA. Qed. Fact pair_addC : commutative add_pair. Proof. by move=> x y; congr (_, _); apply: addrC. Qed. Fact pair_add0 : left_id (0, 0) add_pair. Proof. by case=> x1 x2; congr (_, _); apply: add0r. Qed. Fact pair_addN : left_inverse (0, 0) opp_pair add_pair. Proof. by move=> x; congr (_, _); apply: addNr. Qed. Definition pair_zmodMixin := ZmodMixin pair_addA pair_addC pair_add0 pair_addN. Canonical pair_zmodType := Eval hnf in ZmodType (M1 * M2) pair_zmodMixin. End PairZmod. Section PairRing. Variables R1 R2 : ringType. Definition mul_pair (x y : R1 * R2) := (x.1 * y.1, x.2 * y.2). Fact pair_mulA : associative mul_pair. Proof. by move=> x y z; congr (_, _); apply: mulrA. Qed. Fact pair_mul1l : left_id (1, 1) mul_pair. Proof. by case=> x1 x2; congr (_, _); apply: mul1r. Qed. Fact pair_mul1r : right_id (1, 1) mul_pair. Proof. by case=> x1 x2; congr (_, _); apply: mulr1. Qed. Fact pair_mulDl : left_distributive mul_pair +%R. Proof. by move=> x y z; congr (_, _); apply: mulrDl. Qed. Fact pair_mulDr : right_distributive mul_pair +%R. Proof. by move=> x y z; congr (_, _); apply: mulrDr. Qed. Fact pair_one_neq0 : (1, 1) != 0 :> R1 * R2. Proof. by rewrite xpair_eqE oner_eq0. Qed. Definition pair_ringMixin := RingMixin pair_mulA pair_mul1l pair_mul1r pair_mulDl pair_mulDr pair_one_neq0. Canonical pair_ringType := Eval hnf in RingType (R1 * R2) pair_ringMixin. End PairRing. Section PairComRing. Variables R1 R2 : comRingType. Fact pair_mulC : commutative (@mul_pair R1 R2). Proof. by move=> x y; congr (_, _); apply: mulrC. Qed. Canonical pair_comRingType := Eval hnf in ComRingType (R1 * R2) pair_mulC. End PairComRing. Section PairLmod. Variables (R : ringType) (V1 V2 : lmodType R). Definition scale_pair a (v : V1 * V2) : V1 * V2 := (a *: v.1, a *: v.2). Fact pair_scaleA a b u : scale_pair a (scale_pair b u) = scale_pair (a * b) u. Proof. by congr (_, _); apply: scalerA. Qed. Fact pair_scale1 u : scale_pair 1 u = u. Proof. by case: u => u1 u2; congr (_, _); apply: scale1r. Qed. Fact pair_scaleDr : right_distributive scale_pair +%R. Proof. by move=> a u v; congr (_, _); apply: scalerDr. Qed. Fact pair_scaleDl u : {morph scale_pair^~ u: a b / a + b}. Proof. by move=> a b; congr (_, _); apply: scalerDl. Qed. Definition pair_lmodMixin := LmodMixin pair_scaleA pair_scale1 pair_scaleDr pair_scaleDl. Canonical pair_lmodType := Eval hnf in LmodType R (V1 * V2) pair_lmodMixin. End PairLmod. Section PairLalg. Variables (R : ringType) (A1 A2 : lalgType R). Fact pair_scaleAl a (u v : A1 * A2) : a *: (u * v) = (a *: u) * v. Proof. by congr (_, _); apply: scalerAl. Qed. Canonical pair_lalgType := Eval hnf in LalgType R (A1 * A2) pair_scaleAl. End PairLalg. Section PairAlg. Variables (R : comRingType) (A1 A2 : algType R). Fact pair_scaleAr a (u v : A1 * A2) : a *: (u * v) = u * (a *: v). Proof. by congr (_, _); apply: scalerAr. Qed. Canonical pair_algType := Eval hnf in AlgType R (A1 * A2) pair_scaleAr. End PairAlg. Section PairUnitRing. Variables R1 R2 : unitRingType. Definition pair_unitr := [qualify a x : R1 * R2 | (x.1 \is a GRing.unit) && (x.2 \is a GRing.unit)]. Definition pair_invr x := if x \is a pair_unitr then (x.1^-1, x.2^-1) else x. Lemma pair_mulVl : {in pair_unitr, left_inverse 1 pair_invr *%R}. Proof. rewrite /pair_invr=> x; case: ifP => // /andP[Ux1 Ux2] _. by congr (_, _); apply: mulVr. Qed. Lemma pair_mulVr : {in pair_unitr, right_inverse 1 pair_invr *%R}. Proof. rewrite /pair_invr=> x; case: ifP => // /andP[Ux1 Ux2] _. by congr (_, _); apply: mulrV. Qed. Lemma pair_unitP x y : y * x = 1 /\ x * y = 1 -> x \is a pair_unitr. Proof. case=> [[y1x y2x] [x1y x2y]]; apply/andP. by split; apply/unitrP; [exists y.1 | exists y.2]. Qed. Lemma pair_invr_out : {in [predC pair_unitr], pair_invr =1 id}. Proof. by rewrite /pair_invr => x /negPf/= ->. Qed. Definition pair_unitRingMixin := UnitRingMixin pair_mulVl pair_mulVr pair_unitP pair_invr_out. Canonical pair_unitRingType := Eval hnf in UnitRingType (R1 * R2) pair_unitRingMixin. End PairUnitRing. Canonical pair_comUnitRingType (R1 R2 : comUnitRingType) := Eval hnf in [comUnitRingType of R1 * R2]. Canonical pair_unitAlgType (R : comUnitRingType) (A1 A2 : unitAlgType R) := Eval hnf in [unitAlgType R of A1 * A2]. (* begin hide *) (* Testing subtype hierarchy Section Test0. Variables (T : choiceType) (S : predPredType T). Inductive B := mkB x & x \in S. Definition vB u := let: mkB x _ := u in x. Canonical B_subType := [subType for vB]. Definition B_eqMixin := [eqMixin of B by <:]. Canonical B_eqType := EqType B B_eqMixin. Definition B_choiceMixin := [choiceMixin of B by <:]. Canonical B_choiceType := ChoiceType B B_choiceMixin. End Test0. Section Test1. Variables (R : unitRingType) (S : pred R). Variables (ringS : divringPred S) (kS : keyed_pred ringS). Definition B_zmodMixin := [zmodMixin of B kS by <:]. Canonical B_zmodType := ZmodType (B kS) B_zmodMixin. Definition B_ringMixin := [ringMixin of B kS by <:]. Canonical B_ringType := RingType (B kS) B_ringMixin. Definition B_unitRingMixin := [unitRingMixin of B kS by <:]. Canonical B_unitRingType := UnitRingType (B kS) B_unitRingMixin. End Test1. Section Test2. Variables (R : comUnitRingType) (A : unitAlgType R) (S : pred A). Variables (algS : divalgPred S) (kS : keyed_pred algS). Definition B_lmodMixin := [lmodMixin of B kS by <:]. Canonical B_lmodType := LmodType R (B kS) B_lmodMixin. Definition B_lalgMixin := [lalgMixin of B kS by <:]. Canonical B_lalgType := LalgType R (B kS) B_lalgMixin. Definition B_algMixin := [algMixin of B kS by <:]. Canonical B_algType := AlgType R (B kS) B_algMixin. Canonical B_unitAlgType := [unitAlgType R of B kS]. End Test2. Section Test3. Variables (F : fieldType) (S : pred F). Variables (ringS : divringPred S) (kS : keyed_pred ringS). Definition B_comRingMixin := [comRingMixin of B kS by <:]. Canonical B_comRingType := ComRingType (B kS) B_comRingMixin. Canonical B_comUnitRingType := [comUnitRingType of B kS]. Definition B_idomainMixin := [idomainMixin of B kS by <:]. Canonical B_idomainType := IdomainType (B kS) B_idomainMixin. Definition B_fieldMixin := [fieldMixin of B kS by <:]. Canonical B_fieldType := FieldType (B kS) B_fieldMixin. End Test3. *) (* end hide *) mathcomp-1.5/theories/poly.v0000644000175000017500000026766512307636117015203 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div choice fintype. Require Import bigop ssralg binomial. (******************************************************************************) (* This file provides a library for univariate polynomials over ring *) (* structures; it also provides an extended theory for polynomials whose *) (* coefficients range over commutative rings and integral domains. *) (* *) (* {poly R} == the type of polynomials with coefficients of type R, *) (* represented as lists with a non zero last element *) (* (big endian representation); the coeficient type R *) (* must have a canonical ringType structure cR. In fact *) (* {poly R} denotes the concrete type polynomial cR; R *) (* is just a phantom argument that lets type inference *) (* reconstruct the (hidden) ringType structure cR. *) (* p : seq R == the big-endian sequence of coefficients of p, via *) (* the coercion polyseq : polynomial >-> seq. *) (* Poly s == the polynomial with coefficient sequence s (ignoring *) (* trailing zeroes). *) (* \poly_(i < n) E(i) == the polynomial of degree at most n - 1 whose *) (* coefficients are given by the general term E(i) *) (* 0, 1, - p, p + q, == the usual ring operations: {poly R} has a canonical *) (* p * q, p ^+ n, ... ringType structure, which is commutative / integral *) (* when R is commutative / integral, respectively. *) (* polyC c, c%:P == the constant polynomial c *) (* 'X == the (unique) variable *) (* 'X^n == a power of 'X; 'X^0 is 1, 'X^1 is convertible to 'X *) (* p`_i == the coefficient of 'X^i in p; this is in fact just *) (* the ring_scope notation generic seq-indexing using *) (* nth 0%R, combined with the polyseq coercion. *) (* coefp i == the linear function p |-> p`_i (self-exapanding). *) (* size p == 1 + the degree of p, or 0 if p = 0 (this is the *) (* generic seq function combined with polyseq). *) (* lead_coef p == the coefficient of the highest monomial in p, or 0 *) (* if p = 0 (hence lead_coef p = 0 iff p = 0) *) (* p \is monic <=> lead_coef p == 1 (0 is not monic). *) (* p \is a polyOver S <=> the coefficients of p satisfy S; S should have a *) (* key that should be (at least) an addrPred. *) (* p.[x] == the evaluation of a polynomial p at a point x using *) (* the Horner scheme *) (* *** The multi-rule hornerE (resp., hornerE_comm) unwinds *) (* horner evaluation of a polynomial expression (resp., *) (* in a non commutative ring, with side conditions). *) (* p^`() == formal derivative of p *) (* p^`(n) == formal n-derivative of p *) (* p^`N(n) == formal n-derivative of p divided by n! *) (* p \Po q == polynomial composition; because this is naturally a *) (* a linear morphism in the first argument, this *) (* notation is transposed (q comes before p for redex *) (* selection, etc). *) (* := \sum(i < size p) p`_i *: q ^+ i *) (* comm_poly p x == x and p.[x] commute; this is a sufficient condition *) (* for evaluating (q * p).[x] as q.[x] * p.[x] when R *) (* is not commutative. *) (* comm_coef p x == x commutes with all the coefficients of p (clearly, *) (* this implies comm_poly p x). *) (* root p x == x is a root of p, i.e., p.[x] = 0 *) (* n.-unity_root x == x is an nth root of unity, i.e., a root of 'X^n - 1 *) (* n.-primitive_root x == x is a primitive nth root of unity, i.e., n is the *) (* least positive integer m > 0 such that x ^+ m = 1. *) (* *** The submodule poly.UnityRootTheory can be used to *) (* import selectively the part of the theory of roots *) (* of unity that doesn't mention polynomials explicitly *) (* map_poly f p == the image of the polynomial by the function f (which *) (* (locally, p^f) is usually a ring morphism). *) (* p^:P == p lifted to {poly {poly R}} (:= map_poly polyC p). *) (* commr_rmorph f u == u commutes with the image of f (i.e., with all f x). *) (* horner_morph cfu == given cfu : commr_rmorph f u, the function mapping p *) (* to the value of map_poly f p at u; this is a ring *) (* morphism from {poly R} to the codomain of f when f *) (* is a ring morphism. *) (* horner_eval u == the function mapping p to p.[u]; this function can *) (* only be used for u in a commutative ring, so it is *) (* always a linear ring morphism from {poly R} to R. *) (* diff_roots x y == x and y are distinct roots; if R is a field, this *) (* just means x != y, but this concept is generalized *) (* to the case where R is only a ring with units (i.e., *) (* a unitRingType); in which case it means that x and y *) (* commute, and that the difference x - y is a unit *) (* (i.e., has a multiplicative inverse) in R. *) (* to just x != y). *) (* uniq_roots s == s is a sequence or pairwise distinct roots, in the *) (* sense of diff_roots p above. *) (* *** We only show that these operations and properties are transferred by *) (* morphisms whose domain is a field (thus ensuring injectivity). *) (* We prove the factor_theorem, and the max_poly_roots inequality relating *) (* the number of distinct roots of a polynomial and its size. *) (* The some polynomial lemmas use following suffix interpretation : *) (* C - constant polynomial (as in polyseqC : a%:P = nseq (a != 0) a). *) (* X - the polynomial variable 'X (as in coefX : 'X`_i = (i == 1%N)). *) (* Xn - power of 'X (as in monicXn : monic 'X^n). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GRing.Theory. Open Local Scope ring_scope. Reserved Notation "{ 'poly' T }" (at level 0, format "{ 'poly' T }"). Reserved Notation "c %:P" (at level 2, format "c %:P"). Reserved Notation "p ^:P" (at level 2, format "p ^:P"). Reserved Notation "'X" (at level 0). Reserved Notation "''X^' n" (at level 3, n at level 2, format "''X^' n"). Reserved Notation "\poly_ ( i < n ) E" (at level 36, E at level 36, i, n at level 50, format "\poly_ ( i < n ) E"). Reserved Notation "p \Po q" (at level 50). Reserved Notation "p ^`N ( n )" (at level 8, format "p ^`N ( n )"). Reserved Notation "n .-unity_root" (at level 2, format "n .-unity_root"). Reserved Notation "n .-primitive_root" (at level 2, format "n .-primitive_root"). Local Notation simp := Monoid.simpm. Section Polynomial. Variable R : ringType. (* Defines a polynomial as a sequence with <> 0 last element *) Record polynomial := Polynomial {polyseq :> seq R; _ : last 1 polyseq != 0}. Canonical polynomial_subType := Eval hnf in [subType for polyseq]. Definition polynomial_eqMixin := Eval hnf in [eqMixin of polynomial by <:]. Canonical polynomial_eqType := Eval hnf in EqType polynomial polynomial_eqMixin. Definition polynomial_choiceMixin := [choiceMixin of polynomial by <:]. Canonical polynomial_choiceType := Eval hnf in ChoiceType polynomial polynomial_choiceMixin. Lemma poly_inj : injective polyseq. Proof. exact: val_inj. Qed. Definition poly_of of phant R := polynomial. Identity Coercion type_poly_of : poly_of >-> polynomial. Definition coefp_head h i (p : poly_of (Phant R)) := let: tt := h in p`_i. End Polynomial. (* We need to break off the section here to let the argument scope *) (* directives take effect. *) Bind Scope ring_scope with poly_of. Bind Scope ring_scope with polynomial. Arguments Scope polyseq [_ ring_scope]. Arguments Scope poly_inj [_ ring_scope ring_scope _]. Arguments Scope coefp_head [_ _ nat_scope ring_scope _]. Notation "{ 'poly' T }" := (poly_of (Phant T)). Notation coefp i := (coefp_head tt i). Section PolynomialTheory. Variable R : ringType. Implicit Types (a b c x y z : R) (p q r d : {poly R}). Canonical poly_subType := Eval hnf in [subType of {poly R}]. Canonical poly_eqType := Eval hnf in [eqType of {poly R}]. Canonical poly_choiceType := Eval hnf in [choiceType of {poly R}]. Definition lead_coef p := p`_(size p).-1. Lemma lead_coefE p : lead_coef p = p`_(size p).-1. Proof. by []. Qed. Definition poly_nil := @Polynomial R [::] (oner_neq0 R). Definition polyC c : {poly R} := insubd poly_nil [:: c]. Local Notation "c %:P" := (polyC c). (* Remember the boolean (c != 0) is coerced to 1 if true and 0 if false *) Lemma polyseqC c : c%:P = nseq (c != 0) c :> seq R. Proof. by rewrite val_insubd /=; case: (c == 0). Qed. Lemma size_polyC c : size c%:P = (c != 0). Proof. by rewrite polyseqC size_nseq. Qed. Lemma coefC c i : c%:P`_i = if i == 0%N then c else 0. Proof. by rewrite polyseqC; case: i => [|[]]; case: eqP. Qed. Lemma polyCK : cancel polyC (coefp 0). Proof. by move=> c; rewrite [coefp 0 _]coefC. Qed. Lemma polyC_inj : injective polyC. Proof. by move=> c1 c2 eqc12; have:= coefC c2 0; rewrite -eqc12 coefC. Qed. Lemma lead_coefC c : lead_coef c%:P = c. Proof. by rewrite /lead_coef polyseqC; case: eqP. Qed. (* Extensional interpretation (poly <=> nat -> R) *) Lemma polyP p q : nth 0 p =1 nth 0 q <-> p = q. Proof. split=> [eq_pq | -> //]; apply: poly_inj. without loss lt_pq: p q eq_pq / size p < size q. move=> IH; case: (ltngtP (size p) (size q)); try by move/IH->. move/(@eq_from_nth _ 0); exact. case: q => q nz_q /= in lt_pq eq_pq *; case/eqP: nz_q. by rewrite (last_nth 0) -(subnKC lt_pq) /= -eq_pq nth_default ?leq_addr. Qed. Lemma size1_polyC p : size p <= 1 -> p = (p`_0)%:P. Proof. move=> le_p_1; apply/polyP=> i; rewrite coefC. by case: i => // i; rewrite nth_default // (leq_trans le_p_1). Qed. (* Builds a polynomial by extension. *) Definition cons_poly c p : {poly R} := if p is Polynomial ((_ :: _) as s) ns then @Polynomial R (c :: s) ns else c%:P. Lemma polyseq_cons c p : cons_poly c p = (if ~~ nilp p then c :: p else c%:P) :> seq R. Proof. by case: p => [[]]. Qed. Lemma size_cons_poly c p : size (cons_poly c p) = (if nilp p && (c == 0) then 0%N else (size p).+1). Proof. by case: p => [[|c' s] _] //=; rewrite size_polyC; case: eqP. Qed. Lemma coef_cons c p i : (cons_poly c p)`_i = if i == 0%N then c else p`_i.-1. Proof. by case: p i => [[|c' s] _] [] //=; rewrite polyseqC; case: eqP => //= _ []. Qed. (* Build a polynomial directly from a list of coefficients. *) Definition Poly := foldr cons_poly 0%:P. Lemma PolyK c s : last c s != 0 -> Poly s = s :> seq R. Proof. case: s => {c}/= [_ |c s]; first by rewrite polyseqC eqxx. elim: s c => /= [|a s IHs] c nz_c; rewrite polyseq_cons ?{}IHs //. by rewrite !polyseqC !eqxx nz_c. Qed. Lemma polyseqK p : Poly p = p. Proof. by apply: poly_inj; exact: PolyK (valP p). Qed. Lemma size_Poly s : size (Poly s) <= size s. Proof. elim: s => [|c s IHs] /=; first by rewrite polyseqC eqxx. by rewrite polyseq_cons; case: ifP => // _; rewrite size_polyC; case: (~~ _). Qed. Lemma coef_Poly s i : (Poly s)`_i = s`_i. Proof. by elim: s i => [|c s IHs] /= [|i]; rewrite !(coefC, eqxx, coef_cons) /=. Qed. (* Build a polynomial from an infinite sequence of coefficients and a bound. *) Definition poly_expanded_def n E := Poly (mkseq E n). Fact poly_key : unit. Proof. by []. Qed. Definition poly := locked_with poly_key poly_expanded_def. Canonical poly_unlockable := [unlockable fun poly]. Local Notation "\poly_ ( i < n ) E" := (poly n (fun i : nat => E)). Lemma polyseq_poly n E : E n.-1 != 0 -> \poly_(i < n) E i = mkseq [eta E] n :> seq R. Proof. rewrite unlock; case: n => [|n] nzEn; first by rewrite polyseqC eqxx. by rewrite (@PolyK 0) // -nth_last nth_mkseq size_mkseq. Qed. Lemma size_poly n E : size (\poly_(i < n) E i) <= n. Proof. by rewrite unlock (leq_trans (size_Poly _)) ?size_mkseq. Qed. Lemma size_poly_eq n E : E n.-1 != 0 -> size (\poly_(i < n) E i) = n. Proof. by move/polyseq_poly->; apply: size_mkseq. Qed. Lemma coef_poly n E k : (\poly_(i < n) E i)`_k = (if k < n then E k else 0). Proof. rewrite unlock coef_Poly. have [lt_kn | le_nk] := ltnP k n; first by rewrite nth_mkseq. by rewrite nth_default // size_mkseq. Qed. Lemma lead_coef_poly n E : n > 0 -> E n.-1 != 0 -> lead_coef (\poly_(i < n) E i) = E n.-1. Proof. by case: n => // n _ nzE; rewrite /lead_coef size_poly_eq // coef_poly leqnn. Qed. Lemma coefK p : \poly_(i < size p) p`_i = p. Proof. by apply/polyP=> i; rewrite coef_poly; case: ltnP => // /(nth_default 0)->. Qed. (* Zmodule structure for polynomial *) Definition add_poly_def p q := \poly_(i < maxn (size p) (size q)) (p`_i + q`_i). Fact add_poly_key : unit. Proof. by []. Qed. Definition add_poly := locked_with add_poly_key add_poly_def. Canonical add_poly_unlockable := [unlockable fun add_poly]. Definition opp_poly_def p := \poly_(i < size p) - p`_i. Fact opp_poly_key : unit. Proof. by []. Qed. Definition opp_poly := locked_with opp_poly_key opp_poly_def. Canonical opp_poly_unlockable := [unlockable fun opp_poly]. Fact coef_add_poly p q i : (add_poly p q)`_i = p`_i + q`_i. Proof. rewrite unlock coef_poly; case: leqP => //. by rewrite geq_max => /andP[le_p_i le_q_i]; rewrite !nth_default ?add0r. Qed. Fact coef_opp_poly p i : (opp_poly p)`_i = - p`_i. Proof. rewrite unlock coef_poly /=. by case: leqP => // le_p_i; rewrite nth_default ?oppr0. Qed. Fact add_polyA : associative add_poly. Proof. by move=> p q r; apply/polyP=> i; rewrite !coef_add_poly addrA. Qed. Fact add_polyC : commutative add_poly. Proof. by move=> p q; apply/polyP=> i; rewrite !coef_add_poly addrC. Qed. Fact add_poly0 : left_id 0%:P add_poly. Proof. by move=> p; apply/polyP=> i; rewrite coef_add_poly coefC if_same add0r. Qed. Fact add_polyN : left_inverse 0%:P opp_poly add_poly. Proof. move=> p; apply/polyP=> i. by rewrite coef_add_poly coef_opp_poly coefC if_same addNr. Qed. Definition poly_zmodMixin := ZmodMixin add_polyA add_polyC add_poly0 add_polyN. Canonical poly_zmodType := Eval hnf in ZmodType {poly R} poly_zmodMixin. Canonical polynomial_zmodType := Eval hnf in ZmodType (polynomial R) poly_zmodMixin. (* Properties of the zero polynomial *) Lemma polyC0 : 0%:P = 0 :> {poly R}. Proof. by []. Qed. Lemma polyseq0 : (0 : {poly R}) = [::] :> seq R. Proof. by rewrite polyseqC eqxx. Qed. Lemma size_poly0 : size (0 : {poly R}) = 0%N. Proof. by rewrite polyseq0. Qed. Lemma coef0 i : (0 : {poly R})`_i = 0. Proof. by rewrite coefC if_same. Qed. Lemma lead_coef0 : lead_coef 0 = 0 :> R. Proof. exact: lead_coefC. Qed. Lemma size_poly_eq0 p : (size p == 0%N) = (p == 0). Proof. by rewrite size_eq0 -polyseq0. Qed. Lemma size_poly_leq0 p : (size p <= 0) = (p == 0). Proof. by rewrite leqn0 size_poly_eq0. Qed. Lemma size_poly_leq0P p : reflect (p = 0) (size p <= 0%N). Proof. by apply: (iffP idP); rewrite size_poly_leq0; move/eqP. Qed. Lemma size_poly_gt0 p : (0 < size p) = (p != 0). Proof. by rewrite lt0n size_poly_eq0. Qed. Lemma nil_poly p : nilp p = (p == 0). Proof. exact: size_poly_eq0. Qed. Lemma poly0Vpos p : {p = 0} + {size p > 0}. Proof. by rewrite lt0n size_poly_eq0; exact: eqVneq. Qed. Lemma polySpred p : p != 0 -> size p = (size p).-1.+1. Proof. by rewrite -size_poly_eq0 -lt0n => /prednK. Qed. Lemma lead_coef_eq0 p : (lead_coef p == 0) = (p == 0). Proof. rewrite -nil_poly /lead_coef nth_last. by case: p => [[|x s] /= /negbTE // _]; rewrite eqxx. Qed. Lemma polyC_eq0 (c : R) : (c%:P == 0) = (c == 0). Proof. by rewrite -nil_poly polyseqC; case: (c == 0). Qed. Lemma size_poly1P p : reflect (exists2 c, c != 0 & p = c%:P) (size p == 1%N). Proof. apply: (iffP eqP) => [pC | [c nz_c ->]]; last by rewrite size_polyC nz_c. have def_p: p = (p`_0)%:P by rewrite -size1_polyC ?pC. by exists p`_0; rewrite // -polyC_eq0 -def_p -size_poly_eq0 pC. Qed. Lemma leq_sizeP p i : reflect (forall j, i <= j -> p`_j = 0) (size p <= i). Proof. apply: (iffP idP) => [hp j hij| hp]. by apply: nth_default; apply: leq_trans hij. case p0: (p == 0); first by rewrite (eqP p0) size_poly0. move: (lead_coef_eq0 p); rewrite p0 leqNgt; move/negbT; apply: contra => hs. by apply/eqP; apply: hp; rewrite -ltnS (ltn_predK hs). Qed. (* Size, leading coef, morphism properties of coef *) Lemma coefD p q i : (p + q)`_i = p`_i + q`_i. Proof. exact: coef_add_poly. Qed. Lemma coefN p i : (- p)`_i = - p`_i. Proof. exact: coef_opp_poly. Qed. Lemma coefB p q i : (p - q)`_i = p`_i - q`_i. Proof. by rewrite coefD coefN. Qed. Canonical coefp_additive i := Additive ((fun p => (coefB p)^~ i) : additive (coefp i)). Lemma coefMn p n i : (p *+ n)`_i = p`_i *+ n. Proof. exact: (raddfMn (coefp_additive i)). Qed. Lemma coefMNn p n i : (p *- n)`_i = p`_i *- n. Proof. by rewrite coefN coefMn. Qed. Lemma coef_sum I (r : seq I) (P : pred I) (F : I -> {poly R}) k : (\sum_(i <- r | P i) F i)`_k = \sum_(i <- r | P i) (F i)`_k. Proof. exact: (raddf_sum (coefp_additive k)). Qed. Lemma polyC_add : {morph polyC : a b / a + b}. Proof. by move=> a b; apply/polyP=> [[|i]]; rewrite coefD !coefC ?addr0. Qed. Lemma polyC_opp : {morph polyC : c / - c}. Proof. by move=> c; apply/polyP=> [[|i]]; rewrite coefN !coefC ?oppr0. Qed. Lemma polyC_sub : {morph polyC : a b / a - b}. Proof. by move=> a b; rewrite polyC_add polyC_opp. Qed. Canonical polyC_additive := Additive polyC_sub. Lemma polyC_muln n : {morph polyC : c / c *+ n}. Proof. exact: raddfMn. Qed. Lemma size_opp p : size (- p) = size p. Proof. by apply/eqP; rewrite eqn_leq -{3}(opprK p) -[-%R]/opp_poly unlock !size_poly. Qed. Lemma lead_coef_opp p : lead_coef (- p) = - lead_coef p. Proof. by rewrite /lead_coef size_opp coefN. Qed. Lemma size_add p q : size (p + q) <= maxn (size p) (size q). Proof. by rewrite -[+%R]/add_poly unlock; apply: size_poly. Qed. Lemma size_addl p q : size p > size q -> size (p + q) = size p. Proof. move=> ltqp; rewrite -[+%R]/add_poly unlock size_poly_eq (maxn_idPl (ltnW _))//. by rewrite addrC nth_default ?simp ?nth_last //; case: p ltqp => [[]]. Qed. Lemma size_sum I (r : seq I) (P : pred I) (F : I -> {poly R}) : size (\sum_(i <- r | P i) F i) <= \max_(i <- r | P i) size (F i). Proof. elim/big_rec2: _ => [|i p q _ IHp]; first by rewrite size_poly0. by rewrite -(maxn_idPr IHp) maxnA leq_max size_add. Qed. Lemma lead_coefDl p q : size p > size q -> lead_coef (p + q) = lead_coef p. Proof. move=> ltqp; rewrite /lead_coef coefD size_addl //. by rewrite addrC nth_default ?simp // -ltnS (ltn_predK ltqp). Qed. (* Polynomial ring structure. *) Definition mul_poly_def p q := \poly_(i < (size p + size q).-1) (\sum_(j < i.+1) p`_j * q`_(i - j)). Fact mul_poly_key : unit. Proof. by []. Qed. Definition mul_poly := locked_with mul_poly_key mul_poly_def. Canonical mul_poly_unlockable := [unlockable fun mul_poly]. Fact coef_mul_poly p q i : (mul_poly p q)`_i = \sum_(j < i.+1) p`_j * q`_(i - j)%N. Proof. rewrite unlock coef_poly -subn1 ltn_subRL add1n; case: leqP => // le_pq_i1. rewrite big1 // => j _; have [lq_q_ij | gt_q_ij] := leqP (size q) (i - j). by rewrite [q`__]nth_default ?mulr0. rewrite nth_default ?mul0r // -(leq_add2r (size q)) (leq_trans le_pq_i1) //. by rewrite -leq_subLR -subnSK. Qed. Fact coef_mul_poly_rev p q i : (mul_poly p q)`_i = \sum_(j < i.+1) p`_(i - j)%N * q`_j. Proof. rewrite coef_mul_poly (reindex_inj rev_ord_inj) /=. by apply: eq_bigr => j _; rewrite (sub_ordK j). Qed. Fact mul_polyA : associative mul_poly. Proof. move=> p q r; apply/polyP=> i; rewrite coef_mul_poly coef_mul_poly_rev. pose coef3 j k := p`_j * (q`_(i - j - k)%N * r`_k). transitivity (\sum_(j < i.+1) \sum_(k < i.+1 | k <= i - j) coef3 j k). apply: eq_bigr => /= j _; rewrite coef_mul_poly_rev big_distrr /=. by rewrite (big_ord_narrow_leq (leq_subr _ _)). rewrite (exchange_big_dep predT) //=; apply: eq_bigr => k _. transitivity (\sum_(j < i.+1 | j <= i - k) coef3 j k). apply: eq_bigl => j; rewrite -ltnS -(ltnS j) -!subSn ?leq_ord //. by rewrite -subn_gt0 -(subn_gt0 j) -!subnDA addnC. rewrite (big_ord_narrow_leq (leq_subr _ _)) coef_mul_poly big_distrl /=. by apply: eq_bigr => j _; rewrite /coef3 -!subnDA addnC mulrA. Qed. Fact mul_1poly : left_id 1%:P mul_poly. Proof. move=> p; apply/polyP => i; rewrite coef_mul_poly big_ord_recl subn0. by rewrite big1 => [|j _]; rewrite coefC !simp. Qed. Fact mul_poly1 : right_id 1%:P mul_poly. Proof. move=> p; apply/polyP => i; rewrite coef_mul_poly_rev big_ord_recl subn0. by rewrite big1 => [|j _]; rewrite coefC !simp. Qed. Fact mul_polyDl : left_distributive mul_poly +%R. Proof. move=> p q r; apply/polyP=> i; rewrite coefD !coef_mul_poly -big_split. by apply: eq_bigr => j _; rewrite coefD mulrDl. Qed. Fact mul_polyDr : right_distributive mul_poly +%R. Proof. move=> p q r; apply/polyP=> i; rewrite coefD !coef_mul_poly -big_split. by apply: eq_bigr => j _; rewrite coefD mulrDr. Qed. Fact poly1_neq0 : 1%:P != 0 :> {poly R}. Proof. by rewrite polyC_eq0 oner_neq0. Qed. Definition poly_ringMixin := RingMixin mul_polyA mul_1poly mul_poly1 mul_polyDl mul_polyDr poly1_neq0. Canonical poly_ringType := Eval hnf in RingType {poly R} poly_ringMixin. Canonical polynomial_ringType := Eval hnf in RingType (polynomial R) poly_ringMixin. Lemma polyC1 : 1%:P = 1 :> {poly R}. Proof. by []. Qed. Lemma polyseq1 : (1 : {poly R}) = [:: 1] :> seq R. Proof. by rewrite polyseqC oner_neq0. Qed. Lemma size_poly1 : size (1 : {poly R}) = 1%N. Proof. by rewrite polyseq1. Qed. Lemma coef1 i : (1 : {poly R})`_i = (i == 0%N)%:R. Proof. by case: i => [|i]; rewrite polyseq1 /= ?nth_nil. Qed. Lemma lead_coef1 : lead_coef 1 = 1 :> R. Proof. exact: lead_coefC. Qed. Lemma coefM p q i : (p * q)`_i = \sum_(j < i.+1) p`_j * q`_(i - j)%N. Proof. exact: coef_mul_poly. Qed. Lemma coefMr p q i : (p * q)`_i = \sum_(j < i.+1) p`_(i - j)%N * q`_j. Proof. exact: coef_mul_poly_rev. Qed. Lemma size_mul_leq p q : size (p * q) <= (size p + size q).-1. Proof. by rewrite -[*%R]/mul_poly unlock size_poly. Qed. Lemma mul_lead_coef p q : lead_coef p * lead_coef q = (p * q)`_(size p + size q).-2. Proof. pose dp := (size p).-1; pose dq := (size q).-1. have [-> | nz_p] := eqVneq p 0; first by rewrite lead_coef0 !mul0r coef0. have [-> | nz_q] := eqVneq q 0; first by rewrite lead_coef0 !mulr0 coef0. have ->: (size p + size q).-2 = (dp + dq)%N. by do 2! rewrite polySpred // addSn addnC. have lt_p_pq: dp < (dp + dq).+1 by rewrite ltnS leq_addr. rewrite coefM (bigD1 (Ordinal lt_p_pq)) ?big1 ?simp ?addKn //= => i. rewrite -val_eqE neq_ltn /= => /orP[lt_i_p | gt_i_p]; last first. by rewrite nth_default ?mul0r //; rewrite -polySpred in gt_i_p. rewrite [q`__]nth_default ?mulr0 //= -subSS -{1}addnS -polySpred //. by rewrite addnC -addnBA ?leq_addr. Qed. Lemma size_proper_mul p q : lead_coef p * lead_coef q != 0 -> size (p * q) = (size p + size q).-1. Proof. apply: contraNeq; rewrite mul_lead_coef eqn_leq size_mul_leq -ltnNge => lt_pq. by rewrite nth_default // -subn1 -(leq_add2l 1) -leq_subLR leq_sub2r. Qed. Lemma lead_coef_proper_mul p q : let c := lead_coef p * lead_coef q in c != 0 -> lead_coef (p * q) = c. Proof. by move=> /= nz_c; rewrite mul_lead_coef -size_proper_mul. Qed. Lemma size_prod_leq (I : finType) (P : pred I) (F : I -> {poly R}) : size (\prod_(i | P i) F i) <= (\sum_(i | P i) size (F i)).+1 - #|P|. Proof. rewrite -sum1_card. elim/big_rec3: _ => [|i n m p _ IHp]; first by rewrite size_poly1. have [-> | nz_p] := eqVneq p 0; first by rewrite mulr0 size_poly0. rewrite (leq_trans (size_mul_leq _ _)) // subnS -!subn1 leq_sub2r //. rewrite -addnS -addnBA ?leq_add2l // ltnW // -subn_gt0 (leq_trans _ IHp) //. by rewrite polySpred. Qed. Lemma coefCM c p i : (c%:P * p)`_i = c * p`_i. Proof. rewrite coefM big_ord_recl subn0. by rewrite big1 => [|j _]; rewrite coefC !simp. Qed. Lemma coefMC c p i : (p * c%:P)`_i = p`_i * c. Proof. rewrite coefMr big_ord_recl subn0. by rewrite big1 => [|j _]; rewrite coefC !simp. Qed. Lemma polyC_mul : {morph polyC : a b / a * b}. Proof. by move=> a b; apply/polyP=> [[|i]]; rewrite coefCM !coefC ?simp. Qed. Fact polyC_multiplicative : multiplicative polyC. Proof. by split; first exact: polyC_mul. Qed. Canonical polyC_rmorphism := AddRMorphism polyC_multiplicative. Lemma polyC_exp n : {morph polyC : c / c ^+ n}. Proof. exact: rmorphX. Qed. Lemma size_exp_leq p n : size (p ^+ n) <= ((size p).-1 * n).+1. Proof. elim: n => [|n IHn]; first by rewrite size_poly1. have [-> | nzp] := poly0Vpos p; first by rewrite exprS mul0r size_poly0. rewrite exprS (leq_trans (size_mul_leq _ _)) //. by rewrite -{1}(prednK nzp) mulnS -addnS leq_add2l. Qed. Lemma size_Msign p n : size ((-1) ^+ n * p) = size p. Proof. by rewrite -signr_odd; case: (odd n); rewrite ?mul1r // mulN1r size_opp. Qed. Fact coefp0_multiplicative : multiplicative (coefp 0 : {poly R} -> R). Proof. split=> [p q|]; last by rewrite polyCK. by rewrite [coefp 0 _]coefM big_ord_recl big_ord0 addr0. Qed. Canonical coefp0_rmorphism := AddRMorphism coefp0_multiplicative. (* Algebra structure of polynomials. *) Definition scale_poly_def a (p : {poly R}) := \poly_(i < size p) (a * p`_i). Fact scale_poly_key : unit. Proof. by []. Qed. Definition scale_poly := locked_with scale_poly_key scale_poly_def. Canonical scale_poly_unlockable := [unlockable fun scale_poly]. Fact scale_polyE a p : scale_poly a p = a%:P * p. Proof. apply/polyP=> n; rewrite unlock coef_poly coefCM. by case: leqP => // le_p_n; rewrite nth_default ?mulr0. Qed. Fact scale_polyA a b p : scale_poly a (scale_poly b p) = scale_poly (a * b) p. Proof. by rewrite !scale_polyE mulrA polyC_mul. Qed. Fact scale_1poly : left_id 1 scale_poly. Proof. by move=> p; rewrite scale_polyE mul1r. Qed. Fact scale_polyDr a : {morph scale_poly a : p q / p + q}. Proof. by move=> p q; rewrite !scale_polyE mulrDr. Qed. Fact scale_polyDl p : {morph scale_poly^~ p : a b / a + b}. Proof. by move=> a b /=; rewrite !scale_polyE raddfD mulrDl. Qed. Fact scale_polyAl a p q : scale_poly a (p * q) = scale_poly a p * q. Proof. by rewrite !scale_polyE mulrA. Qed. Definition poly_lmodMixin := LmodMixin scale_polyA scale_1poly scale_polyDr scale_polyDl. Canonical poly_lmodType := Eval hnf in LmodType R {poly R} poly_lmodMixin. Canonical polynomial_lmodType := Eval hnf in LmodType R (polynomial R) poly_lmodMixin. Canonical poly_lalgType := Eval hnf in LalgType R {poly R} scale_polyAl. Canonical polynomial_lalgType := Eval hnf in LalgType R (polynomial R) scale_polyAl. Lemma mul_polyC a p : a%:P * p = a *: p. Proof. by rewrite -scale_polyE. Qed. Lemma alg_polyC a : a%:A = a%:P :> {poly R}. Proof. by rewrite -mul_polyC mulr1. Qed. Lemma coefZ a p i : (a *: p)`_i = a * p`_i. Proof. rewrite -[*:%R]/scale_poly unlock coef_poly. by case: leqP => // le_p_n; rewrite nth_default ?mulr0. Qed. Lemma size_scale_leq a p : size (a *: p) <= size p. Proof. by rewrite -[*:%R]/scale_poly unlock size_poly. Qed. Canonical coefp_linear i : {scalar {poly R}} := AddLinear ((fun a => (coefZ a) ^~ i) : scalable_for *%R (coefp i)). Canonical coefp0_lrmorphism := [lrmorphism of coefp 0]. (* The indeterminate, at last! *) Definition polyX_def := Poly [:: 0; 1]. Fact polyX_key : unit. Proof. by []. Qed. Definition polyX : {poly R} := locked_with polyX_key polyX_def. Canonical polyX_unlockable := [unlockable of polyX]. Local Notation "'X" := polyX. Lemma polyseqX : 'X = [:: 0; 1] :> seq R. Proof. by rewrite unlock !polyseq_cons nil_poly eqxx /= polyseq1. Qed. Lemma size_polyX : size 'X = 2. Proof. by rewrite polyseqX. Qed. Lemma polyX_eq0 : ('X == 0) = false. Proof. by rewrite -size_poly_eq0 size_polyX. Qed. Lemma coefX i : 'X`_i = (i == 1%N)%:R. Proof. by case: i => [|[|i]]; rewrite polyseqX //= nth_nil. Qed. Lemma lead_coefX : lead_coef 'X = 1. Proof. by rewrite /lead_coef polyseqX. Qed. Lemma commr_polyX p : GRing.comm p 'X. Proof. apply/polyP=> i; rewrite coefMr coefM. by apply: eq_bigr => j _; rewrite coefX commr_nat. Qed. Lemma coefMX p i : (p * 'X)`_i = (if (i == 0)%N then 0 else p`_i.-1). Proof. rewrite coefMr big_ord_recl coefX ?simp. case: i => [|i]; rewrite ?big_ord0 //= big_ord_recl polyseqX subn1 /=. by rewrite big1 ?simp // => j _; rewrite nth_nil !simp. Qed. Lemma coefXM p i : ('X * p)`_i = (if (i == 0)%N then 0 else p`_i.-1). Proof. by rewrite -commr_polyX coefMX. Qed. Lemma cons_poly_def p a : cons_poly a p = p * 'X + a%:P. Proof. apply/polyP=> i; rewrite coef_cons coefD coefMX coefC. by case: ifP; rewrite !simp. Qed. Lemma poly_ind (K : {poly R} -> Type) : K 0 -> (forall p c, K p -> K (p * 'X + c%:P)) -> (forall p, K p). Proof. move=> K0 Kcons p; rewrite -[p]polyseqK. elim: {p}(p : seq R) => //= p c IHp; rewrite cons_poly_def; exact: Kcons. Qed. Lemma polyseqXsubC a : 'X - a%:P = [:: - a; 1] :> seq R. Proof. by rewrite -['X]mul1r -polyC_opp -cons_poly_def polyseq_cons polyseq1. Qed. Lemma size_XsubC a : size ('X - a%:P) = 2%N. Proof. by rewrite polyseqXsubC. Qed. Lemma size_XaddC b : size ('X + b%:P) = 2. Proof. by rewrite -[b]opprK rmorphN size_XsubC. Qed. Lemma lead_coefXsubC a : lead_coef ('X - a%:P) = 1. Proof. by rewrite lead_coefE polyseqXsubC. Qed. Lemma polyXsubC_eq0 a : ('X - a%:P == 0) = false. Proof. by rewrite -nil_poly polyseqXsubC. Qed. Lemma size_MXaddC p c : size (p * 'X + c%:P) = (if (p == 0) && (c == 0) then 0%N else (size p).+1). Proof. by rewrite -cons_poly_def size_cons_poly nil_poly. Qed. Lemma polyseqMX p : p != 0 -> p * 'X = 0 :: p :> seq R. Proof. by move=> nz_p; rewrite -[p * _]addr0 -cons_poly_def polyseq_cons nil_poly nz_p. Qed. Lemma size_mulX p : p != 0 -> size (p * 'X) = (size p).+1. Proof. by move/polyseqMX->. Qed. Lemma lead_coefMX p : lead_coef (p * 'X) = lead_coef p. Proof. have [-> | nzp] := eqVneq p 0; first by rewrite mul0r. by rewrite /lead_coef !nth_last polyseqMX. Qed. Lemma size_XmulC a : a != 0 -> size ('X * a%:P) = 2. Proof. by move=> nz_a; rewrite -commr_polyX size_mulX ?polyC_eq0 ?size_polyC nz_a. Qed. Local Notation "''X^' n" := ('X ^+ n). Lemma coefXn n i : 'X^n`_i = (i == n)%:R. Proof. by elim: n i => [|n IHn] [|i]; rewrite ?coef1 // exprS coefXM ?IHn. Qed. Lemma polyseqXn n : 'X^n = rcons (nseq n 0) 1 :> seq R. Proof. elim: n => [|n IHn]; rewrite ?polyseq1 // exprSr. by rewrite polyseqMX -?size_poly_eq0 IHn ?size_rcons. Qed. Lemma size_polyXn n : size 'X^n = n.+1. Proof. by rewrite polyseqXn size_rcons size_nseq. Qed. Lemma commr_polyXn p n : GRing.comm p 'X^n. Proof. by apply: commrX; exact: commr_polyX. Qed. Lemma lead_coefXn n : lead_coef 'X^n = 1. Proof. by rewrite /lead_coef nth_last polyseqXn last_rcons. Qed. Lemma polyseqMXn n p : p != 0 -> p * 'X^n = ncons n 0 p :> seq R. Proof. case: n => [|n] nz_p; first by rewrite mulr1. elim: n => [|n IHn]; first exact: polyseqMX. by rewrite exprSr mulrA polyseqMX -?nil_poly IHn. Qed. Lemma coefMXn n p i : (p * 'X^n)`_i = if i < n then 0 else p`_(i - n). Proof. have [-> | /polyseqMXn->] := eqVneq p 0; last exact: nth_ncons. by rewrite mul0r !coef0 if_same. Qed. Lemma coefXnM n p i : ('X^n * p)`_i = if i < n then 0 else p`_(i - n). Proof. by rewrite -commr_polyXn coefMXn. Qed. (* Expansion of a polynomial as an indexed sum *) Lemma poly_def n E : \poly_(i < n) E i = \sum_(i < n) E i *: 'X^i. Proof. rewrite unlock; elim: n => [|n IHn] in E *; first by rewrite big_ord0. rewrite big_ord_recl /= cons_poly_def addrC expr0 alg_polyC. congr (_ + _); rewrite (iota_addl 1 0) -map_comp IHn big_distrl /=. by apply: eq_bigr => i _; rewrite -scalerAl exprSr. Qed. (* Monic predicate *) Definition monic := [qualify p | lead_coef p == 1]. Fact monic_key : pred_key monic. Proof. by []. Qed. Canonical monic_keyed := KeyedQualifier monic_key. Lemma monicE p : (p \is monic) = (lead_coef p == 1). Proof. by []. Qed. Lemma monicP p : reflect (lead_coef p = 1) (p \is monic). Proof. exact: eqP. Qed. Lemma monic1 : 1 \is monic. Proof. exact/eqP/lead_coef1. Qed. Lemma monicX : 'X \is monic. Proof. exact/eqP/lead_coefX. Qed. Lemma monicXn n : 'X^n \is monic. Proof. exact/eqP/lead_coefXn. Qed. Lemma monic_neq0 p : p \is monic -> p != 0. Proof. by rewrite -lead_coef_eq0 => /eqP->; exact: oner_neq0. Qed. Lemma lead_coef_monicM p q : p \is monic -> lead_coef (p * q) = lead_coef q. Proof. have [-> | nz_q] := eqVneq q 0; first by rewrite mulr0. by move/monicP=> mon_p; rewrite lead_coef_proper_mul mon_p mul1r ?lead_coef_eq0. Qed. Lemma lead_coef_Mmonic p q : q \is monic -> lead_coef (p * q) = lead_coef p. Proof. have [-> | nz_p] := eqVneq p 0; first by rewrite mul0r. by move/monicP=> mon_q; rewrite lead_coef_proper_mul mon_q mulr1 ?lead_coef_eq0. Qed. Lemma size_monicM p q : p \is monic -> q != 0 -> size (p * q) = (size p + size q).-1. Proof. move/monicP=> mon_p nz_q. by rewrite size_proper_mul // mon_p mul1r lead_coef_eq0. Qed. Lemma size_Mmonic p q : p != 0 -> q \is monic -> size (p * q) = (size p + size q).-1. Proof. move=> nz_p /monicP mon_q. by rewrite size_proper_mul // mon_q mulr1 lead_coef_eq0. Qed. Lemma monicMl p q : p \is monic -> (p * q \is monic) = (q \is monic). Proof. by move=> mon_p; rewrite !monicE lead_coef_monicM. Qed. Lemma monicMr p q : q \is monic -> (p * q \is monic) = (p \is monic). Proof. by move=> mon_q; rewrite !monicE lead_coef_Mmonic. Qed. Fact monic_mulr_closed : mulr_closed monic. Proof. by split=> [|p q mon_p]; rewrite (monic1, monicMl). Qed. Canonical monic_mulrPred := MulrPred monic_mulr_closed. Lemma monic_exp p n : p \is monic -> p ^+ n \is monic. Proof. exact: rpredX. Qed. Lemma monic_prod I rI (P : pred I) (F : I -> {poly R}): (forall i, P i -> F i \is monic) -> \prod_(i <- rI | P i) F i \is monic. Proof. exact: rpred_prod. Qed. Lemma monicXsubC c : 'X - c%:P \is monic. Proof. exact/eqP/lead_coefXsubC. Qed. Lemma monic_prod_XsubC I rI (P : pred I) (F : I -> R) : \prod_(i <- rI | P i) ('X - (F i)%:P) \is monic. Proof. by apply: monic_prod => i _; exact: monicXsubC. Qed. Lemma size_prod_XsubC I rI (F : I -> R) : size (\prod_(i <- rI) ('X - (F i)%:P)) = (size rI).+1. Proof. elim: rI => [|i r /= <-]; rewrite ?big_nil ?size_poly1 // big_cons. rewrite size_monicM ?monicXsubC ?monic_neq0 ?monic_prod_XsubC //. by rewrite size_XsubC. Qed. Lemma size_exp_XsubC n a : size (('X - a%:P) ^+ n) = n.+1. Proof. by rewrite -[n]card_ord -prodr_const size_prod_XsubC cardE enumT. Qed. (* Some facts about regular elements. *) Lemma lreg_lead p : GRing.lreg (lead_coef p) -> GRing.lreg p. Proof. move/mulrI_eq0=> reg_p; apply: mulrI0_lreg => q /eqP; apply: contraTeq => nz_q. by rewrite -lead_coef_eq0 lead_coef_proper_mul reg_p lead_coef_eq0. Qed. Lemma rreg_lead p : GRing.rreg (lead_coef p) -> GRing.rreg p. Proof. move/mulIr_eq0=> reg_p; apply: mulIr0_rreg => q /eqP; apply: contraTeq => nz_q. by rewrite -lead_coef_eq0 lead_coef_proper_mul reg_p lead_coef_eq0. Qed. Lemma lreg_lead0 p : GRing.lreg (lead_coef p) -> p != 0. Proof. by move/lreg_neq0; rewrite lead_coef_eq0. Qed. Lemma rreg_lead0 p : GRing.rreg (lead_coef p) -> p != 0. Proof. by move/rreg_neq0; rewrite lead_coef_eq0. Qed. Lemma lreg_size c p : GRing.lreg c -> size (c *: p) = size p. Proof. move=> reg_c; have [-> | nz_p] := eqVneq p 0; first by rewrite scaler0. rewrite -mul_polyC size_proper_mul; first by rewrite size_polyC lreg_neq0. by rewrite lead_coefC mulrI_eq0 ?lead_coef_eq0. Qed. Lemma lreg_polyZ_eq0 c p : GRing.lreg c -> (c *: p == 0) = (p == 0). Proof. by rewrite -!size_poly_eq0 => /lreg_size->. Qed. Lemma lead_coef_lreg c p : GRing.lreg c -> lead_coef (c *: p) = c * lead_coef p. Proof. by move=> reg_c; rewrite !lead_coefE coefZ lreg_size. Qed. Lemma rreg_size c p : GRing.rreg c -> size (p * c%:P) = size p. Proof. move=> reg_c; have [-> | nz_p] := eqVneq p 0; first by rewrite mul0r. rewrite size_proper_mul; first by rewrite size_polyC rreg_neq0 ?addn1. by rewrite lead_coefC mulIr_eq0 ?lead_coef_eq0. Qed. Lemma rreg_polyMC_eq0 c p : GRing.rreg c -> (p * c%:P == 0) = (p == 0). Proof. by rewrite -!size_poly_eq0 => /rreg_size->. Qed. Lemma rreg_div0 q r d : GRing.rreg (lead_coef d) -> size r < size d -> (q * d + r == 0) = (q == 0) && (r == 0). Proof. move=> reg_d lt_r_d; rewrite addrC addr_eq0. have [-> | nz_q] := altP (q =P 0); first by rewrite mul0r oppr0. apply: contraTF lt_r_d => /eqP->; rewrite -leqNgt size_opp. rewrite size_proper_mul ?mulIr_eq0 ?lead_coef_eq0 //. by rewrite (polySpred nz_q) leq_addl. Qed. Lemma monic_comreg p : p \is monic -> GRing.comm p (lead_coef p)%:P /\ GRing.rreg (lead_coef p). Proof. by move/monicP->; split; [exact: commr1 | exact: rreg1]. Qed. (* Horner evaluation of polynomials *) Implicit Types s rs : seq R. Fixpoint horner_rec s x := if s is a :: s' then horner_rec s' x * x + a else 0. Definition horner p := horner_rec p. Local Notation "p .[ x ]" := (horner p x) : ring_scope. Lemma horner0 x : (0 : {poly R}).[x] = 0. Proof. by rewrite /horner polyseq0. Qed. Lemma hornerC c x : (c%:P).[x] = c. Proof. by rewrite /horner polyseqC; case: eqP; rewrite /= ?simp. Qed. Lemma hornerX x : 'X.[x] = x. Proof. by rewrite /horner polyseqX /= !simp. Qed. Lemma horner_cons p c x : (cons_poly c p).[x] = p.[x] * x + c. Proof. rewrite /horner polyseq_cons; case: nilP => //= ->. by rewrite !simp -/(_.[x]) hornerC. Qed. Lemma horner_coef0 p : p.[0] = p`_0. Proof. by rewrite /horner; case: (p : seq R) => //= c p'; rewrite !simp. Qed. Lemma hornerMXaddC p c x : (p * 'X + c%:P).[x] = p.[x] * x + c. Proof. by rewrite -cons_poly_def horner_cons. Qed. Lemma hornerMX p x : (p * 'X).[x] = p.[x] * x. Proof. by rewrite -[p * 'X]addr0 hornerMXaddC addr0. Qed. Lemma horner_Poly s x : (Poly s).[x] = horner_rec s x. Proof. by elim: s => [|a s /= <-]; rewrite (horner0, horner_cons). Qed. Lemma horner_coef p x : p.[x] = \sum_(i < size p) p`_i * x ^+ i. Proof. rewrite /horner. elim: {p}(p : seq R) => /= [|a s ->]; first by rewrite big_ord0. rewrite big_ord_recl simp addrC big_distrl /=. by congr (_ + _); apply: eq_bigr => i _; rewrite -mulrA exprSr. Qed. Lemma horner_coef_wide n p x : size p <= n -> p.[x] = \sum_(i < n) p`_i * x ^+ i. Proof. move=> le_p_n. rewrite horner_coef (big_ord_widen n (fun i => p`_i * x ^+ i)) // big_mkcond. by apply: eq_bigr => i _; case: ltnP => // le_p_i; rewrite nth_default ?simp. Qed. Lemma horner_poly n E x : (\poly_(i < n) E i).[x] = \sum_(i < n) E i * x ^+ i. Proof. rewrite (@horner_coef_wide n) ?size_poly //. by apply: eq_bigr => i _; rewrite coef_poly ltn_ord. Qed. Lemma hornerN p x : (- p).[x] = - p.[x]. Proof. rewrite -[-%R]/opp_poly unlock horner_poly horner_coef -sumrN /=. by apply: eq_bigr => i _; rewrite mulNr. Qed. Lemma hornerD p q x : (p + q).[x] = p.[x] + q.[x]. Proof. rewrite -[+%R]/add_poly unlock horner_poly; set m := maxn _ _. rewrite !(@horner_coef_wide m) ?leq_max ?leqnn ?orbT // -big_split /=. by apply: eq_bigr => i _; rewrite -mulrDl. Qed. Lemma hornerXsubC a x : ('X - a%:P).[x] = x - a. Proof. by rewrite hornerD hornerN hornerC hornerX. Qed. Lemma horner_sum I (r : seq I) (P : pred I) F x : (\sum_(i <- r | P i) F i).[x] = \sum_(i <- r | P i) (F i).[x]. Proof. by elim/big_rec2: _ => [|i _ p _ <-]; rewrite (horner0, hornerD). Qed. Lemma hornerCM a p x : (a%:P * p).[x] = a * p.[x]. Proof. elim/poly_ind: p => [|p c IHp]; first by rewrite !(mulr0, horner0). by rewrite mulrDr mulrA -polyC_mul !hornerMXaddC IHp mulrDr mulrA. Qed. Lemma hornerZ c p x : (c *: p).[x] = c * p.[x]. Proof. by rewrite -mul_polyC hornerCM. Qed. Lemma hornerMn n p x : (p *+ n).[x] = p.[x] *+ n. Proof. by elim: n => [| n IHn]; rewrite ?horner0 // !mulrS hornerD IHn. Qed. Definition comm_coef p x := forall i, p`_i * x = x * p`_i. Definition comm_poly p x := x * p.[x] = p.[x] * x. Lemma comm_coef_poly p x : comm_coef p x -> comm_poly p x. Proof. move=> cpx; rewrite /comm_poly !horner_coef big_distrl big_distrr /=. by apply: eq_bigr => i _; rewrite /= mulrA -cpx -!mulrA commrX. Qed. Lemma comm_poly0 x : comm_poly 0 x. Proof. by rewrite /comm_poly !horner0 !simp. Qed. Lemma comm_poly1 x : comm_poly 1 x. Proof. by rewrite /comm_poly !hornerC !simp. Qed. Lemma comm_polyX x : comm_poly 'X x. Proof. by rewrite /comm_poly !hornerX. Qed. Lemma hornerM_comm p q x : comm_poly q x -> (p * q).[x] = p.[x] * q.[x]. Proof. move=> comm_qx. elim/poly_ind: p => [|p c IHp]; first by rewrite !(simp, horner0). rewrite mulrDl hornerD hornerCM -mulrA -commr_polyX mulrA hornerMX. by rewrite {}IHp -mulrA -comm_qx mulrA -mulrDl hornerMXaddC. Qed. Lemma horner_exp_comm p x n : comm_poly p x -> (p ^+ n).[x] = p.[x] ^+ n. Proof. move=> comm_px; elim: n => [|n IHn]; first by rewrite hornerC. by rewrite !exprSr -IHn hornerM_comm. Qed. Lemma hornerXn x n : ('X^n).[x] = x ^+ n. Proof. by rewrite horner_exp_comm /comm_poly hornerX. Qed. Definition hornerE_comm := (hornerD, hornerN, hornerX, hornerC, horner_cons, simp, hornerCM, hornerZ, (fun p x => hornerM_comm p (comm_polyX x))). Definition root p : pred R := fun x => p.[x] == 0. Lemma mem_root p x : x \in root p = (p.[x] == 0). Proof. by []. Qed. Lemma rootE p x : (root p x = (p.[x] == 0)) * ((x \in root p) = (p.[x] == 0)). Proof. by []. Qed. Lemma rootP p x : reflect (p.[x] = 0) (root p x). Proof. exact: eqP. Qed. Lemma rootPt p x : reflect (p.[x] == 0) (root p x). Proof. exact: idP. Qed. Lemma rootPf p x : reflect ((p.[x] == 0) = false) (~~ root p x). Proof. exact: negPf. Qed. Lemma rootC a x : root a%:P x = (a == 0). Proof. by rewrite rootE hornerC. Qed. Lemma root0 x : root 0 x. Proof. by rewrite rootC. Qed. Lemma root1 x : ~~ root 1 x. Proof. by rewrite rootC oner_eq0. Qed. Lemma rootX x : root 'X x = (x == 0). Proof. by rewrite rootE hornerX. Qed. Lemma rootN p x : root (- p) x = root p x. Proof. by rewrite rootE hornerN oppr_eq0. Qed. Lemma root_size_gt1 a p : p != 0 -> root p a -> 1 < size p. Proof. rewrite ltnNge => nz_p; apply: contraL => /size1_polyC Dp. by rewrite Dp rootC -polyC_eq0 -Dp. Qed. Lemma root_XsubC a x : root ('X - a%:P) x = (x == a). Proof. by rewrite rootE hornerXsubC subr_eq0. Qed. Lemma root_XaddC a x : root ('X + a%:P) x = (x == - a). Proof. by rewrite -root_XsubC rmorphN opprK. Qed. Theorem factor_theorem p a : reflect (exists q, p = q * ('X - a%:P)) (root p a). Proof. apply: (iffP eqP) => [pa0 | [q ->]]; last first. by rewrite hornerM_comm /comm_poly hornerXsubC subrr ?simp. exists (\poly_(i < size p) horner_rec (drop i.+1 p) a). apply/polyP=> i; rewrite mulrBr coefB coefMX coefMC !coef_poly. apply: canRL (addrK _) _; rewrite addrC; have [le_p_i | lt_i_p] := leqP. rewrite nth_default // !simp drop_oversize ?if_same //. exact: leq_trans (leqSpred _). case: i => [|i] in lt_i_p *; last by rewrite ltnW // (drop_nth 0 lt_i_p). by rewrite drop1 /= -{}pa0 /horner; case: (p : seq R) lt_i_p. Qed. Lemma multiplicity_XsubC p a : {m | exists2 q, (p != 0) ==> ~~ root q a & p = q * ('X - a%:P) ^+ m}. Proof. elim: {p}(size p) {-2}p (eqxx (size p)) => [|n IHn] p. by rewrite size_poly_eq0 => ->; exists 0%N, p; rewrite ?mulr1. have [/sig_eqW[{p}p ->] sz_p | nz_pa] := altP (factor_theorem p a); last first. by exists 0%N, p; rewrite ?mulr1 ?nz_pa ?implybT. have nz_p: p != 0 by apply: contraTneq sz_p => ->; rewrite mul0r size_poly0. rewrite size_Mmonic ?monicXsubC // size_XsubC addn2 eqSS in sz_p. have [m /sig2_eqW[q nz_qa Dp]] := IHn p sz_p; rewrite nz_p /= in nz_qa. by exists m.+1, q; rewrite ?nz_qa ?implybT // exprSr mulrA -Dp. Qed. (* Roots of unity. *) Lemma size_Xn_sub_1 n : n > 0 -> size ('X^n - 1 : {poly R}) = n.+1. Proof. by move=> n_gt0; rewrite size_addl size_polyXn // size_opp size_poly1. Qed. Lemma monic_Xn_sub_1 n : n > 0 -> 'X^n - 1 \is monic. Proof. move=> n_gt0; rewrite monicE lead_coefE size_Xn_sub_1 // coefB. by rewrite coefXn coef1 eqxx eqn0Ngt n_gt0 subr0. Qed. Definition root_of_unity n : pred R := root ('X^n - 1). Local Notation "n .-unity_root" := (root_of_unity n) : ring_scope. Lemma unity_rootE n z : n.-unity_root z = (z ^+ n == 1). Proof. by rewrite /root_of_unity rootE hornerD hornerN hornerXn hornerC subr_eq0. Qed. Lemma unity_rootP n z : reflect (z ^+ n = 1) (n.-unity_root z). Proof. by rewrite unity_rootE; exact: eqP. Qed. Definition primitive_root_of_unity n z := (n > 0) && [forall i : 'I_n, i.+1.-unity_root z == (i.+1 == n)]. Local Notation "n .-primitive_root" := (primitive_root_of_unity n) : ring_scope. Lemma prim_order_exists n z : n > 0 -> z ^+ n = 1 -> {m | m.-primitive_root z & (m %| n)}. Proof. move=> n_gt0 zn1. have: exists m, (m > 0) && (z ^+ m == 1) by exists n; rewrite n_gt0 /= zn1. case/ex_minnP=> m /andP[m_gt0 /eqP zm1] m_min. exists m. apply/andP; split=> //; apply/eqfunP=> [[i]] /=. rewrite leq_eqVlt unity_rootE. case: eqP => [-> _ | _]; first by rewrite zm1 eqxx. by apply: contraTF => zi1; rewrite -leqNgt m_min. have: n %% m < m by rewrite ltn_mod. apply: contraLR; rewrite -lt0n -leqNgt => nm_gt0; apply: m_min. by rewrite nm_gt0 /= expr_mod ?zn1. Qed. Section OnePrimitive. Variables (n : nat) (z : R). Hypothesis prim_z : n.-primitive_root z. Lemma prim_order_gt0 : n > 0. Proof. by case/andP: prim_z. Qed. Let n_gt0 := prim_order_gt0. Lemma prim_expr_order : z ^+ n = 1. Proof. case/andP: prim_z => _; rewrite -(prednK n_gt0) => /forallP/(_ ord_max). by rewrite unity_rootE eqxx eqb_id => /eqP. Qed. Lemma prim_expr_mod i : z ^+ (i %% n) = z ^+ i. Proof. exact: expr_mod prim_expr_order. Qed. Lemma prim_order_dvd i : (n %| i) = (z ^+ i == 1). Proof. move: n_gt0; rewrite -prim_expr_mod /dvdn -(ltn_mod i). case: {i}(i %% n)%N => [|i] lt_i; first by rewrite !eqxx. case/andP: prim_z => _ /forallP/(_ (Ordinal (ltnW lt_i))). by move/eqP; rewrite unity_rootE eqn_leq andbC leqNgt lt_i. Qed. Lemma eq_prim_root_expr i j : (z ^+ i == z ^+ j) = (i == j %[mod n]). Proof. wlog le_ji: i j / j <= i. move=> IH; case: (leqP j i); last move/ltnW; move/IH=> //. by rewrite eq_sym (eq_sym (j %% n)%N). rewrite -{1}(subnKC le_ji) exprD -prim_expr_mod eqn_mod_dvd //. rewrite prim_order_dvd; apply/eqP/eqP=> [|->]; last by rewrite mulr1. move/(congr1 ( *%R (z ^+ (n - j %% n)))); rewrite mulrA -exprD. by rewrite subnK ?prim_expr_order ?mul1r // ltnW ?ltn_mod. Qed. Lemma exp_prim_root k : (n %/ gcdn k n).-primitive_root (z ^+ k). Proof. set d := gcdn k n; have d_gt0: (0 < d)%N by rewrite gcdn_gt0 orbC n_gt0. have [d_dv_k d_dv_n]: (d %| k /\ d %| n)%N by rewrite dvdn_gcdl dvdn_gcdr. set q := (n %/ d)%N; rewrite /q.-primitive_root ltn_divRL // n_gt0. apply/forallP=> i; rewrite unity_rootE -exprM -prim_order_dvd. rewrite -(divnK d_dv_n) -/q -(divnK d_dv_k) mulnAC dvdn_pmul2r //. apply/eqP; apply/idP/idP=> [|/eqP->]; last by rewrite dvdn_mull. rewrite Gauss_dvdr; first by rewrite eqn_leq ltn_ord; exact: dvdn_leq. by rewrite /coprime gcdnC -(eqn_pmul2r d_gt0) mul1n muln_gcdl !divnK. Qed. Lemma dvdn_prim_root m : (m %| n)%N -> m.-primitive_root (z ^+ (n %/ m)). Proof. set k := (n %/ m)%N => m_dv_n; rewrite -{1}(mulKn m n_gt0) -divnA // -/k. by rewrite -{1}(@gcdn_idPl k n _) ?exp_prim_root // -(divnK m_dv_n) dvdn_mulr. Qed. End OnePrimitive. Lemma prim_root_exp_coprime n z k : n.-primitive_root z -> n.-primitive_root (z ^+ k) = coprime k n. Proof. move=> prim_z;have n_gt0 := prim_order_gt0 prim_z. apply/idP/idP=> [prim_zk | co_k_n]. set d := gcdn k n; have dv_d_n: (d %| n)%N := dvdn_gcdr _ _. rewrite /coprime -/d -(eqn_pmul2r n_gt0) mul1n -{2}(gcdnMl n d). rewrite -{2}(divnK dv_d_n) (mulnC _ d) -muln_gcdr (gcdn_idPr _) //. rewrite (prim_order_dvd prim_zk) -exprM -(prim_order_dvd prim_z). by rewrite muln_divCA_gcd dvdn_mulr. have zkn_1: z ^+ k ^+ n = 1 by rewrite exprAC (prim_expr_order prim_z) expr1n. have{zkn_1} [m prim_zk dv_m_n]:= prim_order_exists n_gt0 zkn_1. suffices /eqP <-: m == n by []. rewrite eqn_dvd dv_m_n -(@Gauss_dvdr n k m) 1?coprime_sym //=. by rewrite (prim_order_dvd prim_z) exprM (prim_expr_order prim_zk). Qed. (* Lifting a ring predicate to polynomials. *) Definition polyOver (S : pred_class) := [qualify a p : {poly R} | all (mem S) p]. Fact polyOver_key S : pred_key (polyOver S). Proof. by []. Qed. Canonical polyOver_keyed S := KeyedQualifier (polyOver_key S). Lemma polyOverS (S1 S2 : pred_class) : {subset S1 <= S2} -> {subset polyOver S1 <= polyOver S2}. Proof. by move=> sS12 p /(all_nthP 0)S1p; apply/(all_nthP 0)=> i /S1p; apply: sS12. Qed. Lemma polyOver0 S : 0 \is a polyOver S. Proof. by rewrite qualifE polyseq0. Qed. Lemma polyOver_poly (S : pred_class) n E : (forall i, i < n -> E i \in S) -> \poly_(i < n) E i \is a polyOver S. Proof. move=> S_E; apply/(all_nthP 0)=> i lt_i_p /=; rewrite coef_poly. by case: ifP => [/S_E// | /idP[]]; apply: leq_trans lt_i_p (size_poly n E). Qed. Section PolyOverAdd. Variables (S : predPredType R) (addS : addrPred S) (kS : keyed_pred addS). Lemma polyOverP {p} : reflect (forall i, p`_i \in kS) (p \in polyOver kS). Proof. apply: (iffP (all_nthP 0)) => [Sp i | Sp i _]; last exact: Sp. by have [/Sp // | /(nth_default 0)->] := ltnP i (size p); apply: rpred0. Qed. Lemma polyOverC c : (c%:P \in polyOver kS) = (c \in kS). Proof. by rewrite qualifE polyseqC; case: eqP => [->|] /=; rewrite ?andbT ?rpred0. Qed. Fact polyOver_addr_closed : addr_closed (polyOver kS). Proof. split=> [|p q Sp Sq]; first exact: polyOver0. by apply/polyOverP=> i; rewrite coefD rpredD ?(polyOverP _). Qed. Canonical polyOver_addrPred := AddrPred polyOver_addr_closed. End PolyOverAdd. Fact polyOverNr S (addS : zmodPred S) (kS : keyed_pred addS) : oppr_closed (polyOver kS). Proof. by move=> p /polyOverP Sp; apply/polyOverP=> i; rewrite coefN rpredN. Qed. Canonical polyOver_opprPred S addS kS := OpprPred (@polyOverNr S addS kS). Canonical polyOver_zmodPred S addS kS := ZmodPred (@polyOverNr S addS kS). Section PolyOverSemiring. Context (S : pred_class) (ringS : @semiringPred R S) (kS : keyed_pred ringS). Fact polyOver_mulr_closed : mulr_closed (polyOver kS). Proof. split=> [|p q /polyOverP Sp /polyOverP Sq]; first by rewrite polyOverC rpred1. by apply/polyOverP=> i; rewrite coefM rpred_sum // => j _; apply: rpredM. Qed. Canonical polyOver_mulrPred := MulrPred polyOver_mulr_closed. Canonical polyOver_semiringPred := SemiringPred polyOver_mulr_closed. Lemma polyOverZ : {in kS & polyOver kS, forall c p, c *: p \is a polyOver kS}. Proof. by move=> c p Sc /polyOverP Sp; apply/polyOverP=> i; rewrite coefZ rpredM ?Sp. Qed. Lemma polyOverX : 'X \in polyOver kS. Proof. by rewrite qualifE polyseqX /= rpred0 rpred1. Qed. Lemma rpred_horner : {in polyOver kS & kS, forall p x, p.[x] \in kS}. Proof. move=> p x /polyOverP Sp Sx; rewrite horner_coef rpred_sum // => i _. by rewrite rpredM ?rpredX. Qed. End PolyOverSemiring. Section PolyOverRing. Context (S : pred_class) (ringS : @subringPred R S) (kS : keyed_pred ringS). Canonical polyOver_smulrPred := SmulrPred (polyOver_mulr_closed kS). Canonical polyOver_subringPred := SubringPred (polyOver_mulr_closed kS). Lemma polyOverXsubC c : ('X - c%:P \in polyOver kS) = (c \in kS). Proof. by rewrite rpredBl ?polyOverX ?polyOverC. Qed. End PolyOverRing. (* Single derivative. *) Definition deriv p := \poly_(i < (size p).-1) (p`_i.+1 *+ i.+1). Local Notation "a ^` ()" := (deriv a). Lemma coef_deriv p i : p^`()`_i = p`_i.+1 *+ i.+1. Proof. rewrite coef_poly -subn1 ltn_subRL. by case: leqP => // /(nth_default 0) ->; rewrite mul0rn. Qed. Lemma polyOver_deriv S (ringS : semiringPred S) (kS : keyed_pred ringS) : {in polyOver kS, forall p, p^`() \is a polyOver kS}. Proof. by move=> p /polyOverP Kp; apply/polyOverP=> i; rewrite coef_deriv rpredMn ?Kp. Qed. Lemma derivC c : c%:P^`() = 0. Proof. by apply/polyP=> i; rewrite coef_deriv coef0 coefC mul0rn. Qed. Lemma derivX : ('X)^`() = 1. Proof. by apply/polyP=> [[|i]]; rewrite coef_deriv coef1 coefX ?mul0rn. Qed. Lemma derivXn n : 'X^n^`() = 'X^n.-1 *+ n. Proof. case: n => [|n]; first exact: derivC. apply/polyP=> i; rewrite coef_deriv coefMn !coefXn eqSS. by case: eqP => [-> // | _]; rewrite !mul0rn. Qed. Fact deriv_is_linear : linear deriv. Proof. move=> k p q; apply/polyP=> i. by rewrite !(coef_deriv, coefD, coefZ) mulrnDl mulrnAr. Qed. Canonical deriv_additive := Additive deriv_is_linear. Canonical deriv_linear := Linear deriv_is_linear. Lemma deriv0 : 0^`() = 0. Proof. exact: linear0. Qed. Lemma derivD : {morph deriv : p q / p + q}. Proof. exact: linearD. Qed. Lemma derivN : {morph deriv : p / - p}. Proof. exact: linearN. Qed. Lemma derivB : {morph deriv : p q / p - q}. Proof. exact: linearB. Qed. Lemma derivXsubC (a : R) : ('X - a%:P)^`() = 1. Proof. by rewrite derivB derivX derivC subr0. Qed. Lemma derivMn n p : (p *+ n)^`() = p^`() *+ n. Proof. exact: linearMn. Qed. Lemma derivMNn n p : (p *- n)^`() = p^`() *- n. Proof. exact: linearMNn. Qed. Lemma derivZ c p : (c *: p)^`() = c *: p^`(). Proof. by rewrite linearZ. Qed. Lemma deriv_mulC c p : (c%:P * p)^`() = c%:P * p^`(). Proof. by rewrite !mul_polyC derivZ. Qed. Lemma derivMXaddC p c : (p * 'X + c%:P)^`() = p + p^`() * 'X. Proof. apply/polyP=> i; rewrite raddfD /= derivC addr0 coefD !(coefMX, coef_deriv). by case: i; rewrite ?addr0. Qed. Lemma derivM p q : (p * q)^`() = p^`() * q + p * q^`(). Proof. elim/poly_ind: p => [|p b IHp]; first by rewrite !(mul0r, add0r, derivC). rewrite mulrDl -mulrA -commr_polyX mulrA -[_ * 'X]addr0 raddfD /= !derivMXaddC. by rewrite deriv_mulC IHp !mulrDl -!mulrA !commr_polyX !addrA. Qed. Definition derivE := Eval lazy beta delta [morphism_2 morphism_1] in (derivZ, deriv_mulC, derivC, derivX, derivMXaddC, derivXsubC, derivM, derivB, derivD, derivN, derivXn, derivM, derivMn). (* Iterated derivative. *) Definition derivn n p := iter n deriv p. Local Notation "a ^` ( n )" := (derivn n a) : ring_scope. Lemma derivn0 p : p^`(0) = p. Proof. by []. Qed. Lemma derivn1 p : p^`(1) = p^`(). Proof. by []. Qed. Lemma derivnS p n : p^`(n.+1) = p^`(n)^`(). Proof. by []. Qed. Lemma derivSn p n : p^`(n.+1) = p^`()^`(n). Proof. exact: iterSr. Qed. Lemma coef_derivn n p i : p^`(n)`_i = p`_(n + i) *+ (n + i) ^_ n. Proof. elim: n i => [|n IHn] i; first by rewrite ffactn0 mulr1n. by rewrite derivnS coef_deriv IHn -mulrnA ffactnSr addSnnS addKn. Qed. Lemma polyOver_derivn S (ringS : semiringPred S) (kS : keyed_pred ringS) : {in polyOver kS, forall p n, p^`(n) \is a polyOver kS}. Proof. move=> p /polyOverP Kp /= n; apply/polyOverP=> i. by rewrite coef_derivn rpredMn. Qed. Fact derivn_is_linear n : linear (derivn n). Proof. by elim: n => // n IHn a p q; rewrite derivnS IHn linearP. Qed. Canonical derivn_additive n := Additive (derivn_is_linear n). Canonical derivn_linear n := Linear (derivn_is_linear n). Lemma derivnC c n : c%:P^`(n) = if n == 0%N then c%:P else 0. Proof. by case: n => // n; rewrite derivSn derivC linear0. Qed. Lemma derivnD n : {morph derivn n : p q / p + q}. Proof. exact: linearD. Qed. Lemma derivn_sub n : {morph derivn n : p q / p - q}. Proof. exact: linearB. Qed. Lemma derivnMn n m p : (p *+ m)^`(n) = p^`(n) *+ m. Proof. exact: linearMn. Qed. Lemma derivnMNn n m p : (p *- m)^`(n) = p^`(n) *- m. Proof. exact: linearMNn. Qed. Lemma derivnN n : {morph derivn n : p / - p}. Proof. exact: linearN. Qed. Lemma derivnZ n : scalable (derivn n). Proof. exact: linearZZ. Qed. Lemma derivnXn m n : 'X^m^`(n) = 'X^(m - n) *+ m ^_ n. Proof. apply/polyP=>i; rewrite coef_derivn coefMn !coefXn. case: (ltnP m n) => [lt_m_n | le_m_n]. by rewrite eqn_leq leqNgt ltn_addr // mul0rn ffact_small. by rewrite -{1 3}(subnKC le_m_n) eqn_add2l; case: eqP => [->|]; rewrite ?mul0rn. Qed. Lemma derivnMXaddC n p c : (p * 'X + c%:P)^`(n.+1) = p^`(n) *+ n.+1 + p^`(n.+1) * 'X. Proof. elim: n => [|n IHn]; first by rewrite derivn1 derivMXaddC. rewrite derivnS IHn derivD derivM derivX mulr1 derivMn -!derivnS. by rewrite addrA addrAC -mulrSr. Qed. Lemma derivn_poly0 p n : size p <= n -> p^`(n) = 0. Proof. move=> le_p_n; apply/polyP=> i; rewrite coef_derivn. rewrite nth_default; first by rewrite mul0rn coef0. by apply: leq_trans le_p_n _; apply leq_addr. Qed. Lemma lt_size_deriv (p : {poly R}) : p != 0 -> size p^`() < size p. Proof. by move=> /polySpred->; exact: size_poly. Qed. (* A normalising version of derivation to get the division by n! in Taylor *) Definition nderivn n p := \poly_(i < size p - n) (p`_(n + i) *+ 'C(n + i, n)). Local Notation "a ^`N ( n )" := (nderivn n a) : ring_scope. Lemma coef_nderivn n p i : p^`N(n)`_i = p`_(n + i) *+ 'C(n + i, n). Proof. rewrite coef_poly ltn_subRL; case: leqP => // le_p_ni. by rewrite nth_default ?mul0rn. Qed. (* Here is the division by n! *) Lemma nderivn_def n p : p^`(n) = p^`N(n) *+ n`!. Proof. by apply/polyP=> i; rewrite coefMn coef_nderivn coef_derivn -mulrnA bin_ffact. Qed. Lemma polyOver_nderivn S (ringS : semiringPred S) (kS : keyed_pred ringS) : {in polyOver kS, forall p n, p^`N(n) \in polyOver kS}. Proof. move=> p /polyOverP Sp /= n; apply/polyOverP=> i. by rewrite coef_nderivn rpredMn. Qed. Lemma nderivn0 p : p^`N(0) = p. Proof. by rewrite -[p^`N(0)](nderivn_def 0). Qed. Lemma nderivn1 p : p^`N(1) = p^`(). Proof. by rewrite -[p^`N(1)](nderivn_def 1). Qed. Lemma nderivnC c n : (c%:P)^`N(n) = if n == 0%N then c%:P else 0. Proof. apply/polyP=> i; rewrite coef_nderivn. by case: n => [|n]; rewrite ?bin0 // coef0 coefC mul0rn. Qed. Lemma nderivnXn m n : 'X^m^`N(n) = 'X^(m - n) *+ 'C(m, n). Proof. apply/polyP=> i; rewrite coef_nderivn coefMn !coefXn. have [lt_m_n | le_n_m] := ltnP m n. by rewrite eqn_leq leqNgt ltn_addr // mul0rn bin_small. by rewrite -{1 3}(subnKC le_n_m) eqn_add2l; case: eqP => [->|]; rewrite ?mul0rn. Qed. Fact nderivn_is_linear n : linear (nderivn n). Proof. move=> k p q; apply/polyP=> i. by rewrite !(coef_nderivn, coefD, coefZ) mulrnDl mulrnAr. Qed. Canonical nderivn_additive n := Additive(nderivn_is_linear n). Canonical nderivn_linear n := Linear (nderivn_is_linear n). Lemma nderivnD n : {morph nderivn n : p q / p + q}. Proof. exact: linearD. Qed. Lemma nderivnB n : {morph nderivn n : p q / p - q}. Proof. exact: linearB. Qed. Lemma nderivnMn n m p : (p *+ m)^`N(n) = p^`N(n) *+ m. Proof. exact: linearMn. Qed. Lemma nderivnMNn n m p : (p *- m)^`N(n) = p^`N(n) *- m. Proof. exact: linearMNn. Qed. Lemma nderivnN n : {morph nderivn n : p / - p}. Proof. exact: linearN. Qed. Lemma nderivnZ n : scalable (nderivn n). Proof. exact: linearZZ. Qed. Lemma nderivnMXaddC n p c : (p * 'X + c%:P)^`N(n.+1) = p^`N(n) + p^`N(n.+1) * 'X. Proof. apply/polyP=> i; rewrite coef_nderivn !coefD !coefMX coefC. rewrite !addSn /= !coef_nderivn addr0 binS mulrnDr addrC; congr (_ + _). by rewrite addSnnS; case: i; rewrite // addn0 bin_small. Qed. Lemma nderivn_poly0 p n : size p <= n -> p^`N(n) = 0. Proof. move=> le_p_n; apply/polyP=> i; rewrite coef_nderivn. rewrite nth_default; first by rewrite mul0rn coef0. by apply: leq_trans le_p_n _; apply leq_addr. Qed. Lemma nderiv_taylor p x h : GRing.comm x h -> p.[x + h] = \sum_(i < size p) p^`N(i).[x] * h ^+ i. Proof. move/commrX=> cxh; elim/poly_ind: p => [|p c IHp]. by rewrite size_poly0 big_ord0 horner0. rewrite hornerMXaddC size_MXaddC. have [-> | nz_p] := altP (p =P 0). rewrite horner0 !simp; have [-> | _] := c =P 0; first by rewrite big_ord0. by rewrite size_poly0 big_ord_recl big_ord0 nderivn0 hornerC !simp. rewrite big_ord_recl nderivn0 !simp hornerMXaddC addrAC; congr (_ + _). rewrite mulrDr {}IHp !big_distrl polySpred //= big_ord_recl /= mulr1 -addrA. rewrite nderivn0 /bump /(addn 1) /=; congr (_ + _). rewrite !big_ord_recr /= nderivnMXaddC -mulrA -exprSr -polySpred // !addrA. congr (_ + _); last by rewrite (nderivn_poly0 (leqnn _)) !simp. rewrite addrC -big_split /=; apply: eq_bigr => i _. by rewrite nderivnMXaddC !hornerE_comm /= mulrDl -!mulrA -exprSr cxh. Qed. Lemma nderiv_taylor_wide n p x h : GRing.comm x h -> size p <= n -> p.[x + h] = \sum_(i < n) p^`N(i).[x] * h ^+ i. Proof. move/nderiv_taylor=> -> le_p_n. rewrite (big_ord_widen n (fun i => p^`N(i).[x] * h ^+ i)) // big_mkcond. apply: eq_bigr => i _; case: leqP => // /nderivn_poly0->. by rewrite horner0 simp. Qed. End PolynomialTheory. Prenex Implicits polyC Poly lead_coef root horner polyOver. Implicit Arguments monic [[R]]. Notation "\poly_ ( i < n ) E" := (poly n (fun i => E)) : ring_scope. Notation "c %:P" := (polyC c) : ring_scope. Notation "'X" := (polyX _) : ring_scope. Notation "''X^' n" := ('X ^+ n) : ring_scope. Notation "p .[ x ]" := (horner p x) : ring_scope. Notation "n .-unity_root" := (root_of_unity n) : ring_scope. Notation "n .-primitive_root" := (primitive_root_of_unity n) : ring_scope. Notation "a ^` ()" := (deriv a) : ring_scope. Notation "a ^` ( n )" := (derivn n a) : ring_scope. Notation "a ^`N ( n )" := (nderivn n a) : ring_scope. Implicit Arguments monicP [R p]. Implicit Arguments rootP [R p x]. Implicit Arguments rootPf [R p x]. Implicit Arguments rootPt [R p x]. Implicit Arguments unity_rootP [R n z]. Implicit Arguments polyOverP [[R] [S0] [addS] [kS] [p]]. (* Container morphism. *) Section MapPoly. Section Definitions. Variables (aR rR : ringType) (f : aR -> rR). Definition map_poly (p : {poly aR}) := \poly_(i < size p) f p`_i. (* Alternative definition; the one above is more convenient because it lets *) (* us use the lemmas on \poly, e.g., size (map_poly p) <= size p is an *) (* instance of size_poly. *) Lemma map_polyE p : map_poly p = Poly (map f p). Proof. rewrite /map_poly unlock; congr Poly. apply: (@eq_from_nth _ 0); rewrite size_mkseq ?size_map // => i lt_i_p. by rewrite (nth_map 0) ?nth_mkseq. Qed. Definition commr_rmorph u := forall x, GRing.comm u (f x). Definition horner_morph u of commr_rmorph u := fun p => (map_poly p).[u]. End Definitions. Variables aR rR : ringType. Section Combinatorial. Variables (iR : ringType) (f : aR -> rR). Local Notation "p ^f" := (map_poly f p) : ring_scope. Lemma map_poly0 : 0^f = 0. Proof. by rewrite map_polyE polyseq0. Qed. Lemma eq_map_poly (g : aR -> rR) : f =1 g -> map_poly f =1 map_poly g. Proof. by move=> eq_fg p; rewrite !map_polyE (eq_map eq_fg). Qed. Lemma map_poly_id g (p : {poly iR}) : {in (p : seq iR), g =1 id} -> map_poly g p = p. Proof. by move=> g_id; rewrite map_polyE map_id_in ?polyseqK. Qed. Lemma coef_map_id0 p i : f 0 = 0 -> (p^f)`_i = f p`_i. Proof. by move=> f0; rewrite coef_poly; case: ltnP => // le_p_i; rewrite nth_default. Qed. Lemma map_Poly_id0 s : f 0 = 0 -> (Poly s)^f = Poly (map f s). Proof. move=> f0; apply/polyP=> j; rewrite coef_map_id0 ?coef_Poly //. have [/(nth_map 0 0)->// | le_s_j] := ltnP j (size s). by rewrite !nth_default ?size_map. Qed. Lemma map_poly_comp_id0 (g : iR -> aR) p : f 0 = 0 -> map_poly (f \o g) p = (map_poly g p)^f. Proof. by move=> f0; rewrite map_polyE map_comp -map_Poly_id0 -?map_polyE. Qed. Lemma size_map_poly_id0 p : f (lead_coef p) != 0 -> size p^f = size p. Proof. by move=> nz_fp; apply: size_poly_eq. Qed. Lemma map_poly_eq0_id0 p : f (lead_coef p) != 0 -> (p^f == 0) = (p == 0). Proof. by rewrite -!size_poly_eq0 => /size_map_poly_id0->. Qed. Lemma lead_coef_map_id0 p : f 0 = 0 -> f (lead_coef p) != 0 -> lead_coef p^f = f (lead_coef p). Proof. by move=> f0 nz_fp; rewrite lead_coefE coef_map_id0 ?size_map_poly_id0. Qed. Hypotheses (inj_f : injective f) (f_0 : f 0 = 0). Lemma size_map_inj_poly p : size p^f = size p. Proof. have [-> | nz_p] := eqVneq p 0; first by rewrite map_poly0 !size_poly0. by rewrite size_map_poly_id0 // -f_0 (inj_eq inj_f) lead_coef_eq0. Qed. Lemma map_inj_poly : injective (map_poly f). Proof. move=> p q /polyP eq_pq; apply/polyP=> i; apply: inj_f. by rewrite -!coef_map_id0 ?eq_pq. Qed. Lemma lead_coef_map_inj p : lead_coef p^f = f (lead_coef p). Proof. by rewrite !lead_coefE size_map_inj_poly coef_map_id0. Qed. End Combinatorial. Lemma map_polyK (f : aR -> rR) g : cancel g f -> f 0 = 0 -> cancel (map_poly g) (map_poly f). Proof. by move=> gK f_0 p; rewrite /= -map_poly_comp_id0 ?map_poly_id // => x _ //=. Qed. Section Additive. Variables (iR : ringType) (f : {additive aR -> rR}). Local Notation "p ^f" := (map_poly (GRing.Additive.apply f) p) : ring_scope. Lemma coef_map p i : p^f`_i = f p`_i. Proof. exact: coef_map_id0 (raddf0 f). Qed. Lemma map_Poly s : (Poly s)^f = Poly (map f s). Proof. exact: map_Poly_id0 (raddf0 f). Qed. Lemma map_poly_comp (g : iR -> aR) p : map_poly (f \o g) p = map_poly f (map_poly g p). Proof. exact: map_poly_comp_id0 (raddf0 f). Qed. Fact map_poly_is_additive : additive (map_poly f). Proof. by move=> p q; apply/polyP=> i; rewrite !(coef_map, coefB) raddfB. Qed. Canonical map_poly_additive := Additive map_poly_is_additive. Lemma map_polyC a : (a%:P)^f = (f a)%:P. Proof. by apply/polyP=> i; rewrite !(coef_map, coefC) -!mulrb raddfMn. Qed. Lemma lead_coef_map_eq p : f (lead_coef p) != 0 -> lead_coef p^f = f (lead_coef p). Proof. exact: lead_coef_map_id0 (raddf0 f). Qed. End Additive. Variable f : {rmorphism aR -> rR}. Implicit Types p : {poly aR}. Local Notation "p ^f" := (map_poly (GRing.RMorphism.apply f) p) : ring_scope. Fact map_poly_is_rmorphism : rmorphism (map_poly f). Proof. split; first exact: map_poly_is_additive. split=> [p q|]; apply/polyP=> i; last first. by rewrite !(coef_map, coef1) /= rmorph_nat. rewrite coef_map /= !coefM /= !rmorph_sum; apply: eq_bigr => j _. by rewrite !coef_map rmorphM. Qed. Canonical map_poly_rmorphism := RMorphism map_poly_is_rmorphism. Lemma map_polyZ c p : (c *: p)^f = f c *: p^f. Proof. by apply/polyP=> i; rewrite !(coef_map, coefZ) /= rmorphM. Qed. Canonical map_poly_linear := AddLinear (map_polyZ : scalable_for (f \; *:%R) (map_poly f)). Canonical map_poly_lrmorphism := [lrmorphism of map_poly f]. Lemma map_polyX : ('X)^f = 'X. Proof. by apply/polyP=> i; rewrite coef_map !coefX /= rmorph_nat. Qed. Lemma map_polyXn n : ('X^n)^f = 'X^n. Proof. by rewrite rmorphX /= map_polyX. Qed. Lemma monic_map p : p \is monic -> p^f \is monic. Proof. move/monicP=> mon_p; rewrite monicE. by rewrite lead_coef_map_eq mon_p /= rmorph1 ?oner_neq0. Qed. Lemma horner_map p x : p^f.[f x] = f p.[x]. Proof. elim/poly_ind: p => [|p c IHp]; first by rewrite !(rmorph0, horner0). rewrite hornerMXaddC !rmorphD !rmorphM /=. by rewrite map_polyX map_polyC hornerMXaddC IHp. Qed. Lemma map_comm_poly p x : comm_poly p x -> comm_poly p^f (f x). Proof. by rewrite /comm_poly horner_map -!rmorphM // => ->. Qed. Lemma map_comm_coef p x : comm_coef p x -> comm_coef p^f (f x). Proof. by move=> cpx i; rewrite coef_map -!rmorphM ?cpx. Qed. Lemma rmorph_root p x : root p x -> root p^f (f x). Proof. by move/eqP=> px0; rewrite rootE horner_map px0 rmorph0. Qed. Lemma rmorph_unity_root n z : n.-unity_root z -> n.-unity_root (f z). Proof. move/rmorph_root; rewrite rootE rmorphB hornerD hornerN. by rewrite /= map_polyXn rmorph1 hornerC hornerXn subr_eq0 unity_rootE. Qed. Section HornerMorph. Variable u : rR. Hypothesis cfu : commr_rmorph f u. Lemma horner_morphC a : horner_morph cfu a%:P = f a. Proof. by rewrite /horner_morph map_polyC hornerC. Qed. Lemma horner_morphX : horner_morph cfu 'X = u. Proof. by rewrite /horner_morph map_polyX hornerX. Qed. Fact horner_is_lrmorphism : lrmorphism_for (f \; *%R) (horner_morph cfu). Proof. rewrite /horner_morph; split=> [|c p]; last by rewrite linearZ hornerZ. split=> [p q|]; first by rewrite /horner_morph rmorphB hornerD hornerN. split=> [p q|]; last by rewrite /horner_morph rmorph1 hornerC. rewrite /horner_morph rmorphM /= hornerM_comm //. by apply: comm_coef_poly => i; rewrite coef_map cfu. Qed. Canonical horner_additive := Additive horner_is_lrmorphism. Canonical horner_rmorphism := RMorphism horner_is_lrmorphism. Canonical horner_linear := AddLinear horner_is_lrmorphism. Canonical horner_lrmorphism := [lrmorphism of horner_morph cfu]. End HornerMorph. Lemma deriv_map p : p^f^`() = (p^`())^f. Proof. by apply/polyP => i; rewrite !(coef_map, coef_deriv) //= rmorphMn. Qed. Lemma derivn_map p n : p^f^`(n) = (p^`(n))^f. Proof. by apply/polyP => i; rewrite !(coef_map, coef_derivn) //= rmorphMn. Qed. Lemma nderivn_map p n : p^f^`N(n) = (p^`N(n))^f. Proof. by apply/polyP => i; rewrite !(coef_map, coef_nderivn) //= rmorphMn. Qed. End MapPoly. (* Morphisms from the polynomial ring, and the initiality of polynomials *) (* with respect to these. *) Section MorphPoly. Variable (aR rR : ringType) (pf : {rmorphism {poly aR} -> rR}). Lemma poly_morphX_comm : commr_rmorph (pf \o polyC) (pf 'X). Proof. by move=> a; rewrite /GRing.comm /= -!rmorphM // commr_polyX. Qed. Lemma poly_initial : pf =1 horner_morph poly_morphX_comm. Proof. apply: poly_ind => [|p a IHp]; first by rewrite !rmorph0. by rewrite !rmorphD !rmorphM /= -{}IHp horner_morphC ?horner_morphX. Qed. End MorphPoly. Notation "p ^:P" := (map_poly polyC p) : ring_scope. Section PolyCompose. Variable R : ringType. Implicit Types p q : {poly R}. Definition comp_poly q p := p^:P.[q]. Local Notation "p \Po q" := (comp_poly q p) : ring_scope. Lemma size_map_polyC p : size p^:P = size p. Proof. exact: size_map_inj_poly (@polyC_inj R) _ _. Qed. Lemma map_polyC_eq0 p : (p^:P == 0) = (p == 0). Proof. by rewrite -!size_poly_eq0 size_map_polyC. Qed. Lemma root_polyC p x : root p^:P x%:P = root p x. Proof. by rewrite rootE horner_map polyC_eq0. Qed. Lemma comp_polyE p q : p \Po q = \sum_(i < size p) p`_i *: q^+i. Proof. by rewrite [p \Po q]horner_poly; apply: eq_bigr => i _; rewrite mul_polyC. Qed. Lemma polyOver_comp S (ringS : semiringPred S) (kS : keyed_pred ringS) : {in polyOver kS &, forall p q, p \Po q \in polyOver kS}. Proof. move=> p q /polyOverP Sp Sq; rewrite comp_polyE rpred_sum // => i _. by rewrite polyOverZ ?rpredX. Qed. Lemma comp_polyCr p c : p \Po c%:P = p.[c]%:P. Proof. exact: horner_map. Qed. Lemma comp_poly0r p : p \Po 0 = (p`_0)%:P. Proof. by rewrite comp_polyCr horner_coef0. Qed. Lemma comp_polyC c p : c%:P \Po p = c%:P. Proof. by rewrite /(_ \Po p) map_polyC hornerC. Qed. Fact comp_poly_is_linear p : linear (comp_poly p). Proof. move=> a q r. by rewrite /comp_poly rmorphD /= map_polyZ !hornerE_comm mul_polyC. Qed. Canonical comp_poly_additive p := Additive (comp_poly_is_linear p). Canonical comp_poly_linear p := Linear (comp_poly_is_linear p). Lemma comp_poly0 p : 0 \Po p = 0. Proof. exact: raddf0. Qed. Lemma comp_polyD p q r : (p + q) \Po r = (p \Po r) + (q \Po r). Proof. exact: raddfD. Qed. Lemma comp_polyB p q r : (p - q) \Po r = (p \Po r) - (q \Po r). Proof. exact: raddfB. Qed. Lemma comp_polyZ c p q : (c *: p) \Po q = c *: (p \Po q). Proof. exact: linearZZ. Qed. Lemma comp_polyXr p : p \Po 'X = p. Proof. by rewrite -{2}/(idfun p) poly_initial. Qed. Lemma comp_polyX p : 'X \Po p = p. Proof. by rewrite /(_ \Po p) map_polyX hornerX. Qed. Lemma comp_poly_MXaddC c p q : (p * 'X + c%:P) \Po q = (p \Po q) * q + c%:P. Proof. by rewrite /(_ \Po q) rmorphD rmorphM /= map_polyX map_polyC hornerMXaddC. Qed. Lemma comp_polyXaddC_K p z : (p \Po ('X + z%:P)) \Po ('X - z%:P) = p. Proof. have addzK: ('X + z%:P) \Po ('X - z%:P) = 'X. by rewrite raddfD /= comp_polyC comp_polyX subrK. elim/poly_ind: p => [|p c IHp]; first by rewrite !comp_poly0. rewrite comp_poly_MXaddC linearD /= comp_polyC {1}/comp_poly rmorphM /=. by rewrite hornerM_comm /comm_poly -!/(_ \Po _) ?IHp ?addzK ?commr_polyX. Qed. Lemma size_comp_poly_leq p q : size (p \Po q) <= ((size p).-1 * (size q).-1).+1. Proof. rewrite comp_polyE (leq_trans (size_sum _ _ _)) //; apply/bigmax_leqP => i _. rewrite (leq_trans (size_scale_leq _ _)) // (leq_trans (size_exp_leq _ _)) //. by rewrite ltnS mulnC leq_mul // -{2}(subnKC (valP i)) leq_addr. Qed. End PolyCompose. Notation "p \Po q" := (comp_poly q p) : ring_scope. Lemma map_comp_poly (aR rR : ringType) (f : {rmorphism aR -> rR}) p q : map_poly f (p \Po q) = map_poly f p \Po map_poly f q. Proof. elim/poly_ind: p => [|p a IHp]; first by rewrite !raddf0. rewrite comp_poly_MXaddC !rmorphD !rmorphM /= !map_polyC map_polyX. by rewrite comp_poly_MXaddC -IHp. Qed. Section PolynomialComRing. Variable R : comRingType. Implicit Types p q : {poly R}. Fact poly_mul_comm p q : p * q = q * p. Proof. apply/polyP=> i; rewrite coefM coefMr. by apply: eq_bigr => j _; rewrite mulrC. Qed. Canonical poly_comRingType := Eval hnf in ComRingType {poly R} poly_mul_comm. Canonical polynomial_comRingType := Eval hnf in ComRingType (polynomial R) poly_mul_comm. Canonical poly_algType := Eval hnf in CommAlgType R {poly R}. Canonical polynomial_algType := Eval hnf in [algType R of polynomial R for poly_algType]. Lemma hornerM p q x : (p * q).[x] = p.[x] * q.[x]. Proof. by rewrite hornerM_comm //; exact: mulrC. Qed. Lemma horner_exp p x n : (p ^+ n).[x] = p.[x] ^+ n. Proof. by rewrite horner_exp_comm //; exact: mulrC. Qed. Lemma horner_prod I r (P : pred I) (F : I -> {poly R}) x : (\prod_(i <- r | P i) F i).[x] = \prod_(i <- r | P i) (F i).[x]. Proof. by elim/big_rec2: _ => [|i _ p _ <-]; rewrite (hornerM, hornerC). Qed. Definition hornerE := (hornerD, hornerN, hornerX, hornerC, horner_cons, simp, hornerCM, hornerZ, hornerM). Definition horner_eval (x : R) := horner^~ x. Lemma horner_evalE x p : horner_eval x p = p.[x]. Proof. by []. Qed. Fact horner_eval_is_lrmorphism x : lrmorphism_for *%R (horner_eval x). Proof. have cxid: commr_rmorph idfun x by exact: mulrC. have evalE : horner_eval x =1 horner_morph cxid. by move=> p; congr _.[x]; rewrite map_poly_id. split=> [|c p]; last by rewrite !evalE /= -linearZ. by do 2?split=> [p q|]; rewrite !evalE (rmorphB, rmorphM, rmorph1). Qed. Canonical horner_eval_additive x := Additive (horner_eval_is_lrmorphism x). Canonical horner_eval_rmorphism x := RMorphism (horner_eval_is_lrmorphism x). Canonical horner_eval_linear x := AddLinear (horner_eval_is_lrmorphism x). Canonical horner_eval_lrmorphism x := [lrmorphism of horner_eval x]. Fact comp_poly_multiplicative q : multiplicative (comp_poly q). Proof. split=> [p1 p2|]; last by rewrite comp_polyC. by rewrite /comp_poly rmorphM hornerM_comm //; exact: mulrC. Qed. Canonical comp_poly_rmorphism q := AddRMorphism (comp_poly_multiplicative q). Canonical comp_poly_lrmorphism q := [lrmorphism of comp_poly q]. Lemma comp_polyM p q r : (p * q) \Po r = (p \Po r) * (q \Po r). Proof. exact: rmorphM. Qed. Lemma comp_polyA p q r : p \Po (q \Po r) = (p \Po q) \Po r. Proof. elim/poly_ind: p => [|p c IHp]; first by rewrite !comp_polyC. by rewrite !comp_polyD !comp_polyM !comp_polyX IHp !comp_polyC. Qed. Lemma horner_comp p q x : (p \Po q).[x] = p.[q.[x]]. Proof. by apply: polyC_inj; rewrite -!comp_polyCr comp_polyA. Qed. Lemma root_comp p q x : root (p \Po q) x = root p (q.[x]). Proof. by rewrite !rootE horner_comp. Qed. Lemma deriv_comp p q : (p \Po q) ^`() = (p ^`() \Po q) * q^`(). Proof. elim/poly_ind: p => [|p c IHp]; first by rewrite !(deriv0, comp_poly0) mul0r. rewrite comp_poly_MXaddC derivD derivC derivM IHp derivMXaddC comp_polyD. by rewrite comp_polyM comp_polyX addr0 addrC mulrAC -mulrDl. Qed. Lemma deriv_exp p n : (p ^+ n)^`() = p^`() * p ^+ n.-1 *+ n. Proof. elim: n => [|n IHn]; first by rewrite expr0 mulr0n derivC. by rewrite exprS derivM {}IHn (mulrC p) mulrnAl -mulrA -exprSr mulrS; case n. Qed. Definition derivCE := (derivE, deriv_exp). End PolynomialComRing. Section PolynomialIdomain. (* Integral domain structure on poly *) Variable R : idomainType. Implicit Types (a b x y : R) (p q r m : {poly R}). Lemma size_mul p q : p != 0 -> q != 0 -> size (p * q) = (size p + size q).-1. Proof. by move=> nz_p nz_q; rewrite -size_proper_mul ?mulf_neq0 ?lead_coef_eq0. Qed. Fact poly_idomainAxiom p q : p * q = 0 -> (p == 0) || (q == 0). Proof. move=> pq0; apply/norP=> [[p_nz q_nz]]; move/eqP: (size_mul p_nz q_nz). by rewrite eq_sym pq0 size_poly0 (polySpred p_nz) (polySpred q_nz) addnS. Qed. Definition poly_unit : pred {poly R} := fun p => (size p == 1%N) && (p`_0 \in GRing.unit). Definition poly_inv p := if p \in poly_unit then (p`_0)^-1%:P else p. Fact poly_mulVp : {in poly_unit, left_inverse 1 poly_inv *%R}. Proof. move=> p Up; rewrite /poly_inv Up. by case/andP: Up => /size_poly1P[c _ ->]; rewrite coefC -polyC_mul => /mulVr->. Qed. Fact poly_intro_unit p q : q * p = 1 -> p \in poly_unit. Proof. move=> pq1; apply/andP; split; last first. apply/unitrP; exists q`_0. by rewrite 2!mulrC -!/(coefp 0 _) -rmorphM pq1 rmorph1. have: size (q * p) == 1%N by rewrite pq1 size_poly1. have [-> | nz_p] := eqVneq p 0; first by rewrite mulr0 size_poly0. have [-> | nz_q] := eqVneq q 0; first by rewrite mul0r size_poly0. rewrite size_mul // (polySpred nz_p) (polySpred nz_q) addnS addSn !eqSS. by rewrite addn_eq0 => /andP[]. Qed. Fact poly_inv_out : {in [predC poly_unit], poly_inv =1 id}. Proof. by rewrite /poly_inv => p /negbTE/= ->. Qed. Definition poly_comUnitMixin := ComUnitRingMixin poly_mulVp poly_intro_unit poly_inv_out. Canonical poly_unitRingType := Eval hnf in UnitRingType {poly R} poly_comUnitMixin. Canonical polynomial_unitRingType := Eval hnf in [unitRingType of polynomial R for poly_unitRingType]. Canonical poly_unitAlgType := Eval hnf in [unitAlgType R of {poly R}]. Canonical polynomial_unitAlgType := Eval hnf in [unitAlgType R of polynomial R]. Canonical poly_comUnitRingType := Eval hnf in [comUnitRingType of {poly R}]. Canonical polynomial_comUnitRingType := Eval hnf in [comUnitRingType of polynomial R]. Canonical poly_idomainType := Eval hnf in IdomainType {poly R} poly_idomainAxiom. Canonical polynomial_idomainType := Eval hnf in [idomainType of polynomial R for poly_idomainType]. Lemma poly_unitE p : (p \in GRing.unit) = (size p == 1%N) && (p`_0 \in GRing.unit). Proof. by []. Qed. Lemma poly_invE p : p ^-1 = if p \in GRing.unit then (p`_0)^-1%:P else p. Proof. by []. Qed. Lemma polyC_inv c : c%:P^-1 = (c^-1)%:P. Proof. have [/rmorphV-> // | nUc] := boolP (c \in GRing.unit). by rewrite !invr_out // poly_unitE coefC (negbTE nUc) andbF. Qed. Lemma rootM p q x : root (p * q) x = root p x || root q x. Proof. by rewrite !rootE hornerM mulf_eq0. Qed. Lemma rootZ x a p : a != 0 -> root (a *: p) x = root p x. Proof. by move=> nz_a; rewrite -mul_polyC rootM rootC (negPf nz_a). Qed. Lemma size_scale a p : a != 0 -> size (a *: p) = size p. Proof. by move/lregP/lreg_size->. Qed. Lemma size_Cmul a p : a != 0 -> size (a%:P * p) = size p. Proof. by rewrite mul_polyC => /size_scale->. Qed. Lemma lead_coefM p q : lead_coef (p * q) = lead_coef p * lead_coef q. Proof. have [-> | nz_p] := eqVneq p 0; first by rewrite !(mul0r, lead_coef0). have [-> | nz_q] := eqVneq q 0; first by rewrite !(mulr0, lead_coef0). by rewrite lead_coef_proper_mul // mulf_neq0 ?lead_coef_eq0. Qed. Lemma lead_coefZ a p : lead_coef (a *: p) = a * lead_coef p. Proof. by rewrite -mul_polyC lead_coefM lead_coefC. Qed. Lemma scale_poly_eq0 a p : (a *: p == 0) = (a == 0) || (p == 0). Proof. by rewrite -mul_polyC mulf_eq0 polyC_eq0. Qed. Lemma size_prod (I : finType) (P : pred I) (F : I -> {poly R}) : (forall i, P i -> F i != 0) -> size (\prod_(i | P i) F i) = ((\sum_(i | P i) size (F i)).+1 - #|P|)%N. Proof. move=> nzF; transitivity (\sum_(i | P i) (size (F i)).-1).+1; last first. apply: canRL (addKn _) _; rewrite addnS -sum1_card -big_split /=. by congr _.+1; apply: eq_bigr => i /nzF/polySpred. elim/big_rec2: _ => [|i d p /nzF nzFi IHp]; first by rewrite size_poly1. by rewrite size_mul // -?size_poly_eq0 IHp // addnS polySpred. Qed. Lemma size_exp p n : (size (p ^+ n)).-1 = ((size p).-1 * n)%N. Proof. elim: n => [|n IHn]; first by rewrite size_poly1 muln0. have [-> | nz_p] := eqVneq p 0; first by rewrite exprS mul0r size_poly0. rewrite exprS size_mul ?expf_neq0 // mulnS -{}IHn. by rewrite polySpred // [size (p ^+ n)]polySpred ?expf_neq0 ?addnS. Qed. Lemma lead_coef_exp p n : lead_coef (p ^+ n) = lead_coef p ^+ n. Proof. elim: n => [|n IHn]; first by rewrite !expr0 lead_coef1. by rewrite !exprS lead_coefM IHn. Qed. Lemma root_prod_XsubC rs x : root (\prod_(a <- rs) ('X - a%:P)) x = (x \in rs). Proof. elim: rs => [|a rs IHrs]; first by rewrite rootE big_nil hornerC oner_eq0. by rewrite big_cons rootM IHrs root_XsubC. Qed. Lemma root_exp_XsubC n a x : root (('X - a%:P) ^+ n.+1) x = (x == a). Proof. by rewrite rootE horner_exp expf_eq0 [_ == 0]root_XsubC. Qed. Lemma size_comp_poly p q : (size (p \Po q)).-1 = ((size p).-1 * (size q).-1)%N. Proof. have [-> | nz_p] := eqVneq p 0; first by rewrite comp_poly0 size_poly0. have [/size1_polyC-> | nc_q] := leqP (size q) 1. by rewrite comp_polyCr !size_polyC -!sub1b -!subnS muln0. have nz_q: q != 0 by rewrite -size_poly_eq0 -(subnKC nc_q). rewrite mulnC comp_polyE (polySpred nz_p) /= big_ord_recr /= addrC. rewrite size_addl size_scale ?lead_coef_eq0 ?size_exp //=. rewrite [X in _ < X]polySpred ?expf_neq0 // ltnS size_exp. rewrite (leq_trans (size_sum _ _ _)) //; apply/bigmax_leqP => i _. rewrite (leq_trans (size_scale_leq _ _)) // polySpred ?expf_neq0 //. by rewrite size_exp -(subnKC nc_q) ltn_pmul2l. Qed. Lemma size_comp_poly2 p q : size q = 2 -> size (p \Po q) = size p. Proof. have [/size1_polyC->| p_gt1] := leqP (size p) 1; first by rewrite comp_polyC. move=> lin_q; have{lin_q} sz_pq: (size (p \Po q)).-1 = (size p).-1. by rewrite size_comp_poly lin_q muln1. rewrite -(ltn_predK p_gt1) -sz_pq -polySpred // -size_poly_gt0 ltnW //. by rewrite -subn_gt0 subn1 sz_pq -subn1 subn_gt0. Qed. Lemma comp_poly2_eq0 p q : size q = 2 -> (p \Po q == 0) = (p == 0). Proof. by rewrite -!size_poly_eq0 => /size_comp_poly2->. Qed. Lemma lead_coef_comp p q : size q > 1 -> lead_coef (p \Po q) = lead_coef p * lead_coef q ^+ (size p).-1. Proof. move=> q_gt1; have nz_q: q != 0 by rewrite -size_poly_gt0 ltnW. have [-> | nz_p] := eqVneq p 0; first by rewrite comp_poly0 !lead_coef0 mul0r. rewrite comp_polyE polySpred //= big_ord_recr /= addrC -lead_coefE. rewrite lead_coefDl; first by rewrite lead_coefZ lead_coef_exp. rewrite size_scale ?lead_coef_eq0 // (polySpred (expf_neq0 _ nz_q)) ltnS. apply/leq_sizeP=> i le_qp_i; rewrite coef_sum big1 // => j _. rewrite coefZ (nth_default 0 (leq_trans _ le_qp_i)) ?mulr0 //=. by rewrite polySpred ?expf_neq0 // !size_exp -(subnKC q_gt1) ltn_pmul2l. Qed. End PolynomialIdomain. Section MapFieldPoly. Variables (F : fieldType) (R : ringType) (f : {rmorphism F -> R}). Local Notation "p ^f" := (map_poly f p) : ring_scope. Lemma size_map_poly p : size p^f = size p. Proof. have [-> | nz_p] := eqVneq p 0; first by rewrite rmorph0 !size_poly0. by rewrite size_poly_eq // fmorph_eq0 // lead_coef_eq0. Qed. Lemma lead_coef_map p : lead_coef p^f = f (lead_coef p). Proof. have [-> | nz_p] := eqVneq p 0; first by rewrite !(rmorph0, lead_coef0). by rewrite lead_coef_map_eq // fmorph_eq0 // lead_coef_eq0. Qed. Lemma map_poly_eq0 p : (p^f == 0) = (p == 0). Proof. by rewrite -!size_poly_eq0 size_map_poly. Qed. Lemma map_poly_inj : injective (map_poly f). Proof. move=> p q eqfpq; apply/eqP; rewrite -subr_eq0 -map_poly_eq0. by rewrite rmorphB /= eqfpq subrr. Qed. Lemma map_monic p : (p^f \is monic) = (p \is monic). Proof. by rewrite monicE lead_coef_map fmorph_eq1. Qed. Lemma map_poly_com p x : comm_poly p^f (f x). Proof. exact: map_comm_poly (mulrC x _). Qed. Lemma fmorph_root p x : root p^f (f x) = root p x. Proof. by rewrite rootE horner_map // fmorph_eq0. Qed. Lemma fmorph_unity_root n z : n.-unity_root (f z) = n.-unity_root z. Proof. by rewrite !unity_rootE -(inj_eq (fmorph_inj f)) rmorphX ?rmorph1. Qed. Lemma fmorph_primitive_root n z : n.-primitive_root (f z) = n.-primitive_root z. Proof. by congr (_ && _); apply: eq_forallb => i; rewrite fmorph_unity_root. Qed. End MapFieldPoly. Implicit Arguments map_poly_inj [[F] [R] x1 x2]. Section MaxRoots. Variable R : unitRingType. Implicit Types (x y : R) (rs : seq R) (p : {poly R}). Definition diff_roots (x y : R) := (x * y == y * x) && (y - x \in GRing.unit). Fixpoint uniq_roots rs := if rs is x :: rs' then all (diff_roots x) rs' && uniq_roots rs' else true. Lemma uniq_roots_prod_XsubC p rs : all (root p) rs -> uniq_roots rs -> exists q, p = q * \prod_(z <- rs) ('X - z%:P). Proof. elim: rs => [|z rs IHrs] /=; first by rewrite big_nil; exists p; rewrite mulr1. case/andP=> rpz rprs /andP[drs urs]; case: IHrs => {urs rprs}// q def_p. have [|q' def_q] := factor_theorem q z _; last first. by exists q'; rewrite big_cons mulrA -def_q. rewrite {p}def_p in rpz. elim/last_ind: rs drs rpz => [|rs t IHrs] /=; first by rewrite big_nil mulr1. rewrite all_rcons => /andP[/andP[/eqP czt Uzt] /IHrs {IHrs}IHrs]. rewrite -cats1 big_cat big_seq1 /= mulrA rootE hornerM_comm; last first. by rewrite /comm_poly hornerXsubC mulrBl mulrBr czt. rewrite hornerXsubC -opprB mulrN oppr_eq0 -(mul0r (t - z)). by rewrite (inj_eq (mulIr Uzt)) => /IHrs. Qed. Theorem max_ring_poly_roots p rs : p != 0 -> all (root p) rs -> uniq_roots rs -> size rs < size p. Proof. move=> nz_p _ /(@uniq_roots_prod_XsubC p)[// | q def_p]; rewrite def_p in nz_p *. have nz_q: q != 0 by apply: contraNneq nz_p => ->; rewrite mul0r. rewrite size_Mmonic ?monic_prod_XsubC // (polySpred nz_q) addSn /=. by rewrite size_prod_XsubC leq_addl. Qed. Lemma all_roots_prod_XsubC p rs : size p = (size rs).+1 -> all (root p) rs -> uniq_roots rs -> p = lead_coef p *: \prod_(z <- rs) ('X - z%:P). Proof. move=> size_p /uniq_roots_prod_XsubC def_p Urs. case/def_p: Urs => q -> {p def_p} in size_p *. have [q0 | nz_q] := eqVneq q 0; first by rewrite q0 mul0r size_poly0 in size_p. have{q nz_q size_p} /size_poly1P[c _ ->]: size q == 1%N. rewrite -(eqn_add2r (size rs)) add1n -size_p. by rewrite size_Mmonic ?monic_prod_XsubC // size_prod_XsubC addnS. by rewrite lead_coef_Mmonic ?monic_prod_XsubC // lead_coefC mul_polyC. Qed. End MaxRoots. Section FieldRoots. Variable F : fieldType. Implicit Types (p : {poly F}) (rs : seq F). Lemma poly2_root p : size p = 2 -> {r | root p r}. Proof. case: p => [[|p0 [|p1 []]] //= nz_p1]; exists (- p0 / p1). by rewrite /root addr_eq0 /= mul0r add0r mulrC divfK ?opprK. Qed. Lemma uniq_rootsE rs : uniq_roots rs = uniq rs. Proof. elim: rs => //= r rs ->; congr (_ && _); rewrite -has_pred1 -all_predC. by apply: eq_all => t; rewrite /diff_roots mulrC eqxx unitfE subr_eq0. Qed. Theorem max_poly_roots p rs : p != 0 -> all (root p) rs -> uniq rs -> size rs < size p. Proof. by rewrite -uniq_rootsE; exact: max_ring_poly_roots. Qed. Section UnityRoots. Variable n : nat. Lemma max_unity_roots rs : n > 0 -> all n.-unity_root rs -> uniq rs -> size rs <= n. Proof. move=> n_gt0 rs_n_1 Urs; have szPn := size_Xn_sub_1 F n_gt0. by rewrite -ltnS -szPn max_poly_roots -?size_poly_eq0 ?szPn. Qed. Lemma mem_unity_roots rs : n > 0 -> all n.-unity_root rs -> uniq rs -> size rs = n -> n.-unity_root =i rs. Proof. move=> n_gt0 rs_n_1 Urs sz_rs_n x; rewrite -topredE /=. apply/idP/idP=> xn1; last exact: (allP rs_n_1). apply: contraFT (ltnn n) => not_rs_x. by rewrite -{1}sz_rs_n (@max_unity_roots (x :: rs)) //= ?xn1 ?not_rs_x. Qed. (* Showing the existence of a primitive root requires the theory in cyclic. *) Variable z : F. Hypothesis prim_z : n.-primitive_root z. Let zn := [seq z ^+ i | i <- index_iota 0 n]. Lemma factor_Xn_sub_1 : \prod_(0 <= i < n) ('X - (z ^+ i)%:P) = 'X^n - 1. Proof. transitivity (\prod_(w <- zn) ('X - w%:P)); first by rewrite big_map. have n_gt0: n > 0 := prim_order_gt0 prim_z. rewrite (@all_roots_prod_XsubC _ ('X^n - 1) zn); first 1 last. - by rewrite size_Xn_sub_1 // size_map size_iota subn0. - apply/allP=> _ /mapP[i _ ->] /=; rewrite rootE !hornerE hornerXn. by rewrite exprAC (prim_expr_order prim_z) expr1n subrr. - rewrite uniq_rootsE map_inj_in_uniq ?iota_uniq // => i j. rewrite !mem_index_iota => ltin ltjn /eqP. by rewrite (eq_prim_root_expr prim_z) !modn_small // => /eqP. by rewrite (monicP (monic_Xn_sub_1 F n_gt0)) scale1r. Qed. Lemma prim_rootP x : x ^+ n = 1 -> {i : 'I_n | x = z ^+ i}. Proof. move=> xn1; pose logx := [pred i : 'I_n | x == z ^+ i]. case: (pickP logx) => [i /eqP-> | no_i]; first by exists i. case: notF; suffices{no_i}: x \in zn. case/mapP=> i; rewrite mem_index_iota => lt_i_n def_x. by rewrite -(no_i (Ordinal lt_i_n)) /= -def_x. rewrite -root_prod_XsubC big_map factor_Xn_sub_1. by rewrite [root _ x]unity_rootE xn1. Qed. End UnityRoots. End FieldRoots. Section MapPolyRoots. Variables (F : fieldType) (R : unitRingType) (f : {rmorphism F -> R}). Lemma map_diff_roots x y : diff_roots (f x) (f y) = (x != y). Proof. rewrite /diff_roots -rmorphB // fmorph_unit // subr_eq0 //. by rewrite rmorph_comm // eqxx eq_sym. Qed. Lemma map_uniq_roots s : uniq_roots (map f s) = uniq s. Proof. elim: s => //= x s ->; congr (_ && _); elim: s => //= y s ->. by rewrite map_diff_roots -negb_or. Qed. End MapPolyRoots. Section AutPolyRoot. (* The action of automorphisms on roots of unity. *) Variable F : fieldType. Implicit Types u v : {rmorphism F -> F}. Lemma aut_prim_rootP u z n : n.-primitive_root z -> {k | coprime k n & u z = z ^+ k}. Proof. move=> prim_z; have:= prim_z; rewrite -(fmorph_primitive_root u) => prim_uz. have [[k _] /= def_uz] := prim_rootP prim_z (prim_expr_order prim_uz). by exists k; rewrite // -(prim_root_exp_coprime _ prim_z) -def_uz. Qed. Lemma aut_unity_rootP u z n : n > 0 -> z ^+ n = 1 -> {k | u z = z ^+ k}. Proof. by move=> _ /prim_order_exists[// | m /(aut_prim_rootP u)[k]]; exists k. Qed. Lemma aut_unity_rootC u v z n : n > 0 -> z ^+ n = 1 -> u (v z) = v (u z). Proof. move=> n_gt0 /(aut_unity_rootP _ n_gt0) def_z. have [[i def_uz] [j def_vz]] := (def_z u, def_z v). by rewrite !(def_uz, def_vz, rmorphX) exprAC. Qed. End AutPolyRoot. Module UnityRootTheory. Notation "n .-unity_root" := (root_of_unity n) : unity_root_scope. Notation "n .-primitive_root" := (primitive_root_of_unity n) : unity_root_scope. Open Scope unity_root_scope. Definition unity_rootE := unity_rootE. Definition unity_rootP := @unity_rootP. Implicit Arguments unity_rootP [R n z]. Definition prim_order_exists := prim_order_exists. Notation prim_order_gt0 := prim_order_gt0. Notation prim_expr_order := prim_expr_order. Definition prim_expr_mod := prim_expr_mod. Definition prim_order_dvd := prim_order_dvd. Definition eq_prim_root_expr := eq_prim_root_expr. Definition rmorph_unity_root := rmorph_unity_root. Definition fmorph_unity_root := fmorph_unity_root. Definition fmorph_primitive_root := fmorph_primitive_root. Definition max_unity_roots := max_unity_roots. Definition mem_unity_roots := mem_unity_roots. Definition prim_rootP := prim_rootP. End UnityRootTheory. Module PreClosedField. Section UseAxiom. Variable F : fieldType. Hypothesis closedF : GRing.ClosedField.axiom F. Implicit Type p : {poly F}. Lemma closed_rootP p : reflect (exists x, root p x) (size p != 1%N). Proof. have [-> | nz_p] := eqVneq p 0. by rewrite size_poly0; left; exists 0; rewrite root0. rewrite neq_ltn {1}polySpred //=. apply: (iffP idP) => [p_gt1 | [a]]; last exact: root_size_gt1. pose n := (size p).-1; have n_gt0: n > 0 by rewrite -ltnS -polySpred. have [a Dan] := closedF (fun i => - p`_i / lead_coef p) n_gt0. exists a; apply/rootP; rewrite horner_coef polySpred // big_ord_recr /= -/n. rewrite {}Dan mulr_sumr -big_split big1 //= => i _. by rewrite -!mulrA mulrCA mulNr mulVKf ?subrr ?lead_coef_eq0. Qed. Lemma closed_nonrootP p : reflect (exists x, ~~ root p x) (p != 0). Proof. apply: (iffP idP) => [nz_p | [x]]; last first. by apply: contraNneq => ->; apply: root0. have [[x /rootP p1x0]|] := altP (closed_rootP (p - 1)). by exists x; rewrite -[p](subrK 1) /root hornerD p1x0 add0r hornerC oner_eq0. rewrite negbK => /size_poly1P[c _ /(canRL (subrK 1)) Dp]. by exists 0; rewrite Dp -raddfD polyC_eq0 rootC in nz_p *. Qed. End UseAxiom. End PreClosedField. Section ClosedField. Variable F : closedFieldType. Implicit Type p : {poly F}. Let closedF := @solve_monicpoly F. Lemma closed_rootP p : reflect (exists x, root p x) (size p != 1%N). Proof. exact: PreClosedField.closed_rootP. Qed. Lemma closed_nonrootP p : reflect (exists x, ~~ root p x) (p != 0). Proof. exact: PreClosedField.closed_nonrootP. Qed. Lemma closed_field_poly_normal p : {r : seq F | p = lead_coef p *: \prod_(z <- r) ('X - z%:P)}. Proof. apply: sig_eqW; elim: {p}_.+1 {-2}p (ltnSn (size p)) => // n IHn p le_p_n. have [/size1_polyC-> | p_gt1] := leqP (size p) 1. by exists nil; rewrite big_nil lead_coefC alg_polyC. have [|x /factor_theorem[q Dp]] := closed_rootP p _; first by rewrite gtn_eqF. have nz_p: p != 0 by rewrite -size_poly_eq0 -(subnKC p_gt1). have:= nz_p; rewrite Dp mulf_eq0 lead_coefM => /norP[nz_q nz_Xx]. rewrite ltnS polySpred // Dp size_mul // size_XsubC addn2 in le_p_n. have [r {1}->] := IHn q le_p_n; exists (x :: r). by rewrite lead_coefXsubC mulr1 big_cons -scalerAl mulrC. Qed. End ClosedField. mathcomp-1.5/theories/intdiv.v0000644000175000017500000013230112307636117015467 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. Require Import fintype tuple finfun bigop prime ssralg poly ssrnum ssrint rat. Require Import polydiv finalg perm zmodp matrix mxalgebra vector. (******************************************************************************) (* This file provides various results on divisibility of integers. *) (* It defines, for m, n, d : int, *) (* (m %% d)%Z == the remainder of the Euclidean division of m by d; this is *) (* the least non-negative element of the coset m + dZ when *) (* d != 0, and m if d = 0. *) (* (m %/ d)%Z == the quotient of the Euclidean division of m by d, such *) (* that m = (m %/ d)%Z * d + (m %% d)%Z. Since for d != 0 the *) (* remainder is non-negative, (m %/ d)%Z is non-zero for *) (* (d %| m)%Z <=> m is divisible by d; dvdz d is the (collective) predicate *) (* for integers divisible by d, and (d %| m)%Z is actually *) (* (transposing) notation for m \in dvdz d. *) (* (m = n %[mod d])%Z, (m == n %[mod d])%Z, (m != n %[mod d])%Z *) (* m and n are (resp. compare, don't compare) equal mod d. *) (* gcdz m n == the (non-negative) greatest common divisor of m and n, *) (* with gcdz 0 0 = 0. *) (* coprimez m n <=> m and n are coprime. *) (* egcdz m n == the Bezout coefficients of the gcd of m and n: a pair *) (* (u, v) of coprime integers such that u*m + v*n = gcdz m n. *) (* Alternatively, a Bezoutz lemma states such u and v exist. *) (* zchinese m1 m2 n1 n2 == for coprime m1 and m2, a solution to the Chinese *) (* remainder problem for n1 and n2, i.e., and integer n such *) (* that n = n1 %[mod m1] and n = n2 %[mod m2]. *) (* zcontents p == the contents of p : {poly int}, that is, the gcd of the *) (* coefficients of p, with the lead coefficient of p, *) (* zprimitive p == the primitive part of p : {poly int}, i.e., p divided by *) (* its contents. *) (* inIntSpan X v <-> v is an integral linear combination of elements of *) (* X : seq V, where V is a zmodType. We prove that this is a *) (* decidable property for Q-vector spaces. *) (* int_Smith_normal_form :: a theorem asserting the existence of the Smith *) (* normal form for integer matrices. *) (* Note that many of the concepts and results in this file could and perhaps *) (* sould be generalized to the more general setting of integral, unique *) (* factorization, principal ideal, or Euclidean domains. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GRing.Theory Num.Theory. Local Open Scope ring_scope. Definition divz (m d : int) := let: (K, n) := match m with Posz n => (Posz, n) | Negz n => (Negz, n) end in sgz d * K (n %/ `|d|)%N. Definition modz (m d : int) : int := m - divz m d * d. Definition dvdz d m := (`|d| %| `|m|)%N. Definition gcdz m n := (gcdn `|m| `|n|)%:Z. Definition egcdz m n : int * int := if m == 0 then (0, (-1) ^+ (n < 0)%R) else let: (u, v) := egcdn `|m| `|n| in (sgz m * u, - (-1) ^+ (n < 0)%R * v%:Z). Definition coprimez m n := (gcdz m n == 1). Infix "%/" := divz : int_scope. Infix "%%" := modz : int_scope. Notation "d %| m" := (m \in dvdz d) : int_scope. Notation "m = n %[mod d ]" := (modz m d = modz n d) : int_scope. Notation "m == n %[mod d ]" := (modz m d == modz n d) : int_scope. Notation "m <> n %[mod d ]" := (modz m d <> modz n d) : int_scope. Notation "m != n %[mod d ]" := (modz m d != modz n d) : int_scope. Lemma divz_nat (n d : nat) : (n %/ d)%Z = (n %/ d)%N. Proof. by case: d => // d; rewrite /divz /= mul1r. Qed. Lemma divzN m d : (m %/ - d)%Z = - (m %/ d)%Z. Proof. by case: m => n; rewrite /divz /= sgzN abszN mulNr. Qed. Lemma divz_abs m d : (m %/ `|d|)%Z = (-1) ^+ (d < 0)%R * (m %/ d)%Z. Proof. by rewrite {3}[d]intEsign !mulr_sign; case: ifP => -> //; rewrite divzN opprK. Qed. Lemma div0z d : (0 %/ d)%Z = 0. Proof. by rewrite -(canLR (signrMK _) (divz_abs _ _)) (divz_nat 0) div0n mulr0. Qed. Lemma divNz_nat m d : (d > 0)%N -> (Negz m %/ d)%Z = - (m %/ d).+1%:Z. Proof. by case: d => // d _; apply: mul1r. Qed. Lemma divz_eq m d : m = (m %/ d)%Z * d + (m %% d)%Z. Proof. by rewrite addrC subrK. Qed. Lemma modzN m d : (m %% - d)%Z = (m %% d)%Z. Proof. by rewrite /modz divzN mulrNN. Qed. Lemma modz_abs m d : (m %% `|d|%N)%Z = (m %% d)%Z. Proof. by rewrite {2}[d]intEsign mulr_sign; case: ifP; rewrite ?modzN. Qed. Lemma modz_nat (m d : nat) : (m %% d)%Z = (m %% d)%N. Proof. by apply: (canLR (addrK _)); rewrite addrC divz_nat {1}(divn_eq m d). Qed. Lemma modNz_nat m d : (d > 0)%N -> (Negz m %% d)%Z = d%:Z - 1 - (m %% d)%:Z. Proof. rewrite /modz => /divNz_nat->; apply: (canLR (addrK _)). rewrite -!addrA -!opprD -!PoszD -opprB mulnSr !addnA PoszD addrK. by rewrite addnAC -addnA mulnC -divn_eq. Qed. Lemma modz_ge0 m d : d != 0 -> 0 <= (m %% d)%Z. Proof. rewrite -absz_gt0 -modz_abs => d_gt0. case: m => n; rewrite ?modNz_nat ?modz_nat // -addrA -opprD subr_ge0. by rewrite lez_nat ltn_mod. Qed. Lemma divz0 m : (m %/ 0)%Z = 0. Proof. by case: m. Qed. Lemma mod0z d : (0 %% d)%Z = 0. Proof. by rewrite /modz div0z mul0r subrr. Qed. Lemma modz0 m : (m %% 0)%Z = m. Proof. by rewrite /modz mulr0 subr0. Qed. Lemma divz_small m d : 0 <= m < `|d|%:Z -> (m %/ d)%Z = 0. Proof. rewrite -(canLR (signrMK _) (divz_abs _ _)); case: m => // n /divn_small. by rewrite divz_nat => ->; rewrite mulr0. Qed. Lemma divzMDl q m d : d != 0 -> ((q * d + m) %/ d)%Z = q + (m %/ d)%Z. Proof. rewrite neqr_lt -oppr_gt0 => nz_d. wlog{nz_d} d_gt0: q d / d > 0; last case: d => // d in d_gt0 *. move=> IH; case/orP: nz_d => /IH// /(_ (- q)). by rewrite mulrNN !divzN -opprD => /oppr_inj. wlog q_gt0: q m / q >= 0; last case: q q_gt0 => // q _. move=> IH; case: q => n; first exact: IH; rewrite NegzE mulNr. by apply: canRL (addKr _) _; rewrite -IH ?addNKr. case: m => n; first by rewrite !divz_nat divnMDl. have [le_qd_n | lt_qd_n] := leqP (q * d) n. rewrite divNz_nat // NegzE -(subnKC le_qd_n) divnMDl //. by rewrite -!addnS !PoszD !opprD !addNKr divNz_nat. rewrite divNz_nat // NegzE -PoszM subzn // divz_nat. apply: canRL (addrK _) _; congr _%:Z; rewrite addnC -divnMDl // mulSnr. rewrite -{3}(subnKC (ltn_pmod n d_gt0)) addnA addnS -divn_eq addnAC. by rewrite subnKC // divnMDl // divn_small ?addn0 // subnSK ?ltn_mod ?leq_subr. Qed. Lemma mulzK m d : d != 0 -> (m * d %/ d)%Z = m. Proof. by move=> d_nz; rewrite -[m * d]addr0 divzMDl // div0z addr0. Qed. Lemma mulKz m d : d != 0 -> (d * m %/ d)%Z = m. Proof. by move=> d_nz; rewrite mulrC mulzK. Qed. Lemma expzB p m n : p != 0 -> (m >= n)%N -> p ^+ (m - n) = (p ^+ m %/ p ^+ n)%Z. Proof. by move=> p_nz /subnK{2}<-; rewrite exprD mulzK // expf_neq0. Qed. Lemma modz1 m : (m %% 1)%Z = 0. Proof. by case: m => n; rewrite (modNz_nat, modz_nat) ?modn1. Qed. Lemma divn1 m : (m %/ 1)%Z = m. Proof. by rewrite -{1}[m]mulr1 mulzK. Qed. Lemma divzz d : (d %/ d)%Z = (d != 0). Proof. by have [-> // | d_nz] := altP eqP; rewrite -{1}[d]mul1r mulzK. Qed. Lemma ltz_pmod m d : d > 0 -> (m %% d)%Z < d. Proof. case: m d => n [] // d d_gt0; first by rewrite modz_nat ltz_nat ltn_pmod. by rewrite modNz_nat // -lez_addr1 addrAC subrK ger_addl oppr_le0. Qed. Lemma ltz_mod m d : d != 0 -> (m %% d)%Z < `|d|. Proof. by rewrite -absz_gt0 -modz_abs => d_gt0; apply: ltz_pmod. Qed. Lemma divzMpl p m d : p > 0 -> (p * m %/ (p * d) = m %/ d)%Z. Proof. case: p => // p p_gt0; wlog d_gt0: d / d > 0; last case: d => // d in d_gt0 *. by move=> IH; case/intP: d => [|d|d]; rewrite ?mulr0 ?divz0 ?mulrN ?divzN ?IH. rewrite {1}(divz_eq m d) mulrDr mulrCA divzMDl ?mulf_neq0 ?gtr_eqF // addrC. rewrite divz_small ?add0r // PoszM pmulr_rge0 ?modz_ge0 ?gtr_eqF //=. by rewrite ltr_pmul2l ?ltz_pmod. Qed. Implicit Arguments divzMpl [p m d]. Lemma divzMpr p m d : p > 0 -> (m * p %/ (d * p) = m %/ d)%Z. Proof. by move=> p_gt0; rewrite -!(mulrC p) divzMpl. Qed. Implicit Arguments divzMpr [p m d]. Lemma lez_floor m d : d != 0 -> (m %/ d)%Z * d <= m. Proof. by rewrite -subr_ge0; apply: modz_ge0. Qed. (* leq_mod does not extend to negative m. *) Lemma lez_div m d : (`|(m %/ d)%Z| <= `|m|)%N. Proof. wlog d_gt0: d / d > 0; last case: d d_gt0 => // d d_gt0. by move=> IH; case/intP: d => [|n|n]; rewrite ?divz0 ?divzN ?abszN // IH. case: m => n; first by rewrite divz_nat leq_div. by rewrite divNz_nat // NegzE !abszN ltnS leq_div. Qed. Lemma ltz_ceil m d : d > 0 -> m < ((m %/ d)%Z + 1) * d. Proof. by case: d => // d d_gt0; rewrite mulrDl mul1r -ltr_subl_addl ltz_mod ?gtr_eqF. Qed. Lemma ltz_divLR m n d : d > 0 -> ((m %/ d)%Z < n) = (m < n * d). Proof. move=> d_gt0; apply/idP/idP. by rewrite -lez_addr1 -(ler_pmul2r d_gt0); apply: ltr_le_trans (ltz_ceil _ _). rewrite -(ltr_pmul2r d_gt0 _ n) //; apply: ler_lt_trans (lez_floor _ _). by rewrite gtr_eqF. Qed. Lemma lez_divRL m n d : d > 0 -> (m <= (n %/ d)%Z) = (m * d <= n). Proof. by move=> d_gt0; rewrite !lerNgt ltz_divLR. Qed. Lemma divz_ge0 m d : d > 0 -> ((m %/ d)%Z >= 0) = (m >= 0). Proof. by case: d m => // d [] n d_gt0; rewrite (divz_nat, divNz_nat). Qed. Lemma divzMA_ge0 m n p : n >= 0 -> (m %/ (n * p) = (m %/ n)%Z %/ p)%Z. Proof. case: n => // [[|n]] _; first by rewrite mul0r !divz0 div0z. wlog p_gt0: p / p > 0; last case: p => // p in p_gt0 *. by case/intP: p => [|p|p] IH; rewrite ?mulr0 ?divz0 ?mulrN ?divzN // IH. rewrite {2}(divz_eq m (n.+1%:Z * p)) mulrA mulrAC !divzMDl // ?gtr_eqF //. rewrite [rhs in _ + rhs]divz_small ?addr0 // ltz_divLR // divz_ge0 //. by rewrite mulrC ltz_pmod ?modz_ge0 ?gtr_eqF ?pmulr_lgt0. Qed. Lemma modz_small m d : 0 <= m < d -> (m %% d)%Z = m. Proof. by case: m d => //= m [] // d; rewrite modz_nat => /modn_small->. Qed. Lemma modz_mod m d : ((m %% d)%Z = m %[mod d])%Z. Proof. rewrite -!(modz_abs _ d); case: {d}`|d|%N => [|d]; first by rewrite !modz0. by rewrite modz_small ?modz_ge0 ?ltz_mod. Qed. Lemma modzMDl p m d : (p * d + m = m %[mod d])%Z. Proof. have [-> | d_nz] := eqVneq d 0; first by rewrite mulr0 add0r. by rewrite /modz divzMDl // mulrDl opprD addrACA subrr add0r. Qed. Lemma mulz_modr {p m d} : 0 < p -> p * (m %% d)%Z = ((p * m) %% (p * d))%Z. Proof. case: p => // p p_gt0; rewrite mulrBr; apply: canLR (addrK _) _. by rewrite mulrCA -(divzMpl p_gt0) subrK. Qed. Lemma mulz_modl {p m d} : 0 < p -> (m %% d)%Z * p = ((m * p) %% (d * p))%Z. Proof. by rewrite -!(mulrC p); apply: mulz_modr. Qed. Lemma modzDl m d : (d + m = m %[mod d])%Z. Proof. by rewrite -{1}[d]mul1r modzMDl. Qed. Lemma modzDr m d : (m + d = m %[mod d])%Z. Proof. by rewrite addrC modzDl. Qed. Lemma modzz d : (d %% d)%Z = 0. Proof. by rewrite -{1}[d]addr0 modzDl mod0z. Qed. Lemma modzMl p d : (p * d %% d)%Z = 0. Proof. by rewrite -[p * d]addr0 modzMDl mod0z. Qed. Lemma modzMr p d : (d * p %% d)%Z = 0. Proof. by rewrite mulrC modzMl. Qed. Lemma modzDml m n d : ((m %% d)%Z + n = m + n %[mod d])%Z. Proof. by rewrite {2}(divz_eq m d) -[_ * d + _ + n]addrA modzMDl. Qed. Lemma modzDmr m n d : (m + (n %% d)%Z = m + n %[mod d])%Z. Proof. by rewrite !(addrC m) modzDml. Qed. Lemma modzDm m n d : ((m %% d)%Z + (n %% d)%Z = m + n %[mod d])%Z. Proof. by rewrite modzDml modzDmr. Qed. Lemma eqz_modDl p m n d : (p + m == p + n %[mod d])%Z = (m == n %[mod d])%Z. Proof. have [-> | d_nz] := eqVneq d 0; first by rewrite !modz0 (inj_eq (addrI p)). apply/eqP/eqP=> eq_mn; last by rewrite -modzDmr eq_mn modzDmr. by rewrite -(addKr p m) -modzDmr eq_mn modzDmr addKr. Qed. Lemma eqz_modDr p m n d : (m + p == n + p %[mod d])%Z = (m == n %[mod d])%Z. Proof. by rewrite -!(addrC p) eqz_modDl. Qed. Lemma modzMml m n d : ((m %% d)%Z * n = m * n %[mod d])%Z. Proof. by rewrite {2}(divz_eq m d) mulrDl mulrAC modzMDl. Qed. Lemma modzMmr m n d : (m * (n %% d)%Z = m * n %[mod d])%Z. Proof. by rewrite !(mulrC m) modzMml. Qed. Lemma modzMm m n d : ((m %% d)%Z * (n %% d)%Z = m * n %[mod d])%Z. Proof. by rewrite modzMml modzMmr. Qed. Lemma modzXm k m d : ((m %% d)%Z ^+ k = m ^+ k %[mod d])%Z. Proof. by elim: k => // k IHk; rewrite !exprS -modzMmr IHk modzMm. Qed. Lemma modzNm m d : (- (m %% d)%Z = - m %[mod d])%Z. Proof. by rewrite -mulN1r modzMmr mulN1r. Qed. Lemma modz_absm m d : ((-1) ^+ (m < 0)%R * (m %% d)%Z = `|m|%:Z %[mod d])%Z. Proof. by rewrite modzMmr -abszEsign. Qed. (** Divisibility **) Fact dvdz_key d : pred_key (dvdz d). Proof. by []. Qed. Canonical dvdz_keyed d := KeyedPred (dvdz_key d). Lemma dvdzE d m : (d %| m)%Z = (`|d| %| `|m|)%N. Proof. by []. Qed. Lemma dvdz0 d : (d %| 0)%Z. Proof. exact: dvdn0. Qed. Lemma dvd0z n : (0 %| n)%Z = (n == 0). Proof. by rewrite -absz_eq0 -dvd0n. Qed. Lemma dvdz1 d : (d %| 1)%Z = (`|d|%N == 1%N). Proof. exact: dvdn1. Qed. Lemma dvd1z m : (1 %| m)%Z. Proof. exact: dvd1n. Qed. Lemma dvdzz m : (m %| m)%Z. Proof. exact: dvdnn. Qed. Lemma dvdz_mull d m n : (d %| n)%Z -> (d %| m * n)%Z. Proof. by rewrite !dvdzE abszM; apply: dvdn_mull. Qed. Lemma dvdz_mulr d m n : (d %| m)%Z -> (d %| m * n)%Z. Proof. by move=> d_m; rewrite mulrC dvdz_mull. Qed. Hint Resolve dvdz0 dvd1z dvdzz dvdz_mull dvdz_mulr. Lemma dvdz_mul d1 d2 m1 m2 : (d1 %| m1 -> d2 %| m2 -> d1 * d2 %| m1 * m2)%Z. Proof. by rewrite !dvdzE !abszM; apply: dvdn_mul. Qed. Lemma dvdz_trans n d m : (d %| n -> n %| m -> d %| m)%Z. Proof. by rewrite !dvdzE; apply: dvdn_trans. Qed. Lemma dvdzP d m : reflect (exists q, m = q * d) (d %| m)%Z. Proof. apply: (iffP dvdnP) => [] [q Dm]; last by exists `|q|%N; rewrite Dm abszM. exists ((-1) ^+ (m < 0)%R * q%:Z * (-1) ^+ (d < 0)%R). by rewrite -!mulrA -abszEsign -PoszM -Dm -intEsign. Qed. Implicit Arguments dvdzP [d m]. Lemma dvdz_mod0P d m : reflect (m %% d = 0)%Z (d %| m)%Z. Proof. apply: (iffP dvdzP) => [[q ->] | md0]; first by rewrite modzMl. by rewrite (divz_eq m d) md0 addr0; exists (m %/ d)%Z. Qed. Implicit Arguments dvdz_mod0P [d m]. Lemma dvdz_eq d m : (d %| m)%Z = ((m %/ d)%Z * d == m). Proof. by rewrite (sameP dvdz_mod0P eqP) subr_eq0 eq_sym. Qed. Lemma divzK d m : (d %| m)%Z -> (m %/ d)%Z * d = m. Proof. by rewrite dvdz_eq => /eqP. Qed. Lemma lez_divLR d m n : 0 < d -> (d %| m)%Z -> ((m %/ d)%Z <= n) = (m <= n * d). Proof. by move=> /ler_pmul2r <- /divzK->. Qed. Lemma ltz_divRL d m n : 0 < d -> (d %| m)%Z -> (n < m %/ d)%Z = (n * d < m). Proof. by move=> /ltr_pmul2r <- /divzK->. Qed. Lemma eqz_div d m n : d != 0 -> (d %| m)%Z -> (n == m %/ d)%Z = (n * d == m). Proof. by move=> /mulIf/inj_eq <- /divzK->. Qed. Lemma eqz_mul d m n : d != 0 -> (d %| m)%Z -> (m == n * d) = (m %/ d == n)%Z. Proof. by move=> d_gt0 dv_d_m; rewrite eq_sym -eqz_div // eq_sym. Qed. Lemma divz_mulAC d m n : (d %| m)%Z -> (m %/ d)%Z * n = (m * n %/ d)%Z. Proof. have [-> | d_nz] := eqVneq d 0; first by rewrite !divz0 mul0r. by move/divzK=> {2} <-; rewrite mulrAC mulzK. Qed. Lemma mulz_divA d m n : (d %| n)%Z -> m * (n %/ d)%Z = (m * n %/ d)%Z. Proof. by move=> dv_d_m; rewrite !(mulrC m) divz_mulAC. Qed. Lemma mulz_divCA d m n : (d %| m)%Z -> (d %| n)%Z -> m * (n %/ d)%Z = n * (m %/ d)%Z. Proof. by move=> dv_d_m dv_d_n; rewrite mulrC divz_mulAC ?mulz_divA. Qed. Lemma divzA m n p : (p %| n -> n %| m * p -> m %/ (n %/ p)%Z = m * p %/ n)%Z. Proof. move/divzK=> p_dv_n; have [->|] := eqVneq n 0; first by rewrite div0z !divz0. rewrite -{1 2}p_dv_n mulf_eq0 => /norP[pn_nz p_nz] /divzK; rewrite mulrA p_dv_n. by move/mulIf=> {1} <- //; rewrite mulzK. Qed. Lemma divzMA m n p : (n * p %| m -> m %/ (n * p) = (m %/ n)%Z %/ p)%Z. Proof. have [-> | nz_p] := eqVneq p 0; first by rewrite mulr0 !divz0. have [-> | nz_n] := eqVneq n 0; first by rewrite mul0r !divz0 div0z. by move/divzK=> {2} <-; rewrite mulrA mulrAC !mulzK. Qed. Lemma divzAC m n p : (n * p %| m -> (m %/ n)%Z %/ p = (m %/ p)%Z %/ n)%Z. Proof. by move=> np_dv_mn; rewrite -!divzMA // mulrC. Qed. Lemma divzMl p m d : p != 0 -> (d %| m -> p * m %/ (p * d) = m %/ d)%Z. Proof. have [-> | nz_d nz_p] := eqVneq d 0; first by rewrite mulr0 !divz0. by move/divzK=> {1}<-; rewrite mulrCA mulzK ?mulf_neq0. Qed. Lemma divzMr p m d : p != 0 -> (d %| m -> m * p %/ (d * p) = m %/ d)%Z. Proof. by rewrite -!(mulrC p); apply: divzMl. Qed. Lemma dvdz_mul2l p d m : p != 0 -> (p * d %| p * m)%Z = (d %| m)%Z. Proof. by rewrite !dvdzE -absz_gt0 !abszM; apply: dvdn_pmul2l. Qed. Implicit Arguments dvdz_mul2l [p m d]. Lemma dvdz_mul2r p d m : p != 0 -> (d * p %| m * p)%Z = (d %| m)%Z. Proof. by rewrite !dvdzE -absz_gt0 !abszM; apply: dvdn_pmul2r. Qed. Implicit Arguments dvdz_mul2r [p m d]. Lemma dvdz_exp2l p m n : (m <= n)%N -> (p ^+ m %| p ^+ n)%Z. Proof. by rewrite dvdzE !abszX; apply: dvdn_exp2l. Qed. Lemma dvdz_Pexp2l p m n : `|p| > 1 -> (p ^+ m %| p ^+ n)%Z = (m <= n)%N. Proof. by rewrite dvdzE !abszX ltz_nat; apply: dvdn_Pexp2l. Qed. Lemma dvdz_exp2r m n k : (m %| n -> m ^+ k %| n ^+ k)%Z. Proof. by rewrite !dvdzE !abszX; apply: dvdn_exp2r. Qed. Fact dvdz_zmod_closed d : zmod_closed (dvdz d). Proof. split=> [|_ _ /dvdzP[p ->] /dvdzP[q ->]]; first exact: dvdz0. by rewrite -mulrBl dvdz_mull. Qed. Canonical dvdz_addPred d := AddrPred (dvdz_zmod_closed d). Canonical dvdz_oppPred d := OpprPred (dvdz_zmod_closed d). Canonical dvdz_zmodPred d := ZmodPred (dvdz_zmod_closed d). Lemma dvdz_exp k d m : (0 < k)%N -> (d %| m -> d %| m ^+ k)%Z. Proof. by case: k => // k _ d_dv_m; rewrite exprS dvdz_mulr. Qed. Lemma eqz_mod_dvd d m n : (m == n %[mod d])%Z = (d %| m - n)%Z. Proof. apply/eqP/dvdz_mod0P=> eq_mn. by rewrite -modzDml eq_mn modzDml subrr mod0z. by rewrite -(subrK n m) -modzDml eq_mn add0r. Qed. Lemma divzDl m n d : (d %| m)%Z -> ((m + n) %/ d)%Z = (m %/ d)%Z + (n %/ d)%Z. Proof. have [-> | d_nz] := eqVneq d 0; first by rewrite !divz0. by move/divzK=> {1}<-; rewrite divzMDl. Qed. Lemma divzDr m n d : (d %| n)%Z -> ((m + n) %/ d)%Z = (m %/ d)%Z + (n %/ d)%Z. Proof. by move=> dv_n; rewrite addrC divzDl // addrC. Qed. Lemma Qint_dvdz (m d : int) : (d %| m)%Z -> ((m%:~R / d%:~R : rat) \is a Qint). Proof. case/dvdzP=> z ->; rewrite rmorphM /=; case: (altP (d =P 0)) => [->|dn0]. by rewrite mulr0 mul0r. by rewrite mulfK ?intr_eq0 // rpred_int. Qed. Lemma Qnat_dvd (m d : nat) : (d %| m)%N -> ((m%:R / d%:R : rat) \is a Qnat). Proof. move=> h; rewrite Qnat_def divr_ge0 ?ler0n // -[m%:R]/(m%:~R) -[d%:R]/(d%:~R). by rewrite Qint_dvdz. Qed. (* Greatest common divisor *) Lemma gcdzz m : gcdz m m = `|m|%:Z. Proof. by rewrite /gcdz gcdnn. Qed. Lemma gcdzC : commutative gcdz. Proof. by move=> m n; rewrite /gcdz gcdnC. Qed. Lemma gcd0z m : gcdz 0 m = `|m|%:Z. Proof. by rewrite /gcdz gcd0n. Qed. Lemma gcdz0 m : gcdz m 0 = `|m|%:Z. Proof. by rewrite /gcdz gcdn0. Qed. Lemma gcd1z : left_zero 1 gcdz. Proof. by move=> m; rewrite /gcdz gcd1n. Qed. Lemma gcdz1 : right_zero 1 gcdz. Proof. by move=> m; rewrite /gcdz gcdn1. Qed. Lemma dvdz_gcdr m n : (gcdz m n %| n)%Z. Proof. exact: dvdn_gcdr. Qed. Lemma dvdz_gcdl m n : (gcdz m n %| m)%Z. Proof. exact: dvdn_gcdl. Qed. Lemma gcdz_eq0 m n : (gcdz m n == 0) = (m == 0) && (n == 0). Proof. by rewrite -absz_eq0 eqn0Ngt gcdn_gt0 !negb_or -!eqn0Ngt !absz_eq0. Qed. Lemma gcdNz m n : gcdz (- m) n = gcdz m n. Proof. by rewrite /gcdz abszN. Qed. Lemma gcdzN m n : gcdz m (- n) = gcdz m n. Proof. by rewrite /gcdz abszN. Qed. Lemma gcdz_modr m n : gcdz m (n %% m)%Z = gcdz m n. Proof. rewrite -modz_abs /gcdz; move/absz: m => m. have [-> | m_gt0] := posnP m; first by rewrite modz0. case: n => n; first by rewrite modz_nat gcdn_modr. rewrite modNz_nat // NegzE abszN {2}(divn_eq n m) -addnS gcdnMDl. rewrite -addrA -opprD -intS /=; set m1 := _.+1. have le_m1m: (m1 <= m)%N by exact: ltn_pmod. by rewrite subzn // !(gcdnC m) -{2 3}(subnK le_m1m) gcdnDl gcdnDr gcdnC. Qed. Lemma gcdz_modl m n : gcdz (m %% n)%Z n = gcdz m n. Proof. by rewrite -!(gcdzC n) gcdz_modr. Qed. Lemma gcdzMDl q m n : gcdz m (q * m + n) = gcdz m n. Proof. by rewrite -gcdz_modr modzMDl gcdz_modr. Qed. Lemma gcdzDl m n : gcdz m (m + n) = gcdz m n. Proof. by rewrite -{2}(mul1r m) gcdzMDl. Qed. Lemma gcdzDr m n : gcdz m (n + m) = gcdz m n. Proof. by rewrite addrC gcdzDl. Qed. Lemma gcdzMl n m : gcdz n (m * n) = `|n|%:Z. Proof. by rewrite -[m * n]addr0 gcdzMDl gcdz0. Qed. Lemma gcdzMr n m : gcdz n (n * m) = `|n|%:Z. Proof. by rewrite mulrC gcdzMl. Qed. Lemma gcdz_idPl {m n} : reflect (gcdz m n = `|m|%:Z) (m %| n)%Z. Proof. by apply: (iffP gcdn_idPl) => [<- | []]. Qed. Lemma gcdz_idPr {m n} : reflect (gcdz m n = `|n|%:Z) (n %| m)%Z. Proof. by rewrite gcdzC; apply: gcdz_idPl. Qed. Lemma expz_min e m n : e >= 0 -> e ^+ minn m n = gcdz (e ^+ m) (e ^+ n). Proof. by case: e => // e _; rewrite /gcdz !abszX -expn_min -natz -natrX !natz. Qed. Lemma dvdz_gcd p m n : (p %| gcdz m n)%Z = (p %| m)%Z && (p %| n)%Z. Proof. exact: dvdn_gcd. Qed. Lemma gcdzAC : right_commutative gcdz. Proof. by move=> m n p; rewrite /gcdz gcdnAC. Qed. Lemma gcdzA : associative gcdz. Proof. by move=> m n p; rewrite /gcdz gcdnA. Qed. Lemma gcdzCA : left_commutative gcdz. Proof. by move=> m n p; rewrite /gcdz gcdnCA. Qed. Lemma gcdzACA : interchange gcdz gcdz. Proof. by move=> m n p q; rewrite /gcdz gcdnACA. Qed. Lemma mulz_gcdr m n p : `|m|%:Z * gcdz n p = gcdz (m * n) (m * p). Proof. by rewrite -PoszM muln_gcdr -!abszM. Qed. Lemma mulz_gcdl m n p : gcdz m n * `|p|%:Z = gcdz (m * p) (n * p). Proof. by rewrite -PoszM muln_gcdl -!abszM. Qed. Lemma mulz_divCA_gcd n m : n * (m %/ gcdz n m)%Z = m * (n %/ gcdz n m)%Z. Proof. by rewrite mulz_divCA ?dvdz_gcdl ?dvdz_gcdr. Qed. (* Not including lcm theory, for now. *) (* Coprime factors *) Lemma coprimezE m n : coprimez m n = coprime `|m| `|n|. Proof. by []. Qed. Lemma coprimez_sym : symmetric coprimez. Proof. by move=> m n; apply: coprime_sym. Qed. Lemma coprimeNz m n : coprimez (- m) n = coprimez m n. Proof. by rewrite coprimezE abszN. Qed. Lemma coprimezN m n : coprimez m (- n) = coprimez m n. Proof. by rewrite coprimezE abszN. Qed. CoInductive egcdz_spec m n : int * int -> Type := EgcdzSpec u v of u * m + v * n = gcdz m n & coprimez u v : egcdz_spec m n (u, v). Lemma egcdzP m n : egcdz_spec m n (egcdz m n). Proof. rewrite /egcdz; have [-> | m_nz] := altP eqP. by split; [rewrite -abszEsign gcd0z | rewrite coprimezE absz_sign]. have m_gt0 : (`|m| > 0)%N by rewrite absz_gt0. case: egcdnP (coprime_egcdn `|n| m_gt0) => //= u v Duv _ co_uv; split. rewrite !mulNr -!mulrA mulrCA -abszEsg mulrCA -abszEsign. by rewrite -!PoszM Duv addnC PoszD addrK. by rewrite coprimezE abszM absz_sg m_nz mul1n mulNr abszN abszMsign. Qed. Lemma Bezoutz m n : {u : int & {v : int | u * m + v * n = gcdz m n}}. Proof. by exists (egcdz m n).1, (egcdz m n).2; case: egcdzP. Qed. Lemma coprimezP m n : reflect (exists uv, uv.1 * m + uv.2 * n = 1) (coprimez m n). Proof. apply: (iffP eqP) => [<-| [[u v] /= Duv]]. by exists (egcdz m n); case: egcdzP. congr _%:Z; apply: gcdn_def; rewrite ?dvd1n // => d dv_d_n dv_d_m. by rewrite -(dvdzE d 1) -Duv [m]intEsg [n]intEsg rpredD ?dvdz_mull. Qed. Lemma Gauss_dvdz m n p : coprimez m n -> (m * n %| p)%Z = (m %| p)%Z && (n %| p)%Z. Proof. by move/Gauss_dvd <-; rewrite -abszM. Qed. Lemma Gauss_dvdzr m n p : coprimez m n -> (m %| n * p)%Z = (m %| p)%Z. Proof. by rewrite dvdzE abszM => /Gauss_dvdr->. Qed. Lemma Gauss_dvdzl m n p : coprimez m p -> (m %| n * p)%Z = (m %| n)%Z. Proof. by rewrite mulrC; apply: Gauss_dvdzr. Qed. Lemma Gauss_gcdzr p m n : coprimez p m -> gcdz p (m * n) = gcdz p n. Proof. by rewrite /gcdz abszM => /Gauss_gcdr->. Qed. Lemma Gauss_gcdzl p m n : coprimez p n -> gcdz p (m * n) = gcdz p m. Proof. by move=> co_pn; rewrite mulrC Gauss_gcdzr. Qed. Lemma coprimez_mulr p m n : coprimez p (m * n) = coprimez p m && coprimez p n. Proof. by rewrite -coprime_mulr -abszM. Qed. Lemma coprimez_mull p m n : coprimez (m * n) p = coprimez m p && coprimez n p. Proof. by rewrite -coprime_mull -abszM. Qed. Lemma coprimez_pexpl k m n : (0 < k)%N -> coprimez (m ^+ k) n = coprimez m n. Proof. by rewrite /coprimez /gcdz abszX; apply: coprime_pexpl. Qed. Lemma coprimez_pexpr k m n : (0 < k)%N -> coprimez m (n ^+ k) = coprimez m n. Proof. by move=> k_gt0; rewrite !(coprimez_sym m) coprimez_pexpl. Qed. Lemma coprimez_expl k m n : coprimez m n -> coprimez (m ^+ k) n. Proof. by rewrite /coprimez /gcdz abszX; apply: coprime_expl. Qed. Lemma coprimez_expr k m n : coprimez m n -> coprimez m (n ^+ k). Proof. by rewrite !(coprimez_sym m); apply: coprimez_expl. Qed. Lemma coprimez_dvdl m n p : (m %| n)%N -> coprimez n p -> coprimez m p. Proof. exact: coprime_dvdl. Qed. Lemma coprimez_dvdr m n p : (m %| n)%N -> coprimez p n -> coprimez p m. Proof. exact: coprime_dvdr. Qed. Lemma dvdz_pexp2r m n k : (k > 0)%N -> (m ^+ k %| n ^+ k)%Z = (m %| n)%Z. Proof. by rewrite dvdzE !abszX; apply: dvdn_pexp2r. Qed. Section Chinese. (***********************************************************************) (* The chinese remainder theorem *) (***********************************************************************) Variables m1 m2 : int. Hypothesis co_m12 : coprimez m1 m2. Lemma zchinese_remainder x y : (x == y %[mod m1 * m2])%Z = (x == y %[mod m1])%Z && (x == y %[mod m2])%Z. Proof. by rewrite !eqz_mod_dvd Gauss_dvdz. Qed. (***********************************************************************) (* A function that solves the chinese remainder problem *) (***********************************************************************) Definition zchinese r1 r2 := r1 * m2 * (egcdz m1 m2).2 + r2 * m1 * (egcdz m1 m2).1. Lemma zchinese_modl r1 r2 : (zchinese r1 r2 = r1 %[mod m1])%Z. Proof. rewrite /zchinese; have [u v /= Duv _] := egcdzP m1 m2. rewrite -{2}[r1]mulr1 -((gcdz _ _ =P 1) co_m12) -Duv. by rewrite mulrDr mulrAC addrC (mulrAC r2) !mulrA !modzMDl. Qed. Lemma zchinese_modr r1 r2 : (zchinese r1 r2 = r2 %[mod m2])%Z. Proof. rewrite /zchinese; have [u v /= Duv _] := egcdzP m1 m2. rewrite -{2}[r2]mulr1 -((gcdz _ _ =P 1) co_m12) -Duv. by rewrite mulrAC modzMDl mulrAC addrC mulrDr !mulrA modzMDl. Qed. Lemma zchinese_mod x : (x = zchinese (x %% m1)%Z (x %% m2)%Z %[mod m1 * m2])%Z. Proof. apply/eqP; rewrite zchinese_remainder //. by rewrite zchinese_modl zchinese_modr !modz_mod !eqxx. Qed. End Chinese. Section ZpolyScale. Definition zcontents p := sgz (lead_coef p) * \big[gcdn/0%N]_(i < size p) `|(p`_i)%R|%N. Lemma sgz_contents p : sgz (zcontents p) = sgz (lead_coef p). Proof. rewrite /zcontents mulrC sgzM sgz_id; set d := _%:Z. have [-> | nz_p] := eqVneq p 0; first by rewrite lead_coef0 mulr0. rewrite gtr0_sgz ?mul1r // ltz_nat polySpred ?big_ord_recr //= -lead_coefE. by rewrite gcdn_gt0 orbC absz_gt0 lead_coef_eq0 nz_p. Qed. Lemma zcontents_eq0 p : (zcontents p == 0) = (p == 0). Proof. by rewrite -sgz_eq0 sgz_contents sgz_eq0 lead_coef_eq0. Qed. Lemma zcontents0 : zcontents 0 = 0. Proof. by apply/eqP; rewrite zcontents_eq0. Qed. Lemma zcontentsZ a p : zcontents (a *: p) = a * zcontents p. Proof. have [-> | nz_a] := eqVneq a 0; first by rewrite scale0r mul0r zcontents0. rewrite {2}[a]intEsg mulrCA -mulrA -PoszM big_distrr /= mulrCA mulrA -sgzM. rewrite -lead_coefZ; congr (_ * _%:Z); rewrite size_scale //. by apply: eq_bigr => i _; rewrite coefZ abszM. Qed. Lemma zcontents_monic p : p \is monic -> zcontents p = 1. Proof. move=> mon_p; rewrite /zcontents polySpred ?monic_neq0 //. by rewrite big_ord_recr /= -lead_coefE (monicP mon_p) gcdn1. Qed. Lemma dvdz_contents a p : (a %| zcontents p)%Z = (p \is a polyOver (dvdz a)). Proof. rewrite dvdzE abszM absz_sg lead_coef_eq0. have [-> | nz_p] := altP eqP; first by rewrite mul0n dvdn0 rpred0. rewrite mul1n; apply/dvdn_biggcdP/(all_nthP 0)=> a_dv_p i ltip /=. exact: (a_dv_p (Ordinal ltip)). exact: a_dv_p. Qed. Lemma map_poly_divzK a p : p \is a polyOver (dvdz a) -> a *: map_poly (divz^~ a) p = p. Proof. move/polyOverP=> a_dv_p; apply/polyP=> i. by rewrite coefZ coef_map_id0 ?div0z // mulrC divzK. Qed. Lemma polyOver_dvdzP a p : reflect (exists q, p = a *: q) (p \is a polyOver (dvdz a)). Proof. apply: (iffP idP) => [/map_poly_divzK | [q ->]]. by exists (map_poly (divz^~ a) p). by apply/polyOverP=> i; rewrite coefZ dvdz_mulr. Qed. Definition zprimitive p := map_poly (divz^~ (zcontents p)) p. Lemma zpolyEprim p : p = zcontents p *: zprimitive p. Proof. by rewrite map_poly_divzK // -dvdz_contents. Qed. Lemma zprimitive0 : zprimitive 0 = 0. Proof. by apply/polyP=> i; rewrite coef0 coef_map_id0 ?div0z // zcontents0 divz0. Qed. Lemma zprimitive_eq0 p : (zprimitive p == 0) = (p == 0). Proof. apply/idP/idP=> /eqP p0; first by rewrite [p]zpolyEprim p0 scaler0. by rewrite p0 zprimitive0. Qed. Lemma size_zprimitive p : size (zprimitive p) = size p. Proof. have [-> | ] := eqVneq p 0; first by rewrite zprimitive0. by rewrite {1 3}[p]zpolyEprim scale_poly_eq0 => /norP[/size_scale-> _]. Qed. Lemma sgz_lead_primitive p : sgz (lead_coef (zprimitive p)) = (p != 0). Proof. have [-> | nz_p] := altP eqP; first by rewrite zprimitive0 lead_coef0. apply: (@mulfI _ (sgz (zcontents p))); first by rewrite sgz_eq0 zcontents_eq0. by rewrite -sgzM mulr1 -lead_coefZ -zpolyEprim sgz_contents. Qed. Lemma zcontents_primitive p : zcontents (zprimitive p) = (p != 0). Proof. have [-> | nz_p] := altP eqP; first by rewrite zprimitive0 zcontents0. apply: (@mulfI _ (zcontents p)); first by rewrite zcontents_eq0. by rewrite mulr1 -zcontentsZ -zpolyEprim. Qed. Lemma zprimitive_id p : zprimitive (zprimitive p) = zprimitive p. Proof. have [-> | nz_p] := eqVneq p 0; first by rewrite !zprimitive0. by rewrite {2}[zprimitive p]zpolyEprim zcontents_primitive nz_p scale1r. Qed. Lemma zprimitive_monic p : p \in monic -> zprimitive p = p. Proof. by move=> mon_p; rewrite {2}[p]zpolyEprim zcontents_monic ?scale1r. Qed. Lemma zprimitiveZ a p : a != 0 -> zprimitive (a *: p) = zprimitive p. Proof. have [-> | nz_p nz_a] := eqVneq p 0; first by rewrite scaler0. apply: (@mulfI _ (a * zcontents p)%:P). by rewrite polyC_eq0 mulf_neq0 ?zcontents_eq0. by rewrite -{1}zcontentsZ !mul_polyC -zpolyEprim -scalerA -zpolyEprim. Qed. Lemma zprimitive_min p a q : p != 0 -> p = a *: q -> {b | sgz b = sgz (lead_coef q) & q = b *: zprimitive p}. Proof. move=> nz_p Dp; have /dvdzP/sig_eqW[b Db]: (a %| zcontents p)%Z. by rewrite dvdz_contents; apply/polyOver_dvdzP; exists q. suffices ->: q = b *: zprimitive p. by rewrite lead_coefZ sgzM sgz_lead_primitive nz_p mulr1; exists b. apply: (@mulfI _ a%:P). by apply: contraNneq nz_p; rewrite Dp -mul_polyC => ->; rewrite mul0r. by rewrite !mul_polyC -Dp scalerA mulrC -Db -zpolyEprim. Qed. Lemma zprimitive_irr p a q : p != 0 -> zprimitive p = a *: q -> a = sgz (lead_coef q). Proof. move=> nz_p Dp; have: p = (a * zcontents p) *: q. by rewrite mulrC -scalerA -Dp -zpolyEprim. case/zprimitive_min=> // b <- /eqP. rewrite Dp -{1}[q]scale1r scalerA -subr_eq0 -scalerBl scale_poly_eq0 subr_eq0. have{Dp} /negPf->: q != 0. by apply: contraNneq nz_p; rewrite -zprimitive_eq0 Dp => ->; rewrite scaler0. by case: b a => [[|[|b]] | [|b]] [[|[|a]] | [|a]] //; rewrite mulr0. Qed. Lemma zcontentsM p q : zcontents (p * q) = zcontents p * zcontents q. Proof. have [-> | nz_p] := eqVneq p 0; first by rewrite !(mul0r, zcontents0). have [-> | nz_q] := eqVneq q 0; first by rewrite !(mulr0, zcontents0). rewrite -[zcontents q]mulr1 {1}[p]zpolyEprim {1}[q]zpolyEprim. rewrite -scalerAl -scalerAr !zcontentsZ; congr (_ * (_ * _)). rewrite [zcontents _]intEsg sgz_contents lead_coefM sgzM !sgz_lead_primitive. apply/eqP; rewrite nz_p nz_q !mul1r [_ == _]eqn_leq absz_gt0 zcontents_eq0. rewrite mulf_neq0 ?zprimitive_eq0 // andbT leqNgt. apply/negP=> /pdivP[r r_pr r_dv_d]; pose to_r : int -> 'F_r := intr. have nz_prim_r q1: q1 != 0 -> map_poly to_r (zprimitive q1) != 0. move=> nz_q1; apply: contraTneq (prime_gt1 r_pr) => r_dv_q1. rewrite -leqNgt dvdn_leq // -(dvdzE r true) -nz_q1 -zcontents_primitive. rewrite dvdz_contents; apply/polyOverP=> i /=; rewrite dvdzE /=. have /polyP/(_ i)/eqP := r_dv_q1; rewrite coef_map coef0 /=. rewrite {1}[_`_i]intEsign rmorphM rmorph_sign /= mulf_eq0 signr_eq0 /=. by rewrite -val_eqE /= val_Fp_nat. suffices{nz_prim_r} /idPn[]: map_poly to_r (zprimitive p * zprimitive q) == 0. by rewrite rmorphM mulf_neq0 ?nz_prim_r. rewrite [_ * _]zpolyEprim [zcontents _]intEsign mulrC -scalerA map_polyZ /=. by rewrite scale_poly_eq0 -val_eqE /= val_Fp_nat ?(eqnP r_dv_d). Qed. Lemma zprimitiveM p q : zprimitive (p * q) = zprimitive p * zprimitive q. Proof. have [pq_0|] := eqVneq (p * q) 0. rewrite pq_0; move/eqP: pq_0; rewrite mulf_eq0. by case/pred2P=> ->; rewrite !zprimitive0 (mul0r, mulr0). rewrite -zcontents_eq0 -polyC_eq0 => /mulfI; apply; rewrite !mul_polyC. by rewrite -zpolyEprim zcontentsM -scalerA scalerAr scalerAl -!zpolyEprim. Qed. Lemma dvdpP_int p q : p %| q -> {r | q = zprimitive p * r}. Proof. case/Pdiv.Idomain.dvdpP/sig2_eqW=> [[c r] /= nz_c Dpr]. exists (zcontents q *: zprimitive r); rewrite -scalerAr. by rewrite -zprimitiveM mulrC -Dpr zprimitiveZ // -zpolyEprim. Qed. Local Notation pZtoQ := (map_poly (intr : int -> rat)). Lemma size_rat_int_poly p : size (pZtoQ p) = size p. Proof. by apply: size_map_inj_poly; first exact: intr_inj. Qed. Lemma rat_poly_scale (p : {poly rat}) : {q : {poly int} & {a | a != 0 & p = a%:~R^-1 *: pZtoQ q}}. Proof. pose a := \prod_(i < size p) denq p`_i. have nz_a: a != 0 by apply/prodf_neq0=> i _; exact: denq_neq0. exists (map_poly numq (a%:~R *: p)), a => //. apply: canRL (scalerK _) _; rewrite ?intr_eq0 //. apply/polyP=> i; rewrite !(coefZ, coef_map_id0) // numqK // Qint_def mulrC. have [ltip | /(nth_default 0)->] := ltnP i (size p); last by rewrite mul0r. by rewrite [a](bigD1 (Ordinal ltip)) // rmorphM mulrA -numqE -rmorphM denq_int. Qed. Lemma dvdp_rat_int p q : (pZtoQ p %| pZtoQ q) = (p %| q). Proof. apply/dvdpP/Pdiv.Idomain.dvdpP=> [[/= r1 Dq] | [[/= a r] nz_a Dq]]; last first. exists (a%:~R^-1 *: pZtoQ r); rewrite -scalerAl -rmorphM -Dq. by rewrite -{2}[a]intz scaler_int rmorphMz -scaler_int scalerK ?intr_eq0. have [r [a nz_a Dr1]] := rat_poly_scale r1; exists (a, r) => //=. apply: (map_inj_poly _ _ : injective pZtoQ) => //; first exact: intr_inj. rewrite -[a]intz scaler_int rmorphMz -scaler_int /= Dq Dr1. by rewrite -scalerAl -rmorphM scalerKV ?intr_eq0. Qed. Lemma dvdpP_rat_int p q : p %| pZtoQ q -> {p1 : {poly int} & {a | a != 0 & p = a *: pZtoQ p1} & {r | q = p1 * r}}. Proof. have{p} [p [a nz_a ->]] := rat_poly_scale p. rewrite dvdp_scalel ?invr_eq0 ?intr_eq0 // dvdp_rat_int => dv_p_q. exists (zprimitive p); last exact: dvdpP_int. have [-> | nz_p] := eqVneq p 0. by exists 1; rewrite ?oner_eq0 // zprimitive0 map_poly0 !scaler0. exists ((zcontents p)%:~R / a%:~R). by rewrite mulf_neq0 ?invr_eq0 ?intr_eq0 ?zcontents_eq0. by rewrite mulrC -scalerA -map_polyZ -zpolyEprim. Qed. End ZpolyScale. (* Integral spans. *) Lemma int_Smith_normal_form m n (M : 'M[int]_(m, n)) : {L : 'M[int]_m & L \in unitmx & {R : 'M[int]_n & R \in unitmx & {d : seq int | sorted dvdz d & M = L *m (\matrix_(i, j) (d`_i *+ (i == j :> nat))) *m R}}}. Proof. move: {2}_.+1 (ltnSn (m + n)) => mn. elim: mn => // mn IHmn in m n M *; rewrite ltnS => le_mn. have [[i j] nzMij | no_ij] := pickP (fun k => M k.1 k.2 != 0%N); last first. do 2![exists 1%:M; first exact: unitmx1]; exists nil => //=. apply/matrixP=> i j; apply/eqP; rewrite mulmx1 mul1mx mxE nth_nil mul0rn. exact: negbFE (no_ij (i, j)). do [case: m i => [[]//|m] i; case: n j => [[]//|n] j /=] in M nzMij le_mn *. wlog Dj: j M nzMij / j = 0; last rewrite {j}Dj in nzMij. case/(_ 0 (xcol j 0 M)); rewrite ?mxE ?tpermR // => L uL [R uR [d dvD dM]]. exists L => //; exists (xcol j 0 R); last exists d => //=. by rewrite xcolE unitmx_mul uR unitmx_perm. by rewrite xcolE !mulmxA -dM xcolE -mulmxA -perm_mxM tperm2 perm_mx1 mulmx1. move Da: (M i 0) nzMij => a nz_a. elim: {a}_.+1 {-2}a (ltnSn `|a|) => // A IHa a leA in m n M i Da nz_a le_mn *. wlog [j a'Mij]: m n M i Da le_mn / {j | ~~ (a %| M i j)%Z}; last first. have nz_j: j != 0 by apply: contraNneq a'Mij => ->; rewrite Da. case: n => [[[]//]|n] in j le_mn nz_j M a'Mij Da *. wlog{nz_j} Dj: j M a'Mij Da / j = 1; last rewrite {j}Dj in a'Mij. case/(_ 1 (xcol j 1 M)); rewrite ?mxE ?tpermR ?tpermD //. move=> L uL [R uR [d dvD dM]]; exists L => //. exists (xcol j 1 R); first by rewrite xcolE unitmx_mul uR unitmx_perm. exists d; rewrite //= xcolE !mulmxA -dM xcolE -mulmxA -perm_mxM tperm2. by rewrite perm_mx1 mulmx1. have [u [v]] := Bezoutz a (M i 1); set b := gcdz _ _ => Db. have{leA} ltA: (`|b| < A)%N. rewrite -ltnS (leq_trans _ leA) // ltnS ltn_neqAle andbC. rewrite dvdn_leq ?absz_gt0 ? dvdn_gcdl //=. by rewrite (contraNneq _ a'Mij) ?dvdzE // => <-; exact: dvdn_gcdr. pose t2 := [fun j : 'I_2 => [tuple _; _]`_j : int]; pose a1 := M i 1. pose Uul := \matrix_(k, j) t2 (t2 u (- (a1 %/ b)%Z) j) (t2 v (a %/ b)%Z j) k. pose U : 'M_(2 + n) := block_mx Uul 0 0 1%:M; pose M1 := M *m U. have{nz_a} nz_b: b != 0 by rewrite gcdz_eq0 (negPf nz_a). have uU: U \in unitmx. rewrite unitmxE det_ublock det1 (expand_det_col _ 0) big_ord_recl big_ord1. do 2!rewrite /cofactor [row' _ _]mx11_scalar !mxE det_scalar1 /=. rewrite mulr1 mul1r mulN1r opprK -[_ + _](mulzK _ nz_b) mulrDl. by rewrite -!mulrA !divzK ?dvdz_gcdl ?dvdz_gcdr // Db divzz nz_b unitr1. have{Db} Db: M1 i 0 = b. rewrite /M1 -(lshift0 n 1) [U]block_mxEh mul_mx_row row_mxEl. rewrite -[M](@hsubmxK _ _ 2) (@mul_row_col _ _ 2) mulmx0 addr0 !mxE /=. rewrite big_ord_recl big_ord1 !mxE /= [lshift _ _]((_ =P 0) _) // Da. by rewrite [lshift _ _]((_ =P 1) _) // mulrC -(mulrC v). have [L uL [R uR [d dvD dM1]]] := IHa b ltA _ _ M1 i Db nz_b le_mn. exists L => //; exists (R *m invmx U); last exists d => //. by rewrite unitmx_mul uR unitmx_inv. by rewrite mulmxA -dM1 mulmxK. move=> {A leA IHa} IHa; wlog Di: i M Da / i = 0; last rewrite {i}Di in Da. case/(_ 0 (xrow i 0 M)); rewrite ?mxE ?tpermR // => L uL [R uR [d dvD dM]]. exists (xrow i 0 L); first by rewrite xrowE unitmx_mul unitmx_perm. exists R => //; exists d; rewrite //= xrowE -!mulmxA (mulmxA L) -dM xrowE. by rewrite mulmxA -perm_mxM tperm2 perm_mx1 mul1mx. without loss /forallP a_dvM0: / [forall j, a %| M 0 j]%Z. have [_|] := altP forallP; first exact; rewrite negb_forall => /existsP/sigW. by move/IHa=> IH _; apply: IH. without loss{Da a_dvM0} Da: M / forall j, M 0 j = a. pose Uur := col' 0 (\row_j (1 - (M 0 j %/ a)%Z)). pose U : 'M_(1 + n) := block_mx 1 Uur 0 1%:M; pose M1 := M *m U. have uU: U \in unitmx by rewrite unitmxE det_ublock !det1 mulr1. case/(_ (M *m U)) => [j | L uL [R uR [d dvD dM]]]. rewrite -(lshift0 m 0) -[M](@submxK _ 1 _ 1) (@mulmx_block _ 1 m 1). rewrite (@col_mxEu _ 1) !mulmx1 mulmx0 addr0 [ulsubmx _]mx11_scalar. rewrite mul_scalar_mx !mxE !lshift0 Da. case: splitP => [j0 _ | j1 Dj]; rewrite ?ord1 !mxE // lshift0 rshift1. by rewrite mulrBr mulr1 mulrC divzK ?subrK. exists L => //; exists (R * U^-1); first by rewrite unitmx_mul uR unitmx_inv. by exists d; rewrite //= mulmxA -dM mulmxK. without loss{IHa} /forallP/(_ (_, _))/= a_dvM: / [forall k, a %| M k.1 k.2]%Z. have [_|] := altP forallP; first exact; rewrite negb_forall => /existsP/sigW. case=> [[i j] /= a'Mij] _. have [|||L uL [R uR [d dvD dM]]] := IHa _ _ M^T j; rewrite ?mxE 1?addnC //. by exists i; rewrite mxE. exists R^T; last exists L^T; rewrite ?unitmx_tr //; exists d => //. rewrite -[M]trmxK dM !trmx_mul mulmxA; congr (_ *m _ *m _). by apply/matrixP=> i1 j1; rewrite !mxE eq_sym; case: eqP => // ->. without loss{nz_a a_dvM} a1: M a Da / a = 1. pose M1 := map_mx (divz^~ a) M; case/(_ M1 1)=> // [k|L uL [R uR [d dvD dM]]]. by rewrite !mxE Da divzz nz_a. exists L => //; exists R => //; exists [seq a * x | x <- d]. case: d dvD {dM} => //= x d; elim: d x => //= y d IHd x /andP[dv_xy /IHd]. by rewrite [dvdz _ _]dvdz_mul2l ?[_ \in _]dv_xy. have ->: M = a *: M1 by apply/matrixP=> i j; rewrite !mxE mulrC divzK ?a_dvM. rewrite dM scalemxAl scalemxAr; congr (_ *m _ *m _). apply/matrixP=> i j; rewrite !mxE mulrnAr; congr (_ *+ _). have [lt_i_d | le_d_i] := ltnP i (size d); first by rewrite (nth_map 0). by rewrite !nth_default ?size_map ?mulr0. rewrite {a}a1 -[m.+1]/(1 + m)%N -[n.+1]/(1 + n)%N in M Da *. pose Mu := ursubmx M; pose Ml := dlsubmx M. have{Da} Da: ulsubmx M = 1 by rewrite [_ M]mx11_scalar !mxE !lshift0 Da. pose M1 := - (Ml *m Mu) + drsubmx M. have [|L uL [R uR [d dvD dM1]]] := IHmn m n M1; first by rewrite -addnS ltnW. exists (block_mx 1 0 Ml L). by rewrite unitmxE det_lblock det_scalar1 mul1r. exists (block_mx 1 Mu 0 R). by rewrite unitmxE det_ublock det_scalar1 mul1r. exists (1 :: d); set D1 := \matrix_(i, j) _ in dM1. by rewrite /= path_min_sorted // => g _; exact: dvd1n. rewrite [D in _ *m D *m _](_ : _ = block_mx 1 0 0 D1); last first. by apply/matrixP=> i j; do 3?[rewrite ?mxE ?ord1 //=; case: splitP => ? ->]. rewrite !mulmx_block !(mul0mx, mulmx0, addr0) !mulmx1 add0r mul1mx -Da -dM1. by rewrite addNKr submxK. Qed. Definition inIntSpan (V : zmodType) m (s : m.-tuple V) v := exists a : int ^ m, v = \sum_(i < m) s`_i *~ a i. Lemma dec_Qint_span (vT : vectType rat) m (s : m.-tuple vT) v : decidable (inIntSpan s v). Proof. have s_s (i : 'I_m): s`_i \in <>%VS by rewrite memv_span ?memt_nth. have s_Zs a: \sum_(i < m) s`_i *~ a i \in <>%VS. by rewrite memv_suml // => i _; rewrite -scaler_int memvZ. case s_v: (v \in <>%VS); last by right=> [[a Dv]]; rewrite Dv s_Zs in s_v. pose S := \matrix_(i < m, j < _) coord (vbasis <>) j s`_i. pose r := \rank S; pose k := (m - r)%N; pose Em := erefl m; pose Ek := erefl k. have Dm: (m = k + r)%N by rewrite subnK ?rank_leq_row. have [K kerK]: {K : 'M_(k, m) | map_mx intr K == kermx S}%MS. pose B := row_base (kermx S); pose d := \prod_ij denq (B ij.1 ij.2). exists (castmx (mxrank_ker S, Em) (map_mx numq (intr d *: B))). rewrite /k; case: _ / (mxrank_ker S); set B1 := map_mx _ _. have ->: B1 = (intr d *: B). apply/matrixP=> i j; rewrite 3!mxE mulrC [d](bigD1 (i, j)) // rmorphM mulrA. by rewrite -numqE -rmorphM numq_int. suffices nz_d: d%:Q != 0 by rewrite !eqmx_scale // !eq_row_base andbb. by rewrite intr_eq0; apply/prodf_neq0 => i _; exact: denq_neq0. have [L _ [G uG [D _ defK]]] := int_Smith_normal_form K. pose Gud := castmx (Dm, Em) G; pose G'lr := castmx (Em, Dm) (invmx G). have{K L D defK kerK} kerGu: map_mx intr (usubmx Gud) *m S = 0. pose Kl : 'M[rat]_k:= map_mx intr (lsubmx (castmx (Ek, Dm) (K *m invmx G))). have{defK} defK: map_mx intr K = row_mx Kl 0 *m map_mx intr Gud. rewrite -[K](mulmxKV uG) -{2}[G](castmxK Dm Em) -/Gud. rewrite -[K *m _](castmxK Ek Dm) map_mxM map_castmx. rewrite -(hsubmxK (castmx _ _)) map_row_mx -/Kl map_castmx /Em. set Kr := map_mx _ _; case: _ / (esym Dm) (map_mx _ _) => /= GudQ. congr (row_mx _ _ *m _); apply/matrixP=> i j; rewrite !mxE defK mulmxK //=. rewrite castmxE mxE big1 //= => j1 _; rewrite mxE /= eqn_leq andbC. by rewrite leqNgt (leq_trans (valP j1)) ?mulr0 ?leq_addr. have /row_full_inj: row_full Kl; last apply. rewrite /row_full eqn_leq rank_leq_row /= -{1}[k](mxrank_ker S). rewrite -(eqmxP kerK) defK map_castmx mxrankMfree; last first. case: _ / (Dm); apply/row_freeP; exists (map_mx intr (invmx G)). by rewrite -map_mxM mulmxV ?map_mx1. by rewrite -mxrank_tr tr_row_mx trmx0 -addsmxE addsmx0 mxrank_tr. rewrite mulmx0 mulmxA (sub_kermxP _) // -(eqmxP kerK) defK. by rewrite -{2}[Gud]vsubmxK map_col_mx mul_row_col mul0mx addr0. pose T := map_mx intr (dsubmx Gud) *m S. have{kerGu} defS: map_mx intr (rsubmx G'lr) *m T = S. have: G'lr *m Gud = 1%:M by rewrite /G'lr /Gud; case: _ / (Dm); exact: mulVmx. rewrite -{1}[G'lr]hsubmxK -[Gud]vsubmxK mulmxA mul_row_col -map_mxM. move/(canRL (addKr _))->; rewrite -mulNmx raddfD /= map_mx1 map_mxM /=. by rewrite mulmxDl -mulmxA kerGu mulmx0 add0r mul1mx. pose vv := \row_j coord (vbasis <>) j v. have uS: row_full S. apply/row_fullP; exists (\matrix_(i, j) coord s j (vbasis <>)`_i). apply/matrixP=> j1 j2; rewrite !mxE. rewrite -(coord_free _ _ (basis_free (vbasisP _))). rewrite -!tnth_nth (coord_span (vbasis_mem (mem_tnth j1 _))) linear_sum. by apply: eq_bigr => i _; rewrite !mxE (tnth_nth 0) !linearZ. have eqST: (S :=: T)%MS by apply/eqmxP; rewrite -{1}defS !submxMl. case Zv: (map_mx denq (vv *m pinvmx T) == const_mx 1). pose a := map_mx numq (vv *m pinvmx T) *m dsubmx Gud. left; exists [ffun j => a 0 j]. transitivity (\sum_j (map_mx intr a *m S) 0 j *: (vbasis <>)`_j). rewrite {1}(coord_vbasis s_v); apply: eq_bigr => j _; congr (_ *: _). have ->: map_mx intr a = vv *m pinvmx T *m map_mx intr (dsubmx Gud). rewrite map_mxM /=; congr (_ *m _); apply/rowP=> i; rewrite 2!mxE numqE. by have /eqP/rowP/(_ i) := Zv; rewrite !mxE => ->; rewrite mulr1. by rewrite -(mulmxA _ _ S) mulmxKpV ?mxE // -eqST submx_full. rewrite (coord_vbasis (s_Zs _)); apply: eq_bigr => j _; congr (_ *: _). rewrite linear_sum mxE; apply: eq_bigr => i _. by rewrite -scaler_int linearZ [a]lock !mxE ffunE. right=> [[a Dv]]; case/eqP: Zv; apply/rowP. have ->: vv = map_mx intr (\row_i a i) *m S. apply/rowP=> j; rewrite !mxE Dv linear_sum. by apply: eq_bigr => i _; rewrite -scaler_int linearZ !mxE. rewrite -defS -2!mulmxA; have ->: T *m pinvmx T = 1%:M. have uT: row_free T by rewrite /row_free -eqST. by apply: (row_free_inj uT); rewrite mul1mx mulmxKpV. by move=> i; rewrite mulmx1 -map_mxM 2!mxE denq_int mxE. Qed. mathcomp-1.5/theories/ssrint.v0000644000175000017500000016057212307636117015527 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat choice seq. Require Import fintype finfun bigop ssralg ssrnum poly. Import GRing.Theory Num.Theory. (******************************************************************************) (* This file develops a basic theory of signed integers, defining: *) (* int == the type of signed integers, with two constructors Posz for *) (* non-negative integers and Negz for negative integers. It *) (* supports the realDomainType interface (and its parents). *) (* n%:Z == explicit cast from nat to int (:= Posz n); displayed as n. *) (* However (Posz m = Posz n) is displayed as (m = n :> int) *) (* (and so are ==, != and <>) *) (* Lemma NegzE : turns (Negz n) into - n.+1%:Z. *) (* x *~ m == m times x, with m : int; *) (* convertible to x *+ n if m is Posz n *) (* convertible to x *- n.+1 if m is Negz n. *) (* m%:~R == the image of m : int in a generic ring (:= 1 *~ m). *) (* x ^ m == x to the m, with m : int; *) (* convertible to x ^+ n if m is Posz n *) (* convertible to x ^- n.+1 if m is Negz n. *) (* sgz x == sign of x : R, *) (* equals (0 : int) if and only x == 0, *) (* equals (1 : int) if x is positive *) (* and (-1 : int) otherwise. *) (* `|m|%N == the n : nat such that `|m|%R = n%:Z, for m : int. *) (* `|m - n|%N == the distance between m and n; the '-' is specialized to *) (* the int type, so m and n can be either of type nat or int *) (* thanks to the Posz coercion; m and n are however parsed in *) (* the %N scope. The IntDist submodule provides this notation *) (* and the corresponding theory independently of the rest of *) (* of the int and ssralg libraries (and notations). *) (* Warning: due to the declaration of Posz as a coercion, two terms might be *) (* displayed the same while not being convertible, for instance: *) (* (Posz (x - y)) and (Posz x) - (Posz y) for x, y : nat. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Delimit Scope int_scope with Z. Local Open Scope int_scope. (* Defining int *) CoInductive int : Set := Posz of nat | Negz of nat. (* This must be deferred to module DistInt to work around the design flaws of *) (* the Coq module system. *) (* Coercion Posz : nat >-> int. *) Notation "n %:Z" := (Posz n) (at level 2, left associativity, format "n %:Z", only parsing) : int_scope. Notation "n %:Z" := (Posz n) (at level 2, left associativity, format "n %:Z", only parsing) : ring_scope. Notation "n = m :> 'in' 't'" := (Posz n = Posz m) (at level 70, m at next level, format "n = m :> 'in' 't'") : ring_scope. Notation "n == m :> 'in' 't'" := (Posz n == Posz m) (at level 70, m at next level, format "n == m :> 'in' 't'") : ring_scope. Notation "n != m :> 'in' 't'" := (Posz n != Posz m) (at level 70, m at next level, format "n != m :> 'in' 't'") : ring_scope. Notation "n <> m :> 'in' 't'" := (Posz n <> Posz m) (at level 70, m at next level, format "n <> m :> 'in' 't'") : ring_scope. Definition natsum_of_int (m : int) : nat + nat := match m with Posz p => inl _ p | Negz n => inr _ n end. Definition int_of_natsum (m : nat + nat) := match m with inl p => Posz p | inr n => Negz n end. Lemma natsum_of_intK : cancel natsum_of_int int_of_natsum. Proof. by case. Qed. Definition int_eqMixin := CanEqMixin natsum_of_intK. Definition int_countMixin := CanCountMixin natsum_of_intK. Definition int_choiceMixin := CountChoiceMixin int_countMixin. Canonical int_eqType := Eval hnf in EqType int int_eqMixin. Canonical int_choiceType := Eval hnf in ChoiceType int int_choiceMixin. Canonical int_countType := Eval hnf in CountType int int_countMixin. Lemma eqz_nat (m n : nat) : (m%:Z == n%:Z) = (m == n). Proof. by []. Qed. Module intZmod. Section intZmod. Definition addz (m n : int) := match m, n with | Posz m', Posz n' => Posz (m' + n') | Negz m', Negz n' => Negz (m' + n').+1 | Posz m', Negz n' => if n' < m' then Posz (m' - n'.+1) else Negz (n' - m') | Negz n', Posz m' => if n' < m' then Posz (m' - n'.+1) else Negz (n' - m') end. Definition oppz m := nosimpl match m with | Posz n => if n is (n'.+1)%N then Negz n' else Posz 0 | Negz n => Posz (n.+1)%N end. Local Notation "0" := (Posz 0) : int_scope. Local Notation "-%Z" := (@oppz) : int_scope. Local Notation "- x" := (oppz x) : int_scope. Local Notation "+%Z" := (@addz) : int_scope. Local Notation "x + y" := (addz x y) : int_scope. Local Notation "x - y" := (x + - y) : int_scope. Lemma PoszD : {morph Posz : m n / (m + n)%N >-> m + n}. Proof. by []. Qed. Local Coercion Posz : nat >-> int. Lemma NegzE (n : nat) : Negz n = - n.+1. Proof. by []. Qed. Lemma int_rect (P : int -> Type) : P 0 -> (forall n : nat, P n -> P (n.+1)) -> (forall n : nat, P (- n) -> P (- (n.+1))) -> forall n : int, P n. Proof. by move=> P0 hPp hPn []; elim=> [|n ihn]//; do? [apply: hPn | apply: hPp]. Qed. Definition int_rec := int_rect. Definition int_ind := int_rect. CoInductive int_spec (x : int) : int -> Type := | ZintNull of x = 0 : int_spec x 0 | ZintPos n of x = n.+1 : int_spec x n.+1 | ZintNeg n of x = - (n.+1)%:Z : int_spec x (- n.+1). Lemma intP x : int_spec x x. Proof. by move: x=> [] []; constructor. Qed. Lemma addzC : commutative addz. Proof. by move=> [] m [] n //=; rewrite addnC. Qed. Lemma add0z : left_id 0 addz. Proof. by move=> [] [|]. Qed. Lemma oppzK : involutive oppz. Proof. by do 2?case. Qed. Lemma oppz_add : {morph oppz : m n / m + n}. Proof. move=> [[|n]|n] [[|m]|m] /=; rewrite ?NegzE ?oppzK ?addnS ?addn0 ?subn0 //; rewrite ?ltnS[m <= n]leqNgt [n <= m]leqNgt; case: ltngtP=> hmn /=; by rewrite ?hmn ?subnn // ?oppzK ?subSS ?subnS ?prednK // ?subn_gt0. Qed. Lemma add1Pz (n : int) : 1 + (n - 1) = n. Proof. by case: (intP n)=> // n' /= _; rewrite ?(subn1, addn0). Qed. Lemma subSz1 (n : int) : 1 + n - 1 = n. Proof. by apply: (inv_inj oppzK); rewrite addzC !oppz_add oppzK [_ - n]addzC add1Pz. Qed. Lemma addSnz (m : nat) (n : int) : (m.+1%N) + n = 1 + (m + n). Proof. move: m n=> [|m] [] [|n] //=; rewrite ?add1n ?subn1 // !(ltnS, subSS). rewrite [n <= m]leqNgt; case: ltngtP=> hmn /=; rewrite ?hmn ?subnn //. by rewrite subnS add1n prednK ?subn_gt0. by rewrite ltnS leqn0 subn_eq0 leqNgt hmn /= subnS subn1. Qed. Lemma addSz (m n : int) : (1 + m) + n = 1 + (m + n). Proof. case: m => [] m; first by rewrite -PoszD add1n addSnz. rewrite !NegzE; apply: (inv_inj oppzK). rewrite !oppz_add !oppzK addSnz [-1%:Z + _]addzC addSnz add1Pz. by rewrite [-1%:Z + _]addzC subSz1. Qed. Lemma addPz (m n : int) : (m - 1) + n = (m + n) - 1. Proof. by apply: (inv_inj oppzK); rewrite !oppz_add oppzK [_ + 1]addzC addSz addzC. Qed. Lemma addzA : associative addz. Proof. elim=> [|m ihm|m ihm] n p; first by rewrite !add0z. by rewrite -add1n PoszD !addSz ihm. by rewrite -add1n addnC PoszD oppz_add !addPz ihm. Qed. Lemma addNz : left_inverse (0:int) oppz addz. Proof. by do 3?elim. Qed. Lemma predn_int (n : nat) : 0 < n -> n.-1%:Z = n - 1. Proof. by case: n=> // n _ /=; rewrite subn1. Qed. Definition Mixin := ZmodMixin addzA addzC add0z addNz. End intZmod. End intZmod. Canonical int_ZmodType := ZmodType int intZmod.Mixin. Local Open Scope ring_scope. Section intZmoduleTheory. Local Coercion Posz : nat >-> int. Lemma PoszD : {morph Posz : n m / (n + m)%N >-> n + m}. Proof. by []. Qed. Lemma NegzE (n : nat) : Negz n = -(n.+1)%:Z. Proof. by []. Qed. Lemma int_rect (P : int -> Type) : P 0 -> (forall n : nat, P n -> P (n.+1)%N) -> (forall n : nat, P (- (n%:Z)) -> P (- (n.+1%N%:Z))) -> forall n : int, P n. Proof. by move=> P0 hPp hPn []; elim=> [|n ihn]//; do? [apply: hPn | apply: hPp]. Qed. Definition int_rec := int_rect. Definition int_ind := int_rect. CoInductive int_spec (x : int) : int -> Type := | ZintNull : int_spec x 0 | ZintPos n : int_spec x n.+1 | ZintNeg n : int_spec x (- (n.+1)%:Z). Lemma intP x : int_spec x x. Proof. by move: x=> [] [] *; rewrite ?NegzE; constructor. Qed. Definition oppz_add := (@opprD [zmodType of int]). Lemma subzn (m n : nat) : (n <= m)%N -> m%:Z - n%:Z = (m - n)%N. Proof. elim: n=> //= [|n ihn] hmn; first by rewrite subr0 subn0. rewrite subnS -addn1 !PoszD opprD addrA ihn 1?ltnW //. by rewrite intZmod.predn_int // subn_gt0. Qed. Lemma subzSS (m n : nat) : m.+1%:Z - n.+1%:Z = m%:Z - n%:Z. Proof. by elim: n m=> [|n ihn] m //; rewrite !subzn. Qed. End intZmoduleTheory. Module intRing. Section intRing. Local Coercion Posz : nat >-> int. Definition mulz (m n : int) := match m, n with | Posz m', Posz n' => (m' * n')%N%:Z | Negz m', Negz n' => (m'.+1%N * n'.+1%N)%N%:Z | Posz m', Negz n' => - (m' * (n'.+1%N))%N%:Z | Negz n', Posz m' => - (m' * (n'.+1%N))%N%:Z end. Local Notation "1" := (1%N:int) : int_scope. Local Notation "*%Z" := (@mulz) : int_scope. Local Notation "x * y" := (mulz x y) : int_scope. Lemma mul0z : left_zero 0 *%Z. Proof. by case=> [n|[|n]] //=; rewrite muln0. Qed. Lemma mulzC : commutative mulz. Proof. by move=> [] m [] n //=; rewrite mulnC. Qed. Lemma mulz0 : right_zero 0 *%Z. Proof. by move=> x; rewrite mulzC mul0z. Qed. Lemma mulzN (m n : int) : (m * (- n))%Z = - (m * n)%Z. Proof. by case: (intP m)=> {m} [|m|m]; rewrite ?mul0z //; case: (intP n)=> {n} [|n|n]; rewrite ?mulz0 //= mulnC. Qed. Lemma mulNz (m n : int) : ((- m) * n)%Z = - (m * n)%Z. Proof. by rewrite mulzC mulzN mulzC. Qed. Lemma mulzA : associative mulz. Proof. by move=> [] m [] n [] p; rewrite ?NegzE ?(mulnA,mulNz,mulzN,opprK) //= ?mulnA. Qed. Lemma mul1z : left_id 1%Z mulz. Proof. by case=> [[|n]|n] //=; rewrite ?mul1n// plusE addn0. Qed. Lemma mulzS (x : int) (n : nat) : (x * n.+1%:Z)%Z = x + (x * n)%Z. Proof. by case: (intP x)=> [|m'|m'] //=; [rewrite mulnS|rewrite mulSn -opprD]. Qed. Lemma mulz_addl : left_distributive mulz (+%R). Proof. move=> x y z; elim: z=> [|n|n]; first by rewrite !(mul0z,mulzC). by rewrite !mulzS=> ->; rewrite !addrA [X in X + _]addrAC. rewrite !mulzN !mulzS -!opprD=> /(inv_inj (@opprK _))->. by rewrite !addrA [X in X + _]addrAC. Qed. Lemma nonzero1z : 1%Z != 0. Proof. by []. Qed. Definition comMixin := ComRingMixin mulzA mulzC mul1z mulz_addl nonzero1z. End intRing. End intRing. Canonical int_Ring := Eval hnf in RingType int intRing.comMixin. Canonical int_comRing := Eval hnf in ComRingType int intRing.mulzC. Section intRingTheory. Implicit Types m n : int. Local Coercion Posz : nat >-> int. Lemma PoszM : {morph Posz : n m / (n * m)%N >-> n * m}. Proof. by []. Qed. Lemma intS (n : nat) : n.+1%:Z = 1 + n%:Z. Proof. by rewrite -PoszD. Qed. Lemma predn_int (n : nat) : (0 < n)%N -> n.-1%:Z = n%:Z - 1. Proof. exact: intZmod.predn_int. Qed. End intRingTheory. Module intUnitRing. Section intUnitRing. Implicit Types m n : int. Local Coercion Posz : nat >-> int. Definition unitz := [qualify a n : int | (n == 1) || (n == -1)]. Definition invz n : int := n. Lemma mulVz : {in unitz, left_inverse 1%R invz *%R}. Proof. by move=> n /pred2P[] ->. Qed. Lemma mulzn_eq1 m (n : nat) : (m * n == 1) = (m == 1) && (n == 1%N). Proof. by case: m=> m /=; [rewrite -PoszM [_==_]muln_eq1 | case: n]. Qed. Lemma unitzPl m n : n * m = 1 -> m \is a unitz. Proof. case: m => m; move/eqP; rewrite qualifE. * by rewrite mulzn_eq1; case/andP=> _; move/eqP->. * by rewrite NegzE intS mulrN -mulNr mulzn_eq1; case/andP=> _. Qed. Lemma invz_out : {in [predC unitz], invz =1 id}. Proof. exact. Qed. Lemma idomain_axiomz m n : m * n = 0 -> (m == 0) || (n == 0). Proof. by case: m n => m [] n //=; move/eqP; rewrite ?(NegzE,mulrN,mulNr); rewrite ?(inv_eq (@opprK _)) -PoszM [_==_]muln_eq0. Qed. Definition comMixin := ComUnitRingMixin mulVz unitzPl invz_out. End intUnitRing. End intUnitRing. Canonical int_unitRingType := Eval hnf in UnitRingType int intUnitRing.comMixin. Canonical int_comUnitRing := Eval hnf in [comUnitRingType of int]. Canonical int_iDomain := Eval hnf in IdomainType int intUnitRing.idomain_axiomz. Definition absz m := match m with Posz p => p | Negz n => n.+1 end. Notation "m - n" := (@GRing.add int_ZmodType m%N (@GRing.opp int_ZmodType n%N)) : distn_scope. Arguments Scope absz [distn_scope]. Local Notation "`| m |" := (absz m) : nat_scope. Module intOrdered. Section intOrdered. Implicit Types m n p : int. Local Coercion Posz : nat >-> int. Local Notation normz m := (absz m)%:Z. Definition lez m n := match m, n with | Posz m', Posz n' => (m' <= n')%N | Posz m', Negz n' => false | Negz m', Posz n' => true | Negz m', Negz n' => (n' <= m')%N end. Definition ltz m n := match m, n with | Posz m', Posz n' => (m' < n')%N | Posz m', Negz n' => false | Negz m', Posz n' => true | Negz m', Negz n' => (n' < m')%N end. Fact lez_norm_add x y : lez (normz (x + y)) (normz x + normz y). Proof. move: x y=> [] m [] n; rewrite /= ?addnS //=; rewrite /GRing.add /GRing.Zmodule.add /=; case: ltnP=> //=; rewrite ?addSn ?ltnS ?leq_subLR ?(addnS, addSn) ?(leq_trans _ (leqnSn _)) //; by rewrite 1?addnCA ?leq_addr ?addnA ?leq_addl. Qed. Fact ltz_add x y : ltz 0 x -> ltz 0 y -> ltz 0 (x + y). Proof. by move: x y => [] x [] y //= hx hy; rewrite ltn_addr. Qed. Fact eq0_normz x : normz x = 0 -> x = 0. Proof. by case: x. Qed. Fact lez_total x y : lez x y || lez y x. Proof. by move: x y => [] x [] y //=; apply: leq_total. Qed. Lemma abszN (n : nat) : absz (- n%:Z) = n. Proof. by case: n. Qed. Fact normzM : {morph (fun n => normz n) : x y / x * y}. Proof. by move=> [] x [] y; rewrite // abszN // mulnC. Qed. Lemma subz_ge0 m n : lez 0 (n - m) = lez m n. Proof. case: (intP m); case: (intP n)=> // {m n} m n /=; rewrite ?ltnS -?opprD ?opprB ?subzSS; case: leqP=> // hmn; by [ rewrite subzn // | rewrite -opprB subzn ?(ltnW hmn) //; move: hmn; rewrite -subn_gt0; case: (_ - _)%N]. Qed. Fact lez_def x y : (lez x y) = (normz (y - x) == y - x). Proof. by rewrite -subz_ge0; move: (_ - _) => [] n //=; rewrite eqxx. Qed. Fact ltz_def x y : (ltz x y) = (y != x) && (lez x y). Proof. by move: x y=> [] x [] y //=; rewrite (ltn_neqAle, leq_eqVlt) // eq_sym. Qed. Definition Mixin := NumMixin lez_norm_add ltz_add eq0_normz (in2W lez_total) normzM lez_def ltz_def. End intOrdered. End intOrdered. Canonical int_numDomainType := NumDomainType int intOrdered.Mixin. Canonical int_realDomainType := RealDomainType int (intOrdered.lez_total 0). Section intOrderedTheory. Local Coercion Posz : nat >-> int. Implicit Types m n p : nat. Implicit Types x y z : int. Lemma lez_nat m n : (m <= n :> int) = (m <= n)%N. Proof. by []. Qed. Lemma ltz_nat m n : (m < n :> int) = (m < n)%N. Proof. by rewrite ltnNge ltrNge lez_nat. Qed. Definition ltez_nat := (lez_nat, ltz_nat). Lemma leNz_nat m n : (- m%:Z <= n). Proof. by case: m. Qed. Lemma ltNz_nat m n : (- m%:Z < n) = (m != 0%N) || (n != 0%N). Proof. by move: m n=> [|?] []. Qed. Definition lteNz_nat := (leNz_nat, ltNz_nat). Lemma lezN_nat m n : (m%:Z <= - n%:Z) = (m == 0%N) && (n == 0%N). Proof. by move: m n=> [|?] []. Qed. Lemma ltzN_nat m n : (m%:Z < - n%:Z) = false. Proof. by move: m n=> [|?] []. Qed. Lemma le0z_nat n : 0 <= n :> int. Proof. by []. Qed. Lemma lez0_nat n : n <= 0 :> int = (n == 0%N :> nat). Proof. by elim: n. Qed. Definition ltezN_nat := (lezN_nat, ltzN_nat). Definition ltez_natE := (ltez_nat, lteNz_nat, ltezN_nat, le0z_nat, lez0_nat). Lemma gtz0_ge1 x : (0 < x) = (1 <= x). Proof. by case: (intP x). Qed. Lemma lez_add1r x y : (1 + x <= y) = (x < y). Proof. by rewrite -subr_gt0 gtz0_ge1 lter_sub_addr. Qed. Lemma lez_addr1 x y : (x + 1 <= y) = (x < y). Proof. by rewrite addrC lez_add1r. Qed. Lemma ltz_add1r x y : (x < 1 + y) = (x <= y). Proof. by rewrite -lez_add1r ler_add2l. Qed. Lemma ltz_addr1 x y : (x < y + 1) = (x <= y). Proof. by rewrite -lez_addr1 ler_add2r. Qed. End intOrderedTheory. Bind Scope ring_scope with int. (* definition of intmul *) Definition intmul (R : zmodType) (x : R) (n : int) := nosimpl match n with | Posz n => (x *+ n)%R | Negz n => (x *- (n.+1))%R end. Notation "*~%R" := (@intmul _) (at level 0, format " *~%R") : ring_scope. Notation "x *~ n" := (intmul x n) (at level 40, left associativity, format "x *~ n") : ring_scope. Notation intr := ( *~%R 1). Notation "n %:~R" := (1 *~ n)%R (at level 2, left associativity, format "n %:~R") : ring_scope. Lemma pmulrn (R : zmodType) (x : R) (n : nat) : x *+ n = x *~ n%:Z. Proof. by []. Qed. Lemma nmulrn (R : zmodType) (x : R) (n : nat) : x *- n = x *~ - n%:Z. Proof. by case: n=> [] //; rewrite ?oppr0. Qed. Section ZintLmod. Definition zmodule (M : Type) : Type := M. Local Notation "M ^z" := (zmodule M) (at level 2, format "M ^z") : type_scope. Local Coercion Posz : nat >-> int. Variable M : zmodType. Implicit Types m n : int. Implicit Types x y z : M. Fact mulrzA_C m n x : (x *~ n) *~ m = x *~ (m * n). Proof. elim: m=> [|m _|m _]; elim: n=> [|n _|n _]; rewrite /intmul //=; rewrite ?(muln0, mulr0n, mul0rn, oppr0, mulNrn, opprK) //; do ?by rewrite mulnC mulrnA. * by rewrite -mulrnA mulnC. * by rewrite -mulrnA. Qed. Fact mulrzAC m n x : (x *~ n) *~ m = (x *~ m) *~ n. Proof. by rewrite !mulrzA_C mulrC. Qed. Fact mulr1z (x : M) : x *~ 1 = x. Proof. by []. Qed. Fact mulrzDr m : {morph ( *~%R^~ m : M -> M) : x y / x + y}. Proof. by elim: m=> [|m _|m _] x y; rewrite ?addr0 /intmul //= ?mulrnDl // opprD. Qed. Lemma mulrzBl_nat (m n : nat) x : x *~ (m%:Z - n%:Z) = x *~ m - x *~ n. Proof. case: (leqP m n)=> hmn; rewrite /intmul //=. rewrite addrC -{1}[m:int]opprK -opprD subzn //. rewrite -{2}[n](@subnKC m)// mulrnDr opprD addrA subrr sub0r. by case hdmn: (_ - _)%N=> [|dmn] /=; first by rewrite mulr0n oppr0. have hnm := ltnW hmn. rewrite -{2}[m](@subnKC n)// mulrnDr addrAC subrr add0r. by rewrite subzn. Qed. Fact mulrzDl x : {morph *~%R x : m n / m + n}. Proof. elim=> [|m _|m _]; elim=> [|n _|n _]; rewrite /intmul //=; rewrite -?(opprD) ?(add0r, addr0, mulrnDr, subn0) //. * by rewrite -/(intmul _ _) mulrzBl_nat. * by rewrite -/(intmul _ _) addrC mulrzBl_nat addrC. * by rewrite -addnS -addSn mulrnDr. Qed. Definition Mint_LmodMixin := @LmodMixin _ [zmodType of M] (fun n x => x *~ n) mulrzA_C mulr1z mulrzDr mulrzDl. Canonical Mint_LmodType := LmodType int M^z Mint_LmodMixin. Lemma scalezrE n x : n *: (x : M^z) = x *~ n. Proof. by []. Qed. Lemma mulrzA x m n : x *~ (m * n) = x *~ m *~ n. Proof. by rewrite -!scalezrE scalerA mulrC. Qed. Lemma mulr0z x : x *~ 0 = 0. Proof. by []. Qed. Lemma mul0rz n : 0 *~ n = 0 :> M. Proof. by rewrite -scalezrE scaler0. Qed. Lemma mulrNz x n : x *~ (- n) = - (x *~ n). Proof. by rewrite -scalezrE scaleNr. Qed. Lemma mulrN1z x : x *~ (- 1) = - x. Proof. by rewrite -scalezrE scaleN1r. Qed. Lemma mulNrz x n : (- x) *~ n = - (x *~ n). Proof. by rewrite -scalezrE scalerN. Qed. Lemma mulrzBr x m n : x *~ (m - n) = x *~ m - x *~ n. Proof. by rewrite -scalezrE scalerBl. Qed. Lemma mulrzBl x y n : (x - y) *~ n = x *~ n - y *~ n. Proof. by rewrite -scalezrE scalerBr. Qed. Lemma mulrz_nat (n : nat) x : x *~ n%:R = x *+ n. Proof. by rewrite -scalezrE scaler_nat. Qed. Lemma mulrz_sumr : forall x I r (P : pred I) F, x *~ (\sum_(i <- r | P i) F i) = \sum_(i <- r | P i) x *~ F i. Proof. by rewrite -/M^z; exact: scaler_suml. Qed. Lemma mulrz_suml : forall n I r (P : pred I) (F : I -> M), (\sum_(i <- r | P i) F i) *~ n= \sum_(i <- r | P i) F i *~ n. Proof. by rewrite -/M^z; exact: scaler_sumr. Qed. Canonical intmul_additive x := Additive (@mulrzBr x). End ZintLmod. Lemma ffunMzE (I : finType) (M : zmodType) (f : {ffun I -> M}) z x : (f *~ z) x = f x *~ z. Proof. by case: z => n; rewrite ?ffunE ffunMnE. Qed. Lemma intz (n : int) : n%:~R = n. Proof. elim: n=> //= n ihn; rewrite /intmul /=. by rewrite -addn1 mulrnDr /= PoszD -ihn. by rewrite nmulrn intS opprD mulrzDl ihn. Qed. Lemma natz (n : nat) : n%:R = n%:Z :> int. Proof. by rewrite pmulrn intz. Qed. Section RintMod. Local Coercion Posz : nat >-> int. Variable R : ringType. Implicit Types m n : int. Implicit Types x y z : R. Lemma mulrzAl n x y : (x *~ n) * y = (x * y) *~ n. Proof. by elim: n=> //= *; rewrite ?mul0r ?mulr0z // /intmul /= -mulrnAl -?mulNr. Qed. Lemma mulrzAr n x y : x * (y *~ n) = (x * y) *~ n. Proof. by elim: n=> //= *; rewrite ?mulr0 ?mulr0z // /intmul /= -mulrnAr -?mulrN. Qed. Lemma mulrzl x n : n%:~R * x = x *~ n. Proof. by rewrite mulrzAl mul1r. Qed. Lemma mulrzr x n : x * n%:~R = x *~ n. Proof. by rewrite mulrzAr mulr1. Qed. Lemma mulNrNz n x : (-x) *~ (-n) = x *~ n. Proof. by rewrite mulNrz mulrNz opprK. Qed. Lemma mulrbz x (b : bool) : x *~ b = (if b then x else 0). Proof. by case: b. Qed. Lemma intrD m n : (m + n)%:~R = m%:~R + n%:~R :> R. Proof. exact: mulrzDl. Qed. Lemma intrM m n : (m * n)%:~R = m%:~R * n%:~R :> R. Proof. by rewrite mulrzA -mulrzr. Qed. Lemma intmul1_is_rmorphism : rmorphism ( *~%R (1 : R)). Proof. by do ?split; move=> // x y /=; rewrite ?intrD ?mulrNz ?intrM. Qed. Canonical intmul1_rmorphism := RMorphism intmul1_is_rmorphism. Lemma mulr2z n : n *~ 2 = n + n. Proof. exact: mulr2n. Qed. End RintMod. Lemma mulrzz m n : m *~ n = m * n. Proof. by rewrite -mulrzr intz. Qed. Lemma mulz2 n : n * 2%:Z = n + n. Proof. by rewrite -mulrzz. Qed. Lemma mul2z n : 2%:Z * n = n + n. Proof. by rewrite mulrC -mulrzz. Qed. Section LMod. Variable R : ringType. Variable V : (lmodType R). Local Coercion Posz : nat >-> int. Implicit Types m n : int. Implicit Types x y z : R. Implicit Types u v w : V. Lemma scaler_int n v : n%:~R *: v = v *~ n. Proof. elim: n=> [|n ihn|n ihn]; first by rewrite scale0r. by rewrite intS !mulrzDl scalerDl ihn scale1r. by rewrite intS opprD !mulrzDl scalerDl ihn scaleN1r. Qed. Lemma scalerMzl a v n : (a *: v) *~ n = (a *~ n) *: v. Proof. by rewrite -mulrzl -scaler_int scalerA. Qed. Lemma scalerMzr a v n : (a *: v) *~ n = a *: (v *~ n). Proof. by rewrite -!scaler_int !scalerA mulrzr mulrzl. Qed. End LMod. Lemma mulrz_int (M : zmodType) (n : int) (x : M) : x *~ n%:~R = x *~ n. Proof. by rewrite -scalezrE scaler_int. Qed. Section MorphTheory. Local Coercion Posz : nat >-> int. Section Additive. Variables (U V : zmodType) (f : {additive U -> V}). Lemma raddfMz n : {morph f : x / x *~ n}. Proof. case: n=> n x /=; first exact: raddfMn. by rewrite NegzE !mulrNz; apply: raddfMNn. Qed. End Additive. Section Multiplicative. Variables (R S : ringType) (f : {rmorphism R -> S}). Lemma rmorphMz : forall n, {morph f : x / x *~ n}. Proof. exact: raddfMz. Qed. Lemma rmorph_int : forall n, f n%:~R = n%:~R. Proof. by move=> n; rewrite rmorphMz rmorph1. Qed. End Multiplicative. Section Linear. Variable R : ringType. Variables (U V : lmodType R) (f : {linear U -> V}). Lemma linearMn : forall n, {morph f : x / x *~ n}. Proof. exact: raddfMz. Qed. End Linear. Lemma raddf_int_scalable (aV rV : lmodType int) (f : {additive aV -> rV}) : scalable f. Proof. by move=> z u; rewrite -[z]intz !scaler_int raddfMz. Qed. Section Zintmul1rMorph. Variable R : ringType. Lemma commrMz (x y : R) n : GRing.comm x y -> GRing.comm x (y *~ n). Proof. by rewrite /GRing.comm=> com_xy; rewrite mulrzAr mulrzAl com_xy. Qed. Lemma commr_int (x : R) n : GRing.comm x n%:~R. Proof. by apply: commrMz; apply: commr1. Qed. End Zintmul1rMorph. Section ZintBigMorphism. Variable R : ringType. Lemma sumMz : forall I r (P : pred I) F, (\sum_(i <- r | P i) F i)%N%:~R = \sum_(i <- r | P i) ((F i)%:~R) :> R. Proof. by apply: big_morph=> // x y; rewrite !pmulrn -rmorphD. Qed. Lemma prodMz : forall I r (P : pred I) F, (\prod_(i <- r | P i) F i)%N%:~R = \prod_(i <- r | P i) ((F i)%:~R) :> R. Proof. by apply: big_morph=> // x y; rewrite !pmulrn PoszM -rmorphM. Qed. End ZintBigMorphism. Section Frobenius. Variable R : ringType. Implicit Types x y : R. Variable p : nat. Hypothesis charFp : p \in [char R]. Local Notation "x ^f" := (Frobenius_aut charFp x). Lemma Frobenius_autMz x n : (x *~ n)^f = x^f *~ n. Proof. case: n=> n /=; first exact: Frobenius_autMn. by rewrite !NegzE !mulrNz Frobenius_autN Frobenius_autMn. Qed. Lemma Frobenius_aut_int n : (n%:~R)^f = n%:~R. Proof. by rewrite Frobenius_autMz Frobenius_aut1. Qed. End Frobenius. Section NumMorphism. Section PO. Variables (R : numDomainType). Implicit Types n m : int. Implicit Types x y : R. Lemma rmorphzP (f : {rmorphism int -> R}) : f =1 ( *~%R 1). Proof. move=> n; wlog : n / 0 <= n; case: n=> [] n //; do ?exact. by rewrite NegzE !rmorphN=>->. move=> _; elim: n=> [|n ihn]; first by rewrite rmorph0. by rewrite intS !rmorphD !rmorph1 ihn. Qed. (* intmul and ler/ltr *) Lemma ler_pmulz2r n (hn : 0 < n) : {mono *~%R^~ n :x y / x <= y :> R}. Proof. by move=> x y; case: n hn=> [[]|] // n _; rewrite ler_pmuln2r. Qed. Lemma ltr_pmulz2r n (hn : 0 < n) : {mono *~%R^~ n : x y / x < y :> R}. Proof. exact: lerW_mono (ler_pmulz2r _). Qed. Lemma ler_nmulz2r n (hn : n < 0) : {mono *~%R^~ n : x y /~ x <= y :> R}. Proof. move=> x y /=; rewrite -![_ *~ n]mulNrNz. by rewrite ler_pmulz2r (oppr_cp0, ler_opp2). Qed. Lemma ltr_nmulz2r n (hn : n < 0) : {mono *~%R^~ n : x y /~ x < y :> R}. Proof. exact: lerW_nmono (ler_nmulz2r _). Qed. Lemma ler_wpmulz2r n (hn : 0 <= n) : {homo *~%R^~ n : x y / x <= y :> R}. Proof. by move=> x y xy; case: n hn=> [] // n _; rewrite ler_wmuln2r. Qed. Lemma ler_wnmulz2r n (hn : n <= 0) : {homo *~%R^~ n : x y /~ x <= y :> R}. Proof. by move=> x y xy /=; rewrite -ler_opp2 -!mulrNz ler_wpmulz2r // oppr_ge0. Qed. Lemma mulrz_ge0 x n (x0 : 0 <= x) (n0 : 0 <= n) : 0 <= x *~ n. Proof. by rewrite -(mul0rz _ n) ler_wpmulz2r. Qed. Lemma mulrz_le0 x n (x0 : x <= 0) (n0 : n <= 0) : 0 <= x *~ n. Proof. by rewrite -(mul0rz _ n) ler_wnmulz2r. Qed. Lemma mulrz_ge0_le0 x n (x0 : 0 <= x) (n0 : n <= 0) : x *~ n <= 0. Proof. by rewrite -(mul0rz _ n) ler_wnmulz2r. Qed. Lemma mulrz_le0_ge0 x n (x0 : x <= 0) (n0 : 0 <= n) : x *~ n <= 0. Proof. by rewrite -(mul0rz _ n) ler_wpmulz2r. Qed. Lemma pmulrz_lgt0 x n (n0 : 0 < n) : 0 < x *~ n = (0 < x). Proof. by rewrite -(mul0rz _ n) ltr_pmulz2r // mul0rz. Qed. Lemma nmulrz_lgt0 x n (n0 : n < 0) : 0 < x *~ n = (x < 0). Proof. by rewrite -(mul0rz _ n) ltr_nmulz2r // mul0rz. Qed. Lemma pmulrz_llt0 x n (n0 : 0 < n) : x *~ n < 0 = (x < 0). Proof. by rewrite -(mul0rz _ n) ltr_pmulz2r // mul0rz. Qed. Lemma nmulrz_llt0 x n (n0 : n < 0) : x *~ n < 0 = (0 < x). Proof. by rewrite -(mul0rz _ n) ltr_nmulz2r // mul0rz. Qed. Lemma pmulrz_lge0 x n (n0 : 0 < n) : 0 <= x *~ n = (0 <= x). Proof. by rewrite -(mul0rz _ n) ler_pmulz2r // mul0rz. Qed. Lemma nmulrz_lge0 x n (n0 : n < 0) : 0 <= x *~ n = (x <= 0). Proof. by rewrite -(mul0rz _ n) ler_nmulz2r // mul0rz. Qed. Lemma pmulrz_lle0 x n (n0 : 0 < n) : x *~ n <= 0 = (x <= 0). Proof. by rewrite -(mul0rz _ n) ler_pmulz2r // mul0rz. Qed. Lemma nmulrz_lle0 x n (n0 : n < 0) : x *~ n <= 0 = (0 <= x). Proof. by rewrite -(mul0rz _ n) ler_nmulz2r // mul0rz. Qed. Lemma ler_wpmulz2l x (hx : 0 <= x) : {homo *~%R x : x y / x <= y}. Proof. by move=> m n /= hmn; rewrite -subr_ge0 -mulrzBr mulrz_ge0 // subr_ge0. Qed. Lemma ler_wnmulz2l x (hx : x <= 0) : {homo *~%R x : x y /~ x <= y}. Proof. by move=> m n /= hmn; rewrite -subr_ge0 -mulrzBr mulrz_le0 // subr_le0. Qed. Lemma ler_pmulz2l x (hx : 0 < x) : {mono *~%R x : x y / x <= y}. Proof. move=> m n /=; rewrite real_mono ?num_real // => {m n}. by move=> m n /= hmn; rewrite -subr_gt0 -mulrzBr pmulrz_lgt0 // subr_gt0. Qed. Lemma ler_nmulz2l x (hx : x < 0) : {mono *~%R x : x y /~ x <= y}. Proof. move=> m n /=; rewrite real_nmono ?num_real // => {m n}. by move=> m n /= hmn; rewrite -subr_gt0 -mulrzBr nmulrz_lgt0 // subr_lt0. Qed. Lemma ltr_pmulz2l x (hx : 0 < x) : {mono *~%R x : x y / x < y}. Proof. exact: lerW_mono (ler_pmulz2l _). Qed. Lemma ltr_nmulz2l x (hx : x < 0) : {mono *~%R x : x y /~ x < y}. Proof. exact: lerW_nmono (ler_nmulz2l _). Qed. Lemma pmulrz_rgt0 x n (x0 : 0 < x) : 0 < x *~ n = (0 < n). Proof. by rewrite -(mulr0z x) ltr_pmulz2l. Qed. Lemma nmulrz_rgt0 x n (x0 : x < 0) : 0 < x *~ n = (n < 0). Proof. by rewrite -(mulr0z x) ltr_nmulz2l. Qed. Lemma pmulrz_rlt0 x n (x0 : 0 < x) : x *~ n < 0 = (n < 0). Proof. by rewrite -(mulr0z x) ltr_pmulz2l. Qed. Lemma nmulrz_rlt0 x n (x0 : x < 0) : x *~ n < 0 = (0 < n). Proof. by rewrite -(mulr0z x) ltr_nmulz2l. Qed. Lemma pmulrz_rge0 x n (x0 : 0 < x) : 0 <= x *~ n = (0 <= n). Proof. by rewrite -(mulr0z x) ler_pmulz2l. Qed. Lemma nmulrz_rge0 x n (x0 : x < 0) : 0 <= x *~ n = (n <= 0). Proof. by rewrite -(mulr0z x) ler_nmulz2l. Qed. Lemma pmulrz_rle0 x n (x0 : 0 < x) : x *~ n <= 0 = (n <= 0). Proof. by rewrite -(mulr0z x) ler_pmulz2l. Qed. Lemma nmulrz_rle0 x n (x0 : x < 0) : x *~ n <= 0 = (0 <= n). Proof. by rewrite -(mulr0z x) ler_nmulz2l. Qed. Lemma mulrIz x (hx : x != 0) : injective ( *~%R x). Proof. move=> y z; rewrite -![x *~ _]mulrzr => /(mulfI hx). by apply: mono_inj y z; apply: ler_pmulz2l. Qed. Lemma ler_int m n : (m%:~R <= n%:~R :> R) = (m <= n). Proof. by rewrite ler_pmulz2l. Qed. Lemma ltr_int m n : (m%:~R < n%:~R :> R) = (m < n). Proof. by rewrite ltr_pmulz2l. Qed. Lemma eqr_int m n : (m%:~R == n%:~R :> R) = (m == n). Proof. by rewrite (inj_eq (mulrIz _)) ?oner_eq0. Qed. Lemma ler0z n : (0 <= n%:~R :> R) = (0 <= n). Proof. by rewrite pmulrz_rge0. Qed. Lemma ltr0z n : (0 < n%:~R :> R) = (0 < n). Proof. by rewrite pmulrz_rgt0. Qed. Lemma lerz0 n : (n%:~R <= 0 :> R) = (n <= 0). Proof. by rewrite pmulrz_rle0. Qed. Lemma ltrz0 n : (n%:~R < 0 :> R) = (n < 0). Proof. by rewrite pmulrz_rlt0. Qed. Lemma ler1z (n : int) : (1 <= n%:~R :> R) = (1 <= n). Proof. by rewrite -[1]/(1%:~R) ler_int. Qed. Lemma ltr1z (n : int) : (1 < n%:~R :> R) = (1 < n). Proof. by rewrite -[1]/(1%:~R) ltr_int. Qed. Lemma lerz1 n : (n%:~R <= 1 :> R) = (n <= 1). Proof. by rewrite -[1]/(1%:~R) ler_int. Qed. Lemma ltrz1 n : (n%:~R < 1 :> R) = (n < 1). Proof. by rewrite -[1]/(1%:~R) ltr_int. Qed. Lemma intr_eq0 n : (n%:~R == 0 :> R) = (n == 0). Proof. by rewrite -(mulr0z 1) (inj_eq (mulrIz _)) // oner_eq0. Qed. Lemma mulrz_eq0 x n : (x *~ n == 0) = ((n == 0) || (x == 0)). Proof. by rewrite -mulrzl mulf_eq0 intr_eq0. Qed. Lemma mulrz_neq0 x n : x *~ n != 0 = ((n != 0) && (x != 0)). Proof. by rewrite mulrz_eq0 negb_or. Qed. Lemma realz n : (n%:~R : R) \in Num.real. Proof. by rewrite -topredE /Num.real /= ler0z lerz0 ler_total. Qed. Hint Resolve realz. Definition intr_inj := @mulrIz 1 (oner_neq0 R). End PO. End NumMorphism. End MorphTheory. Implicit Arguments intr_inj [[R] x1 x2]. Definition exprz (R : unitRingType) (x : R) (n : int) := nosimpl match n with | Posz n => x ^+ n | Negz n => x ^- (n.+1) end. Notation "x ^ n" := (exprz x n) : ring_scope. Section ExprzUnitRing. Variable R : unitRingType. Implicit Types x y : R. Implicit Types m n : int. Local Coercion Posz : nat >-> int. Lemma exprnP x (n : nat) : x ^+ n = x ^ n. Proof. by []. Qed. Lemma exprnN x (n : nat) : x ^- n = x ^ -n%:Z. Proof. by case: n=> //; rewrite oppr0 expr0 invr1. Qed. Lemma expr0z x : x ^ 0 = 1. Proof. by []. Qed. Lemma expr1z x : x ^ 1 = x. Proof. by []. Qed. Lemma exprN1 x : x ^ (-1) = x^-1. Proof. by []. Qed. Lemma invr_expz x n : (x ^ n)^-1 = x ^ (- n). Proof. by case: (intP n)=> // [|m]; rewrite ?opprK ?expr0z ?invr1 // invrK. Qed. Lemma exprz_inv x n : (x^-1) ^ n = x ^ (- n). Proof. by case: (intP n)=> // m; rewrite -[_ ^ (- _)]exprVn ?opprK ?invrK. Qed. Lemma exp1rz n : 1 ^ n = 1 :> R. Proof. by case: (intP n)=> // m; rewrite -?exprz_inv ?invr1; apply: expr1n. Qed. Lemma exprSz x (n : nat) : x ^ n.+1 = x * x ^ n. Proof. exact: exprS. Qed. Lemma exprSzr x (n : nat) : x ^ n.+1 = x ^ n * x. Proof. exact: exprSr. Qed. Fact exprzD_nat x (m n : nat) : x ^ (m%:Z + n) = x ^ m * x ^ n. Proof. exact: exprD. Qed. Fact exprzD_Nnat x (m n : nat) : x ^ (-m%:Z + -n%:Z) = x ^ (-m%:Z) * x ^ (-n%:Z). Proof. by rewrite -opprD -!exprz_inv exprzD_nat. Qed. Lemma exprzD_ss x m n : (0 <= m) && (0 <= n) || (m <= 0) && (n <= 0) -> x ^ (m + n) = x ^ m * x ^ n. Proof. case: (intP m)=> {m} [|m|m]; case: (intP n)=> {n} [|n|n] //= _; by rewrite ?expr0z ?mul1r ?exprzD_nat ?exprzD_Nnat ?sub0r ?addr0 ?mulr1. Qed. Lemma exp0rz n : 0 ^ n = (n == 0)%:~R :> R. Proof. by case: (intP n)=> // m; rewrite -?exprz_inv ?invr0 exprSz mul0r. Qed. Lemma commrXz x y n : GRing.comm x y -> GRing.comm x (y ^ n). Proof. rewrite /GRing.comm; elim: n x y=> [|n ihn|n ihn] x y com_xy //=. * by rewrite expr0z mul1r mulr1. * by rewrite -exprnP commrX //. rewrite -exprz_inv -exprnP commrX //. case: (boolP (y \is a GRing.unit))=> uy; last by rewrite invr_out. by apply/eqP; rewrite (can2_eq (mulrVK _) (mulrK _)) // -mulrA com_xy mulKr. Qed. Lemma exprMz_comm x y n : x \is a GRing.unit -> y \is a GRing.unit -> GRing.comm x y -> (x * y) ^ n = x ^ n * y ^ n. Proof. move=> ux uy com_xy; elim: n => [|n _|n _]; first by rewrite expr0z mulr1. by rewrite -!exprnP exprMn_comm. rewrite -!exprnN -!exprVn com_xy -exprMn_comm ?invrM//. exact/commrV/commr_sym/commrV. Qed. Lemma commrXz_wmulls x y n : 0 <= n -> GRing.comm x y -> (x * y) ^ n = x ^ n * y ^ n. Proof. move=> n0 com_xy; elim: n n0 => [|n _|n _] //; first by rewrite expr0z mulr1. by rewrite -!exprnP exprMn_comm. Qed. Lemma unitrXz x n (ux : x \is a GRing.unit) : x ^ n \is a GRing.unit. Proof. case: (intP n)=> {n} [|n|n]; rewrite ?expr0z ?unitr1 ?unitrX //. by rewrite -invr_expz unitrV unitrX. Qed. Lemma exprzDr x (ux : x \is a GRing.unit) m n : x ^ (m + n) = x ^ m * x ^ n. Proof. move: n m; apply: wlog_ler=> n m hnm. by rewrite addrC hnm commrXz //; apply: commr_sym; apply: commrXz. case: (intP m) hnm=> {m} [|m|m]; rewrite ?mul1r ?add0r //; case: (intP n)=> {n} [|n|n _]; rewrite ?mulr1 ?addr0 //; do ?by rewrite exprzD_ss. rewrite -invr_expz subzSS !exprSzr invrM ?unitrX // -mulrA mulVKr //. case: (leqP n m)=> [|/ltnW] hmn; rewrite -{2}(subnK hmn) exprzD_nat -subzn //. by rewrite mulrK ?unitrX. by rewrite invrM ?unitrXz // mulVKr ?unitrXz // -opprB -invr_expz. Qed. Lemma exprz_exp x m n : (x ^ m) ^ n = (x ^ (m * n)). Proof. wlog: n / 0 <= n. by case: n=> [n -> //|n]; rewrite ?NegzE mulrN -?invr_expz=> -> /=. elim: n x m=> [|n ihn|n ihn] x m // _; first by rewrite mulr0 !expr0z. rewrite exprSz ihn // intS mulrDr mulr1 exprzD_ss //. by case: (intP m)=> // m'; rewrite ?oppr_le0 //. Qed. Lemma exprzAC x m n : (x ^ m) ^ n = (x ^ n) ^ m. Proof. by rewrite !exprz_exp mulrC. Qed. Lemma exprz_out x n (nux : x \isn't a GRing.unit) (hn : 0 <= n) : x ^ (- n) = x ^ n. Proof. by case: (intP n) hn=> //= m; rewrite -exprnN -exprVn invr_out. Qed. End ExprzUnitRing. Section Exprz_Zint_UnitRing. Variable R : unitRingType. Implicit Types x y : R. Implicit Types m n : int. Local Coercion Posz : nat >-> int. Lemma exprz_pmulzl x m n : 0 <= n -> (x *~ m) ^ n = x ^ n *~ (m ^ n). Proof. by elim: n=> [|n ihn|n _] // _; rewrite !exprSz ihn // mulrzAr mulrzAl -mulrzA. Qed. Lemma exprz_pintl m n (hn : 0 <= n) : m%:~R ^ n = (m ^ n)%:~R :> R. Proof. by rewrite exprz_pmulzl // exp1rz. Qed. Lemma exprzMzl x m n (ux : x \is a GRing.unit) (um : m%:~R \is a @GRing.unit R): (x *~ m) ^ n = (m%:~R ^ n) * x ^ n :> R. Proof. rewrite -[x *~ _]mulrzl exprMz_comm //. by apply: commr_sym; apply: commr_int. Qed. Lemma expNrz x n : (- x) ^ n = (-1) ^ n * x ^ n :> R. Proof. case: n=> [] n; rewrite ?NegzE; first by apply: exprNn. by rewrite -!exprz_inv !invrN invr1; apply: exprNn. Qed. Lemma unitr_n0expz x n : n != 0 -> (x ^ n \is a GRing.unit) = (x \is a GRing.unit). Proof. by case: n => *; rewrite ?NegzE -?exprz_inv ?unitrX_pos ?unitrV ?lt0n. Qed. Lemma intrV (n : int) : n \in [:: 0; 1; -1] -> n%:~R ^-1 = n%:~R :> R. Proof. by case: (intP n)=> // [|[]|[]] //; rewrite ?rmorphN ?invrN (invr0, invr1). Qed. Lemma rmorphXz (R' : unitRingType) (f : {rmorphism R -> R'}) n : {in GRing.unit, {morph f : x / x ^ n}}. Proof. by case: n => n x Ux; rewrite ?rmorphV ?rpredX ?rmorphX. Qed. End Exprz_Zint_UnitRing. Section ExprzIdomain. Variable R : idomainType. Implicit Types x y : R. Implicit Types m n : int. Local Coercion Posz : nat >-> int. Lemma expfz_eq0 x n : (x ^ n == 0) = (n != 0) && (x == 0). Proof. by case: n=> n; rewrite ?NegzE -?exprz_inv ?expf_eq0 ?lt0n ?invr_eq0. Qed. Lemma expfz_neq0 x n : x != 0 -> x ^ n != 0. Proof. by move=> x_nz; rewrite expfz_eq0; apply/nandP; right. Qed. Lemma exprzMl x y n (ux : x \is a GRing.unit) (uy : y \is a GRing.unit) : (x * y) ^ n = x ^ n * y ^ n. Proof. by rewrite exprMz_comm //; apply: mulrC. Qed. Lemma expfV (x : R) (i : int) : (x ^ i) ^-1 = (x ^-1) ^ i. Proof. by rewrite invr_expz exprz_inv. Qed. End ExprzIdomain. Section ExprzField. Variable F : fieldType. Implicit Types x y : F. Implicit Types m n : int. Local Coercion Posz : nat >-> int. Lemma expfzDr x m n : x != 0 -> x ^ (m + n) = x ^ m * x ^ n. Proof. by move=> hx; rewrite exprzDr ?unitfE. Qed. Lemma expfz_n0addr x m n : m + n != 0 -> x ^ (m + n) = x ^ m * x ^ n. Proof. have [-> hmn|nx0 _] := eqVneq x 0; last exact: expfzDr. rewrite !exp0rz (negPf hmn). case: (altP (m =P 0)) hmn=> [->|]; rewrite (mul0r, mul1r) //. by rewrite add0r=> /negPf->. Qed. Lemma expfzMl x y n : (x * y) ^ n = x ^ n * y ^ n. Proof. have [->|/negPf n0] := eqVneq n 0; first by rewrite !expr0z mulr1. case: (boolP ((x * y) == 0)); rewrite ?mulf_eq0. by case/orP=> /eqP->; rewrite ?(mul0r, mulr0, exp0rz, n0). by case/norP=> x0 y0; rewrite exprzMl ?unitfE. Qed. Lemma fmorphXz (R : unitRingType) (f : {rmorphism F -> R}) n : {morph f : x / x ^ n}. Proof. by case: n => n x; rewrite ?fmorphV rmorphX. Qed. End ExprzField. Section ExprzOrder. Variable R : realFieldType. Implicit Types x y : R. Implicit Types m n : int. Local Coercion Posz : nat >-> int. (* ler and exprz *) Lemma exprz_ge0 n x (hx : 0 <= x) : (0 <= x ^ n). Proof. by case: n=> n; rewrite ?NegzE -?invr_expz ?invr_ge0 ?exprn_ge0. Qed. Lemma exprz_gt0 n x (hx : 0 < x) : (0 < x ^ n). Proof. by case: n=> n; rewrite ?NegzE -?invr_expz ?invr_gt0 ?exprn_gt0. Qed. Definition exprz_gte0 := (exprz_ge0, exprz_gt0). Lemma ler_wpiexpz2l x (x0 : 0 <= x) (x1 : x <= 1) : {in >= 0 &, {homo (exprz x) : x y /~ x <= y}}. Proof. move=> [] m [] n; rewrite -!topredE /= ?oppr_cp0 ?ltz_nat // => _ _. by rewrite lez_nat -?exprnP=> /ler_wiexpn2l; apply. Qed. Lemma ler_wniexpz2l x (x0 : 0 <= x) (x1 : x <= 1) : {in < 0 &, {homo (exprz x) : x y /~ x <= y}}. Proof. move=> [] m [] n; rewrite ?NegzE -!topredE /= ?oppr_cp0 ?ltz_nat // => _ _. rewrite ler_opp2 lez_nat -?invr_expz=> hmn; move: (x0). rewrite le0r=> /orP [/eqP->|lx0]; first by rewrite !exp0rz invr0. by rewrite lef_pinv -?topredE /= ?exprz_gt0 // ler_wiexpn2l. Qed. Fact ler_wpeexpz2l x (x1 : 1 <= x) : {in >= 0 &, {homo (exprz x) : x y / x <= y}}. Proof. move=> [] m [] n; rewrite -!topredE /= ?oppr_cp0 ?ltz_nat // => _ _. by rewrite lez_nat -?exprnP=> /ler_weexpn2l; apply. Qed. Fact ler_wneexpz2l x (x1 : 1 <= x) : {in <= 0 &, {homo (exprz x) : x y / x <= y}}. Proof. move=> m n hm hn /= hmn. rewrite -lef_pinv -?topredE /= ?exprz_gt0 ?(ltr_le_trans ltr01) //. by rewrite !invr_expz ler_wpeexpz2l ?ler_opp2 -?topredE //= oppr_cp0. Qed. Lemma ler_weexpz2l x (x1 : 1 <= x) : {homo (exprz x) : x y / x <= y}. Proof. move=> m n /= hmn; case: (lerP 0 m)=> [|/ltrW] hm. by rewrite ler_wpeexpz2l // [_ \in _](ler_trans hm). case: (lerP n 0)=> [|/ltrW] hn. by rewrite ler_wneexpz2l // [_ \in _](ler_trans hmn). apply: (@ler_trans _ (x ^ 0)); first by rewrite ler_wneexpz2l. by rewrite ler_wpeexpz2l. Qed. Lemma pexprz_eq1 x n (x0 : 0 <= x) : (x ^ n == 1) = ((n == 0) || (x == 1)). Proof. case: n=> n; rewrite ?NegzE -?exprz_inv ?oppr_eq0 pexprn_eq1 // ?invr_eq1 //. by rewrite invr_ge0. Qed. Lemma ieexprIz x (x0 : 0 < x) (nx1 : x != 1) : injective (exprz x). Proof. apply: wlog_ltr=> // m n hmn; first by move=> hmn'; rewrite hmn. move=> /(f_equal ( *%R^~ (x ^ (- n)))). rewrite -!expfzDr ?gtr_eqF // subrr expr0z=> /eqP. by rewrite pexprz_eq1 ?(ltrW x0) // (negPf nx1) subr_eq0 orbF=> /eqP. Qed. Lemma ler_piexpz2l x (x0 : 0 < x) (x1 : x < 1) : {in >= 0 &, {mono (exprz x) : x y /~ x <= y}}. Proof. apply: (nhomo_mono_in (nhomo_inj_in_lt _ _)). by move=> n m hn hm /=; apply: ieexprIz; rewrite // ltr_eqF. by apply: ler_wpiexpz2l; rewrite ?ltrW. Qed. Lemma ltr_piexpz2l x (x0 : 0 < x) (x1 : x < 1) : {in >= 0 &, {mono (exprz x) : x y /~ x < y}}. Proof. exact: (lerW_nmono_in (ler_piexpz2l _ _)). Qed. Lemma ler_niexpz2l x (x0 : 0 < x) (x1 : x < 1) : {in < 0 &, {mono (exprz x) : x y /~ x <= y}}. Proof. apply: (nhomo_mono_in (nhomo_inj_in_lt _ _)). by move=> n m hn hm /=; apply: ieexprIz; rewrite // ltr_eqF. by apply: ler_wniexpz2l; rewrite ?ltrW. Qed. Lemma ltr_niexpz2l x (x0 : 0 < x) (x1 : x < 1) : {in < 0 &, {mono (exprz x) : x y /~ x < y}}. Proof. exact: (lerW_nmono_in (ler_niexpz2l _ _)). Qed. Lemma ler_eexpz2l x (x1 : 1 < x) : {mono (exprz x) : x y / x <= y}. Proof. apply: (homo_mono (homo_inj_lt _ _)). by apply: ieexprIz; rewrite ?(ltr_trans ltr01) // gtr_eqF. by apply: ler_weexpz2l; rewrite ?ltrW. Qed. Lemma ltr_eexpz2l x (x1 : 1 < x) : {mono (exprz x) : x y / x < y}. Proof. exact: (lerW_mono (ler_eexpz2l _)). Qed. Lemma ler_wpexpz2r n (hn : 0 <= n) : {in >= 0 & , {homo ((@exprz R)^~ n) : x y / x <= y}}. Proof. by case: n hn=> // n _; apply: ler_expn2r. Qed. Lemma ler_wnexpz2r n (hn : n <= 0) : {in > 0 & , {homo ((@exprz R)^~ n) : x y /~ x <= y}}. Proof. move=> x y /= hx hy hxy; rewrite -lef_pinv ?[_ \in _]exprz_gt0 //. by rewrite !invr_expz ler_wpexpz2r ?[_ \in _]ltrW // oppr_cp0. Qed. Lemma pexpIrz n (n0 : n != 0) : {in >= 0 &, injective ((@exprz R)^~ n)}. Proof. move=> x y; rewrite ![_ \in _]le0r=> /orP [/eqP-> _ /eqP|hx]. by rewrite exp0rz ?(negPf n0) eq_sym expfz_eq0=> /andP [_ /eqP->]. case/orP=> [/eqP-> /eqP|hy]. by rewrite exp0rz ?(negPf n0) expfz_eq0=> /andP [_ /eqP]. move=> /(f_equal ( *%R^~ (y ^ (- n)))) /eqP. rewrite -expfzDr ?(gtr_eqF hy) // subrr expr0z -exprz_inv -expfzMl. rewrite pexprz_eq1 ?(negPf n0) /= ?mulr_ge0 ?invr_ge0 ?ltrW //. by rewrite (can2_eq (mulrVK _) (mulrK _)) ?unitfE ?(gtr_eqF hy) // mul1r=> /eqP. Qed. Lemma nexpIrz n (n0 : n != 0) : {in <= 0 &, injective ((@exprz R)^~ n)}. Proof. move=> x y; rewrite ![_ \in _]ler_eqVlt => /orP [/eqP -> _ /eqP|hx]. by rewrite exp0rz ?(negPf n0) eq_sym expfz_eq0=> /andP [_ /eqP->]. case/orP=> [/eqP -> /eqP|hy]. by rewrite exp0rz ?(negPf n0) expfz_eq0=> /andP [_ /eqP]. move=> /(f_equal ( *%R^~ (y ^ (- n)))) /eqP. rewrite -expfzDr ?(ltr_eqF hy) // subrr expr0z -exprz_inv -expfzMl. rewrite pexprz_eq1 ?(negPf n0) /= ?mulr_le0 ?invr_le0 ?ltrW //. by rewrite (can2_eq (mulrVK _) (mulrK _)) ?unitfE ?(ltr_eqF hy) // mul1r=> /eqP. Qed. Lemma ler_pexpz2r n (hn : 0 < n) : {in >= 0 & , {mono ((@exprz R)^~ n) : x y / x <= y}}. Proof. apply: homo_mono_in (homo_inj_in_lt _ _). by move=> x y hx hy /=; apply: pexpIrz; rewrite // gtr_eqF. by apply: ler_wpexpz2r; rewrite ltrW. Qed. Lemma ltr_pexpz2r n (hn : 0 < n) : {in >= 0 & , {mono ((@exprz R)^~ n) : x y / x < y}}. Proof. exact: lerW_mono_in (ler_pexpz2r _). Qed. Lemma ler_nexpz2r n (hn : n < 0) : {in > 0 & , {mono ((@exprz R)^~ n) : x y /~ x <= y}}. Proof. apply: nhomo_mono_in (nhomo_inj_in_lt _ _); last first. by apply: ler_wnexpz2r; rewrite ltrW. by move=> x y hx hy /=; apply: pexpIrz; rewrite ?[_ \in _]ltrW ?ltr_eqF. Qed. Lemma ltr_nexpz2r n (hn : n < 0) : {in > 0 & , {mono ((@exprz R)^~ n) : x y /~ x < y}}. Proof. exact: lerW_nmono_in (ler_nexpz2r _). Qed. Lemma eqr_expz2 n x y : n != 0 -> 0 <= x -> 0 <= y -> (x ^ n == y ^ n) = (x == y). Proof. by move=> *; rewrite (inj_in_eq (pexpIrz _)). Qed. End ExprzOrder. Local Notation sgr := Num.sg. Section Sgz. Variable R : numDomainType. Implicit Types x y z : R. Implicit Types m n p : int. Local Coercion Posz : nat >-> int. Definition sgz x : int := if x == 0 then 0 else if x < 0 then -1 else 1. Lemma sgz_def x : sgz x = (-1) ^+ (x < 0)%R *+ (x != 0). Proof. by rewrite /sgz; case: (_ == _); case: (_ < _). Qed. Lemma sgrEz x : sgr x = (sgz x)%:~R. Proof. by rewrite !(fun_if intr). Qed. Lemma gtr0_sgz x : 0 < x -> sgz x = 1. Proof. by move=> x_gt0; rewrite /sgz ltr_neqAle andbC eqr_le ltr_geF //. Qed. Lemma ltr0_sgz x : x < 0 -> sgz x = -1. Proof. by move=> x_lt0; rewrite /sgz eq_sym eqr_le x_lt0 ltr_geF. Qed. Lemma sgz0 : sgz (0 : R) = 0. Proof. by rewrite /sgz eqxx. Qed. Lemma sgz1 : sgz (1 : R) = 1. Proof. by rewrite gtr0_sgz // ltr01. Qed. Lemma sgzN1 : sgz (-1 : R) = -1. Proof. by rewrite ltr0_sgz // ltrN10. Qed. Definition sgzE := (sgz0, sgz1, sgzN1). Lemma sgz_sgr x : sgz (sgr x) = sgz x. Proof. by rewrite !(fun_if sgz) !sgzE. Qed. Lemma normr_sgz x : `|sgz x| = (x != 0). Proof. by rewrite sgz_def -mulr_natr normrMsign normr_nat natz. Qed. Lemma normr_sg x : `|sgr x| = (x != 0)%:~R. Proof. by rewrite sgr_def -mulr_natr normrMsign normr_nat. Qed. End Sgz. Section MoreSgz. Variable R : numDomainType. Lemma sgz_int m : sgz (m%:~R : R) = sgz m. Proof. by rewrite /sgz intr_eq0 ltrz0. Qed. Lemma sgrz (n : int) : sgr n = sgz n. Proof. by rewrite sgrEz intz. Qed. Lemma intr_sg m : (sgr m)%:~R = sgr (m%:~R) :> R. Proof. by rewrite sgrz -sgz_int -sgrEz. Qed. Lemma sgz_id (x : R) : sgz (sgz x) = sgz x. Proof. by rewrite !(fun_if (@sgz _)). Qed. End MoreSgz. Section SgzReal. Variable R : realDomainType. Implicit Types x y z : R. Implicit Types m n p : int. Local Coercion Posz : nat >-> int. Lemma sgz_cp0 x : ((sgz x == 1) = (0 < x)) * ((sgz x == -1) = (x < 0)) * ((sgz x == 0) = (x == 0)). Proof. by rewrite /sgz; case: ltrgtP. Qed. CoInductive sgz_val x : bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> bool -> R -> R -> int -> Set := | SgzNull of x = 0 : sgz_val x true true true true false false true false false true false false true false false true false false 0 0 0 | SgzPos of x > 0 : sgz_val x false false true false false true false false true false false true false false true false false true x 1 1 | SgzNeg of x < 0 : sgz_val x false true false false true false false true false false true false false true false false true false (-x) (-1) (-1). Lemma sgzP x : sgz_val x (0 == x) (x <= 0) (0 <= x) (x == 0) (x < 0) (0 < x) (0 == sgr x) (-1 == sgr x) (1 == sgr x) (sgr x == 0) (sgr x == -1) (sgr x == 1) (0 == sgz x) (-1 == sgz x) (1 == sgz x) (sgz x == 0) (sgz x == -1) (sgz x == 1) `|x| (sgr x) (sgz x). Proof. rewrite ![_ == sgz _]eq_sym ![_ == sgr _]eq_sym !sgr_cp0 !sgz_cp0. by rewrite /sgr /sgz !lerNgt; case: ltrgt0P; constructor. Qed. Lemma sgzN x : sgz (- x) = - sgz x. Proof. by rewrite /sgz oppr_eq0 oppr_lt0; case: ltrgtP. Qed. Lemma mulz_sg x : sgz x * sgz x = (x != 0)%:~R. Proof. by case: sgzP; rewrite ?(mulr0, mulr1, mulrNN). Qed. Lemma mulz_sg_eq1 x y : (sgz x * sgz y == 1) = (x != 0) && (sgz x == sgz y). Proof. do 2?case: sgzP=> _; rewrite ?(mulr0, mulr1, mulrN1, opprK, oppr0, eqxx); by rewrite ?[0 == 1]eq_sym ?oner_eq0 //= eqr_oppLR oppr0 oner_eq0. Qed. Lemma mulz_sg_eqN1 x y : (sgz x * sgz y == -1) = (x != 0) && (sgz x == - sgz y). Proof. by rewrite -eqr_oppLR -mulrN -sgzN mulz_sg_eq1. Qed. (* Lemma muls_eqA x y z : sgr x != 0 -> *) (* (sgr y * sgr z == sgr x) = ((sgr y * sgr x == sgr z) && (sgr z != 0)). *) (* Proof. by do 3!case: sgrP=> _. Qed. *) Lemma sgzM x y : sgz (x * y) = sgz x * sgz y. Proof. case: (sgzP x)=> hx; first by rewrite hx ?mul0r sgz0. case: (sgzP y)=> hy; first by rewrite hy !mulr0 sgz0. by apply/eqP; rewrite mul1r sgz_cp0 pmulr_rgt0. by apply/eqP; rewrite mul1r sgz_cp0 nmulr_llt0. case: (sgzP y)=> hy; first by rewrite hy !mulr0 sgz0. by apply/eqP; rewrite mulr1 sgz_cp0 nmulr_rlt0. by apply/eqP; rewrite mulN1r opprK sgz_cp0 nmulr_rgt0. Qed. Lemma sgzX (n : nat) x : sgz (x ^+ n) = (sgz x) ^+ n. Proof. by elim: n => [|n IHn]; rewrite ?sgz1 // !exprS sgzM IHn. Qed. Lemma sgz_eq0 x : (sgz x == 0) = (x == 0). Proof. by rewrite sgz_cp0. Qed. Lemma sgz_odd (n : nat) x : x != 0 -> (sgz x) ^+ n = (sgz x) ^+ (odd n). Proof. by case: sgzP => //=; rewrite ?expr1n // signr_odd. Qed. Lemma sgz_gt0 x : (sgz x > 0) = (x > 0). Proof. by case: sgzP. Qed. Lemma sgz_lt0 x : (sgz x < 0) = (x < 0). Proof. by case: sgzP. Qed. Lemma sgz_ge0 x : (sgz x >= 0) = (x >= 0). Proof. by case: sgzP. Qed. Lemma sgz_le0 x : (sgz x <= 0) = (x <= 0). Proof. by case: sgzP. Qed. Lemma sgz_smul x y : sgz (y *~ (sgz x)) = (sgz x) * (sgz y). Proof. by rewrite -mulrzl sgzM -sgrEz sgz_sgr. Qed. Lemma sgrMz m x : sgr (x *~ m) = sgr x *~ sgr m. Proof. by rewrite -mulrzr sgrM -intr_sg mulrzr. Qed. End SgzReal. Lemma sgz_eq (R R' : realDomainType) (x : R) (y : R') : (sgz x == sgz y) = ((x == 0) == (y == 0)) && ((0 < x) == (0 < y)). Proof. by do 2!case: sgzP. Qed. Lemma intr_sign (R : ringType) s : ((-1) ^+ s)%:~R = (-1) ^+ s :> R. Proof. exact: rmorph_sign. Qed. Section Absz. Implicit Types m n p : int. Open Scope nat_scope. Local Coercion Posz : nat >-> int. Lemma absz_nat (n : nat) : `|n| = n. Proof. by []. Qed. Lemma abszE (m : int) : `|m| = `|m|%R :> int. Proof. by []. Qed. Lemma absz0 : `|0%R| = 0. Proof. by []. Qed. Lemma abszN m : `|- m| = `|m|. Proof. by case: (normrN m). Qed. Lemma absz_eq0 m : (`|m| == 0) = (m == 0%R). Proof. by case: (intP m). Qed. Lemma absz_gt0 m : (`|m| > 0) = (m != 0%R). Proof. by case: (intP m). Qed. Lemma absz1 : `|1%R| = 1. Proof. by []. Qed. Lemma abszN1 : `|-1%R| = 1. Proof. by []. Qed. Lemma absz_id m : `|(`|m|)| = `|m|. Proof. by []. Qed. Lemma abszM m1 m2 : `|(m1 * m2)%R| = `|m1| * `|m2|. Proof. by case: m1 m2 => [[|m1]|m1] [[|m2]|m2]; rewrite //= mulnS mulnC. Qed. Lemma abszX (n : nat) m : `|m ^+ n| = `|m| ^ n. Proof. by elim: n => // n ihn; rewrite exprS expnS abszM ihn. Qed. Lemma absz_sg m : `|sgr m| = (m != 0%R). Proof. by case: (intP m). Qed. Lemma gez0_abs m : (0 <= m)%R -> `|m| = m :> int. Proof. by case: (intP m). Qed. Lemma gtz0_abs m : (0 < m)%R -> `|m| = m :> int. Proof. by case: (intP m). Qed. Lemma lez0_abs m : (m <= 0)%R -> `|m| = - m :> int. Proof. by case: (intP m). Qed. Lemma ltz0_abs m : (m < 0)%R -> `|m| = - m :> int. Proof. by case: (intP m). Qed. Lemma absz_sign s : `|(-1) ^+ s| = 1. Proof. by rewrite abszX exp1n. Qed. Lemma abszMsign s m : `|((-1) ^+ s * m)%R| = `|m|. Proof. by rewrite abszM absz_sign mul1n. Qed. Lemma mulz_sign_abs m : ((-1) ^+ (m < 0)%R * `|m|%:Z)%R = m. Proof. by rewrite abszE mulr_sign_norm. Qed. Lemma mulz_Nsign_abs m : ((-1) ^+ (0 < m)%R * `|m|%:Z)%R = - m. Proof. by rewrite abszE mulr_Nsign_norm. Qed. Lemma intEsign m : m = ((-1) ^+ (m < 0)%R * `|m|%:Z)%R. Proof. exact: numEsign. Qed. Lemma abszEsign m : `|m|%:Z = ((-1) ^+ (m < 0)%R * m)%R. Proof. exact: normrEsign. Qed. Lemma intEsg m : m = (sgz m * `|m|%:Z)%R. Proof. by rewrite -sgrz -numEsg. Qed. Lemma abszEsg m : (`|m|%:Z = sgz m * m)%R. Proof. by rewrite -sgrz -normrEsg. Qed. End Absz. Module Export IntDist. Notation "m - n" := (@GRing.add int_ZmodType m%N (@GRing.opp int_ZmodType n%N)) : distn_scope. Arguments Scope absz [distn_scope]. Notation "`| m |" := (absz m) : nat_scope. Coercion Posz : nat >-> int. Section Distn. Open Scope nat_scope. Implicit Type m : int. Implicit Types n d : nat. Lemma distnC m1 m2 : `|m1 - m2| = `|m2 - m1|. Proof. by rewrite -opprB abszN. Qed. Lemma distnDl d n1 n2 : `|d + n1 - (d + n2)| = `|n1 - n2|. Proof. by rewrite !PoszD opprD addrCA -addrA addKr. Qed. Lemma distnDr d n1 n2 : `|n1 + d - (n2 + d)| = `|n1 - n2|. Proof. by rewrite -!(addnC d) distnDl. Qed. Lemma distnEr n1 n2 : n1 <= n2 -> `|n1 - n2| = n2 - n1. Proof. by move/subnK=> {1}<-; rewrite distnC PoszD addrK absz_nat. Qed. Lemma distnEl n1 n2 : n2 <= n1 -> `|n1 - n2| = n1 - n2. Proof. by move/distnEr <-; rewrite distnC. Qed. Lemma distn0 n : `|n - 0| = n. Proof. by rewrite subr0 absz_nat. Qed. Lemma dist0n n : `|0 - n| = n. Proof. by rewrite distnC distn0. Qed. Lemma distnn m : `|m - m| = 0. Proof. by rewrite subrr. Qed. Lemma distn_eq0 n1 n2 : (`|n1 - n2| == 0) = (n1 == n2). Proof. by rewrite absz_eq0 subr_eq0. Qed. Lemma distnS n : `|n - n.+1| = 1. Proof. exact: distnDr n 0 1. Qed. Lemma distSn n : `|n.+1 - n| = 1. Proof. exact: distnDr n 1 0. Qed. Lemma distn_eq1 n1 n2 : (`|n1 - n2| == 1) = (if n1 < n2 then n1.+1 == n2 else n1 == n2.+1). Proof. case: ltnP => [lt_n12 | le_n21]. by rewrite eq_sym -(eqn_add2r n1) distnEr ?subnK // ltnW. by rewrite -(eqn_add2r n2) distnEl ?subnK. Qed. Lemma leq_add_dist m1 m2 m3 : `|m1 - m3| <= `|m1 - m2| + `|m2 - m3|. Proof. by rewrite -lez_nat PoszD !abszE ler_dist_add. Qed. (* Most of this proof generalizes to all real-ordered rings. *) Lemma leqif_add_distz m1 m2 m3 : `|m1 - m3| <= `|m1 - m2| + `|m2 - m3| ?= iff (m1 <= m2 <= m3)%R || (m3 <= m2 <= m1)%R. Proof. apply/leqifP; rewrite -ltz_nat -eqz_nat PoszD !abszE; apply/lerifP. wlog le_m31 : m1 m3 / (m3 <= m1)%R. move=> IH; case/orP: (ler_total m1 m3) => /IH //. by rewrite (addrC `|_|)%R orbC !(distrC m1) !(distrC m3). rewrite ger0_norm ?subr_ge0 // orb_idl => [|/andP[le_m12 le_m23]]; last first. by have /eqP->: m2 == m3; rewrite ?lerr // eqr_le le_m23 (ler_trans le_m31). rewrite -{1}(subrK m2 m1) -addrA -subr_ge0 andbC -subr_ge0. by apply: lerif_add; apply/real_lerif_norm/num_real. Qed. Lemma leqif_add_dist n1 n2 n3 : `|n1 - n3| <= `|n1 - n2| + `|n2 - n3| ?= iff (n1 <= n2 <= n3) || (n3 <= n2 <= n1). Proof. exact: leqif_add_distz. Qed. Lemma sqrn_dist n1 n2 : `|n1 - n2| ^ 2 + 2 * (n1 * n2) = n1 ^ 2 + n2 ^ 2. Proof. wlog le_n21: n1 n2 / n2 <= n1. move=> IH; case/orP: (leq_total n2 n1) => /IH //. by rewrite (addnC (n2 ^ 2)) (mulnC n2) distnC. by rewrite distnEl ?sqrn_sub ?subnK ?nat_Cauchy. Qed. End Distn. End IntDist. Section NormInt. Variable R : numDomainType. Lemma intr_norm m : `|m|%:~R = `|m%:~R| :> R. Proof. by rewrite {2}[m]intEsign rmorphMsign normrMsign abszE normr_nat. Qed. Lemma normrMz m (x : R) : `|x *~ m| = `|x| *~ `|m|. Proof. by rewrite -mulrzl normrM -intr_norm mulrzl. Qed. Lemma expN1r (i : int) : (-1 : R) ^ i = (-1) ^+ `|i|. Proof. case: i => n; first by rewrite exprnP absz_nat. by rewrite NegzE abszN absz_nat -invr_expz expfV invrN1. Qed. End NormInt. Section PolyZintRing. Variable R : ringType. Implicit Types x y z: R. Implicit Types m n : int. Implicit Types i j k : nat. Implicit Types p q r : {poly R}. Lemma coefMrz : forall p n i, (p *~ n)`_i = (p`_i *~ n). Proof. by move=> p [] n i; rewrite ?NegzE (coefMNn, coefMn). Qed. Lemma polyC_mulrz : forall n, {morph (@polyC R) : c / c *~ n}. Proof. move=> [] n c; rewrite ?NegzE -?pmulrn ?polyC_muln //. by rewrite polyC_opp mulrNz polyC_muln nmulrn. Qed. Lemma hornerMz : forall n (p : {poly R}) x, (p *~ n).[x] = p.[x] *~ n. Proof. by case=> *; rewrite ?NegzE ?mulNzr ?(hornerN, hornerMn). Qed. Lemma horner_int : forall n x, (n%:~R : {poly R}).[x] = n%:~R. Proof. by move=> n x; rewrite hornerMz hornerC. Qed. Lemma derivMz : forall n p, (p *~ n)^`() = p^`() *~ n. Proof. by move=> [] n p; rewrite ?NegzE -?pmulrn (derivMn, derivMNn). Qed. End PolyZintRing. Section PolyZintOIdom. Variable R : realDomainType. Lemma mulpz (p : {poly R}) (n : int) : p *~ n = n%:~R *: p. Proof. by rewrite -[p *~ n]mulrzl -mul_polyC polyC_mulrz polyC1. Qed. End PolyZintOIdom. Section ZnatPred. Definition Znat := [qualify a n : int | 0 <= n]. Fact Znat_key : pred_key Znat. by []. Qed. Canonical Znat_keyd := KeyedQualifier Znat_key. Lemma Znat_def n : (n \is a Znat) = (0 <= n). Proof. by []. Qed. Lemma Znat_semiring_closed : semiring_closed Znat. Proof. by do 2?split => //; [exact: addr_ge0 | exact: mulr_ge0]. Qed. Canonical Znat_addrPred := AddrPred Znat_semiring_closed. Canonical Znat_mulrPred := MulrPred Znat_semiring_closed. Canonical Znat_semiringPred := SemiringPred Znat_semiring_closed. Lemma ZnatP (m : int) : reflect (exists n : nat, m = n) (m \is a Znat). Proof. by apply: (iffP idP) => [|[n -> //]]; case: m => // n; exists n. Qed. End ZnatPred. Section rpred. Lemma rpredMz M S (addS : @zmodPred M S) (kS : keyed_pred addS) m : {in kS, forall u, u *~ m \in kS}. Proof. by case: m => n u Su; rewrite ?rpredN ?rpredMn. Qed. Lemma rpred_int R S (ringS : @subringPred R S) (kS : keyed_pred ringS) m : m%:~R \in kS. Proof. by rewrite rpredMz ?rpred1. Qed. Lemma rpredZint (R : ringType) (M : lmodType R) S (addS : @zmodPred M S) (kS : keyed_pred addS) m : {in kS, forall u, m%:~R *: u \in kS}. Proof. by move=> u Su; rewrite /= scaler_int rpredMz. Qed. Lemma rpredXz R S (divS : @divrPred R S) (kS : keyed_pred divS) m : {in kS, forall x, x ^ m \in kS}. Proof. by case: m => n x Sx; rewrite ?rpredV rpredX. Qed. Lemma rpredXsign R S (divS : @divrPred R S) (kS : keyed_pred divS) n x : (x ^ ((-1) ^+ n) \in kS) = (x \in kS). Proof. by rewrite -signr_odd; case: (odd n); rewrite ?rpredV. Qed. End rpred.mathcomp-1.5/theories/interval.v0000644000175000017500000003777412307636117016040 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq div choice fintype. Require Import bigop ssralg finset fingroup zmodp ssrint ssrnum. (*****************************************************************************) (* This file provide support for intervals in numerical and real domains. *) (* The datatype (interval R) gives a formal characterization of an *) (* interval, as the pair of its right and left bounds. *) (* interval R == the type of formal intervals on R. *) (* x \in i == when i is a formal interval on a numeric domain, *) (* \in can be used to test membership. *) (* itvP x_in_i == where x_in_i has type x \in i, if i is ground, *) (* gives a set of rewrite rules that x_in_i imply. *) (* x <= y ?< if c == x is smaller than y, and strictly if c is true *) (* *) (* We provide a set of notations to write intervals (see below) *) (* `[a, b], `]a, b], ..., `]-oo, a], ..., `]-oo, +oo[ *) (* We also provide the lemma subitvP which computes the inequalities one *) (* needs to prove when trying to prove the inclusion of intervals. *) (* *) (* Remark that we cannot implement a boolean comparison test for intervals *) (* on an arbitrary numeric domains, for this problem might be undecidable. *) (* Note also that type (interval R) may contain several inhabitants coding *) (* for the same interval. However, this pathological issues do nor arise *) (* when R is a real domain: we could provide a specific theory for this *) (* important case. *) (* *) (* See also "Formal proofs in real algebraic geometry: from ordered fields *) (* to quantifier elimination", LMCS journal, 2012 *) (* by Cyril Cohen and Assia Mahboubi *) (* *) (* And "Formalized algebraic numbers: construction and first-order theory" *) (* Cyril Cohen, PhD, 2012, section 4.3. *) (*****************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Local Open Scope ring_scope. Import GRing.Theory Num.Theory. Local Notation mid x y := ((x + y) / 2%:R). Section IntervalPo. CoInductive itv_bound (T : Type) : Type := BOpen_if of bool & T | BInfty. Notation BOpen := (BOpen_if true). Notation BClose := (BOpen_if false). CoInductive interval (T : Type) := Interval of itv_bound T & itv_bound T. Variable (R : numDomainType). Definition pred_of_itv (i : interval R) : pred R := [pred x | let: Interval l u := i in match l with | BOpen a => a < x | BClose a => a <= x | BInfty => true end && match u with | BOpen b => x < b | BClose b => x <= b | BInfty => true end]. Canonical Structure itvPredType := Eval hnf in mkPredType pred_of_itv. (* We provide the 9 following notations to help writing formal intervals *) Notation "`[ a , b ]" := (Interval (BClose a) (BClose b)) (at level 0, a, b at level 9 , format "`[ a , b ]") : ring_scope. Notation "`] a , b ]" := (Interval (BOpen a) (BClose b)) (at level 0, a, b at level 9 , format "`] a , b ]") : ring_scope. Notation "`[ a , b [" := (Interval (BClose a) (BOpen b)) (at level 0, a, b at level 9 , format "`[ a , b [") : ring_scope. Notation "`] a , b [" := (Interval (BOpen a) (BOpen b)) (at level 0, a, b at level 9 , format "`] a , b [") : ring_scope. Notation "`] '-oo' , b ]" := (Interval (BInfty _) (BClose b)) (at level 0, b at level 9 , format "`] '-oo' , b ]") : ring_scope. Notation "`] '-oo' , b [" := (Interval (BInfty _) (BOpen b)) (at level 0, b at level 9 , format "`] '-oo' , b [") : ring_scope. Notation "`[ a , '+oo' [" := (Interval (BClose a) (BInfty _)) (at level 0, a at level 9 , format "`[ a , '+oo' [") : ring_scope. Notation "`] a , '+oo' [" := (Interval (BOpen a) (BInfty _)) (at level 0, a at level 9 , format "`] a , '+oo' [") : ring_scope. Notation "`] -oo , '+oo' [" := (Interval (BInfty _) (BInfty _)) (at level 0, format "`] -oo , '+oo' [") : ring_scope. (* we compute a set of rewrite rules associated to an interval *) Definition itv_rewrite (i : interval R) x : Type := let: Interval l u := i in (match l with | BClose a => (a <= x) * (x < a = false) | BOpen a => (a <= x) * (a < x) * (x <= a = false) | BInfty => forall x : R, x == x end * match u with | BClose b => (x <= b) * (b < x = false) | BOpen b => (x <= b) * (x < b) * (b <= x = false) | BInfty => forall x : R, x == x end * match l, u with | BClose a, BClose b => (a <= b) * (b < a = false) * (a \in `[a, b]) * (b \in `[a, b]) | BClose a, BOpen b => (a <= b) * (a < b) * (b <= a = false) * (a \in `[a, b]) * (a \in `[a, b[)* (b \in `[a, b]) * (b \in `]a, b]) | BOpen a, BClose b => (a <= b) * (a < b) * (b <= a = false) * (a \in `[a, b]) * (a \in `[a, b[)* (b \in `[a, b]) * (b \in `]a, b]) | BOpen a, BOpen b => (a <= b) * (a < b) * (b <= a = false) * (a \in `[a, b]) * (a \in `[a, b[)* (b \in `[a, b]) * (b \in `]a, b]) | _, _ => forall x : R, x == x end)%type. Definition itv_decompose (i : interval R) x : Prop := let: Interval l u := i in ((match l with | BClose a => (a <= x) : Prop | BOpen a => (a < x) : Prop | BInfty => True end : Prop) * (match u with | BClose b => (x <= b) : Prop | BOpen b => (x < b) : Prop | BInfty => True end : Prop))%type. Lemma itv_dec : forall (x : R) (i : interval R), reflect (itv_decompose i x) (x \in i). Proof. by move=> x [[[] a|] [[] b|]]; apply: (iffP andP); case. Qed. Implicit Arguments itv_dec [x i]. Definition lersif (x y : R) b := if b then x < y else x <= y. Local Notation "x <= y ?< 'if' b" := (lersif x y b) (at level 70, y at next level, format "x '[hv' <= y '/' ?< 'if' b ']'") : ring_scope. Lemma lersifxx x b: (x <= x ?< if b) = ~~ b. Proof. by case: b; rewrite /= lterr. Qed. Lemma lersif_trans x y z b1 b2 : x <= y ?< if b1 -> y <= z ?< if b2 -> x <= z ?< if b1 || b2. Proof. move: b1 b2 => [] [] //=; by [exact: ler_trans|exact: ler_lt_trans|exact: ltr_le_trans|exact: ltr_trans]. Qed. Lemma lersifW b x y : x <= y ?< if b -> x <= y. Proof. by case: b => //; move/ltrW. Qed. Lemma lersifNF x y b : y <= x ?< if ~~ b -> x <= y ?< if b = false. Proof. by case: b => /= [/ler_gtF|/ltr_geF]. Qed. Lemma lersifS x y b : x < y -> x <= y ?< if b. Proof. by case: b => //= /ltrW. Qed. Lemma lersifT x y : x <= y ?< if true = (x < y). Proof. by []. Qed. Lemma lersifF x y : x <= y ?< if false = (x <= y). Proof. by []. Qed. Definition le_boundl b1 b2 := match b1, b2 with | BOpen_if b1 x1, BOpen_if b2 x2 => x1 <= x2 ?< if (~~ b2 && b1) | BOpen_if _ _, BInfty => false | _, _ => true end. Definition le_boundr b1 b2 := match b1, b2 with | BOpen_if b1 x1, BOpen_if b2 x2 => x1 <= x2 ?< if (~~ b1 && b2) | BInfty, BOpen_if _ _ => false | _, _ => true end. Lemma itv_boundlr bl br x : (x \in Interval bl br) = (le_boundl bl (BClose x)) && (le_boundr (BClose x) br). Proof. by move: bl br => [[] a|] [[] b|]. Qed. Lemma le_boundr_refl : reflexive le_boundr. Proof. by move=> [[] b|]; rewrite /le_boundr /= ?lerr. Qed. Hint Resolve le_boundr_refl. Lemma le_boundl_refl : reflexive le_boundl. Proof. by move=> [[] b|]; rewrite /le_boundl /= ?lerr. Qed. Hint Resolve le_boundl_refl. Lemma le_boundl_bb x b1 b2 : le_boundl (BOpen_if b1 x) (BOpen_if b2 x) = (b1 ==> b2). Proof. by rewrite /le_boundl lersifxx andbC negb_and negbK implybE. Qed. Lemma le_boundr_bb x b1 b2 : le_boundr (BOpen_if b1 x) (BOpen_if b2 x) = (b2 ==> b1). Proof. by rewrite /le_boundr lersifxx andbC negb_and negbK implybE. Qed. Lemma itv_xx x bl br : Interval (BOpen_if bl x) (BOpen_if br x) =i if ~~ (bl || br) then pred1 x else pred0. Proof. by move: bl br => [] [] y /=; rewrite !inE 1?eq_sym (eqr_le, lter_anti). Qed. Lemma itv_gte ba xa bb xb : xb <= xa ?< if ~~ (ba || bb) -> Interval (BOpen_if ba xa) (BOpen_if bb xb) =i pred0. Proof. move=> hx y; rewrite itv_boundlr inE /=. by apply/negP => /andP [] /lersif_trans hy /hy {hy}; rewrite lersifNF. Qed. Lemma boundl_in_itv : forall ba xa b, xa \in Interval (BOpen_if ba xa) b = if ba then false else le_boundr (BClose xa) b. Proof. by move=> [] xa [[] xb|] //=; rewrite inE lterr. Qed. Lemma boundr_in_itv : forall bb xb a, xb \in Interval a (BOpen_if bb xb) = if bb then false else le_boundl a (BClose xb). Proof. by move=> [] xb [[] xa|] //=; rewrite inE lterr ?andbT ?andbF. Qed. Definition bound_in_itv := (boundl_in_itv, boundr_in_itv). Lemma itvP : forall (x : R) (i : interval R), (x \in i) -> itv_rewrite i x. Proof. move=> x [[[] a|] [[] b|]]; move/itv_dec=> //= [hl hu];do ?[split=> //; do ?[by rewrite ltrW | by rewrite ltrWN | by rewrite ltrNW | by rewrite (ltr_geF, ler_gtF)]]; rewrite ?(bound_in_itv) /le_boundl /le_boundr //=; do ? [ by rewrite (@ler_trans _ x) | by rewrite 1?ltrW // (@ltr_le_trans _ x) | by rewrite 1?ltrW // (@ler_lt_trans _ x) // 1?ltrW | by apply: negbTE; rewrite ler_gtF // (@ler_trans _ x) | by apply: negbTE; rewrite ltr_geF // (@ltr_le_trans _ x) // 1?ltrW | by apply: negbTE; rewrite ltr_geF // (@ler_lt_trans _ x)]. Qed. Hint Rewrite intP. Implicit Arguments itvP [x i]. Definition subitv (i1 i2 : interval R) := match i1, i2 with | Interval a1 b1, Interval a2 b2 => le_boundl a2 a1 && le_boundr b1 b2 end. Lemma subitvP : forall (i2 i1 : interval R), (subitv i1 i2) -> {subset i1 <= i2}. Proof. by move=> [[[] a2|] [[] b2|]] [[[] a1|] [[] b1|]]; rewrite /subitv //; case/andP=> /= ha hb; move=> x hx; rewrite ?inE; rewrite ?(ler_trans ha) ?(ler_lt_trans ha) ?(ltr_le_trans ha) //; rewrite ?(ler_trans _ hb) ?(ltr_le_trans _ hb) ?(ler_lt_trans _ hb) //; rewrite ?(itvP hx) //. Qed. Lemma subitvPr : forall (a b1 b2 : itv_bound R), le_boundr b1 b2 -> {subset (Interval a b1) <= (Interval a b2)}. Proof. by move=> a b1 b2 hb; apply: subitvP=> /=; rewrite hb andbT. Qed. Lemma subitvPl : forall (a1 a2 b : itv_bound R), le_boundl a2 a1 -> {subset (Interval a1 b) <= (Interval a2 b)}. Proof. by move=> a1 a2 b ha; apply: subitvP=> /=; rewrite ha /=. Qed. Lemma lersif_in_itv : forall ba bb xa xb x, x \in Interval (BOpen_if ba xa) (BOpen_if bb xb) -> xa <= xb ?< if ba || bb. Proof. by move=> ba bb xa xb y; rewrite itv_boundlr; case/andP; apply: lersif_trans. Qed. Lemma ltr_in_itv : forall ba bb xa xb x, ba || bb -> x \in Interval (BOpen_if ba xa) (BOpen_if bb xb) -> xa < xb. Proof. move=> ba bb xa xb x; case bab: (_ || _) => // _. by move/lersif_in_itv; rewrite bab. Qed. Lemma ler_in_itv : forall ba bb xa xb x, x \in Interval (BOpen_if ba xa) (BOpen_if bb xb) -> xa <= xb. Proof. by move=> ba bb xa xb x; move/lersif_in_itv; move/lersifW. Qed. Lemma mem0_itvcc_xNx : forall x, (0 \in `[-x, x]) = (0 <= x). Proof. by move=> x; rewrite !inE; case hx: (0 <= _); rewrite (andbT, andbF) ?ge0_cp. Qed. Lemma mem0_itvoo_xNx : forall x, 0 \in `](-x), x[ = (0 < x). Proof. by move=> x; rewrite !inE; case hx: (0 < _); rewrite (andbT, andbF) ?gt0_cp. Qed. Lemma itv_splitI : forall a b, forall x, x \in Interval a b = (x \in Interval a (BInfty _)) && (x \in Interval (BInfty _) b). Proof. by move=> [[] a|] [[] b|] x; rewrite ?inE ?andbT. Qed. Lemma real_lersifN x y b : x \in Num.real -> y \in Num.real -> x <= y ?< if ~~b = ~~ (y <= x ?< if b). Proof. by case: b => [] xR yR /=; rewrite (real_ltrNge, real_lerNgt). Qed. Lemma oppr_itv ba bb (xa xb x : R) : (-x \in Interval (BOpen_if ba xa) (BOpen_if bb xb)) = (x \in Interval (BOpen_if bb (-xb)) (BOpen_if ba (-xa))). Proof. by move: ba bb => [] []; rewrite ?inE lter_oppr andbC lter_oppl. Qed. Lemma oppr_itvoo (a b x : R) : (-x \in `]a, b[) = (x \in `](-b), (-a)[). Proof. exact: oppr_itv. Qed. Lemma oppr_itvco (a b x : R) : (-x \in `[a, b[) = (x \in `](-b), (-a)]). Proof. exact: oppr_itv. Qed. Lemma oppr_itvoc (a b x : R) : (-x \in `]a, b]) = (x \in `[(-b), (-a)[). Proof. exact: oppr_itv. Qed. Lemma oppr_itvcc (a b x : R) : (-x \in `[a, b]) = (x \in `[(-b), (-a)]). Proof. exact: oppr_itv. Qed. End IntervalPo. Notation BOpen := (BOpen_if true). Notation BClose := (BOpen_if false). Notation "`[ a , b ]" := (Interval (BClose a) (BClose b)) (at level 0, a, b at level 9 , format "`[ a , b ]") : ring_scope. Notation "`] a , b ]" := (Interval (BOpen a) (BClose b)) (at level 0, a, b at level 9 , format "`] a , b ]") : ring_scope. Notation "`[ a , b [" := (Interval (BClose a) (BOpen b)) (at level 0, a, b at level 9 , format "`[ a , b [") : ring_scope. Notation "`] a , b [" := (Interval (BOpen a) (BOpen b)) (at level 0, a, b at level 9 , format "`] a , b [") : ring_scope. Notation "`] '-oo' , b ]" := (Interval (BInfty _) (BClose b)) (at level 0, b at level 9 , format "`] '-oo' , b ]") : ring_scope. Notation "`] '-oo' , b [" := (Interval (BInfty _) (BOpen b)) (at level 0, b at level 9 , format "`] '-oo' , b [") : ring_scope. Notation "`[ a , '+oo' [" := (Interval (BClose a) (BInfty _)) (at level 0, a at level 9 , format "`[ a , '+oo' [") : ring_scope. Notation "`] a , '+oo' [" := (Interval (BOpen a) (BInfty _)) (at level 0, a at level 9 , format "`] a , '+oo' [") : ring_scope. Notation "`] -oo , '+oo' [" := (Interval (BInfty _) (BInfty _)) (at level 0, format "`] -oo , '+oo' [") : ring_scope. Notation "x <= y ?< 'if' b" := (lersif x y b) (at level 70, y at next level, format "x '[hv' <= y '/' ?< 'if' b ']'") : ring_scope. Section IntervalOrdered. Variable R : realDomainType. Lemma lersifN (x y : R) b : (x <= y ?< if ~~ b) = ~~ (y <= x ?< if b). Proof. by rewrite real_lersifN ?num_real. Qed. Lemma itv_splitU (xc : R) bc a b : xc \in Interval a b -> forall y, y \in Interval a b = (y \in Interval a (BOpen_if (~~ bc) xc)) || (y \in Interval (BOpen_if bc xc) b). Proof. move=> hxc y; rewrite !itv_boundlr [le_boundr]lock /=. have [la /=|nla /=] := boolP (le_boundl a _); rewrite -lock. have [lb /=|nlb /=] := boolP (le_boundr _ b); rewrite ?andbT ?andbF ?orbF //. by case: bc => //=; case: ltrgtP. symmetry; apply: contraNF nlb; rewrite /le_boundr /=. case: b hxc => // bb xb hxc hyc. suff /(lersif_trans hyc) : xc <= xb ?< if bb. by case: bc {hyc} => //= /lersifS. by case: a bb hxc {la} => [[] ?|] [] /= /itvP->. symmetry; apply: contraNF nla => /andP [hc _]. case: a hxc hc => [[] xa|] hxc; rewrite /le_boundl //=. by move=> /lersifW /(ltr_le_trans _) -> //; move: b hxc=> [[] ?|] /itvP->. by move=> /lersifW /(ler_trans _) -> //; move: b hxc=> [[] ?|] /itvP->. Qed. Lemma itv_splitU2 (x : R) a b : x \in Interval a b -> forall y, y \in Interval a b = [|| (y \in Interval a (BOpen x)), (y == x) | (y \in Interval (BOpen x) b)]. Proof. move=> xab y; rewrite (itv_splitU false xab y); congr (_ || _). rewrite (@itv_splitU x true _ _ _ y); first by rewrite itv_xx inE. by move: xab; rewrite boundl_in_itv itv_boundlr => /andP []. Qed. End IntervalOrdered. Section IntervalField. Variable R : realFieldType. Lemma mid_in_itv : forall ba bb (xa xb : R), xa <= xb ?< if (ba || bb) -> mid xa xb \in Interval (BOpen_if ba xa) (BOpen_if bb xb). Proof. by move=> [] [] xa xb /= hx; apply/itv_dec=> /=; rewrite ?midf_lte // ?ltrW. Qed. Lemma mid_in_itvoo : forall (xa xb : R), xa < xb -> mid xa xb \in `]xa, xb[. Proof. by move=> xa xb hx; apply: mid_in_itv. Qed. Lemma mid_in_itvcc : forall (xa xb : R), xa <= xb -> mid xa xb \in `[xa, xb]. Proof. by move=> xa xb hx; apply: mid_in_itv. Qed. End IntervalField. mathcomp-1.5/theories/binomial.v0000644000175000017500000005457112307636117016000 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq path div. Require Import fintype tuple finfun bigop prime finset. (******************************************************************************) (* This files contains the definition of: *) (* n ^_ m == the falling (or lower) factorial of n with m terms, i.e., *) (* the product n * (n - 1) * ... * (n - m + 1) *) (* Note that n ^_ m = 0 if m > n. *) (* 'C(n, m) == the binomial coeficient n choose m *) (* := n ^_ m %/ fact m *) (* *) (* In additions to the properties of these functions, triangular_sum, Wilson *) (* and Pascal are examples of how to manipulate expressions with bigops. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. (** More properties of the factorial **) Lemma fact_smonotone m n : 0 < m -> m < n -> m`! < n`!. Proof. case: m => // m _; elim: n m => // n IHn [|m] lt_m_n. by rewrite -[_.+1]muln1 leq_mul ?fact_gt0. by rewrite ltn_mul ?IHn. Qed. Lemma fact_prod n : n`! = \prod_(1 <= i < n.+1) i. Proof. elim: n => [|n IHn] //; first by rewrite big_nil. by apply sym_equal; rewrite factS IHn // !big_add1 big_nat_recr //= mulnC. Qed. Lemma logn_fact p n : prime p -> logn p n`! = \sum_(1 <= k < n.+1) n %/ p ^ k. Proof. move=> p_prime; transitivity (\sum_(1 <= i < n.+1) logn p i). rewrite big_add1; elim: n => /= [|n IHn]; first by rewrite logn1 big_geq. by rewrite big_nat_recr // -IHn /= factS mulnC lognM ?fact_gt0. transitivity (\sum_(1 <= i < n.+1) \sum_(1 <= k < n.+1) (p ^ k %| i)). apply: eq_big_nat => i /andP[i_gt0 le_i_n]; rewrite logn_count_dvd //. rewrite -!big_mkcond (big_nat_widen _ _ n.+1) 1?ltnW //; apply: eq_bigl => k. by apply: andb_idr => /dvdn_leq/(leq_trans (ltn_expl _ (prime_gt1 _)))->. by rewrite exchange_big_nat; apply: eq_bigr => i _; rewrite divn_count_dvd. Qed. Theorem Wilson p : p > 1 -> prime p = (p %| ((p.-1)`!).+1). Proof. have dFact n: 0 < n -> (n.-1)`! = \prod_(0 <= i < n | i != 0) i. move=> n_gt0; rewrite -big_filter fact_prod; symmetry; apply: congr_big => //. rewrite /index_iota subn1 -[n]prednK //=; apply/all_filterP. by rewrite all_predC has_pred1 mem_iota. move=> lt1p; have p_gt0 := ltnW lt1p. apply/idP/idP=> [pr_p | dv_pF]; last first. apply/primeP; split=> // d dv_dp; have: d <= p by exact: dvdn_leq. rewrite orbC leq_eqVlt => /orP[-> // | ltdp]. have:= dvdn_trans dv_dp dv_pF; rewrite dFact // big_mkord. rewrite (bigD1 (Ordinal ltdp)) /=; last by rewrite -lt0n (dvdn_gt0 p_gt0). by rewrite orbC -addn1 dvdn_addr ?dvdn_mulr // dvdn1 => ->. pose Fp1 := Ordinal lt1p; pose Fp0 := Ordinal p_gt0. have ltp1p: p.-1 < p by [rewrite prednK]; pose Fpn1 := Ordinal ltp1p. case eqF1n1: (Fp1 == Fpn1); first by rewrite -{1}[p]prednK -1?((1 =P p.-1) _). have toFpP m: m %% p < p by rewrite ltn_mod. pose toFp := Ordinal (toFpP _); pose mFp (i j : 'I_p) := toFp (i * j). have Fp_mod (i : 'I_p) : i %% p = i by exact: modn_small. have mFpA: associative mFp. by move=> i j k; apply: val_inj; rewrite /= modnMml modnMmr mulnA. have mFpC: commutative mFp by move=> i j; apply: val_inj; rewrite /= mulnC. have mFp1: left_id Fp1 mFp by move=> i; apply: val_inj; rewrite /= mul1n. have mFp1r: right_id Fp1 mFp by move=> i; apply: val_inj; rewrite /= muln1. pose mFpLaw := Monoid.Law mFpA mFp1 mFp1r. pose mFpM := Monoid.operator (@Monoid.ComLaw _ _ mFpLaw mFpC). pose vFp (i : 'I_p) := toFp (egcdn i p).1. have vFpV i: i != Fp0 -> mFp (vFp i) i = Fp1. rewrite -val_eqE /= -lt0n => i_gt0; apply: val_inj => /=. rewrite modnMml; case: egcdnP => //= _ km -> _; rewrite {km}modnMDl. suffices: coprime i p by move/eqnP->; rewrite modn_small. rewrite coprime_sym prime_coprime //; apply/negP=> /(dvdn_leq i_gt0). by rewrite leqNgt ltn_ord. have vFp0 i: i != Fp0 -> vFp i != Fp0. move/vFpV=> inv_i; apply/eqP=> vFp0. by have:= congr1 val inv_i; rewrite vFp0 /= mod0n. have vFpK: {in predC1 Fp0, involutive vFp}. move=> i n0i; rewrite /= -[vFp _]mFp1r -(vFpV _ n0i) mFpA. by rewrite vFpV (vFp0, mFp1). have le_pmFp (i : 'I_p) m: i <= p + m. by apply: leq_trans (ltnW _) (leq_addr _ _). have eqFp (i j : 'I_p): (i == j) = (p %| p + i - j). by rewrite -eqn_mod_dvd ?(modnDl, Fp_mod). have vFpId i: (vFp i == i :> nat) = xpred2 Fp1 Fpn1 i. symmetry; have [->{i} | /eqP ni0] := i =P Fp0. by rewrite /= -!val_eqE /= -{2}[p]prednK //= modn_small //= -(subnKC lt1p). rewrite 2!eqFp -Euclid_dvdM //= -[_ - p.-1]subSS prednK //. have lt0i: 0 < i by rewrite lt0n. rewrite -addnS addKn -addnBA // mulnDl -{2}(addn1 i) -subn_sqr. rewrite addnBA ?leq_sqr // mulnS -addnA -mulnn -mulnDl. rewrite -(subnK (le_pmFp (vFp i) i)) mulnDl addnCA. rewrite -[1 ^ 2]/(Fp1 : nat) -addnBA // dvdn_addl. by rewrite Euclid_dvdM // -eqFp eq_sym orbC /dvdn Fp_mod eqn0Ngt lt0i. by rewrite -eqn_mod_dvd // Fp_mod modnDl -(vFpV _ ni0) eqxx. suffices [mod_fact]: toFp (p.-1)`! = Fpn1. by rewrite /dvdn -addn1 -modnDml mod_fact addn1 prednK // modnn. rewrite dFact //; rewrite ((big_morph toFp) Fp1 mFpM) //; first last. - by apply: val_inj; rewrite /= modn_small. - by move=> i j; apply: val_inj; rewrite /= modnMm. rewrite big_mkord (eq_bigr id) => [|i _]; last by apply: val_inj => /=. pose ltv i := vFp i < i; rewrite (bigID ltv) -/mFpM [mFpM _ _]mFpC. rewrite (bigD1 Fp1) -/mFpM; last by rewrite [ltv _]ltn_neqAle vFpId. rewrite [mFpM _ _]mFp1 (bigD1 Fpn1) -?mFpA -/mFpM; last first. rewrite -lt0n -ltnS prednK // lt1p. by rewrite [ltv _]ltn_neqAle vFpId eqxx orbT eq_sym eqF1n1. rewrite (reindex_onto vFp vFp) -/mFpM => [|i]; last by do 3!case/andP; auto. rewrite (eq_bigl (xpredD1 ltv Fp0)) => [|i]; last first. rewrite andbC -!andbA -2!negb_or -vFpId orbC -leq_eqVlt. rewrite andbA -ltnNge; symmetry; case: (altP eqP) => [->|ni0]. by case: eqP => // E; rewrite ?E !andbF. by rewrite vFpK //eqxx vFp0. rewrite -{2}[mFp]/mFpM -[mFpM _ _]big_split -/mFpM. by rewrite big1 ?mFp1r //= => i /andP[]; auto. Qed. (** The falling factorial *) Fixpoint ffact_rec n m := if m is m'.+1 then n * ffact_rec n.-1 m' else 1. Definition falling_factorial := nosimpl ffact_rec. Notation "n ^_ m" := (falling_factorial n m) (at level 30, right associativity) : nat_scope. Lemma ffactE : falling_factorial = ffact_rec. Proof. by []. Qed. Lemma ffactn0 n : n ^_ 0 = 1. Proof. by []. Qed. Lemma ffact0n m : 0 ^_ m = (m == 0). Proof. by case: m. Qed. Lemma ffactnS n m : n ^_ m.+1 = n * n.-1 ^_ m. Proof. by []. Qed. Lemma ffactSS n m : n.+1 ^_ m.+1 = n.+1 * n ^_ m. Proof. by []. Qed. Lemma ffactn1 n : n ^_ 1 = n. Proof. exact: muln1. Qed. Lemma ffactnSr n m : n ^_ m.+1 = n ^_ m * (n - m). Proof. elim: n m => [|n IHn] [|m] //=; first by rewrite ffactn1 mul1n. by rewrite !ffactSS IHn mulnA. Qed. Lemma ffact_gt0 n m : (0 < n ^_ m) = (m <= n). Proof. by elim: n m => [|n IHn] [|m] //=; rewrite ffactSS muln_gt0 IHn. Qed. Lemma ffact_small n m : n < m -> n ^_ m = 0. Proof. by rewrite ltnNge -ffact_gt0; case: posnP. Qed. Lemma ffactnn n : n ^_ n = n`!. Proof. by elim: n => [|n IHn] //; rewrite ffactnS IHn. Qed. Lemma ffact_fact n m : m <= n -> n ^_ m * (n - m)`! = n`!. Proof. by elim: n m => [|n IHn] [|m] //= le_m_n; rewrite ?mul1n // -mulnA IHn. Qed. Lemma ffact_factd n m : m <= n -> n ^_ m = n`! %/ (n - m)`!. Proof. by move/ffact_fact <-; rewrite mulnK ?fact_gt0. Qed. (** Binomial coefficients *) Fixpoint binomial_rec n m := match n, m with | n'.+1, m'.+1 => binomial_rec n' m + binomial_rec n' m' | _, 0 => 1 | 0, _.+1 => 0 end. Definition binomial := nosimpl binomial_rec. Notation "''C' ( n , m )" := (binomial n m) (at level 8, format "''C' ( n , m )") : nat_scope. Lemma binE : binomial = binomial_rec. Proof. by []. Qed. Lemma bin0 n : 'C(n, 0) = 1. Proof. by case: n. Qed. Lemma bin0n m : 'C(0, m) = (m == 0). Proof. by case: m. Qed. Lemma binS n m : 'C(n.+1, m.+1) = 'C(n, m.+1) + 'C(n, m). Proof. by []. Qed. Lemma bin1 n : 'C(n, 1) = n. Proof. by elim: n => //= n IHn; rewrite binS bin0 IHn addn1. Qed. Lemma bin_gt0 m n : (0 < 'C(m, n)) = (n <= m). Proof. elim: m n => [|m IHm] [|n] //. by rewrite binS addn_gt0 !IHm orbC ltn_neqAle andKb. Qed. Lemma leq_bin2l m1 m2 n : m1 <= m2 -> 'C(m1, n) <= 'C(m2, n). Proof. elim: m1 m2 n => [m2 | m1 IHm [|m2] //] [|n] le_m12; rewrite ?bin0 //. by rewrite !binS leq_add // IHm. Qed. Lemma bin_small n m : n < m -> 'C(n, m) = 0. Proof. by rewrite ltnNge -bin_gt0; case: posnP. Qed. Lemma binn n : 'C(n, n) = 1. Proof. by elim: n => [|n IHn] //; rewrite binS bin_small. Qed. Lemma mul_Sm_binm m n : m.+1 * 'C(m, n) = n.+1 * 'C(m.+1, n.+1). Proof. elim: m n => [|m IHm] [|n] //; first by rewrite bin0 bin1 muln1 mul1n. by rewrite mulSn {2}binS mulnDr addnCA !IHm -mulnDr. Qed. Lemma bin_fact m n : n <= m -> 'C(m, n) * (n`! * (m - n)`!) = m`!. Proof. move/subnKC; move: (m - n) => m0 <-{m}. elim: n => [|n IHn]; first by rewrite bin0 !mul1n. by rewrite -mulnA mulnCA mulnA -mul_Sm_binm -mulnA IHn. Qed. (* In fact the only exception is n = 0 and m = 1 *) Lemma bin_factd n m : 0 < n -> 'C(n, m) = n`! %/ (m`! * (n - m)`!). Proof. move=> n_gt0; have [/bin_fact <-|lt_n_m] := leqP m n. by rewrite mulnK // muln_gt0 !fact_gt0. by rewrite bin_small // divnMA !divn_small ?fact_gt0 // fact_smonotone. Qed. Lemma bin_ffact n m : 'C(n, m) * m`! = n ^_ m. Proof. apply/eqP; have [lt_n_m | le_m_n] := ltnP n m. by rewrite bin_small ?ffact_small. by rewrite -(eqn_pmul2r (fact_gt0 (n - m))) ffact_fact // -mulnA bin_fact. Qed. Lemma bin_ffactd n m : 'C(n, m) = n ^_ m %/ m`!. Proof. by rewrite -bin_ffact mulnK ?fact_gt0. Qed. Lemma bin_sub n m : m <= n -> 'C(n, n - m) = 'C(n, m). Proof. move=> le_m_n; apply/eqP; move/eqP: (bin_fact (leq_subr m n)). by rewrite subKn // -(bin_fact le_m_n) !mulnA mulnAC !eqn_pmul2r // fact_gt0. Qed. Lemma binSn n : 'C(n.+1, n) = n.+1. Proof. by rewrite -bin_sub ?leqnSn // subSnn bin1. Qed. Lemma bin2 n : 'C(n, 2) = (n * n.-1)./2. Proof. by case: n => //= n; rewrite -{3}[n]bin1 mul_Sm_binm mul2n half_double. Qed. Lemma bin2odd n : odd n -> 'C(n, 2) = n * n.-1./2. Proof. by case: n => // n oddn; rewrite bin2 -!divn2 muln_divA ?dvdn2. Qed. Lemma prime_dvd_bin k p : prime p -> 0 < k < p -> p %| 'C(p, k). Proof. move=> p_pr /andP[k_gt0 lt_k_p]; have def_p := ltn_predK lt_k_p. have: p %| p * 'C(p.-1, k.-1) by rewrite dvdn_mulr. by rewrite -def_p mul_Sm_binm def_p prednK // Euclid_dvdM // gtnNdvd. Qed. Lemma triangular_sum n : \sum_(0 <= i < n) i = 'C(n, 2). Proof. elim: n => [|n IHn]; first by rewrite big_geq. by rewrite big_nat_recr // IHn binS bin1. Qed. Lemma textbook_triangular_sum n : \sum_(0 <= i < n) i = 'C(n, 2). Proof. rewrite bin2; apply: canRL half_double _. rewrite -addnn {1}big_nat_rev -big_split big_mkord /= ?add0n. rewrite (eq_bigr (fun _ => n.-1)); first by rewrite sum_nat_const card_ord. by case: n => [|n] [i le_i_n] //=; rewrite subSS subnK. Qed. Theorem Pascal a b n : (a + b) ^ n = \sum_(i < n.+1) 'C(n, i) * (a ^ (n - i) * b ^ i). Proof. elim: n => [|n IHn]; rewrite big_ord_recl muln1 ?big_ord0 //. rewrite expnS {}IHn /= mulnDl !big_distrr /= big_ord_recl muln1 subn0. rewrite !big_ord_recr /= !binn !subnn bin0 !subn0 !mul1n -!expnS -addnA. congr (_ + _); rewrite addnA -big_split /=; congr (_ + _). apply: eq_bigr => i _; rewrite mulnCA (mulnA a) -expnS subnSK //=. by rewrite (mulnC b) -2!mulnA -expnSr -mulnDl. Qed. Definition expnDn := Pascal. Lemma Vandermonde k l i : \sum_(j < i.+1) 'C(k, j) * 'C(l, i - j) = 'C(k + l , i). Proof. pose f k i := \sum_(j < i.+1) 'C(k, j) * 'C(l, i - j). suffices{k i} fxx k i: f k.+1 i.+1 = f k i.+1 + f k i. elim: k i => [i | k IHk [|i]]; last by rewrite -/(f _ _) fxx /f !IHk -binS. by rewrite big_ord_recl big1_eq addn0 mul1n subn0. by rewrite big_ord_recl big_ord0 addn0 !bin0 muln1. rewrite {}/f big_ord_recl (big_ord_recl (i.+1)) !bin0 !mul1n. rewrite -addnA -big_split /=; congr (_ + _). by apply: eq_bigr => j _ ; rewrite -mulnDl. Qed. Lemma subn_exp m n k : m ^ k - n ^ k = (m - n) * (\sum_(i < k) m ^ (k.-1 -i) * n ^ i). Proof. case: k => [|k]; first by rewrite big_ord0. rewrite mulnBl !big_distrr big_ord_recl big_ord_recr /= subn0 muln1. rewrite subnn mul1n -!expnS subnDA; congr (_ - _); apply: canRL (addnK _) _. congr (_ + _); apply: eq_bigr => i _. by rewrite (mulnCA n) -expnS mulnA -expnS subnSK /=. Qed. Lemma predn_exp m k : (m ^ k).-1 = m.-1 * (\sum_(i < k) m ^ i). Proof. rewrite -!subn1 -{1}(exp1n k) subn_exp; congr (_ * _). symmetry; rewrite (reindex_inj rev_ord_inj); apply: eq_bigr => i _ /=. by rewrite -subn1 -subnDA exp1n muln1. Qed. Lemma dvdn_pred_predX n e : (n.-1 %| (n ^ e).-1)%N. Proof. by rewrite predn_exp dvdn_mulr. Qed. Lemma modn_summ I r (P : pred I) F d : \sum_(i <- r | P i) F i %% d = \sum_(i <- r | P i) F i %[mod d]. Proof. by apply/eqP; elim/big_rec2: _ => // i m n _; rewrite modnDml eqn_modDl. Qed. (* Combinatorial characterizations. *) Section Combinations. Implicit Types T D : finType. Lemma card_uniq_tuples T n (A : pred T) : #|[set t : n.-tuple T | all A t & uniq t]| = #|A| ^_ n. Proof. elim: n A => [|n IHn] A. by rewrite (@eq_card1 _ [tuple]) // => t; rewrite [t]tuple0 inE. rewrite -sum1dep_card (partition_big (@thead _ _) A) /= => [|t]; last first. by case/tupleP: t => x t; do 2!case/andP. transitivity (#|A| * #|A|.-1 ^_ n)%N; last by case: #|A|. rewrite -sum_nat_const; apply: eq_bigr => x Ax. rewrite (cardD1 x) [x \in A]Ax /= -(IHn [predD1 A & x]) -sum1dep_card. rewrite (reindex (fun t : n.-tuple T => [tuple of x :: t])) /=; last first. pose ttail (t : n.+1.-tuple T) := [tuple of behead t]. exists ttail => [t _ | t /andP[_ /eqP <-]]; first exact: val_inj. by rewrite -tuple_eta. apply: eq_bigl=> t; rewrite Ax theadE eqxx andbT /= andbA; congr (_ && _). by rewrite all_predI all_predC has_pred1 andbC. Qed. Lemma card_inj_ffuns_on D T (R : pred T) : #|[set f : {ffun D -> T} in ffun_on R | injectiveb f]| = #|R| ^_ #|D|. Proof. rewrite -card_uniq_tuples. have bijFF: {on (_ : pred _), bijective (@Finfun D T)}. by exists val => // x _; exact: val_inj. rewrite -(on_card_preimset (bijFF _)); apply: eq_card => t. rewrite !inE -(codom_ffun (Finfun t)); congr (_ && _); apply: negb_inj. by rewrite -has_predC has_map enumT has_filter -size_eq0 -cardE. Qed. Lemma card_inj_ffuns D T : #|[set f : {ffun D -> T} | injectiveb f]| = #|T| ^_ #|D|. Proof. rewrite -card_inj_ffuns_on; apply: eq_card => f. by rewrite 2!inE; case: ffun_onP => // []. Qed. Lemma card_draws T k : #|[set A : {set T} | #|A| == k]| = 'C(#|T|, k). Proof. have [ltTk | lekT] := ltnP #|T| k. rewrite bin_small // eq_card0 // => A. by rewrite inE eqn_leq andbC leqNgt (leq_ltn_trans (max_card _)). apply/eqP; rewrite -(eqn_pmul2r (fact_gt0 k)) bin_ffact // eq_sym. rewrite -sum_nat_dep_const -{1 3}(card_ord k) -card_inj_ffuns -sum1dep_card. pose imIk (f : {ffun 'I_k -> T}) := f @: 'I_k. rewrite (partition_big imIk (fun A => #|A| == k)) /= => [|f]; last first. by move/injectiveP=> inj_f; rewrite card_imset ?card_ord. apply/eqP; apply: eq_bigr => A /eqP cardAk. have [f0 inj_f0 im_f0]: exists2 f, injective f & f @: 'I_k = A. rewrite -cardAk; exists enum_val; first exact: enum_val_inj. apply/setP=> a; apply/imsetP/idP=> [[i _ ->] | Aa]; first exact: enum_valP. by exists (enum_rank_in Aa a); rewrite ?enum_rankK_in. rewrite (reindex (fun p : {ffun _} => [ffun i => f0 (p i)])) /=; last first. pose ff0' f i := odflt i [pick j | f i == f0 j]. exists (fun f => [ffun i => ff0' f i]) => [p _ | f]. apply/ffunP=> i; rewrite ffunE /ff0'; case: pickP => [j | /(_ (p i))]. by rewrite ffunE (inj_eq inj_f0) => /eqP. by rewrite ffunE eqxx. rewrite -im_f0 => /andP[/injectiveP injf /eqP im_f]. apply/ffunP=> i; rewrite !ffunE /ff0'; case: pickP => [y /eqP //|]. have /imsetP[j _ eq_f0j_fi]: f i \in f0 @: 'I_k by rewrite -im_f mem_imset. by move/(_ j)=> /eqP[]. rewrite -ffactnn -card_inj_ffuns -sum1dep_card; apply: eq_bigl => p. apply/andP/injectiveP=> [[/injectiveP inj_f0p _] i j eq_pij | inj_p]. by apply: inj_f0p; rewrite !ffunE eq_pij. set f := finfun _. have injf: injective f by move=> i j; rewrite !ffunE => /inj_f0; exact: inj_p. split; first exact/injectiveP. rewrite eqEcard card_imset // cardAk card_ord leqnn andbT -im_f0. by apply/subsetP=> x /imsetP[i _ ->]; rewrite ffunE mem_imset. Qed. Lemma card_ltn_sorted_tuples m n : #|[set t : m.-tuple 'I_n | sorted ltn (map val t)]| = 'C(n, m). Proof. have [-> | n_gt0] := posnP n; last pose i0 := Ordinal n_gt0. case: m => [|m]; last by apply: eq_card0; case/tupleP=> [[]]. by apply: (@eq_card1 _ [tuple]) => t; rewrite [t]tuple0 inE. rewrite -{12}[n]card_ord -card_draws. pose f_t (t : m.-tuple 'I_n) := [set i in t]. pose f_A (A : {set 'I_n}) := [tuple of mkseq (nth i0 (enum A)) m]. have val_fA (A : {set 'I_n}) : #|A| = m -> val (f_A A) = enum A. by move=> Am; rewrite -[enum _](mkseq_nth i0) -cardE Am. have inc_A (A : {set 'I_n}) : sorted ltn (map val (enum A)). rewrite -[enum _](eq_filter (mem_enum _)). rewrite -(eq_filter (mem_map val_inj _)) -filter_map. by rewrite (sorted_filter ltn_trans) // unlock val_ord_enum iota_ltn_sorted. rewrite -!sum1dep_card (reindex_onto f_t f_A) /= => [|A]; last first. by move/eqP=> cardAm; apply/setP=> x; rewrite inE -(mem_enum (mem A)) -val_fA. apply: eq_bigl => t; apply/idP/idP=> [inc_t|]; last first. by case/andP; move/eqP=> t_m; move/eqP=> <-; rewrite val_fA. have ft_m: #|f_t t| = m. rewrite cardsE (card_uniqP _) ?size_tuple // -(map_inj_uniq val_inj). exact: (sorted_uniq ltn_trans ltnn). rewrite ft_m eqxx -val_eqE val_fA // -(inj_eq (inj_map val_inj)) /=. apply/eqP; apply: (eq_sorted_irr ltn_trans ltnn) => // y. by apply/mapP/mapP=> [] [x t_x ->]; exists x; rewrite // mem_enum inE in t_x *. Qed. Lemma card_sorted_tuples m n : #|[set t : m.-tuple 'I_n.+1 | sorted leq (map val t)]| = 'C(m + n, m). Proof. set In1 := 'I_n.+1; pose x0 : In1 := ord0. have add_mnP (i : 'I_m) (x : In1) : i + x < m + n. by rewrite -ltnS -addSn -!addnS leq_add. pose add_mn t i := Ordinal (add_mnP i (tnth t i)). pose add_mn_nat (t : m.-tuple In1) i := i + nth x0 t i. have add_mnC t: val \o add_mn t =1 add_mn_nat t \o val. by move=> i; rewrite /= (tnth_nth x0). pose f_add t := [tuple of map (add_mn t) (ord_tuple m)]. rewrite -card_ltn_sorted_tuples -!sum1dep_card (reindex f_add) /=. apply: eq_bigl => t; rewrite -map_comp (eq_map (add_mnC t)) map_comp. rewrite enumT unlock val_ord_enum -{1}(drop0 t). have [m0 | m_gt0] := posnP m. by rewrite {2}m0 /= drop_oversize // size_tuple m0. have def_m := subnK m_gt0; rewrite -{2}def_m addn1 /= {1}/add_mn_nat. move: 0 (m - 1) def_m => i k; rewrite -{1}(size_tuple t) => def_m. rewrite (drop_nth x0) /=; last by rewrite -def_m leq_addl. elim: k i (nth x0 t i) def_m => [|k IHk] i x /=. by rewrite add0n => ->; rewrite drop_size. rewrite addSnnS => def_m; rewrite -addSn leq_add2l -IHk //. by rewrite (drop_nth x0) // -def_m leq_addl. pose sub_mn (t : m.-tuple 'I_(m + n)) i : In1 := inord (tnth t i - i). exists (fun t => [tuple of map (sub_mn t) (ord_tuple m)]) => [t _ | t]. apply: eq_from_tnth => i; apply: val_inj. by rewrite /sub_mn !(tnth_ord_tuple, tnth_map) addKn inord_val. rewrite inE /= => inc_t; apply: eq_from_tnth => i; apply: val_inj. rewrite tnth_map tnth_ord_tuple /= tnth_map tnth_ord_tuple. suffices [le_i_ti le_ti_ni]: i <= tnth t i /\ tnth t i <= i + n. by rewrite /sub_mn inordK ?subnKC // ltnS leq_subLR. pose y0 := tnth t i; rewrite (tnth_nth y0) -(nth_map _ (val i)) ?size_tuple //. case def_e: (map _ _) => [|x e] /=; first by rewrite nth_nil ?leq_addr. rewrite def_e in inc_t; split. case: {-2}i; rewrite /= -{1}(size_tuple t) -(size_map val) def_e. elim=> //= j IHj lt_j_t; apply: leq_trans (pathP (val i) inc_t _ lt_j_t). by rewrite ltnS IHj 1?ltnW. move: (_ - _) (subnK (valP i)) => k /=. elim: k {-2}(val i) => /= [|k IHk] j def_m; rewrite -ltnS -addSn. by rewrite [j.+1]def_m -def_e (nth_map y0) ?ltn_ord // size_tuple -def_m. rewrite (leq_trans _ (IHk _ _)) -1?addSnnS //; apply: (pathP _ inc_t). rewrite -ltnS (leq_trans (leq_addl k _)) // -addSnnS def_m. by rewrite -(size_tuple t) -(size_map val) def_e. Qed. Lemma card_partial_ord_partitions m n : #|[set t : m.-tuple 'I_n.+1 | \sum_(i <- t) i <= n]| = 'C(m + n, m). Proof. symmetry; set In1 := 'I_n.+1; pose x0 : In1 := ord0. pose add_mn (i j : In1) : In1 := inord (i + j). pose f_add (t : m.-tuple In1) := [tuple of scanl add_mn x0 t]. rewrite -card_sorted_tuples -!sum1dep_card (reindex f_add) /=. apply: eq_bigl => t; rewrite -[\sum_(i <- t) i]add0n. transitivity (path leq x0 (map val (f_add t))) => /=; first by case: map. rewrite -{1 2}[0]/(val x0); elim: {t}(val t) (x0) => /= [|x t IHt] s. by rewrite big_nil addn0 -ltnS ltn_ord. rewrite big_cons addnA IHt /= val_insubd ltnS. have [_ | ltn_n_sx] := leqP (s + x) n; first by rewrite leq_addr. rewrite -(leq_add2r x) leqNgt (leq_trans (valP x)) //=. by rewrite leqNgt (leq_trans ltn_n_sx) ?leq_addr. pose sub_mn (i j : In1) := Ordinal (leq_ltn_trans (leq_subr i j) (valP j)). exists (fun t : m.-tuple In1 => [tuple of pairmap sub_mn x0 t]) => /= t inc_t. apply: val_inj => /=; have{inc_t}: path leq x0 (map val (f_add t)). by move: inc_t; rewrite inE /=; case: map. rewrite [map _ _]/=; elim: {t}(val t) (x0) => //= x t IHt s. case/andP=> le_s_sx /IHt->; congr (_ :: _); apply: val_inj => /=. move: le_s_sx; rewrite val_insubd. case le_sx_n: (_ < n.+1); first by rewrite addKn. by case: (val s) le_sx_n; rewrite ?ltn_ord. apply: val_inj => /=; have{inc_t}: path leq x0 (map val t). by move: inc_t; rewrite inE /=; case: map. elim: {t}(val t) (x0) => //= x t IHt s /andP[le_s_sx inc_t]. suffices ->: add_mn s (sub_mn s x) = x by rewrite IHt. by apply: val_inj; rewrite /add_mn /= subnKC ?inord_val. Qed. Lemma card_ord_partitions m n : #|[set t : m.+1.-tuple 'I_n.+1 | \sum_(i <- t) i == n]| = 'C(m + n, m). Proof. symmetry; set In1 := 'I_n.+1; pose x0 : In1 := ord0. pose f_add (t : m.-tuple In1) := [tuple of sub_ord (\sum_(x <- t) x) :: t]. rewrite -card_partial_ord_partitions -!sum1dep_card (reindex f_add) /=. by apply: eq_bigl => t; rewrite big_cons /= addnC (sameP maxn_idPr eqP) maxnE. exists (fun t : m.+1.-tuple In1 => [tuple of behead t]) => [t _|]. exact: val_inj. case/tupleP=> x t; rewrite inE /= big_cons => /eqP def_n. by apply: val_inj; congr (_ :: _); apply: val_inj; rewrite /= -{1}def_n addnK. Qed. End Combinations. mathcomp-1.5/theories/primitive_action.v0000644000175000017500000003534212307636117017546 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat. Require Import div seq fintype tuple finset. Require Import fingroup action gseries. (******************************************************************************) (* n-transitive and primitive actions: *) (* [primitive A, on S | to] <=> *) (* A acts on S in a primitive manner, i.e., A is transitive on S and *) (* A does not act on any nontrivial partition of S. *) (* imprimitivity_system A to S Q <=> *) (* Q is a non-trivial primitivity system for the action of A on S via *) (* to, i.e., Q is a non-trivial partiiton of S on which A acts. *) (* to * n == in the %act scope, the total action induced by the total *) (* action to on n.-tuples. via n_act to n. *) (* n.-dtuple S == the set of n-tuples with distinct values in S. *) (* [transitive^n A, on S | to] <=> *) (* A is n-transitive on S, i.e., A is transitive on n.-dtuple S *) (* == the set of n-tuples with distinct values in S. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section PrimitiveDef. Variables (aT : finGroupType) (sT : finType). Variables (A : {set aT}) (S : {set sT}) (to : {action aT &-> sT}). Definition imprimitivity_system Q := [&& partition Q S, [acts A, on Q | to^*] & 1 < #|Q| < #|S|]. Definition primitive := [transitive A, on S | to] && ~~ [exists Q, imprimitivity_system Q]. End PrimitiveDef. Arguments Scope imprimitivity_system [_ _ group_scope group_scope action_scope group_scope]. Arguments Scope primitive [_ _ group_scope group_scope action_scope]. Notation "[ 'primitive' A , 'on' S | to ]" := (primitive A S to) (at level 0, format "[ 'primitive' A , 'on' S | to ]") : form_scope. Prenex Implicits imprimitivity_system. Section Primitive. Variables (aT : finGroupType) (sT : finType). Variables (G : {group aT}) (to : {action aT &-> sT}) (S : {set sT}). Lemma trans_prim_astab x : x \in S -> [transitive G, on S | to] -> [primitive G, on S | to] = maximal_eq 'C_G[x | to] G. Proof. move=> Sx trG; rewrite /primitive trG negb_exists. apply/forallP/maximal_eqP=> /= [primG | [_ maxCx] Q]. split=> [|H sCH sHG]; first exact: subsetIl. pose X := orbit to H x; pose Q := orbit (to^*)%act G X. have Xx: x \in X by exact: orbit_refl. have defH: 'N_(G)(X | to) = H. have trH: [transitive H, on X | to] by apply/imsetP; exists x. have sHN: H \subset 'N_G(X | to) by rewrite subsetI sHG atrans_acts. move/(subgroup_transitiveP Xx sHN): (trH) => /= <-. by rewrite mulSGid //= setIAC subIset ?sCH. apply/imsetP; exists x => //; apply/eqP. by rewrite eqEsubset imsetS // acts_sub_orbit ?subsetIr. have [|/proper_card oCH] := eqVproper sCH; [by left | right]. apply/eqP; rewrite eqEcard sHG leqNgt. apply: contra {primG}(primG Q) => oHG; apply/and3P; split; last first. - rewrite card_orbit astab1_set defH -(@ltn_pmul2l #|H|) ?Lagrange // muln1. rewrite oHG -(@ltn_pmul2l #|H|) ?Lagrange // -(card_orbit_stab to G x). by rewrite -(atransP trG x Sx) mulnC card_orbit ltn_pmul2r. - by apply/actsP=> a Ga Y; apply: orbit_transr; exact: mem_orbit. apply/and3P; split; last 1 first. - rewrite orbit_sym; apply/imsetP=> [[a _]] /= defX. by rewrite defX /setact imset0 inE in Xx. - apply/eqP/setP=> y; apply/bigcupP/idP=> [[_ /imsetP[a Ga ->]] | Sy]. case/imsetP=> _ /imsetP[b Hb ->] ->. by rewrite !(actsP (atrans_acts trG)) //; exact: subsetP Hb. case: (atransP2 trG Sx Sy) => a Ga ->. by exists ((to^*)%act X a); apply: mem_imset; rewrite // orbit_refl. apply/trivIsetP=> _ _ /imsetP[a Ga ->] /imsetP[b Gb ->]. apply: contraR => /exists_inP[_ /imsetP[_ /imsetP[a1 Ha1 ->] ->]]. case/imsetP=> _ /imsetP[b1 Hb1 ->] /(canLR (actK _ _)) /(canLR (actK _ _)). rewrite -(canF_eq (actKV _ _)) -!actM (sameP eqP astab1P) => /astab1P Cab. rewrite astab1_set (subsetP (subsetIr G _)) //= defH. rewrite -(groupMr _ (groupVr Hb1)) -mulgA -(groupMl _ Ha1). by rewrite (subsetP sCH) // inE Cab !groupM ?groupV // (subsetP sHG). apply/and3P=> [[/and3P[/eqP defS tIQ ntQ]]]; set sto := (to^*)%act => actQ. rewrite !ltnNge -negb_or => /orP[]. pose X := pblock Q x; have Xx: x \in X by rewrite mem_pblock defS. have QX: X \in Q by rewrite pblock_mem ?defS. have toX Y a: Y \in Q -> a \in G -> to x a \in Y -> sto X a = Y. move=> QY Ga Yxa; rewrite -(contraNeq (trivIsetP tIQ Y (sto X a) _ _)) //. by rewrite (actsP actQ). by apply/existsP; exists (to x a); rewrite /= Yxa; apply: mem_imset. have defQ: Q = orbit (to^*)%act G X. apply/eqP; rewrite eqEsubset andbC acts_sub_orbit // QX. apply/subsetP=> Y QY. have /set0Pn[y Yy]: Y != set0 by apply: contraNneq ntQ => <-. have Sy: y \in S by rewrite -defS; apply/bigcupP; exists Y. have [a Ga def_y] := atransP2 trG Sx Sy. by apply/imsetP; exists a; rewrite // (toX Y) // -def_y. rewrite defQ card_orbit; case: (maxCx 'C_G[X | sto]%G) => /= [||->|->]. - apply/subsetP=> a /setIP[Ga cxa]; rewrite inE Ga /=. by apply/astab1P; rewrite (toX X) // (astab1P cxa). - exact: subsetIl. - by right; rewrite -card_orbit (atransP trG). by left; rewrite indexgg. Qed. Lemma prim_trans_norm (H : {group aT}) : [primitive G, on S | to] -> H <| G -> H \subset 'C_G(S | to) \/ [transitive H, on S | to]. Proof. move=> primG /andP[sHG nHG]; rewrite subsetI sHG. have [trG _] := andP primG; have [x Sx defS] := imsetP trG. move: primG; rewrite (trans_prim_astab Sx) // => /maximal_eqP[_]. case/(_ ('C_G[x | to] <*> H)%G) => /= [||cxH|]; first exact: joing_subl. - by rewrite join_subG subsetIl. - have{cxH} cxH: H \subset 'C_G[x | to] by rewrite -cxH joing_subr. rewrite subsetI sHG /= in cxH; left; apply/subsetP=> a Ha. apply/astabP=> y Sy; have [b Gb ->] := atransP2 trG Sx Sy. rewrite actCJV [to x (a ^ _)](astab1P _) ?(subsetP cxH) //. by rewrite -mem_conjg (normsP nHG). rewrite norm_joinEl 1?subIset ?nHG //. by move/(subgroup_transitiveP Sx sHG trG); right. Qed. End Primitive. Section NactionDef. Variables (gT : finGroupType) (sT : finType). Variables (to : {action gT &-> sT}) (n : nat). Definition n_act (t : n.-tuple sT) a := [tuple of map (to^~ a) t]. Fact n_act_is_action : is_action setT n_act. Proof. by apply: is_total_action => [t|t a b]; apply: eq_from_tnth => i; rewrite !tnth_map ?act1 ?actM. Qed. Canonical n_act_action := Action n_act_is_action. End NactionDef. Notation "to * n" := (n_act_action to n) : action_scope. Section NTransitive. Variables (gT : finGroupType) (sT : finType). Variables (n : nat) (A : {set gT}) (S : {set sT}) (to : {action gT &-> sT}). Definition dtuple_on := [set t : n.-tuple sT | uniq t & t \subset S]. Definition ntransitive := [transitive A, on dtuple_on | to * n]. Lemma dtuple_onP t : reflect (injective (tnth t) /\ forall i, tnth t i \in S) (t \in dtuple_on). Proof. rewrite inE subset_all -map_tnth_enum. case: (uniq _) / (injectiveP (tnth t)) => f_inj; last by right; case. rewrite -[all _ _]negbK -has_predC has_map has_predC negbK /=. by apply: (iffP allP) => [Sf|[]//]; split=> // i; rewrite Sf ?mem_enum. Qed. Lemma n_act_dtuple t a : a \in 'N(S | to) -> t \in dtuple_on -> n_act to t a \in dtuple_on. Proof. move/astabsP=> toSa /dtuple_onP[t_inj St]; apply/dtuple_onP. split=> [i j | i]; rewrite !tnth_map ?[_ \in S]toSa //. by move/act_inj; exact: t_inj. Qed. End NTransitive. Arguments Scope dtuple_on [_ nat_scope group_scope]. Arguments Scope ntransitive [_ _ nat_scope group_scope group_scope action_scope]. Implicit Arguments n_act [gT sT n]. Notation "n .-dtuple ( S )" := (dtuple_on n S) (at level 8, format "n .-dtuple ( S )") : set_scope. Notation "[ 'transitive' ^ n A , 'on' S | to ]" := (ntransitive n A S to) (at level 0, n at level 8, format "[ 'transitive' ^ n A , 'on' S | to ]") : form_scope. Section NTransitveProp. Variables (gT : finGroupType) (sT : finType). Variables (to : {action gT &-> sT}) (G : {group gT}) (S : {set sT}). Lemma card_uniq_tuple n (t : n.-tuple sT) : uniq t -> #|t| = n. Proof. by move/card_uniqP->; exact: size_tuple. Qed. Lemma n_act0 (t : 0.-tuple sT) a : n_act to t a = [tuple]. Proof. exact: tuple0. Qed. Lemma dtuple_on_add n x (t : n.-tuple sT) : ([tuple of x :: t] \in n.+1.-dtuple(S)) = [&& x \in S, x \notin t & t \in n.-dtuple(S)]. Proof. by rewrite !inE memtE !subset_all -!andbA; do !bool_congr. Qed. Lemma dtuple_on_add_D1 n x (t : n.-tuple sT) : ([tuple of x :: t] \in n.+1.-dtuple(S)) = (x \in S) && (t \in n.-dtuple(S :\ x)). Proof. rewrite dtuple_on_add !inE (andbCA (~~ _)); do 2!congr (_ && _). rewrite -!(eq_subset (in_set (mem t))) setDE setIC subsetI; congr (_ && _). by rewrite -setCS setCK sub1set !inE. Qed. Lemma dtuple_on_subset n (S1 S2 : {set sT}) t : S1 \subset S2 -> t \in n.-dtuple(S1) -> t \in n.-dtuple(S2). Proof. by move=> sS12; rewrite !inE => /andP[-> /subset_trans]; exact. Qed. Lemma n_act_add n x (t : n.-tuple sT) a : n_act to [tuple of x :: t] a = [tuple of to x a :: n_act to t a]. Proof. exact: val_inj. Qed. Lemma ntransitive0 : [transitive^0 G, on S | to]. Proof. have dt0: [tuple] \in 0.-dtuple(S) by rewrite inE memtE subset_all. apply/imsetP; exists [tuple of Nil sT] => //. by apply/setP=> x; rewrite [x]tuple0 orbit_refl. Qed. Lemma ntransitive_weak k m : k <= m -> [transitive^m G, on S | to] -> [transitive^k G, on S | to]. Proof. move/subnKC <-; rewrite addnC; elim: {m}(m - k) => // m IHm. rewrite addSn => tr_m1; apply: IHm; move: {m k}(m + k) tr_m1 => m tr_m1. have ext_t t: t \in dtuple_on m S -> exists x, [tuple of x :: t] \in m.+1.-dtuple(S). - move=> dt. have [sSt | /subsetPn[x Sx ntx]] := boolP (S \subset t); last first. by exists x; rewrite dtuple_on_add andbA /= Sx ntx. case/imsetP: tr_m1 dt => t1; rewrite !inE => /andP[Ut1 St1] _ /andP[Ut _]. have /subset_leq_card := subset_trans St1 sSt. by rewrite !card_uniq_tuple // ltnn. case/imsetP: (tr_m1); case/tupleP=> [x t]; rewrite dtuple_on_add. case/and3P=> Sx ntx dt; set xt := [tuple of _] => tr_xt. apply/imsetP; exists t => //. apply/setP=> u; apply/idP/imsetP=> [du | [a Ga ->{u}]]. case: (ext_t u du) => y; rewrite tr_xt. by case/imsetP=> a Ga [_ def_u]; exists a => //; exact: val_inj. have: n_act to xt a \in dtuple_on _ S by rewrite tr_xt mem_imset. by rewrite n_act_add dtuple_on_add; case/and3P. Qed. Lemma ntransitive1 m : 0 < m -> [transitive^m G, on S | to] -> [transitive G, on S | to]. Proof. have trdom1 x: ([tuple x] \in 1.-dtuple(S)) = (x \in S). by rewrite dtuple_on_add !inE memtE subset_all andbT. move=> m_gt0 /(ntransitive_weak m_gt0) {m m_gt0}. case/imsetP; case/tupleP=> x t0; rewrite {t0}(tuple0 t0) trdom1 => Sx trx. apply/imsetP; exists x => //; apply/setP=> y; rewrite -trdom1 trx. apply/imsetP/imsetP=> [[a ? [->]]|[a ? ->]]; exists a => //; exact: val_inj. Qed. Lemma ntransitive_primitive m : 1 < m -> [transitive^m G, on S | to] -> [primitive G, on S | to]. Proof. move=> lt1m /(ntransitive_weak lt1m) {m lt1m}tr2G. have trG: [transitive G, on S | to] by exact: ntransitive1 tr2G. have [x Sx _]:= imsetP trG; rewrite (trans_prim_astab Sx trG). apply/maximal_eqP; split=> [|H]; first exact: subsetIl; rewrite subEproper. case/predU1P; first by [left]; case/andP=> sCH /subsetPn[a Ha nCa] sHG. right; rewrite -(subgroup_transitiveP Sx sHG trG _) ?mulSGid //. have actH := subset_trans sHG (atrans_acts trG). pose y := to x a; have Sy: y \in S by rewrite (actsP actH). have{nCa} yx: y != x by rewrite inE (sameP astab1P eqP) (subsetP sHG) in nCa. apply/imsetP; exists y => //; apply/eqP. rewrite eqEsubset acts_sub_orbit // Sy andbT; apply/subsetP=> z Sz. have [-> | zx] := eqVneq z x; first by rewrite orbit_sym mem_orbit. pose ty := [tuple y; x]; pose tz := [tuple z; x]. have [Sty Stz]: ty \in 2.-dtuple(S) /\ tz \in 2.-dtuple(S). rewrite !inE !memtE !subset_all /= !mem_seq1 !andbT; split; exact/and3P. case: (atransP2 tr2G Sty Stz) => b Gb [->] /esym/astab1P cxb. by rewrite mem_orbit // (subsetP sCH) // inE Gb. Qed. End NTransitveProp. Section NTransitveProp1. Variables (gT : finGroupType) (sT : finType). Variables (to : {action gT &-> sT}) (G : {group gT}) (S : {set sT}). (* This is the forward implication of Aschbacher (15.12).1 *) Theorem stab_ntransitive m x : 0 < m -> x \in S -> [transitive^m.+1 G, on S | to] -> [transitive^m 'C_G[x | to], on S :\ x | to]. Proof. move=> m_gt0 Sx Gtr; have sSxS: S :\ x \subset S by rewrite subsetDl. case: (imsetP Gtr); case/tupleP=> x1 t1; rewrite dtuple_on_add. case/and3P=> Sx1 nt1x1 dt1 trt1; have Gtr1 := ntransitive1 (ltn0Sn _) Gtr. case: (atransP2 Gtr1 Sx1 Sx) => // a Ga x1ax. pose t := n_act to t1 a. have dxt: [tuple of x :: t] \in m.+1.-dtuple(S). rewrite trt1 x1ax; apply/imsetP; exists a => //; exact: val_inj. apply/imsetP; exists t; first by rewrite dtuple_on_add_D1 Sx in dxt. apply/setP=> t2; apply/idP/imsetP => [dt2|[b]]. have: [tuple of x :: t2] \in dtuple_on _ S by rewrite dtuple_on_add_D1 Sx. case/(atransP2 Gtr dxt)=> b Gb [xbx tbt2]. exists b; [rewrite inE Gb; exact/astab1P | exact: val_inj]. case/setIP=> Gb /astab1P xbx ->{t2}. rewrite n_act_dtuple //; last by rewrite dtuple_on_add_D1 Sx in dxt. apply/astabsP=> y; rewrite !inE -{1}xbx (inj_eq (act_inj _ _)). by rewrite (actsP (atrans_acts Gtr1)). Qed. (* This is the converse implication of Aschbacher (15.12).1 *) Theorem stab_ntransitiveI m x : x \in S -> [transitive G, on S | to] -> [transitive^m 'C_G[x | to], on S :\ x | to] -> [transitive^m.+1 G, on S | to]. Proof. move=> Sx Gtr Gntr. have t_to_x t: t \in m.+1.-dtuple(S) -> exists2 a, a \in G & exists2 t', t' \in m.-dtuple(S :\ x) & t = n_act to [tuple of x :: t'] a. - case/tupleP: t => y t St. have Sy: y \in S by rewrite dtuple_on_add_D1 in St; case/andP: St. rewrite -(atransP Gtr _ Sy) in Sx; case/imsetP: Sx => a Ga toya. exists a^-1; first exact: groupVr. exists (n_act to t a); last by rewrite n_act_add toya !actK. move/(n_act_dtuple (subsetP (atrans_acts Gtr) a Ga)): St. by rewrite n_act_add -toya dtuple_on_add_D1 => /andP[]. case: (imsetP Gntr) => t dt S_tG; pose xt := [tuple of x :: t]. have dxt: xt \in m.+1.-dtuple(S) by rewrite dtuple_on_add_D1 Sx. apply/imsetP; exists xt => //; apply/setP=> t2. apply/esym; apply/imsetP/idP=> [[a Ga ->] | ]. by apply: n_act_dtuple; rewrite // (subsetP (atrans_acts Gtr)). case/t_to_x=> a2 Ga2 [t2']; rewrite S_tG. case/imsetP=> a /setIP[Ga /astab1P toxa] -> -> {t2 t2'}. by exists (a * a2); rewrite (groupM, actM) //= !n_act_add toxa. Qed. End NTransitveProp1. mathcomp-1.5/theories/integral_char.v0000644000175000017500000010667412307636117017012 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div choice. Require Import fintype tuple finfun bigop prime ssralg poly finset. Require Import fingroup morphism perm automorphism quotient action finalg zmodp. Require Import commutator cyclic center pgroup sylow gseries nilpotent abelian. Require Import ssrnum ssrint polydiv rat matrix mxalgebra intdiv mxpoly. Require Import vector falgebra fieldext separable galois algC cyclotomic algnum. Require Import mxrepresentation classfun character. (******************************************************************************) (* This file provides some standard results based on integrality properties *) (* of characters, such as theorem asserting that the degree of an irreducible *) (* character of G divides the order of G (Isaacs 3.11), or the famous p^a.q^b *) (* solvability theorem of Burnside. *) (* Defined here: *) (* 'K_k == the kth class sum in gring F G, where k : 'I_#|classes G|, and *) (* F is inferred from the context. *) (* := gset_mx F G (enum_val k) (see mxrepresentation.v). *) (* --> The 'K_k form a basis of 'Z(group_ring F G)%MS. *) (* gring_classM_coef i j k == the coordinate of 'K_i *m 'K_j on 'K_k; this *) (* is usually abbreviated as a i j k. *) (* gring_classM_coef_set A B z == the set of all (x, y) in setX A B such *) (* that x * y = z; if A and B are respectively the ith and jth *) (* conjugacy class of G, and z is in the kth conjugacy class, then *) (* gring_classM_coef i j k is exactly the cadinal of this set. *) (* 'omega_i[A] == the mode of 'chi[G]_i on (A \in 'Z(group_ring algC G))%MS, *) (* i.e., the z such that gring_op 'Chi_i A = z%:M. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope GRing.Theory Num.Theory. Local Open Scope ring_scope. Lemma group_num_field_exists (gT : finGroupType) (G : {group gT}) : {Qn : splittingFieldType rat & galois 1 {:Qn} & {QnC : {rmorphism Qn -> algC} & forall nuQn : argumentType (mem ('Gal({:Qn}%VS / 1%VS))), {nu : {rmorphism algC -> algC} | {morph QnC: a / nuQn a >-> nu a}} & {w : Qn & #|G|.-primitive_root w /\ <<1; w>>%VS = fullv & forall (hT : finGroupType) (H : {group hT}) (phi : 'CF(H)), phi \is a character -> forall x, (#[x] %| #|G|)%N -> {a | QnC a = phi x}}}}. Proof. have [z prim_z] := C_prim_root_exists (cardG_gt0 G); set n := #|G| in prim_z *. have [Qn [QnC [[|w []] // [Dz] genQn]]] := num_field_exists [:: z]. have prim_w: n.-primitive_root w by rewrite -Dz fmorph_primitive_root in prim_z. have Q_Xn1: ('X^n - 1 : {poly Qn}) \is a polyOver 1%AS. by rewrite rpredB ?rpred1 ?rpredX //= polyOverX. have splitXn1: splittingFieldFor 1 ('X^n - 1) {:Qn}. pose r := codom (fun i : 'I_n => w ^+ i). have Dr: 'X^n - 1 = \prod_(y <- r) ('X - y%:P). by rewrite -(factor_Xn_sub_1 prim_w) big_mkord big_map enumT. exists r; first by rewrite -Dr eqpxx. apply/eqP; rewrite eqEsubv subvf -genQn adjoin_seqSr //; apply/allP=> /=. by rewrite andbT -root_prod_XsubC -Dr; apply/unity_rootP/prim_expr_order. have Qn_ax : SplittingField.axiom Qn by exists ('X^n - 1). exists (SplittingFieldType _ _ Qn_ax). apply/splitting_galoisField. exists ('X^n - 1); split => //. apply: separable_Xn_sub_1; rewrite -(fmorph_eq0 QnC) rmorph_nat. by rewrite pnatr_eq0 -lt0n cardG_gt0. exists QnC => [// nuQn|]. by exact: (extend_algC_subfield_aut QnC [rmorphism of nuQn]). rewrite span_seq1 in genQn. exists w => // hT H phi Nphi x x_dv_n. apply: sig_eqW; have [rH ->] := char_reprP Nphi. have [Hx | /cfun0->] := boolP (x \in H); last by exists 0; rewrite rmorph0. have [e [_ [enx1 _] [-> _] _]] := repr_rsim_diag rH Hx. have /fin_all_exists[k Dk] i: exists k, e 0 i = z ^+ k. have [|k ->] := (prim_rootP prim_z) (e 0 i); last by exists k. by have /dvdnP[q ->] := x_dv_n; rewrite mulnC exprM enx1 expr1n. exists (\sum_i w ^+ k i); rewrite rmorph_sum; apply/eq_bigr => i _. by rewrite rmorphX Dz Dk. Qed. Section GenericClassSums. (* This is Isaacs, Theorem (2.4), generalized to an arbitrary field, and with *) (* the combinatorial definition of the coeficients exposed. *) (* This part could move to mxrepresentation.*) Variable (gT : finGroupType) (G : {group gT}) (F : fieldType). Definition gring_classM_coef_set (Ki Kj : {set gT}) g := [set xy in [predX Ki & Kj] | let: (x, y) := xy in x * y == g]%g. Definition gring_classM_coef (i j k : 'I_#|classes G|) := #|gring_classM_coef_set (enum_val i) (enum_val j) (repr (enum_val k))|. Definition gring_class_sum (i : 'I_#|classes G|) := gset_mx F G (enum_val i). Local Notation "''K_' i" := (gring_class_sum i) (at level 8, i at level 2, format "''K_' i") : ring_scope. Local Notation a := gring_classM_coef. Lemma gring_class_sum_central i : ('K_i \in 'Z(group_ring F G))%MS. Proof. by rewrite -classg_base_center (eq_row_sub i) // rowK. Qed. Lemma set_gring_classM_coef (i j k : 'I_#|classes G|) g : g \in enum_val k -> a i j k = #|gring_classM_coef_set (enum_val i) (enum_val j) g|. Proof. rewrite /a; have /repr_classesP[] := enum_valP k; move: (repr _) => g1 Gg1 ->. have [/imsetP[zi Gzi ->] /imsetP[zj Gzj ->]] := (enum_valP i, enum_valP j). move=> g1Gg; have Gg := subsetP (class_subG Gg1 (subxx _)) _ g1Gg. set Aij := gring_classM_coef_set _ _. without loss suffices IH: g g1 Gg Gg1 g1Gg / (#|Aij g1| <= #|Aij g|)%N. by apply/eqP; rewrite eqn_leq !IH // class_sym. have [w Gw Dg] := imsetP g1Gg; pose J2 (v : gT) xy := (xy.1 ^ v, xy.2 ^ v)%g. have J2inj: injective (J2 w). by apply: can_inj (J2 w^-1)%g _ => [[x y]]; rewrite /J2 /= !conjgK. rewrite -(card_imset _ J2inj) subset_leq_card //; apply/subsetP. move=> _ /imsetP[[x y] /setIdP[/andP[/= x1Gx y1Gy] Dxy1] ->]; rewrite !inE /=. rewrite !(class_sym _ (_ ^ _)) !classGidl // class_sym x1Gx class_sym y1Gy. by rewrite -conjMg (eqP Dxy1) /= -Dg. Qed. Theorem gring_classM_expansion i j : 'K_i *m 'K_j = \sum_k (a i j k)%:R *: 'K_k. Proof. have [/imsetP[zi Gzi dKi] /imsetP[zj Gzj dKj]] := (enum_valP i, enum_valP j). pose aG := regular_repr F G; have sKG := subsetP (class_subG _ (subxx G)). transitivity (\sum_(x in zi ^: G) \sum_(y in zj ^: G) aG (x * y)%g). rewrite mulmx_suml -/aG dKi; apply: eq_bigr => x /sKG Gx. rewrite mulmx_sumr -/aG dKj; apply: eq_bigr => y /sKG Gy. by rewrite repr_mxM ?Gx ?Gy. pose h2 xy : gT := (xy.1 * xy.2)%g. pose h1 xy := enum_rank_in (classes1 G) (h2 xy ^: G). rewrite pair_big (partition_big h1 xpredT) //=; apply: eq_bigr => k _. rewrite (partition_big h2 (mem (enum_val k))) /= => [|[x y]]; last first. case/andP=> /andP[/= /sKG Gx /sKG Gy] /eqP <-. by rewrite enum_rankK_in ?class_refl ?mem_classes ?groupM ?Gx ?Gy. rewrite scaler_sumr; apply: eq_bigr => g Kk_g; rewrite scaler_nat. rewrite (set_gring_classM_coef _ _ Kk_g) -sumr_const; apply: eq_big => [] [x y]. rewrite !inE /= dKi dKj /h1 /h2 /=; apply: andb_id2r => /eqP ->. have /imsetP[zk Gzk dKk] := enum_valP k; rewrite dKk in Kk_g. by rewrite (class_transr Kk_g) -dKk enum_valK_in eqxx andbT. by rewrite /h2 /= => /andP[_ /eqP->]. Qed. Fact gring_irr_mode_key : unit. Proof. by []. Qed. Definition gring_irr_mode_def (i : Iirr G) := ('chi_i 1%g)^-1 *: 'chi_i. Definition gring_irr_mode := locked_with gring_irr_mode_key gring_irr_mode_def. Canonical gring_irr_mode_unlockable := [unlockable fun gring_irr_mode]. End GenericClassSums. Arguments Scope gring_irr_mode [_ Group_scope ring_scope group_scope]. Notation "''K_' i" := (gring_class_sum _ i) (at level 8, i at level 2, format "''K_' i") : ring_scope. Notation "''omega_' i [ A ]" := (xcfun (gring_irr_mode i) A) (at level 8, i at level 2, format "''omega_' i [ A ]") : ring_scope. Section IntegralChar. Variables (gT : finGroupType) (G : {group gT}). (* This is Isaacs, Corollary (3.6). *) Lemma Aint_char (chi : 'CF(G)) x : chi \is a character -> chi x \in Aint. Proof. have [Gx /char_reprP[rG ->] {chi} | /cfun0->//] := boolP (x \in G). have [e [_ [unit_e _] [-> _] _]] := repr_rsim_diag rG Gx. rewrite rpred_sum // => i _; apply: (@Aint_unity_root #[x]) => //. exact/unity_rootP. Qed. Lemma Aint_irr i x : 'chi[G]_i x \in Aint. Proof. by apply: Aint_char; exact: irr_char. Qed. Local Notation R_G := (group_ring algCfield G). Local Notation a := gring_classM_coef. (* This is Isaacs (2.25). *) Lemma mx_irr_gring_op_center_scalar n (rG : mx_representation algCfield G n) A : mx_irreducible rG -> (A \in 'Z(R_G))%MS -> is_scalar_mx (gring_op rG A). Proof. move/groupC=> irrG /center_mxP[R_A cGA]. apply: mx_abs_irr_cent_scalar irrG _ _; apply/centgmxP => x Gx. by rewrite -(gring_opG rG Gx) -!gring_opM ?cGA // envelop_mx_id. Qed. Section GringIrrMode. Variable i : Iirr G. Let n := irr_degree (socle_of_Iirr i). Let mxZn_inj: injective (@scalar_mx algCfield n). Proof. by rewrite -[n]prednK ?irr_degree_gt0 //; apply: fmorph_inj. Qed. Lemma cfRepr_gring_center n1 (rG : mx_representation algCfield G n1) A : cfRepr rG = 'chi_i -> (A \in 'Z(R_G))%MS -> gring_op rG A = 'omega_i[A]%:M. Proof. move=> def_rG Z_A; rewrite unlock xcfunZl -{2}def_rG xcfun_repr. have irr_rG: mx_irreducible rG. have sim_rG: mx_rsim 'Chi_i rG by apply: cfRepr_inj; rewrite irrRepr. exact: mx_rsim_irr sim_rG (socle_irr _). have /is_scalar_mxP[e ->] := mx_irr_gring_op_center_scalar irr_rG Z_A. congr _%:M; apply: (canRL (mulKf (irr1_neq0 i))). by rewrite mulrC -def_rG cfunE repr_mx1 group1 -mxtraceZ scalemx1. Qed. Lemma irr_gring_center A : (A \in 'Z(R_G))%MS -> gring_op 'Chi_i A = 'omega_i[A]%:M. Proof. exact: cfRepr_gring_center (irrRepr i). Qed. Lemma gring_irr_modeM A B : (A \in 'Z(R_G))%MS -> (B \in 'Z(R_G))%MS -> 'omega_i[A *m B] = 'omega_i[A] * 'omega_i[B]. Proof. move=> Z_A Z_B; have [[R_A cRA] [R_B cRB]] := (center_mxP Z_A, center_mxP Z_B). apply: mxZn_inj; rewrite scalar_mxM -!irr_gring_center ?gring_opM //. apply/center_mxP; split=> [|C R_C]; first exact: envelop_mxM. by rewrite mulmxA cRA // -!mulmxA cRB. Qed. Lemma gring_mode_class_sum_eq (k : 'I_#|classes G|) g : g \in enum_val k -> 'omega_i['K_k] = #|g ^: G|%:R * 'chi_i g / 'chi_i 1%g. Proof. have /imsetP[x Gx DxG] := enum_valP k; rewrite DxG => /imsetP[u Gu ->{g}]. rewrite unlock classGidl ?cfunJ {u Gu}// mulrC mulr_natl. rewrite xcfunZl raddf_sum DxG -sumr_const /=; congr (_ * _). by apply: eq_bigr => _ /imsetP[u Gu ->]; rewrite xcfunG ?groupJ ?cfunJ. Qed. (* This is Isaacs, Theorem (3.7). *) Lemma Aint_gring_mode_class_sum k : 'omega_i['K_k] \in Aint. Proof. move: k; pose X := [tuple 'omega_i['K_k] | k < #|classes G| ]. have memX k: 'omega_i['K_k] \in X by apply: map_f; exact: mem_enum. have S_P := Cint_spanP X; set S := Cint_span X in S_P. have S_X: {subset X <= S} by exact: mem_Cint_span. have S_1: 1 \in S. apply: S_X; apply/codomP; exists (enum_rank_in (classes1 G) 1%g). rewrite (@gring_mode_class_sum_eq _ 1%g) ?enum_rankK_in ?classes1 //. by rewrite mulfK ?irr1_neq0 // class1G cards1. suffices Smul: mulr_closed S. by move=> k; apply: fin_Csubring_Aint S_P _ _; rewrite ?S_X. split=> // _ _ /S_P[x ->] /S_P[y ->]. rewrite mulr_sumr rpred_sum // => j _. rewrite mulrzAr mulr_suml rpredMz ?rpred_sum // => k _. rewrite mulrzAl rpredMz {x y}// !nth_mktuple. rewrite -gring_irr_modeM ?gring_class_sum_central //. rewrite gring_classM_expansion raddf_sum rpred_sum // => jk _. by rewrite scaler_nat raddfMn rpredMn ?S_X ?memX. Qed. (* A more usable reformulation that does not involve the class sums. *) Corollary Aint_class_div_irr1 x : x \in G -> #|x ^: G|%:R * 'chi_i x / 'chi_i 1%g \in Aint. Proof. move=> Gx; have clGxG := mem_classes Gx; pose k := enum_rank_in clGxG (x ^: G). have k_x: x \in enum_val k by rewrite enum_rankK_in // class_refl. by rewrite -(gring_mode_class_sum_eq k_x) Aint_gring_mode_class_sum. Qed. (* This is Isaacs, Theorem (3.8). *) Theorem coprime_degree_support_cfcenter g : coprime (truncC ('chi_i 1%g)) #|g ^: G| -> g \notin ('Z('chi_i))%CF -> 'chi_i g = 0. Proof. set m := truncC _ => co_m_gG notZg. have [Gg | /cfun0-> //] := boolP (g \in G). have Dm: 'chi_i 1%g = m%:R by rewrite truncCK ?Cnat_irr1. have m_gt0: (0 < m)%N by rewrite -ltC_nat -Dm irr1_gt0. have nz_m: m%:R != 0 :> algC by rewrite pnatr_eq0 -lt0n. pose alpha := 'chi_i g / m%:R. have a_lt1: `|alpha| < 1. rewrite normrM normfV normr_nat -{2}(divff nz_m). rewrite ltr_def (can_eq (mulfVK nz_m)) eq_sym -{1}Dm -irr_cfcenterE // notZg. by rewrite ler_pmul2r ?invr_gt0 ?ltr0n // -Dm char1_ge_norm ?irr_char. have Za: alpha \in Aint. have [u _ /dvdnP[v eq_uv]] := Bezoutl #|g ^: G| m_gt0. suffices ->: alpha = v%:R * 'chi_i g - u%:R * (alpha * #|g ^: G|%:R). rewrite rpredB // rpredM ?rpred_nat ?Aint_irr //. by rewrite mulrC mulrA -Dm Aint_class_div_irr1. rewrite -mulrCA -[v%:R](mulfK nz_m) -!natrM -eq_uv (eqnP co_m_gG). by rewrite mulrAC -mulrA -/alpha mulr_natl mulr_natr mulrS addrK. have [Qn galQn [QnC gQnC [_ _ Qn_g]]] := group_num_field_exists <[g]>. have{Qn_g} [a Da]: exists a, QnC a = alpha. rewrite /alpha; have [a <-] := Qn_g _ G _ (irr_char i) g (dvdnn _). by exists (a / m%:R); rewrite fmorph_div rmorph_nat. have Za_nu nu: sval (gQnC nu) alpha \in Aint by rewrite Aint_aut. have norm_a_nu nu: `|sval (gQnC nu) alpha| <= 1. move: {nu}(sval _) => nu; rewrite fmorph_div rmorph_nat normrM normfV. rewrite normr_nat -Dm -(ler_pmul2r (irr1_gt0 (aut_Iirr nu i))) mul1r. congr (_ <= _): (char1_ge_norm g (irr_char (aut_Iirr nu i))). by rewrite !aut_IirrE !cfunE Dm rmorph_nat divfK. pose beta := QnC (galNorm 1 {:Qn} a). have Dbeta: beta = \prod_(nu in 'Gal({:Qn} / 1)) sval (gQnC nu) alpha. rewrite /beta rmorph_prod. apply: eq_bigr => nu _. by case: (gQnC nu) => f /= ->; rewrite Da. have Zbeta: beta \in Cint. apply: Cint_rat_Aint; last by rewrite Dbeta rpred_prod. rewrite /beta; have /vlineP[/= c ->] := mem_galNorm galQn (memvf a). by rewrite alg_num_field fmorph_rat rpred_rat. have [|nz_a] := boolP (alpha == 0). by rewrite (can2_eq (divfK _) (mulfK _)) // mul0r => /eqP. have: beta != 0 by rewrite Dbeta; apply/prodf_neq0 => nu _; rewrite fmorph_eq0. move/(norm_Cint_ge1 Zbeta); rewrite ltr_geF //; apply: ler_lt_trans a_lt1. rewrite -[`|alpha|]mulr1 Dbeta (bigD1 1%g) ?group1 //= -Da. case: (gQnC _) => /= _ <-; rewrite gal_id normrM. rewrite -subr_ge0 -mulrBr mulr_ge0 ?normr_ge0 // Da subr_ge0. elim/big_rec: _ => [|nu c _]; first by rewrite normr1 lerr. apply: ler_trans; rewrite -subr_ge0 -{1}[`|c|]mul1r normrM -mulrBl. by rewrite mulr_ge0 ?normr_ge0 // subr_ge0 norm_a_nu. Qed. End GringIrrMode. (* This is Isaacs, Theorem (3.9). *) Theorem primes_class_simple_gt1 C : simple G -> ~~ abelian G -> C \in (classes G)^# -> (size (primes #|C|) > 1)%N. Proof. move=> simpleG not_cGG /setD1P[ntC /imsetP[g Gg defC]]. have{ntC} nt_g: g != 1%g by rewrite defC classG_eq1 in ntC. rewrite ltnNge {C}defC; set m := #|_|; apply/negP=> p_natC. have{p_natC} [p p_pr [a Dm]]: {p : nat & prime p & {a | m = p ^ a}%N}. have /prod_prime_decomp->: (0 < m)%N by rewrite /m -index_cent1. rewrite prime_decompE; case Dpr: (primes _) p_natC => [|p []] // _. by exists 2 => //; rewrite big_nil; exists 0%N. rewrite big_seq1; exists p; last by exists (logn p m). by have:= mem_primes p m; rewrite Dpr mem_head => /esym/and3P[]. have{simpleG} [ntG minG] := simpleP _ simpleG. pose p_dv1 i := (p %| 'chi[G]_i 1%g)%C. have p_dvd_supp_g i: ~~ p_dv1 i && (i != 0) -> 'chi_i g = 0. rewrite /p_dv1 irr1_degree dvdC_nat -prime_coprime // => /andP[co_p_i1 nz_i]. have fful_i: cfker 'chi_i = [1]. have /minG[//|/eqP] := cfker_normal 'chi_i. by rewrite eqEsubset subGcfker (negPf nz_i) andbF. have trivZ: 'Z(G) = [1] by have /minG[|/center_idP/idPn] := center_normal G. have trivZi: ('Z('chi_i))%CF = [1]. apply/trivgP; rewrite -quotient_sub1 ?norms1 //= -fful_i cfcenter_eq_center. rewrite fful_i subG1 -(isog_eq1 (isog_center (quotient1_isog G))) /=. by rewrite trivZ. rewrite coprime_degree_support_cfcenter ?trivZi ?inE //. by rewrite -/m Dm irr1_degree natCK coprime_sym coprime_expl. pose alpha := \sum_(i | p_dv1 i && (i != 0)) 'chi_i 1%g / p%:R * 'chi_i g. have nz_p: p%:R != 0 :> algC by rewrite pnatr_eq0 -lt0n prime_gt0. have Dalpha: alpha = - 1 / p%:R. apply/(canRL (mulfK nz_p))/eqP; rewrite -addr_eq0 addrC; apply/eqP/esym. transitivity (cfReg G g); first by rewrite cfRegE (negPf nt_g). rewrite cfReg_sum sum_cfunE (bigD1 0) //= irr0 !cfunE cfun11 cfun1E Gg. rewrite mulr1; congr (1 + _); rewrite (bigID p_dv1) /= addrC big_andbC. rewrite big1 => [|i /p_dvd_supp_g chig0]; last by rewrite cfunE chig0 mulr0. rewrite add0r big_andbC mulr_suml; apply: eq_bigr => i _. by rewrite mulrAC divfK // cfunE. suffices: (p %| 1)%C by rewrite (dvdC_nat p 1) dvdn1 -(subnKC (prime_gt1 p_pr)). rewrite unfold_in (negPf nz_p). rewrite Cint_rat_Aint ?rpred_div ?rpred1 ?rpred_nat //. rewrite -rpredN // -mulNr -Dalpha rpred_sum // => i /andP[/dvdCP[c Zc ->] _]. by rewrite mulfK // rpredM ?Aint_irr ?Aint_Cint. Qed. End IntegralChar. Section MoreIntegralChar. Implicit Type gT : finGroupType. (* This is Burnside's famous p^a.q^b theorem (Isaacs, Theorem (3.10)). *) Theorem Burnside_p_a_q_b gT (G : {group gT}) : (size (primes #|G|) <= 2)%N -> solvable G. Proof. move: {2}_.+1 (ltnSn #|G|) => n; elim: n => // n IHn in gT G *. rewrite ltnS => leGn piGle2; have [simpleG | ] := boolP (simple G); last first. rewrite negb_forall_in => /exists_inP[N sNG]; rewrite eq_sym. have [-> | ] := altP (N =P G). rewrite groupP /= genGid normG andbT eqb_id negbK => /eqP->. exact: solvable1. rewrite [N == G]eqEproper sNG eqbF_neg !negbK => ltNG /and3P[grN]. case/isgroupP: grN => {N}N -> in sNG ltNG *; rewrite /= genGid => ntN nNG. have nsNG: N <| G by exact/andP. have dv_le_pi m: (m %| #|G| -> size (primes m) <= 2)%N. move=> m_dv_G; apply: leq_trans piGle2. by rewrite uniq_leq_size ?primes_uniq //; apply: pi_of_dvd. rewrite (series_sol nsNG) !IHn ?dv_le_pi ?cardSg ?dvdn_quotient //. by apply: leq_trans leGn; apply: ltn_quotient. by apply: leq_trans leGn; apply: proper_card. have [->|[p p_pr p_dv_G]] := trivgVpdiv G; first exact: solvable1. have piGp: p \in \pi(G) by rewrite mem_primes p_pr cardG_gt0. have [P sylP] := Sylow_exists p G; have [sPG pP p'GP] := and3P sylP. have ntP: P :!=: 1%g by rewrite -rank_gt0 (rank_Sylow sylP) p_rank_gt0. have /trivgPn[g /setIP[Pg cPg] nt_g]: 'Z(P) != 1%g. by rewrite center_nil_eq1 // (pgroup_nil pP). apply: abelian_sol; have: (size (primes #|g ^: G|) <= 1)%N. rewrite -ltnS -[_.+1]/(size (p :: _)) (leq_trans _ piGle2) //. rewrite -index_cent1 uniq_leq_size // => [/= | q]. rewrite primes_uniq -p'natEpi ?(pnat_dvd _ p'GP) ?indexgS //. by rewrite subsetI sPG sub_cent1. by rewrite inE => /predU1P[-> // |]; apply: pi_of_dvd; rewrite ?dvdn_indexg. rewrite leqNgt; apply: contraR => /primes_class_simple_gt1-> //. by rewrite !inE classG_eq1 nt_g mem_classes // (subsetP sPG). Qed. (* This is Isaacs, Theorem (3.11). *) Theorem dvd_irr1_cardG gT (G : {group gT}) i : ('chi[G]_i 1%g %| #|G|)%C. Proof. rewrite unfold_in -if_neg irr1_neq0 Cint_rat_Aint //=. by rewrite rpred_div ?rpred_nat // rpred_Cnat ?Cnat_irr1. rewrite -[n in n / _]/(_ *+ true) -(eqxx i) -mulr_natr. rewrite -first_orthogonality_relation mulVKf ?neq0CG //. rewrite sum_by_classes => [|x y Gx Gy]; rewrite -?conjVg ?cfunJ //. rewrite mulr_suml rpred_sum // => K /repr_classesP[Gx {1}->]. by rewrite !mulrA mulrAC rpredM ?Aint_irr ?Aint_class_div_irr1. Qed. (* This is Isaacs, Theorem (3.12). *) Theorem dvd_irr1_index_center gT (G : {group gT}) i : ('chi[G]_i 1%g %| #|G : 'Z('chi_i)%CF|)%C. Proof. without loss fful: gT G i / cfaithful 'chi_i. rewrite -{2}[i](quo_IirrK _ (subxx _)) ?mod_IirrE ?cfModE ?cfker_normal //. rewrite morph1; set i1 := quo_Iirr _ i => /(_ _ _ i1) IH. have fful_i1: cfaithful 'chi_i1. by rewrite quo_IirrE ?cfker_normal ?cfaithful_quo. have:= IH fful_i1; rewrite cfcenter_fful_irr // -cfcenter_eq_center. rewrite index_quotient_eq ?cfcenter_sub ?cfker_norm //. by rewrite setIC subIset // normal_sub ?cfker_center_normal. have [lambda lin_lambda Dlambda] := cfcenter_Res 'chi_i. have DchiZ: {in G & 'Z(G), forall x y, 'chi_i (x * y)%g = 'chi_i x * lambda y}. rewrite -(cfcenter_fful_irr fful) => x y Gx Zy. apply: (mulfI (irr1_neq0 i)); rewrite mulrCA. transitivity ('chi_i x * ('chi_i 1%g *: lambda) y); last by rewrite !cfunE. rewrite -Dlambda cfResE ?cfcenter_sub //. rewrite -irrRepr cfcenter_repr !cfunE in Zy *. case/setIdP: Zy => Gy /is_scalar_mxP[e De]. rewrite repr_mx1 group1 (groupM Gx Gy) (repr_mxM _ Gx Gy) Gx Gy De. by rewrite mul_mx_scalar mxtraceZ mulrCA mulrA mulrC -mxtraceZ scalemx1. have inj_lambda: {in 'Z(G) &, injective lambda}. rewrite -(cfcenter_fful_irr fful) => x y Zx Zy eq_xy. apply/eqP; rewrite eq_mulVg1 -in_set1 (subsetP fful) // cfkerEirr inE. apply/eqP; transitivity ('Res['Z('chi_i)%CF] 'chi_i (x^-1 * y)%g). by rewrite cfResE ?cfcenter_sub // groupM ?groupV. rewrite Dlambda !cfunE lin_charM ?groupV // -eq_xy -lin_charM ?groupV //. by rewrite mulrC mulVg lin_char1 ?mul1r. rewrite unfold_in -if_neg irr1_neq0 Cint_rat_Aint //. by rewrite rpred_div ?rpred_nat // rpred_Cnat ?Cnat_irr1. rewrite (cfcenter_fful_irr fful) nCdivE natf_indexg ?center_sub //=. have ->: #|G|%:R = \sum_(x in G) 'chi_i x * 'chi_i (x^-1)%g. rewrite -[_%:R]mulr1; apply: canLR (mulVKf (neq0CG G)) _. by rewrite first_orthogonality_relation eqxx. rewrite (big_setID [set x | 'chi_i x == 0]) /= -setIdE. rewrite big1 ?add0r => [| x /setIdP[_ /eqP->]]; last by rewrite mul0r. pose h x := (x ^: G * 'Z(G))%g; rewrite (partition_big_imset h). rewrite !mulr_suml rpred_sum //= => _ /imsetP[x /setDP[Gx nz_chi_x] ->]. have: #|x ^: G|%:R * ('chi_i x * 'chi_i x^-1%g) / 'chi_i 1%g \in Aint. by rewrite !mulrA mulrAC rpredM ?Aint_irr ?Aint_class_div_irr1. congr 2 (_ * _ \in Aint); apply: canRL (mulfK (neq0CG _)) _. rewrite inE in nz_chi_x. transitivity ('chi_i x * 'chi_i (x^-1)%g *+ #|h x|); last first. rewrite -sumr_const. apply: eq_big => [y | _ /mulsgP[_ z /imsetP[u Gu ->] Zz] ->]. rewrite !inE -andbA; apply/idP/and3P=> [|[_ _ /eqP <-]]; last first. by rewrite -{1}[y]mulg1 mem_mulg ?class_refl. case/mulsgP=> _ z /imsetP[u Gu ->] Zz ->; have /centerP[Gz cGz] := Zz. rewrite groupM 1?DchiZ ?groupJ ?cfunJ //; split=> //. by rewrite mulf_neq0 // lin_char_neq0 /= ?cfcenter_fful_irr. rewrite -[z](mulKg u) -cGz // -conjMg /h classGidl {u Gu}//. apply/eqP/setP=> w; apply/mulsgP/mulsgP=> [][_ z1 /imsetP[v Gv ->] Zz1 ->]. exists (x ^ v)%g (z * z1)%g; rewrite ?mem_imset ?groupM //. by rewrite conjMg -mulgA /(z ^ v)%g cGz // mulKg. exists ((x * z) ^ v)%g (z^-1 * z1)%g; rewrite ?mem_imset ?groupM ?groupV //. by rewrite conjMg -mulgA /(z ^ v)%g cGz // mulKg mulKVg. rewrite !irr_inv DchiZ ?groupJ ?cfunJ // rmorphM mulrACA -!normCK -exprMn. by rewrite (normC_lin_char lin_lambda) ?mulr1 //= cfcenter_fful_irr. rewrite mulrAC -natrM mulr_natl; congr (_ *+ _). symmetry; rewrite /h /mulg /= /set_mulg [in _ @2: (_, _)]unlock cardsE. rewrite -cardX card_in_image // => [] [y1 z1] [y2 z2] /=. move=> /andP[/=/imsetP[u1 Gu1 ->] Zz1] /andP[/=/imsetP[u2 Gu2 ->] Zz2] {y1 y2}. move=> eq12; have /eqP := congr1 'chi_i eq12. rewrite !(cfunJ, DchiZ) ?groupJ // (can_eq (mulKf nz_chi_x)). rewrite (inj_in_eq inj_lambda) // => /eqP eq_z12; rewrite eq_z12 in eq12 *. by rewrite (mulIg _ _ _ eq12). Qed. (* This is Isaacs, Problem (3.7). *) Lemma gring_classM_coef_sum_eq gT (G : {group gT}) j1 j2 k g1 g2 g : let a := @gring_classM_coef gT G j1 j2 in let a_k := a k in g1 \in enum_val j1 -> g2 \in enum_val j2 -> g \in enum_val k -> let sum12g := \sum_i 'chi[G]_i g1 * 'chi_i g2 * ('chi_i g)^* / 'chi_i 1%g in a_k%:R = (#|enum_val j1| * #|enum_val j2|)%:R / #|G|%:R * sum12g. Proof. move=> a /= Kg1 Kg2 Kg; rewrite mulrAC; apply: canRL (mulfK (neq0CG G)) _. transitivity (\sum_j (#|G| * a j)%:R *+ (j == k) : algC). by rewrite (bigD1 k) //= eqxx -natrM mulnC big1 ?addr0 // => j /negPf->. have defK (j : 'I_#|classes G|) x: x \in enum_val j -> enum_val j = x ^: G. by have /imsetP[y Gy ->] := enum_valP j => /class_transr. have Gg: g \in G. by case/imsetP: (enum_valP k) Kg => x Gx -> /imsetP[y Gy ->]; apply: groupJ. transitivity (\sum_j \sum_i 'omega_i['K_j] * 'chi_i 1%g * ('chi_i g)^* *+ a j). apply: eq_bigr => j _; have /imsetP[z Gz Dj] := enum_valP j. have Kz: z \in enum_val j by rewrite Dj class_refl. rewrite -(Lagrange (subsetIl G 'C[z])) index_cent1 -mulnA natrM -mulrnAl. have ->: (j == k) = (z \in enum_val k). by rewrite -(inj_eq enum_val_inj); apply/eqP/idP=> [<-|/defK->]. rewrite (defK _ g) // -second_orthogonality_relation // mulr_suml. apply: eq_bigr=> i _; rewrite natrM mulrA mulr_natr mulrC mulrA. by rewrite (gring_mode_class_sum_eq i Kz) divfK ?irr1_neq0. rewrite exchange_big /= mulr_sumr; apply: eq_bigr => i _. transitivity ('omega_i['K_j1 *m 'K_j2] * 'chi_i 1%g * ('chi_i g)^*). rewrite gring_classM_expansion -/a raddf_sum !mulr_suml /=. by apply: eq_bigr => j _; rewrite xcfunZr -!mulrA mulr_natl. rewrite !mulrA 2![_ / _]mulrAC (defK _ _ Kg1) (defK _ _ Kg2); congr (_ * _). rewrite gring_irr_modeM ?gring_class_sum_central // mulnC natrM. rewrite (gring_mode_class_sum_eq i Kg2) !mulrA divfK ?irr1_neq0 //. by congr (_ * _); rewrite [_ * _]mulrC (gring_mode_class_sum_eq i Kg1) !mulrA. Qed. (* This is Isaacs, Problem (2.16). *) Lemma index_support_dvd_degree gT (G H : {group gT}) chi : H \subset G -> chi \is a character -> chi \in 'CF(G, H) -> (H :==: 1%g) || abelian G -> (#|G : H| %| chi 1%g)%C. Proof. move=> sHG Nchi Hchi ZHG. suffices: (#|G : H| %| 'Res[H] chi 1%g)%C by rewrite cfResE ?group1. rewrite ['Res _]cfun_sum_cfdot sum_cfunE rpred_sum // => i _. rewrite cfunE dvdC_mulr ?Cint_Cnat ?Cnat_irr1 //. have [j ->]: exists j, 'chi_i = 'Res 'chi[G]_j. case/predU1P: ZHG => [-> | cGG] in i *. suffices ->: i = 0 by exists 0; rewrite !irr0 cfRes_cfun1 ?sub1G. apply/val_inj; case: i => [[|i] //=]; rewrite ltnNge NirrE. by rewrite (@leq_trans 1) // leqNgt classes_gt1 eqxx. have linG := char_abelianP G cGG; have linG1 j := eqP (proj2 (andP (linG j))). have /fin_all_exists[rH DrH] j: exists k, 'Res[H, G] 'chi_j = 'chi_k. apply/irrP/lin_char_irr/andP. by rewrite cfRes_char ?irr_char // cfRes1 ?linG1. suffices{i} all_rH: codom rH =i Iirr H. by exists (iinv (all_rH i)); rewrite DrH f_iinv. apply/subset_cardP; last exact/subsetP; apply/esym/eqP. rewrite card_Iirr_abelian ?(abelianS sHG) //. rewrite -(eqn_pmul2r (indexg_gt0 G H)) Lagrange //; apply/eqP. rewrite -sum_nat_const -card_Iirr_abelian // -sum1_card. rewrite (partition_big rH (mem (codom rH))) /=; last exact: image_f. have nsHG: H <| G by rewrite -sub_abelian_normal. apply: eq_bigr => _ /codomP[i ->]; rewrite -card_quotient ?normal_norm //. rewrite -card_Iirr_abelian ?quotient_abelian //. have Mlin j1 j2: exists k, 'chi_j1 * 'chi_j2 = 'chi[G]_k. exact/irrP/lin_char_irr/rpredM. have /fin_all_exists[rQ DrQ] (j : Iirr (G / H)) := Mlin i (mod_Iirr j). have mulJi: ('chi[G]_i)^*%CF * 'chi_i = 1. apply/cfun_inP=> x Gx; rewrite !cfunE -lin_charV_conj ?linG // cfun1E Gx. by rewrite lin_charV ?mulVf ?lin_char_neq0 ?linG. have inj_rQ: injective rQ. move=> j1 j2 /(congr1 (fun k => (('chi_i)^*%CF * 'chi_k) / H)%CF). by rewrite -!DrQ !mulrA mulJi !mul1r !mod_IirrE ?cfModK // => /irr_inj. rewrite -(card_imset _ inj_rQ) -sum1_card; apply: eq_bigl => j. rewrite -(inj_eq irr_inj) -!DrH; apply/eqP/imsetP=> [eq_ij | [k _ ->]]. have [k Dk] := Mlin (conjC_Iirr i) j; exists (quo_Iirr H k) => //. apply/irr_inj; rewrite -DrQ quo_IirrK //. by rewrite -Dk conjC_IirrE mulrCA mulrA mulJi mul1r. apply/subsetP=> x Hx; have Gx := subsetP sHG x Hx. rewrite cfkerEirr inE linG1 -Dk conjC_IirrE; apply/eqP. transitivity ((1 : 'CF(G)) x); last by rewrite cfun1E Gx. by rewrite -mulJi !cfunE -!(cfResE _ sHG Hx) eq_ij. rewrite -DrQ; apply/cfun_inP=> x Hx; rewrite !cfResE // cfunE mulrC. by rewrite cfker1 ?linG1 ?mul1r ?(subsetP _ x Hx) // mod_IirrE ?cfker_mod. have: (#|G : H| %| #|G : H|%:R * '[chi, 'chi_j])%C. by rewrite dvdC_mulr ?Cint_Cnat ?Cnat_cfdot_char_irr. congr (_ %| _)%C; rewrite (cfdotEl _ Hchi) -(Lagrange sHG) mulnC natrM. rewrite invfM -mulrA mulVKf ?neq0CiG //; congr (_ * _). by apply: eq_bigr => x Hx; rewrite !cfResE. Qed. (* This is Isaacs, Theorem (3.13). *) Theorem faithful_degree_p_part gT (p : nat) (G P : {group gT}) i : cfaithful 'chi[G]_i -> p.-nat (truncC ('chi_i 1%g)) -> p.-Sylow(G) P -> abelian P -> 'chi_i 1%g = (#|G : 'Z(G)|`_p)%:R. Proof. have [p_pr | pr'p] := boolP (prime p); last first. have p'n n: (n > 0)%N -> p^'.-nat n. by move/p'natEpi->; rewrite mem_primes (negPf pr'p). rewrite irr1_degree natCK => _ /pnat_1-> => [_ _|]. by rewrite part_p'nat ?p'n. by rewrite p'n ?irr_degree_gt0. move=> fful_i /p_natP[a Dchi1] sylP cPP. have Dchi1C: 'chi_i 1%g = (p ^ a)%:R by rewrite -Dchi1 irr1_degree natCK. have pa_dv_ZiG: (p ^ a %| #|G : 'Z(G)|)%N. rewrite -dvdC_nat -[pa in (pa %| _)%C]Dchi1C -(cfcenter_fful_irr fful_i). exact: dvd_irr1_index_center. have [sPG pP p'PiG] := and3P sylP. have ZchiP: 'Res[P] 'chi_i \in 'CF(P, P :&: 'Z(G)). apply/cfun_onP=> x; rewrite inE; have [Px | /cfun0->//] := boolP (x \in P). rewrite /= -(cfcenter_fful_irr fful_i) cfResE //. apply: coprime_degree_support_cfcenter. rewrite Dchi1 coprime_expl // prime_coprime // -p'natE //. apply: pnat_dvd p'PiG; rewrite -index_cent1 indexgS // subsetI sPG. by rewrite sub_cent1 (subsetP cPP). have /andP[_ nZG] := center_normal G; have nZP := subset_trans sPG nZG. apply/eqP; rewrite Dchi1C eqr_nat eqn_dvd -{1}(pfactorK a p_pr) -p_part. rewrite partn_dvd //= -dvdC_nat -[pa in (_ %| pa)%C]Dchi1C -card_quotient //=. rewrite -(card_Hall (quotient_pHall nZP sylP)) card_quotient // -indexgI. rewrite -(cfResE _ sPG) // index_support_dvd_degree ?subsetIl ?cPP ?orbT //. by rewrite cfRes_char ?irr_char. Qed. (* This is Isaacs, Lemma (3.14). *) (* Note that the assumption that G be cyclic is unnecessary, as S will be *) (* empty if this is not the case. *) Lemma sum_norm2_char_generators gT (G : {group gT}) (chi : 'CF(G)) : let S := [pred s | generator G s] in chi \is a character -> {in S, forall s, chi s != 0} -> \sum_(s in S) `|chi s| ^+ 2 >= #|S|%:R. Proof. move=> S Nchi nz_chi_S; pose n := #|G|. have [g Sg | S_0] := pickP (generator G); last first. by rewrite eq_card0 // big_pred0 ?lerr. have defG: <[g]> = G by apply/esym/eqP. have [cycG Gg]: cyclic G /\ g \in G by rewrite -defG cycle_cyclic cycle_id. pose I := {k : 'I_n | coprime n k}; pose ItoS (k : I) := (g ^+ sval k)%g. have imItoS: codom ItoS =i S. move=> s; rewrite inE /= /ItoS /I /n /S -defG -orderE. apply/codomP/idP=> [[[i cogi] ->] | Ss]; first by rewrite generator_coprime. have [m ltmg Ds] := cyclePmin (cycle_generator Ss). by rewrite Ds generator_coprime in Ss; apply: ex_intro (Sub (Sub m _) _) _. have /injectiveP injItoS: injective ItoS. move=> k1 k2 /eqP; apply: contraTeq. by rewrite eq_expg_mod_order orderE defG -/n !modn_small. have [Qn galQn [QnC gQnC [eps [pr_eps defQn] QnG]]] := group_num_field_exists G. have{QnG} QnGg := QnG _ G _ _ g (order_dvdG Gg). pose calG := 'Gal({:Qn} / 1). have /fin_all_exists2[ItoQ inItoQ defItoQ] (k : I): exists2 nu, nu \in calG & nu eps = eps ^+ val k. - case: k => [[m _] /=]; rewrite coprime_sym => /Qn_aut_exists[nuC DnuC]. have [nuQ DnuQ] := restrict_aut_to_normal_num_field QnC nuC. have hom_nu: kHom 1 {:Qn} (linfun nuQ). rewrite k1HomE; apply/ahom_inP. by split=> [u v | ]; rewrite !lfunE ?rmorphM ?rmorph1. have [|nu cGnu Dnu] := kHom_to_gal _ (normalFieldf 1) hom_nu. by rewrite !subvf. exists nu => //; apply: (fmorph_inj QnC). rewrite -Dnu ?memvf // lfunE DnuQ rmorphX DnuC //. by rewrite prim_expr_order // fmorph_primitive_root. have{defQn} imItoQ: calG = ItoQ @: {:I}. apply/setP=> nu; apply/idP/imsetP=> [cGnu | [k _ ->] //]. have pr_nu_e: n.-primitive_root (nu eps) by rewrite fmorph_primitive_root. have [i Dnue] := prim_rootP pr_eps (prim_expr_order pr_nu_e). rewrite Dnue prim_root_exp_coprime // coprime_sym in pr_nu_e. apply: ex_intro2 (Sub i _) _ _ => //; apply/eqP. rewrite /calG /= -defQn in ItoQ inItoQ defItoQ nu cGnu Dnue *. by rewrite gal_adjoin_eq // defItoQ -Dnue. have injItoQ: {in {:I} &, injective ItoQ}. move=> k1 k2 _ _ /(congr1 (fun nu : gal_of _ => nu eps))/eqP. by apply: contraTeq; rewrite !defItoQ (eq_prim_root_expr pr_eps) !modn_small. pose pi1 := \prod_(s in S) chi s; pose pi2 := \prod_(s in S) `|chi s| ^+ 2. have Qpi1: pi1 \in Crat. have [a Da] := QnGg _ Nchi; suffices ->: pi1 = QnC (galNorm 1 {:Qn} a). have /vlineP[q ->] := mem_galNorm galQn (memvf a). by rewrite rmorphZ_num rmorph1 mulr1 Crat_rat. rewrite /galNorm rmorph_prod -/calG imItoQ big_imset //=. rewrite /pi1 -(eq_bigl _ _ imItoS) -big_uniq // big_map big_filter /=. apply: eq_bigr => k _; have [nuC DnuC] := gQnC (ItoQ k); rewrite DnuC Da. have [r ->] := char_sum_irr Nchi; rewrite !sum_cfunE rmorph_sum. apply: eq_bigr => i _; have /QnGg[b Db] := irr_char i. have Lchi_i: 'chi_i \is a linear_char by rewrite irr_cyclic_lin. have /(prim_rootP pr_eps)[m Dem]: b ^+ n = 1. apply/eqP; rewrite -(fmorph_eq1 QnC) rmorphX Db -lin_charX //. by rewrite -expg_mod_order orderE defG modnn lin_char1. rewrite -Db -DnuC Dem rmorphX /= defItoQ exprAC -{m}Dem rmorphX {b}Db. by rewrite lin_charX. clear I ItoS imItoS injItoS ItoQ inItoQ defItoQ imItoQ injItoQ. clear Qn galQn QnC gQnC eps pr_eps QnGg calG. have{Qpi1} Zpi1: pi1 \in Cint. by rewrite Cint_rat_Aint // rpred_prod // => s _; apply: Aint_char. have{pi1 Zpi1} pi2_ge1: 1 <= pi2. have ->: pi2 = `|pi1| ^+ 2. by rewrite (big_morph Num.norm (@normrM _) (@normr1 _)) -prodrXl. by rewrite Cint_normK // sqr_Cint_ge1 //; exact/prodf_neq0. have Sgt0: (#|S| > 0)%N by rewrite (cardD1 g) [g \in S]Sg. rewrite -mulr_natr -ler_pdivl_mulr ?ltr0n //. have n2chi_ge0 s: s \in S -> 0 <= `|chi s| ^+ 2 by rewrite exprn_ge0 ?normr_ge0. rewrite -(expr_ge1 Sgt0); last by rewrite divr_ge0 ?ler0n ?sumr_ge0. by rewrite (ler_trans pi2_ge1) // lerif_AGM. Qed. (* This is Burnside's vanishing theorem (Isaacs, Theorem (3.15)). *) Theorem nonlinear_irr_vanish gT (G : {group gT}) i : 'chi[G]_i 1%g > 1 -> exists2 x, x \in G & 'chi_i x = 0. Proof. move=> chi1gt1; apply/exists_eq_inP; apply: contraFT (ltr_geF chi1gt1). rewrite negb_exists_in => /forall_inP nz_chi. rewrite -(norm_Cnat (Cnat_irr1 i)) -(@expr_le1 _ 2) ?normr_ge0 //. rewrite -(ler_add2r (#|G|%:R * '['chi_i])) {1}cfnorm_irr mulr1. rewrite (cfnormE (cfun_onG _)) mulVKf ?neq0CG // (big_setD1 1%g) //=. rewrite addrCA ler_add2l (cardsD1 1%g) group1 mulrS ler_add2l. rewrite -sumr_const !(partition_big_imset (fun s => <[s]>)) /=. apply: ler_sum => _ /imsetP[g /setD1P[ntg Gg] ->]. have sgG: <[g]> \subset G by rewrite cycle_subG. pose S := [pred s | generator <[g]> s]; pose chi := 'Res[<[g]>] 'chi_i. have defS: [pred s in G^# | <[s]> == <[g]>] =i S. move=> s; rewrite inE /= eq_sym andb_idl // !inE -cycle_eq1 -cycle_subG. by move/eqP <-; rewrite cycle_eq1 ntg. have resS: {in S, 'chi_i =1 chi}. by move=> s /cycle_generator=> g_s; rewrite cfResE ?cycle_subG. rewrite !(eq_bigl _ _ defS) sumr_const. rewrite (eq_bigr (fun s => `|chi s| ^+ 2)) => [|s /resS-> //]. apply: sum_norm2_char_generators => [|s Ss]. by rewrite cfRes_char ?irr_char. by rewrite -resS // nz_chi ?(subsetP sgG) ?cycle_generator. Qed. End MoreIntegralChar.mathcomp-1.5/theories/tuple.v0000644000175000017500000003506712307636117015336 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq choice fintype. Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. (******************************************************************************) (* Tuples, i.e., sequences with a fixed (known) length. We define: *) (* n.-tuple T == the type of n-tuples of elements of type T. *) (* [tuple of s] == the tuple whose underlying sequence (value) is s. *) (* The size of s must be known: specifically, Coq must *) (* be able to infer a Canonical tuple projecting on s. *) (* in_tuple s == the (size s)-tuple with value s. *) (* [tuple] == the empty tuple, and *) (* [tuple x1; ..; xn] == the explicit n.-tuple . *) (* [tuple E | i < n] == the n.-tuple with general term E (i : 'I_n is bound *) (* in E). *) (* tcast Emn t == the m-tuple t cast as an n-tuple using Emn : m = n. *) (* As n.-tuple T coerces to seq t, all seq operations (size, nth, ...) can be *) (* applied to t : n.-tuple T; we provide a few specialized instances when *) (* avoids the need for a default value. *) (* tsize t == the size of t (the n in n.-tuple T) *) (* tnth t i == the i'th component of t, where i : 'I_n. *) (* [tnth t i] == the i'th component of t, where i : nat and i < n *) (* is convertible to true. *) (* thead t == the first element of t, when n is m.+1 for some m. *) (* Most seq constructors (cons, behead, cat, rcons, belast, take, drop, rot, *) (* map, ...) can be used to build tuples via the [tuple of s] construct. *) (* Tuples are actually a subType of seq, and inherit all combinatorial *) (* structures, including the finType structure. *) (* Some useful lemmas and definitions: *) (* tuple0 : [tuple] is the only 0.-tuple *) (* tupleP : elimination view for n.+1.-tuple *) (* ord_tuple n : the n.-tuple of all i : 'I_n *) (******************************************************************************) Section Def. Variables (n : nat) (T : Type). Structure tuple_of : Type := Tuple {tval :> seq T; _ : size tval == n}. Canonical tuple_subType := Eval hnf in [subType for tval]. Implicit Type t : tuple_of. Definition tsize of tuple_of := n. Lemma size_tuple t : size t = n. Proof. exact: (eqP (valP t)). Qed. Lemma tnth_default t : 'I_n -> T. Proof. by rewrite -(size_tuple t); case: (tval t) => [|//] []. Qed. Definition tnth t i := nth (tnth_default t i) t i. Lemma tnth_nth x t i : tnth t i = nth x t i. Proof. by apply: set_nth_default; rewrite size_tuple. Qed. Lemma map_tnth_enum t : map (tnth t) (enum 'I_n) = t. Proof. case def_t: {-}(val t) => [|x0 t']. by rewrite [enum _]size0nil // -cardE card_ord -(size_tuple t) def_t. apply: (@eq_from_nth _ x0) => [|i]; rewrite size_map. by rewrite -cardE size_tuple card_ord. move=> lt_i_e; have lt_i_n: i < n by rewrite -cardE card_ord in lt_i_e. by rewrite (nth_map (Ordinal lt_i_n)) // (tnth_nth x0) nth_enum_ord. Qed. Lemma eq_from_tnth t1 t2 : tnth t1 =1 tnth t2 -> t1 = t2. Proof. by move/eq_map=> eq_t; apply: val_inj; rewrite /= -!map_tnth_enum eq_t. Qed. Definition tuple t mkT : tuple_of := mkT (let: Tuple _ tP := t return size t == n in tP). Lemma tupleE t : tuple (fun sP => @Tuple t sP) = t. Proof. by case: t. Qed. End Def. Notation "n .-tuple" := (tuple_of n) (at level 2, format "n .-tuple") : type_scope. Notation "{ 'tuple' n 'of' T }" := (n.-tuple T : predArgType) (at level 0, only parsing) : form_scope. Notation "[ 'tuple' 'of' s ]" := (tuple (fun sP => @Tuple _ _ s sP)) (at level 0, format "[ 'tuple' 'of' s ]") : form_scope. Notation "[ 'tnth' t i ]" := (tnth t (@Ordinal (tsize t) i (erefl true))) (at level 0, t, i at level 8, format "[ 'tnth' t i ]") : form_scope. Canonical nil_tuple T := Tuple (isT : @size T [::] == 0). Canonical cons_tuple n T x (t : n.-tuple T) := Tuple (valP t : size (x :: t) == n.+1). Notation "[ 'tuple' x1 ; .. ; xn ]" := [tuple of x1 :: .. [:: xn] ..] (at level 0, format "[ 'tuple' '[' x1 ; '/' .. ; '/' xn ']' ]") : form_scope. Notation "[ 'tuple' ]" := [tuple of [::]] (at level 0, format "[ 'tuple' ]") : form_scope. Section CastTuple. Variable T : Type. Definition in_tuple (s : seq T) := Tuple (eqxx (size s)). Definition tcast m n (eq_mn : m = n) t := let: erefl in _ = n := eq_mn return n.-tuple T in t. Lemma tcastE m n (eq_mn : m = n) t i : tnth (tcast eq_mn t) i = tnth t (cast_ord (esym eq_mn) i). Proof. by case: n / eq_mn in i *; rewrite cast_ord_id. Qed. Lemma tcast_id n (eq_nn : n = n) t : tcast eq_nn t = t. Proof. by rewrite (eq_axiomK eq_nn). Qed. Lemma tcastK m n (eq_mn : m = n) : cancel (tcast eq_mn) (tcast (esym eq_mn)). Proof. by case: n / eq_mn. Qed. Lemma tcastKV m n (eq_mn : m = n) : cancel (tcast (esym eq_mn)) (tcast eq_mn). Proof. by case: n / eq_mn. Qed. Lemma tcast_trans m n p (eq_mn : m = n) (eq_np : n = p) t: tcast (etrans eq_mn eq_np) t = tcast eq_np (tcast eq_mn t). Proof. by case: n / eq_mn eq_np; case: p /. Qed. Lemma tvalK n (t : n.-tuple T) : in_tuple t = tcast (esym (size_tuple t)) t. Proof. by apply: val_inj => /=; case: _ / (esym _). Qed. Lemma in_tupleE s : in_tuple s = s :> seq T. Proof. by []. Qed. End CastTuple. Section SeqTuple. Variables (n m : nat) (T U rT : Type). Implicit Type t : n.-tuple T. Lemma rcons_tupleP t x : size (rcons t x) == n.+1. Proof. by rewrite size_rcons size_tuple. Qed. Canonical rcons_tuple t x := Tuple (rcons_tupleP t x). Lemma nseq_tupleP x : @size T (nseq n x) == n. Proof. by rewrite size_nseq. Qed. Canonical nseq_tuple x := Tuple (nseq_tupleP x). Lemma iota_tupleP : size (iota m n) == n. Proof. by rewrite size_iota. Qed. Canonical iota_tuple := Tuple iota_tupleP. Lemma behead_tupleP t : size (behead t) == n.-1. Proof. by rewrite size_behead size_tuple. Qed. Canonical behead_tuple t := Tuple (behead_tupleP t). Lemma belast_tupleP x t : size (belast x t) == n. Proof. by rewrite size_belast size_tuple. Qed. Canonical belast_tuple x t := Tuple (belast_tupleP x t). Lemma cat_tupleP t (u : m.-tuple T) : size (t ++ u) == n + m. Proof. by rewrite size_cat !size_tuple. Qed. Canonical cat_tuple t u := Tuple (cat_tupleP t u). Lemma take_tupleP t : size (take m t) == minn m n. Proof. by rewrite size_take size_tuple eqxx. Qed. Canonical take_tuple t := Tuple (take_tupleP t). Lemma drop_tupleP t : size (drop m t) == n - m. Proof. by rewrite size_drop size_tuple. Qed. Canonical drop_tuple t := Tuple (drop_tupleP t). Lemma rev_tupleP t : size (rev t) == n. Proof. by rewrite size_rev size_tuple. Qed. Canonical rev_tuple t := Tuple (rev_tupleP t). Lemma rot_tupleP t : size (rot m t) == n. Proof. by rewrite size_rot size_tuple. Qed. Canonical rot_tuple t := Tuple (rot_tupleP t). Lemma rotr_tupleP t : size (rotr m t) == n. Proof. by rewrite size_rotr size_tuple. Qed. Canonical rotr_tuple t := Tuple (rotr_tupleP t). Lemma map_tupleP f t : @size rT (map f t) == n. Proof. by rewrite size_map size_tuple. Qed. Canonical map_tuple f t := Tuple (map_tupleP f t). Lemma scanl_tupleP f x t : @size rT (scanl f x t) == n. Proof. by rewrite size_scanl size_tuple. Qed. Canonical scanl_tuple f x t := Tuple (scanl_tupleP f x t). Lemma pairmap_tupleP f x t : @size rT (pairmap f x t) == n. Proof. by rewrite size_pairmap size_tuple. Qed. Canonical pairmap_tuple f x t := Tuple (pairmap_tupleP f x t). Lemma zip_tupleP t (u : n.-tuple U) : size (zip t u) == n. Proof. by rewrite size1_zip !size_tuple. Qed. Canonical zip_tuple t u := Tuple (zip_tupleP t u). Lemma allpairs_tupleP f t (u : m.-tuple U) : @size rT (allpairs f t u) == n * m. Proof. by rewrite size_allpairs !size_tuple. Qed. Canonical allpairs_tuple f t u := Tuple (allpairs_tupleP f t u). Definition thead (u : n.+1.-tuple T) := tnth u ord0. Lemma tnth0 x t : tnth [tuple of x :: t] ord0 = x. Proof. by []. Qed. Lemma theadE x t : thead [tuple of x :: t] = x. Proof. by []. Qed. Lemma tuple0 : all_equal_to ([tuple] : 0.-tuple T). Proof. by move=> t; apply: val_inj; case: t => [[]]. Qed. CoInductive tuple1_spec : n.+1.-tuple T -> Type := Tuple1spec x t : tuple1_spec [tuple of x :: t]. Lemma tupleP u : tuple1_spec u. Proof. case: u => [[|x s] //= sz_s]; pose t := @Tuple n _ s sz_s. rewrite (_ : Tuple _ = [tuple of x :: t]) //; exact: val_inj. Qed. Lemma tnth_map f t i : tnth [tuple of map f t] i = f (tnth t i) :> rT. Proof. by apply: nth_map; rewrite size_tuple. Qed. End SeqTuple. Lemma tnth_behead n T (t : n.+1.-tuple T) i : tnth [tuple of behead t] i = tnth t (inord i.+1). Proof. by case/tupleP: t => x t; rewrite !(tnth_nth x) inordK ?ltnS. Qed. Lemma tuple_eta n T (t : n.+1.-tuple T) : t = [tuple of thead t :: behead t]. Proof. by case/tupleP: t => x t; exact: val_inj. Qed. Section TupleQuantifiers. Variables (n : nat) (T : Type). Implicit Types (a : pred T) (t : n.-tuple T). Lemma forallb_tnth a t : [forall i, a (tnth t i)] = all a t. Proof. apply: negb_inj; rewrite -has_predC -has_map negb_forall. apply/existsP/(has_nthP true) => [[i a_t_i] | [i lt_i_n a_t_i]]. by exists i; rewrite ?size_tuple // -tnth_nth tnth_map. rewrite size_tuple in lt_i_n; exists (Ordinal lt_i_n). by rewrite -tnth_map (tnth_nth true). Qed. Lemma existsb_tnth a t : [exists i, a (tnth t i)] = has a t. Proof. by apply: negb_inj; rewrite negb_exists -all_predC -forallb_tnth. Qed. Lemma all_tnthP a t : reflect (forall i, a (tnth t i)) (all a t). Proof. by rewrite -forallb_tnth; apply: forallP. Qed. Lemma has_tnthP a t : reflect (exists i, a (tnth t i)) (has a t). Proof. by rewrite -existsb_tnth; apply: existsP. Qed. End TupleQuantifiers. Implicit Arguments all_tnthP [n T a t]. Implicit Arguments has_tnthP [n T a t]. Section EqTuple. Variables (n : nat) (T : eqType). Definition tuple_eqMixin := Eval hnf in [eqMixin of n.-tuple T by <:]. Canonical tuple_eqType := Eval hnf in EqType (n.-tuple T) tuple_eqMixin. Canonical tuple_predType := Eval hnf in mkPredType (fun t : n.-tuple T => mem_seq t). Lemma memtE (t : n.-tuple T) : mem t = mem (tval t). Proof. by []. Qed. Lemma mem_tnth i (t : n.-tuple T) : tnth t i \in t. Proof. by rewrite mem_nth ?size_tuple. Qed. Lemma memt_nth x0 (t : n.-tuple T) i : i < n -> nth x0 t i \in t. Proof. by move=> i_lt_n; rewrite mem_nth ?size_tuple. Qed. Lemma tnthP (t : n.-tuple T) x : reflect (exists i, x = tnth t i) (x \in t). Proof. apply: (iffP idP) => [/(nthP x)[i ltin <-] | [i ->]]; last exact: mem_tnth. by rewrite size_tuple in ltin; exists (Ordinal ltin); rewrite (tnth_nth x). Qed. Lemma seq_tnthP (s : seq T) x : x \in s -> {i | x = tnth (in_tuple s) i}. Proof. move=> s_x; pose i := index x s; have lt_i: i < size s by rewrite index_mem. by exists (Ordinal lt_i); rewrite (tnth_nth x) nth_index. Qed. End EqTuple. Definition tuple_choiceMixin n (T : choiceType) := [choiceMixin of n.-tuple T by <:]. Canonical tuple_choiceType n (T : choiceType) := Eval hnf in ChoiceType (n.-tuple T) (tuple_choiceMixin n T). Definition tuple_countMixin n (T : countType) := [countMixin of n.-tuple T by <:]. Canonical tuple_countType n (T : countType) := Eval hnf in CountType (n.-tuple T) (tuple_countMixin n T). Canonical tuple_subCountType n (T : countType) := Eval hnf in [subCountType of n.-tuple T]. Module Type FinTupleSig. Section FinTupleSig. Variables (n : nat) (T : finType). Parameter enum : seq (n.-tuple T). Axiom enumP : Finite.axiom enum. Axiom size_enum : size enum = #|T| ^ n. End FinTupleSig. End FinTupleSig. Module FinTuple : FinTupleSig. Section FinTuple. Variables (n : nat) (T : finType). Definition enum : seq (n.-tuple T) := let extend e := flatten (codom (fun x => map (cons x) e)) in pmap insub (iter n extend [::[::]]). Lemma enumP : Finite.axiom enum. Proof. case=> /= t t_n; rewrite -(count_map _ (pred1 t)) (pmap_filter (@insubK _ _ _)). rewrite count_filter -(@eq_count _ (pred1 t)) => [|s /=]; last first. by rewrite isSome_insub; case: eqP=> // ->. elim: n t t_n => [|m IHm] [|x t] //= {IHm}/IHm; move: (iter m _ _) => em IHm. transitivity (x \in T : nat); rewrite // -mem_enum codomE. elim: (fintype.enum T) (enum_uniq T) => //= y e IHe /andP[/negPf ney]. rewrite count_cat count_map inE /preim /= {1}/eq_op /= eq_sym => /IHe->. by case: eqP => [->|_]; rewrite ?(ney, count_pred0, IHm). Qed. Lemma size_enum : size enum = #|T| ^ n. Proof. rewrite /= cardE size_pmap_sub; elim: n => //= m IHm. rewrite expnS /codom /image_mem; elim: {2 3}(fintype.enum T) => //= x e IHe. by rewrite count_cat {}IHe count_map IHm. Qed. End FinTuple. End FinTuple. Section UseFinTuple. Variables (n : nat) (T : finType). Canonical tuple_finMixin := Eval hnf in FinMixin (@FinTuple.enumP n T). Canonical tuple_finType := Eval hnf in FinType (n.-tuple T) tuple_finMixin. Canonical tuple_subFinType := Eval hnf in [subFinType of n.-tuple T]. Lemma card_tuple : #|{:n.-tuple T}| = #|T| ^ n. Proof. by rewrite [#|_|]cardT enumT unlock FinTuple.size_enum. Qed. Lemma enum_tupleP (A : pred T) : size (enum A) == #|A|. Proof. by rewrite -cardE. Qed. Canonical enum_tuple A := Tuple (enum_tupleP A). Definition ord_tuple : n.-tuple 'I_n := Tuple (introT eqP (size_enum_ord n)). Lemma val_ord_tuple : val ord_tuple = enum 'I_n. Proof. by []. Qed. Lemma tuple_map_ord U (t : n.-tuple U) : t = [tuple of map (tnth t) ord_tuple]. Proof. by apply: val_inj => /=; rewrite map_tnth_enum. Qed. Lemma tnth_ord_tuple i : tnth ord_tuple i = i. Proof. apply: val_inj; rewrite (tnth_nth i) -(nth_map _ 0) ?size_tuple //. by rewrite /= enumT unlock val_ord_enum nth_iota. Qed. Section ImageTuple. Variables (T' : Type) (f : T -> T') (A : pred T). Canonical image_tuple : #|A|.-tuple T' := [tuple of image f A]. Canonical codom_tuple : #|T|.-tuple T' := [tuple of codom f]. End ImageTuple. Section MkTuple. Variables (T' : Type) (f : 'I_n -> T'). Definition mktuple := map_tuple f ord_tuple. Lemma tnth_mktuple i : tnth mktuple i = f i. Proof. by rewrite tnth_map tnth_ord_tuple. Qed. Lemma nth_mktuple x0 (i : 'I_n) : nth x0 mktuple i = f i. Proof. by rewrite -tnth_nth tnth_mktuple. Qed. End MkTuple. End UseFinTuple. Notation "[ 'tuple' F | i < n ]" := (mktuple (fun i : 'I_n => F)) (at level 0, i at level 0, format "[ '[hv' 'tuple' F '/' | i < n ] ']'") : form_scope. mathcomp-1.5/theories/polyXY.v0000644000175000017500000004341312307636117015443 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool choice eqtype ssrnat seq div fintype. Require Import tuple finfun bigop fingroup perm ssralg zmodp matrix mxalgebra. Require Import poly polydiv mxpoly binomial. (******************************************************************************) (* This file provides additional primitives and theory for bivariate *) (* polynomials (polynomials of two variables), represented as polynomials *) (* with (univariate) polynomial coefficients : *) (* 'Y == the (generic) second variable (:= 'X%:P). *) (* p^:P == the bivariate polynomial p['X], for p univariate. *) (* := map_poly polyC p (this notation is defined in poly.v). *) (* u.[x, y] == the bivariate polynomial u evaluated at 'X = x, 'Y = y. *) (* := u.[x%:P].[y]. *) (* sizeY u == the size of u in 'Y (1 + the 'Y-degree of u, if u != 0). *) (* := \max_(i < size u) size u`_i. *) (* swapXY u == the bivariate polynomial u['Y, 'X], for u bivariate. *) (* poly_XaY p == the bivariate polynomial p['X + 'Y], for p univariate. *) (* := p^:P \Po ('X + 'Y). *) (* poly_XmY p == the bivariate polynomial p['X * 'Y], for p univariate. *) (* := P^:P \Po ('X * 'Y). *) (* sub_annihilant p q == for univariate p, q != 0, a nonzero polynomial whose *) (* roots include all the differences of roots of p and q, in *) (* all field extensions (:= resultant (poly_XaY p) q^:P). *) (* div_annihilant p q == for polynomials p != 0, q with q.[0] != 0, a nonzero *) (* polynomial whose roots include all the quotients of roots *) (* of p by roots of q, in all field extensions *) (* (:= resultant (poly_XmY p) q^:P). *) (* The latter two "annhilants" provide uniform witnesses for an alternative *) (* proof of the closure of the algebraicOver predicate (see mxpoly.v). The *) (* fact that the annhilant does not depend on the particular choice of roots *) (* of p and q is crucial for the proof of the Primitive Element Theorem (file *) (* separable.v). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Local Open Scope ring_scope. Import GRing.Theory. Local Notation "p ^ f" := (map_poly f p) : ring_scope. Local Notation eval := horner_eval. Notation "'Y" := 'X%:P : ring_scope. Notation "p ^:P" := (p ^ polyC) (at level 2, format "p ^:P") : ring_scope. Notation "p .[ x , y ]" := (p.[x%:P].[y]) (at level 2, left associativity, format "p .[ x , y ]") : ring_scope. Section PolyXY_Ring. Variable R : ringType. Implicit Types (u : {poly {poly R}}) (p q : {poly R}) (x : R). Fact swapXY_key : unit. Proof. by []. Qed. Definition swapXY_def u : {poly {poly R}} := (u ^ map_poly polyC).['Y]. Definition swapXY := locked_with swapXY_key swapXY_def. Canonical swapXY_unlockable := [unlockable fun swapXY]. Definition sizeY u : nat := \max_(i < size u) (size u`_i). Definition poly_XaY p : {poly {poly R}} := p^:P \Po ('X + 'Y). Definition poly_XmY p : {poly {poly R}} := p^:P \Po ('X * 'Y). Definition sub_annihilant p q := resultant (poly_XaY p) q^:P. Definition div_annihilant p q := resultant (poly_XmY p) q^:P. Lemma swapXY_polyC p : swapXY p%:P = p^:P. Proof. by rewrite unlock map_polyC hornerC. Qed. Lemma swapXY_X : swapXY 'X = 'Y. Proof. by rewrite unlock map_polyX hornerX. Qed. Lemma swapXY_Y : swapXY 'Y = 'X. Proof. by rewrite swapXY_polyC map_polyX. Qed. Lemma swapXY_is_additive : additive swapXY. Proof. by move=> u v; rewrite unlock rmorphB !hornerE. Qed. Canonical swapXY_addf := Additive swapXY_is_additive. Lemma coef_swapXY u i j : (swapXY u)`_i`_j = u`_j`_i. Proof. elim/poly_ind: u => [|u p IHu] in i j *; first by rewrite raddf0 !coef0. rewrite raddfD !coefD /= swapXY_polyC coef_map /= !coefC coefMX. rewrite !(fun_if (fun q : {poly R} => q`_i)) coef0 -IHu; congr (_ + _). by rewrite unlock rmorphM /= map_polyX hornerMX coefMC coefMX. Qed. Lemma swapXYK : involutive swapXY. Proof. by move=> u; apply/polyP=> i; apply/polyP=> j; rewrite !coef_swapXY. Qed. Lemma swapXY_map_polyC p : swapXY p^:P = p%:P. Proof. by rewrite -swapXY_polyC swapXYK. Qed. Lemma swapXY_eq0 u : (swapXY u == 0) = (u == 0). Proof. by rewrite (inv_eq swapXYK) raddf0. Qed. Lemma swapXY_is_multiplicative : multiplicative swapXY. Proof. split=> [u v|]; last by rewrite swapXY_polyC map_polyC. apply/polyP=> i; apply/polyP=> j; rewrite coef_swapXY !coefM !coef_sum. rewrite (eq_bigr _ (fun _ _ => coefM _ _ _)) exchange_big /=. apply: eq_bigr => j1 _; rewrite coefM; apply: eq_bigr=> i1 _. by rewrite !coef_swapXY. Qed. Canonical swapXY_rmorphism := AddRMorphism swapXY_is_multiplicative. Lemma swapXY_is_scalable : scalable_for (map_poly polyC \; *%R) swapXY. Proof. by move=> p u /=; rewrite -mul_polyC rmorphM /= swapXY_polyC. Qed. Canonical swapXY_linear := AddLinear swapXY_is_scalable. Canonical swapXY_lrmorphism := [lrmorphism of swapXY]. Lemma swapXY_comp_poly p u : swapXY (p^:P \Po u) = p^:P \Po swapXY u. Proof. rewrite -horner_map; congr _.[_]; rewrite -!map_poly_comp /=. by apply: eq_map_poly => x; rewrite /= swapXY_polyC map_polyC. Qed. Lemma max_size_coefXY u i : size u`_i <= sizeY u. Proof. have [ltiu | /(nth_default 0)->] := ltnP i (size u); last by rewrite size_poly0. exact: (bigmax_sup (Ordinal ltiu)). Qed. Lemma max_size_lead_coefXY u : size (lead_coef u) <= sizeY u. Proof. by rewrite lead_coefE max_size_coefXY. Qed. Lemma max_size_evalX u : size u.['X] <= sizeY u + (size u).-1. Proof. rewrite horner_coef (leq_trans (size_sum _ _ _)) //; apply/bigmax_leqP=> i _. rewrite (leq_trans (size_mul_leq _ _)) // size_polyXn addnS. by rewrite leq_add ?max_size_coefXY //= -ltnS (leq_trans _ (leqSpred _)). Qed. Lemma max_size_evalC u x : size u.[x%:P] <= sizeY u. Proof. rewrite horner_coef (leq_trans (size_sum _ _ _)) //; apply/bigmax_leqP=> i _. rewrite (leq_trans (size_mul_leq _ _)) // -polyC_exp size_polyC addnC -subn1. by rewrite (leq_trans _ (max_size_coefXY _ i)) // leq_subLR leq_add2r leq_b1. Qed. Lemma sizeYE u : sizeY u = size (swapXY u). Proof. apply/eqP; rewrite eqn_leq; apply/andP; split. apply/bigmax_leqP=> /= i _; apply/leq_sizeP => j /(nth_default 0) u_j_0. by rewrite -coef_swapXY u_j_0 coef0. apply/leq_sizeP=> j le_uY_j; apply/polyP=> i; rewrite coef_swapXY coef0. by rewrite nth_default // (leq_trans _ le_uY_j) ?max_size_coefXY. Qed. Lemma sizeY_eq0 u : (sizeY u == 0%N) = (u == 0). Proof. by rewrite sizeYE size_poly_eq0 swapXY_eq0. Qed. Lemma sizeY_mulX u : sizeY (u * 'X) = sizeY u. Proof. rewrite !sizeYE rmorphM /= swapXY_X rreg_size //. by have /monic_comreg[_ /rreg_lead] := monicX R. Qed. Lemma swapXY_poly_XaY p : swapXY (poly_XaY p) = poly_XaY p. Proof. by rewrite swapXY_comp_poly rmorphD /= swapXY_X swapXY_Y addrC. Qed. Lemma swapXY_poly_XmY p : swapXY (poly_XmY p) = poly_XmY p. Proof. by rewrite swapXY_comp_poly rmorphM /= swapXY_X swapXY_Y commr_polyX. Qed. Lemma poly_XaY0 : poly_XaY 0 = 0. Proof. by rewrite /poly_XaY rmorph0 comp_poly0. Qed. Lemma poly_XmY0 : poly_XmY 0 = 0. Proof. by rewrite /poly_XmY rmorph0 comp_poly0. Qed. End PolyXY_Ring. Prenex Implicits swapXY sizeY poly_XaY poly_XmY sub_annihilant div_annihilant. Prenex Implicits swapXYK. Lemma swapXY_map (R S : ringType) (f : {additive R -> S}) u : swapXY (u ^ map_poly f) = swapXY u ^ map_poly f. Proof. by apply/polyP=> i; apply/polyP=> j; rewrite !(coef_map, coef_swapXY). Qed. Section PolyXY_ComRing. Variable R : comRingType. Implicit Types (u : {poly {poly R}}) (p : {poly R}) (x y : R). Lemma horner_swapXY u x : (swapXY u).[x%:P] = u ^ eval x. Proof. apply/polyP=> i /=; rewrite coef_map /= /eval horner_coef coef_sum -sizeYE. rewrite (horner_coef_wide _ (max_size_coefXY u i)); apply: eq_bigr=> j _. by rewrite -polyC_exp coefMC coef_swapXY. Qed. Lemma horner_polyC u x : u.[x%:P] = swapXY u ^ eval x. Proof. by rewrite -horner_swapXY swapXYK. Qed. Lemma horner2_swapXY u x y : (swapXY u).[x, y] = u.[y, x]. Proof. by rewrite horner_swapXY -{1}(hornerC y x) horner_map. Qed. Lemma horner_poly_XaY p v : (poly_XaY p).[v] = p \Po (v + 'X). Proof. by rewrite horner_comp !hornerE. Qed. Lemma horner_poly_XmY p v : (poly_XmY p).[v] = p \Po (v * 'X). Proof. by rewrite horner_comp !hornerE. Qed. End PolyXY_ComRing. Section PolyXY_Idomain. Variable R : idomainType. Implicit Types (p q : {poly R}) (x y : R). Lemma size_poly_XaY p : size (poly_XaY p) = size p. Proof. by rewrite size_comp_poly2 ?size_XaddC // size_map_polyC. Qed. Lemma poly_XaY_eq0 p : (poly_XaY p == 0) = (p == 0). Proof. by rewrite -!size_poly_eq0 size_poly_XaY. Qed. Lemma size_poly_XmY p : size (poly_XmY p) = size p. Proof. by rewrite size_comp_poly2 ?size_XmulC ?polyX_eq0 ?size_map_polyC. Qed. Lemma poly_XmY_eq0 p : (poly_XmY p == 0) = (p == 0). Proof. by rewrite -!size_poly_eq0 size_poly_XmY. Qed. Lemma lead_coef_poly_XaY p : lead_coef (poly_XaY p) = (lead_coef p)%:P. Proof. rewrite lead_coef_comp ?size_XaddC // -['Y]opprK -polyC_opp lead_coefXsubC. by rewrite expr1n mulr1 lead_coef_map_inj //; apply: polyC_inj. Qed. Lemma sub_annihilant_in_ideal p q : 1 < size p -> 1 < size q -> {uv : {poly {poly R}} * {poly {poly R}} | size uv.1 < size q /\ size uv.2 < size p & forall x y, (sub_annihilant p q).[y] = uv.1.[x, y] * p.[x + y] + uv.2.[x, y] * q.[x]}. Proof. rewrite -size_poly_XaY -(size_map_polyC q) => p1_gt1 q1_gt1. have [uv /= [ub_u ub_v Dr]] := resultant_in_ideal p1_gt1 q1_gt1. exists uv => // x y; rewrite -[r in r.[y]](hornerC _ x%:P) Dr. by rewrite !(hornerE, horner_comp). Qed. Lemma sub_annihilantP p q x y : p != 0 -> q != 0 -> p.[x] = 0 -> q.[y] = 0 -> (sub_annihilant p q).[x - y] = 0. Proof. move=> nz_p nz_q px0 qy0. have p_gt1: size p > 1 by have /rootP/root_size_gt1-> := px0. have q_gt1: size q > 1 by have /rootP/root_size_gt1-> := qy0. have [uv /= _ /(_ y)->] := sub_annihilant_in_ideal p_gt1 q_gt1. by rewrite (addrC y) subrK px0 qy0 !mulr0 addr0. Qed. Lemma sub_annihilant_neq0 p q : p != 0 -> q != 0 -> sub_annihilant p q != 0. Proof. rewrite resultant_eq0; set p1 := poly_XaY p => nz_p nz_q. have [nz_p1 nz_q1]: p1 != 0 /\ q^:P != 0 by rewrite poly_XaY_eq0 map_polyC_eq0. rewrite -leqNgt eq_leq //; apply/eqP/Bezout_coprimepPn=> // [[[u v]]] /=. rewrite !size_poly_gt0 -andbA => /and4P[nz_u ltuq nz_v _] Duv. have /eqP/= := congr1 (size \o (lead_coef \o swapXY)) Duv. rewrite ltn_eqF // !rmorphM !lead_coefM (leq_trans (leq_ltn_trans _ ltuq)) //=. rewrite -{2}[u]swapXYK -sizeYE swapXY_poly_XaY lead_coef_poly_XaY. by rewrite mulrC mul_polyC size_scale ?max_size_lead_coefXY ?lead_coef_eq0. rewrite swapXY_map_polyC lead_coefC size_map_polyC. set v1 := lead_coef _; have nz_v1: v1 != 0 by rewrite lead_coef_eq0 swapXY_eq0. rewrite [in rhs in _ <= rhs]polySpred ?mulf_neq0 // size_mul //. by rewrite (polySpred nz_v1) addnC addnS polySpred // ltnS leq_addr. Qed. Lemma div_annihilant_in_ideal p q : 1 < size p -> 1 < size q -> {uv : {poly {poly R}} * {poly {poly R}} | size uv.1 < size q /\ size uv.2 < size p & forall x y, (div_annihilant p q).[y] = uv.1.[x, y] * p.[x * y] + uv.2.[x, y] * q.[x]}. Proof. rewrite -size_poly_XmY -(size_map_polyC q) => p1_gt1 q1_gt1. have [uv /= [ub_u ub_v Dr]] := resultant_in_ideal p1_gt1 q1_gt1. exists uv => // x y; rewrite -[r in r.[y]](hornerC _ x%:P) Dr. by rewrite !(hornerE, horner_comp). Qed. Lemma div_annihilant_neq0 p q : p != 0 -> q.[0] != 0 -> div_annihilant p q != 0. Proof. have factorX u: u != 0 -> root u 0 -> exists2 v, v != 0 & u = v * 'X. move=> nz_u /factor_theorem[v]; rewrite subr0 => Du; exists v => //. by apply: contraNneq nz_u => v0; rewrite Du v0 mul0r. have nzX: 'X != 0 := monic_neq0 (monicX _); have rootC0 := root_polyC _ 0. rewrite resultant_eq0 -leqNgt -rootE // => nz_p nz_q0; apply/eq_leq/eqP. have nz_q: q != 0 by apply: contraNneq nz_q0 => ->; rewrite root0. apply/Bezout_coprimepPn; rewrite ?map_polyC_eq0 ?poly_XmY_eq0 // => [[uv]]. rewrite !size_poly_gt0 -andbA ltnNge => /and4P[nz_u /negP ltuq nz_v _] Duv. pose u := swapXY uv.1; pose v := swapXY uv.2. suffices{ltuq}: size q <= sizeY u by rewrite sizeYE swapXYK -size_map_polyC. have{nz_u nz_v} [nz_u nz_v Dvu]: [/\ u != 0, v != 0 & q *: v = u * poly_XmY p]. rewrite !swapXY_eq0; split=> //; apply: (can_inj swapXYK). by rewrite linearZ rmorphM /= !swapXYK swapXY_poly_XmY Duv mulrC. have{Duv} [n ltvn]: {n | size v < n} by exists (size v).+1. elim: n {uv} => // n IHn in p (v) (u) nz_u nz_v Dvu nz_p ltvn *. have Dp0: root (poly_XmY p) 0 = root p 0 by rewrite root_comp !hornerE rootC0. have Dv0: root u 0 || root p 0 = root v 0 by rewrite -Dp0 -rootM -Dvu rootZ. have [v0_0 | nz_v0] := boolP (root v 0); last first. have nz_p0: ~~ root p 0 by apply: contra nz_v0; rewrite -Dv0 orbC => ->. apply: (@leq_trans (size (q * v.[0]))). by rewrite size_mul // (polySpred nz_v0) addnS leq_addr. rewrite -hornerZ Dvu !(horner_comp, hornerE) horner_map mulrC size_Cmul //. by rewrite horner_coef0 max_size_coefXY. have [v1 nz_v1 Dv] := factorX _ _ nz_v v0_0; rewrite Dv size_mulX // in ltvn. have /orP[/factorX[//|u1 nz_u1 Du] | p0_0]: root u 0 || root p 0 by rewrite Dv0. rewrite Du sizeY_mulX; apply: IHn nz_u1 nz_v1 _ nz_p ltvn. by apply: (mulIf (nzX _)); rewrite mulrAC -scalerAl -Du -Dv. have /factorX[|v2 nz_v2 Dv1]: root (swapXY v1) 0; rewrite ?swapXY_eq0 //. suffices: root (swapXY v1 * 'Y) 0 by rewrite mulrC mul_polyC rootZ ?polyX_eq0. have: root (swapXY (q *: v)) 0. by rewrite Dvu rmorphM rootM /= swapXY_poly_XmY Dp0 p0_0 orbT. by rewrite linearZ rootM rootC0 (negPf nz_q0) /= Dv rmorphM /= swapXY_X. rewrite ltnS (canRL swapXYK Dv1) -sizeYE sizeY_mulX sizeYE in ltvn. have [p1 nz_p1 Dp] := factorX _ _ nz_p p0_0. apply: IHn nz_u _ _ nz_p1 ltvn; first by rewrite swapXY_eq0. apply: (@mulIf _ ('X * 'Y)); first by rewrite mulf_neq0 ?polyC_eq0 ?nzX. rewrite -scalerAl mulrA mulrAC -{1}swapXY_X -rmorphM /= -Dv1 swapXYK -Dv Dvu. by rewrite /poly_XmY Dp rmorphM /= map_polyX comp_polyM comp_polyX mulrA. Qed. End PolyXY_Idomain. Section PolyXY_Field. Variables (F E : fieldType) (FtoE : {rmorphism F -> E}). Local Notation pFtoE := (map_poly (GRing.RMorphism.apply FtoE)). Lemma div_annihilantP (p q : {poly E}) (x y : E) : p != 0 -> q != 0 -> y != 0 -> p.[x] = 0 -> q.[y] = 0 -> (div_annihilant p q).[x / y] = 0. Proof. move=> nz_p nz_q nz_y px0 qy0. have p_gt1: size p > 1 by have /rootP/root_size_gt1-> := px0. have q_gt1: size q > 1 by have /rootP/root_size_gt1-> := qy0. have [uv /= _ /(_ y)->] := div_annihilant_in_ideal p_gt1 q_gt1. by rewrite (mulrC y) divfK // px0 qy0 !mulr0 addr0. Qed. Lemma map_sub_annihilantP (p q : {poly F}) (x y : E) : p != 0 -> q != 0 ->(p ^ FtoE).[x] = 0 -> (q ^ FtoE).[y] = 0 -> (sub_annihilant p q ^ FtoE).[x - y] = 0. Proof. move=> nz_p nz_q px0 qy0; have pFto0 := map_poly_eq0 FtoE. rewrite map_resultant ?pFto0 ?lead_coef_eq0 ?map_poly_eq0 ?poly_XaY_eq0 //. rewrite map_comp_poly rmorphD /= map_polyC /= !map_polyX -!map_poly_comp /=. by rewrite !(eq_map_poly (map_polyC _)) !map_poly_comp sub_annihilantP ?pFto0. Qed. Lemma map_div_annihilantP (p q : {poly F}) (x y : E) : p != 0 -> q != 0 -> y != 0 -> (p ^ FtoE).[x] = 0 -> (q ^ FtoE).[y] = 0 -> (div_annihilant p q ^ FtoE).[x / y] = 0. Proof. move=> nz_p nz_q nz_y px0 qy0; have pFto0 := map_poly_eq0 FtoE. rewrite map_resultant ?pFto0 ?lead_coef_eq0 ?map_poly_eq0 ?poly_XmY_eq0 //. rewrite map_comp_poly rmorphM /= map_polyC /= !map_polyX -!map_poly_comp /=. by rewrite !(eq_map_poly (map_polyC _)) !map_poly_comp div_annihilantP ?pFto0. Qed. Lemma root_annihilant x p (pEx := (p ^ pFtoE).[x%:P]) : pEx != 0 -> algebraicOver FtoE x -> exists2 r : {poly F}, r != 0 & forall y, root pEx y -> root (r ^ FtoE) y. Proof. move=> nz_px [q nz_q qx0]. have [/size1_polyC Dp | p_gt1] := leqP (size p) 1. by rewrite {}/pEx Dp map_polyC hornerC map_poly_eq0 in nz_px *; exists p`_0. have nz_p: p != 0 by rewrite -size_poly_gt0 ltnW. elim: {q}_.+1 {-2}q (ltnSn (size q)) => // m IHm q le_qm in nz_q qx0 *. have nz_q1: q^:P != 0 by rewrite map_poly_eq0. have sz_q1: size q^:P = size q by rewrite size_map_polyC. have q1_gt1: size q^:P > 1. by rewrite sz_q1 -(size_map_poly FtoE) (root_size_gt1 _ qx0) ?map_poly_eq0. have [uv _ Dr] := resultant_in_ideal p_gt1 q1_gt1; set r := resultant p _ in Dr. have /eqP q1x0: (q^:P ^ pFtoE).[x%:P] == 0. by rewrite -swapXY_polyC -swapXY_map horner_swapXY !map_polyC polyC_eq0. have [|r_nz] := boolP (r == 0); last first. exists r => // y pxy0; rewrite -[r ^ _](hornerC _ x%:P) -map_polyC Dr. by rewrite rmorphD !rmorphM !hornerE q1x0 mulr0 addr0 rootM pxy0 orbT. rewrite resultant_eq0 => /gtn_eqF/Bezout_coprimepPn[]// [q2 p1] /=. rewrite size_poly_gt0 sz_q1 => /andP[/andP[nz_q2 ltq2] _] Dq. pose n := (size (lead_coef q2)).-1; pose q3 := map_poly (coefp n) q2. have nz_q3: q3 != 0 by rewrite map_poly_eq0_id0 ?lead_coef_eq0. apply: (IHm q3); rewrite ?(leq_ltn_trans (size_poly _ _)) ?(leq_trans ltq2) //. have /polyP/(_ n)/eqP: (q2 ^ pFtoE).[x%:P] = 0. apply: (mulIf nz_px); rewrite -hornerM -rmorphM Dq rmorphM hornerM /= q1x0. by rewrite mul0r mulr0. rewrite coef0; congr (_ == 0); rewrite !horner_coef coef_sum. rewrite size_map_poly !size_map_poly_id0 ?map_poly_eq0 ?lead_coef_eq0 //. by apply: eq_bigr => i _; rewrite -rmorphX coefMC !coef_map. Qed. Lemma algebraic_root_polyXY x y : (let pEx p := (p ^ map_poly FtoE).[x%:P] in exists2 p, pEx p != 0 & root (pEx p) y) -> algebraicOver FtoE x -> algebraicOver FtoE y. Proof. by case=> p nz_px pxy0 /(root_annihilant nz_px)[r]; exists r; auto. Qed. End PolyXY_Field. mathcomp-1.5/theories/closed_field.v0000644000175000017500000006063412307636117016617 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq. Require Import bigop ssralg poly polydiv. (******************************************************************************) (* A proof that algebraically closed field enjoy quantifier elimination, *) (* as described in *) (* ``A formal quantifier elimination for algebraically closed fields'', *) (* proceedings of Calculemus 2010, by Cyril Cohen and Assia Mahboubi *) (* *) (* This file constructs an instance of quantifier elimination mixin, *) (* (see the ssralg library) from the theory of polynomials with coefficients *) (* is an algebraically closed field (see the polydiv library). *) (* *) (* This file hence deals with the transformation of formulae part, which we *) (* address by implementing one CPS style formula transformer per effective *) (* operation involved in the proof of quantifier elimination. See the paper *) (* for more details. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GRing. Local Open Scope ring_scope. Import Pdiv.Ring. Import PreClosedField. Section ClosedFieldQE. Variable F : Field.type. Variable axiom : ClosedField.axiom F. Notation fF := (formula F). Notation qf f := (qf_form f && rformula f). Definition polyF := seq (term F). Fixpoint eval_poly (e : seq F) pf := if pf is c::qf then (eval_poly e qf)*'X + (eval e c)%:P else 0. Definition rpoly (p : polyF) := all (@rterm F) p. Fixpoint sizeT (k : nat -> fF) (p : polyF) := if p is c::q then sizeT (fun n => if n is m.+1 then k m.+2 else GRing.If (c == 0) (k 0%N) (k 1%N)) q else k O%N. Lemma sizeTP (k : nat -> formula F) (pf : polyF) (e : seq F) : qf_eval e (sizeT k pf) = qf_eval e (k (size (eval_poly e pf))). Proof. elim: pf e k; first by move=> *; rewrite size_poly0. move=> c qf Pqf e k; rewrite Pqf. rewrite size_MXaddC -(size_poly_eq0 (eval_poly _ _)). by case: (size (eval_poly e qf))=> //=; case: eqP; rewrite // orbF. Qed. Lemma sizeT_qf (k : nat -> formula F) (p : polyF) : (forall n, qf (k n)) -> rpoly p -> qf (sizeT k p). Proof. elim: p k => /= [|c q ihp] k kP rp; first exact: kP. case/andP: rp=> rc rq. apply: ihp; rewrite ?rq //; case=> [|n]; last exact: kP. have [/andP[qf0 rf0] /andP[qf1 rf1]] := (kP 0, kP 1)%N. by rewrite If_form_qf ?If_form_rf //= andbT. Qed. Definition isnull (k : bool -> fF) (p : polyF) := sizeT (fun n => k (n == 0%N)) p. Lemma isnullP (k : bool -> formula F) (p : polyF) (e : seq F) : qf_eval e (isnull k p) = qf_eval e (k (eval_poly e p == 0)). Proof. by rewrite sizeTP size_poly_eq0. Qed. Lemma isnull_qf (k : bool -> formula F) (p : polyF) : (forall b, qf (k b)) -> rpoly p -> qf (isnull k p). Proof. by move=> *; apply: sizeT_qf. Qed. Definition lt_sizeT (k : bool -> fF) (p q : polyF) : fF := sizeT (fun n => sizeT (fun m => k (n [|p c]; first by rewrite /lift polyseq0. rewrite -cons_poly_def /lift polyseq_cons /nilp. case pn0: (_ == _) => /=; last by move->; rewrite -cons_poly_def. move=> _; rewrite polyseqC. case c0: (_==_)=> /=. move: pn0; rewrite (eqP c0) size_poly_eq0; move/eqP->. by apply:val_inj=> /=; rewrite polyseq_cons // polyseq0. by rewrite mul0r add0r; apply:val_inj=> /=; rewrite polyseq_cons // /nilp pn0. Qed. Fixpoint lead_coefT (k : term F -> fF) p := if p is c::q then lead_coefT (fun l => GRing.If (l == 0) (k c) (k l)) q else k (Const 0). Lemma lead_coefTP (k : term F -> formula F) : (forall x e, qf_eval e (k x) = qf_eval e (k (Const (eval e x)))) -> forall (p : polyF) (e : seq F), qf_eval e (lead_coefT k p) = qf_eval e (k (Const (lead_coef (eval_poly e p)))). Proof. move=> Pk p e; elim: p k Pk => /= [*|a p' Pp' k Pk]; first by rewrite lead_coef0. rewrite Pp'; last by move=> *; rewrite //= -Pk. rewrite GRing.eval_If /= lead_coef_eq0. case p'0: (_ == _); first by rewrite (eqP p'0) mul0r add0r lead_coefC -Pk. rewrite lead_coefDl ?lead_coefMX // polyseqC size_mul ?p'0 //; last first. by rewrite -size_poly_eq0 size_polyX. rewrite size_polyX addnC /=; case: (_ == _)=> //=. by rewrite ltnS lt0n size_poly_eq0 p'0. Qed. Lemma lead_coefT_qf (k : term F -> formula F) (p : polyF) : (forall c, rterm c -> qf (k c)) -> rpoly p -> qf (lead_coefT k p). Proof. elim: p k => /= [|c q ihp] k kP rp; first exact: kP. move: rp; case/andP=> rc rq; apply: ihp; rewrite ?rq // => l rl. have [/andP[qfc rfc] /andP[qfl rfl]] := (kP c rc, kP l rl). by rewrite If_form_qf ?If_form_rf //= andbT. Qed. Fixpoint amulXnT (a : term F) (n : nat) : polyF := if n is n'.+1 then (Const 0) :: (amulXnT a n') else [::a]. Lemma eval_amulXnT (a : term F) (n : nat) (e : seq F) : eval_poly e (amulXnT a n) = (eval e a)%:P * 'X^n. Proof. elim: n=> [|n] /=; first by rewrite expr0 mulr1 mul0r add0r. by move->; rewrite addr0 -mulrA -exprSr. Qed. Lemma ramulXnT: forall a n, rterm a -> rpoly (amulXnT a n). Proof. by move=> a n; elim: n a=> [a /= -> //|n ihn a ra]; apply: ihn. Qed. Fixpoint sumpT (p q : polyF) := if p is a::p' then if q is b::q' then (Add a b)::(sumpT p' q') else p else q. Lemma eval_sumpT (p q : polyF) (e : seq F) : eval_poly e (sumpT p q) = (eval_poly e p) + (eval_poly e q). Proof. elim: p q => [|a p Hp] q /=; first by rewrite add0r. case: q => [|b q] /=; first by rewrite addr0. rewrite Hp mulrDl -!addrA; congr (_+_); rewrite polyC_add addrC -addrA. by congr (_+_); rewrite addrC. Qed. Lemma rsumpT (p q : polyF) : rpoly p -> rpoly q -> rpoly (sumpT p q). Proof. elim: p q=> [|a p ihp] q rp rq //; move: rp; case/andP=> ra rp. case: q rq => [|b q]; rewrite /= ?ra ?rp //=. by case/andP=> -> rq //=; apply: ihp. Qed. Fixpoint mulpT (p q : polyF) := if p is a :: p' then sumpT (map (Mul a) q) (Const 0::(mulpT p' q)) else [::]. Lemma eval_mulpT (p q : polyF) (e : seq F) : eval_poly e (mulpT p q) = (eval_poly e p) * (eval_poly e q). Proof. elim: p q=> [|a p Hp] q /=; first by rewrite mul0r. rewrite eval_sumpT /= Hp addr0 mulrDl addrC mulrAC; congr (_+_). elim: q=> [|b q Hq] /=; first by rewrite mulr0. by rewrite Hq polyC_mul mulrDr mulrA. Qed. Lemma rpoly_map_mul (t : term F) (p : polyF) (rt : rterm t) : rpoly (map (Mul t) p) = rpoly p. Proof. by rewrite /rpoly all_map /= (@eq_all _ _ (@rterm _)) // => x; rewrite /= rt. Qed. Lemma rmulpT (p q : polyF) : rpoly p -> rpoly q -> rpoly (mulpT p q). Proof. elim: p q=> [|a p ihp] q rp rq //=; move: rp; case/andP=> ra rp /=. apply: rsumpT; last exact: ihp. by rewrite rpoly_map_mul. Qed. Definition opppT := map (Mul (@Const F (-1))). Lemma eval_opppT (p : polyF) (e : seq F) : eval_poly e (opppT p) = - eval_poly e p. Proof. by elim: p; rewrite /= ?oppr0 // => ? ? ->; rewrite !mulNr opprD polyC_opp mul1r. Qed. Definition natmulpT n := map (Mul (@NatConst F n)). Lemma eval_natmulpT (p : polyF) (n : nat) (e : seq F) : eval_poly e (natmulpT n p) = (eval_poly e p) *+ n. Proof. elim: p; rewrite //= ?mul0rn // => c p ->. rewrite mulrnDl mulr_natl polyC_muln; congr (_+_). by rewrite -mulr_natl mulrAC -mulrA mulr_natl mulrC. Qed. Fixpoint redivp_rec_loopT (q : polyF) sq cq (k : nat * polyF * polyF -> fF) (c : nat) (qq r : polyF) (n : nat) {struct n}:= sizeT (fun sr => if sr < sq then k (c, qq, r) else lead_coefT (fun lr => let m := amulXnT lr (sr - sq) in let qq1 := sumpT (mulpT qq [::cq]) m in let r1 := sumpT (mulpT r ([::cq])) (opppT (mulpT m q)) in if n is n1.+1 then redivp_rec_loopT q sq cq k c.+1 qq1 r1 n1 else k (c.+1, qq1, r1) ) r ) r. Fixpoint redivp_rec_loop (q : {poly F}) sq cq (k : nat) (qq r : {poly F})(n : nat) {struct n} := if size r < sq then (k, qq, r) else let m := (lead_coef r) *: 'X^(size r - sq) in let qq1 := qq * cq%:P + m in let r1 := r * cq%:P - m * q in if n is n1.+1 then redivp_rec_loop q sq cq k.+1 qq1 r1 n1 else (k.+1, qq1, r1). Lemma redivp_rec_loopTP (k : nat * polyF * polyF -> formula F) : (forall c qq r e, qf_eval e (k (c,qq,r)) = qf_eval e (k (c, lift (eval_poly e qq), lift (eval_poly e r)))) -> forall q sq cq c qq r n e (d := redivp_rec_loop (eval_poly e q) sq (eval e cq) c (eval_poly e qq) (eval_poly e r) n), qf_eval e (redivp_rec_loopT q sq cq k c qq r n) = qf_eval e (k (d.1.1, lift d.1.2, lift d.2)). Proof. move=> Pk q sq cq c qq r n e /=. elim: n c qq r k Pk e => [|n Pn] c qq r k Pk e; rewrite sizeTP. case ltrq : (_ < _); first by rewrite /= ltrq /= -Pk. rewrite lead_coefTP => [|a p]; rewrite Pk. rewrite ?(eval_mulpT,eval_amulXnT,eval_sumpT,eval_opppT) //=. by rewrite ltrq //= mul_polyC ?(mul0r,add0r). by symmetry; rewrite Pk ?(eval_mulpT,eval_amulXnT,eval_sumpT, eval_opppT). case ltrq : (_<_); first by rewrite /= ltrq Pk. rewrite lead_coefTP. rewrite Pn ?(eval_mulpT,eval_amulXnT,eval_sumpT,eval_opppT) //=. by rewrite ltrq //= mul_polyC ?(mul0r,add0r). rewrite -/redivp_rec_loopT => x e'. rewrite Pn; last by move=>*; rewrite Pk. symmetry; rewrite Pn; last by move=>*; rewrite Pk. rewrite Pk ?(eval_lift,eval_mulpT,eval_amulXnT,eval_sumpT,eval_opppT). by rewrite mul_polyC ?(mul0r,add0r). Qed. Lemma redivp_rec_loopT_qf (q : polyF) (sq : nat) (cq : term F) (k : nat * polyF * polyF -> formula F) (c : nat) (qq r : polyF) (n : nat) : (forall r, [&& rpoly r.1.2 & rpoly r.2] -> qf (k r)) -> rpoly q -> rterm cq -> rpoly qq -> rpoly r -> qf (redivp_rec_loopT q sq cq k c qq r n). Proof. elim: n q sq cq k c qq r => [|n ihn] q sq cq k c qq r kP rq rcq rqq rr. apply: sizeT_qf=> // n; case: (_ < _); first by apply: kP; rewrite // rqq rr. apply: lead_coefT_qf=> // l rl; apply: kP. by rewrite /= ?(rsumpT,rmulpT,ramulXnT,rpoly_map_mul) //= rcq. apply: sizeT_qf=> // m; case: (_ < _); first by apply: kP => //=; rewrite rqq rr. apply: lead_coefT_qf=> // l rl; apply: ihn; rewrite //= ?rcq //. by rewrite ?(rsumpT,rmulpT,ramulXnT,rpoly_map_mul) //= rcq. by rewrite ?(rsumpT,rmulpT,ramulXnT,rpoly_map_mul) //= rcq. Qed. Definition redivpT (p : polyF) (k : nat * polyF * polyF -> fF) (q : polyF) : fF := isnull (fun b => if b then k (0%N, [::Const 0], p) else sizeT (fun sq => sizeT (fun sp => lead_coefT (fun lq => redivp_rec_loopT q sq lq k 0 [::Const 0] p sp ) q ) p ) q ) q. Lemma redivp_rec_loopP (q : {poly F}) (c : nat) (qq r : {poly F}) (n : nat) : redivp_rec q c qq r n = redivp_rec_loop q (size q) (lead_coef q) c qq r n. Proof. by elim: n c qq r => [| n Pn] c qq r //=; rewrite Pn. Qed. Lemma redivpTP (k : nat * polyF * polyF -> formula F) : (forall c qq r e, qf_eval e (k (c,qq,r)) = qf_eval e (k (c, lift (eval_poly e qq), lift (eval_poly e r)))) -> forall p q e (d := redivp (eval_poly e p) (eval_poly e q)), qf_eval e (redivpT p k q) = qf_eval e (k (d.1.1, lift d.1.2, lift d.2)). Proof. move=> Pk p q e /=; rewrite isnullP unlock. case q0 : (_ == _); first by rewrite Pk /= mul0r add0r polyC0. rewrite !sizeTP lead_coefTP /=; last by move=> *; rewrite !redivp_rec_loopTP. rewrite redivp_rec_loopTP /=; last by move=> *; rewrite Pk. by rewrite mul0r add0r polyC0 redivp_rec_loopP. Qed. Lemma redivpT_qf (p : polyF) (k : nat * polyF * polyF -> formula F) (q : polyF) : (forall r, [&& rpoly r.1.2 & rpoly r.2] -> qf (k r)) -> rpoly p -> rpoly q -> qf (redivpT p k q). Proof. move=> kP rp rq; rewrite /redivpT; apply: isnull_qf=> // [[]]; first exact: kP. apply: sizeT_qf => // sq; apply: sizeT_qf=> // sp. apply: lead_coefT_qf=> // lq rlq; exact: redivp_rec_loopT_qf. Qed. Definition rmodpT (p : polyF) (k : polyF -> fF) (q : polyF) : fF := redivpT p (fun d => k d.2) q. Definition rdivpT (p : polyF) (k:polyF -> fF) (q : polyF) : fF := redivpT p (fun d => k d.1.2) q. Definition rscalpT (p : polyF) (k: nat -> fF) (q : polyF) : fF := redivpT p (fun d => k d.1.1) q. Definition rdvdpT (p : polyF) (k:bool -> fF) (q : polyF) : fF := rmodpT p (isnull k) q. Fixpoint rgcdp_loop n (pp qq : {poly F}) {struct n} := if rmodp pp qq == 0 then qq else if n is n1.+1 then rgcdp_loop n1 qq (rmodp pp qq) else rmodp pp qq. Fixpoint rgcdp_loopT (pp : polyF) (k : polyF -> formula F) n (qq : polyF) := rmodpT pp (isnull (fun b => if b then (k qq) else (if n is n1.+1 then rmodpT pp (rgcdp_loopT qq k n1) qq else rmodpT pp k qq) ) ) qq. Lemma rgcdp_loopP (k : polyF -> formula F) : (forall p e, qf_eval e (k p) = qf_eval e (k (lift (eval_poly e p)))) -> forall n p q e, qf_eval e (rgcdp_loopT p k n q) = qf_eval e (k (lift (rgcdp_loop n (eval_poly e p) (eval_poly e q)))). Proof. move=> Pk n p q e. elim: n p q e => /= [| m Pm] p q e. rewrite redivpTP; last by move=>*; rewrite !isnullP eval_lift. rewrite isnullP eval_lift; case: (_ == 0); first by rewrite Pk. by rewrite redivpTP; last by move=>*; rewrite Pk. rewrite redivpTP; last by move=>*; rewrite !isnullP eval_lift. rewrite isnullP eval_lift; case: (_ == 0); first by rewrite Pk. by rewrite redivpTP; move=>*; rewrite ?Pm !eval_lift. Qed. Lemma rgcdp_loopT_qf (p : polyF) (k : polyF -> formula F) (q : polyF) (n : nat) : (forall r, rpoly r -> qf (k r)) -> rpoly p -> rpoly q -> qf (rgcdp_loopT p k n q). elim: n p k q => [|n ihn] p k q kP rp rq. apply: redivpT_qf=> // r; case/andP=> _ rr. apply: isnull_qf=> // [[]]; first exact: kP. by apply: redivpT_qf=> // r'; case/andP=> _ rr'; apply: kP. apply: redivpT_qf=> // r; case/andP=> _ rr. apply: isnull_qf=> // [[]]; first exact: kP. by apply: redivpT_qf=> // r'; case/andP=> _ rr'; apply: ihn. Qed. Definition rgcdpT (p : polyF) k (q : polyF) : fF := let aux p1 k q1 := isnull (fun b => if b then (k q1) else (sizeT (fun n => (rgcdp_loopT p1 k n q1)) p1)) p1 in (lt_sizeT (fun b => if b then (aux q k p) else (aux p k q)) p q). Lemma rgcdpTP (k : seq (term F) -> formula F) : (forall p e, qf_eval e (k p) = qf_eval e (k (lift (eval_poly e p)))) -> forall p q e, qf_eval e (rgcdpT p k q) = qf_eval e (k (lift (rgcdp (eval_poly e p) (eval_poly e q)))). Proof. move=> Pk p q e; rewrite /rgcdpT !sizeTP; case lqp: (_ < _). rewrite isnullP; case q0: (_ == _); first by rewrite Pk (eqP q0) rgcdp0. rewrite sizeTP rgcdp_loopP => [|e' p']; last by rewrite Pk. by rewrite /rgcdp lqp q0. rewrite isnullP; case p0: (_ == _); first by rewrite Pk (eqP p0) rgcd0p. rewrite sizeTP rgcdp_loopP => [|e' p']; last by rewrite Pk. by rewrite /rgcdp lqp p0. Qed. Lemma rgcdpT_qf (p : polyF) (k : polyF -> formula F) (q : polyF) : (forall r, rpoly r -> qf (k r)) -> rpoly p -> rpoly q -> qf (rgcdpT p k q). Proof. move=> kP rp rq; apply: sizeT_qf=> // n; apply: sizeT_qf=> // m. by case:(_ < _); apply: isnull_qf=> //; case; do ?apply: kP=> //; apply: sizeT_qf=> // n'; apply: rgcdp_loopT_qf. Qed. Fixpoint rgcdpTs k (ps : seq polyF) : fF := if ps is p::pr then rgcdpTs (rgcdpT p k) pr else k [::Const 0]. Lemma rgcdpTsP (k : polyF -> formula F) : (forall p e, qf_eval e (k p) = qf_eval e (k (lift (eval_poly e p)))) -> forall ps e, qf_eval e (rgcdpTs k ps) = qf_eval e (k (lift (\big[@rgcdp _/0%:P]_(i <- ps)(eval_poly e i)))). Proof. move=> Pk ps e. elim: ps k Pk; first by move=> p Pk; rewrite /= big_nil Pk /= mul0r add0r. move=> p ps Pps /= k Pk /=; rewrite big_cons Pps => [|p' e']. by rewrite rgcdpTP // eval_lift. by rewrite !rgcdpTP // Pk !eval_lift . Qed. Definition rseq_poly ps := all rpoly ps. Lemma rgcdpTs_qf (k : polyF -> formula F) (ps : seq polyF) : (forall r, rpoly r -> qf (k r)) -> rseq_poly ps -> qf (rgcdpTs k ps). Proof. elim: ps k=> [|c p ihp] k kP rps=> /=; first exact: kP. by move: rps; case/andP=> rc rp; apply: ihp=> // r rr; apply: rgcdpT_qf. Qed. Fixpoint rgdcop_recT (q : polyF) k (p : polyF) n := if n is m.+1 then rgcdpT p (sizeT (fun sd => if sd == 1%N then k p else rgcdpT p (rdivpT p (fun r => rgdcop_recT q k r m)) q )) q else isnull (fun b => k [::Const b%:R]) q. Lemma rgdcop_recTP (k : polyF -> formula F) : (forall p e, qf_eval e (k p) = qf_eval e (k (lift (eval_poly e p)))) -> forall p q n e, qf_eval e (rgdcop_recT p k q n) = qf_eval e (k (lift (rgdcop_rec (eval_poly e p) (eval_poly e q) n))). Proof. move=> Pk p q n e. elim: n k Pk p q e => [|n Pn] k Pk p q e /=. rewrite isnullP /=. by case: (_ == _); rewrite Pk /= mul0r add0r ?(polyC0, polyC1). rewrite rgcdpTP ?sizeTP ?eval_lift //. rewrite /rcoprimep; case se : (_==_); rewrite Pk //. do ?[rewrite (rgcdpTP,Pn,eval_lift,redivpTP) | move=> * //=]. by do ?[rewrite (sizeTP,eval_lift) | move=> * //=]. Qed. Lemma rgdcop_recT_qf (p : polyF) (k : polyF -> formula F) (q : polyF) (n : nat) : (forall r, rpoly r -> qf (k r)) -> rpoly p -> rpoly q -> qf (rgdcop_recT p k q n). Proof. elim: n p k q => [|n ihn] p k q kP rp rq /=. apply: isnull_qf=> //; first by case; rewrite kP. apply: rgcdpT_qf=> // g rg; apply: sizeT_qf=> // n'. case: (_ == _); first exact: kP. apply: rgcdpT_qf=> // g' rg'; apply: redivpT_qf=> // r; case/andP=> rr _. exact: ihn. Qed. Definition rgdcopT q k p := sizeT (rgdcop_recT q k p) p. Lemma rgdcopTP (k : polyF -> formula F) : (forall p e, qf_eval e (k p) = qf_eval e (k (lift (eval_poly e p)))) -> forall p q e, qf_eval e (rgdcopT p k q) = qf_eval e (k (lift (rgdcop (eval_poly e p) (eval_poly e q)))). Proof. by move=> *; rewrite sizeTP rgdcop_recTP 1?Pk. Qed. Lemma rgdcopT_qf (p : polyF) (k : polyF -> formula F) (q : polyF) : (forall r, rpoly r -> qf (k r)) -> rpoly p -> rpoly q -> qf (rgdcopT p k q). Proof. by move=> kP rp rq; apply: sizeT_qf => // n; apply: rgdcop_recT_qf. Qed. Definition ex_elim_seq (ps : seq polyF) (q : polyF) := (rgcdpTs (rgdcopT q (sizeT (fun n => Bool (n != 1%N)))) ps). Lemma ex_elim_seqP (ps : seq polyF) (q : polyF) (e : seq F) : let gp := (\big[@rgcdp _/0%:P]_(p <- ps)(eval_poly e p)) in qf_eval e (ex_elim_seq ps q) = (size (rgdcop (eval_poly e q) gp) != 1%N). Proof. by do ![rewrite (rgcdpTsP,rgdcopTP,sizeTP,eval_lift) //= | move=> * //=]. Qed. Lemma ex_elim_seq_qf (ps : seq polyF) (q : polyF) : rseq_poly ps -> rpoly q -> qf (ex_elim_seq ps q). Proof. move=> rps rq; apply: rgcdpTs_qf=> // g rg; apply: rgdcopT_qf=> // d rd. exact : sizeT_qf. Qed. Fixpoint abstrX (i : nat) (t : term F) := match t with | (Var n) => if n == i then [::Const 0; Const 1] else [::t] | (Opp x) => opppT (abstrX i x) | (Add x y) => sumpT (abstrX i x) (abstrX i y) | (Mul x y) => mulpT (abstrX i x) (abstrX i y) | (NatMul x n) => natmulpT n (abstrX i x) | (Exp x n) => let ax := (abstrX i x) in iter n (mulpT ax) [::Const 1] | _ => [::t] end. Lemma abstrXP (i : nat) (t : term F) (e : seq F) (x : F) : rterm t -> (eval_poly e (abstrX i t)).[x] = eval (set_nth 0 e i x) t. Proof. elim: t => [n | r | n | t tP s sP | t tP | t tP n | t tP s sP | t tP | t tP n] h. - move=> /=; case ni: (_ == _); rewrite //= ?(mul0r,add0r,addr0,polyC1,mul1r,hornerX,hornerC); by rewrite // nth_set_nth /= ni. - by rewrite /= mul0r add0r hornerC. - by rewrite /= mul0r add0r hornerC. - by case/andP: h => *; rewrite /= eval_sumpT hornerD tP ?sP. - by rewrite /= eval_opppT hornerN tP. - by rewrite /= eval_natmulpT hornerMn tP. - by case/andP: h => *; rewrite /= eval_mulpT hornerM tP ?sP. - by []. - elim: n h => [|n ihn] rt; first by rewrite /= expr0 mul0r add0r hornerC. by rewrite /= eval_mulpT exprSr hornerM ihn // mulrC tP. Qed. Lemma rabstrX (i : nat) (t : term F) : rterm t -> rpoly (abstrX i t). Proof. elim: t; do ?[ by move=> * //=; do ?case: (_ == _)]. - move=> t irt s irs /=; case/andP=> rt rs. by apply: rsumpT; rewrite ?irt ?irs //. - by move=> t irt /= rt; rewrite rpoly_map_mul ?irt //. - by move=> t irt /= n rt; rewrite rpoly_map_mul ?irt //. - move=> t irt s irs /=; case/andP=> rt rs. by apply: rmulpT; rewrite ?irt ?irs //. - move=> t irt /= n rt; move: (irt rt)=> {rt} rt; elim: n => [|n ihn] //=. exact: rmulpT. Qed. Implicit Types tx ty : term F. Lemma abstrX_mulM (i : nat) : {morph abstrX i : x y / Mul x y >-> mulpT x y}. Proof. done. Qed. Lemma abstrX1 (i : nat) : abstrX i (Const 1) = [::Const 1]. Proof. done. Qed. Lemma eval_poly_mulM e : {morph eval_poly e : x y / mulpT x y >-> mul x y}. Proof. by move=> x y; rewrite eval_mulpT. Qed. Lemma eval_poly1 e : eval_poly e [::Const 1] = 1. Proof. by rewrite /= mul0r add0r. Qed. Notation abstrX_bigmul := (big_morph _ (abstrX_mulM _) (abstrX1 _)). Notation eval_bigmul := (big_morph _ (eval_poly_mulM _) (eval_poly1 _)). Notation bigmap_id := (big_map _ (fun _ => true) id). Lemma rseq_poly_map (x : nat) (ts : seq (term F)) : all (@rterm _) ts -> rseq_poly (map (abstrX x) ts). Proof. by elim: ts => //= t ts iht; case/andP=> rt rts; rewrite rabstrX // iht. Qed. Definition ex_elim (x : nat) (pqs : seq (term F) * seq (term F)) := ex_elim_seq (map (abstrX x) pqs.1) (abstrX x (\big[Mul/Const 1]_(q <- pqs.2) q)). Lemma ex_elim_qf (x : nat) (pqs : seq (term F) * seq (term F)) : dnf_rterm pqs -> qf (ex_elim x pqs). case: pqs => ps qs; case/andP=> /= rps rqs. apply: ex_elim_seq_qf; first exact: rseq_poly_map. apply: rabstrX=> /=. elim: qs rqs=> [|t ts iht] //=; first by rewrite big_nil. by case/andP=> rt rts; rewrite big_cons /= rt /= iht. Qed. Lemma holds_conj : forall e i x ps, all (@rterm _) ps -> (holds (set_nth 0 e i x) (foldr (fun t : term F => And (t == 0)) True ps) <-> all ((@root _)^~ x) (map (eval_poly e \o abstrX i) ps)). Proof. move=> e i x; elim=> [|p ps ihps] //=. case/andP=> rp rps; rewrite rootE abstrXP //. constructor; first by case=> -> hps; rewrite eqxx /=; apply/ihps. by case/andP; move/eqP=> -> psr; split=> //; apply/ihps. Qed. Lemma holds_conjn (e : seq F) (i : nat) (x : F) (ps : seq (term F)) : all (@rterm _) ps -> (holds (set_nth 0 e i x) (foldr (fun t : term F => And (t != 0)) True ps) <-> all (fun p => ~~root p x) (map (eval_poly e \o abstrX i) ps)). Proof. elim: ps => [|p ps ihps] //=. case/andP=> rp rps; rewrite rootE abstrXP //. constructor; first by case=> /eqP-> hps /=; apply/ihps. by case/andP=> pr psr; split; first apply/eqP=> //; apply/ihps. Qed. Lemma holds_ex_elim : GRing.valid_QE_proj ex_elim. Proof. move=> i [ps qs] /= e; case/andP=> /= rps rqs. rewrite ex_elim_seqP big_map. have -> : \big[@rgcdp _/0%:P]_(j <- ps) eval_poly e (abstrX i j) = \big[@rgcdp _/0%:P]_(j <- (map (eval_poly e) (map (abstrX i) (ps)))) j. by rewrite !big_map. rewrite -!map_comp. have aux I (l : seq I) (P : I -> {poly F}) : \big[(@gcdp F)/0]_(j <- l) P j %= \big[(@rgcdp F)/0]_(j <- l) P j. elim: l => [| u l ihl] /=; first by rewrite !big_nil eqpxx. rewrite !big_cons; move: ihl; move/(eqp_gcdr (P u)) => h. apply: eqp_trans h _; rewrite eqp_sym; exact: eqp_rgcd_gcd. case g0: (\big[(@rgcdp F)/0%:P]_(j <- map (eval_poly e \o abstrX i) ps) j == 0). rewrite (eqP g0) rgdcop0. case m0 : (_ == 0)=> //=; rewrite ?(size_poly1,size_poly0) //=. rewrite abstrX_bigmul eval_bigmul -bigmap_id in m0. constructor=> [[x] // []] //. case=> _; move/holds_conjn=> hc; move/hc:rqs. by rewrite -root_bigmul //= (eqP m0) root0. constructor; move/negP:m0; move/negP=>m0. case: (closed_nonrootP axiom _ m0) => x {m0}. rewrite abstrX_bigmul eval_bigmul -bigmap_id root_bigmul=> m0. exists x; do 2?constructor=> //; last by apply/holds_conjn. apply/holds_conj; rewrite //= -root_biggcd. by rewrite (eqp_root (aux _ _ _ )) (eqP g0) root0. apply:(iffP (closed_rootP axiom _)); case=> x Px; exists x; move:Px => //=. rewrite (eqp_root (eqp_rgdco_gdco _ _)) root_gdco ?g0 //. rewrite -(eqp_root (aux _ _ _ )) root_biggcd abstrX_bigmul eval_bigmul. rewrite -bigmap_id root_bigmul; case/andP=> psr qsr. do 2?constructor; first by apply/holds_conj. by apply/holds_conjn. rewrite (eqp_root (eqp_rgdco_gdco _ _)) root_gdco ?g0 // -(eqp_root (aux _ _ _)). rewrite root_biggcd abstrX_bigmul eval_bigmul -bigmap_id. rewrite root_bigmul=> [[] // [hps hqs]]; apply/andP. constructor; first by apply/holds_conj. by apply/holds_conjn. Qed. Lemma wf_ex_elim : GRing.wf_QE_proj ex_elim. Proof. by move=> i bc /= rbc; apply: ex_elim_qf. Qed. Definition closed_fields_QEMixin := QEdecFieldMixin wf_ex_elim holds_ex_elim. End ClosedFieldQE. mathcomp-1.5/theories/algebraics_fundamentals.v0000644000175000017500000015061112307636117021033 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun ssrnat eqtype seq choice div fintype. Require Import path tuple bigop finset prime ssralg poly polydiv mxpoly. Require Import countalg ssrnum ssrint rat intdiv. Require Import fingroup finalg zmodp cyclic pgroup sylow. Require Import vector falgebra fieldext separable galois. (******************************************************************************) (* The main result in this file is the existence theorem that underpins the *) (* construction of the algebraic numbers in file algC.v. This theorem simply *) (* asserts the existence of an algebraically closed field with an *) (* automorphism of order 2, and dubbed the Fundamental_Theorem_of_Algebraics *) (* because it is essentially the Fundamental Theorem of Algebra for algebraic *) (* numbers (the more familiar version for complex numbers can be derived by *) (* continuity). *) (* Although our proof does indeed construct exactly the algebraics, we *) (* choose not to expose this in the statement of our Theorem. In algC.v we *) (* construct the norm and partial order of the "complex field" introduced by *) (* the Theorem; as these imply is has characteristic 0, we then get the *) (* algebraics as a subfield. To avoid some duplication a few basic properties *) (* of the algebraics, such as the existence of minimal polynomials, that are *) (* required by the proof of the Theorem, are also proved here. *) (* The main theorem of countalg.v supplies us directly with an algebraic *) (* closure of the rationals (as the rationals are a countable field), so all *) (* we really need to construct is a conjugation automorphism that exchanges *) (* the two roots (i and -i) of X^2 + 1, and fixes a (real) subfield of *) (* index 2. This does not require actually constructing this field: the *) (* kHomExtend construction from galois.v supplies us with an automorphism *) (* conj_n of the number field Q[z_n] = Q[x_n, i] for any x_n such that Q[x_n] *) (* does not contain i (e.g., such that Q[x_n] is real). As conj_n will extend *) (* conj_m when Q[x_n] contains x_m, it therefore suffices to construct a *) (* sequence x_n such that *) (* (1) For each n, Q[x_n] is a REAL field containing Q[x_m] for all m <= n. *) (* (2) Each z in C belongs to Q[z_n] = Q[x_n, i] for large enough n. *) (* This, of course, amounts to proving the Fundamental Theorem of Algebra. *) (* Indeed, we use a constructive variant of Artin's algebraic proof of that *) (* Theorem to replace (2) by *) (* (3) Each monic polynomial over Q[x_m] whose constant term is -c^2 for some *) (* c in Q[x_m] has a root in Q[x_n] for large enough n. *) (* We then ensure (3) by setting Q[x_n+1] = Q[x_n, y] where y is the root of *) (* of such a polynomial p found by dichotomy in some interval [0, b] with b *) (* suitably large (such that p[b] >= 0), and p is obtained by decoding n into *) (* a triple (m, p, c) that satisfies the conditions of (3) (taking x_n+1=x_n *) (* if this is not the case), thereby ensuring that all such triples are *) (* ultimately considered. *) (* In more detail, the 600-line proof consists in six (uneven) parts: *) (* (A) - Construction of number fields (~ 100 lines): in order to make use of *) (* the theory developped in falgebra, fieldext, separable and galois we *) (* construct a separate fielExtType Q z for the number field Q[z], with *) (* z in C, the closure of rat supplied by countable_algebraic_closure. *) (* The morphism (ofQ z) maps Q z to C, and the Primitive Element Theorem *) (* lets us define a predicate sQ z characterizing the image of (ofQ z), *) (* as well as a partial inverse (inQ z) to (ofQ z). *) (* (B) - Construction of the real extension Q[x, y] (~ 230 lines): here y has *) (* to be a root of a polynomial p over Q[x] satisfying the conditions of *) (* (3), and Q[x] should be real and archimedean, which we represent by *) (* a morphism from Q x to some archimedean field R, as the ssrnum and *) (* fieldext structures are not compatible. The construction starts by *) (* weakening the condition p[0] = -c^2 to p[0] <= 0 (in R), then reducing *) (* to the case where p is the minimal polynomial over Q[x] of some y (in *) (* some Q[w] that contains x and all roots of p). Then we only need to *) (* construct a realFieldType structure for Q[t] = Q[x,y] (we don't even *) (* need to show it is consistent with that of R). This amounts to fixing *) (* the sign of all z != 0 in Q[t], consistently with arithmetic in Q[t]. *) (* Now any such z is equal to q[y] for some q in Q[x][X] coprime with p. *) (* Then up + vq = 1 for Bezout coefficients u and v. As p is monic, there *) (* is some b0 >= 0 in R such that p changes sign in ab0 = [0; b0]. As R *) (* is archimedean, some iteration of the binary search for a root of p in *) (* ab0 will yield an interval ab_n such that |up[d]| < 1/2 for d in ab_n. *) (* Then |q[d]| > 1/2M > 0 for any upper bound M on |v[X]| in ab0, so q *) (* cannot change sign in ab_n (as then root-finding in ab_n would yield a *) (* d with |Mq[d]| < 1/2), so we can fix the sign of z to that of q in *) (* ab_n. *) (* (C) - Construction of the x_n and z_n (~50 lines): x_ n is obtained by *) (* iterating (B), starting with x_0 = 0, and then (A) and the PET yield *) (* z_ n. We establish (1) and (3), and that the minimal polynomial of the *) (* preimage i_ n of i over the preimage R_ n of Q[x_n] is X^2 + 1. *) (* (D) - Establish (2), i.e., prove the FTA (~180 lines). We must depart from *) (* Artin's proof because deciding membership in the union of the Q[x_n] *) (* requires the FTA, i.e., we cannot (yet) construct a maximal real *) (* subfield of C. We work around this issue by first reducing to the case *) (* where Q[z] is Galois over Q and contains i, then using induction over *) (* the degree of z over Q[z_ n] (i.e., the degree of a monic polynomial *) (* over Q[z_n] that has z as a root). We can assume that z is not in *) (* Q[z_n]; then it suffices to find some y in Q[z_n, z] \ Q[z_n] that is *) (* also in Q[z_m] for some m > n, as then we can apply induction with the *) (* minimal polynomial of z over Q[z_n, y]. In any Galois extension Q[t] *) (* of Q that contains both z and z_n, Q[x_n, z] = Q[z_n, z] is Galois *) (* over both Q[x_n] and Q[z_n]. If Gal(Q[x_n,z] / Q[x_n]) isn't a 2-group *) (* take one of its Sylow 2-groups P; the minimal polynomial p of any *) (* generator of the fixed field F of P over Q[x_n] has odd degree, hence *) (* by (3) - p[X]p[-X] and thus p has a root y in some Q[x_m], hence in *) (* Q[z_m]. As F is normal, y is in F, with minimal polynomial p, and y *) (* is not in Q[z_n] = Q[x_n, i] since p has odd degree. Otherwise, *) (* Gal(Q[z_n,z] / Q[z_n]) is a proper 2-group, and has a maximal subgroup *) (* P of index 2. The fixed field F of P has a generator w over Q[z_n] *) (* with w^2 in Q[z_n] \ Q[x_n], i.e. w^2 = u + 2iv with v != 0. From (3) *) (* X^4 - uX^2 - v^2 has a root x in some Q[x_m]; then x != 0 as v != 0, *) (* hence w^2 = y^2 for y = x + iv/x in Q[z_m], and y generates F. *) (* (E) - Construct conj and conclude (~40 lines): conj z is defined as *) (* conj_ n z with the n provided by (2); since each conj_ m is a morphism *) (* of order 2 and conj z = conj_ m z for any m >= n, it follows that conj *) (* is also a morphism of order 2. *) (* Note that (C), (D) and (E) only depend on Q[x_n] not containing i; the *) (* order structure is not used (hence we need not prove that the ordering of *) (* Q[x_m] is consistent with that of Q[x_n] for m >= n). *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope GRing.Theory Num.Theory. Local Open Scope ring_scope. Local Notation "p ^ f" := (map_poly f p) : ring_scope. Local Notation "p ^@" := (p ^ in_alg _) (at level 2, format "p ^@"): ring_scope. Local Notation "<< E ; u >>" := <>%VS. Local Notation Qmorphism C := {rmorphism rat -> C}. Lemma rat_algebraic_archimedean (C : numFieldType) (QtoC : Qmorphism C) : integralRange QtoC -> Num.archimedean_axiom C. Proof. move=> algC x. without loss x_ge0: x / 0 <= x by rewrite -normr_id; apply; apply: normr_ge0. have [-> | nz_x] := eqVneq x 0; first by exists 1%N; rewrite normr0. have [p mon_p px0] := algC x; exists (\sum_(j < size p) `|numq p`_j|)%N. rewrite ger0_norm // real_ltrNge ?rpred_nat ?ger0_real //. apply: contraL px0 => lb_x; rewrite rootE gtr_eqF // horner_coef size_map_poly. have x_gt0 k: 0 < x ^+ k by rewrite exprn_gt0 // ltr_def nz_x. move: lb_x; rewrite polySpred ?monic_neq0 // !big_ord_recr coef_map /=. rewrite -lead_coefE (monicP mon_p) natrD rmorph1 mul1r => lb_x. case: _.-1 (lb_x) => [|n]; first by rewrite !big_ord0 !add0r ltr01. rewrite -ltr_subl_addl add0r -(ler_pmul2r (x_gt0 n)) -exprS. apply: ltr_le_trans; rewrite mulrDl mul1r ltr_spaddr // -sumrN. rewrite natr_sum mulr_suml ler_sum // => j _. rewrite coef_map /= fmorph_eq_rat (ler_trans (real_ler_norm _)) //. by rewrite rpredN rpredM ?rpred_rat ?rpredX // ger0_real. rewrite normrN normrM ler_pmul //=. rewrite normf_div -!intr_norm -!abszE ler_pimulr ?ler0n //. by rewrite invf_le1 ?ler1n ?ltr0n ?absz_gt0 ?denq_eq0. rewrite normrX ger0_norm ?(ltrW x_gt0) // ler_weexpn2l ?leq_ord //. by rewrite (ler_trans _ lb_x) // -natrD addn1 ler1n. Qed. Definition decidable_embedding sT T (f : sT -> T) := forall y, decidable (exists x, y = f x). Lemma rat_algebraic_decidable (C : fieldType) (QtoC : Qmorphism C) : integralRange QtoC -> decidable_embedding QtoC. Proof. have QtoCinj: injective QtoC by apply: fmorph_inj. pose ZtoQ : int -> rat := intr; pose ZtoC : int -> C := intr. have ZtoQinj: injective ZtoQ by apply: intr_inj. have defZtoC: ZtoC =1 QtoC \o ZtoQ by move=> m; rewrite /= rmorph_int. move=> algC x; have /sig2_eqW[q mon_q qx0] := algC x; pose d := (size q).-1. have [n ub_n]: {n | forall y, root q y -> `|y| < n}. have [n1 ub_n1] := monic_Cauchy_bound mon_q. have /monic_Cauchy_bound[n2 ub_n2]: (-1) ^+ d *: (q \Po - 'X) \is monic. rewrite monicE lead_coefZ lead_coef_comp ?size_opp ?size_polyX // -/d. by rewrite lead_coef_opp lead_coefX (monicP mon_q) (mulrC 1) signrMK. exists (Num.max n1 n2) => y; rewrite ltrNge ler_normr !ler_maxl rootE. apply: contraL => /orP[]/andP[] => [/ub_n1/gtr_eqF->// | _ /ub_n2/gtr_eqF]. by rewrite hornerZ horner_comp !hornerE opprK mulf_eq0 signr_eq0 => /= ->. have [p [a nz_a Dq]] := rat_poly_scale q; pose N := Num.bound `|n * a%:~R|. pose xa : seq rat := [seq (m%:R - N%:R) / a%:~R | m <- iota 0 N.*2]. have [/sig2_eqW[y _ ->] | xa'x] := @mapP _ _ QtoC xa x; first by left; exists y. right=> [[y Dx]]; case: xa'x; exists y => //. have{x Dx qx0} qy0: root q y by rewrite Dx fmorph_root in qx0. have /dvdzP[b Da]: (denq y %| a)%Z. have /Gauss_dvdzl <-: coprimez (denq y) (numq y ^+ d). by rewrite coprimez_sym coprimez_expl //; apply: coprime_num_den. pose p1 : {poly int} := a *: 'X^d - p. have Dp1: p1 ^ intr = a%:~R *: ('X^d - q). by rewrite rmorphB linearZ /= map_polyXn scalerBr Dq scalerKV ?intr_eq0. apply/dvdzP; exists (\sum_(i < d) p1`_i * numq y ^+ i * denq y ^+ (d - i.+1)). apply: ZtoQinj; rewrite /ZtoQ rmorphM mulr_suml rmorph_sum /=. transitivity ((p1 ^ intr).[y] * (denq y ^+ d)%:~R). rewrite Dp1 !hornerE hornerXn (rootP qy0) subr0. by rewrite !rmorphX /= numqE exprMn mulrA. have sz_p1: (size (p1 ^ ZtoQ)%R <= d)%N. rewrite Dp1 size_scale ?intr_eq0 //; apply/leq_sizeP=> i. rewrite leq_eqVlt eq_sym -polySpred ?monic_neq0 // coefB coefXn. case: eqP => [-> _ | _ /(nth_default 0)->//]. by rewrite -lead_coefE (monicP mon_q). rewrite (horner_coef_wide _ sz_p1) mulr_suml; apply: eq_bigr => i _. rewrite -!mulrA -exprSr coef_map !rmorphM !rmorphX /= numqE exprMn -mulrA. by rewrite -exprD -addSnnS subnKC. pose m := `|(numq y * b + N)%R|%N. have Dm: m%:R = `|y * a%:~R + N%:R|. by rewrite pmulrn abszE intr_norm Da rmorphD !rmorphM /= numqE mulrAC mulrA. have ltr_Qnat n1 n2 : (n1%:R < n2%:R :> rat = _) := ltr_nat _ n1 n2. have ub_y: `|y * a%:~R| < N%:R. apply: ler_lt_trans (archi_boundP (normr_ge0 _)); rewrite !normrM. by rewrite ler_pmul ?normr_ge0 // (ler_trans _ (ler_norm n)) ?ltrW ?ub_n. apply/mapP; exists m. rewrite mem_iota /= add0n -addnn -ltr_Qnat Dm natrD. by rewrite (ler_lt_trans (ler_norm_add _ _)) // normr_nat ltr_add2r. rewrite Dm ger0_norm ?addrK ?mulfK ?intr_eq0 // -ler_subl_addl sub0r. by rewrite (ler_trans (ler_norm _)) ?normrN ?ltrW. Qed. Lemma minPoly_decidable_closure (F : fieldType) (L : closedFieldType) (FtoL : {rmorphism F -> L}) x : decidable_embedding FtoL -> integralOver FtoL x -> {p | [/\ p \is monic, root (p ^ FtoL) x & irreducible_poly p]}. Proof. move=> isF /sig2W[p /monicP mon_p px0]. have [r Dp] := closed_field_poly_normal (p ^ FtoL); pose n := size r. rewrite lead_coef_map {}mon_p rmorph1 scale1r in Dp. pose Fpx q := (q \is a polyOver isF) && root q x. have FpxF q: Fpx (q ^ FtoL) = root (q ^ FtoL) x. by rewrite /Fpx polyOver_poly // => j _; apply/sumboolP; exists q`_j. pose p_ (I : {set 'I_n}) := \prod_(i <- enum I) ('X - (r`_i)%:P). have{px0 Dp} /ex_minset[I /minsetP[/andP[FpI pIx0] minI]]: exists I, Fpx (p_ I). exists setT; suffices ->: p_ setT = p ^ FtoL by rewrite FpxF. by rewrite Dp (big_nth 0) big_mkord /p_ (eq_enum (in_set _)) big_filter. have{p} [p DpI]: {p | p_ I = p ^ FtoL}. exists (p_ I ^ (fun y => if isF y is left Fy then sval (sig_eqW Fy) else 0)). rewrite -map_poly_comp map_poly_id // => y /(allP FpI) /=. by rewrite unfold_in; case: (isF y) => // Fy _; case: (sig_eqW _). have mon_pI: p_ I \is monic by apply: monic_prod_XsubC. have mon_p: p \is monic by rewrite -(map_monic FtoL) -DpI. exists p; rewrite -DpI; split=> //; split=> [|q nCq q_dv_p]. by rewrite -(size_map_poly FtoL) -DpI (root_size_gt1 _ pIx0) ?monic_neq0. rewrite -dvdp_size_eqp //; apply/eqP. without loss mon_q: q nCq q_dv_p / q \is monic. move=> IHq; pose a := lead_coef q; pose q1 := a^-1 *: q. have nz_a: a != 0 by rewrite lead_coef_eq0 (dvdpN0 q_dv_p) ?monic_neq0. have /IHq IHq1: q1 \is monic by rewrite monicE lead_coefZ mulVf. by rewrite -IHq1 ?size_scale ?dvdp_scalel ?invr_eq0. without loss{nCq} qx0: q mon_q q_dv_p / root (q ^ FtoL) x. have /dvdpP[q1 Dp] := q_dv_p; rewrite DpI Dp rmorphM rootM -implyNb in pIx0. have mon_q1: q1 \is monic by rewrite Dp monicMr in mon_p. move=> IH; apply: (IH) (implyP pIx0 _) => //; apply: contra nCq => /IH IHq1. rewrite -(subnn (size q1)) {1}IHq1 ?Dp ?dvdp_mulr // polySpred ?monic_neq0 //. by rewrite eqSS size_monicM ?monic_neq0 // -!subn1 subnAC addKn. have /dvdp_prod_XsubC[m Dq]: q ^ FtoL %| p_ I by rewrite DpI dvdp_map. pose B := [set j in mask m (enum I)]; have{Dq} Dq: q ^ FtoL = p_ B. apply/eqP; rewrite -eqp_monic ?monic_map ?monic_prod_XsubC //. congr (_ %= _): Dq; apply: eq_big_perm => //. by rewrite uniq_perm_eq ?mask_uniq ?enum_uniq // => j; rewrite mem_enum inE. rewrite -!(size_map_poly FtoL) Dq -DpI (minI B) // -?Dq ?FpxF //. by apply/subsetP=> j; rewrite inE => /mem_mask; rewrite mem_enum. Qed. Lemma alg_integral (F : fieldType) (L : fieldExtType F) : integralRange (in_alg L). Proof. move=> x; have [/polyOver1P[p Dp]] := (minPolyOver 1 x, monic_minPoly 1 x). by rewrite Dp map_monic; exists p; rewrite // -Dp root_minPoly. Qed. Prenex Implicits alg_integral. Lemma imaginary_exists (C : closedFieldType) : {i : C | i ^+ 2 = -1}. Proof. have /sig_eqW[i Di2] := @solve_monicpoly C 2 (nth 0 [:: -1]) isT. by exists i; rewrite Di2 big_ord_recl big_ord1 mul0r mulr1 !addr0. Qed. Import DefaultKeying GRing.DefaultPred. Implicit Arguments map_poly_inj [[F] [R] x1 x2]. Theorem Fundamental_Theorem_of_Algebraics : {L : closedFieldType & {conj : {rmorphism L -> L} | involutive conj & ~ conj =1 id}}. Proof. have maxn3 n1 n2 n3: {m | [/\ n1 <= m, n2 <= m & n3 <= m]%N}. by exists (maxn n1 (maxn n2 n3)); apply/and3P; rewrite -!geq_max. have [C [/= QtoC algC]] := countable_algebraic_closure [countFieldType of rat]. exists C; have [i Di2] := imaginary_exists C. pose Qfield := fieldExtType rat; pose Cmorph (L : Qfield) := {rmorphism L -> C}. have charQ (L : Qfield): [char L] =i pred0 := ftrans (char_lalg L) (char_num _). have sepQ (L : Qfield) (K E : {subfield L}): separable K E. by apply/separableP=> u _; apply: charf0_separable. pose genQfield z L := {LtoC : Cmorph L & {u | LtoC u = z & <<1; u>> = fullv}}. have /all_tag[Q /all_tag[ofQ genQz]] z: {Qz : Qfield & genQfield z Qz}. have [|p [/monic_neq0 nzp pz0 irr_p]] := minPoly_decidable_closure _ (algC z). exact: rat_algebraic_decidable. pose Qz := SubFieldExtType pz0 irr_p. pose QzC := subfx_inj_rmorphism QtoC z p. exists Qz, QzC, (subfx_root QtoC z p); first exact: subfx_inj_root. apply/vspaceP=> u; rewrite memvf; apply/Fadjoin1_polyP. by have [q] := subfxEroot pz0 nzp u; exists q. have pQof z p: p^@ ^ ofQ z = p ^ QtoC. by rewrite -map_poly_comp; apply: eq_map_poly => x; rewrite !fmorph_eq_rat. have pQof2 z p u: ofQ z p^@.[u] = (p ^ QtoC).[ofQ z u]. by rewrite -horner_map pQof. have PET_Qz z (E : {subfield Q z}): {u | <<1; u>> = E}. exists (separable_generator 1 E). by rewrite -eq_adjoin_separable_generator ?sub1v. pose gen z x := exists q, x = (q ^ QtoC).[z]. have PET2 x y: {z | gen z x & gen z y}. pose Gxy := (x, y) = let: (p, q, z) := _ in ((p ^ QtoC).[z], (q ^ QtoC).[z]). suffices [[[p q] z] []]: {w | Gxy w} by exists z; [exists p | exists q]. apply/sig_eqW; have /integral_algebraic[px nz_px pxx0] := algC x. have /integral_algebraic[py nz_py pyy0] := algC y. have [n [[p Dx] [q Dy]]] := char0_PET nz_px pxx0 nz_py pyy0 (char_num _). by exists (p, q, y *+ n - x); congr (_, _). have gen_inQ z x: gen z x -> {u | ofQ z u = x}. have [u Dz _] := genQz z => /sig_eqW[q ->]. by exists q^@.[u]; rewrite pQof2 Dz. have gen_ofP z u v: reflect (gen (ofQ z u) (ofQ z v)) (v \in <<1; u>>). apply: (iffP Fadjoin1_polyP) => [[q ->]|]; first by rewrite pQof2; exists q. by case=> q; rewrite -pQof2 => /fmorph_inj->; exists q. have /all_tag[sQ genP] z: {s : pred C & forall x, reflect (gen z x) (x \in s)}. apply: all_tag (fun x => reflect (gen z x)) _ => x. have [w /gen_inQ[u <-] /gen_inQ[v <-]] := PET2 z x. by exists (v \in <<1; u>>)%VS; apply: gen_ofP. have sQtrans: transitive (fun x z => x \in sQ z). move=> x y z /genP[p ->] /genP[q ->]; apply/genP; exists (p \Po q). by rewrite map_comp_poly horner_comp. have sQid z: z \in sQ z by apply/genP; exists 'X; rewrite map_polyX hornerX. have{gen_ofP} sQof2 z u v: (ofQ z u \in sQ (ofQ z v)) = (u \in <<1; v>>%VS). exact/genP/(gen_ofP z). have sQof z v: ofQ z v \in sQ z. by have [u Dz defQz] := genQz z; rewrite -[in sQ z]Dz sQof2 defQz memvf. have{gen_inQ} sQ_inQ z x z_x := gen_inQ z x (genP z x z_x). have /all_sig[inQ inQ_K] z: {inQ | {in sQ z, cancel inQ (ofQ z)}}. by apply: all_sig_cond (fun x u => ofQ z u = x) 0 _ => x /sQ_inQ. have ofQ_K z: cancel (ofQ z) (inQ z). by move=> x; have /inQ_K/fmorph_inj := sQof z x. have sQring z: divring_closed (sQ z). have sQ_1: 1 \in sQ z by rewrite -(rmorph1 (ofQ z)) sQof. by split=> // x y /inQ_K<- /inQ_K<- /=; rewrite -(rmorphB, fmorph_div) sQof. have sQopp z : oppr_closed (sQ z) := sQring z. have sQadd z : addr_closed (sQ z) := sQring z. have sQmul z : mulr_closed (sQ z) := sQring z. have sQinv z : invr_closed (sQ z) := sQring z. pose morph_ofQ x z Qxz := forall u, ofQ z (Qxz u) = ofQ x u. have QtoQ z x: x \in sQ z -> {Qxz : 'AHom(Q x, Q z) | morph_ofQ x z Qxz}. move=> z_x; pose Qxz u := inQ z (ofQ x u). have QxzE u: ofQ z (Qxz u) = ofQ x u by apply/inQ_K/(sQtrans x). suffices /rat_lrmorphism QxzM: rmorphism Qxz. by exists (linfun_ahom (LRMorphism QxzM)) => u; rewrite lfunE QxzE. split=> [u v|]; first by apply: (canLR (ofQ_K z)); rewrite !rmorphB !QxzE. by split=> [u v|]; apply: (canLR (ofQ_K z)); rewrite ?rmorph1 ?rmorphM ?QxzE. pose sQs z s := all (mem (sQ z)) s. have inQsK z s: sQs z s -> map (ofQ z) (map (inQ z) s) = s. by rewrite -map_comp => /allP/(_ _ _)/inQ_K; apply: map_id_in. have inQpK z p: p \is a polyOver (sQ z) -> (p ^ inQ z) ^ ofQ z = p. by move=> /allP/(_ _ _)/inQ_K/=/map_poly_id; rewrite -map_poly_comp. have{gen PET2 genP} PET s: {z | sQs z s & <<1 & map (inQ z) s>>%VS = fullv}. have [y /inQsK Ds]: {y | sQs y s}. elim: s => [|x s /= [y IHs]]; first by exists 0. have [z /genP z_x /genP z_y] := PET2 x y. by exists z; rewrite /= {x}z_x; apply: sub_all IHs => x /sQtrans/= ->. have [w defQs] := PET_Qz _ <<1 & map (inQ y) s>>%AS; pose z := ofQ y w. have z_s: sQs z s. rewrite -Ds /sQs all_map; apply/allP=> u s_u /=. by rewrite sQof2 defQs seqv_sub_adjoin. have [[u Dz defQz] [Qzy QzyE]] := (genQz z, QtoQ y z (sQof y w)). exists z => //; apply/eqP; rewrite eqEsubv subvf /= -defQz. rewrite -(limg_ker0 _ _ (AHom_lker0 Qzy)) aimg_adjoin_seq aimg_adjoin aimg1. rewrite -[map _ _](mapK (ofQ_K y)) -(map_comp (ofQ y)) (eq_map QzyE) inQsK //. by rewrite -defQs -(canLR (ofQ_K y) Dz) -QzyE ofQ_K. pose rp s := \prod_(z <- s) ('X - z%:P). have map_rp (f : {rmorphism _}) s: rp _ s ^ f = rp _ (map f s). rewrite rmorph_prod /rp big_map; apply: eq_bigr => x _. by rewrite rmorphB /= map_polyX map_polyC. pose is_Gal z := SplittingField.axiom (Q z). have galQ x: {z | x \in sQ z & is_Gal z}. have /sig2W[p mon_p pz0] := algC x. have [s Dp] := closed_field_poly_normal (p ^ QtoC). rewrite (monicP _) ?monic_map // scale1r in Dp; have [z z_s defQz] := PET s. exists z; first by apply/(allP z_s); rewrite -root_prod_XsubC -Dp. exists p^@; first exact: alg_polyOver. exists (map (inQ z) s); last by apply/vspaceP=> u; rewrite defQz memvf. by rewrite -(eqp_map (ofQ z)) pQof Dp map_rp inQsK ?eqpxx. pose is_realC x := {R : archiFieldType & {rmorphism Q x -> R}}. pose realC := {x : C & is_realC x}. pose has_Rroot (xR : realC) p c (Rx := sQ (tag xR)) := [&& p \is a polyOver Rx, p \is monic, c \in Rx & p.[0] == - c ^+ 2]. pose root_in (xR : realC) p := exists2 w, w \in sQ (tag xR) & root p w. pose extendsR (xR yR : realC) := tag xR \in sQ (tag yR). have add_Rroot xR p c: {yR | extendsR xR yR & has_Rroot xR p c -> root_in yR p}. rewrite {}/extendsR; case: (has_Rroot xR p c) / and4P; last by exists xR. case: xR => x [R QxR] /= [/inQpK <-]; move: (p ^ _) => {p}p mon_p /inQ_K<- Dc. have{c Dc} p0_le0: (p ^ QxR).[0] <= 0. rewrite horner_coef0 coef_map -[p`_0]ofQ_K -coef_map -horner_coef0 (eqP Dc). by rewrite -rmorphX -rmorphN ofQ_K /= rmorphN rmorphX oppr_le0 sqr_ge0. have [s Dp] := closed_field_poly_normal (p ^ ofQ x). have{Dp} /all_and2[s_p p_s] y: root (p ^ ofQ x) y <-> (y \in s). by rewrite Dp (monicP mon_p) scale1r root_prod_XsubC. rewrite map_monic in mon_p; have [z /andP[z_x /allP/=z_s] _] := PET (x :: s). have{z_x} [[Qxz QxzE] Dx] := (QtoQ z x z_x, inQ_K z x z_x). pose Qx := <<1; inQ z x>>%AS; pose QxzM := [rmorphism of Qxz]. have pQwx q1: q1 \is a polyOver Qx -> {q | q1 = q ^ Qxz}. move/polyOverP=> Qx_q1; exists ((q1 ^ ofQ z) ^ inQ x). apply: (map_poly_inj (ofQ z)); rewrite -map_poly_comp (eq_map_poly QxzE). by rewrite inQpK ?polyOver_poly // => j _; rewrite -Dx sQof2 Qx_q1. have /all_sig[t_ Dt] u: {t | <<1; t>> = <>} by apply: PET_Qz. suffices{p_s}[u Ry px0]: {u : Q z & is_realC (ofQ z (t_ u)) & ofQ z u \in s}. exists (Tagged is_realC Ry) => [|_] /=. by rewrite -Dx sQof2 Dt subvP_adjoin ?memv_adjoin. by exists (ofQ z u); rewrite ?p_s // sQof2 Dt memv_adjoin. without loss{z_s s_p} [u Dp s_y]: p mon_p p0_le0 / {u | minPoly Qx u = p ^ Qxz & ofQ z u \in s}. - move=> IHp; move: {2}_.+1 (ltnSn (size p)) => d. elim: d => // d IHd in p mon_p s_p p0_le0 *; rewrite ltnS => le_p_d. have /closed_rootP/sig_eqW[y py0]: size (p ^ ofQ x) != 1%N. rewrite size_map_poly size_poly_eq1 eqp_monic ?rpred1 //. by apply: contraTneq p0_le0 => ->; rewrite rmorph1 hornerC ltr_geF ?ltr01. have /s_p s_y := py0; have /z_s/sQ_inQ[u Dy] := s_y. have /pQwx[q Dq] := minPolyOver Qx u. have mon_q: q \is monic by have:= monic_minPoly Qx u; rewrite Dq map_monic. have /dvdpP/sig_eqW[r Dp]: q %| p. rewrite -(dvdp_map QxzM) -Dq minPoly_dvdp //. by apply: polyOver_poly => j _; rewrite -sQof2 QxzE Dx. by rewrite -(fmorph_root (ofQ z)) Dy -map_poly_comp (eq_map_poly QxzE). have mon_r: r \is monic by rewrite Dp monicMr in mon_p. have [q0_le0 | q0_gt0] := lerP ((q ^ QxR).[0]) 0. by apply: (IHp q) => //; exists u; rewrite ?Dy. have r0_le0: (r ^ QxR).[0] <= 0. by rewrite -(ler_pmul2r q0_gt0) mul0r -hornerM -rmorphM -Dp. apply: (IHd r mon_r) => // [w rw0|]. by rewrite s_p // Dp rmorphM rootM rw0. apply: leq_trans le_p_d; rewrite Dp size_Mmonic ?monic_neq0 // addnC. by rewrite -(size_map_poly QxzM q) -Dq size_minPoly !ltnS leq_addl. exists u => {s s_y}//; set y := ofQ z (t_ u); set p1 := minPoly Qx u in Dp. have /QtoQ[Qyz QyzE]: y \in sQ z := sQof z (t_ u). pose q1_ v := Fadjoin_poly Qx u (Qyz v). have{QyzE} QyzE v: Qyz v = (q1_ v).[u]. by rewrite Fadjoin_poly_eq // -Dt -sQof2 QyzE sQof. have /all_sig2[q_ coqp Dq] v: {q | v != 0 -> coprimep p q & q ^ Qxz = q1_ v}. have /pQwx[q Dq]: q1_ v \is a polyOver Qx by apply: Fadjoin_polyOver. exists q => // nz_v; rewrite -(coprimep_map QxzM) -Dp -Dq -gcdp_eqp1. have /minPoly_irr/orP[] // := dvdp_gcdl p1 (q1_ v). by rewrite gcdp_polyOver ?minPolyOver ?Fadjoin_polyOver. rewrite -/p1 {1}/eqp dvdp_gcd => /and3P[_ _ /dvdp_leq/=/implyP]. rewrite size_minPoly ltnNge size_poly (contraNneq _ nz_v) // => q1v0. by rewrite -(fmorph_eq0 [rmorphism of Qyz]) /= QyzE q1v0 horner0. pose h2 : R := 2%:R^-1; have nz2: 2%:R != 0 :> R by rewrite pnatr_eq0. pose itv ab := [pred c : R | ab.1 <= c <= ab.2]. pose wid ab : R := ab.2 - ab.1; pose mid ab := (ab.1 + ab.2) * h2. pose sub_itv ab cd := cd.1 <= ab.1 :> R /\ ab.2 <= cd.2 :> R. pose xup q ab := [/\ q.[ab.1] <= 0, q.[ab.2] >= 0 & ab.1 <= ab.2 :> R]. pose narrow q ab (c := mid ab) := if q.[c] >= 0 then (ab.1, c) else (c, ab.2). pose find k q := iter k (narrow q). have findP k q ab (cd := find k q ab): xup q ab -> [/\ xup q cd, sub_itv cd ab & wid cd = wid ab / (2 ^ k)%:R]. - rewrite {}/cd; case: ab => a b xq_ab. elim: k => /= [|k]; first by rewrite divr1. case: (find k q _) => c d [[/= qc_le0 qd_ge0 le_cd] [/= le_ac le_db] Dcd]. have [/= le_ce le_ed] := midf_le le_cd; set e := _ / _ in le_ce le_ed. rewrite expnSr natrM invfM mulrA -{}Dcd /narrow /= -[mid _]/e. have [qe_ge0 // | /ltrW qe_le0] := lerP 0 q.[e]. do ?split=> //=; [exact: (ler_trans le_ed) | apply: canRL (mulfK nz2) _]. by rewrite mulrBl divfK // mulr_natr opprD addrACA subrr add0r. do ?split=> //=; [exact: (ler_trans le_ac) | apply: canRL (mulfK nz2) _]. by rewrite mulrBl divfK // mulr_natr opprD addrACA subrr addr0. have find_root r q ab: xup q ab -> {n | forall x, x \in itv (find n q ab) ->`|(r * q).[x]| < h2}. - move=> xab; have ub_ab := poly_itv_bound _ ab.1 ab.2. have [Mu MuP] := ub_ab r; have /all_sig[Mq MqP] j := ub_ab q^`N(j). pose d := wid ab; pose dq := \poly_(i < (size q).-1) Mq i.+1. have d_ge0: 0 <= d by rewrite subr_ge0; case: xab. have [Mdq MdqP] := poly_disk_bound dq d. pose n := Num.bound (Mu * Mdq * d); exists n => c /= /andP[]. have{xab} [[]] := findP n _ _ xab; case: (find n q ab) => a1 b1 /=. rewrite -/d => qa1_le0 qb1_ge0 le_ab1 [/= le_aa1 le_b1b] Dab1 le_a1c le_cb1. have /MuP lbMu: c \in itv ab. by rewrite !inE (ler_trans le_aa1) ?(ler_trans le_cb1). have Mu_ge0: 0 <= Mu by rewrite (ler_trans _ lbMu) ?normr_ge0. have Mdq_ge0: 0 <= Mdq. by rewrite (ler_trans _ (MdqP 0 _)) ?normr_ge0 ?normr0. suffices lb1 a2 b2 (ab1 := (a1, b1)) (ab2 := (a2, b2)) : xup q ab2 /\ sub_itv ab2 ab1 -> q.[b2] - q.[a2] <= Mdq * wid ab1. + apply: ler_lt_trans (_ : Mu * Mdq * wid (a1, b1) < h2); last first. rewrite {}Dab1 mulrA ltr_pdivr_mulr ?ltr0n ?expn_gt0 //. rewrite (ltr_le_trans (archi_boundP _)) ?mulr_ge0 ?ltr_nat // -/n. rewrite ler_pdivl_mull ?ltr0n // -natrM ler_nat. by case: n => // n; rewrite expnS leq_pmul2l // ltn_expl. rewrite -mulrA hornerM normrM ler_pmul ?normr_ge0 //. have [/ltrW qc_le0 | qc_ge0] := ltrP q.[c] 0. by apply: ler_trans (lb1 c b1 _); rewrite ?ler0_norm ?ler_paddl. by apply: ler_trans (lb1 a1 c _); rewrite ?ger0_norm ?ler_paddr ?oppr_ge0. case{c le_a1c le_cb1 lbMu}=> [[/=qa2_le0 qb2_ge0 le_ab2] [/=le_a12 le_b21]]. pose h := b2 - a2; have h_ge0: 0 <= h by rewrite subr_ge0. have [-> | nz_q] := eqVneq q 0. by rewrite !horner0 subrr mulr_ge0 ?subr_ge0. rewrite -(subrK a2 b2) (addrC h) (nderiv_taylor q (mulrC a2 h)). rewrite (polySpred nz_q) big_ord_recl /= mulr1 nderivn0 addrC addKr. have [le_aa2 le_b2b] := (ler_trans le_aa1 le_a12, ler_trans le_b21 le_b1b). have /MqP MqPx1: a2 \in itv ab by rewrite inE le_aa2 (ler_trans le_ab2). apply: ler_trans (ler_trans (ler_norm _) (ler_norm_sum _ _ _)) _. apply: ler_trans (_ : `|dq.[h] * h| <= _); last first. by rewrite normrM ler_pmul ?normr_ge0 ?MdqP // ?ger0_norm ?ler_sub ?h_ge0. rewrite horner_poly ger0_norm ?mulr_ge0 ?sumr_ge0 // => [|j _]; last first. by rewrite mulr_ge0 ?exprn_ge0 // (ler_trans _ (MqPx1 _)) ?normr_ge0. rewrite mulr_suml ler_sum // => j _; rewrite normrM -mulrA -exprSr. by rewrite ler_pmul ?normr_ge0 // normrX ger0_norm. have [ab0 xab0]: {ab | xup (p ^ QxR) ab}. have /monic_Cauchy_bound[b pb_gt0]: p ^ QxR \is monic by apply: monic_map. by exists (0, `|b|); rewrite /xup normr_ge0 p0_le0 ltrW ?pb_gt0 ?ler_norm. pose ab_ n := find n (p ^ QxR) ab0; pose Iab_ n := itv (ab_ n). pose lim v a := (q_ v ^ QxR).[a]; pose nlim v n := lim v (ab_ n).2. have lim0 a: lim 0 a = 0. rewrite /lim; suffices /eqP ->: q_ 0 == 0 by rewrite rmorph0 horner0. by rewrite -(map_poly_eq0 QxzM) Dq /q1_ !raddf0. have limN v a: lim (- v) a = - lim v a. rewrite /lim; suffices ->: q_ (- v) = - q_ v by rewrite rmorphN hornerN. by apply: (map_poly_inj QxzM); rewrite Dq /q1_ !raddfN /= Dq. pose lim_nz n v := exists2 e, e > 0 & {in Iab_ n, forall a, e < `|lim v a| }. have /(all_sig_cond 0%N)[n_ nzP] v: v != 0 -> {n | lim_nz n v}. move=> nz_v; do [move/(_ v nz_v); rewrite -(coprimep_map QxR)] in coqp. have /sig_eqW[r r_pq_1] := Bezout_eq1_coprimepP _ _ coqp. have /(find_root r.1)[n ub_rp] := xab0; exists n. have [M Mgt0 ubM]: {M | 0 < M & {in Iab_ n, forall a, `|r.2.[a]| <= M}}. have [M ubM] := poly_itv_bound r.2 (ab_ n).1 (ab_ n).2. exists (Num.max 1 M) => [|s /ubM vM]; first by rewrite ltr_maxr ltr01. by rewrite ler_maxr orbC vM. exists (h2 / M) => [|a xn_a]; first by rewrite divr_gt0 ?invr_gt0 ?ltr0n. rewrite ltr_pdivr_mulr // -(ltr_add2l h2) -mulr2n -mulr_natl divff //. rewrite -normr1 -(hornerC 1 a) -[1%:P]r_pq_1 hornerD. rewrite ?(ler_lt_trans (ler_norm_add _ _)) ?ltr_le_add ?ub_rp //. by rewrite mulrC hornerM normrM ler_wpmul2l ?ubM. have ab_le m n: (m <= n)%N -> (ab_ n).2 \in Iab_ m. move/subnKC=> <-; move: {n}(n - m)%N => n; rewrite /ab_. have /(findP m)[/(findP n)[[_ _]]] := xab0. rewrite /find -iter_add -!/(find _ _) -!/(ab_ _) addnC !inE. by move: (ab_ _) => /= ab_mn le_ab_mn [/ler_trans->]. pose lt v w := 0 < nlim (w - v) (n_ (w - v)). have posN v: lt 0 (- v) = lt v 0 by rewrite /lt subr0 add0r. have posB v w: lt 0 (w - v) = lt v w by rewrite /lt subr0. have posE n v: (n_ v <= n)%N -> lt 0 v = (0 < nlim v n). rewrite /lt subr0 /nlim => /ab_le; set a := _.2; set b := _.2 => Iv_a. have [-> | /nzP[e e_gt0]] := eqVneq v 0; first by rewrite !lim0 ltrr. move: (n_ v) => m in Iv_a b * => v_gte. without loss lt0v: v v_gte / 0 < lim v b. move=> IHv; apply/idP/idP => [v_gt0 | /ltrW]; first by rewrite -IHv. rewrite ltr_def -normr_gt0 ?(ltr_trans _ (v_gte _ _)) ?ab_le //=. rewrite !lerNgt -!oppr_gt0 -!limN; apply: contra => v_lt0. by rewrite -IHv // => c /v_gte; rewrite limN normrN. rewrite lt0v (ltr_trans e_gt0) ?(ltr_le_trans (v_gte a Iv_a)) //. rewrite ger0_norm // lerNgt; apply/negP=> /ltrW lev0. have [le_a le_ab] : _ /\ a <= b := andP Iv_a. have xab: xup (q_ v ^ QxR) (a, b) by move/ltrW in lt0v. have /(find_root (h2 / e)%:P)[n1] := xab; have /(findP n1)[[_ _]] := xab. case: (find _ _ _) => c d /= le_cd [/= le_ac le_db] _ /(_ c)/implyP. rewrite inE lerr le_cd hornerM hornerC normrM ler_gtF //. rewrite ger0_norm ?divr_ge0 ?invr_ge0 ?ler0n ?(ltrW e_gt0) // mulrAC. rewrite ler_pdivl_mulr // ler_wpmul2l ?invr_ge0 ?ler0n // ltrW // v_gte //=. by rewrite inE -/b (ler_trans le_a) //= (ler_trans le_cd). pose lim_pos m v := exists2 e, e > 0 & forall n, (m <= n)%N -> e < nlim v n. have posP v: reflect (exists m, lim_pos m v) (lt 0 v). apply: (iffP idP) => [v_gt0|[m [e e_gt0 v_gte]]]; last first. by rewrite (posE _ _ (leq_maxl _ m)) (ltr_trans e_gt0) ?v_gte ?leq_maxr. have [|e e_gt0 v_gte] := nzP v. by apply: contraTneq v_gt0 => ->; rewrite /lt subr0 /nlim lim0 ltrr. exists (n_ v), e => // n le_vn; rewrite (posE n) // in v_gt0. by rewrite -(ger0_norm (ltrW v_gt0)) v_gte ?ab_le. have posNneg v: lt 0 v -> ~~ lt v 0. case/posP=> m [d d_gt0 v_gtd]; rewrite -posN. apply: contraL d_gt0 => /posP[n [e e_gt0 nv_gte]]. rewrite ltr_gtF // (ltr_trans (v_gtd _ (leq_maxl m n))) // -oppr_gt0. by rewrite /nlim -limN (ltr_trans e_gt0) ?nv_gte ?leq_maxr. have posVneg v: v != 0 -> lt 0 v || lt v 0. case/nzP=> e e_gt0 v_gte; rewrite -posN; set w := - v. have [m [le_vm le_wm _]] := maxn3 (n_ v) (n_ w) 0%N; rewrite !(posE m) //. by rewrite /nlim limN -ltr_normr (ltr_trans e_gt0) ?v_gte ?ab_le. have posD v w: lt 0 v -> lt 0 w -> lt 0 (v + w). move=> /posP[m [d d_gt0 v_gtd]] /posP[n [e e_gt0 w_gte]]. apply/posP; exists (maxn m n), (d + e) => [|k]; first exact: addr_gt0. rewrite geq_max => /andP[le_mk le_nk]; rewrite /nlim /lim. have ->: q_ (v + w) = q_ v + q_ w. by apply: (map_poly_inj QxzM); rewrite rmorphD /= !{1}Dq /q1_ !raddfD. by rewrite rmorphD hornerD ltr_add ?v_gtd ?w_gte. have posM v w: lt 0 v -> lt 0 w -> lt 0 (v * w). move=> /posP[m [d d_gt0 v_gtd]] /posP[n [e e_gt0 w_gte]]. have /dvdpP[r /(canRL (subrK _))Dqvw]: p %| q_ (v * w) - q_ v * q_ w. rewrite -(dvdp_map QxzM) rmorphB rmorphM /= !Dq -Dp minPoly_dvdp //. by rewrite rpredB 1?rpredM ?Fadjoin_polyOver. by rewrite rootE !hornerE -!QyzE rmorphM subrr. have /(find_root ((d * e)^-1 *: r ^ QxR))[N ub_rp] := xab0. pose f := d * e * h2; apply/posP; exists (maxn N (maxn m n)), f => [|k]. by rewrite !mulr_gt0 ?invr_gt0 ?ltr0n. rewrite !geq_max => /and3P[/ab_le/ub_rp{ub_rp}ub_rp le_mk le_nk]. rewrite -(ltr_add2r f) -mulr2n -mulr_natr divfK // /nlim /lim Dqvw. rewrite rmorphD hornerD /= -addrA -ltr_subl_addl ler_lt_add //. by rewrite rmorphM hornerM ler_pmul ?ltrW ?v_gtd ?w_gte. rewrite -ltr_pdivr_mull ?mulr_gt0 // (ler_lt_trans _ ub_rp) //. by rewrite -scalerAl hornerZ -rmorphM mulrN -normrN ler_norm. pose le v w := (w == v) || lt v w. pose abs v := if le 0 v then v else - v. have absN v: abs (- v) = abs v. rewrite /abs /le oppr_eq0 opprK posN. have [-> | /posVneg/orP[v_gt0 | v_lt0]] := altP eqP; first by rewrite oppr0. by rewrite v_gt0 /= -if_neg posNneg. by rewrite v_lt0 /= -if_neg -(opprK v) posN posNneg ?posN. have absE v: le 0 v -> abs v = v by rewrite /abs => ->. pose QyNum := RealLtMixin posD posM posNneg posB posVneg absN absE (rrefl _). pose QyNumField := [numFieldType of NumDomainType (Q y) QyNum]. pose Ry := [realFieldType of RealDomainType _ (RealLeAxiom QyNumField)]. have archiRy := @rat_algebraic_archimedean Ry _ alg_integral. by exists (ArchiFieldType Ry archiRy); apply: [rmorphism of idfun]. have some_realC: realC. suffices /all_sig[f QfK] x: {a | in_alg (Q 0) a = x}. exists 0, [archiFieldType of rat], f. exact: can2_rmorphism (inj_can_sym QfK (fmorph_inj _)) QfK. have /Fadjoin1_polyP/sig_eqW[q]: x \in <<1; 0>>%VS by rewrite -sQof2 rmorph0. by exists q.[0]; rewrite -horner_map rmorph0. pose fix xR n : realC := if n isn't n'.+1 then some_realC else if unpickle (nth 0%N (CodeSeq.decode n') 1) isn't Some (p, c) then xR n' else tag (add_Rroot (xR n') p c). pose x_ n := tag (xR n). have sRle m n: (m <= n)%N -> {subset sQ (x_ m) <= sQ (x_ n)}. move/subnK <-; elim: {n}(n - m)%N => // n IHn x /IHn{IHn}Rx. rewrite addSn /x_ /=; case: (unpickle _) => [[p c]|] //=. by case: (add_Rroot _ _ _) => yR /= /(sQtrans _ x)->. have xRroot n p c: has_Rroot (xR n) p c -> {m | n <= m & root_in (xR m) p}%N. case/and4P=> Rp mon_p Rc Dc; pose m := CodeSeq.code [:: n; pickle (p, c)]. have le_n_m: (n <= m)%N by apply/ltnW/(allP (CodeSeq.ltn_code _))/mem_head. exists m.+1; rewrite ?leqW /x_ //= CodeSeq.codeK pickleK. case: (add_Rroot _ _ _) => yR /= _; apply; apply/and4P. by split=> //; first apply: polyOverS Rp; apply: (sRle n). have /all_sig[z_ /all_and3[Ri_R Ri_i defRi]] n (x := x_ n): {z | [/\ x \in sQ z, i \in sQ z & <<<<1; inQ z x>>; inQ z i>> = fullv]}. - have [z /and3P[z_x z_i _] Dzi] := PET [:: x; i]. by exists z; rewrite -adjoin_seq1 -adjoin_cons. pose i_ n := inQ (z_ n) i; pose R_ n := <<1; inQ (z_ n) (x_ n)>>%AS. have memRi n: <> =i predT by move=> u; rewrite defRi memvf. have sCle m n: (m <= n)%N -> {subset sQ (z_ m) <= sQ (z_ n)}. move/sRle=> Rmn _ /sQ_inQ[u <-]. have /Fadjoin_polyP[p /polyOverP Rp ->] := memRi m u. rewrite -horner_map inQ_K ?rpred_horner //=; apply/polyOver_poly=> j _. by apply: sQtrans (Ri_R n); rewrite Rmn // -(inQ_K _ _ (Ri_R m)) sQof2. have R'i n: i \notin sQ (x_ n). rewrite /x_; case: (xR n) => x [Rn QxR] /=. apply: contraL (@ltr01 Rn) => /sQ_inQ[v Di]. suffices /eqP <-: - QxR v ^+ 2 == 1 by rewrite oppr_gt0 -lerNgt sqr_ge0. rewrite -rmorphX -rmorphN fmorph_eq1 -(fmorph_eq1 (ofQ x)) rmorphN eqr_oppLR. by rewrite rmorphX Di Di2. have szX2_1: size ('X^2 + 1) = 3. by move=> R; rewrite size_addl ?size_polyXn ?size_poly1. have minp_i n (p_i := minPoly (R_ n) (i_ n)): p_i = 'X^2 + 1. have p_dv_X2_1: p_i %| 'X^2 + 1. rewrite minPoly_dvdp ?rpredD ?rpredX ?rpred1 ?polyOverX //. rewrite -(fmorph_root (ofQ _)) inQ_K // rmorphD rmorph1 /= map_polyXn. by rewrite rootE hornerD hornerXn hornerC Di2 addNr. apply/eqP; rewrite -eqp_monic ?monic_minPoly //; last first. by rewrite monicE lead_coefE szX2_1 coefD coefXn coefC addr0. rewrite -dvdp_size_eqp // eqn_leq dvdp_leq -?size_poly_eq0 ?szX2_1 //= ltnNge. by rewrite size_minPoly ltnS leq_eqVlt orbF adjoin_deg_eq1 -sQof2 !inQ_K. have /all_sig[n_ FTA] z: {n | z \in sQ (z_ n)}. without loss [z_i gal_z]: z / i \in sQ z /\ is_Gal z. have [y /and3P[/sQtrans y_z /sQtrans y_i _] _] := PET [:: z; i]. have [t /sQtrans t_y gal_t] := galQ y. by case/(_ t)=> [|n]; last exists n; rewrite ?y_z ?y_i ?t_y. apply/sig_eqW; have n := 0%N. have [p]: exists p, [&& p \is monic, root p z & p \is a polyOver (sQ (z_ n))]. have [p mon_p pz0] := algC z; exists (p ^ QtoC). by rewrite map_monic mon_p pz0 -(pQof (z_ n)); apply/polyOver_poly. elim: {p}_.+1 {-2}p n (ltnSn (size p)) => // d IHd p n lepd pz0. have [t [t_C t_z gal_t]]: exists t, [/\ z_ n \in sQ t, z \in sQ t & is_Gal t]. have [y /and3P[y_C y_z _]] := PET [:: z_ n; z]. by have [t /(sQtrans y)t_y] := galQ y; exists t; rewrite !t_y. pose Qt := SplittingFieldType rat (Q t) gal_t; have /QtoQ[CnQt CnQtE] := t_C. pose Rn : {subfield Qt} := (CnQt @: R_ n)%AS; pose i_t : Qt := CnQt (i_ n). pose Cn : {subfield Qt} := <>%AS. have defCn: Cn = limg CnQt :> {vspace Q t} by rewrite /= -aimg_adjoin defRi. have memRn u: (u \in Rn) = (ofQ t u \in sQ (x_ n)). by rewrite /= aimg_adjoin aimg1 -sQof2 CnQtE inQ_K. have memCn u: (u \in Cn) = (ofQ t u \in sQ (z_ n)). have [v Dv genCn] := genQz (z_ n). by rewrite -Dv -CnQtE sQof2 defCn -genCn aimg_adjoin aimg1. have Dit: ofQ t i_t = i by rewrite CnQtE inQ_K. have Dit2: i_t ^+ 2 = -1. by apply: (fmorph_inj (ofQ t)); rewrite rmorphX rmorphN1 Dit. have dimCn: \dim_Rn Cn = 2. rewrite -adjoin_degreeE adjoin_degree_aimg. by apply: succn_inj; rewrite -size_minPoly minp_i. have /sQ_inQ[u_z Dz] := t_z; pose Rz := <>%AS. have{p lepd pz0} le_Rz_d: (\dim_Cn Rz < d)%N. rewrite -ltnS -adjoin_degreeE -size_minPoly (leq_trans _ lepd) // !ltnS. have{pz0} [mon_p pz0 Cp] := and3P pz0. have{Cp} Dp: ((p ^ inQ (z_ n)) ^ CnQt) ^ ofQ t = p. by rewrite -map_poly_comp (eq_map_poly CnQtE) inQpK. rewrite -Dp size_map_poly dvdp_leq ?monic_neq0 -?(map_monic (ofQ _)) ?Dp //. rewrite defCn minPoly_dvdp //; try by rewrite -(fmorph_root (ofQ t)) Dz Dp. by apply/polyOver_poly=> j _; rewrite memv_img ?memvf. have [sRCn sCnRz]: (Rn <= Cn)%VS /\ (Cn <= Rz)%VS by rewrite !subv_adjoin. have sRnRz := subv_trans sRCn sCnRz. have{gal_z} galRz: galois Rn Rz. apply/and3P; split=> //; apply/splitting_normalField=> //. pose u : SplittingFieldType rat (Q z) gal_z := inQ z z. have /QtoQ[Qzt QztE] := t_z; exists (minPoly 1 u ^ Qzt). have /polyOver1P[q ->] := minPolyOver 1 u; apply/polyOver_poly=> j _. by rewrite coef_map linearZZ rmorph1 rpredZ ?rpred1. have [s /eqP Ds] := splitting_field_normal 1 u. rewrite Ds; exists (map Qzt s); first by rewrite map_rp eqpxx. apply/eqP; rewrite eqEsubv; apply/andP; split. apply/Fadjoin_seqP; split=> // _ /mapP[w s_w ->]. by rewrite (subvP (adjoinSl u_z (sub1v _))) // -sQof2 Dz QztE. rewrite /= adjoinC (Fadjoin_idP _) -/Rz; last first. by rewrite (subvP (adjoinSl _ (sub1v _))) // -sQof2 Dz Dit. rewrite /= -adjoin_seq1 adjoin_seqSr //; apply/allP=> /=; rewrite andbT. rewrite -(mem_map (fmorph_inj (ofQ _))) -map_comp (eq_map QztE); apply/mapP. by exists u; rewrite ?inQ_K // -root_prod_XsubC -Ds root_minPoly. have galCz: galois Cn Rz by rewrite (galoisS _ galRz) ?sRCn. have [Cz | C'z]:= boolP (u_z \in Cn); first by exists n; rewrite -Dz -memCn. pose G := 'Gal(Rz / Cn)%G; have{C'z} ntG: G :!=: 1%g. rewrite trivg_card1 -galois_dim 1?(galoisS _ galCz) ?subvv //=. by rewrite -adjoin_degreeE adjoin_deg_eq1. pose extRz m := exists2 w, ofQ t w \in sQ (z_ m) & w \in [predD Rz & Cn]. suffices [m le_n_m [w Cw /andP[C'w Rz_w]]]: exists2 m, (n <= m)%N & extRz m. pose p := minPoly <> u_z; apply: (IHd (p ^ ofQ t) m). apply: leq_trans le_Rz_d; rewrite size_map_poly size_minPoly ltnS. rewrite adjoin_degreeE adjoinC (addv_idPl Rz_w) agenv_id. rewrite ltn_divLR ?adim_gt0 // mulnC. rewrite muln_divCA ?field_dimS ?subv_adjoin // ltn_Pmulr ?adim_gt0 //. by rewrite -adjoin_degreeE ltnNge leq_eqVlt orbF adjoin_deg_eq1. rewrite map_monic monic_minPoly -Dz fmorph_root root_minPoly /=. have /polyOverP Cw_p: p \is a polyOver <>%VS by apply: minPolyOver. apply/polyOver_poly=> j _; have /Fadjoin_polyP[q Cq {j}->] := Cw_p j. rewrite -horner_map rpred_horner //; apply/polyOver_poly=> j _. by rewrite (sCle n) // -memCn (polyOverP Cq). have [evenG | oddG] := boolP (2.-group G); last first. have [P /and3P[sPG evenP oddPG]] := Sylow_exists 2 'Gal(Rz / Rn). have [w defQw] := PET_Qz t [aspace of fixedField P]. pose pw := minPoly Rn w; pose p := (- pw * (pw \Po - 'X)) ^ ofQ t. have sz_pw: (size pw).-1 = #|'Gal(Rz / Rn) : P|. rewrite size_minPoly adjoin_degreeE -dim_fixed_galois //= -defQw. congr (\dim_Rn _); apply/esym/eqP; rewrite eqEsubv adjoinSl ?sub1v //=. by apply/FadjoinP; rewrite memv_adjoin /= defQw -galois_connection. have mon_p: p \is monic. have mon_pw: pw \is monic := monic_minPoly _ _. rewrite map_monic mulNr -mulrN monicMl // monicE. rewrite !(lead_coef_opp, lead_coef_comp) ?size_opp ?size_polyX //. by rewrite lead_coefX sz_pw -signr_odd odd_2'nat oddPG mulrN1 opprK. have Dp0: p.[0] = - ofQ t pw.[0] ^+ 2. rewrite -(rmorph0 (ofQ t)) horner_map hornerM rmorphM. by rewrite horner_comp !hornerN hornerX oppr0 rmorphN mulNr. have Rpw: pw \is a polyOver Rn by apply: minPolyOver. have Rp: p \is a polyOver (sQ (x_ n)). apply/polyOver_poly=> j _; rewrite -memRn; apply: polyOverP j => /=. by rewrite rpredM 1?polyOver_comp ?rpredN ?polyOverX. have Rp0: ofQ t pw.[0] \in sQ (x_ n) by rewrite -memRn rpred_horner ?rpred0. have [|{mon_p Rp Rp0 Dp0}m lenm p_Rm_0] := xRroot n p (ofQ t pw.[0]). by rewrite /has_Rroot mon_p Rp Rp0 -Dp0 /=. have{p_Rm_0} [y Ry pw_y]: {y | y \in sQ (x_ m) & root (pw ^ ofQ t) y}. apply/sig2W; have [y Ry] := p_Rm_0. rewrite [p]rmorphM /= map_comp_poly !rmorphN /= map_polyX. rewrite rootM rootN root_comp hornerN hornerX. by case/orP; [exists y | exists (- y)]; rewrite ?rpredN. have [u Rz_u Dy]: exists2 u, u \in Rz & y = ofQ t u. have Rz_w: w \in Rz by rewrite -sub_adjoin1v defQw capvSl. have [sg [Gsg _ Dpw]] := galois_factors sRnRz galRz w Rz_w. set s := map _ sg in Dpw. have /mapP[u /mapP[g Gg Du] ->]: y \in map (ofQ t) s. by rewrite -root_prod_XsubC -/(rp C _) -map_rp -[rp _ _]Dpw. by exists u; rewrite // Du memv_gal. have{pw_y} pw_u: root pw u by rewrite -(fmorph_root (ofQ t)) -Dy. exists m => //; exists u; first by rewrite -Dy; apply: sQtrans Ry _. rewrite inE /= Rz_u andbT; apply: contra oddG => Cu. suffices: 2.-group 'Gal(Rz / Rn). apply: pnat_dvd; rewrite -!galois_dim // ?(galoisS _ galQr) ?sRCz //. rewrite dvdn_divLR ?field_dimS ?adim_gt0 //. by rewrite mulnC muln_divCA ?field_dimS ?dvdn_mulr. congr (2.-group _): evenP; apply/eqP. rewrite eqEsubset sPG -indexg_eq1 (pnat_1 _ oddPG) // -sz_pw. have (pu := minPoly Rn u): (pu %= pw) || (pu %= 1). by rewrite minPoly_irr ?minPoly_dvdp ?minPolyOver. rewrite /= -size_poly_eq1 {1}size_minPoly orbF => /eqp_size <-. rewrite size_minPoly /= adjoin_degreeE (@pnat_dvd _ 2) // -dimCn. rewrite dvdn_divLR ?divnK ?adim_gt0 ?field_dimS ?subv_adjoin //. exact/FadjoinP. have [w Rz_w deg_w]: exists2 w, w \in Rz & adjoin_degree Cn w = 2. have [P sPG iPG]: exists2 P : {group gal_of Rz}, P \subset G & #|G : P| = 2. have [_ _ [k oG]] := pgroup_pdiv evenG ntG. have [P [sPG _ oP]] := normal_pgroup evenG (normal_refl G) (leq_pred _). by exists P => //; rewrite -divgS // oP oG pfactorK // -expnB ?subSnn. have [w defQw] := PET_Qz _ [aspace of fixedField P]. exists w; first by rewrite -sub_adjoin1v defQw capvSl. rewrite adjoin_degreeE -iPG -dim_fixed_galois // -defQw; congr (\dim_Cn _). apply/esym/eqP; rewrite eqEsubv adjoinSl ?sub1v //=; apply/FadjoinP. by rewrite memv_adjoin /= defQw -galois_connection. have nz2: 2%:R != 0 :> Qt by move/charf0P: (charQ (Q t)) => ->. without loss{deg_w} [C'w Cw2]: w Rz_w / w \notin Cn /\ w ^+ 2 \in Cn. pose p := minPoly Cn w; pose v := p`_1 / 2%:R. have /polyOverP Cp: p \is a polyOver Cn := minPolyOver Cn w. have Cv: v \in Cn by rewrite rpred_div ?rpred_nat ?Cp. move/(_ (v + w)); apply; first by rewrite rpredD // subvP_adjoin. split; first by rewrite rpredDl // -adjoin_deg_eq1 deg_w. rewrite addrC -[_ ^+ 2]subr0 -(rootP (root_minPoly Cn w)) -/p. rewrite sqrrD [_ - _]addrAC rpredD ?rpredX // -mulr_natr -mulrA divfK //. rewrite [w ^+ 2 + _]addrC mulrC -rpredN opprB horner_coef. have /monicP := monic_minPoly Cn w; rewrite lead_coefE size_minPoly deg_w. by rewrite 2!big_ord_recl big_ord1 => ->; rewrite mulr1 mul1r addrK Cp. without loss R'w2: w Rz_w C'w Cw2 / w ^+ 2 \notin Rn. move=> IHw; have [Rw2 | /IHw] := boolP (w ^+ 2 \in Rn); last exact. have R'it: i_t \notin Rn by rewrite memRn Dit. pose v := 1 + i_t; have R'v: v \notin Rn by rewrite rpredDl ?rpred1. have Cv: v \in Cn by rewrite rpredD ?rpred1 ?memv_adjoin. have nz_v: v != 0 by rewrite (memPnC R'v) ?rpred0. apply: (IHw (v * w)); last 1 [|] || by rewrite fpredMl // subvP_adjoin. by rewrite exprMn rpredM // rpredX. rewrite exprMn fpredMr //=; last by rewrite expf_eq0 (memPnC C'w) ?rpred0. by rewrite sqrrD Dit2 expr1n addrC addKr -mulrnAl fpredMl ?rpred_nat. pose rect_w2 u v := [/\ u \in Rn, v \in Rn & u + i_t * (v * 2%:R) = w ^+ 2]. have{Cw2} [u [v [Ru Rv Dw2]]]: {u : Qt & {v | rect_w2 u v}}. rewrite /rect_w2 -(Fadjoin_poly_eq Cw2); set p := Fadjoin_poly Rn i_t _. have /polyOverP Rp: p \is a polyOver Rn by apply: Fadjoin_polyOver. exists p`_0, (p`_1 / 2%:R); split; rewrite ?rpred_div ?rpred_nat //. rewrite divfK // (horner_coef_wide _ (size_Fadjoin_poly _ _ _)) -/p. by rewrite adjoin_degreeE dimCn big_ord_recl big_ord1 mulr1 mulrC. pose p := Poly [:: - (ofQ t v ^+ 2); 0; - ofQ t u; 0; 1]. have [|m lenm [x Rx px0]] := xRroot n p (ofQ t v). rewrite /has_Rroot 2!unfold_in lead_coefE horner_coef0 -memRn Rv. rewrite (@PolyK _ 1) ?oner_eq0 //= !eqxx !rpred0 ?rpred1 ?rpredN //=. by rewrite !andbT rpredX -memRn. suffices [y Cy Dy2]: {y | y \in sQ (z_ m) & ofQ t w ^+ 2 == y ^+ 2}. exists m => //; exists w; last by rewrite inE C'w. by move: Dy2; rewrite eqf_sqr => /pred2P[]->; rewrite ?rpredN. exists (x + i * (ofQ t v / x)). rewrite rpredD 1?rpredM ?rpred_div //= (sQtrans (x_ m)) //. by rewrite (sRle n) // -memRn. rewrite rootE /horner (@PolyK _ 1) ?oner_eq0 //= ?addr0 ?mul0r in px0. rewrite add0r mul1r -mulrA -expr2 subr_eq0 in px0. have nz_x2: x ^+ 2 != 0. apply: contraNneq R'w2 => y2_0; rewrite -Dw2 mulrCA. suffices /eqP->: v == 0 by rewrite mul0r addr0. by rewrite y2_0 mulr0 eq_sym sqrf_eq0 fmorph_eq0 in px0. apply/eqP/esym/(mulIf nz_x2); rewrite -exprMn -rmorphX -Dw2 rmorphD rmorphM. rewrite Dit mulrDl -expr2 mulrA divfK; last by rewrite expf_eq0 in nz_x2. rewrite mulr_natr addrC sqrrD exprMn Di2 mulN1r -(eqP px0) -mulNr opprB. by rewrite -mulrnAl -mulrnAr -rmorphMn -!mulrDl addrAC subrK. have inFTA n z: (n_ z <= n)%N -> z = ofQ (z_ n) (inQ (z_ n) z). by move/sCle=> le_zn; rewrite inQ_K ?le_zn. pose is_cj n cj := {in R_ n, cj =1 id} /\ cj (i_ n) = - i_ n. have /all_sig[cj_ /all_and2[cj_R cj_i]] n: {cj : 'AEnd(Q (z_ n)) | is_cj n cj}. have cj_P: root (minPoly (R_ n) (i_ n) ^ \1%VF) (- i_ n). rewrite minp_i -(fmorph_root (ofQ _)) !rmorphD !rmorph1 /= !map_polyXn. by rewrite rmorphN inQ_K // rootE hornerD hornerXn hornerC sqrrN Di2 addNr. have cj_M: ahom_in fullv (kHomExtend (R_ n) \1 (i_ n) (- i_ n)). by rewrite -defRi -k1HomE kHomExtendP ?sub1v ?kHom1. exists (AHom cj_M); split=> [y /kHomExtend_id->|]; first by rewrite ?id_lfunE. by rewrite (kHomExtend_val (kHom1 1 _)). pose conj_ n z := ofQ _ (cj_ n (inQ _ z)); pose conj z := conj_ (n_ z) z. have conjK n m z: (n_ z <= n)%N -> (n <= m)%N -> conj_ m (conj_ n z) = z. move/sCle=> le_z_n le_n_m; have /le_z_n/sQ_inQ[u <-] := FTA z. have /QtoQ[Qmn QmnE]: z_ n \in sQ (z_ m) by rewrite (sCle n). rewrite /conj_ ofQ_K -!QmnE !ofQ_K -!comp_lfunE; congr (ofQ _ _). move: u (memRi n u); apply/eqlfun_inP/FadjoinP; split=> /=. apply/eqlfun_inP=> y Ry; rewrite !comp_lfunE !cj_R //. by move: Ry; rewrite -!sQof2 QmnE !inQ_K //; apply: sRle. apply/eqlfunP; rewrite !comp_lfunE cj_i !linearN /=. suffices ->: Qmn (i_ n) = i_ m by rewrite cj_i ?opprK. by apply: (fmorph_inj (ofQ _)); rewrite QmnE !inQ_K. have conjE n z: (n_ z <= n)%N -> conj z = conj_ n z. move/leq_trans=> le_zn; set x := conj z; set y := conj_ n z. have [m [le_xm le_ym le_nm]] := maxn3 (n_ x) (n_ y) n. by have /conjK/=/can_in_inj := leqnn m; apply; rewrite ?conjK // le_zn. suffices conjM: rmorphism conj. exists (RMorphism conjM) => [z | /(_ i)/eqP/idPn[]] /=. by have [n [/conjE-> /(conjK (n_ z))->]] := maxn3 (n_ (conj z)) (n_ z) 0%N. rewrite /conj/conj_ cj_i rmorphN inQ_K // eq_sym -addr_eq0 -mulr2n -mulr_natl. rewrite mulf_neq0 ?(memPnC (R'i 0%N)) ?rpred0 //. by have /charf0P-> := ftrans (fmorph_char QtoC) (char_num _). do 2?split=> [x y|]; last pose n1 := n_ 1. - have [m [le_xm le_ym le_xym]] := maxn3 (n_ x) (n_ y) (n_ (x - y)). by rewrite !(conjE m) // (inFTA m x) // (inFTA m y) -?rmorphB /conj_ ?ofQ_K. - have [m [le_xm le_ym le_xym]] := maxn3 (n_ x) (n_ y) (n_ (x * y)). by rewrite !(conjE m) // (inFTA m x) // (inFTA m y) -?rmorphM /conj_ ?ofQ_K. by rewrite /conj -/n1 -(rmorph1 (ofQ (z_ n1))) /conj_ ofQ_K !rmorph1. Qed. mathcomp-1.5/theories/morphism.v0000644000175000017500000015061712307636117016042 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq choice fintype finfun. Require Import bigop finset fingroup. (******************************************************************************) (* This file contains the definitions of: *) (* *) (* {morphism D >-> rT} == *) (* the structure type of functions that are group morphisms mapping a *) (* domain set D : {set aT} to a type rT; rT must have a finGroupType *) (* structure, and D is usually a group (most of the theory expects this). *) (* mfun == the coercion projecting {morphism D >-> rT} to aT -> rT *) (* *) (* Basic examples: *) (* idm D == the identity morphism with domain D, or more precisely *) (* the identity function, but with a canonical *) (* {morphism G -> gT} structure. *) (* trivm D == the trivial morphism with domain D *) (* If f has a {morphism D >-> rT} structure *) (* 'dom f == D *) (* f @* A == the image of A by f, where f is defined *) (* := f @: (D :&: A) *) (* f @*^-1 R == the pre-image of R by f, where f is defined *) (* := D :&: f @^-1: R *) (* 'ker f == the kernel of f *) (* := f @^-1: 1 *) (* 'ker_G f == the kernel of f restricted to G *) (* := G :&: 'ker f (this is a pure notation) *) (* 'injm f <=> f injective on D *) (* <-> ker f \subset 1 (this is a pure notation) *) (* invm injf == the inverse morphism of f, with domain f @* D, when f *) (* is injective (injf : 'injm f) *) (* restrm f sDom == the restriction of f to a subset A of D, given *) (* (sDom : A \subset D); restrm f sDom is transparently *) (* identical to f; the restrmP and domP lemmas provide *) (* opaque restrictions. *) (* invm f infj == the inverse morphism for an injective f, with domain *) (* f @* D, given (injf : 'injm f) *) (* *) (* G \isog H <=> G and H are isomorphic as groups *) (* H \homg G <=> H is a homomorphic image of G *) (* isom G H f <=> f maps G isomorphically to H, provided D contains G *) (* <-> f @: G^# == H^# *) (* *) (* If, moreover, g : {morphism G >-> gT} with G : {group aT}, *) (* factm sKer sDom == the (natural) factor morphism mapping f @* G to g @* G *) (* given sDom : G \subset D, sKer : 'ker f \subset 'ker g *) (* ifactm injf g == the (natural) factor morphism mapping f @* G to g @* G *) (* when f is injective (injf : 'injm f); here g must *) (* be an actual morphism structure, not its function *) (* projection. *) (* *) (* If g has a {morphism G >-> aT} structure for any G : {group gT}, then *) (* f \o g has a canonical {morphism g @*^-1 D >-> rT} structure *) (* *) (* Finally, for an arbitrary function f : aT -> rT *) (* morphic D f <=> f preserves group multiplication in D, i.e., *) (* f (x * y) = (f x) * (f y) for all x, y in D *) (* morphm fM == a function identical to f, but with a canonical *) (* {morphism D >-> rT} structure, given fM : morphic D f *) (* misom D C f <=> f maps D isomorphically to C *) (* := morphic D f && isom D C f *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Reserved Notation "x \isog y" (at level 70). Section MorphismStructure. Variables aT rT : finGroupType. Structure morphism (D : {set aT}) : Type := Morphism { mfun :> aT -> FinGroup.sort rT; _ : {in D &, {morph mfun : x y / x * y}} }. (* We give the most 'lightweight' possible specification to define morphisms:*) (* local congruence with the group law of aT. We then provide the properties *) (* for the 'textbook' notion of morphism, when the required structures are *) (* available (e.g. its domain is a group). *) Definition morphism_for D of phant rT := morphism D. Definition clone_morphism D f := let: Morphism _ fM := f return {type of @Morphism D for f} -> morphism_for D (Phant rT) in fun k => k fM. Variables (D A : {set aT}) (R : {set rT}) (x : aT) (y : rT) (f : aT -> rT). CoInductive morphim_spec : Prop := MorphimSpec z & z \in D & z \in A & y = f z. Lemma morphimP : reflect morphim_spec (y \in f @: (D :&: A)). Proof. apply: (iffP imsetP) => [] [z]; first by case/setIP; exists z. by exists z; first apply/setIP. Qed. Lemma morphpreP : reflect (x \in D /\ f x \in R) (x \in D :&: f @^-1: R). Proof. rewrite !inE; exact: andP. Qed. End MorphismStructure. Notation "{ 'morphism' D >-> T }" := (morphism_for D (Phant T)) (at level 0, format "{ 'morphism' D >-> T }") : group_scope. Notation "[ 'morphism' D 'of' f ]" := (@clone_morphism _ _ D _ (fun fM => @Morphism _ _ D f fM)) (at level 0, format "[ 'morphism' D 'of' f ]") : form_scope. Notation "[ 'morphism' 'of' f ]" := (clone_morphism (@Morphism _ _ _ f)) (at level 0, format "[ 'morphism' 'of' f ]") : form_scope. Implicit Arguments morphimP [aT rT D A f y]. Implicit Arguments morphpreP [aT rT D R f x]. Prenex Implicits morphimP morphpreP. (* domain, image, preimage, kernel, using phantom types to infer the domain *) Section MorphismOps1. Variables (aT rT : finGroupType) (D : {set aT}) (f : {morphism D >-> rT}). Lemma morphM : {in D &, {morph f : x y / x * y}}. Proof. by case f. Qed. Notation morPhantom := (phantom (aT -> rT)). Definition MorPhantom := Phantom (aT -> rT). Definition dom of morPhantom f := D. Definition morphim of morPhantom f := fun A => f @: (D :&: A). Definition morphpre of morPhantom f := fun R : {set rT} => D :&: f @^-1: R. Definition ker mph := morphpre mph 1. End MorphismOps1. Arguments Scope morphim [_ _ group_scope _ _ group_scope]. Arguments Scope morphpre [_ _ group_scope _ _ group_scope]. Notation "''dom' f" := (dom (MorPhantom f)) (at level 10, f at level 8, format "''dom' f") : group_scope. Notation "''ker' f" := (ker (MorPhantom f)) (at level 10, f at level 8, format "''ker' f") : group_scope. Notation "''ker_' H f" := (H :&: 'ker f) (at level 10, H at level 2, f at level 8, format "''ker_' H f") : group_scope. Notation "f @* A" := (morphim (MorPhantom f) A) (at level 24, format "f @* A") : group_scope. Notation "f @*^-1 R" := (morphpre (MorPhantom f) R) (at level 24, format "f @*^-1 R") : group_scope. Notation "''injm' f" := (pred_of_set ('ker f) \subset pred_of_set 1) (at level 10, f at level 8, format "''injm' f") : group_scope. Section MorphismTheory. Variables aT rT : finGroupType. Implicit Types A B : {set aT}. Implicit Types G H : {group aT}. Implicit Types R S : {set rT}. Implicit Types M : {group rT}. (* Most properties of morphims hold only when the domain is a group. *) Variables (D : {group aT}) (f : {morphism D >-> rT}). Lemma morph1 : f 1 = 1. Proof. by apply: (mulgI (f 1)); rewrite -morphM ?mulg1. Qed. Lemma morph_prod I r (P : pred I) F : (forall i, P i -> F i \in D) -> f (\prod_(i <- r | P i) F i) = \prod_( i <- r | P i) f (F i). Proof. move=> D_F; elim/(big_load (fun x => x \in D)): _. elim/big_rec2: _ => [|i _ x Pi [Dx <-]]; first by rewrite morph1. by rewrite groupM ?morphM // D_F. Qed. Lemma morphV : {in D, {morph f : x / x^-1}}. Proof. move=> x Dx; apply: (mulgI (f x)). by rewrite -morphM ?groupV // !mulgV morph1. Qed. Lemma morphJ : {in D &, {morph f : x y / x ^ y}}. Proof. by move=> * /=; rewrite !morphM ?morphV // ?groupM ?groupV. Qed. Lemma morphX n : {in D, {morph f : x / x ^+ n}}. Proof. by elim: n => [|n IHn] x Dx; rewrite ?morph1 // !expgS morphM ?(groupX, IHn). Qed. Lemma morphR : {in D &, {morph f : x y / [~ x, y]}}. Proof. by move=> * /=; rewrite morphM ?(groupV, groupJ) // morphJ ?morphV. Qed. (* morphic image,preimage properties w.r.t. set-theoretic operations *) Lemma morphimE A : f @* A = f @: (D :&: A). Proof. by []. Qed. Lemma morphpreE R : f @*^-1 R = D :&: f @^-1: R. Proof. by []. Qed. Lemma kerE : 'ker f = f @*^-1 1. Proof. by []. Qed. Lemma morphimEsub A : A \subset D -> f @* A = f @: A. Proof. by move=> sAD; rewrite /morphim (setIidPr sAD). Qed. Lemma morphimEdom : f @* D = f @: D. Proof. exact: morphimEsub. Qed. Lemma morphimIdom A : f @* (D :&: A) = f @* A. Proof. by rewrite /morphim setIA setIid. Qed. Lemma morphpreIdom R : D :&: f @*^-1 R = f @*^-1 R. Proof. by rewrite /morphim setIA setIid. Qed. Lemma morphpreIim R : f @*^-1 (f @* D :&: R) = f @*^-1 R. Proof. apply/setP=> x; rewrite morphimEdom !inE. by case Dx: (x \in D); rewrite // mem_imset. Qed. Lemma morphimIim A : f @* D :&: f @* A = f @* A. Proof. by apply/setIidPr; rewrite imsetS // setIid subsetIl. Qed. Lemma mem_morphim A x : x \in D -> x \in A -> f x \in f @* A. Proof. by move=> Dx Ax; apply/morphimP; exists x. Qed. Lemma mem_morphpre R x : x \in D -> f x \in R -> x \in f @*^-1 R. Proof. by move=> Dx Rfx; exact/morphpreP. Qed. Lemma morphimS A B : A \subset B -> f @* A \subset f @* B. Proof. by move=> sAB; rewrite imsetS ?setIS. Qed. Lemma morphim_sub A : f @* A \subset f @* D. Proof. by rewrite imsetS // setIid subsetIl. Qed. Lemma leq_morphim A : #|f @* A| <= #|A|. Proof. by apply: (leq_trans (leq_imset_card _ _)); rewrite subset_leq_card ?subsetIr. Qed. Lemma morphpreS R S : R \subset S -> f @*^-1 R \subset f @*^-1 S. Proof. by move=> sRS; rewrite setIS ?preimsetS. Qed. Lemma morphpre_sub R : f @*^-1 R \subset D. Proof. exact: subsetIl. Qed. Lemma morphim_setIpre A R : f @* (A :&: f @*^-1 R) = f @* A :&: R. Proof. apply/setP=> fa; apply/morphimP/setIP=> [[a Da] | [/morphimP[a Da Aa ->] Rfa]]. by rewrite !inE Da /= => /andP[Aa Rfa] ->; rewrite mem_morphim. by exists a; rewrite // !inE Aa Da. Qed. Lemma morphim0 : f @* set0 = set0. Proof. by rewrite morphimE setI0 imset0. Qed. Lemma morphim_eq0 A : A \subset D -> (f @* A == set0) = (A == set0). Proof. by rewrite imset_eq0 => /setIidPr->. Qed. Lemma morphim_set1 x : x \in D -> f @* [set x] = [set f x]. Proof. by rewrite /morphim -sub1set => /setIidPr->; exact: imset_set1. Qed. Lemma morphim1 : f @* 1 = 1. Proof. by rewrite morphim_set1 ?morph1. Qed. Lemma morphimV A : f @* A^-1 = (f @* A)^-1. Proof. wlog suffices: A / f @* A^-1 \subset (f @* A)^-1. by move=> IH; apply/eqP; rewrite eqEsubset IH -invSg invgK -{1}(invgK A) IH. apply/subsetP=> _ /morphimP[x Dx Ax' ->]; rewrite !inE in Ax' *. by rewrite -morphV // mem_imset // inE groupV Dx. Qed. Lemma morphpreV R : f @*^-1 R^-1 = (f @*^-1 R)^-1. Proof. apply/setP=> x; rewrite !inE groupV; case Dx: (x \in D) => //=. by rewrite morphV. Qed. Lemma morphimMl A B : A \subset D -> f @* (A * B) = f @* A * f @* B. Proof. move=> sAD; rewrite /morphim setIC -group_modl // (setIidPr sAD). apply/setP=> fxy; apply/idP/idP. case/imsetP=> _ /imset2P[x y Ax /setIP[Dy By] ->] ->{fxy}. by rewrite morphM // (subsetP sAD, mem_imset2) // mem_imset // inE By. case/imset2P=> _ _ /imsetP[x Ax ->] /morphimP[y Dy By ->] ->{fxy}. by rewrite -morphM // (subsetP sAD, mem_imset) // mem_mulg // inE By. Qed. Lemma morphimMr A B : B \subset D -> f @* (A * B) = f @* A * f @* B. Proof. move=> sBD; apply: invg_inj. by rewrite invMg -!morphimV invMg morphimMl // -invGid invSg. Qed. Lemma morphpreMl R S : R \subset f @* D -> f @*^-1 (R * S) = f @*^-1 R * f @*^-1 S. Proof. move=> sRfD; apply/setP=> x; rewrite !inE. apply/andP/imset2P=> [[Dx] | [y z]]; last first. rewrite !inE => /andP[Dy Rfy] /andP[Dz Rfz] ->. by rewrite ?(groupM, morphM, mem_imset2). case/imset2P=> fy fz Rfy Rfz def_fx. have /morphimP[y Dy _ def_fy]: fy \in f @* D := subsetP sRfD fy Rfy. exists y (y^-1 * x); last by rewrite mulKVg. by rewrite !inE Dy -def_fy. by rewrite !inE groupM ?(morphM, morphV, groupV) // def_fx -def_fy mulKg. Qed. Lemma morphimJ A x : x \in D -> f @* (A :^ x) = f @* A :^ f x. Proof. move=> Dx; rewrite !conjsgE morphimMl ?(morphimMr, sub1set, groupV) //. by rewrite !(morphim_set1, groupV, morphV). Qed. Lemma morphpreJ R x : x \in D -> f @*^-1 (R :^ f x) = f @*^-1 R :^ x. Proof. move=> Dx; apply/setP=> y; rewrite conjIg !inE conjGid // !mem_conjg inE. by case Dy: (y \in D); rewrite // morphJ ?(morphV, groupV). Qed. Lemma morphim_class x A : x \in D -> A \subset D -> f @* (x ^: A) = f x ^: f @* A. Proof. move=> Dx sAD; rewrite !morphimEsub ?class_subG // /class -!imset_comp. by apply: eq_in_imset => y Ay /=; rewrite morphJ // (subsetP sAD). Qed. Lemma classes_morphim A : A \subset D -> classes (f @* A) = [set f @* xA | xA in classes A]. Proof. move=> sAD; rewrite morphimEsub // /classes -!imset_comp. apply: eq_in_imset => x /(subsetP sAD) Dx /=. by rewrite morphim_class ?morphimEsub. Qed. Lemma morphimT : f @* setT = f @* D. Proof. by rewrite -morphimIdom setIT. Qed. Lemma morphimU A B : f @* (A :|: B) = f @* A :|: f @* B. Proof. by rewrite -imsetU -setIUr. Qed. Lemma morphimI A B : f @* (A :&: B) \subset f @* A :&: f @* B. Proof. by rewrite subsetI // ?morphimS ?(subsetIl, subsetIr). Qed. Lemma morphpre0 : f @*^-1 set0 = set0. Proof. by rewrite morphpreE preimset0 setI0. Qed. Lemma morphpreT : f @*^-1 setT = D. Proof. by rewrite morphpreE preimsetT setIT. Qed. Lemma morphpreU R S : f @*^-1 (R :|: S) = f @*^-1 R :|: f @*^-1 S. Proof. by rewrite -setIUr -preimsetU. Qed. Lemma morphpreI R S : f @*^-1 (R :&: S) = f @*^-1 R :&: f @*^-1 S. Proof. by rewrite -setIIr -preimsetI. Qed. Lemma morphpreD R S : f @*^-1 (R :\: S) = f @*^-1 R :\: f @*^-1 S. Proof. by apply/setP=> x; rewrite !inE; case: (x \in D). Qed. (* kernel, domain properties *) Lemma kerP x : x \in D -> reflect (f x = 1) (x \in 'ker f). Proof. move=> Dx; rewrite 2!inE Dx; exact: set1P. Qed. Lemma dom_ker : {subset 'ker f <= D}. Proof. by move=> x /morphpreP[]. Qed. Lemma mker x : x \in 'ker f -> f x = 1. Proof. by move=> Kx; apply/kerP=> //; exact: dom_ker. Qed. Lemma mkerl x y : x \in 'ker f -> y \in D -> f (x * y) = f y. Proof. by move=> Kx Dy; rewrite morphM // ?(dom_ker, mker Kx, mul1g). Qed. Lemma mkerr x y : x \in D -> y \in 'ker f -> f (x * y) = f x. Proof. by move=> Dx Ky; rewrite morphM // ?(dom_ker, mker Ky, mulg1). Qed. Lemma rcoset_kerP x y : x \in D -> y \in D -> reflect (f x = f y) (x \in 'ker f :* y). Proof. move=> Dx Dy; rewrite mem_rcoset !inE groupM ?morphM ?groupV //=. rewrite morphV // -eq_mulgV1; exact: eqP. Qed. Lemma ker_rcoset x y : x \in D -> y \in D -> f x = f y -> exists2 z, z \in 'ker f & x = z * y. Proof. move=> Dx Dy eqfxy; apply/rcosetP; exact/rcoset_kerP. Qed. Lemma ker_norm : D \subset 'N('ker f). Proof. apply/subsetP=> x Dx; rewrite inE; apply/subsetP=> _ /imsetP[y Ky ->]. by rewrite !inE groupJ ?morphJ // ?dom_ker //= mker ?conj1g. Qed. Lemma ker_normal : 'ker f <| D. Proof. by rewrite /(_ <| D) subsetIl ker_norm. Qed. Lemma morphimGI G A : 'ker f \subset G -> f @* (G :&: A) = f @* G :&: f @* A. Proof. move=> sKG; apply/eqP; rewrite eqEsubset morphimI setIC. apply/subsetP=> _ /setIP[/morphimP[x Dx Ax ->] /morphimP[z Dz Gz]]. case/ker_rcoset=> {Dz}// y Ky def_x. have{z Gz y Ky def_x} Gx: x \in G by rewrite def_x groupMl // (subsetP sKG). by rewrite mem_imset ?inE // Dx Gx Ax. Qed. Lemma morphimIG A G : 'ker f \subset G -> f @* (A :&: G) = f @* A :&: f @* G. Proof. by move=> sKG; rewrite setIC morphimGI // setIC. Qed. Lemma morphimD A B : f @* A :\: f @* B \subset f @* (A :\: B). Proof. rewrite subDset -morphimU morphimS //. by rewrite setDE setUIr setUCr setIT subsetUr. Qed. Lemma morphimDG A G : 'ker f \subset G -> f @* (A :\: G) = f @* A :\: f @* G. Proof. move=> sKG; apply/eqP; rewrite eqEsubset morphimD andbT !setDE subsetI. rewrite morphimS ?subsetIl // -[~: f @* G]setU0 -subDset setDE setCK. by rewrite -morphimIG //= setIAC -setIA setICr setI0 morphim0. Qed. Lemma morphimD1 A : (f @* A)^# \subset f @* A^#. Proof. by rewrite -!set1gE -morphim1 morphimD. Qed. (* group structure preservation *) Lemma morphpre_groupset M : group_set (f @*^-1 M). Proof. apply/group_setP; split=> [|x y]; rewrite !inE ?(morph1, group1) //. by case/andP=> Dx Mfx /andP[Dy Mfy]; rewrite morphM ?groupM. Qed. Lemma morphim_groupset G : group_set (f @* G). Proof. apply/group_setP; split=> [|_ _ /morphimP[x Dx Gx ->] /morphimP[y Dy Gy ->]]. by rewrite -morph1 mem_imset ?group1. by rewrite -morphM ?mem_imset ?inE ?groupM. Qed. Canonical morphpre_group fPh M := @group _ (morphpre fPh M) (morphpre_groupset M). Canonical morphim_group fPh G := @group _ (morphim fPh G) (morphim_groupset G). Canonical ker_group fPh : {group aT} := Eval hnf in [group of ker fPh]. Lemma morph_dom_groupset : group_set (f @: D). Proof. by rewrite -morphimEdom groupP. Qed. Canonical morph_dom_group := group morph_dom_groupset. Lemma morphpreMr R S : S \subset f @* D -> f @*^-1 (R * S) = f @*^-1 R * f @*^-1 S. Proof. move=> sSfD; apply: invg_inj. by rewrite invMg -!morphpreV invMg morphpreMl // -invSg invgK invGid. Qed. Lemma morphimK A : A \subset D -> f @*^-1 (f @* A) = 'ker f * A. Proof. move=> sAD; apply/setP=> x; rewrite !inE. apply/idP/idP=> [/andP[Dx /morphimP[y Dy Ay eqxy]] | /imset2P[z y Kz Ay ->{x}]]. rewrite -(mulgKV y x) mem_mulg // !inE !(groupM, morphM, groupV) //. by rewrite morphV //= eqxy mulgV. have [Dy Dz]: y \in D /\ z \in D by rewrite (subsetP sAD) // dom_ker. by rewrite groupM // morphM // mker // mul1g mem_imset // inE Dy. Qed. Lemma morphimGK G : 'ker f \subset G -> G \subset D -> f @*^-1 (f @* G) = G. Proof. by move=> sKG sGD; rewrite morphimK // mulSGid. Qed. Lemma morphpre_set1 x : x \in D -> f @*^-1 [set f x] = 'ker f :* x. Proof. by move=> Dx; rewrite -morphim_set1 // morphimK ?sub1set. Qed. Lemma morphpreK R : R \subset f @* D -> f @* (f @*^-1 R) = R. Proof. move=> sRfD; apply/setP=> y; apply/morphimP/idP=> [[x _] | Ry]. by rewrite !inE; case/andP=> _ Rfx ->. have /morphimP[x Dx _ defy]: y \in f @* D := subsetP sRfD y Ry. by exists x; rewrite // !inE Dx -defy. Qed. Lemma morphim_ker : f @* 'ker f = 1. Proof. by rewrite morphpreK ?sub1G. Qed. Lemma ker_sub_pre M : 'ker f \subset f @*^-1 M. Proof. by rewrite morphpreS ?sub1G. Qed. Lemma ker_normal_pre M : 'ker f <| f @*^-1 M. Proof. by rewrite /normal ker_sub_pre subIset ?ker_norm. Qed. Lemma morphpreSK R S : R \subset f @* D -> (f @*^-1 R \subset f @*^-1 S) = (R \subset S). Proof. move=> sRfD; apply/idP/idP=> [sf'RS|]; last exact: morphpreS. suffices: R \subset f @* D :&: S by rewrite subsetI sRfD. rewrite -(morphpreK sRfD) -[_ :&: S]morphpreK (morphimS, subsetIl) //. by rewrite morphpreI morphimGK ?subsetIl // setIA setIid. Qed. Lemma sub_morphim_pre A R : A \subset D -> (f @* A \subset R) = (A \subset f @*^-1 R). Proof. move=> sAD; rewrite -morphpreSK (morphimS, morphimK) //. apply/idP/idP; first by apply: subset_trans; exact: mulG_subr. by move/(mulgS ('ker f)); rewrite -morphpreMl ?(sub1G, mul1g). Qed. Lemma morphpre_proper R S : R \subset f @* D -> S \subset f @* D -> (f @*^-1 R \proper f @*^-1 S) = (R \proper S). Proof. by move=> dQ dR; rewrite /proper !morphpreSK. Qed. Lemma sub_morphpre_im R G : 'ker f \subset G -> G \subset D -> R \subset f @* D -> (f @*^-1 R \subset G) = (R \subset f @* G). Proof. by symmetry; rewrite -morphpreSK ?morphimGK. Qed. Lemma ker_trivg_morphim A : (A \subset 'ker f) = (A \subset D) && (f @* A \subset [1]). Proof. case sAD: (A \subset D); first by rewrite sub_morphim_pre. by rewrite subsetI sAD. Qed. Lemma morphimSK A B : A \subset D -> (f @* A \subset f @* B) = (A \subset 'ker f * B). Proof. move=> sAD; transitivity (A \subset 'ker f * (D :&: B)). by rewrite -morphimK ?subsetIl // -sub_morphim_pre // /morphim setIA setIid. by rewrite setIC group_modl (subsetIl, subsetI) // andbC sAD. Qed. Lemma morphimSGK A G : A \subset D -> 'ker f \subset G -> (f @* A \subset f @* G) = (A \subset G). Proof. by move=> sGD skfK; rewrite morphimSK // mulSGid. Qed. Lemma ltn_morphim A : [1] \proper 'ker_A f -> #|f @* A| < #|A|. Proof. case/properP; rewrite sub1set => /setIP[A1 _] [x /setIP[Ax kx] x1]. rewrite (cardsD1 1 A) A1 ltnS -{1}(setD1K A1) morphimU morphim1. rewrite (setUidPr _) ?sub1set; last first. by rewrite -(mker kx) mem_morphim ?(dom_ker kx) // inE x1. by rewrite (leq_trans (leq_imset_card _ _)) ?subset_leq_card ?subsetIr. Qed. (* injectivity of image and preimage *) Lemma morphpre_inj : {in [pred R : {set rT} | R \subset f @* D] &, injective (fun R => f @*^-1 R)}. Proof. exact: can_in_inj morphpreK. Qed. Lemma morphim_injG : {in [pred G : {group aT} | 'ker f \subset G & G \subset D] &, injective (fun G => f @* G)}. Proof. move=> G H /andP[sKG sGD] /andP[sKH sHD] eqfGH. by apply: val_inj; rewrite /= -(morphimGK sKG sGD) eqfGH morphimGK. Qed. Lemma morphim_inj G H : ('ker f \subset G) && (G \subset D) -> ('ker f \subset H) && (H \subset D) -> f @* G = f @* H -> G :=: H. Proof. by move=> nsGf nsHf /morphim_injG->. Qed. (* commutation with generated groups and cycles *) Lemma morphim_gen A : A \subset D -> f @* <> = <>. Proof. move=> sAD; apply/eqP. rewrite eqEsubset andbC gen_subG morphimS; last exact: subset_gen. by rewrite sub_morphim_pre gen_subG // -sub_morphim_pre // subset_gen. Qed. Lemma morphim_cycle x : x \in D -> f @* <[x]> = <[f x]>. Proof. by move=> Dx; rewrite morphim_gen (sub1set, morphim_set1). Qed. Lemma morphimY A B : A \subset D -> B \subset D -> f @* (A <*> B) = f @* A <*> f @* B. Proof. by move=> sAD sBD; rewrite morphim_gen ?morphimU // subUset sAD. Qed. Lemma morphpre_gen R : 1 \in R -> R \subset f @* D -> f @*^-1 <> = <>. Proof. move=> R1 sRfD; apply/eqP. rewrite eqEsubset andbC gen_subG morphpreS; last exact: subset_gen. rewrite -{1}(morphpreK sRfD) -morphim_gen ?subsetIl // morphimGK //=. by rewrite sub_gen // setIS // preimsetS ?sub1set. by rewrite gen_subG subsetIl. Qed. (* commutator, normaliser, normal, center properties*) Lemma morphimR A B : A \subset D -> B \subset D -> f @* [~: A, B] = [~: f @* A, f @* B]. Proof. move/subsetP=> sAD /subsetP sBD. rewrite morphim_gen; last first; last congr <<_>>. by apply/subsetP=> _ /imset2P[x y Ax By ->]; rewrite groupR; auto. apply/setP=> fz; apply/morphimP/imset2P=> [[z _] | [fx fy]]. case/imset2P=> x y Ax By -> -> {z fz}. have Dx := sAD x Ax; have Dy := sBD y By. by exists (f x) (f y); rewrite ?(mem_imset, morphR) // ?(inE, Dx, Dy). case/morphimP=> x Dx Ax ->{fx}; case/morphimP=> y Dy By ->{fy} -> {fz}. by exists [~ x, y]; rewrite ?(inE, morphR, groupR, mem_imset2). Qed. Lemma morphim_norm A : f @* 'N(A) \subset 'N(f @* A). Proof. apply/subsetP=> fx; case/morphimP=> x Dx Nx -> {fx}. by rewrite inE -morphimJ ?(normP Nx). Qed. Lemma morphim_norms A B : A \subset 'N(B) -> f @* A \subset 'N(f @* B). Proof. by move=> nBA; apply: subset_trans (morphim_norm B); exact: morphimS. Qed. Lemma morphim_subnorm A B : f @* 'N_A(B) \subset 'N_(f @* A)(f @* B). Proof. exact: subset_trans (morphimI A _) (setIS _ (morphim_norm B)). Qed. Lemma morphim_normal A B : A <| B -> f @* A <| f @* B. Proof. by case/andP=> sAB nAB; rewrite /(_ <| _) morphimS // morphim_norms. Qed. Lemma morphim_cent1 x : x \in D -> f @* 'C[x] \subset 'C[f x]. Proof. by move=> Dx; rewrite -(morphim_set1 Dx) morphim_norm. Qed. Lemma morphim_cent1s A x : x \in D -> A \subset 'C[x] -> f @* A \subset 'C[f x]. Proof. by move=> Dx cAx; apply: subset_trans (morphim_cent1 Dx); exact: morphimS. Qed. Lemma morphim_subcent1 A x : x \in D -> f @* 'C_A[x] \subset 'C_(f @* A)[f x]. Proof. by move=> Dx; rewrite -(morphim_set1 Dx) morphim_subnorm. Qed. Lemma morphim_cent A : f @* 'C(A) \subset 'C(f @* A). Proof. apply/bigcapsP=> fx; case/morphimP=> x Dx Ax ->{fx}. by apply: subset_trans (morphim_cent1 Dx); apply: morphimS; exact: bigcap_inf. Qed. Lemma morphim_cents A B : A \subset 'C(B) -> f @* A \subset 'C(f @* B). Proof. by move=> cBA; apply: subset_trans (morphim_cent B); exact: morphimS. Qed. Lemma morphim_subcent A B : f @* 'C_A(B) \subset 'C_(f @* A)(f @* B). Proof. exact: subset_trans (morphimI A _) (setIS _ (morphim_cent B)). Qed. Lemma morphim_abelian A : abelian A -> abelian (f @* A). Proof. exact: morphim_cents. Qed. Lemma morphpre_norm R : f @*^-1 'N(R) \subset 'N(f @*^-1 R). Proof. apply/subsetP=> x; rewrite !inE => /andP[Dx Nfx]. by rewrite -morphpreJ ?morphpreS. Qed. Lemma morphpre_norms R S : R \subset 'N(S) -> f @*^-1 R \subset 'N(f @*^-1 S). Proof. by move=> nSR; apply: subset_trans (morphpre_norm S); exact: morphpreS. Qed. Lemma morphpre_normal R S : R \subset f @* D -> S \subset f @* D -> (f @*^-1 R <| f @*^-1 S) = (R <| S). Proof. move=> sRfD sSfD; apply/idP/andP=> [|[sRS nSR]]. by move/morphim_normal; rewrite !morphpreK //; case/andP. by rewrite /(_ <| _) (subset_trans _ (morphpre_norm _)) morphpreS. Qed. Lemma morphpre_subnorm R S : f @*^-1 'N_R(S) \subset 'N_(f @*^-1 R)(f @*^-1 S). Proof. by rewrite morphpreI setIS ?morphpre_norm. Qed. Lemma morphim_normG G : 'ker f \subset G -> G \subset D -> f @* 'N(G) = 'N_(f @* D)(f @* G). Proof. move=> sKG sGD; apply/eqP; rewrite eqEsubset -{1}morphimIdom morphim_subnorm. rewrite -(morphpreK (subsetIl _ _)) morphimS //= morphpreI subIset // orbC. by rewrite -{2}(morphimGK sKG sGD) morphpre_norm. Qed. Lemma morphim_subnormG A G : 'ker f \subset G -> G \subset D -> f @* 'N_A(G) = 'N_(f @* A)(f @* G). Proof. move=> sKB sBD; rewrite morphimIG ?normsG // morphim_normG //. by rewrite setICA setIA morphimIim. Qed. Lemma morphpre_cent1 x : x \in D -> 'C_D[x] \subset f @*^-1 'C[f x]. Proof. move=> Dx; rewrite -sub_morphim_pre ?subsetIl //. by apply: subset_trans (morphim_cent1 Dx); rewrite morphimS ?subsetIr. Qed. Lemma morphpre_cent1s R x : x \in D -> R \subset f @* D -> f @*^-1 R \subset 'C[x] -> R \subset 'C[f x]. Proof. by move=> Dx sRfD; move/(morphim_cent1s Dx); rewrite morphpreK. Qed. Lemma morphpre_subcent1 R x : x \in D -> 'C_(f @*^-1 R)[x] \subset f @*^-1 'C_R[f x]. Proof. move=> Dx; rewrite -morphpreIdom -setIA setICA morphpreI setIS //. exact: morphpre_cent1. Qed. Lemma morphpre_cent A : 'C_D(A) \subset f @*^-1 'C(f @* A). Proof. rewrite -sub_morphim_pre ?subsetIl // morphimGI ?(subsetIl, subIset) // orbC. by rewrite (subset_trans (morphim_cent _)). Qed. Lemma morphpre_cents A R : R \subset f @* D -> f @*^-1 R \subset 'C(A) -> R \subset 'C(f @* A). Proof. by move=> sRfD; move/morphim_cents; rewrite morphpreK. Qed. Lemma morphpre_subcent R A : 'C_(f @*^-1 R)(A) \subset f @*^-1 'C_R(f @* A). Proof. by rewrite -morphpreIdom -setIA setICA morphpreI setIS //; exact: morphpre_cent. Qed. (* local injectivity properties *) Lemma injmP : reflect {in D &, injective f} ('injm f). Proof. apply: (iffP subsetP) => [injf x y Dx Dy | injf x /= Kx]. by case/ker_rcoset=> // z /injf/set1P->; rewrite mul1g. have Dx := dom_ker Kx; apply/set1P/injf => //. by apply/rcoset_kerP; rewrite // mulg1. Qed. Lemma card_im_injm : (#|f @* D| == #|D|) = 'injm f. Proof. by rewrite morphimEdom (sameP imset_injP injmP). Qed. Section Injective. Hypothesis injf : 'injm f. Lemma ker_injm : 'ker f = 1. Proof. exact/trivgP. Qed. Lemma injmK A : A \subset D -> f @*^-1 (f @* A) = A. Proof. by move=> sAD; rewrite morphimK // ker_injm // mul1g. Qed. Lemma injm_morphim_inj A B : A \subset D -> B \subset D -> f @* A = f @* B -> A = B. Proof. by move=> sAD sBD eqAB; rewrite -(injmK sAD) eqAB injmK. Qed. Lemma card_injm A : A \subset D -> #|f @* A| = #|A|. Proof. move=> sAD; rewrite morphimEsub // card_in_imset //. exact: (sub_in2 (subsetP sAD) (injmP injf)). Qed. Lemma order_injm x : x \in D -> #[f x] = #[x]. Proof. by move=> Dx; rewrite orderE -morphim_cycle // card_injm ?cycle_subG. Qed. Lemma injm1 x : x \in D -> f x = 1 -> x = 1. Proof. by move=> Dx; move/(kerP Dx); rewrite ker_injm; move/set1P. Qed. Lemma morph_injm_eq1 x : x \in D -> (f x == 1) = (x == 1). Proof. by move=> Dx; rewrite -morph1 (inj_in_eq (injmP injf)) ?group1. Qed. Lemma injmSK A B : A \subset D -> (f @* A \subset f @* B) = (A \subset B). Proof. by move=> sAD; rewrite morphimSK // ker_injm mul1g. Qed. Lemma sub_morphpre_injm R A : A \subset D -> R \subset f @* D -> (f @*^-1 R \subset A) = (R \subset f @* A). Proof. by move=> sAD sRfD; rewrite -morphpreSK ?injmK. Qed. Lemma injm_eq A B : A \subset D -> B \subset D -> (f @* A == f @* B) = (A == B). Proof. by move=> sAD sBD; rewrite !eqEsubset !injmSK. Qed. Lemma morphim_injm_eq1 A : A \subset D -> (f @* A == 1) = (A == 1). Proof. by move=> sAD; rewrite -morphim1 injm_eq ?sub1G. Qed. Lemma injmI A B : f @* (A :&: B) = f @* A :&: f @* B. Proof. rewrite -morphimIdom setIIr -4!(injmK (subsetIl D _), =^~ morphimIdom). by rewrite -morphpreI morphpreK // subIset ?morphim_sub. Qed. Lemma injmD1 A : f @* A^# = (f @* A)^#. Proof. by have:= morphimDG A injf; rewrite morphim1. Qed. Lemma nclasses_injm A : A \subset D -> #|classes (f @* A)| = #|classes A|. Proof. move=> sAD; rewrite classes_morphim // card_in_imset //. move=> _ _ /imsetP[x Ax ->] /imsetP[y Ay ->]. by apply: injm_morphim_inj; rewrite // class_subG ?(subsetP sAD). Qed. Lemma injm_norm A : A \subset D -> f @* 'N(A) = 'N_(f @* D)(f @* A). Proof. move=> sAD; apply/eqP; rewrite -morphimIdom eqEsubset morphim_subnorm. rewrite -sub_morphpre_injm ?subsetIl // morphpreI injmK // setIS //. by rewrite -{2}(injmK sAD) morphpre_norm. Qed. Lemma injm_norms A B : A \subset D -> B \subset D -> (f @* A \subset 'N(f @* B)) = (A \subset 'N(B)). Proof. by move=> sAD sBD; rewrite -injmSK // injm_norm // subsetI morphimS. Qed. Lemma injm_normal A B : A \subset D -> B \subset D -> (f @* A <| f @* B) = (A <| B). Proof. by move=> sAD sBD; rewrite /normal injmSK ?injm_norms. Qed. Lemma injm_subnorm A B : B \subset D -> f @* 'N_A(B) = 'N_(f @* A)(f @* B). Proof. by move=> sBD; rewrite injmI injm_norm // setICA setIA morphimIim. Qed. Lemma injm_cent1 x : x \in D -> f @* 'C[x] = 'C_(f @* D)[f x]. Proof. by move=> Dx; rewrite injm_norm ?morphim_set1 ?sub1set. Qed. Lemma injm_subcent1 A x : x \in D -> f @* 'C_A[x] = 'C_(f @* A)[f x]. Proof. by move=> Dx; rewrite injm_subnorm ?morphim_set1 ?sub1set. Qed. Lemma injm_cent A : A \subset D -> f @* 'C(A) = 'C_(f @* D)(f @* A). Proof. move=> sAD; apply/eqP; rewrite -morphimIdom eqEsubset morphim_subcent. apply/subsetP=> fx; case/setIP; case/morphimP=> x Dx _ ->{fx} cAfx. rewrite mem_morphim // inE Dx -sub1set centsC cent_set1 -injmSK //. by rewrite injm_cent1 // subsetI morphimS // -cent_set1 centsC sub1set. Qed. Lemma injm_cents A B : A \subset D -> B \subset D -> (f @* A \subset 'C(f @* B)) = (A \subset 'C(B)). Proof. by move=> sAD sBD; rewrite -injmSK // injm_cent // subsetI morphimS. Qed. Lemma injm_subcent A B : B \subset D -> f @* 'C_A(B) = 'C_(f @* A)(f @* B). Proof. by move=> sBD; rewrite injmI injm_cent // setICA setIA morphimIim. Qed. Lemma injm_abelian A : A \subset D -> abelian (f @* A) = abelian A. Proof. by move=> sAD; rewrite /abelian -subsetIidl -injm_subcent // injmSK ?subsetIidl. Qed. End Injective. Lemma eq_morphim (g : {morphism D >-> rT}): {in D, f =1 g} -> forall A, f @* A = g @* A. Proof. by move=> efg A; apply: eq_in_imset; apply: sub_in1 efg => x /setIP[]. Qed. Lemma eq_in_morphim B A (g : {morphism B >-> rT}) : D :&: A = B :&: A -> {in A, f =1 g} -> f @* A = g @* A. Proof. move=> eqDBA eqAfg; rewrite /morphim /= eqDBA. by apply: eq_in_imset => x /setIP[_]/eqAfg. Qed. End MorphismTheory. Notation "''ker' f" := (ker_group (MorPhantom f)) : Group_scope. Notation "''ker_' G f" := (G :&: 'ker f)%G : Group_scope. Notation "f @* G" := (morphim_group (MorPhantom f) G) : Group_scope. Notation "f @*^-1 M" := (morphpre_group (MorPhantom f) M) : Group_scope. Notation "f @: D" := (morph_dom_group f D) : Group_scope. Implicit Arguments injmP [aT rT D f]. Section IdentityMorphism. Variable gT : finGroupType. Implicit Types A B : {set gT}. Implicit Type G : {group gT}. Definition idm of {set gT} := fun x : gT => x : FinGroup.sort gT. Lemma idm_morphM A : {in A & , {morph idm A : x y / x * y}}. Proof. by []. Qed. Canonical idm_morphism A := Morphism (@idm_morphM A). Lemma injm_idm G : 'injm (idm G). Proof. by apply/injmP=> x y _ _. Qed. Lemma ker_idm G : 'ker (idm G) = 1. Proof. by apply/trivgP; exact: injm_idm. Qed. Lemma morphim_idm A B : B \subset A -> idm A @* B = B. Proof. rewrite /morphim /= /idm => /setIidPr->. by apply/setP=> x; apply/imsetP/idP=> [[y By ->]|Bx]; last exists x. Qed. Lemma morphpre_idm A B : idm A @*^-1 B = A :&: B. Proof. by apply/setP=> x; rewrite !inE. Qed. Lemma im_idm A : idm A @* A = A. Proof. exact: morphim_idm. Qed. End IdentityMorphism. Arguments Scope idm [_ group_scope group_scope]. Prenex Implicits idm. Section RestrictedMorphism. Variables aT rT : finGroupType. Variables A D : {set aT}. Implicit Type B : {set aT}. Implicit Type R : {set rT}. Definition restrm of A \subset D := @id (aT -> FinGroup.sort rT). Section Props. Hypothesis sAD : A \subset D. Variable f : {morphism D >-> rT}. Local Notation fA := (restrm sAD (mfun f)). Canonical restrm_morphism := @Morphism aT rT A fA (sub_in2 (subsetP sAD) (morphM f)). Lemma morphim_restrm B : fA @* B = f @* (A :&: B). Proof. by rewrite {2}/morphim setIA (setIidPr sAD). Qed. Lemma restrmEsub B : B \subset A -> fA @* B = f @* B. Proof. by rewrite morphim_restrm => /setIidPr->. Qed. Lemma im_restrm : fA @* A = f @* A. Proof. exact: restrmEsub. Qed. Lemma morphpre_restrm R : fA @*^-1 R = A :&: f @*^-1 R. Proof. by rewrite setIA (setIidPl sAD). Qed. Lemma ker_restrm : 'ker fA = 'ker_A f. Proof. exact: morphpre_restrm. Qed. Lemma injm_restrm : 'injm f -> 'injm fA. Proof. by apply: subset_trans; rewrite ker_restrm subsetIr. Qed. End Props. Lemma restrmP (f : {morphism D >-> rT}) : A \subset 'dom f -> {g : {morphism A >-> rT} | [/\ g = f :> (aT -> rT), 'ker g = 'ker_A f, forall R, g @*^-1 R = A :&: f @*^-1 R & forall B, B \subset A -> g @* B = f @* B]}. Proof. move=> sAD; exists (restrm_morphism sAD f). split=> // [|R|B sBA]; first 1 [exact: ker_restrm | exact: morphpre_restrm]. by rewrite morphim_restrm (setIidPr sBA). Qed. Lemma domP (f : {morphism D >-> rT}) : 'dom f = A -> {g : {morphism A >-> rT} | [/\ g = f :> (aT -> rT), 'ker g = 'ker f, forall R, g @*^-1 R = f @*^-1 R & forall B, g @* B = f @* B]}. Proof. by move <-; exists f. Qed. End RestrictedMorphism. Arguments Scope restrm [_ _ group_scope group_scope _ group_scope]. Prenex Implicits restrm. Implicit Arguments restrmP [aT rT D A]. Implicit Arguments domP [aT rT D A]. Section TrivMorphism. Variables aT rT : finGroupType. Definition trivm of {set aT} & aT := 1 : FinGroup.sort rT. Lemma trivm_morphM (A : {set aT}) : {in A &, {morph trivm A : x y / x * y}}. Proof. by move=> x y /=; rewrite mulg1. Qed. Canonical triv_morph A := Morphism (@trivm_morphM A). Lemma morphim_trivm (G H : {group aT}) : trivm G @* H = 1. Proof. apply/setP=> /= y; rewrite inE; apply/idP/eqP=> [|->]; first by case/morphimP. by apply/morphimP; exists (1 : aT); rewrite /= ?group1. Qed. Lemma ker_trivm (G : {group aT}) : 'ker (trivm G) = G. Proof. by apply/setIidPl/subsetP=> x _; rewrite !inE /=. Qed. End TrivMorphism. Arguments Scope trivm [_ _ group_scope group_scope]. Implicit Arguments trivm [[aT] [rT]]. (* The composition of two morphisms is a Canonical morphism instance. *) Section MorphismComposition. Variables gT hT rT : finGroupType. Variables (G : {group gT}) (H : {group hT}). Variable f : {morphism G >-> hT}. Variable g : {morphism H >-> rT}. Notation Local gof := (mfun g \o mfun f). Lemma comp_morphM : {in f @*^-1 H &, {morph gof: x y / x * y}}. Proof. by move=> x y; rewrite /= !inE => /andP[? ?] /andP[? ?]; rewrite !morphM. Qed. Canonical comp_morphism := Morphism comp_morphM. Lemma ker_comp : 'ker gof = f @*^-1 'ker g. Proof. by apply/setP=> x; rewrite !inE andbA. Qed. Lemma injm_comp : 'injm f -> 'injm g -> 'injm gof. Proof. by move=> injf; rewrite ker_comp; move/trivgP=> ->. Qed. Lemma morphim_comp (A : {set gT}) : gof @* A = g @* (f @* A). Proof. apply/setP=> z; apply/morphimP/morphimP=> [[x]|[y Hy fAy ->{z}]]. rewrite !inE => /andP[Gx Hfx]; exists (f x) => //. by apply/morphimP; exists x. by case/morphimP: fAy Hy => x Gx Ax ->{y} Hfx; exists x; rewrite ?inE ?Gx. Qed. Lemma morphpre_comp (C : {set rT}) : gof @*^-1 C = f @*^-1 (g @*^-1 C). Proof. by apply/setP=> z; rewrite !inE andbA. Qed. End MorphismComposition. (* The factor morphism *) Section FactorMorphism. Variables aT qT rT : finGroupType. Variables G H : {group aT}. Variable f : {morphism G >-> rT}. Variable q : {morphism H >-> qT}. Definition factm of 'ker q \subset 'ker f & G \subset H := fun x => f (repr (q @*^-1 [set x])). Hypothesis sKqKf : 'ker q \subset 'ker f. Hypothesis sGH : G \subset H. Notation ff := (factm sKqKf sGH). Lemma factmE x : x \in G -> ff (q x) = f x. Proof. rewrite /ff => Gx; have Hx := subsetP sGH x Gx. have /mem_repr: x \in q @*^-1 [set q x] by rewrite !inE Hx /=. case/morphpreP; move: (repr _) => y Hy /set1P. by case/ker_rcoset=> // z Kz ->; rewrite mkerl ?(subsetP sKqKf). Qed. Lemma factm_morphM : {in q @* G &, {morph ff : x y / x * y}}. Proof. move=> _ _ /morphimP[x Hx Gx ->] /morphimP[y Hy Gy ->]. by rewrite -morphM ?factmE ?groupM // morphM. Qed. Canonical factm_morphism := Morphism factm_morphM. Lemma morphim_factm (A : {set aT}) : ff @* (q @* A) = f @* A. Proof. rewrite -morphim_comp /= {1}/morphim /= morphimGK //; last first. by rewrite (subset_trans sKqKf) ?subsetIl. apply/setP=> y; apply/morphimP/morphimP; by case=> x Gx Ax ->{y}; exists x; rewrite //= factmE. Qed. Lemma morphpre_factm (C : {set rT}) : ff @*^-1 C = q @* (f @*^-1 C). Proof. apply/setP=> y; rewrite !inE /=; apply/andP/morphimP=> [[]|[x Hx]]; last first. by case/morphpreP=> Gx Cfx ->; rewrite factmE ?mem_imset ?inE ?Hx. case/morphimP=> x Hx Gx ->; rewrite factmE //. by exists x; rewrite // !inE Gx. Qed. Lemma ker_factm : 'ker ff = q @* 'ker f. Proof. exact: morphpre_factm. Qed. Lemma injm_factm : 'injm f -> 'injm ff. Proof. by rewrite ker_factm => /trivgP->; rewrite morphim1. Qed. Lemma injm_factmP : reflect ('ker f = 'ker q) ('injm ff). Proof. rewrite ker_factm -morphimIdom sub_morphim_pre ?subsetIl //. rewrite setIA (setIidPr sGH) (sameP setIidPr eqP) (setIidPl _) // eq_sym. exact: eqP. Qed. Lemma ker_factm_loc (K : {group aT}) : 'ker_(q @* K) ff = q @* 'ker_K f. Proof. by rewrite ker_factm -morphimIG. Qed. End FactorMorphism. Prenex Implicits factm. Section InverseMorphism. Variables aT rT : finGroupType. Implicit Types A B : {set aT}. Implicit Types C D : {set rT}. Variables (G : {group aT}) (f : {morphism G >-> rT}). Hypothesis injf : 'injm f. Lemma invm_subker : 'ker f \subset 'ker (idm G). Proof. by rewrite ker_idm. Qed. Definition invm := factm invm_subker (subxx _). Canonical invm_morphism := Eval hnf in [morphism of invm]. Lemma invmE : {in G, cancel f invm}. Proof. exact: factmE. Qed. Lemma invmK : {in f @* G, cancel invm f}. Proof. by move=> fx; case/morphimP=> x _ Gx ->; rewrite invmE. Qed. Lemma morphpre_invm A : invm @*^-1 A = f @* A. Proof. by rewrite morphpre_factm morphpre_idm morphimIdom. Qed. Lemma morphim_invm A : A \subset G -> invm @* (f @* A) = A. Proof. by move=> sAG; rewrite morphim_factm morphim_idm. Qed. Lemma morphim_invmE C : invm @* C = f @*^-1 C. Proof. rewrite -morphpreIdom -(morphim_invm (subsetIl _ _)). by rewrite morphimIdom -morphpreIim morphpreK (subsetIl, morphimIdom). Qed. Lemma injm_proper A B : A \subset G -> B \subset G -> (f @* A \proper f @* B) = (A \proper B). Proof. move=> dA dB; rewrite -morphpre_invm -(morphpre_invm B). by rewrite morphpre_proper ?morphim_invm. Qed. Lemma injm_invm : 'injm invm. Proof. by move/can_in_inj/injmP: invmK. Qed. Lemma ker_invm : 'ker invm = 1. Proof. by move/trivgP: injm_invm. Qed. Lemma im_invm : invm @* (f @* G) = G. Proof. exact: morphim_invm. Qed. End InverseMorphism. Prenex Implicits invm. Section InjFactm. Variables (gT aT rT : finGroupType) (D G : {group gT}). Variables (g : {morphism G >-> rT}) (f : {morphism D >-> aT}) (injf : 'injm f). Definition ifactm := tag (domP [morphism of g \o invm injf] (morphpre_invm injf G)). Lemma ifactmE : {in D, forall x, ifactm (f x) = g x}. Proof. rewrite /ifactm => x Dx; case: domP => f' /= [def_f' _ _ _]. by rewrite {f'}def_f' //= invmE. Qed. Lemma morphim_ifactm (A : {set gT}) : A \subset D -> ifactm @* (f @* A) = g @* A. Proof. rewrite /ifactm => sAD; case: domP => _ /= [_ _ _ ->]. by rewrite morphim_comp morphim_invm. Qed. Lemma im_ifactm : G \subset D -> ifactm @* (f @* G) = g @* G. Proof. exact: morphim_ifactm. Qed. Lemma morphpre_ifactm C : ifactm @*^-1 C = f @* (g @*^-1 C). Proof. rewrite /ifactm; case: domP => _ /= [_ _ -> _]. by rewrite morphpre_comp morphpre_invm. Qed. Lemma ker_ifactm : 'ker ifactm = f @* 'ker g. Proof. exact: morphpre_ifactm. Qed. Lemma injm_ifactm : 'injm g -> 'injm ifactm. Proof. by rewrite ker_ifactm => /trivgP->; rewrite morphim1. Qed. End InjFactm. (* Reflected (boolean) form of morphism and isomorphism properties *) Section ReflectProp. Variables aT rT : finGroupType. Section Defs. Variables (A : {set aT}) (B : {set rT}). (* morphic is the morphM property of morphisms seen through morphicP *) Definition morphic (f : aT -> rT) := [forall u in [predX A & A], f (u.1 * u.2) == f u.1 * f u.2]. Definition isom f := f @: A^# == B^#. Definition misom f := morphic f && isom f. Definition isog := [exists f : {ffun aT -> rT}, misom f]. Section MorphicProps. Variable f : aT -> rT. Lemma morphicP : reflect {in A &, {morph f : x y / x * y}} (morphic f). Proof. apply: (iffP forallP) => [fM x y Ax Ay | fM [x y] /=]. by apply/eqP; have:= fM (x, y); rewrite inE /= Ax Ay. by apply/implyP=> /andP[Ax Ay]; rewrite fM. Qed. Definition morphm of morphic f := f : aT -> FinGroup.sort rT. Lemma morphmE fM : morphm fM = f. Proof. by []. Qed. Canonical morphm_morphism fM := @Morphism _ _ A (morphm fM) (morphicP fM). End MorphicProps. Lemma misomP f : reflect {fM : morphic f & isom (morphm fM)} (misom f). Proof. by apply: (iffP andP) => [] [fM fiso] //; exists fM. Qed. Lemma misom_isog f : misom f -> isog. Proof. case/andP=> fM iso_f; apply/existsP; exists (finfun f). apply/andP; split; last by rewrite /misom /isom !(eq_imset _ (ffunE f)). apply/forallP=> u; rewrite !ffunE; exact: forallP fM u. Qed. Lemma isom_isog (D : {group aT}) (f : {morphism D >-> rT}) : A \subset D -> isom f -> isog. Proof. move=> sAD isof; apply: (@misom_isog f); rewrite /misom isof andbT. apply/morphicP; exact: (sub_in2 (subsetP sAD) (morphM f)). Qed. Lemma isog_isom : isog -> {f : {morphism A >-> rT} | isom f}. Proof. by case/existsP/sigW=> f /misomP[fM isom_f]; exists (morphm_morphism fM). Qed. End Defs. Infix "\isog" := isog. Implicit Arguments isom_isog [A B D]. (* The real reflection properties only hold for true groups and morphisms. *) Section Main. Variables (G : {group aT}) (H : {group rT}). Lemma isomP (f : {morphism G >-> rT}) : reflect ('injm f /\ f @* G = H) (isom G H f). Proof. apply: (iffP eqP) => [eqfGH | [injf <-]]; last first. by rewrite -injmD1 // morphimEsub ?subsetDl. split. apply/subsetP=> x /morphpreP[Gx fx1]; have: f x \notin H^# by rewrite inE fx1. by apply: contraR => ntx; rewrite -eqfGH mem_imset // inE ntx. rewrite morphimEdom -{2}(setD1K (group1 G)) imsetU eqfGH. by rewrite imset_set1 morph1 setD1K. Qed. Lemma isogP : reflect (exists2 f : {morphism G >-> rT}, 'injm f & f @* G = H) (G \isog H). Proof. apply: (iffP idP) => [/isog_isom[f /isomP[]] | [f injf fG]]; first by exists f. by apply: (isom_isog f) => //; apply/isomP. Qed. Variable f : {morphism G >-> rT}. Hypothesis isoGH : isom G H f. Lemma isom_inj : 'injm f. Proof. by have /isomP[] := isoGH. Qed. Lemma isom_im : f @* G = H. Proof. by have /isomP[] := isoGH. Qed. Lemma isom_card : #|G| = #|H|. Proof. by rewrite -isom_im card_injm ?isom_inj. Qed. Lemma isom_sub_im : H \subset f @* G. Proof. by rewrite isom_im. Qed. Definition isom_inv := restrm isom_sub_im (invm isom_inj). End Main. Variables (G : {group aT}) (f : {morphism G >-> rT}). Lemma morphim_isom (H : {group aT}) (K : {group rT}) : H \subset G -> isom H K f -> f @* H = K. Proof. by case/(restrmP f)=> g [gf _ _ <- //]; rewrite -gf; case/isomP. Qed. Lemma sub_isom (A : {set aT}) (C : {set rT}) : A \subset G -> f @* A = C -> 'injm f -> isom A C f. Proof. move=> sAG; case: (restrmP f sAG) => g [_ _ _ img] <-{C} injf. rewrite /isom -morphimEsub ?morphimDG ?morphim1 //. by rewrite subDset setUC subsetU ?sAG. Qed. Lemma sub_isog (A : {set aT}) : A \subset G -> 'injm f -> isog A (f @* A). Proof. by move=> sAG injf; apply: (isom_isog f sAG); exact: sub_isom. Qed. Lemma restr_isom_to (A : {set aT}) (C R : {group rT}) (sAG : A \subset G) : f @* A = C -> isom G R f -> isom A C (restrm sAG f). Proof. by move=> defC /isomP[inj_f _]; apply: sub_isom. Qed. Lemma restr_isom (A : {group aT}) (R : {group rT}) (sAG : A \subset G) : isom G R f -> isom A (f @* A) (restrm sAG f). Proof. exact: restr_isom_to. Qed. End ReflectProp. Arguments Scope isom [_ _ group_scope group_scope _]. Arguments Scope morphic [_ _ group_scope _]. Arguments Scope misom [_ _ group_scope group_scope _]. Arguments Scope isog [_ _ group_scope group_scope]. Implicit Arguments morphicP [aT rT A f]. Implicit Arguments misomP [aT rT A B f]. Implicit Arguments isom_isog [aT rT A B D]. Implicit Arguments isomP [aT rT G H f]. Implicit Arguments isogP [aT rT G H]. Prenex Implicits morphic morphicP morphm isom isog isomP misomP isogP. Notation "x \isog y":= (isog x y). Section Isomorphisms. Variables gT hT kT : finGroupType. Variables (G : {group gT}) (H : {group hT}) (K : {group kT}). Lemma idm_isom : isom G G (idm G). Proof. exact: sub_isom (im_idm G) (injm_idm G). Qed. Lemma isog_refl : G \isog G. Proof. exact: isom_isog idm_isom. Qed. Lemma card_isog : G \isog H -> #|G| = #|H|. Proof. case/isogP=> f injf <-; apply: isom_card (f) _; exact/isomP. Qed. Lemma isog_abelian : G \isog H -> abelian G = abelian H. Proof. by case/isogP=> f injf <-; rewrite injm_abelian. Qed. Lemma trivial_isog : G :=: 1 -> H :=: 1 -> G \isog H. Proof. move=> -> ->; apply/isogP. exists [morphism of @trivm gT hT 1]; rewrite /= ?morphim1 //. rewrite ker_trivm; exact: subxx. Qed. Lemma isog_eq1 : G \isog H -> (G :==: 1) = (H :==: 1). Proof. by move=> isoGH; rewrite !trivg_card1 card_isog. Qed. Lemma isom_sym (f : {morphism G >-> hT}) (isoGH : isom G H f) : isom H G (isom_inv isoGH). Proof. rewrite sub_isom 1?injm_restrm ?injm_invm // im_restrm. by rewrite -(isom_im isoGH) im_invm. Qed. Lemma isog_symr : G \isog H -> H \isog G. Proof. by case/isog_isom=> f /isom_sym/isom_isog->. Qed. Lemma isog_trans : G \isog H -> H \isog K -> G \isog K. Proof. case/isogP=> f injf <-; case/isogP=> g injg <-. have defG: f @*^-1 (f @* G) = G by rewrite morphimGK ?subsetIl. rewrite -morphim_comp -{1 8}defG. by apply/isogP; exists [morphism of g \o f]; rewrite ?injm_comp. Qed. Lemma nclasses_isog : G \isog H -> #|classes G| = #|classes H|. Proof. by case/isogP=> f injf <-; rewrite nclasses_injm. Qed. End Isomorphisms. Section IsoBoolEquiv. Variables gT hT kT : finGroupType. Variables (G : {group gT}) (H : {group hT}) (K : {group kT}). Lemma isog_sym : (G \isog H) = (H \isog G). Proof. apply/idP/idP; exact: isog_symr. Qed. Lemma isog_transl : G \isog H -> (G \isog K) = (H \isog K). Proof. by move=> iso; apply/idP/idP; apply: isog_trans; rewrite // -isog_sym. Qed. Lemma isog_transr : G \isog H -> (K \isog G) = (K \isog H). Proof. by move=> iso; apply/idP/idP; move/isog_trans; apply; rewrite // -isog_sym. Qed. End IsoBoolEquiv. Section Homg. Implicit Types rT gT aT : finGroupType. Definition homg rT aT (C : {set rT}) (D : {set aT}) := [exists (f : {ffun aT -> rT} | morphic D f), f @: D == C]. Lemma homgP rT aT (C : {set rT}) (D : {set aT}) : reflect (exists f : {morphism D >-> rT}, f @* D = C) (homg C D). Proof. apply: (iffP exists_eq_inP) => [[f fM <-] | [f <-]]. by exists (morphm_morphism fM); rewrite /morphim /= setIid. exists (finfun f); first by apply/morphicP=> x y Dx Dy; rewrite !ffunE morphM. by rewrite /morphim setIid; apply: eq_imset => x; rewrite ffunE. Qed. Lemma morphim_homg aT rT (A D : {set aT}) (f : {morphism D >-> rT}) : A \subset D -> homg (f @* A) A. Proof. move=> sAD; apply/homgP; exists (restrm_morphism sAD f). by rewrite morphim_restrm setIid. Qed. Lemma leq_homg rT aT (C : {set rT}) (G : {group aT}) : homg C G -> #|C| <= #|G|. Proof. by case/homgP=> f <-; apply: leq_morphim. Qed. Lemma homg_refl aT (A : {set aT}) : homg A A. Proof. by apply/homgP; exists (idm_morphism A); rewrite im_idm. Qed. Lemma homg_trans aT (B : {set aT}) rT (C : {set rT}) gT (G : {group gT}) : homg C B -> homg B G -> homg C G. Proof. move=> homCB homBG; case/homgP: homBG homCB => fG <- /homgP[fK <-]. by rewrite -morphim_comp morphim_homg // -sub_morphim_pre. Qed. Lemma isogEcard rT aT (G : {group rT}) (H : {group aT}) : (G \isog H) = (homg G H) && (#|H| <= #|G|). Proof. rewrite isog_sym; apply/isogP/andP=> [[f injf <-] | []]. by rewrite leq_eqVlt eq_sym card_im_injm injf morphim_homg. case/homgP=> f <-; rewrite leq_eqVlt eq_sym card_im_injm. by rewrite ltnNge leq_morphim orbF; exists f. Qed. Lemma isog_hom rT aT (G : {group rT}) (H : {group aT}) : G \isog H -> homg G H. Proof. by rewrite isogEcard; case/andP. Qed. Lemma isogEhom rT aT (G : {group rT}) (H : {group aT}) : (G \isog H) = homg G H && homg H G. Proof. apply/idP/andP=> [isoGH | [homGH homHG]]. by rewrite !isog_hom // isog_sym. by rewrite isogEcard homGH leq_homg. Qed. Lemma eq_homgl gT aT rT (G : {group gT}) (H : {group aT}) (K : {group rT}) : G \isog H -> homg G K = homg H K. Proof. by rewrite isogEhom => /andP[homGH homHG]; apply/idP/idP; exact: homg_trans. Qed. Lemma eq_homgr gT rT aT (G : {group gT}) (H : {group rT}) (K : {group aT}) : G \isog H -> homg K G = homg K H. Proof. rewrite isogEhom => /andP[homGH homHG]. by apply/idP/idP=> homK; exact: homg_trans homK _. Qed. End Homg. Arguments Scope homg [_ _ group_scope group_scope]. Notation "G \homg H" := (homg G H) (at level 70, no associativity) : group_scope. Implicit Arguments homgP [rT aT C D]. (* Isomorphism between a group and its subtype. *) Section SubMorphism. Variables (gT : finGroupType) (G : {group gT}). Canonical sgval_morphism := Morphism (@sgvalM _ G). Canonical subg_morphism := Morphism (@subgM _ G). Lemma injm_sgval : 'injm sgval. Proof. apply/injmP; apply: in2W; exact: subg_inj. Qed. Lemma injm_subg : 'injm (subg G). Proof. apply/injmP; exact: can_in_inj (@subgK _ _). Qed. Hint Resolve injm_sgval injm_subg. Lemma ker_sgval : 'ker sgval = 1. Proof. exact/trivgP. Qed. Lemma ker_subg : 'ker (subg G) = 1. Proof. exact/trivgP. Qed. Lemma im_subg : subg G @* G = [subg G]. Proof. apply/eqP; rewrite -subTset morphimEdom. by apply/subsetP=> u _; rewrite -(sgvalK u) mem_imset ?subgP. Qed. Lemma sgval_sub A : sgval @* A \subset G. Proof. apply/subsetP=> x; case/imsetP=> u _ ->; exact: subgP. Qed. Lemma sgvalmK A : subg G @* (sgval @* A) = A. Proof. apply/eqP; rewrite eqEcard !card_injm ?subsetT ?sgval_sub // leqnn andbT. rewrite -morphim_comp; apply/subsetP=> _ /morphimP[v _ Av ->] /=. by rewrite sgvalK. Qed. Lemma subgmK (A : {set gT}) : A \subset G -> sgval @* (subg G @* A) = A. Proof. move=> sAG; apply/eqP; rewrite eqEcard !card_injm ?subsetT //. rewrite leqnn andbT -morphim_comp morphimE /= morphpreT. by apply/subsetP=> _ /morphimP[v Gv Av ->] /=; rewrite subgK. Qed. Lemma im_sgval : sgval @* [subg G] = G. Proof. by rewrite -{2}im_subg subgmK. Qed. Lemma isom_subg : isom G [subg G] (subg G). Proof. by apply/isomP; rewrite im_subg. Qed. Lemma isom_sgval : isom [subg G] G sgval. Proof. by apply/isomP; rewrite im_sgval. Qed. Lemma isog_subg : isog G [subg G]. Proof. exact: isom_isog isom_subg. Qed. End SubMorphism. mathcomp-1.5/theories/prime.v0000644000175000017500000015663512307636117015326 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq path fintype. Require Import div bigop. (******************************************************************************) (* This file contains the definitions of: *) (* prime p <=> p is a prime. *) (* primes m == the sorted list of prime divisors of m > 1, else [::]. *) (* pfactor == the type of prime factors, syntax (p ^ e)%pfactor. *) (* prime_decomp m == the list of prime factors of m > 1, sorted by primes. *) (* logn p m == the e such that (p ^ e) \in prime_decomp n, else 0. *) (* trunc_log p m == the largest e such that p ^ e <= m, or 0 if p or m is 0. *) (* pdiv n == the smallest prime divisor of n > 1, else 1. *) (* max_pdiv n == the largest prime divisor of n > 1, else 1. *) (* divisors m == the sorted list of divisors of m > 0, else [::]. *) (* totient n == the Euler totient (#|{i < n | i and n coprime}|). *) (* nat_pred == the type of explicit collective nat predicates. *) (* := simpl_pred nat. *) (* -> We allow the coercion nat >-> nat_pred, interpreting p as pred1 p. *) (* -> We define a predType for nat_pred, enabling the notation p \in pi. *) (* -> We don't have nat_pred >-> pred, which would imply nat >-> Funclass. *) (* pi^' == the complement of pi : nat_pred, i.e., the nat_pred such *) (* that (p \in pi^') = (p \notin pi). *) (* \pi(n) == the set of prime divisors of n, i.e., the nat_pred such *) (* that (p \in \pi(n)) = (p \in primes n). *) (* \pi(A) == the set of primes of #|A|, with A a collective predicate *) (* over a finite Type. *) (* -> The notation \pi(A) is implemented with a collapsible Coercion, so *) (* the type of A must coerce to finpred_class (e.g., by coercing to *) (* {set T}), not merely implement the predType interface (as seq T *) (* does). *) (* -> The expression #|A| will only appear in \pi(A) after simplification *) (* collapses the coercion stack, so it is advisable to do so early on. *) (* pi.-nat n <=> n > 0 and all prime divisors of n are in pi. *) (* n`_pi == the pi-part of n -- the largest pi.-nat divisor of n. *) (* := \prod_(0 <= p < n.+1 | p \in pi) p ^ logn p n. *) (* -> The nat >-> nat_pred coercion lets us write p.-nat n and n`_p. *) (* In addition to the lemmas relevant to these definitions, this file also *) (* contains the dvdn_sum lemma, so that bigop.v doesn't depend on div.v. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. (* The complexity of any arithmetic operation with the Peano representation *) (* is pretty dreadful, so using algorithms for "harder" problems such as *) (* factoring, that are geared for efficient artihmetic leads to dismal *) (* performance -- it takes a significant time, for instance, to compute the *) (* divisors of just a two-digit number. On the other hand, for Peano *) (* integers, prime factoring (and testing) is linear-time with a small *) (* constant factor -- indeed, the same as converting in and out of a binary *) (* representation. This is implemented by the code below, which is then *) (* used to give the "standard" definitions of prime, primes, and divisors, *) (* which can then be used casually in proofs with moderately-sized numeric *) (* values (indeed, the code here performs well for up to 6-digit numbers). *) (* We start with faster mod-2 functions. *) Fixpoint edivn2 q r := if r is r'.+2 then edivn2 q.+1 r' else (q, r). Lemma edivn2P n : edivn_spec n 2 (edivn2 0 n). Proof. rewrite -[n]odd_double_half addnC -{1}[n./2]addn0 -{1}mul2n mulnC. elim: n./2 {1 4}0 => [|r IHr] q; first by case (odd n) => /=. rewrite addSnnS; exact: IHr. Qed. Fixpoint elogn2 e q r {struct q} := match q, r with | 0, _ | _, 0 => (e, q) | q'.+1, 1 => elogn2 e.+1 q' q' | q'.+1, r'.+2 => elogn2 e q' r' end. CoInductive elogn2_spec n : nat * nat -> Type := Elogn2Spec e m of n = 2 ^ e * m.*2.+1 : elogn2_spec n (e, m). Lemma elogn2P n : elogn2_spec n.+1 (elogn2 0 n n). Proof. rewrite -{1}[n.+1]mul1n -[1]/(2 ^ 0) -{1}(addKn n n) addnn. elim: n {1 4 6}n {2 3}0 (leqnn n) => [|q IHq] [|[|r]] e //=; last first. by move/ltnW; exact: IHq. clear 1; rewrite subn1 -[_.-1.+1]doubleS -mul2n mulnA -expnSr. rewrite -{1}(addKn q q) addnn; exact: IHq. Qed. Definition ifnz T n (x y : T) := if n is 0 then y else x. CoInductive ifnz_spec T n (x y : T) : T -> Type := | IfnzPos of n > 0 : ifnz_spec n x y x | IfnzZero of n = 0 : ifnz_spec n x y y. Lemma ifnzP T n (x y : T) : ifnz_spec n x y (ifnz n x y). Proof. by case: n => [|n]; [right | left]. Qed. (* For pretty-printing. *) Definition NumFactor (f : nat * nat) := ([Num of f.1], f.2). Definition pfactor p e := p ^ e. Definition cons_pfactor (p e : nat) pd := ifnz e ((p, e) :: pd) pd. Notation Local "p ^? e :: pd" := (cons_pfactor p e pd) (at level 30, e at level 30, pd at level 60) : nat_scope. Section prime_decomp. Import NatTrec. Fixpoint prime_decomp_rec m k a b c e := let p := k.*2.+1 in if a is a'.+1 then if b - (ifnz e 1 k - c) is b'.+1 then [rec m, k, a', b', ifnz c c.-1 (ifnz e p.-2 1), e] else if (b == 0) && (c == 0) then let b' := k + a' in [rec b'.*2.+3, k, a', b', k.-1, e.+1] else let bc' := ifnz e (ifnz b (k, 0) (edivn2 0 c)) (b, c) in p ^? e :: ifnz a' [rec m, k.+1, a'.-1, bc'.1 + a', bc'.2, 0] [:: (m, 1)] else if (b == 0) && (c == 0) then [:: (p, e.+2)] else p ^? e :: [:: (m, 1)] where "[ 'rec' m , k , a , b , c , e ]" := (prime_decomp_rec m k a b c e). Definition prime_decomp n := let: (e2, m2) := elogn2 0 n.-1 n.-1 in if m2 < 2 then 2 ^? e2 :: 3 ^? m2 :: [::] else let: (a, bc) := edivn m2.-2 3 in let: (b, c) := edivn (2 - bc) 2 in 2 ^? e2 :: [rec m2.*2.+1, 1, a, b, c, 0]. (* The list of divisors and the Euler function are computed directly from *) (* the decomposition, using a merge_sort variant sort the divisor list. *) Definition add_divisors f divs := let: (p, e) := f in let add1 divs' := merge leq (map (NatTrec.mul p) divs') divs in iter e add1 divs. Definition add_totient_factor f m := let: (p, e) := f in p.-1 * p ^ e.-1 * m. End prime_decomp. Definition primes n := unzip1 (prime_decomp n). Definition prime p := if prime_decomp p is [:: (_ , 1)] then true else false. Definition nat_pred := simpl_pred nat. Definition pi_unwrapped_arg := nat. Definition pi_wrapped_arg := wrapped nat. Coercion unwrap_pi_arg (wa : pi_wrapped_arg) : pi_unwrapped_arg := unwrap wa. Coercion pi_arg_of_nat (n : nat) := Wrap n : pi_wrapped_arg. Coercion pi_arg_of_fin_pred T pT (A : @fin_pred_sort T pT) : pi_wrapped_arg := Wrap #|A|. Definition pi_of (n : pi_unwrapped_arg) : nat_pred := [pred p in primes n]. Notation "\pi ( n )" := (pi_of n) (at level 2, format "\pi ( n )") : nat_scope. Notation "\p 'i' ( A )" := \pi(#|A|) (at level 2, format "\p 'i' ( A )") : nat_scope. Definition pdiv n := head 1 (primes n). Definition max_pdiv n := last 1 (primes n). Definition divisors n := foldr add_divisors [:: 1] (prime_decomp n). Definition totient n := foldr add_totient_factor (n > 0) (prime_decomp n). (* Correctness of the decomposition algorithm. *) Lemma prime_decomp_correct : let pd_val pd := \prod_(f <- pd) pfactor f.1 f.2 in let lb_dvd q m := ~~ has [pred d | d %| m] (index_iota 2 q) in let pf_ok f := lb_dvd f.1 f.1 && (0 < f.2) in let pd_ord q pd := path ltn q (unzip1 pd) in let pd_ok q n pd := [/\ n = pd_val pd, all pf_ok pd & pd_ord q pd] in forall n, n > 0 -> pd_ok 1 n (prime_decomp n). Proof. rewrite unlock => pd_val lb_dvd pf_ok pd_ord pd_ok. have leq_pd_ok m p q pd: q <= p -> pd_ok p m pd -> pd_ok q m pd. rewrite /pd_ok /pd_ord; case: pd => [|[r _] pd] //= leqp [<- ->]. by case/andP=> /(leq_trans _)->. have apd_ok m e q p pd: lb_dvd p p || (e == 0) -> q < p -> pd_ok p m pd -> pd_ok q (p ^ e * m) (p ^? e :: pd). - case: e => [|e]; rewrite orbC /= => pr_p ltqp. rewrite mul1n; apply: leq_pd_ok; exact: ltnW. by rewrite /pd_ok /pd_ord /pf_ok /= pr_p ltqp => [[<- -> ->]]. case=> // n _; rewrite /prime_decomp. case: elogn2P => e2 m2 -> {n}; case: m2 => [|[|abc]]; try exact: apd_ok. rewrite [_.-2]/= !ltnS ltn0 natTrecE; case: edivnP => a bc ->{abc}. case: edivnP => b c def_bc /= ltc2 ltbc3; apply: (apd_ok) => //. move def_m: _.*2.+1 => m; set k := {2}1; rewrite -[2]/k.*2; set e := 0. pose p := k.*2.+1; rewrite -{1}[m]mul1n -[1]/(p ^ e)%N. have{def_m bc def_bc ltc2 ltbc3}: let kb := (ifnz e k 1).*2 in [&& k > 0, p < m, lb_dvd p m, c < kb & lb_dvd p p || (e == 0)] /\ m + (b * kb + c).*2 = p ^ 2 + (a * p).*2. - rewrite -{-2}def_m; split=> //=; last first. by rewrite -def_bc addSn -doubleD 2!addSn -addnA subnKC // addnC. rewrite ltc2 /lb_dvd /index_iota /= dvdn2 -def_m. by rewrite [_.+2]lock /= odd_double. move: {2}a.+1 (ltnSn a) => n; clearbody k e. elim: n => // n IHn in a k p m b c e *; rewrite ltnS => le_a_n []. set kb := _.*2; set d := _ + c => /and5P[lt0k ltpm leppm ltc pr_p def_m]. have def_k1: k.-1.+1 = k := ltn_predK lt0k. have def_kb1: kb.-1.+1 = kb by rewrite /kb -def_k1; case e. have eq_bc_0: (b == 0) && (c == 0) = (d == 0). by rewrite addn_eq0 muln_eq0 orbC -def_kb1. have lt1p: 1 < p by rewrite ltnS double_gt0. have co_p_2: coprime p 2 by rewrite /coprime gcdnC gcdnE modn2 /= odd_double. have if_d0: d = 0 -> [/\ m = (p + a.*2) * p, lb_dvd p p & lb_dvd p (p + a.*2)]. move=> d0; have{d0 def_m} def_m: m = (p + a.*2) * p. by rewrite d0 addn0 -mulnn -!mul2n mulnA -mulnDl in def_m *. split=> //; apply/hasPn=> r /(hasPn leppm); apply: contra => /= dv_r. by rewrite def_m dvdn_mull. by rewrite def_m dvdn_mulr. case def_a: a => [|a'] /= in le_a_n *; rewrite !natTrecE -/p {}eq_bc_0. case: d if_d0 def_m => [[//| def_m {pr_p}pr_p pr_m'] _ | d _ def_m] /=. rewrite def_m def_a addn0 mulnA -2!expnSr. by split; rewrite /pd_ord /pf_ok /= ?muln1 ?pr_p ?leqnn. apply: apd_ok; rewrite // /pd_ok /= /pfactor expn1 muln1 /pd_ord /= ltpm. rewrite /pf_ok !andbT /=; split=> //; apply: contra leppm. case/hasP=> r /=; rewrite mem_index_iota => /andP[lt1r ltrm] dvrm; apply/hasP. have [ltrp | lepr] := ltnP r p. by exists r; rewrite // mem_index_iota lt1r. case/dvdnP: dvrm => q def_q; exists q; last by rewrite def_q /= dvdn_mulr. rewrite mem_index_iota -(ltn_pmul2r (ltnW lt1r)) -def_q mul1n ltrm. move: def_m; rewrite def_a addn0 -(@ltn_pmul2r p) // mulnn => <-. apply: (@leq_ltn_trans m); first by rewrite def_q leq_mul. by rewrite -addn1 leq_add2l. have def_k2: k.*2 = ifnz e 1 k * kb. by rewrite /kb; case: (e) => [|e']; rewrite (mul1n, muln2). case def_b': (b - _) => [|b']; last first. have ->: ifnz e k.*2.-1 1 = kb.-1 by rewrite /kb; case e. apply: IHn => {n le_a_n}//; rewrite -/p -/kb; split=> //. rewrite lt0k ltpm leppm pr_p andbT /=. by case: ifnzP; [move/ltn_predK->; exact: ltnW | rewrite def_kb1]. apply: (@addIn p.*2). rewrite -2!addnA -!doubleD -addnA -mulSnr -def_a -def_m /d. have ->: b * kb = b' * kb + (k.*2 - c * kb + kb). rewrite addnCA addnC -mulSnr -def_b' def_k2 -mulnBl -mulnDl subnK //. by rewrite ltnW // -subn_gt0 def_b'. rewrite -addnA; congr (_ + (_ + _).*2). case: (c) ltc; first by rewrite -addSnnS def_kb1 subn0 addn0 addnC. rewrite /kb; case e => [[] // _ | e' c' _] /=; last first. by rewrite subnDA subnn addnC addSnnS. by rewrite mul1n -doubleB -doubleD subn1 !addn1 def_k1. have ltdp: d < p. move/eqP: def_b'; rewrite subn_eq0 -(@leq_pmul2r kb); last first. by rewrite -def_kb1. rewrite mulnBl -def_k2 ltnS -(leq_add2r c); move/leq_trans; apply. have{ltc} ltc: c < k.*2. by apply: (leq_trans ltc); rewrite leq_double /kb; case e. rewrite -{2}(subnK (ltnW ltc)) leq_add2r leq_sub2l //. by rewrite -def_kb1 mulnS leq_addr. case def_d: d if_d0 => [|d'] => [[//|{def_m ltdp pr_p} def_m pr_p pr_m'] | _]. rewrite eqxx -doubleS -addnS -def_a doubleD -addSn -/p def_m. rewrite mulnCA mulnC -expnSr. apply: IHn => {n le_a_n}//; rewrite -/p -/kb; split. rewrite lt0k -addn1 leq_add2l {1}def_a pr_m' pr_p /= def_k1 -addnn. by rewrite leq_addr. rewrite -addnA -doubleD addnCA def_a addSnnS def_k1 -(addnC k) -mulnSr. rewrite -[_.*2.+1]/p mulnDl doubleD addnA -mul2n mulnA mul2n -mulSn. by rewrite -/p mulnn. have next_pm: lb_dvd p.+2 m. rewrite /lb_dvd /index_iota 2!subSS subn0 -(subnK lt1p) iota_add. rewrite has_cat; apply/norP; split=> //=; rewrite orbF subnKC // orbC. apply/norP; split; apply/dvdnP=> [[q def_q]]. case/hasP: leppm; exists 2; first by rewrite /p -(subnKC lt0k). by rewrite /= def_q dvdn_mull // dvdn2 /= odd_double. move/(congr1 (dvdn p)): def_m; rewrite -mulnn -!mul2n mulnA -mulnDl. rewrite dvdn_mull // dvdn_addr; last by rewrite def_q dvdn_mull. case/dvdnP=> r; rewrite mul2n => def_r; move: ltdp (congr1 odd def_r). rewrite odd_double -ltn_double {1}def_r -mul2n ltn_pmul2r //. by case: r def_r => [|[|[]]] //; rewrite def_d // mul1n /= odd_double. apply: apd_ok => //; case: a' def_a le_a_n => [|a'] def_a => [_ | lta] /=. rewrite /pd_ok /= /pfactor expn1 muln1 /pd_ord /= ltpm /pf_ok !andbT /=. split=> //; apply: contra next_pm. case/hasP=> q; rewrite mem_index_iota => /andP[lt1q ltqm] dvqm; apply/hasP. have [ltqp | lepq] := ltnP q p.+2. by exists q; rewrite // mem_index_iota lt1q. case/dvdnP: dvqm => r def_r; exists r; last by rewrite def_r /= dvdn_mulr. rewrite mem_index_iota -(ltn_pmul2r (ltnW lt1q)) -def_r mul1n ltqm /=. rewrite -(@ltn_pmul2l p.+2) //; apply: (@leq_ltn_trans m). by rewrite def_r mulnC leq_mul. rewrite -addn2 mulnn sqrnD mul2n muln2 -addnn addnCA -addnA addnCA addnA. by rewrite def_a mul1n in def_m; rewrite -def_m addnS -addnA ltnS leq_addr. set bc := ifnz _ _ _; apply: leq_pd_ok (leqnSn _) _. rewrite -doubleS -{1}[m]mul1n -[1]/(k.+1.*2.+1 ^ 0)%N. apply: IHn; first exact: ltnW. rewrite doubleS -/p [ifnz 0 _ _]/=; do 2?split => //. rewrite orbT next_pm /= -(leq_add2r d.*2) def_m 2!addSnnS -doubleS leq_add. - move: ltc; rewrite /kb {}/bc andbT; case e => //= e' _; case: ifnzP => //. by case: edivn2P. - by rewrite -{1}[p]muln1 -mulnn ltn_pmul2l. by rewrite leq_double def_a mulSn (leq_trans ltdp) ?leq_addr. rewrite mulnDl !muln2 -addnA addnCA doubleD addnCA. rewrite (_ : _ + bc.2 = d); last first. rewrite /d {}/bc /kb -muln2. case: (e) (b) def_b' => //= _ []; first by case: edivn2P. by case c; do 2?case; rewrite // mul1n /= muln2. rewrite def_m 3!doubleS addnC -(addn2 p) sqrnD mul2n muln2 -3!addnA. congr (_ + _); rewrite 4!addnS -!doubleD; congr _.*2.+2.+2. by rewrite def_a -add2n mulnDl -addnA -muln2 -mulnDr mul2n. Qed. Lemma primePn n : reflect (n < 2 \/ exists2 d, 1 < d < n & d %| n) (~~ prime n). Proof. rewrite /prime; case: n => [|[|p2]]; try by do 2!left. case: (@prime_decomp_correct p2.+2) => //; rewrite unlock. case: prime_decomp => [|[q [|[|e]]] pd] //=; last first; last by rewrite andbF. rewrite {1}/pfactor 2!expnS -!mulnA /=. case: (_ ^ _ * _) => [|u -> _ /andP[lt1q _]]; first by rewrite !muln0. left; right; exists q; last by rewrite dvdn_mulr. have lt0q := ltnW lt1q; rewrite lt1q -{1}[q]muln1 ltn_pmul2l //. by rewrite -[2]muln1 leq_mul. rewrite {1}/pfactor expn1; case: pd => [|[r e] pd] /=; last first. case: e => [|e] /=; first by rewrite !andbF. rewrite {1}/pfactor expnS -mulnA. case: (_ ^ _ * _) => [|u -> _ /and3P[lt1q ltqr _]]; first by rewrite !muln0. left; right; exists q; last by rewrite dvdn_mulr. by rewrite lt1q -{1}[q]mul1n ltn_mul // -[q.+1]muln1 leq_mul. rewrite muln1 !andbT => def_q pr_q lt1q; right=> [[]] // [d]. by rewrite def_q -mem_index_iota => in_d_2q dv_d_q; case/hasP: pr_q; exists d. Qed. Lemma primeP p : reflect (p > 1 /\ forall d, d %| p -> xpred2 1 p d) (prime p). Proof. rewrite -[prime p]negbK; have [npr_p | pr_p] := primePn p. right=> [[lt1p pr_p]]; case: npr_p => [|[d n1pd]]. by rewrite ltnNge lt1p. by move/pr_p=> /orP[] /eqP def_d; rewrite def_d ltnn ?andbF in n1pd. have [lep1 | lt1p] := leqP; first by case: pr_p; left. left; split=> // d dv_d_p; apply/norP=> [[nd1 ndp]]; case: pr_p; right. exists d; rewrite // andbC 2!ltn_neqAle ndp eq_sym nd1. by have lt0p := ltnW lt1p; rewrite dvdn_leq // (dvdn_gt0 lt0p). Qed. Lemma prime_nt_dvdP d p : prime p -> d != 1 -> reflect (d = p) (d %| p). Proof. case/primeP=> _ min_p d_neq1; apply: (iffP idP) => [/min_p|-> //]. by rewrite (negPf d_neq1) /= => /eqP. Qed. Implicit Arguments primeP [p]. Implicit Arguments primePn [n]. Prenex Implicits primePn primeP. Lemma prime_gt1 p : prime p -> 1 < p. Proof. by case/primeP. Qed. Lemma prime_gt0 p : prime p -> 0 < p. Proof. by move/prime_gt1; exact: ltnW. Qed. Hint Resolve prime_gt1 prime_gt0. Lemma prod_prime_decomp n : n > 0 -> n = \prod_(f <- prime_decomp n) f.1 ^ f.2. Proof. by case/prime_decomp_correct. Qed. Lemma even_prime p : prime p -> p = 2 \/ odd p. Proof. move=> pr_p; case odd_p: (odd p); [by right | left]. have: 2 %| p by rewrite dvdn2 odd_p. by case/primeP: pr_p => _ dv_p /dv_p/(2 =P p). Qed. Lemma prime_oddPn p : prime p -> reflect (p = 2) (~~ odd p). Proof. by move=> p_pr; apply: (iffP idP) => [|-> //]; case/even_prime: p_pr => ->. Qed. Lemma odd_prime_gt2 p : odd p -> prime p -> p > 2. Proof. by move=> odd_p /prime_gt1; apply: odd_gt2. Qed. Lemma mem_prime_decomp n p e : (p, e) \in prime_decomp n -> [/\ prime p, e > 0 & p ^ e %| n]. Proof. case: (posnP n) => [-> //| /prime_decomp_correct[def_n mem_pd ord_pd pd_pe]]. have /andP[pr_p ->] := allP mem_pd _ pd_pe; split=> //; last first. case/splitPr: pd_pe def_n => pd1 pd2 ->. by rewrite big_cat big_cons /= mulnCA dvdn_mulr. have lt1p: 1 < p. apply: (allP (order_path_min ltn_trans ord_pd)). by apply/mapP; exists (p, e). apply/primeP; split=> // d dv_d_p; apply/norP=> [[nd1 ndp]]. case/hasP: pr_p; exists d => //. rewrite mem_index_iota andbC 2!ltn_neqAle ndp eq_sym nd1. by have lt0p := ltnW lt1p; rewrite dvdn_leq // (dvdn_gt0 lt0p). Qed. Lemma prime_coprime p m : prime p -> coprime p m = ~~ (p %| m). Proof. case/primeP=> p_gt1 p_pr; apply/eqP/negP=> [d1 | ndv_pm]. case/dvdnP=> k def_m; rewrite -(addn0 m) def_m gcdnMDl gcdn0 in d1. by rewrite d1 in p_gt1. by apply: gcdn_def => // d /p_pr /orP[] /eqP->. Qed. Lemma dvdn_prime2 p q : prime p -> prime q -> (p %| q) = (p == q). Proof. move=> pr_p pr_q; apply: negb_inj. by rewrite eqn_dvd negb_and -!prime_coprime // coprime_sym orbb. Qed. Lemma Euclid_dvdM m n p : prime p -> (p %| m * n) = (p %| m) || (p %| n). Proof. move=> pr_p; case dv_pm: (p %| m); first exact: dvdn_mulr. by rewrite Gauss_dvdr // prime_coprime // dv_pm. Qed. Lemma Euclid_dvd1 p : prime p -> (p %| 1) = false. Proof. by rewrite dvdn1; case: eqP => // ->. Qed. Lemma Euclid_dvdX m n p : prime p -> (p %| m ^ n) = (p %| m) && (n > 0). Proof. case: n => [|n] pr_p; first by rewrite andbF Euclid_dvd1. by apply: (inv_inj negbK); rewrite !andbT -!prime_coprime // coprime_pexpr. Qed. Lemma mem_primes p n : (p \in primes n) = [&& prime p, n > 0 & p %| n]. Proof. rewrite andbCA; case: posnP => [-> // | /= n_gt0]. apply/mapP/andP=> [[[q e]]|[pr_p]] /=. case/mem_prime_decomp=> pr_q e_gt0; case/dvdnP=> u -> -> {p}. by rewrite -(prednK e_gt0) expnS mulnCA dvdn_mulr. rewrite {1}(prod_prime_decomp n_gt0) big_seq. apply big_ind => [| u v IHu IHv | [q e] /= mem_qe dv_p_qe]. - by rewrite Euclid_dvd1. - by rewrite Euclid_dvdM // => /orP[]. exists (q, e) => //=; case/mem_prime_decomp: mem_qe => pr_q _ _. by rewrite Euclid_dvdX // dvdn_prime2 // in dv_p_qe; case: eqP dv_p_qe. Qed. Lemma sorted_primes n : sorted ltn (primes n). Proof. by case: (posnP n) => [-> // | /prime_decomp_correct[_ _]]; exact: path_sorted. Qed. Lemma eq_primes m n : (primes m =i primes n) <-> (primes m = primes n). Proof. split=> [eqpr| -> //]. by apply: (eq_sorted_irr ltn_trans ltnn); rewrite ?sorted_primes. Qed. Lemma primes_uniq n : uniq (primes n). Proof. exact: (sorted_uniq ltn_trans ltnn (sorted_primes n)). Qed. (* The smallest prime divisor *) Lemma pi_pdiv n : (pdiv n \in \pi(n)) = (n > 1). Proof. case: n => [|[|n]] //; rewrite /pdiv !inE /primes. have:= prod_prime_decomp (ltn0Sn n.+1); rewrite unlock. by case: prime_decomp => //= pf pd _; rewrite mem_head. Qed. Lemma pdiv_prime n : 1 < n -> prime (pdiv n). Proof. by rewrite -pi_pdiv mem_primes; case/and3P. Qed. Lemma pdiv_dvd n : pdiv n %| n. Proof. by case: n (pi_pdiv n) => [|[|n]] //; rewrite mem_primes=> /and3P[]. Qed. Lemma pi_max_pdiv n : (max_pdiv n \in \pi(n)) = (n > 1). Proof. rewrite !inE -pi_pdiv /max_pdiv /pdiv !inE. by case: (primes n) => //= p ps; rewrite mem_head mem_last. Qed. Lemma max_pdiv_prime n : n > 1 -> prime (max_pdiv n). Proof. by rewrite -pi_max_pdiv mem_primes => /andP[]. Qed. Lemma max_pdiv_dvd n : max_pdiv n %| n. Proof. by case: n (pi_max_pdiv n) => [|[|n]] //; rewrite mem_primes => /andP[]. Qed. Lemma pdiv_leq n : 0 < n -> pdiv n <= n. Proof. by move=> n_gt0; rewrite dvdn_leq // pdiv_dvd. Qed. Lemma max_pdiv_leq n : 0 < n -> max_pdiv n <= n. Proof. by move=> n_gt0; rewrite dvdn_leq // max_pdiv_dvd. Qed. Lemma pdiv_gt0 n : 0 < pdiv n. Proof. by case: n => [|[|n]] //; rewrite prime_gt0 ?pdiv_prime. Qed. Lemma max_pdiv_gt0 n : 0 < max_pdiv n. Proof. by case: n => [|[|n]] //; rewrite prime_gt0 ?max_pdiv_prime. Qed. Hint Resolve pdiv_gt0 max_pdiv_gt0. Lemma pdiv_min_dvd m d : 1 < d -> d %| m -> pdiv m <= d. Proof. move=> lt1d dv_d_m; case: (posnP m) => [->|mpos]; first exact: ltnW. rewrite /pdiv; apply: leq_trans (pdiv_leq (ltnW lt1d)). have: pdiv d \in primes m. by rewrite mem_primes mpos pdiv_prime // (dvdn_trans (pdiv_dvd d)). case: (primes m) (sorted_primes m) => //= p pm ord_pm. rewrite inE => /predU1P[-> //|]. move/(allP (order_path_min ltn_trans ord_pm)); exact: ltnW. Qed. Lemma max_pdiv_max n p : p \in \pi(n) -> p <= max_pdiv n. Proof. rewrite /max_pdiv !inE => n_p. case/splitPr: n_p (sorted_primes n) => p1 p2; rewrite last_cat -cat_rcons /=. rewrite headI /= cat_path -(last_cons 0) -headI last_rcons; case/andP=> _. move/(order_path_min ltn_trans); case/lastP: p2 => //= p2 q. by rewrite all_rcons last_rcons ltn_neqAle -andbA => /and3P[]. Qed. Lemma ltn_pdiv2_prime n : 0 < n -> n < pdiv n ^ 2 -> prime n. Proof. case def_n: n => [|[|n']] // _; rewrite -def_n => lt_n_p2. suffices ->: n = pdiv n by rewrite pdiv_prime ?def_n. apply/eqP; rewrite eqn_leq leqNgt andbC pdiv_leq; last by rewrite def_n. move: lt_n_p2; rewrite ltnNge; apply: contra => lt_pm_m. case/dvdnP: (pdiv_dvd n) => q def_q. rewrite {2}def_q -mulnn leq_pmul2r // pdiv_min_dvd //. by rewrite -[pdiv n]mul1n {2}def_q ltn_pmul2r in lt_pm_m. by rewrite def_q dvdn_mulr. Qed. Lemma primePns n : reflect (n < 2 \/ exists p, [/\ prime p, p ^ 2 <= n & p %| n]) (~~ prime n). Proof. apply: (iffP idP) => [npr_p|]; last first. case=> [|[p [pr_p le_p2_n dv_p_n]]]; first by case: n => [|[]]. apply/negP=> pr_n; move: dv_p_n le_p2_n; rewrite dvdn_prime2 //; move/eqP->. by rewrite leqNgt -{1}[n]muln1 -mulnn ltn_pmul2l ?prime_gt1 ?prime_gt0. case: leqP => [lt1p|]; [right | by left]. exists (pdiv n); rewrite pdiv_dvd pdiv_prime //; split=> //. by case: leqP npr_p => //; move/ltn_pdiv2_prime->; auto. Qed. Implicit Arguments primePns [n]. Prenex Implicits primePns. Lemma pdivP n : n > 1 -> {p | prime p & p %| n}. Proof. by move=> lt1n; exists (pdiv n); rewrite ?pdiv_dvd ?pdiv_prime. Qed. Lemma primes_mul m n p : m > 0 -> n > 0 -> (p \in primes (m * n)) = (p \in primes m) || (p \in primes n). Proof. move=> m_gt0 n_gt0; rewrite !mem_primes muln_gt0 m_gt0 n_gt0. by case pr_p: (prime p); rewrite // Euclid_dvdM. Qed. Lemma primes_exp m n : n > 0 -> primes (m ^ n) = primes m. Proof. case: n => // n _; rewrite expnS; case: (posnP m) => [-> //| m_gt0]. apply/eq_primes => /= p; elim: n => [|n IHn]; first by rewrite muln1. by rewrite primes_mul ?(expn_gt0, expnS, IHn, orbb, m_gt0). Qed. Lemma primes_prime p : prime p -> primes p = [::p]. Proof. move=> pr_p; apply: (eq_sorted_irr ltn_trans ltnn) => // [|q]. exact: sorted_primes. rewrite mem_seq1 mem_primes prime_gt0 //=. by apply/andP/idP=> [[pr_q q_p] | /eqP-> //]; rewrite -dvdn_prime2. Qed. Lemma coprime_has_primes m n : m > 0 -> n > 0 -> coprime m n = ~~ has (mem (primes m)) (primes n). Proof. move=> m_gt0 n_gt0; apply/eqnP/hasPn=> [mn1 p | no_p_mn]. rewrite /= !mem_primes m_gt0 n_gt0 /= => /andP[pr_p p_n]. have:= prime_gt1 pr_p; rewrite pr_p ltnNge -mn1 /=; apply: contra => p_m. by rewrite dvdn_leq ?gcdn_gt0 ?m_gt0 // dvdn_gcd ?p_m. case: (ltngtP (gcdn m n) 1) => //; first by rewrite ltnNge gcdn_gt0 ?m_gt0. move/pdiv_prime; set p := pdiv _ => pr_p. move/implyP: (no_p_mn p); rewrite /= !mem_primes m_gt0 n_gt0 pr_p /=. by rewrite !(dvdn_trans (pdiv_dvd _)) // (dvdn_gcdl, dvdn_gcdr). Qed. Lemma pdiv_id p : prime p -> pdiv p = p. Proof. by move=> p_pr; rewrite /pdiv primes_prime. Qed. Lemma pdiv_pfactor p k : prime p -> pdiv (p ^ k.+1) = p. Proof. by move=> p_pr; rewrite /pdiv primes_exp ?primes_prime. Qed. (* "prime" logarithms and p-parts. *) Fixpoint logn_rec d m r := match r, edivn m d with | r'.+1, (_.+1 as m', 0) => (logn_rec d m' r').+1 | _, _ => 0 end. Definition logn p m := if prime p then logn_rec p m m else 0. Lemma lognE p m : logn p m = if [&& prime p, 0 < m & p %| m] then (logn p (m %/ p)).+1 else 0. Proof. rewrite /logn /dvdn; case p_pr: (prime p) => //. rewrite /divn modn_def; case def_m: {2 3}m => [|m'] //=. case: edivnP def_m => [[|q] [|r] -> _] // def_m; congr _.+1; rewrite [_.1]/=. have{m def_m}: q < m'. by rewrite -ltnS -def_m addn0 mulnC -{1}[q.+1]mul1n ltn_pmul2r // prime_gt1. elim: {m' q}_.+1 {-2}m' q.+1 (ltnSn m') (ltn0Sn q) => // s IHs. case=> [[]|r] //= m; rewrite ltnS => lt_rs m_gt0 le_mr. rewrite -{3}[m]prednK //=; case: edivnP => [[|q] [|_] def_q _] //. have{def_q} lt_qm': q < m.-1. by rewrite -[q.+1]muln1 -ltnS prednK // def_q addn0 ltn_pmul2l // prime_gt1. have{le_mr} le_m'r: m.-1 <= r by rewrite -ltnS prednK. by rewrite (IHs r) ?(IHs m.-1) // ?(leq_trans lt_qm', leq_trans _ lt_rs). Qed. Lemma logn_gt0 p n : (0 < logn p n) = (p \in primes n). Proof. by rewrite lognE -mem_primes; case: {+}(p \in _). Qed. Lemma ltn_log0 p n : n < p -> logn p n = 0. Proof. by case: n => [|n] ltnp; rewrite lognE ?andbF // gtnNdvd ?andbF. Qed. Lemma logn0 p : logn p 0 = 0. Proof. by rewrite /logn if_same. Qed. Lemma logn1 p : logn p 1 = 0. Proof. by rewrite lognE dvdn1 /= andbC; case: eqP => // ->. Qed. Lemma pfactor_gt0 p n : 0 < p ^ logn p n. Proof. by rewrite expn_gt0 lognE; case: (posnP p) => // ->. Qed. Hint Resolve pfactor_gt0. Lemma pfactor_dvdn p n m : prime p -> m > 0 -> (p ^ n %| m) = (n <= logn p m). Proof. move=> p_pr; elim: n m => [|n IHn] m m_gt0; first exact: dvd1n. rewrite lognE p_pr m_gt0 /=; case dv_pm: (p %| m); last first. apply/dvdnP=> [] [/= q def_m]. by rewrite def_m expnS mulnCA dvdn_mulr in dv_pm. case/dvdnP: dv_pm m_gt0 => q ->{m}; rewrite muln_gt0 => /andP[p_gt0 q_gt0]. by rewrite expnSr dvdn_pmul2r // mulnK // IHn. Qed. Lemma pfactor_dvdnn p n : p ^ logn p n %| n. Proof. case: n => // n; case pr_p: (prime p); first by rewrite pfactor_dvdn. by rewrite lognE pr_p dvd1n. Qed. Lemma logn_prime p q : prime q -> logn p q = (p == q). Proof. move=> pr_q; have q_gt0 := prime_gt0 pr_q; rewrite lognE q_gt0 /=. case pr_p: (prime p); last by case: eqP pr_p pr_q => // -> ->. by rewrite dvdn_prime2 //; case: eqP => // ->; rewrite divnn q_gt0 logn1. Qed. Lemma pfactor_coprime p n : prime p -> n > 0 -> {m | coprime p m & n = m * p ^ logn p n}. Proof. move=> p_pr n_gt0; set k := logn p n. have dv_pk_n: p ^ k %| n by rewrite pfactor_dvdn. exists (n %/ p ^ k); last by rewrite divnK. rewrite prime_coprime // -(@dvdn_pmul2r (p ^ k)) ?expn_gt0 ?prime_gt0 //. by rewrite -expnS divnK // pfactor_dvdn // ltnn. Qed. Lemma pfactorK p n : prime p -> logn p (p ^ n) = n. Proof. move=> p_pr; have pn_gt0: p ^ n > 0 by rewrite expn_gt0 prime_gt0. apply/eqP; rewrite eqn_leq -pfactor_dvdn // dvdnn andbT. by rewrite -(leq_exp2l _ _ (prime_gt1 p_pr)) dvdn_leq // pfactor_dvdn. Qed. Lemma pfactorKpdiv p n : prime p -> logn (pdiv (p ^ n)) (p ^ n) = n. Proof. by case: n => // n p_pr; rewrite pdiv_pfactor ?pfactorK. Qed. Lemma dvdn_leq_log p m n : 0 < n -> m %| n -> logn p m <= logn p n. Proof. move=> n_gt0 dv_m_n; have m_gt0 := dvdn_gt0 n_gt0 dv_m_n. case p_pr: (prime p); last by do 2!rewrite lognE p_pr /=. by rewrite -pfactor_dvdn //; apply: dvdn_trans dv_m_n; rewrite pfactor_dvdn. Qed. Lemma ltn_logl p n : 0 < n -> logn p n < n. Proof. move=> n_gt0; have [p_gt1 | p_le1] := boolP (1 < p). by rewrite (leq_trans (ltn_expl _ p_gt1)) // dvdn_leq ?pfactor_dvdnn. by rewrite lognE (contraNF (@prime_gt1 _)). Qed. Lemma logn_Gauss p m n : coprime p m -> logn p (m * n) = logn p n. Proof. move=> co_pm; case p_pr: (prime p); last by rewrite /logn p_pr. have [-> | n_gt0] := posnP n; first by rewrite muln0. have [m0 | m_gt0] := posnP m; first by rewrite m0 prime_coprime ?dvdn0 in co_pm. have mn_gt0: m * n > 0 by rewrite muln_gt0 m_gt0. apply/eqP; rewrite eqn_leq andbC dvdn_leq_log ?dvdn_mull //. set k := logn p _; have: p ^ k %| m * n by rewrite pfactor_dvdn. by rewrite Gauss_dvdr ?coprime_expl // -pfactor_dvdn. Qed. Lemma lognM p m n : 0 < m -> 0 < n -> logn p (m * n) = logn p m + logn p n. Proof. case p_pr: (prime p); last by rewrite /logn p_pr. have xlp := pfactor_coprime p_pr. case/xlp=> m' co_m' def_m /xlp[n' co_n' def_n] {xlp}. by rewrite {1}def_m {1}def_n mulnCA -mulnA -expnD !logn_Gauss // pfactorK. Qed. Lemma lognX p m n : logn p (m ^ n) = n * logn p m. Proof. case p_pr: (prime p); last by rewrite /logn p_pr muln0. elim: n => [|n IHn]; first by rewrite logn1. have [->|m_gt0] := posnP m; first by rewrite exp0n // lognE andbF muln0. by rewrite expnS lognM ?IHn // expn_gt0 m_gt0. Qed. Lemma logn_div p m n : m %| n -> logn p (n %/ m) = logn p n - logn p m. Proof. rewrite dvdn_eq => /eqP def_n. case: (posnP n) => [-> |]; first by rewrite div0n logn0. by rewrite -{1 3}def_n muln_gt0 => /andP[q_gt0 m_gt0]; rewrite lognM ?addnK. Qed. Lemma dvdn_pfactor p d n : prime p -> reflect (exists2 m, m <= n & d = p ^ m) (d %| p ^ n). Proof. move=> p_pr; have pn_gt0: p ^ n > 0 by rewrite expn_gt0 prime_gt0. apply: (iffP idP) => [dv_d_pn|[m le_m_n ->]]; last first. by rewrite -(subnK le_m_n) expnD dvdn_mull. exists (logn p d); first by rewrite -(pfactorK n p_pr) dvdn_leq_log. have d_gt0: d > 0 by exact: dvdn_gt0 dv_d_pn. case: (pfactor_coprime p_pr d_gt0) => q co_p_q def_d. rewrite {1}def_d ((q =P 1) _) ?mul1n // -dvdn1. suff: q %| p ^ n * 1 by rewrite Gauss_dvdr // coprime_sym coprime_expl. by rewrite muln1 (dvdn_trans _ dv_d_pn) // def_d dvdn_mulr. Qed. Lemma prime_decompE n : prime_decomp n = [seq (p, logn p n) | p <- primes n]. Proof. case: n => // n; pose f0 := (0, 0); rewrite -map_comp. apply: (@eq_from_nth _ f0) => [|i lt_i_n]; first by rewrite size_map. rewrite (nth_map f0) //; case def_f: (nth _ _ i) => [p e] /=. congr (_, _); rewrite [n.+1]prod_prime_decomp //. have: (p, e) \in prime_decomp n.+1 by rewrite -def_f mem_nth. case/mem_prime_decomp=> pr_p _ _. rewrite (big_nth f0) big_mkord (bigD1 (Ordinal lt_i_n)) //=. rewrite def_f mulnC logn_Gauss ?pfactorK //. apply big_ind => [|m1 m2 com1 com2| [j ltj] /=]; first exact: coprimen1. by rewrite coprime_mulr com1. rewrite -val_eqE /= => nji; case def_j: (nth _ _ j) => [q e1] /=. have: (q, e1) \in prime_decomp n.+1 by rewrite -def_j mem_nth. case/mem_prime_decomp=> pr_q e1_gt0 _; rewrite coprime_pexpr //. rewrite prime_coprime // dvdn_prime2 //; apply: contra nji => eq_pq. rewrite -(nth_uniq 0 _ _ (primes_uniq n.+1)) ?size_map //=. by rewrite !(nth_map f0) // def_f def_j /= eq_sym. Qed. (* Some combinatorial formulae. *) Lemma divn_count_dvd d n : n %/ d = \sum_(1 <= i < n.+1) (d %| i). Proof. have [-> | d_gt0] := posnP d; first by rewrite big_add1 divn0 big1. apply: (@addnI (d %| 0)); rewrite -(@big_ltn _ 0 _ 0 _ (dvdn d)) // big_mkord. rewrite (partition_big (fun i : 'I_n.+1 => inord (i %/ d)) 'I_(n %/ d).+1) //=. rewrite dvdn0 add1n -{1}[_.+1]card_ord -sum1_card; apply: eq_bigr => [[q ?] _]. rewrite (bigD1 (inord (q * d))) /eq_op /= !inordK ?ltnS -?leq_divRL ?mulnK //. rewrite dvdn_mull ?big1 // => [[i /= ?] /andP[/eqP <- /negPf]]. by rewrite eq_sym dvdn_eq inordK ?ltnS ?leq_div2r // => ->. Qed. Lemma logn_count_dvd p n : prime p -> logn p n = \sum_(1 <= k < n) (p ^ k %| n). Proof. rewrite big_add1 => p_prime; case: n => [|n]; first by rewrite logn0 big_geq. rewrite big_mkord -big_mkcond (eq_bigl _ _ (fun _ => pfactor_dvdn _ _ _)) //=. by rewrite big_ord_narrow ?sum1_card ?card_ord // -ltnS ltn_logl. Qed. (* Truncated real log. *) Definition trunc_log p n := let fix loop n k := if k is k'.+1 then if p <= n then (loop (n %/ p) k').+1 else 0 else 0 in loop n n. Lemma trunc_log_bounds p n : 1 < p -> 0 < n -> let k := trunc_log p n in p ^ k <= n < p ^ k.+1. Proof. rewrite {+}/trunc_log => p_gt1; have p_gt0 := ltnW p_gt1. elim: n {-2 5}n (leqnn n) => [|m IHm] [|n] //=; rewrite ltnS => le_n_m _. have [le_p_n | // ] := leqP p _; rewrite 2!expnSr -leq_divRL -?ltn_divLR //. by apply: IHm; rewrite ?divn_gt0 // -ltnS (leq_trans (ltn_Pdiv _ _)). Qed. Lemma trunc_log_ltn p n : 1 < p -> n < p ^ (trunc_log p n).+1. Proof. have [-> | n_gt0] := posnP n; first by move=> /ltnW; rewrite expn_gt0. by case/trunc_log_bounds/(_ n_gt0)/andP. Qed. Lemma trunc_logP p n : 1 < p -> 0 < n -> p ^ trunc_log p n <= n. Proof. by move=> p_gt1 /(trunc_log_bounds p_gt1)/andP[]. Qed. Lemma trunc_log_max p k j : 1 < p -> p ^ j <= k -> j <= trunc_log p k. Proof. move=> p_gt1 le_pj_k; rewrite -ltnS -(@ltn_exp2l p) //. exact: leq_ltn_trans (trunc_log_ltn _ _). Qed. (* pi- parts *) (* Testing for membership in set of prime factors. *) Canonical nat_pred_pred := Eval hnf in [predType of nat_pred]. Coercion nat_pred_of_nat (p : nat) : nat_pred := pred1 p. Section NatPreds. Variables (n : nat) (pi : nat_pred). Definition negn : nat_pred := [predC pi]. Definition pnat : pred nat := fun m => (m > 0) && all (mem pi) (primes m). Definition partn := \prod_(0 <= p < n.+1 | p \in pi) p ^ logn p n. End NatPreds. Notation "pi ^'" := (negn pi) (at level 2, format "pi ^'") : nat_scope. Notation "pi .-nat" := (pnat pi) (at level 2, format "pi .-nat") : nat_scope. Notation "n `_ pi" := (partn n pi) : nat_scope. Section PnatTheory. Implicit Types (n p : nat) (pi rho : nat_pred). Lemma negnK pi : pi^'^' =i pi. Proof. move=> p; exact: negbK. Qed. Lemma eq_negn pi1 pi2 : pi1 =i pi2 -> pi1^' =i pi2^'. Proof. by move=> eq_pi n; rewrite 3!inE /= eq_pi. Qed. Lemma eq_piP m n : \pi(m) =i \pi(n) <-> \pi(m) = \pi(n). Proof. rewrite /pi_of; have eqs := eq_sorted_irr ltn_trans ltnn. by split=> [|-> //]; move/(eqs _ _ (sorted_primes m) (sorted_primes n)) ->. Qed. Lemma part_gt0 pi n : 0 < n`_pi. Proof. exact: prodn_gt0. Qed. Hint Resolve part_gt0. Lemma sub_in_partn pi1 pi2 n : {in \pi(n), {subset pi1 <= pi2}} -> n`_pi1 %| n`_pi2. Proof. move=> pi12; rewrite ![n`__]big_mkcond /=. apply (big_ind2 (fun m1 m2 => m1 %| m2)) => // [*|p _]; first exact: dvdn_mul. rewrite lognE -mem_primes; case: ifP => pi1p; last exact: dvd1n. by case: ifP => pr_p; [rewrite pi12 | rewrite if_same]. Qed. Lemma eq_in_partn pi1 pi2 n : {in \pi(n), pi1 =i pi2} -> n`_pi1 = n`_pi2. Proof. by move=> pi12; apply/eqP; rewrite eqn_dvd ?sub_in_partn // => p /pi12->. Qed. Lemma eq_partn pi1 pi2 n : pi1 =i pi2 -> n`_pi1 = n`_pi2. Proof. by move=> pi12; apply: eq_in_partn => p _. Qed. Lemma partnNK pi n : n`_pi^'^' = n`_pi. Proof. by apply: eq_partn; exact: negnK. Qed. Lemma widen_partn m pi n : n <= m -> n`_pi = \prod_(0 <= p < m.+1 | p \in pi) p ^ logn p n. Proof. move=> le_n_m; rewrite big_mkcond /=. rewrite [n`_pi](big_nat_widen _ _ m.+1) // big_mkcond /=. apply: eq_bigr => p _; rewrite ltnS lognE. by case: and3P => [[_ n_gt0 p_dv_n]|]; rewrite ?if_same // andbC dvdn_leq. Qed. Lemma partn0 pi : 0`_pi = 1. Proof. by apply: big1_seq => [] [|n]; rewrite andbC. Qed. Lemma partn1 pi : 1`_pi = 1. Proof. by apply: big1_seq => [] [|[|n]]; rewrite andbC. Qed. Lemma partnM pi m n : m > 0 -> n > 0 -> (m * n)`_pi = m`_pi * n`_pi. Proof. have le_pmul m' n': m' > 0 -> n' <= m' * n' by move/prednK <-; exact: leq_addr. move=> mpos npos; rewrite !(@widen_partn (n * m)) 3?(le_pmul, mulnC) //. rewrite !big_mkord -big_split; apply: eq_bigr => p _ /=. by rewrite lognM // expnD. Qed. Lemma partnX pi m n : (m ^ n)`_pi = m`_pi ^ n. Proof. elim: n => [|n IHn]; first exact: partn1. rewrite expnS; case: (posnP m) => [->|m_gt0]; first by rewrite partn0 exp1n. by rewrite expnS partnM ?IHn // expn_gt0 m_gt0. Qed. Lemma partn_dvd pi m n : n > 0 -> m %| n -> m`_pi %| n`_pi. Proof. move=> n_gt0 dvmn; case/dvdnP: dvmn n_gt0 => q ->{n}. by rewrite muln_gt0 => /andP[q_gt0 m_gt0]; rewrite partnM ?dvdn_mull. Qed. Lemma p_part p n : n`_p = p ^ logn p n. Proof. case (posnP (logn p n)) => [log0 |]. by rewrite log0 [n`_p]big1_seq // => q; case/andP; move/eqnP->; rewrite log0. rewrite logn_gt0 mem_primes; case/and3P=> _ n_gt0 dv_p_n. have le_p_n: p < n.+1 by rewrite ltnS dvdn_leq. by rewrite [n`_p]big_mkord (big_pred1 (Ordinal le_p_n)). Qed. Lemma p_part_eq1 p n : (n`_p == 1) = (p \notin \pi(n)). Proof. rewrite mem_primes p_part lognE; case: and3P => // [[p_pr _ _]]. by rewrite -dvdn1 pfactor_dvdn // logn1. Qed. Lemma p_part_gt1 p n : (n`_p > 1) = (p \in \pi(n)). Proof. by rewrite ltn_neqAle part_gt0 andbT eq_sym p_part_eq1 negbK. Qed. Lemma primes_part pi n : primes n`_pi = filter (mem pi) (primes n). Proof. have ltnT := ltn_trans. case: (posnP n) => [-> | n_gt0]; first by rewrite partn0. apply: (eq_sorted_irr ltnT ltnn); rewrite ?(sorted_primes, sorted_filter) //. move=> p; rewrite mem_filter /= !mem_primes n_gt0 part_gt0 /=. apply/andP/and3P=> [[p_pr] | [pi_p p_pr dv_p_n]]. rewrite /partn; apply big_ind => [|n1 n2 IHn1 IHn2|q pi_q]. - by rewrite dvdn1; case: eqP p_pr => // ->. - by rewrite Euclid_dvdM //; case/orP. rewrite -{1}(expn1 p) pfactor_dvdn // lognX muln_gt0. rewrite logn_gt0 mem_primes n_gt0 - andbA /=; case/and3P=> pr_q dv_q_n. by rewrite logn_prime //; case: eqP => // ->. have le_p_n: p < n.+1 by rewrite ltnS dvdn_leq. rewrite [n`_pi]big_mkord (bigD1 (Ordinal le_p_n)) //= dvdn_mulr //. by rewrite lognE p_pr n_gt0 dv_p_n expnS dvdn_mulr. Qed. Lemma filter_pi_of n m : n < m -> filter \pi(n) (index_iota 0 m) = primes n. Proof. move=> lt_n_m; have ltnT := ltn_trans; apply: (eq_sorted_irr ltnT ltnn). - by rewrite sorted_filter // iota_ltn_sorted. - exact: sorted_primes. move=> p; rewrite mem_filter mem_index_iota /= mem_primes; case: and3P => //. case=> _ n_gt0 dv_p_n; apply: leq_ltn_trans lt_n_m; exact: dvdn_leq. Qed. Lemma partn_pi n : n > 0 -> n`_\pi(n) = n. Proof. move=> n_gt0; rewrite {3}(prod_prime_decomp n_gt0) prime_decompE big_map. by rewrite -[n`__]big_filter filter_pi_of. Qed. Lemma partnT n : n > 0 -> n`_predT = n. Proof. move=> n_gt0; rewrite -{2}(partn_pi n_gt0) {2}/partn big_mkcond /=. by apply: eq_bigr => p _; rewrite -logn_gt0; case: (logn p _). Qed. Lemma partnC pi n : n > 0 -> n`_pi * n`_pi^' = n. Proof. move=> n_gt0; rewrite -{3}(partnT n_gt0) /partn. do 2!rewrite mulnC big_mkcond /=; rewrite -big_split; apply: eq_bigr => p _ /=. by rewrite mulnC inE /=; case: (p \in pi); rewrite /= (muln1, mul1n). Qed. Lemma dvdn_part pi n : n`_pi %| n. Proof. by case: n => // n; rewrite -{2}[n.+1](@partnC pi) // dvdn_mulr. Qed. Lemma logn_part p m : logn p m`_p = logn p m. Proof. case p_pr: (prime p); first by rewrite p_part pfactorK. by rewrite lognE (lognE p m) p_pr. Qed. Lemma partn_lcm pi m n : m > 0 -> n > 0 -> (lcmn m n)`_pi = lcmn m`_pi n`_pi. Proof. move=> m_gt0 n_gt0; have p_gt0: lcmn m n > 0 by rewrite lcmn_gt0 m_gt0. apply/eqP; rewrite eqn_dvd dvdn_lcm !partn_dvd ?dvdn_lcml ?dvdn_lcmr //. rewrite -(dvdn_pmul2r (part_gt0 pi^' (lcmn m n))) partnC // dvdn_lcm !andbT. rewrite -{1}(partnC pi m_gt0) andbC -{1}(partnC pi n_gt0). by rewrite !dvdn_mul ?partn_dvd ?dvdn_lcml ?dvdn_lcmr. Qed. Lemma partn_gcd pi m n : m > 0 -> n > 0 -> (gcdn m n)`_pi = gcdn m`_pi n`_pi. Proof. move=> m_gt0 n_gt0; have p_gt0: gcdn m n > 0 by rewrite gcdn_gt0 m_gt0. apply/eqP; rewrite eqn_dvd dvdn_gcd !partn_dvd ?dvdn_gcdl ?dvdn_gcdr //=. rewrite -(dvdn_pmul2r (part_gt0 pi^' (gcdn m n))) partnC // dvdn_gcd. rewrite -{3}(partnC pi m_gt0) andbC -{3}(partnC pi n_gt0). by rewrite !dvdn_mul ?partn_dvd ?dvdn_gcdl ?dvdn_gcdr. Qed. Lemma partn_biglcm (I : finType) (P : pred I) F pi : (forall i, P i -> F i > 0) -> (\big[lcmn/1%N]_(i | P i) F i)`_pi = \big[lcmn/1%N]_(i | P i) (F i)`_pi. Proof. move=> F_gt0; set m := \big[lcmn/1%N]_(i | P i) F i. have m_gt0: 0 < m by apply big_ind => // p q p_gt0; rewrite lcmn_gt0 p_gt0. apply/eqP; rewrite eqn_dvd andbC; apply/andP; split. by apply/dvdn_biglcmP=> i Pi; rewrite partn_dvd // (@biglcmn_sup _ i). rewrite -(dvdn_pmul2r (part_gt0 pi^' m)) partnC //. apply/dvdn_biglcmP=> i Pi; rewrite -(partnC pi (F_gt0 i Pi)) dvdn_mul //. by rewrite (@biglcmn_sup _ i). by rewrite partn_dvd // (@biglcmn_sup _ i). Qed. Lemma partn_biggcd (I : finType) (P : pred I) F pi : #|SimplPred P| > 0 -> (forall i, P i -> F i > 0) -> (\big[gcdn/0]_(i | P i) F i)`_pi = \big[gcdn/0]_(i | P i) (F i)`_pi. Proof. move=> ntP F_gt0; set d := \big[gcdn/0]_(i | P i) F i. have d_gt0: 0 < d. case/card_gt0P: ntP => i /= Pi; have:= F_gt0 i Pi. rewrite !lt0n -!dvd0n; apply: contra => dv0d. by rewrite (dvdn_trans dv0d) // (@biggcdn_inf _ i). apply/eqP; rewrite eqn_dvd; apply/andP; split. by apply/dvdn_biggcdP=> i Pi; rewrite partn_dvd ?F_gt0 // (@biggcdn_inf _ i). rewrite -(dvdn_pmul2r (part_gt0 pi^' d)) partnC //. apply/dvdn_biggcdP=> i Pi; rewrite -(partnC pi (F_gt0 i Pi)) dvdn_mul //. by rewrite (@biggcdn_inf _ i). by rewrite partn_dvd ?F_gt0 // (@biggcdn_inf _ i). Qed. Lemma sub_in_pnat pi rho n : {in \pi(n), {subset pi <= rho}} -> pi.-nat n -> rho.-nat n. Proof. rewrite /pnat => subpi /andP[-> pi_n]. apply/allP=> p pr_p; apply: subpi => //; exact: (allP pi_n). Qed. Lemma eq_in_pnat pi rho n : {in \pi(n), pi =i rho} -> pi.-nat n = rho.-nat n. Proof. by move=> eqpi; apply/idP/idP; apply: sub_in_pnat => p /eqpi->. Qed. Lemma eq_pnat pi rho n : pi =i rho -> pi.-nat n = rho.-nat n. Proof. by move=> eqpi; apply: eq_in_pnat => p _. Qed. Lemma pnatNK pi n : pi^'^'.-nat n = pi.-nat n. Proof. exact: eq_pnat (negnK pi). Qed. Lemma pnatI pi rho n : [predI pi & rho].-nat n = pi.-nat n && rho.-nat n. Proof. by rewrite /pnat andbCA all_predI !andbA andbb. Qed. Lemma pnat_mul pi m n : pi.-nat (m * n) = pi.-nat m && pi.-nat n. Proof. rewrite /pnat muln_gt0 andbCA -andbA andbCA. case: posnP => // n_gt0; case: posnP => //= m_gt0. apply/allP/andP=> [pi_mn | [pi_m pi_n] p]. by split; apply/allP=> p m_p; apply: pi_mn; rewrite primes_mul // m_p ?orbT. rewrite primes_mul // => /orP[]; [exact: (allP pi_m) | exact: (allP pi_n)]. Qed. Lemma pnat_exp pi m n : pi.-nat (m ^ n) = pi.-nat m || (n == 0). Proof. by case: n => [|n]; rewrite orbC // /pnat expn_gt0 orbC primes_exp. Qed. Lemma part_pnat pi n : pi.-nat n`_pi. Proof. rewrite /pnat primes_part part_gt0. by apply/allP=> p; rewrite mem_filter => /andP[]. Qed. Lemma pnatE pi p : prime p -> pi.-nat p = (p \in pi). Proof. by move=> pr_p; rewrite /pnat prime_gt0 ?primes_prime //= andbT. Qed. Lemma pnat_id p : prime p -> p.-nat p. Proof. by move=> pr_p; rewrite pnatE ?inE /=. Qed. Lemma coprime_pi' m n : m > 0 -> n > 0 -> coprime m n = \pi(m)^'.-nat n. Proof. by move=> m_gt0 n_gt0; rewrite /pnat n_gt0 all_predC coprime_has_primes. Qed. Lemma pnat_pi n : n > 0 -> \pi(n).-nat n. Proof. rewrite /pnat => ->; exact/allP. Qed. Lemma pi_of_dvd m n : m %| n -> n > 0 -> {subset \pi(m) <= \pi(n)}. Proof. move=> m_dv_n n_gt0 p; rewrite !mem_primes n_gt0 => /and3P[-> _ p_dv_m]. exact: dvdn_trans p_dv_m m_dv_n. Qed. Lemma pi_ofM m n : m > 0 -> n > 0 -> \pi(m * n) =i [predU \pi(m) & \pi(n)]. Proof. move=> m_gt0 n_gt0 p; exact: primes_mul. Qed. Lemma pi_of_part pi n : n > 0 -> \pi(n`_pi) =i [predI \pi(n) & pi]. Proof. by move=> n_gt0 p; rewrite /pi_of primes_part mem_filter andbC. Qed. Lemma pi_of_exp p n : n > 0 -> \pi(p ^ n) = \pi(p). Proof. by move=> n_gt0; rewrite /pi_of primes_exp. Qed. Lemma pi_of_prime p : prime p -> \pi(p) =i (p : nat_pred). Proof. by move=> pr_p q; rewrite /pi_of primes_prime // mem_seq1. Qed. Lemma p'natEpi p n : n > 0 -> p^'.-nat n = (p \notin \pi(n)). Proof. by case: n => // n _; rewrite /pnat all_predC has_pred1. Qed. Lemma p'natE p n : prime p -> p^'.-nat n = ~~ (p %| n). Proof. case: n => [|n] p_pr; first by case: p p_pr. by rewrite p'natEpi // mem_primes p_pr. Qed. Lemma pnatPpi pi n p : pi.-nat n -> p \in \pi(n) -> p \in pi. Proof. by case/andP=> _ /allP; exact. Qed. Lemma pnat_dvd m n pi : m %| n -> pi.-nat n -> pi.-nat m. Proof. by case/dvdnP=> q ->; rewrite pnat_mul; case/andP. Qed. Lemma pnat_div m n pi : m %| n -> pi.-nat n -> pi.-nat (n %/ m). Proof. case/dvdnP=> q ->; rewrite pnat_mul andbC => /andP[]. by case: m => // m _; rewrite mulnK. Qed. Lemma pnat_coprime pi m n : pi.-nat m -> pi^'.-nat n -> coprime m n. Proof. case/andP=> m_gt0 pi_m /andP[n_gt0 pi'_n]. rewrite coprime_has_primes //; apply/hasPn=> p /(allP pi'_n). apply: contra; exact: allP. Qed. Lemma p'nat_coprime pi m n : pi^'.-nat m -> pi.-nat n -> coprime m n. Proof. by move=> pi'm pi_n; rewrite (pnat_coprime pi'm) ?pnatNK. Qed. Lemma sub_pnat_coprime pi rho m n : {subset rho <= pi^'} -> pi.-nat m -> rho.-nat n -> coprime m n. Proof. by move=> pi'rho pi_m; move/(sub_in_pnat (in1W pi'rho)); exact: pnat_coprime. Qed. Lemma coprime_partC pi m n : coprime m`_pi n`_pi^'. Proof. by apply: (@pnat_coprime pi); exact: part_pnat. Qed. Lemma pnat_1 pi n : pi.-nat n -> pi^'.-nat n -> n = 1. Proof. by move=> pi_n pi'_n; rewrite -(eqnP (pnat_coprime pi_n pi'_n)) gcdnn. Qed. Lemma part_pnat_id pi n : pi.-nat n -> n`_pi = n. Proof. case/andP=> n_gt0 pi_n. rewrite -{2}(partnT n_gt0) /partn big_mkcond; apply: eq_bigr=> p _. case: (posnP (logn p n)) => [-> |]; first by rewrite if_same. by rewrite logn_gt0 => /(allP pi_n)/= ->. Qed. Lemma part_p'nat pi n : pi^'.-nat n -> n`_pi = 1. Proof. case/andP=> n_gt0 pi'_n; apply: big1_seq => p /andP[pi_p _]. case: (posnP (logn p n)) => [-> //|]. by rewrite logn_gt0; move/(allP pi'_n); case/negP. Qed. Lemma partn_eq1 pi n : n > 0 -> (n`_pi == 1) = pi^'.-nat n. Proof. move=> n_gt0; apply/eqP/idP=> [pi_n_1|]; last exact: part_p'nat. by rewrite -(partnC pi n_gt0) pi_n_1 mul1n part_pnat. Qed. Lemma pnatP pi n : n > 0 -> reflect (forall p, prime p -> p %| n -> p \in pi) (pi.-nat n). Proof. move=> n_gt0; rewrite /pnat n_gt0. apply: (iffP allP) => /= pi_n p => [pr_p p_n|]. by rewrite pi_n // mem_primes pr_p n_gt0. by rewrite mem_primes n_gt0 /=; case/andP; move: p. Qed. Lemma pi_pnat pi p n : p.-nat n -> p \in pi -> pi.-nat n. Proof. move=> p_n pi_p; have [n_gt0 _] := andP p_n. by apply/pnatP=> // q q_pr /(pnatP _ n_gt0 p_n _ q_pr)/eqnP->. Qed. Lemma p_natP p n : p.-nat n -> {k | n = p ^ k}. Proof. by move=> p_n; exists (logn p n); rewrite -p_part part_pnat_id. Qed. Lemma pi'_p'nat pi p n : pi^'.-nat n -> p \in pi -> p^'.-nat n. Proof. move=> pi'n pi_p; apply: sub_in_pnat pi'n => q _. by apply: contraNneq => ->. Qed. Lemma pi_p'nat p pi n : pi.-nat n -> p \in pi^' -> p^'.-nat n. Proof. by move=> pi_n; apply: pi'_p'nat; rewrite pnatNK. Qed. Lemma partn_part pi rho n : {subset pi <= rho} -> n`_rho`_pi = n`_pi. Proof. move=> pi_sub_rho; have [->|n_gt0] := posnP n; first by rewrite !partn0 partn1. rewrite -{2}(partnC rho n_gt0) partnM //. suffices: pi^'.-nat n`_rho^' by move/part_p'nat->; rewrite muln1. apply: sub_in_pnat (part_pnat _ _) => q _; apply: contra; exact: pi_sub_rho. Qed. Lemma partnI pi rho n : n`_[predI pi & rho] = n`_pi`_rho. Proof. rewrite -(@partnC [predI pi & rho] _`_rho) //. symmetry; rewrite 2?partn_part; try by move=> p /andP []. rewrite mulnC part_p'nat ?mul1n // pnatNK pnatI part_pnat andbT. exact: pnat_dvd (dvdn_part _ _) (part_pnat _ _). Qed. Lemma odd_2'nat n : odd n = 2^'.-nat n. Proof. by case: n => // n; rewrite p'natE // dvdn2 negbK. Qed. End PnatTheory. Hint Resolve part_gt0. (************************************) (* Properties of the divisors list. *) (************************************) Lemma divisors_correct n : n > 0 -> [/\ uniq (divisors n), sorted leq (divisors n) & forall d, (d \in divisors n) = (d %| n)]. Proof. move/prod_prime_decomp=> def_n; rewrite {4}def_n {def_n}. have: all prime (primes n) by apply/allP=> p; rewrite mem_primes; case/andP. have:= primes_uniq n; rewrite /primes /divisors; move/prime_decomp: n. elim=> [|[p e] pd] /=; first by split=> // d; rewrite big_nil dvdn1 mem_seq1. rewrite big_cons /=; move: (foldr _ _ pd) => divs. move=> IHpd /andP[npd_p Upd] /andP[pr_p pr_pd]. have lt0p: 0 < p by exact: prime_gt0. have {IHpd Upd}[Udivs Odivs mem_divs] := IHpd Upd pr_pd. have ndivs_p m: p * m \notin divs. suffices: p \notin divs; rewrite !mem_divs. by apply: contra => /dvdnP[n ->]; rewrite mulnCA dvdn_mulr. have ndv_p_1: ~~(p %| 1) by rewrite dvdn1 neq_ltn orbC prime_gt1. rewrite big_seq; elim/big_ind: _ => [//|u v npu npv|[q f] /= pd_qf]. by rewrite Euclid_dvdM //; apply/norP. elim: (f) => // f'; rewrite expnS Euclid_dvdM // orbC negb_or => -> {f'}/=. have pd_q: q \in unzip1 pd by apply/mapP; exists (q, f). by apply: contra npd_p; rewrite dvdn_prime2 // ?(allP pr_pd) // => /eqP->. elim: e => [|e] /=; first by split=> // d; rewrite mul1n. have Tmulp_inj: injective (NatTrec.mul p). by move=> u v /eqP; rewrite !natTrecE eqn_pmul2l // => /eqP. move: (iter e _ _) => divs' [Udivs' Odivs' mem_divs']; split=> [||d]. - rewrite merge_uniq cat_uniq map_inj_uniq // Udivs Udivs' andbT /=. apply/hasP=> [[d dv_d /mapP[d' _ def_d]]]. by case/idPn: dv_d; rewrite def_d natTrecE. - rewrite (merge_sorted leq_total) //; case: (divs') Odivs' => //= d ds. rewrite (@map_path _ _ _ _ leq xpred0) ?has_pred0 // => u v _. by rewrite !natTrecE leq_pmul2l. rewrite mem_merge mem_cat; case dv_d_p: (p %| d). case/dvdnP: dv_d_p => d' ->{d}; rewrite mulnC (negbTE (ndivs_p d')) orbF. rewrite expnS -mulnA dvdn_pmul2l // -mem_divs'. by rewrite -(mem_map Tmulp_inj divs') natTrecE. case pdiv_d: (_ \in _). by case/mapP: pdiv_d dv_d_p => d' _ ->; rewrite natTrecE dvdn_mulr. rewrite mem_divs Gauss_dvdr // coprime_sym. by rewrite coprime_expl ?prime_coprime ?dv_d_p. Qed. Lemma sorted_divisors n : sorted leq (divisors n). Proof. by case: (posnP n) => [-> | /divisors_correct[]]. Qed. Lemma divisors_uniq n : uniq (divisors n). Proof. by case: (posnP n) => [-> | /divisors_correct[]]. Qed. Lemma sorted_divisors_ltn n : sorted ltn (divisors n). Proof. by rewrite ltn_sorted_uniq_leq divisors_uniq sorted_divisors. Qed. Lemma dvdn_divisors d m : 0 < m -> (d %| m) = (d \in divisors m). Proof. by case/divisors_correct. Qed. Lemma divisor1 n : 1 \in divisors n. Proof. by case: n => // n; rewrite -dvdn_divisors // dvd1n. Qed. Lemma divisors_id n : 0 < n -> n \in divisors n. Proof. by move/dvdn_divisors <-. Qed. (* Big sum / product lemmas*) Lemma dvdn_sum d I r (K : pred I) F : (forall i, K i -> d %| F i) -> d %| \sum_(i <- r | K i) F i. Proof. move=> dF; elim/big_ind: _ => //; exact: dvdn_add. Qed. Lemma dvdn_partP n m : 0 < n -> reflect (forall p, p \in \pi(n) -> n`_p %| m) (n %| m). Proof. move=> n_gt0; apply: (iffP idP) => n_dvd_m => [p _|]. apply: dvdn_trans n_dvd_m; exact: dvdn_part. have [-> // | m_gt0] := posnP m. rewrite -(partnT n_gt0) -(partnT m_gt0). rewrite !(@widen_partn (m + n)) ?leq_addl ?leq_addr // /in_mem /=. elim/big_ind2: _ => // [* | q _]; first exact: dvdn_mul. have [-> // | ] := posnP (logn q n); rewrite logn_gt0 => q_n. have pr_q: prime q by move: q_n; rewrite mem_primes; case/andP. by have:= n_dvd_m q q_n; rewrite p_part !pfactor_dvdn // pfactorK. Qed. Lemma modn_partP n a b : 0 < n -> reflect (forall p : nat, p \in \pi(n) -> a = b %[mod n`_p]) (a == b %[mod n]). Proof. move=> n_gt0; wlog le_b_a: a b / b <= a. move=> IH; case: (leqP b a) => [|/ltnW] /IH {IH}// IH. by rewrite eq_sym; apply: (iffP IH) => eqab p; move/eqab. rewrite eqn_mod_dvd //; apply: (iffP (dvdn_partP _ n_gt0)) => eqab p /eqab; by rewrite -eqn_mod_dvd // => /eqP. Qed. (* The Euler totient function *) Lemma totientE n : n > 0 -> totient n = \prod_(p <- primes n) (p.-1 * p ^ (logn p n).-1). Proof. move=> n_gt0; rewrite /totient n_gt0 prime_decompE unlock. by elim: (primes n) => //= [p pr ->]; rewrite !natTrecE. Qed. Lemma totient_gt0 n : (0 < totient n) = (0 < n). Proof. case: n => // n; rewrite totientE // big_seq_cond prodn_cond_gt0 // => p. by rewrite mem_primes muln_gt0 expn_gt0; case: p => [|[|]]. Qed. Lemma totient_pfactor p e : prime p -> e > 0 -> totient (p ^ e) = p.-1 * p ^ e.-1. Proof. move=> p_pr e_gt0; rewrite totientE ?expn_gt0 ?prime_gt0 //. by rewrite primes_exp // primes_prime // unlock /= muln1 pfactorK. Qed. Lemma totient_coprime m n : coprime m n -> totient (m * n) = totient m * totient n. Proof. move=> co_mn; have [-> //| m_gt0] := posnP m. have [->|n_gt0] := posnP n; first by rewrite !muln0. rewrite !totientE ?muln_gt0 ?m_gt0 //. have /(eq_big_perm _)->: perm_eq (primes (m * n)) (primes m ++ primes n). apply: uniq_perm_eq => [||p]; first exact: primes_uniq. by rewrite cat_uniq !primes_uniq -coprime_has_primes // co_mn. by rewrite mem_cat primes_mul. rewrite big_cat /= !big_seq. congr (_ * _); apply: eq_bigr => p; rewrite mem_primes => /and3P[_ _ dvp]. rewrite (mulnC m) logn_Gauss //; move: co_mn. by rewrite -(divnK dvp) coprime_mull => /andP[]. rewrite logn_Gauss //; move: co_mn. by rewrite coprime_sym -(divnK dvp) coprime_mull => /andP[]. Qed. Lemma totient_count_coprime n : totient n = \sum_(0 <= d < n) coprime n d. Proof. elim: {n}_.+1 {-2}n (ltnSn n) => // m IHm n; rewrite ltnS => le_n_m. case: (leqP n 1) => [|lt1n]; first by rewrite unlock; case: (n) => [|[]]. pose p := pdiv n; have p_pr: prime p by exact: pdiv_prime. have p1 := prime_gt1 p_pr; have p0 := ltnW p1. pose np := n`_p; pose np' := n`_p^'. have co_npp': coprime np np' by rewrite coprime_partC. have [n0 np0 np'0]: [/\ n > 0, np > 0 & np' > 0] by rewrite ltnW ?part_gt0. have def_n: n = np * np' by rewrite partnC. have lnp0: 0 < logn p n by rewrite lognE p_pr n0 pdiv_dvd. pose in_mod k (k0 : k > 0) d := Ordinal (ltn_pmod d k0). rewrite {1}def_n totient_coprime // {IHm}(IHm np') ?big_mkord; last first. apply: leq_trans le_n_m; rewrite def_n ltn_Pmull //. by rewrite /np p_part -(expn0 p) ltn_exp2l. have ->: totient np = #|[pred d : 'I_np | coprime np d]|. rewrite {1}[np]p_part totient_pfactor //=; set q := p ^ _. apply: (@addnI (1 * q)); rewrite -mulnDl [1 + _]prednK // mul1n. have def_np: np = p * q by rewrite -expnS prednK // -p_part. pose mulp := [fun d : 'I_q => in_mod _ np0 (p * d)]. rewrite -def_np -{1}[np]card_ord -(cardC (mem (codom mulp))). rewrite card_in_image => [|[d1 ltd1] [d2 ltd2] /= _ _ []]; last first. move/eqP; rewrite def_np -!muln_modr ?modn_small //. by rewrite eqn_pmul2l // => eq_op12; exact/eqP. rewrite card_ord; congr (q + _); apply: eq_card => d /=. rewrite !inE [np in coprime np _]p_part coprime_pexpl ?prime_coprime //. congr (~~ _); apply/codomP/idP=> [[d' -> /=] | /dvdnP[r def_d]]. by rewrite def_np -muln_modr // dvdn_mulr. do [rewrite mulnC; case: d => d ltd /=] in def_d *. have ltr: r < q by rewrite -(ltn_pmul2l p0) -def_np -def_d. by exists (Ordinal ltr); apply: val_inj; rewrite /= -def_d modn_small. pose h (d : 'I_n) := (in_mod _ np0 d, in_mod _ np'0 d). pose h' (d : 'I_np * 'I_np') := in_mod _ n0 (chinese np np' d.1 d.2). rewrite -!big_mkcond -sum_nat_const pair_big (reindex_onto h h') => [|[d d'] _]. apply: eq_bigl => [[d ltd] /=]; rewrite !inE /= -val_eqE /= andbC. rewrite !coprime_modr def_n -chinese_mod // -coprime_mull -def_n. by rewrite modn_small ?eqxx. apply/eqP; rewrite /eq_op /= /eq_op /= !modn_dvdm ?dvdn_part //. by rewrite chinese_modl // chinese_modr // !modn_small ?eqxx ?ltn_ord. Qed. mathcomp-1.5/theories/pgroup.v0000644000175000017500000014530512307636117015516 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div. Require Import fintype bigop finset prime fingroup morphism. Require Import gfunctor automorphism quotient action gproduct cyclic. (******************************************************************************) (* Standard group notions and constructions based on the prime decomposition *) (* of the order of the group or its elements: *) (* pi.-group G <=> G is a pi-group, i.e., pi.-nat #|G|. *) (* -> Recall that here and in the sequel pi can be a single prime p. *) (* pi.-subgroup(H) G <=> H is a pi-subgroup of G. *) (* := (H \subset G) && pi.-group H. *) (* -> This is provided mostly as a shorhand, with few associated lemmas. *) (* However, we do establish some results on maximal pi-subgroups. *) (* pi.-elt x <=> x is a pi-element. *) (* := pi.-nat #[x] or pi.-group <[x]>. *) (* x.`_pi == the pi-constituent of x: the (unique) pi-element *) (* y \in <[x]> such that x * y^-1 is a pi'-element. *) (* pi.-Hall(G) H <=> H is a Hall pi-subgroup of G. *) (* := [&& H \subset G, pi.-group H & pi^'.-nat #|G : H|]. *) (* -> This is also eqivalent to H \subset G /\ #|H| = #|G|`_pi. *) (* p.-Sylow(G) P <=> P is a Sylow p-subgroup of G. *) (* -> This is the display and preferred input notation for p.-Hall(G) P. *) (* 'Syl_p(G) == the set of the p-Sylow subgroups of G. *) (* := [set P : {group _} | p.-Sylow(G) P]. *) (* p_group P <=> P is a p-group for some prime p. *) (* Hall G H <=> H is a Hall pi-subgroup of G for some pi. *) (* := coprime #|H| #|G : H| && (H \subset G). *) (* Sylow G P <=> P is a Sylow p-subgroup of G for some p. *) (* := p_group P && Hall G P. *) (* 'O_pi(G) == the pi-core (largest normal pi-subgroup) of G. *) (* pcore_mod pi G H == the pi-core of G mod H. *) (* := G :&: (coset H @*^-1 'O_pi(G / H)). *) (* 'O_{pi2, pi1}(G) == the pi1,pi2-core of G. *) (* := the pi1-core of G mod 'O_pi2(G). *) (* -> We have 'O_{pi2, pi1}(G) / 'O_pi2(G) = 'O_pi1(G / 'O_pi2(G)) *) (* with 'O_pi2(G) <| 'O_{pi2, pi1}(G) <| G. *) (* 'O_{pn, ..., p1}(G) == the p1, ..., pn-core of G. *) (* := the p1-core of G mod 'O_{pn, ..., p2}(G). *) (* Note that notions are always defined on sets even though their name *) (* indicates "group" properties; the actual definition of the notion never *) (* tests for the group property, since this property will always be provided *) (* by a (canonical) group structure. Similarly, p-group properties assume *) (* without test that p is a prime. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section PgroupDefs. (* We defer the definition of the functors ('0_p(G), etc) because they need *) (* to quantify over the finGroupType explicitly. *) Variable gT : finGroupType. Implicit Type (x : gT) (A B : {set gT}) (pi : nat_pred) (p n : nat). Definition pgroup pi A := pi.-nat #|A|. Definition psubgroup pi A B := (B \subset A) && pgroup pi B. Definition p_group A := pgroup (pdiv #|A|) A. Definition p_elt pi x := pi.-nat #[x]. Definition constt x pi := x ^+ (chinese #[x]`_pi #[x]`_pi^' 1 0). Definition Hall A B := (B \subset A) && coprime #|B| #|A : B|. Definition pHall pi A B := [&& B \subset A, pgroup pi B & pi^'.-nat #|A : B|]. Definition Syl p A := [set P : {group gT} | pHall p A P]. Definition Sylow A B := p_group B && Hall A B. End PgroupDefs. Arguments Scope pgroup [_ nat_scope group_scope]. Arguments Scope psubgroup [_ nat_scope group_scope group_scope]. Arguments Scope p_group [_ group_scope]. Arguments Scope p_elt [_ nat_scope]. Arguments Scope constt [_ group_scope nat_scope]. Arguments Scope Hall [_ group_scope group_scope]. Arguments Scope pHall [_ nat_scope group_scope group_scope]. Arguments Scope Syl [_ nat_scope group_scope]. Arguments Scope Sylow [_ group_scope group_scope]. Prenex Implicits p_group Hall Sylow. Notation "pi .-group" := (pgroup pi) (at level 2, format "pi .-group") : group_scope. Notation "pi .-subgroup ( A )" := (psubgroup pi A) (at level 8, format "pi .-subgroup ( A )") : group_scope. Notation "pi .-elt" := (p_elt pi) (at level 2, format "pi .-elt") : group_scope. Notation "x .`_ pi" := (constt x pi) (at level 3, format "x .`_ pi") : group_scope. Notation "pi .-Hall ( G )" := (pHall pi G) (at level 8, format "pi .-Hall ( G )") : group_scope. Notation "p .-Sylow ( G )" := (nat_pred_of_nat p).-Hall(G) (at level 8, format "p .-Sylow ( G )") : group_scope. Notation "''Syl_' p ( G )" := (Syl p G) (at level 8, p at level 2, format "''Syl_' p ( G )") : group_scope. Section PgroupProps. Variable gT : finGroupType. Implicit Types (pi rho : nat_pred) (p : nat). Implicit Types (x y z : gT) (A B C D : {set gT}) (G H K P Q R : {group gT}). Lemma trivgVpdiv G : G :=: 1 \/ (exists2 p, prime p & p %| #|G|). Proof. have [leG1|lt1G] := leqP #|G| 1; first by left; exact: card_le1_trivg. by right; exists (pdiv #|G|); rewrite ?pdiv_dvd ?pdiv_prime. Qed. Lemma prime_subgroupVti G H : prime #|G| -> G \subset H \/ H :&: G = 1. Proof. move=> prG; have [|[p p_pr pG]] := trivgVpdiv (H :&: G); first by right. left; rewrite (sameP setIidPr eqP) eqEcard subsetIr. suffices <-: p = #|G| by rewrite dvdn_leq ?cardG_gt0. by apply/eqP; rewrite -dvdn_prime2 // -(LagrangeI G H) setIC dvdn_mulr. Qed. Lemma pgroupE pi A : pi.-group A = pi.-nat #|A|. Proof. by []. Qed. Lemma sub_pgroup pi rho A : {subset pi <= rho} -> pi.-group A -> rho.-group A. Proof. by move=> pi_sub_rho; exact: sub_in_pnat (in1W pi_sub_rho). Qed. Lemma eq_pgroup pi rho A : pi =i rho -> pi.-group A = rho.-group A. Proof. exact: eq_pnat. Qed. Lemma eq_p'group pi rho A : pi =i rho -> pi^'.-group A = rho^'.-group A. Proof. by move/eq_negn; exact: eq_pnat. Qed. Lemma pgroupNK pi A : pi^'^'.-group A = pi.-group A. Proof. exact: pnatNK. Qed. Lemma pi_pgroup p pi A : p.-group A -> p \in pi -> pi.-group A. Proof. exact: pi_pnat. Qed. Lemma pi_p'group p pi A : pi.-group A -> p \in pi^' -> p^'.-group A. Proof. exact: pi_p'nat. Qed. Lemma pi'_p'group p pi A : pi^'.-group A -> p \in pi -> p^'.-group A. Proof. exact: pi'_p'nat. Qed. Lemma p'groupEpi p G : p^'.-group G = (p \notin \pi(G)). Proof. exact: p'natEpi (cardG_gt0 G). Qed. Lemma pgroup_pi G : \pi(G).-group G. Proof. by rewrite /=; exact: pnat_pi. Qed. Lemma partG_eq1 pi G : (#|G|`_pi == 1%N) = pi^'.-group G. Proof. exact: partn_eq1 (cardG_gt0 G). Qed. Lemma pgroupP pi G : reflect (forall p, prime p -> p %| #|G| -> p \in pi) (pi.-group G). Proof. exact: pnatP. Qed. Implicit Arguments pgroupP [pi G]. Lemma pgroup1 pi : pi.-group [1 gT]. Proof. by rewrite /pgroup cards1. Qed. Lemma pgroupS pi G H : H \subset G -> pi.-group G -> pi.-group H. Proof. by move=> sHG; exact: pnat_dvd (cardSg sHG). Qed. Lemma oddSg G H : H \subset G -> odd #|G| -> odd #|H|. Proof. by rewrite !odd_2'nat; exact: pgroupS. Qed. Lemma odd_pgroup_odd p G : odd p -> p.-group G -> odd #|G|. Proof. move=> p_odd pG; rewrite odd_2'nat (pi_pnat pG) // !inE. by case: eqP p_odd => // ->. Qed. Lemma card_pgroup p G : p.-group G -> #|G| = (p ^ logn p #|G|)%N. Proof. by move=> pG; rewrite -p_part part_pnat_id. Qed. Lemma properG_ltn_log p G H : p.-group G -> H \proper G -> logn p #|H| < logn p #|G|. Proof. move=> pG; rewrite properEneq eqEcard andbC ltnNge => /andP[sHG]. rewrite sHG /= {1}(card_pgroup pG) {1}(card_pgroup (pgroupS sHG pG)). by apply: contra; case: p {pG} => [|p] leHG; rewrite ?logn0 // leq_pexp2l. Qed. Lemma pgroupM pi G H : pi.-group (G * H) = pi.-group G && pi.-group H. Proof. have GH_gt0: 0 < #|G :&: H| := cardG_gt0 _. rewrite /pgroup -(mulnK #|_| GH_gt0) -mul_cardG -(LagrangeI G H) -mulnA. by rewrite mulKn // -(LagrangeI H G) setIC !pnat_mul andbCA; case: (pnat _). Qed. Lemma pgroupJ pi G x : pi.-group (G :^ x) = pi.-group G. Proof. by rewrite /pgroup cardJg. Qed. Lemma pgroup_p p P : p.-group P -> p_group P. Proof. case: (leqP #|P| 1); first by move=> /card_le1_trivg-> _; exact: pgroup1. move/pdiv_prime=> pr_q pgP; have:= pgroupP pgP _ pr_q (pdiv_dvd _). by rewrite /p_group => /eqnP->. Qed. Lemma p_groupP P : p_group P -> exists2 p, prime p & p.-group P. Proof. case: (ltnP 1 #|P|); first by move/pdiv_prime; exists (pdiv #|P|). move/card_le1_trivg=> -> _; exists 2 => //; exact: pgroup1. Qed. Lemma pgroup_pdiv p G : p.-group G -> G :!=: 1 -> [/\ prime p, p %| #|G| & exists m, #|G| = p ^ m.+1]%N. Proof. move=> pG; rewrite trivg_card1; case/p_groupP: (pgroup_p pG) => q q_pr qG. move/implyP: (pgroupP pG q q_pr); case/p_natP: qG => // [[|m] ->] //. by rewrite dvdn_exp // => /eqnP <- _; split; rewrite ?dvdn_exp //; exists m. Qed. Lemma coprime_p'group p K R : coprime #|K| #|R| -> p.-group R -> R :!=: 1 -> p^'.-group K. Proof. move=> coKR pR ntR; have [p_pr _ [e oK]] := pgroup_pdiv pR ntR. by rewrite oK coprime_sym coprime_pexpl // prime_coprime // -p'natE in coKR. Qed. Lemma card_Hall pi G H : pi.-Hall(G) H -> #|H| = #|G|`_pi. Proof. case/and3P=> sHG piH pi'H; rewrite -(Lagrange sHG). by rewrite partnM ?Lagrange // part_pnat_id ?part_p'nat ?muln1. Qed. Lemma pHall_sub pi A B : pi.-Hall(A) B -> B \subset A. Proof. by case/andP. Qed. Lemma pHall_pgroup pi A B : pi.-Hall(A) B -> pi.-group B. Proof. by case/and3P. Qed. Lemma pHallP pi G H : reflect (H \subset G /\ #|H| = #|G|`_pi) (pi.-Hall(G) H). Proof. apply: (iffP idP) => [piH | [sHG oH]]. split; [exact: pHall_sub piH | exact: card_Hall]. rewrite /pHall sHG -divgS // /pgroup oH. by rewrite -{2}(@partnC pi #|G|) ?mulKn ?part_pnat. Qed. Lemma pHallE pi G H : pi.-Hall(G) H = (H \subset G) && (#|H| == #|G|`_pi). Proof. by apply/pHallP/andP=> [] [->] /eqP. Qed. Lemma coprime_mulpG_Hall pi G K R : K * R = G -> pi.-group K -> pi^'.-group R -> pi.-Hall(G) K /\ pi^'.-Hall(G) R. Proof. move=> defG piK pi'R; apply/andP. rewrite /pHall piK -!divgS /= -defG ?mulG_subl ?mulg_subr //= pnatNK. by rewrite coprime_cardMg ?(pnat_coprime piK) // mulKn ?mulnK //; exact/and3P. Qed. Lemma coprime_mulGp_Hall pi G K R : K * R = G -> pi^'.-group K -> pi.-group R -> pi^'.-Hall(G) K /\ pi.-Hall(G) R. Proof. move=> defG pi'K piR; apply/andP; rewrite andbC; apply/andP. by apply: coprime_mulpG_Hall => //; rewrite -(comm_group_setP _) defG ?groupP. Qed. Lemma eq_in_pHall pi rho G H : {in \pi(G), pi =i rho} -> pi.-Hall(G) H = rho.-Hall(G) H. Proof. move=> eq_pi_rho; apply: andb_id2l => sHG. congr (_ && _); apply: eq_in_pnat => p piHp. by apply: eq_pi_rho; exact: (piSg sHG). by congr (~~ _); apply: eq_pi_rho; apply: (pi_of_dvd (dvdn_indexg G H)). Qed. Lemma eq_pHall pi rho G H : pi =i rho -> pi.-Hall(G) H = rho.-Hall(G) H. Proof. by move=> eq_pi_rho; exact: eq_in_pHall (in1W eq_pi_rho). Qed. Lemma eq_p'Hall pi rho G H : pi =i rho -> pi^'.-Hall(G) H = rho^'.-Hall(G) H. Proof. by move=> eq_pi_rho; exact: eq_pHall (eq_negn _). Qed. Lemma pHallNK pi G H : pi^'^'.-Hall(G) H = pi.-Hall(G) H. Proof. exact: eq_pHall (negnK _). Qed. Lemma subHall_Hall pi rho G H K : rho.-Hall(G) H -> {subset pi <= rho} -> pi.-Hall(H) K -> pi.-Hall(G) K. Proof. move=> hallH pi_sub_rho hallK. rewrite pHallE (subset_trans (pHall_sub hallK) (pHall_sub hallH)) /=. by rewrite (card_Hall hallK) (card_Hall hallH) partn_part. Qed. Lemma subHall_Sylow pi p G H P : pi.-Hall(G) H -> p \in pi -> p.-Sylow(H) P -> p.-Sylow(G) P. Proof. move=> hallH pi_p sylP; have [sHG piH _] := and3P hallH. rewrite pHallE (subset_trans (pHall_sub sylP) sHG) /=. by rewrite (card_Hall sylP) (card_Hall hallH) partn_part // => q; move/eqnP->. Qed. Lemma pHall_Hall pi A B : pi.-Hall(A) B -> Hall A B. Proof. by case/and3P=> sBA piB pi'B; rewrite /Hall sBA (pnat_coprime piB). Qed. Lemma Hall_pi G H : Hall G H -> \pi(H).-Hall(G) H. Proof. by case/andP=> sHG coHG /=; rewrite /pHall sHG /pgroup pnat_pi -?coprime_pi'. Qed. Lemma HallP G H : Hall G H -> exists pi, pi.-Hall(G) H. Proof. by exists \pi(H); exact: Hall_pi. Qed. Lemma sdprod_Hall G K H : K ><| H = G -> Hall G K = Hall G H. Proof. case/sdprod_context=> /andP[sKG _] sHG defG _ tiKH. by rewrite /Hall sKG sHG -!divgS // -defG TI_cardMg // coprime_sym mulKn ?mulnK. Qed. Lemma coprime_sdprod_Hall_l G K H : K ><| H = G -> coprime #|K| #|H| = Hall G K. Proof. case/sdprod_context=> /andP[sKG _] _ defG _ tiKH. by rewrite /Hall sKG -divgS // -defG TI_cardMg ?mulKn. Qed. Lemma coprime_sdprod_Hall_r G K H : K ><| H = G -> coprime #|K| #|H| = Hall G H. Proof. by move=> defG; rewrite (coprime_sdprod_Hall_l defG) (sdprod_Hall defG). Qed. Lemma compl_pHall pi K H G : pi.-Hall(G) K -> (H \in [complements to K in G]) = pi^'.-Hall(G) H. Proof. move=> hallK; apply/complP/idP=> [[tiKH mulKH] | hallH]. have [_] := andP hallK; rewrite /pHall pnatNK -{3}(invGid G) -mulKH mulG_subr. by rewrite invMG !indexMg -indexgI andbC -indexgI setIC tiKH !indexg1. have [[sKG piK _] [sHG pi'H _]] := (and3P hallK, and3P hallH). have tiKH: K :&: H = 1 := coprime_TIg (pnat_coprime piK pi'H). split=> //; apply/eqP; rewrite eqEcard mul_subG //= TI_cardMg //. by rewrite (card_Hall hallK) (card_Hall hallH) partnC. Qed. Lemma compl_p'Hall pi K H G : pi^'.-Hall(G) K -> (H \in [complements to K in G]) = pi.-Hall(G) H. Proof. by move/compl_pHall->; exact: eq_pHall (negnK pi). Qed. Lemma sdprod_normal_p'HallP pi K H G : K <| G -> pi^'.-Hall(G) H -> reflect (K ><| H = G) (pi.-Hall(G) K). Proof. move=> nsKG hallH; rewrite -(compl_p'Hall K hallH). exact: sdprod_normal_complP. Qed. Lemma sdprod_normal_pHallP pi K H G : K <| G -> pi.-Hall(G) H -> reflect (K ><| H = G) (pi^'.-Hall(G) K). Proof. by move=> nsKG hallH; apply: sdprod_normal_p'HallP; rewrite ?pHallNK. Qed. Lemma pHallJ2 pi G H x : pi.-Hall(G :^ x) (H :^ x) = pi.-Hall(G) H. Proof. by rewrite !pHallE conjSg !cardJg. Qed. Lemma pHallJnorm pi G H x : x \in 'N(G) -> pi.-Hall(G) (H :^ x) = pi.-Hall(G) H. Proof. by move=> Nx; rewrite -{1}(normP Nx) pHallJ2. Qed. Lemma pHallJ pi G H x : x \in G -> pi.-Hall(G) (H :^ x) = pi.-Hall(G) H. Proof. by move=> Gx; rewrite -{1}(conjGid Gx) pHallJ2. Qed. Lemma HallJ G H x : x \in G -> Hall G (H :^ x) = Hall G H. Proof. by move=> Gx; rewrite /Hall -!divgI -{1 3}(conjGid Gx) conjSg -conjIg !cardJg. Qed. Lemma psubgroupJ pi G H x : x \in G -> pi.-subgroup(G) (H :^ x) = pi.-subgroup(G) H. Proof. by move=> Gx; rewrite /psubgroup pgroupJ -{1}(conjGid Gx) conjSg. Qed. Lemma p_groupJ P x : p_group (P :^ x) = p_group P. Proof. by rewrite /p_group cardJg pgroupJ. Qed. Lemma SylowJ G P x : x \in G -> Sylow G (P :^ x) = Sylow G P. Proof. by move=> Gx; rewrite /Sylow p_groupJ HallJ. Qed. Lemma p_Sylow p G P : p.-Sylow(G) P -> Sylow G P. Proof. by move=> pP; rewrite /Sylow (pgroup_p (pHall_pgroup pP)) (pHall_Hall pP). Qed. Lemma pHall_subl pi G K H : H \subset K -> K \subset G -> pi.-Hall(G) H -> pi.-Hall(K) H. Proof. move=> sHK sKG; rewrite /pHall sHK; case/and3P=> _ ->. by apply: pnat_dvd; exact: indexSg. Qed. Lemma Hall1 G : Hall G 1. Proof. by rewrite /Hall sub1G cards1 coprime1n. Qed. Lemma p_group1 : @p_group gT 1. Proof. by rewrite (@pgroup_p 2) ?pgroup1. Qed. Lemma Sylow1 G : Sylow G 1. Proof. by rewrite /Sylow p_group1 Hall1. Qed. Lemma SylowP G P : reflect (exists2 p, prime p & p.-Sylow(G) P) (Sylow G P). Proof. apply: (iffP idP) => [| [p _]]; last exact: p_Sylow. case/andP=> /p_groupP[p p_pr] /p_natP[[P1 _ | n oP /Hall_pi]]; last first. by rewrite /= oP pi_of_exp // (eq_pHall _ _ (pi_of_prime _)) //; exists p. have{p p_pr P1} ->: P :=: 1 by apply: card1_trivg; rewrite P1. pose p := pdiv #|G|.+1; have p_pr: prime p by rewrite pdiv_prime ?ltnS. exists p; rewrite // pHallE sub1G cards1 part_p'nat //. apply/pgroupP=> q pr_q qG; apply/eqnP=> def_q. have: p %| #|G| + 1 by rewrite addn1 pdiv_dvd. by rewrite dvdn_addr -def_q // Euclid_dvd1. Qed. Lemma p_elt_exp pi x m : pi.-elt (x ^+ m) = (#[x]`_pi^' %| m). Proof. apply/idP/idP=> [pi_xm | /dvdnP[q ->{m}]]; last first. rewrite mulnC; apply: pnat_dvd (part_pnat pi #[x]). by rewrite order_dvdn -expgM mulnC mulnA partnC // -order_dvdn dvdn_mulr. rewrite -(@Gauss_dvdr _ #[x ^+ m]); last first. by rewrite coprime_sym (pnat_coprime pi_xm) ?part_pnat. apply: (@dvdn_trans #[x]); first by rewrite -{2}[#[x]](partnC pi) ?dvdn_mull. by rewrite order_dvdn mulnC expgM expg_order. Qed. Lemma mem_p_elt pi x G : pi.-group G -> x \in G -> pi.-elt x. Proof. by move=> piG Gx; apply: pgroupS piG; rewrite cycle_subG. Qed. Lemma p_eltM_norm pi x y : x \in 'N(<[y]>) -> pi.-elt x -> pi.-elt y -> pi.-elt (x * y). Proof. move=> nyx pi_x pi_y; apply: (@mem_p_elt pi _ (<[x]> <*> <[y]>)%G). by rewrite /= norm_joinEl ?cycle_subG // pgroupM; exact/andP. by rewrite groupM // mem_gen // inE cycle_id ?orbT. Qed. Lemma p_eltM pi x y : commute x y -> pi.-elt x -> pi.-elt y -> pi.-elt (x * y). Proof. move=> cxy; apply: p_eltM_norm; apply: (subsetP (cent_sub _)). by rewrite cent_gen cent_set1; exact/cent1P. Qed. Lemma p_elt1 pi : pi.-elt (1 : gT). Proof. by rewrite /p_elt order1. Qed. Lemma p_eltV pi x : pi.-elt x^-1 = pi.-elt x. Proof. by rewrite /p_elt orderV. Qed. Lemma p_eltX pi x n : pi.-elt x -> pi.-elt (x ^+ n). Proof. by rewrite -{1}[x]expg1 !p_elt_exp dvdn1 => /eqnP->. Qed. Lemma p_eltJ pi x y : pi.-elt (x ^ y) = pi.-elt x. Proof. by congr pnat; rewrite orderJ. Qed. Lemma sub_p_elt pi1 pi2 x : {subset pi1 <= pi2} -> pi1.-elt x -> pi2.-elt x. Proof. by move=> pi12; apply: sub_in_pnat => q _; exact: pi12. Qed. Lemma eq_p_elt pi1 pi2 x : pi1 =i pi2 -> pi1.-elt x = pi2.-elt x. Proof. by move=> pi12; exact: eq_pnat. Qed. Lemma p_eltNK pi x : pi^'^'.-elt x = pi.-elt x. Proof. exact: pnatNK. Qed. Lemma eq_constt pi1 pi2 x : pi1 =i pi2 -> x.`_pi1 = x.`_pi2. Proof. move=> pi12; congr (x ^+ (chinese _ _ 1 0)); apply: eq_partn => // a. by congr (~~ _); exact: pi12. Qed. Lemma consttNK pi x : x.`_pi^'^' = x.`_pi. Proof. by rewrite /constt !partnNK. Qed. Lemma cycle_constt pi x : x.`_pi \in <[x]>. Proof. exact: mem_cycle. Qed. Lemma consttV pi x : (x^-1).`_pi = (x.`_pi)^-1. Proof. by rewrite /constt expgVn orderV. Qed. Lemma constt1 pi : 1.`_pi = 1 :> gT. Proof. exact: expg1n. Qed. Lemma consttJ pi x y : (x ^ y).`_pi = x.`_pi ^ y. Proof. by rewrite /constt orderJ conjXg. Qed. Lemma p_elt_constt pi x : pi.-elt x.`_pi. Proof. by rewrite p_elt_exp /chinese addn0 mul1n dvdn_mulr. Qed. Lemma consttC pi x : x.`_pi * x.`_pi^' = x. Proof. apply/eqP; rewrite -{3}[x]expg1 -expgD eq_expg_mod_order. rewrite partnNK -{5 6}(@partnC pi #[x]) // /chinese !addn0. by rewrite chinese_remainder ?chinese_modl ?chinese_modr ?coprime_partC ?eqxx. Qed. Lemma p'_elt_constt pi x : pi^'.-elt (x * (x.`_pi)^-1). Proof. by rewrite -{1}(consttC pi^' x) consttNK mulgK p_elt_constt. Qed. Lemma order_constt pi (x : gT) : #[x.`_pi] = #[x]`_pi. Proof. rewrite -{2}(consttC pi x) orderM; [|exact: commuteX2|]; last first. by apply: (@pnat_coprime pi); exact: p_elt_constt. by rewrite partnM // part_pnat_id ?part_p'nat ?muln1 //; exact: p_elt_constt. Qed. Lemma consttM pi x y : commute x y -> (x * y).`_pi = x.`_pi * y.`_pi. Proof. move=> cxy; pose m := #|<<[set x; y]>>|; have m_gt0: 0 < m := cardG_gt0 _. pose k := chinese m`_pi m`_pi^' 1 0. suffices kXpi z: z \in <<[set x; y]>> -> z.`_pi = z ^+ k. by rewrite !kXpi ?expgMn // ?groupM ?mem_gen // !inE eqxx ?orbT. move=> xyz; have{xyz} zm: #[z] %| m by rewrite cardSg ?cycle_subG. apply/eqP; rewrite eq_expg_mod_order -{3 4}[#[z]](partnC pi) //. rewrite chinese_remainder ?chinese_modl ?chinese_modr ?coprime_partC //. rewrite -!(modn_dvdm k (partn_dvd _ m_gt0 zm)). rewrite chinese_modl ?chinese_modr ?coprime_partC //. by rewrite !modn_dvdm ?partn_dvd ?eqxx. Qed. Lemma consttX pi x n : (x ^+ n).`_pi = x.`_pi ^+ n. Proof. elim: n => [|n IHn]; first exact: constt1. rewrite !expgS consttM ?IHn //; exact: commuteX. Qed. Lemma constt1P pi x : reflect (x.`_pi = 1) (pi^'.-elt x). Proof. rewrite -{2}[x]expg1 p_elt_exp -order_constt consttNK order_dvdn expg1. exact: eqP. Qed. Lemma constt_p_elt pi x : pi.-elt x -> x.`_pi = x. Proof. by rewrite -p_eltNK -{3}(consttC pi x) => /constt1P->; rewrite mulg1. Qed. Lemma sub_in_constt pi1 pi2 x : {in \pi(#[x]), {subset pi1 <= pi2}} -> x.`_pi2.`_pi1 = x.`_pi1. Proof. move=> pi12; rewrite -{2}(consttC pi2 x) consttM; last exact: commuteX2. rewrite (constt1P _ x.`_pi2^' _) ?mulg1 //. apply: sub_in_pnat (p_elt_constt _ x) => p; rewrite order_constt => pi_p. apply: contra; apply: pi12. by rewrite -[#[x]](partnC pi2^') // primes_mul // pi_p. Qed. Lemma prod_constt x : \prod_(0 <= p < #[x].+1) x.`_p = x. Proof. pose lp n := [pred p | p < n]. have: (lp #[x].+1).-elt x by apply/pnatP=> // p _; exact: dvdn_leq. move/constt_p_elt=> def_x; symmetry; rewrite -{1}def_x {def_x}. elim: _.+1 => [|p IHp]. by rewrite big_nil; apply/constt1P; exact/pgroupP. rewrite big_nat_recr //= -{}IHp -(consttC (lp p) x.`__); congr (_ * _). rewrite sub_in_constt // => q _; exact: leqW. set y := _.`__; rewrite -(consttC p y) (constt1P p^' _ _) ?mulg1. by rewrite 2?sub_in_constt // => q _; move/eqnP->; rewrite !inE ?ltnn. rewrite /p_elt pnatNK !order_constt -partnI. apply: sub_in_pnat (part_pnat _ _) => q _. by rewrite !inE ltnS -leqNgt -eqn_leq. Qed. Lemma max_pgroupJ pi M G x : x \in G -> [max M | pi.-subgroup(G) M] -> [max M :^ x of M | pi.-subgroup(G) M]. Proof. move=> Gx /maxgroupP[piM maxM]; apply/maxgroupP. split=> [|H piH]; first by rewrite psubgroupJ. by rewrite -(conjsgKV x H) conjSg => /maxM/=-> //; rewrite psubgroupJ ?groupV. Qed. Lemma comm_sub_max_pgroup pi H M G : [max M | pi.-subgroup(G) M] -> pi.-group H -> H \subset G -> commute H M -> H \subset M. Proof. case/maxgroupP=> /andP[sMG piM] maxM piH sHG cHM. rewrite -(maxM (H <*> M)%G) /= comm_joingE ?(mulG_subl, mulG_subr) //. by rewrite /psubgroup pgroupM piM piH mul_subG. Qed. Lemma normal_sub_max_pgroup pi H M G : [max M | pi.-subgroup(G) M] -> pi.-group H -> H <| G -> H \subset M. Proof. move=> maxM piH /andP[sHG nHG]. apply: comm_sub_max_pgroup piH sHG _ => //; apply: commute_sym; apply: normC. by apply: subset_trans nHG; case/andP: (maxgroupp maxM). Qed. Lemma norm_sub_max_pgroup pi H M G : [max M | pi.-subgroup(G) M] -> pi.-group H -> H \subset G -> H \subset 'N(M) -> H \subset M. Proof. by move=> maxM piH sHG /normC; exact: comm_sub_max_pgroup piH sHG. Qed. Lemma sub_pHall pi H G K : pi.-Hall(G) H -> pi.-group K -> H \subset K -> K \subset G -> K :=: H. Proof. move=> hallH piK sHK sKG; apply/eqP; rewrite eq_sym eqEcard sHK. by rewrite (card_Hall hallH) -(part_pnat_id piK) dvdn_leq ?partn_dvd ?cardSg. Qed. Lemma Hall_max pi H G : pi.-Hall(G) H -> [max H | pi.-subgroup(G) H]. Proof. move=> hallH; apply/maxgroupP; split=> [|K]. by rewrite /psubgroup; case/and3P: hallH => ->. case/andP=> sKG piK sHK; exact: (sub_pHall hallH). Qed. Lemma pHall_id pi H G : pi.-Hall(G) H -> pi.-group G -> H :=: G. Proof. by move=> hallH piG; rewrite (sub_pHall hallH piG) ?(pHall_sub hallH). Qed. Lemma psubgroup1 pi G : pi.-subgroup(G) 1. Proof. by rewrite /psubgroup sub1G pgroup1. Qed. Lemma Cauchy p G : prime p -> p %| #|G| -> {x | x \in G & #[x] = p}. Proof. move=> p_pr; elim: {G}_.+1 {-2}G (ltnSn #|G|) => // n IHn G. rewrite ltnS => leGn pG; pose xpG := [pred x in G | #[x] == p]. have [x /andP[Gx /eqP] | no_x] := pickP xpG; first by exists x. have{pG n leGn IHn} pZ: p %| #|'C_G(G)|. suffices /dvdn_addl <-: p %| #|G :\: 'C(G)| by rewrite cardsID. have /acts_sum_card_orbit <-: [acts G, on G :\: 'C(G) | 'J]. by apply/actsP=> x Gx y; rewrite !inE -!mem_conjgV -centJ conjGid ?groupV. elim/big_rec: _ => // _ _ /imsetP[x /setDP[Gx nCx] ->] /dvdn_addl->. have ltCx: 'C_G[x] \proper G by rewrite properE subsetIl subsetIidl sub_cent1. have /negP: ~ p %| #|'C_G[x]|. case/(IHn _ (leq_trans (proper_card ltCx) leGn))=> y /setIP[Gy _] /eqP-oy. by have /andP[] := no_x y. by apply/implyP; rewrite -index_cent1 indexgI implyNb -Euclid_dvdM ?LagrangeI. have [Q maxQ _]: {Q | [max Q | p^'.-subgroup('C_G(G)) Q] & 1%G \subset Q}. apply: maxgroup_exists; exact: psubgroup1. case/andP: (maxgroupp maxQ) => sQC; rewrite /pgroup p'natE // => /negP[]. apply: dvdn_trans pZ (cardSg _); apply/subsetP=> x /setIP[Gx Cx]. rewrite -sub1set -gen_subG (normal_sub_max_pgroup maxQ) //; last first. rewrite /normal subsetI !cycle_subG ?Gx ?cents_norm ?subIset ?andbT //=. by rewrite centsC cycle_subG Cx. rewrite /pgroup p'natE //= -[#|_|]/#[x]; apply/dvdnP=> [[m oxm]]. have m_gt0: 0 < m by apply: dvdn_gt0 (order_gt0 x) _; rewrite oxm dvdn_mulr. case/idP: (no_x (x ^+ m)); rewrite /= groupX //= orderXgcd //= oxm. by rewrite gcdnC gcdnMr mulKn. Qed. (* These lemmas actually hold for maximal pi-groups, but below we'll *) (* derive from the Cauchy lemma that a normal max pi-group is Hall. *) Lemma sub_normal_Hall pi G H K : pi.-Hall(G) H -> H <| G -> K \subset G -> (K \subset H) = pi.-group K. Proof. move=> hallH nsHG sKG; apply/idP/idP=> [sKH | piK]. by rewrite (pgroupS sKH) ?(pHall_pgroup hallH). apply: norm_sub_max_pgroup (Hall_max hallH) piK _ _ => //. exact: subset_trans sKG (normal_norm nsHG). Qed. Lemma mem_normal_Hall pi H G x : pi.-Hall(G) H -> H <| G -> x \in G -> (x \in H) = pi.-elt x. Proof. by rewrite -!cycle_subG; exact: sub_normal_Hall. Qed. Lemma uniq_normal_Hall pi H G K : pi.-Hall(G) H -> H <| G -> [max K | pi.-subgroup(G) K] -> K :=: H. Proof. move=> hallH nHG /maxgroupP[/andP[sKG piK] /(_ H) -> //]. exact: (maxgroupp (Hall_max hallH)). by rewrite (sub_normal_Hall hallH). Qed. End PgroupProps. Implicit Arguments pgroupP [gT pi G]. Implicit Arguments constt1P [gT pi x]. Prenex Implicits pgroupP constt1P. Section NormalHall. Variables (gT : finGroupType) (pi : nat_pred). Implicit Types G H K : {group gT}. Lemma normal_max_pgroup_Hall G H : [max H | pi.-subgroup(G) H] -> H <| G -> pi.-Hall(G) H. Proof. case/maxgroupP=> /andP[sHG piH] maxH nsHG; have [_ nHG] := andP nsHG. rewrite /pHall sHG piH; apply/pnatP=> // p p_pr. rewrite inE /= -pnatE // -card_quotient //. case/Cauchy=> //= Hx; rewrite -sub1set -gen_subG -/<[Hx]> /order. case/inv_quotientS=> //= K -> sHK sKG {Hx}. rewrite card_quotient ?(subset_trans sKG) // => iKH; apply/negP=> pi_p. rewrite -iKH -divgS // (maxH K) ?divnn ?cardG_gt0 // in p_pr. by rewrite /psubgroup sKG /pgroup -(Lagrange sHK) mulnC pnat_mul iKH pi_p. Qed. Lemma setI_normal_Hall G H K : H <| G -> pi.-Hall(G) H -> K \subset G -> pi.-Hall(K) (H :&: K). Proof. move=> nsHG hallH sKG; apply: normal_max_pgroup_Hall; last first. by rewrite /= setIC (normalGI sKG nsHG). apply/maxgroupP; split=> [|M /andP[sMK piM] sHK_M]. by rewrite /psubgroup subsetIr (pgroupS (subsetIl _ _) (pHall_pgroup hallH)). apply/eqP; rewrite eqEsubset sHK_M subsetI sMK !andbT. by rewrite (sub_normal_Hall hallH) // (subset_trans sMK). Qed. End NormalHall. Section Morphim. Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}). Implicit Types (pi : nat_pred) (G H P : {group aT}). Lemma morphim_pgroup pi G : pi.-group G -> pi.-group (f @* G). Proof. by apply: pnat_dvd; exact: dvdn_morphim. Qed. Lemma morphim_odd G : odd #|G| -> odd #|f @* G|. Proof. by rewrite !odd_2'nat; exact: morphim_pgroup. Qed. Lemma pmorphim_pgroup pi G : pi.-group ('ker f) -> G \subset D -> pi.-group (f @* G) = pi.-group G. Proof. move=> piker sGD; apply/idP/idP=> [pifG|]; last exact: morphim_pgroup. apply: (@pgroupS _ _ (f @*^-1 (f @* G))); first by rewrite -sub_morphim_pre. by rewrite /pgroup card_morphpre ?morphimS // pnat_mul; exact/andP. Qed. Lemma morphim_p_index pi G H : H \subset D -> pi.-nat #|G : H| -> pi.-nat #|f @* G : f @* H|. Proof. by move=> sHD; apply: pnat_dvd; rewrite index_morphim ?subIset // sHD orbT. Qed. Lemma morphim_pHall pi G H : H \subset D -> pi.-Hall(G) H -> pi.-Hall(f @* G) (f @* H). Proof. move=> sHD /and3P[sHG piH pi'GH]. by rewrite /pHall morphimS // morphim_pgroup // morphim_p_index. Qed. Lemma pmorphim_pHall pi G H : G \subset D -> H \subset D -> pi.-subgroup(H :&: G) ('ker f) -> pi.-Hall(f @* G) (f @* H) = pi.-Hall(G) H. Proof. move=> sGD sHD /andP[/subsetIP[sKH sKG] piK]; rewrite !pHallE morphimSGK //. apply: andb_id2l => sHG; rewrite -(Lagrange sKH) -(Lagrange sKG) partnM //. by rewrite (part_pnat_id piK) !card_morphim !(setIidPr _) // eqn_pmul2l. Qed. Lemma morphim_Hall G H : H \subset D -> Hall G H -> Hall (f @* G) (f @* H). Proof. by move=> sHD /HallP[pi piH]; apply: (@pHall_Hall _ pi); exact: morphim_pHall. Qed. Lemma morphim_pSylow p G P : P \subset D -> p.-Sylow(G) P -> p.-Sylow(f @* G) (f @* P). Proof. exact: morphim_pHall. Qed. Lemma morphim_p_group P : p_group P -> p_group (f @* P). Proof. by move/morphim_pgroup; exact: pgroup_p. Qed. Lemma morphim_Sylow G P : P \subset D -> Sylow G P -> Sylow (f @* G) (f @* P). Proof. by move=> sPD /andP[pP hallP]; rewrite /Sylow morphim_p_group // morphim_Hall. Qed. Lemma morph_p_elt pi x : x \in D -> pi.-elt x -> pi.-elt (f x). Proof. by move=> Dx; apply: pnat_dvd; exact: morph_order. Qed. Lemma morph_constt pi x : x \in D -> f x.`_pi = (f x).`_pi. Proof. move=> Dx; rewrite -{2}(consttC pi x) morphM ?groupX //. rewrite consttM; last by rewrite !morphX //; exact: commuteX2. have: pi.-elt (f x.`_pi) by rewrite morph_p_elt ?groupX ?p_elt_constt //. have: pi^'.-elt (f x.`_pi^') by rewrite morph_p_elt ?groupX ?p_elt_constt //. by move/constt1P->; move/constt_p_elt->; rewrite mulg1. Qed. End Morphim. Section Pquotient. Variables (pi : nat_pred) (gT : finGroupType) (p : nat) (G H K : {group gT}). Hypothesis piK : pi.-group K. Lemma quotient_pgroup : pi.-group (K / H). Proof. exact: morphim_pgroup. Qed. Lemma quotient_pHall : K \subset 'N(H) -> pi.-Hall(G) K -> pi.-Hall(G / H) (K / H). Proof. exact: morphim_pHall. Qed. Lemma quotient_odd : odd #|K| -> odd #|K / H|. Proof. exact: morphim_odd. Qed. Lemma pquotient_pgroup : G \subset 'N(K) -> pi.-group (G / K) = pi.-group G. Proof. by move=> nKG; rewrite pmorphim_pgroup ?ker_coset. Qed. Lemma pquotient_pHall : K <| G -> K <| H -> pi.-Hall(G / K) (H / K) = pi.-Hall(G) H. Proof. case/andP=> sKG nKG; case/andP=> sKH nKH. by rewrite pmorphim_pHall // ker_coset /psubgroup subsetI sKH sKG. Qed. Lemma ltn_log_quotient : p.-group G -> H :!=: 1 -> H \subset G -> logn p #|G / H| < logn p #|G|. Proof. move=> pG ntH sHG; apply: contraLR (ltn_quotient ntH sHG); rewrite -!leqNgt. rewrite {2}(card_pgroup pG) {2}(card_pgroup (morphim_pgroup _ pG)). by case: (posnP p) => [-> //|]; exact: leq_pexp2l. Qed. End Pquotient. (* Application of card_Aut_cyclic to internal faithful action on cyclic *) (* p-subgroups. *) Section InnerAutCyclicPgroup. Variables (gT : finGroupType) (p : nat) (G C : {group gT}). Hypothesis nCG : G \subset 'N(C). Lemma logn_quotient_cent_cyclic_pgroup : p.-group C -> cyclic C -> logn p #|G / 'C_G(C)| <= (logn p #|C|).-1. Proof. move=> pC cycC; have [-> | ntC] := eqsVneq C 1. by rewrite cent1T setIT trivg_quotient cards1 logn1. have [p_pr _ [e oC]] := pgroup_pdiv pC ntC. rewrite -ker_conj_aut (card_isog (first_isog_loc _ _)) //. apply: leq_trans (dvdn_leq_log _ _ (cardSg (Aut_conj_aut _ _))) _ => //. rewrite card_Aut_cyclic // oC totient_pfactor //= logn_Gauss ?pfactorK //. by rewrite prime_coprime // gtnNdvd // -(subnKC (prime_gt1 p_pr)). Qed. Lemma p'group_quotient_cent_prime : prime p -> #|C| %| p -> p^'.-group (G / 'C_G(C)). Proof. move=> p_pr pC; have pgC: p.-group C := pnat_dvd pC (pnat_id p_pr). have [_ dv_p] := primeP p_pr; case/pred2P: {dv_p pC}(dv_p _ pC) => [|pC]. by move/card1_trivg->; rewrite cent1T setIT trivg_quotient pgroup1. have le_oGC := logn_quotient_cent_cyclic_pgroup pgC. rewrite /pgroup -partn_eq1 ?cardG_gt0 // -dvdn1 p_part pfactor_dvdn // logn1. by rewrite (leq_trans (le_oGC _)) ?prime_cyclic // pC ?(pfactorK 1). Qed. End InnerAutCyclicPgroup. Section PcoreDef. (* A functor needs to quantify over the finGroupType just beore the set. *) Variables (pi : nat_pred) (gT : finGroupType) (A : {set gT}). Definition pcore := \bigcap_(G | [max G | pi.-subgroup(A) G]) G. Canonical pcore_group : {group gT} := Eval hnf in [group of pcore]. End PcoreDef. Arguments Scope pcore [_ nat_scope group_scope]. Arguments Scope pcore_group [_ nat_scope Group_scope]. Notation "''O_' pi ( G )" := (pcore pi G) (at level 8, pi at level 2, format "''O_' pi ( G )") : group_scope. Notation "''O_' pi ( G )" := (pcore_group pi G) : Group_scope. Section PseriesDefs. Variables (pis : seq nat_pred) (gT : finGroupType) (A : {set gT}). Definition pcore_mod pi B := coset B @*^-1 'O_pi(A / B). Canonical pcore_mod_group pi B : {group gT} := Eval hnf in [group of pcore_mod pi B]. Definition pseries := foldr pcore_mod 1 (rev pis). Lemma pseries_group_set : group_set pseries. Proof. rewrite /pseries; case: rev => [|pi1 pi1']; exact: groupP. Qed. Canonical pseries_group : {group gT} := group pseries_group_set. End PseriesDefs. Arguments Scope pseries [_ seq_scope group_scope]. Local Notation ConsPred p := (@Cons nat_pred p%N) (only parsing). Notation "''O_{' p1 , .. , pn } ( A )" := (pseries (ConsPred p1 .. (ConsPred pn [::]) ..) A) (at level 8, format "''O_{' p1 , .. , pn } ( A )") : group_scope. Notation "''O_{' p1 , .. , pn } ( A )" := (pseries_group (ConsPred p1 .. (ConsPred pn [::]) ..) A) : Group_scope. Section PCoreProps. Variables (pi : nat_pred) (gT : finGroupType). Implicit Types (A : {set gT}) (G H M K : {group gT}). Lemma pcore_psubgroup G : pi.-subgroup(G) 'O_pi(G). Proof. have [M maxM _]: {M | [max M | pi.-subgroup(G) M] & 1%G \subset M}. by apply: maxgroup_exists; rewrite /psubgroup sub1G pgroup1. have sOM: 'O_pi(G) \subset M by exact: bigcap_inf. have /andP[piM sMG] := maxgroupp maxM. by rewrite /psubgroup (pgroupS sOM) // (subset_trans sOM). Qed. Lemma pcore_pgroup G : pi.-group 'O_pi(G). Proof. by case/andP: (pcore_psubgroup G). Qed. Lemma pcore_sub G : 'O_pi(G) \subset G. Proof. by case/andP: (pcore_psubgroup G). Qed. Lemma pcore_sub_Hall G H : pi.-Hall(G) H -> 'O_pi(G) \subset H. Proof. by move/Hall_max=> maxH; exact: bigcap_inf. Qed. Lemma pcore_max G H : pi.-group H -> H <| G -> H \subset 'O_pi(G). Proof. move=> piH nHG; apply/bigcapsP=> M maxM. exact: normal_sub_max_pgroup piH nHG. Qed. Lemma pcore_pgroup_id G : pi.-group G -> 'O_pi(G) = G. Proof. by move=> piG; apply/eqP; rewrite eqEsubset pcore_sub pcore_max. Qed. Lemma pcore_normal G : 'O_pi(G) <| G. Proof. rewrite /(_ <| G) pcore_sub; apply/subsetP=> x Gx. rewrite inE; apply/bigcapsP=> M maxM; rewrite sub_conjg. by apply: bigcap_inf; apply: max_pgroupJ; rewrite ?groupV. Qed. Lemma normal_Hall_pcore H G : pi.-Hall(G) H -> H <| G -> 'O_pi(G) = H. Proof. move=> hallH nHG; apply/eqP. rewrite eqEsubset (sub_normal_Hall hallH) ?pcore_sub ?pcore_pgroup //=. by rewrite pcore_max //= (pHall_pgroup hallH). Qed. Lemma eq_Hall_pcore G H : pi.-Hall(G) 'O_pi(G) -> pi.-Hall(G) H -> H :=: 'O_pi(G). Proof. move=> hallGpi hallH. exact: uniq_normal_Hall (pcore_normal G) (Hall_max hallH). Qed. Lemma sub_Hall_pcore G K : pi.-Hall(G) 'O_pi(G) -> K \subset G -> (K \subset 'O_pi(G)) = pi.-group K. Proof. by move=> hallGpi; exact: sub_normal_Hall (pcore_normal G). Qed. Lemma mem_Hall_pcore G x : pi.-Hall(G) 'O_pi(G) -> x \in G -> (x \in 'O_pi(G)) = pi.-elt x. Proof. move=> hallGpi; exact: mem_normal_Hall (pcore_normal G). Qed. Lemma sdprod_Hall_pcoreP H G : pi.-Hall(G) 'O_pi(G) -> reflect ('O_pi(G) ><| H = G) (pi^'.-Hall(G) H). Proof. move=> hallGpi; rewrite -(compl_pHall H hallGpi) complgC. exact: sdprod_normal_complP (pcore_normal G). Qed. Lemma sdprod_pcore_HallP H G : pi^'.-Hall(G) H -> reflect ('O_pi(G) ><| H = G) (pi.-Hall(G) 'O_pi(G)). Proof. exact: sdprod_normal_p'HallP (pcore_normal G). Qed. Lemma pcoreJ G x : 'O_pi(G :^ x) = 'O_pi(G) :^ x. Proof. apply/eqP; rewrite eqEsubset -sub_conjgV. rewrite !pcore_max ?pgroupJ ?pcore_pgroup ?normalJ ?pcore_normal //. by rewrite -(normalJ _ _ x) conjsgKV pcore_normal. Qed. End PCoreProps. Section MorphPcore. Implicit Types (pi : nat_pred) (gT rT : finGroupType). Lemma morphim_pcore pi : GFunctor.pcontinuous (pcore pi). Proof. move=> gT rT D G f; apply/bigcapsP=> M /normal_sub_max_pgroup; apply. by rewrite morphim_pgroup ?pcore_pgroup. apply: morphim_normal; exact: pcore_normal. Qed. Lemma pcoreS pi gT (G H : {group gT}) : H \subset G -> H :&: 'O_pi(G) \subset 'O_pi(H). Proof. move=> sHG; rewrite -{2}(setIidPl sHG). do 2!rewrite -(morphim_idm (subsetIl H _)) morphimIdom; exact: morphim_pcore. Qed. Canonical pcore_igFun pi := [igFun by pcore_sub pi & morphim_pcore pi]. Canonical pcore_gFun pi := [gFun by morphim_pcore pi]. Canonical pcore_pgFun pi := [pgFun by morphim_pcore pi]. Lemma pcore_char pi gT (G : {group gT}) : 'O_pi(G) \char G. Proof. exact: gFchar. Qed. Section PcoreMod. Variable F : GFunctor.pmap. Lemma pcore_mod_sub pi gT (G : {group gT}) : pcore_mod G pi (F _ G) \subset G. Proof. have nFD := gFnorm F G; rewrite sub_morphpre_im ?pcore_sub //=. by rewrite ker_coset_prim subIset // gen_subG gFsub. by apply: subset_trans (pcore_sub _ _) _; apply: morphimS. Qed. Lemma quotient_pcore_mod pi gT (G : {group gT}) (B : {set gT}) : pcore_mod G pi B / B = 'O_pi(G / B). Proof. apply: morphpreK; apply: subset_trans (pcore_sub _ _) _. by rewrite /= /quotient -morphimIdom morphimS ?subsetIl. Qed. Lemma morphim_pcore_mod pi gT rT (D G : {group gT}) (f : {morphism D >-> rT}) : f @* pcore_mod G pi (F _ G) \subset pcore_mod (f @* G) pi (F _ (f @* G)). Proof. have sDF: D :&: G \subset 'dom (coset (F _ G)). by rewrite setIC subIset ?gFnorm. have sDFf: D :&: G \subset 'dom (coset (F _ (f @* G)) \o f). by rewrite -sub_morphim_pre ?subsetIl // morphimIdom gFnorm. pose K := 'ker (restrm sDFf (coset (F _ (f @* G)) \o f)). have sFK: 'ker (restrm sDF (coset (F _ G))) \subset K. rewrite /K !ker_restrm ker_comp /= subsetI subsetIl /= -setIA. rewrite -sub_morphim_pre ?subsetIl //. by rewrite morphimIdom !ker_coset (setIidPr _) ?pmorphimF ?gFsub. have sOF := pcore_sub pi (G / F _ G); have sDD: D :&: G \subset D :&: G by []. rewrite -sub_morphim_pre -?quotientE; last first. by apply: subset_trans (gFnorm F _); rewrite morphimS ?pcore_mod_sub. suffices im_fact (H : {group gT}) : F _ G \subset H -> H \subset G -> factm sFK sDD @* (H / F _ G) = f @* H / F _ (f @* G). - rewrite -2?im_fact ?pcore_mod_sub ?gFsub //; try by rewrite -{1}[F _ G]ker_coset morphpreS ?sub1G. by rewrite quotient_pcore_mod morphim_pcore. move=> sFH sHG; rewrite -(morphimIdom _ (H / _)) /= {2}morphim_restrm setIid. rewrite -morphimIG ?ker_coset //. rewrite -(morphim_restrm sDF) morphim_factm morphim_restrm. by rewrite morphim_comp -quotientE -setIA morphimIdom (setIidPr _). Qed. Lemma pcore_mod_res pi gT rT (D : {group gT}) (f : {morphism D >-> rT}) : f @* pcore_mod D pi (F _ D) \subset pcore_mod (f @* D) pi (F _ (f @* D)). Proof. exact: morphim_pcore_mod. Qed. Lemma pcore_mod1 pi gT (G : {group gT}) : pcore_mod G pi 1 = 'O_pi(G). Proof. rewrite /pcore_mod; have inj1 := coset1_injm gT; rewrite -injmF ?norms1 //. by rewrite -(morphim_invmE inj1) morphim_invm ?norms1. Qed. End PcoreMod. Lemma pseries_rcons pi pis gT (A : {set gT}) : pseries (rcons pis pi) A = pcore_mod A pi (pseries pis A). Proof. by rewrite /pseries rev_rcons. Qed. Lemma pseries_subfun pis : GFunctor.closed (pseries pis) /\ GFunctor.pcontinuous (pseries pis). Proof. elim/last_ind: pis => [|pis pi [sFpi fFpi]]. by split=> [gT G | gT rT D G f]; rewrite (sub1G, morphim1). pose fF := [gFun by fFpi : GFunctor.continuous [igFun by sFpi & fFpi]]. pose F := [pgFun by fFpi : GFunctor.hereditary fF]. split=> [gT G | gT rT D G f]; rewrite !pseries_rcons ?(pcore_mod_sub F) //. exact: (morphim_pcore_mod F). Qed. Lemma pseries_sub pis : GFunctor.closed (pseries pis). Proof. by case: (pseries_subfun pis). Qed. Lemma morphim_pseries pis : GFunctor.pcontinuous (pseries pis). Proof. by case: (pseries_subfun pis). Qed. Lemma pseriesS pis : GFunctor.hereditary (pseries pis). Proof. exact: (morphim_pseries pis). Qed. Canonical pseries_igFun pis := [igFun by pseries_sub pis & morphim_pseries pis]. Canonical pseries_gFun pis := [gFun by morphim_pseries pis]. Canonical pseries_pgFun pis := [pgFun by morphim_pseries pis]. Lemma pseries_char pis gT (G : {group gT}) : pseries pis G \char G. Proof. exact: gFchar. Qed. Lemma pseries_normal pis gT (G : {group gT}) : pseries pis G <| G. Proof. exact: gFnormal. Qed. Lemma pseriesJ pis gT (G : {group gT}) x : pseries pis (G :^ x) = pseries pis G :^ x. Proof. rewrite -{1}(setIid G) -morphim_conj -(injmF _ (injm_conj G x)) //=. by rewrite morphim_conj (setIidPr (pseries_sub _ _)). Qed. Lemma pseries1 pi gT (G : {group gT}) : 'O_{pi}(G) = 'O_pi(G). Proof. exact: pcore_mod1. Qed. Lemma pseries_pop pi pis gT (G : {group gT}) : 'O_pi(G) = 1 -> pseries (pi :: pis) G = pseries pis G. Proof. by move=> OG1; rewrite /pseries rev_cons -cats1 foldr_cat /= pcore_mod1 OG1. Qed. Lemma pseries_pop2 pi1 pi2 gT (G : {group gT}) : 'O_pi1(G) = 1 -> 'O_{pi1, pi2}(G) = 'O_pi2(G). Proof. by move/pseries_pop->; exact: pseries1. Qed. Lemma pseries_sub_catl pi1s pi2s gT (G : {group gT}) : pseries pi1s G \subset pseries (pi1s ++ pi2s) G. Proof. elim/last_ind: pi2s => [|pi pis IHpi]; rewrite ?cats0 // -rcons_cat. by rewrite pseries_rcons; apply: subset_trans IHpi _; rewrite sub_cosetpre. Qed. Lemma quotient_pseries pis pi gT (G : {group gT}) : pseries (rcons pis pi) G / pseries pis G = 'O_pi(G / pseries pis G). Proof. by rewrite pseries_rcons quotient_pcore_mod. Qed. Lemma pseries_norm2 pi1s pi2s gT (G : {group gT}) : pseries pi2s G \subset 'N(pseries pi1s G). Proof. apply: subset_trans (normal_norm (pseries_normal pi1s G)); exact: pseries_sub. Qed. Lemma pseries_sub_catr pi1s pi2s gT (G : {group gT}) : pseries pi2s G \subset pseries (pi1s ++ pi2s) G. Proof. elim: pi1s => //= pi1 pi1s /subset_trans; apply. elim/last_ind: {pi1s pi2s}(_ ++ _) => [|pis pi IHpi]; first exact: sub1G. rewrite -rcons_cons (pseries_rcons _ (pi1 :: pis)). rewrite -sub_morphim_pre ?pseries_norm2 //. apply: pcore_max; last by rewrite morphim_normal ?pseries_normal. have: pi.-group (pseries (rcons pis pi) G / pseries pis G). by rewrite quotient_pseries pcore_pgroup. by apply: pnat_dvd; rewrite !card_quotient ?pseries_norm2 // indexgS. Qed. Lemma quotient_pseries2 pi1 pi2 gT (G : {group gT}) : 'O_{pi1, pi2}(G) / 'O_pi1(G) = 'O_pi2(G / 'O_pi1(G)). Proof. by rewrite -pseries1 -quotient_pseries. Qed. Lemma quotient_pseries_cat pi1s pi2s gT (G : {group gT}) : pseries (pi1s ++ pi2s) G / pseries pi1s G = pseries pi2s (G / pseries pi1s G). Proof. elim/last_ind: pi2s => [|pi2s pi IHpi]; first by rewrite cats0 trivg_quotient. have psN := pseries_normal _ G; set K := pseries _ G. case: (third_isom (pseries_sub_catl pi1s pi2s G) (psN _)) => //= f inj_f im_f. have nH2H: pseries pi2s (G / K) <| pseries (pi1s ++ rcons pi2s pi) G / K. rewrite -IHpi morphim_normal // -cats1 catA. by apply/andP; rewrite pseries_sub_catl pseries_norm2. apply: (quotient_inj nH2H). by apply/andP; rewrite /= -cats1 pseries_sub_catl pseries_norm2. rewrite /= quotient_pseries /= -IHpi -rcons_cat. rewrite -[G / _ / _](morphim_invm inj_f) //= {2}im_f //. rewrite -(@injmF [igFun of pcore pi]) /= ?injm_invm ?im_f // -quotient_pseries. by rewrite -im_f ?morphim_invm ?morphimS ?normal_sub. Qed. Lemma pseries_catl_id pi1s pi2s gT (G : {group gT}) : pseries pi1s (pseries (pi1s ++ pi2s) G) = pseries pi1s G. Proof. elim/last_ind: pi1s => [//|pi1s pi IHpi] in pi2s *. apply: (@quotient_inj _ (pseries_group pi1s G)). - rewrite /= -(IHpi (pi :: pi2s)) cat_rcons /(_ <| _) pseries_norm2. by rewrite -cats1 pseries_sub_catl. - by rewrite /= /(_ <| _) pseries_norm2 -cats1 pseries_sub_catl. rewrite /= cat_rcons -(IHpi (pi :: pi2s)) {1}quotient_pseries IHpi. apply/eqP; rewrite quotient_pseries eqEsubset !pcore_max ?pcore_pgroup //=. rewrite -quotient_pseries morphim_normal // /(_ <| _) pseries_norm2. by rewrite -cat_rcons pseries_sub_catl. by rewrite (char_normal_trans (pcore_char _ _)) ?quotient_normal ?gFnormal. Qed. Lemma pseries_char_catl pi1s pi2s gT (G : {group gT}) : pseries pi1s G \char pseries (pi1s ++ pi2s) G. Proof. by rewrite -(pseries_catl_id pi1s pi2s G) pseries_char. Qed. Lemma pseries_catr_id pi1s pi2s gT (G : {group gT}) : pseries pi2s (pseries (pi1s ++ pi2s) G) = pseries pi2s G. Proof. elim/last_ind: pi2s => [//|pi2s pi IHpi] in G *. have Epis: pseries pi2s (pseries (pi1s ++ rcons pi2s pi) G) = pseries pi2s G. by rewrite -cats1 catA -2!IHpi pseries_catl_id. apply: (@quotient_inj _ (pseries_group pi2s G)). - by rewrite /= -Epis /(_ <| _) pseries_norm2 -cats1 pseries_sub_catl. - by rewrite /= /(_ <| _) pseries_norm2 -cats1 pseries_sub_catl. rewrite /= -Epis {1}quotient_pseries Epis quotient_pseries. apply/eqP; rewrite eqEsubset !pcore_max ?pcore_pgroup //=. rewrite -quotient_pseries morphim_normal // /(_ <| _) pseries_norm2. by rewrite pseries_sub_catr. apply: char_normal_trans (pcore_char pi _) (morphim_normal _ _). exact: pseries_normal. Qed. Lemma pseries_char_catr pi1s pi2s gT (G : {group gT}) : pseries pi2s G \char pseries (pi1s ++ pi2s) G. Proof. by rewrite -(pseries_catr_id pi1s pi2s G) pseries_char. Qed. Lemma pcore_modp pi gT (G H : {group gT}) : H <| G -> pi.-group H -> pcore_mod G pi H = 'O_pi(G). Proof. move=> nsHG piH; apply/eqP; rewrite eqEsubset andbC. have nHG := normal_norm nsHG; have sOG := subset_trans (pcore_sub pi _). rewrite -sub_morphim_pre ?(sOG, morphim_pcore) // pcore_max //. rewrite -(pquotient_pgroup piH) ?subsetIl //. by rewrite quotient_pcore_mod pcore_pgroup. by rewrite -{2}(quotientGK nsHG) morphpre_normal ?pcore_normal ?sOG ?morphimS. Qed. Lemma pquotient_pcore pi gT (G H : {group gT}) : H <| G -> pi.-group H -> 'O_pi(G / H) = 'O_pi(G) / H. Proof. by move=> nsHG piH; rewrite -quotient_pcore_mod pcore_modp. Qed. Lemma trivg_pcore_quotient pi gT (G : {group gT}) : 'O_pi(G / 'O_pi(G)) = 1. Proof. by rewrite pquotient_pcore ?pcore_normal ?pcore_pgroup // trivg_quotient. Qed. Lemma pseries_rcons_id pis pi gT (G : {group gT}) : pseries (rcons (rcons pis pi) pi) G = pseries (rcons pis pi) G. Proof. apply/eqP; rewrite -!cats1 eqEsubset pseries_sub_catl andbT -catA. rewrite -(quotientSGK _ (pseries_sub_catl _ _ _)) ?pseries_norm2 //. rewrite !quotient_pseries_cat -quotient_sub1 ?pseries_norm2 //. by rewrite quotient_pseries_cat /= !pseries1 trivg_pcore_quotient. Qed. End MorphPcore. Section EqPcore. Variables gT : finGroupType. Implicit Types (pi rho : nat_pred) (G H : {group gT}). Lemma sub_in_pcore pi rho G : {in \pi(G), {subset pi <= rho}} -> 'O_pi(G) \subset 'O_rho(G). Proof. move=> pi_sub_rho; rewrite pcore_max ?pcore_normal //. apply: sub_in_pnat (pcore_pgroup _ _) => p. move/(piSg (pcore_sub _ _)); exact: pi_sub_rho. Qed. Lemma sub_pcore pi rho G : {subset pi <= rho} -> 'O_pi(G) \subset 'O_rho(G). Proof. by move=> pi_sub_rho; exact: sub_in_pcore (in1W pi_sub_rho). Qed. Lemma eq_in_pcore pi rho G : {in \pi(G), pi =i rho} -> 'O_pi(G) = 'O_rho(G). Proof. move=> eq_pi_rho; apply/eqP; rewrite eqEsubset. by rewrite !sub_in_pcore // => p /eq_pi_rho->. Qed. Lemma eq_pcore pi rho G : pi =i rho -> 'O_pi(G) = 'O_rho(G). Proof. by move=> eq_pi_rho; exact: eq_in_pcore (in1W eq_pi_rho). Qed. Lemma pcoreNK pi G : 'O_pi^'^'(G) = 'O_pi(G). Proof. by apply: eq_pcore; exact: negnK. Qed. Lemma eq_p'core pi rho G : pi =i rho -> 'O_pi^'(G) = 'O_rho^'(G). Proof. by move/eq_negn; exact: eq_pcore. Qed. Lemma sdprod_Hall_p'coreP pi H G : pi^'.-Hall(G) 'O_pi^'(G) -> reflect ('O_pi^'(G) ><| H = G) (pi.-Hall(G) H). Proof. by rewrite -(pHallNK pi G H); exact: sdprod_Hall_pcoreP. Qed. Lemma sdprod_p'core_HallP pi H G : pi.-Hall(G) H -> reflect ('O_pi^'(G) ><| H = G) (pi^'.-Hall(G) 'O_pi^'(G)). Proof. by rewrite -(pHallNK pi G H); exact: sdprod_pcore_HallP. Qed. Lemma pcoreI pi rho G : 'O_[predI pi & rho](G) = 'O_pi('O_rho(G)). Proof. apply/eqP; rewrite eqEsubset !pcore_max //. - rewrite /pgroup pnatI [pnat _ _]pcore_pgroup. exact: pgroupS (pcore_sub _ _) (pcore_pgroup _ _). - exact: char_normal_trans (pcore_char _ _) (pcore_normal _ _). - by apply: sub_in_pnat (pcore_pgroup _ _) => p _ /andP[]. apply/andP; split; first by apply: sub_pcore => p /andP[]. by rewrite (subset_trans (pcore_sub _ _)) ?gFnorm. Qed. Lemma bigcap_p'core pi G : G :&: \bigcap_(p < #|G|.+1 | (p : nat) \in pi) 'O_p^'(G) = 'O_pi^'(G). Proof. apply/eqP; rewrite eqEsubset subsetI pcore_sub pcore_max /=. - by apply/bigcapsP=> p pi_p; apply: sub_pcore => r; apply: contraNneq => ->. - apply/pgroupP=> q q_pr qGpi'; apply: contraL (eqxx q) => /= pi_q. apply: (pgroupP (pcore_pgroup q^' G)) => //. have qG: q %| #|G| by rewrite (dvdn_trans qGpi') // cardSg ?subsetIl. have ltqG: q < #|G|.+1 by rewrite ltnS dvdn_leq. rewrite (dvdn_trans qGpi') ?cardSg ?subIset //= orbC. by rewrite (bigcap_inf (Ordinal ltqG)). rewrite /normal subsetIl normsI ?normG // norms_bigcap //. by apply/bigcapsP => p _; exact: gFnorm. Qed. Lemma coprime_pcoreC (rT : finGroupType) pi G (R : {group rT}) : coprime #|'O_pi(G)| #|'O_pi^'(R)|. Proof. exact: pnat_coprime (pcore_pgroup _ _) (pcore_pgroup _ _). Qed. Lemma TI_pcoreC pi G H : 'O_pi(G) :&: 'O_pi^'(H) = 1. Proof. by rewrite coprime_TIg ?coprime_pcoreC. Qed. Lemma pcore_setI_normal pi G H : H <| G -> 'O_pi(G) :&: H = 'O_pi(H). Proof. move=> nsHG; apply/eqP; rewrite eqEsubset subsetI pcore_sub. rewrite !pcore_max ?(pgroupS (subsetIl _ H)) ?pcore_pgroup //=. exact: char_normal_trans (pcore_char pi H) nsHG. by rewrite setIC (normalGI (normal_sub nsHG)) ?pcore_normal. Qed. End EqPcore. Implicit Arguments sdprod_Hall_pcoreP [gT pi G H]. Implicit Arguments sdprod_Hall_p'coreP [gT pi G H]. Section Injm. Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}). Hypothesis injf : 'injm f. Implicit Types (A : {set aT}) (G H : {group aT}). Lemma injm_pgroup pi A : A \subset D -> pi.-group (f @* A) = pi.-group A. Proof. by move=> sAD; rewrite /pgroup card_injm. Qed. Lemma injm_pelt pi x : x \in D -> pi.-elt (f x) = pi.-elt x. Proof. by move=> Dx; rewrite /p_elt order_injm. Qed. Lemma injm_pHall pi G H : G \subset D -> H \subset D -> pi.-Hall(f @* G) (f @* H) = pi.-Hall(G) H. Proof. by move=> sGD sGH; rewrite !pHallE injmSK ?card_injm. Qed. Lemma injm_pcore pi G : G \subset D -> f @* 'O_pi(G) = 'O_pi(f @* G). Proof. exact: injmF. Qed. Lemma injm_pseries pis G : G \subset D -> f @* pseries pis G = pseries pis (f @* G). Proof. exact: injmF. Qed. End Injm. Section Isog. Variables (aT rT : finGroupType) (G : {group aT}) (H : {group rT}). Lemma isog_pgroup pi : G \isog H -> pi.-group G = pi.-group H. Proof. by move=> isoGH; rewrite /pgroup (card_isog isoGH). Qed. Lemma isog_pcore pi : G \isog H -> 'O_pi(G) \isog 'O_pi(H). Proof. exact: gFisog. Qed. Lemma isog_pseries pis : G \isog H -> pseries pis G \isog pseries pis H. Proof. exact: gFisog. Qed. End Isog. mathcomp-1.5/theories/abelian.v0000644000175000017500000025641112307636117015576 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq path div fintype. Require Import finfun bigop finset prime binomial fingroup morphism perm. Require Import automorphism action quotient gfunctor gproduct zmodp cyclic. Require Import pgroup gseries nilpotent sylow. (******************************************************************************) (* Constructions based on abelian groups and their structure, with some *) (* emphasis on elementary abelian p-groups. *) (* 'Ldiv_n() == the set of all x that satisfy x ^+ n = 1, or, *) (* equivalently the set of x whose order divides n. *) (* 'Ldiv_n(G) == the set of x in G that satisfy x ^+ n = 1. *) (* := G :&: 'Ldiv_n() (pure Notation) *) (* exponent G == the exponent of G: the least e such that x ^+ e = 1 *) (* for all x in G (the LCM of the orders of x \in G). *) (* If G is nilpotent its exponent is reached. Note that *) (* `exponent G %| m' reads as `G has exponent m'. *) (* 'm(G) == the generator rank of G: the size of a smallest *) (* generating set for G (this is a basis for G if G *) (* abelian). *) (* abelian_type G == the abelian type of G : if G is abelian, a lexico- *) (* graphically maximal sequence of the orders of the *) (* elements of a minimal basis of G (if G is a p-group *) (* this is the sequence of orders for any basis of G, *) (* sorted in decending order). *) (* homocyclic G == G is the direct product of cycles of equal order, *) (* i.e., G is abelian with constant abelian type. *) (* p.-abelem G == G is an elementary abelian p-group, i.e., it is *) (* an abelian p-group of exponent p, and thus of order *) (* p ^ 'm(G) and rank (logn p #|G|). *) (* is_abelem G == G is an elementary abelian p-group for some prime p. *) (* 'E_p(G) == the set of elementary abelian p-subgroups of G. *) (* := [set E : {group _} | p.-abelem E & E \subset G] *) (* 'E_p^n(G) == the set of elementary abelian p-subgroups of G of *) (* order p ^ n (or, equivalently, of rank n). *) (* := [set E in 'E_p(G) | logn p #|E| == n] *) (* := [set E in 'E_p(G) | #|E| == p ^ n]%N if p is prime *) (* 'E*_p(G) == the set of maximal elementary abelian p-subgroups *) (* of G. *) (* := [set E | [max E | E \in 'E_p(G)]] *) (* 'E^n(G) == the set of elementary abelian subgroups of G that *) (* have gerank n (i.e., p-rank n for some prime p). *) (* := \bigcup_(0 <= p < #|G|.+1) 'E_p^n(G) *) (* 'r_p(G) == the p-rank of G: the maximal rank of an elementary *) (* subgroup of G. *) (* := \max_(E in 'E_p(G)) logn p #|E|. *) (* 'r(G) == the rank of G. *) (* := \max_(0 <= p < #|G|.+1) 'm_p(G). *) (* Note that 'r(G) coincides with 'r_p(G) if G is a p-group, and with 'm(G) *) (* if G is abelian, but is much more useful than 'm(G) in the proof of the *) (* Odd Order Theorem. *) (* 'Ohm_n(G) == the group generated by the x in G with order p ^ m *) (* for some prime p and some m <= n. Usually, G will be *) (* a p-group, so 'Ohm_n(G) will be generated by *) (* 'Ldiv_(p ^ n)(G), set of elements of G of order at *) (* most p ^ n. If G is also abelian then 'Ohm_n(G) *) (* consists exactly of those element, and the abelian *) (* type of G can be computed from the orders of the *) (* 'Ohm_n(G) subgroups. *) (* 'Mho^n(G) == the group generated by the x ^+ (p ^ n) for x a *) (* p-element of G for some prime p. Usually G is a *) (* p-group, and 'Mho^n(G) is generated by all such *) (* x ^+ (p ^ n); it consists of exactly these if G is *) (* also abelian. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section AbelianDefs. (* We defer the definition of the functors ('Omh_n(G), 'Mho^n(G)) because *) (* they must quantify over the finGroupType explicitly. *) Variable gT : finGroupType. Implicit Types (x : gT) (A B : {set gT}) (pi : nat_pred) (p n : nat). Definition Ldiv n := [set x : gT | x ^+ n == 1]. Definition exponent A := \big[lcmn/1%N]_(x in A) #[x]. Definition abelem p A := [&& p.-group A, abelian A & exponent A %| p]. Definition is_abelem A := abelem (pdiv #|A|) A. Definition pElem p A := [set E : {group gT} | E \subset A & abelem p E]. Definition pnElem p n A := [set E in pElem p A | logn p #|E| == n]. Definition nElem n A := \bigcup_(0 <= p < #|A|.+1) pnElem p n A. Definition pmaxElem p A := [set E | [max E | E \in pElem p A]]. Definition p_rank p A := \max_(E in pElem p A) logn p #|E|. Definition rank A := \max_(0 <= p < #|A|.+1) p_rank p A. Definition gen_rank A := #|[arg min_(B < A | <> == A) #|B|]|. (* The definition of abelian_type depends on an existence lemma. *) (* The definition of homocyclic depends on abelian_type. *) End AbelianDefs. Arguments Scope exponent [_ group_scope]. Arguments Scope abelem [_ nat_scope group_scope]. Arguments Scope is_abelem [_ group_scope]. Arguments Scope pElem [_ nat_scope group_scope]. Arguments Scope pnElem [_ nat_scope nat_scope group_scope]. Arguments Scope nElem [_ nat_scope group_scope]. Arguments Scope pmaxElem [_ nat_scope group_scope]. Arguments Scope p_rank [_ nat_scope group_scope]. Arguments Scope rank [_ group_scope]. Arguments Scope gen_rank [_ group_scope]. Notation "''Ldiv_' n ()" := (Ldiv _ n) (at level 8, n at level 2, format "''Ldiv_' n ()") : group_scope. Notation "''Ldiv_' n ( G )" := (G :&: 'Ldiv_n()) (at level 8, n at level 2, format "''Ldiv_' n ( G )") : group_scope. Prenex Implicits exponent. Notation "p .-abelem" := (abelem p) (at level 2, format "p .-abelem") : group_scope. Notation "''E_' p ( G )" := (pElem p G) (at level 8, p at level 2, format "''E_' p ( G )") : group_scope. Notation "''E_' p ^ n ( G )" := (pnElem p n G) (at level 8, p, n at level 2, format "''E_' p ^ n ( G )") : group_scope. Notation "''E' ^ n ( G )" := (nElem n G) (at level 8, n at level 2, format "''E' ^ n ( G )") : group_scope. Notation "''E*_' p ( G )" := (pmaxElem p G) (at level 8, p at level 2, format "''E*_' p ( G )") : group_scope. Notation "''m' ( A )" := (gen_rank A) (at level 8, format "''m' ( A )") : group_scope. Notation "''r' ( A )" := (rank A) (at level 8, format "''r' ( A )") : group_scope. Notation "''r_' p ( A )" := (p_rank p A) (at level 8, p at level 2, format "''r_' p ( A )") : group_scope. Section Functors. (* A functor needs to quantify over the finGroupType just beore the set. *) Variables (n : nat) (gT : finGroupType) (A : {set gT}). Definition Ohm := <<[set x in A | x ^+ (pdiv #[x] ^ n) == 1]>>. Definition Mho := <<[set x ^+ (pdiv #[x] ^ n) | x in A & (pdiv #[x]).-elt x]>>. Canonical Ohm_group : {group gT} := Eval hnf in [group of Ohm]. Canonical Mho_group : {group gT} := Eval hnf in [group of Mho]. Lemma pdiv_p_elt (p : nat) (x : gT) : p.-elt x -> x != 1 -> pdiv #[x] = p. Proof. move=> p_x; rewrite /order -cycle_eq1. by case/(pgroup_pdiv p_x)=> p_pr _ [k ->]; rewrite pdiv_pfactor. Qed. Lemma OhmPredP (x : gT) : reflect (exists2 p, prime p & x ^+ (p ^ n) = 1) (x ^+ (pdiv #[x] ^ n) == 1). Proof. have [-> | nt_x] := eqVneq x 1. by rewrite expg1n eqxx; left; exists 2; rewrite ?expg1n. apply: (iffP idP) => [/eqP | [p p_pr /eqP x_pn]]. by exists (pdiv #[x]); rewrite ?pdiv_prime ?order_gt1. rewrite (@pdiv_p_elt p) //; rewrite -order_dvdn in x_pn. by rewrite [p_elt _ _](pnat_dvd x_pn) // pnat_exp pnat_id. Qed. Lemma Mho_p_elt (p : nat) x : x \in A -> p.-elt x -> x ^+ (p ^ n) \in Mho. Proof. move=> Ax p_x; case: (eqVneq x 1) => [-> | ntx]; first by rewrite groupX. by apply: mem_gen; apply/imsetP; exists x; rewrite ?inE ?Ax (pdiv_p_elt p_x). Qed. End Functors. Arguments Scope Ohm [nat_scope _ group_scope]. Arguments Scope Ohm_group [nat_scope _ group_scope]. Arguments Scope Mho [nat_scope _ group_scope]. Arguments Scope Mho_group [nat_scope _ group_scope]. Implicit Arguments OhmPredP [n gT x]. Notation "''Ohm_' n ( G )" := (Ohm n G) (at level 8, n at level 2, format "''Ohm_' n ( G )") : group_scope. Notation "''Ohm_' n ( G )" := (Ohm_group n G) : Group_scope. Notation "''Mho^' n ( G )" := (Mho n G) (at level 8, n at level 2, format "''Mho^' n ( G )") : group_scope. Notation "''Mho^' n ( G )" := (Mho_group n G) : Group_scope. Section ExponentAbelem. Variable gT : finGroupType. Implicit Types (p n : nat) (pi : nat_pred) (x : gT) (A B C : {set gT}). Implicit Types E G H K P X Y : {group gT}. Lemma LdivP A n x : reflect (x \in A /\ x ^+ n = 1) (x \in 'Ldiv_n(A)). Proof. by rewrite !inE; apply: (iffP andP) => [] [-> /eqP]. Qed. Lemma dvdn_exponent x A : x \in A -> #[x] %| exponent A. Proof. by move=> Ax; rewrite (biglcmn_sup x). Qed. Lemma expg_exponent x A : x \in A -> x ^+ exponent A = 1. Proof. by move=> Ax; apply/eqP; rewrite -order_dvdn dvdn_exponent. Qed. Lemma exponentS A B : A \subset B -> exponent A %| exponent B. Proof. by move=> sAB; apply/dvdn_biglcmP=> x Ax; rewrite dvdn_exponent ?(subsetP sAB). Qed. Lemma exponentP A n : reflect (forall x, x \in A -> x ^+ n = 1) (exponent A %| n). Proof. apply: (iffP (dvdn_biglcmP _ _ _)) => eAn x Ax. by apply/eqP; rewrite -order_dvdn eAn. by rewrite order_dvdn eAn. Qed. Implicit Arguments exponentP [A n]. Lemma trivg_exponent G : (G :==: 1) = (exponent G %| 1). Proof. rewrite -subG1. by apply/subsetP/exponentP=> trG x /trG; rewrite expg1 => /set1P. Qed. Lemma exponent1 : exponent [1 gT] = 1%N. Proof. by apply/eqP; rewrite -dvdn1 -trivg_exponent eqxx. Qed. Lemma exponent_dvdn G : exponent G %| #|G|. Proof. by apply/dvdn_biglcmP=> x Gx; exact: order_dvdG. Qed. Lemma exponent_gt0 G : 0 < exponent G. Proof. exact: dvdn_gt0 (exponent_dvdn G). Qed. Hint Resolve exponent_gt0. Lemma pnat_exponent pi G : pi.-nat (exponent G) = pi.-group G. Proof. congr (_ && _); first by rewrite cardG_gt0 exponent_gt0. apply: eq_all_r => p; rewrite !mem_primes cardG_gt0 exponent_gt0 /=. apply: andb_id2l => p_pr; apply/idP/idP=> pG. exact: dvdn_trans pG (exponent_dvdn G). by case/Cauchy: pG => // x Gx <-; exact: dvdn_exponent. Qed. Lemma exponentJ A x : exponent (A :^ x) = exponent A. Proof. rewrite /exponent (reindex_inj (conjg_inj x)). by apply: eq_big => [y | y _]; rewrite ?orderJ ?memJ_conjg. Qed. Lemma exponent_witness G : nilpotent G -> {x | x \in G & exponent G = #[x]}. Proof. move=> nilG; have [//=| /= x Gx max_x] := @arg_maxP _ 1 (mem G) order. exists x => //; apply/eqP; rewrite eqn_dvd dvdn_exponent // andbT. apply/dvdn_biglcmP=> y Gy; apply/dvdn_partP=> //= p. rewrite mem_primes => /andP[p_pr _]; have p_gt1: p > 1 := prime_gt1 p_pr. rewrite p_part pfactor_dvdn // -(leq_exp2l _ _ p_gt1) -!p_part. rewrite -(leq_pmul2r (part_gt0 p^' #[x])) partnC // -!order_constt. rewrite -orderM ?order_constt ?coprime_partC // ?max_x ?groupM ?groupX //. case/dprodP: (nilpotent_pcoreC p nilG) => _ _ cGpGp' _. have inGp := mem_normal_Hall (nilpotent_pcore_Hall _ nilG) (pcore_normal _ _). by red; rewrite -(centsP cGpGp') // inGp ?p_elt_constt ?groupX. Qed. Lemma exponent_cycle x : exponent <[x]> = #[x]. Proof. by apply/eqP; rewrite eqn_dvd exponent_dvdn dvdn_exponent ?cycle_id. Qed. Lemma exponent_cyclic X : cyclic X -> exponent X = #|X|. Proof. by case/cyclicP=> x ->; exact: exponent_cycle. Qed. Lemma primes_exponent G : primes (exponent G) = primes (#|G|). Proof. apply/eq_primes => p; rewrite !mem_primes exponent_gt0 cardG_gt0 /=. by apply: andb_id2l => p_pr; apply: negb_inj; rewrite -!p'natE // pnat_exponent. Qed. Lemma pi_of_exponent G : \pi(exponent G) = \pi(G). Proof. by rewrite /pi_of primes_exponent. Qed. Lemma partn_exponentS pi H G : H \subset G -> #|G|`_pi %| #|H| -> (exponent H)`_pi = (exponent G)`_pi. Proof. move=> sHG Gpi_dvd_H; apply/eqP; rewrite eqn_dvd. rewrite partn_dvd ?exponentS ?exponent_gt0 //=; apply/dvdn_partP=> // p. rewrite pi_of_part ?exponent_gt0 // => /andP[_ /= pi_p]. have sppi: {subset (p : nat_pred) <= pi} by move=> q /eqnP->. have [P sylP] := Sylow_exists p H; have sPH := pHall_sub sylP. have{sylP} sylP: p.-Sylow(G) P. rewrite pHallE (subset_trans sPH) //= (card_Hall sylP) eqn_dvd andbC. by rewrite -{1}(partn_part _ sppi) !partn_dvd ?cardSg ?cardG_gt0. rewrite partn_part ?partn_biglcm //. apply: (@big_ind _ (dvdn^~ _)) => [|m n|x Gx]; first exact: dvd1n. by rewrite dvdn_lcm => ->. rewrite -order_constt; have p_y := p_elt_constt p x; set y := x.`_p in p_y *. have sYG: <[y]> \subset G by rewrite cycle_subG groupX. have [z _ Pyz] := Sylow_Jsub sylP sYG p_y. rewrite (bigD1 (y ^ z)) ?(subsetP sPH) -?cycle_subG ?cycleJ //=. by rewrite orderJ part_pnat_id ?dvdn_lcml // (pi_pnat p_y). Qed. Lemma exponent_Hall pi G H : pi.-Hall(G) H -> exponent H = (exponent G)`_pi. Proof. move=> hallH; have [sHG piH _] := and3P hallH. rewrite -(partn_exponentS sHG) -?(card_Hall hallH) ?part_pnat_id //. by apply: pnat_dvd piH; exact: exponent_dvdn. Qed. Lemma exponent_Zgroup G : Zgroup G -> exponent G = #|G|. Proof. move/forall_inP=> ZgG; apply/eqP; rewrite eqn_dvd exponent_dvdn. apply/(dvdn_partP _ (cardG_gt0 _)) => p _. have [S sylS] := Sylow_exists p G; rewrite -(card_Hall sylS). have /cyclicP[x defS]: cyclic S by rewrite ZgG ?(p_Sylow sylS). by rewrite defS dvdn_exponent // -cycle_subG -defS (pHall_sub sylS). Qed. Lemma cprod_exponent A B G : A \* B = G -> lcmn (exponent A) (exponent B) = (exponent G). Proof. case/cprodP=> [[K H -> ->{A B}] <- cKH]. apply/eqP; rewrite eqn_dvd dvdn_lcm !exponentS ?mulG_subl ?mulG_subr //=. apply/exponentP=> _ /imset2P[x y Kx Hy ->]. rewrite -[1]mulg1 expgMn; last by red; rewrite -(centsP cKH). congr (_ * _); apply/eqP; rewrite -order_dvdn. by rewrite (dvdn_trans (dvdn_exponent Kx)) ?dvdn_lcml. by rewrite (dvdn_trans (dvdn_exponent Hy)) ?dvdn_lcmr. Qed. Lemma dprod_exponent A B G : A \x B = G -> lcmn (exponent A) (exponent B) = (exponent G). Proof. case/dprodP=> [[K H -> ->{A B}] defG cKH _]. by apply: cprod_exponent; rewrite cprodE. Qed. Lemma sub_LdivT A n : (A \subset 'Ldiv_n()) = (exponent A %| n). Proof. by apply/subsetP/exponentP=> eAn x /eAn; rewrite inE => /eqP. Qed. Lemma LdivT_J n x : 'Ldiv_n() :^ x = 'Ldiv_n(). Proof. apply/setP=> y; rewrite !inE mem_conjg inE -conjXg. by rewrite (canF_eq (conjgKV x)) conj1g. Qed. Lemma LdivJ n A x : 'Ldiv_n(A :^ x) = 'Ldiv_n(A) :^ x. Proof. by rewrite conjIg LdivT_J. Qed. Lemma sub_Ldiv A n : (A \subset 'Ldiv_n(A)) = (exponent A %| n). Proof. by rewrite subsetI subxx sub_LdivT. Qed. Lemma group_Ldiv G n : abelian G -> group_set 'Ldiv_n(G). Proof. move=> cGG; apply/group_setP. split=> [|x y]; rewrite !inE ?group1 ?expg1n //=. case/andP=> Gx /eqP xn /andP[Gy /eqP yn]. rewrite groupM //= expgMn ?xn ?yn ?mulg1 //; exact: (centsP cGG). Qed. Lemma abelian_exponent_gen A : abelian A -> exponent <> = exponent A. Proof. rewrite -abelian_gen; set n := exponent A; set G := <> => cGG. apply/eqP; rewrite eqn_dvd andbC exponentS ?subset_gen //= -sub_Ldiv. rewrite -(gen_set_id (group_Ldiv n cGG)) genS // subsetI subset_gen /=. by rewrite sub_LdivT. Qed. Lemma abelem_pgroup p A : p.-abelem A -> p.-group A. Proof. by case/andP. Qed. Lemma abelem_abelian p A : p.-abelem A -> abelian A. Proof. by case/and3P. Qed. Lemma abelem1 p : p.-abelem [1 gT]. Proof. by rewrite /abelem pgroup1 abelian1 exponent1 dvd1n. Qed. Lemma abelemE p G : prime p -> p.-abelem G = abelian G && (exponent G %| p). Proof. move=> p_pr; rewrite /abelem -pnat_exponent andbA -!(andbC (_ %| _)). by case: (dvdn_pfactor _ 1 p_pr) => // [[k _ ->]]; rewrite pnat_exp pnat_id. Qed. Lemma abelemP p G : prime p -> reflect (abelian G /\ forall x, x \in G -> x ^+ p = 1) (p.-abelem G). Proof. by move=> p_pr; rewrite abelemE //; apply: (iffP andP) => [] [-> /exponentP]. Qed. Lemma abelem_order_p p G x : p.-abelem G -> x \in G -> x != 1 -> #[x] = p. Proof. case/and3P=> pG _ eG Gx; rewrite -cycle_eq1 => ntX. have{ntX} [p_pr p_x _] := pgroup_pdiv (mem_p_elt pG Gx) ntX. by apply/eqP; rewrite eqn_dvd p_x andbT order_dvdn (exponentP eG). Qed. Lemma cyclic_abelem_prime p X : p.-abelem X -> cyclic X -> X :!=: 1 -> #|X| = p. Proof. move=> abelX cycX; case/cyclicP: cycX => x -> in abelX *. by rewrite cycle_eq1; exact: abelem_order_p abelX (cycle_id x). Qed. Lemma cycle_abelem p x : p.-elt x || prime p -> p.-abelem <[x]> = (#[x] %| p). Proof. move=> p_xVpr; rewrite /abelem cycle_abelian /=. apply/andP/idP=> [[_ xp1] | x_dvd_p]. by rewrite order_dvdn (exponentP xp1) ?cycle_id. split; last exact: dvdn_trans (exponent_dvdn _) x_dvd_p. by case/orP: p_xVpr => // /pnat_id; exact: pnat_dvd. Qed. Lemma exponent2_abelem G : exponent G %| 2 -> 2.-abelem G. Proof. move/exponentP=> expG; apply/abelemP=> //; split=> //. apply/centsP=> x Gx y Gy; apply: (mulIg x); apply: (mulgI y). by rewrite -!mulgA !(mulgA y) -!(expgS _ 1) !expG ?mulg1 ?groupM. Qed. Lemma prime_abelem p G : prime p -> #|G| = p -> p.-abelem G. Proof. move=> p_pr oG; rewrite /abelem -oG exponent_dvdn. by rewrite /pgroup cyclic_abelian ?prime_cyclic ?oG ?pnat_id. Qed. Lemma abelem_cyclic p G : p.-abelem G -> cyclic G = (logn p #|G| <= 1). Proof. move=> abelG; have [pG _ expGp] := and3P abelG. case: (eqsVneq G 1) => [-> | ntG]; first by rewrite cyclic1 cards1 logn1. have [p_pr _ [e oG]] := pgroup_pdiv pG ntG; apply/idP/idP. case/cyclicP=> x defG; rewrite -(pfactorK 1 p_pr) dvdn_leq_log ?prime_gt0 //. by rewrite defG order_dvdn (exponentP expGp) // defG cycle_id. by rewrite oG pfactorK // ltnS leqn0 => e0; rewrite prime_cyclic // oG (eqP e0). Qed. Lemma abelemS p H G : H \subset G -> p.-abelem G -> p.-abelem H. Proof. move=> sHG /and3P[cGG pG Gp1]; rewrite /abelem. by rewrite (pgroupS sHG) // (abelianS sHG) // (dvdn_trans (exponentS sHG)). Qed. Lemma abelemJ p G x : p.-abelem (G :^ x) = p.-abelem G. Proof. by rewrite /abelem pgroupJ abelianJ exponentJ. Qed. Lemma cprod_abelem p A B G : A \* B = G -> p.-abelem G = p.-abelem A && p.-abelem B. Proof. case/cprodP=> [[H K -> ->{A B}] defG cHK]. apply/idP/andP=> [abelG | []]. by rewrite !(abelemS _ abelG) // -defG (mulG_subl, mulG_subr). case/and3P=> pH cHH expHp; case/and3P=> pK cKK expKp. rewrite -defG /abelem pgroupM pH pK abelianM cHH cKK cHK /=. apply/exponentP=> _ /imset2P[x y Hx Ky ->]. rewrite expgMn; last by red; rewrite -(centsP cHK). by rewrite (exponentP expHp) // (exponentP expKp) // mul1g. Qed. Lemma dprod_abelem p A B G : A \x B = G -> p.-abelem G = p.-abelem A && p.-abelem B. Proof. move=> defG; case/dprodP: (defG) => _ _ _ tiHK. by apply: cprod_abelem; rewrite -dprodEcp. Qed. Lemma is_abelem_pgroup p G : p.-group G -> is_abelem G = p.-abelem G. Proof. rewrite /is_abelem => pG. case: (eqsVneq G 1) => [-> | ntG]; first by rewrite !abelem1. by have [p_pr _ [k ->]] := pgroup_pdiv pG ntG; rewrite pdiv_pfactor. Qed. Lemma is_abelemP G : reflect (exists2 p, prime p & p.-abelem G) (is_abelem G). Proof. apply: (iffP idP) => [abelG | [p p_pr abelG]]. case: (eqsVneq G 1) => [-> | ntG]; first by exists 2; rewrite ?abelem1. by exists (pdiv #|G|); rewrite ?pdiv_prime // ltnNge -trivg_card_le1. by rewrite (is_abelem_pgroup (abelem_pgroup abelG)). Qed. Lemma pElemP p A E : reflect (E \subset A /\ p.-abelem E) (E \in 'E_p(A)). Proof. by rewrite inE; exact: andP. Qed. Implicit Arguments pElemP [p A E]. Lemma pElemS p A B : A \subset B -> 'E_p(A) \subset 'E_p(B). Proof. by move=> sAB; apply/subsetP=> E; rewrite !inE => /andP[/subset_trans->]. Qed. Lemma pElemI p A B : 'E_p(A :&: B) = 'E_p(A) :&: subgroups B. Proof. by apply/setP=> E; rewrite !inE subsetI andbAC. Qed. Lemma pElemJ x p A E : ((E :^ x)%G \in 'E_p(A :^ x)) = (E \in 'E_p(A)). Proof. by rewrite !inE conjSg abelemJ. Qed. Lemma pnElemP p n A E : reflect [/\ E \subset A, p.-abelem E & logn p #|E| = n] (E \in 'E_p^n(A)). Proof. by rewrite !inE -andbA; apply: (iffP and3P) => [] [-> -> /eqP]. Qed. Implicit Arguments pnElemP [p n A E]. Lemma pnElemPcard p n A E : E \in 'E_p^n(A) -> [/\ E \subset A, p.-abelem E & #|E| = p ^ n]%N. Proof. by case/pnElemP=> -> abelE <-; rewrite -card_pgroup // abelem_pgroup. Qed. Lemma card_pnElem p n A E : E \in 'E_p^n(A) -> #|E| = (p ^ n)%N. Proof. by case/pnElemPcard. Qed. Lemma pnElem0 p G : 'E_p^0(G) = [set 1%G]. Proof. apply/setP=> E; rewrite !inE -andbA; apply/and3P/idP=> [[_ pE] | /eqP->]. apply: contraLR; case/(pgroup_pdiv (abelem_pgroup pE)) => p_pr _ [k ->]. by rewrite pfactorK. by rewrite sub1G abelem1 cards1 logn1. Qed. Lemma pnElem_prime p n A E : E \in 'E_p^n.+1(A) -> prime p. Proof. by case/pnElemP=> _ _; rewrite lognE; case: prime. Qed. Lemma pnElemE p n A : prime p -> 'E_p^n(A) = [set E in 'E_p(A) | #|E| == (p ^ n)%N]. Proof. move/pfactorK=> pnK; apply/setP=> E; rewrite 3!inE. case: (@andP (E \subset A)) => //= [[_]] /andP[/p_natP[k ->] _]. by rewrite pnK (can_eq pnK). Qed. Lemma pnElemS p n A B : A \subset B -> 'E_p^n(A) \subset 'E_p^n(B). Proof. move=> sAB; apply/subsetP=> E. by rewrite !inE -!andbA => /andP[/subset_trans->]. Qed. Lemma pnElemI p n A B : 'E_p^n(A :&: B) = 'E_p^n(A) :&: subgroups B. Proof. by apply/setP=> E; rewrite !inE subsetI -!andbA; do !bool_congr. Qed. Lemma pnElemJ x p n A E : ((E :^ x)%G \in 'E_p^n(A :^ x)) = (E \in 'E_p^n(A)). Proof. by rewrite inE pElemJ cardJg !inE. Qed. Lemma abelem_pnElem p n G : p.-abelem G -> n <= logn p #|G| -> exists E, E \in 'E_p^n(G). Proof. case: n => [|n] abelG lt_nG; first by exists 1%G; rewrite pnElem0 set11. have p_pr: prime p by move: lt_nG; rewrite lognE; case: prime. case/(normal_pgroup (abelem_pgroup abelG)): lt_nG => // E [sEG _ oE]. by exists E; rewrite pnElemE // !inE oE sEG (abelemS sEG) /=. Qed. Lemma card_p1Elem p A X : X \in 'E_p^1(A) -> #|X| = p. Proof. exact: card_pnElem. Qed. Lemma p1ElemE p A : prime p -> 'E_p^1(A) = [set X in subgroups A | #|X| == p]. Proof. move=> p_pr; apply/setP=> X; rewrite pnElemE // !inE -andbA; congr (_ && _). by apply: andb_idl => /eqP oX; rewrite prime_abelem ?oX. Qed. Lemma TIp1ElemP p A X Y : X \in 'E_p^1(A) -> Y \in 'E_p^1(A) -> reflect (X :&: Y = 1) (X :!=: Y). Proof. move=> EpX EpY; have p_pr := pnElem_prime EpX. have [oX oY] := (card_p1Elem EpX, card_p1Elem EpY). have [<- |] := altP eqP. by right=> X1; rewrite -oX -(setIid X) X1 cards1 in p_pr. by rewrite eqEcard oX oY leqnn andbT; left; rewrite prime_TIg ?oX. Qed. Lemma card_p1Elem_pnElem p n A E : E \in 'E_p^n(A) -> #|'E_p^1(E)| = (\sum_(i < n) p ^ i)%N. Proof. case/pnElemP=> _ {A} abelE dimE; have [pE cEE _] := and3P abelE. have [E1 | ntE] := eqsVneq E 1. rewrite -dimE E1 cards1 logn1 big_ord0 eq_card0 // => X. by rewrite !inE subG1 trivg_card1; case: eqP => // ->; rewrite logn1 andbF. have [p_pr _ _] := pgroup_pdiv pE ntE; have p_gt1 := prime_gt1 p_pr. apply/eqP; rewrite -(@eqn_pmul2l (p - 1)) ?subn_gt0 // subn1 -predn_exp. have groupD1_inj: injective (fun X => (gval X)^#). apply: can_inj (@generated_group _) _ => X. by apply: val_inj; rewrite /= genD1 ?group1 ?genGid. rewrite -dimE -card_pgroup // (cardsD1 1 E) group1 /= mulnC. rewrite -(card_imset _ groupD1_inj) eq_sym. apply/eqP; apply: card_uniform_partition => [X'|]. case/imsetP=> X; rewrite pnElemE // expn1 => /setIdP[_ /eqP <-] ->. by rewrite (cardsD1 1 X) group1. apply/and3P; split; last 1 first. - apply/imsetP=> [[X /card_p1Elem oX X'0]]. by rewrite -oX (cardsD1 1) -X'0 group1 cards0 in p_pr. - rewrite eqEsubset; apply/andP; split. by apply/bigcupsP=> _ /imsetP[X /pnElemP[sXE _ _] ->]; exact: setSD. apply/subsetP=> x /setD1P[ntx Ex]. apply/bigcupP; exists <[x]>^#; last by rewrite !inE ntx cycle_id. apply/imsetP; exists <[x]>%G; rewrite ?p1ElemE // !inE cycle_subG Ex /=. by rewrite -orderE (abelem_order_p abelE). apply/trivIsetP=> _ _ /imsetP[X EpX ->] /imsetP[Y EpY ->]; apply/implyP. rewrite (inj_eq groupD1_inj) -setI_eq0 -setDIl setD_eq0 subG1. by rewrite (sameP eqP (TIp1ElemP EpX EpY)) implybb. Qed. Lemma card_p1Elem_p2Elem p A E : E \in 'E_p^2(A) -> #|'E_p^1(E)| = p.+1. Proof. by move/card_p1Elem_pnElem->; rewrite big_ord_recl big_ord1. Qed. Lemma p2Elem_dprodP p A E X Y : E \in 'E_p^2(A) -> X \in 'E_p^1(E) -> Y \in 'E_p^1(E) -> reflect (X \x Y = E) (X :!=: Y). Proof. move=> Ep2E EpX EpY; have [_ abelE oE] := pnElemPcard Ep2E. apply: (iffP (TIp1ElemP EpX EpY)) => [tiXY|]; last by case/dprodP. have [[sXE _ oX] [sYE _ oY]] := (pnElemPcard EpX, pnElemPcard EpY). rewrite dprodE ?(sub_abelian_cent2 (abelem_abelian abelE)) //. by apply/eqP; rewrite eqEcard mul_subG //= TI_cardMg // oX oY oE. Qed. Lemma nElemP n G E : reflect (exists p, E \in 'E_p^n(G)) (E \in 'E^n(G)). Proof. rewrite ['E^n(G)]big_mkord. apply: (iffP bigcupP) => [[[p /= _] _] | [p]]; first by exists p. case: n => [|n EpnE]; first by rewrite pnElem0; exists ord0; rewrite ?pnElem0. suffices lepG: p < #|G|.+1 by exists (Ordinal lepG). have:= EpnE; rewrite pnElemE ?(pnElem_prime EpnE) // !inE -andbA ltnS. case/and3P=> sEG _ oE; rewrite dvdn_leq // (dvdn_trans _ (cardSg sEG)) //. by rewrite (eqP oE) dvdn_exp. Qed. Implicit Arguments nElemP [n G E]. Lemma nElem0 G : 'E^0(G) = [set 1%G]. Proof. apply/setP=> E; apply/nElemP/idP=> [[p] |]; first by rewrite pnElem0. by exists 2; rewrite pnElem0. Qed. Lemma nElem1P G E : reflect (E \subset G /\ exists2 p, prime p & #|E| = p) (E \in 'E^1(G)). Proof. apply: (iffP nElemP) => [[p pE] | [sEG [p p_pr oE]]]. have p_pr := pnElem_prime pE; rewrite pnElemE // !inE -andbA in pE. by case/and3P: pE => -> _ /eqP; split; last exists p. exists p; rewrite pnElemE // !inE sEG oE eqxx abelemE // -oE exponent_dvdn. by rewrite cyclic_abelian // prime_cyclic // oE. Qed. Lemma nElemS n G H : G \subset H -> 'E^n(G) \subset 'E^n(H). Proof. move=> sGH; apply/subsetP=> E /nElemP[p EpnG_E]. by apply/nElemP; exists p; rewrite // (subsetP (pnElemS _ _ sGH)). Qed. Lemma nElemI n G H : 'E^n(G :&: H) = 'E^n(G) :&: subgroups H. Proof. apply/setP=> E; apply/nElemP/setIP=> [[p] | []]. by rewrite pnElemI; case/setIP; split=> //; apply/nElemP; exists p. by case/nElemP=> p EpnG_E sHE; exists p; rewrite pnElemI inE EpnG_E. Qed. Lemma def_pnElem p n G : 'E_p^n(G) = 'E_p(G) :&: 'E^n(G). Proof. apply/setP=> E; rewrite inE in_setI; apply: andb_id2l => /pElemP[sEG abelE]. apply/idP/nElemP=> [|[q]]; first by exists p; rewrite !inE sEG abelE. rewrite !inE -2!andbA => /and4P[_ /pgroupP qE _]. case: (eqVneq E 1%G) => [-> | ]; first by rewrite cards1 !logn1. case/(pgroup_pdiv (abelem_pgroup abelE)) => p_pr pE _. by rewrite (eqnP (qE p p_pr pE)). Qed. Lemma pmaxElemP p A E : reflect (E \in 'E_p(A) /\ forall H, H \in 'E_p(A) -> E \subset H -> H :=: E) (E \in 'E*_p(A)). Proof. by rewrite [E \in 'E*_p(A)]inE; exact: (iffP maxgroupP). Qed. Lemma pmaxElem_exists p A D : D \in 'E_p(A) -> {E | E \in 'E*_p(A) & D \subset E}. Proof. move=> EpD; have [E maxE sDE] := maxgroup_exists (EpD : mem 'E_p(A) D). by exists E; rewrite // inE. Qed. Lemma pmaxElem_LdivP p G E : prime p -> reflect ('Ldiv_p('C_G(E)) = E) (E \in 'E*_p(G)). Proof. move=> p_pr; apply: (iffP (pmaxElemP p G E)) => [[] | defE]. case/pElemP=> sEG abelE maxE; have [_ cEE eE] := and3P abelE. apply/setP=> x; rewrite !inE -andbA; apply/and3P/idP=> [[Gx cEx xp] | Ex]. rewrite -(maxE (<[x]> <*> E)%G) ?joing_subr //. by rewrite -cycle_subG joing_subl. rewrite inE join_subG cycle_subG Gx sEG /=. rewrite (cprod_abelem _ (cprodEY _)); last by rewrite centsC cycle_subG. by rewrite cycle_abelem ?p_pr ?orbT // order_dvdn xp. by rewrite (subsetP sEG) // (subsetP cEE) // (exponentP eE). split=> [|H]; last first. case/pElemP=> sHG /abelemP[// | cHH Hp1] sEH. apply/eqP; rewrite eqEsubset sEH andbC /= -defE; apply/subsetP=> x Hx. by rewrite 3!inE (subsetP sHG) // Hp1 ?(subsetP (centsS _ cHH)) /=. apply/pElemP; split; first by rewrite -defE -setIA subsetIl. apply/abelemP=> //; rewrite /abelian -{1 3}defE setIAC subsetIr. by split=> //; apply/exponentP; rewrite -sub_LdivT setIAC subsetIr. Qed. Lemma pmaxElemS p A B : A \subset B -> 'E*_p(B) :&: subgroups A \subset 'E*_p(A). Proof. move=> sAB; apply/subsetP=> E; rewrite !inE. case/andP=> /maxgroupP[/pElemP[_ abelE] maxE] sEA. apply/maxgroupP; rewrite inE sEA; split=> // D EpD. by apply: maxE; apply: subsetP EpD; exact: pElemS. Qed. Lemma pmaxElemJ p A E x : ((E :^ x)%G \in 'E*_p(A :^ x)) = (E \in 'E*_p(A)). Proof. apply/pmaxElemP/pmaxElemP=> [] [EpE maxE]. rewrite pElemJ in EpE; split=> //= H EpH sEH; apply: (act_inj 'Js x). by apply: maxE; rewrite ?conjSg ?pElemJ. rewrite pElemJ; split=> // H; rewrite -(actKV 'JG x H) pElemJ conjSg => EpHx'. by move/maxE=> /= ->. Qed. Lemma grank_min B : 'm(<>) <= #|B|. Proof. by rewrite /gen_rank; case: arg_minP => [|_ _ -> //]; rewrite genGid. Qed. Lemma grank_witness G : {B | <> = G & #|B| = 'm(G)}. Proof. rewrite /gen_rank; case: arg_minP => [|B defG _]; first by rewrite genGid. by exists B; first exact/eqP. Qed. Lemma p_rank_witness p G : {E | E \in 'E_p^('r_p(G))(G)}. Proof. have [E EG_E mE]: {E | E \in 'E_p(G) & 'r_p(G) = logn p #|E| }. by apply: eq_bigmax_cond; rewrite (cardD1 1%G) inE sub1G abelem1. by exists E; rewrite inE EG_E -mE /=. Qed. Lemma p_rank_geP p n G : reflect (exists E, E \in 'E_p^n(G)) (n <= 'r_p(G)). Proof. apply: (iffP idP) => [|[E]]; last first. by rewrite inE => /andP[Ep_E /eqP <-]; rewrite (bigmax_sup E). have [D /pnElemP[sDG abelD <-]] := p_rank_witness p G. by case/abelem_pnElem=> // E; exists E; exact: (subsetP (pnElemS _ _ sDG)). Qed. Lemma p_rank_gt0 p H : ('r_p(H) > 0) = (p \in \pi(H)). Proof. rewrite mem_primes cardG_gt0 /=; apply/p_rank_geP/andP=> [[E] | [p_pr]]. case/pnElemP=> sEG _; rewrite lognE; case: and3P => // [[-> _ pE] _]. by rewrite (dvdn_trans _ (cardSg sEG)). case/Cauchy=> // x Hx ox; exists <[x]>%G; rewrite 2!inE [#|_|]ox cycle_subG. by rewrite Hx (pfactorK 1) ?abelemE // cycle_abelian -ox exponent_dvdn. Qed. Lemma p_rank1 p : 'r_p([1 gT]) = 0. Proof. by apply/eqP; rewrite eqn0Ngt p_rank_gt0 /= cards1. Qed. Lemma logn_le_p_rank p A E : E \in 'E_p(A) -> logn p #|E| <= 'r_p(A). Proof. by move=> EpA_E; rewrite (bigmax_sup E). Qed. Lemma p_rank_le_logn p G : 'r_p(G) <= logn p #|G|. Proof. have [E EpE] := p_rank_witness p G. by have [sEG _ <-] := pnElemP EpE; exact: lognSg. Qed. Lemma p_rank_abelem p G : p.-abelem G -> 'r_p(G) = logn p #|G|. Proof. move=> abelG; apply/eqP; rewrite eqn_leq andbC (bigmax_sup G) //. by apply/bigmax_leqP=> E; rewrite inE => /andP[/lognSg->]. by rewrite inE subxx. Qed. Lemma p_rankS p A B : A \subset B -> 'r_p(A) <= 'r_p(B). Proof. move=> sAB; apply/bigmax_leqP=> E /(subsetP (pElemS p sAB)) EpB_E. by rewrite (bigmax_sup E). Qed. Lemma p_rankElem_max p A : 'E_p^('r_p(A))(A) \subset 'E*_p(A). Proof. apply/subsetP=> E /setIdP[EpE dimE]. apply/pmaxElemP; split=> // F EpF sEF; apply/eqP. have pF: p.-group F by case/pElemP: EpF => _ /and3P[]. have pE: p.-group E by case/pElemP: EpE => _ /and3P[]. rewrite eq_sym eqEcard sEF dvdn_leq // (card_pgroup pE) (card_pgroup pF). by rewrite (eqP dimE) dvdn_exp2l // logn_le_p_rank. Qed. Lemma p_rankJ p A x : 'r_p(A :^ x) = 'r_p(A). Proof. rewrite /p_rank (reindex_inj (act_inj 'JG x)). by apply: eq_big => [E | E _]; rewrite ?cardJg ?pElemJ. Qed. Lemma p_rank_Sylow p G H : p.-Sylow(G) H -> 'r_p(H) = 'r_p(G). Proof. move=> sylH; apply/eqP; rewrite eqn_leq (p_rankS _ (pHall_sub sylH)) /=. apply/bigmax_leqP=> E; rewrite inE => /andP[sEG abelE]. have [P sylP sEP] := Sylow_superset sEG (abelem_pgroup abelE). have [x _ ->] := Sylow_trans sylP sylH. by rewrite p_rankJ -(p_rank_abelem abelE) (p_rankS _ sEP). Qed. Lemma p_rank_Hall pi p G H : pi.-Hall(G) H -> p \in pi -> 'r_p(H) = 'r_p(G). Proof. move=> hallH pi_p; have [P sylP] := Sylow_exists p H. by rewrite -(p_rank_Sylow sylP) (p_rank_Sylow (subHall_Sylow hallH pi_p sylP)). Qed. Lemma p_rank_pmaxElem_exists p r G : 'r_p(G) >= r -> exists2 E, E \in 'E*_p(G) & 'r_p(E) >= r. Proof. case/p_rank_geP=> D /setIdP[EpD /eqP <- {r}]. have [E EpE sDE] := pmaxElem_exists EpD; exists E => //. case/pmaxElemP: EpE => /setIdP[_ abelE] _. by rewrite (p_rank_abelem abelE) lognSg. Qed. Lemma rank1 : 'r([1 gT]) = 0. Proof. by rewrite ['r(1)]big1_seq // => p _; rewrite p_rank1. Qed. Lemma p_rank_le_rank p G : 'r_p(G) <= 'r(G). Proof. case: (posnP 'r_p(G)) => [-> //|]; rewrite p_rank_gt0 mem_primes. case/and3P=> p_pr _ pG; have lepg: p < #|G|.+1 by rewrite ltnS dvdn_leq. by rewrite ['r(G)]big_mkord (bigmax_sup (Ordinal lepg)). Qed. Lemma rank_gt0 G : ('r(G) > 0) = (G :!=: 1). Proof. case: (eqsVneq G 1) => [-> |]; first by rewrite rank1 eqxx. case: (trivgVpdiv G) => [-> | [p p_pr]]; first by case/eqP. case/Cauchy=> // x Gx oxp ->; apply: leq_trans (p_rank_le_rank p G). have EpGx: <[x]>%G \in 'E_p(G). by rewrite inE cycle_subG Gx abelemE // cycle_abelian -oxp exponent_dvdn. by apply: leq_trans (logn_le_p_rank EpGx); rewrite -orderE oxp logn_prime ?eqxx. Qed. Lemma rank_witness G : {p | prime p & 'r(G) = 'r_p(G)}. Proof. have [p _ defmG]: {p : 'I_(#|G|.+1) | true & 'r(G) = 'r_p(G)}. by rewrite ['r(G)]big_mkord; apply: eq_bigmax_cond; rewrite card_ord. case: (eqsVneq G 1) => [-> | ]; first by exists 2; rewrite // rank1 p_rank1. by rewrite -rank_gt0 defmG p_rank_gt0 mem_primes; case/andP; exists p. Qed. Lemma rank_pgroup p G : p.-group G -> 'r(G) = 'r_p(G). Proof. move=> pG; apply/eqP; rewrite eqn_leq p_rank_le_rank andbT. rewrite ['r(G)]big_mkord; apply/bigmax_leqP=> [[q /= _] _]. case: (posnP 'r_q(G)) => [-> // |]; rewrite p_rank_gt0 mem_primes. by case/and3P=> q_pr _ qG; rewrite (eqnP (pgroupP pG q q_pr qG)). Qed. Lemma rank_Sylow p G P : p.-Sylow(G) P -> 'r(P) = 'r_p(G). Proof. move=> sylP; have pP := pHall_pgroup sylP. by rewrite -(p_rank_Sylow sylP) -(rank_pgroup pP). Qed. Lemma rank_abelem p G : p.-abelem G -> 'r(G) = logn p #|G|. Proof. by move=> abelG; rewrite (rank_pgroup (abelem_pgroup abelG)) p_rank_abelem. Qed. Lemma nt_pnElem p n E A : E \in 'E_p^n(A) -> n > 0 -> E :!=: 1. Proof. by case/pnElemP=> _ /rank_abelem <- <-; rewrite rank_gt0. Qed. Lemma rankJ A x : 'r(A :^ x) = 'r(A). Proof. by rewrite /rank cardJg; apply: eq_bigr => p _; rewrite p_rankJ. Qed. Lemma rankS A B : A \subset B -> 'r(A) <= 'r(B). Proof. move=> sAB; rewrite /rank !big_mkord; apply/bigmax_leqP=> p _. have leAB: #|A| < #|B|.+1 by rewrite ltnS subset_leq_card. by rewrite (bigmax_sup (widen_ord leAB p)) // p_rankS. Qed. Lemma rank_geP n G : reflect (exists E, E \in 'E^n(G)) (n <= 'r(G)). Proof. apply: (iffP idP) => [|[E]]. have [p _ ->] := rank_witness G; case/p_rank_geP=> E. by rewrite def_pnElem; case/setIP; exists E. case/nElemP=> p; rewrite inE => /andP[EpG_E /eqP <-]. by rewrite (leq_trans (logn_le_p_rank EpG_E)) ?p_rank_le_rank. Qed. End ExponentAbelem. Implicit Arguments LdivP [gT A n x]. Implicit Arguments exponentP [gT A n]. Implicit Arguments abelemP [gT p G]. Implicit Arguments is_abelemP [gT G]. Implicit Arguments pElemP [gT p A E]. Implicit Arguments pnElemP [gT p n A E]. Implicit Arguments nElemP [gT n G E]. Implicit Arguments nElem1P [gT G E]. Implicit Arguments pmaxElemP [gT p A E]. Implicit Arguments pmaxElem_LdivP [gT p G E]. Implicit Arguments p_rank_geP [gT p n G]. Implicit Arguments rank_geP [gT n G]. Section MorphAbelem. Variables (aT rT : finGroupType) (D : {group aT}) (f : {morphism D >-> rT}). Implicit Types (G H E : {group aT}) (A B : {set aT}). Lemma exponent_morphim G : exponent (f @* G) %| exponent G. Proof. apply/exponentP=> _ /morphimP[x Dx Gx ->]. by rewrite -morphX // expg_exponent // morph1. Qed. Lemma morphim_LdivT n : f @* 'Ldiv_n() \subset 'Ldiv_n(). Proof. apply/subsetP=> _ /morphimP[x Dx xn ->]; rewrite inE in xn. by rewrite inE -morphX // (eqP xn) morph1. Qed. Lemma morphim_Ldiv n A : f @* 'Ldiv_n(A) \subset 'Ldiv_n(f @* A). Proof. by apply: subset_trans (morphimI f A _) (setIS _ _); exact: morphim_LdivT. Qed. Lemma morphim_abelem p G : p.-abelem G -> p.-abelem (f @* G). Proof. case: (eqsVneq G 1) => [-> | ntG] abelG; first by rewrite morphim1 abelem1. have [p_pr _ _] := pgroup_pdiv (abelem_pgroup abelG) ntG. case/abelemP: abelG => // abG elemG; apply/abelemP; rewrite ?morphim_abelian //. by split=> // _ /morphimP[x Dx Gx ->]; rewrite -morphX // elemG ?morph1. Qed. Lemma morphim_pElem p G E : E \in 'E_p(G) -> (f @* E)%G \in 'E_p(f @* G). Proof. by rewrite !inE => /andP[sEG abelE]; rewrite morphimS // morphim_abelem. Qed. Lemma morphim_pnElem p n G E : E \in 'E_p^n(G) -> {m | m <= n & (f @* E)%G \in 'E_p^m(f @* G)}. Proof. rewrite inE => /andP[EpE /eqP <-]. by exists (logn p #|f @* E|); rewrite ?logn_morphim // inE morphim_pElem /=. Qed. Lemma morphim_grank G : G \subset D -> 'm(f @* G) <= 'm(G). Proof. have [B defG <-] := grank_witness G; rewrite -defG gen_subG => sBD. by rewrite morphim_gen ?morphimEsub ?(leq_trans (grank_min _)) ?leq_imset_card. Qed. (* There are no general morphism relations for the p-rank. We later prove *) (* some relations for the p-rank of a quotient in the QuotientAbelem section. *) End MorphAbelem. Section InjmAbelem. Variables (aT rT : finGroupType) (D G : {group aT}) (f : {morphism D >-> rT}). Hypotheses (injf : 'injm f) (sGD : G \subset D). Let defG : invm injf @* (f @* G) = G := morphim_invm injf sGD. Lemma exponent_injm : exponent (f @* G) = exponent G. Proof. by apply/eqP; rewrite eqn_dvd -{3}defG !exponent_morphim. Qed. Lemma injm_Ldiv n A : f @* 'Ldiv_n(A) = 'Ldiv_n(f @* A). Proof. apply/eqP; rewrite eqEsubset morphim_Ldiv. rewrite -[f @* 'Ldiv_n(A)](morphpre_invm injf). rewrite -sub_morphim_pre; last by rewrite subIset ?morphim_sub. rewrite injmI ?injm_invm // setISS ?morphim_LdivT //. by rewrite sub_morphim_pre ?morphim_sub // morphpre_invm. Qed. Lemma injm_abelem p : p.-abelem (f @* G) = p.-abelem G. Proof. by apply/idP/idP; first rewrite -{2}defG; exact: morphim_abelem. Qed. Lemma injm_pElem p (E : {group aT}) : E \subset D -> ((f @* E)%G \in 'E_p(f @* G)) = (E \in 'E_p(G)). Proof. move=> sED; apply/idP/idP=> EpE; last exact: morphim_pElem. by rewrite -defG -(group_inj (morphim_invm injf sED)) morphim_pElem. Qed. Lemma injm_pnElem p n (E : {group aT}) : E \subset D -> ((f @* E)%G \in 'E_p^n(f @* G)) = (E \in 'E_p^n(G)). Proof. by move=> sED; rewrite inE injm_pElem // card_injm ?inE. Qed. Lemma injm_nElem n (E : {group aT}) : E \subset D -> ((f @* E)%G \in 'E^n(f @* G)) = (E \in 'E^n(G)). Proof. move=> sED; apply/nElemP/nElemP=> [] [p EpE]; by exists p; rewrite injm_pnElem in EpE *. Qed. Lemma injm_pmaxElem p (E : {group aT}) : E \subset D -> ((f @* E)%G \in 'E*_p(f @* G)) = (E \in 'E*_p(G)). Proof. move=> sED; have defE := morphim_invm injf sED. apply/pmaxElemP/pmaxElemP=> [] [EpE maxE]. split=> [|H EpH sEH]; first by rewrite injm_pElem in EpE. have sHD: H \subset D by apply: subset_trans (sGD); case/pElemP: EpH. by rewrite -(morphim_invm injf sHD) [f @* H]maxE ?morphimS ?injm_pElem. rewrite injm_pElem //; split=> // fH Ep_fH sfEH; have [sfHG _] := pElemP Ep_fH. have sfHD : fH \subset f @* D by rewrite (subset_trans sfHG) ?morphimS. rewrite -(morphpreK sfHD); congr (f @* _). rewrite [_ @*^-1 fH]maxE -?sub_morphim_pre //. by rewrite -injm_pElem ?subsetIl // (group_inj (morphpreK sfHD)). Qed. Lemma injm_grank : 'm(f @* G) = 'm(G). Proof. by apply/eqP; rewrite eqn_leq -{3}defG !morphim_grank ?morphimS. Qed. Lemma injm_p_rank p : 'r_p(f @* G) = 'r_p(G). Proof. apply/eqP; rewrite eqn_leq; apply/andP; split. have [fE] := p_rank_witness p (f @* G); move: 'r_p(_) => n Ep_fE. apply/p_rank_geP; exists (f @*^-1 fE)%G. rewrite -injm_pnElem ?subsetIl ?(group_inj (morphpreK _)) //. by case/pnElemP: Ep_fE => sfEG _ _; rewrite (subset_trans sfEG) ?morphimS. have [E] := p_rank_witness p G; move: 'r_p(_) => n EpE. apply/p_rank_geP; exists (f @* E)%G; rewrite injm_pnElem //. by case/pnElemP: EpE => sEG _ _; rewrite (subset_trans sEG). Qed. Lemma injm_rank : 'r(f @* G) = 'r(G). Proof. apply/eqP; rewrite eqn_leq; apply/andP; split. by have [p _ ->] := rank_witness (f @* G); rewrite injm_p_rank p_rank_le_rank. by have [p _ ->] := rank_witness G; rewrite -injm_p_rank p_rank_le_rank. Qed. End InjmAbelem. Section IsogAbelem. Variables (aT rT : finGroupType) (G : {group aT}) (H : {group rT}). Hypothesis isoGH : G \isog H. Lemma exponent_isog : exponent G = exponent H. Proof. by case/isogP: isoGH => f injf <-; rewrite exponent_injm. Qed. Lemma isog_abelem p : p.-abelem G = p.-abelem H. Proof. by case/isogP: isoGH => f injf <-; rewrite injm_abelem. Qed. Lemma isog_grank : 'm(G) = 'm(H). Proof. by case/isogP: isoGH => f injf <-; rewrite injm_grank. Qed. Lemma isog_p_rank p : 'r_p(G) = 'r_p(H). Proof. by case/isogP: isoGH => f injf <-; rewrite injm_p_rank. Qed. Lemma isog_rank : 'r(G) = 'r(H). Proof. by case/isogP: isoGH => f injf <-; rewrite injm_rank. Qed. End IsogAbelem. Section QuotientAbelem. Variables (gT : finGroupType) (p : nat). Implicit Types E G K H : {group gT}. Lemma exponent_quotient G H : exponent (G / H) %| exponent G. Proof. exact: exponent_morphim. Qed. Lemma quotient_LdivT n H : 'Ldiv_n() / H \subset 'Ldiv_n(). Proof. exact: morphim_LdivT. Qed. Lemma quotient_Ldiv n A H : 'Ldiv_n(A) / H \subset 'Ldiv_n(A / H). Proof. exact: morphim_Ldiv. Qed. Lemma quotient_abelem G H : p.-abelem G -> p.-abelem (G / H). Proof. exact: morphim_abelem. Qed. Lemma quotient_pElem G H E : E \in 'E_p(G) -> (E / H)%G \in 'E_p(G / H). Proof. exact: morphim_pElem. Qed. Lemma logn_quotient G H : logn p #|G / H| <= logn p #|G|. Proof. exact: logn_morphim. Qed. Lemma quotient_pnElem G H n E : E \in 'E_p^n(G) -> {m | m <= n & (E / H)%G \in 'E_p^m(G / H)}. Proof. exact: morphim_pnElem. Qed. Lemma quotient_grank G H : G \subset 'N(H) -> 'm(G / H) <= 'm(G). Proof. exact: morphim_grank. Qed. Lemma p_rank_quotient G H : G \subset 'N(H) -> 'r_p(G) - 'r_p(H) <= 'r_p(G / H). Proof. move=> nHG; rewrite leq_subLR. have [E EpE] := p_rank_witness p G; have{EpE} [sEG abelE <-] := pnElemP EpE. rewrite -(LagrangeI E H) lognM ?cardG_gt0 //. rewrite -card_quotient ?(subset_trans sEG) // leq_add ?logn_le_p_rank // !inE. by rewrite subsetIr (abelemS (subsetIl E H)). by rewrite quotientS ?quotient_abelem. Qed. Lemma p_rank_dprod K H G : K \x H = G -> 'r_p(K) + 'r_p(H) = 'r_p(G). Proof. move=> defG; apply/eqP; rewrite eqn_leq -leq_subLR andbC. have [_ defKH cKH tiKH] := dprodP defG; have nKH := cents_norm cKH. rewrite {1}(isog_p_rank (quotient_isog nKH tiKH)) /= -quotientMidl defKH. rewrite p_rank_quotient; last by rewrite -defKH mul_subG ?normG. have [[E EpE] [F EpF]] := (p_rank_witness p K, p_rank_witness p H). have [[sEK abelE <-] [sFH abelF <-]] := (pnElemP EpE, pnElemP EpF). have defEF: E \x F = E <*> F. by rewrite dprodEY ?(centSS sFH sEK) //; apply/trivgP; rewrite -tiKH setISS. apply/p_rank_geP; exists (E <*> F)%G; rewrite !inE (dprod_abelem p defEF). rewrite -lognM ?cargG_gt0 // (dprod_card defEF) abelE abelF eqxx. by rewrite -(genGid G) -defKH genM_join genS ?setUSS. Qed. Lemma p_rank_p'quotient G H : (p : nat)^'.-group H -> G \subset 'N(H) -> 'r_p(G / H) = 'r_p(G). Proof. move=> p'H nHG; have [P sylP] := Sylow_exists p G. have [sPG pP _] := and3P sylP; have nHP := subset_trans sPG nHG. have tiHP: H :&: P = 1 := coprime_TIg (p'nat_coprime p'H pP). rewrite -(p_rank_Sylow sylP) -(p_rank_Sylow (quotient_pHall nHP sylP)). by rewrite (isog_p_rank (quotient_isog nHP tiHP)). Qed. End QuotientAbelem. Section OhmProps. Section Generic. Variables (n : nat) (gT : finGroupType). Implicit Types (p : nat) (x : gT) (rT : finGroupType). Implicit Types (A B : {set gT}) (D G H : {group gT}). Lemma Ohm_sub G : 'Ohm_n(G) \subset G. Proof. by rewrite gen_subG; apply/subsetP=> x /setIdP[]. Qed. Lemma Ohm1 : 'Ohm_n([1 gT]) = 1. Proof. exact: (trivgP (Ohm_sub _)). Qed. Lemma Ohm_id G : 'Ohm_n('Ohm_n(G)) = 'Ohm_n(G). Proof. apply/eqP; rewrite eqEsubset Ohm_sub genS //. by apply/subsetP=> x /setIdP[Gx oxn]; rewrite inE mem_gen // inE Gx. Qed. Lemma Ohm_cont rT G (f : {morphism G >-> rT}) : f @* 'Ohm_n(G) \subset 'Ohm_n(f @* G). Proof. rewrite morphim_gen ?genS //; last by rewrite -gen_subG Ohm_sub. apply/subsetP=> fx /morphimP[x Gx]; rewrite inE Gx /=. case/OhmPredP=> p p_pr xpn_1 -> {fx}. rewrite inE morphimEdom mem_imset //=; apply/OhmPredP; exists p => //. by rewrite -morphX // xpn_1 morph1. Qed. Lemma OhmS H G : H \subset G -> 'Ohm_n(H) \subset 'Ohm_n(G). Proof. move=> sHG; apply: genS; apply/subsetP=> x; rewrite !inE => /andP[Hx ->]. by rewrite (subsetP sHG). Qed. Lemma OhmE p G : p.-group G -> 'Ohm_n(G) = <<'Ldiv_(p ^ n)(G)>>. Proof. move=> pG; congr <<_>>; apply/setP=> x; rewrite !inE; apply: andb_id2l => Gx. case: (eqVneq x 1) => [-> | ntx]; first by rewrite !expg1n. by rewrite (pdiv_p_elt (mem_p_elt pG Gx)). Qed. Lemma OhmEabelian p G : p.-group G -> abelian 'Ohm_n(G) -> 'Ohm_n(G) = 'Ldiv_(p ^ n)(G). Proof. move=> pG; rewrite (OhmE pG) abelian_gen => cGGn; rewrite gen_set_id //. rewrite -(setIidPr (subset_gen 'Ldiv_(p ^ n)(G))) setIA. by rewrite [_ :&: G](setIidPl _) ?gen_subG ?subsetIl // group_Ldiv ?abelian_gen. Qed. Lemma Ohm_p_cycle p x : p.-elt x -> 'Ohm_n(<[x]>) = <[x ^+ (p ^ (logn p #[x] - n))]>. Proof. move=> p_x; apply/eqP; rewrite (OhmE p_x) eqEsubset cycle_subG mem_gen. rewrite gen_subG andbT; apply/subsetP=> y /LdivP[x_y ypn]. case: (leqP (logn p #[x]) n) => [|lt_n_x]. by rewrite -subn_eq0 => /eqP->. have p_pr: prime p by move: lt_n_x; rewrite lognE; case: (prime p). have def_y: <[y]> = <[x ^+ (#[x] %/ #[y])]>. apply: congr_group; apply/set1P. by rewrite -cycle_sub_group ?cardSg ?inE ?cycle_subG ?x_y /=. rewrite -cycle_subG def_y cycle_subG -{1}(part_pnat_id p_x) p_part. rewrite -{1}(subnK (ltnW lt_n_x)) expnD -muln_divA ?order_dvdn ?ypn //. by rewrite expgM mem_cycle. rewrite !inE mem_cycle -expgM -expnD addnC -maxnE -order_dvdn. by rewrite -{1}(part_pnat_id p_x) p_part dvdn_exp2l ?leq_maxr. Qed. Lemma Ohm_dprod A B G : A \x B = G -> 'Ohm_n(A) \x 'Ohm_n(B) = 'Ohm_n(G). Proof. case/dprodP => [[H K -> ->{A B}]] <- cHK tiHK. rewrite dprodEY //; last first. - by apply/trivgP; rewrite -tiHK setISS ?Ohm_sub. - by rewrite (subset_trans (subset_trans _ cHK)) ?centS ?Ohm_sub. apply/eqP; rewrite -(cent_joinEr cHK) eqEsubset join_subG /=. rewrite !OhmS ?joing_subl ?joing_subr //= cent_joinEr //= -genM_join genS //. apply/subsetP=> _ /setIdP[/imset2P[x y Hx Ky ->] /OhmPredP[p p_pr /eqP]]. have cxy: commute x y by red; rewrite -(centsP cHK). rewrite ?expgMn // -eq_invg_mul => /eqP def_x. have ypn1: y ^+ (p ^ n) = 1. by apply/set1P; rewrite -[[set 1]]tiHK inE -{1}def_x groupV !groupX. have xpn1: x ^+ (p ^ n) = 1 by rewrite -[x ^+ _]invgK def_x ypn1 invg1. by rewrite mem_mulg ?mem_gen // inE (Hx, Ky); apply/OhmPredP; exists p. Qed. Lemma Mho_sub G : 'Mho^n(G) \subset G. Proof. rewrite gen_subG; apply/subsetP=> _ /imsetP[x /setIdP[Gx _] ->]. exact: groupX. Qed. Lemma Mho1 : 'Mho^n([1 gT]) = 1. Proof. exact: (trivgP (Mho_sub _)). Qed. Lemma morphim_Mho rT D G (f : {morphism D >-> rT}) : G \subset D -> f @* 'Mho^n(G) = 'Mho^n(f @* G). Proof. move=> sGD; have sGnD := subset_trans (Mho_sub G) sGD. apply/eqP; rewrite eqEsubset {1}morphim_gen -1?gen_subG // !gen_subG. apply/andP; split; apply/subsetP=> y. case/morphimP=> xpn _ /imsetP[x /setIdP[Gx]]. set p := pdiv _ => p_x -> -> {xpn y}; have Dx := subsetP sGD x Gx. by rewrite morphX // Mho_p_elt ?morph_p_elt ?mem_morphim. case/imsetP=> _ /setIdP[/morphimP[x Dx Gx ->]]. set p := pdiv _ => p_fx ->{y}; rewrite -(constt_p_elt p_fx) -morph_constt //. by rewrite -morphX ?mem_morphim ?Mho_p_elt ?groupX ?p_elt_constt. Qed. Lemma Mho_cont rT G (f : {morphism G >-> rT}) : f @* 'Mho^n(G) \subset 'Mho^n(f @* G). Proof. by rewrite morphim_Mho. Qed. Lemma MhoS H G : H \subset G -> 'Mho^n(H) \subset 'Mho^n(G). Proof. move=> sHG; apply: genS; apply: imsetS; apply/subsetP=> x. by rewrite !inE => /andP[Hx]; rewrite (subsetP sHG). Qed. Lemma MhoE p G : p.-group G -> 'Mho^n(G) = <<[set x ^+ (p ^ n) | x in G]>>. Proof. move=> pG; apply/eqP; rewrite eqEsubset !gen_subG; apply/andP. do [split; apply/subsetP=> xpn; case/imsetP=> x] => [|Gx ->]; last first. by rewrite Mho_p_elt ?(mem_p_elt pG). case/setIdP=> Gx _ ->; have [-> | ntx] := eqVneq x 1; first by rewrite expg1n. by rewrite (pdiv_p_elt (mem_p_elt pG Gx) ntx) mem_gen //; exact: mem_imset. Qed. Lemma MhoEabelian p G : p.-group G -> abelian G -> 'Mho^n(G) = [set x ^+ (p ^ n) | x in G]. Proof. move=> pG cGG; rewrite (MhoE pG); rewrite gen_set_id //; apply/group_setP. split=> [|xn yn]; first by apply/imsetP; exists 1; rewrite ?expg1n. case/imsetP=> x Gx ->; case/imsetP=> y Gy ->. by rewrite -expgMn; [apply: mem_imset; rewrite groupM | exact: (centsP cGG)]. Qed. Lemma trivg_Mho G : 'Mho^n(G) == 1 -> 'Ohm_n(G) == G. Proof. rewrite -subG1 gen_subG eqEsubset Ohm_sub /= => Gp1. rewrite -{1}(Sylow_gen G) genS //; apply/bigcupsP=> P. case/SylowP=> p p_pr /and3P[sPG pP _]; apply/subsetP=> x Px. have Gx := subsetP sPG x Px; rewrite inE Gx //=. rewrite (sameP eqP set1P) (subsetP Gp1) ?mem_gen //; apply: mem_imset. by rewrite inE Gx; exact: pgroup_p (mem_p_elt pP Px). Qed. Lemma Mho_p_cycle p x : p.-elt x -> 'Mho^n(<[x]>) = <[x ^+ (p ^ n)]>. Proof. move=> p_x. apply/eqP; rewrite (MhoE p_x) eqEsubset cycle_subG mem_gen; last first. by apply: mem_imset; exact: cycle_id. rewrite gen_subG andbT; apply/subsetP=> _ /imsetP[_ /cycleP[k ->] ->]. by rewrite -expgM mulnC expgM mem_cycle. Qed. Lemma Mho_cprod A B G : A \* B = G -> 'Mho^n(A) \* 'Mho^n(B) = 'Mho^n(G). Proof. case/cprodP => [[H K -> ->{A B}]] <- cHK; rewrite cprodEY //; last first. by rewrite (subset_trans (subset_trans _ cHK)) ?centS ?Mho_sub. apply/eqP; rewrite -(cent_joinEr cHK) eqEsubset join_subG /=. rewrite !MhoS ?joing_subl ?joing_subr //= cent_joinEr // -genM_join. apply: genS; apply/subsetP=> xypn /imsetP[_ /setIdP[/imset2P[x y Hx Ky ->]]]. move/constt_p_elt; move: (pdiv _) => p <- ->. have cxy: commute x y by red; rewrite -(centsP cHK). rewrite consttM // expgMn; last exact: commuteX2. by rewrite mem_mulg ?Mho_p_elt ?groupX ?p_elt_constt. Qed. Lemma Mho_dprod A B G : A \x B = G -> 'Mho^n(A) \x 'Mho^n(B) = 'Mho^n(G). Proof. case/dprodP => [[H K -> ->{A B}]] defG cHK tiHK. rewrite dprodEcp; first by apply: Mho_cprod; rewrite cprodE. by apply/trivgP; rewrite -tiHK setISS ?Mho_sub. Qed. End Generic. Canonical Ohm_igFun i := [igFun by Ohm_sub i & Ohm_cont i]. Canonical Ohm_gFun i := [gFun by Ohm_cont i]. Canonical Ohm_mgFun i := [mgFun by OhmS i]. Canonical Mho_igFun i := [igFun by Mho_sub i & Mho_cont i]. Canonical Mho_gFun i := [gFun by Mho_cont i]. Canonical Mho_mgFun i := [mgFun by MhoS i]. Section char. Variables (n : nat) (gT rT : finGroupType) (D G : {group gT}). Lemma Ohm_char : 'Ohm_n(G) \char G. Proof. exact: gFchar. Qed. Lemma Ohm_normal : 'Ohm_n(G) <| G. Proof. exact: gFnormal. Qed. Lemma Mho_char : 'Mho^n(G) \char G. Proof. exact: gFchar. Qed. Lemma Mho_normal : 'Mho^n(G) <| G. Proof. exact: gFnormal. Qed. Lemma morphim_Ohm (f : {morphism D >-> rT}) : G \subset D -> f @* 'Ohm_n(G) \subset 'Ohm_n(f @* G). Proof. exact: morphimF. Qed. Lemma injm_Ohm (f : {morphism D >-> rT}) : 'injm f -> G \subset D -> f @* 'Ohm_n(G) = 'Ohm_n(f @* G). Proof. by move=> injf; exact: injmF. Qed. Lemma isog_Ohm (H : {group rT}) : G \isog H -> 'Ohm_n(G) \isog 'Ohm_n(H). Proof. exact: gFisog. Qed. Lemma isog_Mho (H : {group rT}) : G \isog H -> 'Mho^n(G) \isog 'Mho^n(H). Proof. exact: gFisog. Qed. End char. Variable gT : finGroupType. Implicit Types (pi : nat_pred) (p : nat). Implicit Types (A B C : {set gT}) (D G H E : {group gT}). Lemma Ohm0 G : 'Ohm_0(G) = 1. Proof. apply/trivgP; rewrite /= gen_subG. by apply/subsetP=> x /setIdP[_]; rewrite inE. Qed. Lemma Ohm_leq m n G : m <= n -> 'Ohm_m(G) \subset 'Ohm_n(G). Proof. move/subnKC <-; rewrite genS //; apply/subsetP=> y. by rewrite !inE expnD expgM => /andP[-> /eqP->]; rewrite expg1n /=. Qed. Lemma OhmJ n G x : 'Ohm_n(G :^ x) = 'Ohm_n(G) :^ x. Proof. rewrite -{1}(setIid G) -(setIidPr (Ohm_sub n G)). by rewrite -!morphim_conj injm_Ohm ?injm_conj. Qed. Lemma Mho0 G : 'Mho^0(G) = G. Proof. apply/eqP; rewrite eqEsubset Mho_sub /=. apply/subsetP=> x Gx; rewrite -[x]prod_constt group_prod // => p _. exact: Mho_p_elt (groupX _ Gx) (p_elt_constt _ _). Qed. Lemma Mho_leq m n G : m <= n -> 'Mho^n(G) \subset 'Mho^m(G). Proof. move/subnKC <-; rewrite gen_subG //. apply/subsetP=> _ /imsetP[x /setIdP[Gx p_x] ->]. by rewrite expnD expgM groupX ?(Mho_p_elt _ _ p_x). Qed. Lemma MhoJ n G x : 'Mho^n(G :^ x) = 'Mho^n(G) :^ x. Proof. by rewrite -{1}(setIid G) -(setIidPr (Mho_sub n G)) -!morphim_conj morphim_Mho. Qed. Lemma extend_cyclic_Mho G p x : p.-group G -> x \in G -> 'Mho^1(G) = <[x ^+ p]> -> forall k, k > 0 -> 'Mho^k(G) = <[x ^+ (p ^ k)]>. Proof. move=> pG Gx defG1 [//|k _]; have pX := mem_p_elt pG Gx. apply/eqP; rewrite eqEsubset cycle_subG (Mho_p_elt _ Gx pX) andbT. rewrite (MhoE _ pG) gen_subG; apply/subsetP=> ypk; case/imsetP=> y Gy ->{ypk}. have: y ^+ p \in <[x ^+ p]> by rewrite -defG1 (Mho_p_elt 1 _ (mem_p_elt pG Gy)). rewrite !expnS /= !expgM => /cycleP[j ->]. by rewrite -!expgM mulnCA mulnC expgM mem_cycle. Qed. Lemma Ohm1Eprime G : 'Ohm_1(G) = <<[set x in G | prime #[x]]>>. Proof. rewrite -['Ohm_1(G)](genD1 (group1 _)); congr <<_>>. apply/setP=> x; rewrite !inE andbCA -order_dvdn -order_gt1; congr (_ && _). apply/andP/idP=> [[p_gt1] | p_pr]; last by rewrite prime_gt1 ?pdiv_id. set p := pdiv _ => ox_p; have p_pr: prime p by rewrite pdiv_prime. by have [_ dv_p] := primeP p_pr; case/pred2P: (dv_p _ ox_p) p_gt1 => ->. Qed. Lemma abelem_Ohm1 p G : p.-group G -> p.-abelem 'Ohm_1(G) = abelian 'Ohm_1(G). Proof. move=> pG; rewrite /abelem (pgroupS (Ohm_sub 1 G)) //. case abG1: (abelian _) => //=; apply/exponentP=> x. by rewrite (OhmEabelian pG abG1); case/LdivP. Qed. Lemma Ohm1_abelem p G : p.-group G -> abelian G -> p.-abelem ('Ohm_1(G)). Proof. by move=> pG cGG; rewrite abelem_Ohm1 ?(abelianS (Ohm_sub 1 G)). Qed. Lemma Ohm1_id p G : p.-abelem G -> 'Ohm_1(G) = G. Proof. case/and3P=> pG cGG /exponentP Gp. apply/eqP; rewrite eqEsubset Ohm_sub (OhmE 1 pG) sub_gen //. by apply/subsetP=> x Gx; rewrite !inE Gx Gp /=. Qed. Lemma abelem_Ohm1P p G : abelian G -> p.-group G -> reflect ('Ohm_1(G) = G) (p.-abelem G). Proof. move=> cGG pG. apply: (iffP idP) => [| <-]; [exact: Ohm1_id | exact: Ohm1_abelem]. Qed. Lemma TI_Ohm1 G H : H :&: 'Ohm_1(G) = 1 -> H :&: G = 1. Proof. move=> tiHG1; case: (trivgVpdiv (H :&: G)) => // [[p pr_p]]. case/Cauchy=> // x /setIP[Hx Gx] ox. suffices x1: x \in [1] by rewrite -ox (set1P x1) order1 in pr_p. by rewrite -{}tiHG1 inE Hx Ohm1Eprime mem_gen // inE Gx ox. Qed. Lemma Ohm1_eq1 G : ('Ohm_1(G) == 1) = (G :==: 1). Proof. apply/idP/idP => [/eqP G1_1 | /eqP->]; last by rewrite -subG1 Ohm_sub. by rewrite -(setIid G) TI_Ohm1 // G1_1 setIg1. Qed. Lemma meet_Ohm1 G H : G :&: H != 1 -> G :&: 'Ohm_1(H) != 1. Proof. by apply: contraNneq => /TI_Ohm1->. Qed. Lemma Ohm1_cent_max G E p : E \in 'E*_p(G) -> p.-group G -> 'Ohm_1('C_G(E)) = E. Proof. move=> EpmE pG; have [G1 | ntG]:= eqsVneq G 1. case/pmaxElemP: EpmE; case/pElemP; rewrite G1 => /trivgP-> _ _. by apply/trivgP; rewrite cent1T setIT Ohm_sub. have [p_pr _ _] := pgroup_pdiv pG ntG. by rewrite (OhmE 1 (pgroupS (subsetIl G _) pG)) (pmaxElem_LdivP _ _) ?genGid. Qed. Lemma Ohm1_cyclic_pgroup_prime p G : cyclic G -> p.-group G -> G :!=: 1 -> #|'Ohm_1(G)| = p. Proof. move=> cycG pG ntG; set K := 'Ohm_1(G). have abelK: p.-abelem K by rewrite Ohm1_abelem ?cyclic_abelian. have sKG: K \subset G := Ohm_sub 1 G. case/cyclicP: (cyclicS sKG cycG) => x /=; rewrite -/K => defK. rewrite defK -orderE (abelem_order_p abelK) //= -/K ?defK ?cycle_id //. rewrite -cycle_eq1 -defK -(setIidPr sKG). by apply: contraNneq ntG => /TI_Ohm1; rewrite setIid => ->. Qed. Lemma cyclic_pgroup_dprod_trivg p A B C : p.-group C -> cyclic C -> A \x B = C -> A = 1 /\ B = C \/ B = 1 /\ A = C. Proof. move=> pC cycC; case/cyclicP: cycC pC => x ->{C} pC defC. case/dprodP: defC => [] [G H -> ->{A B}] defC _ tiGH; rewrite -defC. case: (eqVneq <[x]> 1) => [|ntC]. move/trivgP; rewrite -defC mulG_subG => /andP[/trivgP-> _]. by rewrite mul1g; left. have [pr_p _ _] := pgroup_pdiv pC ntC; pose K := 'Ohm_1(<[x]>). have prK : prime #|K| by rewrite (Ohm1_cyclic_pgroup_prime _ pC) ?cycle_cyclic. case: (prime_subgroupVti G prK) => [sKG |]; last first. move/TI_Ohm1; rewrite -defC (setIidPl (mulG_subl _ _)) => ->. by left; rewrite mul1g. case: (prime_subgroupVti H prK) => [sKH |]; last first. move/TI_Ohm1; rewrite -defC (setIidPl (mulG_subr _ _)) => ->. by right; rewrite mulg1. have K1: K :=: 1 by apply/trivgP; rewrite -tiGH subsetI sKG. by rewrite K1 cards1 in prK. Qed. Lemma piOhm1 G : \pi('Ohm_1(G)) = \pi(G). Proof. apply/eq_piP => p; apply/idP/idP; first exact: (piSg (Ohm_sub 1 G)). rewrite !mem_primes !cardG_gt0 => /andP[p_pr /Cauchy[] // x Gx oxp]. by rewrite p_pr -oxp order_dvdG //= Ohm1Eprime mem_gen // inE Gx oxp. Qed. Lemma Ohm1Eexponent p G : prime p -> exponent 'Ohm_1(G) %| p -> 'Ohm_1(G) = 'Ldiv_p(G). Proof. move=> p_pr expG1p; have pG: p.-group G. apply: sub_in_pnat (pnat_pi (cardG_gt0 G)) => q _. rewrite -piOhm1 mem_primes; case/and3P=> q_pr _; apply: pgroupP q_pr. by rewrite -pnat_exponent (pnat_dvd expG1p) ?pnat_id. apply/eqP; rewrite eqEsubset {2}(OhmE 1 pG) subset_gen subsetI Ohm_sub. by rewrite sub_LdivT expG1p. Qed. Lemma p_rank_Ohm1 p G : 'r_p('Ohm_1(G)) = 'r_p(G). Proof. apply/eqP; rewrite eqn_leq p_rankS ?Ohm_sub //. apply/bigmax_leqP=> E /setIdP[sEG abelE]. by rewrite (bigmax_sup E) // inE -{1}(Ohm1_id abelE) OhmS. Qed. Lemma rank_Ohm1 G : 'r('Ohm_1(G)) = 'r(G). Proof. apply/eqP; rewrite eqn_leq rankS ?Ohm_sub //. by have [p _ ->] := rank_witness G; rewrite -p_rank_Ohm1 p_rank_le_rank. Qed. Lemma p_rank_abelian p G : abelian G -> 'r_p(G) = logn p #|'Ohm_1(G)|. Proof. move=> cGG; have nilG := abelian_nil cGG; case p_pr: (prime p); last first. by apply/eqP; rewrite lognE p_pr eqn0Ngt p_rank_gt0 mem_primes p_pr. case/dprodP: (Ohm_dprod 1 (nilpotent_pcoreC p nilG)) => _ <- _ /TI_cardMg->. rewrite mulnC logn_Gauss; last first. rewrite prime_coprime // -p'natE // -/(pgroup _ _). exact: pgroupS (Ohm_sub _ _) (pcore_pgroup _ _). rewrite -(p_rank_Sylow (nilpotent_pcore_Hall p nilG)) -p_rank_Ohm1. rewrite p_rank_abelem // Ohm1_abelem ?pcore_pgroup //. exact: abelianS (pcore_sub _ _) cGG. Qed. Lemma rank_abelian_pgroup p G : p.-group G -> abelian G -> 'r(G) = logn p #|'Ohm_1(G)|. Proof. by move=> pG cGG; rewrite (rank_pgroup pG) p_rank_abelian. Qed. End OhmProps. Section AbelianStructure. Variable gT : finGroupType. Implicit Types (p : nat) (G H K E : {group gT}). Lemma abelian_splits x G : x \in G -> #[x] = exponent G -> abelian G -> [splits G, over <[x]>]. Proof. move=> Gx ox cGG; apply/splitsP; move: {2}_.+1 (ltnSn #|G|) => n. elim: n gT => // n IHn aT in x G Gx ox cGG *; rewrite ltnS => leGn. have: <[x]> \subset G by [rewrite cycle_subG]; rewrite subEproper. case/predU1P=> [<-|]; first by exists 1%G; rewrite inE -subG1 subsetIr mulg1 /=. case/properP=> sxG [y]; elim: {y}_.+1 {-2}y (ltnSn #[y]) => // m IHm y. rewrite ltnS => leym Gy x'y; case: (trivgVpdiv <[y]>) => [y1 | [p p_pr p_dv_y]]. by rewrite -cycle_subG y1 sub1G in x'y. case x_yp: (y ^+ p \in <[x]>); last first. apply: IHm (negbT x_yp); rewrite ?groupX ?(leq_trans _ leym) //. by rewrite orderXdiv // ltn_Pdiv ?prime_gt1. have{x_yp} xp_yp: (y ^+ p \in <[x ^+ p]>). have: <[y ^+ p]>%G \in [set <[x ^+ (#[x] %/ #[y ^+ p])]>%G]. by rewrite -cycle_sub_group ?order_dvdG // inE cycle_subG x_yp eqxx. rewrite inE -cycle_subG -val_eqE /=; move/eqP->. rewrite cycle_subG orderXdiv // divnA // mulnC ox. by rewrite -muln_divA ?dvdn_exponent ?expgM 1?groupX ?cycle_id. have: p <= #[y] by rewrite dvdn_leq. rewrite leq_eqVlt; case/predU1P=> [{xp_yp m IHm leym}oy | ltpy]; last first. case/cycleP: xp_yp => k; rewrite -expgM mulnC expgM => def_yp. suffices: #[y * x ^- k] < m. by move/IHm; apply; rewrite groupMr // groupV groupX ?cycle_id. apply: leq_ltn_trans (leq_trans ltpy leym). rewrite dvdn_leq ?prime_gt0 // order_dvdn expgMn. by rewrite expgVn def_yp mulgV. by apply: (centsP cGG); rewrite ?groupV ?groupX. pose Y := <[y]>; have nsYG: Y <| G by rewrite -sub_abelian_normal ?cycle_subG. have [sYG nYG] := andP nsYG; have nYx := subsetP nYG x Gx. have GxY: coset Y x \in G / Y by rewrite mem_morphim. have tiYx: Y :&: <[x]> = 1 by rewrite prime_TIg ?indexg1 -?[#|_|]oy ?cycle_subG. have: #[coset Y x] = exponent (G / Y). apply/eqP; rewrite eqn_dvd dvdn_exponent //. apply/exponentP=> _ /morphimP[z Nz Gz ->]. rewrite -morphX // ((z ^+ _ =P 1) _) ?morph1 //. rewrite orderE -quotient_cycle ?card_quotient ?cycle_subG // -indexgI /=. by rewrite setIC tiYx indexg1 -orderE ox -order_dvdn dvdn_exponent. case/IHn => // [||Hq]; first exact: quotient_abelian. apply: leq_trans leGn; rewrite ltn_quotient // cycle_eq1. by apply: contra x'y; move/eqP->; rewrite group1. case/complP=> /= ti_x_Hq defGq. have: Hq \subset G / Y by rewrite -defGq mulG_subr. case/inv_quotientS=> // H defHq sYH sHG; exists H. have nYX: <[x]> \subset 'N(Y) by rewrite cycle_subG. rewrite inE -subG1 eqEsubset mul_subG //= -tiYx subsetI subsetIl andbT. rewrite -{2}(mulSGid sYH) mulgA (normC nYX) -mulgA -quotientSK ?quotientMl //. rewrite -quotient_sub1 ?(subset_trans (subsetIl _ _)) // quotientIG //= -/Y. by rewrite -defHq quotient_cycle // ti_x_Hq defGq !subxx. Qed. Lemma abelem_splits p G H : p.-abelem G -> H \subset G -> [splits G, over H]. Proof. elim: {G}_.+1 {-2}G H (ltnSn #|G|) => // m IHm G H. rewrite ltnS => leGm abelG sHG; case: (eqsVneq H 1) => [-> | ]. by apply/splitsP; exists G; rewrite inE mul1g -subG1 subsetIl /=. case/trivgPn=> x Hx ntx; have Gx := subsetP sHG x Hx. have [_ cGG eGp] := and3P abelG. have ox: #[x] = exponent G. by apply/eqP; rewrite eqn_dvd dvdn_exponent // (abelem_order_p abelG). case/splitsP: (abelian_splits Gx ox cGG) => K; case/complP=> tixK defG. have sKG: K \subset G by rewrite -defG mulG_subr. have ltKm: #|K| < m. rewrite (leq_trans _ leGm) ?proper_card //; apply/properP; split=> //. exists x => //; apply: contra ntx => Kx; rewrite -cycle_eq1 -subG1 -tixK. by rewrite subsetI subxx cycle_subG. case/splitsP: (IHm _ _ ltKm (abelemS sKG abelG) (subsetIr H K)) => L. case/complP=> tiHKL defK; apply/splitsP; exists L; rewrite inE. rewrite -subG1 -tiHKL -setIA setIS; last by rewrite subsetI -defK mulG_subr /=. by rewrite -(setIidPr sHG) -defG -group_modl ?cycle_subG //= setIC -mulgA defK. Qed. Fact abelian_type_subproof G : {H : {group gT} & abelian G -> {x | #[x] = exponent G & <[x]> \x H = G}}. Proof. case cGG: (abelian G); last by exists G. have [x Gx ox] := exponent_witness (abelian_nil cGG). case/splitsP/ex_mingroup: (abelian_splits Gx (esym ox) cGG) => H. case/mingroupp/complP=> tixH defG; exists H => _. exists x; rewrite ?dprodE // (sub_abelian_cent2 cGG) ?cycle_subG //. by rewrite -defG mulG_subr. Qed. Fixpoint abelian_type_rec n G := if n is n'.+1 then if abelian G && (G :!=: 1) then exponent G :: abelian_type_rec n' (tag (abelian_type_subproof G)) else [::] else [::]. Definition abelian_type (A : {set gT}) := abelian_type_rec #|A| <>. Lemma abelian_type_dvdn_sorted A : sorted [rel m n | n %| m] (abelian_type A). Proof. set R := SimplRel _; pose G := <>%G. suffices: path R (exponent G) (abelian_type A) by case: (_ A) => // m t /andP[]. rewrite /abelian_type -/G; elim: {A}#|A| G {2 3}G (subxx G) => // n IHn G M sGM. simpl; case: ifP => //= /andP[cGG ntG]; rewrite exponentS ?IHn //=. case: (abelian_type_subproof G) => H /= [//| x _] /dprodP[_ /= <- _ _]. exact: mulG_subr. Qed. Lemma abelian_type_gt1 A : all [pred m | m > 1] (abelian_type A). Proof. rewrite /abelian_type; elim: {A}#|A| <>%G => //= n IHn G. case: ifP => //= /andP[_ ntG]; rewrite {n}IHn. by rewrite ltn_neqAle exponent_gt0 eq_sym -dvdn1 -trivg_exponent ntG. Qed. Lemma abelian_type_sorted A : sorted geq (abelian_type A). Proof. have:= abelian_type_dvdn_sorted A; have:= abelian_type_gt1 A. case: (abelian_type A) => //= m t; elim: t m => //= n t IHt m /andP[]. by move/ltnW=> m_gt0 t_gt1 /andP[n_dv_m /IHt->]; rewrite // dvdn_leq. Qed. Theorem abelian_structure G : abelian G -> {b | \big[dprod/1]_(x <- b) <[x]> = G & map order b = abelian_type G}. Proof. rewrite /abelian_type genGidG. elim: {G}#|G| {-2 5}G (leqnn #|G|) => /= [|n IHn] G leGn cGG. by rewrite leqNgt cardG_gt0 in leGn. rewrite {1}cGG /=; case: ifP => [ntG|/eqP->]; last first. by exists [::]; rewrite ?big_nil. case: (abelian_type_subproof G) => H /= [//|x ox xdefG]; rewrite -ox. have [_ defG cxH tixH] := dprodP xdefG. have sHG: H \subset G by rewrite -defG mulG_subr. case/IHn: (abelianS sHG cGG) => [|b defH <-]. rewrite -ltnS (leq_trans _ leGn) // -defG TI_cardMg // -orderE. rewrite ltn_Pmull ?cardG_gt0 // ltn_neqAle order_gt0 eq_sym -dvdn1. by rewrite ox -trivg_exponent ntG. by exists (x :: b); rewrite // big_cons defH xdefG. Qed. Lemma count_logn_dprod_cycle p n b G : \big[dprod/1]_(x <- b) <[x]> = G -> count [pred x | logn p #[x] > n] b = logn p #|'Ohm_n.+1(G) : 'Ohm_n(G)|. Proof. have sOn1 := @Ohm_leq gT _ _ _ (leqnSn n). pose lnO i (A : {set gT}) := logn p #|'Ohm_i(A)|. have lnO_le H: lnO n H <= lnO n.+1 H. by rewrite dvdn_leq_log ?cardG_gt0 // cardSg ?sOn1. have lnOx i A B H: A \x B = H -> lnO i A + lnO i B = lnO i H. move=> defH; case/dprodP: defH (defH) => {A B}[[A B -> ->]] _ _ _ defH. rewrite /lnO; case/dprodP: (Ohm_dprod i defH) => _ <- _ tiOAB. by rewrite TI_cardMg ?lognM. rewrite -divgS //= logn_div ?cardSg //= -/(lnO _ _) -/(lnO _ _). elim: b G => [_ <-|x b IHb G] /=. by rewrite big_nil /lnO !(trivgP (Ohm_sub _ _)) subnn. rewrite /= big_cons => defG; rewrite -!(lnOx _ _ _ _ defG) subnDA. case/dprodP: defG => [[_ H _ defH] _ _ _] {G}; rewrite defH (IHb _ defH). symmetry; do 2!rewrite addnC -addnBA ?lnO_le //; congr (_ + _). pose y := x.`_p; have p_y: p.-elt y by rewrite p_elt_constt. have{lnOx} lnOy i: lnO i <[x]> = lnO i <[y]>. have cXX := cycle_abelian x. have co_yx': coprime #[y] #[x.`_p^'] by rewrite !order_constt coprime_partC. have defX: <[y]> \x <[x.`_p^']> = <[x]>. rewrite dprodE ?coprime_TIg //. by rewrite -cycleM ?consttC //; apply: (centsP cXX); exact: mem_cycle. by apply: (sub_abelian_cent2 cXX); rewrite cycle_subG mem_cycle. rewrite -(lnOx i _ _ _ defX) addnC {1}/lnO lognE. case: and3P => // [[p_pr _ /idPn[]]]; rewrite -p'natE //. exact: pgroupS (Ohm_sub _ _) (p_elt_constt _ _). rewrite -logn_part -order_constt -/y !{}lnOy /lnO !(Ohm_p_cycle _ p_y). case: leqP => [| lt_n_y]. by rewrite -subn_eq0 -addn1 subnDA => /eqP->; rewrite subnn. rewrite -!orderE -(subSS n) subSn // expnSr expgM. have p_pr: prime p by move: lt_n_y; rewrite lognE; case: prime. set m := (p ^ _)%N; have m_gt0: m > 0 by rewrite expn_gt0 prime_gt0. suffices p_ym: p %| #[y ^+ m]. rewrite -logn_div ?orderXdvd // (orderXdiv p_ym) divnA // mulKn //. by rewrite logn_prime ?eqxx. rewrite orderXdiv ?pfactor_dvdn ?leq_subr // -(dvdn_pmul2r m_gt0). by rewrite -expnS -subSn // subSS divnK pfactor_dvdn ?leq_subr. Qed. Lemma perm_eq_abelian_type p b G : p.-group G -> \big[dprod/1]_(x <- b) <[x]> = G -> 1 \notin b -> perm_eq (map order b) (abelian_type G). Proof. move: b => b1 pG defG1 ntb1. have cGG: abelian G. elim: (b1) {pG}G defG1 => [_ <-|x b IHb G]; first by rewrite big_nil abelian1. rewrite big_cons; case/dprodP=> [[_ H _ defH]] <-; rewrite defH => cxH _. by rewrite abelianM cycle_abelian IHb. have p_bG b: \big[dprod/1]_(x <- b) <[x]> = G -> all (p_elt p) b. elim: b {defG1 cGG}G pG => //= x b IHb G pG; rewrite big_cons. case/dprodP=> [[_ H _ defH]]; rewrite defH andbC => defG _ _. by rewrite -defG pgroupM in pG; case/andP: pG => p_x /IHb->. have [b2 defG2 def_t] := abelian_structure cGG. have ntb2: 1 \notin b2. apply: contraL (abelian_type_gt1 G) => b2_1. rewrite -def_t -has_predC has_map. by apply/hasP; exists 1; rewrite //= order1. rewrite -{}def_t; apply/allP=> m; rewrite -map_cat => /mapP[x b_x def_m]. have{ntb1 ntb2} ntx: x != 1. by apply: contraL b_x; move/eqP->; rewrite mem_cat negb_or ntb1 ntb2. have p_x: p.-elt x by apply: allP (x) b_x; rewrite all_cat !p_bG. rewrite -cycle_eq1 in ntx; have [p_pr _ [k ox]] := pgroup_pdiv p_x ntx. apply/eqnP; rewrite {m}def_m orderE ox !count_map. pose cnt_p k := count [pred x : gT | logn p #[x] > k]. have cnt_b b: \big[dprod/1]_(x <- b) <[x]> = G -> count [pred x | #[x] == p ^ k.+1]%N b = cnt_p k b - cnt_p k.+1 b. - move/p_bG; elim: b => //= _ b IHb /andP[/p_natP[j ->] /IHb-> {IHb}]. rewrite eqn_leq !leq_exp2l ?prime_gt1 // -eqn_leq pfactorK // leqNgt. case: ltngtP => // _ {j}; rewrite subSn // add0n; elim: b => //= y b IHb. by rewrite leq_add // ltn_neqAle; case: (~~ _). by rewrite !cnt_b // /cnt_p !(@count_logn_dprod_cycle _ _ _ G). Qed. Lemma size_abelian_type G : abelian G -> size (abelian_type G) = 'r(G). Proof. move=> cGG; have [b defG def_t] := abelian_structure cGG. apply/eqP; rewrite -def_t size_map eqn_leq andbC; apply/andP; split. have [p p_pr ->] := rank_witness G; rewrite p_rank_abelian //. by rewrite -indexg1 -(Ohm0 G) -(count_logn_dprod_cycle _ _ defG) count_size. case/lastP def_b: b => // [b' x]; pose p := pdiv #[x]. have p_pr: prime p. have:= abelian_type_gt1 G; rewrite -def_t def_b map_rcons -cats1 all_cat. by rewrite /= andbT => /andP[_]; exact: pdiv_prime. suffices: all [pred y | logn p #[y] > 0] b. rewrite all_count (count_logn_dprod_cycle _ _ defG) -def_b; move/eqP <-. by rewrite Ohm0 indexg1 -p_rank_abelian ?p_rank_le_rank. apply/allP=> y; rewrite def_b mem_rcons inE /= => b_y. rewrite lognE p_pr order_gt0 (dvdn_trans (pdiv_dvd _)) //. case/predU1P: b_y => [-> // | b'_y]. have:= abelian_type_dvdn_sorted G; rewrite -def_t def_b. case/splitPr: b'_y => b1 b2; rewrite -cat_rcons rcons_cat map_cat !map_rcons. rewrite headI /= cat_path -(last_cons 2) -headI last_rcons. case/andP=> _ /order_path_min min_y. apply: (allP (min_y _)) => [? ? ? ? dv|]; first exact: (dvdn_trans dv). by rewrite mem_rcons mem_head. Qed. Lemma mul_card_Ohm_Mho_abelian n G : abelian G -> (#|'Ohm_n(G)| * #|'Mho^n(G)|)%N = #|G|. Proof. case/abelian_structure => b defG _. elim: b G defG => [_ <-|x b IHb G]. by rewrite !big_nil (trivgP (Ohm_sub _ _)) (trivgP (Mho_sub _ _)) !cards1. rewrite big_cons => defG; rewrite -(dprod_card defG). rewrite -(dprod_card (Ohm_dprod n defG)) -(dprod_card (Mho_dprod n defG)) /=. rewrite mulnCA -!mulnA mulnCA mulnA; case/dprodP: defG => [[_ H _ defH] _ _ _]. rewrite defH {b G defH IHb}(IHb H defH); congr (_ * _)%N => {H}. elim: {x}_.+1 {-2}x (ltnSn #[x]) => // m IHm x; rewrite ltnS => lexm. case p_x: (p_group <[x]>); last first. case: (eqVneq x 1) p_x => [-> |]; first by rewrite cycle1 p_group1. rewrite -order_gt1 /p_group -orderE; set p := pdiv _ => ntx p'x. have def_x: <[x.`_p]> \x <[x.`_p^']> = <[x]>. have ?: coprime #[x.`_p] #[x.`_p^'] by rewrite !order_constt coprime_partC. have ?: commute x.`_p x.`_p^' by exact: commuteX2. rewrite dprodE ?coprime_TIg -?cycleM ?consttC //. by rewrite cent_cycle cycle_subG; exact/cent1P. rewrite -(dprod_card (Ohm_dprod n def_x)) -(dprod_card (Mho_dprod n def_x)). rewrite mulnCA -mulnA mulnCA mulnA. rewrite !{}IHm ?(dprod_card def_x) ?(leq_trans _ lexm) {m lexm}//. rewrite /order -(dprod_card def_x) -!orderE !order_constt ltn_Pmull //. rewrite p_part -(expn0 p) ltn_exp2l 1?lognE ?prime_gt1 ?pdiv_prime //. by rewrite order_gt0 pdiv_dvd. rewrite proper_card // properEneq cycle_subG mem_cycle andbT. by apply: contra (negbT p'x); move/eqP <-; exact: p_elt_constt. case/p_groupP: p_x => p p_pr p_x. rewrite (Ohm_p_cycle n p_x) (Mho_p_cycle n p_x) -!orderE. set k := logn p #[x]; have ox: #[x] = (p ^ k)%N by rewrite -card_pgroup. case: (leqP k n) => [le_k_n | lt_n_k]. rewrite -(subnKC le_k_n) subnDA subnn expg1 expnD expgM -ox. by rewrite expg_order expg1n order1 muln1. rewrite !orderXgcd ox -{-3}(subnKC (ltnW lt_n_k)) expnD. rewrite gcdnC gcdnMl gcdnC gcdnMr. by rewrite mulnK ?mulKn ?expn_gt0 ?prime_gt0. Qed. Lemma grank_abelian G : abelian G -> 'm(G) = 'r(G). Proof. move=> cGG; apply/eqP; rewrite eqn_leq; apply/andP; split. rewrite -size_abelian_type //; case/abelian_structure: cGG => b defG <-. suffices <-: <<[set x in b]>> = G. by rewrite (leq_trans (grank_min _)) // size_map cardsE card_size. rewrite -{G defG}(bigdprodWY defG). elim: b => [|x b IHb]; first by rewrite big_nil gen0. by rewrite big_cons -joingE -joing_idr -IHb joing_idl joing_idr set_cons. have [p p_pr ->] := rank_witness G; pose K := 'Mho^1(G). have ->: 'r_p(G) = logn p #|G / K|. rewrite p_rank_abelian // card_quotient /= ?gFnorm // -divgS ?Mho_sub //. by rewrite -(mul_card_Ohm_Mho_abelian 1 cGG) mulnK ?cardG_gt0. case: (grank_witness G) => B genB <-; rewrite -genB. have: <> \subset G by rewrite genB. elim: {B genB}_.+1 {-2}B (ltnSn #|B|) => // m IHm B; rewrite ltnS. case: (set_0Vmem B) => [-> | [x Bx]]. by rewrite gen0 quotient1 cards1 logn1. rewrite (cardsD1 x) Bx -{2 3}(setD1K Bx); set B' := B :\ x => ltB'm. rewrite -joingE -joing_idl -joing_idr -/<[x]> join_subG => /andP[Gx sB'G]. rewrite cent_joinEl ?(sub_abelian_cent2 cGG) //. have nKx: x \in 'N(K) by rewrite -cycle_subG (subset_trans Gx) ?gFnorm. rewrite quotientMl ?cycle_subG // quotient_cycle //= -/K. have le_Kxp_1: logn p #[coset K x] <= 1. rewrite -(dvdn_Pexp2l _ _ (prime_gt1 p_pr)) -p_part -order_constt. rewrite order_dvdn -morph_constt // -morphX ?groupX //= coset_id //. by rewrite Mho_p_elt ?p_elt_constt ?groupX -?cycle_subG. apply: leq_trans (leq_add le_Kxp_1 (IHm _ ltB'm sB'G)). by rewrite -lognM ?dvdn_leq_log ?muln_gt0 ?cardG_gt0 // mul_cardG dvdn_mulr. Qed. Lemma rank_cycle (x : gT) : 'r(<[x]>) = (x != 1). Proof. have [->|ntx] := altP (x =P 1); first by rewrite cycle1 rank1. apply/eqP; rewrite eqn_leq rank_gt0 cycle_eq1 ntx andbT. by rewrite -grank_abelian ?cycle_abelian //= -(cards1 x) grank_min. Qed. Lemma abelian_rank1_cyclic G : abelian G -> cyclic G = ('r(G) <= 1). Proof. move=> cGG; have [b defG atypG] := abelian_structure cGG. apply/idP/idP; first by case/cyclicP=> x ->; rewrite rank_cycle leq_b1. rewrite -size_abelian_type // -{}atypG -{}defG unlock. by case: b => [|x []] //= _; rewrite ?cyclic1 // dprodg1 cycle_cyclic. Qed. Definition homocyclic A := abelian A && constant (abelian_type A). Lemma homocyclic_Ohm_Mho n p G : p.-group G -> homocyclic G -> 'Ohm_n(G) = 'Mho^(logn p (exponent G) - n)(G). Proof. move=> pG /andP[cGG homoG]; set e := exponent G. have{pG} p_e: p.-nat e by apply: pnat_dvd pG; exact: exponent_dvdn. have{homoG}: all (pred1 e) (abelian_type G). move: homoG; rewrite /abelian_type -(prednK (cardG_gt0 G)) /=. by case: (_ && _) (tag _); rewrite //= genGid eqxx. have{cGG} [b defG <-] := abelian_structure cGG. move: e => e in p_e *; elim: b => /= [|x b IHb] in G defG *. by rewrite -defG big_nil (trivgP (Ohm_sub _ _)) (trivgP (Mho_sub _ _)). case/andP=> /eqP ox e_b; rewrite big_cons in defG. rewrite -(Ohm_dprod _ defG) -(Mho_dprod _ defG). case/dprodP: defG => [[_ H _ defH] _ _ _]; rewrite defH IHb //; congr (_ \x _). by rewrite -ox in p_e *; rewrite (Ohm_p_cycle _ p_e) (Mho_p_cycle _ p_e). Qed. Lemma Ohm_Mho_homocyclic (n p : nat) G : abelian G -> p.-group G -> 0 < n < logn p (exponent G) -> 'Ohm_n(G) = 'Mho^(logn p (exponent G) - n)(G) -> homocyclic G. Proof. set e := exponent G => cGG pG /andP[n_gt0 n_lte] eq_Ohm_Mho. suffices: all (pred1 e) (abelian_type G). by rewrite /homocyclic cGG; exact: all_pred1_constant. case/abelian_structure: cGG (abelian_type_gt1 G) => b defG <-. elim: b {-3}G defG (subxx G) eq_Ohm_Mho => //= x b IHb H. rewrite big_cons => defG; case/dprodP: defG (defG) => [[_ K _ defK]]. rewrite defK => defHm cxK; rewrite setIC; move/trivgP=> tiKx defHd. rewrite -{1}defHm {defHm} mulG_subG cycle_subG ltnNge -trivg_card_le1. case/andP=> Gx sKG; rewrite -(Mho_dprod _ defHd) => /esym defMho /andP[ntx ntb]. have{defHd} defOhm := Ohm_dprod n defHd. apply/andP; split; last first. apply: (IHb K) => //; have:= dprod_modr defMho (Mho_sub _ _). rewrite -(dprod_modr defOhm (Ohm_sub _ _)). rewrite !(trivgP (subset_trans (setIS _ _) tiKx)) ?Ohm_sub ?Mho_sub //. by rewrite !dprod1g. have:= dprod_modl defMho (Mho_sub _ _). rewrite -(dprod_modl defOhm (Ohm_sub _ _)) . rewrite !(trivgP (subset_trans (setSI _ _) tiKx)) ?Ohm_sub ?Mho_sub //. move/eqP; rewrite eqEcard => /andP[_]. have p_x: p.-elt x := mem_p_elt pG Gx. have [p_pr p_dv_x _] := pgroup_pdiv p_x ntx. rewrite !dprodg1 (Ohm_p_cycle _ p_x) (Mho_p_cycle _ p_x) -!orderE. rewrite orderXdiv ?leq_divLR ?pfactor_dvdn ?leq_subr //. rewrite orderXgcd divn_mulAC ?dvdn_gcdl // leq_divRL ?gcdn_gt0 ?order_gt0 //. rewrite leq_pmul2l //; apply: contraLR. rewrite eqn_dvd dvdn_exponent //= -ltnNge => lt_x_e. rewrite (leq_trans (ltn_Pmull (prime_gt1 p_pr) _)) ?expn_gt0 ?prime_gt0 //. rewrite -expnS dvdn_leq // ?gcdn_gt0 ?order_gt0 // dvdn_gcd. rewrite pfactor_dvdn // dvdn_exp2l. by rewrite -{2}[logn p _]subn0 ltn_sub2l // lognE p_pr order_gt0 p_dv_x. rewrite ltn_sub2r // ltnNge -(dvdn_Pexp2l _ _ (prime_gt1 p_pr)) -!p_part. by rewrite !part_pnat_id // (pnat_dvd (exponent_dvdn G)). Qed. Lemma abelem_homocyclic p G : p.-abelem G -> homocyclic G. Proof. move=> abelG; have [_ cGG _] := and3P abelG. rewrite /homocyclic cGG (@all_pred1_constant _ p) //. case/abelian_structure: cGG (abelian_type_gt1 G) => b defG <- => b_gt1. apply/allP=> _ /mapP[x b_x ->] /=; rewrite (abelem_order_p abelG) //. rewrite -cycle_subG -(bigdprodWY defG) ?sub_gen //. by rewrite bigcup_seq (bigcup_sup x). by rewrite -order_gt1 [_ > 1](allP b_gt1) ?map_f. Qed. Lemma homocyclic1 : homocyclic [1 gT]. Proof. exact: abelem_homocyclic (abelem1 _ 2). Qed. Lemma Ohm1_homocyclicP p G : p.-group G -> abelian G -> reflect ('Ohm_1(G) = 'Mho^(logn p (exponent G)).-1(G)) (homocyclic G). Proof. move=> pG cGG; set e := logn p (exponent G); rewrite -subn1. apply: (iffP idP) => [homoG | ]; first exact: homocyclic_Ohm_Mho. case: (ltnP 1 e) => [lt1e | ]; first exact: Ohm_Mho_homocyclic. rewrite -subn_eq0 => /eqP->; rewrite Mho0 => <-. exact: abelem_homocyclic (Ohm1_abelem pG cGG). Qed. Lemma abelian_type_homocyclic G : homocyclic G -> abelian_type G = nseq 'r(G) (exponent G). Proof. case/andP=> cGG; rewrite -size_abelian_type // /abelian_type. rewrite -(prednK (cardG_gt0 G)) /=; case: andP => //= _; move: (tag _) => H. by move/all_pred1P->; rewrite genGid size_nseq. Qed. Lemma abelian_type_abelem p G : p.-abelem G -> abelian_type G = nseq 'r(G) p. Proof. move=> abelG; rewrite (abelian_type_homocyclic (abelem_homocyclic abelG)). case: (eqVneq G 1%G) => [-> | ntG]; first by rewrite rank1. congr nseq; apply/eqP; rewrite eqn_dvd; have [pG _ ->] := and3P abelG. have [p_pr] := pgroup_pdiv pG ntG; case/Cauchy=> // x Gx <- _. exact: dvdn_exponent. Qed. Lemma max_card_abelian G : abelian G -> #|G| <= exponent G ^ 'r(G) ?= iff homocyclic G. Proof. move=> cGG; have [b defG def_tG] := abelian_structure cGG. have Gb: all (mem G) b. apply/allP=> x b_x; rewrite -(bigdprodWY defG); have [b1 b2] := splitPr b_x. by rewrite big_cat big_cons /= mem_gen // setUCA inE cycle_id. have ->: homocyclic G = all (pred1 (exponent G)) (abelian_type G). rewrite /homocyclic cGG /abelian_type; case: #|G| => //= n. by move: (_ (tag _)) => t; case: ifP => //= _; rewrite genGid eqxx. rewrite -size_abelian_type // -{}def_tG -{defG}(bigdprod_card defG) size_map. rewrite unlock; elim: b Gb => //= x b IHb; case/andP=> Gx Gb. have eGgt0: exponent G > 0 := exponent_gt0 G. have le_x_G: #[x] <= exponent G by rewrite dvdn_leq ?dvdn_exponent. have:= leqif_mul (leqif_eq le_x_G) (IHb Gb). by rewrite -expnS expn_eq0 eqn0Ngt eGgt0. Qed. Lemma card_homocyclic G : homocyclic G -> #|G| = (exponent G ^ 'r(G))%N. Proof. by move=> homG; have [cGG _] := andP homG; apply/eqP; rewrite max_card_abelian. Qed. Lemma abelian_type_dprod_homocyclic p K H G : K \x H = G -> p.-group G -> homocyclic G -> abelian_type K = nseq 'r(K) (exponent G) /\ abelian_type H = nseq 'r(H) (exponent G). Proof. move=> defG pG homG; have [cGG _] := andP homG. have /mulG_sub[sKG sHG]: K * H = G by case/dprodP: defG. have [cKK cHH] := (abelianS sKG cGG, abelianS sHG cGG). suffices: all (pred1 (exponent G)) (abelian_type K ++ abelian_type H). rewrite all_cat => /andP[/all_pred1P-> /all_pred1P->]. by rewrite !size_abelian_type. suffices def_atG: abelian_type K ++ abelian_type H =i abelian_type G. rewrite (eq_all_r def_atG); apply/all_pred1P. by rewrite size_abelian_type // -abelian_type_homocyclic. have [bK defK atK] := abelian_structure cKK. have [bH defH atH] := abelian_structure cHH. apply: perm_eq_mem; rewrite -atK -atH -map_cat. apply: (perm_eq_abelian_type pG); first by rewrite big_cat defK defH. have: all [pred m | m > 1] (map order (bK ++ bH)). by rewrite map_cat all_cat atK atH !abelian_type_gt1. by rewrite all_map (eq_all (@order_gt1 _)) all_predC has_pred1. Qed. Lemma dprod_homocyclic p K H G : K \x H = G -> p.-group G -> homocyclic G -> homocyclic K /\ homocyclic H. Proof. move=> defG pG homG; have [cGG _] := andP homG. have /mulG_sub[sKG sHG]: K * H = G by case/dprodP: defG. have [abtK abtH] := abelian_type_dprod_homocyclic defG pG homG. by rewrite /homocyclic !(abelianS _ cGG) // abtK abtH !constant_nseq. Qed. Lemma exponent_dprod_homocyclic p K H G : K \x H = G -> p.-group G -> homocyclic G -> K :!=: 1 -> exponent K = exponent G. Proof. move=> defG pG homG ntK; have [homK _] := dprod_homocyclic defG pG homG. have [] := abelian_type_dprod_homocyclic defG pG homG. by rewrite abelian_type_homocyclic // -['r(K)]prednK ?rank_gt0 => [[]|]. Qed. End AbelianStructure. Arguments Scope abelian_type [_ group_scope]. Arguments Scope homocyclic [_ group_scope]. Prenex Implicits abelian_type homocyclic. Section IsogAbelian. Variables aT rT : finGroupType. Implicit Type (gT : finGroupType) (D G : {group aT}) (H : {group rT}). Lemma isog_abelian_type G H : isog G H -> abelian_type G = abelian_type H. Proof. pose lnO p n gT (A : {set gT}) := logn p #|'Ohm_n.+1(A) : 'Ohm_n(A)|. pose lni i p gT (A : {set gT}) := \max_(e < logn p #|A| | i < lnO p e _ A) e.+1. suffices{G} nth_abty gT (G : {group gT}) i: abelian G -> i < size (abelian_type G) -> nth 1%N (abelian_type G) i = (\prod_(p < #|G|.+1) p ^ lni i p _ G)%N. - move=> isoGH; case cGG: (abelian G); last first. rewrite /abelian_type -(prednK (cardG_gt0 G)) -(prednK (cardG_gt0 H)) /=. by rewrite {1}(genGid G) {1}(genGid H) -(isog_abelian isoGH) cGG. have cHH: abelian H by rewrite -(isog_abelian isoGH). have eq_sz: size (abelian_type G) = size (abelian_type H). by rewrite !size_abelian_type ?(isog_rank isoGH). apply: (@eq_from_nth _ 1%N) => // i lt_i_G; rewrite !nth_abty // -?eq_sz //. rewrite /lni (card_isog isoGH); apply: eq_bigr => p _; congr (p ^ _)%N. apply: eq_bigl => e; rewrite /lnO -!divgS ?(Ohm_leq _ (leqnSn _)) //=. by have:= card_isog (gFisog _ isoGH) => /= eqF; rewrite !eqF. move=> cGG. have (p): path leq 0 (map (logn p) (rev (abelian_type G))). move: (abelian_type_gt1 G) (abelian_type_dvdn_sorted G). case: abelian_type => //= m t; rewrite rev_cons map_rcons. elim: t m => //= n t IHt m /andP[/ltnW m_gt0 nt_gt1]. rewrite -cats1 cat_path rev_cons map_rcons last_rcons /=. by case/andP=> /dvdn_leq_log-> // /IHt->. have{cGG} [b defG <- b_sorted] := abelian_structure cGG. rewrite size_map => ltib; rewrite (nth_map 1 _ _ ltib); set x := nth 1 b i. have Gx: x \in G. have: x \in b by rewrite mem_nth. rewrite -(bigdprodWY defG); case/splitPr=> bl br. by rewrite mem_gen // big_cat big_cons !inE cycle_id orbT. have lexG: #[x] <= #|G| by rewrite dvdn_leq ?order_dvdG. rewrite -[#[x]]partn_pi // (widen_partn _ lexG) big_mkord big_mkcond. apply: eq_bigr => p _; transitivity (p ^ logn p #[x])%N. by rewrite -logn_gt0; case: posnP => // ->. suffices lti_lnO e: (i < lnO p e _ G) = (e < logn p #[x]). congr (p ^ _)%N; apply/eqP; rewrite eqn_leq andbC; apply/andP; split. by apply/bigmax_leqP=> e; rewrite lti_lnO. case: (posnP (logn p #[x])) => [-> // | logx_gt0]. have lexpG: (logn p #[x]).-1 < logn p #|G|. by rewrite prednK // dvdn_leq_log ?order_dvdG. by rewrite (@bigmax_sup _ (Ordinal lexpG)) ?(prednK, lti_lnO). rewrite /lnO -(count_logn_dprod_cycle _ _ defG). case: (ltnP e _) (b_sorted p) => [lt_e_x | le_x_e]. rewrite -(cat_take_drop i.+1 b) -map_rev rev_cat !map_cat cat_path. case/andP=> _ ordb; rewrite count_cat ((count _ _ =P i.+1) _) ?leq_addr //. rewrite -{2}(size_takel ltib) -all_count. move: ordb; rewrite (take_nth 1 ltib) -/x rev_rcons all_rcons /= lt_e_x. case/andP=> _ /=; move/(order_path_min leq_trans); apply: contraLR. rewrite -!has_predC !has_map; case/hasP=> y b_y /= le_y_e; apply/hasP. by exists y; rewrite ?mem_rev //=; apply: contra le_y_e; exact: leq_trans. rewrite -(cat_take_drop i b) -map_rev rev_cat !map_cat cat_path. case/andP=> ordb _; rewrite count_cat -{1}(size_takel (ltnW ltib)) ltnNge. rewrite addnC ((count _ _ =P 0) _) ?count_size //. rewrite eqn0Ngt -has_count; apply/hasPn=> y b_y /=; rewrite -leqNgt. apply: leq_trans le_x_e; have ->: x = last x (rev (drop i b)). by rewrite (drop_nth 1 ltib) rev_cons last_rcons. rewrite -mem_rev in b_y; case/splitPr: (rev _) / b_y ordb => b1 b2. rewrite !map_cat cat_path last_cat /=; case/and3P=> _ _. move/(order_path_min leq_trans); case/lastP: b2 => // b3 x'. by move/allP; apply; rewrite ?map_f ?last_rcons ?mem_rcons ?mem_head. Qed. Lemma eq_abelian_type_isog G H : abelian G -> abelian H -> isog G H = (abelian_type G == abelian_type H). Proof. move=> cGG cHH; apply/idP/eqP; first exact: isog_abelian_type. have{cGG} [bG defG <-] := abelian_structure cGG. have{cHH} [bH defH <-] := abelian_structure cHH. elim: bG bH G H defG defH => [|x bG IHb] [|y bH] // G H. rewrite !big_nil => <- <- _. by rewrite isog_cyclic_card ?cyclic1 ?cards1. rewrite !big_cons => defG defH /= [eqxy eqb]. apply: (isog_dprod defG defH). by rewrite isog_cyclic_card ?cycle_cyclic -?orderE ?eqxy /=. case/dprodP: defG => [[_ G' _ defG]] _ _ _; rewrite defG. case/dprodP: defH => [[_ H' _ defH]] _ _ _; rewrite defH. exact: IHb eqb. Qed. Lemma isog_abelem_card p G H : p.-abelem G -> isog G H = p.-abelem H && (#|H| == #|G|). Proof. move=> abelG; apply/idP/andP=> [isoGH | [abelH eqGH]]. by rewrite -(isog_abelem isoGH) (card_isog isoGH). rewrite eq_abelian_type_isog ?(@abelem_abelian _ p) //. by rewrite !(@abelian_type_abelem _ p) ?(@rank_abelem _ p) // (eqP eqGH). Qed. Variables (D : {group aT}) (f : {morphism D >-> rT}). Lemma morphim_rank_abelian G : abelian G -> 'r(f @* G) <= 'r(G). Proof. move=> cGG; have sHG := subsetIr D G; apply: leq_trans (rankS sHG). rewrite -!grank_abelian ?morphim_abelian ?(abelianS sHG) //=. by rewrite -morphimIdom morphim_grank ?subsetIl. Qed. Lemma morphim_p_rank_abelian p G : abelian G -> 'r_p(f @* G) <= 'r_p(G). Proof. move=> cGG; have sHG := subsetIr D G; apply: leq_trans (p_rankS p sHG). have cHH := abelianS sHG cGG; rewrite -morphimIdom /=; set H := D :&: G. have sylP := nilpotent_pcore_Hall p (abelian_nil cHH). have sPH := pHall_sub sylP. have sPD: 'O_p(H) \subset D by rewrite (subset_trans sPH) ?subsetIl. rewrite -(p_rank_Sylow (morphim_pHall f sPD sylP)) -(p_rank_Sylow sylP) //. rewrite -!rank_pgroup ?morphim_pgroup ?pcore_pgroup //. by rewrite morphim_rank_abelian ?(abelianS sPH). Qed. Lemma isog_homocyclic G H : G \isog H -> homocyclic G = homocyclic H. Proof. move=> isoGH. by rewrite /homocyclic (isog_abelian isoGH) (isog_abelian_type isoGH). Qed. End IsogAbelian. Section QuotientRank. Variables (gT : finGroupType) (p : nat) (G H : {group gT}). Hypothesis cGG : abelian G. Lemma quotient_rank_abelian : 'r(G / H) <= 'r(G). Proof. exact: morphim_rank_abelian. Qed. Lemma quotient_p_rank_abelian : 'r_p(G / H) <= 'r_p(G). Proof. exact: morphim_p_rank_abelian. Qed. End QuotientRank. mathcomp-1.5/theories/extraspecial.v0000644000175000017500000012162612307636117016666 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq div choice fintype. Require Import bigop finset prime binomial fingroup morphism perm automorphism. Require Import presentation quotient action commutator gproduct gfunctor. Require Import ssralg finalg zmodp cyclic pgroup center gseries. Require Import nilpotent sylow abelian finmodule matrix maximal extremal. (******************************************************************************) (* This file contains the fine structure thorems for extraspecial p-groups. *) (* Together with the material in the maximal and extremal libraries, it *) (* completes the coverage of Aschbacher, section 23. *) (* We define canonical representatives for the group classes that cover the *) (* extremal p-groups (non-abelian p-groups with a cyclic maximal subgroup): *) (* 'Mod_m == the modular group of order m, for m = p ^ n, p prime and n >= 3. *) (* 'D_m == the dihedral group of order m, for m = 2n >= 4. *) (* 'Q_m == the generalized quaternion group of order m, for q = 2 ^ n >= 8. *) (* 'SD_m == the semi-dihedral group of order m, for m = 2 ^ n >= 16. *) (* In each case the notation is defined in the %type, %g and %G scopes, where *) (* it denotes a finGroupType, a full gset and the full group for that type. *) (* However each notation is only meaningful under the given conditions, in *) (* We construct and study the following extraspecial groups: *) (* p^{1+2} == if p is prime, an extraspecial group of order p^3 that has *) (* exponent p or 4, and p-rank 2: thus p^{1+2} is isomorphic to *) (* 'D_8 if p - 2, and NOT isomorphic to 'Mod_(p^3) if p is odd. *) (* p^{1+2*n} == the central product of n copies of p^{1+2}, thus of order *) (* p^(1+2*n) if p is a prime, and, when n > 0, a representative *) (* of the (unique) isomorphism class of extraspecial groups of *) (* order p^(1+2*n), of exponent p or 4, and p-rank n+1. *) (* 'D^n == an alternative (and preferred) notation for 2^{1+2*n}, which *) (* is isomorphic to the central product of n copies od 'D_8. *) (* 'D^n*Q == the central product of 'D^n with 'Q_8, thus isomorphic to *) (* all extraspecial groups of order 2 ^ (2 * n + 3) that are *) (* not isomorphic to 'D^n.+1 (or, equivalently, have 2-rank n). *) (* As in extremal.v, these notations are simultaneously defined in the %type, *) (* %g and %G scopes -- depending on the syntactic context, they denote either *) (* a finGroupType, the set, or the group of all its elements. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Local Open Scope ring_scope. Import GroupScope GRing.Theory. Reserved Notation "p ^{1+2}" (at level 2, format "p ^{1+2}"). Reserved Notation "p ^{1+2* n }" (at level 2, n at level 2, format "p ^{1+2* n }"). Reserved Notation "''D^' n" (at level 8, n at level 2, format "''D^' n"). Reserved Notation "''D^' n * 'Q'" (at level 8, n at level 2, format "''D^' n * 'Q'"). Module Pextraspecial. Section Construction. Variable p : nat. Definition act ij (k : 'Z_p) := let: (i, j) := ij in (i + k * j, j). Lemma actP : is_action [set: 'Z_p] act. Proof. apply: is_total_action=> [] [i j] => [|k1 k2] /=; first by rewrite mul0r addr0. by rewrite mulrDl addrA. Qed. Canonical action := Action actP. Lemma gactP : is_groupAction [set: 'Z_p * 'Z_p] action. Proof. move=> k _ /=; rewrite inE. apply/andP; split; first by apply/subsetP=> ij _; rewrite inE. apply/morphicP=> /= [[i1 j1] [i2 j2] _ _]. by rewrite !permE /= mulrDr -addrA (addrCA i2) (addrA i1). Qed. Definition groupAction := GroupAction gactP. Fact gtype_key : unit. Proof. by []. Qed. Definition gtype := locked_with gtype_key (sdprod_groupType groupAction). Definition ngtype := ncprod [set: gtype]. End Construction. Definition ngtypeQ n := xcprod [set: ngtype 2 n] 'Q_8. End Pextraspecial. Notation "p ^{1+2}" := (Pextraspecial.gtype p) : type_scope. Notation "p ^{1+2}" := [set: gsort p^{1+2}] : group_scope. Notation "p ^{1+2}" := [set: gsort p^{1+2}]%G : Group_scope. Notation "p ^{1+2* n }" := (Pextraspecial.ngtype p n) : type_scope. Notation "p ^{1+2* n }" := [set: gsort p^{1+2*n}] : group_scope. Notation "p ^{1+2* n }" := [set: gsort p^{1+2*n}]%G : Group_scope. Notation "''D^' n" := (Pextraspecial.ngtype 2 n) : type_scope. Notation "''D^' n" := [set: gsort 'D^n] : group_scope. Notation "''D^' n" := [set: gsort 'D^n]%G : Group_scope. Notation "''D^' n * 'Q'" := (Pextraspecial.ngtypeQ n) : type_scope. Notation "''D^' n * 'Q'" := [set: gsort 'D^n*Q] : group_scope. Notation "''D^' n * 'Q'" := [set: gsort 'D^n*Q]%G : Group_scope. Section ExponentPextraspecialTheory. Variable p : nat. Hypothesis p_pr : prime p. Let p_gt1 := prime_gt1 p_pr. Let p_gt0 := ltnW p_gt1. Local Notation gtype := Pextraspecial.gtype. Local Notation actp := (Pextraspecial.groupAction p). Lemma card_pX1p2 : #|p^{1+2}| = (p ^ 3)%N. Proof. rewrite [@gtype _]unlock -(sdprod_card (sdprod_sdpair _)). rewrite !card_injm ?injm_sdpair1 ?injm_sdpair2 // !cardsT card_prod card_ord. by rewrite -mulnA Zp_cast. Qed. Lemma Grp_pX1p2 : p^{1+2} \isog Grp (x : y : (x ^+ p, y ^+ p, [~ x, y, x], [~ x, y, y])). Proof. rewrite [@gtype _]unlock ; apply: intro_isoGrp => [|rT H]. apply/existsP; pose x := sdpair1 actp (0, 1)%R; pose y := sdpair2 actp 1%R. exists (x, y); rewrite /= !xpair_eqE; set z := [~ x, y]; set G := _ <*> _. have def_z: z = sdpair1 actp (1, 0)%R. rewrite [z]commgEl -sdpair_act ?inE //=. rewrite -morphV -?morphM ?inE //=; congr (sdpair1 _ (_, _)) => /=. by rewrite mulr1 mulKg. by rewrite mulVg. have def_xi i: x ^+ i = sdpair1 _ (0, i%:R)%R. rewrite -morphX ?inE //; congr (sdpair1 _ _). by apply/eqP; rewrite /eq_op /= !morphX ?inE ?expg1n //=. have def_yi i: y ^+ i = sdpair2 _ i%:R. by rewrite -morphX ?inE //. have def_zi i: z ^+ i = sdpair1 _ (i%:R, 0)%R. rewrite def_z -morphX ?inE //; congr (sdpair1 _ _). by apply/eqP; rewrite /eq_op /= !morphX ?inE ?expg1n ?andbT //=. rewrite def_xi def_yi char_Zp ?morph1 //. rewrite def_z -morphR ?inE // !commgEl -sdpair_act ?inE //= mulr0 addr0. rewrite mulVg -[_ * _]/(_ , _) /= !invg1 mulg1 !mul1g mulVg morph1 !andbT. have Gx: x \in G by rewrite -cycle_subG joing_subl. have Gy: y \in G by rewrite -cycle_subG joing_subr. rewrite eqEsubset subsetT -im_sdpair mulG_subG /= -/G; apply/andP; split. apply/subsetP=> u /morphimP[[i j] _ _ def_u]. suffices ->: u = z ^+ i * x ^+ j by rewrite groupMl groupX ?groupR. rewrite def_zi def_xi !natr_Zp -morphM ?inE // def_u. by congr (sdpair1 _ (_, _)); rewrite ?mulg1 ?mul1g. apply/subsetP=> v /morphimP[k _ _ def_v]. suffices ->: v = y ^+ k by rewrite groupX. by rewrite def_yi natr_Zp. case/existsP=> [[x y] /=]; set z := [~ x, y]. case/eqP=> defH xp yp /eqP/commgP czx /eqP/commgP czy. have zp: z ^+ p = 1 by rewrite -commXg // xp comm1g. pose f1 (ij : 'Z_p * 'Z_p) := let: (i, j) := ij in z ^+ i * x ^+ j. have f1M: {in setT &, {morph f1 : u v / u * v}}. case=> /= [i1 j1] [i2 j2] _ _ /=; rewrite {3 6}Zp_cast // !expg_mod //. rewrite !expgD !mulgA; congr (_ * _); rewrite -!mulgA; congr (_ * _). by apply: commuteX2. pose f2 (k : 'Z_p) := y ^+ k. have f2M: {in setT &, {morph f2 : u v / u * v}}. by move=> k1 k2 _ _; rewrite /f2 /= {3}Zp_cast // expg_mod // expgD. have actf: {in setT & setT, morph_act actp 'J (Morphism f1M) (Morphism f2M)}. case=> /= i j k _ _; rewrite modnDmr {4}Zp_cast // expg_mod // expgD. rewrite /f2 conjMg {1}/conjg (commuteX2 i k czy) mulKg -mulgA. congr (_ * _); rewrite (commuteX2 _ _ czx) mulnC expgM. by rewrite -commXg // -commgX ?mulKVg // commXg // /commute commuteX. apply/homgP; exists (xsdprod_morphism actf). apply/eqP; rewrite eqEsubset -{2}defH -genM_join gen_subG /= im_xsdprodm. have Hx: x \in H by rewrite -cycle_subG -defH joing_subl. have Hy: y \in H by rewrite -cycle_subG -defH joing_subr. rewrite mulG_subG -andbA; apply/and3P; split. - apply/subsetP=> _ /morphimP[[i j] _ _ -> /=]. by rewrite groupMl groupX ?groupR. - by apply/subsetP=> _ /morphimP[k _ _ ->]; rewrite groupX. rewrite mulgSS ?cycle_subG //= morphimEdom; apply/imsetP. by exists (0, 1)%R; rewrite ?inE //= mul1g. by exists 1%R; rewrite ?inE. Qed. Lemma pX1p2_pgroup : p.-group p^{1+2}. Proof. by rewrite /pgroup card_pX1p2 pnat_exp pnat_id. Qed. (* This is part of the existence half of Aschbacher ex. (8.7)(1) *) Lemma pX1p2_extraspecial : extraspecial p^{1+2}. Proof. apply: (p3group_extraspecial pX1p2_pgroup); last first. by rewrite card_pX1p2 pfactorK. case/existsP: (isoGrp_hom Grp_pX1p2) card_pX1p2 => [[x y]] /=. case/eqP=> <- xp yp _ _ oXY. apply: contraL (dvdn_cardMg <[x]> <[y]>) => cXY_XY. rewrite -cent_joinEl ?(sub_abelian_cent2 cXY_XY) ?joing_subl ?joing_subr //. rewrite oXY -!orderE pfactor_dvdn ?muln_gt0 ?order_gt0 // -leqNgt. rewrite -(pfactorK 2 p_pr) dvdn_leq_log ?expn_gt0 ?p_gt0 //. by rewrite dvdn_mul ?order_dvdn ?xp ?yp. Qed. (* This is part of the existence half of Aschbacher ex. (8.7)(1) *) Lemma exponent_pX1p2 : odd p -> exponent p^{1+2} %| p. Proof. move=> p_odd; have pG := pX1p2_pgroup. have ->: p^{1+2} = 'Ohm_1(p^{1+2}). apply/eqP; rewrite eqEsubset Ohm_sub andbT (OhmE 1 pG). case/existsP: (isoGrp_hom Grp_pX1p2) => [[x y]] /=. case/eqP=> <- xp yp _ _; rewrite joing_idl joing_idr genS //. by rewrite subsetI subset_gen subUset !sub1set !inE xp yp!eqxx. rewrite exponent_Ohm1_class2 ?card_pX1p2 ?odd_exp // nil_class2. by have [[_ ->] _ ] := pX1p2_extraspecial. Qed. (* This is the uniqueness half of Aschbacher ex. (8.7)(1) *) Lemma isog_pX1p2 (gT : finGroupType) (G : {group gT}) : extraspecial G -> exponent G %| p -> #|G| = (p ^ 3)%N -> G \isog p^{1+2}. Proof. move=> esG expGp oG; apply/(isoGrpP _ Grp_pX1p2). rewrite card_pX1p2; split=> //. have pG: p.-group G by rewrite /pgroup oG pnat_exp pnat_id. have oZ := card_center_extraspecial pG esG. have [x Gx notZx]: exists2 x, x \in G & x \notin 'Z(G). apply/subsetPn; rewrite proper_subn // properEcard center_sub oZ oG. by rewrite (ltn_exp2l 1 3). have ox: #[x] = p. by apply: nt_prime_order; rewrite ?(exponentP expGp) ?(group1_contra notZx). have [y Gy not_cxy]: exists2 y, y \in G & y \notin 'C[x]. by apply/subsetPn; rewrite sub_cent1; rewrite inE Gx in notZx. apply/existsP; exists (x, y) => /=; set z := [~ x, y]. have [[defPhiG defG'] _] := esG. have Zz: z \in 'Z(G) by rewrite -defG' mem_commg. have [Gz cGz] := setIP Zz; rewrite !xpair_eqE !(exponentP expGp) //. have [_ nZG] := andP (center_normal G). rewrite /commg /conjg !(centP cGz) // !mulKg mulVg !eqxx !andbT. have sXY_G: <[x]> <*> <[y]> \subset G by rewrite join_subG !cycle_subG Gx. have defZ: <[z]> = 'Z(G). apply/eqP; rewrite eqEcard cycle_subG Zz oZ /= -orderE. rewrite (nt_prime_order p_pr) ?(exponentP expGp) //. by rewrite (sameP commgP cent1P) cent1C. have sZ_XY: 'Z(G) \subset <[x]> <*> <[y]>. by rewrite -defZ cycle_subG groupR // mem_gen // inE cycle_id ?orbT. rewrite eqEcard sXY_G /= oG -(Lagrange sZ_XY) oZ leq_pmul2l //. rewrite -card_quotient ?(subset_trans sXY_G) //. rewrite quotientY ?quotient_cycle ?cycle_subG ?(subsetP nZG) //. have abelGz: p.-abelem (G / 'Z(G)) by rewrite -defPhiG Phi_quotient_abelem. have [cGzGz expGz] := abelemP p_pr abelGz. rewrite cent_joinEr ?(sub_abelian_cent2 cGzGz) ?cycle_subG ?mem_quotient //. have oZx: #|<[coset 'Z(G) x]>| = p. rewrite -orderE (nt_prime_order p_pr) ?expGz ?mem_quotient //. by apply: contra notZx; move/eqP=> Zx; rewrite coset_idr ?(subsetP nZG). rewrite TI_cardMg ?oZx -?orderE ?(nt_prime_order p_pr) ?expGz ?mem_quotient //. apply: contra not_cxy; move/eqP=> Zy. rewrite -cent_cycle (subsetP _ y (coset_idr _ Zy)) ?(subsetP nZG) //. by rewrite subIset ?centS ?orbT ?cycle_subG. rewrite prime_TIg ?oZx // cycle_subG; apply: contra not_cxy. case/cycleP=> i; rewrite -morphX ?(subsetP nZG) // => /rcoset_kercosetP. rewrite groupX ?(subsetP nZG) // cent1C => /(_ isT isT); apply: subsetP. rewrite mul_subG ?sub1set ?groupX ?cent1id //= -cent_cycle subIset // orbC. by rewrite centS ?cycle_subG. Qed. End ExponentPextraspecialTheory. Section GeneralExponentPextraspecialTheory. Variable p : nat. Lemma pX1p2id : p^{1+2*1} \isog p^{1+2}. Proof. exact: ncprod1. Qed. Lemma pX1p2S n : xcprod_spec p^{1+2} p^{1+2*n} p^{1+2*n.+1}%type. Proof. exact: ncprodS. Qed. Lemma card_pX1p2n n : prime p -> #|p^{1+2*n}| = (p ^ n.*2.+1)%N. Proof. move=> p_pr; have pG := pX1p2_pgroup p_pr. have oG := card_pX1p2 p_pr; have esG := pX1p2_extraspecial p_pr. have oZ := card_center_extraspecial pG esG. elim: n => [|n IHn]; first by rewrite (card_isog (ncprod0 _)) oZ. case: pX1p2S => gz isoZ; rewrite -im_cpair cardMg_divn setI_im_cpair. rewrite -injm_center ?{1}card_injm ?injm_cpairg1 ?injm_cpair1g ?center_sub //. by rewrite oG oZ IHn -expnD mulKn ?prime_gt0. Qed. Lemma pX1p2n_pgroup n : prime p -> p.-group p^{1+2*n}. Proof. by move=> p_pr; rewrite /pgroup card_pX1p2n // pnat_exp pnat_id. Qed. (* This is part of the existence half of Aschbacher (23.13) *) Lemma exponent_pX1p2n n : prime p -> odd p -> exponent p^{1+2*n} = p. Proof. move=> p_pr odd_p; apply: prime_nt_dvdP => //. rewrite -dvdn1 -trivg_exponent -cardG_gt1 card_pX1p2n //. by rewrite (ltn_exp2l 0) // prime_gt1. elim: n => [|n IHn]. by rewrite (dvdn_trans (exponent_dvdn _)) ?card_pX1p2n. case: pX1p2S => gz isoZ; rewrite -im_cpair /=. apply/exponentP=> xy; case/imset2P=> x y C1x C2y ->{xy}. rewrite expgMn; last by red; rewrite -(centsP (im_cpair_cent isoZ)). rewrite (exponentP _ y C2y) ?exponent_injm ?injm_cpair1g // mulg1. by rewrite (exponentP _ x C1x) ?exponent_injm ?injm_cpairg1 // exponent_pX1p2. Qed. (* This is part of the existence half of Aschbacher (23.13) and (23.14) *) Lemma pX1p2n_extraspecial n : prime p -> n > 0 -> extraspecial p^{1+2*n}. Proof. move=> p_pr; elim: n => [//|n IHn _]. have esG := pX1p2_extraspecial p_pr. have [n0 | n_gt0] := posnP n. by apply: isog_extraspecial esG; rewrite isog_sym n0 pX1p2id. case: pX1p2S (pX1p2n_pgroup n.+1 p_pr) => gz isoZ pGn. apply: (cprod_extraspecial pGn (im_cpair_cprod isoZ) (setI_im_cpair isoZ)). by apply: injm_extraspecial esG; rewrite ?injm_cpairg1. by apply: injm_extraspecial (IHn n_gt0); rewrite ?injm_cpair1g. Qed. (* This is Aschbacher (23.12) *) Lemma Ohm1_extraspecial_odd (gT : finGroupType) (G : {group gT}) : p.-group G -> extraspecial G -> odd #|G| -> let Y := 'Ohm_1(G) in [/\ exponent Y = p, #|G : Y| %| p & Y != G -> exists E : {group gT}, [/\ #|G : Y| = p, #|E| = p \/ extraspecial E, exists2 X : {group gT}, #|X| = p & X \x E = Y & exists M : {group gT}, [/\ M \isog 'Mod_(p ^ 3), M \* E = G & M :&: E = 'Z(M)]]]. Proof. move=> pG esG oddG Y; have [spG _] := esG. have [defPhiG defG'] := spG; set Z := 'Z(G) in defPhiG defG'. have{spG} expG: exponent G %| p ^ 2 by exact: exponent_special. have p_pr := extraspecial_prime pG esG. have p_gt1 := prime_gt1 p_pr; have p_gt0 := ltnW p_gt1. have oZ: #|Z| = p := card_center_extraspecial pG esG. have nsZG: Z <| G := center_normal G; have [sZG nZG] := andP nsZG. have nsYG: Y <| G := Ohm_normal 1 G; have [sYG nYG] := andP nsYG. have ntZ: Z != 1 by rewrite -cardG_gt1 oZ. have sZY: Z \subset Y. by apply: contraR ntZ => ?; rewrite -(setIidPl sZG) TI_Ohm1 ?prime_TIg ?oZ. have ntY: Y != 1 by apply: contra ntZ; rewrite -!subG1; exact: subset_trans. have p_odd: odd p by rewrite -oZ (oddSg sZG). have expY: exponent Y %| p by rewrite exponent_Ohm1_class2 // nil_class2 defG'. rewrite (prime_nt_dvdP p_pr _ expY) -?dvdn1 -?trivg_exponent //. have [-> | neYG] := eqVneq Y G; first by rewrite indexgg dvd1n eqxx; split. have sG1Z: 'Mho^1(G) \subset Z by rewrite -defPhiG (Phi_joing pG) joing_subr. have Z_Gp: {in G, forall x, x ^+ p \in Z}. by move=> x Gx; rewrite /= (subsetP sG1Z) ?(Mho_p_elt 1) ?(mem_p_elt pG). have{expG} oY': {in G :\: Y, forall u, #[u] = (p ^ 2)%N}. move=> u /setDP[Gu notYu]; apply/eqP. have [k ou] := p_natP (mem_p_elt pG Gu). rewrite eqn_dvd order_dvdn (exponentP expG) // eqxx ou dvdn_Pexp2l // ltnNge. apply: contra notYu => k_le_1; rewrite [Y](OhmE _ pG) mem_gen // !inE Gu /=. by rewrite -order_dvdn ou dvdn_exp2l. have isoMod3 (M : {group gT}): M \subset G -> ~~ abelian M -> ~~ (M \subset Y) -> #|M| = (p ^ 3)%N -> M \isog 'Mod_(p ^ 3). - move=> sMG not_cMM /subsetPn[u Mu notYu oM]. have pM := pgroupS sMG pG; have sUM: <[u]> \subset M by rewrite cycle_subG. have Y'u: u \in G :\: Y by rewrite inE notYu (subsetP sMG). have iUM: #|M : <[u]>| = p by rewrite -divgS // oM expnS -(oY' u) ?mulnK. have cM := maximal_cycle_extremal pM not_cMM (cycle_cyclic u) sUM iUM. rewrite (sameP eqP (prime_oddPn p_pr)) p_odd orbF in cM. rewrite /extremal_class oM pdiv_pfactor // pfactorK //= in cM. by do 3!case: ifP => // _ in cM. have iYG: #|G : Y| = p. have [V maxV sYV]: {V : {group gT} | maximal V G & Y \subset V}. by apply: maxgroup_exists; rewrite properEneq neYG. have [sVG [u Gu notVu]] := properP (maxgroupp maxV). without loss [v Vv notYv]: / exists2 v, v \in V & v \notin Y. have [->| ] := eqVneq Y V; first by rewrite (p_maximal_index pG). by rewrite eqEsubset sYV => not_sVY; apply; exact/subsetPn. pose U := <[u]> <*> <[v]>; have Gv := subsetP sVG v Vv. have sUG: U \subset G by rewrite join_subG !cycle_subG Gu. have Uu: u \in U by rewrite -cycle_subG joing_subl. have Uv: v \in U by rewrite -cycle_subG joing_subr. have not_sUY: ~~ (U \subset Y) by apply/subsetPn; exists v. have sU1U: 'Ohm_1(U) \subset U := Ohm_sub 1 _. have sU1Y: 'Ohm_1(U) \subset Y := OhmS 1 sUG. suffices defUV: U :&: V = 'Ohm_1(U). by rewrite (subsetP sU1Y) // -defUV inE Uv in notYv. suffices iU1U: #|U : 'Ohm_1(U)| = p. have: maximal 'Ohm_1(U) U by rewrite p_index_maximal ?Ohm_sub ?iU1U. case/maxgroupP=> _; apply; rewrite /= -/U. by apply/properP; split; last exists u; rewrite ?subsetIl ?inE ?Uu. by rewrite subsetI Ohm_sub (subset_trans sU1Y). apply/prime_nt_dvdP=> //. by apply: contra not_sUY; rewrite /U; move/eqP; move/(index1g sU1U)=> <-. have ov: #[v] = (p ^ 2)%N by rewrite oY' // inE notYv. have sZv: Z \subset <[v]>. suffices defZ: <[v ^+ p]> == Z by rewrite -(eqP defZ) cycleX. by rewrite eqEcard cycle_subG Z_Gp //= oZ -orderE (orderXexp 1 ov). have nvG: G \subset 'N(<[v]>) by rewrite sub_der1_norm ?cycle_subG // defG'. have [cUU | not_cUU] := orP (orbN (abelian U)). rewrite -divgS ?Ohm_sub // -(mul_card_Ohm_Mho_abelian 1 cUU) /= -/U. by rewrite mulKn ?cardG_gt0 //= -oZ cardSg ?(subset_trans (MhoS 1 sUG)). have oU: #|U| = (p ^ 3)%N. have nvu := subsetP nvG u Gu; have nvU := subset_trans sUG nvG. rewrite -(Lagrange (joing_subr _ _)) -orderE ov mulnC; congr (_ * _)%N. rewrite -card_quotient //= quotientYidr ?cycle_subG //=. rewrite quotient_cycle // -orderE; apply: nt_prime_order => //. by rewrite -morphX //= coset_id // (subsetP sZv) // Z_Gp. have svV: <[v]> \subset V by rewrite cycle_subG. by apply: contra notVu; move/eqP=> v_u; rewrite (subsetP svV) // coset_idr. have isoU := isoMod3 _ sUG not_cUU not_sUY oU; rewrite /= -/U in isoU. have [//|[x y] genU modU] := generators_modular_group p_pr _ isoU. case/modular_group_structure: genU => // _ _ _ _. case: eqP (p_odd) => [[-> //] | _ _]; case/(_ 1%N)=> // _ oU1. by rewrite -divgS // oU oU1 mulnK // muln_gt0 p_gt0. have iC1U (U : {group gT}) x: U \subset G -> x \in G :\: 'C(U) -> #|U : 'C_U[x]| = p. - move=> sUG /setDP[Gx not_cUx]; apply/prime_nt_dvdP=> //. apply: contra not_cUx; rewrite -sub_cent1 => /eqP sUCx. by rewrite -(index1g _ sUCx) ?subsetIl ?subsetIr. rewrite -(@dvdn_pmul2l (#|U| * #|'C_G[x]|)) ?muln_gt0 ?cardG_gt0 //. have maxCx: maximal 'C_G[x] G. rewrite cent1_extraspecial_maximal //; apply: contra not_cUx. by rewrite inE Gx; exact: subsetP (centS sUG) _. rewrite {1}mul_cardG setIA (setIidPl sUG) -(p_maximal_index pG maxCx) -!mulnA. rewrite !Lagrange ?subsetIl // mulnC dvdn_pmul2l //. have [sCxG nCxG] := andP (p_maximal_normal pG maxCx). by rewrite -norm_joinEl ?cardSg ?join_subG ?(subset_trans sUG). have oCG (U : {group gT}): Z \subset U -> U \subset G -> #|'C_G(U)| = (p * #|G : U|)%N. - elim: {U}_.+1 {-2}U (ltnSn #|U|) => // m IHm U leUm sZU sUG. have [<- | neZU] := eqVneq Z U. by rewrite -oZ Lagrange // (setIidPl _) // centsC subsetIr. have{neZU} [x Gx not_cUx]: exists2 x, x \in G & x \notin 'C(U). by apply/subsetPn; rewrite eqEsubset sZU subsetI sUG centsC in neZU. pose W := 'C_U[x]; have iWU: #|U : W| = p by rewrite iC1U // inE not_cUx. have maxW: maximal W U by rewrite p_index_maximal ?subsetIl ?iWU. have ltWU: W \proper U by exact: maxgroupp maxW. have [sWU [u Uu notWu]] := properP ltWU. have defU: W * <[u]> = U. have nsWU: W <| U := p_maximal_normal (pgroupS sUG pG) maxW. by rewrite (mulg_normal_maximal nsWU) ?cycle_subG. have sWG := subset_trans sWU sUG. have sZW: Z \subset W. by rewrite subsetI sZU -cent_set1 subIset ?centS ?orbT ?sub1set. have iCW_CU: #|'C_G(W) : 'C_G(U)| = p. rewrite -defU centM cent_cycle setIA /= -/W. rewrite iC1U ?subsetIl ?setIS ?centS // inE andbC (subsetP sUG) //=. rewrite -sub_cent1; apply/subsetPn; exists x. by rewrite inE Gx -sub_cent1 subsetIr. by rewrite -defU centM cent_cycle inE -sub_cent1 subsetIr in not_cUx. apply/eqP; rewrite -(eqn_pmul2r p_gt0) -{1}iCW_CU Lagrange ?setIS ?centS //. rewrite IHm ?(leq_trans (proper_card ltWU)) //= -/W. by rewrite -(Lagrange_index sUG sWU) iWU mulnA. have oCY: #|'C_G(Y)| = (p ^ 2)%N by rewrite oCG // iYG. have [x cYx notZx]: exists2 x, x \in 'C_G(Y) & x \notin Z. apply/subsetPn; rewrite proper_subn // properEcard setIS ?centS //=. by rewrite oZ oCY (ltn_exp2l 1 2). have{cYx} [Gx cYx] := setIP cYx; have nZx := subsetP nZG x Gx. have defCx: 'C_G[x] = Y. apply/eqP; rewrite eq_sym eqEcard subsetI sYG sub_cent1 cYx /=. rewrite -(leq_pmul2r p_gt0) -{2}iYG -(iC1U G x) ?Lagrange ?subsetIl //. by rewrite !inE Gx ?andbT in notZx *. have Yx: x \in Y by rewrite -defCx inE Gx cent1id. have ox: #[x] = p. by apply: nt_prime_order; rewrite ?(exponentP expY) // (group1_contra notZx). have defCy: 'C_G(Y) = Z * <[x]>. apply/eqP; rewrite eq_sym eqEcard mulG_subG setIS ?centS //=. rewrite cycle_subG inE Gx cYx oCY TI_cardMg ?oZ -?orderE ?ox //=. by rewrite setIC prime_TIg -?orderE ?ox ?cycle_subG. have abelYt: p.-abelem (Y / Z). by rewrite (abelemS (quotientS _ sYG)) //= -/Z -defPhiG Phi_quotient_abelem. have Yxt: coset Z x \in Y / Z by rewrite mem_quotient. have{Yxt} [Et [sEtYt oEt defYt]] := p_abelem_split1 abelYt Yxt. have nsZY: Z <| Y := normalS sZY sYG nsZG. have [E defEt sZE sEY] := inv_quotientS nsZY sEtYt. have{defYt} [_ defYt _ tiXEt] := dprodP defYt. have defY: <[x]> \x E = Y. have nZX: <[x]> \subset 'N(Z) by rewrite cycle_subG. have TIxE: <[x]> :&: E = 1. rewrite prime_TIg -?orderE ?ox // -(quotientSGK _ sZE) ?quotient_cycle //. rewrite (sameP setIidPl eqP) eq_sym -defEt tiXEt -quotient_cycle //. by rewrite -subG1 quotient_sub1 // cycle_subG. rewrite dprodE //; last 1 first. by rewrite cent_cycle (subset_trans sEY) //= -/Y -defCx subsetIr. rewrite -[Y](quotientGK nsZY) -defYt cosetpreM -quotient_cycle //. rewrite quotientK // -(normC nZX) defEt quotientGK ?(normalS _ sEY) //. by rewrite -mulgA (mulSGid sZE). have sEG := subset_trans sEY sYG; have nZE := subset_trans sEG nZG. have defZE: 'Z(E) = Z. apply/eqP; rewrite eqEsubset andbC subsetI sZE subIset ?centS ?orbT //. rewrite -quotient_sub1 ?subIset ?nZE //= -tiXEt defEt subsetI andbC. rewrite quotientS ?center_sub //= -quotient_cycle //. rewrite -(quotientMidl _ <[x]>) /= -defCy quotientS // /Y. by case/dprodP: defY => _ <- _ _; rewrite centM setIA cent_cycle defCx setSI. have pE := pgroupS sEG pG. rewrite iYG; split=> // _; exists E. split=> //; first 2 [by exists [group of <[x]>]]. have:= sZE; rewrite subEproper; case/predU1P=> [<- | ltZE]; [by left | right]. split; rewrite /special defZE ?oZ // (Phi_joing pE). have defE': E^`(1) = Z. have sE'Z: E^`(1) \subset Z by rewrite -defG' dergS. apply/eqP; rewrite eqEcard sE'Z -(prime_nt_dvdP _ _ (cardSg sE'Z)) ?oZ //=. rewrite -trivg_card1 (sameP eqP commG1P). by rewrite /proper sZE /= -/Z -defZE subsetI subxx in ltZE. split=> //; rewrite -defE'; apply/joing_idPl. by rewrite /= defE' -defPhiG (Phi_joing pG) joingC sub_gen ?subsetU ?MhoS. have iEG: #|G : E| = (p ^ 2)%N. apply/eqP; rewrite -(@eqn_pmul2l #|E|) // Lagrange // -(Lagrange sYG) iYG. by rewrite -(dprod_card defY) -mulnA mulnCA -orderE ox. pose M := 'C_G(E); exists [group of M] => /=. have sMG: M \subset G := subsetIl _ _; have pM: p.-group M := pgroupS sMG pG. have sZM: Z \subset M by rewrite setIS ?centS. have oM: #|M| = (p ^ 3)%N by rewrite oCG ?iEG. have defME: M * E = G. apply/eqP; rewrite eqEcard mulG_subG sMG sEG /= -(leq_pmul2r p_gt0). rewrite -{2}oZ -defZE /('Z(E)) -{2}(setIidPr sEG) setIAC -mul_cardG /= -/M. by rewrite -(Lagrange sEG) mulnAC -mulnA mulnC iEG oM. have defZM: 'Z(M) = Z. apply/eqP; rewrite eqEsubset andbC subsetI sZM subIset ?centS ?orbT //=. by rewrite /Z /('Z(G)) -{2}defME centM setIA setIAC. rewrite cprodE 1?centsC ?subsetIr //. rewrite defME setIAC (setIidPr sEG) defZM isoMod3 //. rewrite abelianE (sameP setIidPl eqP) eqEcard subsetIl /= -/('Z(M)) -/M. by rewrite defZM oZ oM (leq_exp2l 3 1). by apply: contra neYG => sMY; rewrite eqEsubset sYG -defME mulG_subG sMY. Qed. (* This is the uniqueness half of Aschbacher (23.13); the proof incorporates *) (* in part the proof that symplectic spaces are hyperbolic (19.16). *) Lemma isog_pX1p2n n (gT : finGroupType) (G : {group gT}) : prime p -> extraspecial G -> #|G| = (p ^ n.*2.+1)%N -> exponent G %| p -> G \isog p^{1+2*n}. Proof. move=> p_pr esG oG expG; have p_gt1 := prime_gt1 p_pr. have not_le_p3_p: ~~ (p ^ 3 <= p) by rewrite (leq_exp2l 3 1). have pG: p.-group G by rewrite /pgroup oG pnat_exp pnat_id. have oZ := card_center_extraspecial pG esG. have{pG esG} [Es p3Es defG] := extraspecial_structure pG esG. set Z := 'Z(G) in oZ defG p3Es. elim: Es {+}G => [|E Es IHs] S in n oG expG p3Es defG *. rewrite big_nil cprod1g in defG; rewrite -defG. have ->: n = 0%N. apply: double_inj; apply/eqP. by rewrite -eqSS -(eqn_exp2l _ _ p_gt1) -oG -defG oZ. by rewrite isog_cyclic_card prime_cyclic ?oZ ?card_pX1p2n //=. rewrite big_cons -cprodA in defG; rewrite /= -andbA in p3Es. have [[_ T _ defT] defET cTE] := cprodP defG; rewrite defT in defET cTE defG. case/and3P: p3Es; move/eqP=> oE; move/eqP=> defZE; move/IHs=> {IHs}IHs. have not_cEE: ~~ abelian E. by apply: contra not_le_p3_p => cEE; rewrite -oE -oZ -defZE (center_idP _). have sES: E \subset S by rewrite -defET mulG_subl. have sTS: T \subset S by rewrite -defET mulG_subr. have expE: exponent E %| p by exact: dvdn_trans (exponentS sES) expG. have expT: exponent T %| p by exact: dvdn_trans (exponentS sTS) expG. have{expE not_cEE} isoE: E \isog p^{1+2}. apply: isog_pX1p2 => //. by apply: card_p3group_extraspecial p_pr oE _; rewrite defZE. have sZT: 'Z(E) \subset T. by case/cprodP: defT => [[U _ -> _] <- _]; rewrite defZE mulG_subr. case def_n: n => [|n']. case/negP: not_le_p3_p; rewrite def_n in oG; rewrite -oE -[p]oG. exact: subset_leq_card. have zI_ET: E :&: T = 'Z(E). by apply/eqP; rewrite eqEsubset subsetI sZT subsetIl setIS // centsC. have{n def_n oG} oT: #|T| = (p ^ n'.*2.+1)%N. apply/eqP; rewrite -(eqn_pmul2l (cardG_gt0 E)) mul_cardG zI_ET defET. by rewrite defZE oE oG oZ -expnSr -expnD def_n. have{IHs oT expT defT Es} isoT: T \isog p^{1+2*n'} by rewrite IHs. case: pX1p2S => gz isoZ; rewrite (isog_cprod_by _ defG) //. exact: Aut_extraspecial_full (pX1p2_pgroup p_pr) (pX1p2_extraspecial p_pr). Qed. End GeneralExponentPextraspecialTheory. Lemma isog_2X1p2 : 2^{1+2} \isog 'D_8. Proof. have pr2: prime 2 by []; have oG := card_pX1p2 pr2; rewrite -[8]oG. case/existsP: (isoGrp_hom (Grp_pX1p2 pr2)) => [[x y]] /=. rewrite -/2^{1+2}; case/eqP=> defG x2 y2 _ _. have not_oG_2: ~~ (#|2^{1+2}| %| 2) by rewrite oG. have ox: #[x] = 2. apply: nt_prime_order => //; apply: contra not_oG_2 => x1. by rewrite -defG (eqP x1) cycle1 joing1G order_dvdn y2. have oy: #[y] = 2. apply: nt_prime_order => //; apply: contra not_oG_2 => y1. by rewrite -defG (eqP y1) cycle1 joingG1 order_dvdn x2. rewrite -defG joing_idl joing_idr involutions_gen_dihedral //. apply: contra not_oG_2 => eq_xy; rewrite -defG (eqP eq_xy) (joing_idPl _) //. by rewrite -orderE oy. Qed. Lemma Q8_extraspecial : extraspecial 'Q_8. Proof. have gt32: 3 > 2 by []; have isoQ: 'Q_8 \isog 'Q_(2 ^ 3) by exact: isog_refl. have [[x y] genQ _] := generators_quaternion gt32 isoQ. have [_ [defQ' defPhiQ _ _]] := quaternion_structure gt32 genQ isoQ. case=> defZ oZ _ _ _ _ _; split; last by rewrite oZ. by split; rewrite ?defPhiQ defZ. Qed. Lemma DnQ_P n : xcprod_spec 'D^n 'Q_8 ('D^n*Q)%type. Proof. have pQ: 2.-group 'Q_(2 ^ 3) by rewrite /pgroup card_quaternion. have{pQ} oZQ := card_center_extraspecial pQ Q8_extraspecial. suffices oZDn: #|'Z('D^n)| = 2. by apply: xcprodP; rewrite isog_cyclic_card ?prime_cyclic ?oZQ ?oZDn. have [-> | n_gt0] := posnP n; first by rewrite center_ncprod0 card_pX1p2n. have pr2: prime 2 by []; have pDn := pX1p2n_pgroup n pr2. exact: card_center_extraspecial (pX1p2n_extraspecial pr2 n_gt0). Qed. Lemma card_DnQ n : #|'D^n*Q| = (2 ^ n.+1.*2.+1)%N. Proof. have oQ: #|'Q_(2 ^ 3)| = 8 by rewrite card_quaternion. have pQ: 2.-group 'Q_8 by rewrite /pgroup oQ. case: DnQ_P => gz isoZ. rewrite -im_cpair cardMg_divn setI_im_cpair cpair_center_id. rewrite -injm_center 3?{1}card_injm ?injm_cpairg1 ?injm_cpair1g ?center_sub //. rewrite oQ card_pX1p2n // (card_center_extraspecial pQ Q8_extraspecial). by rewrite -muln_divA // mulnC -(expnD 2 2). Qed. Lemma DnQ_pgroup n : 2.-group 'D^n*Q. Proof. by rewrite /pgroup card_DnQ pnat_exp. Qed. (* Final part of the existence half of Aschbacher (23.14). *) Lemma DnQ_extraspecial n : extraspecial 'D^n*Q. Proof. case: DnQ_P (DnQ_pgroup n) => gz isoZ pDnQ. have [injDn injQ] := (injm_cpairg1 isoZ, injm_cpair1g isoZ). have [n0 | n_gt0] := posnP n. rewrite -im_cpair mulSGid; first exact: injm_extraspecial Q8_extraspecial. apply/setIidPl; rewrite setI_im_cpair -injm_center //=. by congr (_ @* _); rewrite n0 center_ncprod0. apply: (cprod_extraspecial pDnQ (im_cpair_cprod isoZ) (setI_im_cpair _)). exact: injm_extraspecial (pX1p2n_extraspecial _ _). exact: injm_extraspecial Q8_extraspecial. Qed. (* A special case of the uniqueness half of Achsbacher (23.14). *) Lemma card_isog8_extraspecial (gT : finGroupType) (G : {group gT}) : #|G| = 8 -> extraspecial G -> (G \isog 'D_8) || (G \isog 'Q_8). Proof. move=> oG esG; have pG: 2.-group G by rewrite /pgroup oG. apply/norP=> [[notG_D8 notG_Q8]]. have not_extG: extremal_class G = NotExtremal. by rewrite /extremal_class oG andFb (negPf notG_D8) (negPf notG_Q8). have [x Gx ox] := exponent_witness (pgroup_nil pG). pose X := <[x]>; have cycX: cyclic X := cycle_cyclic x. have sXG: X \subset G by rewrite cycle_subG. have iXG: #|G : X| = 2. by rewrite -divgS // oG -orderE -ox exponent_2extraspecial. have not_cGG := extraspecial_nonabelian esG. have:= maximal_cycle_extremal pG not_cGG cycX sXG iXG. by rewrite /extremal2 not_extG. Qed. (* The uniqueness half of Achsbacher (23.14). The proof incorporates in part *) (* the proof that symplectic spces are hyperbolic (Aschbacher (19.16)), and *) (* the determination of quadratic spaces over 'F_2 (21.2); however we use *) (* the second part of exercise (8.4) to avoid resorting to Witt's lemma and *) (* Galois theory as in (20.9) and (21.1). *) Lemma isog_2extraspecial (gT : finGroupType) (G : {group gT}) n : #|G| = (2 ^ n.*2.+1)%N -> extraspecial G -> G \isog 'D^n \/ G \isog 'D^n.-1*Q. Proof. elim: n G => [|n IHn] G oG esG. case/negP: (extraspecial_nonabelian esG). by rewrite cyclic_abelian ?prime_cyclic ?oG. have pG: 2.-group G by rewrite /pgroup oG pnat_exp. have oZ:= card_center_extraspecial pG esG. have: 'Z(G) \subset 'Ohm_1(G). apply/subsetP=> z Zz; rewrite (OhmE _ pG) mem_gen //. by rewrite !inE -order_dvdn -oZ order_dvdG ?(subsetP (center_sub G)). rewrite subEproper; case/predU1P=> [defG1 | ltZG1]. have [n' n'_gt2 isoG]: exists2 n', n' > 2 & G \isog 'Q_(2 ^ n'). apply/quaternion_classP; apply/eqP. have not_cycG: ~~ cyclic G. by apply: contra (extraspecial_nonabelian esG); exact: cyclic_abelian. move: oZ; rewrite defG1; move/prime_Ohm1P; rewrite (negPf not_cycG) /=. by apply=> //; apply: contra not_cycG; move/eqP->; exact: cyclic1. have [n0 n'3]: n = 0%N /\ n' = 3. have [[x y] genG _] := generators_quaternion n'_gt2 isoG. have n'3: n' = 3. have [_ [_ _ oG' _] _ _ _] := quaternion_structure n'_gt2 genG isoG. apply/eqP; rewrite -(subnKC (ltnW n'_gt2)) subn2 !eqSS -(@eqn_exp2l 2) //. by rewrite -oG' -oZ; case: esG => [[_ ->]]. by move/eqP: oG; have [-> _ _ _] := genG; rewrite n'3 eqn_exp2l //; case n. right; rewrite (isog_trans isoG) // n'3 n0 /=. case: DnQ_P => z isoZ; rewrite -im_cpair mulSGid ?sub_isog ?injm_cpair1g //. apply/setIidPl; rewrite setI_im_cpair -injm_center ?injm_cpairg1 //. by rewrite center_ncprod0. case/andP: ltZG1 => _; rewrite (OhmE _ pG) gen_subG. case/subsetPn=> x; case/LdivP=> Gx x2 notZx. have ox: #[x] = 2 by exact: nt_prime_order (group1_contra notZx). have Z'x: x \in G :\: 'Z(G) by rewrite inE notZx. have [E [R [[oE oR] [defG ziER]]]] := split1_extraspecial pG esG Z'x. case=> defZE defZR [esE Ex] esR. have isoE: E \isog 2^{1+2}. apply: isog_trans (isog_symr isog_2X1p2). case/orP: (card_isog8_extraspecial oE esE) => // isoE; case/negP: notZx. have gt32: 3 > 2 by []. have [[y z] genE _] := generators_quaternion gt32 isoE. have [_ _ [defZx _ eq_y2 _ _] _ _] := quaternion_structure gt32 genE isoE. by rewrite (eq_y2 x) // -cycle_subG -defZx defZE. rewrite oG doubleS 2!expnS divnMl ?mulKn // in oR. case: ifP esR => [_ defR | _ esR]. have ->: n = 0%N by move/eqP: oR; rewrite defR oZ (eqn_exp2l 1) //; case n. left; apply: isog_trans (isog_symr (ncprod1 _)). by rewrite -defG defR -defZE cprod_center_id. have AutZin2_1p2: Aut_in (Aut 2^{1+2}) 'Z(2^{1+2}) \isog Aut 'Z(2^{1+2}). exact: Aut_extraspecial_full (pX1p2_pgroup _) (pX1p2_extraspecial _). have [isoR | isoR] := IHn R oR esR. by left; case: pX1p2S => gz isoZ; rewrite (isog_cprod_by _ defG). have n_gt0: n > 0. have pR: 2.-group R by rewrite /pgroup oR pnat_exp. have:= min_card_extraspecial pR esR. by rewrite oR leq_exp2l // ltnS (leq_double 1). case: DnQ_P isoR => gR isoZR /=; rewrite isog_sym; case/isogP=> fR injfR im_fR. have [injDn injQ] := (injm_cpairg1 isoZR, injm_cpair1g isoZR). pose Dn1 := cpairg1 isoZR @* 'D^n.-1; pose Q := cpair1g isoZR @* 'Q_8. have defR: fR @* Dn1 \* fR @* Q = R. rewrite cprodE ?morphim_cents ?im_cpair_cent //. by rewrite -morphimMl ?subsetT ?im_cpair. rewrite -defR cprodA in defG. have [[Dn _ defDn _] _ _] := cprodP defG; rewrite defDn in defG. have isoDn: Dn \isog 'D^n. rewrite -(prednK n_gt0); case: pX1p2S => gz isoZ. rewrite (isog_cprod_by _ defDn) //; last 1 first. by rewrite isog_sym (isog_trans _ (sub_isog _ _)) ?subsetT // sub_isog. rewrite /= -morphimIim im_fR setIA ziER; apply/setIidPl. rewrite defZE -defZR -{1}im_fR -injm_center // morphimS //. by rewrite -cpairg1_center morphimS // center_sub. right; case: DnQ_P => gz isoZ; rewrite (isog_cprod_by _ defG) //; first 1 last. - exact: Aut_extraspecial_full (pX1p2n_pgroup _ _) (pX1p2n_extraspecial _ _). - by rewrite isog_sym (isog_trans _ (sub_isog _ _)) ?subsetT // sub_isog. rewrite /= -morphimIim; case/cprodP: defDn => _ defDn cDn1E. rewrite setICA setIA -defDn -group_modr ?morphimS ?subsetT //. rewrite /= im_fR (setIC R) ziER -center_prod // defZE -defZR. rewrite mulSGid /=; last first. by rewrite -{1}im_fR -injm_center // -cpairg1_center !morphimS ?center_sub. rewrite -injm_center ?subsetT // -injmI // setI_im_cpair. by rewrite -injm_center // cpairg1_center injm_center // im_fR mulGid. Qed. (* The first concluding remark of Aschbacher (23.14). *) Lemma rank_Dn n : 'r_2('D^n) = n.+1. Proof. elim: n => [|n IHn]; first by rewrite p_rank_abelem ?prime_abelem ?card_pX1p2n. have oDDn: #|'D^n.+1| = (2 ^ n.+1.*2.+1)%N by exact: card_pX1p2n. have esDDn: extraspecial 'D^n.+1 by exact: pX1p2n_extraspecial. do [case: pX1p2S => gz isoZ; set DDn := [set: _]] in oDDn esDDn *. have pDDn: 2.-group DDn by rewrite /pgroup oDDn pnat_exp. apply/eqP; rewrite eqn_leq; apply/andP; split. have [E EprE]:= p_rank_witness 2 [group of DDn]. have [sEDDn abelE <-] := pnElemP EprE; have [pE cEE _]:= and3P abelE. rewrite -(@leq_exp2l 2) // -p_part part_pnat_id // -leq_sqr -expnM -mulnn. rewrite muln2 doubleS expnS -oDDn -(@leq_pmul2r #|'C_DDn(E)|) ?cardG_gt0 //. rewrite {1}(card_subcent_extraspecial pDDn) // mulnCA -mulnA Lagrange //=. rewrite mulnAC mulnA leq_pmul2r ?cardG_gt0 // setTI. have ->: (2 * #|'C(E)| = #|'Z(DDn)| * #|'C(E)|)%N. by rewrite (card_center_extraspecial pDDn). by rewrite leq_mul ?subset_leq_card ?subsetIl. have [inj1 injn] := (injm_cpairg1 isoZ, injm_cpair1g isoZ). pose D := cpairg1 isoZ @* 2^{1+2}; pose Dn := cpair1g isoZ @* 'D^n. have [E EprE] := p_rank_witness 2 [group of Dn]. rewrite injm_p_rank //= IHn in EprE; have [sEDn abelE dimE]:= pnElemP EprE. have [x [Dx ox] notDnx]: exists x, [/\ x \in D, #[x] = 2 & x \notin Dn]. have isoD: D \isog 'D_(2 ^ 3). by rewrite isog_sym -(isog_transl _ isog_2X1p2) sub_isog. have [//| [x y] genD [oy _]] := generators_2dihedral _ isoD. have [_ _ _ X'y] := genD; case/setDP: X'y; rewrite /= -/D => Dy notXy. exists y; split=> //; apply: contra notXy => Dny. case/dihedral2_structure: genD => // _ _ _ _ [defZD _ _ _ _]. by rewrite (subsetP (cycleX x 2)) // -defZD -setI_im_cpair inE Dy. have def_xE: <[x]> \x E = <[x]> <*> E. rewrite dprodEY ?prime_TIg -?orderE ?ox //. by rewrite (centSS sEDn _ (im_cpair_cent _)) ?cycle_subG. by rewrite cycle_subG (contra (subsetP sEDn x)). apply/p_rank_geP; exists (<[x]> <*> E)%G. rewrite 2!inE subsetT (dprod_abelem _ def_xE) abelE -(dprod_card def_xE). by rewrite prime_abelem -?orderE ?ox //= lognM ?cardG_gt0 ?dimE. Qed. (* The second concluding remark of Aschbacher (23.14). *) Lemma rank_DnQ n : 'r_2('D^n*Q) = n.+1. Proof. have pDnQ: 2.-group 'D^n*Q := DnQ_pgroup n. have esDnQ: extraspecial 'D^n*Q := DnQ_extraspecial n. do [case: DnQ_P => gz isoZ; set DnQ := setT] in pDnQ esDnQ *. suffices [E]: exists2 E, E \in 'E*_2(DnQ) & logn 2 #|E| = n.+1. by rewrite (pmaxElem_extraspecial pDnQ esDnQ); case/pnElemP=> _ _ <-. have oZ: #|'Z(DnQ)| = 2 by exact: card_center_extraspecial. pose Dn := cpairg1 isoZ @* 'D^n; pose Q := cpair1g isoZ @* 'Q_8. have [injDn injQ] := (injm_cpairg1 isoZ, injm_cpair1g isoZ). have [E EprE]:= p_rank_witness 2 [group of Dn]. have [sEDn abelE dimE] := pnElemP EprE; have [pE cEE eE]:= and3P abelE. rewrite injm_p_rank // rank_Dn in dimE; exists E => //. have sZE: 'Z(DnQ) \subset E. have maxE := subsetP (p_rankElem_max _ _) E EprE. have abelZ: 2.-abelem 'Z(DnQ) by rewrite prime_abelem ?oZ. rewrite -(Ohm1_id abelZ) (OhmE _ (abelem_pgroup abelZ)) gen_subG. rewrite -(pmaxElem_LdivP _ maxE) // setSI //=. by rewrite -cpairg1_center injm_center // setIS ?centS. have scE: 'C_Dn(E) = E. apply/eqP; rewrite eq_sym eqEcard subsetI sEDn -abelianE cEE /=. have [n0 | n_gt0] := posnP n. rewrite subset_leq_card // subIset // (subset_trans _ sZE) //. by rewrite -cpairg1_center morphimS // n0 center_ncprod0. have pDn: 2.-group Dn by rewrite morphim_pgroup ?pX1p2n_pgroup. have esDn: extraspecial Dn. exact: injm_extraspecial (pX1p2n_extraspecial _ _). rewrite dvdn_leq ?cardG_gt0 // (card_subcent_extraspecial pDn) //=. rewrite -injm_center // cpairg1_center (setIidPl sZE) oZ. rewrite -(dvdn_pmul2l (cardG_gt0 E)) mulnn mulnCA Lagrange //. rewrite card_injm ?card_pX1p2n // -expnS pfactor_dvdn ?expn_gt0 ?cardG_gt0 //. by rewrite lognX dimE mul2n. apply/pmaxElemP; split=> [|F E2F sEF]; first by rewrite inE subsetT abelE. have{E2F} [_ abelF] := pElemP E2F; have [pF cFF eF] := and3P abelF. apply/eqP; rewrite eqEsubset sEF andbT; apply/subsetP=> x Fx. have DnQx: x \in Dn * Q by rewrite im_cpair inE. have{DnQx} [y z Dn_y Qz def_x]:= imset2P DnQx. have{Dn_y} Ey: y \in E. have cEz: z \in 'C(E). by rewrite (subsetP (centS sEDn)) // (subsetP (im_cpair_cent _)). rewrite -scE inE Dn_y -(groupMr _ cEz) -def_x (subsetP (centS sEF)) //. by rewrite (subsetP cFF). rewrite def_x groupMl // (subsetP sZE) // -cpair1g_center injm_center //= -/Q. have: z \in 'Ohm_1(Q). rewrite (OhmE 1 (pgroupS (subsetT Q) pDnQ)) mem_gen // !inE Qz /=. rewrite -[z](mulKg y) -def_x (exponentP eF) ?groupM //. by rewrite groupV (subsetP sEF). have isoQ: Q \isog 'Q_(2 ^ 3) by rewrite isog_sym sub_isog. have [//|[u v] genQ _] := generators_quaternion _ isoQ. by case/quaternion_structure: genQ => // _ _ [-> _ _ [-> _] _] _ _. Qed. (* The final concluding remark of Aschbacher (23.14). *) Lemma not_isog_Dn_DnQ n : ~~ ('D^n \isog 'D^n.-1*Q). Proof. case: n => [|n] /=; first by rewrite isogEcard card_pX1p2n // card_DnQ andbF. apply: contraL (leqnn n.+1) => isoDn1DnQ. by rewrite -ltnNge -rank_Dn (isog_p_rank isoDn1DnQ) rank_DnQ. Qed. mathcomp-1.5/theories/finset.v0000644000175000017500000024573412307636117015501 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat div seq choice fintype. Require Import finfun bigop. (******************************************************************************) (* This file defines a type for sets over a finite Type, similar to the type *) (* of functions over a finite Type defined in finfun.v (indeed, based in it): *) (* {set T} where T must have a finType structure *) (* We equip {set T} itself with a finType structure, hence Leibnitz and *) (* extensional equalities coincide on {set T}, and we can form {set {set T}} *) (* If A, B : {set T} and P : {set {set T}}, we define: *) (* x \in A == x belongs to A (i.e., {set T} implements predType, *) (* by coercion to pred_sort). *) (* mem A == the predicate corresponding to A. *) (* finset p == the set corresponding to a predicate p. *) (* [set x | P] == the set containing the x such that P is true (x may *) (* appear in P). *) (* [set x | P & Q] := [set x | P && Q]. *) (* [set x in A] == the set containing the x in a collective predicate A. *) (* [set x in A | P] == the set containing the x in A such that P is true. *) (* [set x in A | P & Q] := [set x in A | P && Q]. *) (* All these have typed variants [set x : T | P], [set x : T in A], etc. *) (* set0 == the empty set. *) (* [set: T] or setT == the full set (the A containing all x : T). *) (* A :|: B == the union of A and B. *) (* x |: A == A with the element x added (:= [set x] :| A). *) (* A :&: B == the intersection of A and B. *) (* ~: A == the complement of A. *) (* A :\: B == the difference A minus B. *) (* A :\ x == A with the element x removed (:= A :\: [set x]). *) (* \bigcup_ A == the union of all A, for i in (i is bound in *) (* A, see bigop.v). *) (* \bigcap_ A == the intersection of all A, for i in . *) (* cover P == the union of the set of sets P. *) (* trivIset P <=> the elements of P are pairwise disjoint. *) (* partition P A <=> P is a partition of A. *) (* pblock P x == a block of P containing x, or else set0. *) (* equivalence_partition R D == the partition induced on D by the relation R *) (* (provided R is an equivalence relation in D). *) (* preim_partition f D == the partition induced on D by the equivalence *) (* [rel x y | f x == f y]. *) (* is_transversal X P D <=> X is a transversal of the partition P of D. *) (* transversal P D == a transversal of P, provided P is a partition of D. *) (* transversal_repr x0 X B == a representative of B \in P selected by the *) (* tranversal X of P, or else x0. *) (* powerset A == the set of all subset of the set A. *) (* P ::&: A == those sets in P that are subsets of the set A. *) (* f @^-1: A == the preimage of the collective predicate A under f. *) (* f @: A == the image set of the collective predicate A by f. *) (* f @2:(A, B) == the image set of A x B by the binary function f. *) (* [set E | x in A] == the set of all the values of the expression E, for x *) (* drawn from the collective predicate A. *) (* [set E | x in A & P] == the set of values of E for x drawn from A, such *) (* that P is true. *) (* [set E | x in A, y in B] == the set of values of E for x drawn from A and *) (* and y drawn from B; B may depend on x. *) (* [set E | x <- A, y <- B & P] == the set of values of E for x drawn from A *) (* y drawn from B, such that P is trye. *) (* [set E | x : T] == the set of all values of E, with x in type T. *) (* [set E | x : T & P] == the set of values of E for x : T s.t. P is true. *) (* [set E | x : T, y : U in B], [set E | x : T, y : U in B & P], *) (* [set E | x : T in A, y : U], [set E | x : T in A, y : U & P], *) (* [set E | x : T, y : U], [set E | x : T, y : U & P] *) (* == type-ranging versions of the binary comprehensions. *) (* [set E | x : T in A], [set E | x in A, y], [set E | x, y & P], etc. *) (* == typed and untyped variants of the comprehensions above. *) (* The types may be required as type inference processes E *) (* before considering A or B. Note that type casts in the *) (* binary comprehension must either be both present or absent *) (* and that there are no untyped variants for single-type *) (* comprehension as Coq parsing confuses [x | P] and [E | x]. *) (* minset p A == A is a minimal set satisfying p. *) (* maxset p A == A is a maximal set satisfying p. *) (* We also provide notations A :=: B, A :<>: B, A :==: B, A :!=: B, A :=P: B *) (* that specialize A = B, A <> B, A == B, etc., to {set _}. This is useful *) (* for subtypes of {set T}, such as {group T}, that coerce to {set T}. *) (* We give many lemmas on these operations, on card, and on set inclusion. *) (* In addition to the standard suffixes described in ssrbool.v, we associate *) (* the following suffixes to set operations: *) (* 0 -- the empty set, as in in_set0 : (x \in set0) = false. *) (* T -- the full set, as in in_setT : x \in [set: T]. *) (* 1 -- a singleton set, as in in_set1 : (x \in [set a]) = (x == a). *) (* 2 -- an unordered pair, as in *) (* in_set2 : (x \in [set a; b]) = (x == a) || (x == b). *) (* C -- complement, as in setCK : ~: ~: A = A. *) (* I -- intersection, as in setIid : A :&: A = A. *) (* U -- union, as in setUid : A :|: A = A. *) (* D -- difference, as in setDv : A :\: A = set0. *) (* S -- a subset argument, as in *) (* setIS: B \subset C -> A :&: B \subset A :&: C *) (* These suffixes are sometimes preceded with an `s' to distinguish them from *) (* their basic ssrbool interpretation, e.g., *) (* card1 : #|pred1 x| = 1 and cards1 : #|[set x]| = 1 *) (* We also use a trailling `r' to distinguish a right-hand complement from *) (* commutativity, e.g., *) (* setIC : A :&: B = B :&: A and setICr : A :&: ~: A = set0. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Section SetType. Variable T : finType. Inductive set_type : predArgType := FinSet of {ffun pred T}. Definition finfun_of_set A := let: FinSet f := A in f. Definition set_of of phant T := set_type. Identity Coercion type_of_set_of : set_of >-> set_type. Canonical set_subType := Eval hnf in [newType for finfun_of_set]. Definition set_eqMixin := Eval hnf in [eqMixin of set_type by <:]. Canonical set_eqType := Eval hnf in EqType set_type set_eqMixin. Definition set_choiceMixin := [choiceMixin of set_type by <:]. Canonical set_choiceType := Eval hnf in ChoiceType set_type set_choiceMixin. Definition set_countMixin := [countMixin of set_type by <:]. Canonical set_countType := Eval hnf in CountType set_type set_countMixin. Canonical set_subCountType := Eval hnf in [subCountType of set_type]. Definition set_finMixin := [finMixin of set_type by <:]. Canonical set_finType := Eval hnf in FinType set_type set_finMixin. Canonical set_subFinType := Eval hnf in [subFinType of set_type]. End SetType. Delimit Scope set_scope with SET. Bind Scope set_scope with set_type. Bind Scope set_scope with set_of. Open Scope set_scope. Arguments Scope finfun_of_set [_ set_scope]. Notation "{ 'set' T }" := (set_of (Phant T)) (at level 0, format "{ 'set' T }") : type_scope. (* We later define several subtypes that coerce to set; for these it is *) (* preferable to state equalities at the {set _} level, even when comparing *) (* subtype values, because the primitive "injection" tactic tends to diverge *) (* on complex types (e.g., quotient groups). We provide some parse-only *) (* notation to make this technicality less obstrusive. *) Notation "A :=: B" := (A = B :> {set _}) (at level 70, no associativity, only parsing) : set_scope. Notation "A :<>: B" := (A <> B :> {set _}) (at level 70, no associativity, only parsing) : set_scope. Notation "A :==: B" := (A == B :> {set _}) (at level 70, no associativity, only parsing) : set_scope. Notation "A :!=: B" := (A != B :> {set _}) (at level 70, no associativity, only parsing) : set_scope. Notation "A :=P: B" := (A =P B :> {set _}) (at level 70, no associativity, only parsing) : set_scope. Notation Local finset_def := (fun T P => @FinSet T (finfun P)). Notation Local pred_of_set_def := (fun T (A : set_type T) => val A : _ -> _). Module Type SetDefSig. Parameter finset : forall T : finType, pred T -> {set T}. Parameter pred_of_set : forall T, set_type T -> fin_pred_sort (predPredType T). (* The weird type of pred_of_set is imposed by the syntactic restrictions on *) (* coercion declarations; it is unfortunately not possible to use a functor *) (* to retype the declaration, because this triggers an ugly bug in the Coq *) (* coercion chaining code. *) Axiom finsetE : finset = finset_def. Axiom pred_of_setE : pred_of_set = pred_of_set_def. End SetDefSig. Module SetDef : SetDefSig. Definition finset := finset_def. Definition pred_of_set := pred_of_set_def. Lemma finsetE : finset = finset_def. Proof. by []. Qed. Lemma pred_of_setE : pred_of_set = pred_of_set_def. Proof. by []. Qed. End SetDef. Notation finset := SetDef.finset. Notation pred_of_set := SetDef.pred_of_set. Canonical finset_unlock := Unlockable SetDef.finsetE. Canonical pred_of_set_unlock := Unlockable SetDef.pred_of_setE. Notation "[ 'set' x : T | P ]" := (finset (fun x : T => P%B)) (at level 0, x at level 99, only parsing) : set_scope. Notation "[ 'set' x | P ]" := [set x : _ | P] (at level 0, x, P at level 99, format "[ 'set' x | P ]") : set_scope. Notation "[ 'set' x 'in' A ]" := [set x | x \in A] (at level 0, x at level 99, format "[ 'set' x 'in' A ]") : set_scope. Notation "[ 'set' x : T 'in' A ]" := [set x : T | x \in A] (at level 0, x at level 99, only parsing) : set_scope. Notation "[ 'set' x : T | P & Q ]" := [set x : T | P && Q] (at level 0, x at level 99, only parsing) : set_scope. Notation "[ 'set' x | P & Q ]" := [set x | P && Q ] (at level 0, x, P at level 99, format "[ 'set' x | P & Q ]") : set_scope. Notation "[ 'set' x : T 'in' A | P ]" := [set x : T | x \in A & P] (at level 0, x at level 99, only parsing) : set_scope. Notation "[ 'set' x 'in' A | P ]" := [set x | x \in A & P] (at level 0, x at level 99, format "[ 'set' x 'in' A | P ]") : set_scope. Notation "[ 'set' x 'in' A | P & Q ]" := [set x in A | P && Q] (at level 0, x at level 99, format "[ 'set' x 'in' A | P & Q ]") : set_scope. Notation "[ 'set' x : T 'in' A | P & Q ]" := [set x : T in A | P && Q] (at level 0, x at level 99, only parsing) : set_scope. (* This lets us use set and subtypes of set, like group or coset_of, both as *) (* collective predicates and as arguments of the \pi(_) notation. *) Coercion pred_of_set: set_type >-> fin_pred_sort. (* Declare pred_of_set as a canonical instance of topred, but use the *) (* coercion to resolve mem A to @mem (predPredType T) (pred_of_set A). *) Canonical set_predType T := Eval hnf in @mkPredType _ (unkeyed (set_type T)) (@pred_of_set T). Section BasicSetTheory. Variable T : finType. Implicit Types (x : T) (A B : {set T}) (pA : pred T). Canonical set_of_subType := Eval hnf in [subType of {set T}]. Canonical set_of_eqType := Eval hnf in [eqType of {set T}]. Canonical set_of_choiceType := Eval hnf in [choiceType of {set T}]. Canonical set_of_countType := Eval hnf in [countType of {set T}]. Canonical set_of_subCountType := Eval hnf in [subCountType of {set T}]. Canonical set_of_finType := Eval hnf in [finType of {set T}]. Canonical set_of_subFinType := Eval hnf in [subFinType of {set T}]. Lemma in_set pA x : x \in finset pA = pA x. Proof. by rewrite [@finset]unlock unlock [x \in _]ffunE. Qed. Lemma setP A B : A =i B <-> A = B. Proof. by split=> [eqAB|-> //]; apply/val_inj/ffunP=> x; have:= eqAB x; rewrite unlock. Qed. Definition set0 := [set x : T | false]. Definition setTfor (phT : phant T) := [set x : T | true]. Lemma in_setT x : x \in setTfor (Phant T). Proof. by rewrite in_set. Qed. Lemma eqsVneq A B : {A = B} + {A != B}. Proof. exact: eqVneq. Qed. End BasicSetTheory. Definition inE := (in_set, inE). Implicit Arguments set0 [T]. Prenex Implicits set0. Hint Resolve in_setT. Notation "[ 'set' : T ]" := (setTfor (Phant T)) (at level 0, format "[ 'set' : T ]") : set_scope. Notation setT := [set: _] (only parsing). Section setOpsDefs. Variable T : finType. Implicit Types (a x : T) (A B D : {set T}) (P : {set {set T}}). Definition set1 a := [set x | x == a]. Definition setU A B := [set x | (x \in A) || (x \in B)]. Definition setI A B := [set x in A | x \in B]. Definition setC A := [set x | x \notin A]. Definition setD A B := [set x | x \notin B & x \in A]. Definition ssetI P D := [set A in P | A \subset D]. Definition powerset D := [set A : {set T} | A \subset D]. End setOpsDefs. Notation "[ 'set' a ]" := (set1 a) (at level 0, a at level 99, format "[ 'set' a ]") : set_scope. Notation "[ 'set' a : T ]" := [set (a : T)] (at level 0, a at level 99, format "[ 'set' a : T ]") : set_scope. Notation "A :|: B" := (setU A B) : set_scope. Notation "a |: A" := ([set a] :|: A) : set_scope. (* This is left-associative due to historical limitations of the .. Notation. *) Notation "[ 'set' a1 ; a2 ; .. ; an ]" := (setU .. (a1 |: [set a2]) .. [set an]) (at level 0, a1 at level 99, format "[ 'set' a1 ; a2 ; .. ; an ]") : set_scope. Notation "A :&: B" := (setI A B) : set_scope. Notation "~: A" := (setC A) (at level 35, right associativity) : set_scope. Notation "[ 'set' ~ a ]" := (~: [set a]) (at level 0, format "[ 'set' ~ a ]") : set_scope. Notation "A :\: B" := (setD A B) : set_scope. Notation "A :\ a" := (A :\: [set a]) : set_scope. Notation "P ::&: D" := (ssetI P D) (at level 48) : set_scope. Section setOps. Variable T : finType. Implicit Types (a x : T) (A B C D : {set T}) (pA pB pC : pred T). Lemma eqEsubset A B : (A == B) = (A \subset B) && (B \subset A). Proof. by apply/eqP/subset_eqP=> /setP. Qed. Lemma subEproper A B : A \subset B = (A == B) || (A \proper B). Proof. by rewrite eqEsubset -andb_orr orbN andbT. Qed. Lemma eqVproper A B : A \subset B -> A = B \/ A \proper B. Proof. by rewrite subEproper => /predU1P. Qed. Lemma properEneq A B : A \proper B = (A != B) && (A \subset B). Proof. by rewrite andbC eqEsubset negb_and andb_orr andbN. Qed. Lemma proper_neq A B : A \proper B -> A != B. Proof. by rewrite properEneq; case/andP. Qed. Lemma eqEproper A B : (A == B) = (A \subset B) && ~~ (A \proper B). Proof. by rewrite negb_and negbK andb_orr andbN eqEsubset. Qed. Lemma eqEcard A B : (A == B) = (A \subset B) && (#|B| <= #|A|). Proof. rewrite eqEsubset; apply: andb_id2l => sAB. by rewrite (geq_leqif (subset_leqif_card sAB)). Qed. Lemma properEcard A B : (A \proper B) = (A \subset B) && (#|A| < #|B|). Proof. by rewrite properEneq ltnNge andbC eqEcard; case: (A \subset B). Qed. Lemma subset_leqif_cards A B : A \subset B -> (#|A| <= #|B| ?= iff (A == B)). Proof. by move=> sAB; rewrite eqEsubset sAB; exact: subset_leqif_card. Qed. Lemma in_set0 x : x \in set0 = false. Proof. by rewrite inE. Qed. Lemma sub0set A : set0 \subset A. Proof. by apply/subsetP=> x; rewrite inE. Qed. Lemma subset0 A : (A \subset set0) = (A == set0). Proof. by rewrite eqEsubset sub0set andbT. Qed. Lemma proper0 A : (set0 \proper A) = (A != set0). Proof. by rewrite properE sub0set subset0. Qed. Lemma subset_neq0 A B : A \subset B -> A != set0 -> B != set0. Proof. by rewrite -!proper0 => sAB /proper_sub_trans->. Qed. Lemma set_0Vmem A : (A = set0) + {x : T | x \in A}. Proof. case: (pickP (mem A)) => [x Ax | A0]; [by right; exists x | left]. apply/setP=> x; rewrite inE; exact: A0. Qed. Lemma enum_set0 : enum set0 = [::] :> seq T. Proof. by rewrite (eq_enum (in_set _)) enum0. Qed. Lemma subsetT A : A \subset setT. Proof. by apply/subsetP=> x; rewrite inE. Qed. Lemma subsetT_hint mA : subset mA (mem [set: T]). Proof. by rewrite unlock; apply/pred0P=> x; rewrite !inE. Qed. Hint Resolve subsetT_hint. Lemma subTset A : (setT \subset A) = (A == setT). Proof. by rewrite eqEsubset subsetT. Qed. Lemma properT A : (A \proper setT) = (A != setT). Proof. by rewrite properEneq subsetT andbT. Qed. Lemma set1P x a : reflect (x = a) (x \in [set a]). Proof. by rewrite inE; exact: eqP. Qed. Lemma enum_setT : enum [set: T] = Finite.enum T. Proof. by rewrite (eq_enum (in_set _)) enumT. Qed. Lemma in_set1 x a : (x \in [set a]) = (x == a). Proof. exact: in_set. Qed. Lemma set11 x : x \in [set x]. Proof. by rewrite inE. Qed. Lemma set1_inj : injective (@set1 T). Proof. by move=> a b eqsab; apply/set1P; rewrite -eqsab set11. Qed. Lemma enum_set1 a : enum [set a] = [:: a]. Proof. by rewrite (eq_enum (in_set _)) enum1. Qed. Lemma setU1P x a B : reflect (x = a \/ x \in B) (x \in a |: B). Proof. by rewrite !inE; exact: predU1P. Qed. Lemma in_setU1 x a B : (x \in a |: B) = (x == a) || (x \in B). Proof. by rewrite !inE. Qed. Lemma set_cons a s : [set x in a :: s] = a |: [set x in s]. Proof. by apply/setP=> x; rewrite !inE. Qed. Lemma setU11 x B : x \in x |: B. Proof. by rewrite !inE eqxx. Qed. Lemma setU1r x a B : x \in B -> x \in a |: B. Proof. by move=> Bx; rewrite !inE predU1r. Qed. (* We need separate lemmas for the explicit enumerations since they *) (* associate on the left. *) Lemma set1Ul x A b : x \in A -> x \in A :|: [set b]. Proof. by move=> Ax; rewrite !inE Ax. Qed. Lemma set1Ur A b : b \in A :|: [set b]. Proof. by rewrite !inE eqxx orbT. Qed. Lemma in_setC1 x a : (x \in [set~ a]) = (x != a). Proof. by rewrite !inE. Qed. Lemma setC11 x : (x \in [set~ x]) = false. Proof. by rewrite !inE eqxx. Qed. Lemma setD1P x A b : reflect (x != b /\ x \in A) (x \in A :\ b). Proof. rewrite !inE; exact: andP. Qed. Lemma in_setD1 x A b : (x \in A :\ b) = (x != b) && (x \in A) . Proof. by rewrite !inE. Qed. Lemma setD11 b A : (b \in A :\ b) = false. Proof. by rewrite !inE eqxx. Qed. Lemma setD1K a A : a \in A -> a |: (A :\ a) = A. Proof. by move=> Aa; apply/setP=> x; rewrite !inE; case: eqP => // ->. Qed. Lemma setU1K a B : a \notin B -> (a |: B) :\ a = B. Proof. by move/negPf=> nBa; apply/setP=> x; rewrite !inE; case: eqP => // ->. Qed. Lemma set2P x a b : reflect (x = a \/ x = b) (x \in [set a; b]). Proof. rewrite !inE; exact: pred2P. Qed. Lemma in_set2 x a b : (x \in [set a; b]) = (x == a) || (x == b). Proof. by rewrite !inE. Qed. Lemma set21 a b : a \in [set a; b]. Proof. by rewrite !inE eqxx. Qed. Lemma set22 a b : b \in [set a; b]. Proof. by rewrite !inE eqxx orbT. Qed. Lemma setUP x A B : reflect (x \in A \/ x \in B) (x \in A :|: B). Proof. by rewrite !inE; exact: orP. Qed. Lemma in_setU x A B : (x \in A :|: B) = (x \in A) || (x \in B). Proof. exact: in_set. Qed. Lemma setUC A B : A :|: B = B :|: A. Proof. by apply/setP => x; rewrite !inE orbC. Qed. Lemma setUS A B C : A \subset B -> C :|: A \subset C :|: B. Proof. move=> sAB; apply/subsetP=> x; rewrite !inE. by case: (x \in C) => //; exact: (subsetP sAB). Qed. Lemma setSU A B C : A \subset B -> A :|: C \subset B :|: C. Proof. by move=> sAB; rewrite -!(setUC C) setUS. Qed. Lemma setUSS A B C D : A \subset C -> B \subset D -> A :|: B \subset C :|: D. Proof. by move=> /(setSU B) /subset_trans sAC /(setUS C)/sAC. Qed. Lemma set0U A : set0 :|: A = A. Proof. by apply/setP => x; rewrite !inE orFb. Qed. Lemma setU0 A : A :|: set0 = A. Proof. by rewrite setUC set0U. Qed. Lemma setUA A B C : A :|: (B :|: C) = A :|: B :|: C. Proof. by apply/setP => x; rewrite !inE orbA. Qed. Lemma setUCA A B C : A :|: (B :|: C) = B :|: (A :|: C). Proof. by rewrite !setUA (setUC B). Qed. Lemma setUAC A B C : A :|: B :|: C = A :|: C :|: B. Proof. by rewrite -!setUA (setUC B). Qed. Lemma setUACA A B C D : (A :|: B) :|: (C :|: D) = (A :|: C) :|: (B :|: D). Proof. by rewrite -!setUA (setUCA B). Qed. Lemma setTU A : setT :|: A = setT. Proof. by apply/setP => x; rewrite !inE orTb. Qed. Lemma setUT A : A :|: setT = setT. Proof. by rewrite setUC setTU. Qed. Lemma setUid A : A :|: A = A. Proof. by apply/setP=> x; rewrite inE orbb. Qed. Lemma setUUl A B C : A :|: B :|: C = (A :|: C) :|: (B :|: C). Proof. by rewrite setUA !(setUAC _ C) -(setUA _ C) setUid. Qed. Lemma setUUr A B C : A :|: (B :|: C) = (A :|: B) :|: (A :|: C). Proof. by rewrite !(setUC A) setUUl. Qed. (* intersection *) (* setIdP is a generalisation of setIP that applies to comprehensions. *) Lemma setIdP x pA pB : reflect (pA x /\ pB x) (x \in [set y | pA y & pB y]). Proof. by rewrite !inE; exact: andP. Qed. Lemma setId2P x pA pB pC : reflect [/\ pA x, pB x & pC x] (x \in [set y | pA y & pB y && pC y]). Proof. by rewrite !inE; exact: and3P. Qed. Lemma setIdE A pB : [set x in A | pB x] = A :&: [set x | pB x]. Proof. by apply/setP=> x; rewrite !inE. Qed. Lemma setIP x A B : reflect (x \in A /\ x \in B) (x \in A :&: B). Proof. exact: (iffP (@setIdP _ _ _)). Qed. Lemma in_setI x A B : (x \in A :&: B) = (x \in A) && (x \in B). Proof. exact: in_set. Qed. Lemma setIC A B : A :&: B = B :&: A. Proof. by apply/setP => x; rewrite !inE andbC. Qed. Lemma setIS A B C : A \subset B -> C :&: A \subset C :&: B. Proof. move=> sAB; apply/subsetP=> x; rewrite !inE. by case: (x \in C) => //; exact: (subsetP sAB). Qed. Lemma setSI A B C : A \subset B -> A :&: C \subset B :&: C. Proof. by move=> sAB; rewrite -!(setIC C) setIS. Qed. Lemma setISS A B C D : A \subset C -> B \subset D -> A :&: B \subset C :&: D. Proof. by move=> /(setSI B) /subset_trans sAC /(setIS C) /sAC. Qed. Lemma setTI A : setT :&: A = A. Proof. by apply/setP => x; rewrite !inE andTb. Qed. Lemma setIT A : A :&: setT = A. Proof. by rewrite setIC setTI. Qed. Lemma set0I A : set0 :&: A = set0. Proof. by apply/setP => x; rewrite !inE andFb. Qed. Lemma setI0 A : A :&: set0 = set0. Proof. by rewrite setIC set0I. Qed. Lemma setIA A B C : A :&: (B :&: C) = A :&: B :&: C. Proof. by apply/setP=> x; rewrite !inE andbA. Qed. Lemma setICA A B C : A :&: (B :&: C) = B :&: (A :&: C). Proof. by rewrite !setIA (setIC A). Qed. Lemma setIAC A B C : A :&: B :&: C = A :&: C :&: B. Proof. by rewrite -!setIA (setIC B). Qed. Lemma setIACA A B C D : (A :&: B) :&: (C :&: D) = (A :&: C) :&: (B :&: D). Proof. by rewrite -!setIA (setICA B). Qed. Lemma setIid A : A :&: A = A. Proof. by apply/setP=> x; rewrite inE andbb. Qed. Lemma setIIl A B C : A :&: B :&: C = (A :&: C) :&: (B :&: C). Proof. by rewrite setIA !(setIAC _ C) -(setIA _ C) setIid. Qed. Lemma setIIr A B C : A :&: (B :&: C) = (A :&: B) :&: (A :&: C). Proof. by rewrite !(setIC A) setIIl. Qed. (* distribute /cancel *) Lemma setIUr A B C : A :&: (B :|: C) = (A :&: B) :|: (A :&: C). Proof. by apply/setP=> x; rewrite !inE andb_orr. Qed. Lemma setIUl A B C : (A :|: B) :&: C = (A :&: C) :|: (B :&: C). Proof. by apply/setP=> x; rewrite !inE andb_orl. Qed. Lemma setUIr A B C : A :|: (B :&: C) = (A :|: B) :&: (A :|: C). Proof. by apply/setP=> x; rewrite !inE orb_andr. Qed. Lemma setUIl A B C : (A :&: B) :|: C = (A :|: C) :&: (B :|: C). Proof. by apply/setP=> x; rewrite !inE orb_andl. Qed. Lemma setUK A B : (A :|: B) :&: A = A. Proof. by apply/setP=> x; rewrite !inE orbK. Qed. Lemma setKU A B : A :&: (B :|: A) = A. Proof. by apply/setP=> x; rewrite !inE orKb. Qed. Lemma setIK A B : (A :&: B) :|: A = A. Proof. by apply/setP=> x; rewrite !inE andbK. Qed. Lemma setKI A B : A :|: (B :&: A) = A. Proof. by apply/setP=> x; rewrite !inE andKb. Qed. (* complement *) Lemma setCP x A : reflect (~ x \in A) (x \in ~: A). Proof. by rewrite !inE; exact: negP. Qed. Lemma in_setC x A : (x \in ~: A) = (x \notin A). Proof. exact: in_set. Qed. Lemma setCK : involutive (@setC T). Proof. by move=> A; apply/setP=> x; rewrite !inE negbK. Qed. Lemma setC_inj : injective (@setC T). Proof. exact: can_inj setCK. Qed. Lemma subsets_disjoint A B : (A \subset B) = [disjoint A & ~: B]. Proof. by rewrite subset_disjoint; apply: eq_disjoint_r => x; rewrite !inE. Qed. Lemma disjoints_subset A B : [disjoint A & B] = (A \subset ~: B). Proof. by rewrite subsets_disjoint setCK. Qed. Lemma powersetCE A B : (A \in powerset (~: B)) = [disjoint A & B]. Proof. by rewrite inE disjoints_subset. Qed. Lemma setCS A B : (~: A \subset ~: B) = (B \subset A). Proof. by rewrite !subsets_disjoint setCK disjoint_sym. Qed. Lemma setCU A B : ~: (A :|: B) = ~: A :&: ~: B. Proof. by apply/setP=> x; rewrite !inE negb_or. Qed. Lemma setCI A B : ~: (A :&: B) = ~: A :|: ~: B. Proof. by apply/setP=> x; rewrite !inE negb_and. Qed. Lemma setUCr A : A :|: ~: A = setT. Proof. by apply/setP=> x; rewrite !inE orbN. Qed. Lemma setICr A : A :&: ~: A = set0. Proof. by apply/setP=> x; rewrite !inE andbN. Qed. Lemma setC0 : ~: set0 = [set: T]. Proof. by apply/setP=> x; rewrite !inE. Qed. Lemma setCT : ~: [set: T] = set0. Proof. by rewrite -setC0 setCK. Qed. (* difference *) Lemma setDP A B x : reflect (x \in A /\ x \notin B) (x \in A :\: B). Proof. by rewrite inE andbC; exact: andP. Qed. Lemma in_setD A B x : (x \in A :\: B) = (x \notin B) && (x \in A). Proof. exact: in_set. Qed. Lemma setDE A B : A :\: B = A :&: ~: B. Proof. by apply/setP => x; rewrite !inE andbC. Qed. Lemma setSD A B C : A \subset B -> A :\: C \subset B :\: C. Proof. by rewrite !setDE; exact: setSI. Qed. Lemma setDS A B C : A \subset B -> C :\: B \subset C :\: A. Proof. by rewrite !setDE -setCS; exact: setIS. Qed. Lemma setDSS A B C D : A \subset C -> D \subset B -> A :\: B \subset C :\: D. Proof. by move=> /(setSD B) /subset_trans sAC /(setDS C) /sAC. Qed. Lemma setD0 A : A :\: set0 = A. Proof. by apply/setP=> x; rewrite !inE. Qed. Lemma set0D A : set0 :\: A = set0. Proof. by apply/setP=> x; rewrite !inE andbF. Qed. Lemma setDT A : A :\: setT = set0. Proof. by apply/setP=> x; rewrite !inE. Qed. Lemma setTD A : setT :\: A = ~: A. Proof. by apply/setP=> x; rewrite !inE andbT. Qed. Lemma setDv A : A :\: A = set0. Proof. by apply/setP=> x; rewrite !inE andNb. Qed. Lemma setCD A B : ~: (A :\: B) = ~: A :|: B. Proof. by rewrite !setDE setCI setCK. Qed. Lemma setID A B : A :&: B :|: A :\: B = A. Proof. by rewrite setDE -setIUr setUCr setIT. Qed. Lemma setDUl A B C : (A :|: B) :\: C = (A :\: C) :|: (B :\: C). Proof. by rewrite !setDE setIUl. Qed. Lemma setDUr A B C : A :\: (B :|: C) = (A :\: B) :&: (A :\: C). Proof. by rewrite !setDE setCU setIIr. Qed. Lemma setDIl A B C : (A :&: B) :\: C = (A :\: C) :&: (B :\: C). Proof. by rewrite !setDE setIIl. Qed. Lemma setIDA A B C : A :&: (B :\: C) = (A :&: B) :\: C. Proof. by rewrite !setDE setIA. Qed. Lemma setIDAC A B C : (A :\: B) :&: C = (A :&: C) :\: B. Proof. by rewrite !setDE setIAC. Qed. Lemma setDIr A B C : A :\: (B :&: C) = (A :\: B) :|: (A :\: C). Proof. by rewrite !setDE setCI setIUr. Qed. Lemma setDDl A B C : (A :\: B) :\: C = A :\: (B :|: C). Proof. by rewrite !setDE setCU setIA. Qed. Lemma setDDr A B C : A :\: (B :\: C) = (A :\: B) :|: (A :&: C). Proof. by rewrite !setDE setCI setIUr setCK. Qed. (* powerset *) Lemma powersetE A B : (A \in powerset B) = (A \subset B). Proof. by rewrite inE. Qed. Lemma powersetS A B : (powerset A \subset powerset B) = (A \subset B). Proof. apply/subsetP/idP=> [sAB | sAB C]; last by rewrite !inE => /subset_trans ->. by rewrite -powersetE sAB // inE. Qed. Lemma powerset0 : powerset set0 = [set set0] :> {set {set T}}. Proof. by apply/setP=> A; rewrite !inE subset0. Qed. Lemma powersetT : powerset [set: T] = [set: {set T}]. Proof. by apply/setP=> A; rewrite !inE subsetT. Qed. Lemma setI_powerset P A : P :&: powerset A = P ::&: A. Proof. by apply/setP=> B; rewrite !inE. Qed. (* cardinal lemmas for sets *) Lemma cardsE pA : #|[set x in pA]| = #|pA|. Proof. by apply: eq_card; exact: in_set. Qed. Lemma sum1dep_card pA : \sum_(x | pA x) 1 = #|[set x | pA x]|. Proof. by rewrite sum1_card cardsE. Qed. Lemma sum_nat_dep_const pA n : \sum_(x | pA x) n = #|[set x | pA x]| * n. Proof. by rewrite sum_nat_const cardsE. Qed. Lemma cards0 : #|@set0 T| = 0. Proof. by rewrite cardsE card0. Qed. Lemma cards_eq0 A : (#|A| == 0) = (A == set0). Proof. by rewrite (eq_sym A) eqEcard sub0set cards0 leqn0. Qed. Lemma set0Pn A : reflect (exists x, x \in A) (A != set0). Proof. by rewrite -cards_eq0; exact: existsP. Qed. Lemma card_gt0 A : (0 < #|A|) = (A != set0). Proof. by rewrite lt0n cards_eq0. Qed. Lemma cards0_eq A : #|A| = 0 -> A = set0. Proof. by move=> A_0; apply/setP=> x; rewrite inE (card0_eq A_0). Qed. Lemma cards1 x : #|[set x]| = 1. Proof. by rewrite cardsE card1. Qed. Lemma cardsUI A B : #|A :|: B| + #|A :&: B| = #|A| + #|B|. Proof. by rewrite !cardsE cardUI. Qed. Lemma cardsU A B : #|A :|: B| = (#|A| + #|B| - #|A :&: B|)%N. Proof. by rewrite -cardsUI addnK. Qed. Lemma cardsI A B : #|A :&: B| = (#|A| + #|B| - #|A :|: B|)%N. Proof. by rewrite -cardsUI addKn. Qed. Lemma cardsT : #|[set: T]| = #|T|. Proof. by rewrite cardsE. Qed. Lemma cardsID B A : #|A :&: B| + #|A :\: B| = #|A|. Proof. by rewrite !cardsE cardID. Qed. Lemma cardsD A B : #|A :\: B| = (#|A| - #|A :&: B|)%N. Proof. by rewrite -(cardsID B A) addKn. Qed. Lemma cardsC A : #|A| + #|~: A| = #|T|. Proof. by rewrite cardsE cardC. Qed. Lemma cardsCs A : #|A| = #|T| - #|~: A|. Proof. by rewrite -(cardsC A) addnK. Qed. Lemma cardsU1 a A : #|a |: A| = (a \notin A) + #|A|. Proof. by rewrite -cardU1; apply: eq_card=> x; rewrite !inE. Qed. Lemma cards2 a b : #|[set a; b]| = (a != b).+1. Proof. by rewrite -card2; apply: eq_card=> x; rewrite !inE. Qed. Lemma cardsC1 a : #|[set~ a]| = #|T|.-1. Proof. by rewrite -(cardC1 a); apply: eq_card=> x; rewrite !inE. Qed. Lemma cardsD1 a A : #|A| = (a \in A) + #|A :\ a|. Proof. by rewrite (cardD1 a); congr (_ + _); apply: eq_card => x; rewrite !inE. Qed. (* other inclusions *) Lemma subsetIl A B : A :&: B \subset A. Proof. by apply/subsetP=> x; rewrite inE; case/andP. Qed. Lemma subsetIr A B : A :&: B \subset B. Proof. by apply/subsetP=> x; rewrite inE; case/andP. Qed. Lemma subsetUl A B : A \subset A :|: B. Proof. by apply/subsetP=> x; rewrite inE => ->. Qed. Lemma subsetUr A B : B \subset A :|: B. Proof. by apply/subsetP=> x; rewrite inE orbC => ->. Qed. Lemma subsetU1 x A : A \subset x |: A. Proof. exact: subsetUr. Qed. Lemma subsetDl A B : A :\: B \subset A. Proof. by rewrite setDE subsetIl. Qed. Lemma subD1set A x : A :\ x \subset A. Proof. by rewrite subsetDl. Qed. Lemma subsetDr A B : A :\: B \subset ~: B. Proof. by rewrite setDE subsetIr. Qed. Lemma sub1set A x : ([set x] \subset A) = (x \in A). Proof. by rewrite -subset_pred1; apply: eq_subset=> y; rewrite !inE. Qed. Lemma cards1P A : reflect (exists x, A = [set x]) (#|A| == 1). Proof. apply: (iffP idP) => [|[x ->]]; last by rewrite cards1. rewrite eq_sym eqn_leq card_gt0 => /andP[/set0Pn[x Ax] leA1]. by exists x; apply/eqP; rewrite eq_sym eqEcard sub1set Ax cards1 leA1. Qed. Lemma subset1 A x : (A \subset [set x]) = (A == [set x]) || (A == set0). Proof. rewrite eqEcard cards1 -cards_eq0 orbC andbC. by case: posnP => // A0; rewrite (cards0_eq A0) sub0set. Qed. Lemma powerset1 x : powerset [set x] = [set set0; [set x]]. Proof. by apply/setP=> A; rewrite !inE subset1 orbC. Qed. Lemma setIidPl A B : reflect (A :&: B = A) (A \subset B). Proof. apply: (iffP subsetP) => [sAB | <- x /setIP[] //]. by apply/setP=> x; rewrite inE; apply: andb_idr; exact: sAB. Qed. Implicit Arguments setIidPl [A B]. Lemma setIidPr A B : reflect (A :&: B = B) (B \subset A). Proof. rewrite setIC; exact: setIidPl. Qed. Lemma cardsDS A B : B \subset A -> #|A :\: B| = (#|A| - #|B|)%N. Proof. by rewrite cardsD => /setIidPr->. Qed. Lemma setUidPl A B : reflect (A :|: B = A) (B \subset A). Proof. by rewrite -setCS (sameP setIidPl eqP) -setCU (inj_eq setC_inj); exact: eqP. Qed. Lemma setUidPr A B : reflect (A :|: B = B) (A \subset B). Proof. rewrite setUC; exact: setUidPl. Qed. Lemma setDidPl A B : reflect (A :\: B = A) [disjoint A & B]. Proof. rewrite setDE disjoints_subset; exact: setIidPl. Qed. Lemma subIset A B C : (B \subset A) || (C \subset A) -> (B :&: C \subset A). Proof. by case/orP; apply: subset_trans; rewrite (subsetIl, subsetIr). Qed. Lemma subsetI A B C : (A \subset B :&: C) = (A \subset B) && (A \subset C). Proof. rewrite !(sameP setIidPl eqP) setIA; have [-> //| ] := altP (A :&: B =P A). by apply: contraNF => /eqP <-; rewrite -setIA -setIIl setIAC. Qed. Lemma subsetIP A B C : reflect (A \subset B /\ A \subset C) (A \subset B :&: C). Proof. by rewrite subsetI; exact: andP. Qed. Lemma subsetIidl A B : (A \subset A :&: B) = (A \subset B). Proof. by rewrite subsetI subxx. Qed. Lemma subsetIidr A B : (B \subset A :&: B) = (B \subset A). Proof. by rewrite setIC subsetIidl. Qed. Lemma powersetI A B : powerset (A :&: B) = powerset A :&: powerset B. Proof. by apply/setP=> C; rewrite !inE subsetI. Qed. Lemma subUset A B C : (B :|: C \subset A) = (B \subset A) && (C \subset A). Proof. by rewrite -setCS setCU subsetI !setCS. Qed. Lemma subsetU A B C : (A \subset B) || (A \subset C) -> A \subset B :|: C. Proof. by rewrite -!(setCS _ A) setCU; exact: subIset. Qed. Lemma subUsetP A B C : reflect (A \subset C /\ B \subset C) (A :|: B \subset C). Proof. by rewrite subUset; exact: andP. Qed. Lemma subsetC A B : (A \subset ~: B) = (B \subset ~: A). Proof. by rewrite -setCS setCK. Qed. Lemma subCset A B : (~: A \subset B) = (~: B \subset A). Proof. by rewrite -setCS setCK. Qed. Lemma subsetD A B C : (A \subset B :\: C) = (A \subset B) && [disjoint A & C]. Proof. by rewrite setDE subsetI -disjoints_subset. Qed. Lemma subDset A B C : (A :\: B \subset C) = (A \subset B :|: C). Proof. apply/subsetP/subsetP=> sABC x; rewrite !inE. by case Bx: (x \in B) => // Ax; rewrite sABC ?inE ?Bx. by case Bx: (x \in B) => //; move/sABC; rewrite inE Bx. Qed. Lemma subsetDP A B C : reflect (A \subset B /\ [disjoint A & C]) (A \subset B :\: C). Proof. by rewrite subsetD; exact: andP. Qed. Lemma setU_eq0 A B : (A :|: B == set0) = (A == set0) && (B == set0). Proof. by rewrite -!subset0 subUset. Qed. Lemma setD_eq0 A B : (A :\: B == set0) = (A \subset B). Proof. by rewrite -subset0 subDset setU0. Qed. Lemma setI_eq0 A B : (A :&: B == set0) = [disjoint A & B]. Proof. by rewrite disjoints_subset -setD_eq0 setDE setCK. Qed. Lemma disjoint_setI0 A B : [disjoint A & B] -> A :&: B = set0. Proof. by rewrite -setI_eq0; move/eqP. Qed. Lemma subsetD1 A B x : (A \subset B :\ x) = (A \subset B) && (x \notin A). Proof. by rewrite setDE subsetI subsetC sub1set inE. Qed. Lemma subsetD1P A B x : reflect (A \subset B /\ x \notin A) (A \subset B :\ x). Proof. by rewrite subsetD1; exact: andP. Qed. Lemma properD1 A x : x \in A -> A :\ x \proper A. Proof. move=> Ax; rewrite properE subsetDl; apply/subsetPn; exists x=> //. by rewrite in_setD1 Ax eqxx. Qed. Lemma properIr A B : ~~ (B \subset A) -> A :&: B \proper B. Proof. by move=> nsAB; rewrite properE subsetIr subsetI negb_and nsAB. Qed. Lemma properIl A B : ~~ (A \subset B) -> A :&: B \proper A. Proof. by move=> nsBA; rewrite properE subsetIl subsetI negb_and nsBA orbT. Qed. Lemma properUr A B : ~~ (A \subset B) -> B \proper A :|: B. Proof. by rewrite properE subsetUr subUset subxx /= andbT. Qed. Lemma properUl A B : ~~ (B \subset A) -> A \proper A :|: B. Proof. by move=> not_sBA; rewrite setUC properUr. Qed. Lemma proper1set A x : ([set x] \proper A) -> (x \in A). Proof. by move/proper_sub; rewrite sub1set. Qed. Lemma properIset A B C : (B \proper A) || (C \proper A) -> (B :&: C \proper A). Proof. by case/orP; apply: sub_proper_trans; rewrite (subsetIl, subsetIr). Qed. Lemma properI A B C : (A \proper B :&: C) -> (A \proper B) && (A \proper C). Proof. move=> pAI; apply/andP. by split; apply: (proper_sub_trans pAI); rewrite (subsetIl, subsetIr). Qed. Lemma properU A B C : (B :|: C \proper A) -> (B \proper A) && (C \proper A). Proof. move=> pUA; apply/andP. by split; apply: sub_proper_trans pUA; rewrite (subsetUr, subsetUl). Qed. Lemma properD A B C : (A \proper B :\: C) -> (A \proper B) && [disjoint A & C]. Proof. by rewrite setDE disjoints_subset => /properI/andP[-> /proper_sub]. Qed. End setOps. Implicit Arguments set1P [T x a]. Implicit Arguments set1_inj [T]. Implicit Arguments set2P [T x a b]. Implicit Arguments setIdP [T x pA pB]. Implicit Arguments setIP [T x A B]. Implicit Arguments setU1P [T x a B]. Implicit Arguments setD1P [T x A b]. Implicit Arguments setUP [T x A B]. Implicit Arguments setDP [T x A B]. Implicit Arguments cards1P [T A]. Implicit Arguments setCP [T x A]. Implicit Arguments setIidPl [T A B]. Implicit Arguments setIidPr [T A B]. Implicit Arguments setUidPl [T A B]. Implicit Arguments setUidPr [T A B]. Implicit Arguments setDidPl [T A B]. Implicit Arguments subsetIP [T A B C]. Implicit Arguments subUsetP [T A B C]. Implicit Arguments subsetDP [T A B C]. Implicit Arguments subsetD1P [T A B x]. Prenex Implicits set1 set1_inj. Prenex Implicits set1P set2P setU1P setD1P setIdP setIP setUP setDP. Prenex Implicits cards1P setCP setIidPl setIidPr setUidPl setUidPr setDidPl. Hint Resolve subsetT_hint. Section setOpsAlgebra. Import Monoid. Variable T : finType. Canonical setI_monoid := Law (@setIA T) (@setTI T) (@setIT T). Canonical setI_comoid := ComLaw (@setIC T). Canonical setI_muloid := MulLaw (@set0I T) (@setI0 T). Canonical setU_monoid := Law (@setUA T) (@set0U T) (@setU0 T). Canonical setU_comoid := ComLaw (@setUC T). Canonical setU_muloid := MulLaw (@setTU T) (@setUT T). Canonical setI_addoid := AddLaw (@setUIl T) (@setUIr T). Canonical setU_addoid := AddLaw (@setIUl T) (@setIUr T). End setOpsAlgebra. Section CartesianProd. Variables fT1 fT2 : finType. Variables (A1 : {set fT1}) (A2 : {set fT2}). Definition setX := [set u | u.1 \in A1 & u.2 \in A2]. Lemma in_setX x1 x2 : ((x1, x2) \in setX) = (x1 \in A1) && (x2 \in A2). Proof. by rewrite inE. Qed. Lemma setXP x1 x2 : reflect (x1 \in A1 /\ x2 \in A2) ((x1, x2) \in setX). Proof. by rewrite inE; exact: andP. Qed. Lemma cardsX : #|setX| = #|A1| * #|A2|. Proof. by rewrite cardsE cardX. Qed. End CartesianProd. Implicit Arguments setXP [x1 x2 fT1 fT2 A1 A2]. Prenex Implicits setXP. Notation Local imset_def := (fun (aT rT : finType) f mD => [set y in @image_mem aT rT f mD]). Notation Local imset2_def := (fun (aT1 aT2 rT : finType) f (D1 : mem_pred aT1) (D2 : _ -> mem_pred aT2) => [set y in @image_mem _ rT (prod_curry f) (mem [pred u | D1 u.1 & D2 u.1 u.2])]). Module Type ImsetSig. Parameter imset : forall aT rT : finType, (aT -> rT) -> mem_pred aT -> {set rT}. Parameter imset2 : forall aT1 aT2 rT : finType, (aT1 -> aT2 -> rT) -> mem_pred aT1 -> (aT1 -> mem_pred aT2) -> {set rT}. Axiom imsetE : imset = imset_def. Axiom imset2E : imset2 = imset2_def. End ImsetSig. Module Imset : ImsetSig. Definition imset := imset_def. Definition imset2 := imset2_def. Lemma imsetE : imset = imset_def. Proof. by []. Qed. Lemma imset2E : imset2 = imset2_def. Proof. by []. Qed. End Imset. Notation imset := Imset.imset. Notation imset2 := Imset.imset2. Canonical imset_unlock := Unlockable Imset.imsetE. Canonical imset2_unlock := Unlockable Imset.imset2E. Definition preimset (aT : finType) rT f (R : mem_pred rT) := [set x : aT | in_mem (f x) R]. Notation "f @^-1: A" := (preimset f (mem A)) (at level 24) : set_scope. Notation "f @: A" := (imset f (mem A)) (at level 24) : set_scope. Notation "f @2: ( A , B )" := (imset2 f (mem A) (fun _ => mem B)) (at level 24, format "f @2: ( A , B )") : set_scope. (* Comprehensions *) Notation "[ 'set' E | x 'in' A ]" := ((fun x => E) @: A) (at level 0, E, x at level 99, format "[ '[hv' 'set' E '/ ' | x 'in' A ] ']'") : set_scope. Notation "[ 'set' E | x 'in' A & P ]" := [set E | x in [set x in A | P]] (at level 0, E, x at level 99, format "[ '[hv' 'set' E '/ ' | x 'in' A '/ ' & P ] ']'") : set_scope. Notation "[ 'set' E | x 'in' A , y 'in' B ]" := (imset2 (fun x y => E) (mem A) (fun x => (mem B))) (at level 0, E, x, y at level 99, format "[ '[hv' 'set' E '/ ' | x 'in' A , '/ ' y 'in' B ] ']'" ) : set_scope. Notation "[ 'set' E | x 'in' A , y 'in' B & P ]" := [set E | x in A, y in [set y in B | P]] (at level 0, E, x, y at level 99, format "[ '[hv' 'set' E '/ ' | x 'in' A , '/ ' y 'in' B '/ ' & P ] ']'" ) : set_scope. (* Typed variants. *) Notation "[ 'set' E | x : T 'in' A ]" := ((fun x : T => E) @: A) (at level 0, E, x at level 99, only parsing) : set_scope. Notation "[ 'set' E | x : T 'in' A & P ]" := [set E | x : T in [set x : T in A | P]] (at level 0, E, x at level 99, only parsing) : set_scope. Notation "[ 'set' E | x : T 'in' A , y : U 'in' B ]" := (imset2 (fun (x : T) (y : U) => E) (mem A) (fun (x : T) => (mem B))) (at level 0, E, x, y at level 99, only parsing) : set_scope. Notation "[ 'set' E | x : T 'in' A , y : U 'in' B & P ]" := [set E | x : T in A, y : U in [set y : U in B | P]] (at level 0, E, x, y at level 99, only parsing) : set_scope. (* Comprehensions over a type. *) Local Notation predOfType T := (sort_of_simpl_pred (@pred_of_argType T)). Notation "[ 'set' E | x : T ]" := [set E | x : T in predOfType T] (at level 0, E, x at level 99, format "[ '[hv' 'set' E '/ ' | x : T ] ']'") : set_scope. Notation "[ 'set' E | x : T & P ]" := [set E | x : T in [set x : T | P]] (at level 0, E, x at level 99, format "[ '[hv' 'set' E '/ ' | x : T '/ ' & P ] ']'") : set_scope. Notation "[ 'set' E | x : T , y : U 'in' B ]" := [set E | x : T in predOfType T, y : U in B] (at level 0, E, x, y at level 99, format "[ '[hv' 'set' E '/ ' | x : T , '/ ' y : U 'in' B ] ']'") : set_scope. Notation "[ 'set' E | x : T , y : U 'in' B & P ]" := [set E | x : T, y : U in [set y in B | P]] (at level 0, E, x, y at level 99, format "[ '[hv ' 'set' E '/' | x : T , '/ ' y : U 'in' B '/' & P ] ']'" ) : set_scope. Notation "[ 'set' E | x : T 'in' A , y : U ]" := [set E | x : T in A, y : U in predOfType U] (at level 0, E, x, y at level 99, format "[ '[hv' 'set' E '/ ' | x : T 'in' A , '/ ' y : U ] ']'") : set_scope. Notation "[ 'set' E | x : T 'in' A , y : U & P ]" := [set E | x : T in A, y : U in [set y in P]] (at level 0, E, x, y at level 99, format "[ '[hv' 'set' E '/ ' | x : T 'in' A , '/ ' y : U & P ] ']'") : set_scope. Notation "[ 'set' E | x : T , y : U ]" := [set E | x : T, y : U in predOfType U] (at level 0, E, x, y at level 99, format "[ '[hv' 'set' E '/ ' | x : T , '/ ' y : U ] ']'") : set_scope. Notation "[ 'set' E | x : T , y : U & P ]" := [set E | x : T, y : U in [set y in P]] (at level 0, E, x, y at level 99, format "[ '[hv' 'set' E '/ ' | x : T , '/ ' y : U & P ] ']'") : set_scope. (* Untyped variants. *) Notation "[ 'set' E | x , y 'in' B ]" := [set E | x : _, y : _ in B] (at level 0, E, x, y at level 99, only parsing) : set_scope. Notation "[ 'set' E | x , y 'in' B & P ]" := [set E | x : _, y : _ in B & P] (at level 0, E, x, y at level 99, only parsing) : set_scope. Notation "[ 'set' E | x 'in' A , y ]" := [set E | x : _ in A, y : _] (at level 0, E, x, y at level 99, only parsing) : set_scope. Notation "[ 'set' E | x 'in' A , y & P ]" := [set E | x : _ in A, y : _ & P] (at level 0, E, x, y at level 99, only parsing) : set_scope. Notation "[ 'set' E | x , y ]" := [set E | x : _, y : _] (at level 0, E, x, y at level 99, only parsing) : set_scope. Notation "[ 'set' E | x , y & P ]" := [set E | x : _, y : _ & P ] (at level 0, E, x, y at level 99, only parsing) : set_scope. (* Print-only variants to work around the Coq pretty-printer K-term kink. *) Notation "[ 'se' 't' E | x 'in' A , y 'in' B ]" := (imset2 (fun x y => E) (mem A) (fun _ => mem B)) (at level 0, E, x, y at level 99, format "[ '[hv' 'se' 't' E '/ ' | x 'in' A , '/ ' y 'in' B ] ']'") : set_scope. Notation "[ 'se' 't' E | x 'in' A , y 'in' B & P ]" := [se t E | x in A, y in [set y in B | P]] (at level 0, E, x, y at level 99, format "[ '[hv ' 'se' 't' E '/' | x 'in' A , '/ ' y 'in' B '/' & P ] ']'" ) : set_scope. Notation "[ 'se' 't' E | x : T , y : U 'in' B ]" := (imset2 (fun x (y : U) => E) (mem (predOfType T)) (fun _ => mem B)) (at level 0, E, x, y at level 99, format "[ '[hv ' 'se' 't' E '/' | x : T , '/ ' y : U 'in' B ] ']'") : set_scope. Notation "[ 'se' 't' E | x : T , y : U 'in' B & P ]" := [se t E | x : T, y : U in [set y in B | P]] (at level 0, E, x, y at level 99, format "[ '[hv ' 'se' 't' E '/' | x : T , '/ ' y : U 'in' B '/' & P ] ']'" ) : set_scope. Notation "[ 'se' 't' E | x : T 'in' A , y : U ]" := (imset2 (fun x y => E) (mem A) (fun _ : T => mem (predOfType U))) (at level 0, E, x, y at level 99, format "[ '[hv' 'se' 't' E '/ ' | x : T 'in' A , '/ ' y : U ] ']'") : set_scope. Notation "[ 'se' 't' E | x : T 'in' A , y : U & P ]" := (imset2 (fun x (y : U) => E) (mem A) (fun _ : T => mem [set y \in P])) (at level 0, E, x, y at level 99, format "[ '[hv ' 'se' 't' E '/' | x : T 'in' A , '/ ' y : U '/' & P ] ']'" ) : set_scope. Notation "[ 'se' 't' E | x : T , y : U ]" := [se t E | x : T, y : U in predOfType U] (at level 0, E, x, y at level 99, format "[ '[hv' 'se' 't' E '/ ' | x : T , '/ ' y : U ] ']'") : set_scope. Notation "[ 'se' 't' E | x : T , y : U & P ]" := [se t E | x : T, y : U in [set y in P]] (at level 0, E, x, y at level 99, format "[ '[hv' 'se' 't' E '/' | x : T , '/ ' y : U '/' & P ] ']'") : set_scope. Section FunImage. Variables aT aT2 : finType. Section ImsetTheory. Variable rT : finType. Section ImsetProp. Variables (f : aT -> rT) (f2 : aT -> aT2 -> rT). Lemma imsetP D y : reflect (exists2 x, in_mem x D & y = f x) (y \in imset f D). Proof. rewrite [@imset]unlock inE; exact: imageP. Qed. CoInductive imset2_spec D1 D2 y : Prop := Imset2spec x1 x2 of in_mem x1 D1 & in_mem x2 (D2 x1) & y = f2 x1 x2. Lemma imset2P D1 D2 y : reflect (imset2_spec D1 D2 y) (y \in imset2 f2 D1 D2). Proof. rewrite [@imset2]unlock inE. apply: (iffP imageP) => [[[x1 x2] Dx12] | [x1 x2 Dx1 Dx2]] -> {y}. by case/andP: Dx12; exists x1 x2. by exists (x1, x2); rewrite //= !inE Dx1. Qed. Lemma mem_imset (D : pred aT) x : x \in D -> f x \in f @: D. Proof. by move=> Dx; apply/imsetP; exists x. Qed. Lemma imset0 : f @: set0 = set0. Proof. by apply/setP => y; rewrite inE; apply/imsetP=> [[x]]; rewrite inE. Qed. Lemma imset_eq0 (A : {set aT}) : (f @: A == set0) = (A == set0). Proof. have [-> | [x Ax]] := set_0Vmem A; first by rewrite imset0 !eqxx. by rewrite -!cards_eq0 (cardsD1 x) Ax (cardsD1 (f x)) mem_imset. Qed. Lemma imset_set1 x : f @: [set x] = [set f x]. Proof. apply/setP => y. by apply/imsetP/set1P=> [[x' /set1P-> //]| ->]; exists x; rewrite ?set11. Qed. Lemma mem_imset2 (D : pred aT) (D2 : aT -> pred aT2) x x2 : x \in D -> x2 \in D2 x -> f2 x x2 \in imset2 f2 (mem D) (fun x1 => mem (D2 x1)). Proof. by move=> Dx Dx2; apply/imset2P; exists x x2. Qed. Lemma sub_imset_pre (A : pred aT) (B : pred rT) : (f @: A \subset B) = (A \subset f @^-1: B). Proof. apply/subsetP/subsetP=> [sfAB x Ax | sAf'B fx]. by rewrite inE sfAB ?mem_imset. by case/imsetP=> x Ax ->; move/sAf'B: Ax; rewrite inE. Qed. Lemma preimsetS (A B : pred rT) : A \subset B -> (f @^-1: A) \subset (f @^-1: B). Proof. move=> sAB; apply/subsetP=> y; rewrite !inE; exact: (subsetP sAB). Qed. Lemma preimset0 : f @^-1: set0 = set0. Proof. by apply/setP=> x; rewrite !inE. Qed. Lemma preimsetT : f @^-1: setT = setT. Proof. by apply/setP=> x; rewrite !inE. Qed. Lemma preimsetI (A B : {set rT}) : f @^-1: (A :&: B) = (f @^-1: A) :&: (f @^-1: B). Proof. by apply/setP=> y; rewrite !inE. Qed. Lemma preimsetU (A B : {set rT}) : f @^-1: (A :|: B) = (f @^-1: A) :|: (f @^-1: B). Proof. by apply/setP=> y; rewrite !inE. Qed. Lemma preimsetD (A B : {set rT}) : f @^-1: (A :\: B) = (f @^-1: A) :\: (f @^-1: B). Proof. by apply/setP=> y; rewrite !inE. Qed. Lemma preimsetC (A : {set rT}) : f @^-1: (~: A) = ~: f @^-1: A. Proof. by apply/setP=> y; rewrite !inE. Qed. Lemma imsetS (A B : pred aT) : A \subset B -> f @: A \subset f @: B. Proof. move=> sAB; apply/subsetP=> _ /imsetP[x Ax ->]. by apply/imsetP; exists x; rewrite ?(subsetP sAB). Qed. Lemma imset_proper (A B : {set aT}) : {in B &, injective f} -> A \proper B -> f @: A \proper f @: B. Proof. move=> injf /properP[sAB [x Bx nAx]]; rewrite properE imsetS //=. apply: contra nAx => sfBA. have: f x \in f @: A by rewrite (subsetP sfBA) ?mem_imset. by case/imsetP=> y Ay /injf-> //; exact: subsetP sAB y Ay. Qed. Lemma preimset_proper (A B : {set rT}) : B \subset codom f -> A \proper B -> (f @^-1: A) \proper (f @^-1: B). Proof. move=> sBc /properP[sAB [u Bu nAu]]; rewrite properE preimsetS //=. by apply/subsetPn; exists (iinv (subsetP sBc _ Bu)); rewrite inE /= f_iinv. Qed. Lemma imsetU (A B : {set aT}) : f @: (A :|: B) = (f @: A) :|: (f @: B). Proof. apply/eqP; rewrite eqEsubset subUset. rewrite 2?imsetS (andbT, subsetUl, subsetUr) // andbT. apply/subsetP=> _ /imsetP[x ABx ->]; apply/setUP. by case/setUP: ABx => [Ax | Bx]; [left | right]; apply/imsetP; exists x. Qed. Lemma imsetU1 a (A : {set aT}) : f @: (a |: A) = f a |: (f @: A). Proof. by rewrite imsetU imset_set1. Qed. Lemma imsetI (A B : {set aT}) : {in A & B, injective f} -> f @: (A :&: B) = f @: A :&: f @: B. Proof. move=> injf; apply/eqP; rewrite eqEsubset subsetI. rewrite 2?imsetS (andTb, subsetIl, subsetIr) //=. apply/subsetP=> _ /setIP[/imsetP[x Ax ->] /imsetP[z Bz /injf eqxz]]. by rewrite mem_imset // inE Ax eqxz. Qed. Lemma imset2Sl (A B : pred aT) (C : pred aT2) : A \subset B -> f2 @2: (A, C) \subset f2 @2: (B, C). Proof. move=> sAB; apply/subsetP=> _ /imset2P[x y Ax Cy ->]. by apply/imset2P; exists x y; rewrite ?(subsetP sAB). Qed. Lemma imset2Sr (A B : pred aT2) (C : pred aT) : A \subset B -> f2 @2: (C, A) \subset f2 @2: (C, B). Proof. move=> sAB; apply/subsetP=> _ /imset2P[x y Ax Cy ->]. by apply/imset2P; exists x y; rewrite ?(subsetP sAB). Qed. Lemma imset2S (A B : pred aT) (A2 B2 : pred aT2) : A \subset B -> A2 \subset B2 -> f2 @2: (A, A2) \subset f2 @2: (B, B2). Proof. by move=> /(imset2Sl B2) sBA /(imset2Sr A)/subset_trans->. Qed. End ImsetProp. Implicit Types (f g : aT -> rT) (D : {set aT}) (R : pred rT). Lemma eq_preimset f g R : f =1 g -> f @^-1: R = g @^-1: R. Proof. by move=> eqfg; apply/setP => y; rewrite !inE eqfg. Qed. Lemma eq_imset f g D : f =1 g -> f @: D = g @: D. Proof. move=> eqfg; apply/setP=> y. by apply/imsetP/imsetP=> [] [x Dx ->]; exists x; rewrite ?eqfg. Qed. Lemma eq_in_imset f g D : {in D, f =1 g} -> f @: D = g @: D. Proof. move=> eqfg; apply/setP => y. by apply/imsetP/imsetP=> [] [x Dx ->]; exists x; rewrite ?eqfg. Qed. Lemma eq_in_imset2 (f g : aT -> aT2 -> rT) (D : pred aT) (D2 : pred aT2) : {in D & D2, f =2 g} -> f @2: (D, D2) = g @2: (D, D2). Proof. move=> eqfg; apply/setP => y. by apply/imset2P/imset2P=> [] [x x2 Dx Dx2 ->]; exists x x2; rewrite ?eqfg. Qed. End ImsetTheory. Lemma imset2_pair (A : {set aT}) (B : {set aT2}) : [set (x, y) | x in A, y in B] = setX A B. Proof. apply/setP=> [[x y]]; rewrite !inE /=. by apply/imset2P/andP=> [[_ _ _ _ [-> ->]//]| []]; exists x y. Qed. Lemma setXS (A1 B1 : {set aT}) (A2 B2 : {set aT2}) : A1 \subset B1 -> A2 \subset B2 -> setX A1 A2 \subset setX B1 B2. Proof. by move=> sAB1 sAB2; rewrite -!imset2_pair imset2S. Qed. End FunImage. Implicit Arguments imsetP [aT rT f D y]. Implicit Arguments imset2P [aT aT2 rT f2 D1 D2 y]. Prenex Implicits imsetP imset2P. Section BigOps. Variables (R : Type) (idx : R). Variables (op : Monoid.law idx) (aop : Monoid.com_law idx). Variables I J : finType. Implicit Type A B : {set I}. Implicit Type h : I -> J. Implicit Type P : pred I. Implicit Type F : I -> R. Lemma big_set0 F : \big[op/idx]_(i in set0) F i = idx. Proof. by apply: big_pred0 => i; rewrite inE. Qed. Lemma big_set1 a F : \big[op/idx]_(i in [set a]) F i = F a. Proof. by apply: big_pred1 => i; rewrite !inE. Qed. Lemma big_setIDdep A B P F : \big[aop/idx]_(i in A | P i) F i = aop (\big[aop/idx]_(i in A :&: B | P i) F i) (\big[aop/idx]_(i in A :\: B | P i) F i). Proof. rewrite (bigID (mem B)) setDE. by congr (aop _ _); apply: eq_bigl => i; rewrite !inE andbAC. Qed. Lemma big_setID A B F : \big[aop/idx]_(i in A) F i = aop (\big[aop/idx]_(i in A :&: B) F i) (\big[aop/idx]_(i in A :\: B) F i). Proof. rewrite (bigID (mem B)) !(eq_bigl _ _ (in_set _)) //=. by congr (aop _); apply: eq_bigl => i; rewrite andbC. Qed. Lemma big_setD1 a A F : a \in A -> \big[aop/idx]_(i in A) F i = aop (F a) (\big[aop/idx]_(i in A :\ a) F i). Proof. move=> Aa; rewrite (bigD1 a Aa); congr (aop _). by apply: eq_bigl => x; rewrite !inE andbC. Qed. Lemma big_setU1 a A F : a \notin A -> \big[aop/idx]_(i in a |: A) F i = aop (F a) (\big[aop/idx]_(i in A) F i). Proof. by move=> notAa; rewrite (@big_setD1 a) ?setU11 //= setU1K. Qed. Lemma big_imset h (A : pred I) G : {in A &, injective h} -> \big[aop/idx]_(j in h @: A) G j = \big[aop/idx]_(i in A) G (h i). Proof. move=> injh; pose hA := mem (image h A). have [x0 Ax0 | A0] := pickP A; last first. by rewrite !big_pred0 // => x; apply/imsetP=> [[i]]; rewrite unfold_in A0. rewrite (eq_bigl hA) => [|j]; last by exact/imsetP/imageP. pose h' j := if insub j : {? j | hA j} is Some u then iinv (svalP u) else x0. rewrite (reindex_onto h h') => [|j hAj]; rewrite {}/h'; last first. by rewrite (insubT hA hAj) f_iinv. apply: eq_bigl => i; case: insubP => [u -> /= def_u | nhAhi]. set i' := iinv _; have Ai' : i' \in A := mem_iinv (svalP u). by apply/eqP/idP=> [<- // | Ai]; apply: injh; rewrite ?f_iinv. symmetry; rewrite (negbTE nhAhi); apply/idP=> Ai. by case/imageP: nhAhi; exists i. Qed. Lemma partition_big_imset h (A : pred I) F : \big[aop/idx]_(i in A) F i = \big[aop/idx]_(j in h @: A) \big[aop/idx]_(i in A | h i == j) F i. Proof. by apply: partition_big => i Ai; apply/imsetP; exists i. Qed. End BigOps. Implicit Arguments big_setID [R idx aop I A]. Implicit Arguments big_setD1 [R idx aop I A F]. Implicit Arguments big_setU1 [R idx aop I A F]. Implicit Arguments big_imset [R idx aop h I J A]. Implicit Arguments partition_big_imset [R idx aop I J]. Section Fun2Set1. Variables aT1 aT2 rT : finType. Variables (f : aT1 -> aT2 -> rT). Lemma imset2_set1l x1 (D2 : pred aT2) : f @2: ([set x1], D2) = f x1 @: D2. Proof. apply/setP=> y; apply/imset2P/imsetP=> [[x x2 /set1P->]| [x2 Dx2 ->]]. by exists x2. by exists x1 x2; rewrite ?set11. Qed. Lemma imset2_set1r x2 (D1 : pred aT1) : f @2: (D1, [set x2]) = f^~ x2 @: D1. Proof. apply/setP=> y; apply/imset2P/imsetP=> [[x1 x Dx1 /set1P->]| [x1 Dx1 ->]]. by exists x1. by exists x1 x2; rewrite ?set11. Qed. End Fun2Set1. Section CardFunImage. Variables aT aT2 rT : finType. Variables (f : aT -> rT) (g : rT -> aT) (f2 : aT -> aT2 -> rT). Variables (D : pred aT) (D2 : pred aT). Lemma imset_card : #|f @: D| = #|image f D|. Proof. by rewrite [@imset]unlock cardsE. Qed. Lemma leq_imset_card : #|f @: D| <= #|D|. Proof. by rewrite imset_card leq_image_card. Qed. Lemma card_in_imset : {in D &, injective f} -> #|f @: D| = #|D|. Proof. by move=> injf; rewrite imset_card card_in_image. Qed. Lemma card_imset : injective f -> #|f @: D| = #|D|. Proof. by move=> injf; rewrite imset_card card_image. Qed. Lemma imset_injP : reflect {in D &, injective f} (#|f @: D| == #|D|). Proof. by rewrite [@imset]unlock cardsE; exact: image_injP. Qed. Lemma can2_in_imset_pre : {in D, cancel f g} -> {on D, cancel g & f} -> f @: D = g @^-1: D. Proof. move=> fK gK; apply/setP=> y; rewrite inE. by apply/imsetP/idP=> [[x Ax ->] | Agy]; last exists (g y); rewrite ?(fK, gK). Qed. Lemma can2_imset_pre : cancel f g -> cancel g f -> f @: D = g @^-1: D. Proof. by move=> fK gK; apply: can2_in_imset_pre; exact: in1W. Qed. End CardFunImage. Implicit Arguments imset_injP [aT rT f D]. Lemma on_card_preimset (aT rT : finType) (f : aT -> rT) (R : pred rT) : {on R, bijective f} -> #|f @^-1: R| = #|R|. Proof. case=> g fK gK; rewrite -(can2_in_imset_pre gK) // card_in_imset //. exact: can_in_inj gK. Qed. Lemma can_imset_pre (T : finType) f g (A : {set T}) : cancel f g -> f @: A = g @^-1: A :> {set T}. Proof. move=> fK; apply: can2_imset_pre => // x. suffices fx: x \in codom f by rewrite -(f_iinv fx) fK. move: x; apply/(subset_cardP (card_codom (can_inj fK))); exact/subsetP. Qed. Lemma imset_id (T : finType) (A : {set T}) : [set x | x in A] = A. Proof. by apply/setP=> x; rewrite (@can_imset_pre _ _ id) ?inE. Qed. Lemma card_preimset (T : finType) (f : T -> T) (A : {set T}) : injective f -> #|f @^-1: A| = #|A|. Proof. move=> injf; apply: on_card_preimset; apply: onW_bij. have ontof: _ \in codom f by exact/(subset_cardP (card_codom injf))/subsetP. by exists (fun x => iinv (ontof x)) => x; rewrite (f_iinv, iinv_f). Qed. Lemma card_powerset (T : finType) (A : {set T}) : #|powerset A| = 2 ^ #|A|. Proof. rewrite -card_bool -(card_pffun_on false) -(card_imset _ val_inj). apply: eq_card => f; pose sf := false.-support f; pose D := finset sf. have sDA: (D \subset A) = (sf \subset A) by apply: eq_subset; exact: in_set. have eq_sf x : sf x = f x by rewrite /= negb_eqb addbF. have valD: val D = f by rewrite /D unlock; apply/ffunP=> x; rewrite ffunE eq_sf. apply/imsetP/pffun_onP=> [[B] | [sBA _]]; last by exists D; rewrite // inE ?sDA. by rewrite inE -sDA -valD => sBA /val_inj->. Qed. Section FunImageComp. Variables T T' U : finType. Lemma imset_comp (f : T' -> U) (g : T -> T') (H : pred T) : (f \o g) @: H = f @: (g @: H). Proof. apply/setP/subset_eqP/andP. split; apply/subsetP=> _ /imsetP[x0 Hx0 ->]; apply/imsetP. by exists (g x0); first apply: mem_imset. by move/imsetP: Hx0 => [x1 Hx1 ->]; exists x1. Qed. End FunImageComp. Notation "\bigcup_ ( i <- r | P ) F" := (\big[@setU _/set0]_(i <- r | P) F%SET) : set_scope. Notation "\bigcup_ ( i <- r ) F" := (\big[@setU _/set0]_(i <- r) F%SET) : set_scope. Notation "\bigcup_ ( m <= i < n | P ) F" := (\big[@setU _/set0]_(m <= i < n | P%B) F%SET) : set_scope. Notation "\bigcup_ ( m <= i < n ) F" := (\big[@setU _/set0]_(m <= i < n) F%SET) : set_scope. Notation "\bigcup_ ( i | P ) F" := (\big[@setU _/set0]_(i | P%B) F%SET) : set_scope. Notation "\bigcup_ i F" := (\big[@setU _/set0]_i F%SET) : set_scope. Notation "\bigcup_ ( i : t | P ) F" := (\big[@setU _/set0]_(i : t | P%B) F%SET) (only parsing): set_scope. Notation "\bigcup_ ( i : t ) F" := (\big[@setU _/set0]_(i : t) F%SET) (only parsing) : set_scope. Notation "\bigcup_ ( i < n | P ) F" := (\big[@setU _/set0]_(i < n | P%B) F%SET) : set_scope. Notation "\bigcup_ ( i < n ) F" := (\big[@setU _/set0]_ (i < n) F%SET) : set_scope. Notation "\bigcup_ ( i 'in' A | P ) F" := (\big[@setU _/set0]_(i in A | P%B) F%SET) : set_scope. Notation "\bigcup_ ( i 'in' A ) F" := (\big[@setU _/set0]_(i in A) F%SET) : set_scope. Notation "\bigcap_ ( i <- r | P ) F" := (\big[@setI _/setT]_(i <- r | P%B) F%SET) : set_scope. Notation "\bigcap_ ( i <- r ) F" := (\big[@setI _/setT]_(i <- r) F%SET) : set_scope. Notation "\bigcap_ ( m <= i < n | P ) F" := (\big[@setI _/setT]_(m <= i < n | P%B) F%SET) : set_scope. Notation "\bigcap_ ( m <= i < n ) F" := (\big[@setI _/setT]_(m <= i < n) F%SET) : set_scope. Notation "\bigcap_ ( i | P ) F" := (\big[@setI _/setT]_(i | P%B) F%SET) : set_scope. Notation "\bigcap_ i F" := (\big[@setI _/setT]_i F%SET) : set_scope. Notation "\bigcap_ ( i : t | P ) F" := (\big[@setI _/setT]_(i : t | P%B) F%SET) (only parsing): set_scope. Notation "\bigcap_ ( i : t ) F" := (\big[@setI _/setT]_(i : t) F%SET) (only parsing) : set_scope. Notation "\bigcap_ ( i < n | P ) F" := (\big[@setI _/setT]_(i < n | P%B) F%SET) : set_scope. Notation "\bigcap_ ( i < n ) F" := (\big[@setI _/setT]_(i < n) F%SET) : set_scope. Notation "\bigcap_ ( i 'in' A | P ) F" := (\big[@setI _/setT]_(i in A | P%B) F%SET) : set_scope. Notation "\bigcap_ ( i 'in' A ) F" := (\big[@setI _/setT]_(i in A) F%SET) : set_scope. Section BigSetOps. Variables T I : finType. Implicit Types (U : pred T) (P : pred I) (A B : {set I}) (F : I -> {set T}). (* It is very hard to use this lemma, because the unification fails to *) (* defer the F j pattern (even though it's a Miller pattern!). *) Lemma bigcup_sup j P F : P j -> F j \subset \bigcup_(i | P i) F i. Proof. by move=> Pj; rewrite (bigD1 j) //= subsetUl. Qed. Lemma bigcup_max j U P F : P j -> U \subset F j -> U \subset \bigcup_(i | P i) F i. Proof. by move=> Pj sUF; exact: subset_trans (bigcup_sup _ Pj). Qed. Lemma bigcupP x P F : reflect (exists2 i, P i & x \in F i) (x \in \bigcup_(i | P i) F i). Proof. apply: (iffP idP) => [|[i Pi]]; last first. apply: subsetP x; exact: bigcup_sup. by elim/big_rec: _ => [|i _ Pi _ /setUP[|//]]; [rewrite inE | exists i]. Qed. Lemma bigcupsP U P F : reflect (forall i, P i -> F i \subset U) (\bigcup_(i | P i) F i \subset U). Proof. apply: (iffP idP) => [sFU i Pi| sFU]. by apply: subset_trans sFU; exact: bigcup_sup. by apply/subsetP=> x /bigcupP[i Pi]; exact: (subsetP (sFU i Pi)). Qed. Lemma bigcup_disjoint U P F : (forall i, P i -> [disjoint U & F i]) -> [disjoint U & \bigcup_(i | P i) F i]. Proof. move=> dUF; rewrite disjoint_sym disjoint_subset. by apply/bigcupsP=> i /dUF; rewrite disjoint_sym disjoint_subset. Qed. Lemma bigcup_setU A B F : \bigcup_(i in A :|: B) F i = (\bigcup_(i in A) F i) :|: (\bigcup_ (i in B) F i). Proof. apply/setP=> x; apply/bigcupP/setUP=> [[i] | ]. by case/setUP; [left | right]; apply/bigcupP; exists i. by case=> /bigcupP[i Pi]; exists i; rewrite // inE Pi ?orbT. Qed. Lemma bigcup_seq r F : \bigcup_(i <- r) F i = \bigcup_(i in r) F i. Proof. elim: r => [|i r IHr]; first by rewrite big_nil big_pred0. rewrite big_cons {}IHr; case r_i: (i \in r). rewrite (setUidPr _) ?bigcup_sup //. by apply: eq_bigl => j; rewrite !inE; case: eqP => // ->. rewrite (bigD1 i (mem_head i r)) /=; congr (_ :|: _). by apply: eq_bigl => j /=; rewrite andbC; case: eqP => // ->. Qed. (* Unlike its setU counterpart, this lemma is useable. *) Lemma bigcap_inf j P F : P j -> \bigcap_(i | P i) F i \subset F j. Proof. by move=> Pj; rewrite (bigD1 j) //= subsetIl. Qed. Lemma bigcap_min j U P F : P j -> F j \subset U -> \bigcap_(i | P i) F i \subset U. Proof. by move=> Pj; exact: subset_trans (bigcap_inf _ Pj). Qed. Lemma bigcapsP U P F : reflect (forall i, P i -> U \subset F i) (U \subset \bigcap_(i | P i) F i). Proof. apply: (iffP idP) => [sUF i Pi | sUF]. apply: subset_trans sUF _; exact: bigcap_inf. elim/big_rec: _ => [|i V Pi sUV]; apply/subsetP=> x Ux; rewrite inE //. by rewrite !(subsetP _ x Ux) ?sUF. Qed. Lemma bigcapP x P F : reflect (forall i, P i -> x \in F i) (x \in \bigcap_(i | P i) F i). Proof. rewrite -sub1set. by apply: (iffP (bigcapsP _ _ _)) => Fx i /Fx; rewrite sub1set. Qed. Lemma setC_bigcup J r (P : pred J) (F : J -> {set T}) : ~: (\bigcup_(j <- r | P j) F j) = \bigcap_(j <- r | P j) ~: F j. Proof. by apply: big_morph => [A B|]; rewrite ?setC0 ?setCU. Qed. Lemma setC_bigcap J r (P : pred J) (F : J -> {set T}) : ~: (\bigcap_(j <- r | P j) F j) = \bigcup_(j <- r | P j) ~: F j. Proof. by apply: big_morph => [A B|]; rewrite ?setCT ?setCI. Qed. Lemma bigcap_setU A B F : (\bigcap_(i in A :|: B) F i) = (\bigcap_(i in A) F i) :&: (\bigcap_(i in B) F i). Proof. by apply: setC_inj; rewrite setCI !setC_bigcap bigcup_setU. Qed. Lemma bigcap_seq r F : \bigcap_(i <- r) F i = \bigcap_(i in r) F i. Proof. by apply: setC_inj; rewrite !setC_bigcap bigcup_seq. Qed. End BigSetOps. Implicit Arguments bigcup_sup [T I P F]. Implicit Arguments bigcup_max [T I U P F]. Implicit Arguments bigcupP [T I x P F]. Implicit Arguments bigcupsP [T I U P F]. Implicit Arguments bigcap_inf [T I P F]. Implicit Arguments bigcap_min [T I U P F]. Implicit Arguments bigcapP [T I x P F]. Implicit Arguments bigcapsP [T I U P F]. Prenex Implicits bigcupP bigcupsP bigcapP bigcapsP. Section ImsetCurry. Variables (aT1 aT2 rT : finType) (f : aT1 -> aT2 -> rT). Section Curry. Variables (A1 : {set aT1}) (A2 : {set aT2}). Variables (D1 : pred aT1) (D2 : pred aT2). Lemma curry_imset2X : f @2: (A1, A2) = prod_curry f @: (setX A1 A2). Proof. rewrite [@imset]unlock unlock; apply/setP=> x; rewrite !in_set; congr (x \in _). by apply: eq_image => u //=; rewrite !inE. Qed. Lemma curry_imset2l : f @2: (D1, D2) = \bigcup_(x1 in D1) f x1 @: D2. Proof. apply/setP=> y; apply/imset2P/bigcupP => [[x1 x2 Dx1 Dx2 ->{y}] | [x1 Dx1]]. by exists x1; rewrite // mem_imset. by case/imsetP=> x2 Dx2 ->{y}; exists x1 x2. Qed. Lemma curry_imset2r : f @2: (D1, D2) = \bigcup_(x2 in D2) f^~ x2 @: D1. Proof. apply/setP=> y; apply/imset2P/bigcupP => [[x1 x2 Dx1 Dx2 ->{y}] | [x2 Dx2]]. by exists x2; rewrite // (mem_imset (f^~ x2)). by case/imsetP=> x1 Dx1 ->{y}; exists x1 x2. Qed. End Curry. Lemma imset2Ul (A B : {set aT1}) (C : {set aT2}) : f @2: (A :|: B, C) = f @2: (A, C) :|: f @2: (B, C). Proof. by rewrite !curry_imset2l bigcup_setU. Qed. Lemma imset2Ur (A : {set aT1}) (B C : {set aT2}) : f @2: (A, B :|: C) = f @2: (A, B) :|: f @2: (A, C). Proof. by rewrite !curry_imset2r bigcup_setU. Qed. End ImsetCurry. Section Partitions. Variables T I : finType. Implicit Types (x y z : T) (A B D X : {set T}) (P Q : {set {set T}}). Implicit Types (J : pred I) (F : I -> {set T}). Definition cover P := \bigcup_(B in P) B. Definition pblock P x := odflt set0 (pick [pred B in P | x \in B]). Definition trivIset P := \sum_(B in P) #|B| == #|cover P|. Definition partition P D := [&& cover P == D, trivIset P & set0 \notin P]. Definition is_transversal X P D := [&& partition P D, X \subset D & [forall B in P, #|X :&: B| == 1]]. Definition transversal P D := [set odflt x [pick y in pblock P x] | x in D]. Definition transversal_repr x0 X B := odflt x0 [pick x in X :&: B]. Lemma leq_card_setU A B : #|A :|: B| <= #|A| + #|B| ?= iff [disjoint A & B]. Proof. rewrite -(addn0 #|_|) -setI_eq0 -cards_eq0 -cardsUI eq_sym. by rewrite (mono_leqif (leq_add2l _)). Qed. Lemma leq_card_cover P : #|cover P| <= \sum_(A in P) #|A| ?= iff trivIset P. Proof. split; last exact: eq_sym. rewrite /cover; elim/big_rec2: _ => [|A n U _ leUn]; first by rewrite cards0. by rewrite (leq_trans (leq_card_setU A U).1) ?leq_add2l. Qed. Lemma trivIsetP P : reflect {in P &, forall A B, A != B -> [disjoint A & B]} (trivIset P). Proof. have->: P = [set x in enum (mem P)] by apply/setP=> x; rewrite inE mem_enum. elim: {P}(enum _) (enum_uniq (mem P)) => [_ | A e IHe] /=. by rewrite /trivIset /cover !big_set0 cards0; left=> A; rewrite inE. case/andP; rewrite set_cons -(in_set (fun B => B \in e)) => PA {IHe}/IHe. move: {e}[set x in e] PA => P PA IHP. rewrite /trivIset /cover !big_setU1 //= eq_sym. have:= leq_card_cover P; rewrite -(mono_leqif (leq_add2l #|A|)). move/(leqif_trans (leq_card_setU _ _))->; rewrite disjoints_subset setC_bigcup. case: bigcapsP => [disjA | meetA]; last first. right=> [tI]; case: meetA => B PB; rewrite -disjoints_subset. by rewrite tI ?setU11 ?setU1r //; apply: contraNneq PA => ->. apply: (iffP IHP) => [] tI B C PB PC; last by apply: tI; exact: setU1r. by case/setU1P: PC PB => [->|PC] /setU1P[->|PB]; try by [exact: tI | case/eqP]; first rewrite disjoint_sym; rewrite disjoints_subset disjA. Qed. Lemma trivIsetS P Q : P \subset Q -> trivIset Q -> trivIset P. Proof. by move/subsetP/sub_in2=> sPQ /trivIsetP/sPQ/trivIsetP. Qed. Lemma trivIsetI P D : trivIset P -> trivIset (P ::&: D). Proof. by apply: trivIsetS; rewrite -setI_powerset subsetIl. Qed. Lemma cover_setI P D : cover (P ::&: D) \subset cover P :&: D. Proof. by apply/bigcupsP=> A /setIdP[PA sAD]; rewrite subsetI sAD andbT (bigcup_max A). Qed. Lemma mem_pblock P x : (x \in pblock P x) = (x \in cover P). Proof. rewrite /pblock; apply/esym/bigcupP. case: pickP => /= [A /andP[PA Ax]| noA]; first by rewrite Ax; exists A. by rewrite inE => [[A PA Ax]]; case/andP: (noA A). Qed. Lemma pblock_mem P x : x \in cover P -> pblock P x \in P. Proof. by rewrite -mem_pblock /pblock; case: pickP => [A /andP[]| _] //=; rewrite inE. Qed. Lemma def_pblock P B x : trivIset P -> B \in P -> x \in B -> pblock P x = B. Proof. move/trivIsetP=> tiP PB Bx; have Px: x \in cover P by apply/bigcupP; exists B. apply: (contraNeq (tiP _ _ _ PB)); first by rewrite pblock_mem. by apply/pred0Pn; exists x; rewrite /= mem_pblock Px. Qed. Lemma same_pblock P x y : trivIset P -> x \in pblock P y -> pblock P x = pblock P y. Proof. rewrite {1 3}/pblock => tI; case: pickP => [A|]; last by rewrite inE. by case/andP=> PA _{y} /= Ax; exact: def_pblock. Qed. Lemma eq_pblock P x y : trivIset P -> x \in cover P -> (pblock P x == pblock P y) = (y \in pblock P x). Proof. move=> tiP Px; apply/eqP/idP=> [eq_xy | /same_pblock-> //]. move: Px; rewrite -mem_pblock eq_xy /pblock. by case: pickP => [B /andP[] // | _]; rewrite inE. Qed. Lemma trivIsetU1 A P : {in P, forall B, [disjoint A & B]} -> trivIset P -> set0 \notin P -> trivIset (A |: P) /\ A \notin P. Proof. move=> tiAP tiP notPset0; split; last first. apply: contra notPset0 => P_A. by have:= tiAP A P_A; rewrite -setI_eq0 setIid => /eqP <-. apply/trivIsetP=> B1 B2 /setU1P[->|PB1] /setU1P[->|PB2]; by [exact: (trivIsetP _ tiP) | rewrite ?eqxx // ?(tiAP, disjoint_sym)]. Qed. Lemma cover_imset J F : cover (F @: J) = \bigcup_(i in J) F i. Proof. apply/setP=> x. apply/bigcupP/bigcupP=> [[_ /imsetP[i Ji ->]] | [i]]; first by exists i. by exists (F i); first exact: mem_imset. Qed. Lemma trivIimset J F (P := F @: J) : {in J &, forall i j, j != i -> [disjoint F i & F j]} -> set0 \notin P -> trivIset P /\ {in J &, injective F}. Proof. move=> tiF notPset0; split=> [|i j Ji Jj /= eqFij]. apply/trivIsetP=> _ _ /imsetP[i Ji ->] /imsetP[j Jj ->] neqFij. by rewrite tiF // (contraNneq _ neqFij) // => ->. apply: contraNeq notPset0 => neq_ij; apply/imsetP; exists i => //; apply/eqP. by rewrite eq_sym -[F i]setIid setI_eq0 {1}eqFij tiF. Qed. Lemma cover_partition P D : partition P D -> cover P = D. Proof. by case/and3P=> /eqP. Qed. Lemma card_partition P D : partition P D -> #|D| = \sum_(A in P) #|A|. Proof. by case/and3P=> /eqP <- /eqnP. Qed. Lemma card_uniform_partition n P D : {in P, forall A, #|A| = n} -> partition P D -> #|D| = #|P| * n. Proof. by move=> uniP /card_partition->; rewrite -sum_nat_const; exact: eq_bigr. Qed. Section BigOps. Variables (R : Type) (idx : R) (op : Monoid.com_law idx). Let rhs_cond P K E := \big[op/idx]_(A in P) \big[op/idx]_(x in A | K x) E x. Let rhs P E := \big[op/idx]_(A in P) \big[op/idx]_(x in A) E x. Lemma big_trivIset_cond P (K : pred T) (E : T -> R) : trivIset P -> \big[op/idx]_(x in cover P | K x) E x = rhs_cond P K E. Proof. move=> tiP; rewrite (partition_big (pblock P) (mem P)) -/op => /= [|x]. apply: eq_bigr => A PA; apply: eq_bigl => x; rewrite andbAC; congr (_ && _). rewrite -mem_pblock; apply/andP/idP=> [[Px /eqP <- //] | Ax]. by rewrite (def_pblock tiP PA Ax). by case/andP=> Px _; exact: pblock_mem. Qed. Lemma big_trivIset P (E : T -> R) : trivIset P -> \big[op/idx]_(x in cover P) E x = rhs P E. Proof. have biginT := eq_bigl _ _ (fun _ => andbT _) => tiP. by rewrite -biginT big_trivIset_cond //; apply: eq_bigr => A _; exact: biginT. Qed. Lemma set_partition_big_cond P D (K : pred T) (E : T -> R) : partition P D -> \big[op/idx]_(x in D | K x) E x = rhs_cond P K E. Proof. by case/and3P=> /eqP <- tI_P _; exact: big_trivIset_cond. Qed. Lemma set_partition_big P D (E : T -> R) : partition P D -> \big[op/idx]_(x in D) E x = rhs P E. Proof. by case/and3P=> /eqP <- tI_P _; exact: big_trivIset. Qed. Lemma partition_disjoint_bigcup (F : I -> {set T}) E : (forall i j, i != j -> [disjoint F i & F j]) -> \big[op/idx]_(x in \bigcup_i F i) E x = \big[op/idx]_i \big[op/idx]_(x in F i) E x. Proof. move=> disjF; pose P := [set F i | i in I & F i != set0]. have trivP: trivIset P. apply/trivIsetP=> _ _ /imsetP[i _ ->] /imsetP[j _ ->] neqFij. by apply: disjF; apply: contraNneq neqFij => ->. have ->: \bigcup_i F i = cover P. apply/esym; rewrite cover_imset big_mkcond; apply: eq_bigr => i _. by rewrite inE; case: eqP. rewrite big_trivIset // /rhs big_imset => [|i j _ /setIdP[_ notFj0] eqFij]. rewrite big_mkcond; apply: eq_bigr => i _; rewrite inE. by case: eqP => //= ->; rewrite big_set0. by apply: contraNeq (disjF _ _) _; rewrite -setI_eq0 eqFij setIid. Qed. End BigOps. Section Equivalence. Variables (R : rel T) (D : {set T}). Let Px x := [set y in D | R x y]. Definition equivalence_partition := [set Px x | x in D]. Local Notation P := equivalence_partition. Hypothesis eqiR : {in D & &, equivalence_rel R}. Let Pxx x : x \in D -> x \in Px x. Proof. by move=> Dx; rewrite !inE Dx (eqiR Dx Dx). Qed. Let PPx x : x \in D -> Px x \in P := fun Dx => mem_imset _ Dx. Lemma equivalence_partitionP : partition P D. Proof. have defD: cover P == D. rewrite eqEsubset; apply/andP; split. by apply/bigcupsP=> _ /imsetP[x Dx ->]; rewrite /Px setIdE subsetIl. by apply/subsetP=> x Dx; apply/bigcupP; exists (Px x); rewrite (Pxx, PPx). have tiP: trivIset P. apply/trivIsetP=> _ _ /imsetP[x Dx ->] /imsetP[y Dy ->]; apply: contraR. case/pred0Pn=> z /andP[]; rewrite !inE => /andP[Dz Rxz] /andP[_ Ryz]. apply/eqP/setP=> t; rewrite !inE; apply: andb_id2l => Dt. by rewrite (eqiR Dx Dz Dt) // (eqiR Dy Dz Dt). rewrite /partition tiP defD /=. by apply/imsetP=> [[x /Pxx Px_x Px0]]; rewrite -Px0 inE in Px_x. Qed. Lemma pblock_equivalence_partition : {in D &, forall x y, (y \in pblock P x) = R x y}. Proof. have [_ tiP _] := and3P equivalence_partitionP. by move=> x y Dx Dy; rewrite /= (def_pblock tiP (PPx Dx) (Pxx Dx)) inE Dy. Qed. End Equivalence. Lemma pblock_equivalence P D : partition P D -> {in D & &, equivalence_rel (fun x y => y \in pblock P x)}. Proof. case/and3P=> /eqP <- tiP _ x y z Px Py Pz. by rewrite mem_pblock; split=> // /same_pblock->. Qed. Lemma equivalence_partition_pblock P D : partition P D -> equivalence_partition (fun x y => y \in pblock P x) D = P. Proof. case/and3P=> /eqP <-{D} tiP notP0; apply/setP=> B /=; set D := cover P. have defP x: x \in D -> [set y in D | y \in pblock P x] = pblock P x. by move=> Dx; apply/setIidPr; rewrite (bigcup_max (pblock P x)) ?pblock_mem. apply/imsetP/idP=> [[x Px ->{B}] | PB]; first by rewrite defP ?pblock_mem. have /set0Pn[x Bx]: B != set0 := memPn notP0 B PB. have Px: x \in cover P by apply/bigcupP; exists B. by exists x; rewrite // defP // (def_pblock tiP PB Bx). Qed. Section Preim. Variables (rT : eqType) (f : T -> rT). Definition preim_partition := equivalence_partition (fun x y => f x == f y). Lemma preim_partitionP D : partition (preim_partition D) D. Proof. by apply/equivalence_partitionP; split=> // /eqP->. Qed. End Preim. Lemma preim_partition_pblock P D : partition P D -> preim_partition (pblock P) D = P. Proof. move=> partP; have [/eqP defD tiP _] := and3P partP. rewrite -{2}(equivalence_partition_pblock partP); apply: eq_in_imset => x Dx. by apply/setP=> y; rewrite !inE eq_pblock ?defD. Qed. Lemma transversalP P D : partition P D -> is_transversal (transversal P D) P D. Proof. case/and3P=> /eqP <- tiP notP0; apply/and3P; split; first exact/and3P. apply/subsetP=> _ /imsetP[x Px ->]; case: pickP => //= y Pxy. by apply/bigcupP; exists (pblock P x); rewrite ?pblock_mem //. apply/forall_inP=> B PB; have /set0Pn[x Bx]: B != set0 := memPn notP0 B PB. apply/cards1P; exists (odflt x [pick y in pblock P x]); apply/esym/eqP. rewrite eqEsubset sub1set inE -andbA; apply/andP; split. by apply/mem_imset/bigcupP; exists B. rewrite (def_pblock tiP PB Bx); case def_y: _ / pickP => [y By | /(_ x)/idP//]. rewrite By /=; apply/subsetP=> _ /setIP[/imsetP[z Pz ->]]. case: {1}_ / pickP => [t zPt Bt | /(_ z)/idP[]]; last by rewrite mem_pblock. by rewrite -(same_pblock tiP zPt) (def_pblock tiP PB Bt) def_y set11. Qed. Section Transversals. Variables (X : {set T}) (P : {set {set T}}) (D : {set T}). Hypothesis trPX : is_transversal X P D. Lemma transversal_sub : X \subset D. Proof. by case/and3P: trPX. Qed. Let tiP : trivIset P. Proof. by case/andP: trPX => /and3P[]. Qed. Let sXP : {subset X <= cover P}. Proof. by case/and3P: trPX => /andP[/eqP-> _] /subsetP. Qed. Let trX : {in P, forall B, #|X :&: B| == 1}. Proof. by case/and3P: trPX => _ _ /forall_inP. Qed. Lemma setI_transversal_pblock x0 B : B \in P -> X :&: B = [set transversal_repr x0 X B]. Proof. by case/trX/cards1P=> x defXB; rewrite /transversal_repr defXB /pick enum_set1. Qed. Lemma repr_mem_pblock x0 B : B \in P -> transversal_repr x0 X B \in B. Proof. by move=> PB; rewrite -sub1set -setI_transversal_pblock ?subsetIr. Qed. Lemma repr_mem_transversal x0 B : B \in P -> transversal_repr x0 X B \in X. Proof. by move=> PB; rewrite -sub1set -setI_transversal_pblock ?subsetIl. Qed. Lemma transversal_reprK x0 : {in P, cancel (transversal_repr x0 X) (pblock P)}. Proof. by move=> B PB; rewrite /= (def_pblock tiP PB) ?repr_mem_pblock. Qed. Lemma pblockK x0 : {in X, cancel (pblock P) (transversal_repr x0 X)}. Proof. move=> x Xx; have /bigcupP[B PB Bx] := sXP Xx; rewrite (def_pblock tiP PB Bx). by apply/esym/set1P; rewrite -setI_transversal_pblock // inE Xx. Qed. Lemma pblock_inj : {in X &, injective (pblock P)}. Proof. by move=> x0; exact: (can_in_inj (pblockK x0)). Qed. Lemma pblock_transversal : pblock P @: X = P. Proof. apply/setP=> B; apply/imsetP/idP=> [[x Xx ->] | PB]. by rewrite pblock_mem ?sXP. have /cards1P[x0 _] := trX PB; set x := transversal_repr x0 X B. by exists x; rewrite ?transversal_reprK ?repr_mem_transversal. Qed. Lemma card_transversal : #|X| = #|P|. Proof. rewrite -pblock_transversal card_in_imset //; exact: pblock_inj. Qed. Lemma im_transversal_repr x0 : transversal_repr x0 X @: P = X. Proof. rewrite -{2}[X]imset_id -pblock_transversal -imset_comp. by apply: eq_in_imset; exact: pblockK. Qed. End Transversals. End Partitions. Implicit Arguments trivIsetP [T P]. Implicit Arguments big_trivIset_cond [T R idx op K E]. Implicit Arguments set_partition_big_cond [T R idx op D K E]. Implicit Arguments big_trivIset [T R idx op E]. Implicit Arguments set_partition_big [T R idx op D E]. Prenex Implicits cover trivIset partition pblock trivIsetP. Lemma partition_partition (T : finType) (D : {set T}) P Q : partition P D -> partition Q P -> partition (cover @: Q) D /\ {in Q &, injective cover}. Proof. move=> /and3P[/eqP defG tiP notP0] /and3P[/eqP defP tiQ notQ0]. have sQP E: E \in Q -> {subset E <= P}. by move=> Q_E; apply/subsetP; rewrite -defP (bigcup_max E). rewrite /partition cover_imset -(big_trivIset _ tiQ) defP -defG eqxx /= andbC. have{notQ0} notQ0: set0 \notin cover @: Q. apply: contra notP0 => /imsetP[E Q_E E0]. have /set0Pn[/= A E_A] := memPn notQ0 E Q_E. congr (_ \in P): (sQP E Q_E A E_A). by apply/eqP; rewrite -subset0 E0 (bigcup_max A). rewrite notQ0; apply: trivIimset => // E F Q_E Q_F. apply: contraR => /pred0Pn[x /andP[/bigcupP[A E_A Ax] /bigcupP[B F_B Bx]]]. rewrite -(def_pblock tiQ Q_E E_A) -(def_pblock tiP _ Ax) ?(sQP E) //. by rewrite -(def_pblock tiQ Q_F F_B) -(def_pblock tiP _ Bx) ?(sQP F). Qed. (**********************************************************************) (* *) (* Maximum and minimun (sub)set with respect to a given pred *) (* *) (**********************************************************************) Section MaxSetMinSet. Variable T : finType. Notation sT := {set T}. Implicit Types A B C : sT. Implicit Type P : pred sT. Definition minset P A := [forall (B : sT | B \subset A), (B == A) == P B]. Lemma minset_eq P1 P2 A : P1 =1 P2 -> minset P1 A = minset P2 A. Proof. by move=> eP12; apply: eq_forallb => B; rewrite eP12. Qed. Lemma minsetP P A : reflect ((P A) /\ (forall B, P B -> B \subset A -> B = A)) (minset P A). Proof. apply: (iffP forallP) => [minA | [PA minA] B]. split; first by have:= minA A; rewrite subxx eqxx /= => /eqP. by move=> B PB sBA; have:= minA B; rewrite PB sBA /= eqb_id => /eqP. by apply/implyP=> sBA; apply/eqP; apply/eqP/idP=> [-> // | /minA]; exact. Qed. Implicit Arguments minsetP [P A]. Lemma minsetp P A : minset P A -> P A. Proof. by case/minsetP. Qed. Lemma minsetinf P A B : minset P A -> P B -> B \subset A -> B = A. Proof. by case/minsetP=> _; exact. Qed. Lemma ex_minset P : (exists A, P A) -> {A | minset P A}. Proof. move=> exP; pose pS n := [pred B | P B & #|B| == n]. pose p n := ~~ pred0b (pS n); have{exP}: exists n, p n. by case: exP => A PA; exists #|A|; apply/existsP; exists A; rewrite /= PA /=. case/ex_minnP=> n /pred0P; case: (pickP (pS n)) => // A /andP[PA] /eqP <-{n} _. move=> minA; exists A => //; apply/minsetP; split=> // B PB sBA; apply/eqP. by rewrite eqEcard sBA minA //; apply/pred0Pn; exists B; rewrite /= PB /=. Qed. Lemma minset_exists P C : P C -> {A | minset P A & A \subset C}. Proof. move=> PC; have{PC}: exists A, P A && (A \subset C) by exists C; rewrite PC /=. case/ex_minset=> A /minsetP[/andP[PA sAC] minA]; exists A => //; apply/minsetP. by split=> // B PB sBA; rewrite (minA B) // PB (subset_trans sBA). Qed. (* The 'locked_with' allows Coq to find the value of P by unification. *) Fact maxset_key : unit. Proof. by []. Qed. Definition maxset P A := minset (fun B => locked_with maxset_key P (~: B)) (~: A). Lemma maxset_eq P1 P2 A : P1 =1 P2 -> maxset P1 A = maxset P2 A. Proof. by move=> eP12; apply: minset_eq => x /=; rewrite !unlock_with eP12. Qed. Lemma maxminset P A : maxset P A = minset [pred B | P (~: B)] (~: A). Proof. by rewrite /maxset unlock. Qed. Lemma minmaxset P A : minset P A = maxset [pred B | P (~: B)] (~: A). Proof. by rewrite /maxset unlock setCK; apply: minset_eq => B /=; rewrite setCK. Qed. Lemma maxsetP P A : reflect ((P A) /\ (forall B, P B -> A \subset B -> B = A)) (maxset P A). Proof. apply: (iffP minsetP); rewrite ?setCK unlock_with => [] [PA minA]. by split=> // B PB sAB; rewrite -[B]setCK [~: B]minA (setCK, setCS). by split=> // B PB' sBA'; rewrite -(minA _ PB') -1?setCS setCK. Qed. Lemma maxsetp P A : maxset P A -> P A. Proof. by case/maxsetP. Qed. Lemma maxsetsup P A B : maxset P A -> P B -> A \subset B -> B = A. Proof. by case/maxsetP=> _; exact. Qed. Lemma ex_maxset P : (exists A, P A) -> {A | maxset P A}. Proof. move=> exP; have{exP}: exists A, P (~: A). by case: exP => A PA; exists (~: A); rewrite setCK. by case/ex_minset=> A minA; exists (~: A); rewrite /maxset unlock setCK. Qed. Lemma maxset_exists P C : P C -> {A : sT | maxset P A & C \subset A}. Proof. move=> PC; pose P' B := P (~: B); have: P' (~: C) by rewrite /P' setCK. case/minset_exists=> B; rewrite -[B]setCK setCS. by exists (~: B); rewrite // /maxset unlock. Qed. End MaxSetMinSet. Implicit Arguments minsetP [T P A]. Implicit Arguments maxsetP [T P A]. Prenex Implicits minset maxset minsetP maxsetP. mathcomp-1.5/theories/action.v0000644000175000017500000030574512307636117015465 0ustar garesgares(* (c) Copyright Microsoft Corporation and Inria. *) (* You may distribute this file under the terms of the CeCILL-B license *) Require Import ssreflect ssrbool ssrfun eqtype ssrnat div seq fintype. Require Import bigop finset fingroup morphism perm automorphism quotient. (******************************************************************************) (* Group action: orbits, stabilisers, transitivity. *) (* is_action D to == the function to : T -> aT -> T defines an action *) (* of D : {set aT} on T. *) (* action D T == structure for a function defining an action of D. *) (* act_dom to == the domain D of to : action D rT. *) (* {action: aT &-> T} == structure for a total action. *) (* := action [set: aT] T *) (* TotalAction to1 toM == the constructor for total actions; to1 and toM *) (* are the proofs of the action identities for 1 and *) (* a * b, respectively. *) (* is_groupAction R to == to is a group action on range R: for all a in D, *) (* the permutation induced by to a is in Aut R. Thus *) (* the action of D must be trivial outside R. *) (* groupAction D R == the structure for group actions of D on R. This *) (* is a telescope on action D rT. *) (* gact_range to == the range R of to : groupAction D R. *) (* GroupAction toAut == construct a groupAction for action to from *) (* toAut : actm to @* D \subset Aut R (actm to is *) (* the morphism to {perm rT} associated to 'to'). *) (* orbit to A x == the orbit of x under the action of A via to. *) (* orbit_transversal to A S == a transversal of the partition orbit to A @: S *) (* of S, provided A acts on S via to. *) (* amove to A x y == the set of a in A whose action send x to y. *) (* 'C_A[x | to] == the stabiliser of x : rT in A :&: D. *) (* 'C_A(S | to) == the point-wise stabiliser of S : {set rT} in D :&: A. *) (* 'N_A(S | to) == the global stabiliser of S : {set rT} in D :&: A. *) (* 'Fix_(S | to)[a] == the set of fixpoints of a in S. *) (* 'Fix_(S | to)(A) == the set of fixpoints of A in S. *) (* In the first three _A can be omitted and defaults to the domain D of to; *) (* In the last two S can be omitted and defaults to [set: T], so 'Fix_to[a] *) (* is the set of all fixpoints of a. *) (* The domain restriction ensures that stabilisers have a canonical group *) (* structure, but note that 'Fix sets are generally not groups. Indeed, we *) (* provide alternative definitions when to is a group action on R: *) (* 'C_(G | to)(A) == the centraliser in R :&: G of the group action of *) (* D :&: A via to *) (* 'C_(G | to)[a] == the centraliser in R :&: G of a \in D, via to. *) (* These sets are groups when G is. G can be omitted: 'C(|to)(A) is the *) (* centraliser in R of the action of D :&: A via to. *) (* [acts A, on S | to] == A \subset D acts on the set S via to. *) (* {acts A, on S | to} == A acts on the set S (Prop statement). *) (* {acts A, on group G | to} == [acts A, on S | to] /\ G \subset R, i.e., *) (* A \subset D acts on G \subset R, via *) (* to : groupAction D R. *) (* [transitive A, on S | to] == A acts transitively on S. *) (* [faithful A, on S | to] == A acts faithfully on S. *) (* acts_irreducibly to A G == A acts irreducibly via the groupAction to *) (* on the nontrivial group G, i.e., A does *) (* not act on any nontrivial subgroup of G. *) (* Important caveat: the definitions of orbit, amove, 'Fix_(S | to)(A), *) (* transitive and faithful assume that A is a subset of the domain D. As most *) (* of the permutation actions we consider are total this is usually harmless. *) (* (Note that the theory of partial actions is only partially developed.) *) (* In all of the above, to is expected to be the actual action structure, *) (* not merely the function. There is a special scope %act for actions, and *) (* constructions and notations for many classical actions: *) (* 'P == natural action of a permutation group via aperm. *) (* 'J == internal group action (conjugation) via conjg (_ ^ _). *) (* 'R == regular group action (right translation) via mulg (_ * _). *) (* (but, to limit ambiguity, _ * _ is NOT a canonical action) *) (* to^* == the action induced by to on {set rT} via to^* (== setact to). *) (* 'Js == the internal action on subsets via _ :^ _, equivalent to 'J^*. *) (* 'Rs == the regular action on subsets via rcoset, equivalent to 'R^*. *) (* 'JG == the conjugation action on {group rT} via (_ :^ _)%G. *) (* to / H == the action induced by to on coset_of H via qact to H, and *) (* restricted to qact_dom to H == 'N(rcosets H 'N(H) | to^* ). *) (* 'Q == the action induced to cosets by conjugation; the domain is *) (* qact_dom 'J H, which is provably equal to 'N(H). *) (* to %% A == the action of coset_of A via modact to A, with domain D / A *) (* and support restricted to 'C(D :&: A | to). *) (* to \ sAD == the action of A via ract to sAD == to, if sAD : A \subset D. *) (* [Aut G] == the permutation action restricted to Aut G, via autact G. *) (* <[nRA]> == the action of A on R via actby nRA == to in A and on R, and *) (* the trivial action elsewhere; here nRA : [acts A, on R | to] *) (* or nRA : {acts A, on group R | to}. *) (* to^? == the action induced by to on sT : @subType rT P, via subact to *) (* with domain subact_dom P to == 'N([set x | P x] | to). *) (* <> == the action of phi : D >-> {perm rT}, via mact phi. *) (* to \o f == the composite action (with domain f @*^-1 D) of the action to *) (* with f : {morphism G >-> aT}, via comp_act to f. Here f must *) (* be the actual morphism object (e.g., coset_morphism H), not *) (* the underlying function (e.g., coset H). *) (* The explicit application of an action to is usually written (to%act x a), *) (* where the %act omitted if to is an abstract action or a set action to0^*. *) (* Note that this form will simplify and expose the acting function. *) (* There is a %gact scope for group actions; the notations above are *) (* recognised in %gact when they denote canonical group actions. *) (* Actions can be used to define morphisms: *) (* actperm to == the morphism D >-> {perm rT} induced by to. *) (* actm to a == if a \in D the function on D induced by the action to, else *) (* the identity function. If to is a group action with range R *) (* then actm to a is canonically a morphism on R. *) (* We also define here the restriction operation on permutations (the domain *) (* of this operations is a stabiliser), and local automorphpism groups: *) (* restr_perm S p == if p acts on S, the permutation with support in S that *) (* coincides with p on S; else the identity. Note that *) (* restr_perm is a permutation group morphism that maps *) (* Aut G to Aut S when S is a subgroup of G. *) (* Aut_in A G == the local permutation group 'N_A(G | 'P) / 'C_A(G | 'P) *) (* Usually A is an automorphism group, and then Aut_in A G *) (* is isomorphic to a subgroup of Aut G, specifically *) (* restr_perm @* A. *) (* Finally, gproduct.v will provide a semi-direct group construction that *) (* maps an external group action to an internal one; the theory of morphisms *) (* between such products makes use of the following definition: *) (* morph_act to to' f fA <=> the action of to' on the images of f and fA is *) (* the image of the action of to, i.e., for all x and a we *) (* have f (to x a) = to' (f x) (fA a). Note that there is *) (* no mention of the domains of to and to'; if needed, this *) (* predicate should be restricted via the {in ...} notation *) (* and domain conditions should be added. *) (******************************************************************************) Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Import GroupScope. Section ActionDef. Variables (aT : finGroupType) (D : {set aT}) (rT : Type). Implicit Types a b : aT. Implicit Type x : rT. Definition act_morph to x := forall a b, to x (a * b) = to (to x a) b. Definition is_action to := left_injective to /\ forall x, {in D &, act_morph to x}. Record action := Action {act :> rT -> aT -> rT; _ : is_action act}. Definition clone_action to := let: Action _ toP := to return {type of Action for to} -> action in fun k => k toP. End ActionDef. (* Need to close the Section here to avoid re-declaring all Argument Scopes *) Delimit Scope action_scope with act. Bind Scope action_scope with action. Arguments Scope act_morph [_ group_scope _ _ group_scope]. Arguments Scope is_action [_ group_scope _ _]. Arguments Scope act [_ group_scope type_scope action_scope group_scope group_scope]. Arguments Scope clone_action [_ group_scope type_scope action_scope _]. Notation "{ 'action' aT &-> T }" := (action [set: aT] T) (at level 0, format "{ 'action' aT &-> T }") : type_scope. Notation "[ 'action' 'of' to ]" := (clone_action (@Action _ _ _ to)) (at level 0, format "[ 'action' 'of' to ]") : form_scope. Definition act_dom aT D rT of @action aT D rT := D. Section TotalAction. Variables (aT : finGroupType) (rT : Type) (to : rT -> aT -> rT). Hypotheses (to1 : to^~ 1 =1 id) (toM : forall x, act_morph to x). Lemma is_total_action : is_action setT to. Proof. split=> [a | x a b _ _] /=; last by rewrite toM. by apply: can_inj (to^~ a^-1) _ => x; rewrite -toM ?mulgV. Qed. Definition TotalAction := Action is_total_action. End TotalAction. Section ActionDefs. Variables (aT aT' : finGroupType) (D : {set aT}) (D' : {set aT'}). Definition morph_act rT rT' (to : action D rT) (to' : action D' rT') f fA := forall x a, f (to x a) = to' (f x) (fA a). Variable rT : finType. (* Most definitions require a finType structure on rT *) Implicit Type to : action D rT. Implicit Type A : {set aT}. Implicit Type S : {set rT}. Definition actm to a := if a \in D then to^~ a else id. Definition setact to S a := [set to x a | x in S]. Definition orbit to A x := to x @: A. Definition amove to A x y := [set a in A | to x a == y]. Definition afix to A := [set x | A \subset [set a | to x a == x]]. Definition astab S to := D :&: [set a | S \subset [set x | to x a == x]]. Definition astabs S to := D :&: [set a | S \subset to^~ a @^-1: S]. Definition acts_on A S to := {in A, forall a x, (to x a \in S) = (x \in S)}. Definition atrans A S to := S \in orbit to A @: S. Definition faithful A S to := A :&: astab S to \subset [1]. End ActionDefs. Arguments Scope setact [_ group_scope _ action_scope group_scope group_scope]. Arguments Scope orbit [_ group_scope _ action_scope group_scope group_scope]. Arguments Scope amove [_ group_scope _ action_scope group_scope group_scope group_scope]. Arguments Scope afix [_ group_scope _ action_scope group_scope]. Arguments Scope astab [_ group_scope _ group_scope action_scope]. Arguments Scope astabs [_ group_scope _ group_scope action_scope]. Arguments Scope acts_on [_ group_scope _ group_scope group_scope action_scope]. Arguments Scope atrans [_ group_scope _ group_scope group_scope action_scope]. Arguments Scope faithful [_ group_scope _ group_scope group_scope action_scope]. Notation "to ^*" := (setact to) (at level 2, format "to ^*") : fun_scope. Prenex Implicits orbit amove. Notation "''Fix_' to ( A )" := (afix to A) (at level 8, to at level 2, format "''Fix_' to ( A )") : group_scope. (* camlp4 grammar factoring *) Notation "''Fix_' ( to ) ( A )" := 'Fix_to(A) (at level 8, only parsing) : group_scope. Notation "''Fix_' ( S | to ) ( A )" := (S :&: 'Fix_to(A)) (at level 8, format "''Fix_' ( S | to ) ( A )") : group_scope. Notation "''Fix_' to [ a ]" := ('Fix_to([set a])) (at level 8, to at level 2, format "''Fix_' to [ a ]") : group_scope. Notation "''Fix_' ( S | to ) [ a ]" := (S :&: 'Fix_to[a]) (at level 8, format "''Fix_' ( S | to ) [ a ]") : group_scope. Notation "''C' ( S | to )" := (astab S to) (at level 8, format "''C' ( S | to )") : group_scope. Notation "''C_' A ( S | to )" := (A :&: 'C(S | to)) (at level 8, A at level 2, format "''C_' A ( S | to )") : group_scope. Notation "''C_' ( A ) ( S | to )" := 'C_A(S | to) (at level 8, only parsing) : group_scope. Notation "''C' [ x | to ]" := ('C([set x] | to)) (at level 8, format "''C' [ x | to ]") : group_scope. Notation "''C_' A [ x | to ]" := (A :&: 'C[x | to]) (at level 8, A at level 2, format "''C_' A [ x | to ]") : group_scope. Notation "''C_' ( A ) [ x | to ]" := 'C_A[x | to] (at level 8, only parsing) : group_scope. Notation "''N' ( S | to )" := (astabs S to) (at level 8, format "''N' ( S | to )") : group_scope. Notation "''N_' A ( S | to )" := (A :&: 'N(S | to)) (at level 8, A at level 2, format "''N_' A ( S | to )") : group_scope. Notation "[ 'acts' A , 'on' S | to ]" := (A \subset pred_of_set 'N(S | to)) (at level 0, format "[ 'acts' A , 'on' S | to ]") : form_scope. Notation "{ 'acts' A , 'on' S | to }" := (acts_on A S to) (at level 0, format "{ 'acts' A , 'on' S | to }") : form_scope. Notation "[ 'transitive' A , 'on' S | to ]" := (atrans A S to) (at level 0, format "[ 'transitive' A , 'on' S | to ]") : form_scope. Notation "[ 'faithful' A , 'on' S | to ]" := (faithful A S to) (at level 0, format "[ 'faithful' A , 'on' S | to ]") : form_scope. Section RawAction. (* Lemmas that do not require the group structure on the action domain. *) (* Some lemmas like actMin would be actually be valid for arbitrary rT, *) (* e.g., for actions on a function type, but would be difficult to use *) (* as a view due to the confusion between parameters and assumptions. *) Variables (aT : finGroupType) (D : {set aT}) (rT : finType) (to : action D rT). Implicit Types (a : aT) (x y : rT) (A B : {set aT}) (S T : {set rT}). Lemma act_inj : left_injective to. Proof. by case: to => ? []. Qed. Implicit Arguments act_inj []. Lemma actMin x : {in D &, act_morph to x}. Proof. by case: to => ? []. Qed. Lemma actmEfun a : a \in D -> actm to a = to^~ a. Proof. by rewrite /actm => ->. Qed. Lemma actmE a : a \in D -> actm to a =1 to^~ a. Proof. by move=> Da; rewrite actmEfun. Qed. Lemma setactE S a : to^* S a = [set to x a | x in S]. Proof. by []. Qed. Lemma mem_setact S a x : x \in S -> to x a \in to^* S a. Proof. exact: mem_imset. Qed. Lemma card_setact S a : #|to^* S a| = #|S|. Proof. by apply: card_imset; exact: act_inj. Qed. Lemma setact_is_action : is_action D to^*. Proof. split=> [a R S eqRS | a b Da Db S]; last first. rewrite /setact /= -imset_comp; apply: eq_imset => x; exact: actMin. apply/setP=> x; apply/idP/idP=> /(mem_setact a). by rewrite eqRS => /imsetP[y Sy /act_inj->]. by rewrite -eqRS => /imsetP[y Sy /act_inj->]. Qed. Canonical set_action := Action setact_is_action. Lemma orbitE A x : orbit to A x = to x @: A. Proof. by []. Qed. Lemma orbitP A x y : reflect (exists2 a, a \in A & to x a = y) (y \in orbit to A x). Proof. by apply: (iffP imsetP) => [] [a]; exists a. Qed. Lemma mem_orbit A x a : a \in A -> to x a \in orbit to A x. Proof. exact: mem_imset. Qed. Lemma afixP A x : reflect (forall a, a \in A -> to x a = x) (x \in 'Fix_to(A)). Proof. rewrite inE; apply: (iffP subsetP) => [xfix a /xfix | xfix a Aa]. by rewrite inE => /eqP. by rewrite inE xfix. Qed. Lemma afixS A B : A \subset B -> 'Fix_to(B) \subset 'Fix_to(A). Proof. by move=> sAB; apply/subsetP=> u; rewrite !inE; exact: subset_trans. Qed. Lemma afixU A B : 'Fix_to(A :|: B) = 'Fix_to(A) :&: 'Fix_to(B). Proof. by apply/setP=> x; rewrite !inE subUset. Qed. Lemma afix1P a x : reflect (to x a = x) (x \in 'Fix_to[a]). Proof. by rewrite inE sub1set inE; exact: eqP. Qed. Lemma astabIdom S : 'C_D(S | to) = 'C(S | to). Proof. by rewrite setIA setIid. Qed. Lemma astab_dom S : {subset 'C(S | to) <= D}. Proof. by move=> a /setIP[]. Qed. Lemma astab_act S a x : a \in 'C(S | to) -> x \in S -> to x a = x. Proof. rewrite 2!inE => /andP[_ cSa] Sx; apply/eqP. by have:= subsetP cSa x Sx; rewrite inE. Qed. Lemma astabS S1 S2 : S1 \subset S2 -> 'C(S2 | to) \subset 'C(S1 | to). Proof. move=> sS12; apply/subsetP=> x; rewrite !inE => /andP[->]. exact: subset_trans. Qed. Lemma astabsIdom S : 'N_D(S | to) = 'N(S | to). Proof. by rewrite setIA setIid. Qed. Lemma astabs_dom S : {subset 'N(S | to) <= D}. Proof. by move=> a /setIdP[]. Qed. Lemma astabs_act S a x : a \in 'N(S | to) -> (to x a \in S) = (x \in S). Proof. rewrite 2!inE subEproper properEcard => /andP[_]. rewrite (card_preimset _ (act_inj _)) ltnn andbF orbF => /eqP{2}->. by rewrite inE. Qed. Lemma astab_sub S : 'C(S | to) \subset 'N(S | to). Proof. apply/subsetP=> a cSa; rewrite !inE (astab_dom cSa). by apply/subsetP=> x Sx; rewrite inE (astab_act cSa). Qed. Lemma astabsC S : 'N(~: S | to) = 'N(S | to). Proof. apply/setP=> a; apply/idP/idP=> nSa; rewrite !inE (astabs_dom nSa). by rewrite -setCS -preimsetC; apply/subsetP=> x; rewrite inE astabs_act. by rewrite preimsetC setCS; apply/subsetP=> x; rewrite inE astabs_act. Qed. Lemma astabsI S T : 'N(S | to) :&: 'N(T | to) \subset 'N(S :&: T | to). Proof. apply/subsetP=> a; rewrite !inE -!andbA preimsetI => /and4P[-> nSa _ nTa] /=. by rewrite setISS. Qed. Lemma astabs_setact S a : a \in 'N(S | to) -> to^* S a = S. Proof. move=> nSa; apply/eqP; rewrite eqEcard card_setact leqnn andbT. by apply/subsetP=> _ /imsetP[x Sx ->]; rewrite astabs_act. Qed. Lemma astab1_set S : 'C[S | set_action] = 'N(S | to). Proof. apply/setP=> a; apply/idP/idP=> nSa. case/setIdP: nSa => Da; rewrite !inE Da sub1set inE => /eqP defS. by apply/subsetP=> x Sx; rewrite inE -defS mem_setact. by rewrite !inE (astabs_dom nSa) sub1set inE /= astabs_setact. Qed. Lemma astabs_set1 x : 'N([set x] | to) = 'C[x | to]. Proof. apply/eqP; rewrite eqEsubset astab_sub andbC setIS //. by apply/subsetP=> a; rewrite ?(inE,sub1set). Qed. Lemma acts_dom A S : [acts A, on S | to] -> A \subset D. Proof. by move=> nSA; rewrite (subset_trans nSA) ?subsetIl. Qed. Lemma acts_act A S : [acts A, on S | to] -> {acts A, on S | to}. Proof. by move=> nAS a Aa x; rewrite astabs_act ?(subsetP nAS). Qed. Lemma astabCin A S : A \subset D -> (A \subset 'C(S | to)) = (S \subset 'Fix_to(A)). Proof. move=> sAD; apply/subsetP/subsetP=> [sAC x xS | sSF a aA]. by apply/afixP=> a aA; exact: astab_act (sAC _ aA) xS. rewrite !inE (subsetP sAD _ aA); apply/subsetP=> x xS. by move/afixP/(_ _ aA): (sSF _ xS); rewrite inE => ->. Qed. Section ActsSetop. Variables (A : {set aT}) (S T : {set rT}). Hypotheses (AactS : [acts A, on S | to]) (AactT : [acts A, on T | to]). Lemma astabU : 'C(S :|: T | to) = 'C(S | to) :&: 'C(T | to). Proof. by apply/setP=> a; rewrite !inE subUset; case: (a \in D). Qed. Lemma astabsU : 'N(S | to) :&: 'N(T | to) \subset 'N(S :|: T | to). Proof. by rewrite -(astabsC S) -(astabsC T) -(astabsC (S :|: T)) setCU astabsI. Qed. Lemma astabsD : 'N(S | to) :&: 'N(T | to) \subset 'N(S :\: T| to). Proof. by rewrite setDE -(astabsC T) astabsI. Qed. Lemma actsI : [acts A, on S :&: T | to]. Proof. by apply: subset_trans (astabsI S T); rewrite subsetI AactS. Qed. Lemma actsU : [acts A, on S :|: T | to]. Proof. by apply: subset_trans astabsU; rewrite subsetI AactS. Qed. Lemma actsD : [acts A, on S :\: T | to]. Proof. by apply: subset_trans astabsD; rewrite subsetI AactS. Qed. End ActsSetop. Lemma acts_in_orbit A S x y : [acts A, on S | to] -> y \in orbit to A x -> x \in S -> y \in S. Proof. by move=> nSA/imsetP[a Aa ->{y}] Sx; rewrite (astabs_act _ (subsetP nSA a Aa)). Qed. Lemma subset_faithful A B S : B \subset A -> [faithful A, on S | to] -> [faithful B, on S | to]. Proof. by move=> sAB; apply: subset_trans; exact: setSI. Qed. Section Reindex. Variables (vT : Type) (idx : vT) (op : Monoid.com_law idx) (S : {set rT}). Lemma reindex_astabs a F : a \in 'N(S | to) -> \big[op/idx]_(i in S) F i = \big[op/idx]_(i in S) F (to i a). Proof. move=> nSa; rewrite (reindex_inj (act_inj a)); apply: eq_bigl => x. exact: astabs_act. Qed. Lemma reindex_acts A a F : [acts A, on S | to] -> a \in A -> \big[op/idx]_(i in S) F i = \big[op/idx]_(i in S) F (to i a). Proof. by move=> nSA /(subsetP nSA); exact: reindex_astabs. Qed. End Reindex. End RawAction. (* Warning: this directive depends on names of bound variables in the *) (* definition of injective, in ssrfun.v. *) Implicit Arguments act_inj [[aT] [D] [rT] x1 x2]. Notation "to ^*" := (set_action to) : action_scope. Implicit Arguments orbitP [aT D rT to A x y]. Implicit Arguments afixP [aT D rT to A x]. Implicit Arguments afix1P [aT D rT to a x]. Prenex Implicits orbitP afixP afix1P. Implicit Arguments reindex_astabs [aT D rT vT idx op S F]. Implicit Arguments reindex_acts [aT D rT vT idx op S A a F]. Section PartialAction. (* Lemmas that require a (partial) group domain. *) Variables (aT : finGroupType) (D : {group aT}) (rT : finType). Variable to : action D rT. Implicit Types a : aT. Implicit Types x y : rT. Implicit Types A B : {set aT}. Implicit Types G H : {group aT}. Implicit Types S : {set rT}. Lemma act1 x : to x 1 = x. Proof. by apply: (act_inj to 1); rewrite -actMin ?mulg1. Qed. Lemma actKin : {in D, right_loop invg to}. Proof. by move=> a Da /= x; rewrite -actMin ?groupV // mulgV act1. Qed. Lemma actKVin : {in D, rev_right_loop invg to}. Proof. by move=> a Da /= x; rewrite -{2}(invgK a) actKin ?groupV. Qed. Lemma setactVin S a : a \in D -> to^* S a^-1 = to^~ a @^-1: S. Proof. by move=> Da; apply: can2_imset_pre; [exact: actKVin | exact: actKin]. Qed. Lemma actXin x a i : a \in D -> to x (a ^+ i) = iter i (to^~ a) x. Proof. move=> Da; elim: i => /= [|i <-]; first by rewrite act1. by rewrite expgSr actMin ?groupX. Qed. Lemma afix1 : 'Fix_to(1) = setT. Proof. by apply/setP=> x; rewrite !inE sub1set inE act1 eqxx. Qed. Lemma afixD1 G : 'Fix_to(G^#) = 'Fix_to(G). Proof. by rewrite -{2}(setD1K (group1 G)) afixU afix1 setTI. Qed. Lemma orbit_refl G x : x \in orbit to G x. Proof. by rewrite -{1}[x]act1 mem_orbit. Qed. Local Notation orbit_rel A := (fun x y => y \in orbit to A x). Lemma contra_orbit G x y : x \notin orbit to G y -> x != y. Proof. by apply: contraNneq => ->; exact: orbit_refl. Qed. Lemma orbit_in_sym G : G \subset D -> symmetric (orbit_rel G). Proof. move=> sGD; apply: symmetric_from_pre => x y /imsetP[a Ga]. by move/(canLR (actKin (subsetP sGD a Ga))) <-; rewrite mem_orbit ?groupV. Qed. Lemma orbit_in_trans G : G \subset D -> transitive (orbit_rel G). Proof. move=> sGD _ x _ /imsetP[a Ga ->] /imsetP[b Gb ->]. by rewrite -actMin ?mem_orbit ?groupM // (subsetP sGD). Qed. Lemma orbit_in_transl G x y : G \subset D -> y \in orbit to G x -> orbit to G y = orbit to G x. Proof. move=> sGD Gxy; apply/setP=> z. by apply/idP/idP; apply: orbit_in_trans; rewrite // orbit_in_sym. Qed. Lemma orbit_in_transr G x y z : G \subset D -> y \in orbit to G x -> (y \in orbit to G z) = (x \in orbit to G z). Proof. by move=> sGD Gxy; rewrite !(orbit_in_sym _ z) ?(orbit_in_transl _ Gxy). Qed. Lemma orbit_act_in x a G : G \subset D -> a \in G -> orbit to G (to x a) = orbit to G x. Proof. by move=> sGD /mem_orbit/orbit_in_transl->. Qed. Lemma orbit_actr_in x a G y : G \subset D -> a \in G -> (to y a \in orbit to G x) = (y \in orbit to G x). Proof. by move=> sGD /mem_orbit/orbit_in_transr->. Qed. Lemma orbit_inv_in A x y : A \subset D -> (y \in orbit to A^-1 x) = (x \in orbit to A y). Proof. move/subsetP=> sAD; apply/imsetP/imsetP=> [] [a Aa ->]. by exists a^-1; rewrite -?mem_invg ?actKin // -groupV sAD -?mem_invg. by exists a^-1; rewrite ?memV_invg ?actKin // sAD. Qed. Lemma orbit_lcoset_in A a x : A \subset D -> a \in D -> orbit to (a *: A) x = orbit to A (to x a). Proof. move/subsetP=> sAD Da; apply/setP=> y; apply/imsetP/imsetP=> [] [b Ab ->{y}]. by exists (a^-1 * b); rewrite -?actMin ?mulKVg // ?sAD -?mem_lcoset. by exists (a * b); rewrite ?mem_mulg ?set11 ?actMin // sAD. Qed. Lemma orbit_rcoset_in A a x y : A \subset D -> a \in D -> (to y a \in orbit to (A :* a) x) = (y \in orbit to A x). Proof. move=> sAD Da; rewrite -orbit_inv_in ?mul_subG ?sub1set // invMg. by rewrite invg_set1 orbit_lcoset_in ?inv_subG ?groupV ?actKin ?orbit_inv_in. Qed. Lemma orbit_conjsg_in A a x y : A \subset D -> a \in D -> (to y a \in orbit to (A :^ a) (to x a)) = (y \in orbit to A x). Proof. move=> sAD Da; rewrite conjsgE. by rewrite orbit_lcoset_in ?groupV ?mul_subG ?sub1set ?actKin ?orbit_rcoset_in. Qed. Lemma orbit1P G x : reflect (orbit to G x = [set x]) (x \in 'Fix_to(G)). Proof. apply: (iffP afixP) => [xfix | xfix a Ga]. apply/eqP; rewrite eq_sym eqEsubset sub1set -{1}[x]act1 mem_imset //=. by apply/subsetP=> y; case/imsetP=> a Ga ->; rewrite inE xfix. by apply/set1P; rewrite -xfix mem_imset. Qed. Lemma card_orbit1 G x : #|orbit to G x| = 1%N -> orbit to G x = [set x]. Proof. move=> orb1; apply/eqP; rewrite eq_sym eqEcard {}orb1 cards1. by rewrite sub1set orbit_refl. Qed. Lemma orbit_partition G S : [acts G, on S | to] -> partition (orbit to G @: S) S. Proof. move=> actsGS; have sGD := acts_dom actsGS. have eqiG: {in S & &, equivalence_rel [rel x y | y \in orbit to G x]}. by move=> x y z * /=; rewrite orbit_refl; split=> // /orbit_in_transl->. congr (partition _ _): (equivalence_partitionP eqiG). apply: eq_in_imset => x Sx; apply/setP=> y. by rewrite inE /= andb_idl // => /acts_in_orbit->. Qed. Definition orbit_transversal A S := transversal (orbit to A @: S) S. Lemma orbit_transversalP G S (P := orbit to G @: S) (X := orbit_transversal G S) : [acts G, on S | to] -> [/\ is_transversal X P S, X \subset S, {in X &, forall x y, (y \in orbit to G x) = (x == y)} & forall x, x \in S -> exists2 a, a \in G & to x a \in X]. Proof. move/orbit_partition; rewrite -/P => partP. have [/eqP defS tiP _] := and3P partP. have trXP: is_transversal X P S := transversalP partP. have sXS: X \subset S := transversal_sub trXP. split=> // [x y Xx Xy /= | x Sx]. have Sx := subsetP sXS x Xx. rewrite -(inj_in_eq (pblock_inj trXP)) // eq_pblock ?defS //. by rewrite (def_pblock tiP (mem_imset _ Sx)) ?orbit_refl. have /imsetP[y Xy defxG]: orbit to G x \in pblock P @: X. by rewrite (pblock_transversal trXP) ?mem_imset. suffices /orbitP[a Ga def_y]: y \in orbit to G x by exists a; rewrite ?def_y. by rewrite defxG mem_pblock defS (subsetP sXS). Qed. Lemma group_set_astab S : group_set 'C(S | to). Proof. apply/group_setP; split=> [|a b cSa cSb]. by rewrite !inE group1; apply/subsetP=> x _; rewrite inE act1. rewrite !inE groupM ?(@astab_dom _ _ _ to S) //; apply/subsetP=> x Sx. by rewrite inE actMin ?(@astab_dom _ _ _ to S) ?(astab_act _ Sx). Qed. Canonical astab_group S := group (group_set_astab S). Lemma afix_gen_in A : A \subset D -> 'Fix_to(<>) = 'Fix_to(A). Proof. move=> sAD; apply/eqP; rewrite eqEsubset afixS ?sub_gen //=. by rewrite -astabCin gen_subG ?astabCin. Qed. Lemma afix_cycle_in a : a \in D -> 'Fix_to(<[a]>) = 'Fix_to[a]. Proof. by move=> Da; rewrite afix_gen_in ?sub1set. Qed. Lemma afixYin A B : A \subset D -> B \subset D -> 'Fix_to(A <*> B) = 'Fix_to(A) :&: 'Fix_to(B). Proof. by move=> sAD sBD; rewrite afix_gen_in ?afixU // subUset sAD. Qed. Lemma afixMin G H : G \subset D -> H \subset D -> 'Fix_to(G * H) = 'Fix_to(G) :&: 'Fix_to(H). Proof. by move=> sGD sHD; rewrite -afix_gen_in ?mul_subG // genM_join afixYin. Qed. Lemma sub_astab1_in A x : A \subset D -> (A \subset 'C[x | to]) = (x \in 'Fix_to(A)). Proof. by move=> sAD; rewrite astabCin ?sub1set. Qed. Lemma group_set_astabs S : group_set 'N(S | to). Proof. apply/group_setP; split=> [|a b cSa cSb]. by rewrite !inE group1; apply/subsetP=> x Sx; rewrite inE act1. rewrite !inE groupM ?(@astabs_dom _ _ _ to S) //; apply/subsetP=> x Sx. by rewrite inE actMin ?(@astabs_dom _ _ _ to S) ?astabs_act. Qed. Canonical astabs_group S := group (group_set_astabs S). Lemma astab_norm S : 'N(S | to) \subset 'N('C(S | to)). Proof. apply/subsetP=> a nSa; rewrite inE sub_conjg; apply/subsetP=> b cSb. have [Da Db] := (astabs_dom nSa, astab_dom cSb). rewrite mem_conjgV !inE groupJ //; apply/subsetP=> x Sx. rewrite inE !actMin ?groupM ?groupV //. by rewrite (astab_act cSb) ?actKVin ?astabs_act ?groupV. Qed. Lemma astab_normal S : 'C(S | to) <| 'N(S | to). Proof. by rewrite /normal astab_sub astab_norm. Qed. Lemma acts_sub_orbit G S x : [acts G, on S | to] -> (orbit to G x \subset S) = (x \in S). Proof. move/acts_act=> GactS. apply/subsetP/idP=> [| Sx y]; first by apply; exact: orbit_refl. by case/orbitP=> a Ga <-{y}; rewrite GactS. Qed. Lemma acts_orbit G x : G \subset D -> [acts G, on orbit to G x | to]. Proof. move/subsetP=> sGD; apply/subsetP=> a Ga; rewrite !inE sGD //. apply/subsetP=> _ /imsetP[b Gb ->]. by rewrite inE -actMin ?sGD // mem_imset ?groupM. Qed. Lemma acts_subnorm_fix A : [acts 'N_D(A), on 'Fix_to(D :&: A) | to]. Proof. apply/subsetP=> a nAa; have [Da _] := setIP nAa; rewrite !inE Da. apply/subsetP=> x Cx; rewrite inE; apply/afixP=> b DAb. have [Db _]:= setIP DAb; rewrite -actMin // conjgCV actMin ?groupJ ?groupV //. by rewrite /= (afixP Cx) // memJ_norm // groupV (subsetP (normsGI _ _) _ nAa). Qed. Lemma atrans_orbit G x : [transitive G, on orbit to G x | to]. Proof. by apply: mem_imset; exact: orbit_refl. Qed. Section OrbitStabilizer. Variables (G : {group aT}) (x : rT). Hypothesis sGD : G \subset D. Let ssGD := subsetP sGD. Lemma amove_act a : a \in G -> amove to G x (to x a) = 'C_G[x | to] :* a. Proof. move=> Ga; apply/setP=> b; have Da := ssGD Ga. rewrite mem_rcoset !(inE, sub1set) !groupMr ?groupV //. by case Gb: (b \in G); rewrite //= actMin ?groupV ?ssGD ?(canF_eq (actKVin Da)). Qed. Lemma amove_orbit : amove to G x @: orbit to G x = rcosets 'C_G[x | to] G. Proof. apply/setP => Ha; apply/imsetP/rcosetsP=> [[y] | [a Ga ->]]. by case/imsetP=> b Gb -> ->{Ha y}; exists b => //; rewrite amove_act. by rewrite -amove_act //; exists (to x a); first exact: mem_orbit. Qed. Lemma amoveK : {in orbit to G x, cancel (amove to G x) (fun Ca => to x (repr Ca))}. Proof. move=> _ /orbitP[a Ga <-]; rewrite amove_act //= -[G :&: _]/(gval _). case: repr_rcosetP => b; rewrite !(inE, sub1set)=> /and3P[Gb _ xbx]. by rewrite actMin ?ssGD ?(eqP xbx). Qed. Lemma orbit_stabilizer : orbit to G x = [set to x (repr Ca) | Ca in rcosets 'C_G[x | to] G]. Proof. rewrite -amove_orbit -imset_comp /=; apply/setP=> z. by apply/idP/imsetP=> [xGz | [y xGy ->]]; first exists z; rewrite /= ?amoveK. Qed. Lemma act_reprK : {in rcosets 'C_G[x | to] G, cancel (to x \o repr) (amove to G x)}. Proof. move=> _ /rcosetsP[a Ga ->] /=; rewrite amove_act ?rcoset_repr //. rewrite -[G :&: _]/(gval _); case: repr_rcosetP => b /setIP[Gb _]. exact: groupM. Qed. End OrbitStabilizer. Lemma card_orbit_in G x : G \subset D -> #|orbit to G x| = #|G : 'C_G[x | to]|. Proof. move=> sGD; rewrite orbit_stabilizer 1?card_in_imset //. exact: can_in_inj (act_reprK _). Qed. Lemma card_orbit_in_stab G x : G \subset D -> (#|orbit to G x| * #|'C_G[x | to]|)%N = #|G|. Proof. by move=> sGD; rewrite mulnC card_orbit_in ?Lagrange ?subsetIl. Qed. Lemma acts_sum_card_orbit G S : [acts G, on S | to] -> \sum_(T in orbit to G @: S) #|T| = #|S|. Proof. by move/orbit_partition/card_partition. Qed. Lemma astab_setact_in S a : a \in D -> 'C(to^* S a | to) = 'C(S | to) :^ a. Proof. move=> Da; apply/setP=> b; rewrite mem_conjg !inE -mem_conjg conjGid //. apply: andb_id2l => Db; rewrite sub_imset_pre; apply: eq_subset_r => x. by rewrite !inE !actMin ?groupM ?groupV // invgK (canF_eq (actKVin Da)). Qed. Lemma astab1_act_in x a : a \in D -> 'C[to x a | to] = 'C[x | to] :^ a. Proof. by move=> Da; rewrite -astab_setact_in // /setact imset_set1. Qed. Theorem Frobenius_Cauchy G S : [acts G, on S | to] -> \sum_(a in G) #|'Fix_(S | to)[a]| = (#|orbit to G @: S| * #|G|)%N. Proof. move=> GactS; have sGD := acts_dom GactS. transitivity (\sum_(a in G) \sum_(x in 'Fix_(S | to)[a]) 1%N). by apply: eq_bigr => a _; rewrite -sum1_card. rewrite (exchange_big_dep (mem S)) /= => [|a x _]; last by case/setIP. rewrite (set_partition_big _ (orbit_partition GactS)) -sum_nat_const /=. apply: eq_bigr => _ /imsetP[x Sx ->]. rewrite -(card_orbit_in_stab x sGD) -sum_nat_const. apply: eq_bigr => y; rewrite orbit_in_sym // => /imsetP[a Ga defx]. rewrite defx astab1_act_in ?(subsetP sGD) //. rewrite -{2}(conjGid Ga) -conjIg cardJg -sum1_card setIA (setIidPl sGD). by apply: eq_bigl => b; rewrite !(sub1set, inE) -(acts_act GactS Ga) -defx Sx. Qed. Lemma atrans_dvd_index_in G S : G \subset D -> [transitive G, on S | to] -> #|S| %| #|G : 'C_G(S | to)|. Proof. move=> sGD /imsetP[x Sx {1}->]; rewrite card_orbit_in //. by rewrite indexgS // setIS // astabS // sub1set. Qed. Lemma atrans_dvd_in G S : G \subset D -> [transitive G, on S | to] -> #|S| %| #|G|. Proof. move=> sGD transG; apply: dvdn_trans (atrans_dvd_index_in sGD transG) _. exact: dvdn_indexg. Qed. Lemma atransPin G S : G \subset D -> [transitive G, on S | to] -> forall x, x \in S -> orbit to G x = S. Proof. by move=> sGD /imsetP[y _ ->] x; exact: orbit_in_transl. Qed. Lemma atransP2in G S : G \subset D -> [transitive G, on S | to] -> {in S &, forall x y, exists2 a, a \in G & y = to x a}. Proof. by move=> sGD transG x y /(atransPin sGD transG) <- /imsetP. Qed. Lemma atrans_acts_in G S : G \subset D -> [transitive G, on S | to] -> [acts G, on S | to]. Proof. move=> sGD transG; apply/subsetP=> a Ga; rewrite !inE (subsetP sGD) //. by apply/subsetP=> x /(atransPin sGD transG) <-; rewrite inE mem_imset. Qed. Lemma subgroup_transitivePin G H S x : x \in S -> H \subset G -> G \subset D -> [transitive G, on S | to] -> reflect ('C_G[x | to] * H = G) [transitive H, on S | to]. Proof. move=> Sx sHG sGD trG; have sHD := subset_trans sHG sGD. apply: (iffP idP) => [trH | defG]. rewrite group_modr //; apply/setIidPl/subsetP=> a Ga. have Sxa: to x a \in S by rewrite (acts_act (atrans_acts_in sGD trG)). have [b Hb xab]:= atransP2in sHD trH Sxa Sx. have Da := subsetP sGD a Ga; have Db := subsetP sHD b Hb. rewrite -(mulgK b a) mem_mulg ?groupV // !inE groupM //= sub1set inE. by rewrite actMin -?xab. apply/imsetP; exists x => //; apply/setP=> y; rewrite -(atransPin sGD trG Sx). apply/imsetP/imsetP=> [] [a]; last by exists a; first exact: (subsetP sHG). rewrite -defG => /imset2P[c b /setIP[_ cxc] Hb ->] ->. exists b; rewrite ?actMin ?(astab_dom cxc) ?(subsetP sHD) //. by rewrite (astab_act cxc) ?inE. Qed. End PartialAction. Arguments Scope orbit_transversal [_ group_scope _ action_scope group_scope group_scope]. Implicit Arguments orbit1P [aT D rT to G x]. Implicit Arguments contra_orbit [aT D rT x y]. Prenex Implicits orbit1P. Notation "''C' ( S | to )" := (astab_group to S) : Group_scope. Notation "''C_' A ( S | to )" := (setI_group A 'C(S | to)) : Group_scope. Notation "''C_' ( A ) ( S | to )" := (setI_group A 'C(S | to)) (only parsing) : Group_scope. Notation "''C' [ x | to ]" := (astab_group to [set x%g]) : Group_scope. Notation "''C_' A [ x | to ]" := (setI_group A 'C[x | to]) : Group_scope. Notation "''C_' ( A ) [ x | to ]" := (setI_group A 'C[x | to]) (only parsing) : Group_scope. Notation "''N' ( S | to )" := (astabs_group to S) : Group_scope. Notation "''N_' A ( S | to )" := (setI_group A 'N(S | to)) : Group_scope. Section TotalActions. (* These lemmas are only established for total actions (domain = [set: rT]) *) Variable (aT : finGroupType) (rT : finType). Variable to : {action aT &-> rT}. Implicit Types (a b : aT) (x y z : rT) (A B : {set aT}) (G H : {group aT}). Implicit Type S : {set rT}. Lemma actM x a b : to x (a * b) = to (to x a) b. Proof. by rewrite actMin ?inE. Qed. Lemma actK : right_loop invg to. Proof. by move=> a; apply: actKin; rewrite inE. Qed. Lemma actKV : rev_right_loop invg to. Proof. by move=> a; apply: actKVin; rewrite inE. Qed. Lemma actX x a n : to x (a ^+ n) = iter n (to^~ a) x. Proof. by elim: n => [|n /= <-]; rewrite ?act1 // -actM expgSr. Qed. Lemma actCJ a b x : to (to x a) b = to (to x b) (a ^ b). Proof. by rewrite !actM actK. Qed. Lemma actCJV a b x : to (to x a) b = to (to x (b ^ a^-1)) a. Proof. by rewrite (actCJ _ a) conjgKV. Qed. Lemma orbit_sym G x y : (y \in orbit to G x) = (x \in orbit to G y). Proof. by apply: orbit_in_sym; exact: subsetT. Qed. Lemma orbit_trans G x y z : y \in orbit to G x -> z \in orbit to G y -> z \in orbit to G x. Proof. by apply: orbit_in_trans; exact: subsetT. Qed. Lemma orbit_transl G x y : y \in orbit to G x -> orbit to G y = orbit to G x. Proof. move=> Gxy; apply/setP=> z; apply/idP/idP; apply: orbit_trans => //. by rewrite orbit_sym. Qed. Lemma orbit_transr G x y z : y \in orbit to G x -> (y \in orbit to G z) = (x \in orbit to G z). Proof. by move=> Gxy; rewrite orbit_sym (orbit_transl Gxy) orbit_sym. Qed. Lemma orbit_act G a x: a \in G -> orbit to G (to x a) = orbit to G x. Proof. by move/mem_orbit/orbit_transl; exact. Qed. Lemma orbit_actr G a x y : a \in G -> (to y a \in orbit to G x) = (y \in orbit to G x). Proof. by move/mem_orbit/orbit_transr; exact. Qed. Lemma orbit_eq_mem G x y : (orbit to G x == orbit to G y) = (x \in orbit to G y). Proof. by apply/eqP/idP=> [<-|]; [exact: orbit_refl | exact: orbit_transl]. Qed. Lemma orbit_inv A x y : (y \in orbit to A^-1 x) = (x \in orbit to A y). Proof. by rewrite orbit_inv_in ?subsetT. Qed. Lemma orbit_lcoset A a x : orbit to (a *: A) x = orbit to A (to x a). Proof. by rewrite orbit_lcoset_in ?subsetT ?inE. Qed. Lemma orbit_rcoset A a x y : (to y a \in orbit to (A :* a) x) = (y \in orbit to A x). Proof. by rewrite orbit_rcoset_in ?subsetT ?inE. Qed. Lemma orbit_conjsg A a x y : (to y a \in orbit to (A :^ a) (to x a)) = (y \in orbit to A x). Proof. by rewrite orbit_conjsg_in ?subsetT ?inE. Qed. Lemma astabP S a : reflect (forall x, x \in S -> to x a = x) (a \in 'C(S | to)). Proof. apply: (iffP idP) => [cSa x|cSa]; first exact: astab_act. by rewrite !inE; apply/subsetP=> x Sx; rewrite inE cSa. Qed. Lemma astab1P x a : reflect (to x a = x) (a \in 'C[x | to]). Proof. by rewrite !inE sub1set inE; exact: eqP. Qed. Lemma sub_astab1 A x : (A \subset 'C[x | to]) = (x \in 'Fix_to(A)). Proof. by rewrite sub_astab1_in ?subsetT. Qed. Lemma astabC A S : (A \subset 'C(S | to)) = (S \subset 'Fix_to(A)). Proof. by rewrite astabCin ?subsetT. Qed. Lemma afix_cycle a : 'Fix_to(<[a]>) = 'Fix_to[a]. Proof. by rewrite afix_cycle_in ?inE. Qed. Lemma afix_gen A : 'Fix_to(<>) = 'Fix_to(A). Proof. by rewrite afix_gen_in ?subsetT. Qed. Lemma afixM G H : 'Fix_to(G * H) = 'Fix_to(G) :&: 'Fix_to(H). Proof. by rewrite afixMin ?subsetT. Qed. Lemma astabsP S a : reflect (forall x, (to x a \in S) = (x \in S)) (a \in 'N(S | to)). Proof. apply: (iffP idP) => [nSa x|nSa]; first exact: astabs_act. by rewrite !inE; apply/subsetP=> x; rewrite inE nSa. Qed. Lemma card_orbit G x : #|orbit to G x| = #|G : 'C_G[x | to]|. Proof. by rewrite card_orbit_in ?subsetT. Qed. Lemma dvdn_orbit G x : #|orbit to G x| %| #|G|. Proof. by rewrite card_orbit dvdn_indexg. Qed. Lemma card_orbit_stab G x : (#|orbit to G x| * #|'C_G[x | to]|)%N = #|G|. Proof. by rewrite mulnC card_orbit Lagrange ?subsetIl. Qed. Lemma actsP A S : reflect {acts A, on S | to} [acts A, on S | to]. Proof. apply: (iffP idP) => [nSA x|nSA]; first exact: acts_act. by apply/subsetP=> a Aa; rewrite !inE; apply/subsetP=> x; rewrite inE nSA. Qed. Implicit Arguments actsP [A S]. Lemma setact_orbit A x b : to^* (orbit to A x) b = orbit to (A :^ b) (to x b). Proof. apply/setP=> y; apply/idP/idP=> /imsetP[_ /imsetP[a Aa ->] ->{y}]. by rewrite actCJ mem_orbit ?memJ_conjg. by rewrite -actCJ mem_setact ?mem_orbit. Qed. Lemma astab_setact S a : 'C(to^* S a | to) = 'C(S | to) :^ a. Proof. apply/setP=> b; rewrite mem_conjg. apply/astabP/astabP=> stab x => [Sx|]. by rewrite conjgE invgK !actM stab ?actK //; apply/imsetP; exists x. by case/imsetP=> y Sy ->{x}; rewrite -actM conjgCV actM stab. Qed. Lemma astab1_act x a : 'C[to x a | to] = 'C[x | to] :^ a. Proof. by rewrite -astab_setact /setact imset_set1. Qed. Lemma atransP G S : [transitive G, on S | to] -> forall x, x \in S -> orbit to G x = S. Proof. by case/imsetP=> x _ -> y; exact: orbit_transl. Qed. Lemma atransP2 G S : [transitive G, on S | to] -> {in S &, forall x y, exists2 a, a \in G & y = to x a}. Proof. by move=> GtrS x y /(atransP GtrS) <- /imsetP. Qed. Lemma atrans_acts G S : [transitive G, on S | to] -> [acts G, on S | to]. Proof. move=> GtrS; apply/subsetP=> a Ga; rewrite !inE. by apply/subsetP=> x /(atransP GtrS) <-; rewrite inE mem_imset. Qed. Lemma atrans_supgroup G H S : G \subset H -> [transitive G, on S | to] -> [transitive H, on S | to] = [acts H, on S | to]. Proof. move=> sGH trG; apply/idP/idP=> [|actH]; first exact: atrans_acts. case/imsetP: trG => x Sx defS; apply/imsetP; exists x => //. by apply/eqP; rewrite eqEsubset acts_sub_orbit ?Sx // defS imsetS. Qed. Lemma atrans_acts_card G S : [transitive G, on S | to] = [acts G, on S | to] && (#|orbit to G @: S| == 1%N). Proof. apply/idP/andP=> [GtrS | [nSG]]. split; first exact: atrans_acts. rewrite ((_ @: S =P [set S]) _) ?cards1 // eqEsubset sub1set. apply/andP; split=> //; apply/subsetP=> _ /imsetP[x Sx ->]. by rewrite inE (atransP GtrS). rewrite eqn_leq andbC lt0n => /andP[/existsP[X /imsetP[x Sx X_Gx]]]. rewrite (cardD1 X) {X}X_Gx mem_imset // ltnS leqn0 => /eqP GtrS. apply/imsetP; exists x => //; apply/eqP. rewrite eqEsubset acts_sub_orbit // Sx andbT. apply/subsetP=> y Sy; have:= card0_eq GtrS (orbit to G y). rewrite !inE /= mem_imset // andbT => /eqP <-; exact: orbit_refl. Qed. Lemma atrans_dvd G S : [transitive G, on S | to] -> #|S| %| #|G|. Proof. by case/imsetP=> x _ ->; exact: dvdn_orbit. Qed. (* Aschbacher 5.2 *) Lemma acts_fix_norm A B : A \subset 'N(B) -> [acts A, on 'Fix_to(B) | to]. Proof. move=> nAB; have:= acts_subnorm_fix to B; rewrite !setTI. exact: subset_trans. Qed. Lemma faithfulP A S : reflect (forall a, a \in A -> {in S, to^~ a =1 id} -> a = 1) [faithful A, on S | to]. Proof. apply: (iffP subsetP) => [Cto1 a Aa Ca | Cto1 a]. apply/set1P; rewrite Cto1 // inE Aa; exact/astabP. case/setIP=> Aa /astabP Ca; apply/set1P; exact: Cto1. Qed. (* This is the first part of Aschbacher (5.7) *) Lemma astab_trans_gcore G S u : [transitive G, on S | to] -> u \in S -> 'C(S | to) = gcore 'C[u | to] G. Proof. move=> transG Su; apply/eqP; rewrite eqEsubset. rewrite gcore_max ?astabS ?sub1set //=; last first. exact: subset_trans (atrans_acts transG) (astab_norm _ _). apply/subsetP=> x cSx; apply/astabP=> uy. case/(atransP2 transG Su) => y Gy ->{uy}. by apply/astab1P; rewrite astab1_act (bigcapP cSx). Qed. (* Aschbacher 5.20 *) Theorem subgroup_transitiveP G H S x : x \in S -> H \subset G -> [transitive G, on S | to] -> reflect ('C_G[x | to] * H = G) [transitive H, on S | to]. Proof. by move=> Sx sHG; exact: subgroup_transitivePin (subsetT G). Qed. (* Aschbacher 5.21 *) Lemma trans_subnorm_fixP x G H S : let C := 'C_G[x | to] in let T := 'Fix_(S | to)(H) in [transitive G, on S | to] -> x \in S -> H \subset C -> reflect ((H :^: G) ::&: C = H :^: C) [transitive 'N_G(H), on T | to]. Proof. move=> C T trGS Sx sHC; have actGS := acts_act (atrans_acts trGS). have:= sHC; rewrite subsetI sub_astab1 => /andP[sHG cHx]. have Tx: x \in T by rewrite inE Sx. apply: (iffP idP) => [trN | trC]. apply/setP=> Ha; apply/setIdP/imsetP=> [[]|[a Ca ->{Ha}]]; last first. by rewrite conj_subG //; case/setIP: Ca => Ga _; rewrite mem_imset. case/imsetP=> a Ga ->{Ha}; rewrite subsetI !sub_conjg => /andP[_ sHCa]. have Txa: to x a^-1 \in T. by rewrite inE -sub_astab1 astab1_act actGS ?Sx ?groupV. have [b] := atransP2 trN Tx Txa; case/setIP=> Gb nHb cxba. exists (b * a); last by rewrite conjsgM (normP nHb). by rewrite inE groupM //; apply/astab1P; rewrite actM -cxba actKV. apply/imsetP; exists x => //; apply/setP=> y; apply/idP/idP=> [Ty|]. have [Sy cHy]:= setIP Ty; have [a Ga defy] := atransP2 trGS Sx Sy. have: H :^ a^-1 \in H :^: C. rewrite -trC inE subsetI mem_imset 1?conj_subG ?groupV // sub_conjgV. by rewrite -astab1_act -defy sub_astab1. case/imsetP=> b /setIP[Gb /astab1P cxb] defHb. rewrite defy -{1}cxb -actM mem_orbit // inE groupM //. by apply/normP; rewrite conjsgM -defHb conjsgKV. case/imsetP=> a /setIP[Ga nHa] ->{y}. by rewrite inE actGS // Sx (acts_act (acts_fix_norm _) nHa). Qed. End TotalActions. Implicit Arguments astabP [aT rT to S a]. Implicit Arguments astab1P [aT rT to x a]. Implicit Arguments astabsP [aT rT to S a]. Implicit Arguments atransP [aT rT to G S]. Implicit Arguments actsP [aT rT to A S]. Implicit Arguments faithfulP [aT rT to A S]. Prenex Implicits astabP astab1P astabsP atransP actsP faithfulP. Section Restrict. Variables (aT : finGroupType) (D : {set aT}) (rT : Type). Variables (to : action D rT) (A : {set aT}). Definition ract of A \subset D := act to. Variable sAD : A \subset D. Lemma ract_is_action : is_action A (ract sAD). Proof. rewrite /ract; case: to => f [injf fM]. split=> // x; exact: (sub_in2 (subsetP sAD)). Qed. Canonical raction := Action ract_is_action. Lemma ractE : raction =1 to. Proof. by []. Qed. (* Other properties of raction need rT : finType; we defer them *) (* until after the definition of actperm. *) End Restrict. Notation "to \ sAD" := (raction to sAD) (at level 50) : action_scope. Section ActBy. Variables (aT : finGroupType) (D : {set aT}) (rT : finType). Definition actby_cond (A : {set aT}) R (to : action D rT) : Prop := [acts A, on R | to]. Definition actby A R to of actby_cond A R to := fun x a => if (x \in R) && (a \in A) then to x a else x. Variables (A : {group aT}) (R : {set rT}) (to : action D rT). Hypothesis nRA : actby_cond A R to. Lemma actby_is_action : is_action A (actby nRA). Proof. rewrite /actby; split=> [a x y | x a b Aa Ab /=]; last first. rewrite Aa Ab groupM // !andbT actMin ?(subsetP (acts_dom nRA)) //. by case Rx: (x \in R); rewrite ?(acts_act nRA) ?Rx. case Aa: (a \in A); rewrite ?andbF ?andbT //. case Rx: (x \in R); case Ry: (y \in R) => // eqxy; first exact: act_inj eqxy. by rewrite -eqxy (acts_act nRA Aa) Rx in Ry. by rewrite eqxy (acts_act nRA Aa) Ry in Rx. Qed. Canonical action_by := Action actby_is_action. Local Notation "<[nRA]>" := action_by : action_scope. Lemma actbyE x a : x \in R -> a \in A -> <[nRA]>%act x a = to x a. Proof. by rewrite /= /actby => -> ->. Qed. Lemma afix_actby B : 'Fix_<[nRA]>(B) = ~: R :|: 'Fix_to(A :&: B). Proof. apply/setP=> x; rewrite !inE /= /actby. case: (x \in R); last by apply/subsetP=> a _; rewrite !inE. apply/subsetP/subsetP=> [cBx a | cABx a Ba]; rewrite !inE. by case/andP=> Aa /cBx; rewrite inE Aa. by case: ifP => //= Aa; have:= cABx a; rewrite !inE Aa => ->. Qed. Lemma astab_actby S : 'C(S | <[nRA]>) = 'C_A(R :&: S | to). Proof. apply/setP=> a; rewrite setIA (setIidPl (acts_dom nRA)) !inE. case Aa: (a \in A) => //=; apply/subsetP/subsetP=> cRSa x => [|Sx]. by case/setIP=> Rx /cRSa; rewrite !inE actbyE. by have:= cRSa x; rewrite !inE /= /actby Aa Sx; case: (x \in R) => //; apply. Qed. Lemma astabs_actby S : 'N(S | <[nRA]>) = 'N_A(R :&: S | to). Proof. apply/setP=> a; rewrite setIA (setIidPl (acts_dom nRA)) !inE. case Aa: (a \in A) => //=; apply/subsetP/subsetP=> nRSa x => [|Sx]. by case/setIP=> Rx /nRSa; rewrite !inE actbyE ?(acts_act nRA) ?Rx. have:= nRSa x; rewrite !inE /= /actby Aa Sx ?(acts_act nRA) //. by case: (x \in R) => //; apply. Qed. Lemma acts_actby (B : {set aT}) S : [acts B, on S | <[nRA]>] = (B \subset A) && [acts B, on R :&: S | to]. Proof. by rewrite astabs_actby subsetI. Qed. End ActBy. Notation "<[ nRA ] >" := (action_by nRA) : action_scope. Section SubAction. Variables (aT : finGroupType) (D : {group aT}). Variables (rT : finType) (sP : pred rT) (sT : subFinType sP) (to : action D rT). Implicit Type A : {set aT}. Implicit Type u : sT. Implicit Type S : {set sT}. Definition subact_dom := 'N([set x | sP x] | to). Canonical subact_dom_group := [group of subact_dom]. Implicit Type Na : {a | a \in subact_dom}. Lemma sub_act_proof u Na : sP (to (val u) (val Na)). Proof. by case: Na => a /= /(astabs_act (val u)); rewrite !inE valP. Qed. Definition subact u a := if insub a is Some Na then Sub _ (sub_act_proof u Na) else u. Lemma val_subact u a : val (subact u a) = if a \in subact_dom then to (val u) a else val u. Proof. by rewrite /subact -if_neg; case: insubP => [Na|] -> //=; rewrite SubK => ->. Qed. Lemma subact_is_action : is_action subact_dom subact. Proof. split=> [a u v eq_uv | u a b Na Nb]; apply: val_inj. move/(congr1 val): eq_uv; rewrite !val_subact. by case: (a \in _); first move/act_inj. have Da := astabs_dom Na; have Db := astabs_dom Nb. by rewrite !val_subact Na Nb groupM ?actMin. Qed. Canonical subaction := Action subact_is_action. Lemma astab_subact S : 'C(S | subaction) = subact_dom :&: 'C(val @: S | to). Proof. apply/setP=> a; rewrite inE in_setI; apply: andb_id2l => sDa. have [Da _] := setIP sDa; rewrite !inE Da. apply/subsetP/subsetP=> [cSa _ /imsetP[x Sx ->] | cSa x Sx]; rewrite !inE. by have:= cSa x Sx; rewrite inE -val_eqE val_subact sDa. by have:= cSa _ (mem_imset val Sx); rewrite inE -val_eqE val_subact sDa. Qed. Lemma astabs_subact S : 'N(S | subaction) = subact_dom :&: 'N(val @: S | to). Proof. apply/setP=> a; rewrite inE in_setI; apply: andb_id2l => sDa. have [Da _] := setIP sDa; rewrite !inE Da. apply/subsetP/subsetP=> [nSa _ /imsetP[x Sx ->] | nSa x Sx]; rewrite !inE. by have:= nSa x Sx; rewrite inE => /(mem_imset val); rewrite val_subact sDa. have:= nSa _ (mem_imset val Sx); rewrite inE => /imsetP[y Sy def_y]. by rewrite ((_ a =P y) _) // -val_eqE val_subact sDa def_y. Qed. Lemma afix_subact A : A \subset subact_dom -> 'Fix_subaction(A) = val @^-1: 'Fix_to(A). Proof. move/subsetP=> sAD; apply/setP=> u. rewrite !inE !(sameP setIidPl eqP); congr (_ == A). apply/setP=> a; rewrite !inE; apply: andb_id2l => Aa. by rewrite -val_eqE val_subact sAD. Qed. End SubAction. Notation "to ^?" := (subaction _ to) (at level 2, format "to ^?") : action_scope. Section QuotientAction. Variables (aT : finGroupType) (D : {group aT}) (rT : finGroupType). Variables (to : action D rT) (H : {group rT}). Definition qact_dom := 'N(rcosets H 'N(H) | to^*). Canonical qact_dom_group := [group of qact_dom]. Local Notation subdom := (subact_dom (coset_range H) to^*). Fact qact_subdomE : subdom = qact_dom. Proof. by congr 'N(_|_); apply/setP=> Hx; rewrite !inE genGid. Qed. Lemma qact_proof : qact_dom \subset subdom. Proof. by rewrite qact_subdomE. Qed. Definition qact : coset_of H -> aT -> coset_of H := act (to^*^? \ qact_proof). Canonical quotient_action := [action of qact]. Lemma acts_qact_dom : [acts qact_dom, on 'N(H) | to]. Proof. apply/subsetP=> a nNa; rewrite !inE (astabs_dom nNa); apply/subsetP=> x Nx. have: H :* x \in rcosets H 'N(H) by rewrite -rcosetE mem_imset. rewrite inE -(astabs_act _ nNa) => /rcosetsP[y Ny defHy]. have: to x a \in H :* y by rewrite -defHy (mem_imset (to^~a)) ?rcoset_refl. by apply: subsetP; rewrite mul_subG ?sub1set ?normG. Qed. Lemma qactEcond x a : x \in 'N(H) -> quotient_action (coset H x) a = (if a \in qact_dom then coset H (to x a) else coset H x). Proof. move=> Nx; apply: val_inj; rewrite val_subact //= qact_subdomE. have: H :* x \in rcosets H 'N(H) by rewrite -rcosetE mem_imset. case nNa: (a \in _); rewrite // -(astabs_act _ nNa). rewrite !val_coset ?(acts_act acts_qact_dom nNa) //=. case/rcosetsP=> y Ny defHy; rewrite defHy; apply: rcoset_transl. by rewrite rcoset_sym -defHy (mem_imset (_^~_)) ?rcoset_refl. Qed. Lemma qactE x a : x \in 'N(H) -> a \in qact_dom -> quotient_action (coset H x) a = coset H (to x a). Proof. by move=> Nx nNa; rewrite qactEcond ?nNa. Qed. Lemma acts_quotient (A : {set aT}) (B : {set rT}) : A \subset 'N_qact_dom(B | to) -> [acts A, on B / H | quotient_action]. Proof. move=> nBA; apply: subset_trans {A}nBA _; apply/subsetP=> a /setIP[dHa nBa]. rewrite inE dHa inE; apply/subsetP=> _ /morphimP[x nHx Bx ->]. rewrite inE /= qactE //. by rewrite mem_morphim ?(acts_act acts_qact_dom) ?(astabs_act _ nBa). Qed. Lemma astabs_quotient (G : {group rT}) : H <| G -> 'N(G / H | quotient_action) = 'N_qact_dom(G | to). Proof. move=> nsHG; have [_ nHG] := andP nsHG. apply/eqP; rewrite eqEsubset acts_quotient // andbT. apply/subsetP=> a nGa; have dHa := astabs_dom nGa; have [Da _]:= setIdP dHa. rewrite inE dHa 2!inE Da; apply/subsetP=> x Gx; have nHx := subsetP nHG x Gx. rewrite -(quotientGK nsHG) 2!inE (acts_act acts_qact_dom) ?nHx //= inE. by rewrite -qactE // (astabs_act _ nGa) mem_morphim. Qed. End QuotientAction. Notation "to / H" := (quotient_action to H) : action_scope. Section ModAction. Variables (aT : finGroupType) (D : {group aT}) (rT : finType). Variable to : action D rT. Implicit Types (G : {group aT}) (S : {set rT}). Section GenericMod. Variable H : {group aT}. Local Notation dom := 'N_D(H). Local Notation range := 'Fix_to(D :&: H). Let acts_dom : {acts dom, on range | to} := acts_act (acts_subnorm_fix to H). Definition modact x (Ha : coset_of H) := if x \in range then to x (repr (D :&: Ha)) else x. Lemma modactEcond x a : a \in dom -> modact x (coset H a) = (if x \in range then to x a else x). Proof. case/setIP=> Da Na; case: ifP => Cx; rewrite /modact Cx //. rewrite val_coset // -group_modr ?sub1set //. case: (repr _) / (repr_rcosetP (D :&: H) a) => a' Ha'. by rewrite actMin ?(afixP Cx _ Ha') //; case/setIP: Ha'. Qed. Lemma modactE x a : a \in D -> a \in 'N(H) -> x \in range -> modact x (coset H a) = to x a. Proof. by move=> Da Na Rx; rewrite modactEcond ?Rx // inE Da. Qed. Lemma modact_is_action : is_action (D / H) modact. Proof. split=> [Ha x y | x Ha Hb]; last first. case/morphimP=> a Na Da ->{Ha}; case/morphimP=> b Nb Db ->{Hb}. rewrite -morphM //= !modactEcond // ?groupM ?(introT setIP _) //. by case: ifP => Cx; rewrite ?(acts_dom, Cx, actMin, introT setIP _). case: (set_0Vmem (D :&: Ha)) => [Da0 | [a /setIP[Da NHa]]]. by rewrite /modact Da0 repr_set0 !act1 !if_same. have Na := subsetP (coset_norm _) _ NHa. have NDa: a \in 'N_D(H) by rewrite inE Da. rewrite -(coset_mem NHa) !modactEcond //. do 2![case: ifP]=> Cy Cx // eqxy; first exact: act_inj eqxy. by rewrite -eqxy acts_dom ?Cx in Cy. by rewrite eqxy acts_dom ?Cy in Cx. Qed. Canonical mod_action := Action modact_is_action. Section Stabilizers. Variable S : {set rT}. Hypothesis cSH : H \subset 'C(S | to). Let fixSH : S \subset 'Fix_to(D :&: H). Proof. by rewrite -astabCin ?subsetIl // subIset ?cSH ?orbT. Qed. Lemma astabs_mod : 'N(S | mod_action) = 'N(S | to) / H. Proof. apply/setP=> Ha; apply/idP/morphimP=> [nSa | [a nHa nSa ->]]. case/morphimP: (astabs_dom nSa) => a nHa Da defHa. exists a => //; rewrite !inE Da; apply/subsetP=> x Sx; rewrite !inE. by have:= Sx; rewrite -(astabs_act x nSa) defHa /= modactE ?(subsetP fixSH). have Da := astabs_dom nSa; rewrite !inE mem_quotient //; apply/subsetP=> x Sx. by rewrite !inE /= modactE ?(astabs_act x nSa) ?(subsetP fixSH). Qed. Lemma astab_mod : 'C(S | mod_action) = 'C(S | to) / H. Proof. apply/setP=> Ha; apply/idP/morphimP=> [cSa | [a nHa cSa ->]]. case/morphimP: (astab_dom cSa) => a nHa Da defHa. exists a => //; rewrite !inE Da; apply/subsetP=> x Sx; rewrite !inE. by rewrite -{2}[x](astab_act cSa) // defHa /= modactE ?(subsetP fixSH). have Da := astab_dom cSa; rewrite !inE mem_quotient //; apply/subsetP=> x Sx. by rewrite !inE /= modactE ?(astab_act cSa) ?(subsetP fixSH). Qed. End Stabilizers. Lemma afix_mod G S : H \subset 'C(S | to) -> G \subset 'N_D(H) -> 'Fix_(S | mod_action)(G / H) = 'Fix_(S | to)(G). Proof. move=> cSH /subsetIP[sGD nHG]. apply/eqP; rewrite eqEsubset !subsetI !subsetIl /= -!astabCin ?quotientS //. have cfixH F: H \subset 'C(S :&: F | to). by rewrite (subset_trans cSH) // astabS ?subsetIl. rewrite andbC astab_mod ?quotientS //=; last by rewrite astabCin ?subsetIr. by rewrite -(quotientSGK nHG) //= -astab_mod // astabCin ?quotientS ?subsetIr. Qed. End GenericMod. Lemma modact_faithful G S : [faithful G / 'C_G(S | to), on S | mod_action 'C_G(S | to)]. Proof. rewrite /faithful astab_mod ?subsetIr //=. by rewrite -quotientIG ?subsetIr ?trivg_quotient. Qed. End ModAction. Notation "to %% H" := (mod_action to H) : action_scope. Section ActPerm. (* Morphism to permutations induced by an action. *) Variables (aT : finGroupType) (D : {set aT}) (rT : finType). Variable to : action D rT. Definition actperm a := perm (act_inj to a). Lemma actpermM : {in D &, {morph actperm : a b / a * b}}. Proof. by move=> a b Da Db; apply/permP=> x; rewrite permM !permE actMin. Qed. Canonical actperm_morphism := Morphism actpermM. Lemma actpermE a x : actperm a x = to x a. Proof. by rewrite permE. Qed. Lemma actpermK x a : aperm x (actperm a) = to x a. Proof. exact: actpermE. Qed. Lemma ker_actperm : 'ker actperm = 'C(setT | to). Proof. congr (_ :&: _); apply/setP=> a; rewrite !inE /=. apply/eqP/subsetP=> [a1 x _ | a1]; first by rewrite inE -actpermE a1 perm1. by apply/permP=> x; apply/eqP; have:= a1 x; rewrite !inE actpermE perm1 => ->. Qed. End ActPerm. Section RestrictActionTheory. Variables (aT : finGroupType) (D : {set aT}) (rT : finType). Variables (to : action D rT). Lemma faithful_isom (A : {group aT}) S (nSA : actby_cond A S to) : [faithful A, on S | to] -> isom A (actperm <[nSA]> @* A) (actperm <[nSA]>). Proof. by move=> ffulAS; apply/isomP; rewrite ker_actperm astab_actby setIT. Qed. Variables (A : {set aT}) (sAD : A \subset D). Lemma ractpermE : actperm (to \ sAD) =1 actperm to. Proof. by move=> a; apply/permP=> x; rewrite !permE. Qed. Lemma afix_ract B : 'Fix_(to \ sAD)(B) = 'Fix_to(B). Proof. by []. Qed. Lemma astab_ract S : 'C(S | to \ sAD) = 'C_A(S | to). Proof. by rewrite setIA (setIidPl sAD). Qed. Lemma astabs_ract S : 'N(S | to \ sAD) = 'N_A(S | to). Proof. by rewrite setIA (setIidPl sAD). Qed. Lemma acts_ract (B : {set aT}) S : [acts B, on S | to \ sAD] = (B \subset A) && [acts B, on S | to]. Proof. by rewrite astabs_ract subsetI. Qed. End RestrictActionTheory. Section MorphAct. (* Action induced by a morphism to permutations. *) Variables (aT : finGroupType) (D : {group aT}) (rT : finType). Variable phi : {morphism D >-> {perm rT}}. Definition mact x a := phi a x. Lemma mact_is_action : is_action D mact. Proof. split=> [a x y | x a b Da Db]; first exact: perm_inj. by rewrite /mact morphM //= permM. Qed. Canonical morph_action := Action mact_is_action. Lemma mactE x a : morph_action x a = phi a x. Proof. by []. Qed. Lemma injm_faithful : 'injm phi -> [faithful D, on setT | morph_action]. Proof. move/injmP=> phi_inj; apply/subsetP=> a /setIP[Da /astab_act a1]. apply/set1P/phi_inj => //; apply/permP=> x. by rewrite morph1 perm1 -mactE a1 ?inE. Qed. Lemma perm_mact a : actperm morph_action a = phi a. Proof. by apply/permP=> x; rewrite permE. Qed. End MorphAct. Notation "<< phi >>" := (morph_action phi) : action_scope. Section CompAct. Variables (gT aT : finGroupType) (rT : finType). Variables (D : {set aT}) (to : action D rT). Variables (B : {set gT}) (f : {morphism B >-> aT}). Definition comp_act x e := to x (f e). Lemma comp_is_action : is_action (f @*^-1 D) comp_act. Proof. split=> [e | x e1 e2]; first exact: act_inj. case/morphpreP=> Be1 Dfe1; case/morphpreP=> Be2 Dfe2. by rewrite /comp_act morphM ?actMin. Qed. Canonical comp_action := Action comp_is_action. Lemma comp_actE x e : comp_action x e = to x (f e). Proof. by []. Qed. Lemma afix_comp (A : {set gT}) : A \subset B -> 'Fix_comp_action(A) = 'Fix_to(f @* A). Proof. move=> sAB; apply/setP=> x; rewrite !inE /morphim (setIidPr sAB). apply/subsetP/subsetP=> [cAx _ /imsetP[a Aa ->] | cfAx a Aa]. by move/cAx: Aa; rewrite !inE. by rewrite inE; move/(_ (f a)): cfAx; rewrite inE mem_imset // => ->. Qed. Lemma astab_comp S : 'C(S | comp_action) = f @*^-1 'C(S | to). Proof. by apply/setP=> x; rewrite !inE -andbA. Qed. Lemma astabs_comp S : 'N(S | comp_action) = f @*^-1 'N(S | to). Proof. by apply/setP=> x; rewrite !inE -andbA. Qed. End CompAct. Notation "to \o f" := (comp_action to f) : action_scope. Section PermAction. (* Natural action of permutation groups. *) Variable rT : finType. Local Notation gT := {perm rT}. Implicit Types a b c : gT. Lemma aperm_is_action : is_action setT (@aperm rT). Proof. by apply: is_total_action => [x|x a b]; rewrite apermE (perm1, permM). Qed. Canonical perm_action := Action aperm_is_action. Lemma pcycleE a : pcycle a = orbit perm_action <[a]>%g. Proof. by []. Qed. Lemma perm_act1P a : reflect (forall x, aperm x a = x) (a == 1). Proof. apply: (iffP eqP) => [-> x | a1]; first exact: act1. by apply/permP=> x; rewrite -apermE a1 perm1. Qed. Lemma perm_faithful A : [faithful A, on setT | perm_action]. Proof. apply/subsetP=> a /setIP[Da crTa]. by apply/set1P; apply/permP=> x; rewrite -apermE perm1 (astabP crTa) ?inE. Qed. Lemma actperm_id p : actperm perm_action p = p. Proof. by apply/permP=> x; rewrite permE. Qed. End PermAction. Implicit Arguments perm_act1P [rT a]. Prenex Implicits perm_act1P. Notation "'P" := (perm_action _) (at level 8) : action_scope. Section ActpermOrbits. Variables (aT : finGroupType) (D : {group aT}) (rT : finType). Variable to : action D rT. Lemma orbit_morphim_actperm (A : {set aT}) : A \subset D -> orbit 'P (actperm to @* A) =1 orbit to A. Proof. move=> sAD x; rewrite morphimEsub // /orbit -imset_comp. by apply: eq_imset => a //=; rewrite actpermK. Qed. Lemma pcycle_actperm (a : aT) : a \in D -> pcycle (actperm to a) =1 orbit to <[a]>. Proof. move=> Da x. by rewrite pcycleE -orbit_morphim_actperm ?cycle_subG ?morphim_cycle. Qed. End ActpermOrbits. Section RestrictPerm. Variables (T : finType) (S : {set T}). Definition restr_perm := actperm (<[subxx 'N(S | 'P)]>). Canonical restr_perm_morphism := [morphism of restr_perm]. Lemma restr_perm_on p : perm_on S (restr_perm p). Proof. apply/subsetP=> x; apply: contraR => notSx. by rewrite permE /= /actby (negPf notSx). Qed. Lemma triv_restr_perm p : p \notin 'N(S | 'P) -> restr_perm p = 1. Proof. move=> not_nSp; apply/permP=> x. by rewrite !permE /= /actby (negPf not_nSp) andbF. Qed. Lemma restr_permE : {in 'N(S | 'P) & S, forall p, restr_perm p =1 p}. Proof. by move=> y x nSp Sx; rewrite /= actpermE actbyE. Qed. Lemma ker_restr_perm : 'ker restr_perm = 'C(S | 'P). Proof. by rewrite ker_actperm astab_actby setIT (setIidPr (astab_sub _ _)). Qed. Lemma im_restr_perm p : restr_perm p @: S = S. Proof. exact: im_perm_on (restr_perm_on p). Qed. End RestrictPerm. Section AutIn. Variable gT : finGroupType. Definition Aut_in A (B : {set gT}) := 'N_A(B | 'P) / 'C_A(B | 'P). Variables G H : {group gT}. Hypothesis sHG: H \subset G. Lemma Aut_restr_perm a : a \in Aut G -> restr_perm H a \in Aut H. Proof. move=> AutGa. case nHa: (a \in 'N(H | 'P)); last by rewrite triv_restr_perm ?nHa ?group1. rewrite inE restr_perm_on; apply/morphicP=> x y Hx Hy /=. by rewrite !restr_permE ?groupM // -(autmE AutGa) morphM ?(subsetP sHG). Qed. Lemma restr_perm_Aut : restr_perm H @* Aut G \subset Aut H. Proof. by apply/subsetP=> a'; case/morphimP=> a _ AutGa ->{a'}; exact: Aut_restr_perm. Qed. Lemma Aut_in_isog : Aut_in (Aut G) H \isog restr_perm H @* Aut G. Proof. rewrite /Aut_in -ker_restr_perm kerE -morphpreIdom -morphimIdom -kerE /=. by rewrite setIA (setIC _ (Aut G)) first_isog_loc ?subsetIr. Qed. Lemma Aut_sub_fullP : reflect (forall h : {morphism H >-> gT}, 'injm h -> h @* H = H -> exists g : {morphism G >-> gT}, [/\ 'injm g, g @* G = G & {in H, g =1 h}]) (Aut_in (Aut G) H \isog Aut H). Proof. rewrite (isog_transl _ Aut_in_isog) /=; set rG := _ @* _. apply: (iffP idP) => [iso_rG h injh hH| AutHinG]. have: aut injh hH \in rG; last case/morphimP=> g nHg AutGg def_g. suffices ->: rG = Aut H by exact: Aut_aut. by apply/eqP; rewrite eqEcard restr_perm_Aut /= (card_isog iso_rG). exists (autm_morphism AutGg); rewrite injm_autm im_autm; split=> // x Hx. by rewrite -(autE injh hH Hx) def_g actpermE actbyE. suffices ->: rG = Aut H by exact: isog_refl. apply/eqP; rewrite eqEsubset restr_perm_Aut /=. apply/subsetP=> h AutHh; have hH := im_autm AutHh. have [g [injg gG eq_gh]] := AutHinG _ (injm_autm AutHh) hH. have [Ng AutGg]: aut injg gG \in 'N(H | 'P) /\ aut injg gG \in Aut G. rewrite Aut_aut !inE; split=> //; apply/subsetP=> x Hx. by rewrite inE /= /aperm autE ?(subsetP sHG) // -hH eq_gh ?mem_morphim. apply/morphimP; exists (aut injg gG) => //; apply: (eq_Aut AutHh) => [|x Hx]. by rewrite (subsetP restr_perm_Aut) // mem_morphim. by rewrite restr_permE //= /aperm autE ?eq_gh ?(subsetP sHG). Qed. End AutIn. Arguments Scope Aut_in [_ group_scope group_scope]. Section InjmAutIn. Variables (gT rT : finGroupType) (D G H : {group gT}) (f : {morphism D >-> rT}). Hypotheses (injf : 'injm f) (sGD : G \subset D) (sHG : H \subset G). Let sHD := subset_trans sHG sGD. Local Notation fGisom := (Aut_isom injf sGD). Local Notation fHisom := (Aut_isom injf sHD). Local Notation inH := (restr_perm H). Local Notation infH := (restr_perm (f @* H)). Lemma astabs_Aut_isom a : a \in Aut G -> (fGisom a \in 'N(f @* H | 'P)) = (a \in 'N(H | 'P)). Proof. move=> AutGa; rewrite !inE sub_morphim_pre // subsetI sHD /= /aperm. rewrite !(sameP setIidPl eqP) !eqEsubset !subsetIl; apply: eq_subset_r => x. rewrite !inE; apply: andb_id2l => Hx; have Gx: x \in G := subsetP sHG x Hx. have Dax: a x \in D by rewrite (subsetP sGD) // Aut_closed. by rewrite Aut_isomE // -!sub1set -morphim_set1 // injmSK ?sub1set. Qed. Lemma isom_restr_perm a : a \in Aut G -> fHisom (inH a) = infH (fGisom a). Proof. move=> AutGa; case nHa: (a \in 'N(H | 'P)); last first. by rewrite !triv_restr_perm ?astabs_Aut_isom ?nHa ?morph1. apply: (eq_Aut (Aut_Aut_isom injf sHD _)) => [|fx Hfx /=]. by rewrite (Aut_restr_perm (morphimS f sHG)) ?Aut_Aut_isom. have [x Dx Hx def_fx] := morphimP Hfx; have Gx := subsetP sHG x Hx. rewrite {1}def_fx Aut_isomE ?(Aut_restr_perm sHG) //. by rewrite !restr_permE ?astabs_Aut_isom // def_fx Aut_isomE. Qed. Lemma restr_perm_isom : isom (inH @* Aut G) (infH @* Aut (f @* G)) fHisom. Proof. apply: sub_isom; rewrite ?restr_perm_Aut ?injm_Aut_isom //=. rewrite -(im_Aut_isom injf sGD) -!morphim_comp. apply: eq_in_morphim; last exact: isom_restr_perm. apply/setP=> a; rewrite 2!in_setI; apply: andb_id2r => AutGa. rewrite /= inE andbC inE (Aut_restr_perm sHG) //=. by symmetry; rewrite inE AutGa inE astabs_Aut_isom. Qed. Lemma injm_Aut_sub : Aut_in (Aut (f @* G)) (f @* H) \isog Aut_in (Aut G) H. Proof. do 2!rewrite isog_sym (isog_transl _ (Aut_in_isog _ _)). by rewrite isog_sym (isom_isog _ _ restr_perm_isom) // restr_perm_Aut. Qed. Lemma injm_Aut_full : (Aut_in (Aut (f @* G)) (f @* H) \isog Aut (f @* H)) = (Aut_in (Aut G) H \isog Aut H). Proof. by rewrite (isog_transl _ injm_Aut_sub) (isog_transr _ (injm_Aut injf sHD)). Qed. End InjmAutIn. Section GroupAction. Variables (aT rT : finGroupType) (D : {set aT}) (R : {set rT}). Local Notation actT := (action D rT). Definition is_groupAction (to : actT) := {in D, forall a, actperm to a \in Aut R}. Structure groupAction := GroupAction {gact :> actT; _ : is_groupAction gact}. Definition clone_groupAction to := let: GroupAction _ toA := to return {type of GroupAction for to} -> _ in fun k => k toA : groupAction. End GroupAction. Delimit Scope groupAction_scope with gact. Bind Scope groupAction_scope with groupAction. Arguments Scope is_groupAction [_ _ group_scope group_scope action_scope]. Arguments Scope groupAction [_ _ group_scope group_scope]. Arguments Scope gact [_ _ group_scope group_scope groupAction_scope]. Notation "[ 'groupAction' 'of' to ]" := (clone_groupAction (@GroupAction _ _ _ _ to)) (at level 0, format "[ 'groupAction' 'of' to ]") : form_scope. Section GroupActionDefs. Variables (aT rT : finGroupType) (D : {set aT}) (R : {set rT}). Implicit Type A : {set aT}. Implicit Type S : {set rT}. Implicit Type to : groupAction D R. Definition gact_range of groupAction D R := R. Definition gacent to A := 'Fix_(R | to)(D :&: A). Definition acts_on_group A S to := [acts A, on S | to] /\ S \subset R. Coercion actby_cond_group A S to : acts_on_group A S to -> actby_cond A S to := @proj1 _ _. Definition acts_irreducibly A S to := [min S of G | G :!=: 1 & [acts A, on G | to]]. End GroupActionDefs. Arguments Scope gacent [_ _ group_scope group_scope groupAction_scope group_scope]. Arguments Scope acts_on_group [_ _ group_scope group_scope group_scope group_scope groupAction_scope]. Arguments Scope acts_irreducibly [_ _ group_scope group_scope group_scope group_scope groupAction_scope]. Notation "''C_' ( | to ) ( A )" := (gacent to A) (at level 8, format "''C_' ( | to ) ( A )") : group_scope. Notation "''C_' ( G | to ) ( A )" := (G :&: 'C_(|to)(A)) (at level 8, format "''C_' ( G | to ) ( A )") : group_scope. Notation "''C_' ( | to ) [ a ]" := 'C_(|to)([set a]) (at level 8, format "''C_' ( | to ) [ a ]") : group_scope. Notation "''C_' ( G | to ) [ a ]" := 'C_(G | to)([set a]) (at level 8, format "''C_' ( G | to ) [ a ]") : group_scope. Notation "{ 'acts' A , 'on' 'group' G | to }" := (acts_on_group A G to) (at level 0, format "{ 'acts' A , 'on' 'group' G | to }") : form_scope. Section RawGroupAction. Variables (aT rT : finGroupType) (D : {set aT}) (R : {set rT}). Variable to : groupAction D R. Lemma actperm_Aut : is_groupAction R to. Proof. by case: to. Qed. Lemma im_actperm_Aut : actperm to @* D \subset Aut R. Proof. by apply/subsetP=> _ /morphimP[a _ Da ->]; exact: actperm_Aut. Qed. Lemma gact_out x a : a \in D -> x \notin R -> to x a = x. Proof. by move=> Da Rx; rewrite -actpermE (out_Aut _ Rx) ?actperm_Aut. Qed. Lemma gactM : {in D, forall a, {in R &, {morph to^~ a : x y / x * y}}}. Proof. move=> a Da /= x y; rewrite -!(actpermE to); apply: morphicP x y. by rewrite Aut_morphic ?actperm_Aut. Qed. Lemma actmM a : {in R &, {morph actm to a : x y / x * y}}. Proof. rewrite /actm; case: ifP => //; exact: gactM. Qed. Canonical act_morphism a := Morphism (actmM a). Lemma morphim_actm : {in D, forall a (S : {set rT}), S \subset R -> actm to a @* S = to^* S a}. Proof. by move=> a Da /= S sSR; rewrite /morphim /= actmEfun ?(setIidPr _). Qed. Variables (a : aT) (A B : {set aT}) (S : {set rT}). Lemma gacentIdom : 'C_(|to)(D :&: A) = 'C_(|to)(A). Proof. by rewrite /gacent setIA setIid. Qed. Lemma gacentIim : 'C_(R | to)(A) = 'C_(|to)(A). Proof. by rewrite setIA setIid. Qed. Lemma gacentS : A \subset B -> 'C_(|to)(B) \subset 'C_(|to)(A). Proof. by move=> sAB; rewrite !(setIS, afixS). Qed. Lemma gacentU : 'C_(|to)(A :|: B) = 'C_(|to)(A) :&: 'C_(|to)(B). Proof. by rewrite -setIIr -afixU -setIUr. Qed. Hypotheses (Da : a \in D) (sAD : A \subset D) (sSR : S \subset R). Lemma gacentE : 'C_(|to)(A) = 'Fix_(R | to)(A). Proof. by rewrite -{2}(setIidPr sAD). Qed. Lemma gacent1E : 'C_(|to)[a] = 'Fix_(R | to)[a]. Proof. by rewrite /gacent [D :&: _](setIidPr _) ?sub1set. Qed. Lemma subgacentE : 'C_(S | to)(A) = 'Fix_(S | to)(A). Proof. by rewrite gacentE setIA (setIidPl sSR). Qed. Lemma subgacent1E : 'C_(S | to)[a] = 'Fix_(S | to)[a]. Proof. by rewrite gacent1E setIA (setIidPl sSR). Qed. End RawGroupAction. Section GroupActionTheory. Variables aT rT : finGroupType. Variables (D : {group aT}) (R : {group rT}) (to : groupAction D R). Implicit Type A B : {set aT}. Implicit Types G H : {group aT}. Implicit Type S : {set rT}. Implicit Types M N : {group rT}. Lemma gact1 : {in D, forall a, to 1 a = 1}. Proof. by move=> a Da; rewrite /= -actmE ?morph1. Qed. Lemma gactV : {in D, forall a, {in R, {morph to^~ a : x / x^-1}}}. Proof. by move=> a Da /= x Rx; move; rewrite -!actmE ?morphV. Qed. Lemma gactX : {in D, forall a n, {in R, {morph to^~ a : x / x ^+ n}}}. Proof. by move=> a Da /= n x Rx; rewrite -!actmE // morphX. Qed. Lemma gactJ : {in D, forall a, {in R &, {morph to^~ a : x y / x ^ y}}}. Proof. by move=> a Da /= x Rx y Ry; rewrite -!actmE // morphJ. Qed. Lemma gactR : {in D, forall a, {in R &, {morph to^~ a : x y / [~ x, y]}}}. Proof. by move=> a Da /= x Rx y Ry; rewrite -!actmE // morphR. Qed. Lemma gact_stable : {acts D, on R | to}. Proof. apply: acts_act; apply/subsetP=> a Da; rewrite !inE Da. apply/subsetP=> x; rewrite inE; apply: contraLR => R'xa. by rewrite -(actKin to Da x) gact_out ?groupV. Qed. Lemma group_set_gacent A : group_set 'C_(|to)(A). Proof. apply/group_setP; split=> [|x y]. by rewrite !inE group1; apply/subsetP=> a /setIP[Da _]; rewrite inE gact1. case/setIP=> Rx /afixP cAx /setIP[Ry /afixP cAy]. rewrite inE groupM //; apply/afixP=> a Aa. by rewrite gactM ?cAx ?cAy //; case/setIP: Aa. Qed. Canonical gacent_group A := Group (group_set_gacent A). Lemma gacent1 : 'C_(|to)(1) = R. Proof. by rewrite /gacent (setIidPr (sub1G _)) afix1 setIT. Qed. Lemma gacent_gen A : A \subset D -> 'C_(|to)(<>) = 'C_(|to)(A). Proof. by move=> sAD; rewrite /gacent ![D :&: _](setIidPr _) ?gen_subG ?afix_gen_in. Qed. Lemma gacentD1 A : 'C_(|to)(A^#) = 'C_(|to)(A). Proof. rewrite -gacentIdom -gacent_gen ?subsetIl // setIDA genD1 ?group1 //. by rewrite gacent_gen ?subsetIl // gacentIdom. Qed. Lemma gacent_cycle a : a \in D -> 'C_(|to)(<[a]>) = 'C_(|to)[a]. Proof. by move=> Da; rewrite gacent_gen ?sub1set. Qed. Lemma gacentY A B : A \subset D -> B \subset D -> 'C_(|to)(A <*> B) = 'C_(|to)(A) :&: 'C_(|to)(B). Proof. by move=> sAD sBD; rewrite gacent_gen ?gacentU // subUset sAD. Qed. Lemma gacentM G H : G \subset D -> H \subset D -> 'C_(|to)(G * H) = 'C_(|to)(G) :&: 'C_(|to)(H). Proof. by move=> sGD sHB; rewrite -gacent_gen ?mul_subG // genM_join gacentY. Qed. Lemma astab1 : 'C(1 | to) = D. Proof. by apply/setP=> x; rewrite ?(inE, sub1set) andb_idr //; move/gact1=> ->. Qed. Lemma astab_range : 'C(R | to) = 'C(setT | to). Proof. apply/eqP; rewrite eqEsubset andbC astabS ?subsetT //=. apply/subsetP=> a cRa; have Da := astab_dom cRa; rewrite !inE Da. apply/subsetP=> x; rewrite -(setUCr R) !inE. by case/orP=> ?; [rewrite (astab_act cRa) | rewrite gact_out]. Qed. Lemma gacentC A S : A \subset D -> S \subset R -> (S \subset 'C_(|to)(A)) = (A \subset 'C(S | to)). Proof. by move=> sAD sSR; rewrite subsetI sSR astabCin // (setIidPr sAD). Qed. Lemma astab_gen S : S \subset R -> 'C(<> | to) = 'C(S | to). Proof. move=> sSR; apply/setP=> a; case Da: (a \in D); last by rewrite !inE Da. by rewrite -!sub1set -!gacentC ?sub1set ?gen_subG. Qed. Lemma astabM M N : M \subset R -> N \subset R -> 'C(M * N | to) = 'C(M | to) :&: 'C(N | to). Proof. move=> sMR sNR; rewrite -astabU -astab_gen ?mul_subG // genM_join. by rewrite astab_gen // subUset sMR. Qed. Lemma astabs1 : 'N(1 | to) = D. Proof. by rewrite astabs_set1 astab1. Qed. Lemma astabs_range : 'N(R | to) = D. Proof. apply/setIidPl; apply/subsetP=> a Da; rewrite inE. by apply/subsetP=> x Rx; rewrite inE gact_stable. Qed. Lemma astabsD1 S : 'N(S^# | to) = 'N(S | to). Proof. case S1: (1 \in S); last first. by rewrite (setDidPl _) // disjoint_sym disjoints_subset sub1set inE S1. apply/eqP; rewrite eqEsubset andbC -{1}astabsIdom -{1}astabs1 setIC astabsD /=. by rewrite -{2}(setD1K S1) -astabsIdom -{1}astabs1 astabsU. Qed. Lemma gacts_range A : A \subset D -> {acts A, on group R | to}. Proof. by move=> sAD; split; rewrite ?astabs_range. Qed. Lemma acts_subnorm_gacent A : A \subset D -> [acts 'N_D(A), on 'C_(| to)(A) | to]. Proof. move=> sAD; rewrite gacentE // actsI ?astabs_range ?subsetIl //. by rewrite -{2}(setIidPr sAD) acts_subnorm_fix. Qed. Lemma acts_subnorm_subgacent A B S : A \subset D -> [acts B, on S | to] -> [acts 'N_B(A), on 'C_(S | to)(A) | to]. Proof. move=> sAD actsB; rewrite actsI //; first by rewrite subIset ?actsB. by rewrite (subset_trans _ (acts_subnorm_gacent sAD)) ?setSI ?(acts_dom actsB). Qed. Lemma acts_gen A S : S \subset R -> [acts A, on S | to] -> [acts A, on <> | to]. Proof. move=> sSR actsA; apply: {A}subset_trans actsA _. apply/subsetP=> a nSa; have Da := astabs_dom nSa; rewrite !inE Da. apply: subset_trans (_ : <> \subset actm to a @*^-1 <>) _. rewrite gen_subG subsetI sSR; apply/subsetP=> x Sx. by rewrite inE /= actmE ?mem_gen // astabs_act. by apply/subsetP=> x; rewrite !inE; case/andP=> Rx; rewrite /= actmE. Qed. Lemma acts_joing A M N : M \subset R -> N \subset R -> [acts A, on M | to] -> [acts A, on N | to] -> [acts A, on M <*> N | to]. Proof. by move=> sMR sNR nMA nNA; rewrite acts_gen ?actsU // subUset sMR. Qed. Lemma injm_actm a : 'injm (actm to a). Proof. apply/injmP=> x y Rx Ry; rewrite /= /actm; case: ifP => Da //. exact: act_inj. Qed. Lemma im_actm a : actm to a @* R = R. Proof. apply/eqP; rewrite eqEcard (card_injm (injm_actm a)) // leqnn andbT. apply/subsetP=> _ /morphimP[x Rx _ ->] /=. by rewrite /actm; case: ifP => // Da; rewrite gact_stable. Qed. Lemma acts_char G M : G \subset D -> M \char R -> [acts G, on M | to]. Proof. move=> sGD /charP[sMR charM]. apply/subsetP=> a Ga; have Da := subsetP sGD a Ga; rewrite !inE Da. apply/subsetP=> x Mx; have Rx := subsetP sMR x Mx. by rewrite inE -(charM _ (injm_actm a) (im_actm a)) -actmE // mem_morphim. Qed. Lemma gacts_char G M : G \subset D -> M \char R -> {acts G, on group M | to}. Proof. by move=> sGD charM; split; rewrite (acts_char, char_sub). Qed. Section Restrict. Variables (A : {group aT}) (sAD : A \subset D). Lemma ract_is_groupAction : is_groupAction R (to \ sAD). Proof. by move=> a Aa /=; rewrite ractpermE actperm_Aut ?(subsetP sAD). Qed. Canonical ract_groupAction := GroupAction ract_is_groupAction. Lemma gacent_ract B : 'C_(|ract_groupAction)(B) = 'C_(|to)(A :&: B). Proof. by rewrite /gacent afix_ract setIA (setIidPr sAD). Qed. End Restrict. Section ActBy. Variables (A : {group aT}) (G : {group rT}) (nGAg : {acts A, on group G | to}). Lemma actby_is_groupAction : is_groupAction G <[nGAg]>. Proof. move=> a Aa; rewrite /= inE; apply/andP; split. apply/subsetP=> x; apply: contraR => Gx. by rewrite actpermE /= /actby (negbTE Gx). apply/morphicP=> x y Gx Gy; rewrite !actpermE /= /actby Aa groupM ?Gx ?Gy //=. by case nGAg; move/acts_dom; do 2!move/subsetP=> ?; rewrite gactM; auto. Qed. Canonical actby_groupAction := GroupAction actby_is_groupAction. Lemma gacent_actby B : 'C_(|actby_groupAction)(B) = 'C_(G | to)(A :&: B). Proof. rewrite /gacent afix_actby !setIA setIid setIUr setICr set0U. by have [nAG sGR] := nGAg; rewrite (setIidPr (acts_dom nAG)) (setIidPl sGR). Qed. End ActBy. Section Quotient. Variable H : {group rT}. Lemma acts_qact_dom_norm : {acts qact_dom to H, on 'N(H) | to}. Proof. move=> a HDa /= x; rewrite {2}(('N(H) =P to^~ a @^-1: 'N(H)) _) ?inE {x}//. rewrite eqEcard (card_preimset _ (act_inj _ _)) leqnn andbT. apply/subsetP=> x Nx; rewrite inE; move/(astabs_act (H :* x)): HDa. rewrite mem_rcosets mulSGid ?normG // Nx => /rcosetsP[y Ny defHy]. suffices: to x a \in H :* y by apply: subsetP; rewrite mul_subG ?sub1set ?normG. by rewrite -defHy; apply: mem_imset; exact: rcoset_refl. Qed. Lemma qact_is_groupAction : is_groupAction (R / H) (to / H). Proof. move=> a HDa /=; have Da := astabs_dom HDa. rewrite inE; apply/andP; split. apply/subsetP=> Hx /=; case: (cosetP Hx) => x Nx ->{Hx}. apply: contraR => R'Hx; rewrite actpermE qactE // gact_out //. by apply: contra R'Hx; apply: mem_morphim. apply/morphicP=> Hx Hy; rewrite !actpermE. case/morphimP=> x Nx Gx ->{Hx}; case/morphimP=> y Ny Gy ->{Hy}. by rewrite -morphM ?qactE ?groupM ?gactM // morphM ?acts_qact_dom_norm. Qed. Canonical quotient_groupAction := GroupAction qact_is_groupAction. Lemma qact_domE : H \subset R -> qact_dom to H = 'N(H | to). Proof. move=> sHR; apply/setP=> a; apply/idP/idP=> nHa; have Da := astabs_dom nHa. rewrite !inE Da; apply/subsetP=> x Hx; rewrite inE -(rcoset1 H). have /rcosetsP[y Ny defHy]: to^~ a @: H \in rcosets H 'N(H). by rewrite (astabs_act _ nHa) -{1}(mulg1 H) -rcosetE mem_imset ?group1. by rewrite (@rcoset_transl _ H 1 y) -defHy -1?(gact1 Da) mem_setact. rewrite !inE Da; apply/subsetP=> Hx; rewrite inE => /rcosetsP[x Nx ->{Hx}]. apply/imsetP; exists (to x a). case Rx: (x \in R); last by rewrite gact_out ?Rx. rewrite inE; apply/subsetP=> _ /imsetP[y Hy ->]. rewrite -(actKVin to Da y) -gactJ // ?(subsetP sHR, astabs_act, groupV) //. by rewrite memJ_norm // astabs_act ?groupV. apply/eqP; rewrite rcosetE eqEcard. rewrite (card_imset _ (act_inj _ _)) !card_rcoset leqnn andbT. apply/subsetP=> _ /imsetP[y Hxy ->]; rewrite !mem_rcoset in Hxy *. have Rxy := subsetP sHR _ Hxy; rewrite -(mulgKV x y). case Rx: (x \in R); last by rewrite !gact_out ?mulgK // 1?groupMl ?Rx. by rewrite -gactV // -gactM 1?groupMr ?groupV // mulgK astabs_act. Qed. End Quotient. Section Mod. Variable H : {group aT}. Lemma modact_is_groupAction : is_groupAction 'C_(|to)(H) (to %% H). Proof. move=> Ha /morphimP[a Na Da ->]; have NDa: a \in 'N_D(H) by exact/setIP. rewrite inE; apply/andP; split. apply/subsetP=> x; rewrite 2!inE andbC actpermE /= modactEcond //. by apply: contraR; case: ifP => // E Rx; rewrite gact_out. apply/morphicP=> x y /setIP[Rx cHx] /setIP[Ry cHy]. rewrite /= !actpermE /= !modactE ?gactM //. suffices: x * y \in 'C_(|to)(H) by case/setIP. rewrite groupM //; exact/setIP. Qed. Canonical mod_groupAction := GroupAction modact_is_groupAction. Lemma modgactE x a : H \subset 'C(R | to) -> a \in 'N_D(H) -> (to %% H)%act x (coset H a) = to x a. Proof. move=> cRH NDa /=; have [Da Na] := setIP NDa. have [Rx | notRx] := boolP (x \in R). by rewrite modactE //; apply/afixP=> b /setIP[_ /(subsetP cRH)/astab_act->]. rewrite gact_out //= /modact; case: ifP => // _; rewrite gact_out //. suffices: a \in D :&: coset H a by case/mem_repr/setIP. by rewrite inE Da val_coset // rcoset_refl. Qed. Lemma gacent_mod G M : H \subset 'C(M | to) -> G \subset 'N(H) -> 'C_(M | mod_groupAction)(G / H) = 'C_(M | to)(G). Proof. move=> cMH nHG; rewrite -gacentIdom gacentE ?subsetIl // setICA. have sHD: H \subset D by rewrite (subset_trans cMH) ?subsetIl. rewrite -quotientGI // afix_mod ?setIS // setICA -gacentIim (setIC R) -setIA. rewrite -gacentE ?subsetIl // gacentIdom setICA (setIidPr _) //. by rewrite gacentC // ?(subset_trans cMH) ?astabS ?subsetIl // setICA subsetIl. Qed. Lemma acts_irr_mod G M : H \subset 'C(M | to) -> G \subset 'N(H) -> acts_irreducibly G M to -> acts_irreducibly (G / H) M mod_groupAction. Proof. move=> cMH nHG /mingroupP[/andP[ntM nMG] minM]. apply/mingroupP; rewrite ntM astabs_mod ?quotientS //; split=> // L modL ntL. have cLH: H \subset 'C(L | to) by rewrite (subset_trans cMH) ?astabS //. apply: minM => //; case/andP: modL => ->; rewrite astabs_mod ?quotientSGK //. by rewrite (subset_trans cLH) ?astab_sub. Qed. End Mod. Lemma modact_coset_astab x a : a \in D -> (to %% 'C(R | to))%act x (coset _ a) = to x a. Proof. move=> Da; apply: modgactE => {x}//. rewrite !inE Da; apply/subsetP=> _ /imsetP[c Cc ->]. have Dc := astab_dom Cc; rewrite !inE groupJ //. apply/subsetP=> x Rx; rewrite inE conjgE !actMin ?groupM ?groupV //. by rewrite (astab_act Cc) ?actKVin // gact_stable ?groupV. Qed. Lemma acts_irr_mod_astab G M : acts_irreducibly G M to -> acts_irreducibly (G / 'C_G(M | to)) M (mod_groupAction _). Proof. move=> irrG; have /andP[_ nMG] := mingroupp irrG. apply: acts_irr_mod irrG; first exact: subsetIr. by rewrite normsI ?normG // (subset_trans nMG) // astab_norm. Qed. Section CompAct. Variables (gT : finGroupType) (G : {group gT}) (f : {morphism G >-> aT}). Lemma comp_is_groupAction : is_groupAction R (comp_action to f). Proof. move=> a /morphpreP[Ba Dfa]; apply: etrans (actperm_Aut to Dfa). by congr (_ \in Aut R); apply/permP=> x; rewrite !actpermE. Qed. Canonical comp_groupAction := GroupAction comp_is_groupAction. Lemma gacent_comp U : 'C_(|comp_groupAction)(U) = 'C_(|to)(f @* U). Proof. rewrite /gacent afix_comp ?subIset ?subxx //. by rewrite -(setIC U) (setIC D) morphim_setIpre. Qed. End CompAct. End GroupActionTheory. Notation "''C_' ( | to ) ( A )" := (gacent_group to A) : Group_scope. Notation "''C_' ( G | to ) ( A )" := (setI_group G 'C_(|to)(A)) : Group_scope. Notation "''C_' ( | to ) [ a ]" := (gacent_group to [set a%g]) : Group_scope. Notation "''C_' ( G | to ) [ a ]" := (setI_group G 'C_(|to)[a]) : Group_scope. Notation "to \ sAD" := (ract_groupAction to sAD) : groupAction_scope. Notation "<[ nGA ] >" := (actby_groupAction nGA) : groupAction_scope. Notation "to / H" := (quotient_groupAction to H) : groupAction_scope. Notation "to %% H" := (mod_groupAction to H) : groupAction_scope. Notation "to \o f" := (comp_groupAction to f) : groupAction_scope. (* Operator group isomorphism. *) Section MorphAction. Variables (aT1 aT2 : finGroupType) (rT1 rT2 : finType). Variables (D1 : {group aT1}) (D2 : {group aT2}). Variables (to1 : action D1 rT1) (to2 : action D2 rT2). Variables (A : {set aT1}) (R S : {set rT1}). Variables (h : rT1 -> rT2) (f : {morphism D1 >-> aT2}). Hypotheses (actsDR : {acts D1, on R | to1}) (injh : {in R &, injective h}). Hypothesis defD2 : f @* D1 = D2. Hypotheses (sSR : S \subset R) (sAD1 : A \subset D1). Hypothesis hfJ : {in S & D1, morph_act to1 to2 h f}. Lemma morph_astabs : f @* 'N(S | to1) = 'N(h @: S | to2). Proof. apply/setP=> fx; apply/morphimP/idP=> [[x D1x nSx ->] | nSx]. rewrite 2!inE -{1}defD2 mem_morphim //=; apply/subsetP=> _ /imsetP[u Su ->]. by rewrite inE -hfJ ?mem_imset // (astabs_act _ nSx). have [|x D1x _ def_fx] := morphimP (_ : fx \in f @* D1). by rewrite defD2 (astabs_dom nSx). exists x => //; rewrite !inE D1x; apply/subsetP=> u Su. have /imsetP[u' Su' /injh def_u']: h (to1 u x) \in h @: S. by rewrite hfJ // -def_fx (astabs_act _ nSx) mem_imset. by rewrite inE def_u' ?actsDR ?(subsetP sSR). Qed. Lemma morph_astab : f @* 'C(S | to1) = 'C(h @: S | to2). Proof. apply/setP=> fx; apply/morphimP/idP=> [[x D1x cSx ->] | cSx]. rewrite 2!inE -{1}defD2 mem_morphim //=; apply/subsetP=> _ /imsetP[u Su ->]. by rewrite inE -hfJ // (astab_act cSx). have [|x D1x _ def_fx] := morphimP (_ : fx \in f @* D1). by rewrite defD2 (astab_dom cSx). exists x => //; rewrite !inE D1x; apply/subsetP=> u Su. rewrite inE -(inj_in_eq injh) ?actsDR ?(subsetP sSR) ?hfJ //. by rewrite -def_fx (astab_act cSx) ?mem_imset. Qed. Lemma morph_afix : h @: 'Fix_(S | to1)(A) = 'Fix_(h @: S | to2)(f @* A). Proof. apply/setP=> hu; apply/imsetP/setIP=> [[u /setIP[Su cAu] ->]|]. split; first by rewrite mem_imset. by apply/afixP=> _ /morphimP[x D1x Ax ->]; rewrite -hfJ ?(afixP cAu). case=> /imsetP[u Su ->] /afixP c_hu_fA; exists u; rewrite // inE Su. apply/afixP=> x Ax; have Dx := subsetP sAD1 x Ax. by apply: injh; rewrite ?actsDR ?(subsetP sSR) ?hfJ // c_hu_fA ?mem_morphim. Qed. End MorphAction. Section MorphGroupAction. Variables (aT1 aT2 rT1 rT2 : finGroupType). Variables (D1 : {group aT1}) (D2 : {group aT2}). Variables (R1 : {group rT1}) (R2 : {group rT2}). Variables (to1 : groupAction D1 R1) (to2 : groupAction D2 R2). Variables (h : {morphism R1 >-> rT2}) (f : {morphism D1 >-> aT2}). Hypotheses (iso_h : isom R1 R2 h) (iso_f : isom D1 D2 f). Hypothesis hfJ : {in R1 & D1, morph_act to1 to2 h f}. Implicit Types (A : {set aT1}) (S : {set rT1}) (M : {group rT1}). Lemma morph_gastabs S : S \subset R1 -> f @* 'N(S | to1) = 'N(h @* S | to2). Proof. have [[_ defD2] [injh _]] := (isomP iso_f, isomP iso_h). move=> sSR1; rewrite (morphimEsub _ sSR1). apply: (morph_astabs (gact_stable to1) (injmP injh)) => // u x. by move/(subsetP sSR1); exact: hfJ. Qed. Lemma morph_gastab S : S \subset R1 -> f @* 'C(S | to1) = 'C(h @* S | to2). Proof. have [[_ defD2] [injh _]] := (isomP iso_f, isomP iso_h). move=> sSR1; rewrite (morphimEsub _ sSR1). apply: (morph_astab (gact_stable to1) (injmP injh)) => // u x. by move/(subsetP sSR1); exact: hfJ. Qed. Lemma morph_gacent A : A \subset D1 -> h @* 'C_(|to1)(A) = 'C_(|to2)(f @* A). Proof. have [[_ defD2] [injh defR2]] := (isomP iso_f, isomP iso_h). move=> sAD1; rewrite !gacentE //; last by rewrite -defD2 morphimS. rewrite morphimEsub ?subsetIl // -{1}defR2 morphimEdom. exact: (morph_afix (gact_stable to1) (injmP injh)). Qed. Lemma morph_gact_irr A M : A \subset D1 -> M \subset R1 -> acts_irreducibly (f @* A) (h @* M) to2 = acts_irreducibly A M to1. Proof. move=> sAD1 sMR1. have [[injf defD2] [injh defR2]] := (isomP iso_f, isomP iso_h). have h_eq1 := morphim_injm_eq1 injh. apply/mingroupP/mingroupP=> [] [/andP[ntM actAM] minM]. split=> [|U]; first by rewrite -h_eq1 // ntM -(injmSK injf) ?morph_gastabs. case/andP=> ntU acts_fAU sUM; have sUR1 := subset_trans sUM sMR1. apply: (injm_morphim_inj injh) => //; apply: minM; last exact: morphimS. by rewrite h_eq1 // ntU -morph_gastabs ?morphimS. split=> [|U]; first by rewrite h_eq1 // ntM -morph_gastabs ?morphimS. case/andP=> ntU acts_fAU sUhM. have sUhR1 := subset_trans sUhM (morphimS h sMR1). have sU'M: h @*^-1 U \subset M by rewrite sub_morphpre_injm. rewrite /= -(minM _ _ sU'M) ?morphpreK // -h_eq1 ?subsetIl // -(injmSK injf) //. by rewrite morph_gastabs ?(subset_trans sU'M) // morphpreK ?ntU. Qed. End MorphGroupAction. (* Conjugation and right translation actions. *) Section InternalActionDefs. Variable gT : finGroupType. Implicit Type A : {set gT}. Implicit Type G : {group gT}. (* This is not a Canonical action because it is seldom used, and it would *) (* cause too many spurious matches (any group product would be viewed as an *) (* action!). *) Definition mulgr_action := TotalAction (@mulg1 gT) (@mulgA gT). Canonical conjg_action := TotalAction (@conjg1 gT) (@conjgM gT). Lemma conjg_is_groupAction : is_groupAction setT conjg_action. Proof. move=> a _; rewrite /= inE; apply/andP; split. by apply/subsetP=> x _; rewrite inE. by apply/morphicP=> x y _ _; rewrite !actpermE /= conjMg. Qed. Canonical conjg_groupAction := GroupAction conjg_is_groupAction. Lemma rcoset_is_action : is_action setT (@rcoset gT). Proof. by apply: is_total_action => [A|A x y]; rewrite !rcosetE (mulg1, rcosetM). Qed. Canonical rcoset_action := Action rcoset_is_action. Canonical conjsg_action := TotalAction (@conjsg1 gT) (@conjsgM gT). Lemma conjG_is_action : is_action setT (@conjG_group gT). Proof. apply: is_total_action => [G | G x y]; apply: val_inj; rewrite /= ?act1 //. exact: actM. Qed. Definition conjG_action := Action conjG_is_action. End InternalActionDefs. Notation "'R" := (@mulgr_action _) (at level 8) : action_scope. Notation "'Rs" := (@rcoset_action _) (at level 8) : action_scope. Notation "'J" := (@conjg_action _) (at level 8) : action_scope. Notation "'J" := (@conjg_groupAction _) (at level 8) : groupAction_scope. Notation "'Js" := (@conjsg_action _) (at level 8) : action_scope. Notation "'JG" := (@conjG_action _) (at level 8) : action_scope. Notation "'Q" := ('J / _)%act (at level 8) : action_scope. Notation "'Q" := ('J / _)%gact (at level 8) : groupAction_scope. Section InternalGroupAction. Variable gT : finGroupType. Implicit Types A B : {set gT}. Implicit Types G H : {group gT}. Implicit Type x : gT. (* Various identities for actions on groups. *) Lemma orbitR G x : orbit 'R G x = x *: G. Proof. by rewrite -lcosetE. Qed. Lemma astab1R x : 'C[x | 'R] = 1. Proof. apply/trivgP/subsetP=> y cxy. by rewrite -(mulKg x y) [x * y](astab1P cxy) mulVg set11. Qed. Lemma astabR G : 'C(G | 'R) = 1. Proof. apply/trivgP/subsetP=> x cGx. by rewrite -(mul1g x) [1 * x](astabP cGx) group1. Qed. Lemma astabsR G : 'N(G | 'R) = G. Proof. apply/setP=> x; rewrite !inE -setactVin ?inE //=. by rewrite -groupV -{1 3}(mulg1 G) rcoset_sym -sub1set -mulGS -!rcosetE. Qed. Lemma atransR G : [transitive G, on G | 'R]. Proof. by rewrite /atrans -{1}(mul1g G) -orbitR mem_imset. Qed. Lemma faithfulR G : [faithful G, on G | 'R]. Proof. by rewrite /faithful astabR subsetIr. Qed. Definition Cayley_repr G := actperm <[atrans_acts (atransR G)]>. Theorem Cayley_isom G : isom G (Cayley_repr G @* G) (Cayley_repr G). Proof. exact: faithful_isom (faithfulR G). Qed. Theorem Cayley_isog G : G \isog Cayley_repr G @* G. Proof. exact: isom_isog (Cayley_isom G). Qed. Lemma orbitJ G x : orbit 'J G x = x ^: G. Proof. by []. Qed. Lemma afixJ A : 'Fix_('J)(A) = 'C(A). Proof. apply/setP=> x; apply/afixP/centP=> cAx y Ay /=. by rewrite /commute conjgC cAx. by rewrite conjgE cAx ?mulKg. Qed. Lemma astabJ A : 'C(A |'J) = 'C(A). Proof. apply/setP=> x; apply/astabP/centP=> cAx y Ay /=. by apply: esym; rewrite conjgC cAx. by rewrite conjgE -cAx ?mulKg. Qed. Lemma astab1J x : 'C[x |'J] = 'C[x]. Proof. by rewrite astabJ cent_set1. Qed. Lemma astabsJ A : 'N(A | 'J) = 'N(A). Proof. by apply/setP=> x; rewrite -2!groupV !inE -conjg_preim -sub_conjg. Qed. Lemma setactJ A x : 'J^*%act A x = A :^ x. Proof. by []. Qed. Lemma gacentJ A : 'C_(|'J)(A) = 'C(A). Proof. by rewrite gacentE ?setTI ?subsetT ?afixJ. Qed. Lemma orbitRs G A : orbit 'Rs G A = rcosets A G. Proof. by []. Qed. Lemma sub_afixRs_norms G x A : (G :* x \in 'Fix_('Rs)(A)) = (A \subset G :^ x). Proof. rewrite inE /=; apply: eq_subset_r => a. rewrite inE rcosetE -(can2_eq (rcosetKV x) (rcosetK x)) -!rcosetM. rewrite eqEcard card_rcoset leqnn andbT mulgA (conjgCV x) mulgK. by rewrite -{2 3}(mulGid G) mulGS sub1set -mem_conjg. Qed. Lemma sub_afixRs_norm G x : (G :* x \in 'Fix_('Rs)(G)) = (x \in 'N(G)). Proof. by rewrite sub_afixRs_norms -groupV inE sub_conjgV. Qed. Lemma afixRs_rcosets A G : 'Fix_(rcosets G A | 'Rs)(G) = rcosets G 'N_A(G). Proof. apply/setP=> Gx; apply/setIP/rcosetsP=> [[/rcosetsP[x Ax ->]]|[x]]. by rewrite sub_afixRs_norm => Nx; exists x; rewrite // inE Ax. by case/setIP=> Ax Nx ->; rewrite -{1}rcosetE mem_imset // sub_afixRs_norm. Qed. Lemma astab1Rs G : 'C[G : {set gT} | 'Rs] = G. Proof. apply/setP=> x. by apply/astab1P/idP=> /= [<- | Gx]; rewrite rcosetE ?rcoset_refl ?rcoset_id. Qed. Lemma actsRs_rcosets H G : [acts G, on rcosets H G | 'Rs]. Proof. by rewrite -orbitRs acts_orbit ?subsetT. Qed. Lemma transRs_rcosets H G : [transitive G, on rcosets H G | 'Rs]. Proof. by rewrite -orbitRs atrans_orbit. Qed. (* This is the second part of Aschbacher (5.7) *) Lemma astabRs_rcosets H G : 'C(rcosets H G | 'Rs) = gcore H G. Proof. have transGH := transRs_rcosets H G. by rewrite (astab_trans_gcore transGH (orbit_refl _ G _)) astab1Rs. Qed. Lemma orbitJs G A : orbit 'Js G A = A :^: G. Proof. by []. Qed. Lemma astab1Js A : 'C[A | 'Js] = 'N(A). Proof. by apply/setP=> x; apply/astab1P/normP. Qed. Lemma card_conjugates A G : #|A :^: G| = #|G : 'N_G(A)|. Proof. by rewrite card_orbit astab1Js. Qed. Lemma afixJG G A : (G \in 'Fix_('JG)(A)) = (A \subset 'N(G)). Proof. by apply/afixP/normsP=> nG x Ax; apply/eqP; move/eqP: (nG x Ax). Qed. Lemma astab1JG G : 'C[G | 'JG] = 'N(G). Proof. by apply/setP=> x; apply/astab1P/normP=> [/congr_group | /group_inj]. Qed. Lemma dom_qactJ H : qact_dom 'J H = 'N(H). Proof. by rewrite qact_domE ?subsetT ?astabsJ. Qed. Lemma qactJ H (Hy : coset_of H) x : 'Q%act Hy x = if x \in 'N(H) then Hy ^ coset H x else Hy. Proof. case: (cosetP Hy) => y Ny ->{Hy}. by rewrite qactEcond // dom_qactJ; case Nx: (x \in 'N(H)); rewrite ?morphJ. Qed. Lemma actsQ A B H : A \subset 'N(H) -> A \subset 'N(B) -> [acts A, on B / H | 'Q]. Proof. by move=> nHA nBA; rewrite acts_quotient // subsetI dom_qactJ nHA astabsJ. Qed. Lemma astabsQ G H : H <| G -> 'N(G / H | 'Q) = 'N(H) :&: 'N(G). Proof. by move=> nsHG; rewrite astabs_quotient // dom_qactJ astabsJ. Qed. Lemma astabQ H Abar : 'C(Abar |'Q) = coset H @*^-1 'C(Abar). Proof. apply/setP=> x; rewrite inE /= dom_qactJ morphpreE in_setI /=. apply: andb_id2l => Nx; rewrite !inE -sub1set centsC cent_set1. apply: eq_subset_r => {Abar} Hy; rewrite inE qactJ Nx (sameP eqP conjg_fixP). by rewrite (sameP cent1P eqP) (sameP commgP eqP). Qed. Lemma sub_astabQ A H Bbar : (A \subset 'C(Bbar | 'Q)) = (A \subset 'N(H)) && (A / H \subset 'C(Bbar)). Proof. rewrite astabQ -morphpreIdom subsetI; apply: andb_id2l => nHA. by rewrite -sub_quotient_pre. Qed. Lemma sub_astabQR A B H : A \subset 'N(H) -> B \subset 'N(H) -> (A \subset 'C(B / H | 'Q)) = ([~: A, B] \subset H). Proof. move=> nHA nHB; rewrite sub_astabQ nHA /= (sameP commG1P eqP). by rewrite eqEsubset sub1G andbT -quotientR // quotient_sub1 // comm_subG. Qed. Lemma astabQR A H : A \subset 'N(H) -> 'C(A / H | 'Q) = [set x in 'N(H) | [~: [set x], A] \subset H]. Proof. move=> nHA; apply/setP=> x; rewrite astabQ -morphpreIdom 2!inE -astabQ. by case nHx: (x \in _); rewrite //= -sub1set sub_astabQR ?sub1set. Qed. Lemma quotient_astabQ H Abar : 'C(Abar | 'Q) / H = 'C(Abar). Proof. by rewrite astabQ cosetpreK. Qed. Lemma conj_astabQ A H x : x \in 'N(H) -> 'C(A / H | 'Q) :^ x = 'C(A :^ x / H | 'Q). Proof. move=> nHx; apply/setP=> y; rewrite !astabQ mem_conjg !in_setI -mem_conjg. rewrite -normJ (normP nHx) quotientJ //; apply/andb_id2l => nHy. by rewrite !inE centJ morphJ ?groupV ?morphV // -mem_conjg. Qed. Section CardClass. Variable G : {group gT}. Lemma index_cent1 x : #|G : 'C_G[x]| = #|x ^: G|. Proof. by rewrite -astab1J -card_orbit. Qed. Lemma classes_partition : partition (classes G) G. Proof. by apply: orbit_partition; apply/actsP=> x Gx y; exact: groupJr. Qed. Lemma sum_card_class : \sum_(C in classes G) #|C| = #|G|. Proof. by apply: acts_sum_card_orbit; apply/actsP=> x Gx y; exact: groupJr. Qed. Lemma class_formula : \sum_(C in classes G) #|G : 'C_G[repr C]| = #|G|. Proof. rewrite -sum_card_class; apply: eq_bigr => _ /imsetP[x Gx ->]. have: x \in x ^: G by rewrite -{1}(conjg1 x) mem_imset. by case/mem_repr/imsetP=> y Gy ->; rewrite index_cent1 classGidl. Qed. Lemma abelian_classP : reflect {in G, forall x, x ^: G = [set x]} (abelian G). Proof. rewrite /abelian -astabJ astabC. by apply: (iffP subsetP) => cGG x Gx; apply/orbit1P; exact: cGG. Qed. Lemma card_classes_abelian : abelian G = (#|classes G| == #|G|). Proof. have cGgt0 C: C \in classes G -> 1 <= #|C| ?= iff (#|C| == 1)%N. by case/imsetP=> x _ ->; rewrite eq_sym -index_cent1. rewrite -sum_card_class -sum1_card (leqif_sum cGgt0). apply/abelian_classP/forall_inP=> [cGG _ /imsetP[x Gx ->]| cGG x Gx]. by rewrite cGG ?cards1. apply/esym/eqP; rewrite eqEcard sub1set cards1 class_refl leq_eqVlt cGG //. exact: mem_imset. Qed. End CardClass. End InternalGroupAction. Lemma gacentQ (gT : finGroupType) (H : {group gT}) (A : {set gT}) : 'C_(|'Q)(A) = 'C(A / H). Proof. apply/setP=> Hx; case: (cosetP Hx) => x Nx ->{Hx}. rewrite -sub_cent1 -astab1J astabC sub1set -(quotientInorm H A). have defD: qact_dom 'J H = 'N(H) by rewrite qact_domE ?subsetT ?astabsJ. rewrite !(inE, mem_quotient) //= defD setIC. apply/subsetP/subsetP=> [cAx _ /morphimP[a Na Aa ->] | cAx a Aa]. by move/cAx: Aa; rewrite !inE qactE ?defD ?morphJ. have [_ Na] := setIP Aa; move/implyP: (cAx (coset H a)); rewrite mem_morphim //. by rewrite !inE qactE ?defD ?morphJ. Qed. Section AutAct. Variable (gT : finGroupType) (G : {set gT}). Definition autact := act ('P \ subsetT (Aut G)). Canonical aut_action := [action of autact]. Lemma autactK a : actperm aut_action a = a. Proof. by apply/permP=> x; rewrite permE. Qed. Lemma autact_is_groupAction : is_groupAction G aut_action. Proof. by move=> a Aa /=; rewrite autactK. Qed. Canonical aut_groupAction := GroupAction autact_is_groupAction. End AutAct. Arguments Scope aut_action [_ group_scope]. Arguments Scope aut_groupAction [_ group_scope]. Notation "[ 'Aut' G ]" := (aut_action G) : action_scope. Notation "[ 'Aut' G ]" := (aut_groupAction G) : groupAction_scope. mathcomp-1.5/Makefile0000644000175000017500000000472512307636117013631 0ustar garesgares# -j2 causes a bug in caml compiler, I believe while accessing/creating the # same file in parallel MAKEFLAGS := -r #-j2 .SUFFIXES: .PHONY: clean all tags install VERSION := 1.5 COQMAKEFILE := Makefile.coq COQMAKE := +$(MAKE) -f $(COQMAKEFILE) ARCHIVE := mathcomp ifneq "$(COQBIN)" "" COQBIN := $(COQBIN)/ endif all: $(COQMAKEFILE) mkdir -p bin $(COQMAKE) all $(COQMAKEFILE): Make $(COQBIN)coq_makefile -f Make > $(COQMAKEFILE) tags: $(COQBIN)coqtags `find . -name \*.v` doc: PATH="$(COQBIN):$$PATH" \ sh -c '. extra/builddoc_lib.sh; mangle_sources theories/*.v' $(MAKE) all PATH="$(COQBIN):$$PATH" TITLE="Mathematical Components" MAKEDOT=extra/ \ COQOPTS="-R theories MathComp" \ COQDOCOPTS="--external http://ssr.msr-inria.inria.fr/doc/ssreflect-$(VERSION) Ssreflect" \ MANGLEDOT="sed -i s?URL=\"./?URL=\"MathComp.?"\ sh -c '. extra/builddoc_lib.sh; build_doc theories/*.v' cp extra/*.css extra/*.png html/ install: $(COQMAKE) install clean: -$(COQMAKE) clean rm -f $(COQMAKEFILE) rm -rf $(ARCHIVE)-$(VERSION) $(ARCHIVE)-$(VERSION).tar.gz rm -rf test-dist dist: # fill in rm -rf $(ARCHIVE)-$(VERSION) mkdir -p $(ARCHIVE)-$(VERSION)/theories/ for f in `cat Make|grep '\.v *$$'`; do \ cp ../`basename $$f` $(ARCHIVE)-$(VERSION)/theories/;\ done cp AUTHORS CeCILL-B INSTALL Make Makefile README $(ARCHIVE)-$(VERSION)/ # handling of NOTICE: All rights reserved -> released under XYZ for X in `find $(ARCHIVE)-$(VERSION)/ -name \*.v`; do\ ( head -1 $$X | grep -q 'All rights reserved' ) || \ echo "warning: `basename $$X` with no reserved"\ "copyrights";\ sed -i -e '1rNOTICE' -e '/All rights reserved/D' $$X;\ done # extra mkdir -p $(ARCHIVE)-$(VERSION)/extra/ cp ../tools/hudson/builddoc_lib.sh $(ARCHIVE)-$(VERSION)/extra cp ../doc/makeDot/dependtodot.ml $(ARCHIVE)-$(VERSION)/extra/ cp ../tools/coqdoc.css $(ARCHIVE)-$(VERSION)/extra/ cp ../doc/misc/jc.png $(ARCHIVE)-$(VERSION)/extra/ # tarball + MANIFEST tar -cvf $(ARCHIVE)-$(VERSION).tar $(ARCHIVE)-$(VERSION)/ | \ sed 's/^[^\/]*\///' | grep -v '^$$' | grep -v '/$$' |\ sort > MANIFEST mv MANIFEST $(ARCHIVE)-$(VERSION)/MANIFEST tar -f $(ARCHIVE)-$(VERSION).tar -r $(ARCHIVE)-$(VERSION)/MANIFEST gzip -f9 $(ARCHIVE)-$(VERSION).tar rm -rf $(ARCHIVE)-$(VERSION)/ mv $(ARCHIVE)-$(VERSION).tar.gz .. test-dist: rm -rf test-dist mkdir test-dist tar -xzf $(ARCHIVE)-$(VERSION).tar.gz -C test-dist make -C test-dist/$(ARCHIVE)-$(VERSION) all install rm -rf test-dist mathcomp-1.5/MANIFEST0000644000175000017500000000272312307636117013316 0ustar garesgaresAUTHORS CeCILL-B extra/builddoc_lib.sh extra/coqdoc.css extra/dependtodot.ml extra/jc.png INSTALL Make Makefile README theories/abelian.v theories/action.v theories/algC.v theories/algebraics_fundamentals.v theories/algnum.v theories/alt.v theories/automorphism.v theories/bigop.v theories/binomial.v theories/center.v theories/character.v theories/classfun.v theories/closed_field.v theories/commutator.v theories/countalg.v theories/cyclic.v theories/cyclotomic.v theories/div.v theories/extraspecial.v theories/extremal.v theories/falgebra.v theories/fieldext.v theories/finalg.v theories/finfun.v theories/fingraph.v theories/fingroup.v theories/finmodule.v theories/finset.v theories/frobenius.v theories/galois.v theories/generic_quotient.v theories/gfunctor.v theories/gproduct.v theories/gseries.v theories/hall.v theories/inertia.v theories/intdiv.v theories/integral_char.v theories/interval.v theories/jordanholder.v theories/matrix.v theories/maximal.v theories/morphism.v theories/mxabelem.v theories/mxalgebra.v theories/mxpoly.v theories/mxrepresentation.v theories/nilpotent.v theories/path.v theories/perm.v theories/pgroup.v theories/polydiv.v theories/poly.v theories/polyXY.v theories/presentation.v theories/prime.v theories/primitive_action.v theories/quotient.v theories/rat.v theories/ring_quotient.v theories/separable.v theories/ssralg.v theories/ssrint.v theories/ssrnum.v theories/sylow.v theories/tuple.v theories/vcharacter.v theories/vector.v theories/zmodp.v