congruence-1.2.3/PackageInfo.g0000664000371700037170000001136513503171577017415 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W PackageInfo.g The Congruence package Ann Dooms #W Eric Jespers #W Alexander Konovalov #W Helena Verrill ## ## ############################################################################# SetPackageInfo( rec( PackageName := "Congruence", Subtitle := "Congruence subgroups of SL(2,Integers)", Version := "1.2.3", Date := "19/05/2019", # dd/mm/yyyy format License := "GPL-2.0-or-later", ## <#GAPDoc Label="PKGVERSIONDATA"> ## ## ## ## <#/GAPDoc> SourceRepository := rec( Type := "git", URL := Concatenation( "https://github.com/gap-packages/", LowercaseString(~.PackageName) ), ), IssueTrackerURL := Concatenation( ~.SourceRepository.URL, "/issues" ), PackageWWWHome := Concatenation( "https://gap-packages.github.io/", LowercaseString(~.PackageName) ), README_URL := Concatenation( ~.PackageWWWHome, "/README.md" ), PackageInfoURL := Concatenation( ~.PackageWWWHome, "/PackageInfo.g" ), ArchiveURL := Concatenation( ~.SourceRepository.URL, "/releases/download/v", ~.Version, "/", LowercaseString(~.PackageName), "-", ~.Version ), ArchiveFormats := ".tar.gz", Persons := [ rec( LastName := "Dooms", FirstNames := "Ann", IsAuthor := true, IsMaintainer := true, Email := "andooms@vub.ac.be", WWWHome := "http://homepages.vub.ac.be/~andooms", PostalAddress := Concatenation( [ "Department of Mathematics\n", "Vrije Universiteit Brussel\n", "Pleinlaan 2, Brussels, B-1050 Belgium" ] ), Place := "Brussels", Institution := "Vrije Universiteit Brussel" ), rec( LastName := "Jespers", FirstNames := "Eric", IsAuthor := true, IsMaintainer := false, Email := "efjesper@vub.ac.be", WWWHome := "http://homepages.vub.ac.be/~efjesper", PostalAddress := Concatenation( [ "Department of Mathematics\n", "Vrije Universiteit Brussel\n", "Pleinlaan 2, Brussels, B-1050 Belgium" ] ), Place := "Brussels", Institution := "Vrije Universiteit Brussel" ), rec( LastName := "Konovalov", FirstNames := "Alexander", IsAuthor := true, IsMaintainer := true, Email := "alexander.konovalov@st-andrews.ac.uk", WWWHome := "https://alexk.host.cs.st-andrews.ac.uk", PostalAddress := Concatenation( [ "School of Computer Science\n", "University of St Andrews\n", "Jack Cole Building, North Haugh,\n", "St Andrews, Fife, KY16 9SX, Scotland" ] ), Place := "St Andrews", Institution := "University of St Andrews" ), rec( LastName := "Verrill", FirstNames := "Helena", IsAuthor := true, IsMaintainer := true, Email := "verrill@math.lsu.edu", WWWHome := "http://www.math.lsu.edu/~verrill", PostalAddress := Concatenation( [ "Department of Mathematics\n", "Louisiana State University\n", "Baton Rouge, Louisiana, 70803-4918\n", "USA" ] ), Place := "Baton Rouge", Institution := "Louisiana State University" ) ], Status := "accepted", CommunicatedBy := "Graham Ellis (Galway)", AcceptDate := "09/2014", AbstractHTML := "The Congruence package provides functions to construct several types of canonical congruence subgroups in SL_2(Z), and also intersections of a finite number of such subgroups. Furthermore, it implements the algorithm for generating Farey symbols for congruence subgroups and using them to produce a system of independent generators for these subgroups", PackageDoc := rec( BookName := "Congruence", ArchiveURLSubset := ["doc"], HTMLStart := "doc/chap0.html", PDFFile := "doc/manual.pdf", SixFile := "doc/manual.six", LongTitle := "Congruence subgroups of SL(2,Integers)", Autoload := true ), Dependencies := rec( GAP := ">=4.8", NeededOtherPackages := [ ["GAPDoc", ">= 1.5.1"] ], SuggestedOtherPackages := [], ExternalConditions := [] ), AvailabilityTest := ReturnTrue, TestFile := "tst/testall.g", Keywords := ["congruence subgroup", "Farey symbol"] )); congruence-1.2.3/README.md0000664000371700037170000000205413503171577016350 0ustar gap-jenkinsgap-jenkins[![Build Status](https://travis-ci.org/gap-packages/congruence.svg?branch=master)](https://travis-ci.org/gap-packages/congruence) [![Code Coverage](https://codecov.io/github/gap-packages/congruence/coverage.svg?branch=master&token=)](https://codecov.io/gh/gap-packages/congruence) # GAP package Congruence The GAP package Congruence provides functions to construct several types of canonical congruence subgroups in SL_2(Z), and also intersections of a finite number of such subgroups. Furthermore, it implements the algorithm for generating Farey symbols for congruence subgroups and using them to produce a system of independent generators for these subgroups. Congruence does not use external binaries and, therefore, works without restrictions on the type of the operating system. It is redistributed with GAP, but is not loaded by default. Therefore, to use Congruence, first you need to load it using the following command: gap> LoadPackage("congruence"); Ann Dooms, Eric Jespers, Alexander Konovalov, Helena Verrill congruence-1.2.3/COPYING0000664000371700037170000004311013503171577016122 0ustar gap-jenkinsgap-jenkins GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General Public License instead of this License. congruence-1.2.3/makedoc.g0000664000371700037170000000745613503171577016657 0ustar gap-jenkinsgap-jenkins########################################################################### ## #W makedoc.g The Congruence package Alexander Konovalov ## ########################################################################### ExtractMyManualExamples:=function( pkgname, main, files ) local path, tst, i, s, basename, name, output, ch, a, location, pos, comment; path:=Directory( Concatenation(PackageInfo(pkgname)[1].InstallationPath, "/doc") ); Print("Extracting manual examples for ", pkgname, " package ...\n" ); tst:=ExtractExamples( path, main, files, "Chapter" ); Print(Length(tst), " chapters detected\n"); for i in [ 1 .. Length(tst) ] do Print( "Chapter ", i, " : \c" ); if Length( tst[i] ) > 0 then s := String(i); if Length(s)=1 then # works for <100 chapters s:=Concatenation("0",s); fi; basename:=Concatenation( LowercaseString(pkgname), s, ".tst" ); name := Filename( Directory( Concatenation( PackageInfo(pkgname)[1].InstallationPath, "/tst" ) ), basename ); output := OutputTextFile( name, false ); # to empty the file first SetPrintFormattingStatus( output, false ); # to avoid line breaks ch := tst[i]; AppendTo(output, "# ", pkgname, ", chapter ",i,"\n"); AppendTo(output, "#\n", "# DO NOT EDIT THIS FILE - EDIT EXAMPLES IN THE SOURCE INSTEAD!\n", "#\n", "# This file has been autogenerated with GAP. It contains examples\n", "# extracted from the documentation. Each example is preceded by the\n", "# comment which points to the location of its source.\n", "#\n"); AppendTo(output, "gap> START_TEST( \"", basename, "\");\n\n"); for a in ch do location := a[2][1]; pos := PositionSublist(location,LowercaseString(pkgname)); if pos <> fail then comment := location{[ pos+Length(pkgname)+1 .. Length(location) ]}; else pos := PositionSublist(location,".//"); comment := location{[ pos+3 .. Length(location) ]}; fi; AppendTo(output, "# ", comment, ":", a[2][2], "-", a[2][3], a[1]); od; AppendTo(output, "gap> STOP_TEST(\"", basename, "\", 1 );\n"); Print("extracted ", Length(ch), " examples \n"); else Print("no examples \n" ); fi; od; end; ########################################################################### CONGRUENCEMANUALFILES:=[ "../PackageInfo.g" ]; MakeGAPDocDoc( "doc", # path to the directory containing the main file "manual", # the name of the main file (without extension) # list of (probably source code) files relative # to path which contain pieces of documentation # which must be included in the document CONGRUENCEMANUALFILES, "Congruence",# the name of the book used by GAP's online help "../../..",# optional: relative path to the main GAP root # directory to produce HTML files with relative # paths to external books. "MathJax" # optional: use "MathJax", "Tth" and/or "MathML" # to produce additional variants of HTML files );; # Copy the *.css and *.js files from the styles directory of the GAPDoc # package into the directory containing the package manual. CopyHTMLStyleFiles( "doc" ); # Create the manual.lab file which is needed if the main manuals or another # package is referring to your package GAPDocManualLab( "Congruence" );; ExtractMyManualExamples( "congruence", "manual.xml", CONGRUENCEMANUALFILES ); QUIT; ########################################################################### ## #E ## congruence-1.2.3/init.g0000664000371700037170000000147413503171577016211 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W init.g The Congruence package Ann Dooms #W Eric Jespers #W Alexander Konovalov #W Helena Verrill ## ## ############################################################################# # read Congruence declarations ReadPackage( "congruence", "lib/cong.gd" ); ReadPackage( "congruence", "lib/farey.gd" ); # read the other part of code ReadPackage( "congruence", "lib/cong.g" ); ReadPackage( "congruence", "lib/buildman.g" ); ReadPackage( "congruence", "lib/factor.g" ); # set the default InfoLevel SetInfoLevel( InfoCongruence, 1 ); congruence-1.2.3/read.g0000664000371700037170000000123613503171577016155 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W read.g The Congruence package Ann Dooms #W Eric Jespers #W Alexander Konovalov #W Helena Verrill ## ## ############################################################################# # read the implementation part of the Congruence package ReadPackage( "congruence", "lib/cong.gi" ); ReadPackage( "congruence", "lib/farey.gi" ); ReadPackage( "congruence", "lib/random.gi" ); congruence-1.2.3/lib/farey.gd0000664000371700037170000000447713503171577017274 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W farey.gd The Congruence package Ann Dooms #W Eric Jespers #W Alexander Konovalov ## ## ############################################################################# ############################################################################# ## ## IsFareySymbol( ) ## DeclareCategory( "IsFareySymbol", IsObject ); ############################################################################# ## ## FareySymbolByData( , ) ## ## This constructor creates Farey symbol with the given generalized Farey ## sequence and list of labels. It also checks conditions from the definition ## of Farey symbol and returns an error if they are not satisfied ## DeclareOperation( "FareySymbolByData", [ IsList, IsList ] ); ############################################################################# ## ## GeneralizedFareySequence( ) ## LabelsOfFareySymbol( ) ## ## The data used to create the Farey symbol are stored as its attributes ## DeclareAttribute( "GeneralizedFareySequence", IsFareySymbol ); DeclareAttribute( "LabelsOfFareySymbol", IsFareySymbol ); ############################################################################# ## ## FareySymbol( ) ## ## For a subgroup of a finite index G, this attribute stores the ## corresponding Farey symbol. The algorithm for its computation must work ## with any matrix group for which the membership test is available ## DeclareAttribute( "FareySymbol", IsMatrixGroup ); ############################################################################# # # GeneratorsByFareySymbol( fs ) # DeclareGlobalFunction( "GeneratorsByFareySymbol" ); ############################################################################# # # IndexInPSL2ZByFareySymbol( fs ) # # By the proposition 7.2 [Kulkarni], for the Farey symbol with underlying # generalized Farey sequence { infinity, x0, x1, ..., xn, infinity }, the # index in PSL_2(Z) is given by the formula d = 3*n + e3, where e3 is the # number of odd intervals. # DeclareGlobalFunction( "IndexInPSL2ZByFareySymbol" ); ############################################################################# ## #E ## congruence-1.2.3/lib/cong.gi0000664000371700037170000007477513503171577017131 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W cong.gi The Congruence package Ann Dooms #W Eric Jespers #W Alexander Konovalov ## ## ############################################################################# ############################################################################# ## ## Constructors of congruence subgroups InstallMethod( PrincipalCongruenceSubgroup, "for positive integer", [ IsPosInt ], function(n) local type, G; type := NewType( FamilyObj([[[1,0],[0,1]]]), IsGroup and IsAttributeStoringRep and IsFinitelyGeneratedGroup and IsMatrixGroup and IsCongruenceSubgroup); G := rec(); ObjectifyWithAttributes( G, type, DimensionOfMatrixGroup, 2, OneImmutable, [[1,0],[0,1]], IsIntegerMatrixGroup, true, IsFinite, false, LevelOfCongruenceSubgroup, n, IsPrincipalCongruenceSubgroup, true, IsIntersectionOfCongruenceSubgroups, false, IsCongruenceSubgroupGamma0, false, IsCongruenceSubgroupGammaUpper0, false, IsCongruenceSubgroupGamma1, false, IsCongruenceSubgroupGammaUpper1, false, IsCongruenceSubgroupGammaMN, false ); return G; end); InstallMethod( CongruenceSubgroupGamma0, "for positive integer", [ IsPosInt ], function(n) local type, G; type := NewType( FamilyObj([[[1,0],[0,1]]]), IsGroup and IsAttributeStoringRep and IsFinitelyGeneratedGroup and IsMatrixGroup and IsCongruenceSubgroup); G := rec(); ObjectifyWithAttributes( G, type, DimensionOfMatrixGroup, 2, OneImmutable, [[1,0],[0,1]], IsIntegerMatrixGroup, true, IsFinite, false, LevelOfCongruenceSubgroup, n, IsPrincipalCongruenceSubgroup, false, IsIntersectionOfCongruenceSubgroups, false, IsCongruenceSubgroupGamma0, true, IsCongruenceSubgroupGammaUpper0, false, IsCongruenceSubgroupGamma1, false, IsCongruenceSubgroupGammaUpper1, false, IsCongruenceSubgroupGammaMN, false ); return G; end); InstallMethod( CongruenceSubgroupGammaUpper0, "for positive integer", [ IsPosInt ], function(n) local type, G; type := NewType( FamilyObj([[[1,0],[0,1]]]), IsGroup and IsAttributeStoringRep and IsFinitelyGeneratedGroup and IsMatrixGroup and IsCongruenceSubgroup); G := rec(); ObjectifyWithAttributes( G, type, DimensionOfMatrixGroup, 2, OneImmutable, [[1,0],[0,1]], IsIntegerMatrixGroup, true, IsFinite, false, LevelOfCongruenceSubgroup, n, IsPrincipalCongruenceSubgroup, false, IsIntersectionOfCongruenceSubgroups, false, IsCongruenceSubgroupGamma0, false, IsCongruenceSubgroupGammaUpper0, true, IsCongruenceSubgroupGamma1, false, IsCongruenceSubgroupGammaUpper1, false, IsCongruenceSubgroupGammaMN, false ); return G; end); InstallMethod( CongruenceSubgroupGamma1, "for positive integer", [ IsPosInt ], function(n) local type, G; type := NewType( FamilyObj([[[1,0],[0,1]]]), IsGroup and IsAttributeStoringRep and IsFinitelyGeneratedGroup and IsMatrixGroup and IsCongruenceSubgroup); G := rec(); ObjectifyWithAttributes( G, type, DimensionOfMatrixGroup, 2, OneImmutable, [[1,0],[0,1]], IsIntegerMatrixGroup, true, IsFinite, false, LevelOfCongruenceSubgroup, n, IsPrincipalCongruenceSubgroup, false, IsIntersectionOfCongruenceSubgroups, false, IsCongruenceSubgroupGamma0, false, IsCongruenceSubgroupGammaUpper0, false, IsCongruenceSubgroupGamma1, true, IsCongruenceSubgroupGammaUpper1, false, IsCongruenceSubgroupGammaMN, false ); return G; end); InstallMethod( CongruenceSubgroupGammaUpper1, "for positive integer", [ IsPosInt ], function(n) local type, G; type := NewType( FamilyObj([[[1,0],[0,1]]]), IsGroup and IsAttributeStoringRep and IsFinitelyGeneratedGroup and IsMatrixGroup and IsCongruenceSubgroup); G := rec(); ObjectifyWithAttributes( G, type, DimensionOfMatrixGroup, 2, OneImmutable, [[1,0],[0,1]], IsIntegerMatrixGroup, true, IsFinite, false, LevelOfCongruenceSubgroup, n, IsPrincipalCongruenceSubgroup, false, IsIntersectionOfCongruenceSubgroups, false, IsCongruenceSubgroupGamma0, false, IsCongruenceSubgroupGammaUpper0, false, IsCongruenceSubgroupGamma1, false, IsCongruenceSubgroupGammaUpper1, true, IsCongruenceSubgroupGammaMN, false ); return G; end); InstallMethod( CongruenceSubgroupGammaMN, "for two positive integers", [ IsPosInt, IsPosInt ], function(m,n) local type, G; type := NewType( FamilyObj([[[1,0],[0,1]]]), IsGroup and IsAttributeStoringRep and IsFinitelyGeneratedGroup and IsMatrixGroup and IsCongruenceSubgroup); G := rec(); ObjectifyWithAttributes( G, type, DimensionOfMatrixGroup, 2, OneImmutable, [[1,0],[0,1]], IsIntegerMatrixGroup, true, IsFinite, false, LevelOfCongruenceSubgroup, m*n, LevelOfCongruenceSubgroupGammaMN, [m,n], IsPrincipalCongruenceSubgroup, false, IsIntersectionOfCongruenceSubgroups, false, IsCongruenceSubgroupGamma0, false, IsCongruenceSubgroupGammaUpper0, false, IsCongruenceSubgroupGamma1, false, IsCongruenceSubgroupGammaUpper1, false, IsCongruenceSubgroupGammaMN, true ); return G; end); InstallGlobalFunction( IntersectionOfCongruenceSubgroups, function( arg ) local type, G, H, K, T, arglist, n, i, pos; type := NewType( FamilyObj([[[1,0],[0,1]]]), IsGroup and IsAttributeStoringRep and IsFinitelyGeneratedGroup and IsMatrixGroup and IsCongruenceSubgroup); if not ForAll( arg, IsCongruenceSubgroup ) then Error("Usage : IntersectionOfCongruenceSubgroups( G1, G2, ... GN ) \n"); fi; # First we create a list arglist to eliminate evident repetitions of subgroups. # Then we eliminate evident inclusions of one subgroup into another: # - since intersection is associative, if we can intersect the group T which # is to be added with another subgroup K already contained in alglist, and # the result is one of the canonical congruence subgroups, we replace K by # the result of intersection of K and T # - we do not add a subgroup T to the list of defining subgroups, if alglist # already contains another subgroup K such that K is in T. # - if we add to alglist a subgroup T and alglist already contains one or more # subgroups K such that T is in K, we add T and remove all these K. arglist := []; for H in arg do if IsIntersectionOfCongruenceSubgroups(H) then for T in DefiningCongruenceSubgroups( H ) do pos:=PositionProperty( arglist, K -> CanReduceIntersectionOfCongruenceSubgroups( K, T ) ); if pos<>fail then arglist[pos]:=Intersection( arglist[pos], T ); else if ForAll( arglist, K -> not CanEasilyCompareCongruenceSubgroups( K, T ) ) and ForAll( arglist, K -> not IsSubgroup( T, K ) ) then for i in [ 1 .. Length(arglist) ] do if IsSubgroup( arglist[i], T ) then Unbind( arglist[i] ); fi; od; arglist := Compacted( arglist ); Add( arglist, T ); fi; fi; od; else pos:=PositionProperty( arglist, K -> CanReduceIntersectionOfCongruenceSubgroups( K, H ) ); if pos<>fail then arglist[pos]:=Intersection( arglist[pos], H ); else if ForAll( arglist, K -> not CanEasilyCompareCongruenceSubgroups( K, H ) ) and ForAll( arglist, K -> not IsSubgroup( H, K ) ) then for i in [ 1 .. Length(arglist) ] do if IsSubgroup( arglist[i], H ) then Unbind( arglist[i] ); fi; od; arglist := Compacted( arglist ); Add( arglist, H ); fi; fi; fi; od; # if the list of defining subgroups was reduced # to a single subgroup, we return this subgroup if Length( arglist ) = 1 then return arglist[1]; fi; # otherwise we sort the list of defining subgroups: # types of subgroups are sorted in the following way: # - IsCongruenceSubgroupGamma0 # - IsCongruenceSubgroupGammaUpper0 # - IsCongruenceSubgroupGamma1 # - IsCongruenceSubgroupGammaUpper1 # - IsPrincipalCongruenceSubgroup # and subgroups of the same type are sorted by ascending level Sort( arglist, function(X,Y) local f, t; f:=[IsCongruenceSubgroupGamma0,IsCongruenceSubgroupGammaUpper0,IsCongruenceSubgroupGamma1,IsCongruenceSubgroupGammaUpper1,IsPrincipalCongruenceSubgroup]; return PositionProperty(f, t -> t(X)) < PositionProperty(f, t -> t(Y)) or ( PositionProperty(f, t -> t(X)) = PositionProperty(f, t -> t(Y)) and LevelOfCongruenceSubgroup(X) < LevelOfCongruenceSubgroup(Y) ); end ); n := Lcm( List( arglist, H -> LevelOfCongruenceSubgroup(H) ) ); G := rec(); ObjectifyWithAttributes( G, type, DimensionOfMatrixGroup, 2, OneImmutable, [[1,0],[0,1]], IsIntegerMatrixGroup, true, IsFinite, false, LevelOfCongruenceSubgroup, n, IsPrincipalCongruenceSubgroup, false, IsIntersectionOfCongruenceSubgroups, true, IsCongruenceSubgroupGamma0, false, IsCongruenceSubgroupGammaUpper0, false, IsCongruenceSubgroupGamma1, false, IsCongruenceSubgroupGammaUpper1, false, DefiningCongruenceSubgroups, arglist ); return G; end); InstallMethod( DefiningCongruenceSubgroups, "for congruence subgroups", [ IsCongruenceSubgroup ], function(G) if not IsIntersectionOfCongruenceSubgroups(G) then return [G]; fi; end); ############################################################################# ## ## Methods for PrintObj and ViewObj for congruence subgroups InstallMethod( ViewObj, "for principal congruence subgroup", [ IsPrincipalCongruenceSubgroup ], 0, function( G ) Print( "" ); end ); InstallMethod( PrintObj, "for principal congruence subgroup", [ IsPrincipalCongruenceSubgroup ], 0, function( G ) Print( "PrincipalCongruenceSubgroup(", LevelOfCongruenceSubgroup(G), ")" ); end ); InstallMethod( ViewObj, "for CongruenceSubgroupGamma0 congruence subgroup", [ IsCongruenceSubgroupGamma0 ], 0, function( G ) Print( "" ); end ); InstallMethod( PrintObj, "for CongruenceSubgroupGamma0 congruence subgroup", [ IsCongruenceSubgroupGamma0 ], 0, function( G ) Print( "CongruenceSubgroupGamma0(", LevelOfCongruenceSubgroup(G), ")" ); end ); InstallMethod( ViewObj, "for CongruenceSubgroupGammaUpper0 congruence subgroup", [ IsCongruenceSubgroupGammaUpper0 ], 0, function( G ) Print( "" ); end ); InstallMethod( PrintObj, "for CongruenceSubgroupGammaUpper0 congruence subgroup", [ IsCongruenceSubgroupGammaUpper0 ], 0, function( G ) Print( "CongruenceSubgroupGammaUpper0(", LevelOfCongruenceSubgroup(G), ")" ); end ); InstallMethod( ViewObj, "for CongruenceSubgroupGamma1 congruence subgroup", [ IsCongruenceSubgroupGamma1 ], 0, function( G ) Print( "" ); end ); InstallMethod( PrintObj, "for CongruenceSubgroupGamma1 congruence subgroup", [ IsCongruenceSubgroupGamma1 ], 0, function( G ) Print( "CongruenceSubgroupGamma1(", LevelOfCongruenceSubgroup(G), ")" ); end ); InstallMethod( ViewObj, "for CongruenceSubgroupGammaUpper1 congruence subgroup", [ IsCongruenceSubgroupGammaUpper1 ], 0, function( G ) Print( "" ); end ); InstallMethod( PrintObj, "for CongruenceSubgroupGammaUpper1 congruence subgroup", [ IsCongruenceSubgroupGammaUpper1 ], 0, function( G ) Print( "CongruenceSubgroupGammaUpper1(", LevelOfCongruenceSubgroup(G), ")" ); end ); InstallMethod( ViewObj, "for CongruenceSubgroupGammaMN congruence subgroup", [ IsCongruenceSubgroupGammaMN ], 0, function( G ) Print( "" ); end ); InstallMethod( PrintObj, "for CongruenceSubgroupGammaMN congruence subgroup", [ IsCongruenceSubgroupGammaMN ], 0, function( G ) Print( "CongruenceSubgroupGammaMN(", LevelOfCongruenceSubgroupGammaMN(G)[1], ",", LevelOfCongruenceSubgroupGammaMN(G)[2], ")" ); end ); InstallMethod( ViewObj, "for intersection of congruence subgroups", [ IsIntersectionOfCongruenceSubgroups ], 0, function( G ) Print( "" ); end ); InstallMethod( PrintObj, "for intersection of congruence subgroups", [ IsIntersectionOfCongruenceSubgroups ], 0, function( G ) local i, k; k := Length(DefiningCongruenceSubgroups(G)); Print( "IntersectionOfCongruenceSubgroups( \n" ); for i in [ 1 .. k-1 ] do Print( " ", DefiningCongruenceSubgroups(G)[i], ", \n" ); od; Print( " ", DefiningCongruenceSubgroups(G)[k], " )" ); end ); ############################################################################# ## ## Membership tests for congruence subgroups InstallMethod( \in, "for a 2x2 matrix and a principal congruence subgroup", [ IsMatrix, IsPrincipalCongruenceSubgroup], 0, function( m, G ) local n; if not DimensionsMat( m ) = [2,2] then return false; elif DeterminantMat(m)<>1 then return false; else n := LevelOfCongruenceSubgroup(G); return IsInt( (m[1][1]-1)/n ) and IsInt(m[1][2]/n) and IsInt(m[2][1]/n) and IsInt( (m[2][2]-1)/n ); fi; end); InstallMethod( \in, "for a 2x2 matrix and a congruence subgroup CongruenceSubgroupGamma0", [ IsMatrix, IsCongruenceSubgroupGamma0 ], 0, function( m, G ) local n; if not DimensionsMat( m ) = [2,2] then return false; elif DeterminantMat(m)<>1 then return false; else n := LevelOfCongruenceSubgroup(G); return IsInt(m[2][1]/n); fi; end); InstallMethod( \in, "for a 2x2 matrix and a congruence subgroup CongruenceSubgroupGammaUpper0", [ IsMatrix, IsCongruenceSubgroupGammaUpper0 ], 0, function( m, G ) local n; if not DimensionsMat( m ) = [2,2] then return false; elif DeterminantMat(m)<>1 then return false; else n := LevelOfCongruenceSubgroup(G); return IsInt(m[1][2]/n); fi; end); InstallMethod( \in, "for a 2x2 matrix and a congruence subgroup CongruenceSubgroupGamma1", [ IsMatrix, IsCongruenceSubgroupGamma1 ], 0, function( m, G ) local n; if not DimensionsMat( m ) = [2,2] then return false; elif DeterminantMat(m)<>1 then return false; else n := LevelOfCongruenceSubgroup(G); return IsInt( (m[1][1]-1)/n ) and IsInt( m[2][1]/n ) and IsInt( (m[2][2]-1)/n ); fi; end); InstallMethod( \in, "for a 2x2 matrix and a congruence subgroup CongruenceSubgroupGammaUpper1", [ IsMatrix, IsCongruenceSubgroupGammaUpper1 ], 0, function( m, G ) local n; if not DimensionsMat( m ) = [2,2] then return false; elif DeterminantMat(m)<>1 then return false; else n := LevelOfCongruenceSubgroup(G); return IsInt( (m[1][1]-1)/n ) and IsInt( m[1][2]/n ) and IsInt( (m[2][2]-1)/n ); fi; end); InstallMethod( \in, "for a 2x2 matrix and a congruence subgroup CongruenceSubgroupGammaMN", [ IsMatrix, IsCongruenceSubgroupGammaMN ], 0, function( mat, G ) local m, n; if not DimensionsMat( mat ) = [2,2] then return false; elif DeterminantMat(mat)<>1 then return false; else m := LevelOfCongruenceSubgroupGammaMN(G)[1]; n := LevelOfCongruenceSubgroupGammaMN(G)[2]; return IsInt( (mat[1][1]-1)/m ) and IsInt(mat[1][2]/m) and IsInt(mat[2][1]/n) and IsInt( (mat[2][2]-1)/n ); fi; end); InstallMethod( \in, "for an intersection of congruence subgroups", [ IsMatrix, IsIntersectionOfCongruenceSubgroups ], 0, function( m, G ) local H; if not DimensionsMat( m ) = [2,2] then return false; elif DeterminantMat(m)<>1 then return false; else return ForAll( DefiningCongruenceSubgroups(G), H -> m in H ); fi; end); ############################################################################# ## ## Installing special methods for congruence subgroups ## for some general methods installed in GAP for matrix groups InstallMethod( DimensionOfMatrixGroup, "for congruence subgroup", [ IsCongruenceSubgroup ], 0, G -> 2 ); InstallMethod( \=, "for a pair of congruence subgroups", [ IsCongruenceSubgroup, IsCongruenceSubgroup ], 0, function( G, H ) if CanEasilyCompareCongruenceSubgroups( G, H ) then return true; else TryNextMethod(); fi; end); ############################################################################# ## ## IsSubset ## ############################################################################# InstallMethod( IsSubset, "for a natural SL_2(Z) and a congruence subgroup", [ IsNaturalSL, IsCongruenceSubgroup ], 0, function( G, H ) return MultiplicativeNeutralElement(G)=[ [ 1, 0 ], [ 0, 1 ] ]; end); InstallMethod( IsSubset, "for a congruence subgroup and a principal congruence subgroup", [ IsCongruenceSubgroup, IsPrincipalCongruenceSubgroup ], 0, function( G, H ) local T; if IsIntersectionOfCongruenceSubgroups(G) then return ForAll( DefiningCongruenceSubgroups(G), T -> IsSubset(T,H) ); elif IsPrincipalCongruenceSubgroup(G) or IsCongruenceSubgroupGamma1(G) or IsCongruenceSubgroupGammaUpper1(G) or IsCongruenceSubgroupGamma0(G) or IsCongruenceSubgroupGammaUpper0(G) then return IsInt( LevelOfCongruenceSubgroup(H) / LevelOfCongruenceSubgroup(G) ); else # for a case of another type of congruence subgroup TryNextMethod(); fi; end); InstallMethod( IsSubset, "for a congruence subgroup and CongruenceSubgroupGamma1", [ IsCongruenceSubgroup, IsCongruenceSubgroupGamma1 ], 0, function( G, H ) local T; if IsIntersectionOfCongruenceSubgroups(G) then return ForAll( DefiningCongruenceSubgroups(G), T -> IsSubset(T,H) ); elif IsPrincipalCongruenceSubgroup(G) or IsCongruenceSubgroupGammaUpper1(G) or IsCongruenceSubgroupGammaUpper0(G) then return false; elif IsCongruenceSubgroupGamma1(G) or IsCongruenceSubgroupGamma0(G) then return IsInt( LevelOfCongruenceSubgroup(H) / LevelOfCongruenceSubgroup(G) ); else # for a case of another type of congruence subgroup TryNextMethod(); fi; end); InstallMethod( IsSubset, "for a congruence subgroup and CongruenceSubgroupGammaUpper1", [ IsCongruenceSubgroup, IsCongruenceSubgroupGammaUpper1 ], 0, function( G, H ) local T; if IsIntersectionOfCongruenceSubgroups(G) then return ForAll( DefiningCongruenceSubgroups(G), T -> IsSubset(T,H) ); elif IsPrincipalCongruenceSubgroup(G) or IsCongruenceSubgroupGamma1(G) or IsCongruenceSubgroupGamma0(G) then return false; elif IsCongruenceSubgroupGammaUpper1(G) or IsCongruenceSubgroupGammaUpper0(G) then return IsInt( LevelOfCongruenceSubgroup(H) / LevelOfCongruenceSubgroup(G) ); else # for a case of another type of congruence subgroup TryNextMethod(); fi; end); InstallMethod( IsSubset, "for a congruence subgroup and CongruenceSubgroupGamma0", [ IsCongruenceSubgroup, IsCongruenceSubgroupGamma0 ], 0, function( G, H ) local T; if IsIntersectionOfCongruenceSubgroups(G) then return ForAll( DefiningCongruenceSubgroups(G), T -> IsSubset(T,H) ); elif IsPrincipalCongruenceSubgroup(G) or IsCongruenceSubgroupGamma1(G) or IsCongruenceSubgroupGammaUpper1(G) or IsCongruenceSubgroupGammaUpper0(G) then return false; elif IsCongruenceSubgroupGamma0(G) then return IsInt( LevelOfCongruenceSubgroup(H) / LevelOfCongruenceSubgroup(G) ); else # for a case of another type of congruence subgroup TryNextMethod(); fi; end); InstallMethod( IsSubset, "for a congruence subgroup and CongruenceSubgroupGammaUpper0", [ IsCongruenceSubgroup, IsCongruenceSubgroupGammaUpper0 ], 0, function( G, H ) local T; if IsIntersectionOfCongruenceSubgroups(G) then return ForAll( DefiningCongruenceSubgroups(G), T -> IsSubset(T,H) ); elif IsPrincipalCongruenceSubgroup(G) or IsCongruenceSubgroupGamma1(G) or IsCongruenceSubgroupGammaUpper1(G) or IsCongruenceSubgroupGamma0(G) then return false; elif IsCongruenceSubgroupGammaUpper0(G) then return IsInt( LevelOfCongruenceSubgroup(H) / LevelOfCongruenceSubgroup(G) ); else # for a case of another type of congruence subgroup TryNextMethod(); fi; end); InstallMethod( IsSubset, "for a congruence subgroup and intersection of congruence subgroups", [ IsCongruenceSubgroup, IsIntersectionOfCongruenceSubgroups ], 0, function( G, H ) local DG, DH; # here we can check only sufficient conditions, and they are not # satisfied, then we call the next method if IsIntersectionOfCongruenceSubgroups(G) then if ForAll( DefiningCongruenceSubgroups(H), DH -> ForAll( DefiningCongruenceSubgroups(G), DG -> IsSubset(G,DH) ) ) then return true; else TryNextMethod(); fi; elif IsPrincipalCongruenceSubgroup(G) or IsCongruenceSubgroupGamma1(G) or IsCongruenceSubgroupGammaUpper1(G) or IsCongruenceSubgroupGamma0(G) or IsCongruenceSubgroupGammaUpper0(G) then if ForAll( DefiningCongruenceSubgroups(H), DH -> IsSubset(G,DH) ) then return true; else TryNextMethod(); fi; else # for a case of another type of congruence subgroup TryNextMethod(); fi; end); ############################################################################# ## ## Intersection2 ## ############################################################################# InstallMethod( Intersection2, "for a pair of congruence subgroups", [ IsCongruenceSubgroup, IsCongruenceSubgroup ], 0, function( G, H ) # # Case 1 - at least one subgroup is an intersection of congruence subgroups # if IsIntersectionOfCongruenceSubgroups(G) or IsIntersectionOfCongruenceSubgroups(H) then return IntersectionOfCongruenceSubgroups(G,H); # # Case 2 - the diagonal (both subgroups has the same type) # elif IsPrincipalCongruenceSubgroup(G) and IsPrincipalCongruenceSubgroup(H) then return PrincipalCongruenceSubgroup( Lcm( LevelOfCongruenceSubgroup(G), LevelOfCongruenceSubgroup(H) ) ); elif IsCongruenceSubgroupGamma1(G) and IsCongruenceSubgroupGamma1(H) then return CongruenceSubgroupGamma1( Lcm( LevelOfCongruenceSubgroup(G), LevelOfCongruenceSubgroup(H) ) ); elif IsCongruenceSubgroupGammaUpper1(G) and IsCongruenceSubgroupGammaUpper1(H) then return CongruenceSubgroupGammaUpper1( Lcm( LevelOfCongruenceSubgroup(G), LevelOfCongruenceSubgroup(H) ) ); elif IsCongruenceSubgroupGamma0(G) and IsCongruenceSubgroupGamma0(H) then return CongruenceSubgroupGamma0( Lcm( LevelOfCongruenceSubgroup(G), LevelOfCongruenceSubgroup(H) ) ); elif IsCongruenceSubgroupGammaUpper0(G) and IsCongruenceSubgroupGammaUpper0(H) then return CongruenceSubgroupGammaUpper0( Lcm( LevelOfCongruenceSubgroup(G), LevelOfCongruenceSubgroup(H) ) ); # # Case 3 - Subgroups has different level # elif LevelOfCongruenceSubgroup(G) <> LevelOfCongruenceSubgroup(H) then return IntersectionOfCongruenceSubgroups(G,H); # # Now subgroups have the same level # elif IsCongruenceSubgroupGamma1(G) and IsCongruenceSubgroupGamma0(H) then return G; # so all properties and attributes of G will be preserved elif IsCongruenceSubgroupGamma0(G) and IsCongruenceSubgroupGamma1(H) then return H; elif IsCongruenceSubgroupGammaUpper1(G) and IsCongruenceSubgroupGammaUpper0(H) then return G; elif IsCongruenceSubgroupGammaUpper0(G) and IsCongruenceSubgroupGammaUpper1(H) then return H; elif IsCongruenceSubgroupGamma0(G) and IsCongruenceSubgroupGammaUpper0(H) or IsCongruenceSubgroupGammaUpper0(G) and IsCongruenceSubgroupGamma0(H) then return IntersectionOfCongruenceSubgroups(G,H); else return PrincipalCongruenceSubgroup(LevelOfCongruenceSubgroup(G)); fi; end); ############################################################################# ## ## Indices of congruence subgroups ## ############################################################################# InstallMethod( Index, "for a natural SL_2(Z) and a congruence subgroup", [ IsNaturalSL, IsCongruenceSubgroup ], 0, function( G, H ) local n, prdiv, r, p; n := LevelOfCongruenceSubgroup(H); if HasIsPrincipalCongruenceSubgroup( H ) and IsPrincipalCongruenceSubgroup( H ) then if n=1 then Assert( 1, IndexInPSL2ZByFareySymbol( FareySymbol ( H ) ) = 1 ); return 1; elif n=2 then Assert( 1, IndexInPSL2ZByFareySymbol( FareySymbol ( H ) ) = 6 ); return 12; # not 6, since we are in SL, not in PSL else prdiv := Set( Factors( n ) ); r := n^3; # not (n^3)/2 since we are in SL, not in PSL for p in prdiv do r := r*(1-1/p^2); od; Assert( 1, IndexInPSL2ZByFareySymbol( FareySymbol ( H ) ) = r/2 ); return r; fi; elif ( HasIsCongruenceSubgroupGamma0( H ) and IsCongruenceSubgroupGamma0( H ) ) or ( HasIsCongruenceSubgroupGammaUpper0( H ) and IsCongruenceSubgroupGammaUpper0( H ) ) then # for CongruenceSubgroupGamma0 we use the formula # [ SL_2(Z) : CongruenceSubgroupGamma0(n) ] = n * "Product over prime p | n" ( 1 + 1/p ) prdiv := Set( Factors( n ) ); r := n; for p in prdiv do r := r*(1+1/p); od; Assert( 1, IndexInPSL2ZByFareySymbol( FareySymbol ( H ) ) = r ); return r; elif ( HasIsCongruenceSubgroupGamma1( H ) and IsCongruenceSubgroupGamma1( H ) ) or ( HasIsCongruenceSubgroupGammaUpper1( H ) and IsCongruenceSubgroupGammaUpper1( H ) ) then # for CongruenceSubgroupGamma1 we use the formula # [ CongruenceSubgroupGamma0(n) : CongruenceSubgroupGamma1(n) ] = n * "Product over prime p | n" ( 1 - 1/p ) # Combining with the previous case, we get that # [ SL_2(Z) : CongruenceSubgroupGamma1(n) ] = n^2 * "Product over prime p | n" ( 1 - 1/p^2 ) prdiv := Set( Factors( n ) ); r := n^2; for p in prdiv do r := r*(1-1/p^2); od; Assert( 1, IndexInPSL2ZByFareySymbol( FareySymbol ( H ) ) = r/2 ); return r; else # if H is not in any of the cases above, for example is an intersection # of some congruence subgroups, we derive the index from its Farey symbol if [[-1,0],[0,-1]] in H then return IndexInPSL2ZByFareySymbol( FareySymbol ( H ) ) ; else return IndexInPSL2ZByFareySymbol( FareySymbol ( H ) ) * 2; fi; fi; end); InstallMethod( IndexInSL2Z, "for a congruence subgroup", [ IsCongruenceSubgroup ], 0, G -> Index( SL(2,Integers), G ) ); InstallMethod( Index, "for a pair of congruence subgroups", [ IsCongruenceSubgroup, IsCongruenceSubgroup ], 0, function( G, H ) if IsSubgroup( G, H ) then return IndexInSL2Z(H)/IndexInSL2Z(G); fi; end); ############################################################################# ## ## Generators of confruence subgroups from Farey symbols ## ############################################################################# InstallMethod( GeneratorsOfGroup, "for a congruence subgroup", [ IsCongruenceSubgroup ], 0, function(G) local gens, i; Info( InfoCongruence, 1, "Using the Congruence package for GeneratorsOfGroup ..."); gens := GeneratorsByFareySymbol( FareySymbol( G ) ); for i in [ 1 .. Length(gens) ] do if not gens[i] in G then gens[i] := -gens[i]; Assert( 1, gens[i] in G ); fi; od; return gens; end ); ############################################################################# ## #E ## congruence-1.2.3/lib/random.gi0000664000371700037170000001644113503171577017445 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W random.gi The Congruence package Ann Dooms #W Eric Jespers #W Alexander Konovalov ## ## ############################################################################# ## ## This file contains implementations of methods to construct random elements ## of congruence subgroups CongruenceSubgroupGamma, CongruenceSubgroupGamma0, ## CongruenceSubgroupGammaUpper0, CongruenceSubgroupGamma1 and ## CongruenceSubgroupGammaUpper1. ## The idea is to select two random entries a and b in the same row or column ## of the matrix, such that a and b will satisfy the requirements arising ## from the congruence subgroup. For example, for the principal congruence ## subgroup we will select a and b as follows: ## a := 1 + n * Random( [ -10 .. 10 ] ); ## b := n * Random( [ -10 .. 10 ] ); ## After this we can find such x and y for the other row (or column) of the ## matrix that its determinant will be equal to one. If the resulting matrix ## will be not in the congruence subgroup because of not suitable x and y, ## we will repeat this process for another a and b until we will find ## suitable x and y. ## For each type of congruence subgroups, we provide one- and two-argument ## versions of Random. The one-argument version uses Random( [ -10 .. 10 ] ) ## to generate a and b, ## and in the two-argument version Random([ -m..m ]) ## will be used, where m is given by the second argument. ############################################################################# ## ## The principal congruence subgroup of level N consists of all matrices ## of the form [ 1+N N ] ## [ N 1+N ] ## InstallMethod( Random, "for a principal congruence subgroup", [ IsPrincipalCongruenceSubgroup ], 0, function( G ) local n, a, b, gcd; n := LevelOfCongruenceSubgroup( G ); repeat a := 1 + n * Random( [ -10 .. 10 ] ); b := n * Random( [ -10 .. 10 ] ); gcd := Gcdex( a, b ); until gcd.gcd = 1 and IsInt( -gcd.coeff2/n ) and IsInt( (gcd.coeff1-1)/n ); return [ [ a, b ], [ -gcd.coeff2, gcd.coeff1 ] ]; end); InstallOtherMethod( Random, "for a principal congruence subgroup", [ IsPrincipalCongruenceSubgroup, IsPosInt ], 0, function( G, m ) local n, a, b, gcd; n := LevelOfCongruenceSubgroup( G ); repeat a := 1 + n * Random( [ -m .. m ] ); b := n * Random( [ -m .. m ] ); gcd := Gcdex( a, b ); until gcd.gcd = 1 and IsInt( -gcd.coeff2/n ) and IsInt( (gcd.coeff1-1)/n ); return [ [ a, b ], [ -gcd.coeff2, gcd.coeff1 ] ]; end); ############################################################################# ## ## The congruence subgroup CongruenceSubgroupGamma0(N) consists of all matrices ## of the form [ * * ] ## [ N * ] ## InstallMethod( Random, "for a congruence subgroup CongruenceSubgroupGamma0", [ IsCongruenceSubgroupGamma0 ], 0, function( G ) local n, a, b, gcd; n := LevelOfCongruenceSubgroup( G ); repeat a := Random( [ -n*10 .. n*10 ] ); b := n * Random( [ -10 .. 10 ] ); gcd := Gcdex( a, b ); until gcd.gcd = 1; return [ [ a, -gcd.coeff2 ], [ b, gcd.coeff1 ] ]; end); InstallOtherMethod( Random, "for a congruence subgroup CongruenceSubgroupGamma0", [ IsCongruenceSubgroupGamma0, IsPosInt ], 0, function( G, m ) local n, a, b, gcd; n := LevelOfCongruenceSubgroup( G ); repeat a := Random( [ -n*m .. n*m ] ); b := n * Random( [ -m .. m ] ); gcd := Gcdex( a, b ); until gcd.gcd = 1; return [ [ a, -gcd.coeff2 ], [ b, gcd.coeff1 ] ]; end); ############################################################################# ## ## The congruence subgroup CongruenceSubgroupGammaUpper0(N) consists of all matrices ## of the form [ * N ] ## [ * * ] ## InstallMethod( Random, "for a congruence subgroup CongruenceSubgroupGammaUpper0", [ IsCongruenceSubgroupGammaUpper0 ], 0, function( G ) local n, a, b, gcd; n := LevelOfCongruenceSubgroup( G ); repeat a := Random( [ -n*10 .. n*10 ] ); b := n * Random( [ -10 .. 10 ] ); gcd := Gcdex( a, b ); until gcd.gcd = 1; return [ [ a, b ], [ -gcd.coeff2, gcd.coeff1 ] ]; end); InstallOtherMethod( Random, "for a congruence subgroup CongruenceSubgroupGammaUpper0", [ IsCongruenceSubgroupGammaUpper0, IsPosInt ], 0, function( G, m ) local n, a, b, gcd; n := LevelOfCongruenceSubgroup( G ); repeat a := Random( [ -n*m .. n*m ] ); b := n * Random( [ -m .. m ] ); gcd := Gcdex( a, b ); until gcd.gcd = 1; return [ [ a, b ], [ -gcd.coeff2, gcd.coeff1 ] ]; end); ############################################################################# ## ## The congruence subgroup CongruenceSubgroupGamma1(N) consists of all matrices ## of the form [ 1+N * ] ## [ N 1+N ] ## InstallMethod( Random, "for a congruence subgroup CongruenceSubgroupGamma1", [ IsCongruenceSubgroupGamma1 ], 0, function( G ) local n, a, b, gcd; n := LevelOfCongruenceSubgroup( G ); repeat a := 1 + n * Random( [ -10 .. 10 ] ); b := n * Random( [ -10 .. 10 ] ); gcd := Gcdex( a, b ); until gcd.gcd = 1 and IsInt( (gcd.coeff1-1)/n ); return [ [ a, -gcd.coeff2 ], [ b, gcd.coeff1 ] ]; end); InstallOtherMethod( Random, "for a congruence subgroup CongruenceSubgroupGamma1", [ IsCongruenceSubgroupGamma1, IsPosInt ], 0, function( G, m ) local n, a, b, gcd; n := LevelOfCongruenceSubgroup( G ); repeat a := 1 + n * Random( [ -m .. m ] ); b := n * Random( [ -m .. m ] ); gcd := Gcdex( a, b ); until gcd.gcd = 1 and IsInt( (gcd.coeff1-1)/n ); return [ [ a, -gcd.coeff2 ], [ b, gcd.coeff1 ] ]; end); ############################################################################# ## ## The congruence subgroup CongruenceSubgroupGammaUpper1(N) consists of all matrices ## of the form [ 1+N N ] ## [ * 1+N ] ## InstallMethod( Random, "for a congruence subgroup CongruenceSubgroupGammaUpper1", [ IsCongruenceSubgroupGammaUpper1 ], 0, function( G ) local n, a, b, gcd; n := LevelOfCongruenceSubgroup( G ); repeat a := 1 + n * Random( [ -10 .. 10 ] ); b := n * Random( [ -10 .. 10 ] ); gcd := Gcdex( a, b ); until gcd.gcd = 1 and IsInt( (gcd.coeff1-1)/n ); return [ [ a, b ], [ -gcd.coeff2, gcd.coeff1 ] ]; end); InstallOtherMethod( Random, "for a congruence subgroup CongruenceSubgroupGammaUpper1", [ IsCongruenceSubgroupGammaUpper1, IsPosInt ], 0, function( G, m ) local n, a, b, gcd; n := LevelOfCongruenceSubgroup( G ); repeat a := 1 + n * Random( [ -m .. m ] ); b := n * Random( [ -m .. m ] ); gcd := Gcdex( a, b ); until gcd.gcd = 1 and IsInt( (gcd.coeff1-1)/n ); return [ [ a, b ], [ -gcd.coeff2, gcd.coeff1 ] ]; end); ############################################################################# ## #E ##congruence-1.2.3/lib/factor.g0000664000371700037170000001734713503171577017300 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W factor.gi The Congruence package Helena Verrill ## ## ############################################################################# # it will be useful to find the maximum value of the labels # though if space is not a problem, this could just return # the Length of the labels. __congruence_max_label:= function(L) local s, i; s:=1; for i in [1..Length(L)] do if (not L[i] = "even") and (not L[i] = "odd") and L[i] > s then s := L[i]; fi; od; return s; end;; # For a list of labels L such as # [1,3,4,7,4,7,3,1,"odd","even"], for reference, indices are: # 1 2 3 4 5 6 7 8 9 10 # want to produce a list: # [[9],[10],[1,8],[],[2,7],[3,5],...] # this is the list of the form: # [[all indices with L[x] = "odd"],[all indices with L[x] = "even"], # [all indices with L[x] = 1], ....] # assume L is a list of integers, or "odd" or "even". __congruence_edgepairs := function(L) local max, pairs, i; pairs:=[]; max:=__congruence_max_label(L); for i in [1..max+2] do pairs[i] := []; od; for i in [1..Length(L)] do if L[i]="odd" then Add(pairs[1],i); elif L[i]="even" then Add(pairs[2],i); else Add(pairs[L[i]+2],i); fi; od; return pairs; end;; # for each edge of a Farey Symbol, we compute the generator # which maps that edge to another edge. # (this is done at the same time as the fundamental # domain is computed, but the data may not have been stored, # and has to be recomputed; suggest change for a future version) # this function gives "edge gluing matrices" as a number in the # list of generators (gens); negative entries mean the inverse matrix, # e.g., -5 would mean (5th generator)^(-1) # (note, the list of labels in a Farey sequence says which edge is # glued to which; -2 and -3 means there is an elliptic point order # 2 or 3) # # the input is assumed to be a FareySymbol; # another version of this function could take input to be the group # # Note, if the output of this function was # stored as an attribute of the FareySymbol, # then it would not have to be recomputed # __congruence_gluing_matrices := function(FS) local cusps, gens, label_list, glue_list, l, i, index, gfs, labels, matrix; # the following is a list of the cusps of the sequence, # and other data extracted from the FareySymbol gfs := GeneralizedFareySequence(FS); labels := LabelsOfFareySymbol(FS); gens := GeneratorsByFareySymbol( FS ); # make a list of which edges have a given label: label_list := __congruence_edgepairs(labels); # the following list will be what is finally returned, # a list of integers as described above. glue_list := []; # make list of which generator joins two edges, # in the non elliptic case for i in [3..Length(label_list)] do l := label_list[i]; matrix := MatrixByFreePairOfIntervals( gfs, l[1], l[2] ); index := PositionNthOccurrence( gens ,matrix,1); if index = "fail" then index := -PositionNthOccurrence(gens,matrix^(-1),1); fi; glue_list[l[1]] := index; glue_list[l[2]] := -index; od; # Now deal with elliptic elements: for i in label_list[1] do matrix := MatrixByOddInterval( gfs, i ); index := PositionNthOccurrence(gens,matrix,1); if index = "fail" then index := -PositionNthOccurrence(gens,matrix^(-1),1); glue_list[i] := -index; else glue_list[i] := -index; fi; od; for i in label_list[2] do matrix := MatrixByEvenInterval( gfs, i ); index := PositionNthOccurrence(gens,matrix,1); if index = "fail" then index := -PositionNthOccurrence(gens,matrix^(-1),1); glue_list[i] := -index; else glue_list[i] := -index; fi; od; return glue_list; end;; # following function determines which edge an image ImL of # a domain is the longest # # The function either returns a index of an edge # which is a number between 1 and #L-1, # or it returns "overlap" meaning that there is overlap, but not equality. __congruence_longest_edge := function(ImL) local i, minImL, maxImL, maxindex, minindex; for i in [1..Length(ImL)] do if ImL[i] = infinity then return "infinity"; fi; od; minImL := Minimum(ImL); maxImL := Maximum(ImL); maxindex := PositionNthOccurrence( ImL ,maxImL,1); return maxindex; end;; # Need to be able to apply action of matrices to cusps __congruence_fractionallineartransformation:= function(g,c) local den, num; if c = infinity then if g[2][1] = 0 then return infinity; else return g[1][1]/g[2][1]; fi; else num:=g[1][1]*c + g[1][2]; den:=g[2][1]*c + g[2][2]; if den = 0 then return infinity; else return num/den; fi; fi; end;; __congruence_PSL2multiply := function(g,L) local imL, i; imL := []; for i in [1..Length(L)] do Add(imL,__congruence_fractionallineartransformation(g,L[i])); od; return imL; end;; # this an algorithm to determine a word for # a given matrix g in G in terms of the generators: find_word_ver2 := function(FS,glue_list,g) local gens, L, ImL, done, word,letter,i, edge, h, maybesame, inf; gens := GeneratorsByFareySymbol( FS ); L := GeneralizedFareySequence( FS ); ImL := __congruence_PSL2multiply(g,L); word:=[]; h := g; done := false; while not done do; edge := __congruence_longest_edge(ImL); if edge = "infinity" then # check equality of L and ImL: maybesame := true; i := 1; while i < Length(L) and maybesame do if not L[i] = ImL[i] then maybesame := false; fi; i := i+1; od; if maybesame then done := true; return Reversed(word); fi; # now assume the domains are not equal inf := PositionNthOccurrence( ImL , infinity ,1); if inf = 1 and ImL[2]L[2] then return "g is not in the group"; elif ImL[i+1]L[2] then return "g is not in the group"; fi; # now assume the domains do not overlap if ImL[inf+1] >= L[2] then letter := glue_list[inf]; elif inf = 1 then letter := glue_list[Length(glue_list)]; else letter := glue_list[inf-1]; fi; Add(word,letter); h:=h*gens[AbsoluteValue(letter)]^(-SignInt(letter)); ImL := __congruence_PSL2multiply(h,L); else # get next "letter" in the word for the matrix: letter := glue_list[edge]; Add(word,letter); h:=h*gens[AbsoluteValue(letter)]^(-SignInt(letter)); ImL := __congruence_PSL2multiply(h,L); fi; od; return Reversed(word); end;; ############################################################################# # # FactorizeMat( G, g ) # __congruence_FactorizeMat := function( G, g ) return find_word_ver2( FareySymbol(G), __congruence_gluing_matrices(FareySymbol(G)), g ); end; ############################################################################# # # CheckFactorizeMat(gens,word) # # the following function is for testing purposes: # gens is a list of generators, "word" a sequence of integers, none # of which is bigger than the size of the list of generators. # a word [4,6,-3] will return the product gens[4]*gens[6]*gens[3]^(-1) # __congruence_CheckFactorizeMat := function(gens,word) local g, i; g := [[1,0],[0,1]]; for i in word do g := g*gens[AbsoluteValue(i)]^SignInt(i); od; return g; end;congruence-1.2.3/lib/cong.g0000664000371700037170000001746313503171577016747 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W cong.g The Congruence package Ann Dooms #W Eric Jespers #W Alexander Konovalov ## ## ############################################################################# ############################################################################# # # CanEasilyCompareCongruenceSubgroups( G, H ) # InstallMethod( CanEasilyCompareCongruenceSubgroups, "for two congruence subgroups", [ IsCongruenceSubgroup, IsCongruenceSubgroup ], function ( G, H ) local i; if ForAll( [ G, H ], IsPrincipalCongruenceSubgroup ) or ForAll( [ G, H ], IsCongruenceSubgroupGamma0 ) or ForAll( [ G, H ], IsCongruenceSubgroupGammaUpper0 ) or ForAll( [ G, H ], IsCongruenceSubgroupGamma1 ) or ForAll( [ G, H ], IsCongruenceSubgroupGammaUpper1 ) then return LevelOfCongruenceSubgroup(G)=LevelOfCongruenceSubgroup(H); elif ForAll( [ G, H ], IsIntersectionOfCongruenceSubgroups ) then # we use the canonical ordering of subgroups # in the intersection of congruence subgroups if Length(DefiningCongruenceSubgroups(G)) <> Length(DefiningCongruenceSubgroups(H)) then return false; else return ForAll( [ 1 .. Length(DefiningCongruenceSubgroups(G)) ], i -> CanEasilyCompareCongruenceSubgroups( DefiningCongruenceSubgroups(G)[i], DefiningCongruenceSubgroups(H)[i]) ); fi; else return false; fi; end); ############################################################################# # # CanReduceIntersectionOfCongruenceSubgroups( G, H ) # # This function mimics the structure of the method for Intersection for # congruence subgroups. It returns true, if their intersection can be reduced # to one of the canonical congruence subgroups, and false otherwise, i.e. the # intersection can be expressed only as IntersectionOfCongruenceSubgroups. # This is used in IntersectionOfCongruenceSubgroups to reduce the list of # canonical subgroups forming the intersection. # InstallMethod( CanReduceIntersectionOfCongruenceSubgroups, "for two congruence subgroups", [ IsCongruenceSubgroup, IsCongruenceSubgroup ], function( G, H ) # # Case 1 - at least one subgroup is an intersection of congruence subgroups # if IsIntersectionOfCongruenceSubgroups(G) or IsIntersectionOfCongruenceSubgroups(H) then return false; # # Case 2 - the diagonal (both subgroups has the same type) # elif IsPrincipalCongruenceSubgroup(G) and IsPrincipalCongruenceSubgroup(H) then return true; elif IsCongruenceSubgroupGamma1(G) and IsCongruenceSubgroupGamma1(H) then return true; elif IsCongruenceSubgroupGammaUpper1(G) and IsCongruenceSubgroupGammaUpper1(H) then return true; elif IsCongruenceSubgroupGamma0(G) and IsCongruenceSubgroupGamma0(H) then return true; elif IsCongruenceSubgroupGammaUpper0(G) and IsCongruenceSubgroupGammaUpper0(H) then return true; # # Case 3 - Subgroups has different level # elif LevelOfCongruenceSubgroup(G) <> LevelOfCongruenceSubgroup(H) then return false; # # Now subgroups have the same level # elif IsCongruenceSubgroupGamma1(G) and IsCongruenceSubgroupGamma0(H) then return true; elif IsCongruenceSubgroupGamma0(G) and IsCongruenceSubgroupGamma1(H) then return true; elif IsCongruenceSubgroupGammaUpper1(G) and IsCongruenceSubgroupGammaUpper0(H) then return true; elif IsCongruenceSubgroupGammaUpper0(G) and IsCongruenceSubgroupGammaUpper1(H) then return true; elif IsCongruenceSubgroupGamma0(G) and IsCongruenceSubgroupGammaUpper0(H) or IsCongruenceSubgroupGammaUpper0(G) and IsCongruenceSubgroupGamma0(H) then return false; else return true; fi; end); ############################################################################# # # NumeratorOfGFSElement( gfs, i ) # # Returns the numerator of the i-th term of the generalised Farey sequence # gfs: for the 1st infinite entry returns -1, for the last one returns 1, # for all other entries returns usual numerator. # InstallGlobalFunction( "NumeratorOfGFSElement", function(gfs,i) if i in [ 2 .. Length(gfs)-1 ] then return NumeratorRat( gfs[i] ); elif i=1 then return -1; # infinity on the left elif i=Length(gfs) then return 1; # infinity on the right else Error("There is no entry number ", i, " in !!! \n"); fi; end); ############################################################################# # # DenominatorOfGFSElement( gfs, i ) # # Returns the denominator of the i-th term of the generalised Farey sequence # gfs: for both infinite entries returns 0, for the other ones returns usual # denominator. # InstallGlobalFunction( "DenominatorOfGFSElement", function(gfs,i) if i in [ 2 .. Length(gfs)-1 ] then return DenominatorRat( gfs[i] ); elif i=1 or i=Length(gfs) then return 0; else Error("There is no entry number ", i, " in !!! \n"); fi; end); ############################################################################# # # IsValidFareySymbol( fs ) # # This function is used in FareySymbolByData to validate its output # InstallGlobalFunction( "IsValidFareySymbol" , function( fs ) local gfs, labels, n, i, t; gfs := GeneralizedFareySequence(fs); labels := LabelsOfFareySymbol(fs); n := Length(gfs); if ForAny( [ 1 .. Length(labels) ], t -> not IsBound(labels[t] ) ) then Error(" must not contain holes !!! \n"); fi; if Length(labels)<>n-1 then Error("Lengths of and do not match !!! \n"); fi; if gfs[1]<>infinity or gfs[n]<>infinity then Error("First and last elements of must be infinity !!! \n"); fi; if not 0 in gfs then Error(" must contain at least one zero element !!! \n"); fi; for i in [ 1 .. n-1 ] do if NumeratorOfGFSElement(gfs,i+1) * DenominatorOfGFSElement(gfs,i) - NumeratorOfGFSElement(gfs,i) * DenominatorOfGFSElement(gfs,i+1) <> 1 then Error("a", i+1, "*b", i, " - a", i, "*b", i+1, " <> 1 !!! \n"); fi; od; if ForAny( Collected(labels), t -> IsInt(t[1]) and t[2]<>2 ) then Error(" are not properly paired !!! \n"); fi; return true; end); ############################################################################# # # MatrixByEvenInterval( gfs, i ) # InstallGlobalFunction( "MatrixByEvenInterval", function(gfs,i) local ai, bi, ai1, bi1; ai := NumeratorOfGFSElement(gfs,i); bi := DenominatorOfGFSElement(gfs,i); ai1 := NumeratorOfGFSElement(gfs,i+1); bi1 := DenominatorOfGFSElement(gfs,i+1); return [ [ ai1*bi1 + ai*bi, -ai^2 - ai1^2 ], [ bi^2 + bi1^2, -ai1*bi1 - ai*bi ] ]; end); ############################################################################# # # MatrixByOddInterval( gfs, i ) # InstallGlobalFunction( "MatrixByOddInterval", function(gfs,j) local aj, bj, aj1, bj1; aj := NumeratorOfGFSElement(gfs,j); bj := DenominatorOfGFSElement(gfs,j); aj1 := NumeratorOfGFSElement(gfs,j+1); bj1 := DenominatorOfGFSElement(gfs,j+1); return [ [ aj1*bj1 + aj*bj1 + aj*bj, -aj^2 - aj*aj1 - aj1^2 ], [ bj^2 + bj*bj1 + bj1^2, -aj1*bj1 - aj1*bj - aj*bj ] ]; end); ############################################################################# # # MatrixByFreePairOfIntervals( gfs, k, kp ) # InstallGlobalFunction( "MatrixByFreePairOfIntervals", function(gfs,k,kp) local ak, bk, ak1, bk1, akp, bkp, akp1, bkp1; ak := NumeratorOfGFSElement(gfs,k); bk := DenominatorOfGFSElement(gfs,k); ak1 := NumeratorOfGFSElement(gfs,k+1); bk1 := DenominatorOfGFSElement(gfs,k+1); akp := NumeratorOfGFSElement(gfs,kp); bkp := DenominatorOfGFSElement(gfs,kp); akp1 := NumeratorOfGFSElement(gfs,kp+1); bkp1 := DenominatorOfGFSElement(gfs,kp+1); return [ [ akp1*bk1 + akp*bk, -akp*ak - akp1*ak1 ], [ bkp*bk + bkp1*bk1, -ak1*bkp1 - ak*bkp ] ]; end); ############################################################################# ## #E ## congruence-1.2.3/lib/cong.gd0000664000371700037170000002235713503171577017111 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W cong.gd The Congruence package Ann Dooms #W Eric Jespers #W Alexander Konovalov ## ## ############################################################################# ############################################################################# ## ## InfoCongruence ## ## We declare new Info class for algorithms from the Congruence package. It ## has 3 levels - 0, 1 and 2. Default level is 1, and it is used to display ## messages when the package is used to replace existing GAP methods. ## To change Info level to k, use command SetInfoLevel(InfoCongruence, k) DeclareInfoClass("InfoCongruence"); ############################################################################# ## ## IsCongruenceSubgroup( ) ## ## We create category of congruence subgroups as a subcategory of matrix ## groups, and declare properties that are used to distinguish several ## important classes of congruence subgroups DeclareCategory( "IsCongruenceSubgroup", IsMatrixGroup ); ############################################################################# ## ## IsPrincipalCongruenceSubgroup( ) ## ## The principal congruence subgroup of level N consists of all matrices ## of the form [ 1+N N ] ## [ N 1+N ] ## DeclareProperty( "IsPrincipalCongruenceSubgroup", IsCongruenceSubgroup ); InstallTrueMethod(IsCongruenceSubgroup, IsPrincipalCongruenceSubgroup); ############################################################################# ## ## IsCongruenceSubgroupGamma0( ) ## ## The congruence subgroup CongruenceSubgroupGamma0(N) consists of all matrices ## of the form [ * * ] ## [ N * ] ## DeclareProperty( "IsCongruenceSubgroupGamma0", IsCongruenceSubgroup ); InstallTrueMethod(IsCongruenceSubgroup, IsCongruenceSubgroupGamma0); ############################################################################# ## ## IsCongruenceSubgroupGammaUpper0( ) ## ## The congruence subgroup CongruenceSubgroupGammaUpper0(N) consists of all matrices ## of the form [ * N ] ## [ * * ] ## DeclareProperty( "IsCongruenceSubgroupGammaUpper0", IsCongruenceSubgroup ); InstallTrueMethod(IsCongruenceSubgroup, IsCongruenceSubgroupGammaUpper0); ############################################################################# ## ## IsCongruenceSubgroupGamma1( ) ## ## The congruence subgroup CongruenceSubgroupGamma1(N) consists of all matrices ## of the form [ 1+N * ] ## [ N 1+N ] ## DeclareProperty( "IsCongruenceSubgroupGamma1", IsCongruenceSubgroup ); InstallTrueMethod(IsCongruenceSubgroup, IsCongruenceSubgroupGamma1); ############################################################################# ## ## IsCongruenceSubgroupGammaUpper1( ) ## ## The congruence subgroup CongruenceSubgroupGammaUpper1(N) consists of all matrices ## of the form [ 1+N N ] ## [ * 1+N ] ## DeclareProperty( "IsCongruenceSubgroupGammaUpper1", IsCongruenceSubgroup ); InstallTrueMethod(IsCongruenceSubgroup, IsCongruenceSubgroupGammaUpper1); ############################################################################# ## ## IsCongruenceSubgroupGammaMN( ) ## ## The congruence subgroup CongruenceSubgroupGammaMN(M,N) consists of all matrices ## of the form [ 1+M M ] ## [ N 1+N ] ## DeclareProperty( "IsCongruenceSubgroupGammaMN", IsCongruenceSubgroup ); InstallTrueMethod(IsCongruenceSubgroup, IsCongruenceSubgroupGammaMN); ############################################################################# ## ## IsIntersectionOfCongruenceSubgroups( ) ## ## This property will be uses for subgroups of SL_2(Z) that were constructed ## as intersection of a finite number of congruence subgroups of types ## CongruenceSubgroupGamma, CongruenceSubgroupGamma_0, ## CongruenceSubgroupGamma^0, CongruenceSubgroupGamma_1, ## CongruenceSubgroupGamma^1 and CongruenceSubgroupGammaMN ## DeclareProperty( "IsIntersectionOfCongruenceSubgroups", IsCongruenceSubgroup ); InstallTrueMethod(IsCongruenceSubgroup, IsIntersectionOfCongruenceSubgroups); ############################################################################# ## ## PrincipalCongruenceSubgroup( n ) ## CongruenceSubgroupGamma0( n ) ## CongruenceSubgroupGammaUpper0( n ) ## CongruenceSubgroupGamma1( n ) ## CongruenceSubgroupGammaUpper1( n ) ## CongruenceSubgroupGammaMN( m, n ) ## ## Declaration of global functions - constructors of congruence subgroups ## DeclareOperation("PrincipalCongruenceSubgroup", [IsPosInt]); DeclareOperation("CongruenceSubgroupGamma0", [IsPosInt]); DeclareOperation("CongruenceSubgroupGammaUpper0", [IsPosInt]); DeclareOperation("CongruenceSubgroupGamma1", [IsPosInt]); DeclareOperation("CongruenceSubgroupGammaUpper1", [IsPosInt]); DeclareOperation("CongruenceSubgroupGammaMN", [IsPosInt,IsPosInt]); ############################################################################# ## ## LevelOfCongruenceSubgroup( ) ## ## The (arithmetic) level of a congruence subgroup G is the smallest positive ## number N such that G contains the principal congruence subgroup of level N ## DeclareAttribute( "LevelOfCongruenceSubgroup", IsCongruenceSubgroup ); ############################################################################# ## ## LevelOfCongruenceSubgroupGammaMN( ) ## ## For the congruence subgroup GammaMN we need to store additionally ## two integers determining the 1st and 2nd lines of the matrix ## DeclareAttribute( "LevelOfCongruenceSubgroupGammaMN", IsCongruenceSubgroup ); ############################################################################# ## ## IndexInSL2Z( ) ## ## The index of a congruence subgroup in SL_2(Z) will be stored as its ## attribute. This also will allow us to install a method for Index(G,H) when ## G is SL_2(Z) and H is a congruence subgroup. You should remember that we ## are working with the SL_2(Z), because it is available in GAP, and not with ## the PSL_2(Z) since the latter is not implemented in GAP. ## DeclareAttribute( "IndexInSL2Z", IsCongruenceSubgroup ); ############################################################################# ## ## IntersectionOfCongruenceSubgroups( ) ## ## We declare special type of congruence subgroups that are intersections of ## a finite number congruence subgroups of types CongruenceSubgroupGamma, ## CongruenceSubgroupGamma_0, CongruenceSubgroupGamma^0, CongruenceSubgroupGamma_1 ## and CongruenceSubgroupGamma^1. The list of subgroups defining this ## intersection will be stored in the attribute "DefiningCongruenceSubgroups". ## DeclareGlobalFunction("IntersectionOfCongruenceSubgroups"); DeclareAttribute( "DefiningCongruenceSubgroups", IsCongruenceSubgroup ); ############################################################################# # # CanEasilyCompareCongruenceSubgroups( G, H ) # DeclareOperation( "CanEasilyCompareCongruenceSubgroups", [ IsCongruenceSubgroup, IsCongruenceSubgroup ] ); ############################################################################# # # CanReduceIntersectionOfCongruenceSubgroups( G, H ) # # This function mimics the structure of the method for Intersection for # congruence subgroups. It returns true, if their intersection can be reduced # to one of the canonical congruence subgroups, and false otherwise, i.e. the # intersection can be expressed only as IntersectionOfCongruenceSubgroups. # This is used in IntersectionOfCongruenceSubgroups to reduce the list of # canonical subgroups forming the intersection. # DeclareOperation( "CanReduceIntersectionOfCongruenceSubgroups", [ IsCongruenceSubgroup, IsCongruenceSubgroup ] ); ############################################################################# # # NumeratorOfGFSElement( gfs, i ) # # Returns the numerator of the i-th term of the generalised Farey sequence # gfs: for the 1st infinite entry returns -1, for the last one returns 1, # for all other entries returns usual numerator. # DeclareGlobalFunction( "NumeratorOfGFSElement" ); ############################################################################# # # DenominatorOfGFSElement( gfs, i ) # # Returns the denominator of the i-th term of the generalised Farey sequence # gfs: for both infinite entries returns 0, for the other ones returns usual # denominator. # DeclareGlobalFunction( "DenominatorOfGFSElement" ); ############################################################################# # # IsValidFareySymbol( fs ) # # This function is used in FareySymbolByData to validate its output # DeclareGlobalFunction( "IsValidFareySymbol" ); ############################################################################# # # MatrixByEvenInterval( gfs, i ) # DeclareGlobalFunction( "MatrixByEvenInterval" ); ############################################################################# # # MatrixByOddInterval( gfs, i ) # DeclareGlobalFunction( "MatrixByOddInterval" ); ############################################################################# # # MatrixByFreePairOfIntervals( gfs, k, kp ) # DeclareGlobalFunction( "MatrixByFreePairOfIntervals" ); ############################################################################# ## #E ## congruence-1.2.3/lib/farey.gi0000664000371700037170000002677113503171577017302 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W farey.gi The Congruence package Ann Dooms #W Eric Jespers #W Alexander Konovalov ## ## ############################################################################# ############################################################################# ## ## IsFareySymbolDefaultRep ## DeclareRepresentation( "IsFareySymbolDefaultRep", IsPositionalObjectRep, [ 1, 2 ] ); ############################################################################# ## ## FareySymbolByData( , ) ## ## This constructor creates Farey symbol with the given generalized Farey ## sequence and list of labels. It also checks conditions from the definition ## of Farey symbol and returns an error if they are not satisfied ## InstallMethod( FareySymbolByData, "for two lists that are g.F.S. and labels for Farey symbol", [ IsList, IsList ], 0, function( gfs, labels) local fs; fs :=Objectify( NewType( NewFamily("FareySymbolsFamily", IsFareySymbol), IsFareySymbol), [ gfs, labels ] ); if IsValidFareySymbol(fs) then return fs; else Error(" is not a valid Farey symbol !!! \n"); fi; end); ############################################################################# ## ## GeneralizedFareySequence( ) ## LabelsOfFareySymbol( ) ## ## The data used to create the Farey symbol are stored as its attributes ## InstallMethod( GeneralizedFareySequence, "for Farey symbol in default representation", [ IsFareySymbol ], fs -> fs![1]); InstallMethod( LabelsOfFareySymbol, "for Farey symbol in default representation", [ IsFareySymbol ], fs -> fs![2] ); ############################################################################# ## ## ViewObj( fs ) ## PrintObj( fs ) ## InstallMethod( ViewObj, "for Farey symbol", [ IsFareySymbol ], 0, function(fs) Print( GeneralizedFareySequence(fs), "\n", LabelsOfFareySymbol(fs) ); end); InstallMethod( PrintObj, "for Farey symbol", [ IsFareySymbol ], 0, function(fs) Print( "FareySymbolByData( ", GeneralizedFareySequence(fs), ", ", LabelsOfFareySymbol(fs), " ] " ); end); ############################################################################# ## ## FareySymbol( ) ## ## For a subgroup of a finite index G, this attribute stores the ## corresponding Farey symbol. The algorithm for its computation must work ## with any matrix group for which the membership test is available ## InstallMethod( FareySymbol, "for a congruence subgroup", [ IsCongruenceSubgroup ], 0, function( G ) local gfs, # generalized Farey sequence (g.F.S.) labels, # labels of this g.F.S. fs, # resulting Farey symbol i, j, k, t, # counters stepnr, # number of the inductive ste newvertex, # new vertex to be inserted on the current inductive step unpairednr, # number of the 1st vertex of the unpaired side lastlabel, # last used label mat, # matrix by free pair of intervals unpairednumbers, # list of positions with assigned labels denominators, # denominators of current g.F.S. elements possibledenominators, # list of denominators arising from these positions minden, # minimum of possible denominators pos, # chosen position of minden in possibledenominators nrlabels, # number of labels assigned range1, # range for the search of odd and even labels range2, # range for the search of free (i.e.numerical) labels isfirstlabelssearch; # flag for determining of the range1 and range2 # # Initial data setup # if LevelOfCongruenceSubgroup(G)=1 then return FareySymbolByData( [ infinity, 0, infinity ], ["even","odd"]) ; fi; gfs := [ infinity, 0, infinity ]; labels:=[]; nrlabels:=0; stepnr:=0; lastlabel:=0; isfirstlabelssearch:=true; # # we perform the next loop until we will have fully labeled gfs # while nrlabels < Length( gfs ) - 1 do stepnr:=stepnr+1; Info( InfoCongruence, 2, "Step ", stepnr, " : g.F.S. of length ", Length(gfs), " with ", nrlabels, " labels"); Info( InfoCongruence, 3, " gfs = ", gfs ); Info( InfoCongruence, 3, "labels = ", labels ); # # 1. Choose any of the unpaired sides and insert new vertex # # 1.1. Find unpaired side that will give us a new vertex # with the minimal denominator (on the first step we # do some trick to get [infinity,0,1,infinity]) unpairednumbers := Filtered( [ 1 .. Length(gfs)-1 ], i -> not IsBound( labels[ i ] ) ); Info( InfoCongruence, 3, "Positions of unpaired labels : ", unpairednumbers ); # to avoid repeated calls of DenominatorOfGFSElement, we are caching # values of denominators from required positions denominators := []; for i in unpairednumbers do if not IsBound(denominators[i]) then denominators[i]:=DenominatorOfGFSElement(gfs,i); fi; denominators[i+1]:=DenominatorOfGFSElement(gfs,i+1); od; possibledenominators := List( unpairednumbers, i -> denominators[i] + denominators[i+1] ); Info( InfoCongruence, 3, "Possible denominators : ", possibledenominators ); minden := Minimum(possibledenominators); # we give priority to positive numbers in g.F.S. pos:=PositionProperty( [ 1 .. Length(unpairednumbers) ], i -> ( possibledenominators[i] = minden ) and ( NumeratorOfGFSElement( gfs, unpairednumbers[i] ) >=0 ) ); if pos=fail then pos:=PositionProperty( [ 1 .. Length(unpairednumbers) ], i -> possibledenominators[i] = minden ); fi; unpairednr := unpairednumbers[ pos ]; #i:=1; #repeat # pos := PositionNthOccurrence( possibledenominators, minden, i ); # i := i+1; # unpairednr := unpairednumbers[ pos ]; #until NumeratorOfGFSElement(gfs, unpairednr) >= 0; # # 1.2. Compute new vertex by the Farey sequence rule # newvertex := ( NumeratorOfGFSElement(gfs, unpairednr) + NumeratorOfGFSElement(gfs, unpairednr+1) ) / minden; # # 1.3. Insert this new vertex and an empty spot for the label # Info( InfoCongruence, 2, "Inserting ", newvertex, " at position ", unpairednr+1); Add( gfs, newvertex, unpairednr+1); Add( unpairednumbers, unpairednr, pos ); for i in [ pos+1 .. Length(unpairednumbers) ] do unpairednumbers[i] := unpairednumbers[i]+1; od; Add( labels, "hole" , unpairednr ); Unbind(labels[unpairednr]); # # 2. For each of new sides, we check if they are paired and # assign labels, if this is the case # if isfirstlabelssearch then range1 := [ 1 .. Length(gfs)-1 ]; range2 := [ 1 .. Length(gfs)-1 ]; else # if we already checked all cases for all possible labels, # on each new step it is enough to check only new intervals range1 := [ unpairednr, unpairednr+1 ]; # Slower but more obvious options for range2 could be: # range2 := [ 1 .. Length(gfs)-1 ]; # range2:= Filtered( [ 1 .. Length(gfs)-1 ], i -> not IsBound( labels[ i ] ) ); # but we use the fastest one range2 := unpairednumbers; fi; if not ( IsPrincipalCongruenceSubgroup(G) and LevelOfCongruenceSubgroup(G) > 2 ) then for i in range1 do # we do not check that labels[i] is not bound because this is # guaranteed by the algorithm mat := MatrixByOddInterval( gfs, i ); if mat in G or -mat in G then labels[i]:="odd"; nrlabels:=nrlabels+1; Info( InfoCongruence, 2, "Putting label ", lastlabel, " at position ", i ); else mat := MatrixByEvenInterval( gfs, i ); if mat in G or -mat in G then labels[i]:="even"; nrlabels:=nrlabels+1; Info( InfoCongruence, 2, "Putting label ", lastlabel, " at position ", i ); fi; fi; od; fi; for i in range1 do for j in range2 do # we eliminate the case i=j since we always check different intervals # now we check that both labels[i] and labels[j] are not bound for a case # if they were already assigned during the search for odd/even labels if i<>j and not IsBound( labels[i] ) and not IsBound( labels[j] ) then mat := MatrixByFreePairOfIntervals( gfs, i, j ); if mat in G or -mat in G then lastlabel := lastlabel+1; labels[i]:=lastlabel; labels[j]:=lastlabel; nrlabels:=nrlabels+2; Info( InfoCongruence, 2, "Putting label ", lastlabel, " at positions ", i, " and ", j ); # since i-th interval can be paired only with one j-th interval, # we quit from inner loop and go to the next i break; fi; fi; od; od; isfirstlabelssearch:=false; if stepnr mod 25000 = 0 then Error("You reached the checkpoint on the ", stepnr, "th iteration \n", "Currently you have g.F.S. of length ", Length(gfs), " with ", nrlabels, " labels assigned \n", "Use the index of the subgroup to get an idea about possible length of the g.F.S.:\n", "it will be equal to the index of in PSL_2Z minus the number of odd intervals in g.F.S.\n"); fi; od; fs := FareySymbolByData( gfs, labels) ; return fs; end); ############################################################################# # # GeneratorsByFareySymbol( fs ) # InstallGlobalFunction( GeneratorsByFareySymbol, function( fs ) local gfs, labels, usedlabels, gens, i, j, m; gfs := GeneralizedFareySequence(fs); labels := LabelsOfFareySymbol(fs); usedlabels:=[]; gens:=[]; for i in [ 1 .. Length(labels) ] do if labels[i]="even" then Info( InfoCongruence, 2, "labels[", i, "] = ", labels[i] ); m := MatrixByEvenInterval( gfs, i ); Add( gens, m ); if InfoLevel( InfoCongruence ) = 2 then Display(m); fi; elif labels[i]="odd" then Info( InfoCongruence, 2, "labels[", i, "] = ", labels[i] ); m := MatrixByOddInterval( gfs, i ); Add( gens, m ); if InfoLevel( InfoCongruence ) = 2 then Display(m); fi; elif not labels[i] in usedlabels then j := PositionNthOccurrence( labels, labels[i], 2 ); Info( InfoCongruence, 2, "labels[", i, "] = ", labels[i], " = labels[", j, "]" ); m := MatrixByFreePairOfIntervals( gfs, i, j ); Add( gens, m ); Add( usedlabels, labels[i] ); if InfoLevel( InfoCongruence ) = 2 then Display(m); fi; fi; od; return gens; end); ############################################################################# # # IndexInPSL2ZByFareySymbol( fs ) # # By the proposition 7.2 [Kulkarni], for the Farey symbol with underlying # generalized Farey sequence { infinity, x0, x1, ..., xn, infinity }, the # index in PSL_2(Z) is given by the formula d = 3*n + e3, where e3 is the # number of odd intervals. # InstallGlobalFunction( IndexInPSL2ZByFareySymbol, function( fs ) local n, e3, x, d; n := Length( GeneralizedFareySequence(fs) ) - 3; e3:= Number( LabelsOfFareySymbol(fs), x -> x = "odd" ); d := 3 * n + e3; return d; end); ############################################################################# ## #E ## congruence-1.2.3/lib/units.g0000664000371700037170000001262613503171577017157 0ustar gap-jenkinsgap-jenkins############################################################################# # # units.g The Congruence package Ann Dooms # Eric Jespers # Alexander Konovalov # ############################################################################# ############################################################################# # # NormalSubgroupsForM2Q(G,H) # # Returns a list of normal subgroups N of G such that quotient G/N is H. # NormalSubgroupsForM2Q := function( G, H ) local ord,m, N; ord:= Size(G)/Size(H); # Can we speedup this computing only normal subgroups of given size? m:=Filtered( NormalSubgroups(G) , N -> Size(N)=ord); m:=Filtered( m, N -> IdGroup( G/N ) = IdGroup( H ) ); return m; end; ############################################################################# # # GeneratorsInM2Q(G,H) # # Returns a list of lists of generators of a subgroup of f.i. in M_2(Q), # one for each homomorphic image. # H has to be S3 or D8! # GeneratorsInM2Q:=function(G,H) local k,m; if IdGroup(H)=[6,1] then k:=3; # H = S_3 else k:=4; # H = D_8 fi; m:=NormalSubgroupsForM2Q(G,H); if Length(m) > 0 then return GeneratorsOfGroup( PrincipalCongruenceSubgroup(k*Size(G)/Size(H) ) ); else return [ ]; fi; end; ############################################################################# # # MatrixEntries( matrix, k ) # # Returns a list with integer entries. Will be applied with k=4n or 3n. # PROBLEM: some matrices gave non-integers! SOLUTION: multiplied with -I_2! # MatrixEntries := function( matrix, k ) local g11,g12,g21,g22; g11:=(matrix[1][1]-1)/k; if not IsInt(g11) then matrix:=-matrix; g11:=(matrix[1][1]-1)/k; fi; g12:=matrix[1][2]/k; g21:=matrix[2][1]/k; g22:=(matrix[2][2]-1)/k; return [ g11, g12, g21, g22 ]; end; ############################################################################# # # D8Alpha(matrix,n) # # Returns a list with integer entries. # Will be applied with n = order of the normal subgroup N determining M_2(Q). # D8Alpha := function(matrix,n) local m,a0,a1,a2,a3; m := MatrixEntries(matrix,4*n); a0 := m[1] + m[4]; a1 := m[1] - m[2] + 2*m[3] - m[4]; a2 := m[1] + 2*m[3] - m[4]; a3 :=-m[1] + m[2] + m[4]; return [ a0, a1, a2, a3 ]; end; ############################################################################# # # S3Alpha(matrix,n) # # Returns a list with integer entries. # Will be applied with n = order of the normal subgroup N determining M_2(Q). # S3Alpha:= function(matrix,n) local m,a0,a1,a2,a3; m := MatrixEntries(matrix,3*n); a0 := m[1] + m[4]; a1 := 2*m[1] + 3*m[2] - m[3] - m[4]; a2 := -2*m[1] - 3*m[2] + m[3] + 2*m[4]; a3 := -m[1] - 3*m[2] + m[4]; return [ a0, a1, a2, a3 ]; end; ############################################################################# # # Alphas( G, H ) # # Returns a list of lists with integer entries which will serve for the units in U(ZG). # Alphas := function( G, H ) local gen,f,alpha,i; gen := GeneratorsInM2Q( G, H ); if IdGroup(H)=[6,1] then f:=S3Alpha; else f:=D8Alpha; fi; alpha:=[]; if Length(gen) > 0 then for i in [1..Length(gen)] do alpha[i] := f( gen[i], Size(G)/Size(H) ); od; fi; return alpha; end; ############################################################################# # # LiftGenerator(G,N) # # Lifts a minimal list of generators form G/N to G. # LiftGenerator := function( G, N ) local l,q,s,hom,i; l:=[]; hom:=NaturalHomomorphismByNormalSubgroup(G,N); q := Image( hom ); s := MinimalGeneratingSet( q ); for i in [ 1 .. Length(s) ] do Add( l, PreImagesRepresentative( hom,s[i]) ); od; return l; end; ############################################################################# # # CreateUnits(G,H) # # Creates units of ZG. H must be D8 or S3. # CreateUnits:=function(G,H) local m,alpha,a,b,x,y,ZG,emb,hat,u,i,j; m:=NormalSubgroupsForM2Q(G,H); alpha:=Alphas(G,H); a:=[]; b:=[]; ZG:=GroupRing(Integers,G); emb := Embedding(G,ZG); hat:=[]; u:=[]; if Length(m)<>0 then for i in [1..Length(m)] do hat[i]:=Sum( List(m[i], x->x^emb)); u[i]:=[]; x := LiftGenerator(G,m[i])[1]; y := LiftGenerator(G,m[i])[2]; if x^2=Identity(G) then a[i]:=y^emb; b[i]:=x^emb; else a[i]:=x^emb; b[i]:=y^emb; fi; if IdGroup(H)=[6,1] then for j in [1..Length(alpha)] do u[i][j]:=Identity(ZG) + (alpha[j][1]*Identity(ZG) + alpha[j][2]*a[i] + alpha[j][3]*b[i] + alpha[j][4]*a[i]^2*b[i])*(Identity(ZG)-a[i])*hat[i]; od; else for j in [1..Length(alpha)] do u[i][j]:=Identity(ZG) + (alpha[j][1]*Identity(ZG) + alpha[j][2]*a[i] + alpha[j][3]*b[i] + alpha[j][4]*a[i]*b[i])*(Identity(ZG)-a[i]^2)*hat[i]; od; fi; od; else fi; return u; end; ############################################################################# # # UnitsOfZGOfFiniteIndexInM2Q(G) # UnitsOfZGOfFiniteIndexInM2Q:= function(G) local u,v; u:=[]; v:=[]; if IsNilpotent(G)=true then u:=CreateUnits(G,DihedralGroup(8)); else u:=CreateUnits(G,DihedralGroup(8)); v:=CreateUnits(G,DihedralGroup(6)); fi; return [u,v]; end;congruence-1.2.3/doc/chapBib_mj.html0000664000371700037170000001063513503171577020546 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - References
Goto Chapter: Top 1 2 3 4 5 Bib Ind

References

[CLLT93] Chan, S.-P., Lang, M.-L., Lim, C.-H. and Tan, S. P., Special polygons for subgroups of the modular group and applications, Internat. J. Math., 4 (1) (1993), 11--34.

[Kul91] Kulkarni, R. S., An arithmetic-geometric method in the study of the subgroups of the modular group, Amer. J. Math., 113 (6) (1991), 1053--1133.

[LLT95a] Lang, M.-L., Lim, C.-H. and Tan, S. P., An algorithm for determining if a subgroup of the modular group is congruence, J. London Math. Soc. (2), 51 (3) (1995), 491--502.

[LLT95b] Lang, M.-L., Lim, C.-H. and Tan, S. P., Independent generators for congruence subgroups of Hecke groups, Math. Z., 220 (4) (1995), 569--594.

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chap0_mj.html0000664000371700037170000003516313503171577020214 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Contents
Goto Chapter: Top 1 2 3 4 5 Bib Ind

Congruence

Congruence subgroups of \(SL_2(ℤ)\)

Version 1.2.3

19 May 2019

Ann Dooms
Email: andooms@vub.ac.be
Homepage: http://homepages.vub.ac.be/~andooms
Address:
Department of Mathematics, Vrije Universiteit Brussel
Pleinlaan 2, Brussels, B-1050 Belgium

Eric Jespers
Email: efjesper@vub.ac.be
Homepage: http://homepages.vub.ac.be/~efjesper
Address:
Department of Mathematics, Vrije Universiteit Brussel
Pleinlaan 2, Brussels, B-1050 Belgium

Alexander Konovalov
Email: alexander.konovalov@st-andrews.ac.uk
Homepage: https://alexk.host.cs.st-andrews.ac.uk
Address:
School of Computer Science
University of St Andrews
Jack Cole Building, North Haugh,
St Andrews, Fife, KY16 9SX, Scotland

Helena Verrill
Email: verrill@math.lsu.edu
Homepage: http://www.math.lsu.edu/~verrill/
Address:
Department of Mathematics
Louisiana State University
Baton Rouge, Louisiana, 70803-4918
USA

Abstract

The GAP package Congruence provides functionality to work with congruence subgroups of \(SL_2(ℤ)\).

Copyright

© 2006-2019 by Ann Dooms, Eric Jespers, Alexander Konovalov and Helena Verrill.

Congruence 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. For details, see the FSF's own site http://www.gnu.org/licenses/gpl.html.

If you obtained Congruence, we would be grateful for a short notification sent to one of the authors.

If you publish a result which was partially obtained with the usage of Congruence, please cite it in the following form:

A. Dooms, E. Jespers, A. Konovalov and H. Verrill. Congruence --- Congruence subgroups of \(SL_2(ℤ)\), Version 1.2.3; 2019 (http://www.cs.st-andrews.ac.uk/~alexk/congruence/).

Acknowledgements

We are very grateful to Mong-Lung Lang, Chong-Hai Lim and Ser Peow Tan for their comments provided while implementing algorithms from [LLT95a] and [LLT95b], and to Francqui Stichting (Belgium) for the support of the third author.

Contents


Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chap2.html0000664000371700037170000007774413503171577017543 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Chapter 2: Construction of congruence subgroups
Goto Chapter: Top 1 2 3 4 5 Bib Ind

2 Construction of congruence subgroups

The package Congruence provides functions to construct several types of canonical congruence subgroups in SL_2(ℤ), and also intersections of a finite number of such subgroups. They will return a matrix group in the category IsCongruenceSubgroup, which is defined as a subcategory of IsMatrixGroup, and which will have a distinguishing property determining whether it is a congruence subgroup of one of the canonical types, or an intersection of such congruence subgroups (if it can not be reduced to one of the canonical congruence subgroups). To start to work with the package, you need first to load it as follows:


gap> LoadPackage("congruence");
-----------------------------------------------------------------------------
Loading  Congruence 1.1.0 (Congruence subgroups of SL(2,Integers))
by Ann Dooms (http://homepages.vub.ac.be/~andooms),
   Eric Jespers (http://homepages.vub.ac.be/~efjesper),
   Alexander Konovalov (http://www.cs.st-andrews.ac.uk/~alexk/), and
   Helena Verrill (http://www.math.lsu.edu/~verrill).
-----------------------------------------------------------------------------
true

2.1 Construction of congruence subgroups

2.1-1 PrincipalCongruenceSubgroup
‣ PrincipalCongruenceSubgroup( N )( operation )

Returns the principal congruence subgroup Γ(N) of level N in SL_2(ℤ).

This subgroup consists of all matrices of the form


                         [1+N*a    N*b]
                         [  N*c  1+N*d]

where a,b,c,d are integers. The returned group will have the property IsPrincipalCongruenceSubgroup (2.2-1).


gap> G_8:=PrincipalCongruenceSubgroup(8);
<principal congruence subgroup of level 8 in SL_2(Z)>
gap> IsGroup(G_8);
true
gap> IsMatrixGroup(G_8);
true
gap> DimensionOfMatrixGroup(G_8);
2
gap> MultiplicativeNeutralElement(G_8);
[ [ 1, 0 ], [ 0, 1 ] ]
gap> One(G);
[ [ 1, 0 ], [ 0, 1 ] ]
gap> [[1,2],[3,4]] in G_8;
false
gap> [[1,8],[8,65]] in G_8;
true
gap> SL_2:=SL(2,Integers);
SL(2,Integers)
gap> IsSubgroup(SL_2,G_8);
true

2.1-2 CongruenceSubgroupGamma0
‣ CongruenceSubgroupGamma0( N )( operation )

Returns the congruence subgroup Γ_0(N) of level N in SL_2(ℤ).

This subgroup consists of all matrices of the form


                         [a    b]
                         [N*c  d]

where a,b,c,d are integers. The returned group will have the property IsCongruenceSubgroupGamma0 (2.2-2).


gap> G0_4:=CongruenceSubgroupGamma0(4);
<congruence subgroup CongruenceSubgroupGamma_0(4) in SL_2(Z)>

2.1-3 CongruenceSubgroupGammaUpper0
‣ CongruenceSubgroupGammaUpper0( N )( operation )

Returns the congruence subgroup Γ^0(N) of level N in SL_2(ℤ).

This subgroup consists of all matrices of the form


                         [a  N*b]
                         [c    d]

where a,b,c,d are integers. The returned group will have the property IsCongruenceSubgroupGammaUpper0 (2.2-3).


gap> GU0_2:=CongruenceSubgroupGammaUpper0(2);
<congruence subgroup CongruenceSubgroupGamma^0(2) in SL_2(Z)>

2.1-4 CongruenceSubgroupGamma1
‣ CongruenceSubgroupGamma1( N )( operation )

Returns the congruence subgroup Γ_1(N) of level N in SL_2(ℤ).

This subgroup consists of all matrices of the form


                         [1+N*a      b]
                         [  N*c  1+N*d]

where a,b,c,d are integers. The returned group will have the property IsCongruenceSubgroupGamma1 (2.2-4).


gap> G1_6:=CongruenceSubgroupGamma1(6);
<congruence subgroup CongruenceSubgroupGamma_1(6) in SL_2(Z)>

2.1-5 CongruenceSubgroupGammaUpper1
‣ CongruenceSubgroupGammaUpper1( N )( operation )

Returns the congruence subgroup Γ^1(N) of level N in SL_2(ℤ).

This subgroup consists of all matrices of the form


                         [1+N*a    N*b]
                         [    c  1+N*d]

where a,b,c,d are integers. The returned group will have the property IsCongruenceSubgroupGammaUpper1 (2.2-5).


gap> GU1_4:=CongruenceSubgroupGammaUpper1(4);
<congruence subgroup CongruenceSubgroupGamma^1(4) in SL_2(Z)>

2.1-6 IntersectionOfCongruenceSubgroups
‣ IntersectionOfCongruenceSubgroups( G1, G2, ..., GN )( function )
‣ Intersection( G1, G2, ..., GN )( function )

Returns the intersection of its arguments, which can be congruence subgroups or their intersections, constructed with the same function. It is not necessary for the user to use IntersectionOfCongruenceSubgroups, since it will be called automatically from Intersection.

The returned group will have the property IsIntersectionOfCongruenceSubgroups (2.2-6).

The list of congruence subgroups that form the intersection can be obtained using DefiningCongruenceSubgroups (2.3-3). Note, that when the intersection appears to be one of the canonical congruence subgroups, the package will recognize this and will return a canonical subgroup of the appropriate type.


gap> I:=IntersectionOfCongruenceSubgroups(G0_4,GU1_4);
<principal congruence subgroup of level 4 in SL_2(Z)>
gap> J:=IntersectionOfCongruenceSubgroups(G0_4,G1_6);
<intersection of congruence subgroups of resulting level 12 in SL_2(Z)>

2.2 Properties of congruence subgroups

A congruence subgroup constructed by one of the five above listed functions will have certain properties determining its type. These properties will be used for method selection by Congruence algorithms. Note that they do not provide an actual test whether a certain matrix group is a congruence subgroup or not.

2.2-1 IsPrincipalCongruenceSubgroup
‣ IsPrincipalCongruenceSubgroup( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by PrincipalCongruenceSubgroup (2.1-1) (or reduced to one as a result of an intersection) and returns false otherwise.


gap> IsPrincipalCongruenceSubgroup(G_8);
true
gap> IsPrincipalCongruenceSubgroup(G0_4);
false
gap> IsPrincipalCongruenceSubgroup(I);
true

2.2-2 IsCongruenceSubgroupGamma0
‣ IsCongruenceSubgroupGamma0( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGamma0 (2.1-2) (or reduced to one as a result of an intersection) and returns false otherwise.

2.2-3 IsCongruenceSubgroupGammaUpper0
‣ IsCongruenceSubgroupGammaUpper0( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGammaUpper0 (2.1-3) (or reduced to one as a result of an intersection) and returns false otherwise.

2.2-4 IsCongruenceSubgroupGamma1
‣ IsCongruenceSubgroupGamma1( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGamma1 (2.1-4) (or reduced to one as a result of an intersection) and returns false otherwise.

2.2-5 IsCongruenceSubgroupGammaUpper1
‣ IsCongruenceSubgroupGammaUpper1( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGammaUpper1 (2.1-5) (or reduced to one as a result of an intersection) and returns false otherwise.

2.2-6 IsIntersectionOfCongruenceSubgroups
‣ IsIntersectionOfCongruenceSubgroups( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by IntersectionOfCongruenceSubgroups (2.1-6) and without being one of the canonical congruence subgroups, otherwise it returns false.


gap> IsIntersectionOfCongruenceSubgroups(I);
false
gap> IsIntersectionOfCongruenceSubgroups(J);
true

2.3 Attributes of congruence subgroups

The next three attributes store key properties of congruence subgroups.

2.3-1 LevelOfCongruenceSubgroup
‣ LevelOfCongruenceSubgroup( G )( attribute )

Stores the level of the congruence subgroup G. The (arithmetic) level of a congruence subgroup G is the smallest positive number N such that G contains the principal congruence subgroup of level N.


gap> LevelOfCongruenceSubgroup(G_8);
8
gap> LevelOfCongruenceSubgroup(G1_6);
6
gap> LevelOfCongruenceSubgroup(I);
4
gap> LevelOfCongruenceSubgroup(J);
12

2.3-2 IndexInSL2Z
‣ IndexInSL2Z( G )( attribute )

Stores the index of the congruence subgroup G in SL_2(ℤ).


gap> IndexInSL2Z(G_8);
384
gap> G_2:=PrincipalCongruenceSubgroup(2);
<principal congruence subgroup of level 2 in SL_2(Z)>
gap> IndexInSL2Z(G_2);
12
gap> IndexInSL2Z(GU1_4);
12

2.3-3 DefiningCongruenceSubgroups
‣ DefiningCongruenceSubgroups( G )( attribute )

Returns: list of congruence subgroups

For an intersection of congruence subgroups, returns the list of congruence subgroups forming this intersection. For a canonical congruence subgroup returns a list of length one containing that subgroup.


gap> DefiningCongruenceSubgroups(J);
[ <congruence subgroup CongruenceSubgroupGamma_0(4) in SL_2(Z)>,
  <congruence subgroup CongruenceSubgroupGamma_1(6) in SL_2(Z)> ]
gap> P:=PrincipalCongruenceSubgroup(6);
<principal congruence subgroup of level 6 in SL_2(Z)>
gap> Q:=PrincipalCongruenceSubgroup(10); 
<principal congruence subgroup of level 10 in SL_2(Z)>
gap> G:=IntersectionOfCongruenceSubgroups(Q,P);  
<principal congruence subgroup of level 30 in SL_2(Z)>
gap> DefiningCongruenceSubgroups(G);
[ <principal congruence subgroup of level 30 in SL_2(Z)> ] 

2.4 Operations for congruence subgroups

Congruence installs several special methods for operations already available in GAP.

2.4-1 Random
‣ Random( G )( operation )
‣ Random( G, m )( operation )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns random element. In the two-argument form, the second parameter will control the absolute value of randomly selected entries of the matrix.


gap> Random(G_2) in G_2;
true
gap> Random(G_8,2) in G_8;
true

2.4-2 \in
‣ \in( m, G )( operation )

It is easy to implement the membership test for congruence subgroups and their intersections.


gap> \in([ [ 21, 10 ], [ 2, 1 ] ],G_2);
true
gap> \in([ [ 21, 10 ], [ 2, 1 ] ],G_8);
false

2.4-3 CanEasilyCompareCongruenceSubgroups
‣ CanEasilyCompareCongruenceSubgroups( G, H )( operation )

For congruence subgroups G,H in the category IsCongruenceSubgroup, returns true if G and H are of the same type listed in PrincipalCongruenceSubgroup (2.1-1) --> CongruenceSubgroupGammaUpper1 (2.1-5) and have the same LevelOfCongruenceSubgroup (2.3-1) or if G and H are of the type IntersectionOfCongruenceSubgroups (2.1-6) and the groups from DefiningCongruenceSubgroups (2.3-3) are in one to one correspondence, otherwise it returns false.


gap> CanEasilyCompareCongruenceSubgroups(G_8,I);
false

2.4-4 IsSubset
‣ IsSubset( G, H )( operation )

Congruence provides methods for IsSubset for congruence subgroups. IsSubset returns true if H is a subset of G. These methods make it possible to use IsSubgroup operation for congruence subgroups.


gap> IsSubset(G_2,G_8);
true
gap> IsSubset(G_8,G_2);
false
gap> f:=[PrincipalCongruenceSubgroup,CongruenceSubgroupGamma1,CongruenceSubgroupGammaUpper1,CongruenceSubgroupGamma0,CongruenceSubgroupGammaUpper0];;
gap> g1:=List(f, t -> t(2));;
gap> g2:=List(f, t -> t(4));;
gap> for g in g2 do
> Print( List( g1, x -> IsSubgroup(x,g) ), "\n");
> od;
[ true, true, true, true, true ]
[ false, true, false, true, false ]
[ false, false, true, false, true ]
[ false, false, false, true, false ]
[ false, false, false, false, true ]

2.4-5 Index
‣ Index( G, H )( operation )

If a congruence subgroup H is a subgroup of a congruence subgroup G, we can easily compute the index of H in G, since we know the index of both subgroups in SL_2(ℤ).


gap> Index(G_2,G_8);
32

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chap3.html0000664000371700037170000002430713503171577017527 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Chapter 3: Farey symbols and their properties
Goto Chapter: Top 1 2 3 4 5 Bib Ind

3 Farey symbols and their properties

A Farey symbol is a compact and useful way to represent a subgroup of finite index in SL_2(ℤ) from which one can deduce independent generators for this subgroup. It consists of two components, namely a so-called generalised Farey sequence (gfs) and an ordered list of labels, giving additional structure to the gfs.

A generalised Farey sequence (g.F.S.) is an ordered list of the form -infinity, x_0, x_1, ... , x_n, infinity, where

1. the x_i = a_i/b_i are rational numbers in reduced form arranged in increasing order for i = 0, ... , n;

2. x_0, ... , x_n ∈ Z, and some x_i = 0;

3. we define x_-1=-infinity=-1/0 and x_n+1=infinity=1/0;

4. a_i+1b_i-a_ib_i+1=1 for i=-1, ... ,n.

The ordered list of labels of a Farey symbol gives an additional structure to the gfs. The labels correspond to each consecutive pair of x_i's and are of the following types:

1. even,

2. odd,

3. a natural number, which occurs in the list of labels exactly twice or not at all.

Note that the actual values of numerical labels are not important; it is the pairing of two intervals that matters.

The package Congruence provides functions to construct Farey symbols by the given generalised Farey sequence and corresponding list of labels. The returned Farey symbol will belong to the category IsFareySymbol and will have the representation IsFareySymbolDefaultRep.

3.1 Construction of Farey symbols

3.1-1 FareySymbolByData
‣ FareySymbolByData( gfs, labels )( function )

This constructor creates the Farey symbol with the given generalized Farey sequence and list of labels. It also checks conditions from the definition of Farey symbol and returns an error if they are not satisfied. The data used to create the Farey symbol are stored as its attributes GeneralizedFareySequence (3.2-1) and LabelsOfFareySymbol (3.2-4).


gap> fs:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]);                         
[ infinity, 0, 1, 2, infinity ]
[ 1, 2, 2, 1 ]

3.1-2 IsValidFareySymbol
‣ IsValidFareySymbol( fs )( function )

This function is used in FareySymbolByData (3.1-1) to validate its output.


gap> IsValidFareySymbol(fs);
true

3.2 Properties of Farey symbols

3.2-1 GeneralizedFareySequence
‣ GeneralizedFareySequence( fs )( attribute )

Returns the generalized Farey sequence gfs of the Farey symbol.


gap> GeneralizedFareySequence(fs);
[ infinity, 0, 1, 2, infinity ]

3.2-2 NumeratorOfGFSElement
‣ NumeratorOfGFSElement( gfs, i )( function )

Returns: integer

Returns the numerator of the i-th term of the generalised Farey sequence gfs: for the 1st infinite entry returns -1, for the last one returns 1, for all other entries returns the usual numerator.


gap> List([1..5], i -> NumeratorOfGFSElement(GeneralizedFareySequence(fs),i));
[ -1, 0, 1, 2, 1 ]

3.2-3 DenominatorOfGFSElement
‣ DenominatorOfGFSElement( gfs, i )( function )

Returns: integer

Returns the denominator of the i-th term of the generalised Farey sequence gfs: for both infinite entries returns 0, for the other ones returns the usual denominator.


gap> List([1..5], i -> DenominatorOfGFSElement(GeneralizedFareySequence(fs),i));         
[ 0, 1, 1, 1, 0 ]

3.2-4 LabelsOfFareySymbol
‣ LabelsOfFareySymbol( fs )( attribute )

Returns the list of labels of the Farey symbol. This list has "odd", "even" and paired integers as entries.


gap> LabelsOfFareySymbol(fs);
[ 1, 2, 2, 1 ]

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chap1_mj.html0000664000371700037170000001262213503171577020210 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Chapter 1: Introduction
Goto Chapter: Top 1 2 3 4 5 Bib Ind

1 Introduction

1.1 General aims of Congruence package

The GAP package Congruence provides functions to construct several types of canonical congruence subgroups in \(SL_2(ℤ)\), and also intersections of a finite number of such subgroups.

Furthermore, it implements the algorithm for generating Farey symbols for congruence subgroups and using them to produce a system of independent generators for these subgroups.

Using the package, one can also determine indices of congruence subgroups and their intersections in \(SL_2(ℤ)\) and in other congruence subgroups, generate their random elements and check element memberships. Success of other group theoretical constructions mostly depends on whether they could be expressed in terms of group generators or not.

For the theoretical backround, we refer to [LLT95b], [LLT95a], [CLLT93] and [Kul91].

1.2 Installation and system requirements

Congruence is distributed in standard formats (tar.gz, tar.bz2, -win.zip) and can be obtained from http://www.cs.st-andrews.ac.uk/~alexk/congruence/.

Congruence does not use external binaries and, therefore, works without restrictions on the operating system. It requires at least version GAP 4.5, and no compatibility with previous releases of GAP 4 is guaranteed.

Installation of the package is standard and follows the guidelines from the GAP manual (see Reference: Installing a GAP Package. After the package is installed, you can start GAP and load the Congruence package using the command:


gap> LoadPackage("congruence");

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chapInd.html0000664000371700037170000001417213503171577020076 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Index
Goto Chapter: Top 1 2 3 4 5 Bib Ind

Index

\in 2.4-2
CanEasilyCompareCongruenceSubgroups 2.4-3
Congruence package .-1
CongruenceSubgroupGamma0 2.1-2
CongruenceSubgroupGamma1 2.1-4
CongruenceSubgroupGammaUpper0 2.1-3
CongruenceSubgroupGammaUpper1 2.1-5
DefiningCongruenceSubgroups 2.3-3
DenominatorOfGFSElement 3.2-3
FareySymbol 4.1-1
FareySymbolByData 3.1-1
GeneralizedFareySequence 3.2-1
GeneratorsByFareySymbol 4.2-4
GeneratorsOfGroup 4.2-5
Index 2.4-5
IndexInPSL2ZByFareySymbol 4.3-1
IndexInSL2Z 2.3-2
InfoCongruence 5.1-1
Intersection 2.1-6
IntersectionOfCongruenceSubgroups 2.1-6
IsCongruenceSubgroup 1.1 2.
IsCongruenceSubgroupGamma0 2.2-2
IsCongruenceSubgroupGamma1 2.2-4
IsCongruenceSubgroupGammaUpper0 2.2-3
IsCongruenceSubgroupGammaUpper1 2.2-5
IsFareySymbol 3.
IsFareySymbolDefaultRep 3.
IsIntersectionOfCongruenceSubgroups 2.2-6
IsPrincipalCongruenceSubgroup 2.2-1
IsSubset 2.4-4
IsValidFareySymbol 3.1-2
LabelsOfFareySymbol 3.2-4
LevelOfCongruenceSubgroup 2.3-1
MatrixByEvenInterval 4.2-1
MatrixByFreePairOfIntervals 4.2-3
MatrixByOddInterval 4.2-2
NumeratorOfGFSElement 3.2-2
PrincipalCongruenceSubgroup 2.1-1
Random 2.4-1
    one and two argument versions 2.4-1

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chap3_mj.html0000664000371700037170000002477413503171577020225 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Chapter 3: Farey symbols and their properties
Goto Chapter: Top 1 2 3 4 5 Bib Ind

3 Farey symbols and their properties

A Farey symbol is a compact and useful way to represent a subgroup of finite index in \(SL_2(ℤ)\) from which one can deduce independent generators for this subgroup. It consists of two components, namely a so-called generalised Farey sequence (gfs) and an ordered list of labels, giving additional structure to the gfs.

A generalised Farey sequence (g.F.S.) is an ordered list of the form \({ -infinity, x_0, x_1, ... , x_n, infinity }\), where

1. the \(x_i = a_i/b_i\) are rational numbers in reduced form arranged in increasing order for \(i = 0, ... , n\);

2. \(x_0, ... , x_n \in Z\), and some \(x_i = 0\);

3. we define \(x_{-1}=-infinity=-1/0\) and \(x_{n+1}=infinity=1/0\);

4. \(a_{i+1}b_{i}-a_{i}b_{i+1}=1\) for \(i=-1, ... ,n\).

The ordered list of labels of a Farey symbol gives an additional structure to the gfs. The labels correspond to each consecutive pair of \(x_i\)'s and are of the following types:

1. even,

2. odd,

3. a natural number, which occurs in the list of labels exactly twice or not at all.

Note that the actual values of numerical labels are not important; it is the pairing of two intervals that matters.

The package Congruence provides functions to construct Farey symbols by the given generalised Farey sequence and corresponding list of labels. The returned Farey symbol will belong to the category IsFareySymbol and will have the representation IsFareySymbolDefaultRep.

3.1 Construction of Farey symbols

3.1-1 FareySymbolByData
‣ FareySymbolByData( gfs, labels )( function )

This constructor creates the Farey symbol with the given generalized Farey sequence and list of labels. It also checks conditions from the definition of Farey symbol and returns an error if they are not satisfied. The data used to create the Farey symbol are stored as its attributes GeneralizedFareySequence (3.2-1) and LabelsOfFareySymbol (3.2-4).


gap> fs:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]);                         
[ infinity, 0, 1, 2, infinity ]
[ 1, 2, 2, 1 ]

3.1-2 IsValidFareySymbol
‣ IsValidFareySymbol( fs )( function )

This function is used in FareySymbolByData (3.1-1) to validate its output.


gap> IsValidFareySymbol(fs);
true

3.2 Properties of Farey symbols

3.2-1 GeneralizedFareySequence
‣ GeneralizedFareySequence( fs )( attribute )

Returns the generalized Farey sequence gfs of the Farey symbol.


gap> GeneralizedFareySequence(fs);
[ infinity, 0, 1, 2, infinity ]

3.2-2 NumeratorOfGFSElement
‣ NumeratorOfGFSElement( gfs, i )( function )

Returns: integer

Returns the numerator of the i-th term of the generalised Farey sequence gfs: for the 1st infinite entry returns -1, for the last one returns 1, for all other entries returns the usual numerator.


gap> List([1..5], i -> NumeratorOfGFSElement(GeneralizedFareySequence(fs),i));
[ -1, 0, 1, 2, 1 ]

3.2-3 DenominatorOfGFSElement
‣ DenominatorOfGFSElement( gfs, i )( function )

Returns: integer

Returns the denominator of the i-th term of the generalised Farey sequence gfs: for both infinite entries returns 0, for the other ones returns the usual denominator.


gap> List([1..5], i -> DenominatorOfGFSElement(GeneralizedFareySequence(fs),i));         
[ 0, 1, 1, 1, 0 ]

3.2-4 LabelsOfFareySymbol
‣ LabelsOfFareySymbol( fs )( attribute )

Returns the list of labels of the Farey symbol. This list has "odd", "even" and paired integers as entries.


gap> LabelsOfFareySymbol(fs);
[ 1, 2, 2, 1 ]

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chapInd.txt0000664000371700037170000000331313503171577017744 0ustar gap-jenkinsgap-jenkins Index \in 2.4-2 CanEasilyCompareCongruenceSubgroups 2.4-3 Congruence package .-1 CongruenceSubgroupGamma0 2.1-2 CongruenceSubgroupGamma1 2.1-4 CongruenceSubgroupGammaUpper0 2.1-3 CongruenceSubgroupGammaUpper1 2.1-5 DefiningCongruenceSubgroups 2.3-3 DenominatorOfGFSElement 3.2-3 FareySymbol 4.1-1 FareySymbolByData 3.1-1 GeneralizedFareySequence 3.2-1 GeneratorsByFareySymbol 4.2-4 GeneratorsOfGroup 4.2-5 Index 2.4-5 IndexInPSL2ZByFareySymbol 4.3-1 IndexInSL2Z 2.3-2 InfoCongruence 5.1-1 Intersection 2.1-6 IntersectionOfCongruenceSubgroups 2.1-6 IsCongruenceSubgroup 1.1 2. IsCongruenceSubgroupGamma0 2.2-2 IsCongruenceSubgroupGamma1 2.2-4 IsCongruenceSubgroupGammaUpper0 2.2-3 IsCongruenceSubgroupGammaUpper1 2.2-5 IsFareySymbol 3. IsFareySymbolDefaultRep 3. IsIntersectionOfCongruenceSubgroups 2.2-6 IsPrincipalCongruenceSubgroup 2.2-1 IsSubset 2.4-4 IsValidFareySymbol 3.1-2 LabelsOfFareySymbol 3.2-4 LevelOfCongruenceSubgroup 2.3-1 MatrixByEvenInterval 4.2-1 MatrixByFreePairOfIntervals 4.2-3 MatrixByOddInterval 4.2-2 NumeratorOfGFSElement 3.2-2 PrincipalCongruenceSubgroup 2.1-1 Random 2.4-1 one and two argument versions 2.4-1 ------------------------------------------------------- congruence-1.2.3/doc/service.xml0000664000371700037170000000142613503171577020022 0ustar gap-jenkinsgap-jenkins Service functions of the &Congruence; package
Additional information displayed by &Congruence; algorithms InfoCongruence is a special Info class for &Congruence; algorithms. It has 3 levels: 0, 1 (default) and 2. To change the info level to k, use the command SetInfoLevel(InfoCongruence, k).

In the example below we use this mechanism to see more details during the Farey symbol construction for a congruence subgroup.

congruence-1.2.3/doc/cong.xml0000664000371700037170000004044613503171577017315 0ustar gap-jenkinsgap-jenkins Construction of congruence subgroups IsCongruenceSubgroup The package &Congruence; provides functions to construct several types of canonical congruence subgroups in SL_2(&ZZ;), and also intersections of a finite number of such subgroups. They will return a matrix group in the category IsCongruenceSubgroup, which is defined as a subcategory of IsMatrixGroup, and which will have a distinguishing property determining whether it is a congruence subgroup of one of the canonical types, or an intersection of such congruence subgroups (if it can not be reduced to one of the canonical congruence subgroups). To start to work with the package, you need first to load it as follows: LoadPackage("congruence"); ----------------------------------------------------------------------------- Loading Congruence 1.1.0 (Congruence subgroups of SL(2,Integers)) by Ann Dooms (http://homepages.vub.ac.be/~andooms), Eric Jespers (http://homepages.vub.ac.be/~efjesper), Alexander Konovalov (http://www.cs.st-andrews.ac.uk/~alexk/), and Helena Verrill (http://www.math.lsu.edu/~verrill). ----------------------------------------------------------------------------- true ]]>
Construction of congruence subgroups Returns the principal congruence subgroup \Gamma(N) of level N in SL_2(&ZZ;).

This subgroup consists of all matrices of the form where a,b,c,d are integers. The returned group will have the property . G_8:=PrincipalCongruenceSubgroup(8); gap> IsGroup(G_8); true gap> IsMatrixGroup(G_8); true gap> DimensionOfMatrixGroup(G_8); 2 gap> MultiplicativeNeutralElement(G_8); [ [ 1, 0 ], [ 0, 1 ] ] gap> One(G); [ [ 1, 0 ], [ 0, 1 ] ] gap> [[1,2],[3,4]] in G_8; false gap> [[1,8],[8,65]] in G_8; true gap> SL_2:=SL(2,Integers); SL(2,Integers) gap> IsSubgroup(SL_2,G_8); true ]]> Returns the congruence subgroup \Gamma_0(N) of level N in SL_2(&ZZ;).

This subgroup consists of all matrices of the form where a,b,c,d are integers. The returned group will have the property . G0_4:=CongruenceSubgroupGamma0(4); ]]> Returns the congruence subgroup \Gamma^0(N) of level N in SL_2(&ZZ;).

This subgroup consists of all matrices of the form where a,b,c,d are integers. The returned group will have the property . GU0_2:=CongruenceSubgroupGammaUpper0(2); ]]> Returns the congruence subgroup \Gamma_1(N) of level N in SL_2(&ZZ;).

This subgroup consists of all matrices of the form where a,b,c,d are integers. The returned group will have the property . G1_6:=CongruenceSubgroupGamma1(6); ]]> Returns the congruence subgroup \Gamma^1(N) of level N in SL_2(&ZZ;).

This subgroup consists of all matrices of the form where a,b,c,d are integers. The returned group will have the property . GU1_4:=CongruenceSubgroupGammaUpper1(4); ]]> Returns the intersection of its arguments, which can be congruence subgroups or their intersections, constructed with the same function. It is not necessary for the user to use IntersectionOfCongruenceSubgroups, since it will be called automatically from Intersection.

The returned group will have the property .

The list of congruence subgroups that form the intersection can be obtained using . Note, that when the intersection appears to be one of the canonical congruence subgroups, the package will recognize this and will return a canonical subgroup of the appropriate type. I:=IntersectionOfCongruenceSubgroups(G0_4,GU1_4); gap> J:=IntersectionOfCongruenceSubgroups(G0_4,G1_6); ]]>

Properties of congruence subgroups A congruence subgroup constructed by one of the five above listed functions will have certain properties determining its type. These properties will be used for method selection by &Congruence; algorithms. Note that they do not provide an actual test whether a certain matrix group is a congruence subgroup or not. For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by (or reduced to one as a result of an intersection) and returns false otherwise. IsPrincipalCongruenceSubgroup(G_8); true gap> IsPrincipalCongruenceSubgroup(G0_4); false gap> IsPrincipalCongruenceSubgroup(I); true ]]> For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by (or reduced to one as a result of an intersection) and returns false otherwise. For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by (or reduced to one as a result of an intersection) and returns false otherwise. For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by (or reduced to one as a result of an intersection) and returns false otherwise. For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by (or reduced to one as a result of an intersection) and returns false otherwise. For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by and without being one of the canonical congruence subgroups, otherwise it returns false. IsIntersectionOfCongruenceSubgroups(I); false gap> IsIntersectionOfCongruenceSubgroups(J); true ]]>
Attributes of congruence subgroups The next three attributes store key properties of congruence subgroups. Stores the level of the congruence subgroup G. The (arithmetic) level of a congruence subgroup G is the smallest positive number N such that G contains the principal congruence subgroup of level N. LevelOfCongruenceSubgroup(G_8); 8 gap> LevelOfCongruenceSubgroup(G1_6); 6 gap> LevelOfCongruenceSubgroup(I); 4 gap> LevelOfCongruenceSubgroup(J); 12 ]]> Stores the index of the congruence subgroup G in SL_2(&ZZ;). IndexInSL2Z(G_8); 384 gap> G_2:=PrincipalCongruenceSubgroup(2); gap> IndexInSL2Z(G_2); 12 gap> IndexInSL2Z(GU1_4); 12 ]]> list of congruence subgroups For an intersection of congruence subgroups, returns the list of congruence subgroups forming this intersection. For a canonical congruence subgroup returns a list of length one containing that subgroup. DefiningCongruenceSubgroups(J); [ , ] gap> P:=PrincipalCongruenceSubgroup(6); gap> Q:=PrincipalCongruenceSubgroup(10); gap> G:=IntersectionOfCongruenceSubgroups(Q,P); gap> DefiningCongruenceSubgroups(G); [ ] ]]>
Operations for congruence subgroups &Congruence; installs several special methods for operations already available in &GAP;. For a congruence subgroup G in the category IsCongruenceSubgroup, returns random element. In the two-argument form, the second parameter will control the absolute value of randomly selected entries of the matrix. Random(G_2) in G_2; true gap> Random(G_8,2) in G_8; true ]]> It is easy to implement the membership test for congruence subgroups and their intersections. \in([ [ 21, 10 ], [ 2, 1 ] ],G_2); true gap> \in([ [ 21, 10 ], [ 2, 1 ] ],G_8); false ]]> For congruence subgroups G,H in the category IsCongruenceSubgroup, returns true if G and H are of the same type listed in --> and have the same or if G and H are of the type and the groups from are in one to one correspondence, otherwise it returns false. CanEasilyCompareCongruenceSubgroups(G_8,I); false ]]> &Congruence; provides methods for IsSubset for congruence subgroups. IsSubset returns true if H is a subset of G. These methods make it possible to use IsSubgroup operation for congruence subgroups. IsSubset(G_2,G_8); true gap> IsSubset(G_8,G_2); false gap> f:=[PrincipalCongruenceSubgroup,CongruenceSubgroupGamma1,CongruenceSubgroupGammaUpper1,CongruenceSubgroupGamma0,CongruenceSubgroupGammaUpper0];; gap> g1:=List(f, t -> t(2));; gap> g2:=List(f, t -> t(4));; gap> for g in g2 do > Print( List( g1, x -> IsSubgroup(x,g) ), "\n"); > od; [ true, true, true, true, true ] [ false, true, false, true, false ] [ false, false, true, false, true ] [ false, false, false, true, false ] [ false, false, false, false, true ] ]]> If a congruence subgroup H is a subgroup of a congruence subgroup G, we can easily compute the index of H in G, since we know the index of both subgroups in SL_2(&ZZ;). Index(G_2,G_8); 32 ]]>
congruence-1.2.3/doc/chap4.html0000664000371700037170000003710013503171577017523 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Chapter 4: Farey symbols for congruence subgroups
Goto Chapter: Top 1 2 3 4 5 Bib Ind

4 Farey symbols for congruence subgroups

The package Congruence provides functions to construct Farey symbols for finite index subgroups. The algorithm used in the package allows to construct a Farey symbol for any finite index subgroup of SL_2(ℤ) for which it is possible to check whether a given matrix belongs to this subgroup or not.

The development of an algorithm to determine the Farey symbol for a subgroup G of a finite index in SL_2(ℤ) was started by Ravi Kulkarni in [Kul91] and later it was improved by Mong-Lung Lang, Chong-Hai Lim and Ser-Peow Tan in [LLT95b], [LLT95a].

4.1 Computation of the Farey symbol for a finite index subgroup

4.1-1 FareySymbol
‣ FareySymbol( G )( attribute )

For a subgroup of a finite index G, this attribute stores one of the Farey symbols corresponding to the congruence subgroup G. The algorithm for its computation will work for any matrix group for which a membership test is available.


gap> FareySymbol(PrincipalCongruenceSubgroup(8));
[ infinity, 0, 1/4, 1/3, 3/8, 2/5, 1/2, 3/5, 5/8, 2/3, 3/4, 1, 5/4, 4/3, 
  11/8, 7/5, 3/2, 8/5, 13/8, 5/3, 7/4, 2, 9/4, 7/3, 19/8, 12/5, 5/2, 13/5, 
  21/8, 8/3, 11/4, 3, 13/4, 10/3, 27/8, 17/5, 7/2, 18/5, 29/8, 11/3, 15/4, 4, 
  17/4, 13/3, 9/2, 14/3, 19/4, 5, 21/4, 16/3, 11/2, 17/3, 23/4, 6, 25/4, 
  19/3, 13/2, 20/3, 27/4, 7, 29/4, 22/3, 15/2, 23/3, 31/4, 8, infinity ]
[ 1, 17, 10, 26, 32, 18, 19, 27, 30, 5, 2, 2, 13, 28, 26, 20, 21, 29, 27, 7, 
  3, 3, 16, 31, 28, 22, 23, 33, 29, 9, 4, 4, 5, 30, 31, 24, 25, 32, 33, 12, 
  6, 6, 7, 19, 18, 15, 8, 8, 9, 21, 20, 10, 11, 11, 12, 23, 22, 13, 14, 14, 
  15, 25, 24, 16, 17, 1 ]
gap> FareySymbol(CongruenceSubgroupGamma0(20));
[ infinity, 0, 1/5, 1/4, 2/7, 3/10, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1, 
  infinity ]
[ 1, 3, 4, 6, 7, 7, 5, 2, 2, 3, 6, 4, 5, 1 ]  

4.2 Computation of generators of a finite index subgroup from its Farey symbol

If fs is the Farey symbol for a group G with r_1 even labels, r_2 odd labels and r_3 pairs of intervals, then G is generated by r_1+r_2+r_3 matrices, which form a set of independent generators for G. These matrices are constructed as follows:

for each even interval [x_i, x_i+1], take the matrix


                       A=  [a_{i+1} b_{i+1} + a_i b_i    -a_i^2 - a_{i+1}^2        ]
                           [b_i^2 +b_{i+1}^2             -a_{i+1} b_{i+1} - a_i b_i]

for each odd interval [x_j,x_j+1], take the matrix


                        B=  [a_{j+1} b_{j+1} + a_j b_{j+1} + a_j b_j      -a_j^2 - a_j a_{j+1} -a_{j+1}^2]
                            [ b_j^2 + b_j b_{j+1} + b_{j+1}^2  -a_{j+1}   b_{j+1} - a_{j+1} b_j - a_j b_j]

for each pair of free intervals [x_k,x_k+1] and [x_s,x_s+1], take the matrix


                        C=  [a_{s+1} b_{k+1} + a_s b_k    -a_s a_k - a_{s+1} a_{k+1}]
                            [b_s b_k- b_{s+1} b_{k+1}c    -a_{k+1} b_{s+1} - a_k b_s]

4.2-1 MatrixByEvenInterval
‣ MatrixByEvenInterval( gfs, i )( function )

Returns the matrix corresponding to the even interval i in the generalized Farey sequence gfs.


gap> H:=CongruenceSubgroupGamma0(5); 
<congruence subgroup CongruenceSubgroupGamma_0(5) in SL_2(Z)>
gap> fs:=FareySymbol(H);
[ infinity, 0, 1/2, 1, infinity ]
[ 1, "even", "even", 1 ]
gap> gfs:=GeneralizedFareySequence(fs);
[ infinity, 0, 1/2, 1, infinity ]
gap> MatrixByEvenInterval(gfs,2);      
[ [ 2, -1 ], [ 5, -2 ] ]

4.2-2 MatrixByOddInterval
‣ MatrixByOddInterval( gfs, i )( function )

Returns the matrix corresponding to the odd interval i in the generalized Farey sequence gfs.


gap> fs_oo:=FareySymbolByData([infinity,0,infinity],["odd","odd"]);;
gap> gfs_oo:=GeneralizedFareySequence(fs_oo);
[ infinity, 0, infinity ]
gap> MatrixByOddInterval(gfs_oo,1);
[ [ -1, -1 ], [ 1, 0 ] ]

4.2-3 MatrixByFreePairOfIntervals
‣ MatrixByFreePairOfIntervals( gfs, k, kp )( function )

Returns the matrix corresponding to the pair of free intervals k and kp in the generalized Farey sequence gfs.


gap> fs_free:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]);;
gap> gfs_free:=GeneralizedFareySequence(fs_free);;
gap> MatrixByFreePairOfIntervals(gfs_free,2,3);                                                        
[ [ 3, -2 ], [ 2, -1 ] ]

4.2-4 GeneratorsByFareySymbol
‣ GeneratorsByFareySymbol( fs )( function )

Returns a set of matrices constructed as above.


gap> fs_eo:=FareySymbolByData([infinity,0,infinity],["even","odd"]);;
gap> GeneratorsByFareySymbol(last);                                  
[ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ]
gap> GeneratorsByFareySymbol(fs); 
[ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ]
gap> GeneratorsByFareySymbol(fs_oo);
[ [ [ -1, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ]
gap> GeneratorsByFareySymbol(fs_free);                                                        
[ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ]

4.2-5 GeneratorsOfGroup
‣ GeneratorsOfGroup( G )( function )

Returns a set of generators for the finite index group G in SL_2(Z).


gap> G:=PrincipalCongruenceSubgroup(2);
<principal congruence subgroup of level 2 in SL_2(Z)>
gap> FareySymbol(G);
[ infinity, 0, 1, 2, infinity ]
[ 2, 1, 1, 2 ]
gap> GeneratorsOfGroup(G);
#I  Using the Congruence package for GeneratorsOfGroup ...
[ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ]
gap> H:=CongruenceSubgroupGamma0(5);        
<congruence subgroup CongruenceSubgroupGamma_0(5) in SL_2(Z)>
gap> GeneratorsOfGroup(H);
#I  Using the Congruence package for GeneratorsOfGroup ...
[ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ]
gap> I:=IntersectionOfCongruenceSubgroups(PrincipalCongruenceSubgroup(2),CongruenceSubgroupGamma0(3));
<intersection of congruence subgroups of resulting level 6 in SL_2(Z)>
gap> FareySymbol(I);
[ infinity, 0, 1/3, 1/2, 2/3, 1, 4/3, 3/2, 5/3, 2, infinity ]
[ 1, 5, 4, 3, 2, 2, 3, 4, 5, 1 ]
gap> GeneratorsOfGroup(I);                                                          
#I  Using the Congruence package for GeneratorsOfGroup ...
[ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 11, -2 ], [ 6, -1 ] ], 
  [ [ 19, -8 ], [ 12, -5 ] ], [ [ 17, -10 ], [ 12, -7 ] ], 
  [ [ 7, -6 ], [ 6, -5 ] ] ]

4.3 Other properties derived from Farey symbols

4.3-1 IndexInPSL2ZByFareySymbol
‣ IndexInPSL2ZByFareySymbol( fs )( function )

By Proposition 7.2 in [Kulkarni], for the Farey symbol with underlying generalized Farey sequence [infinity, x0, x1, ..., xn, infinity], the index in PSL_2(Z) is given by the formula d = 3*n + e3, where e3 is the number of odd intervals.


gap> IndexInPSL2ZByFareySymbol(fs);
6
gap> IndexInPSL2ZByFareySymbol(fs_oo);
2
gap> IndexInPSL2ZByFareySymbol(fs_free);
6

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/nocolorprompt.css0000664000371700037170000000031313503171577021261 0ustar gap-jenkinsgap-jenkins /* colors for ColorPrompt like examples */ span.GAPprompt { color: #000000; font-weight: normal; } span.GAPbrkprompt { color: #000000; font-weight: normal; } span.GAPinput { color: #000000; } congruence-1.2.3/doc/lefttoc.css0000664000371700037170000000047413503171577020014 0ustar gap-jenkinsgap-jenkins/* 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%; } congruence-1.2.3/doc/intro.xml0000664000371700037170000000404113503171577017511 0ustar gap-jenkinsgap-jenkins Introduction
General aims of &Congruence; package IsCongruenceSubgroup The &GAP; package &Congruence; provides functions to construct several types of canonical congruence subgroups in SL_2(&ZZ;), and also intersections of a finite number of such subgroups.

Furthermore, it implements the algorithm for generating Farey symbols for congruence subgroups and using them to produce a system of independent generators for these subgroups.

Using the package, one can also determine indices of congruence subgroups and their intersections in SL_2(&ZZ;) and in other congruence subgroups, generate their random elements and check element memberships. Success of other group theoretical constructions mostly depends on whether they could be expressed in terms of group generators or not.

For the theoretical backround, we refer to , , and .

Installation and system requirements &Congruence; is distributed in standard formats (tar.gz, tar.bz2, -win.zip) and can be obtained from http://www.cs.st-andrews.ac.uk/~alexk/congruence/.

&Congruence; does not use external binaries and, therefore, works without restrictions on the operating system. It requires at least version &GAP; 4.5, and no compatibility with previous releases of &GAP; 4 is guaranteed.

Installation of the package is standard and follows the guidelines from the &GAP; manual (see . After the package is installed, you can start &GAP; and load the &Congruence; package using the command: LoadPackage("congruence"); ]]>

congruence-1.2.3/doc/chap2_mj.html0000664000371700037170000010072213503171577020210 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Chapter 2: Construction of congruence subgroups
Goto Chapter: Top 1 2 3 4 5 Bib Ind

2 Construction of congruence subgroups

The package Congruence provides functions to construct several types of canonical congruence subgroups in \(SL_2(ℤ)\), and also intersections of a finite number of such subgroups. They will return a matrix group in the category IsCongruenceSubgroup, which is defined as a subcategory of IsMatrixGroup, and which will have a distinguishing property determining whether it is a congruence subgroup of one of the canonical types, or an intersection of such congruence subgroups (if it can not be reduced to one of the canonical congruence subgroups). To start to work with the package, you need first to load it as follows:


gap> LoadPackage("congruence");
-----------------------------------------------------------------------------
Loading  Congruence 1.1.0 (Congruence subgroups of SL(2,Integers))
by Ann Dooms (http://homepages.vub.ac.be/~andooms),
   Eric Jespers (http://homepages.vub.ac.be/~efjesper),
   Alexander Konovalov (http://www.cs.st-andrews.ac.uk/~alexk/), and
   Helena Verrill (http://www.math.lsu.edu/~verrill).
-----------------------------------------------------------------------------
true

2.1 Construction of congruence subgroups

2.1-1 PrincipalCongruenceSubgroup
‣ PrincipalCongruenceSubgroup( N )( operation )

Returns the principal congruence subgroup \(\Gamma(N)\) of level N in \(SL_2(ℤ)\).

This subgroup consists of all matrices of the form


                         [1+N*a    N*b]
                         [  N*c  1+N*d]

where \(a\),\(b\),\(c\),\(d\) are integers. The returned group will have the property IsPrincipalCongruenceSubgroup (2.2-1).


gap> G_8:=PrincipalCongruenceSubgroup(8);
<principal congruence subgroup of level 8 in SL_2(Z)>
gap> IsGroup(G_8);
true
gap> IsMatrixGroup(G_8);
true
gap> DimensionOfMatrixGroup(G_8);
2
gap> MultiplicativeNeutralElement(G_8);
[ [ 1, 0 ], [ 0, 1 ] ]
gap> One(G);
[ [ 1, 0 ], [ 0, 1 ] ]
gap> [[1,2],[3,4]] in G_8;
false
gap> [[1,8],[8,65]] in G_8;
true
gap> SL_2:=SL(2,Integers);
SL(2,Integers)
gap> IsSubgroup(SL_2,G_8);
true

2.1-2 CongruenceSubgroupGamma0
‣ CongruenceSubgroupGamma0( N )( operation )

Returns the congruence subgroup \(\Gamma_0(N)\) of level N in \(SL_2(ℤ)\).

This subgroup consists of all matrices of the form


                         [a    b]
                         [N*c  d]

where \(a\),\(b\),\(c\),\(d\) are integers. The returned group will have the property IsCongruenceSubgroupGamma0 (2.2-2).


gap> G0_4:=CongruenceSubgroupGamma0(4);
<congruence subgroup CongruenceSubgroupGamma_0(4) in SL_2(Z)>

2.1-3 CongruenceSubgroupGammaUpper0
‣ CongruenceSubgroupGammaUpper0( N )( operation )

Returns the congruence subgroup \(\Gamma^0(N)\) of level N in \(SL_2(ℤ)\).

This subgroup consists of all matrices of the form


                         [a  N*b]
                         [c    d]

where \(a\),\(b\),\(c\),\(d\) are integers. The returned group will have the property IsCongruenceSubgroupGammaUpper0 (2.2-3).


gap> GU0_2:=CongruenceSubgroupGammaUpper0(2);
<congruence subgroup CongruenceSubgroupGamma^0(2) in SL_2(Z)>

2.1-4 CongruenceSubgroupGamma1
‣ CongruenceSubgroupGamma1( N )( operation )

Returns the congruence subgroup \(\Gamma_1(N)\) of level N in \(SL_2(ℤ)\).

This subgroup consists of all matrices of the form


                         [1+N*a      b]
                         [  N*c  1+N*d]

where \(a\),\(b\),\(c\),\(d\) are integers. The returned group will have the property IsCongruenceSubgroupGamma1 (2.2-4).


gap> G1_6:=CongruenceSubgroupGamma1(6);
<congruence subgroup CongruenceSubgroupGamma_1(6) in SL_2(Z)>

2.1-5 CongruenceSubgroupGammaUpper1
‣ CongruenceSubgroupGammaUpper1( N )( operation )

Returns the congruence subgroup \(\Gamma^1(N)\) of level N in \(SL_2(ℤ)\).

This subgroup consists of all matrices of the form


                         [1+N*a    N*b]
                         [    c  1+N*d]

where \(a\),\(b\),\(c\),\(d\) are integers. The returned group will have the property IsCongruenceSubgroupGammaUpper1 (2.2-5).


gap> GU1_4:=CongruenceSubgroupGammaUpper1(4);
<congruence subgroup CongruenceSubgroupGamma^1(4) in SL_2(Z)>

2.1-6 IntersectionOfCongruenceSubgroups
‣ IntersectionOfCongruenceSubgroups( G1, G2, ..., GN )( function )
‣ Intersection( G1, G2, ..., GN )( function )

Returns the intersection of its arguments, which can be congruence subgroups or their intersections, constructed with the same function. It is not necessary for the user to use IntersectionOfCongruenceSubgroups, since it will be called automatically from Intersection.

The returned group will have the property IsIntersectionOfCongruenceSubgroups (2.2-6).

The list of congruence subgroups that form the intersection can be obtained using DefiningCongruenceSubgroups (2.3-3). Note, that when the intersection appears to be one of the canonical congruence subgroups, the package will recognize this and will return a canonical subgroup of the appropriate type.


gap> I:=IntersectionOfCongruenceSubgroups(G0_4,GU1_4);
<principal congruence subgroup of level 4 in SL_2(Z)>
gap> J:=IntersectionOfCongruenceSubgroups(G0_4,G1_6);
<intersection of congruence subgroups of resulting level 12 in SL_2(Z)>

2.2 Properties of congruence subgroups

A congruence subgroup constructed by one of the five above listed functions will have certain properties determining its type. These properties will be used for method selection by Congruence algorithms. Note that they do not provide an actual test whether a certain matrix group is a congruence subgroup or not.

2.2-1 IsPrincipalCongruenceSubgroup
‣ IsPrincipalCongruenceSubgroup( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by PrincipalCongruenceSubgroup (2.1-1) (or reduced to one as a result of an intersection) and returns false otherwise.


gap> IsPrincipalCongruenceSubgroup(G_8);
true
gap> IsPrincipalCongruenceSubgroup(G0_4);
false
gap> IsPrincipalCongruenceSubgroup(I);
true

2.2-2 IsCongruenceSubgroupGamma0
‣ IsCongruenceSubgroupGamma0( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGamma0 (2.1-2) (or reduced to one as a result of an intersection) and returns false otherwise.

2.2-3 IsCongruenceSubgroupGammaUpper0
‣ IsCongruenceSubgroupGammaUpper0( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGammaUpper0 (2.1-3) (or reduced to one as a result of an intersection) and returns false otherwise.

2.2-4 IsCongruenceSubgroupGamma1
‣ IsCongruenceSubgroupGamma1( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGamma1 (2.1-4) (or reduced to one as a result of an intersection) and returns false otherwise.

2.2-5 IsCongruenceSubgroupGammaUpper1
‣ IsCongruenceSubgroupGammaUpper1( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGammaUpper1 (2.1-5) (or reduced to one as a result of an intersection) and returns false otherwise.

2.2-6 IsIntersectionOfCongruenceSubgroups
‣ IsIntersectionOfCongruenceSubgroups( G )( property )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by IntersectionOfCongruenceSubgroups (2.1-6) and without being one of the canonical congruence subgroups, otherwise it returns false.


gap> IsIntersectionOfCongruenceSubgroups(I);
false
gap> IsIntersectionOfCongruenceSubgroups(J);
true

2.3 Attributes of congruence subgroups

The next three attributes store key properties of congruence subgroups.

2.3-1 LevelOfCongruenceSubgroup
‣ LevelOfCongruenceSubgroup( G )( attribute )

Stores the level of the congruence subgroup G. The (arithmetic) level of a congruence subgroup G is the smallest positive number N such that G contains the principal congruence subgroup of level N.


gap> LevelOfCongruenceSubgroup(G_8);
8
gap> LevelOfCongruenceSubgroup(G1_6);
6
gap> LevelOfCongruenceSubgroup(I);
4
gap> LevelOfCongruenceSubgroup(J);
12

2.3-2 IndexInSL2Z
‣ IndexInSL2Z( G )( attribute )

Stores the index of the congruence subgroup G in \(SL_2(ℤ)\).


gap> IndexInSL2Z(G_8);
384
gap> G_2:=PrincipalCongruenceSubgroup(2);
<principal congruence subgroup of level 2 in SL_2(Z)>
gap> IndexInSL2Z(G_2);
12
gap> IndexInSL2Z(GU1_4);
12

2.3-3 DefiningCongruenceSubgroups
‣ DefiningCongruenceSubgroups( G )( attribute )

Returns: list of congruence subgroups

For an intersection of congruence subgroups, returns the list of congruence subgroups forming this intersection. For a canonical congruence subgroup returns a list of length one containing that subgroup.


gap> DefiningCongruenceSubgroups(J);
[ <congruence subgroup CongruenceSubgroupGamma_0(4) in SL_2(Z)>,
  <congruence subgroup CongruenceSubgroupGamma_1(6) in SL_2(Z)> ]
gap> P:=PrincipalCongruenceSubgroup(6);
<principal congruence subgroup of level 6 in SL_2(Z)>
gap> Q:=PrincipalCongruenceSubgroup(10); 
<principal congruence subgroup of level 10 in SL_2(Z)>
gap> G:=IntersectionOfCongruenceSubgroups(Q,P);  
<principal congruence subgroup of level 30 in SL_2(Z)>
gap> DefiningCongruenceSubgroups(G);
[ <principal congruence subgroup of level 30 in SL_2(Z)> ] 

2.4 Operations for congruence subgroups

Congruence installs several special methods for operations already available in GAP.

2.4-1 Random
‣ Random( G )( operation )
‣ Random( G, m )( operation )

For a congruence subgroup G in the category IsCongruenceSubgroup, returns random element. In the two-argument form, the second parameter will control the absolute value of randomly selected entries of the matrix.


gap> Random(G_2) in G_2;
true
gap> Random(G_8,2) in G_8;
true

2.4-2 \in
‣ \in( m, G )( operation )

It is easy to implement the membership test for congruence subgroups and their intersections.


gap> \in([ [ 21, 10 ], [ 2, 1 ] ],G_2);
true
gap> \in([ [ 21, 10 ], [ 2, 1 ] ],G_8);
false

2.4-3 CanEasilyCompareCongruenceSubgroups
‣ CanEasilyCompareCongruenceSubgroups( G, H )( operation )

For congruence subgroups G,H in the category IsCongruenceSubgroup, returns true if G and H are of the same type listed in PrincipalCongruenceSubgroup (2.1-1) --> CongruenceSubgroupGammaUpper1 (2.1-5) and have the same LevelOfCongruenceSubgroup (2.3-1) or if G and H are of the type IntersectionOfCongruenceSubgroups (2.1-6) and the groups from DefiningCongruenceSubgroups (2.3-3) are in one to one correspondence, otherwise it returns false.


gap> CanEasilyCompareCongruenceSubgroups(G_8,I);
false

2.4-4 IsSubset
‣ IsSubset( G, H )( operation )

Congruence provides methods for IsSubset for congruence subgroups. IsSubset returns true if H is a subset of G. These methods make it possible to use IsSubgroup operation for congruence subgroups.


gap> IsSubset(G_2,G_8);
true
gap> IsSubset(G_8,G_2);
false
gap> f:=[PrincipalCongruenceSubgroup,CongruenceSubgroupGamma1,CongruenceSubgroupGammaUpper1,CongruenceSubgroupGamma0,CongruenceSubgroupGammaUpper0];;
gap> g1:=List(f, t -> t(2));;
gap> g2:=List(f, t -> t(4));;
gap> for g in g2 do
> Print( List( g1, x -> IsSubgroup(x,g) ), "\n");
> od;
[ true, true, true, true, true ]
[ false, true, false, true, false ]
[ false, false, true, false, true ]
[ false, false, false, true, false ]
[ false, false, false, false, true ]

2.4-5 Index
‣ Index( G, H )( operation )

If a congruence subgroup H is a subgroup of a congruence subgroup G, we can easily compute the index of H in G, since we know the index of both subgroups in \(SL_2(ℤ)\).


gap> Index(G_2,G_8);
32

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chap5.html0000664000371700037170000000716713503171577017536 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Chapter 5: Service functions of the Congruence package
Goto Chapter: Top 1 2 3 4 5 Bib Ind

5 Service functions of the Congruence package

5.1 Additional information displayed by Congruence algorithms

5.1-1 InfoCongruence
‣ InfoCongruence( info class )

InfoCongruence is a special Info class for Congruence algorithms. It has 3 levels: 0, 1 (default) and 2. To change the info level to k, use the command SetInfoLevel(InfoCongruence, k).

In the example below we use this mechanism to see more details during the Farey symbol construction for a congruence subgroup.

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/manual.bib0000664000371700037170000000552513503171577017577 0ustar gap-jenkinsgap-jenkins%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %W manual.bib Congruence documentation Ann Dooms %W Eric Jespers %W Alexander Konovalov %% Helena Verrill %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @article {LLT-Hecke, AUTHOR = {Lang, Mong-Lung and Lim, Chong-Hai and Tan, Ser Peow}, TITLE = {Independent generators for congruence subgroups of {H}ecke groups}, JOURNAL = {Math. Z.}, FJOURNAL = {Mathematische Zeitschrift}, VOLUME = {220}, YEAR = {1995}, NUMBER = {4}, PAGES = {569--594}, ISSN = {0025-5874}, CODEN = {MAZEAX}, MRCLASS = {11F06 (30F35)}, MRNUMBER = {MR1363856 (96k:11049)}, MRREVIEWER = {O. V. Shvartsman}, } @article {LLT-Algorithm, AUTHOR = {Lang, Mong-Lung and Lim, Chong-Hai and Tan, Ser Peow}, TITLE = {An algorithm for determining if a subgroup of the modular group is congruence}, JOURNAL = {J. London Math. Soc. (2)}, FJOURNAL = {Journal of the London Mathematical Society. Second Series}, VOLUME = {51}, YEAR = {1995}, NUMBER = {3}, PAGES = {491--502}, ISSN = {0024-6107}, CODEN = {JLMSAK}, MRCLASS = {11F06 (20H10 30F35)}, MRNUMBER = {MR1332886 (96f:11064)}, MRREVIEWER = {B. Sury}, } @article {CLT, AUTHOR = {Chan, Shih-Ping and Lang, Mong-Lung and Lim, Chong-Hai and Tan, Ser Peow}, TITLE = {Special polygons for subgroups of the modular group and applications}, JOURNAL = {Internat. J. Math.}, FJOURNAL = {International Journal of Mathematics}, VOLUME = {4}, YEAR = {1993}, NUMBER = {1}, PAGES = {11--34}, ISSN = {0129-167X}, MRCLASS = {11F06 (20H05)}, MRNUMBER = {MR1209958 (94j:11045)}, MRREVIEWER = {Marvin I. Knopp}, } @article {Kulkarni, AUTHOR = {Kulkarni, Ravi S.}, TITLE = {An arithmetic-geometric method in the study of the subgroups of the modular group}, JOURNAL = {Amer. J. Math.}, FJOURNAL = {American Journal of Mathematics}, VOLUME = {113}, YEAR = {1991}, NUMBER = {6}, PAGES = {1053--1133}, ISSN = {0002-9327}, CODEN = {AJMAAN}, MRCLASS = {11F06}, MRNUMBER = {MR1137534 (92i:11046)}, MRREVIEWER = {Harvey Cohn}, } @article {DoJeKo, AUTHOR = {Dooms, Ann and Jespers, Eric and Konovalov, Alexander}, TITLE = {Farey symbols and generators for subgroups of finite index in integral group rings of finite groups}, JOURNAL = {in preparation}, FJOURNAL = {}, VOLUME = {}, YEAR = {2008}, NUMBER = {}, PAGES = {}, } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %E congruence-1.2.3/doc/chapBib.txt0000664000371700037170000000172013503171577017726 0ustar gap-jenkinsgap-jenkins References [CLLT93] Chan, S.-P., Lang, M.-L., Lim, C.-H. and Tan, S. P., Special polygons for subgroups of the modular group and applications, Internat. J. Math., 4, 1 (1993), 11--34. [Kul91] Kulkarni, R. S., An arithmetic-geometric method in the study of the subgroups of the modular group, Amer. J. Math., 113, 6 (1991), 1053--1133. [LLT95a] Lang, M.-L., Lim, C.-H. and Tan, S. P., An algorithm for determining if a subgroup of the modular group is congruence, J. London Math. Soc. (2), 51, 3 (1995), 491--502. [LLT95b] Lang, M.-L., Lim, C.-H. and Tan, S. P., Independent generators for congruence subgroups of Hecke groups, Math. Z., 220, 4 (1995), 569--594.  congruence-1.2.3/doc/farey.xml0000664000371700037170000001073213503171577017470 0ustar gap-jenkinsgap-jenkins Farey symbols and their properties IsFareySymbol IsFareySymbolDefaultRep A Farey symbol is a compact and useful way to represent a subgroup of finite index in SL_2(&ZZ;) from which one can deduce independent generators for this subgroup. It consists of two components, namely a so-called generalised Farey sequence (gfs) and an ordered list of labels, giving additional structure to the gfs.

A generalised Farey sequence (g.F.S.) is an ordered list of the form { -infinity, x_0, x_1, ... , x_n, infinity }, where

1. the x_i = a_i/b_i are rational numbers in reduced form arranged in increasing order for i = 0, ... , n;

2. x_0, ... , x_n \in Z, and some x_i = 0;

3. we define x_{-1}=-infinity=-1/0 and x_{n+1}=infinity=1/0;

4. a_{i+1}b_{i}-a_{i}b_{i+1}=1 for i=-1, ... ,n.

The ordered list of labels of a Farey symbol gives an additional structure to the gfs. The labels correspond to each consecutive pair of x_i's and are of the following types:

1. even,

2. odd,

3. a natural number, which occurs in the list of labels exactly twice or not at all.

Note that the actual values of numerical labels are not important; it is the pairing of two intervals that matters.

The package &Congruence; provides functions to construct Farey symbols by the given generalised Farey sequence and corresponding list of labels. The returned Farey symbol will belong to the category IsFareySymbol and will have the representation IsFareySymbolDefaultRep.

Construction of Farey symbols This constructor creates the Farey symbol with the given generalized Farey sequence and list of labels. It also checks conditions from the definition of Farey symbol and returns an error if they are not satisfied. The data used to create the Farey symbol are stored as its attributes and . fs:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]); [ infinity, 0, 1, 2, infinity ] [ 1, 2, 2, 1 ] ]]> This function is used in to validate its output. IsValidFareySymbol(fs); true ]]>
Properties of Farey symbols Returns the generalized Farey sequence gfs of the Farey symbol. GeneralizedFareySequence(fs); [ infinity, 0, 1, 2, infinity ] ]]> integer Returns the numerator of the i-th term of the generalised Farey sequence gfs: for the 1st infinite entry returns -1, for the last one returns 1, for all other entries returns the usual numerator. List([1..5], i -> NumeratorOfGFSElement(GeneralizedFareySequence(fs),i)); [ -1, 0, 1, 2, 1 ] ]]> integer Returns the denominator of the i-th term of the generalised Farey sequence gfs: for both infinite entries returns 0, for the other ones returns the usual denominator. List([1..5], i -> DenominatorOfGFSElement(GeneralizedFareySequence(fs),i)); [ 0, 1, 1, 1, 0 ] ]]> Returns the list of labels of the Farey symbol. This list has "odd", "even" and paired integers as entries. LabelsOfFareySymbol(fs); [ 1, 2, 2, 1 ] ]]>
congruence-1.2.3/doc/manual.xml0000664000371700037170000000675313503171577017647 0ustar gap-jenkinsgap-jenkins Congruence"> <#Include Label="PKGVERSIONDATA"> ] > &Congruence; Congruence subgroups of SL_2(&ZZ;) Version &VERSION; Ann Dooms andooms@vub.ac.be http://homepages.vub.ac.be/˜andooms
Department of Mathematics, Vrije Universiteit Brussel
Pleinlaan 2, Brussels, B-1050 Belgium
Eric Jespers efjesper@vub.ac.be http://homepages.vub.ac.be/˜efjesper
Department of Mathematics, Vrije Universiteit Brussel
Pleinlaan 2, Brussels, B-1050 Belgium
Alexander Konovalov alexander.konovalov@st-andrews.ac.uk https://alexk.host.cs.st-andrews.ac.uk
School of Computer Science
University of St Andrews
Jack Cole Building, North Haugh,
St Andrews, Fife, KY16 9SX, Scotland
Helena Verrill verrill@math.lsu.edu http://www.math.lsu.edu/˜verrill/
Department of Mathematics
Louisiana State University
Baton Rouge, Louisiana, 70803-4918
USA
&RELEASEDATE; &Congruence; package The &GAP; package &Congruence; provides functionality to work with congruence subgroups of SL_2(&ZZ;). ©right; 2006-&RELEASEYEAR; by Ann Dooms, Eric Jespers, Alexander Konovalov and Helena Verrill.

&Congruence; 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. For details, see the FSF's own site http://www.gnu.org/licenses/gpl.html.

If you obtained &Congruence;, we would be grateful for a short notification sent to one of the authors.

If you publish a result which was partially obtained with the usage of &Congruence;, please cite it in the following form:

A. Dooms, E. Jespers, A. Konovalov and H. Verrill. Congruence --- Congruence subgroups of SL_2(&ZZ;), Version &VERSION;; &RELEASEYEAR; (http://www.cs.st-andrews.ac.uk/˜alexk/congruence/). We are very grateful to Mong-Lung Lang, Chong-Hai Lim and Ser Peow Tan for their comments provided while implementing algorithms from and , and to Francqui Stichting (Belgium) for the support of the third author. <#Include SYSTEM "intro.xml"> <#Include SYSTEM "cong.xml"> <#Include SYSTEM "farey.xml"> <#Include SYSTEM "gens.xml"> <#Include SYSTEM "service.xml"> congruence-1.2.3/doc/grprings.xml0000664000371700037170000000030013503171577020203 0ustar gap-jenkinsgap-jenkins Generators for U(ZG) up to finite index See . congruence-1.2.3/doc/times.css0000664000371700037170000000026113503171577017467 0ustar gap-jenkinsgap-jenkins/* times.css Frank Lübeck */ /* Change default CSS to use Times font. */ body { font-family: Times,Times New Roman,serif; } congruence-1.2.3/doc/toggless.css0000664000371700037170000000167213503171577020204 0ustar gap-jenkinsgap-jenkins/* 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; } congruence-1.2.3/doc/chap2.txt0000664000371700037170000005031713503171577017401 0ustar gap-jenkinsgap-jenkins 2 Construction of congruence subgroups The package Congruence provides functions to construct several types of canonical congruence subgroups in SL_2(ℤ), and also intersections of a finite number of such subgroups. They will return a matrix group in the category IsCongruenceSubgroup, which is defined as a subcategory of IsMatrixGroup, and which will have a distinguishing property determining whether it is a congruence subgroup of one of the canonical types, or an intersection of such congruence subgroups (if it can not be reduced to one of the canonical congruence subgroups). To start to work with the package, you need first to load it as follows:  Example   gap> LoadPackage("congruence"); ----------------------------------------------------------------------------- Loading Congruence 1.1.0 (Congruence subgroups of SL(2,Integers)) by Ann Dooms (http://homepages.vub.ac.be/~andooms),  Eric Jespers (http://homepages.vub.ac.be/~efjesper),  Alexander Konovalov (http://www.cs.st-andrews.ac.uk/~alexk/), and  Helena Verrill (http://www.math.lsu.edu/~verrill). ----------------------------------------------------------------------------- true   2.1 Construction of congruence subgroups 2.1-1 PrincipalCongruenceSubgroup PrincipalCongruenceSubgroup( N )  operation Returns the principal congruence subgroup Γ(N) of level N in SL_2(ℤ). This subgroup consists of all matrices of the form [1+N*a N*b] [ N*c 1+N*d] where a,b,c,d are integers. The returned group will have the property IsPrincipalCongruenceSubgroup (2.2-1).  Example   gap> G_8:=PrincipalCongruenceSubgroup(8);  gap> IsGroup(G_8); true gap> IsMatrixGroup(G_8); true gap> DimensionOfMatrixGroup(G_8); 2 gap> MultiplicativeNeutralElement(G_8); [ [ 1, 0 ], [ 0, 1 ] ] gap> One(G); [ [ 1, 0 ], [ 0, 1 ] ] gap> [[1,2],[3,4]] in G_8; false gap> [[1,8],[8,65]] in G_8; true gap> SL_2:=SL(2,Integers); SL(2,Integers) gap> IsSubgroup(SL_2,G_8); true   2.1-2 CongruenceSubgroupGamma0 CongruenceSubgroupGamma0( N )  operation Returns the congruence subgroup Γ_0(N) of level N in SL_2(ℤ). This subgroup consists of all matrices of the form [a b] [N*c d] where a,b,c,d are integers. The returned group will have the property IsCongruenceSubgroupGamma0 (2.2-2).  Example   gap> G0_4:=CongruenceSubgroupGamma0(4);    2.1-3 CongruenceSubgroupGammaUpper0 CongruenceSubgroupGammaUpper0( N )  operation Returns the congruence subgroup Γ^0(N) of level N in SL_2(ℤ). This subgroup consists of all matrices of the form [a N*b] [c d] where a,b,c,d are integers. The returned group will have the property IsCongruenceSubgroupGammaUpper0 (2.2-3).  Example   gap> GU0_2:=CongruenceSubgroupGammaUpper0(2);    2.1-4 CongruenceSubgroupGamma1 CongruenceSubgroupGamma1( N )  operation Returns the congruence subgroup Γ_1(N) of level N in SL_2(ℤ). This subgroup consists of all matrices of the form [1+N*a b] [ N*c 1+N*d] where a,b,c,d are integers. The returned group will have the property IsCongruenceSubgroupGamma1 (2.2-4).  Example   gap> G1_6:=CongruenceSubgroupGamma1(6);    2.1-5 CongruenceSubgroupGammaUpper1 CongruenceSubgroupGammaUpper1( N )  operation Returns the congruence subgroup Γ^1(N) of level N in SL_2(ℤ). This subgroup consists of all matrices of the form [1+N*a N*b] [ c 1+N*d] where a,b,c,d are integers. The returned group will have the property IsCongruenceSubgroupGammaUpper1 (2.2-5).  Example   gap> GU1_4:=CongruenceSubgroupGammaUpper1(4);    2.1-6 IntersectionOfCongruenceSubgroups IntersectionOfCongruenceSubgroups( G1, G2, ..., GN )  function Intersection( G1, G2, ..., GN )  function Returns the intersection of its arguments, which can be congruence subgroups or their intersections, constructed with the same function. It is not necessary for the user to use IntersectionOfCongruenceSubgroups, since it will be called automatically from Intersection. The returned group will have the property IsIntersectionOfCongruenceSubgroups (2.2-6). The list of congruence subgroups that form the intersection can be obtained using DefiningCongruenceSubgroups (2.3-3). Note, that when the intersection appears to be one of the canonical congruence subgroups, the package will recognize this and will return a canonical subgroup of the appropriate type.  Example   gap> I:=IntersectionOfCongruenceSubgroups(G0_4,GU1_4);  gap> J:=IntersectionOfCongruenceSubgroups(G0_4,G1_6);    2.2 Properties of congruence subgroups A congruence subgroup constructed by one of the five above listed functions will have certain properties determining its type. These properties will be used for method selection by Congruence algorithms. Note that they do not provide an actual test whether a certain matrix group is a congruence subgroup or not. 2.2-1 IsPrincipalCongruenceSubgroup IsPrincipalCongruenceSubgroup( G )  property For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by PrincipalCongruenceSubgroup (2.1-1) (or reduced to one as a result of an intersection) and returns false otherwise.  Example   gap> IsPrincipalCongruenceSubgroup(G_8); true gap> IsPrincipalCongruenceSubgroup(G0_4); false gap> IsPrincipalCongruenceSubgroup(I); true   2.2-2 IsCongruenceSubgroupGamma0 IsCongruenceSubgroupGamma0( G )  property For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGamma0 (2.1-2) (or reduced to one as a result of an intersection) and returns false otherwise. 2.2-3 IsCongruenceSubgroupGammaUpper0 IsCongruenceSubgroupGammaUpper0( G )  property For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGammaUpper0 (2.1-3) (or reduced to one as a result of an intersection) and returns false otherwise. 2.2-4 IsCongruenceSubgroupGamma1 IsCongruenceSubgroupGamma1( G )  property For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGamma1 (2.1-4) (or reduced to one as a result of an intersection) and returns false otherwise. 2.2-5 IsCongruenceSubgroupGammaUpper1 IsCongruenceSubgroupGammaUpper1( G )  property For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by CongruenceSubgroupGammaUpper1 (2.1-5) (or reduced to one as a result of an intersection) and returns false otherwise. 2.2-6 IsIntersectionOfCongruenceSubgroups IsIntersectionOfCongruenceSubgroups( G )  property For a congruence subgroup G in the category IsCongruenceSubgroup, returns true if G was constructed by IntersectionOfCongruenceSubgroups (2.1-6) and without being one of the canonical congruence subgroups, otherwise it returns false.  Example   gap> IsIntersectionOfCongruenceSubgroups(I); false gap> IsIntersectionOfCongruenceSubgroups(J); true   2.3 Attributes of congruence subgroups The next three attributes store key properties of congruence subgroups. 2.3-1 LevelOfCongruenceSubgroup LevelOfCongruenceSubgroup( G )  attribute Stores the level of the congruence subgroup G. The (arithmetic) level of a congruence subgroup G is the smallest positive number N such that G contains the principal congruence subgroup of level N.  Example   gap> LevelOfCongruenceSubgroup(G_8); 8 gap> LevelOfCongruenceSubgroup(G1_6); 6 gap> LevelOfCongruenceSubgroup(I); 4 gap> LevelOfCongruenceSubgroup(J); 12   2.3-2 IndexInSL2Z IndexInSL2Z( G )  attribute Stores the index of the congruence subgroup G in SL_2(ℤ).  Example   gap> IndexInSL2Z(G_8); 384 gap> G_2:=PrincipalCongruenceSubgroup(2);  gap> IndexInSL2Z(G_2); 12 gap> IndexInSL2Z(GU1_4); 12   2.3-3 DefiningCongruenceSubgroups DefiningCongruenceSubgroups( G )  attribute Returns: list of congruence subgroups For an intersection of congruence subgroups, returns the list of congruence subgroups forming this intersection. For a canonical congruence subgroup returns a list of length one containing that subgroup.  Example   gap> DefiningCongruenceSubgroups(J); [ ,  ] gap> P:=PrincipalCongruenceSubgroup(6);  gap> Q:=PrincipalCongruenceSubgroup(10);   gap> G:=IntersectionOfCongruenceSubgroups(Q,P);   gap> DefiningCongruenceSubgroups(G); [ ]    2.4 Operations for congruence subgroups Congruence installs several special methods for operations already available in GAP. 2.4-1 Random Random( G )  operation Random( G, m )  operation For a congruence subgroup G in the category IsCongruenceSubgroup, returns random element. In the two-argument form, the second parameter will control the absolute value of randomly selected entries of the matrix.  Example   gap> Random(G_2) in G_2; true gap> Random(G_8,2) in G_8; true   2.4-2 \in \in( m, G )  operation It is easy to implement the membership test for congruence subgroups and their intersections.  Example   gap> \in([ [ 21, 10 ], [ 2, 1 ] ],G_2); true gap> \in([ [ 21, 10 ], [ 2, 1 ] ],G_8); false   2.4-3 CanEasilyCompareCongruenceSubgroups CanEasilyCompareCongruenceSubgroups( G, H )  operation For congruence subgroups G,H in the category IsCongruenceSubgroup, returns true if G and H are of the same type listed in PrincipalCongruenceSubgroup (2.1-1) --> CongruenceSubgroupGammaUpper1 (2.1-5) and have the same LevelOfCongruenceSubgroup (2.3-1) or if G and H are of the type IntersectionOfCongruenceSubgroups (2.1-6) and the groups from DefiningCongruenceSubgroups (2.3-3) are in one to one correspondence, otherwise it returns false.  Example   gap> CanEasilyCompareCongruenceSubgroups(G_8,I); false   2.4-4 IsSubset IsSubset( G, H )  operation Congruence provides methods for IsSubset for congruence subgroups. IsSubset returns true if H is a subset of G. These methods make it possible to use IsSubgroup operation for congruence subgroups.  Example   gap> IsSubset(G_2,G_8); true gap> IsSubset(G_8,G_2); false gap> f:=[PrincipalCongruenceSubgroup,CongruenceSubgroupGamma1,CongruenceSubgroupGammaUpper1,CongruenceSubgroupGamma0,CongruenceSubgroupGammaUpper0];; gap> g1:=List(f, t -> t(2));; gap> g2:=List(f, t -> t(4));; gap> for g in g2 do > Print( List( g1, x -> IsSubgroup(x,g) ), "\n"); > od; [ true, true, true, true, true ] [ false, true, false, true, false ] [ false, false, true, false, true ] [ false, false, false, true, false ] [ false, false, false, false, true ]   2.4-5 Index Index( G, H )  operation If a congruence subgroup H is a subgroup of a congruence subgroup G, we can easily compute the index of H in G, since we know the index of both subgroups in SL_2(ℤ).  Example   gap> Index(G_2,G_8); 32   congruence-1.2.3/doc/chap3.txt0000664000371700037170000001320513503171577017375 0ustar gap-jenkinsgap-jenkins 3 Farey symbols and their properties A Farey symbol is a compact and useful way to represent a subgroup of finite index in SL_2(ℤ) from which one can deduce independent generators for this subgroup. It consists of two components, namely a so-called generalised Farey sequence (gfs) and an ordered list of labels, giving additional structure to the gfs. A generalised Farey sequence (g.F.S.) is an ordered list of the form -infinity, x_0, x_1, ... , x_n, infinity, where 1. the x_i = a_i/b_i are rational numbers in reduced form arranged in increasing order for i = 0, ... , n; 2. x_0, ... , x_n ∈ Z, and some x_i = 0; 3. we define x_-1=-infinity=-1/0 and x_n+1=infinity=1/0; 4. a_i+1b_i-a_ib_i+1=1 for i=-1, ... ,n. The ordered list of labels of a Farey symbol gives an additional structure to the gfs. The labels correspond to each consecutive pair of x_i's and are of the following types: 1. even, 2. odd, 3. a natural number, which occurs in the list of labels exactly twice or not at all. Note that the actual values of numerical labels are not important; it is the pairing of two intervals that matters. The package Congruence provides functions to construct Farey symbols by the given generalised Farey sequence and corresponding list of labels. The returned Farey symbol will belong to the category IsFareySymbol and will have the representation IsFareySymbolDefaultRep. 3.1 Construction of Farey symbols 3.1-1 FareySymbolByData FareySymbolByData( gfs, labels )  function This constructor creates the Farey symbol with the given generalized Farey sequence and list of labels. It also checks conditions from the definition of Farey symbol and returns an error if they are not satisfied. The data used to create the Farey symbol are stored as its attributes GeneralizedFareySequence (3.2-1) and LabelsOfFareySymbol (3.2-4).  Example   gap> fs:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]);  [ infinity, 0, 1, 2, infinity ] [ 1, 2, 2, 1 ]   3.1-2 IsValidFareySymbol IsValidFareySymbol( fs )  function This function is used in FareySymbolByData (3.1-1) to validate its output.  Example   gap> IsValidFareySymbol(fs); true   3.2 Properties of Farey symbols 3.2-1 GeneralizedFareySequence GeneralizedFareySequence( fs )  attribute Returns the generalized Farey sequence gfs of the Farey symbol.  Example   gap> GeneralizedFareySequence(fs); [ infinity, 0, 1, 2, infinity ]   3.2-2 NumeratorOfGFSElement NumeratorOfGFSElement( gfs, i )  function Returns: integer Returns the numerator of the i-th term of the generalised Farey sequence gfs: for the 1st infinite entry returns -1, for the last one returns 1, for all other entries returns the usual numerator.  Example   gap> List([1..5], i -> NumeratorOfGFSElement(GeneralizedFareySequence(fs),i)); [ -1, 0, 1, 2, 1 ]   3.2-3 DenominatorOfGFSElement DenominatorOfGFSElement( gfs, i )  function Returns: integer Returns the denominator of the i-th term of the generalised Farey sequence gfs: for both infinite entries returns 0, for the other ones returns the usual denominator.  Example   gap> List([1..5], i -> DenominatorOfGFSElement(GeneralizedFareySequence(fs),i));  [ 0, 1, 1, 1, 0 ]   3.2-4 LabelsOfFareySymbol LabelsOfFareySymbol( fs )  attribute Returns the list of labels of the Farey symbol. This list has "odd", "even" and paired integers as entries.  Example   gap> LabelsOfFareySymbol(fs); [ 1, 2, 2, 1 ]   congruence-1.2.3/doc/chapBib.html0000664000371700037170000001031013503171577020046 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - References

Goto Chapter: Top 1 2 3 4 5 Bib Ind

References

[CLLT93] Chan, S.-P., Lang, M.-L., Lim, C.-H. and Tan, S. P., Special polygons for subgroups of the modular group and applications, Internat. J. Math., 4 (1) (1993), 11--34.

[Kul91] Kulkarni, R. S., An arithmetic-geometric method in the study of the subgroups of the modular group, Amer. J. Math., 113 (6) (1991), 1053--1133.

[LLT95a] Lang, M.-L., Lim, C.-H. and Tan, S. P., An algorithm for determining if a subgroup of the modular group is congruence, J. London Math. Soc. (2), 51 (3) (1995), 491--502.

[LLT95b] Lang, M.-L., Lim, C.-H. and Tan, S. P., Independent generators for congruence subgroups of Hecke groups, Math. Z., 220 (4) (1995), 569--594.

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chap0.html0000664000371700037170000003436313503171577017527 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Contents
Goto Chapter: Top 1 2 3 4 5 Bib Ind

Congruence

Congruence subgroups of SL_2(ℤ)

Version 1.2.3

19 May 2019

Ann Dooms
Email: andooms@vub.ac.be
Homepage: http://homepages.vub.ac.be/~andooms
Address:
Department of Mathematics, Vrije Universiteit Brussel
Pleinlaan 2, Brussels, B-1050 Belgium

Eric Jespers
Email: efjesper@vub.ac.be
Homepage: http://homepages.vub.ac.be/~efjesper
Address:
Department of Mathematics, Vrije Universiteit Brussel
Pleinlaan 2, Brussels, B-1050 Belgium

Alexander Konovalov
Email: alexander.konovalov@st-andrews.ac.uk
Homepage: https://alexk.host.cs.st-andrews.ac.uk
Address:
School of Computer Science
University of St Andrews
Jack Cole Building, North Haugh,
St Andrews, Fife, KY16 9SX, Scotland

Helena Verrill
Email: verrill@math.lsu.edu
Homepage: http://www.math.lsu.edu/~verrill/
Address:
Department of Mathematics
Louisiana State University
Baton Rouge, Louisiana, 70803-4918
USA

Abstract

The GAP package Congruence provides functionality to work with congruence subgroups of SL_2(ℤ).

Copyright

© 2006-2019 by Ann Dooms, Eric Jespers, Alexander Konovalov and Helena Verrill.

Congruence 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. For details, see the FSF's own site http://www.gnu.org/licenses/gpl.html.

If you obtained Congruence, we would be grateful for a short notification sent to one of the authors.

If you publish a result which was partially obtained with the usage of Congruence, please cite it in the following form:

A. Dooms, E. Jespers, A. Konovalov and H. Verrill. Congruence --- Congruence subgroups of SL_2(ℤ), Version 1.2.3; 2019 (http://www.cs.st-andrews.ac.uk/~alexk/congruence/).

Acknowledgements

We are very grateful to Mong-Lung Lang, Chong-Hai Lim and Ser Peow Tan for their comments provided while implementing algorithms from [LLT95a] and [LLT95b], and to Francqui Stichting (Belgium) for the support of the third author.

Contents


Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chap1.txt0000664000371700037170000000421113503171577017370 0ustar gap-jenkinsgap-jenkins 1 Introduction 1.1 General aims of Congruence package The GAP package Congruence provides functions to construct several types of canonical congruence subgroups in SL_2(ℤ), and also intersections of a finite number of such subgroups. Furthermore, it implements the algorithm for generating Farey symbols for congruence subgroups and using them to produce a system of independent generators for these subgroups. Using the package, one can also determine indices of congruence subgroups and their intersections in SL_2(ℤ) and in other congruence subgroups, generate their random elements and check element memberships. Success of other group theoretical constructions mostly depends on whether they could be expressed in terms of group generators or not. For the theoretical backround, we refer to [LLT95b], [LLT95a], [CLLT93] and [Kul91]. 1.2 Installation and system requirements Congruence is distributed in standard formats (tar.gz, tar.bz2, -win.zip) and can be obtained from http://www.cs.st-andrews.ac.uk/~alexk/congruence/. Congruence does not use external binaries and, therefore, works without restrictions on the operating system. It requires at least version GAP 4.5, and no compatibility with previous releases of GAP 4 is guaranteed. Installation of the package is standard and follows the guidelines from the GAP manual (see 'Reference: Installing a GAP Package'. After the package is installed, you can start GAP and load the Congruence package using the command:  Example   gap> LoadPackage("congruence");   congruence-1.2.3/doc/chap0.txt0000664000371700037170000001360413503171577017375 0ustar gap-jenkinsgap-jenkins Congruence Congruence subgroups of SL_2(ℤ) Version 1.2.3 19 May 2019 Ann Dooms Eric Jespers Alexander Konovalov Helena Verrill Ann Dooms Email: mailto:andooms@vub.ac.be Homepage: http://homepages.vub.ac.be/~andooms Address: Department of Mathematics, Vrije Universiteit Brussel Pleinlaan 2, Brussels, B-1050 Belgium Eric Jespers Email: mailto:efjesper@vub.ac.be Homepage: http://homepages.vub.ac.be/~efjesper Address: Department of Mathematics, Vrije Universiteit Brussel Pleinlaan 2, Brussels, B-1050 Belgium Alexander Konovalov Email: mailto:alexander.konovalov@st-andrews.ac.uk Homepage: https://alexk.host.cs.st-andrews.ac.uk Address: School of Computer Science University of St Andrews Jack Cole Building, North Haugh, St Andrews, Fife, KY16 9SX, Scotland Helena Verrill Email: mailto:verrill@math.lsu.edu Homepage: http://www.math.lsu.edu/~verrill/ Address: Department of Mathematics Louisiana State University Baton Rouge, Louisiana, 70803-4918 USA ------------------------------------------------------- Abstract The GAP package Congruence provides functionality to work with congruence subgroups of SL_2(ℤ). ------------------------------------------------------- Copyright © 2006-2019 by Ann Dooms, Eric Jespers, Alexander Konovalov and Helena Verrill. Congruence 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. For details, see the FSF's own site http://www.gnu.org/licenses/gpl.html. If you obtained Congruence, we would be grateful for a short notification sent to one of the authors. If you publish a result which was partially obtained with the usage of Congruence, please cite it in the following form: A. Dooms, E. Jespers, A. Konovalov and H. Verrill. Congruence --- Congruence subgroups of SL_2(ℤ), Version 1.2.3; 2019 (http://www.cs.st-andrews.ac.uk/~alexk/congruence/). ------------------------------------------------------- Acknowledgements We are very grateful to Mong-Lung Lang, Chong-Hai Lim and Ser Peow Tan for their comments provided while implementing algorithms from [LLT95a] and [LLT95b], and to Francqui Stichting (Belgium) for the support of the third author. ------------------------------------------------------- Contents (Congruence) 1 Introduction 1.1 General aims of Congruence package 1.2 Installation and system requirements 2 Construction of congruence subgroups 2.1 Construction of congruence subgroups 2.1-1 PrincipalCongruenceSubgroup 2.1-2 CongruenceSubgroupGamma0 2.1-3 CongruenceSubgroupGammaUpper0 2.1-4 CongruenceSubgroupGamma1 2.1-5 CongruenceSubgroupGammaUpper1 2.1-6 IntersectionOfCongruenceSubgroups 2.2 Properties of congruence subgroups 2.2-1 IsPrincipalCongruenceSubgroup 2.2-2 IsCongruenceSubgroupGamma0 2.2-3 IsCongruenceSubgroupGammaUpper0 2.2-4 IsCongruenceSubgroupGamma1 2.2-5 IsCongruenceSubgroupGammaUpper1 2.2-6 IsIntersectionOfCongruenceSubgroups 2.3 Attributes of congruence subgroups 2.3-1 LevelOfCongruenceSubgroup 2.3-2 IndexInSL2Z 2.3-3 DefiningCongruenceSubgroups 2.4 Operations for congruence subgroups 2.4-1 Random 2.4-2 \in 2.4-3 CanEasilyCompareCongruenceSubgroups 2.4-4 IsSubset 2.4-5 Index 3 Farey symbols and their properties 3.1 Construction of Farey symbols 3.1-1 FareySymbolByData 3.1-2 IsValidFareySymbol 3.2 Properties of Farey symbols 3.2-1 GeneralizedFareySequence 3.2-2 NumeratorOfGFSElement 3.2-3 DenominatorOfGFSElement 3.2-4 LabelsOfFareySymbol 4 Farey symbols for congruence subgroups 4.1 Computation of the Farey symbol for a finite index subgroup 4.1-1 FareySymbol 4.2 Computation of generators of a finite index subgroup from its Farey symbol 4.2-1 MatrixByEvenInterval 4.2-2 MatrixByOddInterval 4.2-3 MatrixByFreePairOfIntervals 4.2-4 GeneratorsByFareySymbol 4.2-5 GeneratorsOfGroup 4.3 Other properties derived from Farey symbols 4.3-1 IndexInPSL2ZByFareySymbol 5 Service functions of the Congruence package 5.1 Additional information displayed by Congruence algorithms 5.1-1 InfoCongruence  congruence-1.2.3/doc/chap4_mj.html0000664000371700037170000003760313503171577020221 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Chapter 4: Farey symbols for congruence subgroups
Goto Chapter: Top 1 2 3 4 5 Bib Ind

4 Farey symbols for congruence subgroups

The package Congruence provides functions to construct Farey symbols for finite index subgroups. The algorithm used in the package allows to construct a Farey symbol for any finite index subgroup of \(SL_2(ℤ)\) for which it is possible to check whether a given matrix belongs to this subgroup or not.

The development of an algorithm to determine the Farey symbol for a subgroup G of a finite index in \(SL_2(ℤ)\) was started by Ravi Kulkarni in [Kul91] and later it was improved by Mong-Lung Lang, Chong-Hai Lim and Ser-Peow Tan in [LLT95b], [LLT95a].

4.1 Computation of the Farey symbol for a finite index subgroup

4.1-1 FareySymbol
‣ FareySymbol( G )( attribute )

For a subgroup of a finite index G, this attribute stores one of the Farey symbols corresponding to the congruence subgroup G. The algorithm for its computation will work for any matrix group for which a membership test is available.


gap> FareySymbol(PrincipalCongruenceSubgroup(8));
[ infinity, 0, 1/4, 1/3, 3/8, 2/5, 1/2, 3/5, 5/8, 2/3, 3/4, 1, 5/4, 4/3, 
  11/8, 7/5, 3/2, 8/5, 13/8, 5/3, 7/4, 2, 9/4, 7/3, 19/8, 12/5, 5/2, 13/5, 
  21/8, 8/3, 11/4, 3, 13/4, 10/3, 27/8, 17/5, 7/2, 18/5, 29/8, 11/3, 15/4, 4, 
  17/4, 13/3, 9/2, 14/3, 19/4, 5, 21/4, 16/3, 11/2, 17/3, 23/4, 6, 25/4, 
  19/3, 13/2, 20/3, 27/4, 7, 29/4, 22/3, 15/2, 23/3, 31/4, 8, infinity ]
[ 1, 17, 10, 26, 32, 18, 19, 27, 30, 5, 2, 2, 13, 28, 26, 20, 21, 29, 27, 7, 
  3, 3, 16, 31, 28, 22, 23, 33, 29, 9, 4, 4, 5, 30, 31, 24, 25, 32, 33, 12, 
  6, 6, 7, 19, 18, 15, 8, 8, 9, 21, 20, 10, 11, 11, 12, 23, 22, 13, 14, 14, 
  15, 25, 24, 16, 17, 1 ]
gap> FareySymbol(CongruenceSubgroupGamma0(20));
[ infinity, 0, 1/5, 1/4, 2/7, 3/10, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1, 
  infinity ]
[ 1, 3, 4, 6, 7, 7, 5, 2, 2, 3, 6, 4, 5, 1 ]  

4.2 Computation of generators of a finite index subgroup from its Farey symbol

If fs is the Farey symbol for a group \(G\) with \(r_1\) even labels, \(r_2\) odd labels and \(r_3\) pairs of intervals, then \(G\) is generated by \(r_1+r_2+r_3\) matrices, which form a set of independent generators for \(G\). These matrices are constructed as follows:

for each even interval \([x_i, x_{i+1}]\), take the matrix


                       A=  [a_{i+1} b_{i+1} + a_i b_i    -a_i^2 - a_{i+1}^2        ]
                           [b_i^2 +b_{i+1}^2             -a_{i+1} b_{i+1} - a_i b_i]

for each odd interval \([x_j,x_{j+1}]\), take the matrix


                        B=  [a_{j+1} b_{j+1} + a_j b_{j+1} + a_j b_j      -a_j^2 - a_j a_{j+1} -a_{j+1}^2]
                            [ b_j^2 + b_j b_{j+1} + b_{j+1}^2  -a_{j+1}   b_{j+1} - a_{j+1} b_j - a_j b_j]

for each pair of free intervals \([x_k,x_{k+1}]\) and \([x_s,x_{s+1}]\), take the matrix


                        C=  [a_{s+1} b_{k+1} + a_s b_k    -a_s a_k - a_{s+1} a_{k+1}]
                            [b_s b_k- b_{s+1} b_{k+1}c    -a_{k+1} b_{s+1} - a_k b_s]

4.2-1 MatrixByEvenInterval
‣ MatrixByEvenInterval( gfs, i )( function )

Returns the matrix corresponding to the even interval i in the generalized Farey sequence gfs.


gap> H:=CongruenceSubgroupGamma0(5); 
<congruence subgroup CongruenceSubgroupGamma_0(5) in SL_2(Z)>
gap> fs:=FareySymbol(H);
[ infinity, 0, 1/2, 1, infinity ]
[ 1, "even", "even", 1 ]
gap> gfs:=GeneralizedFareySequence(fs);
[ infinity, 0, 1/2, 1, infinity ]
gap> MatrixByEvenInterval(gfs,2);      
[ [ 2, -1 ], [ 5, -2 ] ]

4.2-2 MatrixByOddInterval
‣ MatrixByOddInterval( gfs, i )( function )

Returns the matrix corresponding to the odd interval i in the generalized Farey sequence gfs.


gap> fs_oo:=FareySymbolByData([infinity,0,infinity],["odd","odd"]);;
gap> gfs_oo:=GeneralizedFareySequence(fs_oo);
[ infinity, 0, infinity ]
gap> MatrixByOddInterval(gfs_oo,1);
[ [ -1, -1 ], [ 1, 0 ] ]

4.2-3 MatrixByFreePairOfIntervals
‣ MatrixByFreePairOfIntervals( gfs, k, kp )( function )

Returns the matrix corresponding to the pair of free intervals k and kp in the generalized Farey sequence gfs.


gap> fs_free:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]);;
gap> gfs_free:=GeneralizedFareySequence(fs_free);;
gap> MatrixByFreePairOfIntervals(gfs_free,2,3);                                                        
[ [ 3, -2 ], [ 2, -1 ] ]

4.2-4 GeneratorsByFareySymbol
‣ GeneratorsByFareySymbol( fs )( function )

Returns a set of matrices constructed as above.


gap> fs_eo:=FareySymbolByData([infinity,0,infinity],["even","odd"]);;
gap> GeneratorsByFareySymbol(last);                                  
[ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ]
gap> GeneratorsByFareySymbol(fs); 
[ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ]
gap> GeneratorsByFareySymbol(fs_oo);
[ [ [ -1, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ]
gap> GeneratorsByFareySymbol(fs_free);                                                        
[ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ]

4.2-5 GeneratorsOfGroup
‣ GeneratorsOfGroup( G )( function )

Returns a set of generators for the finite index group G in \(SL_2(Z)\).


gap> G:=PrincipalCongruenceSubgroup(2);
<principal congruence subgroup of level 2 in SL_2(Z)>
gap> FareySymbol(G);
[ infinity, 0, 1, 2, infinity ]
[ 2, 1, 1, 2 ]
gap> GeneratorsOfGroup(G);
#I  Using the Congruence package for GeneratorsOfGroup ...
[ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ]
gap> H:=CongruenceSubgroupGamma0(5);        
<congruence subgroup CongruenceSubgroupGamma_0(5) in SL_2(Z)>
gap> GeneratorsOfGroup(H);
#I  Using the Congruence package for GeneratorsOfGroup ...
[ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ]
gap> I:=IntersectionOfCongruenceSubgroups(PrincipalCongruenceSubgroup(2),CongruenceSubgroupGamma0(3));
<intersection of congruence subgroups of resulting level 6 in SL_2(Z)>
gap> FareySymbol(I);
[ infinity, 0, 1/3, 1/2, 2/3, 1, 4/3, 3/2, 5/3, 2, infinity ]
[ 1, 5, 4, 3, 2, 2, 3, 4, 5, 1 ]
gap> GeneratorsOfGroup(I);                                                          
#I  Using the Congruence package for GeneratorsOfGroup ...
[ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 11, -2 ], [ 6, -1 ] ], 
  [ [ 19, -8 ], [ 12, -5 ] ], [ [ 17, -10 ], [ 12, -7 ] ], 
  [ [ 7, -6 ], [ 6, -5 ] ] ]

4.3 Other properties derived from Farey symbols

4.3-1 IndexInPSL2ZByFareySymbol
‣ IndexInPSL2ZByFareySymbol( fs )( function )

By Proposition 7.2 in [Kulkarni], for the Farey symbol with underlying generalized Farey sequence [infinity, x0, x1, ..., xn, infinity], the index in \(PSL_2(Z)\) is given by the formula d = 3*n + e3, where e3 is the number of odd intervals.


gap> IndexInPSL2ZByFareySymbol(fs);
6
gap> IndexInPSL2ZByFareySymbol(fs_oo);
2
gap> IndexInPSL2ZByFareySymbol(fs_free);
6

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/manual.css0000664000371700037170000001575413503171577017640 0ustar gap-jenkinsgap-jenkins/* 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 { } congruence-1.2.3/doc/chap4.txt0000664000371700037170000002466513503171577017412 0ustar gap-jenkinsgap-jenkins 4 Farey symbols for congruence subgroups The package Congruence provides functions to construct Farey symbols for finite index subgroups. The algorithm used in the package allows to construct a Farey symbol for any finite index subgroup of SL_2(ℤ) for which it is possible to check whether a given matrix belongs to this subgroup or not. The development of an algorithm to determine the Farey symbol for a subgroup G of a finite index in SL_2(ℤ) was started by Ravi Kulkarni in [Kul91] and later it was improved by Mong-Lung Lang, Chong-Hai Lim and Ser-Peow Tan in [LLT95b], [LLT95a]. 4.1 Computation of the Farey symbol for a finite index subgroup 4.1-1 FareySymbol FareySymbol( G )  attribute For a subgroup of a finite index G, this attribute stores one of the Farey symbols corresponding to the congruence subgroup G. The algorithm for its computation will work for any matrix group for which a membership test is available.  Example   gap> FareySymbol(PrincipalCongruenceSubgroup(8)); [ infinity, 0, 1/4, 1/3, 3/8, 2/5, 1/2, 3/5, 5/8, 2/3, 3/4, 1, 5/4, 4/3,   11/8, 7/5, 3/2, 8/5, 13/8, 5/3, 7/4, 2, 9/4, 7/3, 19/8, 12/5, 5/2, 13/5,   21/8, 8/3, 11/4, 3, 13/4, 10/3, 27/8, 17/5, 7/2, 18/5, 29/8, 11/3, 15/4, 4,   17/4, 13/3, 9/2, 14/3, 19/4, 5, 21/4, 16/3, 11/2, 17/3, 23/4, 6, 25/4,   19/3, 13/2, 20/3, 27/4, 7, 29/4, 22/3, 15/2, 23/3, 31/4, 8, infinity ] [ 1, 17, 10, 26, 32, 18, 19, 27, 30, 5, 2, 2, 13, 28, 26, 20, 21, 29, 27, 7,   3, 3, 16, 31, 28, 22, 23, 33, 29, 9, 4, 4, 5, 30, 31, 24, 25, 32, 33, 12,   6, 6, 7, 19, 18, 15, 8, 8, 9, 21, 20, 10, 11, 11, 12, 23, 22, 13, 14, 14,   15, 25, 24, 16, 17, 1 ] gap> FareySymbol(CongruenceSubgroupGamma0(20)); [ infinity, 0, 1/5, 1/4, 2/7, 3/10, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1,   infinity ] [ 1, 3, 4, 6, 7, 7, 5, 2, 2, 3, 6, 4, 5, 1 ]    4.2 Computation of generators of a finite index subgroup from its Farey symbol If fs is the Farey symbol for a group G with r_1 even labels, r_2 odd labels and r_3 pairs of intervals, then G is generated by r_1+r_2+r_3 matrices, which form a set of independent generators for G. These matrices are constructed as follows: for each even interval [x_i, x_i+1], take the matrix A= [a_{i+1} b_{i+1} + a_i b_i -a_i^2 - a_{i+1}^2 ] [b_i^2 +b_{i+1}^2 -a_{i+1} b_{i+1} - a_i b_i] for each odd interval [x_j,x_j+1], take the matrix B= [a_{j+1} b_{j+1} + a_j b_{j+1} + a_j b_j -a_j^2 - a_j a_{j+1} -a_{j+1}^2] [ b_j^2 + b_j b_{j+1} + b_{j+1}^2 -a_{j+1} b_{j+1} - a_{j+1} b_j - a_j b_j] for each pair of free intervals [x_k,x_k+1] and [x_s,x_s+1], take the matrix C= [a_{s+1} b_{k+1} + a_s b_k -a_s a_k - a_{s+1} a_{k+1}] [b_s b_k- b_{s+1} b_{k+1}c -a_{k+1} b_{s+1} - a_k b_s] 4.2-1 MatrixByEvenInterval MatrixByEvenInterval( gfs, i )  function Returns the matrix corresponding to the even interval i in the generalized Farey sequence gfs.  Example   gap> H:=CongruenceSubgroupGamma0(5);   gap> fs:=FareySymbol(H); [ infinity, 0, 1/2, 1, infinity ] [ 1, "even", "even", 1 ] gap> gfs:=GeneralizedFareySequence(fs); [ infinity, 0, 1/2, 1, infinity ] gap> MatrixByEvenInterval(gfs,2);  [ [ 2, -1 ], [ 5, -2 ] ]   4.2-2 MatrixByOddInterval MatrixByOddInterval( gfs, i )  function Returns the matrix corresponding to the odd interval i in the generalized Farey sequence gfs.  Example   gap> fs_oo:=FareySymbolByData([infinity,0,infinity],["odd","odd"]);; gap> gfs_oo:=GeneralizedFareySequence(fs_oo); [ infinity, 0, infinity ] gap> MatrixByOddInterval(gfs_oo,1); [ [ -1, -1 ], [ 1, 0 ] ]   4.2-3 MatrixByFreePairOfIntervals MatrixByFreePairOfIntervals( gfs, k, kp )  function Returns the matrix corresponding to the pair of free intervals k and kp in the generalized Farey sequence gfs.  Example   gap> fs_free:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]);; gap> gfs_free:=GeneralizedFareySequence(fs_free);; gap> MatrixByFreePairOfIntervals(gfs_free,2,3);  [ [ 3, -2 ], [ 2, -1 ] ]   4.2-4 GeneratorsByFareySymbol GeneratorsByFareySymbol( fs )  function Returns a set of matrices constructed as above.  Example   gap> fs_eo:=FareySymbolByData([infinity,0,infinity],["even","odd"]);; gap> GeneratorsByFareySymbol(last);  [ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ] gap> GeneratorsByFareySymbol(fs);  [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ] gap> GeneratorsByFareySymbol(fs_oo); [ [ [ -1, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ] gap> GeneratorsByFareySymbol(fs_free);  [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ]   4.2-5 GeneratorsOfGroup GeneratorsOfGroup( G )  function Returns a set of generators for the finite index group G in SL_2(Z).  Example   gap> G:=PrincipalCongruenceSubgroup(2);  gap> FareySymbol(G); [ infinity, 0, 1, 2, infinity ] [ 2, 1, 1, 2 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ] gap> H:=CongruenceSubgroupGamma0(5);   gap> GeneratorsOfGroup(H); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ] gap> I:=IntersectionOfCongruenceSubgroups(PrincipalCongruenceSubgroup(2),CongruenceSubgroupGamma0(3));  gap> FareySymbol(I); [ infinity, 0, 1/3, 1/2, 2/3, 1, 4/3, 3/2, 5/3, 2, infinity ] [ 1, 5, 4, 3, 2, 2, 3, 4, 5, 1 ] gap> GeneratorsOfGroup(I);  #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 11, -2 ], [ 6, -1 ] ],   [ [ 19, -8 ], [ 12, -5 ] ], [ [ 17, -10 ], [ 12, -7 ] ],   [ [ 7, -6 ], [ 6, -5 ] ] ]   4.3 Other properties derived from Farey symbols 4.3-1 IndexInPSL2ZByFareySymbol IndexInPSL2ZByFareySymbol( fs )  function By Proposition 7.2 in [Kulkarni], for the Farey symbol with underlying generalized Farey sequence [infinity, x0, x1, ..., xn, infinity], the index in PSL_2(Z) is given by the formula d = 3*n + e3, where e3 is the number of odd intervals.  Example   gap> IndexInPSL2ZByFareySymbol(fs); 6 gap> IndexInPSL2ZByFareySymbol(fs_oo); 2 gap> IndexInPSL2ZByFareySymbol(fs_free); 6   congruence-1.2.3/doc/chap5.txt0000664000371700037170000000134013503171577017374 0ustar gap-jenkinsgap-jenkins 5 Service functions of the Congruence package 5.1 Additional information displayed by Congruence algorithms 5.1-1 InfoCongruence InfoCongruence info class InfoCongruence is a special Info class for Congruence algorithms. It has 3 levels: 0, 1 (default) and 2. To change the info level to k, use the command SetInfoLevel(InfoCongruence, k). In the example below we use this mechanism to see more details during the Farey symbol construction for a congruence subgroup. congruence-1.2.3/doc/ragged.css0000664000371700037170000000023113503171577017574 0ustar gap-jenkinsgap-jenkins/* times.css Frank Lübeck */ /* Change default CSS to use Times font. */ body { text-align: left; } congruence-1.2.3/doc/chap1.html0000664000371700037170000001223513503171577017522 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Chapter 1: Introduction
Goto Chapter: Top 1 2 3 4 5 Bib Ind

1 Introduction

1.1 General aims of Congruence package

The GAP package Congruence provides functions to construct several types of canonical congruence subgroups in SL_2(ℤ), and also intersections of a finite number of such subgroups.

Furthermore, it implements the algorithm for generating Farey symbols for congruence subgroups and using them to produce a system of independent generators for these subgroups.

Using the package, one can also determine indices of congruence subgroups and their intersections in SL_2(ℤ) and in other congruence subgroups, generate their random elements and check element memberships. Success of other group theoretical constructions mostly depends on whether they could be expressed in terms of group generators or not.

For the theoretical backround, we refer to [LLT95b], [LLT95a], [CLLT93] and [Kul91].

1.2 Installation and system requirements

Congruence is distributed in standard formats (tar.gz, tar.bz2, -win.zip) and can be obtained from http://www.cs.st-andrews.ac.uk/~alexk/congruence/.

Congruence does not use external binaries and, therefore, works without restrictions on the operating system. It requires at least version GAP 4.5, and no compatibility with previous releases of GAP 4 is guaranteed.

Installation of the package is standard and follows the guidelines from the GAP manual (see Reference: Installing a GAP Package. After the package is installed, you can start GAP and load the Congruence package using the command:


gap> LoadPackage("congruence");

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chap5_mj.html0000664000371700037170000000752513503171577020222 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Chapter 5: Service functions of the Congruence package
Goto Chapter: Top 1 2 3 4 5 Bib Ind

5 Service functions of the Congruence package

5.1 Additional information displayed by Congruence algorithms

5.1-1 InfoCongruence
‣ InfoCongruence( info class )

InfoCongruence is a special Info class for Congruence algorithms. It has 3 levels: 0, 1 (default) and 2. To change the info level to k, use the command SetInfoLevel(InfoCongruence, k).

In the example below we use this mechanism to see more details during the Farey symbol construction for a congruence subgroup.

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/gens.xml0000664000371700037170000002145613503171577017323 0ustar gap-jenkinsgap-jenkins Farey symbols for congruence subgroups The package &Congruence; provides functions to construct Farey symbols for finite index subgroups. The algorithm used in the package allows to construct a Farey symbol for any finite index subgroup of SL_2(&ZZ;) for which it is possible to check whether a given matrix belongs to this subgroup or not.

The development of an algorithm to determine the Farey symbol for a subgroup G of a finite index in SL_2(&ZZ;) was started by Ravi Kulkarni in and later it was improved by Mong-Lung Lang, Chong-Hai Lim and Ser-Peow Tan in , .

Computation of the Farey symbol for a finite index subgroup For a subgroup of a finite index G, this attribute stores one of the Farey symbols corresponding to the congruence subgroup G. The algorithm for its computation will work for any matrix group for which a membership test is available. FareySymbol(PrincipalCongruenceSubgroup(8)); [ infinity, 0, 1/4, 1/3, 3/8, 2/5, 1/2, 3/5, 5/8, 2/3, 3/4, 1, 5/4, 4/3, 11/8, 7/5, 3/2, 8/5, 13/8, 5/3, 7/4, 2, 9/4, 7/3, 19/8, 12/5, 5/2, 13/5, 21/8, 8/3, 11/4, 3, 13/4, 10/3, 27/8, 17/5, 7/2, 18/5, 29/8, 11/3, 15/4, 4, 17/4, 13/3, 9/2, 14/3, 19/4, 5, 21/4, 16/3, 11/2, 17/3, 23/4, 6, 25/4, 19/3, 13/2, 20/3, 27/4, 7, 29/4, 22/3, 15/2, 23/3, 31/4, 8, infinity ] [ 1, 17, 10, 26, 32, 18, 19, 27, 30, 5, 2, 2, 13, 28, 26, 20, 21, 29, 27, 7, 3, 3, 16, 31, 28, 22, 23, 33, 29, 9, 4, 4, 5, 30, 31, 24, 25, 32, 33, 12, 6, 6, 7, 19, 18, 15, 8, 8, 9, 21, 20, 10, 11, 11, 12, 23, 22, 13, 14, 14, 15, 25, 24, 16, 17, 1 ] gap> FareySymbol(CongruenceSubgroupGamma0(20)); [ infinity, 0, 1/5, 1/4, 2/7, 3/10, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1, infinity ] [ 1, 3, 4, 6, 7, 7, 5, 2, 2, 3, 6, 4, 5, 1 ] ]]>
Computation of generators of a finite index subgroup from its Farey symbol If fs is the Farey symbol for a group G with r_1 even labels, r_2 odd labels and r_3 pairs of intervals, then G is generated by r_1+r_2+r_3 matrices, which form a set of independent generators for G. These matrices are constructed as follows:

for each even interval [x_i, x_{i+1}], take the matrix

for each odd interval [x_j,x_{j+1}], take the matrix

for each pair of free intervals [x_k,x_{k+1}] and [x_s,x_{s+1}], take the matrix Returns the matrix corresponding to the even interval i in the generalized Farey sequence gfs. H:=CongruenceSubgroupGamma0(5); gap> fs:=FareySymbol(H); [ infinity, 0, 1/2, 1, infinity ] [ 1, "even", "even", 1 ] gap> gfs:=GeneralizedFareySequence(fs); [ infinity, 0, 1/2, 1, infinity ] gap> MatrixByEvenInterval(gfs,2); [ [ 2, -1 ], [ 5, -2 ] ] ]]> Returns the matrix corresponding to the odd interval i in the generalized Farey sequence gfs. fs_oo:=FareySymbolByData([infinity,0,infinity],["odd","odd"]);; gap> gfs_oo:=GeneralizedFareySequence(fs_oo); [ infinity, 0, infinity ] gap> MatrixByOddInterval(gfs_oo,1); [ [ -1, -1 ], [ 1, 0 ] ] ]]> Returns the matrix corresponding to the pair of free intervals k and kp in the generalized Farey sequence gfs. fs_free:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]);; gap> gfs_free:=GeneralizedFareySequence(fs_free);; gap> MatrixByFreePairOfIntervals(gfs_free,2,3); [ [ 3, -2 ], [ 2, -1 ] ] ]]> Returns a set of matrices constructed as above. fs_eo:=FareySymbolByData([infinity,0,infinity],["even","odd"]);; gap> GeneratorsByFareySymbol(last); [ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ] gap> GeneratorsByFareySymbol(fs); [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ] gap> GeneratorsByFareySymbol(fs_oo); [ [ [ -1, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ] gap> GeneratorsByFareySymbol(fs_free); [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ] ]]> Returns a set of generators for the finite index group G in SL_2(Z). G:=PrincipalCongruenceSubgroup(2); gap> FareySymbol(G); [ infinity, 0, 1, 2, infinity ] [ 2, 1, 1, 2 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ] gap> H:=CongruenceSubgroupGamma0(5); gap> GeneratorsOfGroup(H); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ] gap> I:=IntersectionOfCongruenceSubgroups(PrincipalCongruenceSubgroup(2),CongruenceSubgroupGamma0(3)); gap> FareySymbol(I); [ infinity, 0, 1/3, 1/2, 2/3, 1, 4/3, 3/2, 5/3, 2, infinity ] [ 1, 5, 4, 3, 2, 2, 3, 4, 5, 1 ] gap> GeneratorsOfGroup(I); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 11, -2 ], [ 6, -1 ] ], [ [ 19, -8 ], [ 12, -5 ] ], [ [ 17, -10 ], [ 12, -7 ] ], [ [ 7, -6 ], [ 6, -5 ] ] ] ]]>

Other properties derived from Farey symbols By Proposition 7.2 in [Kulkarni], for the Farey symbol with underlying generalized Farey sequence [infinity, x0, x1, ..., xn, infinity], the index in PSL_2(Z) is given by the formula d = 3*n + e3, where e3 is the number of odd intervals. IndexInPSL2ZByFareySymbol(fs); 6 gap> IndexInPSL2ZByFareySymbol(fs_oo); 2 gap> IndexInPSL2ZByFareySymbol(fs_free); 6 ]]>
congruence-1.2.3/doc/chapInd_mj.html0000664000371700037170000001470413503171577020565 0ustar gap-jenkinsgap-jenkins GAP (Congruence) - Index
Goto Chapter: Top 1 2 3 4 5 Bib Ind

Index

\in 2.4-2
CanEasilyCompareCongruenceSubgroups 2.4-3
Congruence package .-1
CongruenceSubgroupGamma0 2.1-2
CongruenceSubgroupGamma1 2.1-4
CongruenceSubgroupGammaUpper0 2.1-3
CongruenceSubgroupGammaUpper1 2.1-5
DefiningCongruenceSubgroups 2.3-3
DenominatorOfGFSElement 3.2-3
FareySymbol 4.1-1
FareySymbolByData 3.1-1
GeneralizedFareySequence 3.2-1
GeneratorsByFareySymbol 4.2-4
GeneratorsOfGroup 4.2-5
Index 2.4-5
IndexInPSL2ZByFareySymbol 4.3-1
IndexInSL2Z 2.3-2
InfoCongruence 5.1-1
Intersection 2.1-6
IntersectionOfCongruenceSubgroups 2.1-6
IsCongruenceSubgroup 1.1 2.
IsCongruenceSubgroupGamma0 2.2-2
IsCongruenceSubgroupGamma1 2.2-4
IsCongruenceSubgroupGammaUpper0 2.2-3
IsCongruenceSubgroupGammaUpper1 2.2-5
IsFareySymbol 3.
IsFareySymbolDefaultRep 3.
IsIntersectionOfCongruenceSubgroups 2.2-6
IsPrincipalCongruenceSubgroup 2.2-1
IsSubset 2.4-4
IsValidFareySymbol 3.1-2
LabelsOfFareySymbol 3.2-4
LevelOfCongruenceSubgroup 2.3-1
MatrixByEvenInterval 4.2-1
MatrixByFreePairOfIntervals 4.2-3
MatrixByOddInterval 4.2-2
NumeratorOfGFSElement 3.2-2
PrincipalCongruenceSubgroup 2.1-1
Random 2.4-1
    one and two argument versions 2.4-1

Goto Chapter: Top 1 2 3 4 5 Bib Ind

generated by GAPDoc2HTML

congruence-1.2.3/doc/chooser.html0000664000371700037170000000745613503171577020201 0ustar gap-jenkinsgap-jenkins 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

Apply settings to last page.

congruence-1.2.3/tst/congruence04.tst0000664000371700037170000000763413503171577020744 0ustar gap-jenkinsgap-jenkins# congruence, chapter 4 # # DO NOT EDIT THIS FILE - EDIT EXAMPLES IN THE SOURCE INSTEAD! # # This file has been autogenerated with GAP. It contains examples # extracted from the documentation. Each example is preceded by the # comment which points to the location of its source. # gap> START_TEST( "congruence04.tst"); # doc/gens.xml:30-47 gap> FareySymbol(PrincipalCongruenceSubgroup(8)); [ infinity, 0, 1/4, 1/3, 3/8, 2/5, 1/2, 3/5, 5/8, 2/3, 3/4, 1, 5/4, 4/3, 11/8, 7/5, 3/2, 8/5, 13/8, 5/3, 7/4, 2, 9/4, 7/3, 19/8, 12/5, 5/2, 13/5, 21/8, 8/3, 11/4, 3, 13/4, 10/3, 27/8, 17/5, 7/2, 18/5, 29/8, 11/3, 15/4, 4, 17/4, 13/3, 9/2, 14/3, 19/4, 5, 21/4, 16/3, 11/2, 17/3, 23/4, 6, 25/4, 19/3, 13/2, 20/3, 27/4, 7, 29/4, 22/3, 15/2, 23/3, 31/4, 8, infinity ] [ 1, 17, 10, 26, 32, 18, 19, 27, 30, 5, 2, 2, 13, 28, 26, 20, 21, 29, 27, 7, 3, 3, 16, 31, 28, 22, 23, 33, 29, 9, 4, 4, 5, 30, 31, 24, 25, 32, 33, 12, 6, 6, 7, 19, 18, 15, 8, 8, 9, 21, 20, 10, 11, 11, 12, 23, 22, 13, 14, 14, 15, 25, 24, 16, 17, 1 ] gap> FareySymbol(CongruenceSubgroupGamma0(20)); [ infinity, 0, 1/5, 1/4, 2/7, 3/10, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1, infinity ] [ 1, 3, 4, 6, 7, 7, 5, 2, 2, 3, 6, 4, 5, 1 ] # doc/gens.xml:128-140 gap> H:=CongruenceSubgroupGamma0(5); gap> fs:=FareySymbol(H); [ infinity, 0, 1/2, 1, infinity ] [ 1, "even", "even", 1 ] gap> gfs:=GeneralizedFareySequence(fs); [ infinity, 0, 1/2, 1, infinity ] gap> MatrixByEvenInterval(gfs,2); [ [ 2, -1 ], [ 5, -2 ] ] # doc/gens.xml:152-160 gap> fs_oo:=FareySymbolByData([infinity,0,infinity],["odd","odd"]);; gap> gfs_oo:=GeneralizedFareySequence(fs_oo); [ infinity, 0, infinity ] gap> MatrixByOddInterval(gfs_oo,1); [ [ -1, -1 ], [ 1, 0 ] ] # doc/gens.xml:172-179 gap> fs_free:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]);; gap> gfs_free:=GeneralizedFareySequence(fs_free);; gap> MatrixByFreePairOfIntervals(gfs_free,2,3); [ [ 3, -2 ], [ 2, -1 ] ] # doc/gens.xml:191-203 gap> fs_eo:=FareySymbolByData([infinity,0,infinity],["even","odd"]);; gap> GeneratorsByFareySymbol(last); [ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ] gap> GeneratorsByFareySymbol(fs); [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ] gap> GeneratorsByFareySymbol(fs_oo); [ [ [ -1, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ] gap> GeneratorsByFareySymbol(fs_free); [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ] # doc/gens.xml:215-241 gap> G:=PrincipalCongruenceSubgroup(2); gap> FareySymbol(G); [ infinity, 0, 1, 2, infinity ] [ 2, 1, 1, 2 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ] gap> H:=CongruenceSubgroupGamma0(5); gap> GeneratorsOfGroup(H); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ] gap> I:=IntersectionOfCongruenceSubgroups(PrincipalCongruenceSubgroup(2),CongruenceSubgroupGamma0(3)); gap> FareySymbol(I); [ infinity, 0, 1/3, 1/2, 2/3, 1, 4/3, 3/2, 5/3, 2, infinity ] [ 1, 5, 4, 3, 2, 2, 3, 4, 5, 1 ] gap> GeneratorsOfGroup(I); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 11, -2 ], [ 6, -1 ] ], [ [ 19, -8 ], [ 12, -5 ] ], [ [ 17, -10 ], [ 12, -7 ] ], [ [ 7, -6 ], [ 6, -5 ] ] ] # doc/gens.xml:262-271 gap> IndexInPSL2ZByFareySymbol(fs); 6 gap> IndexInPSL2ZByFareySymbol(fs_oo); 2 gap> IndexInPSL2ZByFareySymbol(fs_free); 6 gap> STOP_TEST("congruence04.tst", 1 ); congruence-1.2.3/tst/congruence03.tst0000664000371700037170000000175013503171577020734 0ustar gap-jenkinsgap-jenkins# congruence, chapter 3 # # DO NOT EDIT THIS FILE - EDIT EXAMPLES IN THE SOURCE INSTEAD! # # This file has been autogenerated with GAP. It contains examples # extracted from the documentation. Each example is preceded by the # comment which points to the location of its source. # gap> START_TEST( "congruence03.tst"); # doc/farey.xml:59-65 gap> fs:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]); [ infinity, 0, 1, 2, infinity ] [ 1, 2, 2, 1 ] # doc/farey.xml:76-81 gap> IsValidFareySymbol(fs); true # doc/farey.xml:99-104 gap> GeneralizedFareySequence(fs); [ infinity, 0, 1, 2, infinity ] # doc/farey.xml:121-126 gap> List([1..5], i -> NumeratorOfGFSElement(GeneralizedFareySequence(fs),i)); [ -1, 0, 1, 2, 1 ] # doc/farey.xml:142-147 gap> List([1..5], i -> DenominatorOfGFSElement(GeneralizedFareySequence(fs),i)); [ 0, 1, 1, 1, 0 ] # doc/farey.xml:159-164 gap> LabelsOfFareySymbol(fs); [ 1, 2, 2, 1 ] gap> STOP_TEST("congruence03.tst", 1 ); congruence-1.2.3/tst/congruence02.tst0000664000371700037170000000721513503171577020735 0ustar gap-jenkinsgap-jenkins# congruence, chapter 2 # # DO NOT EDIT THIS FILE - EDIT EXAMPLES IN THE SOURCE INSTEAD! # # This file has been autogenerated with GAP. It contains examples # extracted from the documentation. Each example is preceded by the # comment which points to the location of its source. # gap> START_TEST( "congruence02.tst"); # doc/cong.xml:65-88 gap> G_8:=PrincipalCongruenceSubgroup(8); gap> IsGroup(G_8); true gap> IsMatrixGroup(G_8); true gap> DimensionOfMatrixGroup(G_8); 2 gap> MultiplicativeNeutralElement(G_8); [ [ 1, 0 ], [ 0, 1 ] ] gap> One(G); [ [ 1, 0 ], [ 0, 1 ] ] gap> [[1,2],[3,4]] in G_8; false gap> [[1,8],[8,65]] in G_8; true gap> SL_2:=SL(2,Integers); SL(2,Integers) gap> IsSubgroup(SL_2,G_8); true # doc/cong.xml:122-127 gap> G0_4:=CongruenceSubgroupGamma0(4); # doc/cong.xml:161-166 gap> GU0_2:=CongruenceSubgroupGammaUpper0(2); # doc/cong.xml:200-205 gap> G1_6:=CongruenceSubgroupGamma1(6); # doc/cong.xml:239-244 gap> GU1_4:=CongruenceSubgroupGammaUpper1(4); # doc/cong.xml:273-280 gap> I:=IntersectionOfCongruenceSubgroups(G0_4,GU1_4); gap> J:=IntersectionOfCongruenceSubgroups(G0_4,G1_6); # doc/cong.xml:307-316 gap> IsPrincipalCongruenceSubgroup(G_8); true gap> IsPrincipalCongruenceSubgroup(G0_4); false gap> IsPrincipalCongruenceSubgroup(I); true # doc/cong.xml:380-387 gap> IsIntersectionOfCongruenceSubgroups(I); false gap> IsIntersectionOfCongruenceSubgroups(J); true # doc/cong.xml:407-418 gap> LevelOfCongruenceSubgroup(G_8); 8 gap> LevelOfCongruenceSubgroup(G1_6); 6 gap> LevelOfCongruenceSubgroup(I); 4 gap> LevelOfCongruenceSubgroup(J); 12 # doc/cong.xml:429-440 gap> IndexInSL2Z(G_8); 384 gap> G_2:=PrincipalCongruenceSubgroup(2); gap> IndexInSL2Z(G_2); 12 gap> IndexInSL2Z(GU1_4); 12 # doc/cong.xml:456-470 gap> DefiningCongruenceSubgroups(J); [ , ] gap> P:=PrincipalCongruenceSubgroup(6); gap> Q:=PrincipalCongruenceSubgroup(10); gap> G:=IntersectionOfCongruenceSubgroups(Q,P); gap> DefiningCongruenceSubgroups(G); [ ] # doc/cong.xml:497-504 gap> Random(G_2) in G_2; true gap> Random(G_8,2) in G_8; true # doc/cong.xml:516-523 gap> \in([ [ 21, 10 ], [ 2, 1 ] ],G_2); true gap> \in([ [ 21, 10 ], [ 2, 1 ] ],G_8); false # doc/cong.xml:545-550 gap> CanEasilyCompareCongruenceSubgroups(G_8,I); false # doc/cong.xml:564-582 gap> IsSubset(G_2,G_8); true gap> IsSubset(G_8,G_2); false gap> f:=[PrincipalCongruenceSubgroup,CongruenceSubgroupGamma1,CongruenceSubgroupGammaUpper1,CongruenceSubgroupGamma0,CongruenceSubgroupGammaUpper0];; gap> g1:=List(f, t -> t(2));; gap> g2:=List(f, t -> t(4));; gap> for g in g2 do > Print( List( g1, x -> IsSubgroup(x,g) ), "\n"); > od; [ true, true, true, true, true ] [ false, true, false, true, false ] [ false, false, true, false, true ] [ false, false, false, true, false ] [ false, false, false, false, true ] # doc/cong.xml:595-600 gap> Index(G_2,G_8); 32 gap> STOP_TEST("congruence02.tst", 1 ); congruence-1.2.3/tst/testall.g0000664000371700037170000000037313503171577017525 0ustar gap-jenkinsgap-jenkinsLoadPackage( "congruence" ); TestDirectory(DirectoriesPackageLibrary( "congruence", "tst" ), rec(exitGAP := true, testOptions := rec(compareFunction := "uptowhitespace") ) ); FORCE_QUIT_GAP(1); # if we ever get here, there was an error congruence-1.2.3/tst/cong.tst0000664000371700037170000005324613503171577017376 0ustar gap-jenkinsgap-jenkinsgap> G:=PrincipalCongruenceSubgroup(8); gap> IsGroup(G); true gap> IsMatrixGroup(G); true gap> IsPrincipalCongruenceSubgroup(G); true gap> IsFinitelyGeneratedGroup(G); true gap> LevelOfCongruenceSubgroup(G); 8 gap> DimensionOfMatrixGroup(G); 2 gap> MultiplicativeNeutralElement(G); [ [ 1, 0 ], [ 0, 1 ] ] gap> One(G); [ [ 1, 0 ], [ 0, 1 ] ] gap> [[1,2],[3,4]] in G; false gap> [[1,8],[8,65]] in G; true gap> G:=PrincipalCongruenceSubgroup(3); gap> ForAll( List([1..100], k -> Random(G)), m -> m in G); true gap> ForAll( List([1..100], k -> Random(G,10*k)), m -> m in G); true gap> G:=CongruenceSubgroupGamma0(3); gap> ForAll( List([1..100], k -> Random(G)), m -> m in G); true gap> ForAll( List([1..100], k -> Random(G,10*k)), m -> m in G); true gap> G:=CongruenceSubgroupGammaUpper0(3); gap> ForAll( List([1..100], k -> Random(G)), m -> m in G); true gap> ForAll( List([1..100], k -> Random(G,10*k)), m -> m in G); true gap> G:=CongruenceSubgroupGamma1(3); gap> ForAll( List([1..100], k -> Random(G)), m -> m in G); true gap> ForAll( List([1..100], k -> Random(G,10*k)), m -> m in G); true gap> G:=CongruenceSubgroupGammaUpper1(3); gap> ForAll( List([1..100], k -> Random(G)), m -> m in G); true gap> ForAll( List([1..100], k -> Random(G,10*k)), m -> m in G); true gap> G2:=PrincipalCongruenceSubgroup(2); gap> G3:=PrincipalCongruenceSubgroup(3); gap> G6:=PrincipalCongruenceSubgroup(6); gap> G:=SL(2,Integers); SL(2,Integers) gap> IsSubgroup(G,G2); true gap> IsSubgroup(G3,G2); false gap> IsSubgroup(G2,G6); true gap> Index(G,G3); 24 gap> IndexInSL2Z(G6); 144 gap> Index(G3,G6); 6 gap> f:=[PrincipalCongruenceSubgroup, > CongruenceSubgroupGamma1, > CongruenceSubgroupGammaUpper1, > CongruenceSubgroupGamma0, > CongruenceSubgroupGammaUpper0];; gap> g1:=List(f, t -> t(2));; gap> g2:=List(f, t -> t(4));; gap> for g in g2 do > Print( List( g1, x -> IsSubgroup(x,g) ), "\n"); > od; [ true, true, true, true, true ] [ false, true, false, true, false ] [ false, false, true, false, true ] [ false, false, false, true, false ] [ false, false, false, false, true ] gap> Intersection(G2,G3); gap> G6=Intersection(G2,G3); true gap> g1:=List(f, t -> t(2));; gap> g2:=List(f, t -> t(2));; gap> for g in g2 do > Print( List( g1, x -> Intersection(x,g) ), "\n"); > od; [ PrincipalCongruenceSubgroup(2), PrincipalCongruenceSubgroup(2), PrincipalCongruenceSubgroup(2), PrincipalCongruenceSubgroup(2), PrincipalCongruenceSubgroup(2) ] [ PrincipalCongruenceSubgroup(2), CongruenceSubgroupGamma1(2), PrincipalCongruenceSubgroup(2), CongruenceSubgroupGamma1(2), PrincipalCongruenceSubgroup(2) ] [ PrincipalCongruenceSubgroup(2), PrincipalCongruenceSubgroup(2), CongruenceSubgroupGammaUpper1(2), PrincipalCongruenceSubgroup(2), CongruenceSubgroupGammaUpper1(2) ] [ PrincipalCongruenceSubgroup(2), CongruenceSubgroupGamma1(2), PrincipalCongruenceSubgroup(2), CongruenceSubgroupGamma0(2), IntersectionOfCongruenceSubgroups( CongruenceSubgroupGamma0(2), CongruenceSubgroupGammaUpper0(2) ) ] [ PrincipalCongruenceSubgroup(2), PrincipalCongruenceSubgroup(2), CongruenceSubgroupGammaUpper1(2), IntersectionOfCongruenceSubgroups( CongruenceSubgroupGamma0(2), CongruenceSubgroupGammaUpper0(2) ), CongruenceSubgroupGammaUpper0(2) ] gap> G:=Intersection(CongruenceSubgroupGamma0(4),CongruenceSubgroupGamma1(3)); gap> DefiningCongruenceSubgroups(G); [ , ] gap> H:=Intersection(G,CongruenceSubgroupGamma1(4)); gap> DefiningCongruenceSubgroups(H); [ , ] gap> K:=Intersection(H,CongruenceSubgroupGamma0(3)); gap> List([1..6], n -> IndexInSL2Z(PrincipalCongruenceSubgroup(n))); [ 1, 12, 24, 48, 120, 144 ] gap> fs:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]); [ infinity, 0, 1, 2, infinity ] [ 1, 2, 2, 1 ] gap> GeneralizedFareySequence(fs); [ infinity, 0, 1, 2, infinity ] gap> List([1..5], i -> NumeratorOfGFSElement(GeneralizedFareySequence(fs),i)); [ -1, 0, 1, 2, 1 ] gap> List([1..5], i -> DenominatorOfGFSElement(GeneralizedFareySequence(fs),i)); [ 0, 1, 1, 1, 0 ] gap> LabelsOfFareySymbol(fs); [ 1, 2, 2, 1 ] gap> IsValidFareySymbol(fs); true gap> fs:=FareySymbolByData([infinity,0,1,infinity],[1,"even",1]); [ infinity, 0, 1, infinity ] [ 1, "even", 1 ] gap> Print(fs); Print("\n"); FareySymbolByData( [ infinity, 0, 1, infinity ], [ 1, "even", 1 ] ] gap> SetInfoLevel(InfoCongruence,1); gap> fs1_1:=FareySymbolByData([infinity,0,infinity],["even","odd"]);; gap> GeneratorsByFareySymbol(last); [ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ] gap> fs2_1:=FareySymbolByData([infinity,0,infinity],["odd","odd"]);; gap> GeneratorsByFareySymbol(last); [ [ [ -1, -1 ], [ 1, 0 ] ], [ [ 0, -1 ], [ 1, -1 ] ] ] gap> fs2_2:=FareySymbolByData([infinity,0,1,2,infinity],[1,2,2,1]);; gap> GeneratorsByFareySymbol(last); [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ] gap> fs2_3:=FareySymbolByData([infinity,0,1,infinity],[1,"even",1]);; gap> GeneratorsByFareySymbol(last); [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 1, -1 ], [ 2, -1 ] ] ] gap> fs3_1:=FareySymbolByData([infinity,0,1,infinity],["even","even","even"]);; gap> GeneratorsByFareySymbol(last); [ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 1, -1 ], [ 2, -1 ] ], [ [ 1, -2 ], [ 1, -1 ] ] ] gap> fs3_2:=FareySymbolByData([infinity,0,1,2,infinity],["even",1,"even",1]);; gap> GeneratorsByFareySymbol(last); [ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 3, -1 ], [ 1, 0 ] ], [ [ 3, -5 ], [ 2, -3 ] ] ] gap> fs3_3:=FareySymbolByData([infinity,0,1,2,5/2,3,infinity],[1,2,3,3,2,1]);; gap> GeneratorsByFareySymbol(last); [ [ [ 1, 3 ], [ 0, 1 ] ], [ [ 8, -3 ], [ 3, -1 ] ], [ [ 7, -12 ], [ 3, -5 ] ] ] gap> fs3_4:=FareySymbolByData([infinity,0,1,infinity],[1,"odd",1]);; gap> GeneratorsByFareySymbol(last); [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 1, -1 ], [ 3, -2 ] ] ] gap> fs4_1:=FareySymbolByData([infinity,0,1/2,1,3/2,2,infinity],[1,2,3,3,2,1]);; gap> GeneratorsByFareySymbol(last); [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 7, -2 ], [ 4, -1 ] ], [ [ 5, -4 ], [ 4, -3 ] ] ] gap> fs4_2:=FareySymbolByData([infinity,0,1/2,1,3/2,2,5/2,3,7/2,4,infinity],[1,4,5,5,3,3,2,2,4,1]);; gap> GeneratorsByFareySymbol(last); [ [ [ 1, 4 ], [ 0, 1 ] ], [ [ 15, -4 ], [ 4, -1 ] ], [ [ 5, -4 ], [ 4, -3 ] ], [ [ 9, -16 ], [ 4, -7 ] ], [ [ 13, -36 ], [ 4, -11 ] ] ] gap> fs4_4:=FareySymbolByData([infinity,0,1/2,1,infinity],[1,2,2,1]);; gap> GeneratorsByFareySymbol(last); [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 3, -1 ], [ 4, -1 ] ] ] gap> fs4_5:=FareySymbolByData([infinity,0,1,2,infinity],[1,"even","even",1]);; gap> GeneratorsByFareySymbol(last); [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 1, -1 ], [ 2, -1 ] ], [ [ 3, -5 ], [ 2, -3 ] ] ] gap> fs4_6:=FareySymbolByData([infinity,0,1,2,3,4,infinity],[1,"even",2,"even",2,1]);; gap> GeneratorsByFareySymbol(last); [ [ [ 1, 4 ], [ 0, 1 ] ], [ [ 1, -1 ], [ 2, -1 ] ], [ [ 7, -11 ], [ 2, -3 ] ], [ [ 5, -13 ], [ 2, -5 ] ] ] gap> fs4_7:=FareySymbolByData([infinity,0,1,infinity],["odd","even","even"]);; gap> GeneratorsByFareySymbol(last); [ [ [ -1, -1 ], [ 1, 0 ] ], [ [ 1, -1 ], [ 2, -1 ] ], [ [ 1, -2 ], [ 1, -1 ] ] ] gap> fs5_1:=FareySymbolByData([infinity,0,1,2,3,infinity],[1,"even","even",1,"odd"]);; gap> GeneratorsByFareySymbol(last); [ [ [ 3, 2 ], [ 1, 1 ] ], [ [ 1, -1 ], [ 2, -1 ] ], [ [ 3, -5 ], [ 2, -3 ] ], [ [ 3, -13 ], [ 1, -4 ] ] ] gap> fs5_2:=FareySymbolByData([infinity,0,1/2,1,4/3,3/2,2,3,infinity],[1,2,3,3,"odd",2,1,"odd"]);; gap> GeneratorsByFareySymbol(last); [ [ [ 3, 2 ], [ 1, 1 ] ], [ [ 7, -2 ], [ 4, -1 ] ], [ [ 6, -5 ], [ 5, -4 ] ], [ [ 26, -37 ], [ 19, -27 ] ], [ [ 3, -13 ], [ 1, -4 ] ] ] gap> fs5_3:=FareySymbolByData([infinity,0,1/2,1,4/3,7/5,3/2,2,7/3,12/5,5/2,3,10/3,17/5,7/2,4, > 13/3,22/5,9/2,23/5,14/3,5,infinity], > [1,2,6,6,10,11,5,5,11,9,4,4,9,8,3,3,8,7,7,10,2,1]); [ infinity, 0, 1/2, 1, 4/3, 7/5, 3/2, 2, 7/3, 12/5, 5/2, 3, 10/3, 17/5, 7/2, 4, 13/3, 22/5, 9/2, 23/5, 14/3, 5, infinity ] [ 1, 2, 6, 6, 10, 11, 5, 5, 11, 9, 4, 4, 9, 8, 3, 3, 8, 7, 7, 10, 2, 1 ] gap> GeneratorsByFareySymbol(fs5_3); [ [ [ 1, 5 ], [ 0, 1 ] ], [ [ 24, -5 ], [ 5, -1 ] ], [ [ 6, -5 ], [ 5, -4 ] ], [ [ 139, -190 ], [ 30, -41 ] ], [ [ 59, -85 ], [ 25, -36 ] ], [ [ 11, -20 ], [ 5, -9 ] ], [ [ 84, -205 ], [ 25, -61 ] ], [ [ 16, -45 ], [ 5, -14 ] ], [ [ 109, -375 ], [ 25, -86 ] ], [ [ 21, -80 ], [ 5, -19 ] ], [ [ 91, -405 ], [ 20, -89 ] ] ] gap> fs11_1:=FareySymbolByData([infinity,-1,0,1,2,infinity],["even","odd","odd","even","even"]); [ infinity, -1, 0, 1, 2, infinity ] [ "even", "odd", "odd", "even", "even" ] gap> GeneratorsByFareySymbol(last); [ [ [ -1, -2 ], [ 1, 1 ] ], [ [ -2, -1 ], [ 3, 1 ] ], [ [ 1, -1 ], [ 3, -2 ] ], [ [ 3, -5 ], [ 2, -3 ] ], [ [ 2, -5 ], [ 1, -2 ] ] ] gap> fs11_2:=FareySymbolByData([infinity,0,1,2,3,infinity],["even","even","odd","odd","even"]); [ infinity, 0, 1, 2, 3, infinity ] [ "even", "even", "odd", "odd", "even" ] gap> GeneratorsByFareySymbol(last); [ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 1, -1 ], [ 2, -1 ] ], [ [ 4, -7 ], [ 3, -5 ] ], [ [ 7, -19 ], [ 3, -8 ] ], [ [ 3, -10 ], [ 1, -3 ] ] ] gap> fs12_1:=FareySymbolByData([infinity,0,1/6,1/5,1/4,1/3,1/2,3/5,2/3,1,4/3,7/5,3/2,5/3,7/4,9/5,11/6,2,infinity], > [ 1,8, 9, 7, 4, 4, 7, 6, 2,2, 6, 5, 3, 3, 5, 9, 8,1]); [ infinity, 0, 1/6, 1/5, 1/4, 1/3, 1/2, 3/5, 2/3, 1, 4/3, 7/5, 3/2, 5/3, 7/4, 9/5, 11/6, 2, infinity ] [ 1, 8, 9, 7, 4, 4, 7, 6, 2, 2, 6, 5, 3, 3, 5, 9, 8, 1 ] gap> GeneratorsByFareySymbol(last); [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 23, -2 ], [ 12, -1 ] ], [ [ 109, -20 ], [ 60, -11 ] ], [ [ 17, -4 ], [ 30, -7 ] ], [ [ 7, -2 ], [ 18, -5 ] ], [ [ 41, -26 ], [ 30, -19 ] ], [ [ 7, -6 ], [ 6, -5 ] ], [ [ 53, -76 ], [ 30, -43 ] ], [ [ 31, -50 ], [ 18, -29 ] ] ] gap> fs12_2:=FareySymbolByData([infinity,0,1,2,3,4,infinity],[1,"odd","odd","odd","odd",1]); [ infinity, 0, 1, 2, 3, 4, infinity ] [ 1, "odd", "odd", "odd", "odd", 1 ] gap> GeneratorsByFareySymbol(last); [ [ [ 1, 4 ], [ 0, 1 ] ], [ [ 1, -1 ], [ 3, -2 ] ], [ [ 4, -7 ], [ 3, -5 ] ], [ [ 7, -19 ], [ 3, -8 ] ], [ [ 10, -37 ], [ 3, -11 ] ] ] gap> fs12_3:=FareySymbolByData([infinity,0,1,5/4,4/3,3/2,5/3,2,7/3,5/2,8/3,11/4,14/5,3,infinity], > [1,"even",5,4,3,3,"even","even",2,2,4,5,"even",1]); [ infinity, 0, 1, 5/4, 4/3, 3/2, 5/3, 2, 7/3, 5/2, 8/3, 11/4, 14/5, 3, infinity ] [ 1, "even", 5, 4, 3, 3, "even", "even", 2, 2, 4, 5, "even", 1 ] gap> GeneratorsByFareySymbol(last); [ [ [ 1, 3 ], [ 0, 1 ] ], [ [ 1, -1 ], [ 2, -1 ] ], [ [ 67, -81 ], [ 24, -29 ] ], [ [ 65, -84 ], [ 24, -31 ] ], [ [ 19, -27 ], [ 12, -17 ] ], [ [ 17, -29 ], [ 10, -17 ] ], [ [ 23, -53 ], [ 10, -23 ] ], [ [ 31, -75 ], [ 12, -29 ] ], [ [ 73, -205 ], [ 26, -73 ] ] ] gap> fs12_4:=FareySymbolByData([infinity,0,1/3,1/2,2/3,1,2,3,10/3,7/2,11/3,4,5,6,infinity], > [1,"even",3,2,"even","even","even","even",2,3,"even","even","even",1]); [ infinity, 0, 1/3, 1/2, 2/3, 1, 2, 3, 10/3, 7/2, 11/3, 4, 5, 6, infinity ] [ 1, "even", 3, 2, "even", "even", "even", "even", 2, 3, "even", "even", "even", 1 ] gap> GeneratorsByFareySymbol(last); [ [ [ 1, 6 ], [ 0, 1 ] ], [ [ 3, -1 ], [ 10, -3 ] ], [ [ 43, -18 ], [ 12, -5 ] ], [ [ 41, -24 ], [ 12, -7 ] ], [ [ 7, -5 ], [ 10, -7 ] ], [ [ 3, -5 ], [ 2, -3 ] ], [ [ 5, -13 ], [ 2, -5 ] ], [ [ 33, -109 ], [ 10, -33 ] ], [ [ 37, -137 ], [ 10, -37 ] ], [ [ 9, -41 ], [ 2, -9 ] ], [ [ 11, -61 ], [ 2, -11 ] ] ] gap> fs12_5:=FareySymbolByData([infinity,0,1/3,2/5,1/2,1,4/3,3/2,2,3,infinity], > ["even",1,"even","even","even","even",1,"even","even","even"]); [ infinity, 0, 1/3, 2/5, 1/2, 1, 4/3, 3/2, 2, 3, infinity ] [ "even", 1, "even", "even", "even", "even", 1, "even", "even", "even" ] gap> GeneratorsByFareySymbol(last); [ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 13, -3 ], [ 9, -2 ] ], [ [ 13, -5 ], [ 34, -13 ] ], [ [ 12, -5 ], [ 29, -12 ] ], [ [ 3, -2 ], [ 5, -3 ] ], [ [ 13, -17 ], [ 10, -13 ] ], [ [ 8, -13 ], [ 5, -8 ] ], [ [ 5, -13 ], [ 2, -5 ] ], [ [ 3, -10 ], [ 1, -3 ] ] ] gap> fs12_6:=FareySymbolByData([infinity,0,1,4/3,3/2,5/3,2,3,infinity], > [1,"even","even",2,2,"even","even",1]); [ infinity, 0, 1, 4/3, 3/2, 5/3, 2, 3, infinity ] [ 1, "even", "even", 2, 2, "even", "even", 1 ] gap> GeneratorsByFareySymbol(last); [ [ [ 1, 3 ], [ 0, 1 ] ], [ [ 1, -1 ], [ 2, -1 ] ], [ [ 13, -17 ], [ 10, -13 ] ], [ [ 19, -27 ], [ 12, -17 ] ], [ [ 17, -29 ], [ 10, -17 ] ], [ [ 5, -13 ], [ 2, -5 ] ] ] gap> fs12_7:=FareySymbolByData([infinity,0,1,2,3,4,5,6,infinity], > [1,"even","even","even","even","even","even",1]); [ infinity, 0, 1, 2, 3, 4, 5, 6, infinity ] [ 1, "even", "even", "even", "even", "even", "even", 1 ] gap> GeneratorsByFareySymbol(last); [ [ [ 1, 6 ], [ 0, 1 ] ], [ [ 1, -1 ], [ 2, -1 ] ], [ [ 3, -5 ], [ 2, -3 ] ], [ [ 5, -13 ], [ 2, -5 ] ], [ [ 7, -25 ], [ 2, -7 ] ], [ [ 9, -41 ], [ 2, -9 ] ], [ [ 11, -61 ], [ 2, -11 ] ] ] gap> fs12_8:=FareySymbolByData([infinity,0,1,3/2,2,3,infinity], > ["even","even","even","even","even","even"]); [ infinity, 0, 1, 3/2, 2, 3, infinity ] [ "even", "even", "even", "even", "even", "even" ] gap> GeneratorsByFareySymbol(last); [ [ [ 0, -1 ], [ 1, 0 ] ], [ [ 1, -1 ], [ 2, -1 ] ], [ [ 7, -10 ], [ 5, -7 ] ], [ [ 8, -13 ], [ 5, -8 ] ], [ [ 5, -13 ], [ 2, -5 ] ], [ [ 3, -10 ], [ 1, -3 ] ] ] gap> fs12_9:=FareySymbolByData([infinity,0,1/4,1/3,1/2,2/3,3/4,4/5,5/6,1,infinity], > [1,4,3,2,2,3,4,5,5,1]); [ infinity, 0, 1/4, 1/3, 1/2, 2/3, 3/4, 4/5, 5/6, 1, infinity ] [ 1, 4, 3, 2, 2, 3, 4, 5, 5, 1 ] gap> GeneratorsByFareySymbol(last); [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 19, -4 ], [ 24, -5 ] ], [ [ 17, -5 ], [ 24, -7 ] ], [ [ 7, -3 ], [ 12, -5 ] ], [ [ 31, -25 ], [ 36, -29 ] ] ] gap> fs12_10:=FareySymbolByData([infinity,0,1/6,1/5,1/4,2/7,1/3,2/5,1/2,4/7,7/12,3/5,2/3,5/7,3/4,4/5,5/6,1,infinity], > [1,2,3,7,7,8,8,6,6,9,9,4,4,5,5,3,2,1]); [ infinity, 0, 1/6, 1/5, 1/4, 2/7, 1/3, 2/5, 1/2, 4/7, 7/12, 3/5, 2/3, 5/7, 3/4, 4/5, 5/6, 1, infinity ] [ 1, 2, 3, 7, 7, 8, 8, 6, 6, 9, 9, 4, 4, 5, 5, 3, 2, 1 ] gap> GeneratorsByFareySymbol(last); [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 11, -1 ], [ 12, -1 ] ], [ [ 49, -9 ], [ 60, -11 ] ], [ [ 13, -3 ], [ 48, -11 ] ], [ [ 13, -4 ], [ 36, -11 ] ], [ [ 13, -6 ], [ 24, -11 ] ], [ [ 85, -49 ], [ 144, -83 ] ], [ [ 25, -16 ], [ 36, -23 ] ], [ [ 37, -27 ], [ 48, -35 ] ] ] gap> G:=CongruenceSubgroupGamma0(20); gap> fs:=FareySymbol(G); [ infinity, 0, 1/5, 1/4, 2/7, 3/10, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1, infinity ] [ 1, 3, 4, 6, 7, 7, 5, 2, 2, 3, 6, 4, 5, 1 ] gap> G:=PrincipalCongruenceSubgroup(2); gap> FareySymbol(G); [ infinity, 0, 1, 2, infinity ] [ 2, 1, 1, 2 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 3, -2 ], [ 2, -1 ] ] ] gap> G:=CongruenceSubgroupGamma0(2); gap> FareySymbol(G); [ infinity, 0, 1, infinity ] [ 1, "even", 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 1, -1 ], [ 2, -1 ] ] ] gap> G:=CongruenceSubgroupGamma0(3); gap> FareySymbol(G); [ infinity, 0, 1, infinity ] [ 1, "odd", 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 1, -1 ], [ 3, -2 ] ] ] gap> G:=PrincipalCongruenceSubgroup(4); gap> FareySymbol(G); [ infinity, 0, 1/2, 1, 3/2, 2, 5/2, 3, 7/2, 4, infinity ] [ 1, 5, 2, 2, 3, 3, 4, 4, 5, 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 4 ], [ 0, 1 ] ], [ [ -15, 4 ], [ -4, 1 ] ], [ [ 5, -4 ], [ 4, -3 ] ], [ [ 9, -16 ], [ 4, -7 ] ], [ [ 13, -36 ], [ 4, -11 ] ] ] gap> G:=CongruenceSubgroupGamma0(4); gap> FareySymbol(G); [ infinity, 0, 1/2, 1, infinity ] [ 1, 2, 2, 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 3, -1 ], [ 4, -1 ] ] ] gap> G:=CongruenceSubgroupGamma0(5); gap> FareySymbol(G); [ infinity, 0, 1/2, 1, infinity ] [ 1, "even", "even", 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 5, -2 ] ], [ [ 3, -2 ], [ 5, -3 ] ] ] gap> G:=CongruenceSubgroupGamma0(6); gap> FareySymbol(G); [ infinity, 0, 1/3, 1/2, 2/3, 1, infinity ] [ 1, 3, 2, 2, 3, 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 5, -1 ], [ 6, -1 ] ], [ [ 7, -3 ], [ 12, -5 ] ] ] gap> G:=CongruenceSubgroupGamma0(7); gap> FareySymbol(G); [ infinity, 0, 1/2, 1, infinity ] [ 1, "odd", "odd", 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 2, -1 ], [ 7, -3 ] ], [ [ 4, -3 ], [ 7, -5 ] ] ] gap> G:=CongruenceSubgroupGamma0(9); gap> FareySymbol(G); [ infinity, 0, 1/3, 1/2, 2/3, 1, infinity ] [ 1, 2, 2, 3, 3, 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 4, -1 ], [ 9, -2 ] ], [ [ 7, -4 ], [ 9, -5 ] ] ] gap> G:=CongruenceSubgroupGamma0(10); gap> FareySymbol(G); [ infinity, 0, 1/3, 2/5, 1/2, 3/5, 2/3, 1, infinity ] [ 1, "even", 3, 2, 2, 3, "even", 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 3, -1 ], [ 10, -3 ] ], [ [ 19, -7 ], [ 30, -11 ] ], [ [ 11, -5 ], [ 20, -9 ] ], [ [ 7, -5 ], [ 10, -7 ] ] ] gap> G:=CongruenceSubgroupGamma0(13); gap> FareySymbol(G); [ infinity, 0, 1/3, 1/2, 2/3, 1, infinity ] [ 1, "odd", "even", "even", "odd", 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 3, -1 ], [ 13, -4 ] ], [ [ 5, -2 ], [ 13, -5 ] ], [ [ 8, -5 ], [ 13, -8 ] ], [ [ 9, -7 ], [ 13, -10 ] ] ] gap> G:=CongruenceSubgroupGamma0(18); gap> FareySymbol(G); [ infinity, 0, 1/6, 1/5, 2/9, 1/4, 1/3, 1/2, 2/3, 3/4, 7/9, 4/5, 5/6, 1, infinity ] [ 1, 4, 4, 7, 6, 2, 2, 3, 3, 6, 7, 5, 5, 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 7, -1 ], [ 36, -5 ] ], [ [ 71, -15 ], [ 90, -19 ] ], [ [ 55, -13 ], [ 72, -17 ] ], [ [ 7, -2 ], [ 18, -5 ] ], [ [ 13, -8 ], [ 18, -11 ] ], [ [ 31, -25 ], [ 36, -29 ] ] ] gap> G:=CongruenceSubgroupGamma0(25); gap> FareySymbol(G); [ infinity, 0, 1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1, infinity ] [ 1, 2, 2, "even", 3, 3, 4, 4, "even", 5, 5, 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 1 ], [ 0, 1 ] ], [ [ 6, -1 ], [ 25, -4 ] ], [ [ 7, -2 ], [ 25, -7 ] ], [ [ 11, -4 ], [ 25, -9 ] ], [ [ 16, -9 ], [ 25, -14 ] ], [ [ 18, -13 ], [ 25, -18 ] ], [ [ 21, -16 ], [ 25, -19 ] ] ] gap> G:=IntersectionOfCongruenceSubgroups(PrincipalCongruenceSubgroup(2),CongruenceSubgroupGamma0(4)); gap> FareySymbol(G); [ infinity, 0, 1/2, 1, 3/2, 2, infinity ] [ 1, 3, 2, 2, 3, 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 7, -2 ], [ 4, -1 ] ], [ [ 5, -4 ], [ 4, -3 ] ] ] gap> G:=IntersectionOfCongruenceSubgroups(PrincipalCongruenceSubgroup(2),CongruenceSubgroupGamma0(3)); gap> FareySymbol(G); [ infinity, 0, 1/3, 1/2, 2/3, 1, 4/3, 3/2, 5/3, 2, infinity ] [ 1, 5, 4, 3, 2, 2, 3, 4, 5, 1 ] gap> GeneratorsOfGroup(G); #I Using the Congruence package for GeneratorsOfGroup ... [ [ [ 1, 2 ], [ 0, 1 ] ], [ [ 11, -2 ], [ 6, -1 ] ], [ [ 19, -8 ], [ 12, -5 ] ], [ [ 17, -10 ], [ 12, -7 ] ], [ [ 7, -6 ], [ 6, -5 ] ] ] gap> G16:=CongruenceSubgroupGamma0(16);; gap> FS16:=FareySymbol(G16);; gap> gens:=GeneratorsByFareySymbol(FS16);; gap> glue_list:=__congruence_gluing_matrices(FS16); [ 1, 2, -2, 3, -3, 4, -4, 5, -5, -1 ] gap> for i in [1..1000] do > g:=Random(G16); > w:=__congruence_FactorizeMat( G16, g ); > h:=__congruence_CheckFactorizeMat(gens,w); > if g<>h and g<>-h then > Print("Error:", g, " is not plus/minus ", h , "\n"); > fi; > od;congruence-1.2.3/doc/manual.six0000664000371700037170000002310413503171577017637 0ustar gap-jenkinsgap-jenkins#SIXFORMAT GapDocGAP HELPBOOKINFOSIXTMP := rec( encoding := "UTF-8", bookname := "Congruence", entries := [ [ "Title page", ".", [ 0, 0, 0 ], 1, 1, "title page", "X7D2C85EC87DD46E5" ], [ "Abstract", ".-1", [ 0, 0, 1 ], 59, 2, "abstract", "X7AA6C5737B711C89" ], [ "Copyright", ".-2", [ 0, 0, 2 ], 65, 2, "copyright", "X81488B807F2A1CF1" ] , [ "Acknowledgements", ".-3", [ 0, 0, 3 ], 87, 2, "acknowledgements", "X82A988D47DFAFCFA" ], [ "Table of Contents", ".-4", [ 0, 0, 4 ], 95, 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;-2YGeneral aims of \033[5XCongruence\033[105X\033[10\ 1X\027\033[1X\027 package\033[133X\033[101X", "1.1", [ 1, 1, 0 ], 4, 4, "general aims of congruence package", "X80AE633F82C4D9BF" ], [ "\033[1X\033[33X\033[0;-2YInstallation and system requirements\033[133X\\ 033[101X", "1.2", [ 1, 2, 0 ], 24, 4, "installation and system requirements", "X7DB566D5785B7DBC" ], [ "\033[1X\033[33X\033[0;-2YConstruction of congruence subgroups\033[133X\\ 033[101X", "2", [ 2, 0, 0 ], 1, 5, "construction of congruence subgroups", "X7B010EE67FACF45E" ], [ "\033[1X\033[33X\033[0;-2YConstruction of congruence subgroups\033[133X\\ 033[101X", "2.1", [ 2, 1, 0 ], 28, 5, "construction of congruence subgroups", "X7B010EE67FACF45E" ], [ "\033[1X\033[33X\033[0;-2YProperties of congruence subgroups\033[133X\033[1\ 01X", "2.2", [ 2, 2, 0 ], 181, 8, "properties of congruence subgroups", "X8267F261874959E5" ], [ "\033[1X\033[33X\033[0;-2YAttributes of congruence subgroups\033[133X\033[1\ 01X", "2.3", [ 2, 3, 0 ], 259, 9, "attributes of congruence subgroups", "X8664A60E875EA5DE" ], [ "\033[1X\033[33X\033[0;-2YOperations for congruence subgroups\033[133X\033[\ 101X", "2.4", [ 2, 4, 0 ], 329, 11, "operations for congruence subgroups", "X7B15B49583DC9EF5" ], [ "\033[1X\033[33X\033[0;-2YFarey symbols and their properties\033[133X\033[1\ 01X", "3", [ 3, 0, 0 ], 1, 13, "farey symbols and their properties", "X85CABB30818CD99C" ], [ "\033[1X\033[33X\033[0;-2YConstruction of Farey symbols\033[133X\033[101X" , "3.1", [ 3, 1, 0 ], 41, 13, "construction of farey symbols", "X7B7B81E584CCA30C" ], [ "\033[1X\033[33X\033[0;-2YProperties of Farey symbols\033[133X\033[101X", "3.2", [ 3, 2, 0 ], 75, 14, "properties of farey symbols", "X8016C45082AEC784" ], [ "\033[1X\033[33X\033[0;-2YFarey symbols for congruence subgroups\033[133X\\ 033[101X", "4", [ 4, 0, 0 ], 1, 16, "farey symbols for congruence subgroups", "X831C60277F7D80B2" ], [ "\033[1X\033[33X\033[0;-2YComputation of the Farey symbol for a finite inde\ x subgroup\033[133X\033[101X", "4.1", [ 4, 1, 0 ], 15, 16, "computation of the farey symbol for a finite index subgroup", "X7F43DB8B803F313F" ], [ "\033[1X\033[33X\033[0;-2YComputation of generators of a finite index subgr\ oup from its Farey symbol\033[133X\033[101X", "4.2", [ 4, 2, 0 ], 46, 17, "computation of generators of a finite index subgroup from its farey sym\ bol", "X80AE179D869BEE90" ], [ "\033[1X\033[33X\033[0;-2YOther properties derived from Farey symbols\033[1\ 33X\033[101X", "4.3", [ 4, 3, 0 ], 178, 19, "other properties derived from farey symbols", "X7C5AB1D786207745" ], [ "\033[1X\033[33X\033[0;-2YService functions of the \033[5XCongruence\033[10\ 5X\033[101X\027\033[1X\027 package\033[133X\033[101X", "5", [ 5, 0, 0 ], 1, 20, "service functions of the congruence package", "X82C56A367A418E7C" ] , [ "\033[1X\033[33X\033[0;-2YAdditional information displayed by \033[5XCongru\ ence\033[105X\033[101X\027\033[1X\027 algorithms\033[133X\033[101X", "5.1", [ 5, 1, 0 ], 4, 20, "additional information displayed by congruence algorithms", "X86D04EE08437C320" ], [ "Bibliography", "bib", [ "Bib", 0, 0 ], 1, 21, "bibliography", "X7A6F98FD85F02BFE" ], [ "References", "bib", [ "Bib", 0, 0 ], 1, 21, "references", "X7A6F98FD85F02BFE" ], [ "Index", "ind", [ "Ind", 0, 0 ], 1, 22, "index", "X83A0356F839C696F" ], [ "\033[5XCongruence\033[105X package", ".-1", [ 0, 0, 1 ], 59, 2, "congruence package", "X7AA6C5737B711C89" ], [ "\033[10XIsCongruenceSubgroup\033[110X", "1.1", [ 1, 1, 0 ], 4, 4, "iscongruencesubgroup", "X80AE633F82C4D9BF" ], [ "\033[10XIsCongruenceSubgroup\033[110X", "2.", [ 2, 0, 0 ], 1, 5, "iscongruencesubgroup", "X7B010EE67FACF45E" ], [ "\033[2XPrincipalCongruenceSubgroup\033[102X", "2.1-1", [ 2, 1, 1 ], 31, 5, "principalcongruencesubgroup", "X7A61F693873F7136" ], [ "\033[2XCongruenceSubgroupGamma0\033[102X", "2.1-2", [ 2, 1, 2 ], 70, 6, "congruencesubgroupgamma0", "X7B8DB77B81BE58D7" ], [ "\033[2XCongruenceSubgroupGammaUpper0\033[102X", "2.1-3", [ 2, 1, 3 ], 91, 6, "congruencesubgroupgammaupper0", "X7B4FBED17ECE2A7F" ], [ "\033[2XCongruenceSubgroupGamma1\033[102X", "2.1-4", [ 2, 1, 4 ], 112, 7, "congruencesubgroupgamma1", "X7CFDC47279AC0E85" ], [ "\033[2XCongruenceSubgroupGammaUpper1\033[102X", "2.1-5", [ 2, 1, 5 ], 133, 7, "congruencesubgroupgammaupper1", "X7C3FCDD878FE57ED" ], [ "\033[2XIntersectionOfCongruenceSubgroups\033[102X", "2.1-6", [ 2, 1, 6 ], 154, 8, "intersectionofcongruencesubgroups", "X7FE839377D7F45EB" ], [ "\033[2XIntersection\033[102X", "2.1-6", [ 2, 1, 6 ], 154, 8, "intersection", "X7FE839377D7F45EB" ], [ "\033[2XIsPrincipalCongruenceSubgroup\033[102X", "2.2-1", [ 2, 2, 1 ], 190, 8, "isprincipalcongruencesubgroup", "X828F7E08787650DC" ], [ "\033[2XIsCongruenceSubgroupGamma0\033[102X", "2.2-2", [ 2, 2, 2 ], 209, 8, "iscongruencesubgroupgamma0", "X85124A697E826AB4" ], [ "\033[2XIsCongruenceSubgroupGammaUpper0\033[102X", "2.2-3", [ 2, 2, 3 ], 217, 9, "iscongruencesubgroupgammaupper0", "X7A03633C83A286F5" ], [ "\033[2XIsCongruenceSubgroupGamma1\033[102X", "2.2-4", [ 2, 2, 4 ], 225, 9, "iscongruencesubgroupgamma1", "X8262396080F3B0DD" ], [ "\033[2XIsCongruenceSubgroupGammaUpper1\033[102X", "2.2-5", [ 2, 2, 5 ], 233, 9, "iscongruencesubgroupgammaupper1", "X7D731035834CF878" ], [ "\033[2XIsIntersectionOfCongruenceSubgroups\033[102X", "2.2-6", [ 2, 2, 6 ], 241, 9, "isintersectionofcongruencesubgroups", "X83B4E4FA7F4DFB97" ], [ "\033[2XLevelOfCongruenceSubgroup\033[102X", "2.3-1", [ 2, 3, 1 ], 264, 10, "levelofcongruencesubgroup", "X7D5696F584970D21" ], [ "\033[2XIndexInSL2Z\033[102X", "2.3-2", [ 2, 3, 2 ], 285, 10, "indexinsl2z", "X87302F8A7E44D67B" ], [ "\033[2XDefiningCongruenceSubgroups\033[102X", "2.3-3", [ 2, 3, 3 ], 304, 10, "definingcongruencesubgroups", "X7BF57D157824FFC8" ], [ "\033[2XRandom\033[102X one and two argument versions", "2.4-1", [ 2, 4, 1 ], 335, 11, "random one and two argument versions", "X8146AC8587C65DEE" ], [ "\033[2XRandom\033[102X", "2.4-1", [ 2, 4, 1 ], 335, 11, "random", "X8146AC8587C65DEE" ], [ "\033[2X\\in\033[102X", "2.4-2", [ 2, 4, 2 ], 353, 11, "in", "X87BDB89B7AAFE8AD" ], [ "\033[2XCanEasilyCompareCongruenceSubgroups\033[102X", "2.4-3", [ 2, 4, 3 ], 369, 11, "caneasilycomparecongruencesubgroups", "X7FC5BF527931FF4C" ], [ "\033[2XIsSubset\033[102X", "2.4-4", [ 2, 4, 4 ], 388, 12, "issubset", "X79CA175481F8105F" ], [ "\033[2XIndex\033[102X", "2.4-5", [ 2, 4, 5 ], 416, 12, "index", "X83A0356F839C696F" ], [ "\033[10XIsFareySymbol\033[110X", "3.", [ 3, 0, 0 ], 1, 13, "isfareysymbol", "X85CABB30818CD99C" ], [ "\033[10XIsFareySymbolDefaultRep\033[110X", "3.", [ 3, 0, 0 ], 1, 13, "isfareysymboldefaultrep", "X85CABB30818CD99C" ], [ "\033[2XFareySymbolByData\033[102X", "3.1-1", [ 3, 1, 1 ], 44, 13, "fareysymbolbydata", "X7F8F5919870A46FE" ], [ "\033[2XIsValidFareySymbol\033[102X", "3.1-2", [ 3, 1, 2 ], 62, 14, "isvalidfareysymbol", "X845F9BA182F4E73B" ], [ "\033[2XGeneralizedFareySequence\033[102X", "3.2-1", [ 3, 2, 1 ], 78, 14, "generalizedfareysequence", "X8245766978F02751" ], [ "\033[2XNumeratorOfGFSElement\033[102X", "3.2-2", [ 3, 2, 2 ], 91, 14, "numeratorofgfselement", "X80BB58E58492D103" ], [ "\033[2XDenominatorOfGFSElement\033[102X", "3.2-3", [ 3, 2, 3 ], 107, 14, "denominatorofgfselement", "X87477604878BCD42" ], [ "\033[2XLabelsOfFareySymbol\033[102X", "3.2-4", [ 3, 2, 4 ], 123, 15, "labelsoffareysymbol", "X83C941047D486000" ], [ "\033[2XFareySymbol\033[102X", "4.1-1", [ 4, 1, 1 ], 18, 16, "fareysymbol", "X8594896287DCFE8D" ], [ "\033[2XMatrixByEvenInterval\033[102X", "4.2-1", [ 4, 2, 1 ], 70, 17, "matrixbyeveninterval", "X8790C1498107A39A" ], [ "\033[2XMatrixByOddInterval\033[102X", "4.2-2", [ 4, 2, 2 ], 91, 17, "matrixbyoddinterval", "X78779BDF7A1DB4AE" ], [ "\033[2XMatrixByFreePairOfIntervals\033[102X", "4.2-3", [ 4, 2, 3 ], 108, 18, "matrixbyfreepairofintervals", "X7F792846795E3A63" ], [ "\033[2XGeneratorsByFareySymbol\033[102X", "4.2-4", [ 4, 2, 4 ], 124, 18, "generatorsbyfareysymbol", "X7905B050800E4416" ], [ "\033[2XGeneratorsOfGroup\033[102X", "4.2-5", [ 4, 2, 5 ], 144, 18, "generatorsofgroup", "X79C44528864044C5" ], [ "\033[2XIndexInPSL2ZByFareySymbol\033[102X", "4.3-1", [ 4, 3, 1 ], 181, 19, "indexinpsl2zbyfareysymbol", "X80EED34183408106" ], [ "\033[2XInfoCongruence\033[102X", "5.1-1", [ 5, 1, 1 ], 7, 20, "infocongruence", "X83B2A8607C2E6A38" ] ] ); congruence-1.2.3/doc/manual.js0000664000371700037170000001003413503171577017446 0ustar gap-jenkinsgap-jenkins/* 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; } /* 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) 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(","); /* read style's css and js files */ for (var i=0; i < stlist.length; i++) { document.writeln(''); document.writeln(''); } } } /* 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:") { 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](); } congruence-1.2.3/doc/rainbow.js0000664000371700037170000000533613503171577017643 0ustar gap-jenkinsgap-jenkins 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'); congruence-1.2.3/doc/manual.pdf0000664000371700037170000071642413503171577017623 0ustar gap-jenkinsgap-jenkins%PDF-1.5 % 89 0 obj << /Length 921 /Filter /FlateDecode >> stream xVMo8W(ј"%M[ŢvhjdЇw$:I[̛7)o 9^E ʙ7`yɘ"7[xbYS"v)!K yoRB&_W*_lM81L0ģ10*>P9VZIvD} @ %]ݿAQ 8tOl0N!&}@)uUgeai>KFeө2Ifn9-h<|a1)e@mx\ؚr]wiQ))vQeswPz|Mt0L4iЕIy0EPoinrtdxTYR$}W4B!!?V?ʯiB#':.̟@j 7޾=@b"a]m{0Ag^&]꟤P謚fs6,f +6l>8JYr9bWZZG6+Nl^Z-=ŶzљMTm]^k' HWr#YU\IHl:_f{$Ą?b2ןk"D]d\~3-ƊēK/'G nɶgo&JNA!}nnXusY|o,מM8ɦ} 1mj8Xw;$Ct~ד6Y6YJΑr6Ev_Ty,G{%>Xy; ~j"9 +} ߴZעiw9k%;V}SYNi6ݠǼ5IqlM{X;& M#pϋM_$ endstream endobj 106 0 obj << /Length 1422 /Filter /FlateDecode >> stream xڭ]6~oZFH.i.iv2=ie9 8]ιi>xVzj~%^²$rD0^8x-{eSo&u]&N=,nY sYz9 { S@$N2% q29ܛr{*s{Yw" L<ϕu]C ~eʂ=h3+1kmS c)r%'otι)]Jl2@,c)jpiihMPl:{MO" 0z]Be@~߹eG'X4o f]nnv.S_~s+ʆӖ\_U6.\u#G\dhwzMhb8)ny;aP>ǒE@,55>!P !+N5LENX#\_wl0tZݐs#UX0`ike5l]/!.ch*GWmij,Ǒgm|܆Su|~<ٶYcouԘTA2ȋIBs†0vԏҞrmZ jHť$J|eOe{^WW5M_Y0ǵvטa( yCn:1Zf4y߁TTI?RHR#趯:pT*MWUuO'7cY[Ļ &,t޺ Lb Ξ>+Fi\Դnj(A!ngʤ) T0; 9W&b'oQ1"di:q?B$$!nA= Daf "ڑ)-KD䍘%B=2JHf,h`8L>e)lUϋ`7tȘ%2! 6ز`ҟpT0Pco]^$8'Kt.0)Uz{?+t8[icB&T0 }nHn؟٢*C"X(_&/qQ*08xVDUpA.{*Km QFAОTz ^MAX@Ý96 xa2/8D(I*Y ]= xvjC*ߘ.Kvϖbն\]ߵpnU+z> stream xݘMs0:Uߠcک3%Էld 3ɿ 5D#0w,Wi?O/>M881.@, & e f.RF M] q΀^WnHDH0HtaPwE!\F8 l;7yYs}QcK=5{ɾ#$nS8 Tt #b_|]rDv&1d˶_:0+שJA AIӥ]D)`q3hj-:@2VV./%^IWS'r2jힵ͵Z{=8HIyT[CDI0Yt1F*Pe.,$(ؚ#P:6,J=4g VO]Gvi5S{ZUup42*o$ܸ$r?F`:b#eIwPf ,ωK򄎒L&{[q,v_M 1zxc'y֛I_>ȣk~"D4";>vskvYZpx bR d bEX֕Sxɤ˦-a{#x9e Cޙn?|CtvP2FCނv-{}N&逑0Hܫgg®5ƃ˟8! -خYns/_fYsR[- Yڬҧ6gOj8yX9]-KuDk\<+?ȉvnBÄuT՝Q ~s@lkg /b`%`i΅uz> endstream endobj 146 0 obj << /Length 1941 /Filter /FlateDecode >> stream xڭXKs6Wpzf*ҙδƓ64q/Mr$X"U>8.Etb=Ň>>FۈFW?|)E)IS.(K2J%#z4%4f׿]PBl+Lêhh@WU,MBD["2$(_2Ji|e*%jGŀx'&JÎx6 ORCͷ *bh, KJpΣ,ӄ1Я~zUqISMdDO&'RFR> !Y|WyU]k+N  n!`?:Xy ZD%L)Q_m?x?K:>T@Y-*~=9#:hu82"EYb\BǑ*) 5Bm( as0\mlpvH@G!||WEgA׻0%hLT /ۙf_7j%d\tb(T] MzS78غD MxKmycEڻ.۳A!0dRE6U{0]~0~ d&k. :GThͬq+GSo=ԕ*㍁XA,6.ǩdp 8{Y8T=. fa,̾YIrG'e6pjlWi+M1(k {\d_v;9/^HRMqolzFR$~ׯ!\ 4rZ,LBVw\@f_]y1p8$ˍSNCg3 :4 ܎y}oA Wf`dXANƓ 6&igUؙ)vU* k-W|엀&BOں/5I `;L*? |ejͩcFw5/p7ur86X7dWZp:±->Aj7~}u'cNV>|ا<Su1jbiOZ|.E$T )#[,egrV?$gy~>.Riġ x<58> stream xYo~_!ܓ+PຽK]l7Awڒ+eΐ,roQh8q8~"?\\D)c@D ĊMp3>oY _/(A_/+ThJiIC&lzEU:՝{fUy.Kjit" %n %t,{IuI/"//1bFTbΤŌd*t؏ƳĂ}qmK}M¶rY{mۼNW^aiA0giYEI ˂qE5DIT0 V$ {hѹq=}&FS+$N,CuDߨNP$cA.i5J7 ԰E@5"prh^~pf @aUtkQ1ø;7;tbeU{|apm Wi}Ci}7:< ཷ AMx3KS mZ{ZߵÔ^_[.GSÛ);ܺ-i݋*Å}ϻj0.L{;iRdϿ`c` pZ:`FUp}l׆@ 2HF;~7xfaGkk>'ƏnusAf/Q!)aqp'~b@ 51J55 ?2:>ߣ<NCS]Aw}< 5H0OeWZTmrY 쨆ooI&\µEi϶˂0q3E5o6zݿSmqB`{PRWUV=toUYC}~Sx vҴ|Qq~o)r逰az9FDDuXk9ϼm} ldl N}~Ki/ůdBN 86^܄0闿gzl8˜r/љ45*Q Rr©:I"d|O u(AA( 8l0Ag.ʬؤ}=r={4SL%G1Hdj͎["fφ19"JLtׇɩdDm'HQ0R\:EF"Xid D|ʑXw]Ʀ9&;҉{Ю?U ݘb/G,iO-tXv'Q)zg&\D,c-܏TvIFxvqض9&mWU=i=IHJZrٜoέI>LCaA= $CƝHBdc%ڇ@_ޓ endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 807 /Length 2359 /Filter /FlateDecode >> stream xڽZrF}Ẉ fR8ĵN%eiEAV$@zɷi /}=Oe@-p:DB+^UtBa4(&1A{A %aR I Qxd-/PxS"$ Q"2xMV$& lEp _+&9FO+ ӋjOG GWË|\nL7uODw^T$6۵;!XnpF2CRO/r>c1Kӡ*gyy!r4Uq:o^&.-8/,|V 29-uk2/*1r=Z=-O/O);KNl :{HZCq^L&,~+~tvs5ejF8ʉ(MuFWM(w-du*:rܒó S0:Y0rVԳOoVeU48-~Zow/x~4+_DhNx ;" 2 k8b!A%y%|{\~_-I8Nkr{p:-!+@2x;@.bp27~.+XEN߲O|@8aȣF|^rҴ5>jwiY7/fR M 8|t_@ &Z^{:kwh+RX"لSPht2$_>8< Vazk] #&p1nuq?$dW_ӹ,leZuv1f2]]Bt܁.׀fS'y';쮀A5PwDI"l4Ң#ЈpYS?x o>lAdo*_ł;nSm gvm@.iE"KkBFӔDlXkD0yB@B5>Yc7.-,.И.Fۍ<3<3-8l^jm=GoѠ褯@Y UŇ\l >ja,(P l䠄zèpiMldPDl_GYi 8'ɰ`u5X̣5^q`i' ~ 9p_:m?:J-KHdB۴(O0Kuh6QO. <2U35l"cy Rmg Ksqn,ߩ+mWNۮ]9m,tR\nc1gvaX<$ +tĕ[[> stream xZ[sF~#̠/i'\}(XL'﷒`´3yp$sm74htzɓD8CYt~q 62dt~]t^ޏovݘC:O^+1Ju,$g_i?S:?F ҉*2\.m\\FEnkX\;"0E$ds&L̂3´g&S_'κ,Q !`U%`Sj(D%x)7>,D))ǜ:_d"Y] \}E^٧Au&Г{qaUK!z6Ʀ5&"6q5pg `͠{$J٣YI&ӯi`_]qgߋ-@ilR6X7N@? PQ ­l\Zk rS[ֿU##@I>OA_ Ѡ1U8Ҩi9K?g* X<(q+oQ: o'~!Rŕ9@[xƪT$#Ի{p> d2 ҇4`ɼuJ4r(%ڠr" W[Zd2\6Ua(w$R)+ЀM4#Nkin|?m01hXJmE7r_\\]D,,WCp1"UP.ICrdM2mSO[1Ht},`{tP?!r  ǔg*cڛ,Ft:k/4FDEX+LpWm̌ZT Aԑ!bvu TY6G haQ>&F4NR{B!( n %'}f@qAcBGJPSQ(( .4Z:.k& b_pF0AWeJ79d.B{P& !/;Y9+(z?I|p?^DaQ,,r(;&;5d|JsE;4鯘/v ]tc 1u}8bTE1Gb:\~KiN?UaDdbI)cqܯgz\;vwY<+CҍS$ oY8KS.{mɕ%]N '/ 3:6J(TY"-Bq||nXrYND!}pTRQY9|is=CRw5+D%jCd5Pc5+ؿY9W󗫧ՒIֹ4DjsZɳՊ*QEd]-1Y7 0 #ݮdg_Dk+b&n+tENCQH;–|HPni娟he䣚# כ#=yH+K`eh9_y endstream endobj 183 0 obj << /Length 1473 /Filter /FlateDecode >> stream xY]o6}УM,/>hŀ%K.p1Ǚ4ۿ%%ÒCY//=";#MM"c"X2:߬ocq:N@|y;i"R+PkٿݘͧL$Fl< ` -Ѡִm>Iam hV`|ه!bkab:erCM1d$|/醌Ǔ4oE=,on /nsߥy' 8FXKQHa~ݸ|H1 "OjMaaPI!4I܉tobnj0!o'F1zL]"Ŭf,Fit#&}#WH&RnqYbSqs9fޜ3 1S>|c@`pD`j8`s7! MaD%pu'-{m`Z bz:ORZx>Id|^~*fZr@\3?=ᆴ[Aqg~KEtOb0{['hd8f|r7j&f~׶mt' ʝ Y,@ K6]0Oe),v ! x[\ (/^"XӇu k=ijXvr X9zf厘߄Nt"!`e`0_Z> stream xڽZ[~_G4klP`eP[r%99Ȓ%0uD~ߗjhXMLg|^&DSmFPg*9wmE'O#%Y0$k`suZ׏QJEUu6o嬌xvj’m}{&L91a#L$2HW8 EJXEJc6cLp݀I? DDJF53.Yt+~ťM#xBS&zf$I “kc,vF0Zcel°5'H'aASKqsS˫&+&uϟy>:V{Z 1D e/^<[I͛l12 G Iuq#AUKluZu(g*;jʖ2zô~D*ƌ?c~%1U ֹ ODaRz!-5&mr˪܌FNb2V$_AmF=%sF>xs FO }Uͪ ԇ=ra;z]K<RF}߄' pR:w 4#npčQ"k[H~nR`9sVx}kOzӣX>6in;P(=[=[F3H.E8ESd`0zdfາŽ2CXnYZn^inzYr/{rջ@;*MIWn3 Wټ\܇ ~Hp.Zn4ݍ^kr ]7ƗmfaH!Sd0} [@XJg3q"RuBRylB r. t]gÍg{+^(k Vo/VUANjuΛh dNJy GٽEĺ?ݺ2dɪyYpAI_ãR誀u k6 拀EDDixf2k33? yVdŧ3 ͚L1ID_'KUBi)$碿R'mՃco{7gK\&O(@t,EV1Y%l7aRg v\Y Ovdjllt:[8r%݅-NƠF-t}ibʛMM)geUv!/&Ei@Zp+2y8lxdu 0h _|?hBvn#D$v~^Tk9xoMZ_+֦aL>!1L ]=p ;ծod ^W=^$Ӧc 8tzUly@Gudh{`1UYwdb@'7Ǜ4E+mѽ"l1{h+Q'! C>([ޅ Ф]:q8ll{]siwWWac+323.UaL6 KkKHdܜTg7I&U,=_fm#q\$0v2Ua]V~W\Qc7npp/ $`u7.z-mdr^)IUy5<2Z {x v<|ՒgC3WX-JI.$a}u(8Ř7R .g_W- \3ė*(L1;pG$?{ہLKi fjq>2CpAT|`wqCO_ˮň1_&_E о&Y=}/:gf7/= +S"TNuHTw>hL= endstream endobj 214 0 obj << /Length 1438 /Filter /FlateDecode >> stream xoF+hco?TR{DK;)66lh{wfvv淳\~>^8 exp 60d0 nOi22fS2N&ㅲQJF p̀VdX9X!HLA.e^K8_βt:m+⸩^v]Cy=dx}\鋊͘sC|CSm #qb~FY\,$%)N PjMb͊ݮDjwgp..p,1At~lM6Mn8BӚp, ]u=>F*aX"4J @݄^)yQn9WRMwˇ3^%'E񤘧I 0(A} ňZm4z;@@zX =TcqJq;H* 'bõtݱԻu(a?d6bgte{=}K:첎\1\lTGvzXJJeN-L+Y-fB;EY zF- -<;z**fM;J-ӐҾ`uFgaMG\ZOGtq̴zpTqQ@6=K>Jk洠dPh[@)OJv F0Q:,dR#jFYjF_[23r%kFSՌBE{ (WTzߊbTVFU1ʓU q۠u"1f\Y!a&,{)j>xJCy QXb)g$FT!Dx[py5Mi=Ȃ+4smIPB8cDFH-UV!6;@D+_`z/[ ', |-~2筝U\4V'Zy]a=)o϶R!AHֺm8@I&6GoקbʈAr]}-uz#1Ci""%ːFpXWZn9E䐟~+l~weU0mgIy1٬!`|_ HGUzY\:ȋ4^b9?,Fk=j endstream endobj 223 0 obj << /Length 1838 /Filter /FlateDecode >> stream xڽZMs6WHDHԚd@4xh0v;xyeu)K@+ Dp- _&Cz8d ܾy%MXjw!\%πzWؙFdHp ̪`%1Jf/1 d뇠4w##ݻ@i|7!p[U8mpQ F [H6n)7uǂpx0ކ`BLnd|ԑ$]PAqʽt]_mV4DJ &s]pĸQ<~g}fŜdG8 3PE"`S!`hV'BM[i0 ( HfQIb:GmZ-76{&hm7{-M삱mqrhY΋^`+.^pq;w.s΅ P/4‘=8mHޛ7Y^XbS)+%?~LyTPו  0bY`p<LrJEyMM (qtn|k ƋYָ=D3p [߈Eԭ]֢eA9^!`zcD{`M3B53z1s!FH\?CkT*N, <8A.QK|/E)itxZRV;Ap|h63*թbC.:d}jFAa\ޘb/ f-d[]rs>_X=;Qb*iuP),*mgu+궬bH?x(+[tfek y8]T >Lx}&즨ʺJTlO 7Վ(sb_w`{#E?R?SrẖTCd& @ )SwA%uBPr, i¾Ef{$j`eh/EGs TeUC{ .!7W|. `5l*bƋU>h9*2OץEM!(~sHwJ+pIj^o'9*xstmGTDr/9D^OkDL!q`¢SO.AsrR nzd0q5u8QR9h4SFX _Us=mzuWy ueI<?\Xž,bMte\m璟n$lyuT!DqT<\6)Mv_r N'hfx8Zxe '/yvpa*>أdzSEH`NqThp4*)i6&$(mreioCh?L. 5bMJd?giVT/#E.b ,%ZJ Ϟ8짐aMB38GVZF/m-VGK]+ .šh=:&BSbٌr冿Em endstream endobj 237 0 obj << /Length 1905 /Filter /FlateDecode >> stream xZYo8~ϯУ ,c/`ۤ- ʾl,GqN^e)e>)j83f Lqq̨D!0I.n* $JdO.nl2$xPGD 8^]}q&tB02oFL`!v S8#NtH0Mӓ+ F9A!"|+,HbTI JS(8_p$ArHky=) ߚ"o`ߕw/X?3f  N$$w|:86a'›濋R\:*+.w? Ҹ8;ei@80E|@u-0> DCgvn/M*$? ҈RwARu, ๾laI"sFQ aDn@ΣZ.A n. SDMİ:@& bMx1x~ <Z 3v0=1X@5j|'#Iw#"gUZAef<(\E6cc7ьh|˾(!4LEz]3!Bvu(ħfzh'Jv0HE1X6jp|a<?YCoii6[vwj[g5 ÛctjCnwq _.2dˋ¿!r^lM^/*ٮMK oMg+*q!fg!E&~GMv*.aI"QH(m$ bL, t(ČD9`qRĴq!"*!THTQ Nyj XZKēH(eDw4JmW(#8|,Bt =NT@@~8@HWQ?8S*L L`_ȅ< &Aγ6g!ILGFF=D}JT+(L—kۺQ7X71'nVHDŖ)DJϖjQ\g{.%l9Ps7e2P喽5ʦP"[J*U[]纮0~Q`D 5j$Dړ0u#H'{Jh$Ȉj(HaZ>M$u:'lv:x/40(l\ cChлTïz. Af0~l.Hr t]:kSo؁aQ 3." Ahu*N:%Lge^!eǜJ#jζ׌$xذuń@JT+L7SB0UcYō\6GIw6+/Z &nly<sgqr۱LYzX"_sWD u%C7UyP?R\+p55p r Au8q|T֪v.t"sy!/]7Gʵ #H g}?5WfI|?_ endstream endobj 249 0 obj << /Length 1986 /Filter /FlateDecode >> stream xڽZI6ϯz!&HM7A pƲGXr-Og͖%/ \>ܣ42zqePӊ˄w=nq40#& _cXj`h$Nb܍RH#*o%Q_8B'Vs)aU) 6qix=Y|? qh91d!Rt~?NgͲ>oX\d@+Ia:X%:~d*~\&Ml0cPikF~];T&XoĀHagx(,,-QQD'IbJĹb=bQGy:4VAxzVOaRPYgcWq%1m0<$Qg3eԑTwW^9ADQD-5xOȅǬ&Ryޗ U\iK9{YC+I.$ ~_,1 73na׊ϕjn& Xj%>{ojq,JnnځF'[ĞMyH@$ 'ʝhٰET9㧴E0J!A_OuNq`+׊GZ"|٢$!ESaђLfNs4٪,G8JQ]e v){VJK(&ڠOƖ-Wo_8 ,`}O?3M2ZA@]5-aޕ-nѕ'W~@׬i7%UeAJ7Fmʡ`!'!XiSܼ3ѹ"vsFBk>pʑ-[L~8ɻ|e$ k}L183ɚUlڲ56 l;ܒ[ޑdyzL# -$']SD(wҵ )fD C9TS@`QR2@wcǙ@n!CDlkSF0'ﶋ̧(I@UQצLlm/^ $~:砉`͟0 nXkdz_&tg&NqֶKb.Iչ朳?I3_ҮћF{?Zn9YTаd~EJn)vK2DϛR;Ӱ;ʹ=q/JmR.T@T[*ԥ YwaΆs՗7t,X|/_@D{m \6>\exڏZ[WR1wB,&ϋXWtacv?bkp]f)N/N!F$Si>.xk낧[NWp|GJ⭹ pяqL.JޚH[ދ97ٮKNН(ݨtҁD~(.TB\6*4xm[sUg.Z\cW)`dԫyU hw, TNwp#pab%_|s-|r}! y7 ._,EKv>v**!:Yzv}`oӕnSuN8G5"*2"e.5>DS/f6H>TM>>AUܙ`dO (jPDA~Xa"@7Œ :^eDJL3CAìBU?.Jb詟Мt0 fT$ &p#t]hlCR}sΊ݋3ƇcF=^C]uqdz;1|?kfmxH uQӜ%('Q$6 h+XW?Ͽ endstream endobj 259 0 obj << /Length 2534 /Filter /FlateDecode >> stream xڽZI۸-R`!@SNUfkݧx|`S5!);>a -NAo l_IpJ2$"RDIF:8 U\qIb+Jhm2}-,.JUI΄]ݒE-Yhֶ1U#{0C u[@-O%jOM ZZI$+|<.KtQrp}tqg; t+ }vաxXv`ڍ}F)oꡲou6}u4( ȥr\sHqyQ31h!0ŧ$E2y8 +TFxXlR*MqxxbԹ]]-W)l,lu>5wj;USuv}ߴm w!Unf6}nL3n-et k< n}3NZ맋]nWnW1aJDZjʾ@( =*tcJg9aYƲ׬}>n]u+`ppSV;z%\lk/uukPM&t~p*Q2"%4YfiVs㘓q*K-s BO<|Vy{c{PFθyF';Qj$D"\ V9Hc4@A2=.Fc}$OE.4J ]^O. ȱ[17KxYNGmϰ_"wSgg h3E¯` >(u,+Hq86jJ 5IR63'Kyr1$*R+ bb!渿0'4b2ھP0c+쪢h:Fw ,$O@7GyE2(ʢaș{^5qNL%p:2'Q |a0,{OOJ v]e>.ҳYOE;F}R\=G|*%_t$GљMg%n#^:*TdDŽީ(hSXo6 %V>dE(YlG؈0_d](AOK< v%G|IcFV]R71yP| y\,':U9}(;&f&Yb1+f8Zdnáxaacjuخwn K)C9,S7f(cD4g@΁'3ˢv;ץ׍3YӺ HL,_Xr]@hSGM(F!.Q޹u,7Шf$n(YcNHA31{CT}1\<ۨb)//.juLDGHw# [ʊ E~F@oslJjb&2D ؞9VAש/sLѫq]C c"YN͊u&,qBciMNt^A3~*b}P@zZTI&E?` ۶rtva1 ߟw@/Xecrbic(N別dttKS:D)%S"RHox {\Kɧo(EM\0.pفKxd/'b(Oݜ6337MZ2QM2>ɦiRlR#zL3.^ୄ L(BdaS*1UZ?+&+Lw5Θaro\>CÐs1 \pQۻ(VyW㝔6uk=h+6.t;~1DslX}\uŕբ[LņInzZZuS%k 3hfr}Z۞H\u2m@ }փk@[P!06Ҽc@(rB9 O$*)?qrPf,KJ ~5; Ӟ&g61k꧛?)`Ābi +.^mܥW8/H%`%HSFoT7`^k~_?_ïgtqA  ڂU `$͔v?}a"H`?_ endstream endobj 167 0 obj << /Type /ObjStm /N 100 /First 874 /Length 1816 /Filter /FlateDecode >> stream xڽZ]o$5}_i[!"bahF4J2{έNeNJ v__/BRIdID=P"GU<)15裤@d-0**ՁZzjZw=[Yl#AŵXF/1[94e|HaH6FdW Rl{ e6N]KAw\͆Er bV-:;귳]O*qA^ڥƁKKBh\ZeEDa5jb-: "_ЋDYT%IkH5de4[Cㄑ{4OOA;9e% aQ& V%GL2j1,wؔUJƧIOJ$_PvяsSS5CmվfBsfRed Цt 1䧚,6Bfӌ"S ya˫F:TzEmVGؒl:ĽÂ9.tpf <6s asiQxTV>ύwψj1e,2bk4E^r/} 눢Ǟ$?}C\ ^Vmelqn{־Y-Va'BNҐQ1sZ _Ch7Z9,ۘ\cXr FT{m{k3. ʋYė:2YO]ҡNӡil⠮J#Yr9`簡E/+f/C"6'Wp5[AבEư*Ŗ,7ϽA[il̏U`{vN rPAY$-+H)%O,x5Kžd(l]l]l.m79,WcPli[TOO^O{(O:cy7  endstream endobj 272 0 obj << /Length 1586 /Filter /FlateDecode >> stream xYMs6WHXD:CL%HCQm_P(ɢ=ؤ `XHhfvH)D)CH+ Dt߯h\' MI^]$J 5X1Q?ѷ-lt4c8,Gw4z>DpDKH-O_+"CbNj"TjD2g,˳~1_U[ޡn) ݌q$F2n&z -O1$F CAqv!=ıB0¨Fs;)Iq; V,_1?ތ PJֿ z50-ƐӧբuD|u \4;& ?F*JN Z&AN%khF"t`PS@~`^tɿ*#u 7Na'ۯzK>n]V/NWiQfiYum|մv'b+s-a75 '!ISwc4o Z-z( {tSeYd A:$u$Ui)rWڇhC7q$7k5> stream xڽVKo8W9I@5)@ݍm|ssPj`˩n+Nu"=|<8[1ή'g˩̂lɄq 2k*6[y۶Zȓ:P'٧˩rpE^P7w&u5 m9kAKͬ0 Tξo&[tq.g΂ ߚLkd&H4AI~wyX-@@^#z Kg\4@T@2tis%F`jA@d\bC1'\L*>g:xH @6ϴr5#M1yzC\vSV~[Y^Oo~C}}b]ӢO7GȊl/+o{+_L.Fg;8Dt@4V61]ugdo h5%d+!@FmemiH:ĻS )[E{ 9ίw_Ӕ_) nhSp 2j䇗G&uhRVbTgؗe _jM6/KOcfI2aSW]Ir͚ \m-%X>ק)6IH3ex2/wρt],.(%7!E> stream xڽZIo8Wh }}B' SiuPʖ<ܩ(.$U} g gwWطZ Q"{|͔DL 5K4wMPg|W,WY:|r"V)nA0vN,ωߝs9^ujYx]Zwwo 3&*nǵ]l/®\ܚT9a9383wvQI,,9HQZ6e]aS:4q[*(@bp@wiU6ޘzi|s 'n%p7)FͪޗzCze&HMm/jצY1 )g;xH$F4*ٚկdzEDǫT($VI,ub8eX`'t_ȌRt5$Ð&x[˵떍oá|xi:ҺX~ k [(wͪ6o7.6fҎLqƭ7n[T *uy)ca=Le91[ ܳ8&GpÄ01ӹSHlW:MHC$Bʟ"! [ fcd4`PFms>B+?cÍmE-v lK26ym&r"v˾@#vxWkw\!@im;=nc׻‰BDZC[<_oaX7%6QbM6Ga|P@yfBo0 (m7-<3.M 9G*;YiT@Qc)7:-ۏM[0cCSP2m=5]#˗cwkwe],ν3zM/|hKJva(`YAˮ^J+g;T|R>B*є e0RA@.o植jYͧgmå0msU{̋`OFj65(?ޅ ^4o*k;3|ɂ=оG˓_Dy9Ra[?F >!HCQB5x9h0-4RAq(E_ xfکlA(V8UAPCJ;ug/#2rGYÇTOw ;n砜J!EaȨ:|X4X(#: +iKDl@5 K{.$ ׂ-gǩ0E$Q C v_Π71zP I/N3ONTX!ebS쵠6^qGԚx{ݽd vtRO62W2£^XĆx.ژ,#ov1Qx2@c1Ņ(QL9hf[s5]dH$: .'1ԟ1L@ȋLAT{*G"hGkBsM )Ng 1zw9so9(f:PcTZ^" %S^5bt5yɒSH8[q50?e\S2ĉl LA0~ ]+u$\N$NV cC?|DG<<OaPN;"EM.z?RCDLqdϊD~5K?so endstream endobj 301 0 obj << /Length 2628 /Filter /FlateDecode >> stream x[[s۸~IHl36N;;MTǓ,Vז=HH"EZq(>|;G0#=?yިH!0ΧqI"% 2Gbb~}J`y:"b̯__:"lL#cQ N,"1.m< jd4bi)KQQoy~8;.Fc v?l1?Q0p1:($I Y d 7*z(. - Zj1_W>Ib]X:]v X;uζNb* {56 5/B0)Z|[XgUwAH.\hCh8  3+l|^h)o,Cp5+{'C:jtݖe/ &mL 6t Mzm Oo 00F¤^ EoC\E8ZSF7&wm񐽕Г{!s'T+ @'аM48!2P4 G#PD2ɣIjEyBwJ=)]GhD58䌖@u z#s ) \)x RAj%PF@QUȯ [ERiݫ}.1" S#ޢ} aݵ*]ڇv> #,ŸI-ڧG5>8Ÿ8MƔ4՘.cƼlM71M*3o+DE'{%,{Ӂק;i&/o&$zsj+ED44R]Lj|41b!Xb.* .s6NϞ~F<Dt)&tkcIiZA^&I= Z 1i׀]X#̃8" F4XW"-CR~|`$9b!WhO*2C"rȬњVLJ5ef@)r;FLhTxRt@K8Oӹ6^Ʈ[ͽ.=E93_KK/Xw^m5ĭETиMoROiEԌIq@Y]NLkբW$aW6xث6m9.#?0GB#x~fw_bŶty]Tw'MRksc=AΜ/',pRU6 h!MsC$1rvʞlq0ΐPIKr ˼$rl~[T9d*Cd'u*UG8ihf 3f|oYޝqbWV"R*"N FWw'8_G ZE($}6xOFc7omRQd ]2_9%۔[Zt"3 0[ѡ f(b7yR 7>g<)F:w7|$?~cOO/dp|'g] ?T6+PYl{Xj R]lMpu=i OyD7v܅?S_яuAi=:(fǢTJb?>d(:B b#JEVr|~zࡿM^jXn]`Pks˜FTҜ)H@üHg^-ϲY2lOD,KE;ʵ3PQH~ VMkh肰U!j|<ߴ6>g 2#1PPF`ԼFǥ֠pK#\J?2, K-DւflrA'`Iv#7 }.ҤN19EyG @֙皼(@( 6/>%M2}[S_  h bC/ҡ=tu+|aTw蟹K2ZZSGIpii"g\8b))z%KqSM̱tږ:!$!8lsm~3`E endstream endobj 310 0 obj << /Length 1971 /Filter /FlateDecode >> stream xZ]s6}ׯd_ 7Ҧ٭vn}02DUJ EQSd6\^{qFF޻+#ML#, "X}tk d1YN/Kmh  F`\?yhTJ*¬F\dh$#<#4*Y{a܋nG@)=d/~܌M'hxs+bg41$npYtdz8JЛ?*V&FlFtsQ~]*Ğ$l8cͿw$ͲdJsdQjy}_!8*r%lDs(}ddb> ,qųn4E,vHaCɟ;,!.1: `hQTx H.#%, CF!G|k>D`5ڵ[D׽aCŔ7lz'N!.ew:(z솪`qS^:suqXBT>5QT4:Rq#~bM(vWcN endstream endobj 320 0 obj << /Length 1628 /Filter /FlateDecode >> stream xXKs6Wp` M[lQ 'cw EJ{bp0 pp{s;=Q!a\*5$H\y:f*N3ڍe ADS#PŁю"&R-F.i|3# L`ALA^F*M| (cSv1[^ 'c<LS?8.Ya|W ׌ -H' *p (#&89qy{Ru[BuPSŋnQtӊ Ka-\QxVUw5ݑT64۟P:&A'SDwpڝ(;bV@apcE<^&xWo8)Y'AvKHP#'C͆1#d~xK[PlW{ۥ$$$5T+K^\|5]$iO]U"IO{zs_j#_ȹeP>fj=O @9^kPJD4b($Mk @}ZK󲅕Rl+Z` l`m&`CI:LpĈFN깃S *vv*܏E4"E!Iv9$pG:>h Pnaıf5AvC~hң&!;aI6-&@49HݓX"|DQ;$%߂fT…w¹Q};h))4vzgz$ ho~H44p&p f-8X8/ԫn8 e")MN!XSOT8_2s6ļi3ַE5 H(+6?PFF4I9G\n6.VżwHӹjBxJrIb݃Y}:4֮`]ȵr_G?'3WI~x~X npfwE03e5l;Nzg6SDd+.W34bLZe{l13JSk}Lj;BEa( H/sX$~d3`1;s,S 'z4EIgFC"22|ޙGG Hn> stream xڕUI0ϯH[[uFzjs4a "/|{AGD ݻ#8M@R,@3vz>7&fDbs`_{DP4̨+JP(,)C-J27ahMd\3Ɩ՘( U=:4jO1RΟx*A1&') Euh?0GO1%Dtt婔aDdZmYݹ)23^@aBb?0^ 39h۲? +!Ƥ''"qzaXo5LCy(5`L5{eNl@hiPH )\ g)+uEjspʝ^hqb-ii?tgk``6Ӄm}U%BH 3Z*a%"+XfKh's?TƝJ{yDad,.&u-Coh4 gr,6݄K;Fc夛y{[>({0 3[?x6ErCw=u0"xFwӻj^QJn͞' 41^FRE܂8 (9Uq2T։ꗯ!n3%VmeW֏ )mCNaz]V!̷C#.Vsns)V<S׷Cl 0Ntk3alpƫ+cM߃UadywC endstream endobj 345 0 obj << /Length 860 /Filter /FlateDecode >> stream xݕM6+tKbo"i:@ؒ!-;H쵁E/=r8+TH~}{y^,InQ&rdJٓ_.f X^$ .$3k{~R'©Usf`M>MfRk)W!4ST8ffeS MH}(!Sb²YQ5}J"-it{-G6qgvpEF;Ⱥ SJ`㷪k55=`׮rGRH/~[/˾xXNP*Aj? (ˑ?,㦣^9"Ц#mƺHg?߀4wAet .F[< (N endstream endobj 391 0 obj << /Length 1038 /Filter /FlateDecode >> stream x͘Ms:^Eчe[IK&]. 3MmHK}%Y!56{.c~|tp3zD]39=@ u<|g6w&\7_x=B:zt͊qX-Fay\@'P:±/]bFΙvyҤ͙dĪ8u;C/њɏ5O'DRUf 4_D0WѨ "v7ּrϟ2NJ8 r۞Lw/^2 wB]S;É#ߤѯ5)uNeA"iKB"W2w tAWF@#o s:OY+CoǨ"3OL|ڮ u_yf wFLO!#ɪ pK:X.'udl~\M[T}嵏hOnr.z#OW6ʇ  endstream endobj 282 0 obj << /Type /ObjStm /N 100 /First 874 /Length 1998 /Filter /FlateDecode >> stream xZo7_(AESHл +@￿߬hKeymm&wwv|WY)k sʘOKT1JBoWL$5 [-TJH6k Z~ ~^ZD 7_8-Y60B(Hm+0 [Wt g tF8J"!pJuQ$DJ8mGg|?$/dI0O¯ 3p3ą9a dA \+h3X)xX@wrsIC@R6 L8,_ CvͻL@W cR3PQA)3dscJAo R|gcz3E9>UC݂4k3m$v[)r:*5glV,\U2CP28+Ya 3ȴ ZJI ZajyPsmc(䚂Ay@- ̚!nً_>Ϳ__-ί..v6\^_..nӫߐ&ѵa3p ]]̠m2Mo4$,w RE6Gf͎`ڄ9rr=zv#!akLKuÈiѨV@5\{(=?$z=?rH~kǕqj>)e(s$!qBhh&`ge!66T̨w&5+(#l8E5PRG1P [)wI@4`Bp;Ơ9z( uAP|kW~”(,ѪT'IErD;.JAV^cd~„(p) ãu >&}$nRSD*F1 Ɓc3GHch%yj}ڽJ_/h^=Jχ|(t~_\;ErjW;ygӬv~i秝v~igu~YOe:?wx=ͣ 4Tnb{ܗ!e<&!#zEFA9"<7ϱlj[vZKulO^gZcHoG :!?Ui.3 hG 7rA)sO̒(D#_8ڃҔ֐\ 6.;8ʪ$Pv6&tr2īޞ#,'Vᚬ:ڧ 3KWTh!(Jƍ=hmd_ʀcx ʱ Dr{nGg&&ț=c P,2PDNn@ endstream endobj 412 0 obj << /Length1 1411 /Length2 6115 /Length3 0 /Length 7074 /Filter /FlateDecode >> stream xڍt4ֶ.j>{ c Fa:zDDt{AQDDO=5k=v6f=C^y{TGEme3?_/@fCB@0\?H(ucSn8@D$@~~@ h8ԓM9:n p@<nP$ ('MF`(rB%|||`7O (PO(j2@ ` 0D8|H( @7.^p{(p`u"kEW?޿࿝ 0W(@WE Ep_D' nKT AQ@O~fe" GyO Bnݏp]8 n {/w>c8 sc" /ĉW#?wo|C pis=P  D'!AP;# N7f_#aK~zQ=oY詚(qi_ @BBQQ@?a gu W7wDgC8.o[ Cnd+H7n0W?zn@q B]m=QufᎮH jCAR_v_ C__/|A\3i<& M,A[, $M/T xvߧc>x?A;.-Y,`NrpV<5 Ex=c%-U  a&[EG>y;wO*5aG=27BzW E[T -{K"&H<)VX#Ѐ\y%Nˇb%.3/ooI^Fp|0_a|OŭTi*_һ4Qϸǰ?+Yf!+^ĿN#/POZ[r!#6sNS>.+젊/>O+>OD_Qwc`i!pIQ+&,Y"]Wr} [25'#(q1 DS?"]zl/g'E߫^E[/"r1|G. ,/Cj7u<]-eH\↻@Z_a1l2O+22w6o{;w]yadTЪqs';i ^)U$Fv]'w!$^j.V~_ b2YaƇS~LÒ %HYD8z_kޕUdtt$V7%dZ 8dÌI̾87M%e=cbuUԩig]~cXÐ;K_>]aqN:c-{oA!vPU}J|g'R =nv;rcM`Hߡ:Am:8{yQ'˕9Χj[^1r(;俰Ο'B)N Tu|V--`:sX=W;)8>thХ*6 $\pR:؜y {z29wRЌ!ph;]lMs-gW3K8~`pd4߶ɾaMKw) {9zk&.zP`#@[s!%f*xSs0nߢTV\@b?ގ'qQ&s5x+vDB4a'k:9 m仚JnKo\;oyI+#Me >L/[kk2w pxn9H *jUYؑqlxvX FĤ/μ.)F$7D"CŃmdp~W. TyU ҾQݦjG/`A/(/+|uCLb"aQZtӣ'T0/X$f@W=_sn[<#+ּJg 9J3Y}eF*Fտ?yl2_Dˏ N\2 b[[U̼yN{gUFk*O#;b;%hȵwI 8(^|nCJl ּXqb3o8&a3Il4%T,A p202Nbz cwX^cN;L0T? eqHZ7-)a0 "Vir0m: !;<n0 S@Hʔ9jBbO{)Rs[/C ܿt7O=suӯ1H%}v ܓ O O>#iXplZiꄄuk<9nlo%j fR\IT2 a=E/Jez|rZ鿇60Ym"0c)%0n)aڬ6W=XcD"ӊ|-$ޏck۶9H8yMKsN#-ԲI"');#nߎyVӣ*G7L$TL&1R՚ΏڵQ8Ћ ћ$Ri[Itke9[#f# "?sls&xF*sXwP 8mh?`h%*ʱy7W/NL`X d<`!eJUvu q搤WKC3\0;||(?_ֲg5uV(d^lg|iz'6Um8_E?>5Nj> vʇͅrP|%q{S\qQ;sz$D7MەOE)%M!̦#'e]wZ -- Fo)܆ʁ tqD܊<5!!tA?~TMݢh H7ND^9͵ ~U!GVڵO -g;VX ԌNa9ȦE){}a_ %OXd{ mmji^Z1F}q g'ma(|uiN_W`/bl`fdc.ck/0=2SmÂ,󐦜Jl2VXgF? DGq~ϻ1n /QZI]M'HTAWp^ِd.*#je2݆8KK(ylj>_J}%u3=$%h'_Ѳk ^G@֮p|˧c%q*bж H>YIL&>J8}z'#eC^'<ǚ|/*U_0YFjH褁<'eG||ҔꚄs;.'3Pc%'+ q`!2@'d>v0n^fU If?`shh" :{G;ōߛzVyWtDs=>nrKcH\sNo07u;XgKiuR (ڗWX.]TTUEm8AFk;%Vʃ6'6ov 1UIC~o*%&xLw2NwT?f=/V6mURe) #*j%/r#*MӂsOqC:YY+z{j ꊓt'`*qb3jb>;v!,j4o= Gw+|fE+Try.:-4~m U&f: '`ILew\Xٝ5o,[mX3/ؾ]=m0HoK=CXByTFLO3bVҖ$g\}J%4> ;Ut2+W q{]%r0xR΍ yS3Wݭd*nts aWCfzM{@nv?WK5aEn*6j}&PH>1bjGR%4q4iJ&/`g9Nzd: &Uy!YSȿdϨI"*%Wk3qH$֧`ž%ϊ/mzSF}g+9^;x}KINڕݹ Ad)ͽf GH??H6W;X|wal uLýDy%<[=oj9~Adm/*?tS:1O?=~&Kf R> 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 416 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ڍxTT6"t H  2CH ! JJ(H("7sk}ߚ羯ڜlFT@ e"@(&qrpv"N  DB Bclj 4Dt1 "dj /A"("NU- Pz @vz`*Ap) Gy^. _`EA| ф8f0_S3` p@aBS`0"ȿ  ? pC =!ZB@~Ap ' w 1|(Bf*@~1/pH_D+gk 9v1Eā"}*'3Cp' sbQ ( O?WD"" 8A]`gǘ11}ugaM,t/ ((* DDD$1g$@v1w>8G 2@b @0"e_ix<?0Q>C-IW y{W ¨Aa]!ݿ0 1//aDÈ y0b4Ϻ0Klȟs֘8 PJ7B$ pFz:XL^a(KPm mG5V^9-!n/#;.j}?ᯬv&YLjdiNWqTӍ<5Z( b;:'l9]+޿r$X0 dp|NqlLhk˝j9wPGl.Ԧ.PrFΖΈ~׵Țc=l}<6L|,\#mBorHTGQaINiFaq%{Dq-8J.)hOnt1P e`ɻ)>'׳|䰑mM%%U) g l8F ߋKZ?,-;~O B$݅dQ4y*FpgwWri*N*#m6U;B_*XS[-o:{aIVY};go),%unļę<\.MY%ID 13y3M 2CgIʙ_}&"& |4ytCx/nq7<$'#aQB{.WRn$XnՖtؑrOyxo\c}=|f )^o'wڦVӰ {d1)QMuH㴅ЫgԹݍ0OFCUd ֫Cqc,BHJQ&EBXMDpEw4Z(/5=z>P1 q5(le(_]w`w>Z~+~ݕғBB+##ku[խH@"ZiC;AHKKVf,'%3ا߹gY5~ ѣ6qyz"?Nza()^!dqEF;O|1!&U*<6J#u+ شoſy} lf藌Ao%;hR[rֿ~5}(uHV1MS,zdY,O QmaӖSUIN{ȁʮ{ߚҲhL|LTqs\IgiFr:)i;97/+3}J CZ'l Z/q(fjEDR-q'<Y Ih`w5/WOs>I\tby;0zҞBFa`fJ\嫁<3ZJv`:}7tcT3 |0B?Z6T>;6񅭙{pyfO'vRčfT+Wdkᤵ5{,6O} ժUNSĭ+o{,X"eL yBR:aufbDér*;a1!tGLY0`и'bhial`Ay8֡+'[Qu~ՠ&|SŻnPy1J.0Ƨǡd{^:`cfy~uyykz iwbFOYu@HΤ̑I]ՇlMUEv b_1#&F[[e~vLPU (DFK%!8z1~=-+B=RW#'ۋUqzZotߟ4f|%?Ok/ϾAD?(TOf>͙<+G A?YQRDXG<;w7l~ \^Kbnv^t|uَ?N @μ+Ko:?*(5+!|'/qRv煫Ϙiv qYQF >%{$yv"ʴImlZ~Y,K:3ZXwؗ]qw$JPMכVuH i1`Z&25V]Ao@}Ϧ8˖*˜7 -OZ_w]uZXfa~qBF| Ϡ.,_wt,Z"e0Ǔ@a nJ؀MbO7a/uQO>I>\xՖuC:YrpA[rF^)otĬ[[AM ~'ڹ_{jz68baMFiq'ܤu >TpOD4>_2,O]SH"dBzj.l1|ϑmX3xnqo U#u}]><" ٭#ֳ}pՅm8hĎ{cR{ fSÆ竳aT UD" / J "qnB*  ̫cwAۜ3t:/[ {B3wbmS1GQYWYn9p2D*qaܳڵ0ؑ%7=W: &H;N9ťVo'J{ɢ;`dTMĭY'IKz+:jkے#\/ͣ/u2۹o|~5$3> G0Ȩ %%!xS*3r@k JQq աp쯳)5OC5ZGhն8l!v&_(+}7Q3ƜN4An-=юtX1v #i6$7yGvʭ@_2qb*[{e_NZH]4y șͪ9|cd΄PpA'e'42k벒_;`5jQZ\|@nT5xṂ4aq8 Oi U\xr9$';eB%hKwemh^Z &? 3gJXdktW\CAr+EOϻXk),V?V6_Sɋ[{#ǁ5n2~Qc}$sՕObXMz6z_3#dTGDQ#~GO4_GEWvL[wA%Y8{ek΅XnNñNie`̲|rco2)|XgYE܌-J2ZՖUg3+jF᜙mHq:EU\W>Z_&o=I=I'Q٫t_vurB^nDQ*$M} rcfo^zi=>#GW_U+vD hK 6ODهg*wþ#:vlW兢wGB) -F(_]1K՛³^̕o~K%0ˏWrY3#H~TG fƂT|}O+*`n~E!.U$ƦbB8xMTöcB{qay'U w29җKRzHjT[bވvҝoX38^8 JS ү).ڙmB纁cWt}z}aGTnb,}|SQk;SCSPS?Y;|y]Ҹ5{Ui}XBz(s]szpy3|T T"7AQ-^k>v5%u=R\ҝzG{XU~A~V.FؾkVIXS68:t͵e} >փ2+F86evOS\9zv ekgUGvn~H9LXꙒزR-A{#[q[YTN O[h2|o~*a~ѲE=rC=Ua,*I;3}a8;]9JH#߬78K3{js'׆Qv V/UɻtY _G;g(9Xd<؍bO,Susp0gI1Q'NwβofOrBEgşBLy*&[*tl(\&l+}jzIB 80H_IvT0PR齱sg 3{F9p5’w`cގ/f 6&]4%d1'> stream xڍS TSga,LuZŐ KDv"*S y$y/KB rTePEA, "*(XAD ([E¼\p朙s^]kMh#G\  Ƥh M8KvXD0p z ЙF_F)܀7F 0Vl0Vĉp7꺌lV |.ċ|H0>)!"QILaOjX%H OF!ـppaB\)`@$FE ` ^aA` F'A2lSM@|L*P-!"*nOBz $QbRC%!Qd}JJkmA^T Q|Zp(AuoBeT2jU$0>`hL r'ETZlpfD !Qa⏤SBj 1FӁ CPN܉+Fȏh߇S40JS9^ȥ%pzzb @bG'SĩqB!d2O&%>e&LʅGoh|Cn7OW%vCRD@$s@$<QI?4N}$P&dbÄr}P>&Я ҒhttbpAJA1 OBLAҏĕ&Ҕ|BAlarěUOj㻧ƗV ı8>g84~:ŋny{sop2;7&K`f /,"~E/>\xX;EyRlJ:4e-`lo5,>GJᓱƴ׬Ib-;*O_rVb[nݝT]>=2_ސ)Hv<\򘼖ty1WZ6qfgz# N8ݕdivyD38Cpᆨ +/;KW[XPF-ι^'&i2`_>aDeP870|~CEKq/"+c[eȓuR A4͹֝[ h[O<8=ܖ%:[y3.imZF5ٕvK6h}=苏Ƹx~6iwI(VY(Kf' Pi .MYw۵#:v!/&B\yfne{ƔݕGVX'+.mx̫ VT^\]z}uMe!9W%֏}aWdY{]^:vXl,]j^oelu]!IloI=Oo昭_oi9eXW$aG=d_*U8~|;}BTAQl% endstream endobj 422 0 obj << /Length1 737 /Length2 17032 /Length3 0 /Length 17560 /Filter /FlateDecode >> stream xlcp..۶m۶mݱmضmYm+{=O}53WwM ȉ%]ռ L@Ay|[ȜOj>'~nȣ9YMM=J@YJ]Eq`!#1}MW9-!IuMJDm 莨kwl~?"*[f E`[fAprgag2Ip@CL񖂉K7YVTJqQ+֬!avA5jM`~RiUG5)D[Z^Uɼj|%e })CSg'ܱ]'w߽/Ђ`f6L9!w*'*U <`/7,<[yb(Kropȣ%B9# &/x)ӃX璂Is օ%D~~"9ܿ6ZjNxWav].n, yz &ͬNJOI\+DiX>wLg%e*<;c%oZl@"ҧ2 *ַТ ) H٢sk;;GRt:#Ff$[1_9La3xsۋQu{?Vk-#N(I~;kad4АꖟSgB؝ՔT<%jƘVB8@QEpe }"TVl]#G.#k\jkD@O1bY`z?Ftp ) $ҒE)$C Б}+a*P15",Oo3dÑu>ǧ^4AS(0A!(b.kLj!kZ@|2O_JY#1Yqޫ:ny-\jO''mb2g!rnfݶ@j\_b);/4$+A jKķEfO@+dt3RΌW;=$ѩ)=JJ3׎(=48{ݰ^t{̃-`4 "}N+`FPtɄOͬ+ K~zB, Wa余`H[#V6$ `{xytQGUWg5, KHRsSzE2cO5ǵ.X/]fT .&[(?R@`])}pb´lL'hGPB$MiZoF:S!:.̱8 (B}&|Hzњl'L> La }'q}ӡfH du&`*,gDO/_D}/b\jDݞC(cL6 k ^kodY"9=v]PM\*om)JX,#jIP1Idj"3y9/ Y3JC` Ӏ#WSAm>38X}'b2h g7o/phD0q81A>Z[Wg1IE8\YR,o P_ӄ񩄜 u"lE!kpP&bF'H, $`Kӕ 81go9ۖ6 #,\_gnXPJTN'> 5:JG]gΓ ⽲bLNr⤷ܐ#w<Ì`7HA-Sz7r6(a aLRCYHL=4)Eqs>0- Qt"ix)QyAη!6҇}痎!>ɁzĚRL0-l)$?9{)|cHؘm0^9 Zf>Xɹ@tX=NҦc{FR:O5;y#_^͹D|($vN|yPX?`.B%,&SiiG/ƃ׫o]{Q@u^wN4/[A%)WuoDgPj,&[ O+[޺өysޖg qeЉ=`gAːѺRyd%L )3Em'N~;2U"=y)owiU %7zzye u9)Nt'?4_QH%yկaɒH ?#vNHma<);]k,=?]ܢ:/ᯂQI s*B"n !#DUZZn KT|jrOf_SF\qO0WĢ-1*$T@0E%dy5}%]AFH59ͥHGfe~ ۿz+Ye6۽ʚá$3Hm ƶZ#(()ggd|$t.wWY$mMP[`g$P, ܯE5qL3ڄ3!n^oS<$4.RF_aAHr"V`lKnҗ[Gin͹Ek桁F*n6=''K dB ^8~d x{Ds v8E$z#L4;xˬhEJWrZVYf;?H VU'Rz|4Zg[SZ&[{xq̢v1΃~HooN+'k&ǁ OY䅶xաRVeZѽqgl(OLM5EF'Y}Dфw!K]:_?bfeGSiC`kҬկBseGK?{ZڍR[~U ۇ7&^Hlf%ZFZXUs#Sk}%鳞oړBXKt=GqM{%?ZFdll5Qw~ ΚAL{ԿLZGNg`>GgRiUZCWni> . m#(ht&BXhCxwnxp辗O4B&Qږ brYPƄA @u|iˮ'a+SrSLP컍ecѝ~V![];?dߥuދs$l8Ԕ?8X[4eoj'' E.wBdi&R\, ˔_:sT\&P{"3 Q8@7Dw؄I e.iHUQIА}iFf $:B|Nt%5U#` ?o%7hEרE("ݣC Rne&(= 1=i8"#]@ -@%;5RBd?̥x 7E hSsm-(|eo\ZSƝpW;\x< boR^ t}LJNJwN72Zw&zEEQԟF IW{NP|I.7q  ͞-(a ˚R/\-}0H"Aާ- o ~w4ىK 0Y{isr5O&a5Gzp=/u_l۽#φ+KpvVkRGqϸ Qw(6KO ǞEj⣭淋&)PDNip7t'`U'B%K7 SM'H#d80[Z<~ٶaT3Ä[<M]OTœ|+†.s%dT`cGUUg| !@vz/abf3Q70NmqxRĭ{ B:iɰH5+fTFXt!++QӤKC/IVL':LFgLK'2&.3PNJ Enhozda8k'DEbR ;'^Nn!B'mXSFAAPc\yT7{ع+ƐWH^[Mcy 9dMcg"TsC#P[Fqϭ]2d`M&;wbtikf,πTW iMu.J8Eqo"µ Z2ZClncp 'Ȫ@B֓A6V'Zsm̐e.&m KRF&aGN:h.=" x "OWu#>ds-I[k``nS`zfp#<|+؏"U7mCm )\{7=(ajԧO1-%(aⵯkTX#{fV`aPǰgb5V7N9-`V,yb cR;rs0 JOR\gѮWixc!<5_!>o'_UZZV3T$TjSlLxB|<n-CrM x PXǖj[*9(6ΫNk-OkGGFbf}gj+.l%'۸` JF*yҋRe^Ջ2Zg'![USIw⛶gq@",sfUV NuQAo[is'Y>K5ʀ#ic 75V&[hAM2c$('4׮.98~՗4C5 B桋!dsxȉ`҈~:|c(k~փa p@=hR-=uɍJ]2B%ZOÞj_&bk1܄PƜ_"^FhE 59k\K<[O^m7>[Ð%`f+I4[usU% 24ރG?\Xw؁ٯl.|)Z`ɶ$ `sNٛ٨; h'Ǒ4s`'u]QqIZĆ M;R5(bh'krg7Mi45x4L52ԄDNI({SM8z3C`V^_MyiW8 U fn ?I6 BX۾s#agB&pq(pQT7XEب`3rs?)z TGdssSDK3Zh)c θۆ4Ü'%BX\> a8^yL Ѱѝ{=(u@oMTP{DSOg@Q&-䯫%⋭A_?x][3a:s7ӣT;[rl#qyI Wu٪Es3FUj$!{&!w.vc yB YIw~|zA0("á#fS 4c_Sd L{Dge +wx.XFip桶*ZqEv A^ܶtabTP{-_߂b8}MVOj#>#g)e&Up<O-#O)oo.]w'XW8iB<:TUζh]`JJ< j%i1z Ď2<eMP"_`ESQQ5ݛHo|1a:eR4?.uQ. C]t͍;*KJ[K*N!^ 41c] ù&_M| THΑF [,LVE8?gx >ZPp#/lg|q;_nN}sVƂed]4+JWSĀʫ}Kbs pT-ɓV9J9. BWݐ?S qKrCX=gIe&ryJ7^dD1qZ+qc,}/zfNO3&S-z[Zf7U+߁DC.0@\J8sl|K+9=;th)pG%+ܰι(4_pfTjq#/_wm @0:~9T!haoC;BGͣ+k.\8ԝ0Yy]zoVQwKa6Yx'f[k#'ݨ8Y#>npԴY(gpi#છO W[ {w \.c!-;(ߛl ).,sH4y;dWv0O Lcy,؟&BF" WOEZkq _ɫ`]`; 0Q)RUz%Q4ҌCkeGwk>͟K!g~=R,7xYzIG*/}HvS+KGDg 28-ayc\+M jMj#\mɖkSLйTmvP qsk&W=,;P N1Y&u(eVH?z9Um:} „2VUK4•~^I;/S,,fZei^rplD|yo\6ǫS?ұ\MlGX܈1pݜt)sy >YXip~hYT>no5-|ʱE .sfz#jΥܛ\/h?eRhRmoo%#-ɩB Uz6u]fZ8BLDei}1R9=o#:brGBildUjC, 9UwaM-ǚy{m2 tv~ o=ȔU:WJg35WdpET͊>Dq@8xlE~41"mY)VG02$+{y)Q?“Q8 v+jY䵒O9|ɘՇ6/lkRYLwmiΦLWLch cLx9ˑ3fx^[;ׁ#o~pzc4f;P_kqV,B 1@pmmqpqD,iPM@6 calгQŜ<"ec+k5kz%If%#@ 2M#if{ޯ5<8hCVN=eCB\y Ź 9Sk79&GXa? h5ONe%Md֒g$~O'$wsA)GL+_/D>~W8tPoKcL a_3`hgצ~i!6ļV>iƣuv#Ⱦ7k>Gq 뒟&Bˏ>b&HP"J)6h>*~C", t\E+ ā=ŒBJY6lJ w!G.:_άInG:o"v0#pC9>X*q5,Jeͅ`6yƀX-}d`QAzPyh`3YmV EUѝBf^+ 7ֵrϟb nj1KG.&1)-Qڛb^ZtVǓ0YgvV{ňy^24t Ҋ,3 ƒ]%d^aL oVƴaOkMKp O[Iҿw TU沽iC f̆>(N<8ȱ:X| Q n+$V7ֆjc)_5V zn.P޸® ޅfH@5Ě ]2~[}l4hJyvNOsuƤ0.V 7!.CDIгۋWm%SM-GYC@xhNyld,#ɒ:QI?Zbw!<ϵuw-L?e D9/;E!jO9+/tګҖqSSrZ 8PyR4'x_&6m?Wͳ2lv.3tKtQ*t/˥eCks%Ekeo׳t&:2QOG;6_TL豼{Ǘv)/[[K^ 헐X_d4 +%WpH.0L0IUh/ݳaDH9b S =&3@*"NGΪ2 ߔ R蠸t#PK_dڬSU_7p۰Y;a*UZ |-4UYB 73TL:9 7 `%36lKk;*ځxR'KR'^+yks*ukmNͼ"nә# 68dxPPb#dvBcx<'4i !+*/7Y#~7!.=B3h5^V-͙oiv(X9N@Ҁ$}(.cNDG_l<;LSʣҞ@z5yxr); S*sI7%EK+ލ3t4 lFSCE/}ۉlɠhb=tM3ƓLԜڤxB2@ң %fI'id ^o^B f ƃ4GsCXV~Ax#GoPZ_jT9XӼ7NgqCXܓ)y$:H4uosdb~|^_sTvo ` h(w;_2bk Tn= w7Ճ~ͥ@^%R54yB783x9 QԨ +PZm4qbŞc!OCNfOqjp; |Nۑɘt}YG>Vc6ȀU95qi;WqꮹyʑU/S?ݑ~nONjDHL endstream endobj 424 0 obj << /Length1 725 /Length2 37928 /Length3 0 /Length 38490 /Filter /FlateDecode >> stream xlct-vضmɊm۶mmضr;qU=j)=#7@E\UHCF&djbio'jb 05:̌L0d{O'Ks 1տA@&JO"SS) %%/WHڙ:]l,ƦvΦT3{'89?̜mrbB 1U @Vv.d;ZX6c?Q'X0LLKc ÿt36quoBP!lWyC[S@/ݝ,Ajhki3\ CY:[z(Z` 썜?jbog+ʿ1(+H+ ;,fglobigPqGOC'V4' |9C'K#F_-%,lM cag0p8Y8}?t]L\-?0zY7 Jo +F6wl9labptS?hķw+Jlo w25CVJReWTmk,vy'Hz5;NڱY)WEop'; *= ,p4HE7Fo@ nɰ ,*µ Dtz$1uEwܪㆷY!2܅Vt F!oyv!sdyբ⷟X}#^f54t)\f)vňaal6dV\d7'6'5P+-O 0;o΋>lvɄ3 \6M/ً@6MNdE ::*Y>̓a-nMgb[R)$E,YZ↼.T͚.}֑%/i*"=ΫFkRn雥 yU x5JʠR4 O->bNN A _*X3Z儌+(W"Wpσqaaۿ޺[g2{soW/,a@f=[ ȍ 0տLr:HK*,?NJ\AUi-5oobFFyFKI3,i!%t=ZNWE!{-c8eɥw⾦XChFSA)$6c_hw?^Zdl,㛀is:m |;mYӠuX!޲\3Rq\ۑ[a+Uǐрn!҈m~\*6TUS8YJB#NҥP,OIJ7''Vw>Q``nbjYNsa)C%_vItZΩfZYIW(9L-u+Na 7-0 'PH _K?WN踺)4ε9gU:==3~TC۸8EHZvοC=*Fe6ՂD]aP=GŧG/s۱e3-;Rvs,۟@Do1/r7~d+AoxtbZg`IVnQ OnX!z:s!(í2}K?ɳ]JlAK{S CFueI93ItͰ:쀲ElH#N1##u\phҢ39r{1i}qؗl}RƗw?'@p^prޫ:kT\]u+yhr[d7v[? km~BvA6߻9JJ=%tx&6KR?*M8jOh ^Y6U f)Z*kw9ZT+D7LE@>{Tʦ!V80o=a 1TL;xdfY/nqw􅰭Wam&MZ\xP9W&.d< G ]fV[z'L i-p R}]ޥ5;U -Äw qyya޼D/t)z"bm*xr}Y$6h-Σ8+V$B{GG4 w qM}i[)tIWTJjPպrWXi;RT $5+9P{mx :rDɛ u{V 1yNSAHT9٪WM.yuVtu TV̐MD<d4NcicyKJBqKe/(ܻNjƷZ;Y *Vt3> 89T{vvzGo?}-lYPN6q`0@cD1EW ,҂ƿj8˜n JzI]\ 5v4xc2c}=_!r|p0J٥Ù Sazr'|L$P^id0u>DdH|3?K[XEGז&}+4FN*WE0U,ֱ͑;t;pvhɜ]1bOR> 5/hFe f/گ#ǭ X) cvp"b QGzIm# -+}^B,+_${򋺈+>ƴx%IO2vS&@w[a Fz3ĎmQ%YXtU+1upԛ>bRQw >B64qi=~?7y]I \?kwɳA B*5H2 l ~n ࠀQՕ+8c نDxZw2\1-#vX?]JKVbYHH8PP=`<@̫?xt،RP7aR~2뭨>JPl~=lLDŽ`!N=NU[DCXP *4Sma-!T#?s7@6G,@0#C"k\@=a>I 0-@퓱ne=PTE|앎y4x_|$/ #DzeYT2YL$a{;/sG;;w#L#Wf+/HY*n'oRu0E5]D(NKN (0WZb1q쥶W L76[ X\KYTKUPTYHyKY'qkL]I*rSn*}%oFK *}O6*b^)CdDkPjELUFOEDl_cPzeP5oδ[2+\dZ۟[ .6@ߙ"y\_9}AHV\1\V>8' Բ[!Od]!nBJ٫l[K`p2Nj/?()G|qarw #~Jֱ^D@gUgxmmyL#7kRHt8Ξl*g2b}f].\o q/! %]NiW?Xf2;)\] I#5*8^y9%#2 %b{7]oѺ)X*67ؚėW%~acU2 >wx*yxw5p}lVhXs,Cf0Zhsh`\@=Rص 4 :*?`d)n#Yb»} xYN{n|ZOh=?GlO֙˨T,٬>M:E$FI8]mG/ VB D*mEgg2tQ On]% xиLql5L)Um))ywB55q N3JYqG>bV iӯyAx!'m`)(du*:Jb7s6pI ɢ .ZW4X]XZ#iL&i^u8:;QYߕ<͕pa<+?J޲͇eo"#n={|aYt]dq$Betbg*(,o gHقRRpVuBp 3IŰCM|22㻣]Iͧgr_bsH|~H>*-~v]Ŝ02Ƹ?MϜ;hEf3lkZ7.#[I^&f9a ݯ܌mqk,0r׿&-L],n6;;j-bpii0an heA?j0iu&yBG(>P2ވp0}Q?T6re$r M_Qc,:Ybx"3zqpTjBѲ0b'퓏Qqҫ6*h O׼y~~=W\|mSE;BQʹp%тۺGDˡū:"s@!+BpNֹ G$Ǹѥ`B߹ꂬHD h731:4z{GsQA6DY<~iC(He ;,Z.G^fOdY6G6<^;R8&)Ѥ@{CFGyhzvNuh ɨ&: g c72ɒs}^5!6pǖ)_6&I (aptJ{4~e*2<7(Pb87s9,(@R|\j^·!Lw"x1~4 %[FcC 9B Eh~Z_Ò ͦqfyh=^`@ =F)Ќ@{vynN7à .$Y+ HFt#jTі/uH!_FZJfq~+oyNPd[NeTš`ՕG?zCOZ"¿?{wgxj:: ů6?E!y?`V&)fk&D$PnN׊i;$*Y0=)]L7% BCN;+ԓGs=]!A^ yNl9*DA6gCBcZBHri,YM b?EE0hVAA\UOt ѣ<Q6"P(H&ݩn8` o7kqOI?I׳17aY9,p(/+PCϠ;S|\[\V߱ooFŖw[rƈPG 8pI>iFc R0!v% }Y Y!@ez6nʳ#hxirxXm= 880GZnjJl2D؉~9,w ;پD.>]Ut.pRdi#/oLGOb+G.\R}Ac:7PL/ٔ" -Ww}^y9#i`֬Ne9{՛3xQ-v' ϑ:qE^6T`w8 wxpP;(  0꾦z$RiDٌi()gu^(@]vQ}Oac^a[8ꞕf_Kz>(vwY_t1&%o$LZ{qWkeF@Wk-8;@TOw:`ޖA@ MYkjNDQ9PKYa_T-zRlN>d~mY{\1 PA.}U\PIzdWP;V|}^ըjHAj -h#teh8+dmQ2UyXx;VE}K*pވBoz.`w$#;Sϑ>6PO9WtFi,tA\&2)(s !< C0\#U>)H 7|9^j?UzxּC_j)ԽNqN柅)o[Z$<<*aLfbUzot9x5>V0\n*.N+,{$ R00#6ؖ28`1^?(-@&W `-UbC`ppv61 ?9 3թYuUA8SfM^Zwrt.J T$E#cF~A5A4-}@ +*Q<\"1ݞ!߅Ir QtǸFw4$uRj1[G解$ 2^09gЫud;G;!je-vH2CS1q5)ǚR |-10cj!j{4_s!>  loN\*.TgY-|=xj0c<%cxӅbzICc02kܙ$L #;WڄnN3ޅqEg i;(o9#85Oy9H~{zp&in+?I< vC)h>1%[GjT$J܅-/iF*Mv-)h>`sśsH $]W 8+Le2m %6@b`s7zN՟unX=a 8KqF"~&~V0jkѼ l*[^<ܕ;zvRQJz[˫>nkG/.Ci" _D =)T^^j)/M<;AsKҐFR:U ̟v՘hFH x +s=+ZO:v5 'rPߍoZK /6u%;^x5g^'JЮv</z ~r"ƙ虑=CAaa\^4*mF S~pkf/k>T}~f\ZAfG\GѴ"ϛ=@05<ɦ0SHWEB LwJՄҥTdUb,[:GP=WK7{lX'SQGw0Ʒi4 N]=͟* 0;IW׾λiڱ"u ;b0u[ ׫d%k\_2U((W8J>$#T) |io%A/{rk4 B湑"Uv ٨EK?'lE">?UviQ$) m2? ;ܐPA?oֈ P-</kH9kBK; ^5< <:FܝBӼ|ooyҺ)2tD&.O hE+]gE^_Q9*}*V} ̟bJ.*dpKfI{L.Уvm5dYzleڵ_"V0[ }+w? 12jܕbC^=͸Ħ 0*n%ģ dojD63GB),kGՆ5CD$7ql]w70[:G GTH}JoY`3'nK^e~.xPIa"{(z~/Sq [>DӴHDT޻kRsz!N:6bqq<,wO`w Lǭ;?@q:'I 6.$Όm8"l?~ҚW9: yW&>.eUShלP8gJH3t/nvLaAHEMa^ p7Rar~ŒUni86 Kw( =To]MQni%cr" 1:i؋h B}h 6|SEC@8_1DQ?"(n| #*`iyN:X=]bg`n1n^Og_^R/RoJClQC?##օeCqKI[7r>̿IɈۉm~&<R>;nMegc" ZI Qy jt,-Rnmm Mק<+#g+)8(Y vv|6{ҌAF)WP! 7B *݅"㸈_gXLp w:ckq95UZ/.L?=S. | R@cm}-̇ks !gCV78UdLRtBkס7sB/7`/U[Qd!]<a>My|1yzJm |_<1ko+,4(XX!T)rfJȹ@'zÄlWG[7RʥI@]g%Gm-.Q]5 v54Xۄ{(OK]a :i)Նgv|+ux/+3E8/?@Ovc1Px`& ~%:W.˲^ff0 \c}.pD3%ݺחr ;>xQ2?R\R5\ [دgn FXUOJ|@e縮"48,Dž9Nom Ѫ=-)YtW2Uvk 1a'(f֨]Ɋ-vݽBj[[ߣtb umdIнmʠ5cv\6,jӈ0fXGf >X{)(j~^\S?m d'vn,kC!LS ~#\Uc]_vW{q%j"]2Bw.z'YrB: VƱ;ug4'.Bt>8vjcҺvܝ[>1+1l#oed%.)WG{ʓi#yAlDGfR}̘(rX@zkX6A/}6#NZq«`G7^͸JBbVgOx6a0ÞWc.2(^fȽ㌴Xbq^fC 0i8~L2[X,a BE+I_d MWJg #[ʸyczkǷ[P︙-笽t6Y˥^_!lXBF sgA3~?@&Ύ~M?\FnLľ_?_ }PPvP;dʻ) O]m~|)2`"Q}$"Σٳ.Y/KN97N7 zzE2iGX}@/8bCxOY l<.o-_DW9Љ/lHٛ>E@0@-yL9Gu8@D=& S.GbƆN15=j2B[uwv-."ӹUX`!nдus10Y,=.BnqCL.l8<BZp}!-dohlC['\wì f{27} Q–bREBPZAiBGԀG)"6;cngC8Bn7).6FwSǒPmΕTd]e|{bb( b; *7*(xEu!UU(YK)܉p0lcib3}fb.$k|AjtqH]謬٩~syDWcXAJ`i:Jb~ 03*)K"כ*?nOoA8s8̵hص-߁ę!;Kxbtb_䃭,,Ğ`KXGáB23#7כ] ױ coF‡%L =C$^e:j޻؂B0\t!B%\9Uc.8]z.{k¿xȮHX#IRεmQ.5ˊcekaDl'XU~ 0Xѷ{?[XnC͉¡t0l< 7oLqllq!Џ Fv۰iـeZdV?Ij20'xA(?>BY0U 8Ԕ2w8ʠR1A#l2>PP}+Pmߠ N@TTNF@!`@JOG.r. 2w]#<4>Bf>zv\Aŏ4R#rIÇR-ZAq 8"pj"Hl\#Nַ$3`([F^98(3n#R#m5Zp7l(LM gzuDԗYHdFHף8.8?qQ|I;nG&Uia[B&(zU qgiL8#r9?\?uχ_]DEp<œ1]cW@P&= kTj3GYX_R.i~3I{I~C>n² }K`Sx9&NtL3Tx`XDqX%LNb޼EřJAd°W"A#W$f:T.&f JIϧ;ɕBG8@}VtJn G%1:vnX(ž;AL;0UC7A]H]RXp,9G O:𜃝+>ٰ M`0J4 g}~^)QZH],%8T-0VQ\睢˭5G.<9k(p!fRLuTxX8L|9s8WNDWCy@PXA3PW7 J = fO8έOW&A$4ִzv2́h:'! MkUe'Id6c:sٓE+P?K?nL810Euh٫Zk zyxՋTrZZvIR؄Y-p*qh2H+Dɒ@N:=roo0d'O1apzW=yuBB@fBrJϟ]HGW+gtܥ!{$T(.JEsVIy 7 Xa\ qZ8W[ۮ&xͼbGUdg8:QpqN[Z-۶me۶m۶m۶mv=wtd%k.vs5]hN.A;` ;]i#yڌ\#-Zyz2n8 'XHx)Çy22 iMqls=,'V/](b?7/ Z ޽Ûq)Cu./LhAjE%g m8CpdV0I\h+92G ?w\ϯrwӢprxF2"wHhVAsK!!ք:!.7"ɀf0 't- FDWJF| )C +e}㙜SG,8&skx,QD `BT"0 D< Sxm)YY*e Q]e Q/>^Dee}ڍR2BI{q1UQC/$ƴn1pRb*V1x"AHR ɃzAj8 B^aE∝Ȣ)n/8  #)ezdYd |4dc&s3qDYy𙸢3kvQ T\gm(z4Kfh9j=1{x*_OByيN =| m/XJ𲫷YFa*UNzj? eА]sҡM پ/2& Y_-.ZGGEc@RRXns)OF0*k]4 8fqPHM)CYz#}W!fy7k,eʻ? vHḯ;7 ւ*ܐ^`VIJJguuf~+?g&I#g;^)wnWkR#}N1;ymfvS>|!L| 64:44BknK5N&^ QFYT)23~aef<&5̝3,v{SgZ7Z|Isv-<gIq@hYрL3*:oEэ(j*v0cp;(yv㠒<-2Ϧ @;ojr992/.ߦa;=&wIoZ SZF%mĜ[DU \ESr %7`>6 % '@q2pbs'\fBV'hH \P ,H~YoZ?Q2~^s"4[uf<5ޕ#\*G_񓱏`,[Mo;MZV,r%Ǭ,OrYNCV_-x9`5*ZLNaWH-Ht16mEL5~&޿2¦C,frq׸{Z]Zy% ivYۮCOJe HԠ Q#X5ShcHX.:p=Z_^Q{Ԅy / =h/ܪ;{~#\C!Җ67FG(`KZTN! JCoΟ,mB;+]"8͙()>?AX8X}3#?mwAuiLwOSLxHדP-1mBz(%.Њc?o;[\#Wzl6Kz覓PDeY`&hҙcޝW onZ4ʏ1oeM*5. `N6t6QC]w>Qϛ{0/I@{zHc. ޽{cx#3ħs rg?7v<+GACRe\wG*/@A%zTG~=zQ.k}1ZŹpH<\~\e|F̌b4v `19겋im9 y♴}̼%[=Ow%]*l;]%dK JN:rV[v :USΛ[LAL&Dۆx#TvPz{YU@l%M`8K?um0%Ŀdf|c6$CT?V]\8*ߘzpS)'hĠ#U*Ԃ&*OP@|KF;ol]jdoF8ɟO7JHΰ40g7k+RO7 aCb,GȝbUF9DM'qЯEh]xl܆Vȉޏ7x1J=WCW ߥ tӛ]&m@: SO'3A%jQ'X,aퟩQ?IJ"sUY+4eR`XM]r%U { _><*7ŁC SU.ʳi?g5~ߙbWŋrKWQ/`3dvD8)/j0 K^yo ^#W~<\PGIͮEs `!>,l_:ص_@"f]t ÄshHy OT7;^OF*L:)) 4LQUb1}Y~ P:?W-nu6H//;O5\Isanx,ʹz8  <[0_\O6=g , [s!4(.# Q>-7usOEn$ܒMp+T_ʬI$KF}@ҥţRzQG{4x)jxkk ٗU *uv*OS ;yCr/ۗgJիױn[]se .^'df,7A a|:bO^`貒Nb>2+ !x::Gu̸ݲ;3MkB\7?ş>pGIFXw=JS3>'> J*v08i &;Aj PVdLgp>-df㥿Hd*"M \vqB7Q%'{eׅpfDgڙ)'IpHʑy:+gʊ*<4ײ].G@ۯEpaB.{atmpV:pU|V*$ 3TsqBU*~j1FpF)2MBsr>hS>,6۽nEmnW[V"H)9ʭҮrT[@6אRUQ1fx\&T:2SWL{f#g8FoM$>~^;F$hc8zគ.@wP/Kz)";Tɦ5zX-FVpʄT|rXkу%ԍfdE Q5GDKA:7IъqSPXY@ J`7# {Sdķ gX]l`&t=W-ԔVJ)|4EFH0i >SKͮ$^Y%2Z2.F ŷQw7"dq3@BkؠT\`@/uoxDfH)YLlpD1_jpsNүiJo9L"4 Q @5oLoܥ]V ,PI8WW'/E黹[/{u1?bȱvK֏7 v;IWpS<#"έykk_8b0i HFx *Iwq 67{Ee8ufѝu{}-'IF-:,=)5?bdO=:c˴j(_=W Aj":u(gol- vD =7#RY8^,H9xgϱ1mχj:B}:vXAL%ONL$ 22ÈRpv8֗ k"N=AgK] X;Ռ]jw(x~V(CG ( k-Еe}'\*ᝳ =?4v/#$ep4f9)dǫ+.B|L%a~3FQ7U\)_4Ucݍb>o:Qe5KN82NUqdzYC)Z6(oJǗIt ˊ@ Oȑc1hu$kN|љu|Lvڶ%3r+ 0fٰWU*O]wCsRS-N2ɼ/' M /8wJBh359F+ɺJenɓ^ĦyK9zNӀDδ뢡#3kҎ` MU; EUNFyewsxȊOωI6}c383 P (Fis)#t[ R\5 Faj׸( ~c" ЦVZso{z4xK'Q_Y&]?Ct8UYw[J[hFV&%'[@a%Jzw) 'J%O|ԄϹ&oeX*ԗ1@RNLݓt@!]rnwz/ VV둘f,^^㛙Ft{wQ6ZRl`HRvěoӖbT&xO dKƹ66ϖBU76@L*U AhL濌u:iY@:Jn8 ̾x5f8Vrswf-ΨYN4;6[lqpqYGs̾bz;-ϳn@#1wjliT14ErɐHM2ÈI{x`vӹ@UB@aωMpv9(PIr,3=]T*\o;oSED ϥΟf=SYħ}ҙ=c9H7S6~Cִ [,$Dֳå_17KN \R<{MY֪x$ Wx8B{[fŊ_vqzɇ?Oqs,+ϣ>&7o;=r4WIpB@v MtB̢;dvyNBk */V%1ۅ)+ܔ=jYIM{ޛ3Pgjr<,}Ӫ"~_8!g-JK+y{&W55^fN2BCo~"M}-u6*S7hqloɇ T/Ġ`ΛVarqI!ܛRa =:e_UfBο}jh.n`MOcOQP,0w qߣ?'cғ@ViO` ߏӔrB?g8\ O$e =T{υW(>]vpc6\&4i8WnJp ŚẉM_@hU/"}ˆjSaJ|]ǧ*>a $QRy(74۳.QseOZ&-C#:)&9Vt)Rz"rGwnZ4؊i*2.V8Z1xből`T ˍ{)eX+M-ֲaAm0)6J^5bǹ(ItDi"6EH[z":i5?*,] GEgֽ:r4#"|w8&+r|IbOPD.d\Y߬ m(oI 9'fW$mGI6= StPtH,_(/S|m#Ҹ% b7WxBJ ipMoP(]gIB9И@Ъ0;CS  [i`RnsJb?Ed_Z7'j!)4Zw`}k58)jibkLٻǪFN V`c g삧%:th&p c N|]lau]Q=Zfš9d TfًHnpe;+3*fƥ/d'D[:v3wTQ5%n#r$ƥ*rXBltܛRTr_&Qpq wPasܱZ͋8Fԧ4숵% IW0~7yyAjBP 嚥,o"3}V>>;}X]~*ܙqDz $ _7#BH~'nߧC /h~H6a]H;mϝ<%ᗉo4!NS[%FnW b@lm.b*>cz_lw:eThَS䚇BO>S[D*}q,$U&.n&v@Z:T nԿl>BR,hY=?J3Џ|~:0(e8|5ٙ?"h@xr1ܬP?釹ĊPzGٝ5_(i4U1Aԣy'P_Lbf }i)hW,6I_/yv,A܍ ŀX0sy+Jpx+f) Be|Gk:kܔV{^[o!FxEKK"^ jJ:Pa4Y%U%Bϟ.;1n9O՚vXprX|Q */TG1 }Ξ}!:GyX'_fE7bTcM!ZQܨT'ȱ]5:V͐#IЗٸK#._H=BkmЉUj:ʹ@w ӥ`|)ϗAj nCR:ZLQfLWDCTv+K3$.J|NNCb4GyC/'0h:MC]ۈϬ 3ܔ=g+M'̂_o mxRCӕ;ʣueYY`[hQCS"5kn a2L_(DI,<8~ܟ EjC^V̅—)=2چsIxE4DzG)!aJS<3lPؖO> ߮ ؑI#CtR3:a4J,õ'e!=" U4X񀝙j\S H^wQodHJ"6K[h<.*#T96W#qLDҋZZ-iZDc% C1\rO QHG "P~#{Yf,Si$YH;qEuTuf{ RpR )侒͑|a}䓗K:1 B@՜\{.{S=Tp|uٞTwIgp'}uaJ_Ϋ$/2v6A Ҫ;]AJ%BҜt*/Ӊ{-U~\ocy3E%DS.UaۤLǧ^]&8OL%!6d=H rIzu&qٽDAs$GVrU2hAny/@]D2C@S4.^峛O2ds4_({v(,)m l &z&@@znxޣ>c0m75I^{:J6]bm-1f*3pf%iaY*z;.CXmSvXvbրjU.ѩ]pNǁW5mZӼWDK 㳛 &[Sc9L??[;;b4+"1QH|ɕrK@w Դ z0sbA"R8It'{j R Ni4ObCwRG׷,rʣ{"}rvozJE1^ f!rfDI;6'%{Hώv@_ro#z)n@J&հ>P(t}Bb=T+?%K芖n07So&{EEXptd[}.Ƭ,NKL Z^45磌oA5Nt0OL|x]id_{"e/Nrm^(.)~e@'FE.w%+Q&W9^C۽yNSa bzobC`?^_{CuU9VMHva*'`w(7O'ۿ]^8畭ء#Ը+w4uV-nlsxŞ? 9Yj."?Z `]9Vi]Z+kԫ&$%, /Ц@Q_e*6`= ]b-4R5iTIESAiA57u]W#{2қ|LatOX,;)J|ǖG6);!vgPo,6`kqH 4/{gbY) QDQgٯт<4+a-Ș !Ь=%"%sx rfD@ LKXUW;Dl~˧t^㽋$T T{, TnQVpێ ggv xvgk y8L/gvjLڭXP3J tAuJՠkqd:;P@fT mm}""Ɉ;VE~ uWnD_.3B}tu3.uhP8.W#9PC )$PN]}x{QgCUחg;<oW:QeHX~J`>:h.e~d!GA'cq2c:%H2lfnUr2f{JmwX`KZM2EP%?^G\z۝ B. A|0leUNBgieYx(Qs4Hgz0|߄U'ׄk&Je_uA7L-0L4;P/6ؖݢ:4Ex"iX[GZYoR 3*JJEg )؍&%"-` ;L n*dBp<4GVS 9:C䲛4\U [Ɋ"z^/āg x@vSK/k]yǡZY1(TX|9Qg.kfA&χ`]<$㚋jXlY1㚸 S<3}fk `!/18 p#V {wqOYp]s=9| pE`59-WӰ@Đ7(t a=Nd*?4uo~N"c40?&iC'`R )Sq8<}9Q;$ ^F\-Z<"34 $gV98ؓ091ܼE0~uM.F3aAՄK 19]]:"+|1Z1΢.أ/]-C8&THY YwNū#S#]OIO EZ_ "}@~ Pb׺W]]wi坉KS!cՍ9ja^U ^[gh K"Ⓕ vk)5O4;{=&gB>=F='Wv@N:`_vK: a<.#3ixVlf RO0g߼#&=VAK%vZjV@X÷ڳ!I*WLZQ|-g;%_uUc4׺"~oMG:u TψIdA'ZmFӄ,o<€ordu$ߪ1DϟLՏH[{J\=;^|ֹ9@& v3wzؼ`"3*F?G2 [kNzqsZ%,S+K/;;QLL#J‡ՁFwCk`*M-SBa~Y@ƒe9 Wv mevi]1W͓TMsK@@[c'j ex-' pH8;İrxK)x 4lJ/zTa3-A6('Un#TH{ގkvo W_&1بe?vG/3C~@@ED0ŸK@.ضK*ٵXrTne׿ (϶WjM 뻙3sS4%O*aa?xf*u ٝ|XO'Prۄ:HU@iqkwC{ql9Dq+dO8x~QO& %۸hGkg/3 cdοGu| ă ~?z ?DE4yQFщKg|vt92ET++ /C}S^.RJ:h4(a_C/[`ѻqoE;ԋ+9W=azP f떸2oTh9BQxa%B)2hX-v0.,,X@p؁h)꼬a1/ Wl}O(q("9 ma,S0jjKgG$pW5Dv|cd<OgJ旘Hj+,g()«鉇2ڟ=K맃kYJh2E={CtV[UixAt:( g'՘`TVUj! u4$7i]ҋ3vh@52uu F0s{SiξI׉J6 ҉ܜH4،6T>,sML=QBRNg%ʄslzrIzdMb{ ^(rzUi5>Ŗ hy2ݦcjn#yBw'.j|UB\%WK8<&)D?1XWq'͑w4 @(n+>@T~A0~H~{i؟C^}1X(/)Ti~Nl2ׄ/},'OȐs)oG-,rY拞C -k+TֳNɷN9? 1r/By;|' `8%W(TUM9oAiǏEagƂKdx5S_O^,RͰek({@uuf7$#r9~j6iezG|johT/Hﰓa mQTy0J6au'p9Mq! *ޖ2 3Ezg)Oz)~u/Rm XROLV2 noneS ."tU%3KUO "'bAT/IzsRN!Y]s{8sZO# Z,ldjzK|:\룚},wou_+IPwq YNH8}ti0^-d;j.VU%ǣzU(9kok@+Ȓ(~ ݋+oO43-P=JT LTwq zXrբ65ɾѫ$I 6%`0t~VB6 lqCڱ!AkG7"U/}'b^>FBQndqt%wG= qu⟇ 3UOWgA͜HUµrrPg`L^S,VйaJxt5Js#:Wf^o 5`bdo# 6su[Mkk<*0&* P%F| ,0\Oѳ[{d { !8rŧ(9+|5xKknb uWTvuVvETlcjWXL=G>t+b֐'aTNp!l;Ȕvlo۳p,>w'-mGj~CyhQmGHŎ-Y;{+(hX\j-t$>֩Ê5k%[?0 h'ޠf0v<Yܱ pW f0˭EN-'᭬c\|02$ i7yvuSD  N]oUQ"- Xb$BJf*l(].iˆJkX$RȜ޼k=2Dxn`WZ%䆸?#pB$X".N1.) ϥgG8Wb7Q0)_ܮ]js9VT5욓qoMk)iߤU.ѻie*ĖqS?LVƏVn]8)aO6o® &2Rpjak|%$S!."KJs6"<kP7q虽+W[%Q-umf4i~.F)Ri{E ߱^P4W m8q{|l $5!"|L>-U֠bW wJ XL$M%O;XIw譋 7!ixb=2&Q,haP+Ja!֙{ސoNIv^PH)fsBS}kt [AZ< i<1ih:Q4gUma]!cB(,b#I:`~ӱ8vkId#t5b!K,6sZP$-J䥋5&=,wDL+peiuͱo~ۄRnb! [S3zċ6A xʜt@kf'K9LyP3/ѿaDF7O}YgQ5*,|Âms5?enk:]nf{'8\ ? i?M2~{6LNfte *SU# (QL,b!s/)czeUf]Y)oGubJ#=2FfÚ 7l'39+f DyFghA( \Ko .G6pp%)1{({,qڍe~^K\{qJBMOtt]n@rhU?s?e-N,s)$e/#fE03C &Ԅ{NI VgD FI{9% 099Yə5^R5ZP7>t/Y$eHl<Ȩ4u#k,26OPOD R%x3ђ:";|&{~{_@o?&t}\Svw rdHBx %0 u{|Xg`l_oEeZoeL*FC$`"qp!7Y^RәEel @ďj5^X1ލr /R9GߨɥBf:T)=Zꚢ.$f2ija1) cqV' lsdl=ܓ0'/WFꅥoq4a=!D+e2NbU'NnrM4qlUi͇un&\,~2 !6`l[fQ|FtS 2Aeeuy%OմXJqΥfu8é]Tl3 'dzb{ɇ/+ؿ@-ӚH֞PG&U~@ Dg>reY\C R29]()jN i]zI`C <߲2nIS?ح8B88Eݵ̟~-~ gL"Hī-cX뜱)MVCK]HfF^#S67#i.93trm1Z:zVUb{kn|?dum ԨnX1cRjZLZB ã$wڡ;^cW y`9 zHmV_z!q|^v(<|`gb(W2Bs֝# Jy}0t-O]"J=NW3 V6% y)#K̗8D;OGdW9gPZR*EU:MO/SZ !ȳ=kt&' L,̭<&3bޤM+ <֓I@c=vĸsj#SAE\^<@k}8gXWk;[)y69iˊL7f0AzʻSMJھZ> stream xlcfͶ-\Bmq |3DZȲW| Xvg(Ě!6 X5KkDߺ4a ^-oqRm=P x 1az?9//fA".NܴQG e8z]7<u^ Ƨ)N5FRh$cYx dJgM kP"7*߰-E6N ZDLj fH'GAf-콖wb RݩپW8} V$ uിvpUas;2! I"j%)Q!ٓ i Iu}G|ׂ9ѽi6 *si\f1ƖJ.%VLa]6zoSެ7}+.mu*/ΓZsTWivņ0&]$IH} 3e#]t {>n96.(&WFl듇C qxxj!e:mҁ]HUU7huA$- /NBaO mZ1D^,4dS{8JHTU^8b}rc,)3:#7edSdٴZƵ梅p)Q$K{NFҟ>.V^UyhvE+S+0!6PtW4p 3F5^U[B=Ǵ%ۇD(cϲieЙ ,jNQYq7Q|2y:q^L OkTMPpJy$9;Ǎgl;mq htD=NJ1քz[a^ڇD_sQrgN*iO:Օɘ3-XEKino5Cazhڲp~{g&Oz^Z權*fTU,T ׺;rHeJɍ#2@:9\8|u`OF^5ʯF-ucvfqICmQfYz(4_gz w.!zH']2izu¨y8JVCMfoOȢCXrww-uF[Ԍ vJ\na4u'yH` /?[KݟBpĤ ߇C)I2CJI{8OU-qMD!Q<ˏ 6\2jScg 44`]ms<W(ZShӚb${ISZ~3gRB_H6Э\t>?lMJ] P]%EhLV[%.RKӆnįJUP+t]Wi/YllrݐgDŽlLuj `v #*urʳU[|! ;.-ٳɴWF.#=EW@ h <7묄Id&{Fr9n8ҀlDŽ0ux'2?!"*[QwQw>_ƌ%cAkMdAul_j!Yb JqXα|6W#cGfR`N^,Z>3{c-xF.V#h*tnI=HjQďqp厺KE@ʗ1A>u#Kʔo˴pW,nQ7)0(I䒶З~8*)(xo9 ׋~Y&}jq5%QkTK*h }svc "UלNa09>w[>|<*;nFԦn (y{4el_RJ(w-֔yRD\CcBNfb@RGnJu0F:U\r$7Jgg5;p6S ׁaj+U$:e ug+wy7B"jK ֧LAX!9K2F ~_G7jۿ?N;-T%t,M'W ԰ Ury .׳v >4ڜ 4^$^Lou/1 f#C~P}X+vLB{y ylqx󔅘5MD0㉶:1t’pFLb}\h٥^NcM A`93X -)*bq"Ke(7@"3E:v65ᇄPXiqIn)|Oo@AbZ pO٬%^4y% J[e];{^j-W[ o4eg:ygaKz1UآX?60ƋsJĩuyu!'/Q9ܝjM6^T3%N&A%=!k֮vNP'aa6 ٪.hJ C69rzF숳>FJhF7tvc.~5nMBhnqNuVLj̣(hm@C&ˆ\C͵W&P`wB܌(-[VI?E, nZ *kc82}/εf1m'yêR0n'р53j. y]bI)p7IGkźŀ ]A; %"`haZ& gAjG M~L ']Z y4pbp/ԓ^Fnۻ+W|/n8d+m u+AsD?5x>6h\/"FwԸ\*q' N)Lu^SGi'&AvUZu)K S &4ZnD$X Ykftd8 Kd+yu%>usp^"" XR5OjF>ho4w%Ǿ?V!X *}ǁkQgCڣ/? e\.FQ($|n"Fq~]*0%ÖiR3D*ʩ4VZg{mICoOE-g>i> ~a=0)C`?6j"y(Wk -j?!ODaCT=?U~-QQ:{hIW*Nl-GM}??s2PSШ02[[bv\Dj r: غUS 8"ɕũ6؁$hkfy2'7!qϽ+A?3g_lH "'h΃<jDql.QT:* & g-]<k5a.2眖{z}ە]۹ȁE\"!Ik+Py!9ꝸ}~S"^>ۓKQD!qYd'$Y>qj;[1̐/mhJ;E8{DsDGr< 7vF<T"jj;!?!m?xaCrV5\ʔ,*l7Ax&9(w{g,>SRijHWv^Ĉo,WHPH+X矗 Űjn2Lݘ?Wx#l&9rF ]1[bSu٭M;pxT0(2鰻y/ckv,6Id**tK"N`&6ptD,bP~я?x[@={;H}Cte1UzƩ*j/>K2ntG09`Di0 P4f2ODxCƒ,5D ' @{y%|f vl3$y#2FI-% Hy鳑 Y>Ѻ2 x aR<声!rWk GNqƆ4gćYAOtČRaD t{$,'6|K}\ `渰/x}8eM JDВPM&WfZzDO9QRYreMZ{fW S镩%qᏢG?;@p٢,╢kW#!ZxI&Di򶍷 ] O9DH;?c#:,yS-ric̰1^?E3B' FXf{t)s&0龾M#o1Η ~aC݄B}:zl?cR1$]S=V;u*~kځK ^􋹹AnfS+l'0UbhV>I_t^ o4Jhҡy ;xm5B ۥeoV+2W0N>ULD̏zWBa87ֲ+-G;Gn&JJo(ΗygJޱl]/J-) ]hH\)}dJVkȔ㧔 1"REwrYM]g?KV8h+wv˲dٿW)7 HfW^!M(BW-E9U,mLX%d; Nx-Dwt\ڱ۳9 (+7HMuPR xcn*} k:.y;M$ Ҕ,W1ml-%O &^:m6B#.kWx-8tLO cMGx3N70׎nGeO=uϐȋ,)pZ`J,ii29u9L4),^ߥd,T(}pM;6s+ء߸W ;aex+7y~ h);9E5{ucٷzLRHw`}M:2Cnjzr {I :Vbl)jl@MDC^?Hf8R$SnЋ^#"-E0G.՘I@!4Dkq>,@rBt$3!nri[Op ~H eu(oF:4}gkYt Z=0P4Z(#p0o] j 5KlUd HN 0FiWQsvVvdU taXx0`F#mfRs̼(=).f#U06 *\Y߶H@Xt8)b(ma,:<-!y1!1dqK'av}'֙RWzoQPaiTvS&'.I{*dMI[[-,CWEMm$6(biO62^-28V"QFdH"-x*[^WӒH~>= 7h;g6yh[ ؜!|tn1-d) >Ab2m|uV#Kj+N4''i/VǣDg_ͮ&2%1yoh!SpEYYΐǕ4u%Ң[|=CkhmJiG 1gg*i>-æe[(BA[KR8JV&@lW_^iSlȘDnW2#/SA| tE :+hc" ,@vf~nꎇ.W95d͈WU>e1>0o[䱫bJL>b؞\d{;||sG.?!r8윖c \m{(\镳yB pB"sHI+SvĎNׄXxN脥MqaQgwL9./Nvl1ޤRDQxW%K0+m_[L.)D)-sIq)ث}OrW~2O_ΟB#>u0{Xcm2{%\Stlj׻ksc@"[%k D,ᇞpg̎SVlaGy9^V1YG[^.rI`j~Bd?'Q:35sHҧ`7XUaНj=J8Mo±YUgxq; j e/J0_C!帟<7ktKzVⳲW0Rzv=.CecxXvv-66.Q=̿&Aɤ#څ}¡4q3q(aсW5I kh\h_FC>S,HsNO~b}Um-ؙ 4*7밀fZ3C?|3늾KaOO ٟGLWVj{̋{OAW]to$.5 O *=u`Q.l9j DB(] Λ_je|"$s:IqNz$ eU+9nAGXg=BߖLOFWVgMJbő~KAz[G 1{z0Y]~FwLBQ ;oޙz`B:s/2{:*%xiAa[Y<-r <wg-ʵ%b_Cwa)&i/C=^~?!>jG~bwd}aѤ k3^Ђml:{kT$AOA G /LO%g+Z/[3@ؑLiD: '_ȵ%y2e >+UNbS܉$% Wv$I탴 Rև$r+RǖW^ S]2t1G+&H4D>Z98{T ƻ*X2Qw9yo Ҳu͸\ۢ:޹A|{U{_0:HF#1YK+$2b+Q)|Mۼgdo՜ŵ7Q+`+[n Ij!N6&)D_x #;ix3bzXs(_ǃ\= @8 "f x40c^ʷ@cCeEsFCAŞuqO&ڱG(Zv  ςeznn,5[U?R a*b! QgJ+M<K-8M:#aHp@\`6g[ɒQIbJ' _}乶0AltS=ق\sM'6z^UpA2nÞY"c*%+_/eq1–m|:\nq147(5[vp,08`VTZY/+-)a55ç#g N5k;ʣ[)>J`U+U%u Ŋ0<B=jw_-2產9NezԄ _&)&{<T-&ZWY_<9DR /MRpuNJo.;R/1Lm@iS"`8ֱ埊>Md6Bw痮Gm\~|n c =xֽ4⁶ڱ0OAqDf/$ayS{s7f>wf ['{$t(Xqç˖yŰRHͿiDPeVA &*+Ά>Ȉ?g[ǚ٠:`O1qdd{3Fh _DMk {vګ'*n<2{|lSӬb'ʀ23 |ƸB07.f:ȗ#cl$%#V߮01'Eg&Цj` ,qqzQ"Z e@M>fZۈ("1UDҒNYy#/X8ڄfx%,,&jNTq6{u'0}Tq7VNraCC[lAu;#'޽Tlk'|vxT7u!%1{!γDf~{ D[*8,``vB+({Vٌ)%yv~Ǵ]\)bmَ3z"e[ uԒp4u!9uK%4ؑ䋩g?7#85{!8{BnDy ɜ*O17.54D.x`w_1}b6 aIgh)`^191^׵[J8ߪuD\,7F0L vlbA%(̎1Yr&G gc#+@1δiY{g9u<-&nB_8+fb:|AT0%K<^/7 Up>c/\> prlP[ZPvWΑ$y-VO|a I, r2s>aŕBuoR ԰E";,+#DM WR;Yl|,z/[>2VcH&@u=";<9c K\Zԣщmhk`Q5ܑX9ՅN > 4-W:lxlX{2 5o((&x;ԌtOu|qhM~d槫-zVDwTc(xm'bp,R(Mt§?{ΔfC,(~td|M(ĭ.GåD0Q>n2%t} qL$#@J|l0Li(]WFe>j5њO}S_Y0vd6]$Iol\c)cN 5z'4 4L%O.%oP9ȊE=T,OZ Ehl).y4?#h2 x6tFu1oj1&㴙TtPk.UZs}G9)gz-.XU k"1i̛ƥV̨ =|]˼MPnW)@BO#jxvaڒuXÝDR?Ö@:rGH;i@TDֆy Wrc\]ه!%XzB|'YQǴ ?/N~d[Wy-zK VٺfŘΦɭ]yWw#v vR3`mt4|lbc B1jC z75Jq1H͝`/Eb#IB!s}N=o5QHS}ޒutc,- ]CyV6 v-(Srr͕ͳ,4Yi He$(-*-n)P-[@ݴ"*urFcj/3c'yjw9`9Oh͘w>I_/ (Ceޜ1g8S`^~o葒{f l'Zͅ_d ].̝@%K-TT0-6Ќ˧w@5,xj- ):SG?^&!ENu t)1hklXʞZ3 v$ckDX#dDC/q`L 򿣳0OpAqmzkwe-SqC$@j5cZV X/G=hL?SUc$)R( y;@P3>AP c *<*U`q#v9Lh%ŀꠦ_05ȥ"I5hfb5QTLmvqosJt04i}Vh4e2A^%+]C56+m˰lB_laWwY.,.{YlAL{4{HT1nB1)+VȬDmKj]I} L8K4QWX 렊CkV'v_Jtq@Bk.YnX8gK q+o1hnd9HW[7SW{Ꟙ"~rN Lp`k~V^B$VpD vLem Dkș^q  gA W+逤! zB_gtxDX0T˘6%"qLo5jW ֪N[Qj8jD|FYP E{Pذu2l_“ Qr(H; {B;k./1dЁ ~ۿl(>ƲZ?>%FaػD ❰%[z iۻ!1TcjyM2D#qlN`t/d*D@`DL{nɄ}SV1XeH,ܼ$7 $^P,ALU0Di鏾zJV(X-qv@d?A@O\\({wTŶ~ʵ6`v)ȋ`سyRF1iSchm >*NvVR #ZfmQ;˚[q{xU})XpW8K ۈTY sɟvO3@RMhH/8V#H׎8Xi)|WjvMǦ?T;"J>.YFju Ųv)R7Vyj,BM{VLG?YBN#w;p ^}go{Q'L/@۰Zāeeh5]@z]%| kgI+.7]|_M)5# t#=i>f )z?BAAhɱ&{uu;:#iE²KN*G✂jh֒S4-ԺzXQY~ ӬT%w,W^YH_X~fFќ9@ԼӜyn%P|!,mD>5)f"4'nwF3Bn__A.cSxl9㽆{&^w"O U@#XnڶnRHߠ"f=@?e ~ $*>Af rt4YW)KjLe L`)v-WvGFc܌+Id B%؜|#6?ܰlăryiGdpn4l?xrԳhX-{oM?UtuHАMWEQ.:tI ]X`@ZY?nsW1fc u;cgo`@9sgHGJ)J YlKD'%ێ((ڪd叶]p=K0-<ᝒl!xхҤZܩ\;;uK1 <μ| !/2);Tнe$خ'7RInҦ=le\o0ML(.!dX+YX"j  X d,Tñ/Dez>"wZ&N!WIjhBp@ZuڂJ50E 0/.8V!9cKn)GV_zuXќ~h:͋)zZ5 ^B?U$.ї<̘Nv"\kRS ZB9)z 炮YOwF J}4Z'Y),1&X U`'Z^,=rbiȴ_$*u (k6(j l cP4-e4 p5{e, !v?tBtmM{ב1 Cjz& abAxn5%PՁeLaY Kpv-$/ڹ=3K7SFLq\T_:; 7]^0q+$r7b,y0GgGV0{>³%JFs "WǩL-~4}(z9W<c1?ʼ+(hq8~]stϚr]g+?A68'N|- bE!vOҽo+q2WLV KrgJė<Gzv>o݌W&!a,2TN$.2? 6tA25pQ h͂ rq] ͝cp.*R[S4M{8ut'W0?=|'X:mT:xnţ^ϡ8=u:/HxnpMdSdtX#k{Ar- `(H8o(u;͗g'|㬵Z:aѰT tK%R3":ګ .JᄁE6 Ku}P}/cU&}QmC'_ar]7kwɬ}!%M*mHwJX Q&ȩvX ZD\ѻ`uTv]u+ mR׿XQǮ _S9%1 |]XCe@u)UpA!П6v5v^h^ژ=m/ް1BJ鑰?6 m)ikbOS"9$o!Fc(@zdE6=cVjI:t龰LMW 6POM;{\VɳRZqQQ;bCSJ}|JLe綖_/x iyI6$@^ I ɀT /=O2:qXw|՞ *jP_Ɗ+G$t!znQb|&V|^?LMNSmq8_tWw̒F1BR³WsTxF/na w+5r=FREMKUcVU"bPW\Rc>'2afla@uC;>"G$"x>UCnȫ,>Sok$t"l Ӂ)l?,B6DVGǾӖoLgAF!0R0zKe ^ȜĐl}G;-P {Tu]/+uq/Y܎K%K2HUm~}~sAxX?Ր?&rZ Mkz5I;́(>'p],1i`x^cnN,7j~hPQ'c Natw=+읚^A"TK:tu~ӝbX.W[EY#u[Z'΁Zͱ .nΦb-NbІ0fĩx@s_KnM<.Zʍ JF}D.b񔠭$}bR#$/#?UbO׀ +^qvp/݆LFx97T>"\}WJ?5ϐ+?r*vZUkzX!ML xډg6adAe}IB$.] srɦr,#:wXWOSqdo J#S=BȀ;x$Xc|l^$C(R:V+꽵/6ӄ;e6< vy?Ì{@<)WN 8b5EU*.@^]e(SBJM*(ke VFrZFny|ӾG$~53e˘I=b.ƥ.= 3P&PxʪɝJ24 lh0P|#6tk 遾.~>C" `鱗gY.7if%`긱 @vBۼweM~Ro},nOېR4 z?WPdK#6R:Ϛ>Ųnk.)SpݞE60˜9~H6v[iߎ–!7Jh7 _ G>\[#d[yu~w/,̮$AYYd8 ڏet0oю` LMc1^A\g'LywğJ෕^m1FxG/ʟ3=KJr.*4_ߑB!`0d[+y\PJ' tbuHZ(LP; 4RuF&Ln!`'Q-갤wK'>1cs QZ"r"K? a*Ji4AA+x ӒwT|W勞xts{O_PѬg'%99;ӗ#B- u%P9G`\j£&j|'9'6Aɟ`A9.lӧAx^A^-MXΓTf ) ''0d7 f26HK)l]/S@r!, [.m{r8 4{6ӧ.hNǞA)_ERr]ANx dpVxX} ; m VbXYm935I؇4*ptqQϵz+]s$WOۭ>uKn1Ђ8e0_q;x֪-\èCsy{*D*{ eNʡ=53w}"L;&D\W+y}ҀR<ep?&8x=ԓq V3z`}ڊM^Y/p(aO|WY>x2zpU;UJf4sQڂoSݾJVўu aåmjV,ƨ. 8mJٺ@UK `:j5K&w'&r ijhNz~ڤs e// l MB9qL:<Yɵoy(L&Cd:& n[rQ84"*xOzʷN7kJO%,T"^Z!vZ[m71p(EBwDFDq7vKD.@Xgo*I|&YQb@KHvpj^Oء>).,-6[Vi$ߛcASyfvę"x SMdj46p"|l7 kE>A2Cg`BҮm GD1=_P@EmޓD)ͅ||IYRq/X2{f(%zC|" K$–?Ո ѕ ǯ_5Knw+S{< (5`~pxyv\(_#O`KrUWc|r*ȫ`C(ޡ {z OkJd4Zh*ldjYdM" L&/fvAYܣHg(2vh ONC#EOT Vk('-ddf5WXۀ ER8/dE! ,l:ibZ(*XL8iÿyR M( ګǛUQbNN=ob?up|bf#]c @]ڙAll:Ikw'kx1G+ tÀ n_3T]- ]^@*YiBY71O|k}M5N ]fMEݐI:OoP$K<1i5K5@f nKQPmq7XyrQ{<߂d=ݟUă3ΗLqDJ$&gL&YW{BqnS0xek}t\ju Y\0Vr=C>d7'1pMdnF,oDB_ wКEiWK^+p܀2WsJȋE )1Ҕ*bƤJ2Dd.rEh2r 'Ѩh\NT߿Y,@%D;GK"o-Rw)S*#*x5whr5e̖,׆O Î|]!'⟹VR3j[Le_AG*Vy^BE&_i5q[.xh^oOq|8+arI۲f#J=:( ľ5&_6yhy]b!hk?Bߵf&$.lV=n`umєL NH>’Q/MԻ5d -u'bΕFd_?:js1I Ƒk%0)`OjrvN-Uq[X1R=fFL<)/1]P!eT*m93 FkPdFehKv;U->:L49 Uu?/*,ARoR{&,}2Tgx0i[-@*ߝtQ@ۜȁwCN/N?af/q.tw!=-=̃Ok)EsBs+]|f.2Afg.g1?6 6:ž-T8u>nXlLP񸔯wg|+nlp10Os:4I$Oo -1Чþc˿V߬lAc793Y88X@?"tfxL@76~I>3a},=~Ryd}tңRIipW_Fy+T׮]."IguDj+r{^IВ0<ɒXu6r7P#`(*d;fBf/vU3.g\ yc7QٱЭ)ٟvc8DJd is/j6@֬VO#C43!uX+r)0B_PGڥYmDMKN{`<#IYb^ '6{#c{"icU(+ةIljɏe4ʅlCr_.߰4Ȋ5,DvZܥuo3( ne!]A1MäIQkCԂZ7S{h B3jZtC+ɛy3_ +^fE(m{KDLcw|vK'n7g^KSףz&qul.$O5;Յ%e 4,QThT~*avO˳|q] ebÿn˵. nE㽠3=5t"[ O [MZi>?G2K u&AކROGr;dږV?ѝ7>` vE >=DKO5" g V9EhVƂ5nЦj6Xy%pI+#zšK7jbb Jn!}ɘ?X,]8 ms -Jpґou,U uWf{p5_kk4(eOiݏ8 K1Q.?s{7dZwӡb3/S@[Dߍy@a0Vyp3i%Fg爔 H͍2\jI/=G;,ۺ >և*]Mv[AfYNB:oNĵq,7'NoO=5)vYQ3ŠK}ԛ&\7era9n3oDNs_R/ 4*Q>q<D흿vTd{ g{,DJu?a X@?@d}0s8bĀ<-Rx ~a(%}#Z/a"HIB(9:G9IDp d b,s^[ ׊Y^aiFn\Ħ\$m(Idz<*$^)\s8"XSd3.:DYu;h5?,bURjDaگpS}.Ȁ%j[^6jb/,gOp_Y]| 6IV q/=τq_L%4J<@pQ:Hh`B Aک|Pa$B ͗%EA=ߖ>tP]uGY2"{>/JS:\}y]?C 3)Rw_ s*O3(1W91~`U/`̔t<7t3+BוLSU#kx od)-Fd{=Л,1`[],PoX]m)7M;6{g,'gt"yyAƤ6PS{BLRO[Kɫ^/N. q3:|=%IDtK+hb8k2Nw5 p: uA-S-ٮU y!԰[${Ô-hgr\G7d㟶 с^J\[Epn߲/$b77p$ʲW Lwk)uϷsFȭvJh[t)M3!⥞Sӽ}ސTKD0b+-vuMoBv XE5J#%'5!dE6|67Nq2|-E_[ 4hFeMvvkuL Z<*dNJLWyrMhI)#䒲)HD'f.~W |ܧhgV$%U0ƹ0+[.GaǬ G'"hЉhyLjLdRlNg0!݌Nea)bbxc?'/6Sj(9 ܃B;(:SYoF3X6>9O=S5NnHSة]L>umAz*`^ =!zKI~ASW6EYL}rE`?2:ڐjo%-CK!i#9dg&#"E9ۄg~Rӝ#tȴaS2{iKn/Q fz[ ( G$O-X#$_m^/Gc i$1 Mӭ\@[s J)-taEV!܍=TQ3 ~BwiSV1Fo-ZD!E,v@kC>m*Sr!)P68cv 2cQY g& 0mIcseg *ZGEK@Krnw+lO(> o劢$x(Z)`d.#K#V/ ,DhI#V6{؟H:ȆMZ(_1BLvJKNt]Q5>N3s6QZM$1q8))?<1r-'G9;Ӓ,,a+Iwߊ ΅;Lh/=6:j\K<[埻ss?lF\ rn+ۯiiQA@_X[~e vzD袻PbG" վy kM) rNo'K?*E椎#|2wUw~RlmE5|ci+~uڸTLWܙBb춇K;l{Q< 5jeuPNl-mXv ޓx5>CER`+`SXLj1v0!h!,|7|W͔:3+8לEP 0t.wPSjbҒr]\YXf86qF>#~ڤÞPF/$v(=3X"2%0[dvD"Bxx#KkR7,TLb//ʛ\9r= `ֈtlŬ7L%lbL[>~D*]g{fv92B2Gȩn&K{r hiM>Is/0L}fvu@jzveщ t1K1Za ٺmU=ը=8X>5}I~]Lt:DGod&Ic_lܧ/h[l Pѫx#~H:2䥄uωʼnh@EV9*>_hqT#Ԣ.iHB6[Vcjj gwΖoyłl3n`f,Z@0ɦ:Ж7 D YZ!PY[.qetH=ʼuo;8(i\/٥S40B//8JQ^#mYHb44w&Flv?ѝS8DbЂ5[-k,PQ;d 'kG!䔅YLW7-5K9jg)º4PM\$!O7 i!rbPLS.Z~1.w%oQuN.sSuv5i_hC+  bv 5ƪ!Tz"N792Cɑ0p'"{ ^4FG(·b#Rv LSIlnAA4qJ7v >}ADmۅzwFng󘻝HivdqUWN)/ƱDje쨺g;HYcz Af}to!xz V"p;An1GQA ?E@6$*Xo:l 5 u^k6놫U:\P?QZ $7򕷬৫zuT*HK0[opNF6QFEI͖ >4| IңI`g@kNe[j:㽮XݍIm(wv%6tZǻq-q\iRڹP3z~ o] %; Y^jܡ~㸩5:|K.A|~ 8>ccM\1j"S&_;nnkQ\ WPXwU89Sj1<{37];c†R<PcLygPXjVopI Qΰ wqC 0t :Ȕ,LBjR_SY!oǎ~eGO-h\?5X4p X"2+LPomVgQJ;_ZU oбpww3}* D["bk!=Zvѭx#Itug}GXdJ~Oܻ1^8 }&P>:YԎUWv>>Iτ?ѣaϡO7 G857#R*sfO%5^JMlՠ?<*vqi'ILJ>Bwy(X 9qb(#zFB8L{|$ݽR&@+Í8 g+3fďCW%V lIY%y(#]rCqsĺ Y<*% Hr'OC8v[:Ԥ@eiw) 1cCl$!4Q3ruTR,+o"WY endstream endobj 428 0 obj << /Length1 725 /Length2 983 /Length3 0 /Length 1539 /Filter /FlateDecode >> stream xmR{Ti_S# ל7vҨRq.yg[37nq e!!ʢnDbR.ɶ ],IW)g<އnc@!^ǑlN!Q@HPBpE耇+*VA ra WB)NRLBI5@H)bT/7zoA2N ?*X\ШыyBh"d3N=F,wwMo2Ӣf]pBCJ־5%K&󚛶霵;N/t1d24{Q{̛bĠ |aWlV'~m}MS=7yG#=\Eі=Ri?5kSr.H{}gQy'#'OLWxs63L%3>iȃ&yxT*؇*?Җ}"6*ۯKS,9勢+:it~Oq7NK)m>['KxwOU'Ы|s wpj4*6kZ<=s4Zo|XouLXSG_b3˯Prίubݟ➏uu' EG>f f -SU^?՚pvbrihF~kS\>QKA¾3-n[RȆިi3nj';&H|IyGsu`#7X҆K_ץbF*!]oڮm5Q9i1cFYLWc 1;XNnm*N䆅ǚ. %waSqEMuA wєdh&nݺ`=:x|ğC<>_x<ʇLLiev:n9d)4<ðb>B*|ze^]c"nIrV)a?sIjJIwEĿ[. endstream endobj 430 0 obj << /Length1 1608 /Length2 4402 /Length3 0 /Length 5208 /Filter /FlateDecode >> stream xڭVeX֦AixtA&DRIIAA%$K)) AA}_s]^ZzkDΙ[Ik0.4A,# !Q.Dm"$".! 1h= a `@!n@N\RROq $@O $+^5w023 l8xD$0ABh<\p? AÐǭeHXxp(t cCRC!x7M ̀hvLwŜ0 )F3 x(%zIpk㑤0q%e0PqK'1 )J x&r0$!&aqD<# 8'gub=|NNcNI=\erP6f/eÈ<ḓ8A{0+ C ;e>y7qѿ]>2 "- @za p\ h1"@HcF#HRD/#0s$B=@ 1 +d&˥ -bG?7`Uz4sKd7(͢Iy&wyE8*jmavݵO+mkW0o(S2գH$c;,Ǵ^|O $ g#Jo0J0juQOUw{wMÊY?cW[ ܏Ϙa7Ҵ1 T_mQݸx"JUcGabv}fD~|gLĤSa7%qN ~(fUf7|Uc#Jf*;P֋KW\K*/VCS92LTj쒭0u8e?@E֛)}u,i?mOtG'_S>k?!gICӏm7{hh@ X_΄y}HPsjW}.(T&p>EG ioYgD=\R:,EtJ[hOMzu\lIoX4^a֕^?U#gȃ*ԏF(Jpᵮlkd#EU}c#,4ƾ:*B(#n!A‡_~>¸XGLvAxP[`CLgcɹn QeOm.07| fiC7veO#A4CoC msP!G ݫAwau[up(?h˂ 5*&WnA,Ypf]*dF7I-fnBj,߳\3^Ŷ ]fۋ>+7/V!oU.=^DSLB/w֖XXciëPW-1Q,2w[~:b0?S-حvc T?J'cʤrGGn~[eOڛgǮmӿ+lj],PTհb ͘,OTgUy}JLJk}+Ô,Bq=+P.7?(e8&ѦƌE?15 ץ^@YB#vtOb:U.P~)NϸnUETWHL:Q@x.:™ LA1o}}W|!w xVLr$ A ,r[oi˦|fR+[yM^[jgU1x!5`'ycjpg*ZHހg7ˆVL~?Ҹe1:}$;(/9䧾5A6CA9(}Ptu2p\Mm@ZyrbmKʎ`ğ6jxZ]Wc+fmNEZN.^K)ʇ\g6<[|WG[%!vxYy2s|=Dvnݍ+6 K>{ 2A.Oh6Gabm`usձ5<1ŨzF!1狢Xl$}l8G >ߘD7HaWox;փn/P(Ĉ (8ַ$RSA5J bҦą[O j&!OD?ĨE]s.L+T--*%o j ,hE_J/PS<x<颢oKp\@6&1 gx@p-r &s-8G0:i33XbEu*B0E?iv0zCiv"z9l :PZ]a@RgRWMvRUst]aXc4[wgAYLjj3!ezձvT#+ʚdՍ uބ[saǪ~$3~rM, ZTFtޜ~cp JrxH.ۣAlWwSEP_ώF˱Std®"yhEw)0fg IPO;!س\&kvqwEo{4kdVywzxhK`㭝/C WהB՘܆;oF;\MsEeIV'vDidŒG«Xu493=U3K0Ә0[V`إLZ!1N654g2/Ug; 8:QZ.ge8/;som8txDkQ5)N(+-*ca/ppOm]m^tI{kR)2vur)0& QBNɼV&@esc&J=KW~a#4Ik+ /~]z7CLTm O ih>ϼr@ Zt(Ar8=PdIIiw]RKS>z. -V!^A7ERJW#3/?};܎_AMEW{g6a!{&}#mb1'+tps{ysQQx?'߮E.'3 V<$z6ƀ/͠Z̻V:TLu9QvC>m?'U(&fJɥ]3mV_uYz=huqS!%}"ogwc;n4pZlwpܾ= FLܒ5 EХ˵@͢*1}~vdT3W8QC'=2I?VP\mJ2;M}FT2:Ϙ6$*&}.DOeJWm\\7[%)!:ALo ]g0~2ɤk{V}<*[=1rcjPlRG\y[YL#;'dT$b7h/?=P f rY_s:x2E,5tL?8-p8E5B9,ɣ,!QVvllm>fP ~~yGo1L[vJ+^/øk< QgL"+rJ$#/a4+eiL?qy'u:ӻ7fW2~;':Jz~ߗe:Fak^ຽGf:9ufUpW,uaIE4V{WqͭEo9T&#W.xk/JO Pf=)2pJ`ןPDJ3d>-S> stream xuSy<]k}7nY2c_}_Ř11 $5Y,5"YSI5KIIT{z>纾.:b6}0aIeE(l&X KSA5ES C qX#; C5j5T@!qa`0h,2!ɁdO1heqd >lSh_?XYV^^7 ޔ@DbRE0dJZ4G M.XƏDÕ>)}IIZ ,CcfFh6EQsnX\6_WrĢȀo ՠǠ010B~J?R:POR"8<!hc'"0@"/2Fހ/~SaA"CnPE(T ^( P~[!)G''W?{;G(WCiQBUh@"æXp*> .4,JV8 e~S?-gc2_c#8g3) A#DŽ&C e_#68"ǛCՔ,@$R?R"q(4lOA@ d:D=M-B$_ߺ]/PVw'2_UoP!ZE#機N%݁'. )2pp&pК$ (ֲ1<8ϗsuɐdUrERǰ,;Jxua1$(RYZd8" i  AcsX: HYjy`pH-jIfRKqx{DZ~mz:'I/|Vc{+7 b=,F"Ps(?\mPUc z]"<VQX$G`8vs߱mc8Ͼ{Z;Nx:lx|f]V( W|޳4OdZ?Lj':: QtPxRl*7 ~R,NŽ4ܲ@'4ZPb ;m1 nBGR?njؕKŇ E[ vligT҅ktE&'ߦl&Okr(G?GZ"mEs&OuaZ~:dڹ,qтRztͿsԪxm{j[Y9Ie~NWb}`+dbѕx4RBW]^h_ɣ9+U>@q=^/_PZV3&MX8֯O4pTh;¥ܔYW53DV}n4%!$ 1vsI{!E01g!~qjVB߄?ҸTP( Y=!4^rw䪏5Wru:;4iO=w+kwwc9%)UzBٟl+2/QҔHH=rYP]CHoY!|I `@`~2-PTNKMI*1[eo23!4ҏ* Ag NTJXtMJܹ)|_x6BsUV]yA_A] mI%RMŴ+>>>U4=.zY3""2˫ A?XTQ֬ &}ۖ:Y(Ҋ*wh:J["Ry6 rn)4""2 ::]A#õS T<鈍2uHO/8ۿmryX}֗SWdcUTeE6ZHaqٛ-ֻI [GJRoɡ1Z)T0~_ޢ(rsf'L K^[;~oJ I-:wOuvr(?_C:H>+V d0Sz%e.1=.W'ôܩZ(XC ̭s8(᳋ҷ2 reaiyǾ͙4xNNd[5uqDM,gSfcIUGbI42Ӕ&oCEOGEI F;^jpkn;+cd|#(ץtڰA օm=C$`.u*6}-sՑGYiiRvF@ʦp*<2 O[8vT~N.r%SlE,1z7O'{>=uC1I]ftuTS%ܢs Ƌ qRz$}]~ҸS4| oA#UM^fW]cLiHB'&i6"n IKt? ]& > O9 (Ei^\XhW[@ݓE,G+xv'ˮHD8*q&D ~\ 6v[cb5YPRì1a` ;^gWq%1<`߽ےfdZ(\v3u!͵k YxRLQWl`<%+sIÕ6';l*D3_3GM-S,X{qY$_lcɝ*~btMMV`~#Ш)yy䶍6 m+A[#j.e3I|5ab>S/b7au Ԗ8{'8l4`8(R"/K٪1n0V@VT$Le͙y٩1$={-2A]X,n2@p^PbDbw |ޒ*w(M0'h^%>7U c+opF8}"NT*~)di[|*\}̣=r}+U |_y힒nd\۱W=܅`ՀUmo_%8sG$Gv Ϧ f Ej^'S %s.HDgӼd@ NX$mIcLwGyAS19Y1Sv;)b*p̘c -NLs&A~A{F Fw3ZhO6g,&&C}"5豈Aȡ!s>iA<؄͖ g_/.~]׬aD1Yw"{/U\Uժ˵Gpzd/+RgJJ$Cg2tU]`ujTyjc`q|,A'O)&^0_oڅkeFԷ1Jvޑtb寺Z{u'rq4+}CBdyzٝ+i[3ׂTJߢ΄@DE6h/OXZ֌B]rH^]h&vV'2]^]gamO-gyjh̕Kww]]y+|]~#(Ly2Sדw3> stream xmSy!zp.@򢄔 |f]s!b7'zF/a@q^9Qd' 12VRd%0:DdH .WW3t'}8< SֆuJCl?0 `r0ez־7# kDOēk8,H @!QkK{@NA B]a20}闋!?M mnbj{QW&BJTN,u*#jGy(o>x$2ݕ7KdJ 00K#~>Cw]=0Odo8e!=px_xnLEp.đqW@9v )D2n1S8kWڝt+~@Ch"Gp(t3"I=M%svSܿXEh0R-tCAfu*|-Qf){lΊRr[s& XEweW2,< fep,Z5$\ugZǷpd᪭9vn"oк䔗3DGfS6B *̽-պ0[j*~z{ϣW}9lĶ@QFnf5C}Ze6- B#;胐ׯ~oPjgP%>h~Y٧,? ?o{x=h=wЎa|3o k4=oK\;Ls4KӬ]'n"}b]F54d zD_W0,eHX;*)dT* v}bFe1x+hT>" h r3yE [^|fU[5MRߠ[bE:\n]=R&,baȧZqlS;Lyo@wp,-YtAfǷ13_Q|>2R$(氼yڝŤe+z61ookT܅3=QkiJ^4}iÜr$,5I nuv[ c޴߻{(`#pHo9~]ӝHi8'j[|nX{!o33鎅R{gmΌVemm^hj{=VzC #.5*iWxxLԹ=Lp߯6˴;&P9>'ױWict:: Gz#kd?mӁw;9ڢЧ7}FeNhk o{Wߴ5,2LHFE>5(bsgpo,:C 4+u;+rV!D&v>Q/*i-W]Tmh{ۯ,i)q~p聢*ȗN].6q} hiljeb rYa,I֢1΁^DAuo vC+`5MدvVO,Yώ.e/HG޿fTq~bYM`ˑ)?)Pw*Gw)ozMr.sMyN2N$䶶ALK*V[y֣"Ic 6g.g%vb'B՟=V[٘"nIuY|Ļ^Y/waY׺ K~^N[c'Զf&=(OHDT' %'C̴L ؛6+bggC NOܪTCNѮ+OB2:/2O[FQSI+ )f!͍w8btF0;@tx,ݘ(m ZTmlf\1 =?z?p+mC b4S9s endstream endobj 436 0 obj << /Length1 1601 /Length2 997 /Length3 0 /Length 1792 /Filter /FlateDecode >> stream xڭTiTWic tӍ6( H`@dwq+^wTWU[d1$m"" "ĸuTF4FH8Dѐ09㏮wy}ӢāCZ$R?'`4qDNR9; &  ī4  rcXG*UX1 a AQ/H(  IA0/*oa54r!40 Dk)$ij8C4/AX<BDǠ1XȩIG%$) a$ 4 r Pfx92SPa6O0`(`p҂)`PTH Z$RF`,GhhxV0T"q(a3'MR:iƔ+R!d^&1*IZia2鰟аb!g x`CS:@@3PUJޜo@7"s #w6s4N"15ջÐP<\LMR^ B¸0CJ4D:$R hRU@Qh0&BE h{yGU$L'c A3viLx=hc},`_ #@P)bl)b!I.E4T3!FZZLXG|D a^|qN!kH{M@q7TSB3:Xj)q}e3S1[;h\q莙4Wi' B\C#kOptk *e՟ 33]KW=?򙤢GPK˕~,x/ɭ}[?\Ql۾xKJW}DRbbW|>֡Lκ-iuaƄX4|籭>3hѣ_\.\T}QmU{?:cӶ?#Vq=ߏ [vn%O7[T ˚Ʋ{WyC$CABe<9,,.f"iYЎ>xʊ:/a[ml[M8u ~v+ws[cؾa Yz]ӷ3\,0uuqNN>U^Hg.oI-?^MN7?ƪM\]ZpE>Nڟj3O7fϽRkrwӪ^p~!Hg4No\ b-[ *ןYglj{̽A'.Y77x8L'()n$]y:Oc)|ЍƐ3OE?ydG |i5󅾸D[{ޔea1Rg{=_0ʿh,:Yʋ*Lg"r]j(q0#9DO`AGE[uw ?7ECvIWq!ԧ/ PtHl6pLѕ?6Jǭ6xϪ 7ٻ}çyΉŔnkOgT )t_le;/rh /@fbUVkq endstream endobj 438 0 obj << /Length1 1626 /Length2 14184 /Length3 0 /Length 15030 /Filter /FlateDecode >> stream xڭeT&Ӹw 4n %@n93:w^KvTd*Lb/Ll̬%"s!PQI8M\A&@~6 4^ K+W6I1zOͧ @upڻ~vTV@PVѕUJ+i@g[- 2ڻfJsa%08@n@O3?*F# ,M]?{ٛٺSn/@v`*..f GWgV/jeOnЧ`ii`OI}Ժ]@Or G[ܟA/g-3g_uMm/`F`cidϬ[8X-7ws:wD}01w-X\?ShXf#[Gr]?CqU21|Efr1z96hlS'j1{OZXY-|yU@fV ~Kiot?yWKLlӰC׿U@{IտJ**2 U>U(E #. ab0qp}޽O@|ܬ~ _gEWg'@nVU?~u20Rf/?j37gOu?< 4CX]r0Npc u,k(. u H2~ enou/G0ևcKӛ [@GA_Ip 9T;bQaJU`wJUk+ L'3] {a #YZcvZ3F})u=pt>!Cn<  Ym;;#減ܪsyKGE&}@ C; hqRIUi'֡_`MdϚ}1-PxXX8h#-0#H=9ǽعRf5s) fDoΡt3W.¬T ]H5w.M+y^nCc $$ҍ㎕ܓn3Y{!΀֖2Run-6??'KI߿J؃X_+U',׹pI_[aZq7qrwAEii$ҍ/ʠ%u onBYD] ˜ሳamm tכqL3?# &zu3>vcPƫu>X sI*-Y#c'͔;ufBXN $)E{0wۄm iɝ*aƬ(+Pw1Ǵ ۦ;ՖͿL/f5?C֌aL<<p;~~.6K`24JcHr);p@] :Ƹ /7]%RohkV䧰ov >)xn6l8/E^Q7q}e?rvTyGCt\~AxL}ؤמu'_N!S]3VOU=aAҵuU'7js- 9k("0?(kRݭؒDcimV/ #iua^L=[4+왩o_-gM4]=( G=y~fLIwRCV#{(x[?_ Dhe;UL\#g]!J⽢gs8Ec&t)!헽l \"`?1j3&ՐM\|8\ Ruw4;M"ÐVVK2GTLo'_@?YȗTvS8QjAQ]OHgo/)s#.ƤlC_^Q3!>~mxV$R2xZ u+59$߿<@5;i;oo[|#q1/5] EH[BkAݽIpdL&&&4[щ>d>HrՕ0C,W\a,L_3:^~5Q DaO bvuksc{Ȋ x$}lsǨm;%NQ=\Q1vƀ+Eff!s^Q~ћ~ƙچ*"k||#a>+5&gQC2yxfY{>N<]7]lofӞ(Q'+Q>)'Vw urxOÃkjL1TT)Ti}t#.1$.ѧDTԲiW#kZ{,Mrg.֥{rhKiL`˦ 4qN'Pr!8Xi@{; YF]e!AGeqHlrintX(9YgEh|@~]3I0W`~FSk9:#F]WozMw7z5PO9J5(09I ]kqѩˀb=1T*ذ7Ԏ_gsuop2Ӫ?ƒ: S XsiD[_Z7(z)Cs8J^UD'4R%9EB=:XAd.8s_th3ng{!'5\H!cY("ʵ_1GSC Izd\2` N&:*zeD! , %81](2[:XfG+N̫|ic&~#<}Pn'ACI1FVyh!4&yP##Oдg2 0?ǦT'%ǒRږGeMq ڍnNm;m&yn{ٹۏ (-&53)p 0Wy Q0=2dO%\j~bxA^o7SkWbs&0$SԀCgs{6$OdžR  2=#Rቹ36حh(X.9b7;oy-gz~p,!vL(vJ,C>fmcg mTnHOh[ Sb6Hgb>W*M2,j / Y#!DȰ Lq+}SU692dowЃ_ dPُ^_p1?\${-ƘSQNÓbK' F[:8!:AS=yzKAtAk)ͳ0`CͶ ;Ø\IO ڛ_d %IZ檅"C@ Z${KrTeS> b*lH] 348|!Pnª8h'WL#@cܓʪ^Y9ηѽ'UŎ eYZhO$3Wרei`~!\%oW` FU9 )TvޟK\4p*׬A؃ל=sZFuƘ }fzɏ:6<"Z!@ /AهjB&7rc:2#36\ٌ]ZZC(Je3-LqK2 Rx[-'bֶg`U_9 OIM3&]2X̱KppV (]gAZj&j=1Wp_BЫ݈])-r6 krLBMG2=}1l#_F=Qy\ǰ!y \nk蜵9;%9cc{7ˑD@y Y+r[PS-f<9n_st6.+ ݟ(nYqm^ \_%(4)*A>EW87WzG4_j̿U(:YЄCЉ"-%T~sIoտ"&yVv#|9qatoȚIlDMbK&;F'zL,L,WD,"ui@mM\v}: :MfnL'_uP\:SMa~/ѠM3sf{BSۨ!끑iwŘIoΪI`9u^b O PY2=nizwo"J7($d9 z3۰o+E$4rHY^Wu=c UQje'\ Af#@r; ;$Ҕj0rǐH:x,#crj)n;~]7`Hi)65w(5%ZG>B2%lwc%\ŶK@=vC Ьb,656I0tsТ/*(1QalafxP T ^O" ar<@'>8T-TrZ@{jn\;GA QU.aõ?RRl,<ﺝF3mB[ѿXF%I솈,%Ay,1vN_| dJ)V)Givh ~9ή0d+hS6 yl;Y@:xPj6ݵK5z y§ j-ǀ`kv2r8>m@~蜯/(?1rWL{.ۉɹۍ [S܃HXwI'-:_2 :C2vblLvMnɞ}K* bةR$_IgC 6k}W.;|گwfxw} Y 0Kg mli(|*nPm趯Κ3J}V37*uP1oa-l4~Jf2p9C?.o1(⤸6O"?SypRGi俽0j _#AL *Ns.C};̺1UЕ \M:@Нh?~<>=$5iIC{/m,cwOal-f0ylTrԍ6"qISQ&;iGB% :?wDJ]9-1NmEo @&HH=x!l>M*Té,DR|8 MyU(+-@AMSFBB%~N6:+YD.54@Ed.s/:GcU6t&D xrmA. ׍57V`"t3Ln) tjf,Re/h"&֠ }Fr@SpqXIO.ƫ/]ȇMbu=@vV=M]&&9+,߯hF t]">Rc Dk R,YncFؖ( d&<M-Ɗ6 .Gg-l"T 1oEHjZZ*gT71LRCⓐ+Cb)xE=h~ 0jsG<9i1/nO#'e2.+S AFwHH={ˬ\~+b?@,lyLau0YDeb /ЩĔ Lf-ƫ8zGT"y`WPm \Dz;;x_@K'NJM_@ sNH媊F͈Yz߃Xwx+s|^OkC8pǶc }ϓ_R} 1/[g{:AWJ $ǿQ;ZF{mފ162Ik~'tYSs IEHsҸ[Uՠ,uE&U/9OwAlqp;Ul^{}?ӳ@-Ԡ⼦z}y)}M[7>,oABW_ZE EbdAM3Vd ]~K:>KԠgɿ:,rBi/gj ;~2ǘC^Cc6ij:W^Aǚ'UmCgOef+AǴ&aN::M㤙g0 aPX>Jꢰ_tuD_0KP9j 1%Sƴjĝ,e-VY>zd+ jZGilGII50B2Q {1Wgn~{m,TeB4L[LgRq!{)OP#NA9 % &'72'D.n65[{`utYz2- eXHsB™ ХS:xSع@fqޏ_oKϓĚɢxh8KBCZ:4ѳ9C5Gَa$Xe+k|$CWx\0L;;  Sg6kܬ^R6ѕBE3Qa_"fO|Iix}T Ю0QuŮE5b囼ĕ.yᰙIH#jQ:C[2zd)$VLwC(뽩_)zVi+%E3VXzAK,\'=v5ͪwklÚSMj}+rʙ(@3*2)c!ojPpaY4wͫERn˘)ћ #ɢGpGG7\m݌|Z ,2K/`믊Z`,^Ѐ}+/f5J\+}.t\ W 2i+Ĥ }|ltokAMv!H=fQKYҳ@Uu+(^dicp0=r>ejxlpFLI[T4[U#^E=ߠyB'ҰƤXf>8q0ϳ85: 2]S B ~bU#{8U796^޿@5K 0ib*uG.R_Tui쬏/CP9t<]vF(rt[)fE% z*k-Op}!yR|fM{,H'J+vPg*,qf8&\Úm­DJÄF<*󩧣 %5rX@Co6'%r `%BR{%c_nWA>Ƭyn1> w3m.4-wT} dfm!bPXle1]a.5;_IAn @*Et-Q9Rƍkȡ-jؘK AXz)vVJącsU!n5O{5l9iz<%~0۰<>u5kbLx"\HO;HD`QnG]T/ÊukepTU"=ĕ\A8 ̣@d&y>p87(l=^ 84%Vh7O|F}b<\Gd?q6wR0ѥ)}AyJ"CGHw1pG!js]uG*QDn/2Јe-nd&}_b>+yox_m pFH3:NT;lHǸs@Q}P@#9 oѓN5 r8e#g:X _'/D,*;݄OzTߠ]cI0+@qPZQ؟ьjdDž5`jZ Bx64jUv_QP:Wp`R\׽M~J$ ~տf x#Nnq> 6%9=)2zT,)yfj#\-UWnj'#yGJ¦l:Xj 0M>|ZUǩ:;A?mc׺W,8WAqvo߯FXq VZ,׬f蓁(x~Wq4 gf2Z^(R Ab(П]v;˜X4ayFbLA=]$'e;=ZS ;̲ !# $Lv$dIQGⷢ"yҙhX aƺ9T_.ApMD^p˿EGcXdCw * ^0BZNkx?I|&K讬:Ngq~cE nGxf/8f̀^m9϶ b&"E{ٯ8'2)|;lKӒcC`<΁IȖ5xp&5K p%w,J]T+klCKkܢ(@9, ʃhB9H6HD#CqCq)1ei`O*#htLd7k:zryTq"gI"6Iޥ^-%̚2nr6VmQpUX &o+WȻ3FLm( *'C=a(19{*KXFK׽f_J2A'r!#skŬ]N=bV&oT$Ug|8>RT5ʵlbMPHp^yt6\^{䩇ݴ0*=j=GCpXI3R!$[y:@̀@}jBߕI>{E=ؤ /l|,[%LNIgh8$Qo%g~%~޿s|?q~rˢM?bNzT=ШUC%AHE0F3\pLbֈDŽ-}E`,s-Knm˓]4ͫKlM_Qy ?-SU-A=B3~,ae+#O:9XMmgwWÃqS؉FI9 Qty7-%! g~ԬM󇵤Y׽$]P?Ԗ5ZLu0I, 6W,pgU&7r{W:U]IxJ(G櫅VΘݙCSWS%~W1`>Nh$l+Ssf?]TШq[7Hz))S\m&d.1{q_Qn ؓ7m0*۽+d-q(Ҋ;[AYvBIuիyv!Ev: U2O9,nqHfQHgxUIK(7Ld/ ] FG_u<2K d\6ZͲ" խ tT$waAƙ{U;3lcI>7M>b0z~̞!`}~}Lnst/r!pX]gk}d+Įi-p ʑ/Ii.yo=Oh;;d+ro3=~{N:((40~^5YK jvvTRgu>⁐Jڃfvmx#iTcv,.BshzMɊn7Kpc!Ǐ><(0;8C1ûhDyĭ܃2j޿<*AA,v~K͢v@Ώ]D_Z?l!2[RqJ7%9 ci65KU0Q1$T{DpZyC[e>g7MUe<*rg%B%qW4_UՆicTEqO Nv/iFb ػfr],_&3k4P܀ⵔoA7>1G_DځmXgZ_$)BҌ?HʁDw,?4B_u\ ˬhW&DT^9fr]G'Ո?;=c'}w˟رB]pSdxV0BEۄh5- b?I(%rϔ fxN,v+!+FRJ/+πV/[So#z\T%?:/tyyhJ9zB DE&x1r]%n`@7)Ob c\(q_Y1eO3z镠~ [XXo.M AsZŃpGW<>u7Y.Dyl $xPVEB=r1*ֿgz)8(h> endstream endobj 440 0 obj << /Length1 1630 /Length2 17755 /Length3 0 /Length 18595 /Filter /FlateDecode >> stream xڬctf]&;ظSm۶m۶U1+mNŶӧt{&k 3 -='@IF֎CFWCB"hblag+ll P31 0$!;{G 3sgJ1z毧-_kG%  $'!!+ Uؚ8X] -F&N&S;G#;[cJs%08ٛYu3q72GE 7qprp9:큳M_ `vNNF΀QE?,v-\)_0Ngwb- < fh4\,l3j_t?/[{_V3 g'kSZƿ16gV$lM _ "gf(&a`lgk061s@2 B#+]2{ gX8| l,=O^Z$ E/5Z8Z[8L _r[cGk [zS60LlkWtҒT/Ca7Q<#(ha`e03& / <8;ZM'#bkdg(9)Gm-U_sobnblgl\;<):b_Ҡ\_mQQB8tfy Iy8ڋnM֓brׇ/i0N>\-zQzL^pwRAQoŸ5(>4lpldx*'7𗳇C+SRVZ5R' c C%ٷ>=aUX(l,ca"/5Ќn]*럋z^4UX أƨe4B/$Ur~LcqUzvt (6:l>^(Z_E1>P<@Uiu4<41 GnOoe̱|{ )Sk|iM]H5nRW$LoXaH6$ɺ-=Z]i", |3RŻP ݗ@Rмyɚ5CZQ';8Y)={2O{|*SC#bj%ǀO%ա\QZ/#El@ Ww?6 AT@~UmGC{f.Vw/}6y%chi7o̸BděZU㩥(Ov)4I┹纺+[m=Ig)LؙHEsIySTUIg W ꅸ9">٣2<3 9 \TDd6V S1Γ Zs(GW*|plgnμ-qngI{PhH[Ė xLV'T:DP(n,w5TsQBa!7MWRvԘxCo zazK?hSVl2x7[U#6; S^-d@;A#;z5:PGB1U2OGJLiJ,;*F6VO77&)` ^'&43z PK\Y,(Z*456 ~pa+n.bÙ2? 'O/&A5 h;}38.=pw^EA[d!ND#9r6nLS@|9p,x= x2G}꽀ȅ<Dc)Oi4bi;P vZ$w]OVil #U}ģoa^V_epMן;!,BYLtWR|zxh) PїNxAs Ђu im "kRPC}G%l ]xSqahLww9s~k(oL?N_jH7oR1\ܕ3E >&!hw<O SZIϽ)H),XŋXX[ӕ+|DH ə.^>>4ݾ{;DN5ΠPdj#9Y&URlzeѠZ]!_.#M2\K9.3>-t|NOF.#ó˖N{l6rѨuC%Dsc!( `pá!A$ತ+9Eޟ>"oZ_q(Oݛ2j[mMtoHZROW>zb")ߤע'NAS[,=tuÝ}"ƛFt꣹BHH=]zgh୛|MuLPJZGܪWWj(#^਍݂WNea5''T'=H)Q,o{n)B4cwډd؅TXe>ҭu+&/!H{mkH|WY8?A>UHxW+ŋ Lq=i}_xo{D`|As+LoyhM[[ė:Ym- t{)B g_6Sǁ樦ѯ=Aw  m{\<)Ŭ7yϷ<6oVk2kG-=.Tݵ+se g.kz㉂p!ewj?FIxY~ۤ;wȥ>r${%לҐʅO&!ԍ;Tm@"Ko$atv .ϗCۼ_+}x !N?V#xZh k2 *ĻL+zڝ@n6kHRALrKB@-[o"a*>r)w}Ƙ~fI@,K@+fTWz :h=33BV`89RXhgYa419zFLg&c488K1W)缱ɉRm|"k>!8ŌG)m?%Fb=ЭxuNWyjj79caUm$.'k~ԕѐOnHC)/n_GH5gnynO1Q6pW^7/A(}/6s %ӺϦ^RgϺw؟O)ыM|D(c^g %Ʃz@7癰 *Y1]y ᄴp5E~?RO4)2f/s< nrQ^䀛q[((ŘHo[{/ai/kNZ!YKFγL[rD`m2U)5PDtcjZsȱZ/y ayoO5P{b%Ņ.ɥe'Pk6yhTQ/} W"|B7:(y['ZiTtI='W%̑xx腑/o*fIQ.Bm 2!Qb^ݱ+;{ɬ_2ax.١h|z\ '쌌舞~f^$e.Tr>*x<@ ,E"EFq"ɨk`5dqx$ **Q*z͏]Y#NI8 p&0fxZ(HV]z]r`p&ke\Eo85 (qY0PoTaw^Yq '+ML7ς@"_V6I]]u:0(+zk, g$A _1kpEG)/Oj;lORwb6+k<ΠѪs!g~C಄xLqm Q'ZC';z_sCvL]܊&#z 'I&46AE2X-/%z&$t޽KZa_d>L9F4ɉi-N^e-O1uwEZ4Klp9f[m*lz$bð FK5^窓}vzZ8Td&F}˾.8PSm,c>}Ɠ{["}@0 q6Jr md\1a4K.j?3|F{KS^YZN~;6CcSদ\_n8x)C ,~l y0vQ qF@Xx>FG$,/lT_oUp HtYd/?\'WgVRJV7tCuvѭWUCu,_Yս /KY *)_, ?=jIyfS61Zs:x]8 C5Ë1@L"e2fsDA7{ &}AKV cE@jZfT4B0UD@AL)&z]74EO n fё C/rtΟq}솟Z: %V2$F4Xj6u Νp5d%$I0GC$h38Kti 3 ?/^/|Q׆"7,ul]h̊Dlr)8 l@'AM\9`L4Mh1SR]`VHUq,#t}aXod:žL$4~n؝ccN g 'CAO3/<7.bf^-> !N^ld@7p* 1ʠ<(a]x2tK2!ԏp$ɕ$#S9 Bȹ O[,́2ffe 7ڕ,@tJ/&Q7>[~+jax犚Ǜ4 s߻ bUp4ߒ1n28 yIX5}ڴW"+uU 2/k_ٺ:)FH }3cI_)oQgʗ<Qp#KSxHIcW4&s]tu0Y.C?3nHԃpnk@K|A&0qI;(o_1B9Lvjfw] ΌWIqO]YGs/*R'Re TBCZH >}>|iVBU2!OjmA9^`O'Nݭ7E̓Z"(Q@R>ub.֗Jfq[ :?&"x1F*yFUwCMޥ|ғ 1M휍f79Gtg&'˱e7m֡zI{ rq:Nz)v!M ix1ON;JCM~Ԇ(Kȏ1>^ \jv BSiYjK|%%ɥ?jW:G`DkuuM r!ƍiء-*54ז XՒTZr.)~̨2<[ּQn]t-}/!%nQ"z$kv i\$ >Wlgu)kr.GbIaStI+vrel:|GS&cAX ﵵX,G@IvmN_by2 utRjqo1EƧU=s\C!ZgCN6tH,d%ۉYL9a$qVexӸcqJCHװ9†OnۨaII'rSʼn ,9tkLmӒ4&Y--ME lmYw@1-Z!"z L/aT5) ۰v;WQ0 HloWWe3Ѽmğ"31f9a,A;C9~+ԬU9 %Ǜ/d|=H? mUړKNA+QVXDtJ_ _F鋁Ɖgfq\O$pWrO/EhjYwyHnZd`a85z'^BB 8s]NL]6Y7cC{Wu/pF_F7w9*zr hnE7}b5=A8C<>_v3+T>&u-Q$z BƊXtTR͠L`ZQ}fQ{Ap#ќk9-OTs4ۺ3GUcL~5ky^.M2\G=NeB*&Sޕ6WמH"] zSZ66t]^oyr(UzKsk~LHr K8{/HWqt)3P!j-'>v]н /+ڡٽ@Gτ )pMG~/,,Z@xiwq=nz!|Ueݿp6-z :\&qEor\g|( EQ (z}|֯IRmӪ,WIdKP0.)&&oņ!K IvIT@^Zh[ ʅ()bowO?W|-N7ROF,` AP$!-Ĥ:M XA|[|UwVFWO]HSofԮ"O$.([%{[Y4z V{=D6N\'#xw>'Z͎{y>hCA}jiIX/٥:>Z$K5vCA&Wؽ@l ʇQʣ{7F B)}$mJzK g L+dNa+s'!vX,$"uo=sE<-\L @fR|&)%<0$ :%Vf~㘡߈a֎r06>V B?N?Eiuy-~n%|Ño2ER}g8!az:H#etG3Jr-rHBWΞ[~Ӝ&'؛}MzibhNTى#|syD+g@=APUr NbP4o~칥?&&x׻O I$D3 lc9ՠ|xHwGN&$',K(@v80LƠ2dۯtGMPf(MN/֥ר?TBFfTzr C|$|5M,څj߫?wչzϰPZq[гÑCۖ|bXZxm fW.Ӆu+-TS= =b-cx#fN/65?dZbYmMw%r}2U*Q.ypJL."a~KlZx"B7 jy|[+$ (W S" bUTS .Ճ{ϙl4^e e}n:mي ˂fvU;rEgUtK+pzȯ̃r_\ ?׮F6|J;VߺFTY.4~5nR8lEs2b6MR{44_ᦑ8Zf _ks51_Foh;Q"IJ ف> ҳP6kM U>Y'!02w.GTQI%#l0b GWu1WU2w'ELww"CJJ^d$MGnޣc UF!A /jP .Tw6yJM9#wHxS }<1)f~-V1㜲.  I[;Ɣ8:RdR{r*Wݤc֑ Ċch i'=T꫈2a4Iq R4||Pm'XWX_R"1gE@#B[NDT잪TIb@ 6ԅ5#bC)nΨ;75R 1O͆a%iD6$2k{|%ؓɒzt6Sn<ޞd% p *ÑUOc='ir12q1_w=(^~@IRZxIiGa.t@AU]َgч剻 pڞnkL`Qpr1ݿ8$v-$2غxl ?=Aŀ2p8PYL`Mª> 2VnUȽx|GPl^#A_7LguH:(]"Ee0u\X5HO7'cѣsEKU}b~1<0?";Ē^}2*fSrY֓ ^1mxً-=/r5,` |}ov!2LU/!z.^OI}񁹭y65:D+G+ \j+e]`{I sjklTWgtd;']gB?('>[b @A q?'M2+$:j@~Eʟp eº@>FimS1oBBi?-&!8I16ݳ.#٬epdP-M0V% UZe%FUd "lehXU-FdQJ:W)R6&gi~P(\5/Xc! 7oq{ֺ] {|%oN +gwEOF$f*L)hJkS ޺ Β_'ߤܲfw]j Khv&s  ҌWN,=дw?zia'q @4c[rF KGaqa0NĠdU[ X)6/tV'Gٛ\٪g v Y9'JM7Gpi1[sя-Żeeq"x| &ԞQ3[nއHI,3Y'Z֢4_B]e);N) |ŖY AqE,^ʇ\Vߏ@[5t;Q-"m0F+<z*:U(FTMx M-m߸ovsczlnbv(r@tpd){l$:$Ha2cktQcH~D fy<)"xXj-OO賶88F;e,@ԅ|W*:. Ðs,OIELs7b7wXQV;*km?dzwk q ػ)f+ps6 -D8L5;(v#jsqR ,Ю|-KxΎ)_d0}J r3*z,jO3T4p"=H<ƚdËqGz4 Q k~}c[IK8.bfEJW)oj뾻fJ3]Wk(*mP]؜Q; njTNG񭖳'`_|Mu=xxbtDD 0ݝc1yyo }:41hje/m!Btg (1V>4]:_͝FCS ӧ6k Z ]cf1I+Stf*Rd/%;[тDrٲj(E.I3.AC=5Ĭ5K_.|z8#}kER?9H3줨!́X} &O^Q(Zza ~/!W dC܃@BǍjqǔ%jݎ^kFMfp4`{AI5G{Y'ڕ .nL\"^j+ |W;NoUryٛ,ݒF] [4M—ң.&q{8C`ZW~@lɽ\[0JVt-qRfIHihM΢ځ'$]14k/,=m 05hl;5VἈ06q4.XCi鰁 \*uس!!?iu=RCBVj]'|DRSڋڈTWM8lJ)!NsqNeh+IuDY\LDw4ėqRUn'~?UB^>I׏Kp$ͳRZY}ݝKt2cT$ VfmϴR D%e.؜hcTS Q@Ϋ.:+5FK{W_HNSFp߭u ݗ?]ABN[ӈ>̺>+_ iXE(cm_зvn=è[[a:n,E1ɩU0Ip06|–D1׏T8??XRv5ma˷|8%Fs 9OٹOvATՉW?RoioBlإlCJ :Gv]n3Czc^S-gP+sLȚ<֝9K]`S$c/Cل3Þhe:ƀ%{6a;w9 ۮtL;Jk=cN읉Ʀ9(D劻:,SkJ2" #l{. eg2ۅ-m eX2hGşpY^|?fw0IeB^1l075uGoasy ~٫#| N8?Me^&ZBcC4d˨RΚ +mjV- ț[En) Y#=Y^MQ` @mx) 9jD3!t4#.:'=z$j]3322Y"6tuLCmrjj2MW/,)W-eF9-#Rǭj?>X0?d3YCKŲa|pv(mNgKawHWAVzcSJӪ6%J_ϝ*9 7+4DrOՕShf/?: mɔNUin8/g5Ս$8ʂ^=>m\ ?DŌ s:D LlUr{A-~6h=A_{P-#wQKjB f?T:/Ñ!h*&KaWZL^ μW}6[ԣD>gy,GzIvum!EέT+Q$b %0ili=>^8><Ϩ#=YDR+UU6~8AAS Jz l:T)\ SB%w/X$M+]?>0Yf09PX-n+˖=٥I=\/邲m~LōNN{Ƅ7OX09Zk tT"/A!G9rJpo8ެW(Ԁ'}[ƐMh2f`$PEH,7}G# riuaMu D1ˇ, TS_J1Y 'CfxUfʈEi|f@n%!l%9iˉMy&~:Mï ue:j*쿿 /Dm\v[SުzR.K|#?&ݍ4|IR PO'M@nu\SWx:g%uELZCbfKDL \sc&[AJutcl~O׬[^\hY3j*o_ L~/9\q-Q] p#5[#l ~usd @߰x,rr߸NR/<w-lf>y#[!]3CTf@k~B*U௚ p*XbԻ 'l1KV 3U>?FLO+2pE(~U`(VcܿǹW ^%a;LγtWGoI~he0XHxAq1eD5^sZ4Q PQuo ר;7`7(3 FՅBkvb= m<Ԁ&_M̃ MT53yo"OobF re lHOH] ASw?pD wo@}]DʳJ+ntJֺڇgd.3$zZ_a\oZ?*5̲; l4WzCQ5U$DW#T+F䧬ts..[=]çx0%' p?5_q ❾(څ$qd[˜gAbo >ɖ;5aCUm<{,:,ȧZ/% ΏYY2д{s+Q~B)Qu%LUcUv9VjTpM~KA T)|zuX\j8/v<#Hڪ+ݨQh`P܇sh`r73/sw9JoV%RR|T]Usg1׻n+Kܢ :?֜  &+\QGP ﱮC>ΤnL=;;]-L L^#{k?4DGhl?&2@{NcԿk'ҡzNdMH6&LOUHǨK 9@ i~ߦ^eF$Dp6hVՂ4 e~DBH gnV8ﱰlvqub"mCDxv`ˤgۄ8G5GN  \m( uZ@BIζ/?=sy ;@{+_hU'x{wY~K wqݝب Չ\IMjikeBK'~Y=#Ză|ru=do:{T@v:d2\/X̰dԎc; UޝS_MzYeTY=Z}]‡(r034[ 1`y|uf/% 8E$T1L)KZX{i}Dsʼn #Mΐ~SyFJu6u f U1Ji0^or:9u,Kp}f7S>ojRS=yG9Y8hCc> Fc^NS~q2'saAJD"_6Pm(q#-+7^юK9;]MpHN<bd_#?!Y D f9+7eN?3p^mJlh!ӄ+9M BQ_n_ʒoćfs']vfy9"e(z(ڽIi69,gIFu#`w෷Ϧg~aSRGr9 C˅BuՎ]=d xIBv`ֲ E{`Cdʼn fe 'DE4c짰7y#y_4* jX;n>ɺqI.F6[C<}; zk_u<7OS.+zjKwhQ)玒/[qqAPR }nE|3EE9,$8{ P.]"qJ eVa!}uBc$RCWx-X$j8^uGhYpUK /15RSb}FX XX(4;zPOb35f#}O;Z/?<>6\(,Tehc=X2~!\05Ү+lf1넏+e,Vcjg05V~_ulif%[dJ@G)(^GB ,#S|N}x0oVdNGjeZ7tzbC7γ.Z3xlu6M [f2FcP!|7aD)q% +K1 hۯ 76 "W endstream endobj 442 0 obj << /Length1 1647 /Length2 11649 /Length3 0 /Length 12494 /Filter /FlateDecode >> stream xڭwctenccul;ݱm;Yٱm۶mc[Ûg}ƾ9Xk̷쫼!PƉ knmhk-k%M4up2|blpddB@'s[a' 7@ h L\\\pd![;wsS3' $ |Z:?\Vv@Op2Ḽ!9y Y1 @ htLB mnqRLlV8lmJ͑K`p݌vA;3```yNs#+g'I&oh`n*/,8 h lM>5mJou20q8ݜe;Y$s0; gGsE@ p8[?i> /Ymm`2cbi~101CnlOQ3TAX&p N.*+_)_qFeߩEd ?{h l kX8Z8FgjDÅg!6w5w˛;L >/o1Yӈ0e3s#Khc9| EEThmgW8)IM?Q ں<عt9\̬^1,c`bgdd|οшGJN6Ɵ`#gϊ >3!݀FpKF<)N5XCZ}=LCAvyU>)!\A Svo#=VI\|/<_4 ňgjW [쌪; EPS,0WT$.yvHFu 5gǏC7x4YѰd<Xމ_!]8]=RߜIlSljal/ Lv_5k`q5to&?5O$(yFMINu+I ,in9jfqNC3ݑDuR6"/qPy[E2ʓ0,(Vd?bOLxOk-V#n֙q{O)wyHTz0<635U u mvbfU]g}IT?8P*ځE^hzKc caO/)HS$Ę* z돴.[`j5ccnixL^~ë66D= aj>,$2yAN";nHȉ!bh}/hrq@oU׽2(q!+".X4jʫzx<׽.sjLf3Uһ )"4FۍW4;o >1G#ܪ^nW!5杖Bws>PƤZK1%noX8;υC3v7kR1#\d Y%)Tt&;t'qPq& ds*MƬp~qz^T \V 1oJ&ZaMYO%9C2^b'!"]f"g͡"va*nDL fYBGň)}m Cɛx3\ 醾VoІ[/wt ʜMO^$2嘘 -.dS ;+>!uѠ P3l#2R!N>g=XBWӥ-C٠a&64n!?yIb̥o4Kcf4_CZf#!@fiM-0 1{r"69~@쏳ķx7~è,7R2o?:Kj )w j!AȱCa2E)a͗g\l!`=p*vڤj`hTr7]dlH4przZտEZ Kw5Nh&tT|s}(+dV0dғ aN䣰86W&ur(R.:;+j- ɑ :͠vD}m1atF<AVp^qLh踖&?m!C/ I?tƪw+mغqoN z;Ye#صy nA.*<ǭDSbz"|,>d7-u ROe{+ y-!]P5?l%irKcviG=,<ʳcHqCNWZ+WDd&VxFctEQzӽ{Zk34POə`M[O|?OZ6bpR@LӾ]w`"%w,~o_o&s֍cKtߖY"T.3M4zxx>wOPy"aP>kF؜>7tMa[-bfomҍTeRMGma/A89Ԇla  tB驒?{}vrY/ץbLDR~N0*(%x)՝<%9T_VUhD1P'} vOţ ?.=.^%[ 8_OyP-~nH6iI@{zG mO4ʹl9vEgNQoK]r{wr}[G8;swcXs8g|{$u<~-\'Ŀ [h.&^HqՐE4k!c%=\m{+6|@ 4xUm?Y2kN{ /6:\E.7> Vw"8DK:R͏s 8\H\0?F|_NJOɃBThЀ//-4J{k 5ЈC-|1ŻQug8Ү_,wn9u@ve3tiJg=Jh^\6ݟplj3&y7Ks G~ l`'z*+}ri*!&,rgq07錧F%%>>/&bX{g]ܽx'3:j1J3$ @Uڐ Lڧw%t ##qwЭ4\xhMM;At[*l*:4Swa;Z\h0G% yj[hYzFJf>CJI^}] oQ+U>*l7-m-*ȊՍ\\>[F?[#y2#-&AC0 r/{(+rZ;A7{)_<%5Xw7$>ݝy3۹0Z|fYNcrW3bq04?šg<$Qѐ9t]\t;\bXV.VKk [&FCCk&(ƹixK:}RS)9]܁a \@IAQA RZZx_J^ #MB]4dzx/'ڂ7AeY޹j9I ֓42䘞X QaLUOR:Q_@'~4 k}i3/dl!CCJ8 BSmr*wLf f)D$Bx)Pm25AqoZ?n>'ABfcwωl=u"@esYCBUO:$'#8Qɛ{VIϣӨ= TwP9 , [萼еrϠF\~ߣ[ze?uEU p"Ëq~˟= _=e,/Ar< B 0zQPIcS`ЅD|BjfG8'k5E^?M8+uWfTxһQpimQ3QacO$>@H\LaĿȉH;@ 7N,df_i:[,5.sP=pYjO/5 _=7!0Bx9zP~J/p$u$˦UK=`ӓɈ")+HW7uj{ym\ܭQY~wũε 6e3_{[Ӡ@":E{. ^.^=ƍ4w 3Z=qz1Fתl|R:)_,ՓRΠ4%6\-tR!~a"۷p2͟wVIBBKDܗZKntI%iTO0z401nu#Bj/8 N9y~s{\g=QdEp͠IRTI'&39.pRSb ikze`YCxN +9 =~C j T J9AZWL [="a:Yl§z^A }VVezcjȥDi%bSF^U"/<~f,Z1[QX)KFQ }YZaGԄqӿbF󸊧 ft{fK% Ѓ(g奴H/xr^Ȇ;Ѡ Ԡm<7 ZUX!ۃ2_ XpI#PH}՟aey y߁Wt)I1N34#dlH@(9J5U^HL3o%Oy&z5}bH`ez<]KgjSvcPf9 ԑȹ)hZU`8qp2?sًPL4Pua/gF]Z$z$5/= ,k]i'ayFHݦ!-';*0%I){3tEy&r"߅ Brޡ_=E <$Y? I`OaZIA%3%FtU9+ H0AEBv5ι.^B!/“"2_iRt YlRb>, &NJnҳ=T>\An~?($;ZC$2  Ckqv!B#,8n.RͷHg*I'W:#^3O:Puw9AZ\a.?Qf& K SFֳ6XȕtB\Ha{6oDd-AeFґx]5 c=; li 8z“ :L]V%d>ШoǑ,)Jnm63G gRm"2T"edK"wõs7JѪvSR4}qw&Cy<\BXxJcE!P!3Y%suk-!28l[ `6Y60 `[bB~ FiUGg 0jv$$oI8ШVo1.ӛb=* SOUjvTBZ7^LI }_*T tg\8y6m&hYݕ՚ 9 b"k5@&4dncdn4xk|7Cɢr_WF1 ʿ^KChrG6ԴAi`ƫ8NihYm6yV& \IU+s-c>Hf F%m}-(mw9̃ơ66ƨ` }]LBdP`J\@<*z쐼kӳaR ÏKi k(. KoA4:l2LXu&9'BɑkEL$2Ewkᄫ[čҚRi!dt ];9V8yd,xS8Ne&ɽl=헉QNSKQw1zKͻcXi3V^2ǿӫ3 Sv(R 1c*ƙ*@XV[Pܿ t<}@zXfH.م γR:S_ӛNgV>r:b.yZ;|ITW#ckor|HD4YΖ/jjpo$"??աuA@EȔWVH*޾TE\rxs :8^e!RuM5wP4thZB{:jU%=o͌iD(PTubǟ=hZ$?I PQuTES ˾-s[=6o$QCg-]R׺.\jCgXU{@=s-%k_COY /6YҠqT"^Td[`٩% ep6c=B`[wTq##SA|E1?]b&(2=6n8 eN'*NH򅶀tI3uyneU󀙈X5bACliF~-%j D`Ɛ+bcnOzFgSaftr:0wX so*,I&ܒxo4UV=x QhwQHw>}5YS? .EJ<&> stream x\[oI~ϯ]toh%! 0 L$vvfꋫ7ҮvUG;2Ύ)LGs`V#s`>b,*bRX,I܎;I,ϤK`2Ad2b))@0H(h{4SV x42Q T12p)O t>o㎎IBLLxf`F)58 BW2t1# ~>tOf,|L o-=f?)gcƟ .BcE{Ф8 XJ]̈́&&! p]!(@h[8=P?R*R2Хu+A!bڰE9qABP$v<(_ 4 u!@ 0C/t~{hxpGC,-x4r*ӄF,UX,XS <(*ʛ.*RjM[B򛒶@2BGa@ bD%"BD\"bH0`z $d-Ja"O@b)" '%LEB@pŶHUG2wk"4d" +$j.@UDN[ dRMU{ΙBpTJH8Rx0l(QBkb(n kxآkiR (A5y A( ID`6B0h"w **\T|F#=QZ!TR%M(rܢF4V}Rwwf)D"s_?O/wn>Ttgx4KmjӢ}: 15;JƏ3~V9ciB\tOty"-l6M6wkޅ?NUX'$"B 3|ϒO\Na?IL.Z?43)Gpxґ'/.̦5ֱu5Ӻz^Gt*t?usAXh/tNl=N41@Ȟq&t/{ZG E ?>|~3t#O ++t=oN3 5@ yu| t(Vь`h'VҌjw()R}{im{hw4R=Z)@ӈv7z@.׸5#7p.0+%-՘^15K&ۿqşs*A|F5]Mp' B=ukӸ tP(l+72Ix]ehilLs{=Kp7<2ul4$ol4IEtAs=W41@4:Zx=ʕNofڣ9~T#SzF1y綆R 5AU+ΦVH.\96gseHƙ~[ʹME'd!.yJc::oa:e% wI_CNjl-G{hѺjn7B[RVUSu٦yAv~RV^5&z1{aSvN8NsnM^HuHj=''*Odx3O',{_\ .T3<>*vUB>=j n/vlp5<<*YyW- &2<&4.^?^FR8=> [#`<:\Q+`LEI%&PJ2G+Mӫ8~SN >Ld8.V קg'odT#"B]\ dp[9#6ton]Mpxg+ :dRRh8lr2(kQXý=::}r ĮAzWh󙣺jJG19cF zGgRDDդ#zGtnRve#4=Hp3K_!_k>V>׸~Xt' E?P}ы;̟=?IGk~~oh0=χj<^]|U4[xT.xo' ʿ~Z&\)2!T3\N7ZW*ʋW|mNaҴ4?g_'eIvt"Iog k[X Jzk'rK8l`**_,PʙFIľQ;{y%vUꗃ-R(=yţWϷŊ5 O5u98O98WFYrt{@FQxo?OUl Edz]c]QlQn ݃Qxr|w}*6W5ܰZnO>9pt6] &߮_@l??ŦC?,7a>sz`EQyqpV8=*/+9J~Y]$1ﱔ+ݱSM}?a _ ~a)\ׄvQ<<}OkbKn^L>to;A^;cŦr?K_SE3Fyn[u?+YH nEV[_EԳUT36)؁(Qy}%v&:tWg k tu !Զj/|c?@NRi֕}W֐sWKԳb8/%?/죂1mZu3s/娵d*:AH qY,5ldAi'l zڴ=w !9uXn8c( vܬ/?&/H^N$5?aK%7]5c=W"`Y]/yKvou(3Kutd0-ߧ-<90'?LgL"4HSF?][Q?S}eԩ"ӫ2"#N%~'|}O='N9W=jAz2P8z,->R곴` ÒrB6XZ|gitY[aiﳴ`7QV2mpG."ImN}z ;|ȾssiήLmp-sg.7a^ւyefasu}NMu"JlC>oFLwa}aׇOx \O{#S >E?Gκ>l]uI~CBUQ:WY0e½i([]Y:NJj"hU4tU0]:܊F+u{WZޡ:==^ήPOk`5;dtQ!mzM bǓm}n6R.kzWS qǹ>,lj Qr*e\Tٕ=b!fCXh%l+Vk֬TN,٦KI+1`ZFN͚˩aIJ1]4W:YдaĘYb^gOTV콴I+U֬}D/5JX5ۈlܴa6%▭:qwp\*v !Z endstream endobj 477 0 obj << /Author(Ann Dooms ; Eric Jespers ; Alexander Konovalov ; Helena Verrill)/Title(Congruence)/Subject()/Creator(LaTeX with hyperref package / GAPDoc)/Producer(pdfTeX-1.40.17)/Keywords() /CreationDate (D:20190519192926+01'00') /ModDate (D:20190519192926+01'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016) kpathsea version 6.2.2) >> endobj 446 0 obj << /Type /ObjStm /N 33 /First 282 /Length 1826 /Filter /FlateDecode >> stream xڕXQo ~ϯM$%p-Y(p^n=LeE2[홑me>΄H}I yIYϨ|`*O( Z^@OtCDˑS֐/^YbᨎC%lk&0F8p7QY蝂T3rʦ^ͷ>uTnyqYoy9}z^)ݗww[ww@\3nhrkKN:zyp+뜥(M q PņBw:K946o7mrO[\9IEqcfΣvuMP<ה; 5k&8F#ej ߰oz7+Lijg,v\Ӂ+̺F#SN|&1Th!\ufU%g 'c%|þNm 7{"OH5r)TIۄaW\~tdLn& 9ï38roWNs/2ϙ /EϬ`cC^~N3_f&~&gWU5šYh@p7^?׽OQ^>r"/Sv|:<[ұ%/gn_#n endstream endobj 478 0 obj << /Type /XRef /Index [0 479] /Size 479 /W [1 3 1] /Root 476 0 R /Info 477 0 R /ID [<88B6A8B7022E893372DA751DF8ED9AB0> <88B6A8B7022E893372DA751DF8ED9AB0>] /Length 1131 /Filter /FlateDecode >> stream x9l^E羗q%8KvYlvYQ 萠AP (E QP 44t4of; !`@Ȁ{Ԕ`x@M3-KIj%MZ'G@-IjI@=6KO^=Fo+۩%mA HcvCI[AjcnvjnvOPIztQ[v08Bݠc0*`Z `.4З\W<&$'_-:ED8'ip̃p%e]*PvW}N}g e$|f+͐LÜeW^c0S`\ܻ,4r,*V[y]vnrXg,,<`L9O_8.qvuu|F rDZK=C9fV\@?fq0̯}ⴅ8zIT'U䷊4iEZZpgZixq 7-p;-$#G3GcI&eP5Ⴤ i&M[z $TMȝ&M뢒>Yh.E~ H@./N;A o^ So^^hŸYhȬSѰYF^IѨŧƬxKEV|ЪhŠ/V4i7MY}i+^ 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);