autpgrp-1.12.0/0000755000000000000000000000000015202202400010166 5ustar00autpgrp-1.12.0/CHANGES.md0000644000000000000000000000367015202202400011566 0ustar00# CHANGES to the 'autpgrp' GAP package ## 1.12.0 (2026-05-18) - converted the manual to GAPDoc - minor janitorial changes ## 1.11.1 (2025-04-10) - Update an outdated statement in the install instructions (we don't use ".zoo" files anymore) - update Max Horn's contact details yet again ## 1.11 (2022-08-05) - make global functions in this package read-only to prevent accidents caused by overwriting them with different code - update Max Horn's address ## 1.10.1 (2019-07-15) - fixed a manual example and the test derived from it to work with both GAP 4.11 and older GAP versions - made further janitorial changes ## 1.10 (2018-07-30) - added Max Horn as package maintainer - added this file with overview of changes in each package release - moved the internal function `InducedActionFactor` from the GAP library into this package - removed the internal function `BlockPosition` ## 1.9 (2018-03-07) - moved package to GitHub - removed some unused code - added automated test suite ## 1.8 (2016-11-25) - replaced use of obsolete GAP functions `MutableNullMat`, `MutableIdentityMat`, `NormedVectors` by `NullMat`, `IdentityMat` `NormedRowVectors` ## 1.7 (2016-11-20) - changed WedgePlusAction to deal separately with characteristic 2 - added new undocumented functions `NumberOfClass2AssociativeAlgebras` and `NumberOfClass2AssocAlgebrasByDim` - improved orbit calculations to use dictionaries, which drastically improves performance for big orbits (but may slow down very small orbit computations a little bit) - replaced uses of `ConvertToMatrixRep` plus `Immutable` by `ImmutableMatrix` - updated some examples in the package manual; in particular, replaced use of `RequirePackage` by `LoadPackage` - cleaned up some code - stopped using the obsolete GAP variable `Revision` - removed CVS leftovers ## 1.6 (2012-05-29) ## 1.5 (2012-05-29) ## 1.4 (2009-08-31) ## 1.3 (2009-07-03) ## 1.2 (2002-11-19) autpgrp-1.12.0/LICENSE0000644000000000000000000004414215202202400011200 0ustar00The AutPGrp package is free software; you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your opinion) any later version. The AutPGrp package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Version 2 of the GNU General Public License follows. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. autpgrp-1.12.0/PackageInfo.g0000644000000000000000000001344615202202400012515 0ustar00############################################################################# ## ## PackageInfo.g for the package `AutPGrp' Bettina Eick ## SetPackageInfo( rec( PackageName := "AutPGrp", Subtitle := "Computing the Automorphism Group of a p-Group", Version := "1.12.0", Date := "17/05/2026", # dd/mm/yyyy format License := "GPL-2.0-or-later", Persons := [ rec( LastName := "Eick", FirstNames := "Bettina", IsAuthor := true, IsMaintainer := true, Email := "beick@tu-bs.de", WWWHome := "http://www.iaa.tu-bs.de/beick", PostalAddress := Concatenation( "Institut Analysis und Algebra\n", "TU Braunschweig\n", "Universitätsplatz 2\n", "D-38106 Braunschweig\n", "Germany" ), Place := "Braunschweig", Institution := "TU Braunschweig"), rec( LastName := "Horn", FirstNames := "Max", IsAuthor := false, IsMaintainer := true, Email := "mhorn@rptu.de", WWWHome := "https://www.quendi.de/math", GitHubUsername := "fingolfin", PostalAddress := Concatenation( "Fachbereich Mathematik\n", "RPTU Kaiserslautern-Landau\n", "Gottlieb-Daimler-Straße 48\n", "67663 Kaiserslautern\n", "Germany" ), Place := "Kaiserslautern, Germany", Institution := "RPTU Kaiserslautern-Landau" ), rec( LastName := "O'Brien", FirstNames := "Eamonn", IsAuthor := true, IsMaintainer := false, Email := "obrien@math.auckland.ac.nz", WWWHome := "http://www.math.auckland.ac.nz/~obrien", PostalAddress := Concatenation( "Department of Mathematics\n", "University of Auckland\n", "Private Bag 92019\n Auckland\n New Zealand\n" ), Place := "Auckland", Institution := "University of Auckland" ), ], Status := "accepted", CommunicatedBy := "Derek F. Holt (Warwick)", AcceptDate := "09/2000", PackageWWWHome := "https://gap-packages.github.io/autpgrp/", README_URL := Concatenation( ~.PackageWWWHome, "README" ), PackageInfoURL := Concatenation( ~.PackageWWWHome, "PackageInfo.g" ), SourceRepository := rec( Type := "git", URL := "https://github.com/gap-packages/autpgrp", ), IssueTrackerURL := Concatenation( ~.SourceRepository.URL, "/issues" ), ArchiveURL := Concatenation( ~.SourceRepository.URL, "/releases/download/v", ~.Version, "/autpgrp-", ~.Version ), ArchiveFormats := ".tar.gz", AbstractHTML := "The AutPGrp package introduces a new function to compute the automorphism group of a finite $p$-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANUPQ method. Our package is written in GAP code and it makes use of a number of methods from the GAP library such as the MeatAxe for matrix groups and permutation group functions. We have compared our method to the others available in GAP. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed.", PackageDoc := rec( BookName := "AutPGrp", ArchiveURLSubset := ["doc"], HTMLStart := "doc/chap0_mj.html", PDFFile := "doc/manual.pdf", SixFile := "doc/manual.six", LongTitle := "Computing the Automorphism Group of a p-Group", ), Dependencies := rec( GAP := ">=4.7", NeededOtherPackages := [], SuggestedOtherPackages := [], ExternalConditions := [] ), AvailabilityTest := ReturnTrue, TestFile := "tst/testall.g", Keywords := ["p-group", "automorphism group"], AutoDoc := rec( entities := rec( AUTPGRP := "AutPGrp", ), TitlePage := rec( Copyright := """ Bettina Eick and Eamonn O'Brien.

AutPGrp is free software; you can redistribute it and/or modify it under the terms of the https://www.fsf.org/licenses/gpl.html as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.""", Abstract := """ The &AUTPGRP; package introduces a new function to compute the automorphism group of a finite p-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANUPQ method. Our package is written in &GAP; code and it makes use of a number of methods from the &GAP; library such as the MeatAxe for matrix groups and permutation group functions. We have compared our method to the others available in &GAP;. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed.""", Acknowledgements := """ We thank Alexander Hulpke for helping us with efficiency problems. Werner Nickel provided some functions from the &GAP; PQuotient which are used in this package. """)), )); autpgrp-1.12.0/README0000644000000000000000000001053415202202400011051 0ustar00 The AutPGrp package ------------------- AutPGrp is a GAP 4 package for computing automorphism groups of p-groups. Given an arbitrary finite group, the computation of its automorphism group is a very difficult task. Pioneer work in this area was carried out by Felsch & Neubueser (1970), whose algorithm used the output of their subgroup lattice program. A technique developed by Neubueser in the early 1970s sought to compute the automorphism group viewed as a permutation group acting on unions of certain conjugacy classes of the group. A similar method was implemented by Hulpke (1997) in the GAP 4 library. Recently, Cannon & Holt (1999) presented a new algorithm which uses a ``hybrid group'' approach. More efficient approaches are available to determine the automorphism group for groups satisfying certain properties. Following the work of Shoda (1928), Hulpke in 1997 implemented a practical method for finite abelian groups in the GAP 4 library. Wursthorn (1993) adapted modular group algebra techniques to compute the automorphism groups of p-groups; the GAP 3 share package Sisyphos includes an implementation. Smith (1994) introduced an algorithm for finite solvable groups which is available in the AutAg share package of GAP 3. Moreover, the p-group generation method of Newman (1977) and O'Brien (1990) can be modified to compute the automorphism group of a finite p-group as outlined in O'Brien (1995). This algorithm is implemented in the ANU pq C program. In the AutPGrp package we introduce a new function to compute the automorphism group of a finite p-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANU pq method. Our package is written in GAP code and it makes use of a number of methods from the GAP library such as the MeatAxe for matrix groups and permutation group functions. The GAP 4 package ANUPQ, which is an interface to most of the functionality of the ANU pq C program, uses the AutPGrp package to compute automorphism groups of p-groups. We have compared our method to the others available in GAP. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed. Note that since version 1.1 of AutPGrp, at least GAP 4.3fix4 is required. Authors ------- The AutPGrp package was written by: Bettina Eick, Institut Computational Mathematics, TU Braunschweig, Pockelsstr. 14, D-38106 Braunschweig, Germany e-mail: beick@tu-bs.de Eamonn O'Brien Department of Mathematics University of Auckland Private Bag 92019, Auckland, New Zealand e-mail: obrien@math.auckland.ac.nz Installing the AutPGrp package ------------------------------ To install the AutPGrp package, move the archive file 'autpgrp.tar.gz' into the `pkg' directory in which you plan to install AutPGrp. Usually, this will be the directory `pkg' in the hierarchy of your version of GAP 4. (However, it is also possible to keep an additional `pkg' directory in your private directories, see section "ref:Installing GAP Packages" of the GAP 4 reference manual for details on how to do this.) Then unpack the archive file and that's it! Bug reports ----------- If you encounter problems, please contact Bettina Eick . When sending a bug report, remember we will need to be able to reproduce the problem; so please include: * The version of GAP you are using; either look at the header when you start up GAP, or at the gap> prompt type: VERSION; * The operating system you are using e.g. Linux, macOS, Windows, ... * A script in GAP that demonstrates the bug, along with a description of why it's a bug (e.g. by adding comments to the script - recall, comments in GAP begin with a #). - Bettina Eick e-mail: b.eick@tu-bs.de www: http://www.iaa.tu-bs.de/beick/so.html autpgrp-1.12.0/doc/0000755000000000000000000000000015202202400010733 5ustar00autpgrp-1.12.0/doc/_AutoDocMainFile.xml0000644000000000000000000000014115202202400014553 0ustar00   autpgrp-1.12.0/doc/_Chunks.xml0000644000000000000000000000000015202202400013035 0ustar00autpgrp-1.12.0/doc/_entities.xml0000644000000000000000000000027215202202400013441 0ustar00AutPGrp'> AutPGrp'> autpgrp-1.12.0/doc/_main.tex0000644000000000000000000010761515202202400012552 0ustar00% generated by GAPDoc2LaTeX from XML source (Frank Luebeck) \documentclass[a4paper,11pt]{report} \usepackage[top=37mm,bottom=37mm,left=27mm,right=27mm]{geometry} \sloppy \pagestyle{myheadings} \usepackage{amssymb} \usepackage[utf8]{inputenc} \usepackage{makeidx} \makeindex \usepackage{color} \definecolor{FireBrick}{rgb}{0.5812,0.0074,0.0083} \definecolor{RoyalBlue}{rgb}{0.0236,0.0894,0.6179} \definecolor{RoyalGreen}{rgb}{0.0236,0.6179,0.0894} \definecolor{RoyalRed}{rgb}{0.6179,0.0236,0.0894} \definecolor{LightBlue}{rgb}{0.8544,0.9511,1.0000} \definecolor{Black}{rgb}{0.0,0.0,0.0} \definecolor{linkColor}{rgb}{0.0,0.0,0.554} \definecolor{citeColor}{rgb}{0.0,0.0,0.554} \definecolor{fileColor}{rgb}{0.0,0.0,0.554} \definecolor{urlColor}{rgb}{0.0,0.0,0.554} \definecolor{promptColor}{rgb}{0.0,0.0,0.589} \definecolor{brkpromptColor}{rgb}{0.589,0.0,0.0} \definecolor{gapinputColor}{rgb}{0.589,0.0,0.0} \definecolor{gapoutputColor}{rgb}{0.0,0.0,0.0} %% for a long time these were red and blue by default, %% now black, but keep variables to overwrite \definecolor{FuncColor}{rgb}{0.0,0.0,0.0} %% strange name because of pdflatex bug: \definecolor{Chapter }{rgb}{0.0,0.0,0.0} \definecolor{DarkOlive}{rgb}{0.1047,0.2412,0.0064} \usepackage{fancyvrb} \usepackage{mathptmx,helvet} \usepackage[T1]{fontenc} \usepackage{textcomp} \usepackage[ pdftex=true, bookmarks=true, a4paper=true, pdftitle={Written with GAPDoc}, pdfcreator={LaTeX with hyperref package / GAPDoc}, colorlinks=true, backref=page, breaklinks=true, linkcolor=linkColor, citecolor=citeColor, filecolor=fileColor, urlcolor=urlColor, pdfpagemode={UseNone}, ]{hyperref} \newcommand{\maintitlesize}{\fontsize{50}{55}\selectfont} % write page numbers to a .pnr log file for online help \newwrite\pagenrlog \immediate\openout\pagenrlog =\jobname.pnr \immediate\write\pagenrlog{PAGENRS := [} \newcommand{\logpage}[1]{\protect\write\pagenrlog{#1, \thepage,}} %% were never documented, give conflicts with some additional packages \newcommand{\GAP}{\textsf{GAP}} %% nicer description environments, allows long labels \usepackage{enumitem} \setdescription{style=nextline} %% depth of toc \setcounter{tocdepth}{1} %% command for ColorPrompt style examples \newcommand{\gapprompt}[1]{\color{promptColor}{\bfseries #1}} \newcommand{\gapbrkprompt}[1]{\color{brkpromptColor}{\bfseries #1}} \newcommand{\gapinput}[1]{\color{gapinputColor}{#1}} \begin{document} \logpage{[ 0, 0, 0 ]} \begin{titlepage} \mbox{}\vfill \begin{center}{\maintitlesize \textbf{ AutPGrp \\ \mbox{}}}\\ \vfill \hypersetup{pdftitle={ AutPGrp }} \markright{\scriptsize \mbox{}\hfill AutPGrp \hfill\mbox{}} {\Huge \textbf{ Computing the Automorphism Group of a p\texttt{\symbol{45}}Group \\ \mbox{}}}\\ \vfill {\Huge 1.12.0 \mbox{}}\\[1cm] { 17 May 2026 \mbox{}}\\[1cm] \mbox{}\\[2cm] {\Large \textbf{\strut Bettina Eick \strut\mbox{}}}\\ {\Large \textbf{\strut Eamonn O'Brien \strut\mbox{}}}\\ \hypersetup{pdfauthor={ Bettina Eick ; Eamonn O'Brien }} \end{center}\vfill \mbox{}\\ {\mbox{}\\ \small \noindent \textbf{ Bettina Eick } Email: \href{mailto://beick@tu-bs.de} {\texttt{beick@tu\texttt{\symbol{45}}bs.de}}\\ Homepage: \href{http://www.iaa.tu-bs.de/beick} {\texttt{http://www.iaa.tu\texttt{\symbol{45}}bs.de/beick}}\\ Address: \begin{minipage}[t]{8cm}\noindent Institut Analysis und Algebra\\ TU Braunschweig\\ Universit{\"a}tsplatz 2\\ D\texttt{\symbol{45}}38106 Braunschweig\\ Germany\\ \end{minipage} }\\ {\mbox{}\\ \small \noindent \textbf{ Eamonn O'Brien } Email: \href{mailto://obrien@math.auckland.ac.nz} {\texttt{obrien@math.auckland.ac.nz}}\\ Homepage: \href{http://www.math.auckland.ac.nz/~obrien} {\texttt{http://www.math.auckland.ac.nz/\texttt{\symbol{126}}obrien}}\\ Address: \begin{minipage}[t]{8cm}\noindent Department of Mathematics\\ University of Auckland\\ Private Bag 92019\\ Auckland\\ New Zealand\\ \end{minipage} }\\ \end{titlepage} \newpage\setcounter{page}{2} {\small \section*{Abstract} \logpage{[ 0, 0, 1 ]} The \textsf{AutPGrp} package introduces a new function to compute the automorphism group of a finite $p$\texttt{\symbol{45}}group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANUPQ method. Our package is written in \textsf{GAP} code and it makes use of a number of methods from the \textsf{GAP} library such as the MeatAxe for matrix groups and permutation group functions. We have compared our method to the others available in \textsf{GAP}. Our package usually out\texttt{\symbol{45}}performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed. \mbox{}}\\[1cm] {\small \section*{Copyright} \logpage{[ 0, 0, 2 ]} Bettina Eick and Eamonn O'Brien. AutPGrp is free software; you can redistribute it and/or modify it under the terms of the \href{ https://www.fsf.org/licenses/gpl.html} {GNU General Public License} as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. \mbox{}}\\[1cm] {\small \section*{Acknowledgements} \logpage{[ 0, 0, 3 ]} We thank Alexander Hulpke for helping us with efficiency problems. Werner Nickel provided some functions from the \textsf{GAP} \texttt{PQuotient} which are used in this package. \mbox{}}\\[1cm] \newpage \def\contentsname{Contents\logpage{[ 0, 0, 4 ]}} \tableofcontents \newpage \chapter{\textcolor{Chapter }{Introduction}}\label{Introduction} \logpage{[ 1, 0, 0 ]} \hyperdef{L}{X7DFB63A97E67C0A1}{} { \section{\textcolor{Chapter }{Introduction}}\logpage{[ 1, 1, 0 ]} \hyperdef{L}{X7DFB63A97E67C0A1}{} { Given an arbitrary finite group, the computation of its automorphism group is a very difficult task. Pioneer work in this area was carried out by Felsch and Neubueser (1970), whose algorithm used the output of their subgroup lattice program. A technique developed by Neubueser in the early 1970s sought to compute the automorphism group viewed as a permutation group acting on unions of certain conjugacy classes of the group. A similar method was implemented by Hulpke (1997) in the \textsf{GAP} 4 library. Recently, Cannon and Holt (1999) presented a new algorithm which uses a \emph{hybrid group} approach. More efficient approaches are available to determine the automorphism group for groups satisfying certain properties. Following the work of Shoda (1928), Hulpke in 1997 implemented a practical method for finite abelian groups in the \textsf{GAP} 4 library. Wursthorn (1993) adapted modular group algebra techniques to compute the automorphism groups of $p$\texttt{\symbol{45}}groups; the \textsf{GAP} 3 share package \textsf{Sisyphos} includes an implementation. Smith (1994) introduced an algorithm for finite solvable groups which is available in the \textsf{AutAg} share package of \textsf{GAP} 3. Moreover, the $p$\texttt{\symbol{45}}group generation method of Newman (1977) and O'Brien (1990) can be modified to compute the automorphism group of a finite $p$\texttt{\symbol{45}}group as outlined in O'Brien (1995). This algorithm is implemented in the ANU \texttt{pq} C program. Here we introduce a new function to compute the automorphism group of a finite $p$\texttt{\symbol{45}}group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANU \texttt{pq} method. Our package is written in \textsf{GAP} code and it makes use of a number of methods from the \textsf{GAP} library such as the MeatAxe for matrix groups and permutation group functions. The \textsf{GAP} 4 package \textsf{ANUPQ}, which is an interface to most of the functionality of the ANU \texttt{pq} C program, uses the \textsf{AutPGrp} package to compute automorphism groups of $p$\texttt{\symbol{45}}groups. We have compared our method to the others available in \textsf{GAP}. Our package usually out\texttt{\symbol{45}}performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed. } } \chapter{\textcolor{Chapter }{The automorphism group method}}\label{The automorphism group method} \logpage{[ 2, 0, 0 ]} \hyperdef{L}{X858BB98D85D78C8C}{} { \section{\textcolor{Chapter }{The automorphism group method}}\logpage{[ 2, 1, 0 ]} \hyperdef{L}{X858BB98D85D78C8C}{} { The \textsf{AutPGrp} package installs a method for \texttt{AutomorphismGroup} for a finite $p$\texttt{\symbol{45}}group (see also Section{\nobreakspace} (\textbf{Reference: Groups of Automorphisms}) in the \textsf{GAP} Reference Manual). \subsection{\textcolor{Chapter }{AutomorphismGroup}} \logpage{[ 2, 1, 1 ]}\nobreak \hyperdef{L}{X87677B0787B4461A}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{AutomorphismGroup({\mdseries\slshape G})\index{AutomorphismGroup@\texttt{AutomorphismGroup}} \label{AutomorphismGroup} }\hfill{\scriptsize (operation)}}\\ \textbf{\indent Returns:\ } The automorphism group of \mbox{\texttt{\mdseries\slshape G}}. The input is a finite $p$\texttt{\symbol{45}}group \mbox{\texttt{\mdseries\slshape G}}. If the filters \texttt{IsPGroup}, \texttt{IsFinite} and \texttt{CanEasilyComputePcgs} are set and true for \mbox{\texttt{\mdseries\slshape G}}, the method selection of \textsf{GAP}{\nobreakspace}4 invokes this algorithm. The output of the method is an automorphism group, whose generators are given in \texttt{GroupHomomorphismByImages} format in terms of their action on the underlying group \mbox{\texttt{\mdseries\slshape G}}. } \subsection{\textcolor{Chapter }{InfoAutGrp}} \logpage{[ 2, 1, 2 ]}\nobreak \hyperdef{L}{X7D16AFE27E0B7133}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{InfoAutGrp\index{InfoAutGrp@\texttt{InfoAutGrp}} \label{InfoAutGrp} }\hfill{\scriptsize (info class)}}\\ This is a \textsf{GAP} \texttt{InfoClass} (\textbf{Reference: InfoClass for a GAP package}). By assigning an \texttt{level} in the range 1 to 4 via \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] SetInfoLevel(InfoAutGrp, level); \end{Verbatim} varying levels of information on the progress of the computation, will be obtained. \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] !gapprompt@gap>| !gapinput@LoadPackage("autpgrp", false);| true !gapprompt@gap>| !gapinput@G := PcGroupCode(619031068735, 32); # SmallGroup( 32, 15 );| !gapprompt@gap>| !gapinput@SetInfoLevel( InfoAutGrp, 1 );| !gapprompt@gap>| !gapinput@AutomorphismGroup(G);| #I step 1: 2^2 -- init automorphisms #I step 2: 2^2 -- aut grp has size 2 #I step 3: 2^1 -- aut grp has size 32 #I final step: convert \end{Verbatim} The algorithm proceeds by induction down the lower $p$\texttt{\symbol{45}}central series of \texttt{G} and the information corresponds to the steps of this induction. In the following example we observe that the method also accepts permutation groups as input, provided they satisfy the required filters. \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] !gapprompt@gap>| !gapinput@G := DihedralGroup( IsPermGroup, 2^5 );;| !gapprompt@gap>| !gapinput@IsPGroup(G);| true !gapprompt@gap>| !gapinput@CanEasilyComputePcgs(G);| true !gapprompt@gap>| !gapinput@IsFinite(G);| true !gapprompt@gap>| !gapinput@A := AutomorphismGroup(G);| #I step 1: 2^2 -- init automorphisms #I step 2: 2^1 -- aut grp has size 2 #I step 3: 2^1 -- aut grp has size 8 #I step 4: 2^1 -- aut grp has size 32 #I final step: convert !gapprompt@gap>| !gapinput@A.1;| Pcgs([ ( 2,16)( 3,15)( 4,14)( 5,13)( 6,12)( 7,11)( 8,10), ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16), ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16), ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16), ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ]) -> [ ( 1, 2)( 3,16)( 4,15)( 5,14)( 6,13)( 7,12)( 8,11)( 9,10), ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16), ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16), ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16), ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ] !gapprompt@gap>| !gapinput@Order(A.1);| 16 \end{Verbatim} } } } \chapter{\textcolor{Chapter }{The underlying function}}\label{The underlying function} \logpage{[ 3, 0, 0 ]} \hyperdef{L}{X79DCF7D9853381F3}{} { \section{\textcolor{Chapter }{The underlying function}}\logpage{[ 3, 1, 0 ]} \hyperdef{L}{X79DCF7D9853381F3}{} { Underlying the method installation for \texttt{AutomorphismGroup} is the function \texttt{AutomorphismGroupPGroup}. This function is intended for expert users who wish to influence the steps of the algorithm. Note also that \texttt{AutomorphismGroup} will always choose default values. \subsection{\textcolor{Chapter }{AutomorphismGroupPGroup}} \logpage{[ 3, 1, 1 ]}\nobreak \hyperdef{L}{X83ABE66C83446A0B}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{AutomorphismGroupPGroup({\mdseries\slshape G[, flag]})\index{AutomorphismGroupPGroup@\texttt{AutomorphismGroupPGroup}} \label{AutomorphismGroupPGroup} }\hfill{\scriptsize (function)}}\\ The input is a finite $p$\texttt{\symbol{45}}group as above and an optional \mbox{\texttt{\mdseries\slshape flag}} which can be true or false. Here the filters for \mbox{\texttt{\mdseries\slshape G}} need not be set, but they should be true for \mbox{\texttt{\mdseries\slshape G}}. The possible values for \mbox{\texttt{\mdseries\slshape flag}} are considered later in Chapter \ref{Influencing the algorithm}. If \mbox{\texttt{\mdseries\slshape flag}} is not supplied, the algorithm proceeds similarly to the method installed for \texttt{AutomorphismGroup}, but it produces slightly more detailed output. The output of the function is a record which contains the following fields: \begin{description} \item[{ \texttt{glAutos} }] a set of automorphisms which together with \texttt{agAutos} generate the automorphism group; \item[{ \texttt{glOrder} }] an integer whose product with the \texttt{agOrders} gives the size of the automorphism group; \item[{ \texttt{agAutos} }] a polycyclic generating sequence for a soluble normal subgroup of the automorphism group; \item[{ \texttt{agOrder} }] the relative orders corresponding to \texttt{agAutos}; \item[{ \texttt{one} }] the identity element of the automorphism group; \item[{ \texttt{group} }] the underlying group \mbox{\texttt{\mdseries\slshape G}}; \item[{ \texttt{size} }] the size of the automorphism group. \end{description} We do not return an automorphism group in the standard form because we wish to distinguish between \texttt{agAutos} and \texttt{glAutos}; the latter act non\texttt{\symbol{45}}trivially on the Frattini quotient of \mbox{\texttt{\mdseries\slshape G}}. This hybrid\texttt{\symbol{45}}group description of the automorphism group permits more efficient computations with it. The following function converts the output of \texttt{AutomorphismGroupPGroup} to the output of \texttt{AutomorphismGroup}. } \subsection{\textcolor{Chapter }{ConvertHybridAutGroup}} \logpage{[ 3, 1, 2 ]}\nobreak \hyperdef{L}{X7DEE06CF79DC7A7C}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{ConvertHybridAutGroup({\mdseries\slshape A})\index{ConvertHybridAutGroup@\texttt{ConvertHybridAutGroup}} \label{ConvertHybridAutGroup} }\hfill{\scriptsize (function)}}\\ \textbf{\indent Returns:\ } A record. Let \mbox{\texttt{\mdseries\slshape A}} be the automorphism group of a $p$\texttt{\symbol{45}}group $G$ as computed by \texttt{AutomorphismGroupPGroup}. Then \texttt{ConvertHybridAutGroup} can compute a pc group isomorphic to the solvable part of \mbox{\texttt{\mdseries\slshape A}} stored in the record component \texttt{\mbox{\texttt{\mdseries\slshape A}}.agGroup}. This solvable part forms a subgroup of the automorphism group which contains at least the automorphisms centralizing the Frattini factor of $G$. The pc group facilitates various further computations with \mbox{\texttt{\mdseries\slshape A}}. \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] !gapprompt@gap>| !gapinput@LoadPackage("autpgrp", false);| true !gapprompt@gap>| !gapinput@H := PcGroupCode(297368117289422176, 729); # SmallGroup (729, 34);| !gapprompt@gap>| !gapinput@A := AutomorphismGroupPGroup(H);| #I step 1: 3^2 -- init automorphisms #I step 2: 3^1 -- aut grp has size 8 #I step 3: 3^2 -- aut grp has size 72 #I step 4: 3^1 -- aut grp has size 5832 #I final step: convert rec( agAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f2, f1, f3^2, f5^2, f4^2, f6^2 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2^2, f3^2*f5, f4^2*f6, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1^2, f2^2, f3*f4^2*f5^2*f6, f4^2*f6, f5^2*f6, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f3, f2, f3*f5^2, f4*f6^2, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f3, f3*f4, f4, f5*f6, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f4, f2, f3*f6^2, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f4, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f5, f2, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f5, f3*f6, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f6, f2, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f6, f3, f4, f5, f6 ] ], agOrder := [ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 ], glAutos := [ ], glOper := [ ], glOrder := 1, group := , one := IdentityMapping( ), size := 52488 ) !gapprompt@gap>| !gapinput@ConvertHybridAutGroup( A );| \end{Verbatim} } \subsection{\textcolor{Chapter }{PcGroupAutPGroup}} \logpage{[ 3, 1, 3 ]}\nobreak \hyperdef{L}{X7ED1F7C6849CA658}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{PcGroupAutPGroup({\mdseries\slshape A})\index{PcGroupAutPGroup@\texttt{PcGroupAutPGroup}} \label{PcGroupAutPGroup} }\hfill{\scriptsize (function)}}\\ This function computes a pc presentation for the solvable part of the automorphism group \mbox{\texttt{\mdseries\slshape A}} defined by \texttt{\mbox{\texttt{\mdseries\slshape A}}.agGroup}. \mbox{\texttt{\mdseries\slshape A}} is the output of the function \texttt{AutomorphismGroupPGroup}. \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] !gapprompt@gap>| !gapinput@H := PcGroupCode(297368117289422176, 729);; # SmallGroup (729, 34);| !gapprompt@gap>| !gapinput@A := AutomorphismGroupPGroup(H);;| #I step 1: 3^2 -- init automorphisms #I step 2: 3^1 -- aut grp has size 8 #I step 3: 3^2 -- aut grp has size 72 #I step 4: 3^1 -- aut grp has size 5832 #I final step: convert !gapprompt@gap>| !gapinput@B := PcGroupAutPGroup( A );| !gapprompt@gap>| !gapinput@I := InnerAutGroupPGroup( B );| Group([ f5, f4^2*f8, f6^2*f9^2, f11^2, f10^2, of ... ]) \end{Verbatim} } } } \chapter{\textcolor{Chapter }{Influencing the algorithm}}\label{Influencing the algorithm} \logpage{[ 4, 0, 0 ]} \hyperdef{L}{X86240F237D909E1C}{} { A number of choices can be made by the user to influence the performance of \texttt{AutomorphismGroupPGroup}. Below we identify these choices and their default values used in \texttt{AutomorphismGroup} (\ref{AutomorphismGroup}). We use the optional argument \mbox{\texttt{\mdseries\slshape flag}} of \texttt{AutomorphismGroupPGroup} to invoke user\texttt{\symbol{45}}defined choices. The possible values for \mbox{\texttt{\mdseries\slshape flag}} are \begin{description} \item[{\texttt{\mbox{\texttt{\mdseries\slshape flag}} = false} }] the user\texttt{\symbol{45}}defined defaults are employed in the algorithm. See below for a list of possibilities. \item[{\texttt{\mbox{\texttt{\mdseries\slshape flag}} = true} }] invokes the interactive version of the algorithm as described in Section \ref{An interactive version of the algorithm}. \end{description} In the next section we give a brief outline of the algorithm which is necessary to understand the possible choices. Then we introduce the choices the later sections of this chapter. \section{\textcolor{Chapter }{Outline of the algorithm}}\label{Outline of the algorithm} \logpage{[ 4, 1, 0 ]} \hyperdef{L}{X85D2ECC779E3CF7D}{} { The basic algorithm proceeds by induction down the lower $p$\texttt{\symbol{45}}central series of a given $p$\texttt{\symbol{45}}group $G$; that is, it successively computes $Aut(G_i)$ for the quotients $G_i = G / P_i(G)$ of the descending sequence of subgroups defined by $P_1(G) = G$ and $P_{i+1}(G)=[P_i(G),G] P_i(G)^p$ for $i\geq 1$. Hence, in the initial step of the algorithm, $Aut(G_2) = GL(d,p)$ where $d$ is the rank of the elementary abelian group $G_2$. In the inductive step it determines $Aut(G_{i+1})$ from $Aut(G_i)$. For this purpose we introduce an action of $Aut(G_i)$ on a certain elementary abelian $p$\texttt{\symbol{45}}group $M$ (the \emph{$p$\texttt{\symbol{45}}multiplicator} of $G_i$). The main computation of the inductive step is the determination of the stabiliser in $Aut(G_i)$ of a subgroup $U$ of $M$ (the \emph{allowable subgroup} for $G_{i+1}$). This stabiliser calculation is the bottle\texttt{\symbol{45}}neck of the algorithm. Our package incorporates a number of refinements designed to simplify this stabiliser computation. Some of these refinements incur overheads and hence they are not always invoked. The features outlined below allow the user to select them. Observe that the initial step of the algorithm returns $GL(d,p)$. But $Aut(G)$ may induce on $G_2$ a proper subgroup, say $K$, of $GL(d,p)$. Any intermediate subgroup of $GL(d,p)$ which contains $K$ suffices for the algorithm and we supply two methods to construct a suitable subgroup: these use characteristic subgroups or invariants of normal subgroups of $G$. (See Section \ref{The initialisation step}.) In the inductive step an action of $Aut(G_i)$ on an elementary abelian group $M$ is used. This action is computed as a matrix action on a vector space. To simplify the orbit\texttt{\symbol{45}}stabiliser computation of the subspace $U$ of $M$, we can construct the stabiliser of $U$ by iteration over a sequence of $Aut(G_i)$\texttt{\symbol{45}}invariant subspaces of $M$. (See Section \ref{Stabilisers in matrix groups}.) Orbit\texttt{\symbol{45}}stabiliser computations in finite solvable groups given by a polycyclic generating sequence are much more efficient than generic computations of this type. Thus our algorithm makes use of a large solvable normal subgroup $S$ of $Aut(G_i)$. Further, it is useful if the generating set of $Aut(G_i)$ outside $S$ is as small as possible. To achieve this we determine a permutation representation of $Aut(G_i)/S$ and use this to reduce the number of generators if possible. (See Section \ref{Searching for a small generating set}.) } \section{\textcolor{Chapter }{The initialisation step}}\label{The initialisation step} \logpage{[ 4, 2, 0 ]} \hyperdef{L}{X87B27C1F810822F3}{} { Assume we seek to compute the automorphism group of a $p$\texttt{\symbol{45}}group $G$ having Frattini rank $d$. We first determine as small as possible a subgroup of $GL(d, p)$ whose extension can act on $G$. The user can choose the initialisation routine by assigning \texttt{InitAutGroup} to any one of the following: \begin{description} \item[{\texttt{InitAutomorphismGroupOver} }] to use the minimal overgroups: We determine the minimal over\texttt{\symbol{45}}groups of the Frattini subgroup of $G$ and compute invariants of these which must be respected by the automorphism group of $G$. We partition the minimal overgroups and compute the stabiliser in $GL(d, p)$ of this partition. The partition of the minimal overgroups is computed using the function \texttt{PGFingerprint( G, U )}. This is the time\texttt{\symbol{45}}consuming part of this initialisation method. The user can overwrite the function \texttt{PGFingerprint}. \item[{\texttt{InitAutomorphismGroupChar} }] to use the characteristic subgroups: Compute a generating set for the stabiliser in $GL (d, p)$ of a chain of characteristic subgroups of $G$. In practice, we construct a characteristic chain by determining 2\texttt{\symbol{45}}step centralisers and omega subgroups of factors of the lower $p$\texttt{\symbol{45}}central series. However, there are often other characteristic subgroups which are not found by these approaches. The user can overwrite the function \texttt{PGCharSubgroups( G )} to supply a set of characteristic subgroups. \item[{\texttt{InitAutomorphismGroupFull} }] to use the full $GL(d,p)$. \end{description} In the method for \texttt{AutomorphismGroup} (\ref{AutomorphismGroup}) we use a default strategy: if the value $\frac{p^d-1}{p-1}$ is less than 1000, then we use the minimal overgroup approach, otherwise the characteristic subgroups are employed. An exception is made for homogeneous abelian groups where we initialise the algorithm with the full group $GL(d,p)$. } \section{\textcolor{Chapter }{Stabilisers in matrix groups}}\label{Stabilisers in matrix groups} \logpage{[ 4, 3, 0 ]} \hyperdef{L}{X869B678180AD5E21}{} { Consider the $i$th inductive step of the algorithm. Here $A \leq Aut(G_i)$ acts as matrix group on the elementary abelian $p$\texttt{\symbol{45}}group $M$ and we want to determine the stabiliser of a subgroup $U \leq M$. We use the MeatAxe to compute a series of $A$\texttt{\symbol{45}}invariant subspaces through $M$ such that each factor in the series is irreducible as $A$\texttt{\symbol{45}}module. Then we use this series to break the computation of $Stab_A(U)$ into several smaller orbit\texttt{\symbol{45}}stabiliser calculations. Note that a theoretic argument yields an $A$\texttt{\symbol{45}}invariant subspace of $M$ a priori: the nucleus $N$. This is always used to split the computation up. However, it may happen that $N = M$ and hence results in no improvement. \subsection{\textcolor{Chapter }{CHOP{\textunderscore}MULT}} \logpage{[ 4, 3, 1 ]}\nobreak \hyperdef{L}{X86529C2080159D8A}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{CHOP{\textunderscore}MULT\index{CHOP{\textunderscore}MULT@\texttt{CHOP{\textunderscore}MULT}} \label{CHOPuScoreMULT} }\hfill{\scriptsize (global variable)}}\\ The invariant series through $M$ is computed and used if the global variable \texttt{CHOP{\textunderscore}MULT} is set to \texttt{true}. Otherwise, the algorithm tries to determine $Stab_A(U)$ in one step. By default, \texttt{CHOP{\textunderscore}MULT} is \texttt{true}. } } \section{\textcolor{Chapter }{Searching for a small generating set}}\label{Searching for a small generating set} \logpage{[ 4, 4, 0 ]} \hyperdef{L}{X859CF9757A1F51EB}{} { After each step of the computation, we attempt to find a nice generating set for the automorphism group of the current factor. If the automorphism group is soluble, we store a polycyclic generating set; otherwise, we store such a generating set for a large soluble normal subgroup $S$ of the automorphism group $A$, and as few generators outside as possible. If $S = A$ and a polycyclic generating set for $S$ is known, many steps of the algorithm proceed more rapidly. \subsection{\textcolor{Chapter }{NICE{\textunderscore}STAB}} \logpage{[ 4, 4, 1 ]}\nobreak \hyperdef{L}{X83C095D17D35A8DE}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NICE{\textunderscore}STAB\index{NICE{\textunderscore}STAB@\texttt{NICE{\textunderscore}STAB}} \label{NICEuScoreSTAB} }\hfill{\scriptsize (global variable)}}\\ It may be both time\texttt{\symbol{45}}consuming and difficult to reduce the number of generators for $A$ outside $S$. Note that if the initialisation of the algorithm is by \texttt{InitAutomorphismGroupOver}, then we always know a permutation representation for $A/S$. Occasionally the search for a small generating set is expensive. If this is observed, one could set the flag \texttt{NICE{\textunderscore}STAB} to \texttt{false} and the algorithm no longer invokes this search. } } \section{\textcolor{Chapter }{An interactive version of the algorithm}}\label{An interactive version of the algorithm} \logpage{[ 4, 5, 0 ]} \hyperdef{L}{X81A0235D7E15DFBD}{} { The choice of initialisation and the choice of chopping of the $p$\texttt{\symbol{45}}multiplicator can also be driven by an interactive version of the algorithm. We give an example. \begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example] !gapprompt@gap>| !gapinput@G := PcGroupCode(2504972218445939562621471375, 256);; # SmallGroup( 2^8, 1000 );| !gapprompt@gap>| !gapinput@SetInfoLevel( InfoAutGrp, 3 );| !gapprompt@gap>| !gapinput@AutomorphismGroupPGroup( G, true );| #I step 1: 2^3 -- init automorphisms choose initialisation (Over/Char/Full): # we choose Full #I init automorphism group : Full #I step 2: 2^3 -- aut grp has size 168 #I computing cover #I computing matrix action #I computing stabilizer of U #I dim U = 3 dim N = 6 dim M = 6 chop M/N and N: (y/n): # we choose n #I induce autos and add central autos #I step 3: 2^2 -- aut grp has size 12288 #I computing cover #I computing matrix action #I computing stabilizer of U #I dim U = 6 dim N = 5 dim M = 8 chop M/N and N: (y/n): # we choose y #I induce autos and add central autos #I final step: convert rec( glAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f3, f3, f4, f5, f6*f7, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f3*f5*f6, f2*f3, f3, f4, f5*f8, f6*f7, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f3, f2*f4, f3, f4*f7, f5*f7, f6*f7*f8, f7, f8 ] ], glOrder := 4, agAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f4, f2, f3, f4*f8, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f4, f3, f4*f7, f5, f6*f7*f8, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f5, f2, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f5, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2, f3*f5, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f6, f2, f3, f4, f5*f7*f8, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f6, f3, f4*f7*f8, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f8, f2, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f8, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2, f3*f8, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f7, f2, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f7, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2, f3*f7, f4, f5, f6, f7, f8 ] ], agOrder := [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ], one := IdentityMapping( ), group := , size := 32768 ) \end{Verbatim} Two points are worthy of comment. First, the interactive version of the algorithm permits the user to make a suitable choice in each step of the algorithm instead of making one choice at the beginning. Secondly, the output of the \texttt{Info} function shows the ranks of the $p$\texttt{\symbol{45}}multiplicator and allowable subgroup, and thus allow the user to observe the scale of difficulty of the computation. } } \chapter{\textcolor{Chapter }{Additional features of the package}}\label{Additional features of the package} \logpage{[ 5, 0, 0 ]} \hyperdef{L}{X7C0BF58A85D48781}{} { \section{\textcolor{Chapter }{Additional features of the package}}\logpage{[ 5, 1, 0 ]} \hyperdef{L}{X7C0BF58A85D48781}{} { As an additional feature of this package we provide some functions to count extensions of $p$\texttt{\symbol{45}}groups and Lie algebras over $GF(p)$. These functions have been used in counting the $2$\texttt{\symbol{45}}groups of size $2^{10}$. \subsection{\textcolor{Chapter }{NumberOfPClass2PGroups (for 3 arguments)}} \logpage{[ 5, 1, 1 ]}\nobreak \hyperdef{L}{X7E472D2579705246}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NumberOfPClass2PGroups({\mdseries\slshape n, p, k})\index{NumberOfPClass2PGroups@\texttt{NumberOfPClass2PGroups}!for 3 arguments} \label{NumberOfPClass2PGroups:for 3 arguments} }\hfill{\scriptsize (operation)}}\\ This function determines the number of \mbox{\texttt{\mdseries\slshape n}}\texttt{\symbol{45}}generator \mbox{\texttt{\mdseries\slshape p}}\texttt{\symbol{45}}groups of \mbox{\texttt{\mdseries\slshape p}}\texttt{\symbol{45}}class 2 with Frattini subgroup of order \texttt{2\texttt{\symbol{94}}\mbox{\texttt{\mdseries\slshape k}}}. } \subsection{\textcolor{Chapter }{NumberOfPClass2PGroups (for 2 arguments)}} \logpage{[ 5, 1, 2 ]}\nobreak \hyperdef{L}{X825FC0D9796B0D97}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NumberOfPClass2PGroups({\mdseries\slshape n, p})\index{NumberOfPClass2PGroups@\texttt{NumberOfPClass2PGroups}!for 2 arguments} \label{NumberOfPClass2PGroups:for 2 arguments} }\hfill{\scriptsize (operation)}}\\ This function returns a list of of numbers of \mbox{\texttt{\mdseries\slshape n}}\texttt{\symbol{45}}generator \mbox{\texttt{\mdseries\slshape p}}\texttt{\symbol{45}}groups of \mbox{\texttt{\mdseries\slshape p}}\texttt{\symbol{45}}class 2 with Frattini subgroup of order \texttt{2\texttt{\symbol{94}}k} for \texttt{k} in $1, \ldots, n(n+1)/2$. } \subsection{\textcolor{Chapter }{NumberOfClass2LieAlgebras (for 3 arguments)}} \logpage{[ 5, 1, 3 ]}\nobreak \hyperdef{L}{X8399B9137982EBAC}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NumberOfClass2LieAlgebras({\mdseries\slshape n, p, k})\index{NumberOfClass2LieAlgebras@\texttt{NumberOfClass2LieAlgebras}!for 3 arguments} \label{NumberOfClass2LieAlgebras:for 3 arguments} }\hfill{\scriptsize (operation)}}\\ This function determines the number of \mbox{\texttt{\mdseries\slshape n}}\texttt{\symbol{45}}generator Lie algebras of class 2 over \mbox{\texttt{\mdseries\slshape GF(p)}} with derived Lie subalgebra of dimension \mbox{\texttt{\mdseries\slshape k}}. } \subsection{\textcolor{Chapter }{NumberOfClass2LieAlgbras (for 2 arguments)}} \logpage{[ 5, 1, 4 ]}\nobreak \hyperdef{L}{X824DFC307CA9626E}{} {\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NumberOfClass2LieAlgbras({\mdseries\slshape n, p})\index{NumberOfClass2LieAlgbras@\texttt{NumberOfClass2LieAlgbras}!for 2 arguments} \label{NumberOfClass2LieAlgbras:for 2 arguments} }\hfill{\scriptsize (operation)}}\\ This function returns a list of of numbers of \mbox{\texttt{\mdseries\slshape n}}\texttt{\symbol{45}}generator Lie algebras of class 2 over $GF(p)$ with derived Lie subalgebra of dimension $k$ for $k$ in $1, \ldots, n(n-1)/2$. } } } {\nobreakspace} \def\indexname{Index\logpage{[ "Ind", 0, 0 ]} \hyperdef{L}{X83A0356F839C696F}{} } \cleardoublepage \phantomsection \addcontentsline{toc}{chapter}{Index} \printindex \immediate\write\pagenrlog{["Ind", 0, 0], \arabic{page},} \newpage \immediate\write\pagenrlog{["End"], \arabic{page}];} \immediate\closeout\pagenrlog \end{document} autpgrp-1.12.0/doc/_main.xml0000644000000000000000000000073315202202400012543 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "intro.xml"> <#Include SYSTEM "method.xml"> <#Include SYSTEM "underl.xml"> <#Include SYSTEM "influen.xml"> <#Include SYSTEM "additional.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> autpgrp-1.12.0/doc/additional.xml0000644000000000000000000000341415202202400013567 0ustar00 Additional features of the package

Additional features of the package As an additional feature of this package we provide some functions to count extensions of p-groups and Lie algebras over GF(p). These functions have been used in counting the 2-groups of size 2^{10}.

This function determines the number of n-generator p-groups of p-class 2 with Frattini subgroup of order 2^k. This function returns a list of of numbers of n-generator p-groups of p-class 2 with Frattini subgroup of order 2^k for k in 1, \ldots, n(n+1)/2. This function determines the number of n-generator Lie algebras of class 2 over GF(p) with derived Lie subalgebra of dimension k. This function returns a list of of numbers of n-generator Lie algebras of class 2 over GF(p) with derived Lie subalgebra of dimension k for k in 1, \ldots, n(n-1)/2.

autpgrp-1.12.0/doc/autpgrp.xml0000644000000000000000000000073415202202400013143 0ustar00 ] > <#Include SYSTEM "title.xml"> <#Include SYSTEM "intro.xml"> <#Include SYSTEM "method.xml"> <#Include SYSTEM "underl.xml"> <#Include SYSTEM "influen.xml"> <#Include SYSTEM "additional.xml"> <#Include SYSTEM "_AutoDocMainFile.xml"> autpgrp-1.12.0/doc/chap0.html0000644000000000000000000002142515202202400012620 0ustar00 GAP (AutPGrp) - Contents
Goto Chapter: Top 1 2 3 4 5 Ind

AutPGrp

Computing the Automorphism Group of a p-Group

1.12.0

17 May 2026

Bettina Eick
Email: beick@tu-bs.de
Homepage: http://www.iaa.tu-bs.de/beick
Address:
Institut Analysis und Algebra
TU Braunschweig
Universitätsplatz 2
D-38106 Braunschweig
Germany

Eamonn O'Brien
Email: obrien@math.auckland.ac.nz
Homepage: http://www.math.auckland.ac.nz/~obrien
Address:
Department of Mathematics
University of Auckland
Private Bag 92019
Auckland
New Zealand

Abstract

The AutPGrp package introduces a new function to compute the automorphism group of a finite p-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANUPQ method. Our package is written in GAP code and it makes use of a number of methods from the GAP library such as the MeatAxe for matrix groups and permutation group functions. We have compared our method to the others available in GAP. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed.

Copyright

Bettina Eick and Eamonn O'Brien.

AutPGrp is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

Acknowledgements

We thank Alexander Hulpke for helping us with efficiency problems. Werner Nickel provided some functions from the GAP PQuotient which are used in this package.

Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap0.txt0000644000000000000000000001004615202202400012470 0ustar00  AutPGrp   Computing the Automorphism Group of a p-Group  1.12.0 17 May 2026 Bettina Eick Eamonn O'Brien Bettina Eick Email: mailto:beick@tu-bs.de Homepage: http://www.iaa.tu-bs.de/beick Address: Institut Analysis und Algebra TU Braunschweig Universitätsplatz 2 D-38106 Braunschweig Germany Eamonn O'Brien Email: mailto:obrien@math.auckland.ac.nz Homepage: http://www.math.auckland.ac.nz/~obrien Address: Department of Mathematics University of Auckland Private Bag 92019 Auckland New Zealand ------------------------------------------------------- Abstract The AutPGrp package introduces a new function to compute the automorphism group of a finite p-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANUPQ method. Our package is written in GAP code and it makes use of a number of methods from the GAP library such as the MeatAxe for matrix groups and permutation group functions. We have compared our method to the others available in GAP. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed. ------------------------------------------------------- Copyright Bettina Eick and Eamonn O'Brien. AutPGrp is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (https://www.fsf.org/licenses/gpl.html) as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. ------------------------------------------------------- Acknowledgements We thank Alexander Hulpke for helping us with efficiency problems. Werner Nickel provided some functions from the GAP PQuotient which are used in this package. ------------------------------------------------------- Contents (AutPGrp) 1 Introduction 1.1 Introduction 2 The automorphism group method 2.1 The automorphism group method 2.1-1 AutomorphismGroup 2.1-2 InfoAutGrp 3 The underlying function 3.1 The underlying function 3.1-1 AutomorphismGroupPGroup 3.1-2 ConvertHybridAutGroup 3.1-3 PcGroupAutPGroup 4 Influencing the algorithm 4.1 Outline of the algorithm 4.2 The initialisation step 4.3 Stabilisers in matrix groups 4.3-1 CHOP_MULT 4.4 Searching for a small generating set 4.4-1 NICE_STAB 4.5 An interactive version of the algorithm 5 Additional features of the package 5.1 Additional features of the package 5.1-1 NumberOfPClass2PGroups 5.1-2 NumberOfPClass2PGroups 5.1-3 NumberOfClass2LieAlgebras 5.1-4 NumberOfClass2LieAlgbras  autpgrp-1.12.0/doc/chap0_mj.html0000644000000000000000000002204215202202400013302 0ustar00 GAP (AutPGrp) - Contents
Goto Chapter: Top 1 2 3 4 5 Ind

AutPGrp

Computing the Automorphism Group of a p-Group

1.12.0

17 May 2026

Bettina Eick
Email: beick@tu-bs.de
Homepage: http://www.iaa.tu-bs.de/beick
Address:
Institut Analysis und Algebra
TU Braunschweig
Universitätsplatz 2
D-38106 Braunschweig
Germany

Eamonn O'Brien
Email: obrien@math.auckland.ac.nz
Homepage: http://www.math.auckland.ac.nz/~obrien
Address:
Department of Mathematics
University of Auckland
Private Bag 92019
Auckland
New Zealand

Abstract

The AutPGrp package introduces a new function to compute the automorphism group of a finite \(p\)-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANUPQ method. Our package is written in GAP code and it makes use of a number of methods from the GAP library such as the MeatAxe for matrix groups and permutation group functions. We have compared our method to the others available in GAP. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed.

Copyright

Bettina Eick and Eamonn O'Brien.

AutPGrp is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

Acknowledgements

We thank Alexander Hulpke for helping us with efficiency problems. Werner Nickel provided some functions from the GAP PQuotient which are used in this package.

Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap1.html0000644000000000000000000001244515202202400012623 0ustar00 GAP (AutPGrp) - Chapter 1: Introduction
Goto Chapter: Top 1 2 3 4 5 Ind

1 Introduction

1.1 Introduction

Given an arbitrary finite group, the computation of its automorphism group is a very difficult task. Pioneer work in this area was carried out by Felsch and Neubueser (1970), whose algorithm used the output of their subgroup lattice program. A technique developed by Neubueser in the early 1970s sought to compute the automorphism group viewed as a permutation group acting on unions of certain conjugacy classes of the group. A similar method was implemented by Hulpke (1997) in the GAP 4 library. Recently, Cannon and Holt (1999) presented a new algorithm which uses a hybrid group approach.

More efficient approaches are available to determine the automorphism group for groups satisfying certain properties. Following the work of Shoda (1928), Hulpke in 1997 implemented a practical method for finite abelian groups in the GAP 4 library. Wursthorn (1993) adapted modular group algebra techniques to compute the automorphism groups of p-groups; the GAP 3 share package Sisyphos includes an implementation. Smith (1994) introduced an algorithm for finite solvable groups which is available in the AutAg share package of GAP 3.

Moreover, the p-group generation method of Newman (1977) and O'Brien (1990) can be modified to compute the automorphism group of a finite p-group as outlined in O'Brien (1995). This algorithm is implemented in the ANU pq C program.

Here we introduce a new function to compute the automorphism group of a finite p-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANU pq method. Our package is written in GAP code and it makes use of a number of methods from the GAP library such as the MeatAxe for matrix groups and permutation group functions.

The GAP 4 package ANUPQ, which is an interface to most of the functionality of the ANU pq C program, uses the AutPGrp package to compute automorphism groups of p-groups.

We have compared our method to the others available in GAP. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed.

Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap1.txt0000644000000000000000000000555715202202400012504 0ustar00 1 Introduction 1.1 Introduction Given an arbitrary finite group, the computation of its automorphism group is a very difficult task. Pioneer work in this area was carried out by Felsch and Neubueser (1970), whose algorithm used the output of their subgroup lattice program. A technique developed by Neubueser in the early 1970s sought to compute the automorphism group viewed as a permutation group acting on unions of certain conjugacy classes of the group. A similar method was implemented by Hulpke (1997) in the GAP 4 library. Recently, Cannon and Holt (1999) presented a new algorithm which uses a hybrid group approach. More efficient approaches are available to determine the automorphism group for groups satisfying certain properties. Following the work of Shoda (1928), Hulpke in 1997 implemented a practical method for finite abelian groups in the GAP 4 library. Wursthorn (1993) adapted modular group algebra techniques to compute the automorphism groups of p-groups; the GAP 3 share package Sisyphos includes an implementation. Smith (1994) introduced an algorithm for finite solvable groups which is available in the AutAg share package of GAP 3. Moreover, the p-group generation method of Newman (1977) and O'Brien (1990) can be modified to compute the automorphism group of a finite p-group as outlined in O'Brien (1995). This algorithm is implemented in the ANU pq C program. Here we introduce a new function to compute the automorphism group of a finite p-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANU pq method. Our package is written in GAP code and it makes use of a number of methods from the GAP library such as the MeatAxe for matrix groups and permutation group functions. The GAP 4 package ANUPQ, which is an interface to most of the functionality of the ANU pq C program, uses the AutPGrp package to compute automorphism groups of p-groups. We have compared our method to the others available in GAP. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed. autpgrp-1.12.0/doc/chap1_mj.html0000644000000000000000000001300015202202400013275 0ustar00 GAP (AutPGrp) - Chapter 1: Introduction
Goto Chapter: Top 1 2 3 4 5 Ind

1 Introduction

1.1 Introduction

Given an arbitrary finite group, the computation of its automorphism group is a very difficult task. Pioneer work in this area was carried out by Felsch and Neubueser (1970), whose algorithm used the output of their subgroup lattice program. A technique developed by Neubueser in the early 1970s sought to compute the automorphism group viewed as a permutation group acting on unions of certain conjugacy classes of the group. A similar method was implemented by Hulpke (1997) in the GAP 4 library. Recently, Cannon and Holt (1999) presented a new algorithm which uses a hybrid group approach.

More efficient approaches are available to determine the automorphism group for groups satisfying certain properties. Following the work of Shoda (1928), Hulpke in 1997 implemented a practical method for finite abelian groups in the GAP 4 library. Wursthorn (1993) adapted modular group algebra techniques to compute the automorphism groups of \(p\)-groups; the GAP 3 share package Sisyphos includes an implementation. Smith (1994) introduced an algorithm for finite solvable groups which is available in the AutAg share package of GAP 3.

Moreover, the \(p\)-group generation method of Newman (1977) and O'Brien (1990) can be modified to compute the automorphism group of a finite \(p\)-group as outlined in O'Brien (1995). This algorithm is implemented in the ANU pq C program.

Here we introduce a new function to compute the automorphism group of a finite \(p\)-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANU pq method. Our package is written in GAP code and it makes use of a number of methods from the GAP library such as the MeatAxe for matrix groups and permutation group functions.

The GAP 4 package ANUPQ, which is an interface to most of the functionality of the ANU pq C program, uses the AutPGrp package to compute automorphism groups of \(p\)-groups.

We have compared our method to the others available in GAP. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed.

Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap2.html0000644000000000000000000001641515202202400012625 0ustar00 GAP (AutPGrp) - Chapter 2: The automorphism group method
Goto Chapter: Top 1 2 3 4 5 Ind

2 The automorphism group method

2.1 The automorphism group method

The AutPGrp package installs a method for AutomorphismGroup for a finite p-group (see also Section Reference: Groups of Automorphisms in the GAP Reference Manual).

2.1-1 AutomorphismGroup
‣ AutomorphismGroup( G )( operation )

Returns: The automorphism group of G.

The input is a finite p-group G. If the filters IsPGroup, IsFinite and CanEasilyComputePcgs are set and true for G, the method selection of GAP 4 invokes this algorithm.

The output of the method is an automorphism group, whose generators are given in GroupHomomorphismByImages format in terms of their action on the underlying group G.

2.1-2 InfoAutGrp
‣ InfoAutGrp( info class )

This is a GAP InfoClass (Reference: InfoClass for a GAP package). By assigning an level in the range 1 to 4 via

SetInfoLevel(InfoAutGrp, level);

varying levels of information on the progress of the computation, will be obtained.

gap> LoadPackage("autpgrp", false);
true
gap> G := PcGroupCode(619031068735, 32);  # SmallGroup( 32, 15 );
<pc group of size 32 with 5 generators>
gap> SetInfoLevel( InfoAutGrp, 1 );
gap> AutomorphismGroup(G);
#I  step 1: 2^2 -- init automorphisms
#I  step 2: 2^2 -- aut grp has size 2
#I  step 3: 2^1 -- aut grp has size 32
#I  final step: convert
<group of size 64 with 6 generators>

The algorithm proceeds by induction down the lower p-central series of G and the information corresponds to the steps of this induction. In the following example we observe that the method also accepts permutation groups as input, provided they satisfy the required filters.

gap> G := DihedralGroup( IsPermGroup, 2^5 );;
gap> IsPGroup(G);
true
gap> CanEasilyComputePcgs(G);
true
gap> IsFinite(G);
true
gap> A := AutomorphismGroup(G);
#I  step 1: 2^2 -- init automorphisms
#I  step 2: 2^1 -- aut grp has size 2
#I  step 3: 2^1 -- aut grp has size 8
#I  step 4: 2^1 -- aut grp has size 32
#I  final step: convert
<group of size 128 with 7 generators>
gap> A.1;
Pcgs([ ( 2,16)( 3,15)( 4,14)( 5,13)( 6,12)( 7,11)( 8,10),
  ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16),
  ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16),
  ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16),
  ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ]) ->
[ ( 1, 2)( 3,16)( 4,15)( 5,14)( 6,13)( 7,12)( 8,11)( 9,10),
  ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16),
  ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16),
  ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16),
  ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ]
gap> Order(A.1);
16
Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap2.txt0000644000000000000000000001056215202202400012475 0ustar00 2 The automorphism group method 2.1 The automorphism group method The AutPGrp package installs a method for AutomorphismGroup for a finite p-group (see also Section 'Reference: Groups of Automorphisms' in the GAP Reference Manual). 2.1-1 AutomorphismGroup AutomorphismGroup( G )  operation Returns: The automorphism group of G. The input is a finite p-group G. If the filters IsPGroup, IsFinite and CanEasilyComputePcgs are set and true for G, the method selection of GAP 4 invokes this algorithm. The output of the method is an automorphism group, whose generators are given in GroupHomomorphismByImages format in terms of their action on the underlying group G. 2.1-2 InfoAutGrp InfoAutGrp  info class This is a GAP InfoClass (Reference: InfoClass for a GAP package). By assigning an level in the range 1 to 4 via  Example  SetInfoLevel(InfoAutGrp, level);  varying levels of information on the progress of the computation, will be obtained.  Example  gap> LoadPackage("autpgrp", false); true gap> G := PcGroupCode(619031068735, 32); # SmallGroup( 32, 15 );  gap> SetInfoLevel( InfoAutGrp, 1 ); gap> AutomorphismGroup(G); #I step 1: 2^2 -- init automorphisms #I step 2: 2^2 -- aut grp has size 2 #I step 3: 2^1 -- aut grp has size 32 #I final step: convert   The algorithm proceeds by induction down the lower p-central series of G and the information corresponds to the steps of this induction. In the following example we observe that the method also accepts permutation groups as input, provided they satisfy the required filters.  Example  gap> G := DihedralGroup( IsPermGroup, 2^5 );; gap> IsPGroup(G); true gap> CanEasilyComputePcgs(G); true gap> IsFinite(G); true gap> A := AutomorphismGroup(G); #I step 1: 2^2 -- init automorphisms #I step 2: 2^1 -- aut grp has size 2 #I step 3: 2^1 -- aut grp has size 8 #I step 4: 2^1 -- aut grp has size 32 #I final step: convert  gap> A.1; Pcgs([ ( 2,16)( 3,15)( 4,14)( 5,13)( 6,12)( 7,11)( 8,10),  ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16),  ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16),  ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16),  ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ]) -> [ ( 1, 2)( 3,16)( 4,15)( 5,14)( 6,13)( 7,12)( 8,11)( 9,10),  ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16),  ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16),  ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16),  ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ] gap> Order(A.1); 16  autpgrp-1.12.0/doc/chap2_mj.html0000644000000000000000000001675415202202400013321 0ustar00 GAP (AutPGrp) - Chapter 2: The automorphism group method
Goto Chapter: Top 1 2 3 4 5 Ind

2 The automorphism group method

2.1 The automorphism group method

The AutPGrp package installs a method for AutomorphismGroup for a finite \(p\)-group (see also Section Reference: Groups of Automorphisms in the GAP Reference Manual).

2.1-1 AutomorphismGroup
‣ AutomorphismGroup( G )( operation )

Returns: The automorphism group of G.

The input is a finite \(p\)-group G. If the filters IsPGroup, IsFinite and CanEasilyComputePcgs are set and true for G, the method selection of GAP 4 invokes this algorithm.

The output of the method is an automorphism group, whose generators are given in GroupHomomorphismByImages format in terms of their action on the underlying group G.

2.1-2 InfoAutGrp
‣ InfoAutGrp( info class )

This is a GAP InfoClass (Reference: InfoClass for a GAP package). By assigning an level in the range 1 to 4 via

SetInfoLevel(InfoAutGrp, level);

varying levels of information on the progress of the computation, will be obtained.

gap> LoadPackage("autpgrp", false);
true
gap> G := PcGroupCode(619031068735, 32);  # SmallGroup( 32, 15 );
<pc group of size 32 with 5 generators>
gap> SetInfoLevel( InfoAutGrp, 1 );
gap> AutomorphismGroup(G);
#I  step 1: 2^2 -- init automorphisms
#I  step 2: 2^2 -- aut grp has size 2
#I  step 3: 2^1 -- aut grp has size 32
#I  final step: convert
<group of size 64 with 6 generators>

The algorithm proceeds by induction down the lower \(p\)-central series of G and the information corresponds to the steps of this induction. In the following example we observe that the method also accepts permutation groups as input, provided they satisfy the required filters.

gap> G := DihedralGroup( IsPermGroup, 2^5 );;
gap> IsPGroup(G);
true
gap> CanEasilyComputePcgs(G);
true
gap> IsFinite(G);
true
gap> A := AutomorphismGroup(G);
#I  step 1: 2^2 -- init automorphisms
#I  step 2: 2^1 -- aut grp has size 2
#I  step 3: 2^1 -- aut grp has size 8
#I  step 4: 2^1 -- aut grp has size 32
#I  final step: convert
<group of size 128 with 7 generators>
gap> A.1;
Pcgs([ ( 2,16)( 3,15)( 4,14)( 5,13)( 6,12)( 7,11)( 8,10),
  ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16),
  ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16),
  ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16),
  ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ]) ->
[ ( 1, 2)( 3,16)( 4,15)( 5,14)( 6,13)( 7,12)( 8,11)( 9,10),
  ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16),
  ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16),
  ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16),
  ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ]
gap> Order(A.1);
16
Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap3.html0000644000000000000000000002450715202202400012627 0ustar00 GAP (AutPGrp) - Chapter 3: The underlying function
Goto Chapter: Top 1 2 3 4 5 Ind

3 The underlying function

3.1 The underlying function

Underlying the method installation for AutomorphismGroup is the function AutomorphismGroupPGroup. This function is intended for expert users who wish to influence the steps of the algorithm. Note also that AutomorphismGroup will always choose default values.

3.1-1 AutomorphismGroupPGroup
‣ AutomorphismGroupPGroup( G[, flag] )( function )

The input is a finite p-group as above and an optional flag which can be true or false. Here the filters for G need not be set, but they should be true for G. The possible values for flag are considered later in Chapter 4. If flag is not supplied, the algorithm proceeds similarly to the method installed for AutomorphismGroup, but it produces slightly more detailed output. The output of the function is a record which contains the following fields:

glAutos

a set of automorphisms which together with agAutos generate the automorphism group;

glOrder

an integer whose product with the agOrders gives the size of the automorphism group;

agAutos

a polycyclic generating sequence for a soluble normal subgroup of the automorphism group;

agOrder

the relative orders corresponding to agAutos;

one

the identity element of the automorphism group;

group

the underlying group G;

size

the size of the automorphism group.

We do not return an automorphism group in the standard form because we wish to distinguish between agAutos and glAutos; the latter act non-trivially on the Frattini quotient of G. This hybrid-group description of the automorphism group permits more efficient computations with it. The following function converts the output of AutomorphismGroupPGroup to the output of AutomorphismGroup.

3.1-2 ConvertHybridAutGroup
‣ ConvertHybridAutGroup( A )( function )

Returns: A record.

Let A be the automorphism group of a p-group G as computed by AutomorphismGroupPGroup. Then ConvertHybridAutGroup can compute a pc group isomorphic to the solvable part of A stored in the record component A.agGroup. This solvable part forms a subgroup of the automorphism group which contains at least the automorphisms centralizing the Frattini factor of G. The pc group facilitates various further computations with A.

gap> LoadPackage("autpgrp", false);
true
gap> H := PcGroupCode(297368117289422176, 729);  # SmallGroup (729, 34);
<pc group of size 729 with 6 generators>
gap> A := AutomorphismGroupPGroup(H);
#I  step 1: 3^2 -- init automorphisms
#I  step 2: 3^1 -- aut grp has size 8
#I  step 3: 3^2 -- aut grp has size 72
#I  step 4: 3^1 -- aut grp has size 5832
#I  final step: convert
rec(
  agAutos :=
    [ Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f2, f1, f3^2, f5^2, f4^2, f6^2 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2^2, f3^2*f5, f4^2*f6, f5,
          f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) ->
        [ f1^2, f2^2, f3*f4^2*f5^2*f6, f4^2*f6, f5^2*f6, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f3, f2, f3*f5^2, f4*f6^2, f5,
          f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) ->
        [ f1, f2*f3, f3*f4, f4, f5*f6, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f4, f2, f3*f6^2, f4, f5, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f4, f3, f4, f5, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f5, f2, f3, f4, f5, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f5, f3*f6, f4, f5, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f6, f2, f3, f4, f5, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f6, f3, f4, f5, f6 ] ],
  agOrder := [ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 ], glAutos := [  ],
  glOper := [  ], glOrder := 1, group := <pc group of size 729 with
    6 generators>, one := IdentityMapping( <pc group of size 729 with
    6 generators> ), size := 52488 )
gap> ConvertHybridAutGroup( A );
<group of size 52488 with 11 generators>

3.1-3 PcGroupAutPGroup
‣ PcGroupAutPGroup( A )( function )

This function computes a pc presentation for the solvable part of the automorphism group A defined by A.agGroup. A is the output of the function AutomorphismGroupPGroup.

gap> H := PcGroupCode(297368117289422176, 729);;  # SmallGroup (729, 34);
gap> A := AutomorphismGroupPGroup(H);;
#I  step 1: 3^2 -- init automorphisms
#I  step 2: 3^1 -- aut grp has size 8
#I  step 3: 3^2 -- aut grp has size 72
#I  step 4: 3^1 -- aut grp has size 5832
#I  final step: convert
gap> B := PcGroupAutPGroup( A );
<pc group of size 52488 with 11 generators>
gap> I := InnerAutGroupPGroup( B );
Group([ f5, f4^2*f8, f6^2*f9^2, f11^2, f10^2, <identity> of ... ])
Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap3.txt0000644000000000000000000001572115202202400012500 0ustar00 3 The underlying function 3.1 The underlying function Underlying the method installation for AutomorphismGroup is the function AutomorphismGroupPGroup. This function is intended for expert users who wish to influence the steps of the algorithm. Note also that AutomorphismGroup will always choose default values. 3.1-1 AutomorphismGroupPGroup AutomorphismGroupPGroup( G[, flag] )  function The input is a finite p-group as above and an optional flag which can be true or false. Here the filters for G need not be set, but they should be true for G. The possible values for flag are considered later in Chapter 4. If flag is not supplied, the algorithm proceeds similarly to the method installed for AutomorphismGroup, but it produces slightly more detailed output. The output of the function is a record which contains the following fields:  glAutos  a set of automorphisms which together with agAutos generate the automorphism group;  glOrder  an integer whose product with the agOrders gives the size of the automorphism group;  agAutos  a polycyclic generating sequence for a soluble normal subgroup of the automorphism group;  agOrder  the relative orders corresponding to agAutos;  one  the identity element of the automorphism group;  group  the underlying group G;  size  the size of the automorphism group. We do not return an automorphism group in the standard form because we wish to distinguish between agAutos and glAutos; the latter act non-trivially on the Frattini quotient of G. This hybrid-group description of the automorphism group permits more efficient computations with it. The following function converts the output of AutomorphismGroupPGroup to the output of AutomorphismGroup. 3.1-2 ConvertHybridAutGroup ConvertHybridAutGroup( A )  function Returns: A record. Let A be the automorphism group of a p-group G as computed by AutomorphismGroupPGroup. Then ConvertHybridAutGroup can compute a pc group isomorphic to the solvable part of A stored in the record component A.agGroup. This solvable part forms a subgroup of the automorphism group which contains at least the automorphisms centralizing the Frattini factor of G. The pc group facilitates various further computations with A.  Example  gap> LoadPackage("autpgrp", false); true gap> H := PcGroupCode(297368117289422176, 729); # SmallGroup (729, 34);  gap> A := AutomorphismGroupPGroup(H); #I step 1: 3^2 -- init automorphisms #I step 2: 3^1 -- aut grp has size 8 #I step 3: 3^2 -- aut grp has size 72 #I step 4: 3^1 -- aut grp has size 5832 #I final step: convert rec(  agAutos :=  [ Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f2, f1, f3^2, f5^2, f4^2, f6^2 ],  Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2^2, f3^2*f5, f4^2*f6, f5,  f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) ->  [ f1^2, f2^2, f3*f4^2*f5^2*f6, f4^2*f6, f5^2*f6, f6 ],  Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f3, f2, f3*f5^2, f4*f6^2, f5,  f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) ->  [ f1, f2*f3, f3*f4, f4, f5*f6, f6 ],  Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f4, f2, f3*f6^2, f4, f5, f6 ],  Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f4, f3, f4, f5, f6 ],  Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f5, f2, f3, f4, f5, f6 ],  Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f5, f3*f6, f4, f5, f6 ],  Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f6, f2, f3, f4, f5, f6 ],  Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f6, f3, f4, f5, f6 ] ],  agOrder := [ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 ], glAutos := [ ],  glOper := [ ], glOrder := 1, group := , one := IdentityMapping( ), size := 52488 ) gap> ConvertHybridAutGroup( A );   3.1-3 PcGroupAutPGroup PcGroupAutPGroup( A )  function This function computes a pc presentation for the solvable part of the automorphism group A defined by A.agGroup. A is the output of the function AutomorphismGroupPGroup.  Example  gap> H := PcGroupCode(297368117289422176, 729);; # SmallGroup (729, 34); gap> A := AutomorphismGroupPGroup(H);; #I step 1: 3^2 -- init automorphisms #I step 2: 3^1 -- aut grp has size 8 #I step 3: 3^2 -- aut grp has size 72 #I step 4: 3^1 -- aut grp has size 5832 #I final step: convert gap> B := PcGroupAutPGroup( A );  gap> I := InnerAutGroupPGroup( B ); Group([ f5, f4^2*f8, f6^2*f9^2, f11^2, f10^2, of ... ])  autpgrp-1.12.0/doc/chap3_mj.html0000644000000000000000000002505215202202400013311 0ustar00 GAP (AutPGrp) - Chapter 3: The underlying function
Goto Chapter: Top 1 2 3 4 5 Ind

3 The underlying function

3.1 The underlying function

Underlying the method installation for AutomorphismGroup is the function AutomorphismGroupPGroup. This function is intended for expert users who wish to influence the steps of the algorithm. Note also that AutomorphismGroup will always choose default values.

3.1-1 AutomorphismGroupPGroup
‣ AutomorphismGroupPGroup( G[, flag] )( function )

The input is a finite \(p\)-group as above and an optional flag which can be true or false. Here the filters for G need not be set, but they should be true for G. The possible values for flag are considered later in Chapter 4. If flag is not supplied, the algorithm proceeds similarly to the method installed for AutomorphismGroup, but it produces slightly more detailed output. The output of the function is a record which contains the following fields:

glAutos

a set of automorphisms which together with agAutos generate the automorphism group;

glOrder

an integer whose product with the agOrders gives the size of the automorphism group;

agAutos

a polycyclic generating sequence for a soluble normal subgroup of the automorphism group;

agOrder

the relative orders corresponding to agAutos;

one

the identity element of the automorphism group;

group

the underlying group G;

size

the size of the automorphism group.

We do not return an automorphism group in the standard form because we wish to distinguish between agAutos and glAutos; the latter act non-trivially on the Frattini quotient of G. This hybrid-group description of the automorphism group permits more efficient computations with it. The following function converts the output of AutomorphismGroupPGroup to the output of AutomorphismGroup.

3.1-2 ConvertHybridAutGroup
‣ ConvertHybridAutGroup( A )( function )

Returns: A record.

Let A be the automorphism group of a \(p\)-group \(G\) as computed by AutomorphismGroupPGroup. Then ConvertHybridAutGroup can compute a pc group isomorphic to the solvable part of A stored in the record component A.agGroup. This solvable part forms a subgroup of the automorphism group which contains at least the automorphisms centralizing the Frattini factor of \(G\). The pc group facilitates various further computations with A.

gap> LoadPackage("autpgrp", false);
true
gap> H := PcGroupCode(297368117289422176, 729);  # SmallGroup (729, 34);
<pc group of size 729 with 6 generators>
gap> A := AutomorphismGroupPGroup(H);
#I  step 1: 3^2 -- init automorphisms
#I  step 2: 3^1 -- aut grp has size 8
#I  step 3: 3^2 -- aut grp has size 72
#I  step 4: 3^1 -- aut grp has size 5832
#I  final step: convert
rec(
  agAutos :=
    [ Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f2, f1, f3^2, f5^2, f4^2, f6^2 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2^2, f3^2*f5, f4^2*f6, f5,
          f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) ->
        [ f1^2, f2^2, f3*f4^2*f5^2*f6, f4^2*f6, f5^2*f6, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f3, f2, f3*f5^2, f4*f6^2, f5,
          f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) ->
        [ f1, f2*f3, f3*f4, f4, f5*f6, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f4, f2, f3*f6^2, f4, f5, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f4, f3, f4, f5, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f5, f2, f3, f4, f5, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f5, f3*f6, f4, f5, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f6, f2, f3, f4, f5, f6 ],
      Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f6, f3, f4, f5, f6 ] ],
  agOrder := [ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 ], glAutos := [  ],
  glOper := [  ], glOrder := 1, group := <pc group of size 729 with
    6 generators>, one := IdentityMapping( <pc group of size 729 with
    6 generators> ), size := 52488 )
gap> ConvertHybridAutGroup( A );
<group of size 52488 with 11 generators>

3.1-3 PcGroupAutPGroup
‣ PcGroupAutPGroup( A )( function )

This function computes a pc presentation for the solvable part of the automorphism group A defined by A.agGroup. A is the output of the function AutomorphismGroupPGroup.

gap> H := PcGroupCode(297368117289422176, 729);;  # SmallGroup (729, 34);
gap> A := AutomorphismGroupPGroup(H);;
#I  step 1: 3^2 -- init automorphisms
#I  step 2: 3^1 -- aut grp has size 8
#I  step 3: 3^2 -- aut grp has size 72
#I  step 4: 3^1 -- aut grp has size 5832
#I  final step: convert
gap> B := PcGroupAutPGroup( A );
<pc group of size 52488 with 11 generators>
gap> I := InnerAutGroupPGroup( B );
Group([ f5, f4^2*f8, f6^2*f9^2, f11^2, f10^2, <identity> of ... ])
Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap4.html0000644000000000000000000004453615202202400012634 0ustar00 GAP (AutPGrp) - Chapter 4: Influencing the algorithm
Goto Chapter: Top 1 2 3 4 5 Ind

4 Influencing the algorithm

A number of choices can be made by the user to influence the performance of AutomorphismGroupPGroup. Below we identify these choices and their default values used in AutomorphismGroup (2.1-1). We use the optional argument flag of AutomorphismGroupPGroup to invoke user-defined choices. The possible values for flag are

flag = false

the user-defined defaults are employed in the algorithm. See below for a list of possibilities.

flag = true

invokes the interactive version of the algorithm as described in Section 4.5.

In the next section we give a brief outline of the algorithm which is necessary to understand the possible choices. Then we introduce the choices the later sections of this chapter.

4.1 Outline of the algorithm

The basic algorithm proceeds by induction down the lower p-central series of a given p-group G; that is, it successively computes Aut(G_i) for the quotients G_i = G / P_i(G) of the descending sequence of subgroups defined by P_1(G) = G and P_i+1(G)=[P_i(G),G] P_i(G)^p for i≥ 1. Hence, in the initial step of the algorithm, Aut(G_2) = GL(d,p) where d is the rank of the elementary abelian group G_2. In the inductive step it determines Aut(G_i+1) from Aut(G_i). For this purpose we introduce an action of Aut(G_i) on a certain elementary abelian p-group M (the p-multiplicator of G_i). The main computation of the inductive step is the determination of the stabiliser in Aut(G_i) of a subgroup U of M (the allowable subgroup for G_i+1). This stabiliser calculation is the bottle-neck of the algorithm.

Our package incorporates a number of refinements designed to simplify this stabiliser computation. Some of these refinements incur overheads and hence they are not always invoked. The features outlined below allow the user to select them.

Observe that the initial step of the algorithm returns GL(d,p). But Aut(G) may induce on G_2 a proper subgroup, say K, of GL(d,p). Any intermediate subgroup of GL(d,p) which contains K suffices for the algorithm and we supply two methods to construct a suitable subgroup: these use characteristic subgroups or invariants of normal subgroups of G. (See Section 4.2.)

In the inductive step an action of Aut(G_i) on an elementary abelian group M is used. This action is computed as a matrix action on a vector space. To simplify the orbit-stabiliser computation of the subspace U of M, we can construct the stabiliser of U by iteration over a sequence of Aut(G_i)-invariant subspaces of M. (See Section 4.3.)

Orbit-stabiliser computations in finite solvable groups given by a polycyclic generating sequence are much more efficient than generic computations of this type. Thus our algorithm makes use of a large solvable normal subgroup S of Aut(G_i). Further, it is useful if the generating set of Aut(G_i) outside S is as small as possible. To achieve this we determine a permutation representation of Aut(G_i)/S and use this to reduce the number of generators if possible. (See Section 4.4.)

4.2 The initialisation step

Assume we seek to compute the automorphism group of a p-group G having Frattini rank d. We first determine as small as possible a subgroup of GL(d, p) whose extension can act on G.

The user can choose the initialisation routine by assigning InitAutGroup to any one of the following:

InitAutomorphismGroupOver

to use the minimal overgroups: We determine the minimal over-groups of the Frattini subgroup of G and compute invariants of these which must be respected by the automorphism group of G. We partition the minimal overgroups and compute the stabiliser in GL(d, p) of this partition.

The partition of the minimal overgroups is computed using the function PGFingerprint( G, U ). This is the time-consuming part of this initialisation method. The user can overwrite the function PGFingerprint.

InitAutomorphismGroupChar

to use the characteristic subgroups: Compute a generating set for the stabiliser in GL (d, p) of a chain of characteristic subgroups of G. In practice, we construct a characteristic chain by determining 2-step centralisers and omega subgroups of factors of the lower p-central series.

However, there are often other characteristic subgroups which are not found by these approaches. The user can overwrite the function PGCharSubgroups( G ) to supply a set of characteristic subgroups.

InitAutomorphismGroupFull

to use the full GL(d,p).

In the method for AutomorphismGroup (2.1-1) we use a default strategy: if the value fracp^d-1p-1 is less than 1000, then we use the minimal overgroup approach, otherwise the characteristic subgroups are employed. An exception is made for homogeneous abelian groups where we initialise the algorithm with the full group GL(d,p).

4.3 Stabilisers in matrix groups

Consider the ith inductive step of the algorithm. Here A ≤ Aut(G_i) acts as matrix group on the elementary abelian p-group M and we want to determine the stabiliser of a subgroup U ≤ M.

We use the MeatAxe to compute a series of A-invariant subspaces through M such that each factor in the series is irreducible as A-module. Then we use this series to break the computation of Stab_A(U) into several smaller orbit-stabiliser calculations.

Note that a theoretic argument yields an A-invariant subspace of M a priori: the nucleus N. This is always used to split the computation up. However, it may happen that N = M and hence results in no improvement.

4.3-1 CHOP_MULT
‣ CHOP_MULT( global variable )

The invariant series through M is computed and used if the global variable CHOP_MULT is set to true. Otherwise, the algorithm tries to determine Stab_A(U) in one step. By default, CHOP_MULT is true.

4.4 Searching for a small generating set

After each step of the computation, we attempt to find a nice generating set for the automorphism group of the current factor.

If the automorphism group is soluble, we store a polycyclic generating set; otherwise, we store such a generating set for a large soluble normal subgroup S of the automorphism group A, and as few generators outside as possible. If S = A and a polycyclic generating set for S is known, many steps of the algorithm proceed more rapidly.

4.4-1 NICE_STAB
‣ NICE_STAB( global variable )

It may be both time-consuming and difficult to reduce the number of generators for A outside S. Note that if the initialisation of the algorithm is by InitAutomorphismGroupOver, then we always know a permutation representation for A/S. Occasionally the search for a small generating set is expensive. If this is observed, one could set the flag NICE_STAB to false and the algorithm no longer invokes this search.

4.5 An interactive version of the algorithm

The choice of initialisation and the choice of chopping of the p-multiplicator can also be driven by an interactive version of the algorithm. We give an example.

gap> G := PcGroupCode(2504972218445939562621471375, 256);;  # SmallGroup( 2^8, 1000 );
gap> SetInfoLevel( InfoAutGrp, 3 );

gap> AutomorphismGroupPGroup( G, true );
#I  step 1: 2^3 -- init automorphisms

choose initialisation (Over/Char/Full):     # we choose Full
#I    init automorphism group : Full
#I  step 2: 2^3 -- aut grp has size 168
#I    computing cover
#I    computing matrix action
#I    computing stabilizer of U
#I    dim U = 3  dim N = 6  dim M = 6

chop M/N and N: (y/n):                      # we choose n
#I    induce autos and add central autos
#I  step 3: 2^2 -- aut grp has size 12288
#I    computing cover
#I    computing matrix action
#I    computing stabilizer of U
#I    dim U = 6  dim N = 5  dim M = 8

chop M/N and N: (y/n):                      # we choose y
#I    induce autos and add central autos
#I  final step: convert
rec(
  glAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f3, f3,
          f4, f5, f6*f7, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f3*f5*f6, f2*f3, f3, f4, f5*f8, f6*f7, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f3, f2*f4, f3, f4*f7, f5*f7, f6*f7*f8, f7, f8 ] ], glOrder := 4,
  agAutos :=
    [ Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f4, f2, f3, f4*f8, f5,
          f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2*f4, f3, f4*f7, f5, f6*f7*f8, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f5, f2, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2*f5, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2, f3*f5, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f6, f2, f3, f4, f5*f7*f8, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2*f6, f3, f4*f7*f8, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f8, f2, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2*f8, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2, f3*f8, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f7, f2, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2*f7, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2, f3*f7, f4, f5, f6, f7, f8 ] ],
  agOrder := [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ],
  one := IdentityMapping( <pc group of size 256 with 8 generators> ),
  group := <pc group of size 256 with 8 generators>, size := 32768 )

Two points are worthy of comment. First, the interactive version of the algorithm permits the user to make a suitable choice in each step of the algorithm instead of making one choice at the beginning. Secondly, the output of the Info function shows the ranks of the p-multiplicator and allowable subgroup, and thus allow the user to observe the scale of difficulty of the computation.

Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap4.txt0000644000000000000000000003377315202202400012510 0ustar00 4 Influencing the algorithm A number of choices can be made by the user to influence the performance of AutomorphismGroupPGroup. Below we identify these choices and their default values used in AutomorphismGroup (2.1-1). We use the optional argument flag of AutomorphismGroupPGroup to invoke user-defined choices. The possible values for flag are flag = false  the user-defined defaults are employed in the algorithm. See below for a list of possibilities. flag = true  invokes the interactive version of the algorithm as described in Section 4.5. In the next section we give a brief outline of the algorithm which is necessary to understand the possible choices. Then we introduce the choices the later sections of this chapter. 4.1 Outline of the algorithm The basic algorithm proceeds by induction down the lower p-central series of a given p-group G; that is, it successively computes Aut(G_i) for the quotients G_i = G / P_i(G) of the descending sequence of subgroups defined by P_1(G) = G and P_i+1(G)=[P_i(G),G] P_i(G)^p for i≥ 1. Hence, in the initial step of the algorithm, Aut(G_2) = GL(d,p) where d is the rank of the elementary abelian group G_2. In the inductive step it determines Aut(G_i+1) from Aut(G_i). For this purpose we introduce an action of Aut(G_i) on a certain elementary abelian p-group M (the p-multiplicator of G_i). The main computation of the inductive step is the determination of the stabiliser in Aut(G_i) of a subgroup U of M (the allowable subgroup for G_i+1). This stabiliser calculation is the bottle-neck of the algorithm. Our package incorporates a number of refinements designed to simplify this stabiliser computation. Some of these refinements incur overheads and hence they are not always invoked. The features outlined below allow the user to select them. Observe that the initial step of the algorithm returns GL(d,p). But Aut(G) may induce on G_2 a proper subgroup, say K, of GL(d,p). Any intermediate subgroup of GL(d,p) which contains K suffices for the algorithm and we supply two methods to construct a suitable subgroup: these use characteristic subgroups or invariants of normal subgroups of G. (See Section 4.2.) In the inductive step an action of Aut(G_i) on an elementary abelian group M is used. This action is computed as a matrix action on a vector space. To simplify the orbit-stabiliser computation of the subspace U of M, we can construct the stabiliser of U by iteration over a sequence of Aut(G_i)-invariant subspaces of M. (See Section 4.3.) Orbit-stabiliser computations in finite solvable groups given by a polycyclic generating sequence are much more efficient than generic computations of this type. Thus our algorithm makes use of a large solvable normal subgroup S of Aut(G_i). Further, it is useful if the generating set of Aut(G_i) outside S is as small as possible. To achieve this we determine a permutation representation of Aut(G_i)/S and use this to reduce the number of generators if possible. (See Section 4.4.) 4.2 The initialisation step Assume we seek to compute the automorphism group of a p-group G having Frattini rank d. We first determine as small as possible a subgroup of GL(d, p) whose extension can act on G. The user can choose the initialisation routine by assigning InitAutGroup to any one of the following: InitAutomorphismGroupOver  to use the minimal overgroups: We determine the minimal over-groups of the Frattini subgroup of G and compute invariants of these which must be respected by the automorphism group of G. We partition the minimal overgroups and compute the stabiliser in GL(d, p) of this partition. The partition of the minimal overgroups is computed using the function PGFingerprint( G, U ). This is the time-consuming part of this initialisation method. The user can overwrite the function PGFingerprint. InitAutomorphismGroupChar  to use the characteristic subgroups: Compute a generating set for the stabiliser in GL (d, p) of a chain of characteristic subgroups of G. In practice, we construct a characteristic chain by determining 2-step centralisers and omega subgroups of factors of the lower p-central series. However, there are often other characteristic subgroups which are not found by these approaches. The user can overwrite the function PGCharSubgroups( G ) to supply a set of characteristic subgroups. InitAutomorphismGroupFull  to use the full GL(d,p). In the method for AutomorphismGroup (2.1-1) we use a default strategy: if the value fracp^d-1p-1 is less than 1000, then we use the minimal overgroup approach, otherwise the characteristic subgroups are employed. An exception is made for homogeneous abelian groups where we initialise the algorithm with the full group GL(d,p). 4.3 Stabilisers in matrix groups Consider the ith inductive step of the algorithm. Here A ≤ Aut(G_i) acts as matrix group on the elementary abelian p-group M and we want to determine the stabiliser of a subgroup U ≤ M. We use the MeatAxe to compute a series of A-invariant subspaces through M such that each factor in the series is irreducible as A-module. Then we use this series to break the computation of Stab_A(U) into several smaller orbit-stabiliser calculations. Note that a theoretic argument yields an A-invariant subspace of M a priori: the nucleus N. This is always used to split the computation up. However, it may happen that N = M and hence results in no improvement. 4.3-1 CHOP_MULT CHOP_MULT  global variable The invariant series through M is computed and used if the global variable CHOP_MULT is set to true. Otherwise, the algorithm tries to determine Stab_A(U) in one step. By default, CHOP_MULT is true. 4.4 Searching for a small generating set After each step of the computation, we attempt to find a nice generating set for the automorphism group of the current factor. If the automorphism group is soluble, we store a polycyclic generating set; otherwise, we store such a generating set for a large soluble normal subgroup S of the automorphism group A, and as few generators outside as possible. If S = A and a polycyclic generating set for S is known, many steps of the algorithm proceed more rapidly. 4.4-1 NICE_STAB NICE_STAB  global variable It may be both time-consuming and difficult to reduce the number of generators for A outside S. Note that if the initialisation of the algorithm is by InitAutomorphismGroupOver, then we always know a permutation representation for A/S. Occasionally the search for a small generating set is expensive. If this is observed, one could set the flag NICE_STAB to false and the algorithm no longer invokes this search. 4.5 An interactive version of the algorithm The choice of initialisation and the choice of chopping of the p-multiplicator can also be driven by an interactive version of the algorithm. We give an example.  Example  gap> G := PcGroupCode(2504972218445939562621471375, 256);; # SmallGroup( 2^8, 1000 ); gap> SetInfoLevel( InfoAutGrp, 3 );  gap> AutomorphismGroupPGroup( G, true ); #I step 1: 2^3 -- init automorphisms  choose initialisation (Over/Char/Full): # we choose Full #I init automorphism group : Full #I step 2: 2^3 -- aut grp has size 168 #I computing cover #I computing matrix action #I computing stabilizer of U #I dim U = 3 dim N = 6 dim M = 6  chop M/N and N: (y/n): # we choose n #I induce autos and add central autos #I step 3: 2^2 -- aut grp has size 12288 #I computing cover #I computing matrix action #I computing stabilizer of U #I dim U = 6 dim N = 5 dim M = 8  chop M/N and N: (y/n): # we choose y #I induce autos and add central autos #I final step: convert rec(  glAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f3, f3,  f4, f5, f6*f7, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1*f3*f5*f6, f2*f3, f3, f4, f5*f8, f6*f7, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1*f3, f2*f4, f3, f4*f7, f5*f7, f6*f7*f8, f7, f8 ] ], glOrder := 4,  agAutos :=  [ Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f4, f2, f3, f4*f8, f5,  f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1, f2*f4, f3, f4*f7, f5, f6*f7*f8, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1*f5, f2, f3, f4, f5, f6, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1, f2*f5, f3, f4, f5, f6, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1, f2, f3*f5, f4, f5, f6, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1*f6, f2, f3, f4, f5*f7*f8, f6, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1, f2*f6, f3, f4*f7*f8, f5, f6, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1*f8, f2, f3, f4, f5, f6, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1, f2*f8, f3, f4, f5, f6, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1, f2, f3*f8, f4, f5, f6, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1*f7, f2, f3, f4, f5, f6, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1, f2*f7, f3, f4, f5, f6, f7, f8 ],  Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->  [ f1, f2, f3*f7, f4, f5, f6, f7, f8 ] ],  agOrder := [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ],  one := IdentityMapping( ),  group := , size := 32768 )  Two points are worthy of comment. First, the interactive version of the algorithm permits the user to make a suitable choice in each step of the algorithm instead of making one choice at the beginning. Secondly, the output of the Info function shows the ranks of the p-multiplicator and allowable subgroup, and thus allow the user to observe the scale of difficulty of the computation. autpgrp-1.12.0/doc/chap4_mj.html0000644000000000000000000004562715202202400013324 0ustar00 GAP (AutPGrp) - Chapter 4: Influencing the algorithm
Goto Chapter: Top 1 2 3 4 5 Ind

4 Influencing the algorithm

A number of choices can be made by the user to influence the performance of AutomorphismGroupPGroup. Below we identify these choices and their default values used in AutomorphismGroup (2.1-1). We use the optional argument flag of AutomorphismGroupPGroup to invoke user-defined choices. The possible values for flag are

flag = false

the user-defined defaults are employed in the algorithm. See below for a list of possibilities.

flag = true

invokes the interactive version of the algorithm as described in Section 4.5.

In the next section we give a brief outline of the algorithm which is necessary to understand the possible choices. Then we introduce the choices the later sections of this chapter.

4.1 Outline of the algorithm

The basic algorithm proceeds by induction down the lower \(p\)-central series of a given \(p\)-group \(G\); that is, it successively computes \(Aut(G_i)\) for the quotients \(G_i = G / P_i(G)\) of the descending sequence of subgroups defined by \(P_1(G) = G\) and \(P_{i+1}(G)=[P_i(G),G] P_i(G)^p\) for \(i\geq 1\). Hence, in the initial step of the algorithm, \(Aut(G_2) = GL(d,p)\) where \(d\) is the rank of the elementary abelian group \(G_2\). In the inductive step it determines \(Aut(G_{i+1})\) from \(Aut(G_i)\). For this purpose we introduce an action of \(Aut(G_i)\) on a certain elementary abelian \(p\)-group \(M\) (the \(p\)-multiplicator of \(G_i\)). The main computation of the inductive step is the determination of the stabiliser in \(Aut(G_i)\) of a subgroup \(U\) of \(M\) (the allowable subgroup for \(G_{i+1}\)). This stabiliser calculation is the bottle-neck of the algorithm.

Our package incorporates a number of refinements designed to simplify this stabiliser computation. Some of these refinements incur overheads and hence they are not always invoked. The features outlined below allow the user to select them.

Observe that the initial step of the algorithm returns \(GL(d,p)\). But \(Aut(G)\) may induce on \(G_2\) a proper subgroup, say \(K\), of \(GL(d,p)\). Any intermediate subgroup of \(GL(d,p)\) which contains \(K\) suffices for the algorithm and we supply two methods to construct a suitable subgroup: these use characteristic subgroups or invariants of normal subgroups of \(G\). (See Section 4.2.)

In the inductive step an action of \(Aut(G_i)\) on an elementary abelian group \(M\) is used. This action is computed as a matrix action on a vector space. To simplify the orbit-stabiliser computation of the subspace \(U\) of \(M\), we can construct the stabiliser of \(U\) by iteration over a sequence of \(Aut(G_i)\)-invariant subspaces of \(M\). (See Section 4.3.)

Orbit-stabiliser computations in finite solvable groups given by a polycyclic generating sequence are much more efficient than generic computations of this type. Thus our algorithm makes use of a large solvable normal subgroup \(S\) of \(Aut(G_i)\). Further, it is useful if the generating set of \(Aut(G_i)\) outside \(S\) is as small as possible. To achieve this we determine a permutation representation of \(Aut(G_i)/S\) and use this to reduce the number of generators if possible. (See Section 4.4.)

4.2 The initialisation step

Assume we seek to compute the automorphism group of a \(p\)-group \(G\) having Frattini rank \(d\). We first determine as small as possible a subgroup of \(GL(d, p)\) whose extension can act on \(G\).

The user can choose the initialisation routine by assigning InitAutGroup to any one of the following:

InitAutomorphismGroupOver

to use the minimal overgroups: We determine the minimal over-groups of the Frattini subgroup of \(G\) and compute invariants of these which must be respected by the automorphism group of \(G\). We partition the minimal overgroups and compute the stabiliser in \(GL(d, p)\) of this partition.

The partition of the minimal overgroups is computed using the function PGFingerprint( G, U ). This is the time-consuming part of this initialisation method. The user can overwrite the function PGFingerprint.

InitAutomorphismGroupChar

to use the characteristic subgroups: Compute a generating set for the stabiliser in \(GL (d, p)\) of a chain of characteristic subgroups of \(G\). In practice, we construct a characteristic chain by determining 2-step centralisers and omega subgroups of factors of the lower \(p\)-central series.

However, there are often other characteristic subgroups which are not found by these approaches. The user can overwrite the function PGCharSubgroups( G ) to supply a set of characteristic subgroups.

InitAutomorphismGroupFull

to use the full \(GL(d,p)\).

In the method for AutomorphismGroup (2.1-1) we use a default strategy: if the value \(\frac{p^d-1}{p-1}\) is less than 1000, then we use the minimal overgroup approach, otherwise the characteristic subgroups are employed. An exception is made for homogeneous abelian groups where we initialise the algorithm with the full group \(GL(d,p)\).

4.3 Stabilisers in matrix groups

Consider the \(i\)th inductive step of the algorithm. Here \(A \leq Aut(G_i)\) acts as matrix group on the elementary abelian \(p\)-group \(M\) and we want to determine the stabiliser of a subgroup \(U \leq M\).

We use the MeatAxe to compute a series of \(A\)-invariant subspaces through \(M\) such that each factor in the series is irreducible as \(A\)-module. Then we use this series to break the computation of \(Stab_A(U)\) into several smaller orbit-stabiliser calculations.

Note that a theoretic argument yields an \(A\)-invariant subspace of \(M\) a priori: the nucleus \(N\). This is always used to split the computation up. However, it may happen that \(N = M\) and hence results in no improvement.

4.3-1 CHOP_MULT
‣ CHOP_MULT( global variable )

The invariant series through \(M\) is computed and used if the global variable CHOP_MULT is set to true. Otherwise, the algorithm tries to determine \(Stab_A(U)\) in one step. By default, CHOP_MULT is true.

4.4 Searching for a small generating set

After each step of the computation, we attempt to find a nice generating set for the automorphism group of the current factor.

If the automorphism group is soluble, we store a polycyclic generating set; otherwise, we store such a generating set for a large soluble normal subgroup \(S\) of the automorphism group \(A\), and as few generators outside as possible. If \(S = A\) and a polycyclic generating set for \(S\) is known, many steps of the algorithm proceed more rapidly.

4.4-1 NICE_STAB
‣ NICE_STAB( global variable )

It may be both time-consuming and difficult to reduce the number of generators for \(A\) outside \(S\). Note that if the initialisation of the algorithm is by InitAutomorphismGroupOver, then we always know a permutation representation for \(A/S\). Occasionally the search for a small generating set is expensive. If this is observed, one could set the flag NICE_STAB to false and the algorithm no longer invokes this search.

4.5 An interactive version of the algorithm

The choice of initialisation and the choice of chopping of the \(p\)-multiplicator can also be driven by an interactive version of the algorithm. We give an example.

gap> G := PcGroupCode(2504972218445939562621471375, 256);;  # SmallGroup( 2^8, 1000 );
gap> SetInfoLevel( InfoAutGrp, 3 );

gap> AutomorphismGroupPGroup( G, true );
#I  step 1: 2^3 -- init automorphisms

choose initialisation (Over/Char/Full):     # we choose Full
#I    init automorphism group : Full
#I  step 2: 2^3 -- aut grp has size 168
#I    computing cover
#I    computing matrix action
#I    computing stabilizer of U
#I    dim U = 3  dim N = 6  dim M = 6

chop M/N and N: (y/n):                      # we choose n
#I    induce autos and add central autos
#I  step 3: 2^2 -- aut grp has size 12288
#I    computing cover
#I    computing matrix action
#I    computing stabilizer of U
#I    dim U = 6  dim N = 5  dim M = 8

chop M/N and N: (y/n):                      # we choose y
#I    induce autos and add central autos
#I  final step: convert
rec(
  glAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f3, f3,
          f4, f5, f6*f7, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f3*f5*f6, f2*f3, f3, f4, f5*f8, f6*f7, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f3, f2*f4, f3, f4*f7, f5*f7, f6*f7*f8, f7, f8 ] ], glOrder := 4,
  agAutos :=
    [ Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f4, f2, f3, f4*f8, f5,
          f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2*f4, f3, f4*f7, f5, f6*f7*f8, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f5, f2, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2*f5, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2, f3*f5, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f6, f2, f3, f4, f5*f7*f8, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2*f6, f3, f4*f7*f8, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f8, f2, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2*f8, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2, f3*f8, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1*f7, f2, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2*f7, f3, f4, f5, f6, f7, f8 ],
      Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) ->
        [ f1, f2, f3*f7, f4, f5, f6, f7, f8 ] ],
  agOrder := [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ],
  one := IdentityMapping( <pc group of size 256 with 8 generators> ),
  group := <pc group of size 256 with 8 generators>, size := 32768 )

Two points are worthy of comment. First, the interactive version of the algorithm permits the user to make a suitable choice in each step of the algorithm instead of making one choice at the beginning. Secondly, the output of the Info function shows the ranks of the \(p\)-multiplicator and allowable subgroup, and thus allow the user to observe the scale of difficulty of the computation.

Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap5.html0000644000000000000000000001370615202202400012630 0ustar00 GAP (AutPGrp) - Chapter 5: Additional features of the package
Goto Chapter: Top 1 2 3 4 5 Ind

5 Additional features of the package

5.1 Additional features of the package

As an additional feature of this package we provide some functions to count extensions of p-groups and Lie algebras over GF(p). These functions have been used in counting the 2-groups of size 2^10.

5.1-1 NumberOfPClass2PGroups
‣ NumberOfPClass2PGroups( n, p, k )( operation )

This function determines the number of n-generator p-groups of p-class 2 with Frattini subgroup of order 2^k.

5.1-2 NumberOfPClass2PGroups
‣ NumberOfPClass2PGroups( n, p )( operation )

This function returns a list of of numbers of n-generator p-groups of p-class 2 with Frattini subgroup of order 2^k for k in 1, ..., n(n+1)/2.

5.1-3 NumberOfClass2LieAlgebras
‣ NumberOfClass2LieAlgebras( n, p, k )( operation )

This function determines the number of n-generator Lie algebras of class 2 over GF(p) with derived Lie subalgebra of dimension k.

5.1-4 NumberOfClass2LieAlgbras
‣ NumberOfClass2LieAlgbras( n, p )( operation )

This function returns a list of of numbers of n-generator Lie algebras of class 2 over GF(p) with derived Lie subalgebra of dimension k for k in 1, ..., n(n-1)/2.

 

Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chap5.txt0000644000000000000000000000362315202202400012500 0ustar00 5 Additional features of the package 5.1 Additional features of the package As an additional feature of this package we provide some functions to count extensions of p-groups and Lie algebras over GF(p). These functions have been used in counting the 2-groups of size 2^10. 5.1-1 NumberOfPClass2PGroups NumberOfPClass2PGroups( n, p, k )  operation This function determines the number of n-generator p-groups of p-class 2 with Frattini subgroup of order 2^k. 5.1-2 NumberOfPClass2PGroups NumberOfPClass2PGroups( n, p )  operation This function returns a list of of numbers of n-generator p-groups of p-class 2 with Frattini subgroup of order 2^k for k in 1, ..., n(n+1)/2. 5.1-3 NumberOfClass2LieAlgebras NumberOfClass2LieAlgebras( n, p, k )  operation This function determines the number of n-generator Lie algebras of class 2 over GF(p) with derived Lie subalgebra of dimension k. 5.1-4 NumberOfClass2LieAlgbras NumberOfClass2LieAlgbras( n, p )  operation This function returns a list of of numbers of n-generator Lie algebras of class 2 over GF(p) with derived Lie subalgebra of dimension k for k in 1, ..., n(n-1)/2.   autpgrp-1.12.0/doc/chap5_mj.html0000644000000000000000000001430515202202400013312 0ustar00 GAP (AutPGrp) - Chapter 5: Additional features of the package
Goto Chapter: Top 1 2 3 4 5 Ind

5 Additional features of the package

5.1 Additional features of the package

As an additional feature of this package we provide some functions to count extensions of \(p\)-groups and Lie algebras over \(GF(p)\). These functions have been used in counting the \(2\)-groups of size \(2^{10}\).

5.1-1 NumberOfPClass2PGroups
‣ NumberOfPClass2PGroups( n, p, k )( operation )

This function determines the number of n-generator p-groups of p-class 2 with Frattini subgroup of order 2^k.

5.1-2 NumberOfPClass2PGroups
‣ NumberOfPClass2PGroups( n, p )( operation )

This function returns a list of of numbers of n-generator p-groups of p-class 2 with Frattini subgroup of order 2^k for k in \(1, \ldots, n(n+1)/2\).

5.1-3 NumberOfClass2LieAlgebras
‣ NumberOfClass2LieAlgebras( n, p, k )( operation )

This function determines the number of n-generator Lie algebras of class 2 over GF(p) with derived Lie subalgebra of dimension k.

5.1-4 NumberOfClass2LieAlgbras
‣ NumberOfClass2LieAlgbras( n, p )( operation )

This function returns a list of of numbers of n-generator Lie algebras of class 2 over \(GF(p)\) with derived Lie subalgebra of dimension \(k\) for \(k\) in \(1, \ldots, n(n-1)/2\).

 

Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chapInd.html0000644000000000000000000000600215202202400013165 0ustar00 GAP (AutPGrp) - Index
Goto Chapter: Top 1 2 3 4 5 Ind

Index

AutomorphismGroup 2.1-1
AutomorphismGroupPGroup 3.1-1
CHOP_MULT 4.3-1
ConvertHybridAutGroup 3.1-2
InfoAutGrp 2.1-2
NICE_STAB 4.4-1
NumberOfClass2LieAlgbras, for 2 arguments 5.1-4
NumberOfClass2LieAlgebras, for 3 arguments 5.1-3
NumberOfPClass2PGroups, for 2 arguments 5.1-2
    for 3 arguments 5.1-1
PcGroupAutPGroup 3.1-3

Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chapInd.txt0000644000000000000000000000104315202202400013040 0ustar00 Index AutomorphismGroup 2.1-1 AutomorphismGroupPGroup 3.1-1 CHOP_MULT 4.3-1 ConvertHybridAutGroup 3.1-2 InfoAutGrp 2.1-2 NICE_STAB 4.4-1 NumberOfClass2LieAlgbras, for 2 arguments 5.1-4 NumberOfClass2LieAlgebras, for 3 arguments 5.1-3 NumberOfPClass2PGroups, for 2 arguments 5.1-2 for 3 arguments 5.1-1 PcGroupAutPGroup 3.1-3 ------------------------------------------------------- autpgrp-1.12.0/doc/chapInd_mj.html0000644000000000000000000000633615202202400013665 0ustar00 GAP (AutPGrp) - Index
Goto Chapter: Top 1 2 3 4 5 Ind

Index

AutomorphismGroup 2.1-1
AutomorphismGroupPGroup 3.1-1
CHOP_MULT 4.3-1
ConvertHybridAutGroup 3.1-2
InfoAutGrp 2.1-2
NICE_STAB 4.4-1
NumberOfClass2LieAlgbras, for 2 arguments 5.1-4
NumberOfClass2LieAlgebras, for 3 arguments 5.1-3
NumberOfPClass2PGroups, for 2 arguments 5.1-2
    for 3 arguments 5.1-1
PcGroupAutPGroup 3.1-3

Goto Chapter: Top 1 2 3 4 5 Ind

generated by GAPDoc2HTML

autpgrp-1.12.0/doc/chooser.html0000644000000000000000000001130415202202400013262 0ustar00 GAPDoc Style Chooser

Setting preferences for GAPDoc manuals

Unfold subsections in menus only by mouse clicks: no (default)     yes

Show GAP examples as in sessions with ColorPrompt(true): yes (default)     no

Display side of table of contents within chapters: right (default)     left

Main document font: Helvetica/sans serif (default)     Times/serif

Paragraph formatting: left-right justified (default)     ragged right

Appearance: system (default)     light dark

Apply settings to last page.

autpgrp-1.12.0/doc/dark.css0000644000000000000000000000515115202202400012370 0ustar00/* dark.css Frank Luebeck */ /* Initial dark theme contributed by kiryph in issue #75. */ /* colors */ body { background: #121212; color: #eee; } a:link { color: #576cad; } a:visited { color: #576cad; } a:active { color: #eee; } a:hover { background: #eee; } pre { color: black; } tt, code { color: #eee; } /* layout for the definitions of functions, variables, ... */ div.func { background: #909090; } /* Example elements (for old converted manuals, now in div+pre */ table.example { background: #efefef; } /* becomes ... */ div.example { background: #efefef; color: black; } /* Links to chapters in all files at top and bottom. */ div.chlinktop { background: #22272e; border-color: #3a414a; color: #d7dde5; } div.chlinktop a:hover { background: #2f3742; } div.chlinkbot { background: #22272e; border-color: #3a414a; color: #d7dde5; } /* and this is for the "Top", "Prev", "Next" links */ div.chlinkprevnexttop { background: #22272e; border-color: #3a414a; color: #d7dde5; } div.chlinkprevnexttop a:hover { background: #2f3742; } div.chlinkprevnextbot { background: #22272e; border-color: #3a414a; color: #d7dde5; } div.chlinkprevnextbot a:hover { background: #2f3742; } div.ContChap div.ContSect:hover div.ContSSBlock { background: #eee; border-color: #666; color: #000; } div.ContSSBlock a:hover { background: #fff; } /* and here for the side menu of contents in the chapter files */ div.ChapSects a:hover { background: #eee; color: #000; } div.ChapSects div.ContSect:hover div.ContSSBlock { background: #b5b5b5; border-color: #666; color: #000; } div.ChapSects div.ContSect:hover div.ContSSBlock a:hover { background: #828282; } /* Table elements */ table.GAPDocTable { border-color: black; } table.GAPDocTable td, table.GAPDocTable th { border-color: #555; } table.GAPDocTablenoborder td, table.GAPDocTable th { border-color: #555; } /* Colors and fonts can be overwritten for some types of elements. */ /* Verb elements */ pre.normal { color: #eee; } /* Func-like elements and Ref to Func-like */ code.func { color: #eee; } /* K elements */ code.keyw { color: #983d3d; } /* F elements */ code.file { color: #8e4510; } /* Arg elements */ var.Arg { color: #060; } /* colors for ColorPrompt like examples */ span.GAPprompt { color: #000097; } span.GAPbrkprompt { color: #970000; } span.GAPinput { color: #970000; } /* Bib entries */ span.BibKey { color: #052; } /* for light and dark mode pictures */ .only-on-dark { display: block; } .only-on-light { display: none; } autpgrp-1.12.0/doc/influen.xml0000644000000000000000000002701315202202400013120 0ustar00 Influencing the algorithm A number of choices can be made by the user to influence the performance of AutomorphismGroupPGroup. Below we identify these choices and their default values used in . We use the optional argument flag of AutomorphismGroupPGroup to invoke user-defined choices. The possible values for flag are

flag = false the user-defined defaults are employed in the algorithm. See below for a list of possibilities. flag = true invokes the interactive version of the algorithm as described in Section .

In the next section we give a brief outline of the algorithm which is necessary to understand the possible choices. Then we introduce the choices the later sections of this chapter.

Outline of the algorithm The basic algorithm proceeds by induction down the lower p-central series of a given p-group G; that is, it successively computes Aut(G_i) for the quotients G_i = G / P_i(G) of the descending sequence of subgroups defined by P_1(G) = G and P_{i+1}(G)=[P_i(G),G] P_i(G)^p for i\geq 1. Hence, in the initial step of the algorithm, Aut(G_2) = GL(d,p) where d is the rank of the elementary abelian group G_2. In the inductive step it determines Aut(G_{i+1}) from Aut(G_i). For this purpose we introduce an action of Aut(G_i) on a certain elementary abelian p-group M (the p-multiplicator of G_i). The main computation of the inductive step is the determination of the stabiliser in Aut(G_i) of a subgroup U of M (the allowable subgroup for G_{i+1}). This stabiliser calculation is the bottle-neck of the algorithm.

Our package incorporates a number of refinements designed to simplify this stabiliser computation. Some of these refinements incur overheads and hence they are not always invoked. The features outlined below allow the user to select them.

Observe that the initial step of the algorithm returns GL(d,p). But Aut(G) may induce on G_2 a proper subgroup, say K, of GL(d,p). Any intermediate subgroup of GL(d,p) which contains K suffices for the algorithm and we supply two methods to construct a suitable subgroup: these use characteristic subgroups or invariants of normal subgroups of G. (See Section .)

In the inductive step an action of Aut(G_i) on an elementary abelian group M is used. This action is computed as a matrix action on a vector space. To simplify the orbit-stabiliser computation of the subspace U of M, we can construct the stabiliser of U by iteration over a sequence of Aut(G_i)-invariant subspaces of M. (See Section .)

Orbit-stabiliser computations in finite solvable groups given by a polycyclic generating sequence are much more efficient than generic computations of this type. Thus our algorithm makes use of a large solvable normal subgroup S of Aut(G_i). Further, it is useful if the generating set of Aut(G_i) outside S is as small as possible. To achieve this we determine a permutation representation of Aut(G_i)/S and use this to reduce the number of generators if possible. (See Section .)

The initialisation step Assume we seek to compute the automorphism group of a p-group G having Frattini rank d. We first determine as small as possible a subgroup of GL(d, p) whose extension can act on G.

The user can choose the initialisation routine by assigning InitAutGroup to any one of the following: InitAutomorphismGroupOver to use the minimal overgroups: We determine the minimal over-groups of the Frattini subgroup of G and compute invariants of these which must be respected by the automorphism group of G. We partition the minimal overgroups and compute the stabiliser in GL(d, p) of this partition.

The partition of the minimal overgroups is computed using the function PGFingerprint( G, U ). This is the time-consuming part of this initialisation method. The user can overwrite the function PGFingerprint. InitAutomorphismGroupChar to use the characteristic subgroups: Compute a generating set for the stabiliser in GL (d, p) of a chain of characteristic subgroups of G. In practice, we construct a characteristic chain by determining 2-step centralisers and omega subgroups of factors of the lower p-central series.

However, there are often other characteristic subgroups which are not found by these approaches. The user can overwrite the function PGCharSubgroups( G ) to supply a set of characteristic subgroups. InitAutomorphismGroupFull to use the full GL(d,p). In the method for we use a default strategy: if the value \frac{p^d-1}{p-1} is less than 1000, then we use the minimal overgroup approach, otherwise the characteristic subgroups are employed. An exception is made for homogeneous abelian groups where we initialise the algorithm with the full group GL(d,p).

Stabilisers in matrix groups Consider the ith inductive step of the algorithm. Here A \leq Aut(G_i) acts as matrix group on the elementary abelian p-group M and we want to determine the stabiliser of a subgroup U \leq M.

We use the MeatAxe to compute a series of A-invariant subspaces through M such that each factor in the series is irreducible as A-module. Then we use this series to break the computation of Stab_A(U) into several smaller orbit-stabiliser calculations.

Note that a theoretic argument yields an A-invariant subspace of M a priori: the nucleus N. This is always used to split the computation up. However, it may happen that N = M and hence results in no improvement. The invariant series through M is computed and used if the global variable CHOP_MULT is set to true. Otherwise, the algorithm tries to determine Stab_A(U) in one step. By default, CHOP_MULT is true.

Searching for a small generating set After each step of the computation, we attempt to find a nice generating set for the automorphism group of the current factor.

If the automorphism group is soluble, we store a polycyclic generating set; otherwise, we store such a generating set for a large soluble normal subgroup S of the automorphism group A, and as few generators outside as possible. If S = A and a polycyclic generating set for S is known, many steps of the algorithm proceed more rapidly. It may be both time-consuming and difficult to reduce the number of generators for A outside S. Note that if the initialisation of the algorithm is by InitAutomorphismGroupOver, then we always know a permutation representation for A/S. Occasionally the search for a small generating set is expensive. If this is observed, one could set the flag NICE_STAB to false and the algorithm no longer invokes this search.

An interactive version of the algorithm The choice of initialisation and the choice of chopping of the p-multiplicator can also be driven by an interactive version of the algorithm. We give an example.

G := PcGroupCode(2504972218445939562621471375, 256);; # SmallGroup( 2^8, 1000 ); gap> SetInfoLevel( InfoAutGrp, 3 ); gap> AutomorphismGroupPGroup( G, true ); #I step 1: 2^3 -- init automorphisms choose initialisation (Over/Char/Full): # we choose Full #I init automorphism group : Full #I step 2: 2^3 -- aut grp has size 168 #I computing cover #I computing matrix action #I computing stabilizer of U #I dim U = 3 dim N = 6 dim M = 6 chop M/N and N: (y/n): # we choose n #I induce autos and add central autos #I step 3: 2^2 -- aut grp has size 12288 #I computing cover #I computing matrix action #I computing stabilizer of U #I dim U = 6 dim N = 5 dim M = 8 chop M/N and N: (y/n): # we choose y #I induce autos and add central autos #I final step: convert rec( glAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f3, f3, f4, f5, f6*f7, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f3*f5*f6, f2*f3, f3, f4, f5*f8, f6*f7, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f3, f2*f4, f3, f4*f7, f5*f7, f6*f7*f8, f7, f8 ] ], glOrder := 4, agAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f4, f2, f3, f4*f8, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f4, f3, f4*f7, f5, f6*f7*f8, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f5, f2, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f5, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2, f3*f5, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f6, f2, f3, f4, f5*f7*f8, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f6, f3, f4*f7*f8, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f8, f2, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f8, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2, f3*f8, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1*f7, f2, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2*f7, f3, f4, f5, f6, f7, f8 ], Pcgs([ f1, f2, f3, f4, f5, f6, f7, f8 ]) -> [ f1, f2, f3*f7, f4, f5, f6, f7, f8 ] ], agOrder := [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ], one := IdentityMapping( ), group := , size := 32768 ) ]]>

Two points are worthy of comment. First, the interactive version of the algorithm permits the user to make a suitable choice in each step of the algorithm instead of making one choice at the beginning. Secondly, the output of the Info function shows the ranks of the p-multiplicator and allowable subgroup, and thus allow the user to observe the scale of difficulty of the computation.

autpgrp-1.12.0/doc/intro.xml0000644000000000000000000000512715202202400012615 0ustar00 Introduction
Introduction Given an arbitrary finite group, the computation of its automorphism group is a very difficult task. Pioneer work in this area was carried out by Felsch and Neubueser (1970), whose algorithm used the output of their subgroup lattice program. A technique developed by Neubueser in the early 1970s sought to compute the automorphism group viewed as a permutation group acting on unions of certain conjugacy classes of the group. A similar method was implemented by Hulpke (1997) in the &GAP; 4 library. Recently, Cannon and Holt (1999) presented a new algorithm which uses a hybrid group approach.

More efficient approaches are available to determine the automorphism group for groups satisfying certain properties. Following the work of Shoda (1928), Hulpke in 1997 implemented a practical method for finite abelian groups in the &GAP; 4 library. Wursthorn (1993) adapted modular group algebra techniques to compute the automorphism groups of p-groups; the &GAP; 3 share package Sisyphos includes an implementation. Smith (1994) introduced an algorithm for finite solvable groups which is available in the AutAg share package of &GAP; 3.

Moreover, the p-group generation method of Newman (1977) and O'Brien (1990) can be modified to compute the automorphism group of a finite p-group as outlined in O'Brien (1995). This algorithm is implemented in the ANU pq C program.

Here we introduce a new function to compute the automorphism group of a finite p-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANU pq method. Our package is written in &GAP; code and it makes use of a number of methods from the &GAP; library such as the MeatAxe for matrix groups and permutation group functions.

The &GAP; 4 package ANUPQ, which is an interface to most of the functionality of the ANU pq C program, uses the &AUTPGRP; package to compute automorphism groups of p-groups.

We have compared our method to the others available in &GAP;. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed.

autpgrp-1.12.0/doc/lefttoc.css0000644000000000000000000000047415202202400013112 0ustar00/* leftmenu.css Frank Lübeck */ /* Change default CSS to show section menu on left side */ body { padding-left: 28%; } body.chap0 { padding-left: 2%; } div.ChapSects div.ContSect:hover div.ContSSBlock { left: 15%; } div.ChapSects { left: 1%; width: 25%; } autpgrp-1.12.0/doc/manual.css0000644000000000000000000001606615202202400012733 0ustar00/* manual.css Frank Lübeck */ /* This is the default CSS style sheet for GAPDoc HTML manuals. */ /* basic settings, fonts, sizes, colors, ... */ body { position: relative; background: #ffffff; color: #000000; width: 70%; margin: 0pt; padding: 15pt; font-family: Helvetica,Verdana,Arial,sans-serif; text-align: justify; } /* no side toc on title page, bib and index */ body.chap0 { width: 95%; } body.chapBib { width: 95%; } body.chapInd { width: 95%; } h1 { font-size: 200%; } h2 { font-size: 160%; } h3 { font-size: 160%; } h4 { font-size: 130%; } h5 { font-size: 100%; } p.foot { font-size: 60%; font-style: normal; } a:link { color: #00008e; text-decoration: none; } a:visited { color: #00008e; text-decoration: none; } a:active { color: #000000; text-decoration: none; } a:hover { background: #eeeeee; } pre { font-family: "Courier New",Courier,monospace; font-size: 100%; color:#111111; } tt,code { font-family: "Courier New",Courier,monospace; font-size: 110%; color: #000000; } var { } /* general alignment classes */ .pcenter { text-align: center; } .pleft { text-align: left; } .pright { text-align: right; } /* layout for the definitions of functions, variables, ... */ div.func { background: #e0e0e0; margin: 0pt 0pt; } /* general and special table settings */ table { border-collapse: collapse; margin-left: auto; margin-right: auto; } td, th { border-style: none; } table.func { padding: 0pt 1ex; margin-left: 1ex; margin-right: 1ex; background: transparent; /* line-height: 1.1; */ width: 100%; } table.func td.tdright { padding-right: 2ex; } /* Example elements (for old converted manuals, now in div+pre */ table.example { background: #efefef; border-style: none; border-width: 0pt; padding: 0px; width: 100% } table.example td { border-style: none; border-width: 0pt; padding: 0ex 1ex; } /* becomes ... */ div.example { background: #efefef; padding: 0ex 1ex; /* overflow-x: auto; */ overflow: auto; } /* Links to chapters in all files at top and bottom. */ /* If there are too many chapters then use 'display: none' here. */ div.chlinktop { background: #dddddd; border-style: solid; border-width: thin; margin: 2px; text-align: center; } div.chlinktop a { margin: 3px; } div.chlinktop a:hover { background: #ffffff; } div.chlinkbot { background: #dddddd; border-style: solid; border-width: thin; margin: 2px; text-align: center; /* width: 100%; */ } div.chlinkbot a { margin: 3px; } span.chlink1 { } /* and this is for the "Top", "Prev", "Next" links */ div.chlinkprevnexttop { background: #dddddd; border-style: solid; border-width: thin; text-align: center; margin: 2px; } div.chlinkprevnexttop a:hover { background: #ffffff; } div.chlinkprevnextbot { background: #dddddd; border-style: solid; border-width: thin; text-align: center; margin: 2px; } div.chlinkprevnextbot a:hover { background: #ffffff; } /* table of contents, initially don't display subsections */ div.ContSSBlock { display: none; } div.ContSSBlock br { display: none; } /* format in separate lines */ span.tocline { display: block; width: 100%; } div.ContSSBlock a { display: block; } /* this is for the main table of contents */ div.ContChap { } div.ContChap div.ContSect:hover div.ContSSBlock { display: block; position: absolute; background: #eeeeee; border-style: solid; border-width: 1px 4px 4px 1px; border-color: #666666; padding-left: 0.5ex; color: #000000; left: 20%; width: 40%; z-index: 10000; } div.ContSSBlock a:hover { background: #ffffff; } /* and here for the side menu of contents in the chapter files */ div.ChapSects { } div.ChapSects a:hover { background: #eeeeee; } div.ChapSects a:hover { display: block; width: 100%; background: #eeeeee; color: #000000; } div.ChapSects div.ContSect:hover div.ContSSBlock { display: block; position: fixed; background: #eeeeee; border-style: solid; border-width: 1px 2px 2px 1px; border-color: #666666; padding-left: 0ex; padding-right: 0.5ex; color: #000000; left: 54%; width: 25%; z-index: 10000; } div.ChapSects div.ContSect:hover div.ContSSBlock a { display: block; margin-left: 3px; } div.ChapSects div.ContSect:hover div.ContSSBlock a:hover { display: block; background: #ffffff; } div.ContSect { text-align: left; margin-left: 1em; } div.ChapSects { position: fixed; left: 75%; font-size: 90%; overflow: auto; top: 10px; bottom: 0px; } /* Table elements */ table.GAPDocTable { border-collapse: collapse; border-style: none; border-color: black; } table.GAPDocTable td, table.GAPDocTable th { padding: 3pt; border-width: thin; border-style: solid; border-color: #555555; } caption.GAPDocTable { caption-side: bottom; width: 70%; margin-top: 1em; margin-left: auto; margin-right: auto; } td.tdleft { text-align: left; } table.GAPDocTablenoborder { border-collapse: collapse; border-style: none; border-color: black; } table.GAPDocTablenoborder td, table.GAPDocTable th { padding: 3pt; border-width: 0pt; border-style: solid; border-color: #555555; } caption.GAPDocTablenoborder { caption-side: bottom; width: 70%; margin-top: 1em; margin-left: auto; margin-right: auto; } td.tdleft { text-align: left; } td.tdright { text-align: right; } td.tdcenter { text-align: center; } /* Colors and fonts can be overwritten for some types of elements. */ /* Verb elements */ pre.normal { color: #000000; } /* Func-like elements and Ref to Func-like */ code.func { color: #000000; } /* K elements */ code.keyw { color: #770000; } /* F elements */ code.file { color: #8e4510; } /* C elements */ code.code { } /* Item elements */ code.i { } /* Button elements */ strong.button { } /* Headings */ span.Heading { } /* Arg elements */ var.Arg { color: #006600; } /* Example elements, is in tables, see above */ div.Example { } /* Package elements */ strong.pkg { } /* URL-like elements */ span.URL { } /* Mark elements */ strong.Mark { } /* Ref elements */ b.Ref { } span.Ref { } /* this contains the contents page */ div.contents { } /* this contains the index page */ div.index { } /* ignore some text for non-css layout */ span.nocss { display: none; } /* colors for ColorPrompt like examples */ span.GAPprompt { color: #000097; font-weight: normal; } span.GAPbrkprompt { color: #970000; font-weight: normal; } span.GAPinput { color: #970000; } /* Bib entries */ p.BibEntry { } span.BibKey { color: #005522; } span.BibKeyLink { } b.BibAuthor { } i.BibTitle { } i.BibBookTitle { } span.BibEditor { } span.BibJournal { } span.BibType { } span.BibPublisher { } span.BibSchool { } span.BibEdition { } span.BibVolume { } span.BibSeries { } span.BibNumber { } span.BibPages { } span.BibOrganization { } span.BibAddress { } span.BibYear { } span.BibPublisher { } span.BibNote { } span.BibHowpublished { } /* for light and dark mode pictures */ .only-on-dark { display: none; } autpgrp-1.12.0/doc/manual.js0000644000000000000000000001132115202202400012544 0ustar00/* manual.js Frank Lübeck */ /* This file contains a few javascript functions which allow to switch between display styles for GAPDoc HTML manuals. If javascript is switched off in a browser or this file in not available in a manual directory, this is no problem. Users just cannot switch between several styles and don't see the corresponding button. A style with name mystyle can be added by providing two files (or only one of them). mystyle.js: Additional javascript code for the style, it is read in the HTML pages after this current file. The additional code may adjust the preprocessing function jscontent() with is called onload of a file. This is done by appending functions to jscontentfuncs (jscontentfuncs.push(newfunc);). Make sure, that your style is still usable without javascript. mystyle.css: CSS configuration, read after manual.css (so it can just reconfigure a few details, or overwrite everything). Then adjust chooser.html such that users can switch on and off mystyle. A user can change the preferred style permanently by using the [Style] link and choosing one. Or one can append '?GAPDocStyle=mystyle' to the URL when loading any file of the manual (so the style can be configured in the GAP user preferences). */ /* generic helper function */ function deleteCookie(nam) { document.cookie = nam+"=;Path=/;expires=Thu, 01 Jan 1970 00:00:00 GMT"; } /* read a value from a "nam1=val1;nam2=val2;..." string (e.g., the search part of an URL or a cookie */ function valueString(str,nam) { var cs = str.split(";"); for (var i=0; i < cs.length; i++) { var pos = cs[i].search(nam+"="); if (pos > -1) { pos = cs[i].indexOf("="); return cs[i].slice(pos+1); } } return 0; } /* load dark appearance either explicitly or via the OS preference */ function writeAppearanceStyle(mode) { if (mode == "dark") { document.writeln( '' ); } else if (mode != "light") { document.writeln( '' ); } } /* when a non-default style is chosen via URL or a cookie, then the cookie is reset and the styles .js and .css files are read */ function overwriteStyle() { /* style in URL? */ var style = valueString(window.location.search, "GAPDocStyle"); /* otherwise check cookie */ if (style == 0) style = valueString(document.cookie, "GAPDocStyle"); if (style == 0 || style == "default") writeAppearanceStyle(""); if (style == 0) return; if (style == "default") deleteCookie("GAPDocStyle"); else { /* ok, we set the cookie for path "/" */ var path = "/"; /* or better like this ??? var here = window.location.pathname.split("/"); for (var i=0; i+3 < here.length; i++) path = path+"/"+here[i]; */ document.cookie = "GAPDocStyle="+style+";Path="+path; /* split into names of style files */ var stlist = style.split(","); var appearance = ""; /* read style's css and js files */ for (var i=0; i < stlist.length; i++) { if (stlist[i] == "dark" || stlist[i] == "light") { appearance = stlist[i]; } else { document.writeln(''); document.writeln(''); } } writeAppearanceStyle(appearance); } } /* this adds a "[Style]" link next to the MathJax switcher */ function addStyleLink() { var line = document.getElementById("mathjaxlink"); var el = document.createElement("a"); var oncl = document.createAttribute("href"); var back = window.location.protocol+"//" if (window.location.protocol == "http:" || window.location.protocol == "https:") { back = back+window.location.host; if (window.location.port != "") { back = back+":"+window.location.port; } } back = back+window.location.pathname; oncl.nodeValue = "chooser.html?BACK="+back; el.setAttributeNode(oncl); var cont = document.createTextNode(" [Style]"); el.appendChild(cont); line.appendChild(el); } var jscontentfuncs = new Array(); jscontentfuncs.push(addStyleLink); /* the default jscontent() only adds the [Style] link to the page */ function jscontent () { for (var i=0; i < jscontentfuncs.length; i++) jscontentfuncs[i](); } autpgrp-1.12.0/doc/manual.lab0000644000000000000000000000410015202202400012663 0ustar00\GAPDocLabFile{autpgrp} \makelabel{autpgrp:Title page}{}{X7D2C85EC87DD46E5} \makelabel{autpgrp:Abstract}{}{X7AA6C5737B711C89} \makelabel{autpgrp:Copyright}{}{X81488B807F2A1CF1} \makelabel{autpgrp:Acknowledgements}{}{X82A988D47DFAFCFA} \makelabel{autpgrp:Table of Contents}{}{X8537FEB07AF2BEC8} \makelabel{autpgrp:Introduction}{1}{X7DFB63A97E67C0A1} \makelabel{autpgrp:Introduction}{1.1}{X7DFB63A97E67C0A1} \makelabel{autpgrp:The automorphism group method}{2}{X858BB98D85D78C8C} \makelabel{autpgrp:The automorphism group method}{2.1}{X858BB98D85D78C8C} \makelabel{autpgrp:The underlying function}{3}{X79DCF7D9853381F3} \makelabel{autpgrp:The underlying function}{3.1}{X79DCF7D9853381F3} \makelabel{autpgrp:Influencing the algorithm}{4}{X86240F237D909E1C} \makelabel{autpgrp:Outline of the algorithm}{4.1}{X85D2ECC779E3CF7D} \makelabel{autpgrp:The initialisation step}{4.2}{X87B27C1F810822F3} \makelabel{autpgrp:Stabilisers in matrix groups}{4.3}{X869B678180AD5E21} \makelabel{autpgrp:Searching for a small generating set}{4.4}{X859CF9757A1F51EB} \makelabel{autpgrp:An interactive version of the algorithm}{4.5}{X81A0235D7E15DFBD} \makelabel{autpgrp:Additional features of the package}{5}{X7C0BF58A85D48781} \makelabel{autpgrp:Additional features of the package}{5.1}{X7C0BF58A85D48781} \makelabel{autpgrp:Index}{Ind}{X83A0356F839C696F} \makelabel{autpgrp:AutomorphismGroup}{2.1.1}{X87677B0787B4461A} \makelabel{autpgrp:InfoAutGrp}{2.1.2}{X7D16AFE27E0B7133} \makelabel{autpgrp:AutomorphismGroupPGroup}{3.1.1}{X83ABE66C83446A0B} \makelabel{autpgrp:ConvertHybridAutGroup}{3.1.2}{X7DEE06CF79DC7A7C} \makelabel{autpgrp:PcGroupAutPGroup}{3.1.3}{X7ED1F7C6849CA658} \makelabel{autpgrp:CHOPMULT}{4.3.1}{X86529C2080159D8A} \makelabel{autpgrp:NICESTAB}{4.4.1}{X83C095D17D35A8DE} \makelabel{autpgrp:NumberOfPClass2PGroups for 3 arguments}{5.1.1}{X7E472D2579705246} \makelabel{autpgrp:NumberOfPClass2PGroups for 2 arguments}{5.1.2}{X825FC0D9796B0D97} \makelabel{autpgrp:NumberOfClass2LieAlgebras for 3 arguments}{5.1.3}{X8399B9137982EBAC} \makelabel{autpgrp:NumberOfClass2LieAlgbras for 2 arguments}{5.1.4}{X824DFC307CA9626E} autpgrp-1.12.0/doc/manual.mst0000644000000000000000000000046415202202400012741 0ustar00preamble "" postamble "\n" group_skip "\n" headings_flag 1 heading_prefix "\\letter " numhead_positive "{}" symhead_positive "{}" item_0 "\n " item_1 "\n \\sub " item_01 "\n \\sub " item_x1 ", " item_2 "\n \\subsub " item_12 "\n \\subsub " item_x2 ", " page_compositor "--" line_max 1000 autpgrp-1.12.0/doc/manual.pdf0000644000000000000000000046314415202202400012717 0ustar00%PDF-1.5 % 69 0 obj << /Length 696 /Filter /FlateDecode >> stream xڽUMs0+t+>oK9543m3rA`2^$N`}VF+t_\#AFQ, a IA$ ͖2xiD_9ݕ_^u_ A^W} S{姴%y971ϔ endstream endobj 80 0 obj << /Length 1430 /Filter /FlateDecode >> stream xڍWM6 ЭLͥ>(YӓniMh8+*E/Hx<)GFLjFw6YTI|Ҳ",ͣHH>o'?Ͽ?$J(hYF"kN3:wԛȫ(I( %Xgl FymfhNS%j>76RRdSBY0hI,{~ňsC/V)O89L}mqfx39vrjPT!)M{iBŕYHR1uPװ5#i:[p^$/h@^xBgqۣ4NqE!:  v4jXk{o~2T1!\YO-׫?"+$pFF!nhcoԹoG#8ثQԼNJpòxGa$5-v_h5Z q8IH7ׂC+k*K!lI}uH_I"\DuťeJXU0=nn- YЩ;2L;JhJܘFʃءA6J2%N?//ډZulnǦ$oFW3_r>qTA 3hƠw1G_H@B%ܙNE|Zs7]S Z VtV[1nd?{⁰h9 2#UY g-w41xkY|׼S}$9rAehs&!peTs$eb[)IJFE3׽ȝyݽ(g',Ᏹ^hMd9xvdrEe-Q,Ek>9"xcwgy0{ u=` dǡ6PXBZ->="BKC\N@vےzճ-{mZp-7Ε+`4W6@[`Π^醹>-P7#6/S;sl9җЈvpML#'i!+-ۦ: _,ٖ ]}8,{^;͟ʨ:ΠǨ0F||_f_=DwRƲ!zz7)!oiẃ_F endstream endobj 106 0 obj << /Length 646 /Filter /FlateDecode >> stream xX;0+TB'%\$tȶ&< 2ǝ<¸Sx`jADdĈdBH"dh+ Su?!U4|ߕ$nKH]5 !hPBPʧWf8 |ġNF`9B#G! ( d(22Dzط 6 |y=p`wиNj5/v:Ԛl0uژrWZotRn]w̶ܥ>'&Jyx!:5Ep&"ͦTŦ믛b%x : O|05 /LpZU 4oJn:C £d>'u~jLGSa:yV_) mt:m]OHqlD(gS(boz'Qjv:o›JeAQ~> stream xڵYIWacrzVESeI^'B"{wYybRX457 ߼y?FrlO$fFMlS2<7E.v' ߏ߄_{̻jMf3 ETVQs}Դɭ)K$_+淝;Ɉ,YxN5J} v4lo-=_˺sfv,≇u\8BsʢCTM{]5ۈEG-u,N,rqʞ>1C}rgXG_8i?aOEEMa˶ʹM<ض-#4COp~ֻ|o%k_Iit/.M[CD$Q+2$SHݰ}qi6VlA~i~9GyA2Jo!ԧm'jݚ]3/Q/9Oא7C^b~_KZ.d 01i;dkS 1'vvqx*|Ĥ67<^.Ŭ%L΅ 0\y18- ZY?ǣTB#ży{x %;L@ݥ*#ȗ!_ _ 'ЖxPK&]/*)zF6;y Ł:qfPm.veHJ2ӗeFan.Ⓕ(xxU9TPNNyMT(I^ e*6wAcqf ;>x'Ni/_zD6ht_'WK=~H/!{'Dҳ4q7F#Z~Sx6d=5ibF{YäCs&qĭ,lPԠ<[ $TDPݻGJOH|:hV Iv_Gв۷0l7?ўZپ-~'sR@0>$VG:93$zgXIy;T*%KvzH"$'Bi\cDq~Ã4jlYOy.dPSs̖K2|&RsO?qhTi,S>"e99&E.T6R%^>"?x3*t*`rJ7jnb|Ʈzy(|8lo~`|*ݟTB4my ̃S{duOC!%3$CmW uB?y:;ɀ0P74O=h3EDN,uȳՕkv#V ^;ѥptǐiBMH(;N9d-۟})B ózOC-uH2Pf'!OϧF= endstream endobj 117 0 obj << /Length 1970 /Filter /FlateDecode >> stream xڽZnF}W͋DsM8F:H7[DD(R%)wBJH m!rv̙ϰ9{b$%mJ$ Q,O˻hStFwgWs/Pksnb'+V:/O6wIv+XP|q븺˗TO8b\R/_pO%O31>6#um-خX-,m"^bd[]d۸7b9GM|deii$r^S{ fY l ~^)VE+Poȝ4Kl2B#BDcĠRqѨ4:_ zǪpe{2w̘`H0pWIMg`^wBT",_}ocˉ8[/˼&IXߺThUYD q]a1P4/SB7;D6J́hg;AZZ3*) a͛cC84{ލ5x3 f=D |y^% GG !!v>P .o"2_3 } [kGV[PL|0apUMsפ7 @!Yq5#m$ԈÏ- Vֆv DM DM CfST߱Z=gխM5PAAu%F4lUy=)ly~xmCGMcl9; 5^FٛLo_C,Vm$,ʳ1[WlobH|˛۟ IߩpO[y9O)j^\$.JWyTwk+d 6+RmeEV?֖{#l2vb@o6yK/dg&E-HT-gb/ʌ]\-oWkh] &^kN%uoO}fle\ߒl#ӽ 4&'Q<[ѹ+?j9|3Pܘf/n w /Ҩ,J\7]@@$KmPrjTku=F$T uΫ1V{PԦ؋,ݴCah){ Sk߼LVcyQ4aDQ "Vwσu̱ٛ8  g,w@X;0#HXuٟ~\UJS0"hIɌB Gc"p3ԏaJ*'OP,q .P~c\xxP:r>΍ 'x5UA9.s(m&(tT{bWMM;UΤTS׷MWGmf!ISwɿTQKt8pT}ܫ#~0pg0=QQ+ENQ2"2v%]V7 G =ƫhVӰhymJId_ܬ/>Fiu1>D %IR#1ƴs[Rѧ E |hb̝sm/-'h LTaZ[6umlF}Oph{"|{Y8cgskRs}y gaa׿?WԦ1ųאmD}B29fy$͇Urq@=?#*$̗'Z+gW>U샖+l擜&kP @a }(Fdx$!EdM(6"EEuIJzMiB)=hA[؂> stream x՚o6W؋,?ڭ@׵Fn[8lɕ_Hٕi{C@H~<ݑvpp4|9z^H!0.o" GJd.ͦ8-חx/HD02ظ!%)hkfJ;gh‰AL@Z 760&rQY}x]4Wnk|YI₊]V҉eHN#5;B~@\v䐯I4dV2K+g`qsPH>== $7EJeU$7ޮ,j]#Ub\zlӵ[XHZd XW|OM|Dojs|[|6_hjI=}-ndYwV2)xMH4EYl~0m7u( klΝ.{]nMVO|˜.봬P.G_F &"9GGsG3:kf"b>@a}aAkqg(ADs \ҁ#6A4yi ^V#7Ԗ+czUiE~W\QFW?h?6CNBMxvCSп$_0m:d؞lxdZҸ^:Z}=4ø.sn]']aY~ꭽ>NNPC C( .08AL( T0v"]S3j'p;)@Y̊kZ'\mWw=P[csw~د3Evu=w92i. {i扪(ήhֹABgoI1l+aJ3ݹ"&+1] JtL?1̀9 Y!q۸BiQ\kd1ns޾x;4Hct 4~nx=2ޅ 0$80HB!ƐQay2&wv8d) ,.@1dfK+TFiMn‘ SRRt]wr'Bf),ޠ>lS\@VdEPx@ԒfUP7IHTQ6PR41ϧd-ă%jl ϰfv1 +)3RkFCf"&0̴yS4N%$0\\Øbs5r> stream xڵXKs6W(DAӸtܓ-B"g(%A1!߾]''W8psc*QQ!xqMn~Ϊ~oͯWd(4E" .(',ȻT5ꛇ=ahmPAza$E,h"/@ժ9IF*O?g"':$6'e+]5h‹w$XP&`9(> VtU9]zK6C-qBx6{u8EdG|U7(&Oa (bD;I(xAI99ތuk8 )~[m ݩކ`To™JT(1TW!1yҘvLcUg£>]u_v07i;1z<\Uo#Ʋ'b8W=(sħKuӌ )"}JuƆ[֠ j\$9ճ"G*2S>l] yÜhR((`5rZ|9X`Qomw^eU%P|M!嘜c7$@Xs Ҽ\e䶊mmUgs9ҫ[ |n-G9tL@PiW_ݟh s^^QO޽} yTt~P*1ʕU?"wT̂;빈R6#)E)z؁!xUVïQ{7w[*-R\Uzhh7P=53Fg46kL:(9D.{A|i:ŷ裖nM =ĄDl$nTaؕ7ɾ!8]NEMHxڡ 4Qdt <_F{d"9ϙr9\Πm%Q u6hRTlQ7^`_Х&15p޷ll8^7x&$\$Szj/6дbz8Ѯ 1jJ_HPYq60"Y8,pEV![QRn=d =N/2Tb So;E'p|}9kn$uzPMVHQ;sdz@KٺeO袗eSS$!Q> [Ү޷}S#&+ h ,Zݟ8nαCD{e:ݖ[דIg/(9'(%dinۍ>j c|}38?t/=P/3gB,kͦ!r!>1 _y$g~S^ endstream endobj 141 0 obj << /Length 2578 /Filter /FlateDecode >> stream xZ[6~_!/v3_6@h&-h6`Y@ca=+ə~ERKVG3!R MhWi)d&: Ay$Aj]aWF71$iHm\`/>Zpb1 & \Y2_pEfmYlnz,wpw&܋ŭng+[3Mt)&4/-D)2$qoAdq$; 4Hj7>sİV(F2l cqIo 6.$s5v~FT,fH:~Ds*fxDwn^@t}& گD5 #*=.U ϑ[8nPrW@6ٗ,Zz垍V*ɗYz(Rk:5ZU>(!7ddwiᕄQdm ctxXv O[gH ^hZ b0pvoߧu-dzs"fIfղwbip7;a-@m~ V4cb_5Yc~znKlђsR@s U0>.}wB>HHN!`\Ù5⯣nǶ(24S`Lpq+Y͗^-A°Lg7iz@ b}i*m._ytװɽz47v@~A;&^Ju&RAPпखRǍ$X(JAyk[C;zs2'$ҵ xsl.6^$y(Ti-hjk5cwɏ7a-W:[a{>R;!=,$kLaK3enk*[$>s/JQyޫV '*k0i\m C]i\`&Y?.ޮXIiwBi哀xڧW_X 2DH@}U5o ,Wa;2+&;|r^Y> ߜrt eIk+xGa!A.hŻsWtΚN+IXCoFz&tAb'<9<E`mDE#<fC@Q :l\Zx0n?`h:ٿ`>e 6[ir&Hȧ- rYA#!a]# 6O3C11~CB <4Dh S'7z}* qS7\uW`+Ty$t!rF k- }aQp CJ.4O$*HB.d =Q+8^]=hfDA@ Y 1r5 /5Xp‰VO>FE6[M-HF9h XBXWNGsMi9L_top\b|:ɶ1ފ.P&q5 > stream xڽX[s8~Wh/S+_zL)Mf\0Ԙv~,:aXOGAއQpՄ1mdiE&ozp?|q-)[b}αV =#ŵ#) (pL10A/aEҿ5tH/ O>,Rb라Yu0HQ]f/尫%Vܔ]ǂ-ynW|5[05&xf1#6Nm>$|c=,$<ލ3d?L|&]0ُ-B:roӽ6OixebFM`R.$r@`(x$lL`Zӷ_SNPJ8 w7CUσ)Lw:;b*'E!xO'6wtcgCZˋ[gnF%U[EYa%Rac-/{wMgXtD.@_{j% 2pF s~'^Ap9*kXO akl˃G k(_] Q]×-x4.\("Y %ۍkTz/jAx?C3$iQȠqe`0ccT׾fu[0We-^E (/З*angF@ e "7jfV˂ݶ)]6e1}Oa:=H?}9{puiV"#eV\iX8 endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 813 /Length 2079 /Filter /FlateDecode >> stream xZ]o}篘dbHEq M t,D da{%-%9xgsϝKN% E" 2V6h0 7E>Zv"$t"Dr%nPڣ hS&bhY jά: H>I `6 zbmҙ>Pat"(@ĤFDCk`bGВ _ 9zA tEʁ9S6% ٔH釉cJ @W `S!dA j*#U#Afx(iv_D|?17HGAKt.01Yox^D>A1,B3d3b8D;i83D =C,K(-!b" )juu!&dڠEtE%y1AxV&TzbIC28"P'bF*;;2?vt_ Ig>>*eƗ/ r͗_Isw3ɲLNEw'yϗ[|vLQ65*(MjecS6k-jw31:f Fͽ ͔/5g uϛvg [r^t̴Qr{^+e~̹hz/A׻vX[B֝в[CmX~h-!oNeje+/F@ݴ%R6[479zsغm+m -[pWLK,v_ѧ"bV.qg,W,ŸXrRz2qU|P\%'u/ɘ.38a}zgF9T5nB\f-(U,q.,2k6 _pоdXR| o$J ǥrM82V#>ggyb~[{u7L?Ptk:P -׵!JBݥc(#-{勜FrzhCB7\D2\IO07ZLwVVZr,Rp2qe!5DMx[}(P6"jkE|N/wYPL rS?!I5wu{b>( 7"_|-7f#Lp\:Wq)k=*KNEQ%C;ٲX򶼛.*IeizT Y4T-Z#SCLG%Et5XX%hDۤDBh;IMW> $U7T7'TjR!)M= ?5[zhCkzAbvReC.*H r^RXJ5EcA D2q;N'%*5?]nj%C ] 4XO+1^6KQ3 1'l&aNN @[:jxq%ü?֤G2[^teÞ vkx@^2 ǧhЀ !b"IR#Dx_@*&j-!=8N/G|E`\@{;y,ƖD]oӓ"ZVڰrO1^z~{8f+wm:p7uxmgCOWDU:t%Rox֡WcuY":ܑgpߵubmm [+Ks-(jذƢU<džp7/sbIǎ?NR: rqWoc:~zdF!pl0֏ 0 H'SуӼe'ͷL#mm0a2mݣ2՟n&'Lw90[7 Ipk){6}:d{u_+g endstream endobj 158 0 obj << /Length 2819 /Filter /FlateDecode >> stream xK۶_#5`E`wj7M:!Ɂ~-yk74@OīUz"w/^ي$I\V*!U"),[W?F9h&H+kW?CQxhڈc>ͩ0oڲ?g,/H1(9WMTT-4j;6$maNގЙT7f.=4)ohy@SNT}5ͩiDz;mἦf=ǘ$R!dIS.fd4*EݗG3@ly7lھ8)paz+WCG d8fa*s(ؓ5)\p v3B Ɍ9d8*p fYܗMWfkF hqj —RC0ELܮ M@$PLxFkXT%`q|@ZӲ%$mB_$}*j< A"ѝsu嶲<4gĊ$*Zg5C7L$X{Ab<$C^uGdQ%O׈a]%~@Z"58JG$cZ/8n?GUvŽpʾDQ8;EH1MÍ>OQ]_"Fqہp`f9tx_l &ҷtҀeL8Ox muH֛Yg!Г~8mK4=l*k9xA|,wG3,;.o?=зɝhpKH=2-O %ÅmvDz+V|y,:e0:p&x~. >Di x|EܮKV"i+w8Lg7žͦYi1 vfXpv.M;Ֆת9)oC;ӭvײ $Z*a-7T!(Dwq%2BC HzkKv8 + ;Գ #mNZ(!8QbJTxWIbm߸.P$S Y_Pƈb5مQ^z,e,IQ_LՁ3C:hg dկ3IG`byddd!|59ɸa ]K +"-jC@6k4E.atOr&^( 4x.!zu*^y&cvK_Č!3 !g)R021]t%Ff,[4\KLEC{~ 913 r-~9 IYO cAK@!GNX2/ㆉ/_r? S\ JbՈ ڼ0ɫ*J8-Oۢ*ΊЗgI's8ÜL3Ibe3?͜ެ HN-1I/+!{5ڞ9ErDӊAˢ7(?&\]<禳`kZe,\x)*M+_*?!7J$hDtҮ &"z.n.geq?-Lؔ䬘\lFI4T}y]޻1p\ ę|jyUjNmcO#M]"؈FHlVSqHsF:,wk(]>ں/h> "Non`S (qׂN)*wf)ܠY`O^UC>5Jkw 86uE6^N _틮7%"Ą )6o q>7]ӎX.d15qA5olu,ݡ{&hn)3qߣGJ;|l2:y?& /6>ADݛL}QԸKUqP<6MS7#d=1!>GJ}>LЬq?)I2d!rJ?M^RC|&3*)D.Sd8n[Ő7&GӍ rjt"(xu6CYo< {rI '{frKBY,RXXVI/^r'eUMļԫH⥩,/[HXw"|JOʙmDn7S#^A҂w7>FSv۲߫Lu{g]reT~|÷+0B&hl_^ endstream endobj 169 0 obj << /Length 3122 /Filter /FlateDecode >> stream xZKs8WHU^$C6N:=$s%bE5|n]ӯ:mAەծjucNp!sN>N7eWՎz3Ii?^V\AXgx4I"-c{)-.SJt۪ By|)N-]l)0Z;+۝Q]SG Ykv?Ggiz]r%wnoV7urp S60MW[ת} `ǖ gƗp&~PARݶd}cnnwl`ڑ[pM4l 9G"ɡnMH<Jp6 M `xa(^*9ŸBwJ`BcoWV>A_~6if z'XpV9bH%}w$[6juFI2HJ9®cݶlT,}TdBf|z:h+7.9<>6N[dQgIdz` .HlESÆT>o~3. *i"l豮K{Aw5x#goI5 {S:@ (}~rqy:A$g ߰+ ^yFc$|CT8LjIp|Hp&ȅl{@FaIe(H򙥄r? {=h/>&2yڪs:D!;#aY4n+Rn6X ؖ[>Pmgm^L8 2J!yQ!ѿl=w)&N/g MsQI͢]^8na38IY<@5@g909l% 朏z`U6 g>ɖ z`~4zfr`غ7L ަiVQRPN'*#L bvV๵?UcG議A!RW! 3ls2XA˦|\yMdS+Nؔf"Nt G* X `W4N2U;G_ t ,b* f8!  ?0 km!7a7m|  cS:K[6{OcdӠ+?Ш:*@TV:U~䡌m V s_}{m5[S{BzOM 2Bp YQDA0 8ڀdR>ýݖ_\Ix8l 8zv%MۤJ'|7nYDU*-zvfq>(ִ@`qU.h AC䄻Cd?f,@p qj_LhG<尘Y;SxУ9+фGa%ul>tMiL%KC͡ޛnS6,,lx +* Ppᬏf鉽|-˱ -m %7V|SڠRfza4My#Um`Mݣ1>]g菗Bx(R,cW{r9GFGȽVsP,C4uB6x=XNJeHBfn}.V2/s28^ץQa 56n8:|T>/n72HqS }й l+Nt1TbY!4`IRJэa`V w.Bf@\ Ň_b Pĩ_ t ǵq?9x9øT@HQWP ;ݶ.RarX`ux@5R3JУ{7<գE4pF|Wy>hO15檃+}56f"x˵-bc 74<)o*(ֻ{9{wU3>97W{q 䟭 0;ƍB*Fsw"x͐%W+ޗ]S}G6~Y[nF PO1D02ܝ갆vaBbe=`.4rf\rrSR_?.Ad~W h.wa%> Pz}2fS.c"ˇ/9Vl٫QZpO wv5\x)i̾\1Nag-Qc,}dm09?StOq|sBf@G]voK ٤ }϶OR=ڲdvɭ:"P6~:o@-Ön>]1?nYn$ޣE ?svZ󥺯׽0uއV~x Pxruh;g-oゴ3@.xMܧcx$djYá4 :!bnhid(1'oT2 VϿJ%8V^. Sw47ZQ endstream endobj 175 0 obj << /Length 2651 /Filter /FlateDecode >> stream xڽZ[6~_!/23 $A:Ed;C-d[j]V3{%K쌓AQ4EwÄ{./^\<)R^ fа0YyWe]g1iv+E0co4U6e.iitiYmtLD6O !K7ZH$ˆA܉f@d>fFE݊<(Rt4ES%KL'Lu$![ QYYg/fse8Zfrns =MNao~Dқ Nkkg'=,7vCkWiI!k )1{Ú«_ql5WvRދΩ$d)(ebdY1z.GH9;-' 8d.Cqxe]9+zXo=6ӡ9^E~z1a'8sol_𞊣óLt.WOmuh(X[5@**W͋z\DB4o+Uق*Aoo٣g~ \$lҝ38utЅ"~vq%% WCFM:[C1?Pl[f? endstream endobj 185 0 obj << /Length 1885 /Filter /FlateDecode >> stream x[ێ6}߯{3_6@ 4AMSVZvem;)[6mm&~"%RԜ3GIlOW^i)d&,J"eT$Aj}߿V뫷^  6?#35= .立.TqF2;2qI5&6È}nz.loxmoJ3Ҿ@ #R07O G`<HP1?ڂpD4in#F 9FVbc cx3D`,Wgx/+Hh:gE"Qy6Ju(BHR[$0f{~qhPҰB#K/{x?-09#O}Vx[ਜ਼gg{a{].G/vlvܾ* e+3XW* c;Ty9Sm}SѮCmcr^X`#QA l8JF+aerXP!-D3(ᙀZ 3v9[L,h`!7X!*M@Yh&U@ 7 D4f+- [Z@S(Ū#~\zk5i364qrb"MZ"ýn;"ڂ"(hjoM\F3+ $ \2aLeτ͈?N]4: K4A |RthӬ f>=E# Ia f ęA3gBb(̍Q U 4 $D4KH Dg!hT1E 3D9>RH<JE1C *$F H ()? !RH4Xhh(D*x,*$mڍB@ ȯɌ_)$ gK4XHH/ A{ְҢ˱OL4X[H3 ~_D b_ $WEoLA}㟆A> Wy3lo dpi(ux> +*%CoBݭtȴG n]QofY}t4߸V{8+h+go>q\giߜKo(1Zjy endstream endobj 190 0 obj << /Length 362 /Filter /FlateDecode >> stream xmMo0 TAViҸm;]4 Guɉ~`po# HH'H 3L^FHbA8SYIyx:CA1sTYFF̵*ڋ!OD"ڌse-3/1Q=Jc*ʵNu O"R U QI{ $gӎM6y:uOUaӦ|HN'Y; 2 ս6]m0̰%dvVgtmhڢl|r2s}vmڧ{g endstream endobj 194 0 obj << /Length 1355 /Filter /FlateDecode >> stream xXKoFWHf6! jEnI %I/2F].3;3!6nZ^*IIE\GDH Ur}oݾh 8?\a#k64KV+f[}YWU.Y,.ZRvMam+#%uVD 63}Jr{$");ǵyơQFY{ߖ1o\|q㮩D+֏n>TwZ}kk|WѿEz1Go39tc8QdgeVC!^$"x$Y%6M}صZ P$0je#kB?l&'b=+$tn |4 砅2"am:|AsϮEegp)݊9ԲLrωBg}R:hFǥB,#CJZdK%R RBN8#,%T+Jm|X|-xcʻwLzAE\;c.@ǛcQ[]!!!| pN} 9>[ '5I i3FpJQԻuEfz %Jhʬ7uoVr˪pwmJcW&vc"zJ(nMg:46gi&6tvY_|t)z{5+p 7wDݬ<6O-EK7g i!$ʔ15Bc/'^$g@RU"Kq*w+CL'2Hv7CX@B Ly<'^Ҩmڸ[< XfC "H2#qO24D :uX<}v2d.j P|H z v~xHNx#ToBN~&gIDVD / :Ś5c\g-NmȌaJq{e`w:S-&]53ptNnk~k;'*v%ETPx WuM_g]CY?Q0g䒄Qıx.Oa'DOܮY¦lQ-áF D>F{m,Qwg31>;6ߩp-1dYIQڷ(gqZ|M,?űin PL291frt4J$GwvDD~^^ ǎe endstream endobj 218 0 obj << /Length 408 /Filter /FlateDecode >> stream x͕n@<1)²QUғiV&f}2 ??̀@pt2a A`y!F`9 bQe$JmFHAR|Z.((J BP}(`TzG+kXTvXCUMZcvH@Lh.'% iIO◝؏>WbI-jr^qkrE jBU&L`1i|1 2Md#J,Ӌ"HD' EX0x&KOV=ܢ D0wNw}ͽ[]3q* T]B{ "IfE=/*] endstream endobj 221 0 obj << /Length 105 /Filter /FlateDecode >> stream x31ӳP0P04Q04W01R02VH1*22(Aes<̹≠=}JJS ]  b<]?$`)( endstream endobj 227 0 obj << /Length 211 /Filter /FlateDecode >> stream xڕ1 ` S Yzs[-*T;:9::(GR}?( {I^kJd3JҗmYtCDN9,gLgt> stream xڝ= P_H&Gp/TVb]r#XZYbi4$18 0Gg|'e9r&Xr;fw[9+[)5<_JYh0hAJVzƒ5/M[ߗGr:c#Mm'rIT2f6}]]b}[q7S3 endstream endobj 229 0 obj << /Length 171 /Filter /FlateDecode >> stream x31ӳP0P0PеP05Q03VH1*26(Bs<M=\ %E\N @BA,N؃$0z8Q'`& >`& `G${ ?Qr `E endstream endobj 230 0 obj << /Length 171 /Filter /FlateDecode >> stream x}1 @ a!s51VBVbnY-DM(HgjxD1alT+ Q9O=|1!w)ڠ) B T{@6\% .:Z@ Z|ae_U/b endstream endobj 231 0 obj << /Length 143 /Filter /FlateDecode >> stream x=1 @wn^Xbhi(m,-q#(|cYj9֌YJUT΢yךTN̖Y ƭx܎b*N7qDoRp, endstream endobj 232 0 obj << /Length 193 /Filter /FlateDecode >> stream xe̽0[x "~- &2`A+Zl+ z1xK7}`|8CQ'p7.h nv7Z͐1nc!孅+ ݗД>!uBG3%9mM5F4V.կf֚RFiHk7e0)#W^a> endstream endobj 233 0 obj << /Length 200 /Filter /FlateDecode >> stream xڅн 0+ ~`A, vtr'utPt5}4б&O Crɗ3)hX֮*ilEAl&Ws:.{dbB3D]$ p %X3'=íU6}C IB%:+Brm^CseB}]P8qOdz endstream endobj 234 0 obj << /Length 253 /Filter /FlateDecode >> stream xuнJ@ba;/@λ 8BQ7Q̣RZ,;n<9Gu|Z|XroKz)ssO놊+J*4LEsOwT/NXkj6 C"y`ECt>W Y3]>}vrÞ}ԩ:xAjmMcHo/OvjaOMbSjTt0q;٭'Kjiyq:<贡K~) endstream endobj 235 0 obj << /Length 219 /Filter /FlateDecode >> stream xMϱJ1"0>Bt7BBGˣ#\yŒYC_„kJςƵƠoA{]VyfIc/ݝ]Íqh H<YNW͌!#|i~8-v:Q,b#X}n}Hْj`O:Aom"jAk1xp3YvG-m endstream endobj 236 0 obj << /Length 190 /Filter /FlateDecode >> stream x};@%$p.$1q ,ZZhQ8%aaD)e3&SKp4C g0GgԂޠ1mx܎ cncv`3TJyĨJ6$(r&;;/Xy9pED]Kv6}zκOY8ˏywf.'+yWana Oq endstream endobj 237 0 obj << /Length 286 /Filter /FlateDecode >> stream xuJ@g"0y!SZYZZ(]-rvABs.ovI{F%t\tZSSc/ش\-iYqaqKM%ױ 9UXl订 d ybR.aa cX"`?5̆o,, ߫0Ȅg_RPg)$.z4/@ciJKJʓnyA u%>@+ +0@:ɝs<#Nz3b:%^txۺ endstream endobj 238 0 obj << /Length 221 /Filter /FlateDecode >> stream x}Ͻ 0C>B Zt vtr'utPtS,GB1EAA1$$wKҬ`[43\%4}r`^jijD1w5ޤ l. 0Nߚ`gTj*YO8:uȱqJꂽSyXND!uаڻ7ԗ:1D&/e6 xE3~0)<|] endstream endobj 239 0 obj << /Length 159 /Filter /FlateDecode >> stream x31ӳP0P0b#S3CB.cS I$r9yr+r{E=}JJS ]  b<]``Q"? ?8 8{0u L?` .WO@.R_^ endstream endobj 240 0 obj << /Length 190 /Filter /FlateDecode >> stream xm1 P ,jEB`A'qRGE>֣<;B|?Ns42!Mgohu۶՞Lj-)tC*.G'}4!r8FJp-27sX;+YJ>!PDhxհ#qʩe#\Y.D*~ps endstream endobj 241 0 obj << /Length 247 /Filter /FlateDecode >> stream xuпN0/`<JUeTD$02G#d|P,'?.n\uۚPk^kozETkToj/ ׯԭ 6~9H$؀BzF{baIu=L1;> stream x%1 @EqV$Qc N!he!Vji(%Ks)YBJwrn6sZΘ,' Nn&-]?^̞i"fXq^Ĕ%(~ID57T_@=@-6T֑[!6* endstream endobj 247 0 obj << /Length 197 /Filter /FlateDecode >> stream xڍ `4w/Pj)MPԚ>#46_Gth =(TWC# |=yrϭ3;/ft싳^l,N+=u-',]ƠBR"/ w]OJ Hѐ4MJ0?_9.6վэ-iN͋eVL endstream endobj 248 0 obj << /Length 196 /Filter /FlateDecode >> stream xڍ= @ GbVbh%GH"/Vef Ʃj?8$C(gbg(X]r;fwPL@ | ~nF <z/@:Mrp\3]8[FihHOҙAHVxuO endstream endobj 249 0 obj << /Length 106 /Filter /FlateDecode >> stream x31ӳP0P0UеT01R5RH1*26 (C$s<͸=̹=}JJS ]  b<]L!W51 endstream endobj 250 0 obj << /Length 142 /Filter /FlateDecode >> stream x31ӳP0P04S54V06R04TH1*24 (s< M=\ %E\N \. ц \. ?aC??@P`4,r endstream endobj 251 0 obj << /Length 96 /Filter /FlateDecode >> stream x31ӳP0P0@P!Ő H(`\.'O.pU()*Mw pV]zb<]\= endstream endobj 252 0 obj << /Length 111 /Filter /FlateDecode >> stream x31ӳP0P0V04W01Q0PH1*21PA#CLr.'~PKW4K)YwQ6T0tQz ?*1pՓ+ JS endstream endobj 253 0 obj << /Length 102 /Filter /FlateDecode >> stream x31ӳP0PP04W0T02VH1*26PA3Dr.'~BIQi*S!BA,B?ĸ\=E:( endstream endobj 254 0 obj << /Length 190 /Filter /FlateDecode >> stream x31ӳP0P0bSSsCB.1s<L=\ %E\N \. ц \. P߀ J2~~d|"N`%값 hL F'y,$33oAYՓ+ H06 endstream endobj 255 0 obj << /Length 198 /Filter /FlateDecode >> stream x}ϱ 0 [|TkI Nj}>JcҘ 4蠄|4;.ˇ)Jq)+di#  3 bnA5o3bDTYk[z^DyÒ1 <§QSHhUsjD0N/QG<T]KDbh@C63K[xGj endstream endobj 256 0 obj << /Length 230 /Filter /FlateDecode >> stream xڥбJ@/L i +PysQ%o镶={[r\/䶷\C#;"L E(JdG)23!_#2C[{GE{ʐ :Z2 fFb֘9e)QSFO?V2C鎾?9ru endstream endobj 257 0 obj << /Length 149 /Filter /FlateDecode >> stream x31ӳP0P0bSS3CB.C I$r9yr+r{E=}JJS. @-\. $BփI uD6`D2JOĥj2|$(47Ae\=WD endstream endobj 258 0 obj << /Length 141 /Filter /FlateDecode >> stream x31ӳP0P0bS3CB.rAɹ\N\ &\@Q.}O_T.}gC.}hCX.O$3``'Lȁ|DAjD  \\\, endstream endobj 259 0 obj << /Length 230 /Filter /FlateDecode >> stream xڕN0/?BՅv`b@Lб $R_.jKŊ-}oﳻͦTИJr&7R+Ly?ocv~K*^d`dPɑaDZN{8;@Ά:0GdzT 3#'d!Q M4 >15Ȏ×t*ć5 endstream endobj 260 0 obj << /Length 114 /Filter /FlateDecode >> stream x31ӳP0P0bSS3CB.1s<L=\ %E\N \. ц \. p,~BĄ'W NP endstream endobj 261 0 obj << /Length 105 /Filter /FlateDecode >> stream x31ӳP0P0bS3CB.c# I$r9yr+q{E=}JJS ]  b<] 0 %\\\6Qg? endstream endobj 262 0 obj << /Length 126 /Filter /FlateDecode >> stream x31ӳP0P0bS3CB.rAɹ\N\ &\@Q.}O_T.}gC.}hCX.O``'!P:'`b\=jo endstream endobj 263 0 obj << /Length 201 /Filter /FlateDecode >> stream xڭ1 @4 \kP1),J--!9D,,T]S[̃3nQ*9zK5.sWj9!!qSdaV o,cP$nPPBz@Q(>Zll/5.K=&Mإ(o9)[-_m0v`fs8 endstream endobj 264 0 obj << /Length 199 /Filter /FlateDecode >> stream xe1 0-wӖZtP*AAAQPPRo7iqpT I( 8{~B&6}\9Ol[L,7@g@GEq;>:@8w^@8@X&as!eV^zH4 6Q25> stream x͐=@XL #V &naRK (҂.C l}/N竌BJh&)^PF ] 厹Fq(Eu1 }C$QtQZۂgmJ9Հe 7Fд?oaF k ,|_F&h endstream endobj 266 0 obj << /Length 182 /Filter /FlateDecode >> stream xڭϱ 0H^{ӐZZ+AAA(}$]8N KM9&xg,\Od+ f.S0~ ,Ђ)qo19/"jB.P;UuDF 'aybhF4j-iMːO*"`a oƅt endstream endobj 267 0 obj << /Length 250 /Filter /FlateDecode >> stream xu1N@E'rai=1IL,  DѶ. (ig?lncQiں'Tl=yE&lk\FZ,6KNZa| 9|t5iûH Jbz<rd'0 (9qp&8 %?cFi=H^Q #t)g/pxLkDυ3zA endstream endobj 268 0 obj << /Length 127 /Filter /FlateDecode >> stream x31ӳP0P0bSS3CB.1s<L=\ %E\N \. ц \. D?`OY$$ ;R?$XՓ+ VX endstream endobj 269 0 obj << /Length 174 /Filter /FlateDecode >> stream x1 @ ) fa n!he!Vjih-GL2 +7&.&RY S2sjOƠZKFe7?/4#ڂJ"nݯ;QO7ZB؈U$fMYD@ ϝf+;|WW endstream endobj 270 0 obj << /Length 220 /Filter /FlateDecode >> stream xu=N@ _b%79 H" * D[n&"ymafYy.\O:/wa\gVVOK{Ǵý~~|m]=(k}fϋ kEm&fhF hrá +'2ʉ3q4|PY؁0e齳s5\@e'XreSU4Q~MQd endstream endobj 271 0 obj << /Length 206 /Filter /FlateDecode >> stream xڥϽ 0+->Z+S*AAAѹ}>b$*.bBz:ԥVDJQܣmT;fiTTf3:; :Yc6\;lhkb⍹/N-Z6*p|ZX?4>usn tn N2\KKv endstream endobj 272 0 obj << /Length 205 /Filter /FlateDecode >> stream xڍn1 ]1%o )$n@S ZYG!i _ϲ=gzp;:٨T6{hh.DmyءQvF0`80cf̱b9)zA}T$"'S|_Q((M I +TPGey?4dѸYz1_ S endstream endobj 273 0 obj << /Length 220 /Filter /FlateDecode >> stream xڝ; @ )isJE"b=A aS~] endstream endobj 274 0 obj << /Length 216 /Filter /FlateDecode >> stream xu1N0E*ir ,-D $(VT@Iv(>–)VAaYO??V=ϝz`U6]oX?ݕvⷺ}qE XXͨ̎p[P0LhB M 4ESDiDf( DETHIc %)>/~Œ\r/_})oG endstream endobj 275 0 obj << /Length 164 /Filter /FlateDecode >> stream x31ӳP0P0bSsCB.c3 I$r9yr+q{E=}JJS ]  b<]300? C=`cf ?F%5Ƅ@.N%\=CSt endstream endobj 276 0 obj << /Length 275 /Filter /FlateDecode >> stream xڅ=N@ M_(E"T+*AD \%7!H9Ec{BHLid=RI'tT%=VjIM}h=<|ŕԱh UXiSQy :!1{.g t<A9Nt¿ɽ`n [Y'(3@ ~sPoi5E,b6y0ɬ1$V ٺ[Lz #h&;ij$^MR} ^x?m endstream endobj 277 0 obj << /Length 165 /Filter /FlateDecode >> stream xɱ @ : Y k 7:9utPt>ZpcҘ(@>?1t>C1I0IF*x܂ڡA ʮv@F G` t>'C/fH= b賚'b6l Q"Di endstream endobj 278 0 obj << /Length 137 /Filter /FlateDecode >> stream x31ӳP0P0bCSsCB.cc I$r9yr+s{E=}JJS ]  b<](B` D00 aDHpzrrȧYA endstream endobj 279 0 obj << /Length 217 /Filter /FlateDecode >> stream xڭνn0pH' Q" vP+ċekdUGk?>48^iƏ%Ii?1B4,Ⱦr'd Wwc'/kL8TEk%t:u=|?Q ;DN d~U7 S[v0ؼ?bjv? k1N\*7V*=4#S endstream endobj 280 0 obj << /Length 123 /Filter /FlateDecode >> stream x31ӳP0P0b#S3CB.c3 I$r9yr+q{E=}JJS ]  b<]``? ×0? 'W g endstream endobj 281 0 obj << /Length 161 /Filter /FlateDecode >> stream x31ӳP0C CB.sD"9ɓK?\ĜK(ʥPRTʥ`ȥm`C}?  Yo`*?!*9=g!@d\= endstream endobj 282 0 obj << /Length 159 /Filter /FlateDecode >> stream x1 @бa1[ZYZZ(ZoG 2΢]> stream xڍ1@E #0eV$&ZY+h+{4(- 㲘ڼOϛ$ͦ񄇚1'O6MvV6&U~{I7 ֤rkT dR" "/x"o"x Aā, Ң~~5oU9qNȩ9IR 3,hK` endstream endobj 284 0 obj << /Length 221 /Filter /FlateDecode >> stream xڭбn0bt @Y"QPNt@hycs U.ɺϿm˧ > stream xڭϱJA?lq0= %*#xE@+ I-SD5_,9 ,9nsckc_ťc?f5ySǣZhZ}dl5.dj0r DW@`D$  F]67@Hmtt9OYw억g߹٫e&ڥOM&7ۊ` endstream endobj 286 0 obj << /Length 172 /Filter /FlateDecode >> stream xڵ1 A i832VºSZYZZ(ZXYz#llXZO7荆d/9C;GtVibs0W,lQ9O=l1!洖}N)!0Z2-ygg"(.0P5tŷAUɲ+Y0\%-nYW endstream endobj 287 0 obj << /Length 218 /Filter /FlateDecode >> stream xM1J`b`w.~7hXW0VbZ * vnUra!,ǔK-tgQ ->Gy劲p3%WtpK-Ϗ kxzX 33䎅rCF40@:b #LɂY.dČ 曶AȺ lB{,Zxώ`1K{+orSN~o' endstream endobj 288 0 obj << /Length 160 /Filter /FlateDecode >> stream x31ӳP0P0R5T01P05PH1*26 \.'O.pcs.}0BIQi*Sm` $?` #$`'0   Sd.WO@.] endstream endobj 289 0 obj << /Length 159 /Filter /FlateDecode >> stream x31ӳP0P0R5T01U0TH1*21 (@es<L=\ %E\N \. ц \. `,dF }H<00g?`G"?\=kqt endstream endobj 290 0 obj << /Length 174 /Filter /FlateDecode >> stream x31ӳP0P0bScKCB.1s<L=\ %E\N \. ц \. 7P& eJ``$? @cg@%4*PFF2?F2~~F2?N7 H{ r V endstream endobj 291 0 obj << /Length 237 /Filter /FlateDecode >> stream xeαN02D%{pҊ.TD$: &73Ea+RősƂ)eTQS9mr|IJҌ.kk* C秗{˫3Q&l [f۲cvӨh+켍 R PPÛLm55wۃQ?ڋ_"|v։&Ԋ*Z IM ]4O`9kb{0D>7k endstream endobj 292 0 obj << /Length 171 /Filter /FlateDecode >> stream xڍ1 @ aM@ Fp A+ RK EۉG(2E:/u ͧB"IIR9|c#ʅgݺ+Kٕr%:/%!ԕIDeoKhѰj#0#0?Y` ` `]ГnS^yi endstream endobj 293 0 obj << /Length 232 /Filter /FlateDecode >> stream xmN0Kxe' 0Y*E"L vd(~wH`O,+¯.wZt7j='(IB??v7ϭo^x# `0#,yB=:F0A.O= {řs2t 9FtJ:ZTTwHsͪTU!,)b")3t#}wo endstream endobj 301 0 obj << /Length 137 /Filter /FlateDecode >> stream x%; 1F;]]hL!he!Vjih7eIY@5`NKnn;[.>Yʬz8nQuĥ>W#D*L"QCĶ5e" ьwO)B endstream endobj 302 0 obj << /Length 132 /Filter /FlateDecode >> stream x313T0P0S01T0P05TH1*26 (Bes< =\ %E\N @QhX.O 27??~0?P`G( endstream endobj 303 0 obj << /Length 192 /Filter /FlateDecode >> stream xڅ1PDPl Ċ1D+ cmq@IA;WL0 v xlagnEt4'g'Ty!n{> stream xڅO; Pl {I*L!he!Vj)h-G,-$q̃T;LNuihuɗV'/2O4Ĭxq7 $$M | ,G\W{F9^ـ"J[|rY"ֱ4nT?pGrjݬc_e*[M* endstream endobj 305 0 obj << /Length 167 /Filter /FlateDecode >> stream x313T0P0U0Q0T01SH1*26(%s<=\ %E\N \. ц \. L@$AD=$? ?@P&VV̌...SG;&.WO@.n= endstream endobj 306 0 obj << /Length 162 /Filter /FlateDecode >> stream x] 0->KNZ N⤎>cbMN8>] y GGbO%T2[0YFK&pOdLSAZZFHW 2"L}Tߩoﻭ "Іֺ? endstream endobj 307 0 obj << /Length 114 /Filter /FlateDecode >> stream x313T0P04W5W01T0PH1*22(Bs<=\ %E\N \. ц \. a`?r 5ez endstream endobj 308 0 obj << /Length 116 /Filter /FlateDecode >> stream x313T0P0V5W02W0PH1*22 (Bds<=\ %E\N \. ц \. c``pzrrlI endstream endobj 309 0 obj << /Length 171 /Filter /FlateDecode >> stream x313T0P0S0W0P01VH1*26(%s< =\ %E\N @QhX.OXǏ?1 ɁԀԂ2} pzrrxS endstream endobj 310 0 obj << /Length 136 /Filter /FlateDecode >> stream x313T0P04U54R0 R M F0\.'O.pC.}BIQi*S!BA,???PP'W ,5 endstream endobj 311 0 obj << /Length 99 /Filter /FlateDecode >> stream x313T0P04F )\\@$lIr p{IO_T.}g E!'EA0XAՓ+ ; endstream endobj 312 0 obj << /Length 157 /Filter /FlateDecode >> stream x313T0P0U5W0T0PH1*26 (Bds<=\ %E\N \. ц \. @#HD؁:Q'@&> f0d82>3 df Dpzrr@: endstream endobj 313 0 obj << /Length 107 /Filter /FlateDecode >> stream x313T0P04F f )\\@ IrW04 s{*r;8+E]zb<]:\={-= endstream endobj 314 0 obj << /Length 155 /Filter /FlateDecode >> stream x313T0P04U54R06P06SH1*24 (Xs< M=\ %E\N \. ц \. A# ?0` @.WO@.8 endstream endobj 315 0 obj << /Length 110 /Filter /FlateDecode >> stream x313T0P0V04S01T06QH1*26 (Z@ds<͹=\ %E\N \. ц \.  \\\A endstream endobj 316 0 obj << /Length 103 /Filter /FlateDecode >> stream x313T0P0W04S06W02TH1*2 (B$s<,=L=}JJS ]  b<]0 szrr$~ endstream endobj 317 0 obj << /Length 117 /Filter /FlateDecode >> stream x313T0PT02W06U05RH1*22 ()Lr.'~8PKLz*r;8+r(D*ry(01l;cNJ l r \+ endstream endobj 318 0 obj << /Length 168 /Filter /FlateDecode >> stream x313T0P0bCSCCB.cs I$r9yr+s{E=}JJS|hCX.Ov;: PNF01`u@Qf f2J~ 񀿁;'W Ǟs endstream endobj 319 0 obj << /Length 239 /Filter /FlateDecode >> stream xڍ1N0Dg"o|$Q6ZZHPQ *!p!eU8i=opZ-uC玝|H?Я\~4wJ3޻MÍ?ε/2"P<> ufA@5ã`cO4s1d1gʮɧ:eP~Kٜ-˺QvOh9X܅H$% RM Zlmb dr)}A!> stream xm=` .߁1D'㤎]ċ8p n #~$(}L> stream x}0K:#pO`i1NI4 Kd0FMj\ijx@½%\PPGL2P[2;|=7P~K<Ls 9y|9#l K#vӜ_[ZCN _CF,a8[NXTQ endstream endobj 322 0 obj << /Length 218 /Filter /FlateDecode >> stream xڝ1N@4QY AT (Ar 3AzWJ_kN|y9H/vI'Zun8-)\ؙBwoVWg)6r}Gݚ3J~ ZTMa.)- o̤/`tR27V֯ifhh`+-RN]dvg9 endstream endobj 323 0 obj << /Length 183 /Filter /FlateDecode >> stream x313T0P0bCSCCB.c I$r9yr+[p{E=}JJS|hCX.OD|?b0 AD}&> f0H0b!On%rv?s?>  `szrrǁG endstream endobj 324 0 obj << /Length 147 /Filter /FlateDecode >> stream x313T0P0b#SCCB.c HrW0r{*r;8+. ц \.    `|$lthvb)،6 Q .WO@.̌r endstream endobj 325 0 obj << /Length 145 /Filter /FlateDecode >> stream x313T0P0bCSCCB.c I$r9yr+[p{E=}JJS|hCX.OH" $`@CLmQD !( ,x endstream endobj 326 0 obj << /Length 227 /Filter /FlateDecode >> stream xڍ=N@\4PY AT(PR$ގk 7eUI"Q|{;5袥aC]8> stream x313T0P0b#SCCB.c HrW0r{*r;8+. ц \. ?c4 N%'W  endstream endobj 328 0 obj << /Length 108 /Filter /FlateDecode >> stream x313T0P0bc SCCB.crAɹ\N\ \@Q.}O_T.}g E!P E >Փ+ HX~ endstream endobj 329 0 obj << /Length 123 /Filter /FlateDecode >> stream x313T0P0bCSCCB.cs I$r9yr+s{E=}JJS|hCX.OLŘN|? ?*f endstream endobj 330 0 obj << /Length 177 /Filter /FlateDecode >> stream x313T0P0b#SCCB.c HrW0r{*r;8+. ц \.  B`W${1y 01h͇q|Fa  l?`!'W , endstream endobj 331 0 obj << /Length 194 /Filter /FlateDecode >> stream xU-@%&c 迨 P$u[GEev K1h8&nL؃-;CFXA_>pi ?!&+R"c(ɉ(N+ƵGSroW\"Ϡ+tIߣmśh5| dXB]/qs| endstream endobj 332 0 obj << /Length 170 /Filter /FlateDecode >> stream xŐ1 @ERxt)R-n!he!VB9EqW7seϨxAƘxң3U5ݮr 쀾"h `,T'uID x/H 9 Zpqol endstream endobj 333 0 obj << /Length 174 /Filter /FlateDecode >> stream x313T0P0bSCCB.cs I$r9yr+s{E=}JJS|hCX.O0"370`H؃@`?#^^Q`Cƃ-Y  f $700 F"b\\\wN endstream endobj 334 0 obj << /Length 209 /Filter /FlateDecode >> stream x1n0/ʀ! &HYj کC @9j1CNjKޠ{iˊs.y^,V\.x_ЉۜWH[KEԯ|9_do\g ƃHLd pLi'Ai ?NI i&tZ0^gȅX{cY701<5  endstream endobj 335 0 obj << /Length 236 /Filter /FlateDecode >> stream xu1N@ E"a|$H" * DH$*\!G2HQwmT 娔DJsՠg?x#Um<>r\Iq+wn˜24wC0MLNLtA 9a=tC68yF̛aO2/a<&E>oxv endstream endobj 336 0 obj << /Length 167 /Filter /FlateDecode >> stream x1@G(LtYY +D ,ZZhq@IaGhf'_Ϭgɂ#}SqblF.b27+e=Z3bÏB&.ْ`9:Rs)U*H]J^w¤%HRQC/~*hGo8 endstream endobj 337 0 obj << /Length 191 /Filter /FlateDecode >> stream xm= @ x Ղ?` A+ RK E[)S,;h%Xfh< }:ex\T:8^pVQ>EmqF;)C}FE$ sXBט^Hȃ@?|bezYETZ_q-`R!a~K<.Kj/\ endstream endobj 338 0 obj << /Length 187 /Filter /FlateDecode >> stream xڝ= @g"#Xraˀ!N;GYg!BR@[]/w%ܔ|q&?,Lƹ+x"ҡ@yRx -0遍~*?umֽr!0e] EӐ`%Ж*sz endstream endobj 339 0 obj << /Length 182 /Filter /FlateDecode >> stream xڍ1 @EIk9 n!he!Vjihh%GL2Φօ}g?ofǜlS>'t#k5?;2{Zd܆L]rBC\"iJzD=[5/jLAOQ~ߏ@B_Zh4J5Ϋ^RMuZ9uEJ endstream endobj 340 0 obj << /Length 193 /Filter /FlateDecode >> stream xڕα@ .<} L &`qRG;[pqᾤ 5)+H+9s<^&|XLפ*L,r0S⺡MNMC $z11wx!"><Zi&N?>cH RaH'c ˁ:ѴmO, YK endstream endobj 341 0 obj << /Length 201 /Filter /FlateDecode >> stream xmPE4K BBrmM>}}V́;ܹiԥS=T'u9&a+NFF⻥OK+ VZ[( f#2;܃J>PDCv@Z }•cC 7'* 4u.7mp b2rcZI_ endstream endobj 342 0 obj << /Length 154 /Filter /FlateDecode >> stream x313T0P0asSCCB.c1s<=\ %E\N @BA,@Az H?*;&p4Aka[~ `1.WO@.^ endstream endobj 343 0 obj << /Length 253 /Filter /FlateDecode >> stream x}J@#E`}!k.p` A+ RK E#U(y[,gǰzqꜟJz`;볟 Z.(wk~x|ws%{/xv4lnfxYDdItSn\#7@efd=`El6X4jB*`f}E_h0bj1SL̀,x>v*!*:MƢ:?-y%ۧF@-7> endstream endobj 344 0 obj << /Length 161 /Filter /FlateDecode >> stream x313T0P0bcSCCB.1s<L =\ %E\N @B4Pe,B @d ?  B~oAd $?HzI8'W z endstream endobj 345 0 obj << /Length 132 /Filter /FlateDecode >> stream x313T0P0bcKS#CB.cC I$r9yr+r{E=}JJS. @-\.  @x@@?C1;}pA|.WO@.O) endstream endobj 346 0 obj << /Length 198 /Filter /FlateDecode >> stream xڝ;@%$p.H)L0VjiVW(x[_~0E_cƃ=2b4gA ΄Sp)-8lsQy endstream endobj 347 0 obj << /Length 115 /Filter /FlateDecode >> stream x313T0P0b ebUel䃹 \.'O.pc.}(BIQi*Sm`Pz<7,{\W endstream endobj 348 0 obj << /Length 171 /Filter /FlateDecode >> stream xڽ= @[&G\@7!Q1#X^,7[n8ȃW3r9Al&]'-\,cx܎` s0 n ==Cbq1 SeKvI'mr/)T8R`5zf endstream endobj 349 0 obj << /Length 155 /Filter /FlateDecode >> stream x313T0P0bcc3CB.1s<L =\ %E\N @QhX.O$$PD2`$ȃ@H&?:7 q.WO@.ll endstream endobj 350 0 obj << /Length 183 /Filter /FlateDecode >> stream x}=@XLvNBLH0XF[٣Q8ab^2}KJ)*%Kw4 +@@)juE]VQzB[_P :9o.A@9(dq%7@'a/=ߵG.^Tyh p A!\\[>P: endstream endobj 351 0 obj << /Length 200 /Filter /FlateDecode >> stream xڥ= @g fI"SZYZZ(ښͣ[.(wS|7q4HRYs_8 LWCNv?$#(%p:lHj&5pGٌs V,S*7;(&A]t, -GT@8=F> $_ȥF<5ޯ endstream endobj 352 0 obj << /Length 158 /Filter /FlateDecode >> stream xڭ1 @ПJuj!Fp A+ RKAEh9JAqc![̃I`4-ØԈmjw쎜{Vky\Y\/|9êe_Hx+5C8#$RC\B"xo<Iw endstream endobj 353 0 obj << /Length 185 /Filter /FlateDecode >> stream xM1 @4!s7q5@T0XErr,,2ԎgDM&rv=pr^ًYMyaoY!RrGB7 }KD#"eZSW!("PB Ca}96A=> stream x313T0P0bc 3CB.cS I$r9yr+r{E=}JJS ]  b<] @AH2`h AA~[@ Lx:B endstream endobj 355 0 obj << /Length 148 /Filter /FlateDecode >> stream x313T0P0bcc3CB.1s<L =\ %E\N @QhX.O` $0()D? d=H2cģd> endstream endobj 356 0 obj << /Length 186 /Filter /FlateDecode >> stream x5= 0W:oN`B`A'qRGE7^̭ ء4ؔ? ,&Q@>0[}pb*Q)QzܟvI>>yG:J^]S |-,ZHZX:^<r[C准qzb&gaQ$L endstream endobj 357 0 obj << /Length 174 /Filter /FlateDecode >> stream x313T0P0bcc3CB.1s<L =\ %E\N @QhX.O `?aC00~ @2?Dv`N2~+ߎ #ȏߏ`` ?G#g``?A6 H@RՓ+ ɝm endstream endobj 358 0 obj << /Length 202 /Filter /FlateDecode >> stream xE; PEoH!LUBBBN!۲t @!L@,a̻{ې lfOÄܒZrɌOp>ܘW!kJ/LnRQ;H(+p{h/ O.ok> 44W&F&R$}xY& endstream endobj 359 0 obj << /Length 237 /Filter /FlateDecode >> stream xEαj@ dz)CB=ҩCɔdnvj:t&=$%p!:d-"zX!ZnhyxDQd}LKႲ)ֳ[{vȭ+OPy5 @U-G[;z[*lB;v\ɼHer;SHR Z88 ~Ka{ endstream endobj 360 0 obj << /Length 176 /Filter /FlateDecode >> stream x}1 P S2Y<9*BV N⤎G(Ϥc|?!?'S3>gt#͔+^wr~ÏB.9#W!H"Px+"B I / >i`$f_$hj(D{{-ӎ~b endstream endobj 361 0 obj << /Length 203 /Filter /FlateDecode >> stream xڝ= @_L#8MLRL!he!Vjih'({!q-6߲`}t!'<8 91 ũ piNfqJf)c2ot=̜w{@^m W÷x: dTLdO_'X`*w]!WҢqz9KU" }}d endstream endobj 362 0 obj << /Length 141 /Filter /FlateDecode >> stream x313T0Pac S#CB.# I$r9yr+Yp{E=}JJS ]  b<] X큸7001;j?0FJ endstream endobj 363 0 obj << /Length 222 /Filter /FlateDecode >> stream xe1N1E*i| .-V Ab $(UAݣ(>B,?kWEwk.i;O%/$=iI^>$nF6x0ڄʬ ͎X⌾T~fGvlgOȠ<|HTGǂ+ˇD5WTL3*=2,<8h endstream endobj 364 0 obj << /Length 226 /Filter /FlateDecode >> stream xEнN0 J^ @ZHHCL @>ZlDZTe}9W|Qps}ů}PYkP|N#5[ Sj~??ScNzDDFM&4=:4WL hLVښQ5A1;,wKi sęǐ dw;-y"ͧ\ۼ>[z3Vc4 endstream endobj 365 0 obj << /Length 181 /Filter /FlateDecode >> stream xڕ=@!$p. b&ZY+h pJLh$%^5Y (xTHN)74 U[QcL uMĄB9ƛG3a(if M( /#`cV2OZ˿Z;5t endstream endobj 366 0 obj << /Length 207 /Filter /FlateDecode >> stream xڥ= @4{t&)!BBB,xxqFE惝}ov)ZRGk;Sʱڬ)Nюe6aܠOi(Zb>$\Cǹ.5Tº)7 P \)'ߘ'-,e$9ґ i `AY ֚ G9-c endstream endobj 367 0 obj << /Length 241 /Filter /FlateDecode >> stream xm1N0E"4 @TE"Th+)S ͓=3uE5w|pWs/ 5gFGn{n5j+UknS=6@! `dHp糢0g0p \ύF<'"DMbLz[Zj6]*7DE??(jALP5ˠGԡ(OY*G@BR栛 5pI endstream endobj 368 0 obj << /Length 183 /Filter /FlateDecode >> stream xڕͽ 0+- h NB`A'qRGE(}zWEq _~3#)';#I~C"cQ8|Q iT5t] '`010%p1 iBt*Rt 2;nB)4_T+~Ѭ.:\M endstream endobj 369 0 obj << /Length 213 /Filter /FlateDecode >> stream x}O @`qM>!zI 0XɧSW؈p w3s3Y:'sÄ1P{~s8Ӵ$4'tcot=w {* (D`D:y#jAԠBQSQ]9h@9׆mƠ3/"-PIoәn ժ?|R3{6nR}Zn endstream endobj 370 0 obj << /Length 245 /Filter /FlateDecode >> stream xm1N@ Ema|HBbE"Tj`&GkH 4أnv+4rVISJ{!Orݢ~9^ꖋknR*.PI^((`)3Sژ1+-:%8p'?, \%ᔀ^ÊH"4)MP9%7Hi/! GdL!n&{| JMc_u|_!r endstream endobj 375 0 obj << /Length 111 /Filter /FlateDecode >> stream x340Գ0Q0P04W01P0U05PH1*23aRɹ\N\ f\@q.}O_T.}gC.}hCX.OPeĀk\g endstream endobj 380 0 obj << /Length1 1460 /Length2 6185 /Length3 0 /Length 7176 /Filter /FlateDecode >> stream xڍwT[5ҤXIP@{Ej! I ^+P(U#E;_P}[Y+yΞ=sf9 ;}}^95L@--50 @pNn`(000)Bpx P`aq8"0E PG!aX v Dr90p( ЂaN@p )iáŁ@WWW>pz0,  І8G0cQ8W8]!m`~w&@ C&k&9w?_(儆 H;-(kp9~( ԇbh G<?f% a)Sc`P4rEz#ml˰y"Ώ`j8xDED0g j< e=(4_n Pxb!.0(` XHa5:dW p@-uU=-?%mGO)7sdC4wUc¹"I1W3啖p |S MPpup7qBxy8 }@d=[k zlr3dV)a AvNnT K_:a@]Au 6;.JBO~J7' :ɁNǛi{=[yriĨᏖi%,^6u nj\tDvSv8HK-R~d|bϾdo 12leH]a1md9>CY^!d?{bmo XX| &e#;;?&3cL|;<,+BnmPj,~jrHQ@}ߎZ=~C`.co)r4nIň0ZZAm͵1[Fd+j =b| b\Q=AQXwю9,"~x7A(-I֮Lu7x&G.\j\W߇Fe(eI~P94e17P}否9\\[PM#D=Lš3UYlY}%ls ~pB{=5.47uGf]!KHæA *@X5ۦzQ#lvm'6sTN S)=]cEFe)OxZh% -3Tsx#AB_Yik9{Q\F)oÚ6(+Lnҹ}k[x|[w0g{N7ӵ72A }}3t l`4QA+9-1ZCq6ϵ׃͡p֙[L  { W̶?^cZ]"@FemaHK-jw 3~o wKJ'E>MGSwi׸kUM"+\h^^]TeKnMYᨨg鹲ؙHM+X6B*x=[3u ǝne7D_eC[Y1*)g8EqAAH Aطfö:d3 b#qB; ԍ}$41z,У:iQjj]1O{b +wZCU^{z'̰(G< `2gT..3z4Mks$2$eb=Cj){$~j!> 90STzW=QUpNZ':WT;Ov˫Bd^Dž!ӜeD)K/#$0ǔcj6ʗ&- {gTu8IxFZWPb1 =6i rzsOJ5WTN8x{tebznh+/k7.OH'^~ti;k+l#^Y a}a )ltꛓ:Lz9?ޤss^nz3vH^RpüWgLHd2d[r]' ^m|BN_$;Mwc@+3DX`c;4*j*z*df'#H<3[D#͓a!wc /ᭅ^6FR& }ZM[NN\rNH%-#|_VRSV+˪=2~SH uiiajtC̖\SF-aTJWq B_*ˆ?Au Qi*mK |ҥ]^ -öm_32zbгO-03dDL4|ݹ_2i)SNrumn@9&!0,x<`| c 0kGYE'=[ĹCڱESVwc [NӲ3rw??li!Ǧ#wU4%*lD(JI`*^DIΗ bVmۋ>7I[ѳ-T kϮh\.L.77ce $A&԰PV|Dd64Co{k.^</W>p< xiXbҜKavqV*Bq~ \JT*u݉k>dhe0bYD7X,[FOOlTlJU#fo f6#BAގ>C_ܯ"iQbq˱" N.j=/rDvu^P ʴS-/cl3MVbmj?9B*d˳ľւ7);oup<=Byi6YɛGz0K|3Z 1UƛIvA[r9,T̵?P_%ݝ+IBL{.Ŵ]l!Gvm~)о |bE61i@E~cE \9Ub悬X8k LV3blzգ.=C ^!x mB m/ZKj9 t̽1Ƽ2ZVhNෘgs2JV&L׌JT}48cgּܠ k(Kkm&g-(\ՉSz]>cobe}arK4?sfPZsZ–3SjHé~9摆e!bxy*yjD[m5f~6+,ordZK%O8xrGT㧛g[XblJ);~2+<.JDZǷ`|U+Bcʎag"*vQM)oůK\ٳ~-A8vsu՟V*wظgO2?HN?# ^/tW=w;XQPF5b}|v,c T&cFᮄΎAEڹTss6sn앤zB 1v՞}K矦/s 8t˔2b,ĽPq(FRX֯-(]3CkN./:q?ӠTU q85Afz⃍TKߪ.dsaVsN'Uos(56|*CX)m&$q+JJ8Tv5~R[:2Ŀ v7M/)DY(̇TJMcb6i3em0LP Wa48i'EdV}X4d59jxB0fll"nhV&OKI r0g{re=]n4e]c,Rgk@B/6..S+5 2Gd%[]2蔠4Rj;E=V?$]t2.g9KrVZ@ ؗ|r/}y$% $lOBwqC n[;<t",u%o]:Mj&DŽm`Tm"KzÒ=(y3\BUzW4}nWt2,LKZ0 v3(V6V2"tHC=2D!?`0\FKSYly"3,I*xg`ns7ťHFםa.}V|W)^PM*Zb>Ԅg A"e*<#f֤ɸ9 DJD}InC$e^R^US.C7.t8DB4lT־J5pD+o&wLP?@ LؔQ)=?}򑴻(f vwlaBJgAZ>]u%nX1 qcssB3jA#}Ni wP 8jۣ@?\Ըg8Yx܀3sAiaڦfGt?,YW~`"'Zf2!n+zZŗ:|OHSVnUo4lwCWY(cw5m;R3xy:){$4ije~19TcZ5N*۝02VEbpj@v.‹ Zn'=-5e^p6E86 )p31ga%wj5u@?4Jx'PGWN'=EQmt\gs@%)N͒@XB.}QFbV7v=r?qvq-;3M/9XރH0r1|~i]ڃZcV%3puOk(,-puEmOu ^ӈ,&>,4I ^ԅh͗m$V>Zzy'z3uPoh`TM>*%cFZj-߽)ZF*;%<]YD> 8>nտc?~lhs/1b1uÙ]nJǜp QDB]>n^lD&5Dgvײ;Vx؋8 {O[ oII{]pyY]bxŬ:lf5Z9j^ekU*w ѵ!!91_gCAŋ;XcYԽj=f? V1Wcbݫ A=@/BnPj clM޿-[e1 =qVCW]d_#8-)7OJnVfZ_~rTuB~: ]/93ѧztb񪲼ݢ)$ endstream endobj 151 0 obj << /Type /ObjStm /N 100 /First 882 /Length 3673 /Filter /FlateDecode >> stream x[[o~_gI^#ԉM+acoldH2~gJ? ΐC<5.)ʉ2^ʈA2*mLoBLxgS62P2wʠ hA5ELvab fJze"K(-JE"X0;e+\:g=fVֱ Bba# V1 $8B$tfQqt5iK@' DM`R0JF4)F3$3Jbf$XY=~Z PWj >j0J2Zh^Ǐ9d-M5YRoT*q0GC޼^#jKx忟y]-ҫE1!%H#g?XrfHmQyj<*,т=N jo%VgoE}qbȔy| Do<8'e_g)L7@ѓf0rgdHP!gӐaqNL?$#qhR1v>lhޠ-Wz%0 m"Z'C=F {mKhئCF]aM2 GEaU4bRELí`ݍŬЋh0foGy8 1*`@Ɂ`8:_7{8>`381I[[-J}HttT`!+f),ۅ@0Z^; N^wG'E'!=\0;ӄ& h!ɋh}52]Dܐ19KhiwB\K ݎ<^ҡ_,{e}ؽtpκf{fYlKvHo@pW^Ih]F<ܫYD+9N.,A "Z q绂&;D1ˋhM6nzڳ=Zs`ƹܑ!Kܐqz=nƌo3إ,PT@Ef%9}5LA{ȅ#zQAsh8 H,ćc6p ;<@%RY}@ضD0&H9 q&00$bbW6̈́C +D@cT{;fыFYpb9Wfb̝ؑzXXX t3t5z/LD[(s{~!!5NH *D=sq[U!ENvvK'kZ}q;n;\mb WFWHUEߎ v`2ϋ0͹r~i%yE9(~oޞ+'%ML 㮷$F߷p62Lv1/1>-y r?WG-ϹȌdk曂hQ'mɅ5e-)6bE'X:fS^);Ä3gt<Ӷ5 ;jY*&R3{ȱ; ;dw(n_'cK~u-/ߗݜPB[`nBIh9KZND` ٬7٨rDe7DDSˁ7SKdfyPŠrmL:mؔTL $,RS"\<656y]՚"al)RaZ#cn)6g4\u..=*Nˬr7u t:_U06rQ/x}Kw+w341D@}'V`B@w6%!#'WӄTgQ@Js{ &Jу۔w j˙JMӤlp|xذpu#) 6Krah˲س1_Mjy&/mg3}e z+a ->v^a(Wi[MrQWmB㭫)***TO`7*]=獙Z3l]{l6h͘JKH%D߻8;^w1"5%Mw m$5^x)5^x (5^ ;/w/'/oswMqcJU!Ӕf;m=m}CK:#Ax cǷ#1T6tL%8:#XA0U.2MkɾDMlחۏS)'ff77g?n֟'go6 k8'#oOPL^)&ǒ endstream endobj 382 0 obj << /Length1 1478 /Length2 6403 /Length3 0 /Length 7390 /Filter /FlateDecode >> stream xڍtT>H( R3tww30 /!ҭ04ҡtҠt|ck}ߚ~sγgVc~E'D GRe]# B&P &0 =8(#!`S0~8@  @bR q)  J@JTP'@ xs(#PW昿nGHRRW8@ :]09 #?Rp˸PR>>>`7OEE 7 0@L` #Q>`$`PGw ƚ:}wo>@J'g"(W0A.g( W@`OG0{0W`!!#~Rs˪p'e$Y  q\>#|6PON^pDS "7AD@0: Loe1 g H#{C($(? @'# q‰C1GB}V@@߿V6y9!0ꯠ!o))!|"@()2q"i ?eG&]- B5PRS, 5/엙1ݠ0?z0]!Vro& E _TB (Gj21@xB>+~Lkˆ-LJ#_&fry*sĄD`$Gi2f' af KA8 `H`LJi bQ#e c? uyy F_/ q$G8J? o WnW)Iv! 4 l?"͸5#cm]SocXˬ`֯E:jҢq8DN։吴Y+ySŪiƊ.VO]&a +c^z<9KBlu<YKlhoDkbϳ}s %wbWϲX'uh+n_. asxLq;kYf2!e߈@X55_6ūAśZxSZXZ(4g{8S ⻡f-ccwc?TpaS}oX~0XxAB2dL&3XHz-mt2cuo>'|kau۷)4$v}9xVϛ%| dD@cL'XdbuAHm/W4Se, }Z֦%W4SJ0Wb Z7y;k3 kDASKSԠߍn2h =}Egg5`a}aN9ﰜSbG$i0dkYm8{^X1x30Ƃ{ȟ޴mv?U=Jwx=+J_I'[*+i^qw_z %ub9Qղٍdj lٺ/{_CIa5C; Y /C/ޝ)C9=`ު!bDCB/N= 5;/.Wnվf~?oeD⵻A+Y&SdbdgRI/vjxr2vR{\$5P/j4V-vΈt~˷dX7>da+l/NWoηJo],kz|2JRZ=LY>kbSoaZ! civX0;iېp㱁xO(l.Rf-޳­ϑjXH3l"8D|(a$kB滔>s][l)?S|e3 }fm=,Ԅf?~VpdkViaN^[<(u| Y~crX1HZ{SĄ'jD ~6#oJ_$dzO7jbԞ=&[8)V][E?v>1 шȡF`~Q%=T4U&ܘa}RL4~T`ǘȯ09v.A>Ae{@ o2z.MXebjE[U_7lIB']7g/JxͲ#R{;9z=bqf:ATf4>|Dz\4(.UpuTQkJR꫐󇒚ߓ3p?_RNPzrG֖v{Z37[- 7v̐1qO)nhEk .]i`by3te:/E^˧c}::n? Vu2S]~~Uh+X[QՎ{I>pb1"-={CwRAncD^/m3AC1=]&==$t7^'=3Ƌai>;hSsSzv4D:%@ź1רصaKLCi߻OXYnopԢ >_d0!C}m7,fVۄ2OqDͷsդoqqQBc+ [54FțHm+LҮ][+d4.68שԸ&L3ck7 #WJ=Ē$R6z'8lM~}ueE>V]ok|iV`,ERuwT-1Mk# ^3rc$ihF& wM{V2q "~,}Q}-A´0̇lυ2ǨԢӃuѮ$2:$bmue@kUA:cUƔ1R!1m» {$BVj&/2g028nMӅ\B5? u+#bZʮY">?74Eax켌i#yG# mY%cQȓw,w.&_Vl; g+|ߜlP%/GR"K- e #9i/4 F?`[]dh0槟3/4^5/SDsut̞ѾS0o-g޶\1T+mRjYt;&Ui9]W '+wb;#{|UqPv_h6.~/V IRwu:4P4lתjs^&\?u?F,RnѕPKJ Hħ>ÑGj؀ϣ}_O*F!|=]/b:t9M9hN64c'˅i^qKGcJnhT [Q5fB<b]iIM3A9]쁱Â5c{,m_^s[D.7[*\xcܒPrDC3_U/q_j;v4?Ī7|<l佷X=p7m0e_}2)wb\;ǦZ+-iChg@fi/snNN0cl'2*_ wtGrc M.FRF83T7.Ney,Ay RpJR9l0Grԥ +Vv4I@opw:-e.ҝgρʥX{օX6&ǝCZUFe> stream xڍx8m۾ڳv={Y[ Dڳ^ER^[jQU/m}G}םac5CBp(P20@?(fE l7$mPhPw@B8HTbnE@Cl Wo7# G' sA6p  `(('  $b2@WklCG(aq hw 0PBȚ6+_޿A῝m`  wCa&? " fc&.,AwWHGBazJp; BO[u#<p;_mع O!jq1  O/ޮ0_W+jA"m< ;? \@;(8@!wźh_=YfüM} &r</< '(@ @TT86п_5= \>]_k@@+-@0 oE_)` V; =Z,gt vPwl w@+E*C vPjF CtH =d`g-DK UvMPX`f㍏>kJ BO뷘p @G:XA@qlWuo(]w,|bƏrmNRj CwM/[aL4=j(Q99G0nW7-3= 9+۹̔u5hjAGfnf4v w!C{<.sӧ9}B'="U4>̹CI49MH vys"p%ǢKߧ <ntCHv/[g~ ל[*Vmq>qT-bu.ԚB^jb.4> w86+$h*{.uµd*\W Ki}>/ח dvc!dPIG޻&5J"ZYD5W|nT~^.n[8Kq!鬡FS0)"r2W "/R.Rۏ']U۱ F^muԃh^dбRkҧyn5ER&֬_3tgHRm:>&Tg -U4 *|꣌22l?kso۲|N1X'rix3iipұ`ݪ2j/>kb`ݝƯ Axy~HA?K) %~ ;{ZI'E&)#r1¥%h/~c?v/Gk&C^d9 Яܴ,w _'- (cVz{_IXIdv w_.!k"oW= RVjC/J:IT#U: !ƈE$&ZҼ}k%,S'n{+a):MZS w8Qö.u02=ȋT}9B!^ t}5FFa#o[16ke'I.rĩZ Hcgq4*ђ9ۓYIv  Z!Te R 7ڷh#BZtB +SlDawBU }^F[*:~<\/\Oڝz7P8^Z5J0N+#fFg)3Fҏ0OgKԛΘ2D`/0_\5mOY ڂfYc6NO,IRכ-졡oVW 7bTΏ׭PuKo^[aD dK.x3 2kY&.-pF}#'dxgAnݔmF]kS} ˂1ِws-+څT !]6eYg2Ӽ'|Xr#HOHn:ŝ t-n"o%Ҷ=Ŝ IT]%hfN4qcPOٶ>* 2,l~OE۵i#"CE۬M-?;>p t)ݟ.ki$x/!@ `1E3e(]&ñ7gӆ1՚Pbsp~`@yNr[޿.mǹnwYsazJp)w}چ3Js AL/{@JY/9~iBap܇XIZ}{U T{0kUHVB?A>!n^e(_:ML V zhJh=# %<*,MŜ]zRkÏh|>5LjD)b{GmtMkfp|*׿QY~fYn=m Y;zoa*`Ӎwbx:/DcTqCYb{Y s?+ze]ddQ>[z~:yf4o<)vPIigjsr/V;8#<_zԲaGzfXBA|pYIi2o$pI'í$|?.K!".R\HVNT!Njx9|uYDG>ޫ%4zz !fВbqB[+&(}8A\\d7IH<+/v 犊hOxtpu+'QM{6ev|Bn3)-ByuǞk|!D҇$WjeүKGn:SvpQBI,{j}[Y#K #=bI6IN< m;\ rI=5ܻA&ݘƍ>fr \wcw SH{25GNv7HP,E\ec&lg?aD7zOgLLn62KK cF27>\ o [)? AaR`IGi s$;ʥtt-C4~Jk4&? 'H7d}P=Q/[SxWn2@dUrK)뱘RA+U3K@s_BEʇS]ugng˕Vtmv5O/M߻B ʎ¨d4VPݾ|3tmImwBݢҎ^#Lv}ѻHkfg95.jKF͟iXiRn8Dk,k?N ڃ<)`F.HL 1WfN*G+30{KG8Y֓OL}d/nu b}PۚrJ?~90\-tX|9]Ǻjֻ xdžT>KwHN\zQhY_q0BEi 骶})]]TynnY#%!2oh$(H=H2nJgJUbBϯ&!lX ۄ:7\$5aMp@@-Tu8ZVS+T/[m>8\f^Hn2( Ey#`t"QɝeNAjZGWu2]!mI,"F5@-3zS@ /ȝ/l9絈'~gaա:JҢʪ7 uFW3e}[q bUVpޑGǰ7tE=MR>07}0GccӉU 2Vrm9j٫9^\"m ˸;mIx?8޵H3Yh<pAke20jD:D`nvmV9lY4i.xvExLIۖ-<'@G`@8&vfҢ+=w8%.ӍJK109 *}r~t\TPց9dR*[ҨCM"rH$B >헴 Ih:^]C^˓4wQz<3 1M;p%?dTz\TYqo읓.IK[d1qgVz:eBߺ Յ۰XvY@~<ϔfq? :H`ɚ[$XŶ]wnvv+w%'.GxIQ5c94?td ٴՂvQ s8!-k='Zʔ@៣N WYlg^Zo_ ╸&e6/P+i(` xe ]WJ kxMKiFyxM%Ry[S6cI.i˳V'rVCdMI.lNYOKb̡n݀{1 o;VrBwWu=&oy\m6/] ?Q?Ͼe=4͊ U.:O ? MH8r]*z[vgzT%iǒe0fv۲eR;w-0G07Y2.8(c{_ZMJ5ۤR3s%H_]O~{)RSa4$KO5|,)C.vqy ƂRZr. upBIZyfPd.G/BtnN$>n>uT_/#ߕ%K1Y~xWN>*#s=Bhi0݆Ix" 0؊а˩ nu~P/aT Lt]e%c0g۶lm cOW!yZ',Vt.'7uB?0NkSYY*2;2ysZ<Ǫ`^-]΅+@ǰ$a%F{`|xMs?Y'vBlϖk_nȏ(r'tdv+{̏)a7C. B)Td<y} FzmM7 sq1}aWTRFWqɩ@vtP\&ӯ{zq/IW>InPuB oZlg Z_gl:sŋIox@V<&vE٩^1:jϓE])AB=KS=8+۾xH{a[%EʼòӺMX94n1;?ݠ}Gs9ӧ+ѾlM'!!_HJ8% >FoH 3F.f=o.bi})RNike-z4VkBГX y^#kD&XY[yR ieO";F.X+,rC?r6aQV}kJS :+|~k]tzsŗc#\*wdҩ Lf4W9| 9*f - r?L EHcC%Q endstream endobj 387 0 obj << /Length1 1144 /Length2 3989 /Length3 0 /Length 4741 /Filter /FlateDecode >> stream xuSy<&BȞ}Kaf,5}2 c1h%c˚(}-d)Š-{-"v9>{9Ϲ(hnz`z4('̐~nAVp  Jpڋ8_4"8$Ǒxk ) @*DI)BX&`!($D`܃hU? Db@Tٿ1x,7_ @BDI` 3IBF`IE{5z q?{pYYO8zʠ8Y RhmO@ڟ3Ab A D=~/kF! u7y!p%<  k޲?SZH0xQp' #8l"<x q7Q'?py +҅z`(?fp?@mdn*{GiiaH@9EP^U"XIwEs8+s,4F`I.2?08; IAJ ?H?j~ϡB_&(9{O?:88 E{2Py aĹ{i?qǯ0"YPNI7FB=~Kvx ^+pO=%D D !iw8(OB ET̙3N߇ 寿]CO[J}MCX hC Z^*DKV6"\s`%Uzj6NRY |hCH(sYc%YzcJtR;2r~UǓOR^nU=TK0v(|$aU. P-VnGƞG2ϲLnllo?<λ慎߅ޙ:]>HzJ4n9E)on`PxekmjWz^LHuu8r =1L@gar u r6z}קG( 5y J tYmV\[*n+ kgs%5Nev?]k][Mfo}ٶs=ea@ZaRZmq ?6?YOܑ̙Nz!Cqj#\7/2bHzr}xTKt_{+3F,Aaiwظ5N)y-%Y+,4{E Z=!2>.Aߣ:B6K7m2ȪWZ/#?R:t)K<$@qpž7鬝)z+>X/W֠SsTC[SϾ, ;JgevٖY?koi}Op&I=xKf \J^wهoq$8#(쌸U9!W;fZ*2nכ1 j0‡/hy-BgDM^elTW h^3/ mS5aWDg/AMFJba<\7'mj ߞ6kV>µQB|EoYQ) Pϡ_ d٤0͜JoDC5 uUPU/ @j*}NfobR:AnO.~t0]gqA>\4nj7&(yXIo"ԇ<ȟ7X\ƌO l潿FOBT JX|L֑EOo7[nL1vqh)V~"rɐIŵ<]^|*{p4QNЉ>J3(a==z0α+ӑ.)/"Fty.:A*~m 7d0$X<uMj$3Q yY|F*}@yCov)h7ce "{@Afo,ډW_U#JUjIeM/߯*".~$3NnV^o l̟Ø%G:Xl{g?k~%|!K^_c$?)O;)n,.EjY1^L?yO5Jf H5-\j*!tƸ/柲mn?]e=فً Q !}9#LI(I]47Tf'=aGv Ī+. ]wΎXC;NrYV6+?I-|ёo#v2EE'%JNC]{wB],!SwX>'\U3_MN|;as.oyF.XD<4%;(ik#oWh8Yغ释gwD0:,uOuCCUًCgt5._3@mDOۈ%2p endstream endobj 389 0 obj << /Length1 1626 /Length2 13337 /Length3 0 /Length 14182 /Filter /FlateDecode >> stream xڭweTܒ-$Hp];4M N\5h}wfwZ}Jv]nJRe5FQsGShmoh+Ϩ49))A@ $f66+///"%@dmihj3W?=.֖/n@;G'{V@ YQ@#:A&veWS;k3H pq9:[՚ ; 4~Ozr1 {kk%>#/v ǿ 9#}`ʎ.`3^UYB@]׿G `dea_pt0WRMYU^]EMx\T~_;hE9zYxw/Po L k{,w FQ8or@}߻;zWCl28Cz}=CNEՎiۼ/5L S|?`Qw }i{ 6ڹ KOb/`tX4v&TT K^>M/i 0)~;cu|j@-<>rxz`txh w>'/+t[o 1+"Δhؖ`QAO_ʹBfA ךù0? 2H>i$6aG#pp2ʲWֶDZ`DA0yp$z q&O~7T|2؋vAdx-_~X-."lh_rŝO]1NC r˟D;Wmʇ3Re3zpgzu3}o3EֲqMm)ipxVU UXdt,)HT4Nk Gb,a;rǚp85-,5xKdw*I8&(ulPeE2upP6TZbtwgE1jNIb'ҋ̩x[˰!n$ͼx6'2eld?笑|woO8! ϡ{Bhey7nmbOVB͖ǀ fẠh+PWf1;ƫs6F56*g*UypfrK&z,^X9JKO %3q&3ܕ˨7\4[9]4%.?obmcjەK1/ c;V~{I2Rqm ׶MZۦS d&5ZIh!m/ Q f\qym>wG[1P_l[ZM'cZf'51IegFi\!c:DDG5yagC C8/#qXtU#8\cyl8 {gzuyL1(B&^2]%"wXɃG>}B J CEa"VÐh_Fi氚q.+]ij X/!8dc0;?h]~4b=W륏="pyr(_gCSkip @@&]bS)6U<]#zM@"ݓ+n*W)+t4ZCQ^6~N~)n͡)q⓶b}\M屶 }~f@Mz{EXKՒLX3<VwRs#+[aϽWlk0;S>5WLGf: *a^W˨- Nq%_K4`31P#cl{esU[^LݏsJJ""IuSEAd\d|n " ͑.R:1su. i\!~x*Γh銮>Jʝ[ _\$A/N'U˩qx"]gsD 5n=j$KH7ud=m]1N ޖk>*ᬩJ'Thx#Vf:yiz/T++[ȷEmLYo}tdE̷LXsV6e먢7ua'Z/lUB5;rbFLhE) p>GH-KrZvϕa HpO zkPG8ԧ Q\x{V-Eؽjݪ)i8 @%H;G?= -e6}F 7k׊le{6͸BjcZ]̑+|E)G'VџͿ4¼.Cc[~vۻaG.h(Vq5eAhB9SX^.jqu[>}"96 ;Gzr\2EZ)rP\n5ʃsZ QumnĦkc$wH /U+&=*m LǑXlR`+O_P`eL1~T!5qeϟ #R+!T|,@M6v>/4oSҞnўA:OLDs ^JWO[6 ~Ռ!)SXJq,=%Yb7KC_$GARrU(ٲ8F ,|Caw7 k{i9~ͤhhVr}{k,dyej-xΆKzlUeS_AGiWh0\b'hCy_JTq{S¡ΈBnj4UzF:?:b >5A$wQ%Vrm-Q1̮r`6{*7>a"y>B=7`4[U%+e\u@|t c? 3+:P~ f Tȗ'QDUс,q۞yI냾y?$3aϜ 2xl0է}:Vp/'fyw"/?ھh.x~7B,?-R[Jb FLH|i ק]);NK#\Z2 |9)2-m yn%^BUu[:r>͡@o$V`QxLRU`~W~M|; _;,LމX [q'πA2-qx6,N yr'(Ő7ƹMTqnu 3)p٣)CYq}^d!FFbnW^GA෇3EO-W/.2⨊dV YD'xJ2CyK;8ӡԕEzGaZ^IIݾ Xc*'E߱c@_[mR\M1/(΁D| ;.hRH/cHW4OEߖ TKи#Lg \~sl`>Epa\l1,uvX1X6ԁb7汆 74pّw2HٱBG+' k)Ni5IeB=KO C6{nC'I&)<_7 nTۛ->j葚[Ŏ!աh]GyDuFUPL1?ғt6 VJ,W"7uTP<4~b@ 80aR_1jܘm;r0Nk^@FCk&E*7_ƐvCYz_WZk /6CwnEF:aX~Ns%k0+\I^k<׋yD@-RbX C#Ook dj&⣭##kf9;8 X;8Дh:3 B -⷟Ah6' Rgsg{r0e(Qr麠wOnD+15}N.D%vt"N}- d--on<.92D݋ҨWi\G*{}z&/AyIOefGo^ZW;fAγ.$x zOhYA۩b"ڹꙫdOuōnk*};M^,WiI;!k dVG;qg5A0\bOz3,/56FoSm6P"B8x "$7S]@12i) b. '٧fÇm_kd@I29gYÇOg$: x $^ga7?0MφA[% J߇N((Fi.k<a`Wò'Q\%L@uf-W&%2҉#c3cL/Lq;tm} -ޅ4އQIhO}x :pM3r=stWsLA^ʈ0# 4MjL0xTN佅yIbzhQ SܫlGa{˃UDvr9QƷW&R?%k&θx3!2Nj/lǝȼ)2OwTk줋zܣ~ľK9}KbTܝ[Ȑ1Wĩ9۾/DχF>ןx_ĽN|]m9(8M7AJb9\~)p\˩~Pύ(a\ REg r2rJjeTs۴ ϔS$0X9BOs{}F#|YG.DJ)زgT}}nY*ЉYI_%ʒۭ)j-ɨ#"! iY+u[IK>VJCҕ1MXFyjUM^ rR3ʾptfEC0/SgnCv[&-]\{>`Pd1%U87<=ӠiǗWBMbD#הp[:oA}r}/#&hck7=Y'\27Ӎ|A[5 l}RX"5jJ6gfӒˑ?5ʚ!Qd woUf2BɻTYz0ûJwCR | occ>sZ9-&0|4]f]sYO^Bl&a3|e3"qUɼ 47+IET o/z_&zSBo&t0\|{ˢ8<*S+"3A.Ǩ>_ZD:ܫeH-m%K9}!dQH5ꈻjtW,$a~8{w撣Պj{ޜeKUGr]b!1Aav8fj4Pnt:ePyh{4wwq? iAI>NAd^>*?}uT!>.Xt):RG@ :U'w h(¯j '{ xGkTiMKrL;|o(ovn!g -$!^weۯ^nT ;-1E>_p45rr͋1{;I:RJe_ gMAim J22 CS-VC&{YH#, Ө~;GHC֊\uc;$|-*gXd_^ZJ o,H0Ed Yj!:t&EHEJQV]f.t=($3>9a7s W9Zw"u%{] $}m BHY's-,0<BReKr!eZט3il-5xÎr7Y $" y{F(?ZR}py4]Fx6o@ɥvCLVuDg~s !]*@ˠRӈ߶Oq|p'u´>A5ZeJ7-( R}U,˛):f6.6Nס\SZGJ'xZ>i*@pr݉EB mYL*Ѹj#Mz1u{sQ2o V /ԴItYҶ EK&^88rm/@sZfw2Ka4q5JUF MM<3vDFz8p5sk2/: CC'{T1WH`;טمC#sԌ.+d9!HZ:g{ ]=F0 \hߝٲ`'?(dE'^Đ1Q$pM8RJ8yჁ&N!)Plf9>:jH^ѫ`*3@ ׉;y8 2DbY#+xYqý)aumgQ[3H7hgZPiFuRz~Kj5 5 [=1BD퀔0?B&(L:ھdR2ݏ4fղ5YHFB:DcR8 (A76ŎޛW&^1X~٧,,ۨ_ 7]Jji-i} GЗێ meݒKm~ssL kenFO;o^ʜWq qکScLwȷv0}zw6m֐Ws"D.)`ڃ;+U$؛{43/G2ɂJ?Qrw[mӊ0h)\"SW}MF;b: 2חTG Z|v|-%v4 1f;"EYo:)D?19fΩ +qJ-"ΏDʚ?FAt7XLiËLm=8/m#&bcQNj'qغDm48Ϲ c?dZ:w-:87S }}* U#cHvf''bG)xHxO$(Μ+2hЌ U 逛Kv闫: ci}൶"aG'&A|x{=zFqޓiY oT_ GSyQN- 枳PAП{H.%C~AN l{YEzέQ&C(qYHGOEfZ[.>szdzޜ{U(+h]PEƝI=3|Tf}ƒxj͊p=}q<'f3xXEoxvNMo_7fȽ)幪Ϧ! 8f3?L=LWsaҽYһO ,rSқgi:q43TRPs@+WdqE~\T3+qls@}tڟ~qrɗx6HI$+v؛s.&cwU`ωJ=0{-$_' 8)X *O{)4ڹǦvVUI;Kq}l{Pph57ٴ9M)݉^(|.9YןIv"noVUFg1lvL25{_'rN=oT'uZVp٫&U|ߠb]?@<.?_*AC8$dSt;}Ρ͕hDcG>5-#yǕɜL%L~メLt2k̯`'l'lT$e]&gIi Y66+D3%hJNuxG} u@$n^'6IAbKi׊Koo7[n?N(Զ>X)%wBv7I> ru֋#Y2*FpbE$H B,d[8h5BK쭥Hq}֟D &r%;OuLqӋdECd2WJW+-j8[WP䎤:XL1Ef!b?dܵn c:½)rw0] 5!;4G]JIl7&阾y+?2J,?;}8˺~>)f 2f!?QcYoX`JbOEq ҃75y?0(${9}I:c8Pw嘷OV:vlD]ֽ:ߟeں2fQ fk'BBÆ1⵭ 64umlxbiG..`{U,n% GCxjX@n.jh:D LsK?a+;B^71Q#/4сQPl/ &h!M(D֏_/I=~C}j%v IDJtԟ=bJ3h\F󢎉ӇM~MPeFm3-?>jeb>LF"פӬ kA 1̵PhrÙcRTÓi|S^o(N,}Gvkkɜ8ca(COAK CC0WOOCg-m_o]K^. =hؐA?KHfmIF%WT/7s@}3Q4C(_1O6ߺƭ2(ӯ3CBΛMk[Ciz{tRw 6G慧t7!x춠g!I1ExG{LiId:~XDM"H$r("I ǿ+CA$Cܣ Yw&;&8I~?"'gcuBvىʞb|Iιɏp6[M}U P2aryLYXtG-Jng)On>ޕBt12]e,' HsUg`M,lAJ%J8Ճ7-Tc$#IrR:`&=|7VpFOz^^ΰU,-J$T |]ry}xQD9ƥ^(l:GP,dXVC\h.U"y\u ;#ri(` Qo83۞444=Ei[puSeY){\wuH"|8q3K.!& w`H$_H`O=-ٱkn j$ lh3Oq^|FNӮM܇Лy9*g8w@6~jʮ u6PΦ$?i:y98[ÐO#Jkw}tn@,}%.}^ɉrf*v.3`S H4j7Nl6uK oᢹ!1:(}!'~@SfW>gXC׶76ggf&Y Pk5@{{7efU{KbuǙ.xqINvw#^<-rCxwUzME 1mt]c >sã9$!@^ih,͐q՟vNU,O;P\r;R 27r)ω .&Ka:M(]fm2!~%"/wh m"/mN룎L 94֡i`FvW=FJ)uDs<"X~=`,]٠Ƒ 4⤖ }6_NMEUC\oy,(f1%/PʐZ(: ]g5zC^jfqaV64k*Y4B9,`L?wrxz'U=k\Yܔ.=#  #]@Q%(L^SAxHIe[5:crk/ OrKlr4eϫ9C蔾v0P'(߯<ɒUb/Mm/<('LtښDTOT2/e?%Nǡ\YptUDLBmIJi\*4U3wz*wR=kTS0>)zZ+Vk qK۝5?3,>ٗI(-عeB6'rݽC2L/-6nN!%$qLݬ 0-]|[(&j" G'|έL~QTE iͼ!Q=G䫱s kR䄶h|3PfM2ܕhҟkLIyČr[SL 5QsSn%οcf4>>x!/^?%IumwK&4:os熆Ω(qa E)^AӃ71`ډ>y_!$.ί%#,ЏvS  ;dzP8와T6vm}@-@Hc-uGaBM4";mIAykca4կek[@lb*;~{xv3@,fGss %U!RM=f)W!Ol  g`bj'uѝZ{'704PF'›AڇL/qSڊ/< -2t|n}5^Gq*?6Z/Y|#zph8zC$ɀ-!wT9= Au:&%6]U5PਨUh )FHGI endstream endobj 391 0 obj << /Length1 1630 /Length2 16673 /Length3 0 /Length 17516 /Filter /FlateDecode >> stream xڬct&bb۶m۶m۶mۨ$UlW}8_cL]׼"!W034uaZ8)qH(Y`HHM -l M8j&a### dghaf WQTO?.Ct0p51u dbp67ZX5$db*1[Gk@Ʉ`j055'ڿXN0w#L{G ' '8,l])_;k &odha U^Xu:8`g埖e l`ap6qw' o`*?+88[89tOҽǿ?kpv26a`on3 [vE@o\M5 vovcS:Y;)w,@ -_9_{Т.ֲ674Ccm1?EWo5p6;[[i$jnb,old05;UlM-lMrhMXm25_i So.G72vSFPEadgI/ e -ZgW53gu lnTc6rqtK߮Cޛ.q[ge8cN k 3ؗ5)pTԅ6p~ux,HR[\Q "mvQ8W^dW=ܝVP-br~'r-G%~5JkCFlB/:;'M:y~"8ʍ&2M9#Hvw|h2ses^nSEJRqy_v'~Aaȸdi-OϿl'v XK?)4,н,qºv˙nk{,NT̲J/>`,Jώ3܀G" _?Q_F9}!\f&-_2< M9o$u]e*8$_zKlR> VM3>gDɽ}n[VOoK>f](Q Kr)hX|_OEúfj*NԬHֽd.,53+JAPH+ؑzd G=:3zSZuFWfiKA Hʮǯ HwU?*(R}hoW׬4K.-^)K27f]!S͋ ƍjRQ(HT繺+[m=Ig+LٙHEsIySՈU7Hװ 노78">٣2<3 Z9.^jQ#,1s!@e|.hk^ml-ЙwVx:*'PbzPT[ngرJaTa`c*{s;jLĄưq( 2aK=4WBbjo0-.b}C#Qw8Y'$2(уqa#\pϐF`8zCqC\7{M\WND42M'rC<'opl:x=) J <#n~@BB" 0:2 @4oe<`]wc.kTfq0"vI0[C޴\X4]ݑp Q㍙gU վ5 ]0<*cn)N׉;wKp^=0^1*ƙPUY ?qU]IxٰN4p (ɹr Ir?,Psyq̺%6yįbf],lm :wrl̖ Plv^t9?3L' \nȣd@i{n 5CSWzؔ RRrpYŜEM MOLnuvD'A+烶*:Ϸjz$lr[b\t=1xoWkwO()-FNWBھU^M#lx\[z,k=ɳmaɫΪ5$OO^j%49> Pu -/PIR?>LQ f-̗zBijf`A8PL12ȶ ?f>#(aLK`&o~rft.˹sdfېE<\cX'~Y_MzH"T8朻af>حɉ|YChy6EX\قq J?X%c#C:8T=Y\%u>3˜Bvj5g[ܸ״4Mդwlt)K{?{xqaTQISk$A/+jcKDba *`i`HiOw}I7b^PZiT?3Jכ?:HR(So/2gX}ln&b_> ggYZc|j]~vEI~)p2P.=B8[,*Oswv{J2y Z'G@'x %VO]_tI0^]6l:Y"cKT쑶_YNs9Gsb '_(vk,$$uZ<a bB21&+5QXjGҩevXϜ=qeN|_M_.ʋ\p3F ņmkEԗ<,%^qip7$ky)b?®ty6XLxph M<("ڨ\$Er,֓Kk!7O?;nͩ#ԞXIq+ohYZM. 5OGlm K,޼,g~)ХQr=b?~PI;Y`:g+T DvrLٹ\@?)~ AAe~[`_XЮ U\Y s-޲r*L-ZnvɺPg Z|/qAh-QNxbʃ ]DToK{vM4Bă1`kr%]s4a1%%Y+GJ"@8#Xcђ g>;^.5U$Loy.FoK"DةbN ΑUAfS:wXd㿞O1;ׄr,Ua;k[`ۡA%|>Q$viqO%=iTs}9W"|B76(yt ímKOMWtI=<'W5̑xx腑Eoqz16C[ֈ(1noFx{zGK^ýdep2y0*x<@M,%"%9Fq")`uSdqx$SU(UǮ,ppfhrO+0jfyڔ(H453liF̨qPx')v&ƢeZ @aSXS0 PzK@6O W9iG '/n,6MGg:嫳< t/810z~? Q]ȸʰ~0Bۑrkm%EMxE?k+{,!ΐnDS U*K`hjyש{:/MZOJtp|3)n$>b.8WJ?Klxuzc(( +?!)=TS$XђH&cQf2Eu sC `**Y xT&Dt@:` fAA?22{mEux|8gHNn? 7]?#MRd^qGg?Rl$%H>B>wB-̠] }ۈS.4ru1Hch Va`Y϶lĩA"Ǻ(h:вW69iLI_ ct vmaJ>h97g >Իȭ/__TSmcaڣXb_[a =6|oEUsorV`ǟ-s?I! Z53*fTs F4c18Ȃo;0᧧m9mڦd0P@k| 5r1`^9fP 84fNyDy ;3 knmMY`+5 rBk:HK\Da#l> sňRUSAA#-Mzݱ~ Gdx5YRЏ JTٍ#I#cQhp0j6``_ov7 UTS̽Qc&eXaz)^ WjmGbJNxajdB2.S?;?-Z/FYEۃ7)Ҡ2Mܫ֮tԍ*Au}y]ˎ1Qoo9mp/?*IJ'Qfʅ!2IF+W v-Xz2:Z,XB eMf *{=.)i.C F%JYp僼J~h>ݿ0פ9ݟ#3-7*p.Al>{HDmrl$Z׈&KF|_^T{fǃ[j9H{W 2wozиPI{ =:HweV!þdcR'^lM+Bg i3/@LKu6ennnl cn;C'hnRA~~^-Gm達O!iC3r t,:!<9adԺwDX~#w<0s\ɈHZ#'F ]cw(~{XfШRWŠmDoNlM6>{yWy0dԆTs,g&ybj+ٟ<}emL2.O ?x'~Z$kh&4L*hGaYژO4֩Uϒ25 ѐ!!cɭ 1Fi3.|'>k xg2Q+~[*SqQuj9!.(N\ia#GM6r.ѷpnIqHҬnj\>-x%E3O:`; ,\Y!8 sAGd( :Q!}i|ü^2[4f$mAb F'cI8E6ՙjw"\1TAxC^Ct/WS8yOXDMs4*VI.,6-EmZw  eR#a>lyFhiVǶ4AKn9GsJL!NFYaj)Eߐ.,ʻ[V )Ȓ ɬʼnwFmp=N)O&Ν\BiH{˺:0MOРQ|v~x#IZ~*yAF:ۗ.%#V0p휖v:$qV/|Y}䗙`y$(ʅ+#ZQ&>j]{"\en|plٟ2xM ^l8ߟ6 %Cyv5K 5p9,\#F{ `9q'o;SQa_8~4A\n D 6[P+ -ƻ4||Mҹ3aupĶ$?#e~ĭ}ikOP@kZqG25#l,1nDž&|C53m^$+?/Tܹ.vhqʆcS]~Wܶ ljt^ Xp98kiNX~5.z(y>L9y^;%[fz JUqMLCŞV:܆a jC.n,)3Dw$.IQLs'S%wϼ9&p*:OleM3 ,&N;ͪcpN(CF٣ #snJW0LD̕3͑{?Z~(Dj7./hH2sw8x U dt aǏSXs:j Uv5qM{dp)'eAPwmM|L& YV0`xp[}XLfi L龄j`/@&*zԼ"IOϲplFG\H:pY/P:3APPtN8˯G< smHz` k4w"".5 0Doj0IM(ŶCEn QXN7[[7?F3n Po*r_|MLM_ת-;]DI3N.v di͋N261kRnV ˉ~}tx&I:pרG'Xg/MPXq8Rٽ%^Ī5'NO;"xb׻ !*y8o|7o k:SO'c6@X a_#d̓߃y>1FC+YOQMum% N hMkuv^۾Nv;2Ns~2;x-LM5?X}6Q"$>)0̮&L0)/,4>;rI5ꈆ`{mLMT[<׸ +] 'F!avEX/.4_[R21avEuGz>8|R!KżV;-.:1w}V[rSeo>xa<"{yņ`5aC;)! 2ÊLQ؛OL[A"q?01a(۶Hң49h>Ej yσ3Y4_)#C-#Ы"׿_D6D}x}]Y܎"`MZClbGn7gF,6"tǂ=T^6*ݸBGT/ P2/~ \ZaGa`E|vtA d~DCټ.9؇CJD&a };x/ f WUxirA)_V `#D/c?AyK_4C|TLU j &Ԑ)+!F4uᢠ2WQ/rPMbk["^)c+= ^}' Op2Za>sȚ\~ '> ׺RUcFWANQ׬T^6)_Eu)6|1(vݛ7n8Yq ~Lm^({UNŗjlez(E* e'1`EβA"T-OT(( BվlиrA.ީ']7? yn4Mf/*b32׆Vn/kCeFyGy4g5;x(l;*5YAFlTzf(bKgKzQd!&c-_heCP>y겒o06b3n:?vրo8IߛYs>B%NxJ\FI>RX""$Ud="WH e  LnLʙ!'Gƪ PU W6efBws&C#J,#[.u.[뺢TAlovop&HhԠ#{/Lhk0~lqگ'pqPdJ7=:[jQIe׋c_9lRDfN?( fzm7ml.Vǫ"aSfaR[b?1kAlu%1=l*S 3&onZsR&-:+tI7F7}^k czr PN!%,ڴ{͈ئV݋0 wQ8A/-s,gzJI\ %0MOLvYDxo y NPƀvW8`yu\u<*ahiZJ2Z VsE \@LR-\}8MWx<Iqn?B) @b4y4zq3`>=($}-qvHG~]+Z>mb/0Y?}vV|Ƴ(nЋkU ZybР$*5A aN{Dw@\e4X {W2Ac@z^x˨MȬWkdͲ'TP%xk>^5פ.ݸܮ Dz LPwXF/V4]خnͱD}]K_Dc&4liWgFW܇xėD,ec)PeWDtf*;Σ(eQU a,^x:xJ|8IP}h:4(m+]5Bjti-0Yxkr]oMZ-?βլК.%aL|I'[Oze:p;{v9.Pk,f8q Iov-veۃ:/fНumbs( lnZ🿐}N!By,' |Æ\SH^\`GiPLAfEz>팿"ib7a,ۙk;E+q.f-G=VB{,'[` N$eYy)3 tlZMvdh1_bzn caȒ+j9ѕºTp[pز||AK;.nh_y~tu40/w hppͦ^#'mSVe BXU8h_¾o' UM &^ HcYbfr;Rk*_\/b&Y԰rpq;}[D}kf06y+c8zz _ʯjoBU5SP]XxyMgr?rPq9]m㹃Te^{cDNh.o EqH=Y{l>*)T!l鎔AB%Ia6xMfguBa@3n[BHCg "D'UjȦK/f|r<!:U^wd˕P‡ܝQiEwߓȻIq z1~YF&ŢVQv4*./KaP4ZHr>k^bPU\ePߌDc7BsT1O3WoZRޔ^J{R A{ջ[^g ~I c6:na POz8ԨOB-233PS~8D22Ö6TrXSZ$:)=[@贏!BH""mA/DHuikJ0$ )bC+հ)N&> '|r]GXYvL>v&G %?l9F;*)$nlosdVjͷpa۲7'frWhɿAoÔ1\)*<1_[3f*oAaYe0dwz={{7>k5fۃbcF@R"ʀB$VQ=jCN#`|NM3!ۅev1)&Xow~ٖ 'd]`%Sv]eH]uJBڹl:ߊgN.uZtj[l|e2;5yuOwu62[eHUp(k4n0K U iJZO!A龣 vIQ;gmH @e(o{S4vuY[c6lq| ^*=R $ bcYk3`74Yeɦ 愺&  tO0nTf6390'6ΤT1LM pPշ18&.مȱxc)<8 h(KG3 I&N["6 JŒ,[,lvX ٟyQ:`aT]fl̎޷"*H?0Sh!tn[sk%6 όkD5`l`NxK,ݒK9l^`A5þwvi*|4JHG$3E)Pm1Ef4] :d- oa5[O1H.tuRAeŻǿ,gv) kq9nZ PmLяM2]n֕w]ۼSBn4DÆWD?ULȒ/8LHK AUԔ?(L~%jǕ9{oT)'`*H \7 )R%ͦΨ+.D(FR:V]#|^:yƳ˫Bʈ3a>KTDbs،"9B]Kk'}$J+M8?"1@ը&k|!#"day#K2E'gjxUC9χ:DԵgӆXk0EciU,4e z[^ahRTzsX˒='B0^2sVw4g| –(dofQʶ'H+]8 L;>Ak[j. KDYŋs;E9s2 莟y_ V!"";RyBӨpo#>'XշN^|v$ؕj2C54pؒs2Z!!ټDF2Q2F+fq6z| MMC?MU^̷.%AiP&Bo ˊd_<ȯĘbpRH$" 8ڥ5'ucdll/86:Dc9)4Qd Bg,ۆ)/#חei~ߒe;졨y4 M尃o ^ч6/ҥ:>]\'=i/( ?=-{ P$J)sݟ@:GEXt>1-nN4S"dK_Zeu&/h~y:v_*=$`O(J_鏠З_GՂDdP?ۢ2viPqqjDߜYHc4/1(^"HKHöTC0j yuѫ؟`1`R^zvё3܊?"'#F!,nýGaXr)B֡2c0c_#m~@=@IzS؊c7(<6 wɤ3znN1B ! Zh ih|F2TDFpKJ [nO8/BD䉛^2tҽ40vS 2!痼۸՜sSЕjn>l7׸+-$u-MTGF6ʟke.sjRٜM]b։",'衳+c~Jt KH#-m2(p2]\#0?E@K5FJjMͽq\ʲED\>_-uz`?(Zokd6֪EF|;V | ڑ2&`߷NmhJ*.ШGk˘3?ɝ[#2}Ϥ_}+2uu`|8c`vzhJ5A&(xkÖ~E{B6%l<ݹfyl1EG@l童gShIU*#(oT@ЇQP)tZ T 7osM717PmN=c.WA27d:Y+6E)Qy@RVF[gwBIYg ~#bkx 5I.9 ɭ [^QeNp ԔEᨼCFi{tEk<*^ EyTb|\7 Y;:EAD4IKO$v"U`&:~N!<3z4W*5|\S76nu3h?^4LFO4KsMR܊Za$5S^B˽_{\Am#6@y_zq1 z@7.6cv͹}T8 dQê]X T2ev2 #Ƀ1xo5,_l lsf.\4YXڄȈH'AOfBݠ*Vʉ_v"$m(ʝgN18Wn6oNl$]S]jS؎D]N 4M۞O1,gٰY?'8DÄe{6?`C~v9F>h7H4oZT*It٨j~%MLL@fbfDe;Or ENԭ7 vFl"-ScaPNz=9ްyKP4kM[H,R 9C. kgbi&|S㘓6dwJehQ܂wVPbљ|hhրY6qp& I D)$ y a; }K%;:wTVl endstream endobj 393 0 obj << /Length1 1644 /Length2 6659 /Length3 0 /Length 7487 /Filter /FlateDecode >> stream xڭWuXmS~t*]3 HHJHtH())4J( H?_3Ϲss.vcAEt z0CA<]K n* T0B(Ddddȸe$xMe}pDÜnO(B@0X1 `#  ,5^u=S@u8 P74pD. -RD aX7 (;Fc04r`{A070;'!;{ŰdH4 v06_ybA߱0, 7!H`X, @`h䍍%C၆9+rh4;/ՃP(o[ACBd"ؘ` 6̍YtsD"!`P? =3|$@@!1ؐMe-[w#Syz v1vɀtߋro>  y9t2M E7'42B20 1a΀#Ai- (",7vu-_ *ᮥ:_pىHJb 7 g'`vg;ԨX<=&z7. 6SW<];N1a:xrd[jܒ*L1~ˇe.K"mRX$ 1Κ먯6K%̙ J+r,wqn}a^4ZGvwZU\UcIn*/aj9@|pX ,/\{T7jgx|Nv fZ$\O64ܰ'Qlrsk<dPٰV+uX'Ӱ 2~Z, ШyR&BمzEQ{z=Eщ2S1d-T(䙟qFp!Fv!Y+ Dxw;/s~튻ܼ`ъqN. @TWcne̸z6uBm߭lgOYSMoKղ#QN =g@::}Ay J/?^YAhJcZ3g ]lbp GB8 KT>3W겘釔,I(5{7ppwX};e -vCdvn˯J'7M(J ~ xB4H _} {-I~x+3v;TqO+GO5Bd-t`/^;ֺbF==:@iJᯃ?:UOeTJwQ",!!{$rԴ{(l7y$oYvBY0'_J<.]Ȓ|+=1 Q %-ei2* {ڪq+@b;V#[WH}d535 ,ˬH̕w*Nht;<#v#oMHEGrQ=}Bu KEەy{Iߎidb؊ǯ+Mo_n:8wf8/P&P&t$c^ZfQR` UBϟγ7;R$Jp.%m4^%V=ר*$2M}fazunNY:Cskf0(h1V |hQILhT$m{ednR]/3aPQ `!==FH0G/QVYܲh!7ao1 }?<'K0V~riOӅ&˟SMtyCw J6I2:-W/Ĭ O94,sm{ ͆oiM-2!RIhB^@B3养wK۴;:n ,H 8vt^vY7/^Qۼ_nD=r܉Ǟh8eޱRA9gF.uDFAfAJo3 w)eGNPA8{SUTőNR/x'b^=h"SҔ[m=$`M6Y ]qW渊qK7JYc.kRXc]=q; ޵N($!$8>( &b2ϩmu#NJ͉H1vv%I'#f"2jozP;P۞fjVEu_\Zٷt!r|V .:6tp9.׸b/IF,|i>#E? ͸^Jfs bW^loO$/zi>>9Œ@ZPdbm r ]6tlt*ya8u%w_##i%ɪ;QJRL;<.LP:W]R$`4ܨ h=r|]AFә[wYsc='0iҝ'D.dzukmhɴoS~x| HzW%{g%hX`Zr ^Ety6$3ywsĨhL^rQT;~ю$<~tC1xקDžl9kMF% JR륪iPnxΨZ%n1ӓ˺}mGpv u/(!*Y:n,=2Φ6BvV_$Je8*ڛ_g 85^_eZ4mpƿ8ێ**\R0޾]z4d+~Л_<{<Yw_l*YMWBG?X,ރ8NeEPKE!ުMl 'goe;  쭊tl*U5hF"3?@lw1xZ; !8=l}Zes;ɰ{9 ,kFxW^iH@,z6;.g1B5zC-Kw݆hhwe/Z$S]x]<GKH%< 4رM#n܏"ew8Ч#IIַNs{Q{1mQgm GG`h /Q^ J`j;T W6N(k|Rf\q<(%>Ѳ$X縊y_Ǵ2[mT럲x ds@gt! *JO>J„b (ApyGZ2Bgĵĸݱc*Ղ8[Z?vFf"Xvq 2Y~%gRG˦{.GchC;At:YujX<|ݢg4沙f׌Q1n6$k\Igqs6MlmsYj{?;{7}O'KK1pԑ~!vڸ?GN@U@o)1Њ,񖬟EtC* ʨODY}Nq.mkqyʜKdnR814U$_1IQh5b!o2]"QzR};p]6enϽ,=-R6"z_AozWZ V {fJO}VlB>[|婷D-"qiɾ @ϗ_R qz'*}o_yU:,}4·޵04J'M4<( A՛gƠ4K`Z%ɒxLWlSb,һmM"@hfG͋V³MU9e TNS(ֈ3';PN^{L_lFOVtD% (*/ 7#Ӄ^{LP]+D*bPkg*bJqdRu1Km*+G1gMt_˕GdmS {cӊZ齜m! U_yQW@ NrMaV8OwJtfBHŬuWW`ڼk]?%M7,M;E<){ARQ_'=Hu:=R(c4V~UDfDk}n`ܒG'"lޚǻA,/*^b|g${8ew^tzIi+ 9|/P¡$RDvunZ-G@}ZkѡHVgKTIݡ5^)JFCR7%Eu-᳅S!OmIxiOK2_*:DGt|T'^X-Q*{)aOP>놴^ߡ$JG9MǓnyd}FLyɛ9fA'^է=^/ӝi75lF&.-o90ͥ.8"LozDIQQ&!1zR5vX6y^ ϼI'$-K:Ԟ[8Mc@K=܏zdVYwSMWk54ɅFc>7I J~fRtaМc"dZBfy0i%轋uk'+= O|\ 9<:TP9>o{MoxR?"XQYłQ/{2f /:7~i@%) {uzg${T>|[Gk*wҙd;ֵ/3MD#v r ȡ9'l3 )d{z+pBzx]:e')LijJ~d/|1Okw G%Lk vIZբرˑ#9SlgHK]Qć6j76rqt`@Z >4|V׌xWx6Oh.oYmj¼<}EWYD:b#ʪ׹z(4&נyVj۷5޲_m yhYlGN Æ͆i u<6J&hWoOB{> ߻x"7^}ԖNX㪿~sip,F|sXΚ]" N^1&aMAaVa'$q{N#2szV&]#a$d I"=z݋Q[06_2SրkAs)HTPf!jba)GQee_wyin6ڕ|B9׎ج!ŕrLFE,Bu(TPEq cFZ߹,1urÅXJ|yBFisyB\ pxF+b_Q-Q||$J3/.Kn0p^x`)G'[K~Pb(]+!1ْ̰'DZ$&+ף Ux!adi-n ̵;}paf\|#x")ޅ2]^i{?膘ŚIn;Чv0*^["tiNN'˷=Iː45cVÚ[ÊHVr<[Iy'6+&usC_{u:˶debiGnU||_N_$R0=zn.+#|!LO+O{ IBx*A);;GW߸⻕}gD.kx3Z(W'^Uh-CsՉlEOK{*F~V[\{l˳V$onfO&(:Z2S,k8wజ\,ktͿ'ZqpG :i647g6w@pHص]ᎴRb}Ar.a-/IߛV6H89pX &m a׹; ktUDŜ `ȱ6-n%'BF&g3ˮk˄mN{{s$5o1Wdx:6O%w4٘]T(c9e5XG;4oa::u{NҚui:r`{;;1/iOu=aM]O p> stream xڭxUXڒ5Npwk5@h ]5;K 0䜹s?/3]jU^i)ՀsѕC v0wsр8BY5@nfWVd 8ʘ: K DHC6- FffZ̽Ft?A'+:\m@+= NMOQU 9_Ps3[ G# 8Z%08,a O rv]fw -,jU3{%SX8\YdOn+ XzZB,J󊺚] O?AKkW2'g_eY dmlirqyys;ߺ7sr+vu[!srp}m vDf3/V'vK7` .0af qXU!) ;}"$o&j=+gkʀ?g-P3:ON!h+'/fdvXٿ^_v-GK=*_/ C GU:`WH*3/gשpr3  VN>A+?c|}\<~qb pqpp^_hd- jh:ze[9;*6x @^YX~ZK;4.c ;TڠYTX M&qRw‘ӯ=%^|{4i>5 ~`vRO:1>g[p|%do qin-:1k n \#aΉG6#O=Lq2un u#GtW CGUȤTKÊM#е(5iso\-uE9^ i&VFnMr;wOEK<3]aU5L୔zA1nR~PtO,EM/ ŎOI_=J|U5'pcهb{'>RtҨZխpTڮ\z?+Ojv(~`kl.1!EX7Vs#$~{^]0LV$VFp$*f^@@02FԒI%(&RtEmjh78ߠg Yg!~Q旘RI-a9q{hsl4QX.v V+E4rLT|>IC}Y Mr]_衣4K'eTvZb# 8(R@$gxx70)v6\~ӍNU|Ϟ,UYnS/Gϣ=ʧ`wjh#VI)|sg*(TNTC@[KZ4^U$n50~-)۳$e$FQ-sl_f z.tG8e~<}L+`gjVS,AtDO.6,)QavM=d$Vx)M+*n9׏1"CΪZd!ܽ,+;9{_l|,sa sx$َˬzFǮA}>L \׮'c¡Vln\,رgʺFM uikUҖ`$CTLy>v9JS}'޻~pkh'M*߅1XG'U&z-$+&vm.@~Ǵ6IwHؐS0 $抝*̳bvaOnw?I. }c彭$nn:nh'̻r+XfAky-$JXw}> B KbM!:KLʪiubRCy6qy ЩolβX SΧ۬c֞VKjxZu펃G;ݰ:{J Gkw1WMڭ*fj֩/JEXdMn2'P_CDs6gj~D_8pVc̎\]%1JPd>fo)kd8뺮}P8p5Ip_=C$iA#[<6Z~i}Y$ʙ,q\^uii܇Vw3]V&C7&J:oƒzCq=С/sVF>&:g8}]Z'c `. 0/mH7{5i'N=?J &1!2aS-juHޘf@7#;*.RMT7&? d1E2Vҍ}b!b FQnQȐRdyaȳ^fIoGM5n7 A4Gc>1jBokMi^ Wus)vn<|2YժY$ /0 NFu*DY44:ulY\8")+(5nRtm ҳԣżϒ ,=jB˂Ґgy(6Ճ.>z^uo ci]}1 Ur仂Y|p$* 7E-pbѳȿD?`UV{ՊĆ2-m}@PG2{LM* &0Ǵ_ucDEդa-G.i6 Gy甮 4tn(jI+V~-kaK]H)&?;2#UgqThUu!'%8v6It[m򆿆swE4`ޑ+1 ?ŷ3t-)puͿ!7uO@Z!e~/T =5b=[chg^+&,U=A}r"Vtc6`kl̛ tG3`ǁ9H6Y Î^kx.!T3+cO52;Z"ԒkF"/Ӗ]z DNJKUaJ}d@s-! ΢5J(0Z!xmLyiT o;nv>{vѫt R:ނ m^xt̀h#`2yWH$Y-Oxω5Neս%N$jx|n2^Гgt,]g|SwxሓJLZ^__Aj}90ڟܹ(F%I 1^ɞr).o+W!:foynWJ8A>,MZDsXؗu؋V䈄Qxd`n!ך'!c<ё.ub!#뛙}d{@DdKrC8L}[or3/|ϵ22vHbAMpG^nXrL~#NC"jFtV*obћ*R%|n(Cƪvcpgzgd61+}qyKQ`3FHr. qrQh01U6#%sۜF(<~j_FI_~}àFQ PH<~1 SL)cN->ڿO d{q (=.xH$D/Oc'E_1\Q&topy|  Yov vbߘ>qY7*m}~*C* Ze4he%]c偪p}e )G"ш mLCjJK35l+yD=[Cdq^XJ~x2(*eYGy$G 9&123o{U`R_ԍq֨TTOZ%6 cxӉ^GV{,ħ 8x'L̈́-;aٔ4V|:jq1遻@`b3ůɄK4Ty%74Kn[X3#]obw.F6uJFg]1T 3[؁b 6&9?ؘ%Scv8y *9J)iB4ס[* wR9ܭ% MO%i0O6Hz[wR`IݵW%/~"٧hTU+NʓBy*%,EH' osTޅL*9ۜsEz]?ϱ@uk}_cW`Y8U,;=e 8YhP%vg2`B}7k\txX`^yZ*5J}ߙ\6zG%+#Iܳ\\՛Y5_lq\n/x%UCc?zS?,X_`^oVӓ-rhlhOP9G;_\ZN|z|b_ǗCth65S&j(oWOYȗocY_|]⯃w: 0]цic&;]QBw7jz:HKHc?FYKg=i=xԓ] um9н;TÖL Gvem67m-. q B ޒ)c0Ѱ:򃈖=;DzB2]doO?GSO{T`튬4]:31G:[1d;Xa{S=` 6u L0O =3hؾH3{$~͕EqrQ~cן~9ua90Pc=NWê~l6p99>}jd\cX[b ?z>idžox1=vFctk{xQ<_عtT/aG?L8  .t(Nte|xI$eIPi#^Bj5E4!.M5Tޏ:,/եk!dɯSfe3B:tV99$Z]- 7ƙfIYj5ɲޔT^>_?=YM,uN5z@HS7D7o7%bHE5vaEԨWCpm $CvX pEZhh>[D{:DP!.l*~4d{c)덋KЁm}:= []*uV<PiHBv[*ǵ ߴX.tZE9VB)GYDn(\;ի\(D9x!f|x=]=cF<4DREm == 2(*<4QQͿX:LxA]JPI3xkv"ϊ|>):$8 IneYw-xHq|2*5!sszu גNx Uy~㽢%LO֏ 0Ɣ3KM>@e+Mkn]hKUɀ~QH43dᡣȖ7 fŠiQCZ1ԓѲw$v5p y ; W5sIx[Iw{dY@v-0CeȮilJ*םX WbO$ Q港޽ikRRBp|ͼJy>lܵ]3~9şɑw\2zbP]oETD>wRWQ }K-[U^ֱVD LwQ>GvUv]\_5)Ėr肦)J_CZ6X zoJD?4xZj+opM2Ly E[ ?z"$pJ_o~-jP# Ulψ2J!+AcmE T=0༳k;(eNRIsK[ّ%w_#[i{:P:D~(sx0T2_կhtj\P{_ Ŝsk]#0noܯEтR!~+,uz*TMd`y#%2#n~  *ϲ4匶y[{V_e[[[xD!vl^1N@cfאII|U@8A.ϐlyq,(<LYmhGx:SȀyT!s $Aұa UnҬwj4#g#NDJF !!x`TvIFHJH"ipg8Q6rY%l~*$_y=;%4 }N\h8E@6\w.$d(kr?)b&+hjB|!_ɨy-~ [Wa.0Y~Obt1hH- h_ŧ1QO*q_ɻlOH28A+vFZd ֊-z `!;uSA?*5z692 Be2f D(rG /a?BmY=@&MM}WyyteXrz`RYKvT|MS7;;c0Ìٯۤd$Rgld@_md'5!PaR "R2X_|,5kn<6#56->/lJZ8% G#'Tt"aJmXj ]F|C AAV.?==6' #h)/GXosvfW$@/)gvA6mُB$`T9ijTN8E O2K6vvUoo"K={R=*E4FFļDQm7/+3pWơ ;y'K &gfm6)=C1e=|f[Lx4ĸ9Z 'ģ?U4%Z{ 4ɠqr_=Ar )oÜJ`$F{_ZofbjJQbzӑJ^l९?ؠWYwi_)GP|'Ie3@Sۇ4;,S o4YCvX8ԡqxg>vs#?Nhԏ S4IqޘXvTSdҀ #&+\;s~ZK4c7Ӯ{>,;AKh*cbRNB M3] x ѫBgf"«P6Ygoi*LŠ$J>=uKHNLx;1BQ><7S-Bz]f]˪3(H>;Fځ\)܌vu6вw_Gd,13j3:.iXY96fCQΙ>+h{^/d3r~[^eB endstream endobj 397 0 obj << /Length 696 /Filter /FlateDecode >> stream xmTMo0Wx$ ! 8l[jWHL7IPV=M̼ su;Uٛ=w]yil;<[[j<=?׾+v`&ߴț<^*;~&Q>MS >_P{=s@dkx;`VY`s4JaQܡn.Uu9\Y6><ٴ.Z.4>Dӗ}~r:-d0VWk,8yLһʮӮђ[*mLr?q 5F8@=@)& 8Rx uD\j2HV0CzL] bctI g$`htы0\F0s jd< I6zg W qȐ+#k .bsrbmXK7ǵH7Gnb>&jؐu1VljOu$՟qWS/%1{\xB!K(hHTЖ枃Jρϯv=k2UKς_:~$/ ~E+7ˢ/ l(/} -+ZXukoԝE?ZKq endstream endobj 398 0 obj << /Length 739 /Filter /FlateDecode >> stream xmUMo0WxvHUdCmU^!1H#x?gx]OTm$|͜s_Iss :L;<Sz==׾f`*_`ɫڟk3'iѴ}=M;7rfnj-eSӵOLg~8 )ok A8 $`I\3`Af<Z]! xNky"7 _㓧q H`nḱRONH=CpB:# =%888QA~!*zƜАT?!~> tw8y*sύ }nFE>7*QύR>7G];~<6OIyktg>O:yұϓN|I/|yIg>O:y҅ϓ.}2 L> stream xmUMo:W5?$R. d9M eCkmCp;;w~>|3E_?O]5߶w]Occ]=~?}Oyh9%?۹׬B|Ɯ>);vw%g43>\ 6 EJ78 1{~`W(-;]%=xe_,b+-O;q\L}UI--=BKE1p[! Mߊyu>.N5K)Wb٬8i[_uʕMzQ)V(Txޢjy!Z2P="Zd0\ÃGR\).2*Шa!U,H`+j.5Nα@VK-x%3%AYӀzΚ>kP#5m0Woþj.ZT$X/)n)#Wo(oRZ $Kp4Z-b\1ܰJ P"GXQi/8k^Zq:Zs9dB )sL-7xJ`aɽ)f$1 dъcCZC<73JgznHȰYɚTa,_-O87}KԴܗLloK+gJ.GZyVc48Wt]:P~`rZq.n1] S/Pu7Ue:?&?!d&1yHn5)yғBx#1ޞ]Go׏M?X endstream endobj 400 0 obj << /Length 700 /Filter /FlateDecode >> stream xmTn0CƆ@LE"jD;oƤjgy_xN{qV'wC&]\]]u>t\qxں7ŦmN7isƬ'k~G]?ߓ` 4;RV_n86]{̭֚u[sfߴ L:?v>4|`0nhWu}QE KU=5Yw߇l?N6jwwv Z/բ,ko{&PaffIq XMJ0LfhrdĥP> stream xmTn0CƆ@LE"j.RC~8iZ)Ayo7?nkNy$냛G׎ծU[7|SlfM[kwʽ5g x=i6;RV׵_n85]֚̽u[OsE͡i P{ LՑ @4=tb/yVvL MnݞArjwf4P׏ީFT]Nrî}sBZ2pmmR?\rs<, X#.KIɌCH'hjmJIQ09da"2rG~\5hגQv]`n @v)(A'b}qHI($ux-JBJ!^I :ggM597F7FN}Y{}&Ff.pdk_ ΜN0VG9ʱwDK4X=CaCɁg2)4X(rb0/s4lƵǮb]ˌ[r> stream xmTn0CƆ@LE"h.RC~8iZ)Ayo7?^$ŝPIs77EW]}==硫nTشxGɛz?{k۝=` 4vN߷u8NM>(s&`ywS0jzQshz+&TuS~Hxqq`P<+ OC톦}SWUn}@`T;P3qtj}w*5UWSܰo\ze \[3. 9ff ؤdF@!i @F\ ` H sn4ȶ` $(Ng 2R0zd9#Cb.k(@.0[Czr aà8SuX$Q:\CAfpGR~m%^!N%$h&՚R #ƿp'XϾ>AI }3Nh25gNE'bkkؿs %|V !3?fc91ӊ9|u 6ZcWCab d1׮eF-9Ag깐3Z=I= 6-7p?)pegT> stream xmTn0CƆ@LE"j.RC~8M])A̼7W?^$PIsWWEW]}~{SCWmݨMi7mv9I+ڴg{ҏÄ~F )P ǦkZn;@1zz5= 7m=x Fgu P}?i]X<;k C톦}UYoO} A`TS7~wpjmS!詺]]ꂅK(ew&97\=̒5⒁yAa>:M1ȈK,x΍t,@F*&" C,zdWXPv-hakH/]d"btv"gg?|2JB^G5kdwt,uVT Jb9;kBX!00a0bw3W M";\88̿9Earʱs ށ?c>+q p~PrL  hi˜c>:q-+01~k2#Ϡ3\OLqRυ>¹M \)s9O \Y!O>\\/Au*[ӺkzT%C0t endstream endobj 404 0 obj << /Length 700 /Filter /FlateDecode >> stream xmTn0CƆ@LE"j.RC~8M])A̼7W?^$PIsWWEW]}~{SCWmݨMi7mv9I+ڴg{ҏÄ~F )P ǦkZn;@1zz5= 7m=x Fgu P}?i]X<;k C톦}UYoO} A`TS7~wpjmS!詺]]ꂅK(ew&97\=̒5⒁yAa>:M1ȈK,x΍t,@F*&" C,zdWXPv-hakH/]d"btv"gg?|2JB^G5kdwt,uVT Jb9;kBX!00a0bw3W M";\88̿9Earʱs ށ?c>+q p~PrL  hi˜c>:q-+01~k2#Ϡ3\OLqRυ>¹M \)s9O \Y!O>\\/Au*[ӺkzT%C2t endstream endobj 424 0 obj << /Producer (pdfTeX-1.40.25) /Author(\376\377\000\040\000B\000e\000t\000t\000i\000n\000a\000\040\000E\000i\000c\000k\000\040\000;\000\040\000E\000a\000m\000o\000n\000n\000\040\000O\000'\000B\000r\000i\000e\000n\000\040)/Title(\376\377\000\040\000A\000u\000t\000P\000G\000r\000p\000\040)/Subject()/Creator(\376\377\000L\000a\000T\000e\000X\000\040\000w\000i\000t\000h\000\040\000h\000y\000p\000e\000r\000r\000e\000f\000\040\000p\000a\000c\000k\000a\000g\000e\000\040\000/\000\040\000G\000A\000P\000D\000o\000c)/Keywords() /CreationDate (D:19700101000000Z) /ModDate (D:19700101000000Z) /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023/Debian) kpathsea version 6.3.5) >> endobj 384 0 obj << /Type /ObjStm /N 53 /First 448 /Length 2482 /Filter /FlateDecode >> stream xڵYko__@Q"8VҤ) EmHrwCuXrgw9IˆtmuD9OgJ pm%<DxKCŠ|$xM"IO  āC kH+,6D1  0bÈ `kA`%^E89q:SDyth8 BC$ Ja Q0 #Kbz(&Băhr&9w82%l5PkAbˀ:ɗ$]W&_ =Xo^_A"d1]Uo!g(4#1>h `EQ6hm3[dhyH n?`ڀ(l5M7I7f}^8~~-l. cT$8P$PW_}R?"H} = zHŕb{spJgtU2^ut-<1<_}<"Ζgë084k0"d\֌{4wzW szA/k:o-]5GICˊU~yzmJő7# yXMuǛ=yChÛG4cF9$ R1E47&͂䏫*SP( ֿDU_Ϗ9Vу]_%]g ͛UNWyJ~*oCt'/Z2(?A B2XאNOkB:L:JxG? :[YOP+;HvF[f ؓd ww]KZ~ߟׯ.7.fg%IR>p}IWCr!z"}DOI&]@_3Be ց*b, ,ΰKvSs:[}9O/QWZUWu\(bQXeX2E%5].blK*z(NGcg;XoT9uDpmc@O;Al_<:oUQkNzZÁ1gwn WR7&\{CZ6 .?;AhpSLhC6GT{ fy<m0r].m-r+<񋾘2#IYpjMي"%*mWe]p*e[PVd}Y#4Rl6-1"ŚJUǗ *YLնS{z0;GT .o;%%mNۗӐ7) L#}K. 3Ł,@\:w#M3,7"tzԹM1BӘ)D sH0:ܲkpjUV:N0?T<̍jIȶ/kxSS6?T*(t:?X<-uz_ S7s ׏?`zt3[mN-ggOMny;kF"`-ҚpMŽrsE07F6k~*ddd@=YvmZ{|lsAceE"i BvOllqdkV#&Nk Lbly#jBV=Y7#lx s91E1ZEn/}ĝfcB@4;u5f^'&RG.#]8F#bJrX}`ҷ 㧀^ApLXBA_bNr؍U ] /Length 1132 /Filter /FlateDecode >> stream x%yU{% fFcVQXQ:8-B=)IP9C,騔$J Q8>9>]}B7 ! 1 ԞN+B]]C+R'ƴAyMˠ v5p9 ֐VTVZW@ejiӭUUvjp%ѭ5էVnME:tk-w`b-qF7bVH/|CubU|;@SUm(-VdBdĐROkΨ/$ِ-%up= Í:M rcpgp3C7C,a=hEЇn_0 0F-0n\| !FhyNжgKbӻֈVc͟Lj 6!>qkGԻlyCQ5?3! й>JcF4i2dɚBz M_u e0vך)1"e@J)1RbH #F6l0ad#%B^ }0>ǻ݁0XO [Gx [<)j"&Ĥ\1y\L]'i~>@HY_SČy;SpV>'vIi{۴U/gݳWŞEkfwwQ|sF'߱?d]ď9⧉/_ő(\k$ʈ^);7:~Adbq's^g_qf8˶R@/t0 6př>"JbTcb VTbqKxK_񇼕ʭJ2oIQ*KuEHݶzIѯ?g AdB;?ȅ ZChE2|GT endstream endobj startxref 155896 %%EOF autpgrp-1.12.0/doc/manual.six0000644000000000000000000001076315202202400012744 0ustar00#SIXFORMAT GapDocGAP HELPBOOKINFOSIXTMP := rec( encoding := "UTF-8", bookname := "AutPGrp", entries := [ [ "Title page", "0.0", [ 0, 0, 0 ], 1, 1, "title page", "X7D2C85EC87DD46E5" ], [ "Abstract", "0.0-1", [ 0, 0, 1 ], 43, 2, "abstract", "X7AA6C5737B711C89" ] , [ "Copyright", "0.0-2", [ 0, 0, 2 ], 58, 2, "copyright", "X81488B807F2A1CF1" ], [ "Acknowledgements", "0.0-3", [ 0, 0, 3 ], 69, 2, "acknowledgements", "X82A988D47DFAFCFA" ], [ "Table of Contents", "0.0-4", [ 0, 0, 4 ], 76, 3, "table of contents", "X8537FEB07AF2BEC8" ], [ "\033[1X\033[33X\033[0;-2YIntroduction\033[133X\033[101X", "1", [ 1, 0, 0 ], 1, 4, "introduction", "X7DFB63A97E67C0A1" ], [ "\033[1X\033[33X\033[0;-2YIntroduction\033[133X\033[101X", "1.1", [ 1, 1, 0 ], 4, 4, "introduction", "X7DFB63A97E67C0A1" ], [ "\033[1X\033[33X\033[0;-2YThe automorphism group method\033[133X\033[101X" , "2", [ 2, 0, 0 ], 1, 5, "the automorphism group method", "X858BB98D85D78C8C" ], [ "\033[1X\033[33X\033[0;-2YThe automorphism group method\033[133X\033[101X" , "2.1", [ 2, 1, 0 ], 4, 5, "the automorphism group method", "X858BB98D85D78C8C" ], [ "\033[1X\033[33X\033[0;-2YThe underlying function\033[133X\033[101X", "3", [ 3, 0, 0 ], 1, 7, "the underlying function", "X79DCF7D9853381F3" ] , [ "\033[1X\033[33X\033[0;-2YThe underlying function\033[133X\033[101X", "3.1", [ 3, 1, 0 ], 4, 7, "the underlying function", "X79DCF7D9853381F3" ], [ "\033[1X\033[33X\033[0;-2YInfluencing the algorithm\033[133X\033[101X", "4", [ 4, 0, 0 ], 1, 10, "influencing the algorithm", "X86240F237D909E1C" ], [ "\033[1X\033[33X\033[0;-2YOutline of the algorithm\033[133X\033[101X", "4.1", [ 4, 1, 0 ], 22, 10, "outline of the algorithm", "X85D2ECC779E3CF7D" ], [ "\033[1X\033[33X\033[0;-2YThe initialisation step\033[133X\033[101X", "4.2", [ 4, 2, 0 ], 63, 11, "the initialisation step", "X87B27C1F810822F3" ], [ "\033[1X\033[33X\033[0;-2YStabilisers in matrix groups\033[133X\033[101X", "4.3", [ 4, 3, 0 ], 104, 11, "stabilisers in matrix groups", "X869B678180AD5E21" ], [ "\033[1X\033[33X\033[0;-2YSearching for a small generating set\033[133X\\ 033[101X", "4.4", [ 4, 4, 0 ], 128, 12, "searching for a small generating set" , "X859CF9757A1F51EB" ], [ "\033[1X\033[33X\033[0;-2YAn interactive version of the algorithm\033[133X\\ 033[101X", "4.5", [ 4, 5, 0 ], 151, 12, "an interactive version of the algorithm", "X81A0235D7E15DFBD" ], [ "\033[1X\033[33X\033[0;-2YAdditional features of the package\033[133X\033[1\ 01X", "5", [ 5, 0, 0 ], 1, 15, "additional features of the package", "X7C0BF58A85D48781" ], [ "\033[1X\033[33X\033[0;-2YAdditional features of the package\033[133X\033[1\ 01X", "5.1", [ 5, 1, 0 ], 4, 15, "additional features of the package", "X7C0BF58A85D48781" ], [ "Index", "ind", [ "Ind", 0, 0 ], 1, 16, "index", "X83A0356F839C696F" ], [ "\033[2XAutomorphismGroup\033[102X", "2.1-1", [ 2, 1, 1 ], 11, 5, "automorphismgroup", "X87677B0787B4461A" ], [ "\033[2XInfoAutGrp\033[102X", "2.1-2", [ 2, 1, 2 ], 24, 5, "infoautgrp", "X7D16AFE27E0B7133" ], [ "\033[2XAutomorphismGroupPGroup\033[102X", "3.1-1", [ 3, 1, 1 ], 12, 7, "automorphismgrouppgroup", "X83ABE66C83446A0B" ], [ "\033[2XConvertHybridAutGroup\033[102X", "3.1-2", [ 3, 1, 2 ], 55, 8, "converthybridautgroup", "X7DEE06CF79DC7A7C" ], [ "\033[2XPcGroupAutPGroup\033[102X", "3.1-3", [ 3, 1, 3 ], 101, 9, "pcgroupautpgroup", "X7ED1F7C6849CA658" ], [ "\033[2XCHOP_MULT\033[102X", "4.3-1", [ 4, 3, 1 ], 120, 12, "chop_mult", "X86529C2080159D8A" ], [ "\033[2XNICE_STAB\033[102X", "4.4-1", [ 4, 4, 1 ], 140, 12, "nice_stab", "X83C095D17D35A8DE" ], [ "\033[2XNumberOfPClass2PGroups\033[102X for 3 arguments", "5.1-1", [ 5, 1, 1 ], 11, 15, "numberofpclass2pgroups for 3 arguments", "X7E472D2579705246" ], [ "\033[2XNumberOfPClass2PGroups\033[102X for 2 arguments", "5.1-2", [ 5, 1, 2 ], 18, 15, "numberofpclass2pgroups for 2 arguments", "X825FC0D9796B0D97" ], [ "\033[2XNumberOfClass2LieAlgebras\033[102X for 3 arguments", "5.1-3", [ 5, 1, 3 ], 25, 15, "numberofclass2liealgebras for 3 arguments", "X8399B9137982EBAC" ], [ "\033[2XNumberOfClass2LieAlgbras\033[102X for 2 arguments", "5.1-4", [ 5, 1, 4 ], 32, 15, "numberofclass2liealgbras for 2 arguments", "X824DFC307CA9626E" ] ] ); autpgrp-1.12.0/doc/method.xml0000644000000000000000000000602615202202400012741 0ustar00 The automorphism group method
The automorphism group method The &AUTPGRP; package installs a method for AutomorphismGroup for a finite p-group (see also Section  in the &GAP; Reference Manual). The automorphism group of G. The input is a finite p-group G. If the filters IsPGroup, IsFinite and CanEasilyComputePcgs are set and true for G, the method selection of &GAP; 4 invokes this algorithm.

The output of the method is an automorphism group, whose generators are given in GroupHomomorphismByImages format in terms of their action on the underlying group G. This is a &GAP; . By assigning an level in the range 1 to 4 via SetInfoLevel(InfoAutGrp, level); varying levels of information on the progress of the computation, will be obtained.

LoadPackage("autpgrp", false); true gap> G := PcGroupCode(619031068735, 32); # SmallGroup( 32, 15 ); gap> SetInfoLevel( InfoAutGrp, 1 ); gap> AutomorphismGroup(G); #I step 1: 2^2 -- init automorphisms #I step 2: 2^2 -- aut grp has size 2 #I step 3: 2^1 -- aut grp has size 32 #I final step: convert ]]>

The algorithm proceeds by induction down the lower p-central series of G and the information corresponds to the steps of this induction. In the following example we observe that the method also accepts permutation groups as input, provided they satisfy the required filters.

G := DihedralGroup( IsPermGroup, 2^5 );; gap> IsPGroup(G); true gap> CanEasilyComputePcgs(G); true gap> IsFinite(G); true gap> A := AutomorphismGroup(G); #I step 1: 2^2 -- init automorphisms #I step 2: 2^1 -- aut grp has size 2 #I step 3: 2^1 -- aut grp has size 8 #I step 4: 2^1 -- aut grp has size 32 #I final step: convert gap> A.1; Pcgs([ ( 2,16)( 3,15)( 4,14)( 5,13)( 6,12)( 7,11)( 8,10), ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16), ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16), ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16), ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ]) -> [ ( 1, 2)( 3,16)( 4,15)( 5,14)( 6,13)( 7,12)( 8,11)( 9,10), ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16), ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16), ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16), ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ] gap> Order(A.1); 16 ]]>

autpgrp-1.12.0/doc/nocolorprompt.css0000644000000000000000000000031315202202400014357 0ustar00 /* colors for ColorPrompt like examples */ span.GAPprompt { color: #000000; font-weight: normal; } span.GAPbrkprompt { color: #000000; font-weight: normal; } span.GAPinput { color: #000000; } autpgrp-1.12.0/doc/ragged.css0000644000000000000000000000023115202202400012672 0ustar00/* times.css Frank Lübeck */ /* Change default CSS to use Times font. */ body { text-align: left; } autpgrp-1.12.0/doc/rainbow.js0000644000000000000000000000533615202202400012741 0ustar00 function randchar(str) { var i = Math.floor(Math.random() * str.length); while (i == str.length) i = Math.floor(Math.random() * str.length); return str[i]; } hexdigits = "0123456789abcdef"; function randlight() { return randchar("cdef")+randchar(hexdigits)+ randchar("cdef")+randchar(hexdigits)+ randchar("cdef")+randchar(hexdigits) } function randdark() { return randchar("012345789")+randchar(hexdigits)+ randchar("012345789")+randchar(hexdigits)+ randchar("102345789")+randchar(hexdigits) } document.write('\n'); autpgrp-1.12.0/doc/times.css0000644000000000000000000000026115202202400012565 0ustar00/* times.css Frank Lübeck */ /* Change default CSS to use Times font. */ body { font-family: Times,Times New Roman,serif; } autpgrp-1.12.0/doc/title.xml0000644000000000000000000000472415202202400012605 0ustar00 AutPGrp Computing the Automorphism Group of a p-Group 1.12.0 Bettina Eick
Institut Analysis und Algebra
TU Braunschweig
Universitätsplatz 2
D-38106 Braunschweig
Germany
beick@tu-bs.de http://www.iaa.tu-bs.de/beick
Eamonn O'Brien
Department of Mathematics
University of Auckland
Private Bag 92019
Auckland
New Zealand
obrien@math.auckland.ac.nz http://www.math.auckland.ac.nz/~obrien
17 May 2026 The &AUTPGRP; package introduces a new function to compute the automorphism group of a finite p-group. The underlying algorithm is a refinement of the methods described in O'Brien (1995). In particular, this implementation is more efficient in both time and space requirements and hence has a wider range of applications than the ANUPQ method. Our package is written in &GAP; code and it makes use of a number of methods from the &GAP; library such as the MeatAxe for matrix groups and permutation group functions. We have compared our method to the others available in &GAP;. Our package usually out-performs all but the method designed for finite abelian groups. We note that our method uses the small groups library in certain cases and hence our algorithm is more effective if the small groups library is installed. Bettina Eick and Eamonn O'Brien.

AutPGrp is free software; you can redistribute it and/or modify it under the terms of the https://www.fsf.org/licenses/gpl.html as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. We thank Alexander Hulpke for helping us with efficiency problems. Werner Nickel provided some functions from the &GAP; PQuotient which are used in this package. autpgrp-1.12.0/doc/toggless.css0000644000000000000000000000167215202202400013302 0ustar00/* toggless.css Frank Lübeck */ /* Using javascript we change all div.ContSect to div.ContSectOpen or div.ContSectClosed. This way the config for div.ContSect in manual.css is no longer relevant. Here we add the CSS for the new elements. */ /* This layout is based on an idea by Burkhard Höfling. */ div.ContSectClosed { text-align: left; margin-left: 1em; } div.ContSectOpen { text-align: left; margin-left: 1em; } div.ContSectOpen div.ContSSBlock { display: block; text-align: left; margin-left: 1em; } div.ContSectOpen div.ContSSBlock a { display: block; width: 100%; margin-left: 1em; } span.tocline a:hover { display: inline; background: #eeeeee; } span.ContSS a:hover { display: inline; background: #eeeeee; } span.toctoggle { font-size: 80%; display: inline-block; width: 1.2em; } span.toctoggle:hover { background-color: #aaaaaa; } autpgrp-1.12.0/doc/toggless.js0000644000000000000000000000420515202202400013121 0ustar00/* toggless.js Frank Lübeck */ /* this file contains two functions: mergeSideTOCHooks: this changes div.ContSect elements to the class ContSectClosed and includes a hook to toggle between ContSectClosed and ContSectOpen. openclosetoc: this function does the toggling, the rest is done by CSS */ closedTOCMarker = "▶ "; openTOCMarker = "▼ "; noTOCMarker = " "; /* merge hooks into side toc for opening/closing subsections with openclosetoc */ function mergeSideTOCHooks() { var hlist = document.getElementsByTagName("div"); for (var i = 0; i < hlist.length; i++) { if (hlist[i].className == "ContSect") { var chlds = hlist[i].childNodes; var el = document.createElement("span"); var oncl = document.createAttribute("class"); oncl.nodeValue = "toctoggle"; el.setAttributeNode(oncl); var cont; if (chlds.length > 2) { var oncl = document.createAttribute("onclick"); oncl.nodeValue = "openclosetoc(event)"; el.setAttributeNode(oncl); cont = document.createTextNode(closedTOCMarker); } else { cont = document.createTextNode(noTOCMarker); } el.appendChild(cont); hlist[i].firstChild.insertBefore(el, hlist[i].firstChild.firstChild); hlist[i].className = "ContSectClosed"; } } } function openclosetoc (event) { /* first two steps to make it work in most browsers */ var evt=window.event || event; if (!evt.target) evt.target=evt.srcElement; var markClosed = document.createTextNode(closedTOCMarker); var markOpen = document.createTextNode(openTOCMarker); var par = evt.target.parentNode.parentNode; if (par.className == "ContSectOpen") { par.className = "ContSectClosed"; evt.target.replaceChild(markClosed, evt.target.firstChild); } else if (par.className == "ContSectClosed") { par.className = "ContSectOpen"; evt.target.replaceChild(markOpen, evt.target.firstChild); } } /* adjust jscontent which is called onload */ jscontentfuncs.push(mergeSideTOCHooks); autpgrp-1.12.0/doc/underl.xml0000644000000000000000000001325715202202400012756 0ustar00 The underlying function

The underlying function Underlying the method installation for AutomorphismGroup is the function AutomorphismGroupPGroup. This function is intended for expert users who wish to influence the steps of the algorithm. Note also that AutomorphismGroup will always choose default values. The input is a finite p-group as above and an optional flag which can be true or false. Here the filters for G need not be set, but they should be true for G. The possible values for flag are considered later in Chapter . If flag is not supplied, the algorithm proceeds similarly to the method installed for AutomorphismGroup, but it produces slightly more detailed output. The output of the function is a record which contains the following fields:

glAutos a set of automorphisms which together with agAutos generate the automorphism group; glOrder an integer whose product with the agOrders gives the size of the automorphism group; agAutos a polycyclic generating sequence for a soluble normal subgroup of the automorphism group; agOrder the relative orders corresponding to agAutos; one the identity element of the automorphism group; group the underlying group G; size the size of the automorphism group.

We do not return an automorphism group in the standard form because we wish to distinguish between agAutos and glAutos; the latter act non-trivially on the Frattini quotient of G. This hybrid-group description of the automorphism group permits more efficient computations with it. The following function converts the output of AutomorphismGroupPGroup to the output of AutomorphismGroup. A record. Let A be the automorphism group of a p-group G as computed by AutomorphismGroupPGroup. Then can compute a pc group isomorphic to the solvable part of A stored in the record component A.agGroup. This solvable part forms a subgroup of the automorphism group which contains at least the automorphisms centralizing the Frattini factor of G. The pc group facilitates various further computations with A. LoadPackage("autpgrp", false); true gap> H := PcGroupCode(297368117289422176, 729); # SmallGroup (729, 34); gap> A := AutomorphismGroupPGroup(H); #I step 1: 3^2 -- init automorphisms #I step 2: 3^1 -- aut grp has size 8 #I step 3: 3^2 -- aut grp has size 72 #I step 4: 3^1 -- aut grp has size 5832 #I final step: convert rec( agAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f2, f1, f3^2, f5^2, f4^2, f6^2 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2^2, f3^2*f5, f4^2*f6, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1^2, f2^2, f3*f4^2*f5^2*f6, f4^2*f6, f5^2*f6, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f3, f2, f3*f5^2, f4*f6^2, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f3, f3*f4, f4, f5*f6, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f4, f2, f3*f6^2, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f4, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f5, f2, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f5, f3*f6, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f6, f2, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f6, f3, f4, f5, f6 ] ], agOrder := [ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 ], glAutos := [ ], glOper := [ ], glOrder := 1, group := , one := IdentityMapping( ), size := 52488 ) gap> ConvertHybridAutGroup( A ); ]]> This function computes a pc presentation for the solvable part of the automorphism group A defined by A.agGroup. A is the output of the function AutomorphismGroupPGroup. H := PcGroupCode(297368117289422176, 729);; # SmallGroup (729, 34); gap> A := AutomorphismGroupPGroup(H);; #I step 1: 3^2 -- init automorphisms #I step 2: 3^1 -- aut grp has size 8 #I step 3: 3^2 -- aut grp has size 72 #I step 4: 3^1 -- aut grp has size 5832 #I final step: convert gap> B := PcGroupAutPGroup( A ); gap> I := InnerAutGroupPGroup( B ); Group([ f5, f4^2*f8, f6^2*f9^2, f11^2, f10^2, of ... ]) ]]>

autpgrp-1.12.0/gap/0000755000000000000000000000000015202202400010735 5ustar00autpgrp-1.12.0/gap/autoops.gi0000644000000000000000000001542315202202400012755 0ustar00############################################################################# ## #W autoops.gi AutPGrp package Bettina Eick ## ############################################################################# ## #F PGAutomorphism( , , ) ## InstallMethod( PGAutomorphism, "for p-groups", true, [IsPGroup and IsFinite, IsList, IsList ], 0, function( G, gens, imgs ) local filter, type, r, p, pcgs, base, pcgsimgs, baseimgs, def, d; # cache the default type in the group if not IsBound( G!.PGAutomType ) then filter := IsPGAutomorphism and IsBijective; type := TypeOfDefaultGeneralMapping( G, G, filter ); G!.PGAutomType := type; else type := G!.PGAutomType; fi; # get images correct r := RankPGroup( G ); p := PrimePGroup( G ); pcgs := Pcgs( G ); base := pcgs{[1..r]}; if gens = pcgs then pcgsimgs := imgs; baseimgs := imgs{[1..r]}; elif gens = base then baseimgs := ShallowCopy( imgs ); pcgsimgs := ShallowCopy( imgs ); for d in G!.definitions do if not IsNegRat( d ) then Add( pcgsimgs, SubstituteDef( d, pcgsimgs, p ) ); fi; od; else Print("# W computing pcgs in PGAutomorphism \n"); pcgsimgs := CanonicalPcgsByGeneratorsWithImages( pcgs, gens, imgs ); baseimgs := pcgsimgs{[1..r]}; fi; # create homomorphism return Objectify( type, rec( pcgs := pcgs, pcgsimgs := pcgsimgs, base := base, baseimgs := baseimgs ) ); end); ############################################################################# ## #F IdentityPGAutomorphism( ) ## InstallGlobalFunction( IdentityPGAutomorphism, function( G ) return PGAutomorphism( G, Pcgs(G), AsList(Pcgs(G)) ); end ); ############################################################################# ## #F PrintObj(auto) ## InstallMethod( PrintObj, "for group automorphisms", true, [IsPGAutomorphism], SUM_FLAGS, function( auto ) if IsBound( auto!.mat ) then Print("Aut + Mat: ",auto!.pcgsimgs); else Print("Aut: ",auto!.pcgsimgs); fi; end); ############################################################################# ## #F ViewObj(auto) ## InstallMethod( ViewObj, "for group automorphisms", true, [IsPGAutomorphism], SUM_FLAGS, function( auto ) if IsBound( auto!.mat ) then Print("Aut + Mat: ",auto!.pcgsimgs); else Print("Aut: ",auto!.pcgsimgs); fi; end); ############################################################################# ## #F \= ## InstallMethod( \=, "for group automorphisms", IsIdenticalObj, [IsPGAutomorphism, IsPGAutomorphism], 0, function( auto1, auto2 ) return auto1!.base = auto2!.base and auto1!.baseimgs = auto2!.baseimgs; end); ############################################################################# ## #F ImagesRepresentative( auto, g ) ## InstallMethod( ImagesRepresentative, "for group automorphisms", true, [IsPGAutomorphism, IsObject], 0, function( auto, g ) return MappedPcElement( g, auto!.pcgs, auto!.pcgsimgs ); end ); ############################################################################# ## #F PGMult( auto1, auto2 ) ## InstallMethod( PGMult, true, [IsPGAutomorphism, IsPGAutomorphism], 0, function( auto1, auto2 ) local new, aut; # 1. version new := List( auto1!.pcgsimgs, x -> ImagesRepresentative( auto2, x ) ); if IsBound( auto1!.mat ) and IsBound( auto2!.mat ) then aut := PGAutomorphism( Source(auto1), auto1!.pcgs, new ); aut!.mat := auto1!.mat * auto2!.mat; else aut := PGAutomorphism( Source(auto1), auto1!.pcgs, new ); fi; return aut; # 2. version new := List( auto2!.baseimgs, x -> ImagesRepresentative( auto1, x ) ); return PGAutomorphism( Source(auto2), auto2!.base, new ); end ); ############################################################################# ## #F CompositionMapping2( auto1, auto2 ) ## InstallMethod( CompositionMapping2, "for group automorphisms", true, [IsPGAutomorphism, IsPGAutomorphism], 0, function( auto2, auto1 ) return PGMult( auto1, auto2 ); end ); ############################################################################# ## #F PGMultList( autl ) ## InstallMethod( PGMultList, true, [IsList], 0, function( autl ) local l, r, new; if Length( autl ) = 1 then return autl[1]; fi; if Length( autl ) = 2 then return PGMult(autl[1],autl[2]); fi; l := Length( autl ); r := QuoInt( l, 2 ); new := List( [1..r], x -> PGMult( autl[2*x-1], autl[2*x] )); if not IsInt( l/2 ) then Add( new, autl[l] ); fi; return PGMultList( new ); end ); ############################################################################# ## #F PGPower( n, aut ) ## InstallMethod( PGPower, true, [IsInt, IsPGAutomorphism], 0, function( n, aut ) local c, l, i, j, new; if n <= 0 then return fail; fi; if n = 1 then return aut; fi; c := CoefficientsQadic( n, 2 ); # create power list, if necessary if not IsBound( aut!.power ) then aut!.power := []; fi; # add powers, if necessary l := Length( aut!.power ); if l = 0 then new := aut; else new := aut!.power[l]; fi; for i in [l+1..Length(c)-1] do new := PGMult( new, new ); Add( aut!.power, new ); od; # multiply powers together if c[1] = 1 then new := [aut]; else new := []; fi; for i in [2..Length(c)] do if c[i] = 1 then Add( new, aut!.power[i-1] ); fi; od; return PGMultList( new ); end ); ############################################################################# ## #F PGInverse( aut ) ## InstallMethod( PGInverse, true, [IsPGAutomorphism], 0, function( aut ) local new, inv; if not IsBound( aut!.inv ) then new := CanonicalPcgsByGeneratorsWithImages( aut!.pcgs, aut!.pcgsimgs, aut!.pcgs); inv := PGAutomorphism( Source( aut ), aut!.pcgs, new[2] ); else inv := aut!.inv; fi; if IsBound( aut!.mat ) and not IsBound( inv!.mat) then inv!.mat := aut!.mat^-1; fi; aut!.inv := inv; return aut!.inv; end ); ############################################################################# ## #F InverseGeneralMapping(auto) ## InstallOtherMethod( InverseGeneralMapping, "for group automorphism", true, [IsPGAutomorphism], SUM_FLAGS, function( auto ) return PGInverse( auto ); end ); autpgrp-1.12.0/gap/autos.gd0000644000000000000000000000400515202202400012403 0ustar00############################################################################# ## #W autos.gd AutPGrp package Bettina Eick ## ############################################################################# ## #C Choose functionality ## if not IsBound( InitAutGroup ) then InitAutGroup := false; fi; if not IsBound( CHOP_MULT ) then CHOP_MULT := true; fi; if not IsBound( NICE_STAB ) then NICE_STAB := true; fi; if not IsBound( REDU_OPER ) then REDU_OPER := false; fi; if not IsBound( USE_LABEL ) then USE_LABEL := false; fi; if not IsBound( CHECK ) then CHECK := false; fi; ############################################################################# ## #D Declarations for PGAutomorphisms ## DeclareRepresentation( "IsPGAutomorphismRep", IsGroupGeneralMappingByImages, ["base", "baseimgs", "pcgs", "pcgsimgs"] ); IsPGAutomorphism := IsMapping and IsPGAutomorphismRep; DeclareOperation( "PGAutomorphism", [ IsPGroup and IsFinite, IsList, IsList ] ); DeclareGlobalFunction( "AutomorphismGroupPGroup" ); DeclareGlobalFunction( "PcGroupAutPGroup" ); DeclareGlobalFunction( "ConvertHybridAutGroup" ); DeclareGlobalFunction( "PGOrbitStabilizer" ); DeclareGlobalFunction( "IdentityPGAutomorphism" ); DeclareGlobalFunction( "CountOrbitsGL" ); DeclareGlobalFunction( "NumberOfPClass2PGroups" ); DeclareGlobalFunction( "NumberOfClass2LieAlgebras" ); DeclareOperation( "PGMult", [IsObject, IsObject] ); DeclareOperation( "PGInverse",[IsObject] ); DeclareOperation( "PGPower",[IsInt, IsObject] ); DeclareOperation( "PGMultList", [IsList] ); ############################################################################ ## #V for external applications ## DeclareGlobalFunction( "ImageAutPGroup" ); DeclareGlobalFunction( "InnerAutGroupPGroup" ); DeclareGlobalFunction( "ConvertAutGroup" ); DeclareGlobalFunction( "InduceAutGroup" ); DeclareGlobalFunction( "LinearActionAutGrp" ); DeclareGlobalFunction( "AddInfoCover" ); DeclareGlobalFunction( "InitAutomorphismGroupOver" ); autpgrp-1.12.0/gap/autos.gi0000644000000000000000000003005615202202400012415 0ustar00############################################################################# ## #W autos.gi AutPGrp package Bettina Eick ## ############################################################################# ## #F LinearActionPGAut(

, , ) ## BindGlobal( "LinearActionPGAut", function( P, M, aut ) local p, gensP, pcgsM, gensG, defn, imgs, mat, d; # set up p := PrimePGroup( P ); gensP := GeneratorsOfGroup( P ); pcgsM := Pcgs( M ); gensG := DifferenceLists( gensP, pcgsM ); # compute matrix defn := P!.definitions; imgs := List( aut!.baseimgs, x -> MappedPcElement( x, aut!.pcgs, gensG )); for d in defn do if not IsNegRat( d ) then Add( imgs, SubstituteDef( d, imgs, p ) ); fi; od; imgs := imgs{List( pcgsM, x -> Position( gensP, x ) )}; # two cases - the first for efficiency if imgs = pcgsM then aut!.mat := 1; else mat := List(imgs, x -> ExponentsOfPcElement(pcgsM, x)*One(M!.field)); mat := ImmutableMatrix( M!.field, mat ); aut!.mat := mat; fi; end ); ############################################################################# ## #F LinearActionAutGrp( ,

, ) ## InstallGlobalFunction( LinearActionAutGrp, function( A, P, M ) local aut; # add information for aut in A.glAutos do LinearActionPGAut( P, M, aut ); od; for aut in A.agAutos do LinearActionPGAut( P, M, aut ); od; A.field := M!.field; A.prime := PrimePGroup( P ); A.one!.mat := 1; end); ############################################################################# ## #F CentralAutos( , ) ## BindGlobal( "CentralAutos", function( G, N ) local base, pcgs, cent, b, i, imgs, aut; base := Pcgs(N); pcgs := Pcgs(G); cent := []; for b in base do for i in [1..RankPGroup(G)] do imgs := ShallowCopy( pcgs ); imgs[i] := imgs[i] * b; aut := PGAutomorphism( G, pcgs, imgs ); Add( cent, aut ); od; od; return cent; end ); ############################################################################# ## #F InduceAuto( , ) ## BindGlobal( "InduceAuto", function( F, aut ) local pcgsF, baseF, imgsG, imgsF, hom; pcgsF := Pcgs( F ); baseF := pcgsF{[1..RankPGroup(F)]}; imgsG := aut!.baseimgs; imgsF := List( imgsG, x -> MappedPcElement( x, aut!.pcgs, pcgsF ) ); if CHECK then hom := GroupHomomorphismByImages( F, F, baseF, imgsF ); if not IsGroupHomomorphism( hom ) then Error("no hom"); elif not IsBijective( hom ) then Error("no bijection"); fi; fi; return PGAutomorphism( F, baseF, imgsF ); end ); ############################################################################# ## #F InduceAutGroup( , ,

, , ) ## InstallGlobalFunction( InduceAutGroup, function( A, Q, P, M, U ) local p, r, F, s, t, pcgsF, pcgsL, L, B, central; # set up p := PrimePGroup( P ); r := RankPGroup( P ); # create factor F := Range( EpimorphismQuotientSystem(Q) ); SetIsPGroup( F, true ); SetPrimePGroup( F, p ); SetRankPGroup( F, r ); pcgsF := Pcgs(F); # get definitions for F F!.definitions := RewriteDef( pcgsF, Q!.definitions, p ); # get p-centre of F s := Length( Pcgs(P) ) - Length( Pcgs(M) ); t := s + Length( Pcgs(M) ) - Length( Pcgs(U) ); pcgsL := InducedPcgsByPcSequenceNC( pcgsF, pcgsF{[s+1..t]} ); L := SubgroupByPcgs( F, pcgsL ); # induce autos B := rec(); B.glAutos := List( A.glAutos, x -> InduceAuto( F, x ) ); B.agAutos := List( A.agAutos, x -> InduceAuto( F, x ) ); central := CentralAutos( F, L ); Append( B.agAutos, central ); # add information B.glOrder := A.glOrder; B.agOrder := Concatenation( A.agOrder, List( central, x -> p ) ); B.group := F; B.one := IdentityPGAutomorphism( F ); B.size := B.glOrder * Product( B.agOrder ); # if possible add projective operation if IsBound( A.glOper ) then B.glOper := A.glOper; fi; # and return return B; end); ############################################################################# ## #F ConvertAuto( , ) ## BindGlobal( "ConvertAuto", function( aut, iso ) local G, pcgs, imgs, auto; G := Source( iso ); pcgs := SpecialPcgs( G ); imgs := List( pcgs, x -> ImagesRepresentative( iso, x ) ); imgs := List( imgs, x -> ImagesRepresentative( aut, x ) ); imgs := List( imgs, x -> PreImagesRepresentative( iso, x ) ); if not CHECK then auto := GroupHomomorphismByImagesNC(G, G, pcgs, imgs ); SetIsBijective( auto, true ); else auto := GroupHomomorphismByImages( G, G, AsList(pcgs), imgs ); if not IsGroupHomomorphism( auto ) then Error("automorphism is no homomorphism"); elif not IsBijective( auto ) then Error("automorphism is not bijective"); fi; fi; return auto; end ); ############################################################################# ## #F ConvertAutGroup ( , ) ## InstallGlobalFunction( ConvertAutGroup, function( A, G ) local r, gens, imgs, iso, C; r := RankPGroup( G ); gens := SpecialPcgs( G ){[1..r]}; imgs := Pcgs( A.group ){[1..r]}; if not CHECK then iso := GroupHomomorphismByImagesNC( G, A.group, gens, imgs ); SetIsBijective( iso, true ); else iso := GroupHomomorphismByImages( G, A.group, gens, imgs ); if not IsGroupHomomorphism( iso ) then Error("isomorphism is no homomorphism"); elif not IsBijective( iso ) then Error("isomorphism is not bijective"); fi; fi; C := rec(); C.glAutos := List( A.glAutos, x -> ConvertAuto( x, iso ) ); C.glOrder := A.glOrder; C.agAutos := List( A.agAutos, x -> ConvertAuto( x, iso ) ); C.agOrder := A.agOrder; C.one := IdentityMapping( G ); C.group := G; C.size := A.size; # if possible add projective operation if IsBound( A.glOper ) then C.glOper := A.glOper; fi; return C; end); ############################################################################# ## #F AddInfoCover( Q, P, M, U ) ## InstallGlobalFunction( AddInfoCover, function( Q, P, M, U ) local r, p, f, fam, gensP, pcgsP, gensM, pcgsM, gensU, pcgsU, pos, def; r := Q!.RanksOfDescendingSeries; p := Q!.prime; f := Q!.field; fam := FamilyPcgs( P ); # info for P gensP := GeneratorsOfGroup( P ); pcgsP := InducedPcgsByPcSequenceNC( fam, gensP ); SetPcgs( P, pcgsP ); SetRankPGroup( P, r[1] ); SetPrimePGroup( P, p ); # info for M gensM := GeneratorsOfGroup( M ); pcgsM := InducedPcgsByPcSequenceNC( fam, gensM ); SetPcgs( M, pcgsM ); SetPrimePGroup( M, p ); M!.field := f; # info for U gensU := GeneratorsOfGroup( U ); pcgsU := InducedPcgsByGeneratorsNC( fam, gensU ); SetPcgs( U, pcgsU ); # get definitions of M pos := List( pcgsP, x -> Position( fam, x ) ); def := Q!.definitions{pos}; P!.definitions := RewriteDef( pcgsP, def, p ); end); ############################################################################# ## #F AutomorphismGroupPGroup( , ) . . . .automorphisms in hybird form ## InstallGlobalFunction( AutomorphismGroupPGroup, function( arg ) local p, r, G, pcgs, first, n, str, A, F, Q, i, s, t, P, N, M, U, B, baseU, baseN, epi, f; # catch the trivial case G := arg[1]; p := PrimePGroup( G ); r := RankPGroup( G ); if Size( G ) = 1 then return Group( [], IdentityMapping(G) ); fi; # choose a initialisation if Length( arg ) = 1 then if IsHomoCyclic( G ) then InitAutGroup := InitAutomorphismGroupFull; elif (p^r - 1)/(p - 1) < 30000 then InitAutGroup := InitAutomorphismGroupOver; else InitAutGroup := InitAutomorphismGroupChar; fi; elif Length( arg ) = 2 and IsString(arg[2]) then if arg[2] = "Full" then InitAutGroup := InitAutomorphismGroupFull; elif arg[2] = "Over" then InitAutGroup := InitAutomorphismGroupOver; elif arg[2] = "Char" then InitAutGroup := InitAutomorphismGroupChar; else Error("invalid initialisation"); fi; elif Length( arg ) = 2 and IsBool(arg[2]) and arg[2] = true then str := Interrupt("choose initialisation (Over/Char/Full)"); if str = "Over" then InitAutGroup := InitAutomorphismGroupOver; elif str = "Char" then InitAutGroup := InitAutomorphismGroupChar; elif str = "Full" then InitAutGroup := InitAutomorphismGroupFull; else Error("invalid initialisation"); fi; fi; # choose flags CHOP_MULT := true; NICE_STAB := true; USE_LABEL := false; # compute special pcgs pcgs := SpecialPcgs( G ); first := LGFirst( SpecialPcgs(G) ); p := PrimePGroup( G ); n := Length(pcgs); r := RankPGroup( G ); f := GF(p); # init automorphism group - compute Aut(G/G_1) Info( InfoAutGrp, 1, "step 1: ",p,"^", first[2]-1, " -- init automorphisms "); A := InitAutGroup( G ); # loop over remaining steps F := Range( IsomorphismFpGroupByPcgs( pcgs, "f" ) ); Q := PQuotient( F, p, 1 ); for i in [2..Length(first)-1] do # print info s := first[i]; t := first[i+1]; Info( InfoAutGrp, 1, "step ",i,": ",p,"^", t-s, " -- aut grp has size ", A.size ); # the cover Info( InfoAutGrp, 2, " computing cover"); P := PCover( Q ); M := PMultiplicator( Q, P ); N := Nucleus( Q, P ); U := AllowableSubgroup( Q, P ); AddInfoCover( Q, P, M, U ); # induced action of A on M Info( InfoAutGrp, 2, " computing matrix action"); LinearActionAutGrp( A, P, M ); # compute stabilizer Info( InfoAutGrp, 2, " computing stabilizer of U"); baseN := GeneratorsOfGroup(N); baseU := GeneratorsOfGroup(U); baseN := List(baseN, x -> ExponentsOfPcElement(Pcgs(M), x)) * One(f); baseU := List(baseU, x -> ExponentsOfPcElement(Pcgs(M), x)) * One(f); baseU := EcheloniseMat( baseU ); PGOrbitStabilizer( A, baseU, baseN, false ); # next step of p-quotient IncorporateCentralRelations( Q ); RenumberHighestWeightGenerators( Q ); # induce to next factor Info( InfoAutGrp, 2, " induce autos and add central autos"); A := InduceAutGroup( A, Q, P, M, U ); od; # now get a real automorphism group Info( InfoAutGrp, 1, "final step: convert"); return ConvertAutGroup( A, G ); end ); ############################################################################# ## #M ConvertHybridAutGroup( ) ## InstallGlobalFunction( ConvertHybridAutGroup, function( A ) local B, pcgs; B := Group( Concatenation( A.glAutos, A.agAutos ), A.one ); SetSize( B, A.glOrder * Product( A.agOrder ) ); if Length( A.glAutos ) = 0 then SetIsSolvableGroup( B, true ); pcgs := PcgsByPcSequenceNC( FamilyObj( A.one ), A.agAutos ); SetRelativeOrders( pcgs, A.agOrder ); SetOneOfPcgs( pcgs, A.one ); SetGeneralizedPcgs( B, pcgs ); fi; SetIsGroupOfAutomorphisms( B, true ); return B; end ); ############################################################################# ## #M AutomorphismGroup ## InstallMethod( AutomorphismGroup, "for finite p-groups", true, [IsPGroup and IsFinite and CanEasilyComputePcgs], 0, function( G ) local A; # the trivial case is a problem if Size( G ) = 1 then return Group( [], IdentityMapping(G) ); fi; # compute A := AutomorphismGroupPGroup( G ); # translate and return A:=ConvertHybridAutGroup( A ); SetIsAutomorphismGroup(A,true); if IsFinite(G) then SetIsGroupOfAutomorphismsFiniteGroup(A,true); fi; return A; end ); autpgrp-1.12.0/gap/countcl.gi0000644000000000000000000002647715202202400012745 0ustar00############################################################################# ## #W countcl.gi Bettina Eick ## #W Let GL(n,p) act linearly on some space V. The function in this file can #W be used to count the number of orbits of subspaces of dimension k arising #W in this action. ## #W As an application, the function in this file can be used to count the #W number of p-groups of p-class 2 with n generators or the number of #W Lie algebras over GF(p) with n generators. ## ############################################################################# ## #F InducedActionFactor( mats, fac, low ) ## BindGlobal( "InducedActionFactor@", function( mats, fac, low ) local sml, upp, d, i, b, t; sml := List( mats, x -> [] ); upp := Concatenation( fac, low ); d := Length( fac ); for i in [1..Length(mats)] do for b in fac do t := SolutionMat( upp, b*mats[i] ){[1..d]}; Add( sml[i], t ); od; od; return sml; end ); ############################################################################# ## #F SpinUpCyclic( v, mat, d ) ## BindGlobal( "SpinUpCyclic", function( v, mat, d ) local b, i; b := [v]; for i in [1..d-1] do b[i+1] := b[i] * mat; od; TriangulizeMat(b); return b; end ); ############################################################################# ## #F JordanBlockLengths( mat, F ) ## BindGlobal( "JordanBlockLengths", function( g, F ) local chr, min, fc, fm, ns, V, W, U, i, f, e, h, k, v, t; # char poly chr := CharacteristicPolynomial(g); fc := Collected(Factors(chr)); # min poly min := MinimalPolynomial(F, g); fm := Factors(min); # set up ns := List( fc, x -> List( [1..x[2]], y -> 0 ) ); V := g^0; # loop for i in [1..Length(fc)] do # determine V_i f := fc[i][1]; e := Length(Filtered(fm, x -> x = f)); h := Value( f^e, g ); W := TriangulizedNullspaceMat(h); k := InducedActionFactor@( [g], W, [] )[1]; # split cyclic while not IsBool(k) do ns[i][e] := ns[i][e] + 1; if Length(k) = e * Degree(f) then k := false; else h := Value( f^(e-1), k ); v := First( k^0, x -> x*h <> 0*x ); W := SpinUpCyclic( v, k, e*Degree(f) ); U := BaseSteinitzVectors(k^0, W).factorspace; k := InducedActionFactor@( [k], U, W )[1]; t := Collected(Factors(MinimalPolynomial( F, k ))); e := t[1][2]; fi; od; od; return rec( blks := ns, degs := List(fc, x -> Degree(x[1]))); end ); ############################################################################# ## #F Two small help functions ## BindGlobal( "WeightedSum", function(vec) return Sum(List( [1..Length(vec)], x -> x * vec[x] )); end ); BindGlobal( "PartialSums", function(vec) return List( [1..Length(vec)], x -> Sum(vec{[x..Length(vec)]})); end ); ############################################################################# ## #F Deltas( blls, degs, k ) ## BindGlobal( "Deltas", function( ni, d, k ) local ds, i, r, new, del, s, j, m; ds := [[]]; i := 1; r := Length(d); while i <= r do new := []; for del in ds do s := Sum(List([1..i-1], x -> del[x]*d[x])); if i < r then m := Minimum( ni[i], QuoInt(k-s, d[i]) ); for j in [0..m] do Add( new, Concatenation( del, [j] ) ); od; fi; if i = r then j := (k-s) / d[i]; if IsInt(j) and j <= ni[i] then Add( new, Concatenation( del, [j] ) ); fi; fi; od; ds := new; i := i + 1; od; return ds; end ); ############################################################################# ## #F Gammas( deli, vis ) ## BindGlobal( "Gammas", function( d, v ) local par, i; par := Partitions( d ); for i in [1..Length(par)] do if Length(par[i]) <= Length(v) and ForAll( [1..Length(par[i])], x -> par[i][x] <= v[x] ) then par[i] := Concatenation(par[i], 0*[1..Length(v)-Length(par[i])]); else par[i] := false; fi; od; return Filtered(par, x -> not IsBool(x)); end ); ############################################################################# ## #F PChoose( n, k, q ) . . . . . . . . . .number of k-dim subspaces in GF(q)^n ## BindGlobal( "PChoose", function( n, k, q ) local qn, qd, i, size; if n / 2 < k then k:= n - k; fi; size:= 1; qn:= q^n; qd:= q; for i in [ 1 .. k ] do size:= size * ( qn - 1 ) / ( qd - 1 ); qn:= qn / q; qd:= qd * q; od; return size; #return Size(Subspaces(GF(q)^n, k)); end ); ############################################################################# ## #F Feval(a, b, q ) . . . . . . . . . . . . . . . . . . .evaluate f on a, b, q ## BindGlobal( "Feval", function( a, b, q ) local l, s, i; Add( b, 0 ); l := Length(a); s := 1; for i in [1..l] do s := s * q^(b[i+1]*(a[i]-b[i])); s := s * PChoose(a[i]-b[i+1], b[i]-b[i+1], q); od; return s; end ); ############################################################################# ## #F FixedPointsByDecom( blocks, degs, p, k ) ## BindGlobal( "FixedPointsByDecom", function( blks, degs, p, k ) local r, ni, ds, vi, t, td, tg, delta, gamma, i, gs; # set up r := Length(degs); # compute deltas ni := List( blks, WeightedSum ); ds := Deltas( ni, degs, k ); # precompute vij vi := List( blks, PartialSums ); # add up t := 0; for delta in ds do td := 1; for i in [1..r] do gs := Gammas( delta[i], vi[i] ); tg := 0; for gamma in gs do tg := tg + Feval( vi[i], gamma, p^degs[i] ); od; td := td * tg; od; t := t + td; od; # that's it return t; end ); ############################################################################ ## #F CountOrbitsGL( n, p, k, Action ) . . . . . . count the orbits of GL(n,p) ## ## Action defines the action and k the dimension of the subspaces to count. ## InstallGlobalFunction( CountOrbitsGL, function( n, p, k, Action ) local G, cls, jor, len, fix, cl, g, h, J, t, j, l; # set up G := GL(n,p); cls := ConjugacyClasses(G); # catch input if IsBool(k) then l := n*(n-1)/2-1; fi; # infos jor := []; len := []; fix := []; for cl in cls do # get g and action g := Representative(cl); h := Action(g, GF(p)); Info(InfoAutGrp, 1, "start class of order ", Order(g)); # compute jordan blocks n_{ij} J := JordanBlockLengths(h, GF(p)); # check if known j := Position( jor, J ); if IsBool( j ) then Info( InfoAutGrp, 2, " Degree: ",J.degs," -- Jordan ", J.blks); if IsBool(k) then t := List([1..l], x -> FixedPointsByDecom(J.blks,J.degs,p,x)); else t := FixedPointsByDecom( J.blks, J.degs, p, k ); fi; Add( jor, J ); Add( len, Size(cl) ); Add( fix, t ); Info( InfoAutGrp, 2, " class yields ",t); else len[j] := len[j] + Size(cl); fi; od; return Sum( List( [1..Length(jor)], i -> len[i]*fix[i] ) ) / Size(G); end ); ############################################################################# ## #F Some Actions ## BindGlobal( "WedgeAction", function( mat, f ) return WedgeGModule(GModuleByMats([mat], f)).generators[1]; end ); BindGlobal( "TensorAction", function( mat, f ) return KroneckerProduct( mat, mat ); end ); BindGlobal( "WedgePlusChar2Action", function( mat, f ) local d, e, M, i, j, l, k, a, b; # set up d := Length(mat); e := (d^2 - d)/2; M := NullMat(e+d,e+d); # wedge part for i in [2..d] do for j in [1..i-1] do a := (i-1)*(i-2)/2+j; for k in [2..d] do for l in [1..k-1] do b := (k-1)*(k-2)/2+l; M[a][b] := mat[i][k]*mat[j][l] - mat[i][l]*mat[j][k]; od; od; od; od; # power part for i in [1..d] do a := e+i; for k in [2..d] do for l in [1..k-1] do b := (k-1)*(k-2)/2+l; M[a][b] := mat[i][k]*mat[i][l]; od; od; for j in [1..d] do b := e+j; M[a][b] := mat[i][j]; od; od; return M * One(f); end ); BindGlobal( "WedgePlusCharPAction", function( mat, f ) return DirectSumMat( WedgeAction(mat,f), mat ); end ); BindGlobal( "WedgePlusAction", function( mat, f ) if Characteristic(f) = 2 then return WedgePlusChar2Action(mat, f); else return WedgePlusCharPAction(mat, f); fi; end ); ############################################################################ ## #F NumberOfPClass2PGroups( n, p, [k] ) ## InstallGlobalFunction( NumberOfPClass2PGroups, function( arg ) local n, p, l, k, c; n := arg[1]; p := arg[2]; l := n*(n+1)/2; if Length(arg) = 3 then if arg[3] > l then return 0; fi; if arg[3] = l then return 1; fi; if arg[3] = 0 then return 0; fi; return CountOrbitsGL( arg[1], arg[2], arg[3], WedgePlusAction ); elif Length(arg) = 2 then c := []; c[l] := 1; for k in [1..l-1] do if not IsBound( c[k] ) then c[k] := CountOrbitsGL( n, arg[2], k, WedgePlusAction ); c[l-k] := c[k]; fi; od; return c; fi; Error("wrong input"); end ); ############################################################################ ## #F NumberOfClass2LieAlgebras( n, p, [k] ) ## InstallGlobalFunction( NumberOfClass2LieAlgebras, function( arg ) local n, k, c, m; if Length(arg) = 3 then return CountOrbitsGL( arg[1], arg[2], arg[3], WedgeAction ); elif Length(arg) = 2 then n := arg[1]; m := n*(n-1)/2; c := []; c[m] := 1; for k in [1..m-1] do if not IsBound( c[k] ) then c[k] := CountOrbitsGL( n, arg[2], k, WedgeAction ); c[m-k] := c[k]; fi; od; return c; fi; Error("wrong input"); end ); ############################################################################ ## #F NumberOfClass2AssociativeAlgebras( n, p, [k] ) ## BindGlobal( "NumberOfClass2AssocAlgebras", function( arg ) local n, k, c, m; if Length(arg) = 3 then return CountOrbitsGL( arg[1], arg[2], arg[3], TensorAction ); elif Length(arg) = 2 then n := arg[1]; m := n*(n-1)/2; c := []; c[m] := 1; for k in [1..m-1] do if not IsBound( c[k] ) then c[k] := CountOrbitsGL( n, arg[2], k, TensorAction ); c[m-k] := c[k]; fi; od; return c; fi; Error("wrong input"); end ); BindGlobal( "NumberOfClass2AssocAlgebrasByDim", function( d, p ) local r, n, c; r := 2; for n in [2..d-1] do c := NumberOfClass2AssocAlgebras( n, p, d-n ); r := r+c; od; return r; end ); autpgrp-1.12.0/gap/general.gi0000644000000000000000000001055615202202400012702 0ustar00############################################################################# ## #W general.gi AutPGrp package Bettina Eick ## ############################################################################# ## #F Interrupt ## BindGlobal( "Interrupt", function(text) local str, ans; Print("\n",text); Print(": \c"); str := InputTextUser(); ans := ReadLine(str); ans := ans{[1..Length(ans)-1]}; Print("\n"); return ans; end ); ############################################################################# ## #F RewriteDef( pcgs, defn, p ) ## BindGlobal( "RewriteDef", function( pcgs, defn, p ) local words, i, d, e, w; words := []; for i in [1..Length(defn)] do d := defn[i]; if IsNegRat( d ) then Add( words, d ); elif IsInt( d ) then w := pcgs[d]^p; e := ExponentsOfPcElement( pcgs, w ); e[i] := 0; Add( words, [d, e] ); elif IsList( d ) then w := Comm( pcgs[d[1]], pcgs[d[2]] ); e := ExponentsOfPcElement( pcgs, w ); e[i] := 0; Add( words, [d, e] ); fi; od; return words; end ); ############################################################################# ## #F SubstituteDef( def, gens, p ) ## BindGlobal( "SubstituteDef", function( def, gens, p ) local i, e; # definition part if IsInt( def ) then return gens[-def]; elif IsInt( def[1] ) then e := gens[def[1]]^p; else e := Comm( gens[def[1][1]], gens[def[1][2]] ); fi; # tail part for i in [1..Length(def[2])] do if def[2][i] <> 0 then e := gens[i]^-def[2][i] * e; fi; od; return e; end ); ############################################################################# ## #F InducedPcgsByBasis( pcgs, basis ) ## BindGlobal( "InducedPcgsByBasis", function( pcgs, basis ) local pcgsN, pcgsM, seq, pcs; pcgsN := NumeratorOfModuloPcgs( pcgs ); pcgsM := DenominatorOfModuloPcgs( pcgs ); seq := List( basis, b -> PcElementByExponents( pcgs, b ) ); pcs := InducedPcgsByPcSequenceAndGenerators( pcgsN, pcgsM, seq ); return InducedPcgsByPcSequenceNC( pcgsN, pcs ); end ); ############################################################################# ## #F IsHomoCyclic( G ) ## BindGlobal( "IsHomoCyclic", function( G ) return IsAbelian(G) and Length(Set(AbelianInvariants(G))) = 1; end ); ############################################################################# ## #F FrattiniQuotientPGroup( G ) ## BindGlobal( "FrattiniQuotientPGroup", function( G ) local spec, firs, frat, H; spec := SpecialPcgs(G); firs := LGFirst(spec); frat := InducedPcgsByPcSequenceNC( spec, spec{[firs[2]..Length(spec)]}); H := GroupByPcgs( spec mod frat ); SetIsPGroup(H, true ); SetPrimePGroup( H, PrimePGroup(G) ); SetRankPGroup( H, firs[2] - 1 ); H!.definitions := List( [1..firs[2]-1], x -> -x ); return H; end ); ############################################################################# ## #F InitGlAutos( H, mats ) ## BindGlobal( "InitGlAutos", function( H, mats ) local pcgs; pcgs := Pcgs(H); return List( mats, x -> PGAutomorphism( H, pcgs, List( x, y -> PcElementByExponents( pcgs, y) ) ) ); end ); ############################################################################# ## #F InitAgAutos( H, p ) ## BindGlobal( "InitAgAutos", function( H, p ) local pcgs, auts, alpha, fac, i, imgs; if p <> 2 then pcgs := Pcgs(H); auts := []; alpha := PrimitiveRoot( GF(p) ); fac := Factors( p - 1 ); for i in [1..Length(fac)] do imgs := List( pcgs, x-> x^IntFFE( alpha ) ); Add( auts, PGAutomorphism( H, pcgs, imgs ) ); alpha := alpha ^ fac[i]; od; return rec( auts := auts, rels := fac ); else return rec( auts := [], rels := [] ); fi; end ); ############################################################################# ## #F EcheloniseMat( mat ) ## BindGlobal( "EcheloniseMat", function( mat ) local ech, tmp, i; if Length(mat) = 0 then return mat; fi; ech := SemiEchelonMat( mat ); tmp := []; for i in [1..Length(ech.heads)] do if ech.heads[i] <> 0 then Add( tmp, ech.vectors[ech.heads[i]] ); fi; od; return tmp; end); autpgrp-1.12.0/gap/hybrstab.gi0000644000000000000000000002433415202202400013102 0ustar00############################################################################# ## #W hybridst.gi AutPGrp package Bettina Eick ## ############################################################################# ## #F CollectToWord( list ) ## BindGlobal( "CollectToWord", function( list ) local coll, t, i; coll := []; t := [list[1], 1]; for i in [2..Length(list)] do if t[1] <> list[i] then Add( coll, t ); t := [list[i], 1]; else t[2] := t[2] + 1; fi; od; Add( coll, t ); return coll; end ); ############################################################################# ## #F TransformPG( get, list, id ) . . . . . . . . . . . .convert get to element ## BindGlobal( "TransformPG", function( get, list, id ) local coll, res, i; # catch the special case if Length( get ) = 0 then return id; fi; # otherwise compute coll := CollectToWord( get ); if coll[1][1] > 0 then res := [PGPower( coll[1][2],list[coll[1][1]] )]; else res := [PGPower( coll[1][2], PGInverse(list[-coll[1][1]]))]; fi; for i in [2..Length(coll)] do if coll[i][1] > 0 then Add( res, PGPower(coll[i][2],list[coll[i][1]] ) ); else Add( res, PGPower(coll[i][2], PGInverse(list[-coll[i][1]]) ) ); fi; od; return PGMultList( res ); end ); ############################################################################# ## #F Transform( get, list, id ) . . . . . . . . . . . . .convert get to element ## BindGlobal( "Transform", function( get, list, id ) local res, i; if Length( get ) = 0 then return id; fi; if get[1] > 0 then res := list[get[1]]; else res := list[-get[1]]^-1; fi; for i in [2..Length( get )] do if get[i] > 0 then res := res * list[get[i]]; else res := res * list[-get[i]]^-1; fi; od; return res; end ); ############################################################################# ## #F ReduceGet( ords, get ) . . . . . . . . . . . . . . .reduce get with orders ## BindGlobal( "ReduceGet", function( ords, get ) local found, i, j, o; found := true; while found do # first reduce by inverses i := 1; found := false; while i <= Length( get ) - 1 do if not IsBool( get[i+1] ) and get[i] = - get[i+1] then get[i] := false; get[i+1] := false; found := true; i := i + 1; fi; i := i + 1; od; # now reduce by orders i := 1; while i <= Length( get ) do if not IsBool( get[i] ) then if get[i] > 0 then o := ords[ get[i] ]; else o := ords[ -get[i] ]; fi; if i+o-1 <= Length( get ) and ForAll( get{[i..i+o-1]}, x -> x = get[i] ) then for j in [i..i+o-1] do get[j] := false; od; found := true; i := i + o - 1; fi; fi; i := i + 1; od; od; return Filtered( get, x -> not IsBool( x ) ); end ); ############################################################################# ## #F OSTransversalInverse( j, trans, trels, id ) ## BindGlobal( "OSTransversalInverse", function( j, trans, trels, id ) local l, g, s, p, t; if j = 1 then return id; fi; l := Product( trels ); j := j - 1; g := id; for s in Reversed( [1..Length( trans )] ) do p := trels[s]; l := l/p; t := QuoInt( j, l ); j := RemInt( j, l ); if t > 0 then g := PGMult( g, PGInverse(trans[s])^t ); fi; od; return g; end ); ############################################################################# ## #F PcgsOrbitStabilizer( A, oper, pt, fpt, info ) ## BindGlobal( "PcgsOrbitStabilizer", function( A, oper, pt, fpt, info ) local pcgs, rels, stabl, srels, trans, trels, orbit, i, y, j, p, l, s, k, t, h, g, dict; pcgs := A.agAutos; rels := A.agOrder; # catch trivial case if Length( pcgs ) = 0 then return rec( stabl := pcgs, srels := rels, orbit := [pt], trans := [], trels := [] ); fi; # initialise orbit, stabiliser and transversal stabl := []; srels := []; trans := []; trels := []; orbit := [pt]; dict := NewDictionary( pt, true ); AddDictionary( dict, pt, 1 ); # Start constructing orbit. i := Length( pcgs ); while i >= 1 do if oper[i] = 1 then Add( stabl, pcgs[i] ); Add( srels, rels[i] ); else y := fpt( pt, oper[i], info ); j := LookupDictionary( dict, y ); if IsBool( j ) then # enlarge transversal Add( trans, pcgs[i] ); Add( trels, rels[i] ); # enlarge orbit p := rels[i]; l := Length( orbit ); orbit[p*l] := true; s := 0; for k in [ 1 .. p - 1 ] do t := s + l; for h in [ 1 .. l ] do orbit[h + t] := fpt( orbit[h + s], oper[i], info ); AddDictionary( dict, orbit[h + t], h + t ); od; s := t; od; else # enlarge stabilizer if j > 1 then g := OSTransversalInverse(j, trans, trels, A.one); Add( stabl, PGMult( pcgs[i], g ) ); else Add( stabl, pcgs[i] ); fi; Add( srels, rels[i] ); fi; fi; i := i - 1; od; return rec( stabl := Reversed( stabl ), srels := Reversed( srels ), orbit := orbit, trans := trans, trels := trels ); end ); ############################################################################# ## #F BlockOrbitStabilizer( B, oper, os, fpt, info ) ## BindGlobal( "BlockOrbitStabilizer", function( B, oper, os, fpt, info ) local bl, l, li, orbit, trans, stabl, pstab, mats, auts, ords, pers, k, pt, i, y, j, new, get, aut, g, per, s, dict, r, stabGrp; # the block and limit for orbit length bl := os.orbit; l := Length( bl ); li := B.glOrder / Factors( B.glOrder )[1]; # set up orbit, transversal and stab orbit := [ bl ]; dict := NewDictionary( bl[1], true ); for j in [1..l] do AddDictionary( dict, bl[j], [1,j] ); od; trans := [ [] ]; stabl := []; pstab := []; # get acting elements auts := B.glAutos; ords := List( auts, Order ); stabGrp := Group( () ); if IsBound( B.glOper ) then pers := B.glOper; fi; # loop k := 1; while k <= Length( orbit ) do if k mod 10000 = 0 then Info( InfoAutGrp, 5, " orbit pos ", k, " of ",Length(orbit)); fi; pt := orbit[k][1]; for i in [ 1..Length(oper) ] do # compute the image of a point y := fpt( pt, oper[i], info ); j := LookupDictionary( dict, y ); if IsBool( j ) then # enlarge orbit and transversal new := List( [1..l], x -> true ); for s in [1..l] do new[s] := fpt( orbit[k][s], oper[i], info ); AddDictionary( dict, new[s], [Length(orbit)+1, s] ); od; Add( orbit, new ); get := Concatenation( trans[k], [i] ); Add( trans, get ); else # enlarge stabilizer get := Concatenation(trans[k], [i], Reversed(-trans[j[1]])); get := ReduceGet( ords, get ); aut := TransformPG( get, auts, B.one ); # reduce from block-stab to point-stab if j[2] > 1 then g := OSTransversalInverse(j[2], os.trans, os.trels, B.one); aut := PGMult( aut, g ); fi; # add permutations if known if IsBound( B.glOper ) then g := Transform( get, pers, () ); if not g in stabGrp then stabGrp := ClosureGroup( stabGrp, g ); Add( pstab, g ); Add( stabl, aut ); fi; else Add( stabl, aut ); fi; fi; od; if Length( orbit ) * Size(stabGrp) > li then # orbit is going to be the whole domain, and the # stabilizer cannot get any larger, so we are done return rec( stabl := stabl, pstab := pstab, length := B.glOrder / Size(stabGrp) ); else k := k + 1; fi; od; return rec( stabl := stabl, pstab := pstab, length := Length(orbit) ); end ); ############################################################################# ## #F PGHybridOrbitStabilizer( A, glMats, agMats, pt, oper, info ) ## BindGlobal( "PGHybridOrbitStabilizer", function( A, glMats, agMats, pt, oper, info ) local os, OS, B; # compute ag orbit stabilizier if Length( glMats ) = 0 and Length( agMats ) = 0 then return; fi; os := PcgsOrbitStabilizer( A, agMats, pt, oper, info ); Info( InfoAutGrp, 4, " ag-orbit -- length ",Length(os.orbit)); # add info to A A.agAutos := os.stabl; A.agOrder := os.srels; # compute block orbit and stabiliser if Length( glMats ) = 0 then return; fi; OS := BlockOrbitStabilizer( A, glMats, os, oper, info ); Info( InfoAutGrp, 4, " gl-orbit -- length ", OS.length, " -- gens ",Length(OS.stabl)); # set up new aut grp A.glAutos := OS.stabl; A.glOrder := A.glOrder / OS.length; Assert(1,IsInt(A.glOrder)); if IsBound( A.glOper ) then A.glOper := OS.pstab; fi; # nice the glAutos if necessary if NICE_STAB and OS.length > 1 then NiceHybridGroup( A ); fi; end ); autpgrp-1.12.0/gap/initmat.gi0000644000000000000000000001413215202202400012724 0ustar00############################################################################# ## #W initmat.gi AutPGrp package Bettina Eick ## ############################################################################# ## #F TwoStepCentralizersByLcs( G ) ## ## The two-step-centralizers of lower p-central series of G. ## BindGlobal( "TwoStepCentralizersByLcs", function( G ) local pcgs, first, p, field, list, i, f, m, n, max, pcgsN, pcgsM, pcgsH, gensL, gensC, pcgsR, new; # set up pcgs := SpecialPcgs( G ); first := LGFirst( pcgs ); p := PrimePGroup( G ); field := GF(p); list := []; max := Length(pcgs); # run through lower p-central series for i in [3..Length(first)] do f := first[i-2]; m := first[i-1]; n := first[i]; pcgsN := InducedPcgsByPcSequenceNC( pcgs, pcgs{[f..max]} ); pcgsM := InducedPcgsByPcSequenceNC( pcgs, pcgs{[m..max]} ); pcgsH := InducedPcgsByPcSequenceNC( pcgs, pcgs{[n..max]} ); gensL := pcgsN mod pcgsM; gensC := pcgs mod pcgsM; pcgsR := pcgsM mod pcgsH; new := NextStepCentralizer( gensL, gensC, pcgsR, field ); Append(new, pcgsM ); #new := InducedPcgsByPcSequenceNC( pcgs, new ); new := InducedPcgsByGeneratorsNC( pcgs, new ); Add( list, SubgroupByPcgs( G, new ) ); od; return list; end ); ############################################################################# ## #F OmegaSubgroupsByLcs( G ) ## ## The preimages of Omega-subgroups of G_i for all factors G_i of the lower ## p-central series of G. ## BindGlobal( "OmegaSubgroupsByLcs", function( G ) local pcgs, first, p, field, list, max, i, pcgsN, N, hom, F, ser, specF; # catch the trivial case p := PrimePGroup( G ); pcgs := SpecialPcgs( G ); if ForAll( pcgs, x -> Order(x) = p ) then return []; fi; # set up first := LGFirst( pcgs ); field := GF(p); list := []; max := Length(pcgs); # run through lower p-central series for i in [2..Length(first)] do pcgsN := InducedPcgsByPcSequenceNC( pcgs, pcgs{[first[i]..max]} ); N := SubgroupByPcgs( G, pcgsN ); hom := NaturalHomomorphismByNormalSubgroupNC( G, N ); F := Image( hom ); specF := SpecialPcgs(F); if ForAny( specF, x -> Order(x) > p ) and Size(F) < 10000 then ser := OmegaSeries( F ); ser := List( ser, x -> PreImage( hom, x ) ); Append( list, ser ); fi; od; return list; end ); ############################################################################# ## #F MaxSubIntersections(G) ## BindGlobal( "MaxSubIntersections", function(G) local max, fp, fpset, fpbin, i, j; max := MaximalSubgroups(G); fp := List(max, IdGroup); fpset := Set(fp); fpbin := List(fpset, x -> []); for i in [1..Length(max)] do j := Position(fpset, fp[i]); Add(fpbin[j], max[i]); od; return List(fpbin, Intersection); end ); ############################################################################# ## #F PGCharSubgroups( G ) ## BindGlobal( "PGCharSubgroups", function(G) local cent, omega; cent := TwoStepCentralizersByLcs( G ); omega := OmegaSubgroupsByLcs( G ); if Size(G) <= 512 then return Union(cent, omega, MaxSubIntersections(G)); else return Union( cent, omega ); fi; end ); ############################################################################# ## #F FrattiniQuotientBase( , ) ## BindGlobal( "FrattiniQuotientBase", function( spec, U ) local r, frat, pcgs, subU, base; r := LGFirst(spec)[2]; frat := InducedPcgsByPcSequenceNC( spec, spec{[r..Length(spec)]} ); pcgs := spec mod frat; subU := Filtered(InducedPcgs(spec, U), x -> DepthOfPcElement(spec,x) ExponentsOfPcElement( pcgs, x ) ); return base; end ); ############################################################################# ## #F InitAutomorphismGroupChar( G ) ## BindGlobal( "InitAutomorphismGroupChar", function( G ) local r, p, chars, bases, S, H, A, z, spec, kern; Info( InfoAutGrp, 2, " init automorphism group : Char "); # set up r := RankPGroup( G ); p := PrimePGroup( G ); z := One(GF(p)); spec := SpecialPcgs( G ); # compute characteristic subgroups Info( InfoAutGrp, 3, " compute characteristic subgroups "); chars := PGCharSubgroups( G ); bases := List( chars, x -> FrattiniQuotientBase( spec, x ) ) * z; # compute the matrixgroup stabilising all subspaces in chain Info( InfoAutGrp, 3, " compute stabilizer "); S := StabilizingMatrixGroup( bases, r, p ); # the Frattini Quotient H := FrattiniQuotientPGroup( G ); kern := InitAgAutos( H, p ); # the aut group A := rec( ); A.glAutos := InitGlAutos( H, GeneratorsOfGroup(S) ); A.glOrder := Size(S) / Product( kern.rels ); A.glOper := GeneratorsOfGroup(S); Assert(1,IsInt(A.glOrder)); A.agAutos := kern.auts; A.agOrder := kern.rels; A.one := IdentityPGAutomorphism( H ); A.group := H; A.size := A.glOrder * Product( A.agOrder ); # try to construct perm rep NiceInitGroup( A, true ); return A; end ); ############################################################################# ## #F InitAutomorphismGroupFull( G ) ## BindGlobal( "InitAutomorphismGroupFull", function( G ) local r, p, S, H, A, kern; Info( InfoAutGrp, 2, " init automorphism group : Full "); # set up r := RankPGroup( G ); p := PrimePGroup( G ); S := GL(r, p); H := FrattiniQuotientPGroup( G ); kern := InitAgAutos( H, p ); # the aut group A := rec( ); A.glAutos := InitGlAutos( H, GeneratorsOfGroup(S) ); A.glOrder := Size(S) / Product( kern.rels ); A.glOper := GeneratorsOfGroup( S ); Assert(1,IsInt(A.glOrder)); A.agAutos := kern.auts; A.agOrder := kern.rels; A.one := IdentityPGAutomorphism( H ); A.group := H; A.size := A.glOrder * Product( A.agOrder ); # try to compute perm rep NiceInitGroup( A, false ); return A; end ); autpgrp-1.12.0/gap/initperm.gi0000644000000000000000000001257715202202400013121 0ustar00############################################################################# ## #W initperm.gi AutPGrp package Bettina Eick ## ############################################################################# ## #F Fingerprint( G, U ) ## BindGlobal( "FingerprintSmall@", function( G, U ) return Flat( [IdGroup( U ), Size(CommutatorSubgroup( G, U )) ]); end ); BindGlobal( "FingerprintMedium@", function( G, U ) local ranks, invs, comm, all, cls, fus, new; # some general stuff ranks := LGFirst( SpecialPcgs( U ) ); invs := AbelianInvariants( Centre(U) ); comm := Size( CommutatorSubgroup( G, U ) ); # use conjugacy classes all := Orbits( G, AsList(U) ); all := List( all, x -> Set(x)); cls := List( all, x -> Order(x[1]) ); Sort( cls ); return Concatenation( ranks, invs, [comm], cls ); end ); BindGlobal( "FingerprintLarge@", function( G, U ) return LGFirst( SpecialPcgs(U) ); end ); BindGlobal( "FingerprintHuge@", function( G, U ) return List( DerivedSeries(U), Size ); end ); BindGlobal( "PGFingerprint", function ( G, U ) if Size( U ) <= 256 and IsRecord( ID_AVAILABLE( Size(U) ) ) then return FingerprintSmall@( G, U ); elif Size( U ) <= 1000 then return FingerprintMedium@( G, U ); elif Size( U ) <= 2^21 then return FingerprintLarge@( G, U ); else return FingerprintHuge@( G, U ); fi; end ); # FIXME: DualBasis is not used in autpgrp; it is however # used in the sophus package. The next sophus release won't use # it anymore. But for now we keep this function here to not # break existing sophus releases... DualBasis := function( base ) local M; M := NullspaceMat( TransposedMat( base )); M := List( M, ShallowCopy ); TriangulizeMat( M ); return M; end; ############################################################################# ## #F PartitionMinimalOvergrps ( G, pcgs, norm ) ## BindGlobal( "PartitionMinimalOvergrps", function( G, pcgs, norm ) local min, done, part, i, tup, pos; Info( InfoAutGrp, 3, " computing partition "); done := []; part := []; for i in [1..Length(norm)] do Info( InfoAutGrp, 4, " start ",i); min := InducedPcgsByBasis( pcgs, [norm[i]] ); tup := PGFingerprint( G, SubgroupByPcgs( G, min ) ); pos := Position( done, tup ); if IsBool( pos ) then Add( part, [i] ); Add( done, tup ); else Add( part[pos], i ); fi; od; Sort( part, function( x, y ) return Length(x) < Length(y); end ); return part; end ); ############################################################################# ## #F PartitionStabilizer ( A, part, norm ) ## BindGlobal( "PartitionStabilizer", function( A, part, norm ) local iso, P, sub, gens, n, q; Info( InfoAutGrp, 3, " computing stabilizer of ", part); iso := ActionHomomorphism( A, norm, OnLines, "surjective" ); P := Image( iso ); # transfer size info n := DimensionOfMatrixGroup(A); q := Size(FieldOfMatrixGroup(A)); if HasIsNaturalGL(A) and IsNaturalGL(A) then SetSize(P,Size(A)/(q-1)); elif HasIsNaturalSL(A) and IsNaturalSL(A) then SetSize(P,Size(A)/Gcd(n,q-1)); fi; # loop for sub in part{[1..Length(part)-1]} do if Length( sub ) = 1 then P := Stabilizer( P, sub[1], OnPoints ); Info( InfoAutGrp, 3, " found stabilizer of size ", Size(P)); else P := Stabilizer( P, sub, OnSets ); Info( InfoAutGrp, 3, " found stabilizer of size ", Size(P)); fi; od; gens := SmallGeneratingSet( P ); # return return rec( perm := gens, mats := List( gens, x -> PreImagesRepresentative(iso,x) ), size := Size(P) ); end ); ############################################################################# ## #F AutoOfMat( mat, H ) ## BindGlobal( "AutoOfMat", function( mat, H ) local img, aut, pcgs; pcgs := Pcgs(H); img := List( mat, x -> PcElementByExponentsNC(pcgs, x) ); aut := PGAutomorphism( H, pcgs, img ); return aut; end ); ############################################################################# ## #F InitAutomorphismGroupOver( G ) ## InstallGlobalFunction( InitAutomorphismGroupOver, function( G ) local r, p, pcgsG, pcgsN, pcgs, base, V, norm, part, stab, H, kern, A; Info( InfoAutGrp, 2, " initialize automorphism group: Over "); # set up r := RankPGroup( G ); p := PrimePGroup( G ); # pgcs'se pcgsG := SpecialPcgs(G); pcgsN := InducedPcgsByPcSequenceNC( pcgsG, pcgsG{[r+1..Length(pcgsG)]} ); pcgs := pcgsG mod pcgsN; # get partition stabilizer base := IdentityMat( r, GF(p) ); V := GF(p)^r; norm := NormedRowVectors( V ); part := PartitionMinimalOvergrps( G, pcgs, norm ); stab := PartitionStabilizer( GL( r, p ), part, norm ); # get quotient H := FrattiniQuotientPGroup( G ); kern := InitAgAutos( H, p ); # create aut grp A := rec(); A.glAutos := List( stab.mats, x -> AutoOfMat( x, H ) ); A.glOrder := stab.size; A.glOper := ShallowCopy( stab.perm ); A.agAutos := kern.auts; A.agOrder := kern.rels; A.one := IdentityPGAutomorphism(H); A.group := H; A.size := A.glOrder * Product( A.agOrder ); # try to construct solvable normal subgroup NiceInitGroup( A, true ); return A; end); autpgrp-1.12.0/gap/matrix.gi0000644000000000000000000000641315202202400012566 0ustar00############################################################################# ## #W matrix.gi AutPGrp package Bettina Eick ## ############################################################################# ## #F ChainByCollection( bases, full ) ## BindGlobal( "ChainByCollection", function( bases, full ) local chain, base, tmp, i, V, W, int; chain := [ full, [] ]; for base in bases do tmp := []; for i in [2..Length(chain)] do V := chain[i-1]; W := chain[i]; if Length( V ) > Length( W ) + 1 then int := SumIntersectionMat( base, V )[2]; int := SumIntersectionMat( int, W )[1]; if Length( int ) < Length( V ) and Length( int ) > Length( W ) then AddSet( tmp, int ); fi; fi; od; Append( chain, tmp ); Sort( chain, function( x, y ) return Length(x)>Length(y); end ); od; return chain; end ); ############################################################################# ## #F StabilizingMatrixGroup( list of bases ) . . . . . compute stabilizer in GL ## BindGlobal( "StabilizingMatrixGroup", function( bases, d, p ) local full, chain, mats, l, size, i, j, n, mat, G, rel, field; # general set up full := IdentityMat( d, GF(p) ); chain := ChainByCollection( bases, full ); field := GF(p); # loop over chain mats := []; l := 0; size := 1; for i in [2..Length(chain)] do n := Length( chain[i-1] ) - Length( chain[i] ); for j in [1..n] do size := size * (p^(d-l) - p^(d-l-j)); od; # Construct the generators. if p = 2 then if n >= 2 then mat := IdentityMat(d, field); mat[l+1][l+n] := One( field ); mat[l+1][l+1] := Zero( field ); for j in [ 2 .. n ] do mat[l+j][l+j-1] := One( field ); mat[l+j][l+j] := Zero( field ); od; Add( mats, mat ); mat := IdentityMat(d, field); mat[l+1][l+2] := One( field ); Add( mats, mat ); fi; else mat := IdentityMat(d, field); mat[l+1][l+1] := PrimitiveRoot( field ); Add( mats, mat ); if n >= 2 then mat := IdentityMat(d, field); mat[l+1][l+1] := -One( field ); mat[l+1][l+n] := One( field ); for j in [ 2 .. n ] do mat[l+j][l+j-1] := -One( field ); mat[l+j][l+j] := Zero( field ); od; Add( mats, mat ); fi; fi; l := l + n; if l < d then mat := IdentityMat(d, field); mat[l][l+1] := One( field ); Add( mats, mat ); fi; od; # change basis of mats rel := List( [2..Length(chain)], i -> BaseSteinitzVectors( chain[i-1], chain[i] ).factorspace ); rel := Concatenation( rel ); mats := List( mats, x -> rel^-1 * x * rel ); G := Group( mats, IdentityMat( d, field ) ); SetSize( G, size ); return G; end ); autpgrp-1.12.0/gap/matrstab.gi0000644000000000000000000001604015202202400013074 0ustar00############################################################################# ## #W matrstab.gi AutPGrp package Bettina Eick ## ############################################################################# ## #F LabelOfBasis( base, info ) . . . . . . . . . . . . . . . . . label to basis ## BindGlobal( "LabelOfBasis", function( base, info ) local pt, j, i; # compute pt pt := List( [1..info.l], x -> 0 ); for j in [1..info.l] do for i in [1..info.d] do if base[j][i] <> Zero( info.field ) then pt[j] := pt[j] + IntFFE( base[j][i] ) * info.power[i]; fi; od; od; # create label return pt; end ); ############################################################################# ## #F CoeffsInt( int, d, power ) ## BindGlobal( "CoeffsInt", function( int, d, power) local i, exp; i := d; exp := List( power, y -> 0 ); while int <> 0 do exp[i] := QuoInt (int, power[i]); int := RemInt (int, power[i]); i := i - 1; od; return exp; end ); ############################################################################# ## #F BasisOfLabel( lab, info ) . . . . . . . . . . . . . . . . . basis of label ## BindGlobal( "BasisOfLabel", function ( lab, info ) return List( [1..info.l], x -> CoeffsInt( lab[x], info.d, info.power ) ); end ); ############################################################################# ## #F OnLabel( lab, mat, info ) . . . . . . . . . . . . . . . .operation on label ## BindGlobal( "OnLabel", function( lab, mat, info ) local v, w; v := BasisOfLabel( lab, info ); w := v * mat; TriangulizeMat( w ); return LabelOfBasis( w, info ); end ); ############################################################################# ## #F OnBasis( base, mat, info ) . . . . . . . . . . . . . . .operation on basis ## BindGlobal( "OnBasis", function( base, mat, info ) base := base * mat; if not IsMutable(base) then base:=ShallowCopy(base); fi; TriangulizeMat( base ); return base; end ); ############################################################################# ## #F InducedActionByHom( hom, mat ) ## BindGlobal( "InducedActionByHom", function( hom, mat ) local ind, baseI, baseS, b, e, f, g; # catch special case for efficiency if mat = 1 then return mat; fi; # otherwise compute ind := []; baseI := Basis( ImagesSource( hom ) ); baseS := Basis( Source( hom ) ); for b in baseI do e := PreImagesRepresentative( hom, b ); f := e * mat; g := ImagesRepresentative( hom, f ); Add( ind, Coefficients( baseI, g ) ); od; # again catch a special case for efficiency if ind = ind^0 then return 1; fi; # otherwise return return ImmutableMatrix( Characteristic(ind[1][1]), ind); end ); ############################################################################# ## #F ActionOnDual( mat ) ## BindGlobal( "ActionOnDual", function( mat ) local new; if mat = 1 then return 1; fi; new := TransposedMat( mat )^-1; return ImmutableMatrix( Characteristic(new[1][1]), new); end ); ############################################################################# ## #F PGMatrixOrbitStabilizer( A, V, W, R ) ## BindGlobal( "PGMatrixOrbitStabilizer", function( A, V, W, R ) local VS, WS, RS, hom, pt, glMats, agMats, lab, info, l, d, oper; # set up factor space VS := VectorSpace( A.field, V, "basis" ); WS := VectorSpace( A.field, W, Zero(VS), "basis" ); RS := VectorSpace( A.field, R, "basis" ); hom := NaturalHomomorphismBySubspaceOntoFullRowSpace( VS, WS ); pt := ShallowCopy( Basis( ImagesSet( hom, RS ) ) ); TriangulizeMat( pt ); # set up action glMats := List( A.glAutos, x -> InducedActionByHom( hom, x!.mat ) ); agMats := List( A.agAutos, x -> InducedActionByHom( hom, x!.mat ) ); # check if the dual is better if Length(pt) > Length(pt[1])/2 then pt := VectorSpace( A.field, pt, "basis" ); pt := OrthogonalSpaceInFullRowSpace( pt ); pt := ShallowCopy( Basis( pt ) ); TriangulizeMat( pt ); glMats := List( glMats, x -> ActionOnDual( x ) ); agMats := List( agMats, x -> ActionOnDual( x ) ); fi; # use labels - if desired if USE_LABEL then d := Length( pt[1] ); l := Length( pt ); info := rec( power := List( [1..d], x -> A.prime^(x-1) ), field := A.field, l := l, d := d ); lab := LabelOfBasis( pt, info ); PGHybridOrbitStabilizer( A, glMats, agMats, lab, OnLabel, info ); else pt := ImmutableMatrix( A.field, pt ); PGHybridOrbitStabilizer( A, glMats, agMats, pt, OnBasis, rec() ); fi; end ); ############################################################################# ## #F CheckStab(A, pt) ## BindGlobal( "CheckAgStab", function( A, pt ) local g, s, c; for g in A.agAutos do for s in pt do c := SolutionMat(pt, s*g!.mat); if IsBool(c) then return false; fi; od; od; return true; end ); BindGlobal( "CheckGlStab", function( A, pt ) local g, s, c; for g in A.glAutos do for s in pt do c := SolutionMat(pt, s*g!.mat); if IsBool(c) then return false; fi; od; od; return true; end ); ############################################################################# ## #F SumMat( mat1, mat2 ) ## BindGlobal( "SumMat@" ,function( mat1, mat2 ) local tmp; tmp := Concatenation( mat1, mat2 ); tmp := EcheloniseMat( tmp ); TriangulizeMat(tmp); return tmp; end ); ############################################################################# ## #F PGOrbitStabilizerBySeries( A, baseU, chop ) ## BindGlobal( "PGOrbitStabilizerBySeries", function( A, baseU, chop ) local s, U, T, i, S, R, j, V, W, B; s := Length(chop); U := baseU; # loop upwards over series T := []; for i in [1..s-1] do S := ShallowCopy(T); T := SumIntersectionMat( U, chop[i+1] )[2]; if Length( S ) < Length( T ) then # loop downwards over series R := chop[i+1]; for j in Reversed( [1..i] ) do V := ShallowCopy( R ); R := SumMat@( T, chop[j] ); if Length( R ) < Length( V ) then W := SumMat@( S, chop[j] ); if Length( R ) > Length( W ) then PGMatrixOrbitStabilizer( A, V, W, R ); if CHECK then if not CheckAgStab(A, R) then Error("ag stab wrong "); fi; if not CheckGlStab(A, R) then Error("gl stab wrong "); fi; fi; else Info( InfoAutGrp, 4, " skip trivial factor"); fi; fi; od; fi; od; end ); autpgrp-1.12.0/gap/nicestab.gi0000644000000000000000000001411615202202400013051 0ustar00############################################################################# ## #W nicestab.gi AutPGrp package Bettina Eick ## ############################################################################# ## #F GLMatrix( aut ) ## BindGlobal( "GLMatrix", function( aut ) local G, r, pcgsG, pcgsN, pcgsF, mat; G := Source( aut ); r := RankPGroup( G ); pcgsG := Pcgs( G ); pcgsN := InducedPcgsByPcSequenceNC( pcgsG, pcgsG{[r+1..Length(pcgsG)]} ); pcgsF := pcgsG mod pcgsN; mat := List(pcgsF, x->ExponentsOfPcElement(pcgsF,ImagesRepresentative(aut,x))); return mat; end ); ############################################################################# ## #F TryPermOperation( A ) . . . . . . . . resets A.glOper to perms or nothing ## BindGlobal( "TryPermOperation", function( A ) local G, r, p, base, V, norm, f, M, iso, P; # if its too big, then don't try. G := A.group; r := RankPGroup( G ); p := PrimePGroup( G ); if (p^r - 1) / (p - 1) > 1100 then Unbind( A.glOper ); return; fi; Info( InfoAutGrp, 4, " compute perm rep"); # now we compute it base := IdentityMat( r, GF(p) ); V := GF(p)^r; norm := NormedRowVectors( V ); f := function( pt, a ) return NormedRowVector( pt * a ); end; M := Group( A.glOper, base ); iso := ActionHomomorphism( M, norm, f ); P := Image( iso ); # and get images A.glOper := GeneratorsOfGroup( P ); end ); ############################################################################# ## #F ReducePermOper( A ) ## BindGlobal( "ReducePermOper", function(A) local P, B, phom, gens, auts; Info( InfoAutGrp, 4, " reduce permutation operation"); # get perm group P := Group( A.glOper, ()); B := Group( A.glAutos ); SetSize( P, A.glOrder ); # mapping from A to permgroup P phom := GroupHomomorphismByImagesNC( B, P, A.glAutos, A.glOper ); gens := SmallGeneratingSet(P); gens := Filtered( gens, x -> Order(x) > 1 ); auts := List( gens, x -> PreImagesRepresentative( phom, x ) ); A.glAutos := auts; A.glOper := gens; Info( InfoAutGrp, 4, " factor has size ",A.glOrder," and ", Length(A.glAutos)," generators"); end ); ############################################################################# ## #F TrySolvableSubgroup( A ) ## BindGlobal( "TrySolvableSubgroup", function( A ) local P, B, N, pcgs, phom, nhom, G, auts, gens; Info( InfoAutGrp, 4, " try solvable normal subgroup"); # get perm group P := Group( A.glOper, ()); B := Group( A.glAutos ); SetSize( P, A.glOrder ); # mapping from A to permgroup P phom := GroupHomomorphismByImagesNC( B, P, A.glAutos, A.glOper ); # get normal subgroup N := SolvableRadical( P ); pcgs := Pcgs( N ); Info( InfoAutGrp, 4, " found pcgs of length ", Length(pcgs)); if Length(pcgs) = 0 then return; fi; # construct factor nhom := NaturalHomomorphismByNormalSubgroupNC( P, N ); G := ImagesSource( nhom ); # get ag part auts := List( pcgs, x -> PreImagesRepresentative( phom,x ) ); A.agAutos := Concatenation( auts, A.agAutos ); A.agOrder := Concatenation( RelativeOrders( pcgs ), A.agOrder ); # and the factor phom := phom * nhom; gens := SmallGeneratingSet( G ); gens := Filtered( gens, x -> Order(x) > 1 ); auts := List( gens, x -> PreImagesRepresentative( phom, x ) ); A.glAutos := auts; A.glOrder := Size( G ); A.glOper := gens; Info( InfoAutGrp, 4, " factor has size ",A.glOrder," and ", Length(A.glAutos)," generators"); end ); ############################################################################# ## #F NiceInitGroup( A, "init" ) . . . . . . . . flag indicates the init method ## ## try to compute a perm rep and, if successful, compute N. ## BindGlobal( "NiceInitGroup", function( A, flag ) Info( InfoAutGrp, 3, " nice init group"); # catch a trivial case if Length( A.glOper ) = 0 then Unbind( A.glOper ); return; fi; # try to compute perm-oper, if possible if IsMatrix( A.glOper[1] ) then TryPermOperation( A ); return; fi; # finally, if a perm oper is given, then try to enlarge agAutos if IsPerm( A.glOper[1] ) and flag then if REDU_OPER then ReducePermOper( A ); else TrySolvableSubgroup( A ); fi; fi; end ); ############################################################################# ## #F NiceHybridGroup( A ) ## BindGlobal( "NiceHybridGroup", function( A ) local mats, done, auts, i, mat, aut, fac, rels, e, f; # catch the trivial cases if Length( A.glAutos ) = 0 or A.glOrder = 1 then Unbind( A.glOper ); A.glautos := []; return; fi; # in case we have a perm rep if IsBound( A.glOper ) then Info( InfoAutGrp, 3, " nice stabilizer with perm rep"); if REDU_OPER then ReducePermOper(A); else TrySolvableSubgroup( A ); fi; return; fi; Info( InfoAutGrp, 3, " nice stabilizer with matr rep"); # otherwise mats := List( A.glAutos, x -> GLMatrix( x ) * One( A.field ) ); done := [mats[1]^0]; auts := []; for i in [1..Length(mats)] do if not mats[i] in done then Add( auts, A.glAutos[i] ); Add( done, mats[i] ); fi; od; # catch a special case if Length( auts ) = 1 then mat := done[2]; aut := auts[1]; fac := Factors( Order( mat ) ); rels := []; auts := []; e := 1; for f in fac do Add( auts, aut^e ); e := e * f; od; A.agAutos := Concatenation( auts, A.agAutos ); A.agOrder := Concatenation( fac, A.agOrder ); A.glAutos := []; A.glOrder := 1; else A.glAutos := auts; fi; Info( InfoAutGrp, 4, " factor has size ",A.glOrder," and"); Info( InfoAutGrp, 4, Length(A.glAutos)," generators"); end ); autpgrp-1.12.0/gap/orbstab.gi0000644000000000000000000000507115202202400012715 0ustar00############################################################################# ## #W orbstab.gi AutPGrp package Bettina Eick ## ############################################################################# ## #F BasesCompositionSeriesThrough( M, base ) ## BindGlobal( "BasesCompositionSeriesThrough", function( M, base ) local full, chop, indu, smll, i, facb; full := IdentityMat( M.dimension, M.field ); chop := [[]]; # chop N if Length( base ) > 0 then indu := MTX.InducedActionSubmoduleNB( M, base ); smll := MTX.BasesCompositionSeries( indu ); for i in [2..Length( smll )] do smll[i] := smll[i] * base; Add( chop, EcheloniseMat( smll[i] ) ); od; fi; # chop M/N if Length( base ) < Length( full ) then indu := MTX.InducedActionFactorModuleWithBasis( M, base ); facb := indu[2]; indu := indu[1]; smll := MTX.BasesCompositionSeries( indu ); for i in [2..Length( smll )] do smll[i] := smll[i] * facb; Append( smll[i], base ); Add( chop, EcheloniseMat( smll[i] ) ); od; fi; return chop; end ); ############################################################################# ## #F PGOrbitStabilizer( , , , ) ## InstallGlobalFunction( PGOrbitStabilizer, function( A, baseU, baseN, interrupt ) local u, n, l, baseM, str, glMats, agMats, mats, modu, chop; # set up and catch some trivial cases u := Length( baseU ); n := Length( baseN ); if u = 0 or ( A.glOrder = 1 and Length( A.agOrder ) = 0 ) then return; fi; l := Length( baseU[1] ); baseM := IdentityMat( l, A.field ); if l = u then return; fi; # print some info Info( InfoAutGrp, 3, " dim U = ",u, " dim N = ",n, " dim M = ",l ); # check interrupt if interrupt then str := Interrupt("chop M/N and N: (y/n)"); if str = "y" then CHOP_MULT := true; elif str = "n" then CHOP_MULT := false; else Print("not a valid argument"); return; fi; fi; # compute series glMats := List( A.glAutos, x -> x!.mat ); agMats := List( A.agAutos, x -> x!.mat ); mats := Filtered( Concatenation( glMats, agMats ), x -> x<>1 ); modu := GModuleByMats( mats, l, A.field ); chop := [[], baseN, baseM]; if CHOP_MULT then chop := BasesCompositionSeriesThrough( modu, chop[2] ); fi; PGOrbitStabilizerBySeries( A, baseU, chop ); end ); autpgrp-1.12.0/gap/pcpres.gi0000644000000000000000000001364415202202400012562 0ustar00############################################################################# ## #W autpgrp.gi Bettina Eick ## #W The input to the following function is the output of #W AutomorphismGroupPGroup( G ) of the autpgrp package. ## #W The function computes a pc presentation for the solvable subgroup #W of Aut(G) defined by the agAutos of the input. ## ############################################################################# ## #F PcgsInfoAutPGroup( A ) . . . . . . . . . . . . . . . set up info on layers ## BindGlobal( "PcgsInfoAutPGroup", function( A ) local G, d, p, f, spec, gens, layer, bases, i, auto, imgs, base, j, s, n, B, P, M, pcgs, e; # set up G := A.group; d := RankPGroup(G); p := PrimePGroup(G); f := GF(p); spec := SpecialPcgs( G ); gens := spec{[1..d]}; # catch layers and bases layer := []; bases := []; for i in [1..Length(A.agAutos)] do auto := A.agAutos[i]; imgs := List( gens, x -> ExponentsOfPcElement( spec, x^auto ) ); base := imgs{[1..d]}{[1..d]}; # if base <> idmat, then the FrattiniFactor is permuted if base <> IdentityMat(d) then layer[i] := 1; bases[i] := base * One(f); else for j in [1..d] do imgs[j][j] := 0; od; e := Minimum( List( imgs, PositionNonZero ) ); j := LGLayers( spec )[e]; s := LGFirst( spec )[j]; n := LGFirst( spec )[j+1]; base := imgs{[1..d]}{[s..n-1]}; layer[i] := j; bases[i] := Concatenation( base ) * One(f); fi; od; # set up B := rec(); B.agAutos := A.agAutos; B.agOrder := A.agOrder; B.bases := bases; B.layer := layer; B.group := G; B.field := f; B.spec := spec; B.gens := gens; B.rank := d; # the first layer is particularly nasty j := PositionNot( layer, 1 ); if j > 1 then M := Group( bases{[1..j-1]}, IdentityMat(d, f) ); B.agHomom := IsomorphismPermGroup(M); P := Image(B.agHomom); pcgs := List( bases{[1..j-1]}, x -> Image(B.agHomom,x) ); pcgs := PcgsByPcSequence( FamilyObj(One(P)), pcgs ); SetRelativeOrders( pcgs, B.agOrder ); B.agTopfc := pcgs; fi; return B; end ); ############################################################################# ## #F ExponentsAutPGroup( B, auto ) . . . . . . . . . . .compute exponent vector ## BindGlobal( "ExponentsAutPGroup", function( B, auto ) local exps, imgs, perm, news, tmpa, j, e, s, n, subs, base; exps := List( B.agAutos, x -> 0 ); imgs := List( B.gens, x -> ExponentsOfPcElement( B.spec, x^auto ) ); base := imgs{[1..B.rank]}{[1..B.rank]}; # if base <> idmat, then the FrattiniFactor is permuted if base <> IdentityMat(B.rank) then base := base * One(B.field); perm := Image( B.agHomom, base ); news := ExponentsOfPcElement( B.agTopfc, perm ); exps{[1..Length(news)]} := news; tmpa := MappedVector( news, B.agAutos{[1..Length(news)]} ); auto := tmpa^-1 * auto; fi; imgs := List( B.gens, x -> ExponentsOfPcElement( B.spec, x^auto ) ); for j in [1..B.rank] do imgs[j][j] := 0; od; e := Minimum( List( imgs, PositionNonZero ) ); while e <= Length( B.spec ) do # determine base for auto j := LGLayers( B.spec )[e]; s := LGFirst( B.spec )[j]; n := LGFirst( B.spec )[j+1]; base := Concatenation( imgs{[1..B.rank]}{[s..n-1]} ) * One(B.field); # determine bases for layer s := PositionSorted( B.layer, j ); n := PositionSorted( B.layer, j+1 ); subs := B.bases{[s..n-1]}; # solve and set exponents news := IntVecFFE( SolutionMat( subs, base ) ); exps{[s..n-1]} := news; # divide off and reset tmpa := MappedVector( news, B.agAutos{[s..n-1]} ); auto := tmpa^-1 * auto; imgs := List( B.gens, x -> ExponentsOfPcElement( B.spec, x^auto ) ); for j in [1..B.rank] do imgs[j][j] := 0; od; e := Minimum( List( imgs, PositionNonZero ) ); od; return exps; end ); ############################################################################# ## #F ImageAutPGroup( B, G, auto ) . . . . . . . . . . . . . . image in pc group ## InstallGlobalFunction( ImageAutPGroup, function( B, G, auto ) local exp; exp := ExponentsAutPGroup( B, auto ); return MappedVector( exp, GeneratorsOfGroup( G ) ); end); ############################################################################# ## #F PcGroupAutPGroup(A) . . . . . . . . . . . . . . . . . . . compute pc group ## InstallGlobalFunction( PcGroupAutPGroup, function( A ) local B, C, m, F, f, r, i, j, o, w, e; B := PcgsInfoAutPGroup( A ); m := Length( B.agAutos ); F := FreeGroup( m ); f := GeneratorsOfGroup(F); r := []; for i in [1..m] do for j in [i..m] do if i = j then o := B.agOrder[i]; w := B.agAutos[i]^o; e := ExponentsAutPGroup( B, w ); Add( r, f[i]^o / MappedVector( e, f ) ); else w := B.agAutos[j]^B.agAutos[i]; e := ExponentsAutPGroup( B, w ); Add( r, f[j]^f[i] / MappedVector( e, f ) ); fi; od; od; C := PcGroupFpGroup( F/r ); C!.autos := B.agAutos; C!.autrec := B; return C; end ); ############################################################################# ## #F InnerAutGroupPGroup( C ). . . . . . . . . . . . embed Inn(G) into pc group ## InstallGlobalFunction( InnerAutGroupPGroup, function( C ) local B, G, gens, auts, imgs, I; B := C!.autrec; G := B.group; gens := Pcgs(G); auts := List(gens, x -> PGAutomorphism(G, gens, List(gens, y->y^x))); imgs := List( auts, x -> ImageAutPGroup( B, C, x ) ); I := Subgroup(C, imgs ); return I; end); autpgrp-1.12.0/init.g0000644000000000000000000000031515202202400011300 0ustar00############################################################################# ## #W init.g AutPGrp package Bettina Eick ## ReadPackage( "autpgrp", "gap/autos.gd" ); autpgrp-1.12.0/makedoc.g0000644000000000000000000000123615202202400011743 0ustar00############################################################################# ## ## makedoc.g ## Copyright (C) 2025 James D. Mitchell ## ## Licensing information can be found in the README file of this package. ## ############################################################################# ## LoadPackage("AutoDoc"); includes := [ "intro.xml", "method.xml", "underl.xml", "influen.xml", "additional.xml", ]; # The actual call to AutoDoc AutoDoc(rec( autodoc := rec(scan_dirs := []), gapdoc := rec(files := []), extract_examples := true, scaffold := rec(includes := includes) )); QuitGap(); autpgrp-1.12.0/read.g0000644000000000000000000000151215202202400011250 0ustar00############################################################################# ## #W read.g AutPGrp package Bettina Eick ## if not IsBound(SolvableRadical) then # for backwards compatibility with GAP versions before 4.12 BindGlobal( "SolvableRadical", RadicalGroup ); fi; ReadPackage( "autpgrp", "gap/general.gi"); ReadPackage( "autpgrp", "gap/autoops.gi"); ReadPackage( "autpgrp", "gap/matrix.gi"); ReadPackage( "autpgrp", "gap/nicestab.gi"); ReadPackage( "autpgrp", "gap/initmat.gi"); ReadPackage( "autpgrp", "gap/initperm.gi"); ReadPackage( "autpgrp", "gap/hybrstab.gi"); ReadPackage( "autpgrp", "gap/matrstab.gi"); ReadPackage( "autpgrp", "gap/orbstab.gi"); ReadPackage( "autpgrp", "gap/autos.gi"); ReadPackage( "autpgrp", "gap/pcpres.gi"); ReadPackage( "autpgrp", "gap/countcl.gi"); autpgrp-1.12.0/tst/0000755000000000000000000000000015202202400011000 5ustar00autpgrp-1.12.0/tst/autpgrp01.tst0000644000000000000000000000356215202202400013365 0ustar00# AutPGrp, chapter 2 # # DO NOT EDIT THIS FILE - EDIT EXAMPLES IN THE SOURCE INSTEAD! # # This file has been generated by AutoDoc. It contains examples extracted from # the package documentation. Each example is preceded by a comment which gives # the name of a GAPDoc XML file and a line range from which the example were # taken. Note that the XML file in turn may have been generated by AutoDoc # from some other input. # gap> START_TEST("autpgrp01.tst"); # doc/method.xml:36-48 gap> LoadPackage("autpgrp", false); true gap> G := PcGroupCode(619031068735, 32); # SmallGroup( 32, 15 ); gap> SetInfoLevel( InfoAutGrp, 1 ); gap> AutomorphismGroup(G); #I step 1: 2^2 -- init automorphisms #I step 2: 2^2 -- aut grp has size 2 #I step 3: 2^1 -- aut grp has size 32 #I final step: convert # doc/method.xml:56-84 gap> G := DihedralGroup( IsPermGroup, 2^5 );; gap> IsPGroup(G); true gap> CanEasilyComputePcgs(G); true gap> IsFinite(G); true gap> A := AutomorphismGroup(G); #I step 1: 2^2 -- init automorphisms #I step 2: 2^1 -- aut grp has size 2 #I step 3: 2^1 -- aut grp has size 8 #I step 4: 2^1 -- aut grp has size 32 #I final step: convert gap> A.1; Pcgs([ ( 2,16)( 3,15)( 4,14)( 5,13)( 6,12)( 7,11)( 8,10), ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16), ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16), ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16), ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ]) -> [ ( 1, 2)( 3,16)( 4,15)( 5,14)( 6,13)( 7,12)( 8,11)( 9,10), ( 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16), ( 1, 3, 5, 7, 9,11,13,15)( 2, 4, 6, 8,10,12,14,16), ( 1, 5, 9,13)( 2, 6,10,14)( 3, 7,11,15)( 4, 8,12,16), ( 1, 9)( 2,10)( 3,11)( 4,12)( 5,13)( 6,14)( 7,15)( 8,16) ] gap> Order(A.1); 16 # gap> STOP_TEST("autpgrp01.tst", 1); autpgrp-1.12.0/tst/autpgrp02.tst0000644000000000000000000000507415202202400013366 0ustar00# AutPGrp, chapter 3 # # DO NOT EDIT THIS FILE - EDIT EXAMPLES IN THE SOURCE INSTEAD! # # This file has been generated by AutoDoc. It contains examples extracted from # the package documentation. Each example is preceded by a comment which gives # the name of a GAPDoc XML file and a line range from which the example were # taken. Note that the XML file in turn may have been generated by AutoDoc # from some other input. # gap> START_TEST("autpgrp02.tst"); # doc/underl.xml:90-122 gap> LoadPackage("autpgrp", false); true gap> H := PcGroupCode(297368117289422176, 729); # SmallGroup (729, 34); gap> A := AutomorphismGroupPGroup(H); #I step 1: 3^2 -- init automorphisms #I step 2: 3^1 -- aut grp has size 8 #I step 3: 3^2 -- aut grp has size 72 #I step 4: 3^1 -- aut grp has size 5832 #I final step: convert rec( agAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f2, f1, f3^2, f5^2, f4^2, f6^2 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2^2, f3^2*f5, f4^2*f6, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1^2, f2^2, f3*f4^2*f5^2*f6, f4^2*f6, f5^2*f6, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f3, f2, f3*f5^2, f4*f6^2, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f3, f3*f4, f4, f5*f6, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f4, f2, f3*f6^2, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f4, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f5, f2, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f5, f3*f6, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f6, f2, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f6, f3, f4, f5, f6 ] ], agOrder := [ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 ], glAutos := [ ], glOper := [ ], glOrder := 1, group := , one := IdentityMapping( ), size := 52488 ) gap> ConvertHybridAutGroup( A ); # doc/underl.xml:132-144 gap> H := PcGroupCode(297368117289422176, 729);; # SmallGroup (729, 34); gap> A := AutomorphismGroupPGroup(H);; #I step 1: 3^2 -- init automorphisms #I step 2: 3^1 -- aut grp has size 8 #I step 3: 3^2 -- aut grp has size 72 #I step 4: 3^1 -- aut grp has size 5832 #I final step: convert gap> B := PcGroupAutPGroup( A ); gap> I := InnerAutGroupPGroup( B ); Group([ f5, f4^2*f8, f6^2*f9^2, f11^2, f10^2, of ... ]) # gap> STOP_TEST("autpgrp02.tst", 1); autpgrp-1.12.0/tst/manual.example-2.tst0000644000000000000000000000241615202202400014605 0ustar00gap> START_TEST(""); # gap> SetInfoLevel( InfoAutGrp, 1 ); # gap> G := PcGroupCode(619031068735, 32); # SmallGroup( 32, 15 ); gap> AutomorphismGroup(G); #I step 1: 2^2 -- init automorphisms #I step 2: 2^2 -- aut grp has size 2 #I step 3: 2^1 -- aut grp has size 32 #I final step: convert gap> G := DihedralGroup( IsPermGroup, 2^5 );; gap> IsPGroup(G); true gap> CanEasilyComputePcgs(G); true gap> IsFinite(G); true gap> A := AutomorphismGroup(G); #I step 1: 2^2 -- init automorphisms #I step 2: 2^1 -- aut grp has size 2 #I step 3: 2^1 -- aut grp has size 8 #I step 4: 2^1 -- aut grp has size 32 #I final step: convert gap> A.1; Pcgs([ (2,16)(3,15)(4,14)(5,13)(6,12)(7,11)(8,10), (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), (1,3,5,7,9,11,13,15)(2,4,6,8,10, 12,14,16), (1,5,9,13)(2,6,10,14)(3,7,11,15)(4,8,12,16), (1,9)(2,10)(3,11)(4,12)(5,13)(6,14)(7,15)(8,16) ]) -> [ (1,2)(3,16)(4,15)(5,14)(6,13)(7,12)(8,11)(9,10), (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), (1,3,5,7,9,11,13,15)(2,4,6,8,10, 12,14,16), (1,5,9,13)(2,6,10,14)(3,7,11,15)(4,8,12,16), (1,9)(2,10)(3,11)(4,12)(5,13)(6,14)(7,15)(8,16) ] gap> Order(A.1); 16 # gap> STOP_TEST( "" ,1); autpgrp-1.12.0/tst/manual.example-3.tst0000644000000000000000000000413215202202400014603 0ustar00gap> START_TEST(""); # gap> SetInfoLevel( InfoAutGrp, 1 ); # gap> H := PcGroupCode(297368117289422176, 729); # SmallGroup(729, 34); gap> A := AutomorphismGroupPGroup(H); #I step 1: 3^2 -- init automorphisms #I step 2: 3^1 -- aut grp has size 8 #I step 3: 3^2 -- aut grp has size 72 #I step 4: 3^1 -- aut grp has size 5832 #I final step: convert rec( agAutos := [ Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f2, f1, f3^2, f5^2, f4^2, f6^2 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2^2, f3^2*f5, f4^2*f6, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1^2, f2^2, f3*f4^2*f5^2*f6, f4^2*f6, f5^2*f6, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f3, f2, f3*f5^2, f4*f6^2, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f3, f3*f4, f4, f5*f6, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f4, f2, f3*f6^2, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f4, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f5, f2, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f5, f3*f6, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1*f6, f2, f3, f4, f5, f6 ], Pcgs([ f1, f2, f3, f4, f5, f6 ]) -> [ f1, f2*f6, f3, f4, f5, f6 ] ], agOrder := [ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 ], glAutos := [ ], glOper := [ ], glOrder := 1, group := , one := IdentityMapping( ), size := 52488 ) gap> ConvertHybridAutGroup( A ); gap> H := PcGroupCode(297368117289422176, 729);; # SmallGroup(729, 34); gap> A := AutomorphismGroupPGroup(H);; #I step 1: 3^2 -- init automorphisms #I step 2: 3^1 -- aut grp has size 8 #I step 3: 3^2 -- aut grp has size 72 #I step 4: 3^1 -- aut grp has size 5832 #I final step: convert gap> B := PcGroupAutPGroup( A ); gap> I := InnerAutGroupPGroup( B ); Group([ f5, f4^2*f8, f6^2*f9^2, f11^2, f10^2, of ... ]) # gap> STOP_TEST( "" ,1); autpgrp-1.12.0/tst/more.tst0000644000000000000000000001315715202202400012505 0ustar00gap> START_TEST("more.tst"); gap> SetInfoLevel( InfoAutGrp, 1 ); # # # gap> G:= PcGroupCode(9219, 16); # SmallGroup(16,2); gap> StructureDescription(G); "C4 x C4" # gap> A := AutomorphismGroupPGroup(G);; #I step 1: 2^2 -- init automorphisms #I step 2: 2^2 -- aut grp has size 6 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 2, 2 ] 6 96 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Full");; #I step 1: 2^2 -- init automorphisms #I step 2: 2^2 -- aut grp has size 6 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 2, 2 ] 6 96 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Over");; #I step 1: 2^2 -- init automorphisms #I step 2: 2^2 -- aut grp has size 6 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 2, 2, 2, 3 ] 1 96 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Char");; #I step 1: 2^2 -- init automorphisms #I step 2: 2^2 -- aut grp has size 6 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 2, 2 ] 6 96 gap> ConvertHybridAutGroup( A ); # # # gap> G:= PcGroupCode(17734058326, 32); # SmallGroup(32,50); # gap> A := AutomorphismGroupPGroup(G);; #I step 1: 2^4 -- init automorphisms #I step 2: 2^1 -- aut grp has size 120 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 2, 2 ] 120 1920 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Full");; #I step 1: 2^4 -- init automorphisms #I step 2: 2^1 -- aut grp has size 20160 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 2, 2 ] 120 1920 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Over");; #I step 1: 2^4 -- init automorphisms #I step 2: 2^1 -- aut grp has size 120 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 2, 2 ] 120 1920 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Char");; #I step 1: 2^4 -- init automorphisms #I step 2: 2^1 -- aut grp has size 20160 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 2, 2 ] 120 1920 gap> ConvertHybridAutGroup( A ); # # # gap> G := PcGroupCode(16385, 3 ^ 5); # SmallGroup(3^5, 61); gap> StructureDescription(G); "C9 x C3 x C3 x C3" # gap> A := AutomorphismGroupPGroup(G);; #I step 1: 3^4 -- init automorphisms #I step 2: 3^1 -- aut grp has size 606528 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 3, 3, 3, 3, 3, 3, 3 ] 5616 49128768 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Full");; #I step 1: 3^4 -- init automorphisms #I step 2: 3^1 -- aut grp has size 24261120 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 3, 3, 3, 3, 3, 3, 3 ] 5616 49128768 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Over");; #I step 1: 3^4 -- init automorphisms #I step 2: 3^1 -- aut grp has size 606528 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 3, 3, 3, 3, 3, 3, 3 ] 5616 49128768 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Char");; #I step 1: 3^4 -- init automorphisms #I step 2: 3^1 -- aut grp has size 606528 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 3, 3, 3, 3 ] 303264 49128768 gap> ConvertHybridAutGroup( A ); # # # gap> G := PcGroupCode(16400, 11 ^ 5); # SmallGroup(11^5, 81); gap> StructureDescription(G); "C11 x C11 x ((C11 x C11) : C11)" # gap> A := AutomorphismGroupPGroup(G);; #I step 1: 11^4 -- init automorphisms #I step 2: 11^1 -- aut grp has size 2551047840000 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 5, 5, 11, 11, 11, 11, 11, 11, 11, 11 ] 1742400 37349891425440000 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Full");; #I step 1: 11^4 -- init automorphisms #I step 2: 11^1 -- aut grp has size 41393302251840000 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 5, 11, 11, 11, 11 ] 255104784000 37349891425440000 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Over");; #I step 1: 11^4 -- init automorphisms #I step 2: 11^1 -- aut grp has size 2551047840000 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 2, 5, 5, 11, 11, 11, 11, 11, 11, 11, 11 ] 1742400 37349891425440000 gap> ConvertHybridAutGroup( A ); # gap> A := AutomorphismGroupPGroup(G, "Char");; #I step 1: 11^4 -- init automorphisms #I step 2: 11^1 -- aut grp has size 2551047840000 #I final step: convert gap> SortedList(A.agOrder); A.glOrder; A.size; [ 2, 5, 11, 11, 11, 11 ] 255104784000 37349891425440000 gap> ConvertHybridAutGroup( A ); # gap> STOP_TEST( "more.tst" ,1); autpgrp-1.12.0/tst/number.tst0000644000000000000000000000220415202202400013022 0ustar00gap> START_TEST("number.tst"); gap> SetInfoLevel( InfoAutGrp, 0 ); # gap> NumberOfPClass2PGroups(4, 2); [ 6, 54, 604, 3566, 6709, 3566, 604, 54, 6, 1 ] gap> List([0..11], i -> NumberOfPClass2PGroups(4, 2, i)); [ 0, 6, 54, 604, 3566, 6709, 3566, 604, 54, 6, 1, 0 ] # gap> NumberOfPClass2PGroups(4, 3); [ 6, 60, 1361, 23361, 66667, 23361, 1361, 60, 6, 1 ] gap> List([0..11], i -> NumberOfPClass2PGroups(4, 3, i)); [ 0, 6, 60, 1361, 23361, 66667, 23361, 1361, 60, 6, 1, 0 ] # gap> NumberOfClass2LieAlgebras(4, 2); [ 2, 4, 6, 4, 2, 1 ] gap> List([0..7], i -> NumberOfClass2LieAlgebras(4, 2, i)); [ 1, 2, 4, 6, 4, 2, 1, 0 ] # gap> NumberOfClass2LieAlgebras(4, 3); [ 2, 4, 6, 4, 2, 1 ] gap> List([0..7], i -> NumberOfClass2LieAlgebras(4, 3, i)); [ 1, 2, 4, 6, 4, 2, 1, 0 ] # gap> NumberOfClass2AssocAlgebras(4, 2); [ 27, 37269, 83200199, 37269, 27, 1 ] gap> List([1..3], i -> NumberOfClass2AssocAlgebras(4, 2, i)); [ 27, 37269, 83200199 ] # gap> NumberOfClass2AssocAlgebras(4, 3); [ 46, 3205858, 585449616953, 3205858, 46, 1 ] gap> List([1..3], i -> NumberOfClass2AssocAlgebras(4, 3, i)); [ 46, 3205858, 585449616953 ] # gap> STOP_TEST( "number.tst" ,1); autpgrp-1.12.0/tst/testall.g0000644000000000000000000000026615202202400012624 0ustar00LoadPackage("autpgrp"); TestDirectory(DirectoriesPackageLibrary("autpgrp", "tst"), rec(exitGAP := true, testOptions := rec(compareFunction := "uptowhitespace"))); FORCE_QUIT_GAP(1);